diff --git a/link.cpp b/link.cpp index eaf67ab..6013b34 100644 --- a/link.cpp +++ b/link.cpp @@ -1,1102 +1,1102 @@ -/* - * WDC to OMF Linker. - * - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "obj816.h" -#include "expression.h" -#include "omf.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - - -struct { - bool _v = false; - bool _C = false; - bool _X = false; - bool _S = false; - std::string _o; - - unsigned _errors = 0; -} flags; - -enum class endian { - little = __ORDER_LITTLE_ENDIAN__, - big = __ORDER_BIG_ENDIAN__, - native = __BYTE_ORDER__ -}; - - -template -void swap_if(T &t, std::false_type) {} - -void swap_if(uint8_t &, std::true_type) {} - -void swap_if(uint16_t &value, std::true_type) { - value = __builtin_bswap16(value); -} - -void swap_if(uint32_t &value, std::true_type) { - value = __builtin_bswap32(value); -} - -void swap_if(uint64_t &value, std::true_type) { - value = __builtin_bswap64(value); -} - -template -void le_to_host(T &value) { - swap_if(value, std::integral_constant{}); -} - - -#pragma pack(push, 1) -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 */ -}; - -#pragma pack(pop) - - -struct section { - std::string name; - uint8_t flags = 0; - uint32_t org = 0; - uint32_t size = 0; - - unsigned number = -1; - std::vector data; - std::vector expressions; - - unsigned end_symbol = 0; // auto-generated _END_{name} symbol. -}; - -struct symbol { - std::string name; - uint8_t type = 0; - uint8_t flags = 0; - uint32_t offset = 0; - int section = -1; -}; - -template -uint8_t read_8(T &iter) { - uint8_t tmp = *iter; - ++iter; - return tmp; -} - -template -uint16_t read_16(T &iter) { - uint16_t tmp = 0; - - tmp |= *iter << 0; - ++iter; - tmp |= *iter << 8; - ++iter; - return tmp; -} - -template -uint32_t read_32(T &iter) { - uint32_t tmp = 0; - - tmp |= *iter << 0; - ++iter; - tmp |= *iter << 8; - ++iter; - tmp |= *iter << 16; - ++iter; - tmp |= *iter << 24; - ++iter; - - - return tmp; -} - -template -std::string read_cstring(T &iter) { - std::string s; - for(;;) { - uint8_t c = *iter; - ++iter; - if (!c) break; - s.push_back(c); - } - return s; -} - - -template -std::string read_pstring(T &iter) { - std::string s; - unsigned size = *iter; - ++iter; - s.reserve(size); - while (size--) { - uint8_t c = *iter; - ++iter; - s.push_back(c); - } - return s; -} - - -std::vector
read_sections(const std::vector §ion_data) { - - std::vector
sections; - auto iter = section_data.begin(); - while (iter != section_data.end()) { - - section s; - - s.number = read_8(iter); - s.flags = read_8(iter); - s.size = read_32(iter); - s.org = read_32(iter); - - if (!(s.flags & SEC_NONAME)) s.name = read_cstring(iter); - - sections.emplace_back(std::move(s)); - } - return sections; -} - - -std::vector read_symbols(const std::vector &symbol_data) { - - std::vector symbols; - - auto iter = symbol_data.begin(); - while (iter != symbol_data.end()) { - symbol s; - s.type = read_8(iter); - s.flags = read_8(iter); - s.section = read_8(iter); - s.offset = s.type == S_UND ? 0 : read_32(iter); - s.name = read_cstring(iter); - - - symbols.emplace_back(std::move(s)); - } - - return symbols; -} - - -std::unordered_map section_map; -std::vector
sections; - -std::unordered_map symbol_map; -std::vector symbols; - -std::unordered_set undefined_symbols; - - - - - -/* - * replace undefined symbols (if possible) and simplify expressions. - * - */ -void simplify() { - for (auto &s : sections) { - for (auto &e : s.expressions) { - bool delta = false; - - // first check for undefined symbols. - if (e.undefined) { - e.undefined = false; - for (auto &t : e.stack) { - - if (t.tag == OP_SYM) { - const auto &ss = symbols[t.section]; - switch(ss.type & 0x0f) { - case S_UND: - e.undefined = true; - break; - case S_REL: - t = expr{OP_LOC, ss.offset, (uint32_t)ss.section}; - delta = true; - break; - case S_ABS: - t = expr{OP_VAL, (uint32_t)ss.offset}; - delta = true; - break; - } - } - } - } - if (e.stack.size() > 1) simplify_expression(e); - } - } -} - - - -/* - * read and process all sections... - * if section > 5, remap based on name. - * - */ - -void one_module(const std::vector &data, const std::vector §ion_data, const std::vector &symbol_data) { - - std::array remap_section; - - int current_section = SECT_CODE; - std::vector *data_ptr = §ions[current_section].data; - - std::fill(remap_section.begin(), remap_section.end(), -1); - remap_section[SECT_PAGE0] = SECT_PAGE0; - remap_section[SECT_CODE] = SECT_CODE; - remap_section[SECT_KDATA] = SECT_KDATA; - remap_section[SECT_DATA] = SECT_DATA; - remap_section[SECT_UDATA] = SECT_UDATA; - - std::vector
local_sections = read_sections(section_data); - std::vector local_symbols = read_symbols(symbol_data); - - // convert local sections to global - for (auto &s : local_sections) { - if (s.number <= SECT_UDATA) { - sections[s.number].size += s.size; // for page0 / udata sections. - continue; - } - - // todo -- should install section name as global symbol? - - auto iter = section_map.find(s.name); - if (iter == section_map.end()) { - int virtual_section = sections.size(); - remap_section[s.number] = virtual_section; - s.number = virtual_section; - sections.emplace_back(s); - symbol_map.emplace(s.name, virtual_section); - } else { - auto &ss = sections[iter->second]; - assert(ss.flags == s.flags); // check org???? - remap_section[s.number] = iter->second; - s.number = iter->second; - - // update size (for ref-only sections) - ss.size += s.size; - } - } - - // convert local symbols to global. - for (auto &s : local_symbols) { - if (s.type == S_UND) { - auto iter = symbol_map.find(s.name); - if (iter == symbol_map.end()) { - s.section = symbols.size(); - symbol_map.emplace(s.name, s.section); - undefined_symbols.emplace(s.name); - } - else { - // already exists... - const auto &ss = symbols[iter->second]; - if (ss.type != S_UND) s = ss; - } - continue; - } - - // remap and fudge the offset. - if ((s.type & 0x0f) == S_REL) { - int virtual_section = remap_section[s.section]; - assert(virtual_section != -1); - s.section = virtual_section; - s.offset += sections[virtual_section].data.size(); - } else { - s.section = -1; - } - - constexpr const unsigned mask = SF_GBL | SF_DEF; - if ((s.flags & mask) == mask) { - - auto iter = symbol_map.find(s.name); - - if (iter == symbol_map.end()) { - unsigned tmp = symbols.size(); - symbol_map.emplace(s.name, tmp); - symbols.emplace_back(s); - } else { - auto &ss = symbols[iter->second]; - - // if it was undefined, define it! - if (ss.type == S_UND) { - ss = s; - undefined_symbols.erase(s.name); - } - else { - // ok if symbols are identical.. - if (ss.type != s.type || ss.flags != s.flags || ss.section != s.section || ss.offset != s.offset) { - warnx("Duplicate label %s", s.name.c_str()); - flags._errors++; - } - } - } - - } - - } - - - auto iter = data.begin(); - for(;;) { - uint8_t op = read_8(iter); - if (op == REC_END) return; - - if (op < 0xf0) { - data_ptr->insert(data_ptr->end(), iter, iter + op); - iter += op; - continue; - } - - switch(op) { - case REC_SPACE: { - uint16_t count = read_16(iter); - data_ptr->insert(data_ptr->end(), count, 0); - break; - } - - case REC_SECT: { - /* switch sections */ - uint8_t s = read_8(iter); - current_section = remap_section[s]; - assert(current_section > 0 && current_section < sections.size()); - - data_ptr = §ions[current_section].data; - break; - } - - case REC_ORG: { - assert(!"ORG not supported."); - break; - } - - case REC_RELEXP: - case REC_EXPR: { - - expression e; - e.relative = op == REC_RELEXP; - - e.offset = data_ptr->size(); - e.size = read_8(iter); - - data_ptr->insert(data_ptr->end(), e.size, 0); - - /**/ - for(;;) { - op = read_8(iter); - if (op == OP_END) break; - - switch(op) { - case OP_VAL: { - uint32_t offset = read_32(iter); - e.stack.emplace_back(op, offset); - break; - } - case OP_SYM: { - uint16_t symbol = read_16(iter); - assert(symbol < local_symbols.size()); - auto &s = local_symbols[symbol]; - switch (s.type & 0x0f) { - case S_UND: - // S_UND indicates it's still undefined globally. - e.stack.emplace_back(OP_SYM, 0, s.section); /* section is actually a symbol number */ - e.undefined = true; - break; - case S_REL: - e.stack.emplace_back(OP_LOC, s.offset, s.section); - break; - - case S_ABS: - e.stack.emplace_back(OP_VAL, s.offset); - break; - - default: - assert(!"unsupported symbol flags."); - } - break; - } - case OP_LOC: { - uint8_t section = read_8(iter); - uint32_t offset = read_32(iter); - int real_section = remap_section[section]; - assert(real_section >= 0); - e.stack.emplace_back(op, offset, real_section); - break; - } - // operations.. - //unary - case OP_NOT: - case OP_NEG: - case OP_FLP: - // binary - case OP_EXP: - case OP_MUL: - case OP_DIV: - case OP_MOD: - case OP_SHR: - case OP_SHL: - 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: - e.stack.emplace_back(op); - break; - default: - assert(!"unsupported expression opcode."); - } - } - sections[current_section].expressions.emplace_back(std::move(e)); - break; - } - - - case REC_LINE: break; - case REC_DEBUG: { - uint16_t size = read_16(iter); - iter += size; - break; - } - - } - } -} - - -/* - * n.b -- UDATA and PAGE0 are ref only, therefore no data is generated. - * as a special case for UDATA (but not PAGE0) have a flag so it will be 0-filled and generate data? - * - */ -void init() { - - sections.resize(5); - - sections[SECT_PAGE0].number = SECT_PAGE0; - sections[SECT_PAGE0].flags = SEC_DATA | SEC_NONAME | SEC_DIRECT | SEC_REF_ONLY; - sections[SECT_PAGE0].name = "page0"; - - sections[SECT_CODE].number = SECT_CODE; - sections[SECT_CODE].flags = SEC_NONAME; - sections[SECT_CODE].name = "code"; - - sections[SECT_KDATA].number = SECT_KDATA; - sections[SECT_KDATA].flags = SEC_DATA | SEC_NONAME; - sections[SECT_KDATA].name = "kdata"; - - sections[SECT_DATA].number = SECT_DATA; - sections[SECT_DATA].flags = SEC_DATA | SEC_NONAME; - sections[SECT_DATA].name = "data"; - - sections[SECT_UDATA].number = SECT_UDATA; - sections[SECT_UDATA].flags = SEC_DATA | SEC_NONAME | SEC_REF_ONLY; - sections[SECT_UDATA].name = "udata"; - - /* - * For each section, [the linker] creates three symbols, - * _ROM_BEG_secname, _BEG_secname and _END_secname, which - * correspond to the rom location and the execution beginning - * and end of the section. These will be used more in the next - * two sections of code. - */ - - // n.b - only for pre-defined sections [?], skip the _ROM_BEG_* symbols... - - static std::string names[] = { - "_BEG_PAGE0", "_END_PAGE0", - "_BEG_CODE", "_END_CODE", - "_BEG_KDATA", "_END_KDATA", - "_BEG_DATA", "_END_DATA", - "_BEG_UDATA", "_END_UDATA", - }; - - for (int i = 0; i < 5; ++i) { - - // begin is 0. - symbol s; - s.name = names[i * 2]; - s.section = i; - s.type = S_REL; - s.flags = SF_DEF | SF_GBL; - symbol_map.emplace(s.name, i * 2); - symbols.emplace_back(s); - - // end is undefined... - s.name = names[i * 2 + 1]; - s.section = i * 2 + 1; // symbol number. - s.type = S_UND; - s.flags = 0; - - symbol_map.emplace(s.name, i * 2 + 1); - symbols.emplace_back(s); - - } - -} - - -void generate_end() { - -/* - const std::string names[] = { - "_END_PAGE0", - "_END_CODE", - "_END_KDATA" - "_END_DATA" - "_END_UDATA" - }; -*/ - for (int i = 0; i < 5; ++i) { - symbol s; - s.section = i; - s.type = S_REL; - s.flags = SF_DEF | SF_GBL; - s.offset = sections[i].size; // data.size() doesn't word w/ ref_only - - symbols[i * 2 + 1] = s; - } -} - - -std::vector omf_segments; - - -template -void append(std::vector &to, std::vector &from) { - to.insert(to.end(), - std::make_move_iterator(from.begin()), - std::make_move_iterator(from.end()) - ); -} - - -template -void append(std::vector &to, const std::vector &from) { - to.insert(to.end(), - from.begin(), - from.end() - ); -} - -template -void append(std::vector &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 > 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_code_size = 0; - uint32_t total_data_size = 0; - for (const auto &s : sections) { - if (s.flags & SEC_REF_ONLY) continue; - if (s.flags & SEC_DATA) { - total_data_size += s.size; - } else { - total_code_size += s.size; - } - } - - // add in UDATA - total_data_size += sections[SECT_UDATA].size; - - if (total_data_size + sections[SECT_CODE].size > 0xffff) { - - omf_segments.emplace_back(); - - auto &seg = omf_segments.back(); - data_segment = seg.segnum = omf_segments.size(); - seg.kind = 0x0001; // static data segment. - } - - //omf::segment &code_seg = omf_segments[code_segment-1]; - omf::segment &data_seg = omf_segments[data_segment-1]; - - - // KDATA, DATA, UDATA, other segment order. - for (auto &s : sections) { - if (s.flags & SEC_REF_ONLY) continue; - if ((s.flags & SEC_DATA) == 0) continue; - - remap[s.number] = std::make_pair(data_segment, data_seg.data.size()); - - append(data_seg.data, s.data); - s.data.clear(); - } - - // add in UDATA - { - auto &s = sections[SECT_UDATA]; - remap[s.number] = std::make_pair(data_segment, data_seg.data.size()); - append(data_seg.data, s.size, (uint8_t)0); - } - - // for all other sections, create a new segment. - 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 &t : e.stack) { - if (t.tag == OP_LOC) { - const auto &x = remap[t.section]; - t.section = x.first; - t.value += x.second; - } - } - simplify_expression(e); - to_omf(e, omf_segments[s.number-1]); - } - } - - // and we're done... - -} - - - - -bool one_file(const std::string &name) { - - int fd = open(name.c_str(), O_RDONLY | O_BINARY); - if (fd < 0) { - warn("Unable to open %s", name.c_str()); - return false; - } - bool rv = false; - - Header h; - ssize_t ok; - - ok = read(fd, &h, sizeof(h)); - if (ok != sizeof(h)) { - warnx("Invalid object file: %s", name.c_str()); - close(fd); - return false; - } - - le_to_host(h.magic); - le_to_host(h.version); - le_to_host(h.filetype); - - if (h.magic != MOD_MAGIC || h.version != MOD_VERSION || h.filetype < MOD_OBJECT || h.filetype > MOD_LIBRARY) { - warnx("Invalid object file: %s", name.c_str()); - close(fd); - return false; - } - - if (h.filetype == MOD_LIBRARY) { - warnx("%s is a library", name.c_str()); - close(fd); - // todo -- add to library list... - return true; - } - - // - rv = true; - lseek(fd, 0, SEEK_SET); - for(;;) { - Mod_head h; - - ok = read(fd, &h, sizeof(h)); - if (ok == 0) break; // eof. - - rv = false; - if (ok < sizeof(h)) { - warnx("Invalid object file: %s", name.c_str()); - break; - } - - le_to_host(h.h_magic); - le_to_host(h.h_version); - le_to_host(h.h_filtyp); - le_to_host(h.h_namlen); - le_to_host(h.h_recsize); - le_to_host(h.h_secsize); - le_to_host(h.h_symsize); - le_to_host(h.h_optsize); - le_to_host(h.h_tot_secs); - le_to_host(h.h_num_secs); - le_to_host(h.h_num_syms); - - assert(h.h_magic == MOD_MAGIC); - assert(h.h_version == 1); - assert(h.h_filtyp == 1); - - - std::string module_name; - { - // now read the name (h_namlen includes 0 terminator.) - std::vector tmp; - tmp.resize(h.h_namlen); - ok = read(fd, tmp.data(), h.h_namlen); - if (ok != h.h_namlen) { - warnx("Invalid object file: %s", name.c_str()); - break; - } - module_name.assign(tmp.data()); - } - - std::vector record_data; - std::vector symbol_data; - std::vector section_data; - - record_data.resize(h.h_recsize); - ok = read(fd, record_data.data(), h.h_recsize); - if (ok != h.h_recsize) { - warnx("Truncated object file: %s", name.c_str()); - break; - } - - section_data.resize(h.h_secsize); - ok = read(fd, section_data.data(), h.h_secsize); - if (ok != h.h_secsize) { - warnx("Truncated object file: %s", name.c_str()); - break; - } - - symbol_data.resize(h.h_symsize); - ok = read(fd, symbol_data.data(), h.h_symsize); - if (ok != h.h_symsize) { - warnx("Truncated object file: %s", name.c_str()); - break; - } - - if (flags._v) { - printf("Processing %s:%s\n", name.c_str(), module_name.c_str()); - } - - // should probably pass in name and module.... - one_module(record_data, section_data, symbol_data); - rv = true; - } - - - close(fd); - return rv; -} - -void help() { - exit(0); -} - -void usage() { - exit(EX_USAGE); -} - -int main(int argc, char **argv) { - - std::vector _l; - std::vector _L; - - - int c; - while ((c = getopt(argc, argv, "vCXL:l:o:")) != -1) { - switch(c) { - case 'v': flags._v = true; break; - case 'X': flags._X = true; break; - case 'C': flags._C = true; break; - case 'o': flags._o = optarg; break; - case 'l': _l.emplace_back(optarg); break; - case 'L': _L.emplace_back(optarg); break; - case 'h': help(); break; - case ':': - case '?': - default: - usage(); - } - } - - argc -= optind; - argv += optind; - - if (argc == 0) usage(); - - init(); - - for (int i = 0 ; i < argc; ++i) { - if (!one_file(argv[i])) flags._errors++; - } - - // - simplify(); - - // for each undefined, try to find it in a library... - // ... except for the _BEG / _END symbols! - - for (const auto & s : undefined_symbols) { - printf("%s\n", s.c_str()); - } - - generate_end(); - - - if (flags._v) { - for (const auto &s : sections) { - //if (s.flags & SEC_REF_ONLY) continue; - printf("section %3d %-20s $%04x $%04x\n", - s.number, s.name.c_str(), (uint32_t)s.data.size(), s.size); - } - fputs("\n", stdout); - } - - build_omf_segments(); - - if (flags._v) { - for (const auto &s : omf_segments) { - printf("segment %3d %-20s $%04x\n", - s.segnum, s.segname.c_str(), (uint32_t)s.data.size()); - - for (auto &r : s.relocs) { - printf(" %02x %02x %06x %06x\n", - r.size, r.shift, r.offset, r.value); - } - 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 &segments, bool expressload, const std::string &path); - - save_omf(omf_segments, false, "out.omf"); - - -} - +/* + * WDC to OMF Linker. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "obj816.h" +#include "expression.h" +#include "omf.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + + +struct { + bool _v = false; + bool _C = false; + bool _X = false; + bool _S = false; + std::string _o; + + unsigned _errors = 0; +} flags; + +enum class endian { + little = __ORDER_LITTLE_ENDIAN__, + big = __ORDER_BIG_ENDIAN__, + native = __BYTE_ORDER__ +}; + + +template +void swap_if(T &t, std::false_type) {} + +void swap_if(uint8_t &, std::true_type) {} + +void swap_if(uint16_t &value, std::true_type) { + value = __builtin_bswap16(value); +} + +void swap_if(uint32_t &value, std::true_type) { + value = __builtin_bswap32(value); +} + +void swap_if(uint64_t &value, std::true_type) { + value = __builtin_bswap64(value); +} + +template +void le_to_host(T &value) { + swap_if(value, std::integral_constant{}); +} + + +#pragma pack(push, 1) +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 */ +}; + +#pragma pack(pop) + + +struct section { + std::string name; + uint8_t flags = 0; + uint32_t org = 0; + uint32_t size = 0; + + unsigned number = -1; + std::vector data; + std::vector expressions; + + unsigned end_symbol = 0; // auto-generated _END_{name} symbol. +}; + +struct symbol { + std::string name; + uint8_t type = 0; + uint8_t flags = 0; + uint32_t offset = 0; + int section = -1; +}; + +template +uint8_t read_8(T &iter) { + uint8_t tmp = *iter; + ++iter; + return tmp; +} + +template +uint16_t read_16(T &iter) { + uint16_t tmp = 0; + + tmp |= *iter << 0; + ++iter; + tmp |= *iter << 8; + ++iter; + return tmp; +} + +template +uint32_t read_32(T &iter) { + uint32_t tmp = 0; + + tmp |= *iter << 0; + ++iter; + tmp |= *iter << 8; + ++iter; + tmp |= *iter << 16; + ++iter; + tmp |= *iter << 24; + ++iter; + + + return tmp; +} + +template +std::string read_cstring(T &iter) { + std::string s; + for(;;) { + uint8_t c = *iter; + ++iter; + if (!c) break; + s.push_back(c); + } + return s; +} + + +template +std::string read_pstring(T &iter) { + std::string s; + unsigned size = *iter; + ++iter; + s.reserve(size); + while (size--) { + uint8_t c = *iter; + ++iter; + s.push_back(c); + } + return s; +} + + +std::vector
read_sections(const std::vector §ion_data) { + + std::vector
sections; + auto iter = section_data.begin(); + while (iter != section_data.end()) { + + section s; + + s.number = read_8(iter); + s.flags = read_8(iter); + s.size = read_32(iter); + s.org = read_32(iter); + + if (!(s.flags & SEC_NONAME)) s.name = read_cstring(iter); + + sections.emplace_back(std::move(s)); + } + return sections; +} + + +std::vector read_symbols(const std::vector &symbol_data) { + + std::vector symbols; + + auto iter = symbol_data.begin(); + while (iter != symbol_data.end()) { + symbol s; + s.type = read_8(iter); + s.flags = read_8(iter); + s.section = read_8(iter); + s.offset = s.type == S_UND ? 0 : read_32(iter); + s.name = read_cstring(iter); + + + symbols.emplace_back(std::move(s)); + } + + return symbols; +} + + +std::unordered_map section_map; +std::vector
sections; + +std::unordered_map symbol_map; +std::vector symbols; + +std::unordered_set undefined_symbols; + + + + + +/* + * replace undefined symbols (if possible) and simplify expressions. + * + */ +void simplify() { + for (auto &s : sections) { + for (auto &e : s.expressions) { + bool delta = false; + + // first check for undefined symbols. + if (e.undefined) { + e.undefined = false; + for (auto &t : e.stack) { + + if (t.tag == OP_SYM) { + const auto &ss = symbols[t.section]; + switch(ss.type & 0x0f) { + case S_UND: + e.undefined = true; + break; + case S_REL: + t = expr{OP_LOC, ss.offset, (uint32_t)ss.section}; + delta = true; + break; + case S_ABS: + t = expr{OP_VAL, (uint32_t)ss.offset}; + delta = true; + break; + } + } + } + } + if (e.stack.size() > 1) simplify_expression(e); + } + } +} + + + +/* + * read and process all sections... + * if section > 5, remap based on name. + * + */ + +void one_module(const std::vector &data, const std::vector §ion_data, const std::vector &symbol_data) { + + std::array remap_section; + + int current_section = SECT_CODE; + std::vector *data_ptr = §ions[current_section].data; + + std::fill(remap_section.begin(), remap_section.end(), -1); + remap_section[SECT_PAGE0] = SECT_PAGE0; + remap_section[SECT_CODE] = SECT_CODE; + remap_section[SECT_KDATA] = SECT_KDATA; + remap_section[SECT_DATA] = SECT_DATA; + remap_section[SECT_UDATA] = SECT_UDATA; + + std::vector
local_sections = read_sections(section_data); + std::vector local_symbols = read_symbols(symbol_data); + + // convert local sections to global + for (auto &s : local_sections) { + if (s.number <= SECT_UDATA) { + sections[s.number].size += s.size; // for page0 / udata sections. + continue; + } + + // todo -- should install section name as global symbol? + + auto iter = section_map.find(s.name); + if (iter == section_map.end()) { + int virtual_section = sections.size(); + remap_section[s.number] = virtual_section; + s.number = virtual_section; + sections.emplace_back(s); + symbol_map.emplace(s.name, virtual_section); + } else { + auto &ss = sections[iter->second]; + assert(ss.flags == s.flags); // check org???? + remap_section[s.number] = iter->second; + s.number = iter->second; + + // update size (for ref-only sections) + ss.size += s.size; + } + } + + // convert local symbols to global. + for (auto &s : local_symbols) { + if (s.type == S_UND) { + auto iter = symbol_map.find(s.name); + if (iter == symbol_map.end()) { + s.section = symbols.size(); + symbol_map.emplace(s.name, s.section); + undefined_symbols.emplace(s.name); + } + else { + // already exists... + const auto &ss = symbols[iter->second]; + if (ss.type != S_UND) s = ss; + } + continue; + } + + // remap and fudge the offset. + if ((s.type & 0x0f) == S_REL) { + int virtual_section = remap_section[s.section]; + assert(virtual_section != -1); + s.section = virtual_section; + s.offset += sections[virtual_section].data.size(); + } else { + s.section = -1; + } + + constexpr const unsigned mask = SF_GBL | SF_DEF; + if ((s.flags & mask) == mask) { + + auto iter = symbol_map.find(s.name); + + if (iter == symbol_map.end()) { + unsigned tmp = symbols.size(); + symbol_map.emplace(s.name, tmp); + symbols.emplace_back(s); + } else { + auto &ss = symbols[iter->second]; + + // if it was undefined, define it! + if (ss.type == S_UND) { + ss = s; + undefined_symbols.erase(s.name); + } + else { + // ok if symbols are identical.. + if (ss.type != s.type || ss.flags != s.flags || ss.section != s.section || ss.offset != s.offset) { + warnx("Duplicate label %s", s.name.c_str()); + flags._errors++; + } + } + } + + } + + } + + + auto iter = data.begin(); + for(;;) { + uint8_t op = read_8(iter); + if (op == REC_END) return; + + if (op < 0xf0) { + data_ptr->insert(data_ptr->end(), iter, iter + op); + iter += op; + continue; + } + + switch(op) { + case REC_SPACE: { + uint16_t count = read_16(iter); + data_ptr->insert(data_ptr->end(), count, 0); + break; + } + + case REC_SECT: { + /* switch sections */ + uint8_t s = read_8(iter); + current_section = remap_section[s]; + assert(current_section > 0 && current_section < sections.size()); + + data_ptr = §ions[current_section].data; + break; + } + + case REC_ORG: { + assert(!"ORG not supported."); + break; + } + + case REC_RELEXP: + case REC_EXPR: { + + expression e; + e.relative = op == REC_RELEXP; + + e.offset = data_ptr->size(); + e.size = read_8(iter); + + data_ptr->insert(data_ptr->end(), e.size, 0); + + /**/ + for(;;) { + op = read_8(iter); + if (op == OP_END) break; + + switch(op) { + case OP_VAL: { + uint32_t offset = read_32(iter); + e.stack.emplace_back(op, offset); + break; + } + case OP_SYM: { + uint16_t symbol = read_16(iter); + assert(symbol < local_symbols.size()); + auto &s = local_symbols[symbol]; + switch (s.type & 0x0f) { + case S_UND: + // S_UND indicates it's still undefined globally. + e.stack.emplace_back(OP_SYM, 0, s.section); /* section is actually a symbol number */ + e.undefined = true; + break; + case S_REL: + e.stack.emplace_back(OP_LOC, s.offset, s.section); + break; + + case S_ABS: + e.stack.emplace_back(OP_VAL, s.offset); + break; + + default: + assert(!"unsupported symbol flags."); + } + break; + } + case OP_LOC: { + uint8_t section = read_8(iter); + uint32_t offset = read_32(iter); + int real_section = remap_section[section]; + assert(real_section >= 0); + e.stack.emplace_back(op, offset, real_section); + break; + } + // operations.. + //unary + case OP_NOT: + case OP_NEG: + case OP_FLP: + // binary + case OP_EXP: + case OP_MUL: + case OP_DIV: + case OP_MOD: + case OP_SHR: + case OP_SHL: + 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: + e.stack.emplace_back(op); + break; + default: + assert(!"unsupported expression opcode."); + } + } + sections[current_section].expressions.emplace_back(std::move(e)); + break; + } + + + case REC_LINE: break; + case REC_DEBUG: { + uint16_t size = read_16(iter); + iter += size; + break; + } + + } + } +} + + +/* + * n.b -- UDATA and PAGE0 are ref only, therefore no data is generated. + * as a special case for UDATA (but not PAGE0) have a flag so it will be 0-filled and generate data? + * + */ +void init() { + + sections.resize(5); + + sections[SECT_PAGE0].number = SECT_PAGE0; + sections[SECT_PAGE0].flags = SEC_DATA | SEC_NONAME | SEC_DIRECT | SEC_REF_ONLY; + sections[SECT_PAGE0].name = "page0"; + + sections[SECT_CODE].number = SECT_CODE; + sections[SECT_CODE].flags = SEC_NONAME; + sections[SECT_CODE].name = "code"; + + sections[SECT_KDATA].number = SECT_KDATA; + sections[SECT_KDATA].flags = SEC_DATA | SEC_NONAME; + sections[SECT_KDATA].name = "kdata"; + + sections[SECT_DATA].number = SECT_DATA; + sections[SECT_DATA].flags = SEC_DATA | SEC_NONAME; + sections[SECT_DATA].name = "data"; + + sections[SECT_UDATA].number = SECT_UDATA; + sections[SECT_UDATA].flags = SEC_DATA | SEC_NONAME | SEC_REF_ONLY; + sections[SECT_UDATA].name = "udata"; + + /* + * For each section, [the linker] creates three symbols, + * _ROM_BEG_secname, _BEG_secname and _END_secname, which + * correspond to the rom location and the execution beginning + * and end of the section. These will be used more in the next + * two sections of code. + */ + + // n.b - only for pre-defined sections [?], skip the _ROM_BEG_* symbols... + + static std::string names[] = { + "_BEG_PAGE0", "_END_PAGE0", + "_BEG_CODE", "_END_CODE", + "_BEG_KDATA", "_END_KDATA", + "_BEG_DATA", "_END_DATA", + "_BEG_UDATA", "_END_UDATA", + }; + + for (int i = 0; i < 5; ++i) { + + // begin is 0. + symbol s; + s.name = names[i * 2]; + s.section = i; + s.type = S_REL; + s.flags = SF_DEF | SF_GBL; + symbol_map.emplace(s.name, i * 2); + symbols.emplace_back(s); + + // end is undefined... + s.name = names[i * 2 + 1]; + s.section = i * 2 + 1; // symbol number. + s.type = S_UND; + s.flags = 0; + + symbol_map.emplace(s.name, i * 2 + 1); + symbols.emplace_back(s); + + } + +} + + +void generate_end() { + +/* + const std::string names[] = { + "_END_PAGE0", + "_END_CODE", + "_END_KDATA" + "_END_DATA" + "_END_UDATA" + }; +*/ + for (int i = 0; i < 5; ++i) { + symbol s; + s.section = i; + s.type = S_REL; + s.flags = SF_DEF | SF_GBL; + s.offset = sections[i].size; // data.size() doesn't word w/ ref_only + + symbols[i * 2 + 1] = s; + } +} + + +std::vector omf_segments; + + +template +void append(std::vector &to, std::vector &from) { + to.insert(to.end(), + std::make_move_iterator(from.begin()), + std::make_move_iterator(from.end()) + ); +} + + +template +void append(std::vector &to, const std::vector &from) { + to.insert(to.end(), + from.begin(), + from.end() + ); +} + +template +void append(std::vector &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 > 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_code_size = 0; + uint32_t total_data_size = 0; + for (const auto &s : sections) { + if (s.flags & SEC_REF_ONLY) continue; + if (s.flags & SEC_DATA) { + total_data_size += s.size; + } else { + total_code_size += s.size; + } + } + + // add in UDATA + total_data_size += sections[SECT_UDATA].size; + + if (total_data_size + sections[SECT_CODE].size > 0xffff) { + + omf_segments.emplace_back(); + + auto &seg = omf_segments.back(); + data_segment = seg.segnum = omf_segments.size(); + seg.kind = 0x0001; // static data segment. + } + + //omf::segment &code_seg = omf_segments[code_segment-1]; + omf::segment &data_seg = omf_segments[data_segment-1]; + + + // KDATA, DATA, UDATA, other segment order. + for (auto &s : sections) { + if (s.flags & SEC_REF_ONLY) continue; + if ((s.flags & SEC_DATA) == 0) continue; + + remap[s.number] = std::make_pair(data_segment, data_seg.data.size()); + + append(data_seg.data, s.data); + s.data.clear(); + } + + // add in UDATA + { + auto &s = sections[SECT_UDATA]; + remap[s.number] = std::make_pair(data_segment, data_seg.data.size()); + append(data_seg.data, s.size, (uint8_t)0); + } + + // for all other sections, create a new segment. + 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 &t : e.stack) { + if (t.tag == OP_LOC) { + const auto &x = remap[t.section]; + t.section = x.first; + t.value += x.second; + } + } + simplify_expression(e); + to_omf(e, omf_segments[s.number-1]); + } + } + + // and we're done... + +} + + + + +bool one_file(const std::string &name) { + + int fd = open(name.c_str(), O_RDONLY | O_BINARY); + if (fd < 0) { + warn("Unable to open %s", name.c_str()); + return false; + } + bool rv = false; + + Header h; + ssize_t ok; + + ok = read(fd, &h, sizeof(h)); + if (ok != sizeof(h)) { + warnx("Invalid object file: %s", name.c_str()); + close(fd); + return false; + } + + le_to_host(h.magic); + le_to_host(h.version); + le_to_host(h.filetype); + + if (h.magic != MOD_MAGIC || h.version != MOD_VERSION || h.filetype < MOD_OBJECT || h.filetype > MOD_LIBRARY) { + warnx("Invalid object file: %s", name.c_str()); + close(fd); + return false; + } + + if (h.filetype == MOD_LIBRARY) { + warnx("%s is a library", name.c_str()); + close(fd); + // todo -- add to library list... + return true; + } + + // + rv = true; + lseek(fd, 0, SEEK_SET); + for(;;) { + Mod_head h; + + ok = read(fd, &h, sizeof(h)); + if (ok == 0) break; // eof. + + rv = false; + if (ok < sizeof(h)) { + warnx("Invalid object file: %s", name.c_str()); + break; + } + + le_to_host(h.h_magic); + le_to_host(h.h_version); + le_to_host(h.h_filtyp); + le_to_host(h.h_namlen); + le_to_host(h.h_recsize); + le_to_host(h.h_secsize); + le_to_host(h.h_symsize); + le_to_host(h.h_optsize); + le_to_host(h.h_tot_secs); + le_to_host(h.h_num_secs); + le_to_host(h.h_num_syms); + + assert(h.h_magic == MOD_MAGIC); + assert(h.h_version == 1); + assert(h.h_filtyp == 1); + + + std::string module_name; + { + // now read the name (h_namlen includes 0 terminator.) + std::vector tmp; + tmp.resize(h.h_namlen); + ok = read(fd, tmp.data(), h.h_namlen); + if (ok != h.h_namlen) { + warnx("Invalid object file: %s", name.c_str()); + break; + } + module_name.assign(tmp.data()); + } + + std::vector record_data; + std::vector symbol_data; + std::vector section_data; + + record_data.resize(h.h_recsize); + ok = read(fd, record_data.data(), h.h_recsize); + if (ok != h.h_recsize) { + warnx("Truncated object file: %s", name.c_str()); + break; + } + + section_data.resize(h.h_secsize); + ok = read(fd, section_data.data(), h.h_secsize); + if (ok != h.h_secsize) { + warnx("Truncated object file: %s", name.c_str()); + break; + } + + symbol_data.resize(h.h_symsize); + ok = read(fd, symbol_data.data(), h.h_symsize); + if (ok != h.h_symsize) { + warnx("Truncated object file: %s", name.c_str()); + break; + } + + if (flags._v) { + printf("Processing %s:%s\n", name.c_str(), module_name.c_str()); + } + + // should probably pass in name and module.... + one_module(record_data, section_data, symbol_data); + rv = true; + } + + + close(fd); + return rv; +} + +void help() { + exit(0); +} + +void usage() { + exit(EX_USAGE); +} + +int main(int argc, char **argv) { + + std::vector _l; + std::vector _L; + + + int c; + while ((c = getopt(argc, argv, "vCXL:l:o:")) != -1) { + switch(c) { + case 'v': flags._v = true; break; + case 'X': flags._X = true; break; + case 'C': flags._C = true; break; + case 'o': flags._o = optarg; break; + case 'l': _l.emplace_back(optarg); break; + case 'L': _L.emplace_back(optarg); break; + case 'h': help(); break; + case ':': + case '?': + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + if (argc == 0) usage(); + + init(); + + for (int i = 0 ; i < argc; ++i) { + if (!one_file(argv[i])) flags._errors++; + } + + // + simplify(); + + // for each undefined, try to find it in a library... + // ... except for the _BEG / _END symbols! + + for (const auto & s : undefined_symbols) { + printf("%s\n", s.c_str()); + } + + generate_end(); + + + if (flags._v) { + for (const auto &s : sections) { + //if (s.flags & SEC_REF_ONLY) continue; + printf("section %3d %-20s $%04x $%04x\n", + s.number, s.name.c_str(), (uint32_t)s.data.size(), s.size); + } + fputs("\n", stdout); + } + + build_omf_segments(); + + if (flags._v) { + for (const auto &s : omf_segments) { + printf("segment %3d %-20s $%04x\n", + s.segnum, s.segname.c_str(), (uint32_t)s.data.size()); + + for (auto &r : s.relocs) { + printf(" %02x %02x %06x %06x\n", + r.size, r.shift, r.offset, r.value); + } + 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 &segments, bool expressload, const std::string &path); + + save_omf(omf_segments, false, "out.omf"); + + +} + diff --git a/obj816.h b/obj816.h index 42dd44f..2f948a2 100644 --- a/obj816.h +++ b/obj816.h @@ -1,181 +1,181 @@ -#ifndef __obj816_h__ -#define __obj816_h__ - -#include - -#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 \ No newline at end of file +#ifndef __obj816_h__ +#define __obj816_h__ + +#include + +#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