mirror of
https://github.com/ksherlock/wdc-utils.git
synced 2025-02-07 08:30:36 +00:00
linker compiles and works for simple cases.
This commit is contained in:
parent
cef989b17b
commit
b35358fdd8
4
Makefile
4
Makefile
@ -3,7 +3,7 @@ CXXFLAGS = -std=c++14 -g -Wall
|
|||||||
CCFLAGS = -g
|
CCFLAGS = -g
|
||||||
|
|
||||||
DUMP_OBJS = dumpobj.o disassembler.o zrdz_disassembler.o
|
DUMP_OBJS = dumpobj.o disassembler.o zrdz_disassembler.o
|
||||||
LINK_OBJS = link.o expression.o
|
LINK_OBJS = link.o expression.o omf.o
|
||||||
|
|
||||||
#UNAME_S := $(shell uname -s)
|
#UNAME_S := $(shell uname -s)
|
||||||
#ifeq ($(UNAME_S),MINGW64_NT-10.0)
|
#ifeq ($(UNAME_S),MINGW64_NT-10.0)
|
||||||
@ -27,6 +27,8 @@ wdclink : $(LINK_OBJS)
|
|||||||
disassembler.o : disassembler.cpp disassembler.h
|
disassembler.o : disassembler.cpp disassembler.h
|
||||||
zrdz_disassembler.o : zrdz_disassembler.cpp zrdz_disassembler.h disassembler.h
|
zrdz_disassembler.o : zrdz_disassembler.cpp zrdz_disassembler.h disassembler.h
|
||||||
dumpobj.o : dumpobj.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
|
mingw/err.o : mingw/err.c mingw/err.h
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
@ -83,6 +83,7 @@ bool binary_op(unsigned op, std::vector<expr> &v) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// optimization... regardless of where it's located, shifting > 24 bits will result in 0...
|
||||||
if (a.tag == OP_LOC && b.tag == OP_VAL) {
|
if (a.tag == OP_LOC && b.tag == OP_VAL) {
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case OP_ADD: a.value += b.value; return true;
|
case OP_ADD: a.value += b.value; return true;
|
||||||
|
397
link.cpp
397
link.cpp
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#include "obj816.h"
|
#include "obj816.h"
|
||||||
#include "expression.h"
|
#include "expression.h"
|
||||||
|
#include "omf.h"
|
||||||
|
|
||||||
#ifndef O_BINARY
|
#ifndef O_BINARY
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
@ -35,6 +35,9 @@ struct {
|
|||||||
bool _v = false;
|
bool _v = false;
|
||||||
bool _C = false;
|
bool _C = false;
|
||||||
bool _X = false;
|
bool _X = false;
|
||||||
|
bool _S = false;
|
||||||
|
std::string _o;
|
||||||
|
|
||||||
unsigned _errors = 0;
|
unsigned _errors = 0;
|
||||||
} flags;
|
} flags;
|
||||||
|
|
||||||
@ -477,6 +480,7 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
assert(!"unsupported expression opcode.");
|
assert(!"unsupported expression opcode.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sections[current_section].expressions.emplace_back(std::move(e));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,6 +570,8 @@ void init() {
|
|||||||
|
|
||||||
|
|
||||||
void generate_end() {
|
void generate_end() {
|
||||||
|
|
||||||
|
/*
|
||||||
const std::string names[] = {
|
const std::string names[] = {
|
||||||
"_END_PAGE0",
|
"_END_PAGE0",
|
||||||
"_END_CODE",
|
"_END_CODE",
|
||||||
@ -573,158 +579,318 @@ void generate_end() {
|
|||||||
"_END_DATA"
|
"_END_DATA"
|
||||||
"_END_UDATA"
|
"_END_UDATA"
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
for (int i = 0; i < 5; ++i) {
|
for (int i = 0; i < 5; ++i) {
|
||||||
symbol s;
|
symbol s;
|
||||||
s.section = i;
|
s.section = i;
|
||||||
s.type = S_REL;
|
s.type = S_REL;
|
||||||
s.flags = SF_DEF | SF_GBL;
|
s.flags = SF_DEF | SF_GBL;
|
||||||
s.offset = sections[i].data.size();
|
s.offset = sections[i].size; // data.size() doesn't word w/ ref_only
|
||||||
|
|
||||||
symbols[i * 2 + 1] = s;
|
symbols[i * 2 + 1] = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void merge_data() {
|
|
||||||
|
|
||||||
// merge data sections -- kdata, data, udata.
|
std::vector<omf::segment> omf_segments;
|
||||||
// merge custom data sections?
|
|
||||||
|
|
||||||
std::vector<uint8_t> new_data;
|
|
||||||
std::vector<expression> new_expr;
|
|
||||||
|
|
||||||
unsigned new_number = 0;
|
template<class T>
|
||||||
|
void append(std::vector<T> &to, std::vector<T> &from) {
|
||||||
|
to.insert(to.end(),
|
||||||
|
std::make_move_iterator(from.begin()),
|
||||||
|
std::make_move_iterator(from.end())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void append(std::vector<T> &to, const std::vector<T> &from) {
|
||||||
|
to.insert(to.end(),
|
||||||
|
from.begin(),
|
||||||
|
from.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void append(std::vector<T> &to, unsigned count, const T& value) {
|
||||||
|
to.insert(to.end(),
|
||||||
|
count,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert a wdc expression to an omf reloc/interseg record.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void to_omf(const expression &e, omf::segment &seg) {
|
||||||
|
if (e.stack.empty()) return; //?
|
||||||
|
|
||||||
|
if (e.stack.size() == 1 && e.stack[0].tag == OP_VAL) {
|
||||||
|
uint32_t value = e.stack[0].value;
|
||||||
|
|
||||||
|
for(int i = 0; i < e.size; ++i, value >>= 8)
|
||||||
|
seg.data[e.offset + i] = value & 0xff;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.stack.size() == 1 && e.stack[0].tag == OP_LOC) {
|
||||||
|
auto &loc = e.stack[0];
|
||||||
|
|
||||||
|
uint32_t value = loc.value;
|
||||||
|
|
||||||
|
if (loc.section == 0) {
|
||||||
|
warnx("Unable to relocate (invalid segment).");
|
||||||
|
flags._errors++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (loc.section == seg.segnum) {
|
||||||
|
omf::reloc r;
|
||||||
|
r.size = e.size;
|
||||||
|
r.offset = e.offset;
|
||||||
|
r.value = value;
|
||||||
|
|
||||||
|
// also store value in data
|
||||||
|
for (int i = 0; i < e.size; ++i, value >>= 8)
|
||||||
|
seg.data[e.offset + i] = value & 0xff;
|
||||||
|
|
||||||
|
seg.relocs.emplace_back(r);
|
||||||
|
} else {
|
||||||
|
omf::interseg r;
|
||||||
|
r.size = e.size;
|
||||||
|
r.offset = e.offset;
|
||||||
|
r.segment = loc.section;
|
||||||
|
r.segment_offset = loc.value;
|
||||||
|
|
||||||
|
seg.intersegs.emplace_back(r);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.stack.size() == 3
|
||||||
|
&& e.stack[0].tag == OP_LOC
|
||||||
|
&& e.stack[1].tag == OP_VAL
|
||||||
|
&& (e.stack[2].tag == OP_SHL || e.stack[2].tag == OP_SHR)) {
|
||||||
|
|
||||||
|
auto &loc = e.stack[0];
|
||||||
|
auto &shift = e.stack[1];
|
||||||
|
auto &op = e.stack[2];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (shift.value > 24) {
|
||||||
|
warnx("shift %d", shift.value);
|
||||||
|
for(int i = 0; i < e.size; ++i)
|
||||||
|
seg.data[e.offset +i] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (loc.section == 0) {
|
||||||
|
warnx("Unable to relocate expression (invalid segment).");
|
||||||
|
flags._errors++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t value = loc.value;
|
||||||
|
uint8_t shift_value = shift.value;
|
||||||
|
if (op.tag == OP_SHR) {
|
||||||
|
value >>= shift_value;
|
||||||
|
shift_value = -shift_value;
|
||||||
|
} else {
|
||||||
|
value <<= shift_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loc.section == seg.segnum) {
|
||||||
|
omf::reloc r;
|
||||||
|
r.size = e.size;
|
||||||
|
r.offset = e.offset;
|
||||||
|
r.value = loc.value;
|
||||||
|
r.shift = shift_value;
|
||||||
|
|
||||||
|
// also store value in data
|
||||||
|
for (int i = 0; i < e.size; ++i, value >>= 8)
|
||||||
|
seg.data[e.offset + i] = value & 0xff;
|
||||||
|
|
||||||
|
seg.relocs.emplace_back(r);
|
||||||
|
} else {
|
||||||
|
omf::interseg r;
|
||||||
|
r.size = e.size;
|
||||||
|
r.offset = e.offset;
|
||||||
|
r.segment = loc.section;
|
||||||
|
r.segment_offset = loc.value;
|
||||||
|
r.shift = shift_value;
|
||||||
|
|
||||||
|
seg.intersegs.emplace_back(r);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warnx("Relocation expression too complex.");
|
||||||
|
flags._errors++;
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void build_omf_segments() {
|
||||||
|
|
||||||
|
|
||||||
|
std::vector< std::pair<unsigned, uint32_t> > remap;
|
||||||
|
|
||||||
|
remap.resize(sections.size());
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (!flags._X) {
|
||||||
|
// create an expressload segments.
|
||||||
|
// (should verify it's expressable later...)
|
||||||
|
omf::segment seg;
|
||||||
|
seg.segnum = omf_segments.size()+ 1;
|
||||||
|
seg.kind = 0x8001; // dynamic data segment
|
||||||
|
seg.segname = "~ExpressLoad";
|
||||||
|
|
||||||
|
omf_segments.emplace_back(std::move(seg));
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// if data + code can fit in one bank, merge them
|
||||||
|
// otherwise, merge all data sections and 1 omf segment
|
||||||
|
// per code section.
|
||||||
|
|
||||||
|
// code is next segment...
|
||||||
|
unsigned code_segment = 0;
|
||||||
|
unsigned data_segment = 0;
|
||||||
|
{
|
||||||
|
omf_segments.emplace_back();
|
||||||
|
auto &seg = omf_segments.back();
|
||||||
|
|
||||||
|
code_segment = data_segment = seg.segnum = omf_segments.size();
|
||||||
|
seg.kind = 0x0000; // static code segment.
|
||||||
|
|
||||||
|
auto &s = sections[SECT_CODE];
|
||||||
|
|
||||||
|
remap[s.number] = std::make_pair(code_segment, 0);
|
||||||
|
append(seg.data, s.data);
|
||||||
|
s.data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint32_t total_data_size = 0;
|
|
||||||
uint32_t total_code_size = 0;
|
uint32_t total_code_size = 0;
|
||||||
unsigned data_sections = 0;
|
uint32_t total_data_size = 0;
|
||||||
unsigned code_sections = 0;
|
|
||||||
|
|
||||||
for (const auto &s : sections) {
|
for (const auto &s : sections) {
|
||||||
if (s.flags & SEC_REF_ONLY) continue;
|
if (s.flags & SEC_REF_ONLY) continue;
|
||||||
if (s.flags & SEC_DATA) {
|
if (s.flags & SEC_DATA) {
|
||||||
total_data_size += s.data.size();
|
total_data_size += s.size;
|
||||||
data_sections++;
|
} else {
|
||||||
}
|
total_code_size += s.size;
|
||||||
else {
|
|
||||||
if (s.data.size() > 0xffff) {
|
|
||||||
flags._errors++;
|
|
||||||
warnx("code section %s ($%04x) exceeds bank size.",
|
|
||||||
s.name.c_str(), (uint32_t)s.data.size());
|
|
||||||
}
|
|
||||||
total_code_size += s.data.size();
|
|
||||||
code_sections++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add in udata...
|
// add in UDATA
|
||||||
total_data_size += sections[SECT_UDATA].size;
|
total_data_size += sections[SECT_UDATA].size;
|
||||||
|
|
||||||
|
if (total_data_size + sections[SECT_CODE].size > 0xffff) {
|
||||||
|
|
||||||
if (sections[SECT_CODE].data.size() + total_data_size < 0xffff) {
|
omf_segments.emplace_back();
|
||||||
auto &s = sections[SECT_CODE];
|
|
||||||
new_number = SECT_CODE;
|
auto &seg = omf_segments.back();
|
||||||
new_data = std::move(s.data);
|
data_segment = seg.segnum = omf_segments.size();
|
||||||
new_expr = std::move(s.expressions);
|
seg.kind = 0x0001; // static data segment.
|
||||||
s.data.clear();
|
|
||||||
s.expressions.clear();
|
|
||||||
} else {
|
|
||||||
new_number = SECT_DATA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//omf::segment &code_seg = omf_segments[code_segment-1];
|
||||||
// new section, offset fudge pair.
|
omf::segment &data_seg = omf_segments[data_segment-1];
|
||||||
std::vector< std::pair<unsigned, uint32_t> > remap;
|
|
||||||
remap.reserve(sections.size());
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < sections.size(); ++i)
|
|
||||||
remap.emplace_back(std::make_pair(i, 0));
|
|
||||||
|
|
||||||
|
|
||||||
if (total_data_size > 0xffff) {
|
|
||||||
warnx("total data ($%04x) exceeds bank size,", total_data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// merge all code sections?
|
|
||||||
if (total_code_size <= 0xffff && code_sections > 0) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
// KDATA, DATA, UDATA, other segment order.
|
||||||
for (auto &s : sections) {
|
for (auto &s : sections) {
|
||||||
if (s.flags & SEC_REF_ONLY) continue;
|
if (s.flags & SEC_REF_ONLY) continue;
|
||||||
if ((s.flags & SEC_DATA) == 0) continue;
|
if ((s.flags & SEC_DATA) == 0) continue;
|
||||||
|
|
||||||
uint32_t offset = new_data.size();
|
remap[s.number] = std::make_pair(data_segment, data_seg.data.size());
|
||||||
remap[s.number] = std::make_pair(new_number, offset);
|
|
||||||
new_data.insert(new_data.end(), s.data.begin(), s.data.end());
|
|
||||||
new_expr.insert(new_expr.end(),
|
|
||||||
std::make_move_iterator(s.expressions.begin()),
|
|
||||||
std::make_move_iterator(s.expressions.end())
|
|
||||||
);
|
|
||||||
|
|
||||||
// preserve the name and flags.
|
append(data_seg.data, s.data);
|
||||||
s.data.clear();
|
s.data.clear();
|
||||||
s.expressions.clear();
|
|
||||||
s.size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add in SECT_UDATA
|
// add in UDATA
|
||||||
{
|
{
|
||||||
auto &s = sections[SECT_UDATA];
|
auto &s = sections[SECT_UDATA];
|
||||||
uint32_t offset = new_data.size();
|
remap[s.number] = std::make_pair(data_segment, data_seg.data.size());
|
||||||
|
append(data_seg.data, s.size, (uint8_t)0);
|
||||||
remap[s.number] = std::make_pair(new_number, offset);
|
|
||||||
// reference only -- no expressions or data.
|
|
||||||
new_data.insert(new_data.end(), s.size, 0);
|
|
||||||
|
|
||||||
s.size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
// for all other sections, create a new segment.
|
||||||
auto &s = sections[new_number];
|
|
||||||
s.size = new_data.size();
|
|
||||||
s.data = std::move(new_data);
|
|
||||||
s.expressions = std::move(new_expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// now remap symbols
|
|
||||||
for (auto &s : symbols) {
|
|
||||||
if ((s.type & 0x0f) == S_REL) {
|
|
||||||
auto x = remap[s.section];
|
|
||||||
s.section = x.first;
|
|
||||||
s.offset += x.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// and expressions...
|
|
||||||
|
|
||||||
// update expressions with new section / offset.
|
|
||||||
for (auto &s : sections) {
|
for (auto &s : sections) {
|
||||||
|
if (s.flags & SEC_REF_ONLY) continue;
|
||||||
|
if (s.flags & SEC_DATA) continue;
|
||||||
|
if (s.number == SECT_CODE) continue;
|
||||||
|
|
||||||
|
omf::segment seg;
|
||||||
|
seg.segnum = omf_segments.size() + 1;
|
||||||
|
seg.kind = 0x0000; // static code.
|
||||||
|
seg.data = std::move(s.data);
|
||||||
|
seg.segname = s.name;
|
||||||
|
s.data.clear();
|
||||||
|
|
||||||
|
remap[s.number] = std::make_pair(seg.segnum, 0);
|
||||||
|
|
||||||
|
omf_segments.emplace_back(std::move(seg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// add a stack segment at the end
|
||||||
|
if (flags._S) {
|
||||||
|
auto &s = sections[SECT_PAGE0];
|
||||||
|
|
||||||
|
// create stack/dp segment.
|
||||||
|
uint32_t size = s.size;
|
||||||
|
if (size) {
|
||||||
|
// ????
|
||||||
|
size = (size + 255) & ~255;
|
||||||
|
|
||||||
|
omf::segment seg;
|
||||||
|
seg.segnum = omf_segments.size() + 1;
|
||||||
|
seg.kind = 0x12; // static dp/stack segment.
|
||||||
|
seg.data.resize(size, 0);
|
||||||
|
seg.loadname = "~Stack";
|
||||||
|
omf_segments.emplace_back(std::move(seg));
|
||||||
|
|
||||||
|
// remap SECT_PAGE0...
|
||||||
|
remap[s.number] = std::make_pair(seg.segnum, 0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
warnx("page0 is 0 sized. Stack/dp segment not created.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now adjust all the expressions, simplify, and convert to reloc records.
|
||||||
|
for (auto &s :sections) {
|
||||||
for (auto &e : s.expressions) {
|
for (auto &e : s.expressions) {
|
||||||
bool delta = false;
|
|
||||||
for (auto &t : e.stack) {
|
for (auto &t : e.stack) {
|
||||||
if (t.tag == OP_LOC) {
|
if (t.tag == OP_LOC) {
|
||||||
auto x = remap[t.section];
|
const auto &x = remap[t.section];
|
||||||
if (x.first != t.section || x.second != 0) {
|
|
||||||
delta = true;
|
|
||||||
t.section = x.first;
|
t.section = x.first;
|
||||||
t.value += x.second;
|
t.value += x.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
simplify_expression(e);
|
||||||
if (delta) simplify_expression(e);
|
to_omf(e, omf_segments[s.number-1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// and we're done...
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool one_file(const std::string &name) {
|
bool one_file(const std::string &name) {
|
||||||
|
|
||||||
int fd = open(name.c_str(), O_RDONLY | O_BINARY);
|
int fd = open(name.c_str(), O_RDONLY | O_BINARY);
|
||||||
@ -855,10 +1021,6 @@ void usage() {
|
|||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
std::string _o;
|
|
||||||
bool _C = false;
|
|
||||||
bool _X = false;
|
|
||||||
|
|
||||||
std::vector<std::string> _l;
|
std::vector<std::string> _l;
|
||||||
std::vector<std::string> _L;
|
std::vector<std::string> _L;
|
||||||
|
|
||||||
@ -867,9 +1029,9 @@ int main(int argc, char **argv) {
|
|||||||
while ((c = getopt(argc, argv, "vCXL:l:o:")) != -1) {
|
while ((c = getopt(argc, argv, "vCXL:l:o:")) != -1) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'v': flags._v = true; break;
|
case 'v': flags._v = true; break;
|
||||||
case 'X': _X = true; break;
|
case 'X': flags._X = true; break;
|
||||||
case 'C': _C = true; break;
|
case 'C': flags._C = true; break;
|
||||||
case 'o': _o = optarg; break;
|
case 'o': flags._o = optarg; break;
|
||||||
case 'l': _l.emplace_back(optarg); break;
|
case 'l': _l.emplace_back(optarg); break;
|
||||||
case 'L': _L.emplace_back(optarg); break;
|
case 'L': _L.emplace_back(optarg); break;
|
||||||
case 'h': help(); break;
|
case 'h': help(); break;
|
||||||
@ -905,7 +1067,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
|
|
||||||
if (flags._v) {
|
if (flags._v) {
|
||||||
for (auto &s : sections) {
|
for (const auto &s : sections) {
|
||||||
//if (s.flags & SEC_REF_ONLY) continue;
|
//if (s.flags & SEC_REF_ONLY) continue;
|
||||||
printf("section %3d %-20s $%04x $%04x\n",
|
printf("section %3d %-20s $%04x $%04x\n",
|
||||||
s.number, s.name.c_str(), (uint32_t)s.data.size(), s.size);
|
s.number, s.name.c_str(), (uint32_t)s.data.size(), s.size);
|
||||||
@ -913,16 +1075,27 @@ int main(int argc, char **argv) {
|
|||||||
fputs("\n", stdout);
|
fputs("\n", stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
merge_data();
|
build_omf_segments();
|
||||||
|
|
||||||
if (flags._v) {
|
if (flags._v) {
|
||||||
for (auto &s : sections) {
|
for (const auto &s : omf_segments) {
|
||||||
//if (s.flags & SEC_REF_ONLY) continue;
|
printf("segment %3d %-20s $%04x\n",
|
||||||
printf("section %3d %-20s $%04x $%04x\n",
|
s.segnum, s.segname.c_str(), (uint32_t)s.data.size());
|
||||||
s.number, s.name.c_str(), (uint32_t)s.data.size(), s.size);
|
|
||||||
|
for (auto &r : s.relocs) {
|
||||||
|
printf(" %02x %02x %06x %06x\n",
|
||||||
|
r.size, r.shift, r.offset, r.value);
|
||||||
}
|
}
|
||||||
fputs("\n", stdout);
|
for (auto &r : s.intersegs) {
|
||||||
|
printf(" %02x %02x %06x %02x %04x %06x\n",
|
||||||
|
r.size, r.shift, r.offset, r.file, r.segment, r.segment_offset);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_omf(std::vector<omf::segment> &segments, bool expressload, const std::string &path);
|
||||||
|
|
||||||
|
save_omf(omf_segments, false, "out.omf");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
147
omf.cpp
Normal file
147
omf.cpp
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#include "omf.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <sysexits.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
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.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void save_omf(std::vector<omf::segment> &segments, bool expressload, const std::string &path) {
|
||||||
|
|
||||||
|
if (expressload) {
|
||||||
|
for (auto &s : segments) {
|
||||||
|
s.segnum++;
|
||||||
|
for (auto &r : s.intersegs) r.segment++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
|
if (fd < 0) {
|
||||||
|
err(EX_CANTCREAT, "Unable to open %s", path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (auto &s : segments) {
|
||||||
|
omf_header h;
|
||||||
|
h.length = s.data.size();
|
||||||
|
h.kind = s.kind;
|
||||||
|
h.banksize = s.data.size() > 0xffff ? 0x0000 : 0x010000;
|
||||||
|
h.segnum = s.segnum;
|
||||||
|
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
// push segname and load name onto data.
|
||||||
|
data.insert(data.end(), 10, ' ');
|
||||||
|
push(data, s.segname);
|
||||||
|
|
||||||
|
h.dispname = sizeof(omf_header);
|
||||||
|
h.dispdata = sizeof(omf_header) + data.size();
|
||||||
|
|
||||||
|
//lconst record
|
||||||
|
push(data, (uint8_t)0xf2);
|
||||||
|
push(data, (uint32_t)h.length);
|
||||||
|
data.insert(data.end(), s.data.begin(), s.data.end());
|
||||||
|
|
||||||
|
// should interseg/reloc records be sorted?
|
||||||
|
// todo -- compress into super records.
|
||||||
|
for (const auto &r : s.relocs) {
|
||||||
|
if (r.can_compress()) {
|
||||||
|
push(data, (uint8_t)0xf5);
|
||||||
|
push(data, (uint8_t)r.size);
|
||||||
|
push(data, (uint8_t)r.shift);
|
||||||
|
push(data, (uint16_t)r.offset);
|
||||||
|
push(data, (uint16_t)r.value);
|
||||||
|
} else {
|
||||||
|
push(data, (uint8_t)0xe5);
|
||||||
|
push(data, (uint8_t)r.size);
|
||||||
|
push(data, (uint8_t)r.shift);
|
||||||
|
push(data, (uint32_t)r.offset);
|
||||||
|
push(data, (uint32_t)r.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &r : s.intersegs) {
|
||||||
|
if (r.can_compress()) {
|
||||||
|
push(data, (uint8_t)0xf6);
|
||||||
|
push(data, (uint8_t)r.size);
|
||||||
|
push(data, (uint8_t)r.shift);
|
||||||
|
push(data, (uint16_t)r.offset);
|
||||||
|
push(data, (uint16_t)r.segment);
|
||||||
|
push(data, (uint16_t)r.segment_offset);
|
||||||
|
} else {
|
||||||
|
push(data, (uint8_t)0xe3);
|
||||||
|
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, (uint32_t)r.segment);
|
||||||
|
push(data, (uint32_t)r.segment_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// end-of-record
|
||||||
|
push(data, (uint8_t)0x00);
|
||||||
|
|
||||||
|
h.bytecount = data.size() + sizeof(omf_header);
|
||||||
|
|
||||||
|
write(fd, &h, sizeof(h));
|
||||||
|
write(fd, data.data(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
52
omf.h
Normal file
52
omf.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#ifndef __omf_h__
|
||||||
|
#define __omf_h__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace omf {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::string loadname;
|
||||||
|
std::string segname;
|
||||||
|
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
std::vector<interseg> intersegs;
|
||||||
|
std::vector<reloc> relocs;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user