Compare commits

...

100 Commits
r1 ... master

Author SHA1 Message Date
Kelvin Sherlock
a455e48a2b v1 omf support (-1), improved big endian support, -S to convert PAGE0 to a stack segment. 2022-12-15 21:13:08 -05:00
Kelvin Sherlock
65d373be25 improved usage information. 2022-12-15 21:11:38 -05:00
Kelvin Sherlock
42347e4d40 bump github actions 2022-12-15 21:10:46 -05:00
ksherlock
3ab26264f6
_XOPEN_SOURCE 2020-11-18 15:17:14 -05:00
Kelvin Sherlock
9430f99270 replace _S since it is used in msys ctype.h 2020-11-18 12:37:38 -05:00
ksherlock
32495371de
Update msys2.yml 2020-11-17 22:33:39 -05:00
ksherlock
8ff374eced
Update msys2.yml 2020-11-17 22:26:48 -05:00
ksherlock
b9ce1e2d3f
Update msys2.yml 2020-11-17 22:13:01 -05:00
ksherlock
ec6619c8c7
Update msys2.yml 2020-11-17 22:02:50 -05:00
ksherlock
2364cae06a
Update msys2.yml 2020-11-17 21:46:06 -05:00
ksherlock
9fa57d0a12
Update msys2.yml 2020-11-17 16:11:46 -05:00
ksherlock
ae182abaa4
Update msys2.yml 2020-11-17 16:07:41 -05:00
ksherlock
66cf463cbf
Update msys2.yml 2020-11-17 15:51:01 -05:00
ksherlock
e7720a69bb
Update make.yml 2020-11-17 15:49:55 -05:00
ksherlock
d66de57273
Create msys2.yml 2020-11-17 15:45:51 -05:00
Kelvin Sherlock
ab5961c1a9 bump submodule. 2020-11-12 13:04:41 -05:00
ksherlock
d3df7b2c47
Create make.yml 2020-11-12 10:24:16 -05:00
Kelvin Sherlock
885fcc7958 bug fixes/enhancements found when testing with merlin
* super page calculation was off by 1
* (untested) binary file generation
* reserved space support
* alignment support
* loadname support.
2019-12-22 16:48:18 -05:00
Kelvin Sherlock
db1d452f53 Merge branch 'master' of https://github.com/ksherlock/wdc-utils 2019-12-14 19:09:59 -05:00
Kelvin Sherlock
236dc538b0 bug fixes.
- didn't generate SUPER for 3-byte, no shift interseg
- labels not properly truncated at 255.
2019-12-14 19:09:47 -05:00
ksherlock
8147da2cfc
Update .travis.yml 2019-12-10 13:40:45 -05:00
Kelvin Sherlock
5f9d1a900d headers for gcc. 2017-08-12 23:11:06 -04:00
Kelvin Sherlock
348b97669b use disassembler traits 2017-08-12 22:01:41 -04:00
Kelvin Sherlock
606747cba3 updates from omm disassembler. 2017-08-12 21:58:47 -04:00
Kelvin Sherlock
4f833d83a6 bump submodule 2017-08-08 21:46:34 -04:00
Kelvin Sherlock
285763c318 bump submodule. 2017-08-08 20:33:39 -04:00
Kelvin Sherlock
7c07cbcd17 use submodule for finder info. 2017-08-08 20:16:58 -04:00
Kelvin Sherlock
1e810db107 Merge branch 'master' of git://qnap.local/wdcdumpobj 2017-08-08 15:00:06 -04:00
Kelvin Sherlock
13389be323 fix typo. 2017-08-08 14:59:40 -04:00
Kelvin Sherlock
2f2809dcb2 remove dead code 2017-08-08 14:59:34 -04:00
Kelvin Sherlock
b9092401f6 mingw32 makefile 2017-03-11 11:48:21 -05:00
Kelvin Sherlock
b18467a641 disassembler updates. 2017-03-06 00:47:01 -05:00
Kelvin Sherlock
7f3ccd84c8 commentary. 2017-03-06 00:40:00 -05:00
Kelvin Sherlock
ebd67dc0cc update finder_info_helper. 2017-03-06 00:39:50 -05:00
Kelvin Sherlock
97787b30e4 sync finder_info_helper. 2017-01-24 16:28:40 -05:00
Kelvin Sherlock
e81e47d4c8 win32/afp compile 2017-01-24 12:16:39 -05:00
Kelvin Sherlock
e43ace0d1c use finder_info_helper. 2017-01-23 10:02:50 -05:00
Kelvin Sherlock
06a3c5b5ae properly initialize afp backup date. 2017-01-21 15:05:01 -05:00
Kelvin Sherlock
4e51bd6c51 reserve symbol code (unused) 2017-01-21 12:43:18 -05:00
Kelvin Sherlock
466c90a34e use unordered_map for library symbol table. 2017-01-21 12:42:53 -05:00
Kelvin Sherlock
253a3ccc49 delay adding a symbol for the section name. 2017-01-21 00:11:55 -05:00
Kelvin Sherlock
e9383cfcdc gcc… 2017-01-20 22:47:45 -05:00
Kelvin Sherlock
b29b208b06 add _BEG_xxx / _END_xxx symbols for all sections. 2017-01-20 22:12:44 -05:00
Kelvin Sherlock
dd0a369ac1 generate full section header for ref-only sections 2017-01-20 10:33:00 -05:00
Kelvin Sherlock
e693ad8ef3 more fixes... 2017-01-17 23:31:28 -05:00
Kelvin Sherlock
91d7f60bff fix stdio test some more. 2017-01-17 23:25:09 -05:00
Kelvin Sherlock
47130d0e67 fix stdio 2017-01-17 23:14:55 -05:00
Kelvin Sherlock
bcb2ba03ef updated stdio test. 2017-01-17 23:06:12 -05:00
Kelvin Sherlock
18c9ede89f tweak library headers, add missing expression operands. 2017-01-17 19:57:37 -05:00
Kelvin Sherlock
c08c84c593 expr_error - handle precedence when pretty-printing expression.
sanity check the expression can reduce to a single value when parsing.
2017-01-17 19:47:19 -05:00
Kelvin Sherlock
adafabd419 Merge branch 'master' of https://github.com/ksherlock/wdc-utils 2017-01-16 20:56:41 -05:00
Kelvin Sherlock
6aa7418561 remove dead code, fix expression location adjustment. 2017-01-16 20:55:36 -05:00
Kelvin Sherlock
ef838227d2 remove dead code, fix expression location adjustment. 2017-01-16 20:55:24 -05:00
Kelvin Sherlock
7e09ecd5f2 fix section to segment remap bugs when creating the omf file. 2017-01-16 20:17:58 -05:00
Kelvin Sherlock
eed6958275 fix link bug with custom segments. 2017-01-16 16:16:33 -05:00
Kelvin Sherlock
03f24ec829 fix make clean. 2017-01-16 16:15:05 -05:00
Kelvin Sherlock
6b99d138a2 expression simplification was sometimes leaving data on the stack. 2017-01-16 16:14:56 -05:00
Kelvin Sherlock
5db92377d6 resize buffer before reading, don’t just reserve it. 2017-01-16 16:14:18 -05:00
Kelvin Sherlock
8ba832d9a9 update c library test. 2017-01-16 14:02:34 -05:00
Kelvin Sherlock
e4e6febf7d test object for library linkage. 2017-01-16 11:26:35 -05:00
Kelvin Sherlock
d5105336dd linux compile. 2017-01-15 22:02:30 -05:00
Kelvin Sherlock
ac071f1d9a pretty-print erroneous expressions, fix undefined symbol bug. 2017-01-15 21:54:59 -05:00
Kelvin Sherlock
7c71a97550 linker library support [WIP] 2017-01-15 21:21:33 -05:00
Kelvin Sherlock
6aa54979a9 gcc 5 doesn't support enum : uint8_t... 2017-01-13 12:16:30 -05:00
Kelvin Sherlock
add8545906 linker now generates SUPER records. 2017-01-13 10:39:02 -05:00
Kelvin Sherlock
25e6e61989 generate super records… 2017-01-13 00:33:44 -05:00
Kelvin Sherlock
6d1e684f8d optional emplacement. 2017-01-13 00:33:21 -05:00
Kelvin Sherlock
61c3b82aaf endian.h 2017-01-13 00:33:06 -05:00
Kelvin Sherlock
4317d2929b clean up expression to omf errors. 2017-01-12 21:32:11 -05:00
Kelvin Sherlock
2ff8267af3 beginning support for SUPER relocation records. 2017-01-12 20:56:09 -05:00
Kelvin Sherlock
ff09d63678 support for relative expressions. 2017-01-12 20:55:47 -05:00
Kelvin Sherlock
11bce44253 more samples 2017-01-12 12:27:32 -05:00
Kelvin Sherlock
9de248b599 gccism 2017-01-11 20:37:03 -05:00
Kelvin Sherlock
e3b555b0cc -t xx,xxxx for filetype/auxtype. 2017-01-11 20:17:06 -05:00
Kelvin Sherlock
38e4f135ac compile w/ windows 2017-01-11 14:31:15 -05:00
Kelvin Sherlock
75bd907dad compile w/ windows 2017-01-11 14:28:18 -05:00
Kelvin Sherlock
8f2b86b882 set file type. 2017-01-11 14:05:12 -05:00
Kelvin Sherlock
432a023213 generate express load segment. 2017-01-11 00:36:03 -05:00
ksherlock
960170f831 Update .travis.yml
travis ci is outdated shit.
2017-01-10 19:32:29 -05:00
ksherlock
9563e2f8f5 Update .travis.yml
travis ci is horrible outdated.
2017-01-10 16:20:49 -05:00
Kelvin Sherlock
6ff5a4599a add a readme. 2017-01-10 16:16:01 -05:00
Kelvin Sherlock
ec92c3b599 travis ci 2017-01-10 16:10:29 -05:00
Kelvin Sherlock
09628cb2c3 O_BINARY flag. 2017-01-10 15:21:26 -05:00
Kelvin Sherlock
337840cb3c update gitattributes. 2017-01-10 14:16:51 -05:00
Kelvin Sherlock
d54d8f2924 fix line endings. 2017-01-10 14:16:02 -05:00
Kelvin Sherlock
4178be1db1 gitrattributes 2017-01-10 13:52:45 -05:00
Kelvin Sherlock
b35358fdd8 linker compiles and works for simple cases. 2017-01-10 08:36:06 -05:00
Kelvin Sherlock
cef989b17b linker updates [WIP] 2017-01-08 20:17:32 -05:00
Kelvin Sherlock
1deafa3ad1 add c++17 optional 2017-01-08 20:17:10 -05:00
Kelvin Sherlock
eb993acd2a -n flag to inhibit symbol lookup in expressions. 2017-01-08 20:16:32 -05:00
Kelvin Sherlock
966a879419 ref_only test 2017-01-08 12:59:01 -05:00
Kelvin Sherlock
822b685d46 Merge branch 'master' of git://qnap.local/wdcdumpobj 2017-01-08 12:44:23 -05:00
Kelvin Sherlock
2d69c18bd1 two-module hello 2017-01-08 12:44:17 -05:00
Kelvin Sherlock
9b1900c8f7 linker… 2017-01-07 22:19:28 -05:00
Kelvin Sherlock
498738d1a2 Merge branch 'master' of git://qnap.local/wdcdumpobj 2017-01-07 22:18:19 -05:00
Kelvin Sherlock
6d4b9cbd3f white space. 2017-01-07 22:17:30 -05:00
Kelvin Sherlock
c5f2ed5562 link.c now compiles… 2017-01-07 14:04:26 -05:00
Kelvin Sherlock
174acc708c untested linker code… 2017-01-07 13:04:34 -05:00
Kelvin Sherlock
8d63e66e7a linker - relocation expression code. 2017-01-07 13:04:13 -05:00
Kelvin Sherlock
f1e7e0f0e3 mingw64 -- static link so it works without mingw64. 2017-01-06 11:27:49 -05:00
38 changed files with 4838 additions and 424 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.obj binary

17
.github/workflows/make.yml vendored Normal file
View 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
View 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
View File

@ -0,0 +1,3 @@
[submodule "afp"]
path = afp
url = https://github.com/ksherlock/afp

12
.travis.yml Normal file
View File

@ -0,0 +1,12 @@
dist: bionic
language: cpp
os:
- osx
- linux
compiler:
- clang
- gcc
script: make all

View File

@ -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
View 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

@ -0,0 +1 @@
Subproject commit bf4399146d7402a390cad78102d4169e2a41ac04

View File

@ -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();
}

View File

@ -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

View File

@ -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
View 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
View 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
View 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

1846
link.cpp

File diff suppressed because it is too large Load Diff

362
obj816.h
View File

@ -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
View 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
View 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
View 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

View File

@ -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
View 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
View 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

Binary file not shown.

29
samples/hello4.asm Normal file
View 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
View 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

Binary file not shown.

67
samples/ref_only.asm Normal file
View 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
View 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

Binary file not shown.

37
samples/relative.asm Normal file
View 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
View 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

Binary file not shown.

109
samples/stdio_test.c Normal file
View 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
View 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

Binary file not shown.

20
set_file_type.cpp Normal file
View 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;
}

View File

@ -7,8 +7,8 @@
static constexpr const int equ_type = (ST_EQU << 4) | S_ABS;
zrdz_disassembler::zrdz_disassembler(std::vector<section> &&sections, std::vector<symbol> &&symbols) :
_symbols(std::move(symbols))
zrdz_disassembler::zrdz_disassembler(std::vector<section> &&sections, 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;
}

View File

@ -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: