mirror of
https://github.com/ksherlock/wdc-utils.git
synced 2024-06-16 21:29:37 +00:00
Compare commits
100 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a455e48a2b | ||
|
65d373be25 | ||
|
42347e4d40 | ||
|
3ab26264f6 | ||
|
9430f99270 | ||
|
32495371de | ||
|
8ff374eced | ||
|
b9ce1e2d3f | ||
|
ec6619c8c7 | ||
|
2364cae06a | ||
|
9fa57d0a12 | ||
|
ae182abaa4 | ||
|
66cf463cbf | ||
|
e7720a69bb | ||
|
d66de57273 | ||
|
ab5961c1a9 | ||
|
d3df7b2c47 | ||
|
885fcc7958 | ||
|
db1d452f53 | ||
|
236dc538b0 | ||
|
8147da2cfc | ||
|
5f9d1a900d | ||
|
348b97669b | ||
|
606747cba3 | ||
|
4f833d83a6 | ||
|
285763c318 | ||
|
7c07cbcd17 | ||
|
1e810db107 | ||
|
13389be323 | ||
|
2f2809dcb2 | ||
|
b9092401f6 | ||
|
b18467a641 | ||
|
7f3ccd84c8 | ||
|
ebd67dc0cc | ||
|
97787b30e4 | ||
|
e81e47d4c8 | ||
|
e43ace0d1c | ||
|
06a3c5b5ae | ||
|
4e51bd6c51 | ||
|
466c90a34e | ||
|
253a3ccc49 | ||
|
e9383cfcdc | ||
|
b29b208b06 | ||
|
dd0a369ac1 | ||
|
e693ad8ef3 | ||
|
91d7f60bff | ||
|
47130d0e67 | ||
|
bcb2ba03ef | ||
|
18c9ede89f | ||
|
c08c84c593 | ||
|
adafabd419 | ||
|
6aa7418561 | ||
|
ef838227d2 | ||
|
7e09ecd5f2 | ||
|
eed6958275 | ||
|
03f24ec829 | ||
|
6b99d138a2 | ||
|
5db92377d6 | ||
|
8ba832d9a9 | ||
|
e4e6febf7d | ||
|
d5105336dd | ||
|
ac071f1d9a | ||
|
7c71a97550 | ||
|
6aa54979a9 | ||
|
add8545906 | ||
|
25e6e61989 | ||
|
6d1e684f8d | ||
|
61c3b82aaf | ||
|
4317d2929b | ||
|
2ff8267af3 | ||
|
ff09d63678 | ||
|
11bce44253 | ||
|
9de248b599 | ||
|
e3b555b0cc | ||
|
38e4f135ac | ||
|
75bd907dad | ||
|
8f2b86b882 | ||
|
432a023213 | ||
|
960170f831 | ||
|
9563e2f8f5 | ||
|
6ff5a4599a | ||
|
ec92c3b599 | ||
|
09628cb2c3 | ||
|
337840cb3c | ||
|
d54d8f2924 | ||
|
4178be1db1 | ||
|
b35358fdd8 | ||
|
cef989b17b | ||
|
1deafa3ad1 | ||
|
eb993acd2a | ||
|
966a879419 | ||
|
822b685d46 | ||
|
2d69c18bd1 | ||
|
9b1900c8f7 | ||
|
498738d1a2 | ||
|
6d4b9cbd3f | ||
|
c5f2ed5562 | ||
|
174acc708c | ||
|
8d63e66e7a | ||
|
f1e7e0f0e3 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
*.obj binary
|
17
.github/workflows/make.yml
vendored
Normal file
17
.github/workflows/make.yml
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
name: Make
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: make
|
||||
run: make all
|
32
.github/workflows/msys2.yml
vendored
Normal file
32
.github/workflows/msys2.yml
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
name: MSYS2 build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
msys: [MSYS, MINGW32, MINGW64]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
path-type: strict
|
||||
msystem: ${{ matrix.msys }}
|
||||
install: make gcc mingw32/mingw-w64-i686-gcc mingw64/mingw-w64-x86_64-gcc
|
||||
|
||||
# Runs a single command using the runners shell
|
||||
- name: Make ${{ matrix.msys }}
|
||||
run: msys2 -c 'make'
|
||||
|
||||
- name: Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binaries - ${{ matrix.msys }}
|
||||
path: "*.exe"
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "afp"]
|
||||
path = afp
|
||||
url = https://github.com/ksherlock/afp
|
12
.travis.yml
Normal file
12
.travis.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
dist: bionic
|
||||
language: cpp
|
||||
os:
|
||||
- osx
|
||||
- linux
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
script: make all
|
||||
|
43
Makefile
43
Makefile
|
@ -1,28 +1,55 @@
|
|||
LINK.o = $(LINK.cc)
|
||||
CXXFLAGS = -std=c++11 -g -Wall
|
||||
CXXFLAGS = -std=c++14 -g -Wall -Wno-sign-compare
|
||||
CCFLAGS = -g
|
||||
|
||||
OBJS = dumpobj.o disassembler.o zrdz_disassembler.o
|
||||
DUMP_OBJS = dumpobj.o disassembler.o zrdz_disassembler.o
|
||||
LINK_OBJS = link.o expression.o omf.o set_file_type.o afp/libafp.a
|
||||
|
||||
#UNAME_S := $(shell uname -s)
|
||||
#ifeq ($(UNAME_S),MINGW64_NT-10.0)
|
||||
ifeq ($(MSYSTEM),MINGW64)
|
||||
OBJS += mingw/err.o
|
||||
# static link if using mingw32 or mingw64 to make redistribution easier.
|
||||
# also add mingw directory.
|
||||
ifeq ($(MSYSTEM),MINGW32)
|
||||
DUMP_OBJS += mingw/err.o
|
||||
LINK_OBJS += mingw/err.o
|
||||
CPPFLAGS += -I mingw/
|
||||
LDLIBS += -static
|
||||
endif
|
||||
|
||||
ifeq ($(MSYSTEM),MINGW64)
|
||||
DUMP_OBJS += mingw/err.o
|
||||
LINK_OBJS += mingw/err.o
|
||||
CPPFLAGS += -I mingw/
|
||||
LDLIBS += -static
|
||||
endif
|
||||
|
||||
wdcdumpobj : $(OBJS)
|
||||
.PHONY: all
|
||||
all: wdcdumpobj wdclink
|
||||
|
||||
wdcdumpobj : $(DUMP_OBJS)
|
||||
$(LINK.o) $^ $(LDLIBS) -o $@
|
||||
|
||||
wdclink : $(LINK_OBJS)
|
||||
$(LINK.o) $^ $(LDLIBS) -o $@
|
||||
|
||||
|
||||
subdirs :
|
||||
$(MAKE) -C afp
|
||||
|
||||
disassembler.o : disassembler.cpp disassembler.h
|
||||
zrdz_disassembler.o : zrdz_disassembler.cpp zrdz_disassembler.h disassembler.h
|
||||
dumpobj.o : dumpobj.cpp zrdz_disassembler.h disassembler.h
|
||||
omf.o : omf.cpp omf.h
|
||||
expression.o : expression.cpp expression.h
|
||||
mingw/err.o : mingw/err.c mingw/err.h
|
||||
|
||||
set_file_type.o : CPPFLAGS += -I afp/include
|
||||
set_file_type.o : set_file_type.cpp
|
||||
|
||||
afp/libafp.a : subdirs
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) wdcdumpobj $(OBJS)
|
||||
$(RM) wdcdumpobj wdclink $(DUMP_OBJS) $(LINK_OBJS)
|
||||
$(MAKE) -C afp clean
|
||||
|
||||
|
||||
.PHONY: variables
|
||||
|
|
14
README.md
Normal file
14
README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
wdcomf
|
||||
------
|
||||
object file linker. Generates OMF files (for use with the Apple IIgs)
|
||||
|
||||
wdcdumpobj
|
||||
----------
|
||||
|
||||
object file disassembler
|
||||
|
||||
|
||||
building
|
||||
--------
|
||||
builds with MSYS2/MingW64 (most useful since WDC's tools are windows-based) or MacOS, etc.
|
1
afp
Submodule
1
afp
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit bf4399146d7402a390cad78102d4169e2a41ac04
|
435
disassembler.cpp
435
disassembler.cpp
|
@ -1,7 +1,11 @@
|
|||
#define _XOPEN_SOURCE
|
||||
|
||||
#include "disassembler.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
static constexpr const char opcodes[] =
|
||||
"brkoracoporatsboraaslora"
|
||||
|
@ -49,6 +53,7 @@ static constexpr const int mDPI = 0x7000;
|
|||
static constexpr const int mDPIL = 0x8000;
|
||||
static constexpr const int mRelative = 0x9000;
|
||||
static constexpr const int mBlockMove = 0xa000;
|
||||
static constexpr const int mImpliedA = 0xb000; // inc a, dec a, etc.
|
||||
|
||||
static constexpr const int m_S = 0x0100;
|
||||
static constexpr const int m_X = 0x0200;
|
||||
|
@ -69,7 +74,7 @@ static constexpr const int modes[] =
|
|||
1 | mDPIL, // 07 ora [dp]
|
||||
0 | mImplied, // 08 php
|
||||
1 | mImmediate | m_M, // 09 ora #imm
|
||||
0 | mImplied, // 0a asl a
|
||||
0 | mImpliedA, // 0a asl a
|
||||
0 | mImplied, // 0b phd
|
||||
2 | mAbsolute, // 0c tsb |abs
|
||||
2 | mAbsolute, // 0d ora |abs
|
||||
|
@ -86,7 +91,7 @@ static constexpr const int modes[] =
|
|||
1 | mDPIL | m_Y, // 17 ora [dp],y
|
||||
0 | mImplied, // 18 clc
|
||||
2 | mAbsolute | m_Y, // 19 ora |abs,y
|
||||
0 | mImplied, // 1a inc a
|
||||
0 | mImpliedA, // 1a inc a
|
||||
0 | mImplied, // 1b tcs
|
||||
2 | mAbsolute, // 1c trb |abs
|
||||
2 | mAbsolute | m_X, // 1d ora |abs,x
|
||||
|
@ -103,7 +108,7 @@ static constexpr const int modes[] =
|
|||
1 | mDPIL, // 27 and [dp]
|
||||
0 | mImplied, // 28 plp
|
||||
1 | mImmediate | m_M, // 29 and #imm
|
||||
0 | mImplied, // 2a rol a
|
||||
0 | mImpliedA, // 2a rol a
|
||||
0 | mImplied, // 2b pld
|
||||
2 | mAbsolute, // 2c bit |abs
|
||||
2 | mAbsolute, // 2d and |abs
|
||||
|
@ -120,7 +125,7 @@ static constexpr const int modes[] =
|
|||
1 | mDPIL | m_Y, // 37 and [dp],y
|
||||
0 | mImplied, // 38 sec
|
||||
2 | mAbsolute | m_Y, // 39 and |abs,y
|
||||
0 | mImplied, // 3a dec a
|
||||
0 | mImpliedA, // 3a dec a
|
||||
0 | mImplied, // 3b tsc
|
||||
2 | mAbsolute | m_X, // 3c bits |abs,x
|
||||
2 | mAbsolute | m_X, // 3d and |abs,x
|
||||
|
@ -137,7 +142,7 @@ static constexpr const int modes[] =
|
|||
1 | mDPIL, // 47 eor [dp]
|
||||
0 | mImplied, // 48 pha
|
||||
1 | mImmediate | m_M, // 49 eor #imm
|
||||
0 | mImplied, // 4a lsr a
|
||||
0 | mImpliedA, // 4a lsr a
|
||||
0 | mImplied, // 4b phk
|
||||
2 | mAbsolute, // 4c jmp |abs
|
||||
2 | mAbsolute, // 4d eor |abs
|
||||
|
@ -318,7 +323,7 @@ static constexpr const int modes[] =
|
|||
1 | mDPI | m_Y, // f1 sbc (dp),y
|
||||
1 | mDPI, // f2 sbc (dp)
|
||||
1 | mDPI | m_S | m_Y, // f3 sbc ,s,y
|
||||
2 | mImmediate, // f4 pea |abs --> pea #imm
|
||||
2 | mAbsolute, // f4 pea |abs --> pea #imm
|
||||
1 | mDP | m_X, // f5 sbc dp,x
|
||||
1 | mDP | m_X, // f6 inc dp,x
|
||||
1 | mDPIL | m_Y, // f7 sbc [dp],y
|
||||
|
@ -333,6 +338,38 @@ static constexpr const int modes[] =
|
|||
|
||||
};
|
||||
|
||||
static bool branchlike(uint8_t op) {
|
||||
|
||||
switch(op) {
|
||||
case 0x10: // bpl
|
||||
//case 0x20: // jsr
|
||||
//case 0x22: // jsl
|
||||
case 0x30: // bmi
|
||||
case 0x40: // rti
|
||||
case 0x4c: // jmp
|
||||
case 0x50: // bvc
|
||||
case 0x5c: // jml
|
||||
case 0x60: // rts
|
||||
case 0x6b: // rtl
|
||||
case 0x6c: // jmp
|
||||
case 0x70: // bvs
|
||||
case 0x7c: // jmp
|
||||
case 0x80: // bra
|
||||
case 0x82: // brl
|
||||
case 0x90: // bcc
|
||||
case 0xb0: // bcs
|
||||
case 0xd0: // bne
|
||||
case 0xdc: // jml
|
||||
case 0xf0: // beq
|
||||
//case 0xfc: // jsr
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
constexpr const int kOpcodeTab = 20;
|
||||
constexpr const int kOperandTab = 30;
|
||||
constexpr const int kCommentTab = 80;
|
||||
|
@ -368,6 +405,15 @@ std::string disassembler::to_x(uint32_t x, unsigned bytes, char prefix) {
|
|||
return s;
|
||||
}
|
||||
|
||||
int disassembler::operand_size(uint8_t op, bool m, bool x) {
|
||||
unsigned mode = modes[op];
|
||||
unsigned size = mode & 0x0f;
|
||||
if ((mode & m_I) && x) size++;
|
||||
if ((mode & m_M) && m) size++;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void disassembler::emit(const std::string &label) {
|
||||
fputs(label.c_str(), stdout);
|
||||
|
@ -378,13 +424,8 @@ void disassembler::emit(const std::string &label, const std::string &opcode) {
|
|||
std::string tmp;
|
||||
tmp = label;
|
||||
|
||||
int column = tmp.length();
|
||||
|
||||
if (!opcode.empty()) {
|
||||
do {
|
||||
tmp.push_back(' ');
|
||||
column++;
|
||||
} while (column < kOpcodeTab);
|
||||
indent_to(tmp, kOpcodeTab);
|
||||
tmp += opcode;
|
||||
}
|
||||
|
||||
|
@ -399,22 +440,14 @@ void disassembler::emit(const std::string &label, const std::string &opcode, con
|
|||
std::string tmp;
|
||||
tmp = label;
|
||||
|
||||
int column = tmp.length();
|
||||
|
||||
if (!opcode.empty()) {
|
||||
do {
|
||||
tmp.push_back(' ');
|
||||
column++;
|
||||
} while (column < kOpcodeTab);
|
||||
indent_to(tmp, kOpcodeTab);
|
||||
tmp += opcode;
|
||||
}
|
||||
|
||||
column = tmp.length();
|
||||
if (!operand.empty()) {
|
||||
do {
|
||||
tmp.push_back(' ');
|
||||
column++;
|
||||
} while (column < kOperandTab);
|
||||
indent_to(tmp, kOperandTab);
|
||||
tmp += operand;
|
||||
}
|
||||
|
||||
|
@ -423,6 +456,33 @@ void disassembler::emit(const std::string &label, const std::string &opcode, con
|
|||
}
|
||||
|
||||
|
||||
void disassembler::emit(const std::string &label, const std::string &opcode, const std::string &operand, const std::string &comment) {
|
||||
|
||||
std::string tmp;
|
||||
tmp = label;
|
||||
|
||||
if (!opcode.empty()) {
|
||||
indent_to(tmp, kOpcodeTab);
|
||||
tmp += opcode;
|
||||
}
|
||||
|
||||
if (!operand.empty()) {
|
||||
indent_to(tmp, kOperandTab);
|
||||
tmp += operand;
|
||||
}
|
||||
|
||||
if (!comment.empty()) {
|
||||
indent_to(tmp, kCommentTab);
|
||||
tmp += "; ";
|
||||
tmp += comment;
|
||||
}
|
||||
|
||||
tmp.push_back('\n');
|
||||
fputs(tmp.c_str(), stdout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void disassembler::reset() {
|
||||
|
@ -431,7 +491,36 @@ void disassembler::reset() {
|
|||
}
|
||||
|
||||
|
||||
std::pair<std::string, std::string>
|
||||
disassembler::format_data(unsigned size, const uint8_t *data) {
|
||||
|
||||
std::string tmp;
|
||||
|
||||
for (unsigned i = 0; i < size; ++i) {
|
||||
if (i > 0) tmp += ", ";
|
||||
tmp += to_x(data[i], 2, '$');
|
||||
}
|
||||
|
||||
return std::make_pair("db", tmp);
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string>
|
||||
disassembler::format_data(unsigned size, const std::string &data) {
|
||||
|
||||
switch(size) {
|
||||
case 1: return std::make_pair("db", data);
|
||||
case 2: return std::make_pair("dw", data);
|
||||
case 3: return std::make_pair("da", data);
|
||||
case 4: return std::make_pair("dl", data);
|
||||
|
||||
default: {
|
||||
std::string tmp;
|
||||
tmp = std::to_string(size) + " bytes";
|
||||
return std::make_pair(tmp, data);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::dump() {
|
||||
|
||||
|
@ -440,15 +529,12 @@ void disassembler::dump() {
|
|||
if (!_st) return;
|
||||
|
||||
|
||||
auto p = format_data(_st, _bytes);
|
||||
|
||||
indent_to(line, kOpcodeTab);
|
||||
line += "db";
|
||||
line += p.first;
|
||||
indent_to(line, kOperandTab);
|
||||
|
||||
|
||||
for (unsigned i = 0; i < _st; ++i) {
|
||||
if (i > 0) line += ", ";
|
||||
line += to_x(_bytes[i], 2, '$');
|
||||
}
|
||||
line += p.second;
|
||||
|
||||
hexdump(line);
|
||||
line.push_back('\n');
|
||||
|
@ -458,28 +544,23 @@ void disassembler::dump() {
|
|||
reset();
|
||||
}
|
||||
|
||||
void disassembler::dump(const std::string &expr, unsigned size) {
|
||||
void disassembler::dump(const std::string &expr, unsigned size, uint32_t value) {
|
||||
|
||||
std::string line;
|
||||
|
||||
if (_st) dump();
|
||||
|
||||
for (_st = 0; _st < size; ++_st) _bytes[_st] = 0;
|
||||
for (_st = 0; _st < size; ++_st) {
|
||||
_bytes[_st] = value & 0xff;
|
||||
value >>= 8;
|
||||
}
|
||||
|
||||
auto p = format_data(size, expr);
|
||||
|
||||
indent_to(line, kOpcodeTab);
|
||||
|
||||
switch(size) {
|
||||
case 1: line += "db"; break;
|
||||
case 2: line += "dw"; break;
|
||||
case 3: line += "da"; break;
|
||||
case 4: line += "dl"; break;
|
||||
default:
|
||||
line += std::to_string(size);
|
||||
line += " bytes";
|
||||
break;
|
||||
}
|
||||
line += p.first;
|
||||
indent_to(line, kOperandTab);
|
||||
line += expr;
|
||||
line += p.second;
|
||||
|
||||
hexdump(line);
|
||||
line.push_back('\n');
|
||||
|
@ -512,7 +593,7 @@ void disassembler::space(unsigned size) {
|
|||
std::string line;
|
||||
|
||||
indent_to(line, kOpcodeTab);
|
||||
line += "ds";
|
||||
line += ds();
|
||||
indent_to(line, kOperandTab);
|
||||
|
||||
|
||||
|
@ -544,21 +625,28 @@ void disassembler::space(unsigned size) {
|
|||
}
|
||||
|
||||
|
||||
void disassembler::operator()(const std::string &expr, unsigned size) {
|
||||
void disassembler::operator()(const std::string &expr, unsigned size, uint32_t value) {
|
||||
|
||||
// todo -- what if label within size?
|
||||
check_labels();
|
||||
if (_st == 0 || !_code)
|
||||
check_labels();
|
||||
|
||||
if (!_code) {
|
||||
dump(expr, size);
|
||||
dump(expr, size, value);
|
||||
if (_inline_data) {
|
||||
_inline_data -= size;
|
||||
if (_inline_data <= 0) _code = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_st != 1 || size != _size) {
|
||||
dump(expr, size);
|
||||
dump(expr, size, value);
|
||||
return;
|
||||
}
|
||||
for(int i = 0; i < size; ++i) _bytes[_st++] = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
_bytes[_st++] = value & 0xff;
|
||||
value >>= 8;
|
||||
}
|
||||
print(expr);
|
||||
}
|
||||
|
||||
|
@ -566,10 +654,18 @@ void disassembler::operator()(const std::string &expr, unsigned size) {
|
|||
|
||||
void disassembler::operator()(uint8_t byte) {
|
||||
|
||||
check_labels();
|
||||
if (_st == 0 || !_code)
|
||||
check_labels();
|
||||
|
||||
if (!_code) {
|
||||
_bytes[_st++] = byte;
|
||||
|
||||
if (_inline_data && --_inline_data <= 0) {
|
||||
dump();
|
||||
_code = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_st == 4) dump();
|
||||
return;
|
||||
}
|
||||
|
@ -578,12 +674,24 @@ void disassembler::operator()(uint8_t byte) {
|
|||
if (_st == 1) {
|
||||
_op = byte;
|
||||
_mode = modes[_op];
|
||||
|
||||
// bit hack
|
||||
if (_traits & bit_hacks && _op == 0x2c) {
|
||||
if (_next_label == _pc + 1) {
|
||||
dump();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_traits & pea_immediate && _op == 0xf4) _mode = 2 | mImmediate;
|
||||
_size = _mode & 0x0f;
|
||||
if (_mode & _flags & m_I) _size++;
|
||||
if (_mode & _flags & m_M) _size++;
|
||||
|
||||
if (!_size) {
|
||||
print();
|
||||
|
||||
if (branchlike(byte)) fputs("\n", stdout);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -591,42 +699,38 @@ void disassembler::operator()(uint8_t byte) {
|
|||
_arg = _arg + (byte << shift);
|
||||
if (_st <= _size) return;
|
||||
|
||||
switch(_op) {
|
||||
case 0xc2: // REP
|
||||
_flags |= (_arg & 0x30);
|
||||
break;
|
||||
case 0xe2: // SEP
|
||||
_flags &= ~(_arg & 0x30);
|
||||
break;
|
||||
uint8_t op = _op;
|
||||
uint32_t arg = _arg;
|
||||
|
||||
if (_traits & track_rep_sep) {
|
||||
switch(_op) {
|
||||
case 0xc2: // REP
|
||||
_flags |= (_arg & 0x30);
|
||||
break;
|
||||
case 0xe2: // SEP
|
||||
_flags &= ~(_arg & 0x30);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// all done... now print it.
|
||||
print();
|
||||
}
|
||||
|
||||
if (branchlike(op)) fputs("\n", stdout);
|
||||
|
||||
|
||||
void disassembler::print_prefix() {
|
||||
|
||||
switch(_mode & 0xf000) {
|
||||
case mImmediate: printf("\t#"); break;
|
||||
case mDP: printf("\t<"); break;
|
||||
case mDPI: printf("\t(<"); break;
|
||||
case mDPIL: printf("\t[<"); break;
|
||||
case mAbsoluteIL: printf("\t["); break;
|
||||
|
||||
case mRelative:
|
||||
case mBlockMove:
|
||||
printf("\t"); break;
|
||||
|
||||
// cop, brk are treated as absolute.
|
||||
case mAbsolute:
|
||||
if (_size == 1) printf("\t");
|
||||
else printf("\t|");
|
||||
// todo -- subscribe to before/after events...
|
||||
switch(op) {
|
||||
case 0xc2:
|
||||
case 0xe2:
|
||||
case 0x22:
|
||||
case 0x5c:
|
||||
case 0xdc:
|
||||
event(op, arg);
|
||||
break;
|
||||
case mAbsoluteLong: printf("\t>"); break;
|
||||
case mAbsoluteI: printf("\t("); break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -692,36 +796,6 @@ std::string disassembler::suffix() {
|
|||
|
||||
}
|
||||
|
||||
void disassembler::print_suffix() {
|
||||
|
||||
switch(_mode & 0x0f00) {
|
||||
case m_X: printf(",x"); break;
|
||||
case m_Y: if (!(_mode & (mDPI|mDPIL))) printf(",y"); break;
|
||||
case m_S:
|
||||
case m_S | m_Y:
|
||||
printf(",s"); break;
|
||||
}
|
||||
|
||||
switch(_mode & 0xf000) {
|
||||
case mAbsoluteI:
|
||||
case mDPI:
|
||||
printf(")"); break;
|
||||
case mAbsoluteIL:
|
||||
case mDPIL:
|
||||
printf("]"); break;
|
||||
}
|
||||
|
||||
// (xxx,s),y
|
||||
// (xxx),y
|
||||
// [xxx],y
|
||||
switch(_mode & 0x0f00) {
|
||||
case m_Y: if (_mode & (mDPI|mDPIL)) printf(",y"); break;
|
||||
case m_S | m_Y:
|
||||
printf(",y"); break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void disassembler::hexdump(std::string &line) {
|
||||
// print pc and hexdump...
|
||||
|
@ -743,33 +817,16 @@ void disassembler::hexdump(std::string &line) {
|
|||
line += " ";
|
||||
for (i = 0; i < _st; ++i) {
|
||||
uint8_t c = _bytes[i];
|
||||
// msb flag?
|
||||
if (_traits & msb_hexdump) c &= 0x7f;
|
||||
if (isprint(c) && isascii(c)) line += c;
|
||||
else line += '.';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void disassembler::hexdump() {
|
||||
// print pc and hexdump...
|
||||
int i;
|
||||
printf("%04x:", _pc);
|
||||
for (i = 0; i < _st; ++i) {
|
||||
printf(" %02x", _bytes[i]);
|
||||
}
|
||||
for ( ; i < 4; ++i) {
|
||||
printf(" ");
|
||||
}
|
||||
printf(" ");
|
||||
for (i = 0; i < _st; ++i) {
|
||||
uint8_t c = _bytes[i];
|
||||
if (isprint(c) && isascii(c)) putc(c, stdout);
|
||||
else putc('.', stdout);
|
||||
}
|
||||
for ( ; i < 4; ++i) {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
std::string disassembler::label_for_address(uint32_t address) { return ""; }
|
||||
std::string disassembler::label_for_zp(uint32_t address) { return ""; }
|
||||
|
||||
void disassembler::print() {
|
||||
|
||||
|
@ -785,8 +842,11 @@ void disassembler::print() {
|
|||
if ((_size == 1) && (_arg & 0x80))
|
||||
pc += 0xff00;
|
||||
pc &= 0xffff;
|
||||
tmp = to_x(pc, 4, '$');
|
||||
|
||||
|
||||
// it would be really fancy if it checked for a label name @pc...
|
||||
tmp = label_for_address(pc);
|
||||
if (tmp.empty()) tmp = to_x(pc, 4, '$');
|
||||
break;
|
||||
}
|
||||
case mBlockMove: {
|
||||
|
@ -796,10 +856,25 @@ void disassembler::print() {
|
|||
+ to_x((_arg >> 0) & 0xff, 2, '$');
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
case mDP:
|
||||
case mDPI:
|
||||
case mDPIL:
|
||||
tmp = label_for_zp(_arg);
|
||||
if (tmp.empty()) tmp = to_x(_arg, _size * 2, '$');
|
||||
break;
|
||||
|
||||
//case mImmediate:
|
||||
case mAbsolute:
|
||||
case mAbsoluteI:
|
||||
case mAbsoluteIL:
|
||||
case mAbsoluteLong:
|
||||
tmp = label_for_address(_arg);
|
||||
if (tmp.empty()) tmp = to_x(_arg, _size * 2, '$');
|
||||
break;
|
||||
|
||||
default:
|
||||
tmp = to_x(_arg, _size * 2, '$');
|
||||
break;
|
||||
}
|
||||
}
|
||||
print(tmp);
|
||||
return;
|
||||
|
@ -808,9 +883,17 @@ void disassembler::print() {
|
|||
|
||||
std::string line;
|
||||
|
||||
|
||||
|
||||
|
||||
indent_to(line, kOpcodeTab);
|
||||
line.append(&opcodes[_op * 3], 3);
|
||||
|
||||
if (_mode == mImpliedA && (_traits & explicit_implied_a)) {
|
||||
indent_to(line, kOperandTab);
|
||||
line.append("a");
|
||||
}
|
||||
|
||||
|
||||
hexdump(line);
|
||||
line.push_back('\n');
|
||||
|
@ -842,3 +925,89 @@ void disassembler::print(const std::string &expr) {
|
|||
_pc += _size + 1;
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
const std::vector<uint32_t> &analyzer::finish() {
|
||||
std::sort(_labels.begin(), _labels.end());
|
||||
auto end = std::unique(_labels.begin(), _labels.end());
|
||||
_labels.erase(end, _labels.end());
|
||||
return _labels;
|
||||
}
|
||||
|
||||
|
||||
void analyzer::operator()(uint8_t byte) {
|
||||
|
||||
|
||||
if (!_code) {
|
||||
|
||||
if (_inline_data && --_inline_data <= 0) {
|
||||
_code = true;
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_st++;
|
||||
if (_st == 1) {
|
||||
_op = byte;
|
||||
_mode = modes[_op];
|
||||
|
||||
_size = _mode & 0x0f;
|
||||
if (_mode & _flags & m_I) _size++;
|
||||
if (_mode & _flags & m_M) _size++;
|
||||
|
||||
if (!_size) { reset(); }
|
||||
return;
|
||||
}
|
||||
unsigned shift = (_st - 2) * 8;
|
||||
_arg = _arg + (byte << shift);
|
||||
if (_st <= _size) return;
|
||||
|
||||
|
||||
// all done... now process it
|
||||
process();
|
||||
}
|
||||
|
||||
void analyzer::reset() {
|
||||
_pc += _st;
|
||||
_arg = 0;
|
||||
_st = 0;
|
||||
}
|
||||
|
||||
void analyzer::process() {
|
||||
|
||||
if (_traits & disassembler::track_rep_sep) {
|
||||
switch(_op) {
|
||||
case 0xc2: // REP
|
||||
_flags |= (_arg & 0x30);
|
||||
break;
|
||||
case 0xe2: // SEP
|
||||
_flags &= ~(_arg & 0x30);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (_mode & 0xf000) {
|
||||
case mRelative: {
|
||||
|
||||
uint32_t pc = _pc + 1 + _size + _arg;
|
||||
|
||||
if ((_size == 1) && (_arg & 0x80))
|
||||
pc += 0xff00;
|
||||
pc &= 0xffff;
|
||||
|
||||
_labels.push_back(pc);
|
||||
break;
|
||||
}
|
||||
case mAbsolute:
|
||||
case mAbsoluteI:
|
||||
case mAbsoluteLong: {
|
||||
_labels.push_back(_arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
|
118
disassembler.h
118
disassembler.h
|
@ -3,21 +3,46 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// disassembler traits
|
||||
|
||||
class disassembler {
|
||||
|
||||
|
||||
public:
|
||||
|
||||
enum {
|
||||
|
||||
// pea #xxxx vs pea |xxxx
|
||||
pea_immediate = 1,
|
||||
// jml [|xxxx] vs jml [xxxx]
|
||||
jml_indirect_modifier = 2,
|
||||
// asl vs asl a
|
||||
explicit_implied_a = 4,
|
||||
// and & 07f hexdump
|
||||
msb_hexdump = 8,
|
||||
track_rep_sep = 16,
|
||||
bit_hacks = 32,
|
||||
|
||||
orca = jml_indirect_modifier | explicit_implied_a,
|
||||
mpw = jml_indirect_modifier | explicit_implied_a,
|
||||
wdc = pea_immediate,
|
||||
};
|
||||
|
||||
|
||||
disassembler() = default;
|
||||
disassembler(unsigned traits) : _traits(traits)
|
||||
{}
|
||||
virtual ~disassembler();
|
||||
|
||||
void operator()(uint8_t byte);
|
||||
void operator()(const std::string &expr, unsigned size);
|
||||
void operator()(const std::string &expr, unsigned size, uint32_t value = 0);
|
||||
|
||||
template<class Iter>
|
||||
void operator()(Iter begin, Iter end) { while (begin != end) code(*begin++); }
|
||||
void operator()(Iter begin, Iter end) { while (begin != end) (*this)(*begin++); }
|
||||
|
||||
template<class T>
|
||||
void operator()(const T &t) { code(std::begin(t), std::end(t)); }
|
||||
void operator()(const T &t) { (*this)(std::begin(t), std::end(t)); }
|
||||
|
||||
void space(unsigned bytes);
|
||||
|
||||
|
@ -52,30 +77,49 @@ class disassembler {
|
|||
static void emit(const std::string &label);
|
||||
static void emit(const std::string &label, const std::string &opcode);
|
||||
static void emit(const std::string &label, const std::string &opcode, const std::string &operand);
|
||||
static void emit(const std::string &label, const std::string &opcode, const std::string &operand, const std::string &comment);
|
||||
|
||||
static int operand_size(uint8_t op, bool m = true, bool x = true);
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
virtual std::pair<std::string, std::string> format_data(unsigned size, const uint8_t *data);
|
||||
virtual std::pair<std::string, std::string> format_data(unsigned size, const std::string &);
|
||||
|
||||
virtual std::string label_for_address(uint32_t address);
|
||||
virtual std::string label_for_zp(uint32_t address);
|
||||
|
||||
|
||||
virtual std::string ds() const { return "ds"; }
|
||||
|
||||
|
||||
void set_inline_data(int count) {
|
||||
flush();
|
||||
_code = count ? false : true;
|
||||
_inline_data = count;
|
||||
}
|
||||
|
||||
virtual int32_t next_label(int32_t pc) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual void event(uint8_t opcode, uint32_t operand) {}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void reset();
|
||||
|
||||
void dump();
|
||||
void dump(const std::string &expr, unsigned size);
|
||||
void dump(const std::string &expr, unsigned size, uint32_t value = 0);
|
||||
|
||||
void print();
|
||||
void print(const std::string &expr);
|
||||
|
||||
void print_prefix();
|
||||
void print_suffix();
|
||||
|
||||
std::string prefix();
|
||||
std::string suffix();
|
||||
|
||||
void hexdump();
|
||||
void hexdump(std::string &);
|
||||
|
||||
unsigned _st = 0;
|
||||
|
@ -88,9 +132,65 @@ class disassembler {
|
|||
unsigned _arg = 0;
|
||||
|
||||
bool _code = true;
|
||||
int _inline_data = 0;
|
||||
int32_t _next_label = -1;
|
||||
|
||||
unsigned _traits = 0;
|
||||
|
||||
void check_labels();
|
||||
};
|
||||
|
||||
class analyzer {
|
||||
|
||||
public:
|
||||
|
||||
analyzer(unsigned traits = 0) : _traits(traits)
|
||||
{}
|
||||
|
||||
void set_pc(uint32_t pc) { _pc = pc; }
|
||||
uint32_t pc() const { return _pc; }
|
||||
|
||||
|
||||
bool m() const { return _flags & 0x20; }
|
||||
bool x() const { return _flags & 0x10; }
|
||||
|
||||
void set_m(bool x) {
|
||||
if (x) _flags |= 0x20;
|
||||
else _flags &= ~0x20;
|
||||
}
|
||||
|
||||
void set_x(bool x) {
|
||||
if (x) _flags |= 0x10;
|
||||
else _flags &= ~0x10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void operator()(uint8_t x);
|
||||
void operator()(uint32_t x, unsigned size);
|
||||
|
||||
|
||||
const std::vector<uint32_t> &finish();
|
||||
|
||||
bool state() const { return _st == 0; }
|
||||
|
||||
private:
|
||||
|
||||
void reset();
|
||||
void process();
|
||||
|
||||
unsigned _traits = 0;
|
||||
int _inline_data = 0;
|
||||
bool _code = true;
|
||||
unsigned _st = 0;
|
||||
uint8_t _op = 0;
|
||||
unsigned _size = 0;
|
||||
unsigned _flags = 0x30;
|
||||
unsigned _pc = 0;
|
||||
unsigned _arg = 0;
|
||||
unsigned _mode = 0;
|
||||
|
||||
std::vector<uint32_t> _labels;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
86
dumpobj.cpp
86
dumpobj.cpp
|
@ -16,6 +16,8 @@
|
|||
#include "obj816.h"
|
||||
#include "zrdz_disassembler.h"
|
||||
|
||||
#include "endian.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
@ -28,17 +30,12 @@
|
|||
|
||||
|
||||
struct {
|
||||
bool _S = false;
|
||||
bool _g = false;
|
||||
bool S = false;
|
||||
bool g = false;
|
||||
bool n = false;
|
||||
} flags;
|
||||
|
||||
|
||||
enum class endian {
|
||||
little = __ORDER_LITTLE_ENDIAN__,
|
||||
big = __ORDER_BIG_ENDIAN__,
|
||||
native = __BYTE_ORDER__
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
void swap_if(T &t, std::false_type) {}
|
||||
|
@ -72,7 +69,7 @@ void usage() {
|
|||
struct Header {
|
||||
uint32_t magic; /* magic number for detection */
|
||||
uint16_t version; /* version number of object format */
|
||||
uint8_t filetype; /* file type, object or library */
|
||||
uint8_t filetype; /* file type, object or library */
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
@ -238,6 +235,9 @@ bool dump_obj(const char *name, int fd)
|
|||
ok = read(fd, symbol_data.data(), h.h_symsize);
|
||||
if (ok != h.h_symsize) errx(EX_DATAERR, "%s symbols truncated", name);
|
||||
|
||||
if (h.h_optsize) lseek(fd, h.h_optsize, SEEK_CUR);
|
||||
|
||||
|
||||
zrdz_disassembler d(read_sections(section_data), read_symbols(symbol_data));
|
||||
|
||||
uint8_t op = REC_END;
|
||||
|
@ -285,7 +285,13 @@ bool dump_obj(const char *name, int fd)
|
|||
uint8_t section = read_8(iter);
|
||||
uint32_t offset = read_32(iter);
|
||||
|
||||
std::string name = d.location_name(section, offset);
|
||||
|
||||
std::string name;
|
||||
if (flags.n) {
|
||||
name = d.section_name(section) + "+" + d.to_x(offset, 4, '$');
|
||||
} else {
|
||||
name = d.location_name(section, offset);
|
||||
}
|
||||
stack.emplace_back(std::move(name));
|
||||
break;
|
||||
}
|
||||
|
@ -304,7 +310,7 @@ bool dump_obj(const char *name, int fd)
|
|||
case OP_NOT:
|
||||
case OP_NEG:
|
||||
case OP_FLP: {
|
||||
static const char *ops[] = {
|
||||
static const std::string ops[] = {
|
||||
".NOT.", "-", "\\"
|
||||
};
|
||||
|
||||
|
@ -316,12 +322,24 @@ bool dump_obj(const char *name, int fd)
|
|||
}
|
||||
|
||||
// binary operators
|
||||
case OP_SHR:
|
||||
case OP_EXP:
|
||||
case OP_MUL:
|
||||
case OP_DIV:
|
||||
case OP_MOD:
|
||||
case OP_SHR:
|
||||
case OP_SHL:
|
||||
case OP_ADD:
|
||||
case OP_SUB: {
|
||||
static const char *ops[] = {
|
||||
"**", "*", "/", ".MOD.", ">>", "<<", "+", "-", "&", "|", "^", "=", ">", "<"
|
||||
case OP_ADD:
|
||||
case OP_SUB:
|
||||
case OP_AND:
|
||||
case OP_OR:
|
||||
case OP_XOR:
|
||||
case OP_EQ:
|
||||
case OP_GT:
|
||||
case OP_LT:
|
||||
case OP_UGT:
|
||||
case OP_ULT: {
|
||||
static const std::string ops[] = {
|
||||
"**", "*", "/", ".MOD.", ">>", "<<", "+", "-", "&", "|", "^", "=", ">", "<", ".UGT.", ".ULT."
|
||||
|
||||
};
|
||||
if (stack.size() < 2) errx(EX_DATAERR, "%s : stack underflow error", name);
|
||||
|
@ -531,7 +549,7 @@ bool dump_obj(const char *name, int fd)
|
|||
|
||||
|
||||
unsigned f = 0;
|
||||
if (flags._S) f |= 0x01;
|
||||
if (flags.S) f |= 0x01;
|
||||
d.back_matter(f);
|
||||
|
||||
if (iter != data.end() || op != REC_END) errx(EX_DATAERR, "%s records ended early", name);
|
||||
|
@ -565,43 +583,48 @@ void dump_lib(const char *name, int fd)
|
|||
assert(h.l_version == 1);
|
||||
assert(h.l_filtyp == 2);
|
||||
|
||||
printf("modstart : $%04x\n", h.l_modstart);
|
||||
printf("number symbols: $%04x\n", h.l_numsyms);
|
||||
printf("number files : $%04x\n", h.l_numfiles);
|
||||
|
||||
printf("; library %s\n\n", name);
|
||||
/*
|
||||
printf("; modstart : $%04x\n", h.l_modstart);
|
||||
printf("; number symbols: $%04x\n", h.l_numsyms);
|
||||
printf("; number files : $%04x\n", h.l_numfiles);
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
long count = h.l_modstart - sizeof(h);
|
||||
if (count < 0) errx(EX_DATAERR, "%s", name);
|
||||
data.reserve(count);
|
||||
data.resize(count);
|
||||
ok = read(fd, data.data(), count);
|
||||
if (ok != count) errx(EX_DATAERR, "%s truncated", name);
|
||||
|
||||
|
||||
// files
|
||||
printf("; files:\n");
|
||||
auto iter = data.begin();
|
||||
for (int i = 0; i < h.l_numfiles; ++i) {
|
||||
uint16_t file_number = read_16(iter);
|
||||
std::string s = read_pstring(iter);
|
||||
printf("$%02x %s\n", file_number, s.c_str());
|
||||
printf("; $%02x %s\n", file_number, s.c_str());
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// symbols
|
||||
printf("; symbols:\n");
|
||||
auto name_iter = iter + h.l_numsyms * 8;
|
||||
for (int i = 0; i < h.l_numsyms; ++i) {
|
||||
uint16_t name_offset = read_16(iter);
|
||||
uint16_t file_number = read_16(iter);
|
||||
uint32_t offset = read_32(iter);
|
||||
std::string name = read_pstring(name_iter);
|
||||
auto tmp = name_iter + name_offset;
|
||||
std::string name = read_pstring(tmp);
|
||||
|
||||
printf("symbol : $%04x %s\n", i, name.c_str());
|
||||
printf("; $%04x %s\n", i, name.c_str());
|
||||
//printf("name offset: %02x\n", name_offset);
|
||||
printf("file_number : $%02x\n", file_number);
|
||||
printf("module offset: $%04x\n", offset);
|
||||
//printf("file_number : $%02x\n", file_number);
|
||||
//printf("module offset: $%04x\n", offset);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
|
||||
void dump(const char *name) {
|
||||
|
@ -636,10 +659,11 @@ void dump(const char *name) {
|
|||
int main(int argc, char **argv) {
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "Sg")) != -1) {
|
||||
while ((c = getopt(argc, argv, "Sgn")) != -1) {
|
||||
switch(c) {
|
||||
case 'S': flags._S = true; break;
|
||||
case 'g': flags._g = true; break;
|
||||
case 'S': flags.S = true; break;
|
||||
case 'g': flags.g = true; break;
|
||||
case 'n': flags.n = true; break;
|
||||
default: exit(EX_USAGE); break;
|
||||
}
|
||||
}
|
||||
|
|
16
endian.h
Normal file
16
endian.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef endian_h
|
||||
#define endian_h
|
||||
|
||||
enum class endian {
|
||||
#ifdef _WIN32
|
||||
little = 1234,
|
||||
big = 4321,
|
||||
native = little
|
||||
#else
|
||||
little = __ORDER_LITTLE_ENDIAN__,
|
||||
big = __ORDER_BIG_ENDIAN__,
|
||||
native = __BYTE_ORDER__
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
183
expression.cpp
Normal file
183
expression.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
#include "expression.h"
|
||||
#include <vector>
|
||||
#include "obj816.h"
|
||||
|
||||
#include <sysexits.h>
|
||||
#include <err.h>
|
||||
|
||||
/* a ** b */
|
||||
uint32_t power(uint32_t a, uint32_t b) {
|
||||
|
||||
uint32_t rv = 1;
|
||||
for( ; b; b >>= 1) {
|
||||
if (b & 0x01) rv *= a;
|
||||
a = a * a;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool unary_op(unsigned op, std::vector<expr> &v) {
|
||||
if (v.size() >=1 ) {
|
||||
expr &a = v.back();
|
||||
if (a.tag == OP_VAL) {
|
||||
switch(a.tag) {
|
||||
case OP_NOT: a.value = !a.value; break;
|
||||
case OP_NEG: a.value = -a.value; break;
|
||||
case OP_FLP: a.value = ~a.value; break;
|
||||
default:
|
||||
errx(EX_SOFTWARE, "Unsupported unary op %02x", a.tag);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
v.emplace_back(op);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool binary_op(unsigned op, std::vector<expr> &v) {
|
||||
if (v.size() >= 2) {
|
||||
expr &a = v[v.size() - 2];
|
||||
expr &b = v[v.size() - 1];
|
||||
|
||||
if (a.tag == OP_VAL && b.tag == OP_VAL) {
|
||||
uint32_t value = 0;
|
||||
switch(op) {
|
||||
case OP_EXP: value = power(a.value, b.value); break;
|
||||
case OP_MUL: value = a.value * b.value; break;
|
||||
case OP_DIV: value = a.value / b.value; break;
|
||||
case OP_MOD: value = a.value % b.value; break;
|
||||
case OP_SHR: value = a.value >> b.value; break;
|
||||
case OP_SHL: value = a.value << b.value; break;
|
||||
case OP_ADD: value = a.value + b.value; break;
|
||||
case OP_SUB: value = a.value - b.value; break;
|
||||
case OP_AND: value = a.value & b.value; break;
|
||||
case OP_OR: value = a.value | b.value; break;
|
||||
case OP_XOR: value = a.value ^ b.value; break;
|
||||
case OP_EQ: value = a.value == b.value; break;
|
||||
case OP_GT: value = (int32_t)a.value > (int32_t)b.value; break;
|
||||
case OP_LT: value = (int32_t)a.value < (int32_t)b.value; break;
|
||||
case OP_UGT: value = a.value > b.value; break;
|
||||
case OP_ULT: value = a.value < b.value; break;
|
||||
default:
|
||||
errx(EX_SOFTWARE, "Unsupported binary op %02x", a.tag);
|
||||
}
|
||||
v.pop_back();
|
||||
v.back().value = value;
|
||||
return true;
|
||||
}
|
||||
if (a.tag == OP_VAL && b.tag == OP_LOC) {
|
||||
switch(op) {
|
||||
case OP_ADD: {
|
||||
// constant + symbol
|
||||
expr tmp = b;
|
||||
tmp.value = a.value + b.value;
|
||||
v.pop_back();
|
||||
v.pop_back();
|
||||
v.emplace_back(tmp);
|
||||
return true;
|
||||
}
|
||||
#if 0
|
||||
case OP_SUB: {
|
||||
// constant - symbol .. does this even make sense?
|
||||
expr tmp = b;
|
||||
tmp.value = a.value - b.value;
|
||||
v.pop_back();
|
||||
v.pop_back();
|
||||
v.emplace_back(tmp);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// optimization... regardless of where it's located, shifting > 24 bits will result in 0...
|
||||
if (a.tag == OP_LOC && b.tag == OP_VAL) {
|
||||
switch(op) {
|
||||
case OP_ADD: {
|
||||
a.value += b.value;
|
||||
v.pop_back();
|
||||
return true;
|
||||
}
|
||||
case OP_SUB: {
|
||||
a.value -= b.value;
|
||||
v.pop_back();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (a.tag == OP_LOC && b.tag == OP_LOC && a.section == b.section) {
|
||||
uint32_t value = 0;
|
||||
bool rv = false;
|
||||
switch (op) {
|
||||
case OP_SUB:
|
||||
// end - start
|
||||
value = a.value - b.value;
|
||||
rv = true; break;
|
||||
case OP_EQ:
|
||||
value = a.value == b.value;
|
||||
rv = true; break;
|
||||
case OP_GT:
|
||||
case OP_UGT:
|
||||
value = a.value > b.value;
|
||||
rv = true; break;
|
||||
case OP_LT:
|
||||
case OP_ULT:
|
||||
value = a.value < b.value;
|
||||
rv = true; break;
|
||||
}
|
||||
if (rv) {
|
||||
v.pop_back();
|
||||
v.pop_back();
|
||||
v.emplace_back(OP_VAL, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
v.emplace_back(op);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool simplify_expression(expression &e) {
|
||||
std::vector<expr> tmp;
|
||||
bool rv = false;
|
||||
for (auto &t : e.stack) {
|
||||
if (t.tag >= OP_BIN) {
|
||||
rv = binary_op(t.tag, tmp) || rv;
|
||||
} else if (t.tag >= OP_UNA) {
|
||||
rv = unary_op(t.tag, tmp) || rv;
|
||||
} else {
|
||||
tmp.emplace_back(t);
|
||||
}
|
||||
}
|
||||
if (rv) e.stack = std::move(tmp);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* if force is true, treat OP_LOC records as OP_VAL (for omf)
|
||||
*/
|
||||
|
||||
optional<uint32_t> evaluate_expression(expression &e, bool force) {
|
||||
std::vector<expr> tmp;
|
||||
for (const auto &t : e.stack) {
|
||||
if (t.tag == OP_LOC && force) {
|
||||
tmp.emplace_back(OP_VAL, t.value);
|
||||
continue;
|
||||
}
|
||||
if (t.tag >= OP_BIN) {
|
||||
binary_op(t.tag, tmp);
|
||||
} else if (t.tag >= OP_UNA) {
|
||||
unary_op(t.tag, tmp);
|
||||
} else {
|
||||
tmp.emplace_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp.size() == 1 && tmp.front().tag == OP_VAL) return optional<uint32_t>(tmp.front().value);
|
||||
return optional<uint32_t>();
|
||||
}
|
||||
|
34
expression.h
Normal file
34
expression.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef __expression_h__
|
||||
#define __expression_h__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "optional.h"
|
||||
|
||||
struct expr {
|
||||
expr(int t = 0, uint32_t v = 0, uint32_t s = 0)
|
||||
: tag(t), value(v), section(s)
|
||||
{}
|
||||
int tag = 0;
|
||||
uint32_t value = 0;
|
||||
unsigned section = 0;
|
||||
};
|
||||
|
||||
|
||||
struct expression {
|
||||
unsigned section = 0;
|
||||
uint32_t offset = 0;
|
||||
uint8_t size = 0;
|
||||
uint8_t relative = false;
|
||||
bool undefined = false;
|
||||
|
||||
std::vector<expr> stack;
|
||||
|
||||
};
|
||||
|
||||
optional<uint32_t> evaluate_expression(expression &e, bool force = false);
|
||||
|
||||
bool simplify_expression(expression &e);
|
||||
|
||||
#endif
|
362
obj816.h
362
obj816.h
|
@ -1,181 +1,181 @@
|
|||
#ifndef __obj816_h__
|
||||
#define __obj816_h__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#define VERS " 3.01 " /* version number for programs */
|
||||
#define CDATE "1992-1997" /* copyright date for programs */
|
||||
|
||||
typedef struct Mod_head {
|
||||
uint32_t h_magic; /* magic number for detection */
|
||||
uint16_t h_version; /* version number of object format */
|
||||
uint8_t h_filtyp; /* file type, object or library */
|
||||
uint8_t h_namlen; /* length of module name */
|
||||
uint32_t h_recsize; /* sizeof records section */
|
||||
uint16_t h_secsize; /* sizeof section section */
|
||||
uint32_t h_symsize; /* sizeof symbol section */
|
||||
uint16_t h_optsize; /* sizeof options section */
|
||||
uint8_t h_tot_secs; /* total number of sections in module */
|
||||
uint8_t h_num_secs; /* number of sections referenced */
|
||||
uint16_t h_num_syms; /* number of symbols */
|
||||
} Mod_head;
|
||||
|
||||
typedef struct Lib_head {
|
||||
uint32_t l_magic; /* magic number for detection */
|
||||
uint16_t l_version; /* version number of object format */
|
||||
uint8_t l_filtyp; /* file type, object or library */
|
||||
uint8_t l_unused1;
|
||||
uint32_t l_modstart; /* offset of modules start */
|
||||
uint32_t l_numsyms; /* number of symbol entries */
|
||||
uint32_t l_symsize; /* sizeof symbol section */
|
||||
uint32_t l_numfiles; /* number of files */
|
||||
} Lib_head;
|
||||
|
||||
#define MOD_CONVERT "lwbblslsbbw"
|
||||
#define LIB_CONVERT "lwbbllll"
|
||||
|
||||
#define MOD_REC_OFF(x) (sizeof(x)+x.h_namlen)
|
||||
#define MOD_SEC_OFF(x) (MOD_REC_OFF(x)+x.h_recsize)
|
||||
#define MOD_SYM_OFF(x) (MOD_SEC_OFF(x)+x.h_secsize)
|
||||
#define MOD_OPT_OFF(x) (MOD_SYM_OFF(x)+x.h_symsize)
|
||||
#define MOD_NEXT_OFF(x) (MOD_OPT_OFF(x)+x.h_optsize)
|
||||
|
||||
#define MOD_MAGIC 0x5a44525a /* 'ZRDZ' */
|
||||
#define MOD_VERSION 1
|
||||
#define MOD_OBJECT 1
|
||||
#define MOD_LIBRARY 2
|
||||
#define MOD_OBJ68K 3
|
||||
|
||||
#define REC_END 0
|
||||
/* 1-xx are numbers of constant data bytes */
|
||||
#define REC_SECT 0xf0 /* next word is section number */
|
||||
#define REC_EXPR 0xf1 /* expression follows */
|
||||
#define REC_SPACE 0xf2 /* word count of bytes to reserve */
|
||||
#define REC_ORG 0xf3 /* long word new pc */
|
||||
#define REC_RELEXP 0xf4 /* pc-relative expression */
|
||||
#define REC_DEBUG 0xf5 /* debug info record */
|
||||
#define REC_LINE 0xf6 /* bump line counter */
|
||||
|
||||
enum {
|
||||
OP_END=0, /* end of expression */
|
||||
OP_SYM, /* ref to extern symbol */
|
||||
OP_VAL, /* constant value */
|
||||
OP_LOC, /* ref to offset from start of section */
|
||||
|
||||
OP_UNA=10,
|
||||
OP_NOT=10,
|
||||
OP_NEG,
|
||||
OP_FLP,
|
||||
|
||||
OP_BIN=20,
|
||||
OP_EXP=20, OP_MUL, OP_DIV, OP_MOD, OP_SHR,
|
||||
OP_SHL, OP_ADD, OP_SUB, OP_AND, OP_OR,
|
||||
OP_XOR, OP_EQ, OP_GT, OP_LT, OP_UGT,
|
||||
OP_ULT,
|
||||
OP_LAST
|
||||
};
|
||||
|
||||
enum { S_UND, S_ABS, S_REL, S_EXP, S_REG, S_FREG }; /* symbol type */
|
||||
enum { ST_NOSIZE, ST_8BIT, ST_16BIT, ST_32BIT,
|
||||
ST_FLOAT, ST_DOUBLE, ST_8051, ST_Z8, ST_DS, ST_EQU };
|
||||
|
||||
enum {
|
||||
D_C_FILE=100,
|
||||
D_C_LINE,
|
||||
D_C_SYM,
|
||||
D_C_STAG,
|
||||
D_C_ETAG,
|
||||
D_C_UTAG,
|
||||
D_C_MEMBER,
|
||||
D_C_EOS,
|
||||
D_C_FUNC,
|
||||
D_C_ENDFUNC,
|
||||
D_C_BLOCK,
|
||||
D_C_ENDBLOCK,
|
||||
D_LONGA_ON,
|
||||
D_LONGA_OFF,
|
||||
D_LONGI_ON,
|
||||
D_LONGI_OFF
|
||||
};
|
||||
|
||||
/* used for generating source level debugging information */
|
||||
|
||||
enum { DT_NON, DT_PTR, DT_FCN, DT_ARY, DT_FPTR, DT_FFCN };
|
||||
enum { T_NULL, T_VOID, T_SCHAR, T_CHAR, T_SHORT, T_INT16, T_INT32, T_LONG,
|
||||
T_FLOAT, T_DOUBLE, T_STRUCT, T_UNION, T_ENUM, T_LDOUBLE,
|
||||
T_UCHAR, T_USHORT, T_UINT16, T_UINT32, T_ULONG };
|
||||
enum { C_NULL, C_AUTO, C_EXT, C_STAT, C_REG, C_EXTDEF, C_ARG,
|
||||
C_STRTAG, C_MOS, C_EOS, C_UNTAG, C_MOU, C_ENTAG, C_MOE,
|
||||
C_TPDEF, C_USTATIC, C_REGPARM, C_FIELD, C_UEXT, C_STATLAB,
|
||||
C_EXTLAB, C_BLOCK, C_EBLOCK, C_FUNC, C_EFUNC, C_FILE, C_LINE,
|
||||
C_FRAME };
|
||||
|
||||
|
||||
#define SF_GBL 0x01 /* label is global */
|
||||
#define SF_DEF 0x02 /* label is defined in this module */
|
||||
#define SF_REF 0x04 /* label is referenced in this module */
|
||||
#define SF_VAR 0x08 /* label is variable */
|
||||
#define SF_PG0 0x10 /* label is Page0 type */
|
||||
#define SF_TMP 0x20 /* label is temporary (LLCHAR) */
|
||||
#define SF_DEF2 0x40 /* label has been defined in pass 2 ( ZAS only ) */
|
||||
#define SF_LIB 0x40 /* label in library (used by ZLN) */
|
||||
|
||||
#define SEC_OFFSET 0x0001
|
||||
#define SEC_INDIRECT 0x0002
|
||||
#define SEC_STACKED 0x0004
|
||||
#define SEC_REF_ONLY 0x0008
|
||||
#define SEC_CONST 0x0010
|
||||
#define SEC_DIRECT 0x0020
|
||||
#define SEC_NONAME 0x0040
|
||||
#define SEC_DATA 0x0080
|
||||
|
||||
/* pre-defined sections */
|
||||
enum {SECT_PAGE0, SECT_CODE, SECT_KDATA, SECT_DATA, SECT_UDATA };
|
||||
|
||||
/*
|
||||
Module format:
|
||||
Module header
|
||||
s: Module name (null terminated)
|
||||
Records
|
||||
Each record is in stack order terminated by REC_END
|
||||
Section info
|
||||
Section info format: --- for each section that has references
|
||||
b: section number
|
||||
b: section flags
|
||||
l: size
|
||||
l: org
|
||||
s: name of section (only if SEC_NONAME not in flags)
|
||||
Symbol info
|
||||
Symbol info format: --- for each symbol
|
||||
b: type
|
||||
b: flags
|
||||
b: section number
|
||||
l: offset (only if type != S_UND)
|
||||
s: name of symbol (null terminated)
|
||||
|
||||
Library format:
|
||||
Library header
|
||||
File info - for each file
|
||||
w: file number
|
||||
b: file name len
|
||||
c: file name (no null)
|
||||
Symbol data - for each symbol
|
||||
w: offset of name
|
||||
w: file number
|
||||
l: module offset - Hdr.l_modstart
|
||||
Symbol names - for each symbol
|
||||
b: length of name
|
||||
c: symbol name (no null)
|
||||
Modules - each module
|
||||
*/
|
||||
|
||||
|
||||
/**************************************************/
|
||||
/* End of File OBJ816.H */
|
||||
/**************************************************/
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
#ifndef __obj816_h__
|
||||
#define __obj816_h__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#define VERS " 3.01 " /* version number for programs */
|
||||
#define CDATE "1992-1997" /* copyright date for programs */
|
||||
|
||||
typedef struct Mod_head {
|
||||
uint32_t h_magic; /* magic number for detection */
|
||||
uint16_t h_version; /* version number of object format */
|
||||
uint8_t h_filtyp; /* file type, object or library */
|
||||
uint8_t h_namlen; /* length of module name */
|
||||
uint32_t h_recsize; /* sizeof records section */
|
||||
uint16_t h_secsize; /* sizeof section section */
|
||||
uint32_t h_symsize; /* sizeof symbol section */
|
||||
uint16_t h_optsize; /* sizeof options section */
|
||||
uint8_t h_tot_secs; /* total number of sections in module */
|
||||
uint8_t h_num_secs; /* number of sections referenced */
|
||||
uint16_t h_num_syms; /* number of symbols */
|
||||
} Mod_head;
|
||||
|
||||
typedef struct Lib_head {
|
||||
uint32_t l_magic; /* magic number for detection */
|
||||
uint16_t l_version; /* version number of object format */
|
||||
uint8_t l_filtyp; /* file type, object or library */
|
||||
uint8_t l_unused1;
|
||||
uint32_t l_modstart; /* offset of modules start */
|
||||
uint32_t l_numsyms; /* number of symbol entries */
|
||||
uint32_t l_symsize; /* sizeof symbol section */
|
||||
uint32_t l_numfiles; /* number of files */
|
||||
} Lib_head;
|
||||
|
||||
#define MOD_CONVERT "lwbblslsbbw"
|
||||
#define LIB_CONVERT "lwbbllll"
|
||||
|
||||
#define MOD_REC_OFF(x) (sizeof(x)+x.h_namlen)
|
||||
#define MOD_SEC_OFF(x) (MOD_REC_OFF(x)+x.h_recsize)
|
||||
#define MOD_SYM_OFF(x) (MOD_SEC_OFF(x)+x.h_secsize)
|
||||
#define MOD_OPT_OFF(x) (MOD_SYM_OFF(x)+x.h_symsize)
|
||||
#define MOD_NEXT_OFF(x) (MOD_OPT_OFF(x)+x.h_optsize)
|
||||
|
||||
#define MOD_MAGIC 0x5a44525a /* 'ZRDZ' */
|
||||
#define MOD_VERSION 1
|
||||
#define MOD_OBJECT 1
|
||||
#define MOD_LIBRARY 2
|
||||
#define MOD_OBJ68K 3
|
||||
|
||||
#define REC_END 0
|
||||
/* 1-xx are numbers of constant data bytes */
|
||||
#define REC_SECT 0xf0 /* next word is section number */
|
||||
#define REC_EXPR 0xf1 /* expression follows */
|
||||
#define REC_SPACE 0xf2 /* word count of bytes to reserve */
|
||||
#define REC_ORG 0xf3 /* long word new pc */
|
||||
#define REC_RELEXP 0xf4 /* pc-relative expression */
|
||||
#define REC_DEBUG 0xf5 /* debug info record */
|
||||
#define REC_LINE 0xf6 /* bump line counter */
|
||||
|
||||
enum {
|
||||
OP_END=0, /* end of expression */
|
||||
OP_SYM, /* ref to extern symbol */
|
||||
OP_VAL, /* constant value */
|
||||
OP_LOC, /* ref to offset from start of section */
|
||||
|
||||
OP_UNA=10,
|
||||
OP_NOT=10,
|
||||
OP_NEG,
|
||||
OP_FLP,
|
||||
|
||||
OP_BIN=20,
|
||||
OP_EXP=20, OP_MUL, OP_DIV, OP_MOD, OP_SHR,
|
||||
OP_SHL, OP_ADD, OP_SUB, OP_AND, OP_OR,
|
||||
OP_XOR, OP_EQ, OP_GT, OP_LT, OP_UGT,
|
||||
OP_ULT,
|
||||
OP_LAST
|
||||
};
|
||||
|
||||
enum { S_UND, S_ABS, S_REL, S_EXP, S_REG, S_FREG }; /* symbol type */
|
||||
enum { ST_NOSIZE, ST_8BIT, ST_16BIT, ST_32BIT,
|
||||
ST_FLOAT, ST_DOUBLE, ST_8051, ST_Z8, ST_DS, ST_EQU };
|
||||
|
||||
enum {
|
||||
D_C_FILE=100,
|
||||
D_C_LINE,
|
||||
D_C_SYM,
|
||||
D_C_STAG,
|
||||
D_C_ETAG,
|
||||
D_C_UTAG,
|
||||
D_C_MEMBER,
|
||||
D_C_EOS,
|
||||
D_C_FUNC,
|
||||
D_C_ENDFUNC,
|
||||
D_C_BLOCK,
|
||||
D_C_ENDBLOCK,
|
||||
D_LONGA_ON,
|
||||
D_LONGA_OFF,
|
||||
D_LONGI_ON,
|
||||
D_LONGI_OFF
|
||||
};
|
||||
|
||||
/* used for generating source level debugging information */
|
||||
|
||||
enum { DT_NON, DT_PTR, DT_FCN, DT_ARY, DT_FPTR, DT_FFCN };
|
||||
enum { T_NULL, T_VOID, T_SCHAR, T_CHAR, T_SHORT, T_INT16, T_INT32, T_LONG,
|
||||
T_FLOAT, T_DOUBLE, T_STRUCT, T_UNION, T_ENUM, T_LDOUBLE,
|
||||
T_UCHAR, T_USHORT, T_UINT16, T_UINT32, T_ULONG };
|
||||
enum { C_NULL, C_AUTO, C_EXT, C_STAT, C_REG, C_EXTDEF, C_ARG,
|
||||
C_STRTAG, C_MOS, C_EOS, C_UNTAG, C_MOU, C_ENTAG, C_MOE,
|
||||
C_TPDEF, C_USTATIC, C_REGPARM, C_FIELD, C_UEXT, C_STATLAB,
|
||||
C_EXTLAB, C_BLOCK, C_EBLOCK, C_FUNC, C_EFUNC, C_FILE, C_LINE,
|
||||
C_FRAME };
|
||||
|
||||
|
||||
#define SF_GBL 0x01 /* label is global */
|
||||
#define SF_DEF 0x02 /* label is defined in this module */
|
||||
#define SF_REF 0x04 /* label is referenced in this module */
|
||||
#define SF_VAR 0x08 /* label is variable */
|
||||
#define SF_PG0 0x10 /* label is Page0 type */
|
||||
#define SF_TMP 0x20 /* label is temporary (LLCHAR) */
|
||||
#define SF_DEF2 0x40 /* label has been defined in pass 2 ( ZAS only ) */
|
||||
#define SF_LIB 0x40 /* label in library (used by ZLN) */
|
||||
|
||||
#define SEC_OFFSET 0x0001
|
||||
#define SEC_INDIRECT 0x0002
|
||||
#define SEC_STACKED 0x0004
|
||||
#define SEC_REF_ONLY 0x0008
|
||||
#define SEC_CONST 0x0010
|
||||
#define SEC_DIRECT 0x0020
|
||||
#define SEC_NONAME 0x0040
|
||||
#define SEC_DATA 0x0080
|
||||
|
||||
/* pre-defined sections */
|
||||
enum {SECT_PAGE0, SECT_CODE, SECT_KDATA, SECT_DATA, SECT_UDATA };
|
||||
|
||||
/*
|
||||
Module format:
|
||||
Module header
|
||||
s: Module name (null terminated)
|
||||
Records
|
||||
Each record is in stack order terminated by REC_END
|
||||
Section info
|
||||
Section info format: --- for each section that has references
|
||||
b: section number
|
||||
b: section flags
|
||||
l: size
|
||||
l: org
|
||||
s: name of section (only if SEC_NONAME not in flags)
|
||||
Symbol info
|
||||
Symbol info format: --- for each symbol
|
||||
b: type
|
||||
b: flags
|
||||
b: section number
|
||||
l: offset (only if type != S_UND)
|
||||
s: name of symbol (null terminated)
|
||||
|
||||
Library format:
|
||||
Library header
|
||||
File info - for each file
|
||||
w: file number
|
||||
b: file name len
|
||||
c: file name (no null)
|
||||
Symbol data - for each symbol
|
||||
w: offset of name
|
||||
w: file number
|
||||
l: module offset - Hdr.l_modstart
|
||||
Symbol names - for each symbol
|
||||
b: length of name
|
||||
c: symbol name (no null)
|
||||
Modules - each module
|
||||
*/
|
||||
|
||||
|
||||
/**************************************************/
|
||||
/* End of File OBJ816.H */
|
||||
/**************************************************/
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
|
|
675
omf.cpp
Normal file
675
omf.cpp
Normal file
|
@ -0,0 +1,675 @@
|
|||
#include "omf.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <sysexits.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "optional.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
enum class endian {
|
||||
#ifdef _WIN32
|
||||
little = 0,
|
||||
big = 1,
|
||||
native = little
|
||||
#else
|
||||
little = __ORDER_LITTLE_ENDIAN__,
|
||||
big = __ORDER_BIG_ENDIAN__,
|
||||
native = __BYTE_ORDER__
|
||||
#endif
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct omf_header {
|
||||
uint32_t bytecount = 0;
|
||||
uint32_t reserved_space = 0;
|
||||
uint32_t length = 0;
|
||||
uint8_t unused1 = 0;
|
||||
uint8_t lablen = 0;
|
||||
uint8_t numlen = 4;
|
||||
uint8_t version = 2;
|
||||
uint32_t banksize = 0;
|
||||
uint16_t kind = 0;
|
||||
uint16_t unused2 = 0;
|
||||
uint32_t org = 0;
|
||||
uint32_t alignment = 0;
|
||||
uint8_t numsex = 0;
|
||||
uint8_t unused3 = 0;
|
||||
uint16_t segnum = 0;
|
||||
uint32_t entry = 0;
|
||||
uint16_t dispname = 0;
|
||||
uint16_t dispdata = 0;
|
||||
};
|
||||
|
||||
struct omf_express_header {
|
||||
uint32_t lconst_mark;
|
||||
uint32_t lconst_size;
|
||||
uint32_t reloc_mark;
|
||||
uint32_t reloc_size;
|
||||
uint8_t unused1 = 0;
|
||||
uint8_t lablen = 0;
|
||||
uint8_t numlen = 4;
|
||||
uint8_t version = 2;
|
||||
uint32_t banksize = 0;
|
||||
uint16_t kind = 0;
|
||||
uint16_t unused2 = 0;
|
||||
uint32_t org = 0;
|
||||
uint32_t alignment = 0;
|
||||
uint8_t numsex = 0;
|
||||
uint8_t unused3 = 0;
|
||||
uint16_t segnum = 0;
|
||||
uint32_t entry = 0;
|
||||
uint16_t dispname = 0;
|
||||
uint16_t dispdata = 0;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(omf_header) == 44, "OMF Header not packed");
|
||||
static_assert(sizeof(omf_express_header) == 48, "OMF Express Header not packed");
|
||||
|
||||
|
||||
static void swap(uint8_t &x) {}
|
||||
static void swap(uint16_t &x) {
|
||||
#if defined(__GNUC__)
|
||||
x = __builtin_bswap16(x);
|
||||
#else
|
||||
x = (x >> 8) | (x << 8);
|
||||
#endif
|
||||
}
|
||||
static void swap(uint32_t &x) {
|
||||
#if defined(__GNUC__)
|
||||
x = __builtin_bswap32(x);
|
||||
#else
|
||||
x = ((x & 0xff000000) >> 24) |
|
||||
((x & 0x00ff0000) >> 8) |
|
||||
((x & 0x0000ff00) << 8) |
|
||||
((x & 0x000000ff) << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void to_little(struct omf_header &h) {
|
||||
if (endian::native != endian::little) {
|
||||
swap(h.bytecount);
|
||||
swap(h.reserved_space);
|
||||
swap(h.length);
|
||||
swap(h.unused1);
|
||||
swap(h.lablen);
|
||||
swap(h.numlen);
|
||||
swap(h.version);
|
||||
swap(h.banksize);
|
||||
swap(h.kind);
|
||||
swap(h.unused2);
|
||||
swap(h.org);
|
||||
swap(h.alignment);
|
||||
swap(h.numsex);
|
||||
swap(h.unused3);
|
||||
swap(h.segnum);
|
||||
swap(h.entry);
|
||||
swap(h.dispname);
|
||||
swap(h.dispdata);
|
||||
}
|
||||
}
|
||||
|
||||
static void to_little(struct omf_express_header &h) {
|
||||
if (endian::native != endian::little) {
|
||||
swap(h.lconst_mark);
|
||||
swap(h.lconst_size);
|
||||
swap(h.reloc_mark);
|
||||
swap(h.reloc_size);
|
||||
swap(h.unused1);
|
||||
swap(h.lablen);
|
||||
swap(h.numlen);
|
||||
swap(h.version);
|
||||
swap(h.banksize);
|
||||
swap(h.kind);
|
||||
swap(h.unused2);
|
||||
swap(h.org);
|
||||
swap(h.alignment);
|
||||
swap(h.numsex);
|
||||
swap(h.unused3);
|
||||
swap(h.segnum);
|
||||
swap(h.entry);
|
||||
swap(h.dispname);
|
||||
swap(h.dispdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void to_v1(struct omf_header &h) {
|
||||
|
||||
// KIND op value used as-is, no translation.
|
||||
|
||||
h.version = 1;
|
||||
// byte count -> block count
|
||||
h.bytecount = (h.bytecount + 511) >> 9;
|
||||
h.unused1 = h.kind;
|
||||
h.kind = 0;
|
||||
}
|
||||
|
||||
|
||||
void push(std::vector<uint8_t> &v, uint8_t x) {
|
||||
v.push_back(x);
|
||||
}
|
||||
|
||||
void push(std::vector<uint8_t> &v, uint16_t x) {
|
||||
v.push_back(x & 0xff);
|
||||
x >>= 8;
|
||||
v.push_back(x & 0xff);
|
||||
}
|
||||
|
||||
void push(std::vector<uint8_t> &v, uint32_t x) {
|
||||
v.push_back(x & 0xff);
|
||||
x >>= 8;
|
||||
v.push_back(x & 0xff);
|
||||
x >>= 8;
|
||||
v.push_back(x & 0xff);
|
||||
x >>= 8;
|
||||
v.push_back(x & 0xff);
|
||||
}
|
||||
|
||||
void push(std::vector<uint8_t> &v, const std::string &s) {
|
||||
uint8_t count = std::min((int)s.size(), 255);
|
||||
push(v, count);
|
||||
v.insert(v.end(), s.begin(), s.begin() + count);
|
||||
}
|
||||
|
||||
void push(std::vector<uint8_t> &v, const std::string &s, size_t count) {
|
||||
std::string tmp(s, 0, count);
|
||||
tmp.resize(count, ' ');
|
||||
v.insert(v.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
class super_helper {
|
||||
|
||||
std::vector<uint8_t> _data;
|
||||
uint32_t _page = 0;
|
||||
int _count = 0;
|
||||
|
||||
public:
|
||||
|
||||
super_helper() = default;
|
||||
|
||||
|
||||
void append(uint32_t pc) {
|
||||
unsigned offset = pc & 0xff;
|
||||
unsigned page = pc >> 8;
|
||||
assert(page >= _page);
|
||||
|
||||
if (page != _page) {
|
||||
unsigned skip = page - _page;
|
||||
if (_count) --skip;
|
||||
if (skip) {
|
||||
|
||||
while (skip >= 0x80) {
|
||||
_data.push_back(0xff);
|
||||
skip -= 0x7f;
|
||||
}
|
||||
if (skip)
|
||||
_data.push_back(0x80 | skip);
|
||||
}
|
||||
_page = page;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
if (!_count) {
|
||||
_data.push_back(0); // count-1 place holder.
|
||||
} else {
|
||||
_data[_data.size() - _count - 1] = _count; // count is count - 1 at this point,
|
||||
}
|
||||
|
||||
_data.push_back(offset);
|
||||
++_count;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_data.clear();
|
||||
_page = 0;
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> &data() {
|
||||
return _data;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
SUPER_RELOC2,
|
||||
SUPER_RELOC3,
|
||||
SUPER_INTERSEG1,
|
||||
SUPER_INTERSEG2,
|
||||
SUPER_INTERSEG3,
|
||||
SUPER_INTERSEG4,
|
||||
SUPER_INTERSEG5,
|
||||
SUPER_INTERSEG6,
|
||||
SUPER_INTERSEG7,
|
||||
SUPER_INTERSEG8,
|
||||
SUPER_INTERSEG9,
|
||||
SUPER_INTERSEG10,
|
||||
SUPER_INTERSEG11,
|
||||
SUPER_INTERSEG12,
|
||||
SUPER_INTERSEG13,
|
||||
SUPER_INTERSEG14,
|
||||
SUPER_INTERSEG15,
|
||||
SUPER_INTERSEG16,
|
||||
SUPER_INTERSEG17,
|
||||
SUPER_INTERSEG18,
|
||||
SUPER_INTERSEG19,
|
||||
SUPER_INTERSEG20,
|
||||
SUPER_INTERSEG21,
|
||||
SUPER_INTERSEG22,
|
||||
SUPER_INTERSEG23,
|
||||
SUPER_INTERSEG24,
|
||||
SUPER_INTERSEG25,
|
||||
SUPER_INTERSEG26,
|
||||
SUPER_INTERSEG27,
|
||||
SUPER_INTERSEG28,
|
||||
SUPER_INTERSEG29,
|
||||
SUPER_INTERSEG30,
|
||||
SUPER_INTERSEG31,
|
||||
SUPER_INTERSEG32,
|
||||
SUPER_INTERSEG33,
|
||||
SUPER_INTERSEG34,
|
||||
SUPER_INTERSEG35,
|
||||
SUPER_INTERSEG36,
|
||||
};
|
||||
|
||||
uint32_t add_relocs(std::vector<uint8_t> &data, size_t data_offset, omf::segment &seg, bool compress, bool super) {
|
||||
|
||||
std::array< optional<super_helper>, 38 > ss;
|
||||
|
||||
|
||||
uint32_t reloc_size = 0;
|
||||
|
||||
for (auto &r : seg.relocs) {
|
||||
|
||||
if (compress && r.can_compress()) {
|
||||
|
||||
if (super) {
|
||||
if (r.shift == 0 && r.size == 2) {
|
||||
constexpr int n = SUPER_RELOC2;
|
||||
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
sr->append(r.offset);
|
||||
|
||||
uint32_t value = r.value;
|
||||
for (int i = 0; i < 2; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// sreloc 3 is for 3 bytes. however 4 bytes is also ok since
|
||||
// it's 24-bit address space.
|
||||
if (r.shift == 0 && (r.size == 2 || r.size == 3))
|
||||
{
|
||||
constexpr int n = SUPER_RELOC3;
|
||||
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
sr->append(r.offset);
|
||||
|
||||
uint32_t value = r.value;
|
||||
for (int i = 0; i < 3; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if size == 2 && shift == -16, -> SUPER INTERSEG
|
||||
if (seg.segnum <= 12 && r.shift == 0xf0 && r.size == 2) {
|
||||
|
||||
int n = SUPER_INTERSEG24 + seg.segnum;
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
sr->append(r.offset);
|
||||
|
||||
uint32_t value = r.value;
|
||||
for (int i = 0; i < 2; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
push(data, (uint8_t)omf::cRELOC);
|
||||
push(data, (uint8_t)r.size);
|
||||
push(data, (uint8_t)r.shift);
|
||||
push(data, (uint16_t)r.offset);
|
||||
push(data, (uint16_t)r.value);
|
||||
reloc_size += 7;
|
||||
} else {
|
||||
push(data, (uint8_t)omf::RELOC);
|
||||
push(data, (uint8_t)r.size);
|
||||
push(data, (uint8_t)r.shift);
|
||||
push(data, (uint32_t)r.offset);
|
||||
push(data, (uint32_t)r.value);
|
||||
reloc_size += 11;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &r : seg.intersegs) {
|
||||
if (compress && r.can_compress()) {
|
||||
|
||||
if (super) {
|
||||
|
||||
if (r.shift == 0 && r.size == 3) {
|
||||
constexpr int n = SUPER_INTERSEG1;
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
sr->append(r.offset);
|
||||
|
||||
uint32_t value = r.segment_offset;
|
||||
|
||||
data[data_offset + r.offset + 0] = value; value >>= 8;
|
||||
data[data_offset + r.offset + 1] = value; value >>= 8;
|
||||
data[data_offset + r.offset + 2] = r.segment;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (r.shift == 0 && r.size == 2 && r.segment <= 12) {
|
||||
|
||||
int n = SUPER_INTERSEG12 + r.segment;
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
sr->append(r.offset);
|
||||
|
||||
uint32_t value = r.segment_offset;
|
||||
for (int i = 0; i < 2; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r.shift == 0xf0 && r.size == 2 && r.segment <= 12) {
|
||||
|
||||
int n = SUPER_INTERSEG24 + r.segment;
|
||||
auto &sr = ss[n];
|
||||
if (!sr) sr.emplace();
|
||||
sr->append(r.offset);
|
||||
|
||||
uint32_t value = r.segment_offset;
|
||||
for (int i = 0; i < 2; ++i, value >>= 8)
|
||||
data[data_offset + r.offset + i] = value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
push(data, (uint8_t)omf::cINTERSEG);
|
||||
push(data, (uint8_t)r.size);
|
||||
push(data, (uint8_t)r.shift);
|
||||
push(data, (uint16_t)r.offset);
|
||||
push(data, (uint8_t)r.segment);
|
||||
push(data, (uint16_t)r.segment_offset);
|
||||
reloc_size += 8;
|
||||
} else {
|
||||
push(data, (uint8_t)omf::INTERSEG);
|
||||
push(data, (uint8_t)r.size);
|
||||
push(data, (uint8_t)r.shift);
|
||||
push(data, (uint32_t)r.offset);
|
||||
push(data, (uint16_t)r.file);
|
||||
push(data, (uint16_t)r.segment);
|
||||
push(data, (uint32_t)r.segment_offset);
|
||||
reloc_size += 15;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < ss.size(); ++i) {
|
||||
auto &s = ss[i];
|
||||
if (!s) continue;
|
||||
|
||||
auto tmp = s->data();
|
||||
if (tmp.empty()) continue;
|
||||
|
||||
reloc_size += tmp.size() + 6;
|
||||
data.push_back(omf::SUPER);
|
||||
push(data, ((uint32_t)tmp.size() + 1));
|
||||
data.push_back(i);
|
||||
|
||||
data.insert(data.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
return reloc_size;
|
||||
}
|
||||
|
||||
void save_bin(const std::string &path, omf::segment &segment, uint32_t org) {
|
||||
|
||||
int fd;
|
||||
fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
|
||||
if (fd < 0) {
|
||||
err(EX_CANTCREAT, "Unable to open %s", path.c_str());
|
||||
}
|
||||
|
||||
auto &data = segment.data;
|
||||
|
||||
for (auto &r : segment.relocs) {
|
||||
|
||||
uint32_t value = r.value + org;
|
||||
value >>= -(int8_t)r.shift;
|
||||
|
||||
unsigned offset = r.offset;
|
||||
unsigned size = r.size;
|
||||
while (size--) {
|
||||
data[offset++] = value & 0xff;
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
auto ok = write(fd, data.data(), data.size());
|
||||
if (ok < 0) {
|
||||
close(fd);
|
||||
err(EX_OSERR, "write %s", path.c_str());
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
void save_omf(const std::string &path, std::vector<omf::segment> &segments, unsigned flags) {
|
||||
|
||||
// expressload doesn't support links to other files.
|
||||
// fortunately, we don't either.
|
||||
|
||||
std::vector<uint8_t> expr_headers;
|
||||
std::vector<unsigned> expr_offsets;
|
||||
|
||||
|
||||
bool compress = !(flags & OMF_NO_COMPRESS);
|
||||
bool super = !(flags & OMF_NO_SUPER);
|
||||
bool expressload = !(flags & OMF_NO_EXPRESS);
|
||||
bool v1 = flags & OMF_V1;
|
||||
|
||||
if (v1) {
|
||||
expressload = false;
|
||||
super = false;
|
||||
}
|
||||
|
||||
int fd;
|
||||
fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
|
||||
if (fd < 0) {
|
||||
err(EX_CANTCREAT, "Unable to open %s", path.c_str());
|
||||
}
|
||||
|
||||
|
||||
uint32_t offset = 0;
|
||||
if (expressload) {
|
||||
for (auto &s : segments) {
|
||||
s.segnum++;
|
||||
for (auto &r : s.intersegs) r.segment++;
|
||||
}
|
||||
|
||||
// calculate express load segment size.
|
||||
// sizeof includes the trailing 0, so no need to add in byte size.
|
||||
offset = sizeof(omf_header) + 10 + sizeof("~ExpressLoad");
|
||||
|
||||
offset += 6; // lconst + end
|
||||
offset += 6; // header.
|
||||
for (auto &s : segments) {
|
||||
offset += 8 + 2;
|
||||
offset += sizeof(omf_express_header) + 10;
|
||||
offset += s.segname.length() + 1;
|
||||
}
|
||||
|
||||
lseek(fd, offset, SEEK_SET);
|
||||
}
|
||||
|
||||
|
||||
for (auto &s : segments) {
|
||||
omf_header h;
|
||||
h.length = s.data.size() + s.reserved_space;
|
||||
h.kind = s.kind;
|
||||
h.banksize = s.data.size() > 0xffff ? 0x0000 : 0x010000;
|
||||
h.segnum = s.segnum;
|
||||
h.alignment = s.alignment;
|
||||
h.reserved_space = s.reserved_space;
|
||||
|
||||
uint32_t reserved_space = 0;
|
||||
if (expressload) {
|
||||
std::swap(reserved_space, h.reserved_space);
|
||||
}
|
||||
|
||||
// length field INCLUDES reserved space. Express expand reserved space.
|
||||
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
// push segname and load name onto data.
|
||||
// data.insert(data.end(), 10, ' ');
|
||||
push(data, s.loadname, 10);
|
||||
push(data, s.segname);
|
||||
|
||||
h.dispname = sizeof(omf_header);
|
||||
h.dispdata = sizeof(omf_header) + data.size();
|
||||
|
||||
|
||||
|
||||
uint32_t lconst_offset = offset + sizeof(omf_header) + data.size() + 5;
|
||||
uint32_t lconst_size = s.data.size() + reserved_space;
|
||||
|
||||
|
||||
//lconst record
|
||||
push(data, (uint8_t)omf::LCONST);
|
||||
push(data, (uint32_t)lconst_size);
|
||||
|
||||
size_t data_offset = data.size();
|
||||
|
||||
data.insert(data.end(), s.data.begin(), s.data.end());
|
||||
|
||||
if (reserved_space) {
|
||||
data.insert(data.end(), reserved_space, 0);
|
||||
}
|
||||
|
||||
uint32_t reloc_offset = offset + sizeof(omf_header) + data.size();
|
||||
uint32_t reloc_size = 0;
|
||||
|
||||
reloc_size = add_relocs(data, data_offset, s, compress, super);
|
||||
|
||||
// end-of-record
|
||||
push(data, (uint8_t)omf::END);
|
||||
|
||||
h.bytecount = data.size() + sizeof(omf_header);
|
||||
|
||||
if (expressload) {
|
||||
|
||||
expr_offsets.emplace_back(expr_headers.size());
|
||||
|
||||
if (lconst_size == 0) lconst_offset = 0;
|
||||
if (reloc_size == 0) reloc_offset = 0;
|
||||
|
||||
|
||||
push(expr_headers, (uint32_t)lconst_offset);
|
||||
push(expr_headers, (uint32_t)lconst_size);
|
||||
push(expr_headers, (uint32_t)reloc_offset);
|
||||
push(expr_headers, (uint32_t)reloc_size);
|
||||
|
||||
push(expr_headers, h.unused1);
|
||||
push(expr_headers, h.lablen);
|
||||
push(expr_headers, h.numlen);
|
||||
push(expr_headers, h.version);
|
||||
push(expr_headers, h.banksize);
|
||||
push(expr_headers, h.kind);
|
||||
push(expr_headers, h.unused2);
|
||||
push(expr_headers, h.org);
|
||||
push(expr_headers, h.alignment);
|
||||
push(expr_headers, h.numsex);
|
||||
push(expr_headers, h.unused3);
|
||||
push(expr_headers, h.segnum);
|
||||
push(expr_headers, h.entry);
|
||||
push(expr_headers, (uint16_t)(h.dispname-4));
|
||||
push(expr_headers, h.dispdata);
|
||||
|
||||
expr_headers.insert(expr_headers.end(), 10, ' ');
|
||||
push(expr_headers, s.segname);
|
||||
}
|
||||
|
||||
if (v1) to_v1(h);
|
||||
to_little(h);
|
||||
|
||||
offset += write(fd, &h, sizeof(h));
|
||||
offset += write(fd, data.data(), data.size());
|
||||
|
||||
// version 1 needs 512-byte padding for all but final segment.
|
||||
if (v1 && &s != &segments.back()) {
|
||||
static uint8_t zero[512];
|
||||
offset += write(fd, zero, 512 - (offset & 511) );
|
||||
}
|
||||
}
|
||||
|
||||
if (expressload) {
|
||||
omf_header h;
|
||||
h.segnum = 1;
|
||||
h.banksize = 0x00010000;
|
||||
h.kind = 0x8001;
|
||||
h.dispname = 0x2c;
|
||||
h.dispdata = 0x43;
|
||||
|
||||
unsigned fudge = 10 * segments.size();
|
||||
|
||||
h.length = 6 + expr_headers.size() + fudge;
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
data.insert(data.begin(), 10, ' ');
|
||||
push(data, std::string("~ExpressLoad"));
|
||||
push(data, (uint8_t)0xf2); // lconst.
|
||||
push(data, (uint32_t)h.length);
|
||||
|
||||
push(data, (uint32_t)0); // reserved
|
||||
push(data, (uint16_t)(segments.size() - 1)); // seg count - 1
|
||||
|
||||
|
||||
for (auto &offset : expr_offsets) {
|
||||
push(data, (uint16_t)(fudge + offset));
|
||||
push(data, (uint16_t)0);
|
||||
push(data, (uint32_t)0);
|
||||
}
|
||||
|
||||
for (auto &s : segments) {
|
||||
push(data, (uint16_t)s.segnum);
|
||||
}
|
||||
|
||||
data.insert(data.end(), expr_headers.begin(), expr_headers.end());
|
||||
push(data, (uint8_t)0); // end.
|
||||
|
||||
h.bytecount = data.size() + sizeof(omf_header);
|
||||
|
||||
to_little(h);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
write(fd, &h, sizeof(h));
|
||||
write(fd, data.data(), data.size());
|
||||
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
95
omf.h
Normal file
95
omf.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#ifndef __omf_h__
|
||||
#define __omf_h__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace omf {
|
||||
|
||||
enum opcode : uint8_t {
|
||||
END = 0x00,
|
||||
// 0x01-0xdf CONST
|
||||
ALIGN = 0xe0,
|
||||
ORG = 0xe1,
|
||||
RELOC = 0xe2,
|
||||
INTERSEG = 0xe3,
|
||||
USING = 0xe4,
|
||||
STRONG = 0xe5,
|
||||
GLOBAL = 0xe6,
|
||||
GEQU = 0xe7,
|
||||
MEM = 0xe8,
|
||||
EXPR = 0xeb,
|
||||
ZEXPR = 0xec,
|
||||
BEXPR = 0xed,
|
||||
RELEXPR = 0xee,
|
||||
LOCAL = 0xef,
|
||||
EQU = 0xf0,
|
||||
DS = 0xf1,
|
||||
LCONST = 0xf2,
|
||||
LEXPR = 0xf3,
|
||||
ENTRY = 0xf4,
|
||||
cRELOC = 0xf5,
|
||||
cINTERSEG = 0xf6,
|
||||
SUPER = 0xf7,
|
||||
};
|
||||
|
||||
struct reloc {
|
||||
uint8_t size = 0;
|
||||
uint8_t shift = 0;
|
||||
uint32_t offset = 0;
|
||||
uint32_t value = 0;
|
||||
|
||||
constexpr bool can_compress() const {
|
||||
return offset <= 0xffff && value <= 0xffff;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct interseg {
|
||||
|
||||
uint8_t size = 0;
|
||||
uint8_t shift = 0;
|
||||
uint32_t offset = 0;
|
||||
uint16_t file = 1;
|
||||
uint16_t segment = 0;
|
||||
uint32_t segment_offset = 0;
|
||||
|
||||
constexpr bool can_compress() const {
|
||||
return file == 1 && segment <= 255 && offset <= 0xffff && segment_offset <= 0xffff;
|
||||
}
|
||||
};
|
||||
|
||||
struct segment {
|
||||
|
||||
uint16_t segnum = 0;
|
||||
uint16_t kind = 0;
|
||||
uint32_t alignment = 0;
|
||||
uint32_t reserved_space = 0;
|
||||
|
||||
std::string loadname;
|
||||
std::string segname;
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
std::vector<interseg> intersegs;
|
||||
std::vector<reloc> relocs;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
enum {
|
||||
// flags
|
||||
OMF_V1 = 1,
|
||||
OMF_V2 = 0,
|
||||
OMF_NO_SUPER = 2,
|
||||
OMF_NO_COMPRESS = 4,
|
||||
OMF_NO_EXPRESS = 8
|
||||
|
||||
};
|
||||
|
||||
void save_omf(const std::string &path, std::vector<omf::segment> &segments, unsigned flags);
|
||||
|
||||
|
||||
#endif
|
171
optional.h
Normal file
171
optional.h
Normal file
|
@ -0,0 +1,171 @@
|
|||
#ifndef __optional_h__
|
||||
#define __optional_h__
|
||||
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
|
||||
class bad_optional_access : public std::exception {
|
||||
public:
|
||||
virtual const char* what() const noexcept {
|
||||
return "bad optional access";
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class optional {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
optional() = default;
|
||||
|
||||
optional( const optional& other ) {
|
||||
if (other._engaged) {
|
||||
new (std::addressof(_data)) T(*other);
|
||||
_engaged = true;
|
||||
}
|
||||
}
|
||||
|
||||
optional( const optional&& other ) {
|
||||
if (other._engaged) {
|
||||
new (std::addressof(_data)) T(std::move(*other));
|
||||
_engaged = true;
|
||||
}
|
||||
}
|
||||
|
||||
template < class U >
|
||||
optional( const optional<U>& other ) {
|
||||
if (other._engaged) {
|
||||
new (std::addressof(_data)) T(*other);
|
||||
_engaged = true;
|
||||
}
|
||||
}
|
||||
|
||||
template < class U >
|
||||
optional( optional<U>&& other ) {
|
||||
if (other._engaged) {
|
||||
new (std::addressof(_data)) T(std::move(*other));
|
||||
_engaged = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class U = T>
|
||||
optional(U &&value) {
|
||||
new(std::addressof(_data)) T(std::forward<U>(value));
|
||||
_engaged = true;
|
||||
}
|
||||
|
||||
|
||||
~optional() {
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
template< class U = T >
|
||||
optional& operator=( U&& value ) {
|
||||
if (_engaged) {
|
||||
auto &self = *reinterpret_cast<T*>(std::addressof(_data));
|
||||
self = std::forward<U>(value);
|
||||
}
|
||||
else {
|
||||
new(std::addressof(_data)) T(std::forward<U>(value));
|
||||
_engaged = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional& operator=(optional &&rhs) {
|
||||
if (rhs._engaged) this->operator=(std::forward<T>(*rhs));
|
||||
else reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional& operator=(const optional &rhs) {
|
||||
if (rhs._engaged) this->operator=(*rhs);
|
||||
else reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class... Args >
|
||||
void emplace( Args&&... args ) {
|
||||
reset();
|
||||
new(std::addressof(_data)) T(std::forward<Args>(args)...);
|
||||
_engaged = true;
|
||||
}
|
||||
|
||||
|
||||
constexpr explicit operator bool() const {
|
||||
return _engaged;
|
||||
}
|
||||
|
||||
constexpr bool has_value() const {
|
||||
return _engaged;
|
||||
}
|
||||
|
||||
/* these should throw ... */
|
||||
constexpr T& value() & {
|
||||
if (!_engaged) throw bad_optional_access();
|
||||
return *reinterpret_cast<T*>(std::addressof(_data));
|
||||
}
|
||||
|
||||
constexpr const T & value() const & {
|
||||
if (!_engaged) throw bad_optional_access();
|
||||
return *reinterpret_cast<const T*>(std::addressof(_data));
|
||||
}
|
||||
|
||||
constexpr T&& value() && {
|
||||
if (!_engaged) throw bad_optional_access();
|
||||
return *reinterpret_cast<T*>(std::addressof(_data));
|
||||
}
|
||||
|
||||
constexpr const T&& value() const && {
|
||||
if (!_engaged) throw bad_optional_access();
|
||||
return *reinterpret_cast<const T*>(std::addressof(_data));
|
||||
}
|
||||
|
||||
|
||||
template< class U >
|
||||
constexpr T value_or( U&& default_value ) const& {
|
||||
return bool(*this) ? **this : static_cast<T>(std::forward<U>(default_value));
|
||||
}
|
||||
|
||||
template< class U >
|
||||
constexpr T value_or( U&& default_value ) && {
|
||||
return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(default_value));
|
||||
}
|
||||
|
||||
constexpr const T* operator->() const {
|
||||
return reinterpret_cast<const T*>(std::addressof(_data));
|
||||
}
|
||||
constexpr T* operator->() {
|
||||
return reinterpret_cast<T*>(std::addressof(_data));
|
||||
}
|
||||
|
||||
constexpr const T& operator*() const& {
|
||||
return *reinterpret_cast<const T*>(std::addressof(_data));
|
||||
}
|
||||
constexpr T& operator*() & {
|
||||
return *reinterpret_cast<T*>(std::addressof(_data));
|
||||
}
|
||||
constexpr const T&& operator*() const&& {
|
||||
return *reinterpret_cast<const T*>(std::addressof(_data));
|
||||
}
|
||||
constexpr T&& operator*() && {
|
||||
return *reinterpret_cast<T*>(std::addressof(_data));
|
||||
}
|
||||
|
||||
|
||||
void reset() {
|
||||
if (_engaged) {
|
||||
reinterpret_cast<const T*>(std::addressof(_data))->~T();
|
||||
_engaged = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool _engaged = false;
|
||||
typename std::aligned_storage<sizeof(T), alignof(T)>::type _data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,7 +1,13 @@
|
|||
AS = wdc816as
|
||||
CC = wdc816cc
|
||||
ASFLAGS = -L
|
||||
CCFLAGS = -LT -ML -I../include
|
||||
|
||||
all: instructions.obj hello1.obj hello2.obj hello3.obj labels.obj ref_only.obj
|
||||
|
||||
%.obj : %.c
|
||||
$(CC) $(CCFLAGS) $< -o $@
|
||||
|
||||
all: instructions.obj hello1.obj hello2.obj labels.obj
|
||||
|
||||
%.obj : %.asm
|
||||
$(AS) $(ASFLAGS) $< -o $@
|
||||
|
|
28
samples/hello3.asm
Normal file
28
samples/hello3.asm
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
;
|
||||
; 2-segment, 2 module code.
|
||||
;
|
||||
include 'hello.macros'
|
||||
|
||||
macdelim {
|
||||
|
||||
module code
|
||||
CODE
|
||||
extern text
|
||||
pea #^text
|
||||
pea #text
|
||||
_WriteLine
|
||||
|
||||
rtl
|
||||
ends
|
||||
endmod
|
||||
|
||||
module data
|
||||
KDATA
|
||||
public text
|
||||
text
|
||||
pstr {'hello, world'}
|
||||
ends
|
||||
endmod
|
||||
|
||||
|
49
samples/hello3.lst
Normal file
49
samples/hello3.lst
Normal file
|
@ -0,0 +1,49 @@
|
|||
Sun Jan 8 2017 12:42 Page 1
|
||||
|
||||
|
||||
***************************************
|
||||
** WDC 65C816 Macro Assembler **
|
||||
** **
|
||||
** Version 3.49.1- Feb 6 2006 **
|
||||
***************************************
|
||||
|
||||
1
|
||||
2 ;
|
||||
3 ; 2-segment, 2 module code.
|
||||
4 ;
|
||||
5 include 'hello.macros'
|
||||
6
|
||||
7 macdelim {
|
||||
8
|
||||
9 module code
|
||||
10 CODE
|
||||
11 extern text
|
||||
12 00:0000: F4 xx xx pea #^text
|
||||
13 00:0003: F4 xx xx pea #text
|
||||
14 _WriteLine
|
||||
+ 14 00:0006: A2 0C 1A ldx #$1a0c
|
||||
+ 14 00:0009: 22 00 00 E1 jsl $e10000
|
||||
15
|
||||
16 00:000D: 6B rtl
|
||||
17 ends
|
||||
18 endmod
|
||||
19
|
||||
20 module data
|
||||
21 KDATA
|
||||
22 public text
|
||||
23 text
|
||||
24 pstr {'hello, world'}
|
||||
+ 24 00:0000: 0C db end0001-start0001
|
||||
+ 24 start0001
|
||||
+ 24 00:0001: 68 65 6C 6C db 'hello, world'
|
||||
00:0005: 6F 2C 20 77
|
||||
00:0009: 6F 72 6C 64
|
||||
+ 24 end0001
|
||||
25 00:000D: ends
|
||||
26 endmod
|
||||
27
|
||||
28
|
||||
|
||||
|
||||
Lines assembled: 58
|
||||
Errors: 0
|
BIN
samples/hello3.obj
Normal file
BIN
samples/hello3.obj
Normal file
Binary file not shown.
29
samples/hello4.asm
Normal file
29
samples/hello4.asm
Normal file
|
@ -0,0 +1,29 @@
|
|||
|
||||
;
|
||||
; 2-segment, 2 module code.
|
||||
; with intersegment linkage.
|
||||
|
||||
include 'hello.macros'
|
||||
|
||||
macdelim {
|
||||
|
||||
module code
|
||||
CODE
|
||||
extern text
|
||||
pea #^text
|
||||
pea #text
|
||||
_WriteLine
|
||||
|
||||
rtl
|
||||
ends
|
||||
endmod
|
||||
|
||||
module data
|
||||
XDATA SECTION
|
||||
public text
|
||||
text
|
||||
pstr {'hello, world'}
|
||||
ends
|
||||
endmod
|
||||
|
||||
|
50
samples/hello4.lst
Normal file
50
samples/hello4.lst
Normal file
|
@ -0,0 +1,50 @@
|
|||
Thu Jan 12 2017 12:17 Page 1
|
||||
|
||||
|
||||
***************************************
|
||||
** WDC 65C816 Macro Assembler **
|
||||
** **
|
||||
** Version 3.49.1- Feb 6 2006 **
|
||||
***************************************
|
||||
|
||||
1
|
||||
2 ;
|
||||
3 ; 2-segment, 2 module code.
|
||||
4 ; with intersegment linkage.
|
||||
5
|
||||
6 include 'hello.macros'
|
||||
7
|
||||
8 macdelim {
|
||||
9
|
||||
10 module code
|
||||
11 CODE
|
||||
12 extern text
|
||||
13 00:0000: F4 xx xx pea #^text
|
||||
14 00:0003: F4 xx xx pea #text
|
||||
15 _WriteLine
|
||||
+ 15 00:0006: A2 0C 1A ldx #$1a0c
|
||||
+ 15 00:0009: 22 00 00 E1 jsl $e10000
|
||||
16
|
||||
17 00:000D: 6B rtl
|
||||
18 ends
|
||||
19 endmod
|
||||
20
|
||||
21 module data
|
||||
22 XDATA SECTION
|
||||
23 public text
|
||||
24 text
|
||||
25 pstr {'hello, world'}
|
||||
+ 25 00:0000: 0C db end0001-start0001
|
||||
+ 25 start0001
|
||||
+ 25 00:0001: 68 65 6C 6C db 'hello, world'
|
||||
00:0005: 6F 2C 20 77
|
||||
00:0009: 6F 72 6C 64
|
||||
+ 25 end0001
|
||||
26 00:000D: ends
|
||||
27 endmod
|
||||
28
|
||||
29
|
||||
|
||||
|
||||
Lines assembled: 59
|
||||
Errors: 0
|
BIN
samples/hello4.obj
Normal file
BIN
samples/hello4.obj
Normal file
Binary file not shown.
67
samples/ref_only.asm
Normal file
67
samples/ref_only.asm
Normal file
|
@ -0,0 +1,67 @@
|
|||
|
||||
;
|
||||
; test ref-only sections (PAGE0, UDATA)
|
||||
;
|
||||
;
|
||||
|
||||
module part_1
|
||||
|
||||
globals on
|
||||
externs on
|
||||
|
||||
page0
|
||||
page0_start
|
||||
|
||||
offset_0 ds 2
|
||||
offset_2 ds 4
|
||||
ends
|
||||
|
||||
udata
|
||||
|
||||
uoffset_0 ds 2
|
||||
uoffset_4 ds 4
|
||||
ds 1024-4
|
||||
ends
|
||||
|
||||
code
|
||||
longa on
|
||||
longi on
|
||||
lda offset_0
|
||||
lda offset_2
|
||||
lda uoffset_0
|
||||
lda uoffset_4
|
||||
ends
|
||||
|
||||
|
||||
endmod
|
||||
|
||||
module part_2
|
||||
|
||||
globals on
|
||||
externs on
|
||||
|
||||
|
||||
page0
|
||||
uoffset_6 ds 2
|
||||
uoffset_8 ds 4
|
||||
ends
|
||||
|
||||
udata
|
||||
uoffset_1024 ds 1024
|
||||
uoffset_2048 ds 1024
|
||||
ends
|
||||
|
||||
code
|
||||
longa on
|
||||
longi on
|
||||
|
||||
lda #_BEG_PAGE0
|
||||
lda #_END_PAGE0
|
||||
lda #_BEG_UDATA
|
||||
lda #_END_UDATA
|
||||
lda #_BEG_DATA
|
||||
lda #_END_DATA
|
||||
ends
|
||||
|
||||
|
||||
endmod
|
83
samples/ref_only.lst
Normal file
83
samples/ref_only.lst
Normal file
|
@ -0,0 +1,83 @@
|
|||
Sun Jan 8 2017 12:55 Page 1
|
||||
|
||||
|
||||
***************************************
|
||||
** WDC 65C816 Macro Assembler **
|
||||
** **
|
||||
** Version 3.49.1- Feb 6 2006 **
|
||||
***************************************
|
||||
|
||||
1
|
||||
2 ;
|
||||
3 ; test ref-only sections (PAGE0, UDATA)
|
||||
4 ;
|
||||
5 ;
|
||||
6
|
||||
7 module part_1
|
||||
8
|
||||
9 globals on
|
||||
10 externs on
|
||||
11
|
||||
12 page0
|
||||
13 page0_start
|
||||
14
|
||||
15 00:0000: offset_0 ds 2
|
||||
16 00:0002: offset_2 ds 4
|
||||
17 00:0006: ends
|
||||
18
|
||||
19 udata
|
||||
20
|
||||
21 00:0000: uoffset_0 ds 2
|
||||
22 00:0002: uoffset_4 ds 4
|
||||
23 00:0006: ds 1024-4
|
||||
24 00:0402: ends
|
||||
25
|
||||
26 code
|
||||
27 longa on
|
||||
28 longi on
|
||||
29 00:0000: A5 xx lda offset_0
|
||||
30 00:0002: A5 xx lda offset_2
|
||||
31 00:0004: AD xx xx lda uoffset_0
|
||||
32 00:0007: AD xx xx lda uoffset_4
|
||||
33 ends
|
||||
34
|
||||
35
|
||||
36 endmod
|
||||
37
|
||||
38 module part_2
|
||||
39
|
||||
40 globals on
|
||||
41 externs on
|
||||
42
|
||||
43
|
||||
44 page0
|
||||
45 00:0000: uoffset_6 ds 2
|
||||
46 00:0002: uoffset_8 ds 4
|
||||
47 00:0006: ends
|
||||
48
|
||||
49 udata
|
||||
50 00:0000: uoffset_1024 ds 1024
|
||||
51 00:0400: uoffset_2048 ds 1024
|
||||
52 00:0800: ends
|
||||
Sun Jan 8 2017 12:55 Page 2
|
||||
|
||||
|
||||
53
|
||||
54 code
|
||||
55 longa on
|
||||
56 longi on
|
||||
57
|
||||
58 00:0000: A9 xx xx lda #_BEG_PAGE0
|
||||
59 00:0003: A9 xx xx lda #_END_PAGE0
|
||||
60 00:0006: A9 xx xx lda #_BEG_UDATA
|
||||
61 00:0009: A9 xx xx lda #_END_UDATA
|
||||
62 00:000C: A9 xx xx lda #_BEG_DATA
|
||||
63 00:000F: A9 xx xx lda #_END_DATA
|
||||
64 ends
|
||||
65
|
||||
66
|
||||
67 endmod
|
||||
|
||||
|
||||
Lines assembled: 67
|
||||
Errors: 0
|
BIN
samples/ref_only.obj
Normal file
BIN
samples/ref_only.obj
Normal file
Binary file not shown.
37
samples/relative.asm
Normal file
37
samples/relative.asm
Normal file
|
@ -0,0 +1,37 @@
|
|||
; test relative expressions.
|
||||
|
||||
module code1
|
||||
globals on
|
||||
externs on
|
||||
branchb
|
||||
nop
|
||||
nop
|
||||
endmod
|
||||
|
||||
module code2
|
||||
globals on
|
||||
externs on
|
||||
jmp branchb
|
||||
bra branchb
|
||||
brl branchb
|
||||
per branchb
|
||||
;
|
||||
nop
|
||||
nop
|
||||
;
|
||||
jmp branchf
|
||||
bra branchf
|
||||
brl branchf
|
||||
per branchf
|
||||
|
||||
endmod
|
||||
|
||||
module code3
|
||||
globals on
|
||||
externs on
|
||||
branchf
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
rtl
|
||||
endmod
|
50
samples/relative.lst
Normal file
50
samples/relative.lst
Normal file
|
@ -0,0 +1,50 @@
|
|||
Thu Jan 12 2017 12:24 Page 1
|
||||
|
||||
|
||||
***************************************
|
||||
** WDC 65C816 Macro Assembler **
|
||||
** **
|
||||
** Version 3.49.1- Feb 6 2006 **
|
||||
***************************************
|
||||
|
||||
1 ; test relative expressions.
|
||||
2
|
||||
3 module code1
|
||||
4 globals on
|
||||
5 externs on
|
||||
6 branchb
|
||||
7 00:0000: EA nop
|
||||
8 00:0001: EA nop
|
||||
9 endmod
|
||||
10
|
||||
11 module code2
|
||||
12 globals on
|
||||
13 externs on
|
||||
14 00:0000: 4C xx xx jmp branchb
|
||||
15 00:0003: 80 xx bra branchb
|
||||
16 00:0005: 82 xx xx brl branchb
|
||||
17 00:0008: 62 xx xx per branchb
|
||||
18 ;
|
||||
19 00:000B: EA nop
|
||||
20 00:000C: EA nop
|
||||
21 ;
|
||||
22 00:000D: 4C xx xx jmp branchf
|
||||
23 00:0010: 80 xx bra branchf
|
||||
24 00:0012: 82 xx xx brl branchf
|
||||
25 00:0015: 62 xx xx per branchf
|
||||
26
|
||||
27 endmod
|
||||
28
|
||||
29 module code3
|
||||
30 globals on
|
||||
31 externs on
|
||||
32 branchf
|
||||
33 00:0000: EA nop
|
||||
34 00:0001: EA nop
|
||||
35 00:0002: EA nop
|
||||
36 00:0003: 6B rtl
|
||||
37 endmod
|
||||
|
||||
|
||||
Lines assembled: 37
|
||||
Errors: 0
|
BIN
samples/relative.obj
Normal file
BIN
samples/relative.obj
Normal file
Binary file not shown.
109
samples/stdio_test.c
Normal file
109
samples/stdio_test.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
void main(void) {
|
||||
FILE *fp;
|
||||
|
||||
#asm
|
||||
phk
|
||||
plb
|
||||
#endasm
|
||||
|
||||
fputs("hello, world\n", stdout);
|
||||
|
||||
fp = fopen("file.txt", "wb");
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// these stubs are not provided in the library but could call gs/os.
|
||||
|
||||
int open(const char *name, int mode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int close(int fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
size_t read(int fd, void *buffer, size_t count) {
|
||||
|
||||
static struct {
|
||||
unsigned pCount;
|
||||
unsigned refNum;
|
||||
void *dataBuffer;
|
||||
unsigned long requestCount;
|
||||
unsigned long transferCount;
|
||||
unsigned cachePriority;
|
||||
} dcb;
|
||||
|
||||
|
||||
unsigned tool_error = 0x0043;
|
||||
|
||||
dcb.pCount = 4;
|
||||
dcb.refNum = fd+1;
|
||||
dcb.dataBuffer = buffer;
|
||||
dcb.requestCount = count;
|
||||
#asm
|
||||
pea #^%%dcb
|
||||
pea #%%dcb
|
||||
pea #$2012
|
||||
jsl $e100b0
|
||||
sta %%tool_error;
|
||||
#endasm
|
||||
if (tool_error) return -1;
|
||||
return dcb.transferCount;
|
||||
|
||||
}
|
||||
|
||||
size_t write(int fd, void *buffer, size_t count) {
|
||||
|
||||
static struct {
|
||||
unsigned pCount;
|
||||
unsigned refNum;
|
||||
void *dataBuffer;
|
||||
unsigned long requestCount;
|
||||
unsigned long transferCount;
|
||||
unsigned cachePriority;
|
||||
} dcb;
|
||||
|
||||
|
||||
unsigned tool_error = 0x0043;
|
||||
|
||||
dcb.pCount = 4;
|
||||
dcb.refNum = fd+1;
|
||||
dcb.dataBuffer = buffer;
|
||||
dcb.requestCount = count;
|
||||
#asm
|
||||
pea #^%%dcb
|
||||
pea #%%dcb
|
||||
pea #$2013
|
||||
jsl $e100b0
|
||||
sta %%tool_error;
|
||||
#endasm
|
||||
if (tool_error) return -1;
|
||||
return dcb.transferCount;
|
||||
}
|
||||
|
||||
long lseek(int fd, long offset, int whence) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int creat(const char *name, int mode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unlink(const char *name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int isatty(int fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#pragma section udata=heap
|
||||
char __heap[8192];
|
||||
void *heap_start = (void *)__heap;
|
||||
void *heap_end = (void *)&__heap[8092];
|
563
samples/stdio_test.lst
Normal file
563
samples/stdio_test.lst
Normal file
|
@ -0,0 +1,563 @@
|
|||
Tue Jan 17 2017 23:30 Page 1
|
||||
|
||||
|
||||
***************************************
|
||||
** WDC 65C816 Macro Assembler **
|
||||
** **
|
||||
** Version 3.49.1- Feb 6 2006 **
|
||||
***************************************
|
||||
|
||||
1 ;:ts=8
|
||||
2 00000001 R0 equ 1
|
||||
3 00000005 R1 equ 5
|
||||
4 00000009 R2 equ 9
|
||||
5 0000000D R3 equ 13
|
||||
6 ;#include <stdio.h>
|
||||
7 ;#include <fcntl.h>
|
||||
8 ;
|
||||
9 ;
|
||||
10 ;void main(void) {
|
||||
11 code
|
||||
12 xdef ~~main
|
||||
13 func
|
||||
14 ~~main:
|
||||
15 longa on
|
||||
16 longi on
|
||||
17 00:0000: 3B tsc
|
||||
18 00:0001: 38 sec
|
||||
19 00:0002: E9 08 00 sbc #L2
|
||||
20 00:0005: 1B tcs
|
||||
21 00:0006: 0B phd
|
||||
22 00:0007: 5B tcd
|
||||
23 ; FILE *fp;
|
||||
24 ;
|
||||
25 ; #asm
|
||||
26 00000000 fp_1 set 0
|
||||
27 ; phk
|
||||
28 ; plb
|
||||
29 ; #endasm
|
||||
30 asmstart
|
||||
31 00:0008: 4B phk
|
||||
32 00:0009: AB plb
|
||||
33 asmend
|
||||
34 ;
|
||||
35 ; fputs("hello, world\n", stdout);
|
||||
36 00:000A: A9 xx xx lda #<~~_iob+20
|
||||
37 00:000D: 85 01 sta <R0
|
||||
38 xref _BEG_DATA
|
||||
39 00:000F: A9 xx xx lda #_BEG_DATA>>16
|
||||
40 00:0012: 85 03 sta <R0+2
|
||||
41 00:0014: D4 03 pei <R0+2
|
||||
42 00:0016: D4 01 pei <R0
|
||||
43 00:0018: F4 xx xx pea #^L1
|
||||
44 00:001B: F4 xx xx pea #<L1
|
||||
45 00:001E: 22 xx xx xx jsl ~~fputs
|
||||
46 ;
|
||||
47 ; fp = fopen("file.txt", "wb");
|
||||
48 00:0022: F4 xx xx pea #^L1+23
|
||||
49 00:0025: F4 xx xx pea #<L1+23
|
||||
50 00:0028: F4 xx xx pea #^L1+14
|
||||
51 00:002B: F4 xx xx pea #<L1+14
|
||||
52 00:002E: 22 xx xx xx jsl ~~fopen
|
||||
Tue Jan 17 2017 23:30 Page 2
|
||||
|
||||
|
||||
53 00:0032: 85 05 sta <L3+fp_1
|
||||
54 00:0034: 86 07 stx <L3+fp_1+2
|
||||
55 ; fclose(fp);
|
||||
56 00:0036: D4 07 pei <L3+fp_1+2
|
||||
57 00:0038: D4 05 pei <L3+fp_1
|
||||
58 00:003A: 22 xx xx xx jsl ~~fclose
|
||||
59 ;}
|
||||
60 L4:
|
||||
61 00:003E: 2B pld
|
||||
62 00:003F: 3B tsc
|
||||
63 00:0040: 18 clc
|
||||
64 00:0041: 69 08 00 adc #L2
|
||||
65 00:0044: 1B tcs
|
||||
66 00:0045: 6B rtl
|
||||
67 00000008 L2 equ 8
|
||||
68 00000005 L3 equ 5
|
||||
69 ends
|
||||
70 efunc
|
||||
71 data
|
||||
72 L1:
|
||||
73 00:0000: 68 65 6C 6C db $68,$65,$6C,$6C,$6F,$2C,$20,$77,$6F,$72,
|
||||
$6C,$64,$0A,$00,$66
|
||||
00:0004: 6F 2C 20 77
|
||||
00:0008: 6F 72 6C 64
|
||||
00:000C: 0A 00 66
|
||||
74 00:000F: 69 6C 65 2E db $69,$6C,$65,$2E,$74,$78,$74,$00,$77,$62,
|
||||
$00
|
||||
00:0013: 74 78 74 00
|
||||
00:0017: 77 62 00
|
||||
75 00:001A: ends
|
||||
76 ;
|
||||
77 ;// these stubs are not provided in the library bu
|
||||
t could call gs/os.
|
||||
78 ;
|
||||
79 ;int open(const char *name, int mode) {
|
||||
80 code
|
||||
81 xdef ~~open
|
||||
82 func
|
||||
83 ~~open:
|
||||
84 longa on
|
||||
85 longi on
|
||||
86 00:0046: 3B tsc
|
||||
87 00:0047: 38 sec
|
||||
88 00:0048: E9 00 00 sbc #L6
|
||||
89 00:004B: 1B tcs
|
||||
90 00:004C: 0B phd
|
||||
91 00:004D: 5B tcd
|
||||
92 00000004 name_0 set 4
|
||||
93 00000008 mode_0 set 8
|
||||
94 ; return -1;
|
||||
95 00:004E: A9 FF FF lda #$ffff
|
||||
96 L8:
|
||||
97 00:0051: A8 tay
|
||||
98 00:0052: A5 02 lda <L6+2
|
||||
99 00:0054: 85 08 sta <L6+2+6
|
||||
100 00:0056: A5 01 lda <L6+1
|
||||
101 00:0058: 85 07 sta <L6+1+6
|
||||
102 00:005A: 2B pld
|
||||
Tue Jan 17 2017 23:30 Page 3
|
||||
|
||||
|
||||
103 00:005B: 3B tsc
|
||||
104 00:005C: 18 clc
|
||||
105 00:005D: 69 06 00 adc #L6+6
|
||||
106 00:0060: 1B tcs
|
||||
107 00:0061: 98 tya
|
||||
108 00:0062: 6B rtl
|
||||
109 ;}
|
||||
110 00000000 L6 equ 0
|
||||
111 00000001 L7 equ 1
|
||||
112 ends
|
||||
113 efunc
|
||||
114 ;
|
||||
115 ;int close(int fd) {
|
||||
116 code
|
||||
117 xdef ~~close
|
||||
118 func
|
||||
119 ~~close:
|
||||
120 longa on
|
||||
121 longi on
|
||||
122 00:0063: 3B tsc
|
||||
123 00:0064: 38 sec
|
||||
124 00:0065: E9 00 00 sbc #L9
|
||||
125 00:0068: 1B tcs
|
||||
126 00:0069: 0B phd
|
||||
127 00:006A: 5B tcd
|
||||
128 00000004 fd_0 set 4
|
||||
129 ; return -1;
|
||||
130 00:006B: A9 FF FF lda #$ffff
|
||||
131 L11:
|
||||
132 00:006E: A8 tay
|
||||
133 00:006F: A5 02 lda <L9+2
|
||||
134 00:0071: 85 04 sta <L9+2+2
|
||||
135 00:0073: A5 01 lda <L9+1
|
||||
136 00:0075: 85 03 sta <L9+1+2
|
||||
137 00:0077: 2B pld
|
||||
138 00:0078: 3B tsc
|
||||
139 00:0079: 18 clc
|
||||
140 00:007A: 69 02 00 adc #L9+2
|
||||
141 00:007D: 1B tcs
|
||||
142 00:007E: 98 tya
|
||||
143 00:007F: 6B rtl
|
||||
144 ;}
|
||||
145 00000000 L9 equ 0
|
||||
146 00000001 L10 equ 1
|
||||
147 ends
|
||||
148 efunc
|
||||
149 ;
|
||||
150 ;
|
||||
151 ;size_t read(int fd, void *buffer, size_t count) {
|
||||
152 code
|
||||
153 xdef ~~read
|
||||
154 func
|
||||
155 ~~read:
|
||||
156 longa on
|
||||
157 longi on
|
||||
158 00:0080: 3B tsc
|
||||
159 00:0081: 38 sec
|
||||
160 00:0082: E9 02 00 sbc #L12
|
||||
Tue Jan 17 2017 23:30 Page 4
|
||||
|
||||
|
||||
161 00:0085: 1B tcs
|
||||
162 00:0086: 0B phd
|
||||
163 00:0087: 5B tcd
|
||||
164 00000004 fd_0 set 4
|
||||
165 00000006 buffer_0 set 6
|
||||
166 0000000A count_0 set 10
|
||||
167 ;
|
||||
168 ;static struct {
|
||||
169 ; unsigned pCount;
|
||||
170 ; unsigned refNum;
|
||||
171 ; void *dataBuffer;
|
||||
172 ; unsigned long requestCount;
|
||||
173 ; unsigned long transferCount;
|
||||
174 ; unsigned cachePriority;
|
||||
175 ;} dcb;
|
||||
176 udata
|
||||
177 L10001:
|
||||
178 00:0000: ds 18
|
||||
179 00:0012: ends
|
||||
180 ;
|
||||
181 ;
|
||||
182 ; unsigned tool_error = 0x0043;
|
||||
183 ;
|
||||
184 ; dcb.pCount = 4;
|
||||
185 00000000 tool_error_1 set 0
|
||||
186 00:0088: A9 43 00 lda #$43
|
||||
187 00:008B: 85 01 sta <L13+tool_error_1
|
||||
188 00:008D: A9 04 00 lda #$4
|
||||
189 00:0090: 8D xx xx sta |L10001
|
||||
190 ; dcb.refNum = fd+1;
|
||||
191 00:0093: A5 06 lda <L12+fd_0
|
||||
192 00:0095: 1A ina
|
||||
193 00:0096: 8D xx xx sta |L10001+2
|
||||
194 ; dcb.dataBuffer = buffer;
|
||||
195 00:0099: A5 08 lda <L12+buffer_0
|
||||
196 00:009B: 8D xx xx sta |L10001+4
|
||||
197 00:009E: A5 0A lda <L12+buffer_0+2
|
||||
198 00:00A0: 8D xx xx sta |L10001+4+2
|
||||
199 ; dcb.requestCount = count;
|
||||
200 00:00A3: A5 0C lda <L12+count_0
|
||||
201 00:00A5: 8D xx xx sta |L10001+8
|
||||
202 00:00A8: 9C xx xx stz |L10001+8+2
|
||||
203 ; #asm
|
||||
204 ; pea #^%%dcb
|
||||
205 ; pea #%%dcb
|
||||
206 ; pea #$2012
|
||||
207 ; jsl $e100b0
|
||||
208 ; sta %%tool_error;
|
||||
209 ; #endasm
|
||||
210 asmstart
|
||||
211 00:00AB: F4 xx xx pea #^L10001
|
||||
212 00:00AE: F4 xx xx pea #L10001
|
||||
213 00:00B1: F4 12 20 pea #$2012
|
||||
214 00:00B4: 22 B0 00 E1 jsl $e100b0
|
||||
215 00:00B8: 85 01 sta <L13+tool_error_1;
|
||||
216 asmend
|
||||
217 ; if (tool_error) return -1;
|
||||
218 00:00BA: A5 01 lda <L13+tool_error_1
|
||||
Tue Jan 17 2017 23:30 Page 5
|
||||
|
||||
|
||||
219 00:00BC: D0 03 bne L14
|
||||
220 00:00BE: 82 15 00 brl L10002
|
||||
221 L14:
|
||||
222 00:00C1: A9 FF FF lda #$ffff
|
||||
223 L15:
|
||||
224 00:00C4: A8 tay
|
||||
225 00:00C5: A5 04 lda <L12+2
|
||||
226 00:00C7: 85 0C sta <L12+2+8
|
||||
227 00:00C9: A5 03 lda <L12+1
|
||||
228 00:00CB: 85 0B sta <L12+1+8
|
||||
229 00:00CD: 2B pld
|
||||
230 00:00CE: 3B tsc
|
||||
231 00:00CF: 18 clc
|
||||
232 00:00D0: 69 0A 00 adc #L12+8
|
||||
233 00:00D3: 1B tcs
|
||||
234 00:00D4: 98 tya
|
||||
235 00:00D5: 6B rtl
|
||||
236 ; return dcb.transferCount;
|
||||
237 L10002:
|
||||
238 00:00D6: AD xx xx lda |L10001+12
|
||||
239 00:00D9: 82 E8 FF brl L15
|
||||
240 ;
|
||||
241 ;}
|
||||
242 00000002 L12 equ 2
|
||||
243 00000001 L13 equ 1
|
||||
244 ends
|
||||
245 efunc
|
||||
246 ;
|
||||
247 ;size_t write(int fd, void *buffer, size_t count)
|
||||
{
|
||||
248 code
|
||||
249 xdef ~~write
|
||||
250 func
|
||||
251 ~~write:
|
||||
252 longa on
|
||||
253 longi on
|
||||
254 00:00DC: 3B tsc
|
||||
255 00:00DD: 38 sec
|
||||
256 00:00DE: E9 02 00 sbc #L16
|
||||
257 00:00E1: 1B tcs
|
||||
258 00:00E2: 0B phd
|
||||
259 00:00E3: 5B tcd
|
||||
260 00000004 fd_0 set 4
|
||||
261 00000006 buffer_0 set 6
|
||||
262 0000000A count_0 set 10
|
||||
263 ;
|
||||
264 ;static struct {
|
||||
265 ; unsigned pCount;
|
||||
266 ; unsigned refNum;
|
||||
267 ; void *dataBuffer;
|
||||
268 ; unsigned long requestCount;
|
||||
269 ; unsigned long transferCount;
|
||||
270 ; unsigned cachePriority;
|
||||
271 ;} dcb;
|
||||
272 udata
|
||||
273 L10003:
|
||||
274 00:0012: ds 18
|
||||
275 00:0024: ends
|
||||
Tue Jan 17 2017 23:30 Page 6
|
||||
|
||||
|
||||
276 ;
|
||||
277 ;
|
||||
278 ; unsigned tool_error = 0x0043;
|
||||
279 ;
|
||||
280 ; dcb.pCount = 4;
|
||||
281 00000000 tool_error_1 set 0
|
||||
282 00:00E4: A9 43 00 lda #$43
|
||||
283 00:00E7: 85 01 sta <L17+tool_error_1
|
||||
284 00:00E9: A9 04 00 lda #$4
|
||||
285 00:00EC: 8D xx xx sta |L10003
|
||||
286 ; dcb.refNum = fd+1;
|
||||
287 00:00EF: A5 06 lda <L16+fd_0
|
||||
288 00:00F1: 1A ina
|
||||
289 00:00F2: 8D xx xx sta |L10003+2
|
||||
290 ; dcb.dataBuffer = buffer;
|
||||
291 00:00F5: A5 08 lda <L16+buffer_0
|
||||
292 00:00F7: 8D xx xx sta |L10003+4
|
||||
293 00:00FA: A5 0A lda <L16+buffer_0+2
|
||||
294 00:00FC: 8D xx xx sta |L10003+4+2
|
||||
295 ; dcb.requestCount = count;
|
||||
296 00:00FF: A5 0C lda <L16+count_0
|
||||
297 00:0101: 8D xx xx sta |L10003+8
|
||||
298 00:0104: 9C xx xx stz |L10003+8+2
|
||||
299 ; #asm
|
||||
300 ; pea #^%%dcb
|
||||
301 ; pea #%%dcb
|
||||
302 ; pea #$2013
|
||||
303 ; jsl $e100b0
|
||||
304 ; sta %%tool_error;
|
||||
305 ; #endasm
|
||||
306 asmstart
|
||||
307 00:0107: F4 xx xx pea #^L10003
|
||||
308 00:010A: F4 xx xx pea #L10003
|
||||
309 00:010D: F4 13 20 pea #$2013
|
||||
310 00:0110: 22 B0 00 E1 jsl $e100b0
|
||||
311 00:0114: 85 01 sta <L17+tool_error_1;
|
||||
312 asmend
|
||||
313 ; if (tool_error) return -1;
|
||||
314 00:0116: A5 01 lda <L17+tool_error_1
|
||||
315 00:0118: D0 03 bne L18
|
||||
316 00:011A: 82 15 00 brl L10004
|
||||
317 L18:
|
||||
318 00:011D: A9 FF FF lda #$ffff
|
||||
319 L19:
|
||||
320 00:0120: A8 tay
|
||||
321 00:0121: A5 04 lda <L16+2
|
||||
322 00:0123: 85 0C sta <L16+2+8
|
||||
323 00:0125: A5 03 lda <L16+1
|
||||
324 00:0127: 85 0B sta <L16+1+8
|
||||
325 00:0129: 2B pld
|
||||
326 00:012A: 3B tsc
|
||||
327 00:012B: 18 clc
|
||||
328 00:012C: 69 0A 00 adc #L16+8
|
||||
329 00:012F: 1B tcs
|
||||
330 00:0130: 98 tya
|
||||
331 00:0131: 6B rtl
|
||||
332 ; return dcb.transferCount;
|
||||
333 L10004:
|
||||
Tue Jan 17 2017 23:30 Page 7
|
||||
|
||||
|
||||
334 00:0132: AD xx xx lda |L10003+12
|
||||
335 00:0135: 82 E8 FF brl L19
|
||||
336 ;}
|
||||
337 00000002 L16 equ 2
|
||||
338 00000001 L17 equ 1
|
||||
339 ends
|
||||
340 efunc
|
||||
341 ;
|
||||
342 ;long lseek(int fd, long offset, int whence) {
|
||||
343 code
|
||||
344 xdef ~~lseek
|
||||
345 func
|
||||
346 ~~lseek:
|
||||
347 longa on
|
||||
348 longi on
|
||||
349 00:0138: 3B tsc
|
||||
350 00:0139: 38 sec
|
||||
351 00:013A: E9 00 00 sbc #L20
|
||||
352 00:013D: 1B tcs
|
||||
353 00:013E: 0B phd
|
||||
354 00:013F: 5B tcd
|
||||
355 00000004 fd_0 set 4
|
||||
356 00000006 offset_0 set 6
|
||||
357 0000000A whence_0 set 10
|
||||
358 ; return -1;
|
||||
359 00:0140: A9 FF FF lda #$ffff
|
||||
360 00:0143: AA tax
|
||||
361 00:0144: A9 FF FF lda #$ffff
|
||||
362 L22:
|
||||
363 00:0147: A8 tay
|
||||
364 00:0148: A5 02 lda <L20+2
|
||||
365 00:014A: 85 0A sta <L20+2+8
|
||||
366 00:014C: A5 01 lda <L20+1
|
||||
367 00:014E: 85 09 sta <L20+1+8
|
||||
368 00:0150: 2B pld
|
||||
369 00:0151: 3B tsc
|
||||
370 00:0152: 18 clc
|
||||
371 00:0153: 69 08 00 adc #L20+8
|
||||
372 00:0156: 1B tcs
|
||||
373 00:0157: 98 tya
|
||||
374 00:0158: 6B rtl
|
||||
375 ;}
|
||||
376 00000000 L20 equ 0
|
||||
377 00000001 L21 equ 1
|
||||
378 ends
|
||||
379 efunc
|
||||
380 ;
|
||||
381 ;int creat(const char *name, int mode) {
|
||||
382 code
|
||||
383 xdef ~~creat
|
||||
384 func
|
||||
385 ~~creat:
|
||||
386 longa on
|
||||
387 longi on
|
||||
388 00:0159: 3B tsc
|
||||
389 00:015A: 38 sec
|
||||
390 00:015B: E9 00 00 sbc #L23
|
||||
391 00:015E: 1B tcs
|
||||
Tue Jan 17 2017 23:30 Page 8
|
||||
|
||||
|
||||
392 00:015F: 0B phd
|
||||
393 00:0160: 5B tcd
|
||||
394 00000004 name_0 set 4
|
||||
395 00000008 mode_0 set 8
|
||||
396 ; return -1;
|
||||
397 00:0161: A9 FF FF lda #$ffff
|
||||
398 L25:
|
||||
399 00:0164: A8 tay
|
||||
400 00:0165: A5 02 lda <L23+2
|
||||
401 00:0167: 85 08 sta <L23+2+6
|
||||
402 00:0169: A5 01 lda <L23+1
|
||||
403 00:016B: 85 07 sta <L23+1+6
|
||||
404 00:016D: 2B pld
|
||||
405 00:016E: 3B tsc
|
||||
406 00:016F: 18 clc
|
||||
407 00:0170: 69 06 00 adc #L23+6
|
||||
408 00:0173: 1B tcs
|
||||
409 00:0174: 98 tya
|
||||
410 00:0175: 6B rtl
|
||||
411 ;}
|
||||
412 00000000 L23 equ 0
|
||||
413 00000001 L24 equ 1
|
||||
414 ends
|
||||
415 efunc
|
||||
416 ;
|
||||
417 ;int unlink(const char *name) {
|
||||
418 code
|
||||
419 xdef ~~unlink
|
||||
420 func
|
||||
421 ~~unlink:
|
||||
422 longa on
|
||||
423 longi on
|
||||
424 00:0176: 3B tsc
|
||||
425 00:0177: 38 sec
|
||||
426 00:0178: E9 00 00 sbc #L26
|
||||
427 00:017B: 1B tcs
|
||||
428 00:017C: 0B phd
|
||||
429 00:017D: 5B tcd
|
||||
430 00000004 name_0 set 4
|
||||
431 ; return -1;
|
||||
432 00:017E: A9 FF FF lda #$ffff
|
||||
433 L28:
|
||||
434 00:0181: A8 tay
|
||||
435 00:0182: A5 02 lda <L26+2
|
||||
436 00:0184: 85 06 sta <L26+2+4
|
||||
437 00:0186: A5 01 lda <L26+1
|
||||
438 00:0188: 85 05 sta <L26+1+4
|
||||
439 00:018A: 2B pld
|
||||
440 00:018B: 3B tsc
|
||||
441 00:018C: 18 clc
|
||||
442 00:018D: 69 04 00 adc #L26+4
|
||||
443 00:0190: 1B tcs
|
||||
444 00:0191: 98 tya
|
||||
445 00:0192: 6B rtl
|
||||
446 ;}
|
||||
447 00000000 L26 equ 0
|
||||
448 00000001 L27 equ 1
|
||||
449 ends
|
||||
Tue Jan 17 2017 23:30 Page 9
|
||||
|
||||
|
||||
450 efunc
|
||||
451 ;
|
||||
452 ;int isatty(int fd) {
|
||||
453 code
|
||||
454 xdef ~~isatty
|
||||
455 func
|
||||
456 ~~isatty:
|
||||
457 longa on
|
||||
458 longi on
|
||||
459 00:0193: 3B tsc
|
||||
460 00:0194: 38 sec
|
||||
461 00:0195: E9 00 00 sbc #L29
|
||||
462 00:0198: 1B tcs
|
||||
463 00:0199: 0B phd
|
||||
464 00:019A: 5B tcd
|
||||
465 00000004 fd_0 set 4
|
||||
466 ; return -1;
|
||||
467 00:019B: A9 FF FF lda #$ffff
|
||||
468 L31:
|
||||
469 00:019E: A8 tay
|
||||
470 00:019F: A5 02 lda <L29+2
|
||||
471 00:01A1: 85 04 sta <L29+2+2
|
||||
472 00:01A3: A5 01 lda <L29+1
|
||||
473 00:01A5: 85 03 sta <L29+1+2
|
||||
474 00:01A7: 2B pld
|
||||
475 00:01A8: 3B tsc
|
||||
476 00:01A9: 18 clc
|
||||
477 00:01AA: 69 02 00 adc #L29+2
|
||||
478 00:01AD: 1B tcs
|
||||
479 00:01AE: 98 tya
|
||||
480 00:01AF: 6B rtl
|
||||
481 ;}
|
||||
482 00000000 L29 equ 0
|
||||
483 00000001 L30 equ 1
|
||||
484 ends
|
||||
485 efunc
|
||||
486 ;
|
||||
487 ;
|
||||
488 ;#pragma section udata=heap
|
||||
489 heap section
|
||||
490 00:0000: ends
|
||||
491 ;char __heap[8192];
|
||||
492 ;void *heap_start = (void *)__heap;
|
||||
493 data
|
||||
494 xdef ~~heap_start
|
||||
495 ~~heap_start:
|
||||
496 00:001A: xx xx xx xx dl ~~__heap
|
||||
497 00:001E: ends
|
||||
498 ;void *heap_end = (void *)&__heap[8092];
|
||||
499 data
|
||||
500 xdef ~~heap_end
|
||||
501 ~~heap_end:
|
||||
502 00:001E: xx xx xx xx dl ~~__heap+8092
|
||||
503 00:0022: ends
|
||||
504 ;
|
||||
505 xref ~~fputs
|
||||
506 xref ~~fopen
|
||||
507 xref ~~fclose
|
||||
Tue Jan 17 2017 23:30 Page 10
|
||||
|
||||
|
||||
508 heap
|
||||
509 xdef ~~__heap
|
||||
510 ~~__heap
|
||||
511 00:0000: ds 8192
|
||||
512 00:2000: ends
|
||||
513 xref ~~_iob
|
||||
514 end
|
||||
|
||||
|
||||
Lines assembled: 514
|
||||
Errors: 0
|
BIN
samples/stdio_test.obj
Normal file
BIN
samples/stdio_test.obj
Normal file
Binary file not shown.
20
set_file_type.cpp
Normal file
20
set_file_type.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <system_error>
|
||||
#include <afp/finder_info.h>
|
||||
|
||||
|
||||
int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type) {
|
||||
|
||||
afp::finder_info fi;
|
||||
std::error_code ec;
|
||||
|
||||
if (!fi.open(path, afp::finder_info::read_write, ec))
|
||||
return -1;
|
||||
|
||||
fi.set_prodos_file_type(file_type, aux_type);
|
||||
if (!fi.write(ec))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
static constexpr const int equ_type = (ST_EQU << 4) | S_ABS;
|
||||
|
||||
zrdz_disassembler::zrdz_disassembler(std::vector<section> &§ions, std::vector<symbol> &&symbols) :
|
||||
_symbols(std::move(symbols))
|
||||
zrdz_disassembler::zrdz_disassembler(std::vector<section> &§ions, std::vector<symbol> &&symbols) :
|
||||
disassembler(wdc), _symbols(std::move(symbols))
|
||||
{
|
||||
|
||||
// do not sort _symbols ... order matters for lookup by entry number.
|
||||
|
@ -91,10 +91,10 @@ void zrdz_disassembler::front_matter(const std::string &module) {
|
|||
if ((e.flags & SEC_REF_ONLY) == 0) continue;
|
||||
if (e.size == 0 && e.symbols.empty()) continue;
|
||||
|
||||
e.processed = true;
|
||||
print_section(e);
|
||||
print_globals(e.number);
|
||||
print_equs(e.number);
|
||||
e.processed = true;
|
||||
|
||||
if (e.org) emit("", ".org", to_x(e.org, 4, '$'));
|
||||
uint32_t pc = e.org;
|
||||
|
@ -374,3 +374,21 @@ std::string zrdz_disassembler::symbol_name(unsigned entry) const {
|
|||
}
|
||||
return _symbols[entry].name;
|
||||
}
|
||||
|
||||
std::string zrdz_disassembler::section_name(unsigned section) const {
|
||||
|
||||
std::string defname = std::string("section") + std::to_string(section);
|
||||
|
||||
if (section >= _sections.size()) {
|
||||
warnx("Invalid section %d", section);
|
||||
return defname;
|
||||
}
|
||||
auto &e = _sections[section];
|
||||
if (!e.valid) {
|
||||
warnx("Invalid section %d", section);
|
||||
return defname;
|
||||
}
|
||||
|
||||
return e.name;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
|
||||
std::string location_name(unsigned section, uint32_t offset) const;
|
||||
std::string symbol_name(unsigned entry) const;
|
||||
std::string section_name(unsigned entry) const;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user