merlin-utils/link.cpp

1520 lines
32 KiB
C++
Raw Permalink Normal View History

2019-12-08 18:55:33 +00:00
/* c++17 */
#include <algorithm>
2020-06-03 14:57:05 +00:00
#include <numeric>
2019-12-08 18:55:33 +00:00
#include <string>
2019-12-09 18:02:15 +00:00
#include <string_view>
#include <system_error>
#include <unordered_map>
#include <utility>
#include <vector>
2019-12-09 18:02:15 +00:00
#include <cassert>
2019-12-11 03:46:04 +00:00
#include <cerrno>
#include <cstdint>
2019-12-09 18:02:15 +00:00
#include <cstdio>
2019-12-15 00:01:12 +00:00
#include <cstring>
#include <ctime>
2019-12-09 18:02:15 +00:00
#include <err.h>
2019-12-10 00:45:45 +00:00
#include <sysexits.h>
#include <unistd.h>
2019-12-09 18:02:15 +00:00
#include <afp/finder_info.h>
2019-12-08 18:55:33 +00:00
2019-12-10 00:45:45 +00:00
#include "mapped_file.h"
2019-12-08 18:55:33 +00:00
#include "omf.h"
2019-12-09 18:02:15 +00:00
#include "rel.h"
2019-12-15 00:01:12 +00:00
#include "link.h"
#include "script.h"
2019-12-08 18:55:33 +00:00
2022-12-07 04:25:44 +00:00
void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool compress, bool expressload, unsigned version = 2);
2020-11-13 00:24:28 +00:00
void save_bin(const std::string &path, omf::segment &segment);
2019-12-15 18:04:45 +00:00
2019-12-10 00:45:45 +00:00
int set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type, std::error_code &ec);
void set_file_type(const std::string &path, uint16_t file_type, uint32_t aux_type);
2019-12-08 18:55:33 +00:00
2019-12-09 18:02:15 +00:00
/* since span isn't standard yet */
typedef std::basic_string_view<uint8_t> byte_view;
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
struct pending_reloc : public omf::reloc {
unsigned id = 0;
2019-12-08 18:55:33 +00:00
};
2019-12-10 00:45:45 +00:00
2019-12-15 00:01:12 +00:00
struct cookie {
std::string file;
std::vector<unsigned> remap;
uint32_t begin = 0;
uint32_t end = 0;
2019-12-08 18:55:33 +00:00
};
2019-12-15 00:01:12 +00:00
namespace {
std::unordered_map<std::string, unsigned> symbol_map;
std::vector<symbol> symbol_table;
std::vector<omf::segment> segments;
std::vector<std::vector<pending_reloc>> relocations;
std::unordered_map<std::string, uint32_t> file_types = {
{ "NON", 0x00 },
{ "BAD", 0x01 },
{ "BIN", 0x06 },
{ "TXT", 0x04 },
{ "DIR", 0x0f },
{ "ADB", 0x19 },
{ "AWP", 0x1a },
{ "ASP", 0x1b },
{ "GSB", 0xab },
{ "TDF", 0xac },
{ "BDF", 0xad },
{ "SRC", 0xb0 },
{ "OBJ", 0xb1 },
{ "LIB", 0xb2 },
{ "S16", 0xb3 },
{ "RTL", 0xb4 },
{ "EXE", 0xb5 },
{ "PIF", 0xb6 },
{ "TIF", 0xb7 },
{ "NDA", 0xb8 },
{ "CDA", 0xb9 },
{ "TOL", 0xba },
{ "DRV", 0xbb },
{ "DOC", 0xbf },
{ "PNT", 0xc0 },
{ "PIC", 0xc1 },
{ "FON", 0xcb },
{ "PAS", 0xef },
{ "CMD", 0xf0 },
{ "LNK", 0xf8 },
{ "BAS", 0xfc },
{ "VAR", 0xfd },
{ "REL", 0xfe },
{ "SYS", 0xff },
};
}
/*
Variable types:
linker symbol table includes =, EQU, GEQ, and KBD
GEQ - global absolute label, in effect for all subsequent asms.
inhibits KBD, otherwise causes duplicate symbol errors during assembly.
KBD - same as GEQ
EQU - same as GEQ BUT symbol is discarded after ASM (ie, only in effect for 1 assembly)
= - internal to link script (DO, etc). not passed to assembler. not passed to linker.
POS - current offset
LEN - length of last linked file
a = assembler
l = linker
c = command file
a l c
EQU y n n
= n n y
GEQ y y y
KBD y y y
POS n y n
LEN n y n
seems like it might be nice for POS and LEN to be available in the command file, eg
POS xxx
DO xxx>4096
ERR too big
ELS
DS 4096-xxx
FIN
*/
namespace {
/* script related */
unsigned lkv = 1;
unsigned ver = 2;
unsigned ftype = 0xb3;
unsigned atype = 0x0000;
// unsigned kind = 0x0000;
unsigned org = 0x0000;
2019-12-15 00:01:12 +00:00
unsigned sav = 0;
unsigned lnk = 0;
bool end = false;
bool fas = false;
int ovr = OVR_OFF;
size_t pos_var = 0;
size_t len_var = 0;
2019-12-15 00:01:12 +00:00
/* do/els/fin stuff. 32 do levels supported. */
2019-12-15 00:01:12 +00:00
uint32_t active_bits = 1;
bool active = true;
std::unordered_map<std::string, uint32_t> local_symbol_table;
std::string loadname;
2019-12-15 00:01:12 +00:00
}
2019-12-09 18:02:15 +00:00
/* nb - pointer may be invalidated by next call */
2019-12-15 00:01:12 +00:00
symbol *find_symbol(const std::string &name, bool insert) {
2019-12-08 18:55:33 +00:00
auto iter = symbol_map.find(name);
if (iter != symbol_map.end()) return &symbol_table[iter->second];
2019-12-15 00:01:12 +00:00
if (!insert) return nullptr;
2019-12-08 18:55:33 +00:00
unsigned id = symbol_table.size();
2019-12-08 18:55:33 +00:00
symbol_map.emplace(name, id);
auto &rv = symbol_table.emplace_back();
rv.name = name;
rv.id = id;
2019-12-09 18:02:15 +00:00
return &rv;
2019-12-08 18:55:33 +00:00
}
2019-12-15 00:01:12 +00:00
void define(std::string name, uint32_t value, int type) {
bool warn = false;
if (type & 4) {
/* command script */
auto iter = local_symbol_table.find(name);
if (iter == local_symbol_table.end()) {
local_symbol_table.emplace(std::make_pair(name, value));
} else if (iter->second != value) {
warn = true;
}
}
if (type & 2) {
/* linker */
auto e = find_symbol(name, true);
if (e->defined) {
if (!e->absolute || e->value != value) {
warn = true;
}
} else {
e->absolute = true;
e->defined = true;
e->file = "-D";
e->value = value;
}
}
if (warn) warnx("duplicate symbol %s", name.c_str());
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
}
2019-12-08 18:55:33 +00:00
2019-12-15 18:06:05 +00:00
void new_segment(bool reset = false) {
if (reset) {
segments.clear();
relocations.clear();
save_file.clear();
}
2019-12-15 02:56:52 +00:00
segments.emplace_back();
relocations.emplace_back();
segments.back().segnum = segments.size();
segments.back().kind = 4096; /* no special memory */
len_var = 0;
pos_var = 0;
2019-12-15 02:56:52 +00:00
}
2019-12-10 02:58:01 +00:00
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
static void process_labels(byte_view &data, cookie &cookie) {
2019-12-08 18:55:33 +00:00
2019-12-15 02:56:52 +00:00
unsigned segnum = segments.back().segnum;
2019-12-08 18:55:33 +00:00
for(;;) {
2019-12-09 18:02:15 +00:00
assert(data.size());
2019-12-08 18:55:33 +00:00
unsigned flag = data[0];
if (flag == 0x00) return;
unsigned length = flag & 0x1f;
assert(length != 0);
assert(data.size() >= length + 4);
std::string name(data.data() + 1, data.data() + 1 + length);
data.remove_prefix(1 + length);
uint32_t value = data[0] | (data[1] << 8) | (data[2] << 16);
data.remove_prefix(3);
2019-12-09 18:02:15 +00:00
symbol *e = find_symbol(name);
2019-12-08 18:55:33 +00:00
switch (flag & ~0x1f) {
case SYMBOL_EXTERNAL:
/* map the unit symbol # to a global symbol # */
2020-06-03 03:33:34 +00:00
if (!(value & 0x8000)) e->exd = true;
2019-12-08 18:55:33 +00:00
value &= 0x7fff;
2019-12-09 18:02:15 +00:00
if (cookie.remap.size() < value + 1)
cookie.remap.resize(value + 1);
cookie.remap[value] = e->id;
2019-12-08 18:55:33 +00:00
break;
case SYMBOL_ENTRY+SYMBOL_ABSOLUTE:
if (e->defined && e->absolute && e->value == value)
break; /* allow redef */
case SYMBOL_ENTRY:
if (e->defined) {
2019-12-09 18:02:15 +00:00
warnx("%s previously defined (%s)", e->name.c_str(), e->file.c_str());
2019-12-08 18:55:33 +00:00
break;
}
e->defined = true;
2019-12-09 18:02:15 +00:00
e->file = cookie.file;
2019-12-15 02:56:52 +00:00
e->segment = segnum;
2019-12-08 18:55:33 +00:00
if (flag & SYMBOL_ABSOLUTE) {
e->absolute = true;
e->value = value;
} else {
e->absolute = false;
2019-12-10 03:15:55 +00:00
e->value = value - 0x8000 + cookie.begin;
2019-12-08 18:55:33 +00:00
}
break;
default:
2019-12-09 18:02:15 +00:00
errx(1, "%s: Unsupported flag: %02x\n", cookie.file.c_str(), flag);
break;
2019-12-08 18:55:33 +00:00
}
}
}
2019-12-15 00:01:12 +00:00
static void process_reloc(byte_view &data, cookie &cookie) {
2019-12-09 18:02:15 +00:00
2019-12-10 00:45:45 +00:00
auto &seg = segments.back();
2019-12-15 00:01:12 +00:00
auto &pending = relocations.back();
2019-12-08 18:55:33 +00:00
for(;;) {
assert(data.size());
unsigned flag = data[0];
if (flag == 0x00) return;
assert(data.size() >= 4);
uint32_t offset = data[1] | (data[2] << 8);
unsigned x = data[3];
data.remove_prefix(4);
2019-12-10 03:15:55 +00:00
offset += cookie.begin;
2019-12-08 18:55:33 +00:00
bool external = false;
bool ddb = false;
2019-12-08 18:55:33 +00:00
unsigned shift = 0;
uint32_t value = 0;
unsigned size = 0;
if (flag == 0xff) {
/* shift */
assert(data.size() >= 4);
unsigned flag = data[0];
value = data[1] | (data[2] << 8) | (data[3] << 16);
value -= 0x8000;
external = flag & 0x04;
switch(flag & ~0x04) {
case 0xd0:
2019-12-10 02:58:01 +00:00
shift = -16;
2019-12-08 18:55:33 +00:00
size = 1;
break;
case 0xd1:
2019-12-10 02:58:01 +00:00
shift = -8;
2019-12-08 18:55:33 +00:00
size = 2;
break;
case 0xd3:
2019-12-10 02:58:01 +00:00
shift = -8;
2019-12-08 18:55:33 +00:00
size = 1;
break;
default: /* bad */
2019-12-09 18:02:15 +00:00
errx(1, "%s: Unsupported flag: %02x\n", cookie.file.c_str(), flag);
break;
2019-12-08 18:55:33 +00:00
}
2019-12-10 02:58:01 +00:00
data.remove_prefix(4);
2019-12-08 18:55:33 +00:00
} else {
2019-12-10 03:15:55 +00:00
// offset already adjusted by start so below comparisons are wrong.
switch(flag & 0xf0) {
case 0x00:
case 0x10:
2019-12-09 18:02:15 +00:00
size = 1;
break;
case 0x20:
case 0x30:
2019-12-09 18:02:15 +00:00
size = 3;
break;
case 0x40:
size = 1;
shift = -8;
2019-12-09 18:02:15 +00:00
break;
case 0x80:
case 0x90:
2019-12-09 18:02:15 +00:00
size = 2;
break;
case 0xa0:
case 0xb0:
/* ddb */
size = 2;
ddb = true;
break;
case 0xc0: /* ds fill */
case 0xe0: /* err constraint */
return;
2019-12-08 18:55:33 +00:00
default: /* bad size */
2019-12-09 18:02:15 +00:00
errx(1, "%s: Unsupported flag: %02x\n", cookie.file.c_str(), flag);
break;
2019-12-08 18:55:33 +00:00
}
external = flag & 0x10;
assert(offset + size <= cookie.end);
2019-12-08 18:55:33 +00:00
switch(size) {
2019-12-10 00:45:45 +00:00
case 3: value |= seg.data[offset+2] << 16;
case 2: value |= seg.data[offset+1] << 8;
case 1: value |= seg.data[offset+0];
2019-12-08 18:55:33 +00:00
}
if (ddb) value = ((value >> 8) | (value << 8)) & 0xffff;
if (flag & 0x40) {
/* value is already shifted, so need to adjust back */
value <<= 8;
value += x; /* low-byte of address */
value -= 0x8000;
assert(!external);
}
2019-12-08 18:55:33 +00:00
if (size > 1) value -= 0x8000;
}
/* clear out the inline relocation data */
for (unsigned i = 0; i < size; ++i) {
seg.data[offset + i] = 0;
}
if (ddb) {
/*
* ddb - data is stored inline in big-endian format.
* generate 1-byte, -8 shift for offset+0
* generate 1-byte, 0 shift for offset+1
*/
if (external) {
pending_reloc r;
assert(x < cookie.remap.size());
r.id = cookie.remap[x];
r.size = 1;
r.offset = offset;
r.value = value;
r.shift = -8;
symbol_table[r.id].count += 1;
pending.emplace_back(r);
pending.emplace_back(r);
r.offset++;
r.shift = 0;
pending.emplace_back(r);
} else {
omf::reloc r;
r.size = 1;
r.offset = offset;
r.value = value + cookie.begin;
r.shift = -8;
seg.relocs.emplace_back(r);
r.offset++;
r.shift = 0;
seg.relocs.emplace_back(r);
}
return;
}
2019-12-08 18:55:33 +00:00
/* external resolutions are deferred for later */
if (external) {
/* x = local symbol # */
2019-12-09 18:02:15 +00:00
pending_reloc r;
assert(x < cookie.remap.size());
r.id = cookie.remap[x];
2019-12-08 18:55:33 +00:00
r.size = size;
r.offset = offset;
r.value = value;
r.shift = shift;
2019-12-10 00:45:45 +00:00
symbol_table[r.id].count += 1;
2019-12-15 00:01:12 +00:00
pending.emplace_back(r);
2019-12-08 18:55:33 +00:00
} else {
omf::reloc r;
r.size = size;
2019-12-10 03:15:55 +00:00
r.offset = offset;
r.value = value + cookie.begin;
2019-12-08 18:55:33 +00:00
r.shift = shift;
seg.relocs.emplace_back(r);
}
2019-12-10 02:58:01 +00:00
//cookie.zero.emplace_back(std::make_pair(offset, size));
2019-12-08 18:55:33 +00:00
}
}
static void process_ds_err(byte_view &data) {
auto &seg = segments.back();
for(;;) {
assert(data.size());
unsigned flag = data[0];
if (flag == 0x00) return;
assert(data.size() >= 4);
if (flag == 0xcf) {
/* ds \ fill. */
uint8_t c = data[3];
size_t sz = seg.data.size() & 0xff;
if (sz) {
seg.data.insert(seg.data.end(), 0x100-sz, c);
}
}
if (flag == 0xef) {
/* err \ constraint */
size_t sz = seg.data.size() + org;
uint32_t addr = (data[1] << 0) | (data[2] << 8) | (data[3] << 16);
if (sz >= addr) {
warnx("Constraint at $%04x excess = $%04x", addr, static_cast<uint32_t>(sz - addr));
}
}
if (flag == 0xff) {
assert(data.size() >= 8);
data.remove_prefix(8);
} else {
data.remove_prefix(4);
}
}
}
2019-12-15 00:01:12 +00:00
static void process_unit(const std::string &path) {
2019-12-08 18:55:33 +00:00
2019-12-09 18:02:15 +00:00
cookie cookie;
2019-12-08 18:55:33 +00:00
/* skip over relocs, do symbols first */
if (verbose) printf("Linking %s\n", path.c_str());
2019-12-09 18:02:15 +00:00
std::error_code ec;
mapped_file mf(path, mapped_file::readonly, ec);
if (ec) {
2019-12-10 00:45:45 +00:00
errx(1, "Unable to open %s: %s", path.c_str(), ec.message().c_str());
2019-12-09 18:02:15 +00:00
}
afp::finder_info fi;
fi.read(path, ec);
if (ec) {
errx(1, "Error reading filetype %s: %s", path.c_str(), ec.message().c_str());
}
if (fi.prodos_file_type() != 0xf8) {
errx(1, "Wrong file type: %s", path.c_str());
}
uint32_t offset = fi.prodos_aux_type();
if (offset+2 > mf.size()) {
errx(1, "Invalid aux type %s", path.c_str());
}
2019-12-15 00:01:12 +00:00
auto &seg = segments.back();
2019-12-09 18:02:15 +00:00
2019-12-10 03:15:55 +00:00
cookie.begin = seg.data.size();
cookie.end = cookie.begin + offset;
2019-12-09 18:02:15 +00:00
cookie.file = path;
2019-12-10 02:58:01 +00:00
seg.data.insert(seg.data.end(), mf.data(), mf.data() + offset);
byte_view data(mf.data() + offset, mf.size() - offset);
2019-12-09 18:02:15 +00:00
byte_view rr = data;
/* skip over the relocation records so we can process the labels first. */
/* this is so external references can use the global symbol id */
2019-12-10 02:58:01 +00:00
assert(data.size() >= 2);
2019-12-08 18:55:33 +00:00
for(;;) {
if (data[0] == 0) break;
2019-12-10 02:58:01 +00:00
assert(data.size() >= 6);
2019-12-08 18:55:33 +00:00
data.remove_prefix(4);
}
data.remove_prefix(1);
2019-12-09 18:02:15 +00:00
process_labels(data, cookie);
assert(data.size() == 1);
2019-12-08 18:55:33 +00:00
/* now relocations */
process_ds_err(rr);
2019-12-09 18:02:15 +00:00
process_reloc(rr, cookie);
2019-12-15 00:01:12 +00:00
2019-12-15 00:01:12 +00:00
// LEN support
/* per empirical merlin testing,
LEN/POS opcodes not affected by DS \ fills.
*/
len_var = offset;
pos_var += offset;
2019-12-08 18:55:33 +00:00
}
2019-12-15 00:01:12 +00:00
static void import(const std::string &path, const std::string &name) {
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
std::error_code ec;
mapped_file mf(path, mapped_file::readonly, ec);
if (ec) {
errx(1, "Unable to open %s: %s", path.c_str(), ec.message().c_str());
}
2019-12-08 18:55:33 +00:00
2019-12-10 00:45:45 +00:00
auto &seg = segments.back();
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
// check for duplicate label.
auto e = find_symbol(name);
if (e->defined) {
warnx("Duplicate symbol %s", name.c_str());
return;
}
2019-12-15 00:01:12 +00:00
e->file = path;
e->defined = true;
e->value = seg.data.size();
2019-12-21 22:32:06 +00:00
e->segment = segments.back().segnum;
2019-12-15 00:01:12 +00:00
seg.data.insert(seg.data.end(), mf.data(), mf.data() + mf.size());
// LEN support
len_var = mf.size();
pos_var += mf.size();
2019-12-15 00:01:12 +00:00
}
static void resolve(bool allow_unresolved = false) {
2019-12-15 00:01:12 +00:00
2019-12-15 02:56:52 +00:00
for (unsigned ix = 0; ix < segments.size(); ++ix) {
2019-12-15 02:56:52 +00:00
auto &seg = segments[ix];
auto &pending = relocations[ix];
2019-12-15 00:01:12 +00:00
std::vector<pending_reloc> unresolved;
if ((seg.kind & 0x0001) == 0x0001 && seg.data.size() > 65535) {
throw std::runtime_error("code exceeds bank");
}
2019-12-15 00:01:12 +00:00
for (auto &r : pending) {
assert(r.id < symbol_map.size());
const auto &e = symbol_table[r.id];
if (!e.defined) {
if (allow_unresolved) {
unresolved.emplace_back(std::move(r));
} else {
warnx("%s is not defined", e.name.c_str());
}
2019-12-15 00:01:12 +00:00
continue;
}
2019-12-15 00:01:12 +00:00
/* if this is an absolute value, do the math */
2019-12-15 00:01:12 +00:00
if (e.absolute) {
uint32_t value = e.value + r.value;
/* shift is a uint8_t so negating doesn't work right */
value >>= -(int8_t)r.shift;
unsigned offset = r.offset;
unsigned size = r.size;
while (size--) {
seg.data[offset++] = value & 0xff;
value >>= 8;
}
continue;
}
2019-12-15 02:56:52 +00:00
if (e.segment == seg.segnum) {
2019-12-15 00:01:12 +00:00
r.value += e.value;
seg.relocs.emplace_back(r);
continue;
}
omf::interseg inter;
inter.size = r.size;
inter.shift = r.shift;
inter.offset = r.offset;
2019-12-15 02:56:52 +00:00
inter.segment = e.segment;
2019-12-15 00:01:12 +00:00
inter.segment_offset = r.value + e.value;
seg.intersegs.emplace_back(inter);
}
2019-12-15 00:01:12 +00:00
pending.clear();
2019-12-15 00:01:12 +00:00
/* sort them */
std::sort(seg.relocs.begin(), seg.relocs.end(), [](const auto &a, const auto &b){
return a.offset < b.offset;
});
2019-12-15 00:01:12 +00:00
std::sort(seg.intersegs.begin(), seg.intersegs.end(), [](const auto &a, const auto &b){
return a.offset < b.offset;
});
std::sort(unresolved.begin(), unresolved.end(), [](const auto &a, const auto &b){
return a.offset < b.offset;
});
pending = std::move(unresolved);
2019-12-15 00:01:12 +00:00
}
2019-12-08 18:55:33 +00:00
}
2019-12-15 18:06:05 +00:00
2020-06-03 14:57:05 +00:00
static void print_symbols2(const std::vector<size_t> &ix) {
size_t len = 8;
for (const auto &e : symbol_table) {
len = std::max(len, e.name.size());
}
2020-06-03 14:57:05 +00:00
for (auto i : ix) {
const auto &e = symbol_table[i];
char q = ' ';
if (!e.count) q = '?';
if (!e.defined) q = '!';
uint32_t value = e.value;
if (!e.absolute) value += (e.segment << 16);
fprintf(stdout, "%c %-*s=$%06x\n", q, (int)len, e.name.c_str(), value);
}
}
2019-12-15 00:01:12 +00:00
static void print_symbols(void) {
2019-12-08 18:55:33 +00:00
if (symbol_table.empty()) return;
2020-06-03 14:57:05 +00:00
std::vector<size_t> ix(symbol_table.size());
std::iota(ix.begin(), ix.end(), 0);
2019-12-08 18:55:33 +00:00
/* alpha */
fputs("\nSymbol table, alphabetical order:\n", stdout);
2020-06-03 14:57:05 +00:00
std::sort(ix.begin(), ix.end(), [&](const size_t a, const size_t b){
const symbol &aa = symbol_table[a];
const symbol &bb = symbol_table[b];
return aa.name < bb.name;
});
#if 0
2019-12-08 18:55:33 +00:00
std::sort(symbol_table.begin(), symbol_table.end(),
[](const symbol &a, const symbol &b){
return a.name < b.name;
});
2020-06-03 14:57:05 +00:00
#endif
print_symbols2(ix);
2019-12-08 18:55:33 +00:00
2020-06-03 14:57:05 +00:00
std::iota(ix.begin(), ix.end(), 0);
fputs("\nSymbol table, numerical order:\n", stdout);
/* numeric, factoring in segment #, absolute first */
2020-06-03 14:57:05 +00:00
std::sort(ix.begin(), ix.end(), [&](const size_t a, const size_t b){
const symbol &aa = symbol_table[a];
const symbol &bb = symbol_table[b];
/* absolute have a segment # of 0 so will sort first */
auto aaa = std::make_pair(aa.segment, aa.value);
auto bbb = std::make_pair(bb.segment, bb.value);
return aaa < bbb;
});
#if 0
2019-12-08 18:55:33 +00:00
std::sort(symbol_table.begin(), symbol_table.end(),
[](const symbol &a, const symbol &b){
/* absolute have a segment # of 0 so will sort first */
auto aa = std::make_pair(a.segment, a.value);
auto bb = std::make_pair(b.segment, b.value);
return aa < bb;
2019-12-08 18:55:33 +00:00
});
2020-06-03 14:57:05 +00:00
#endif
print_symbols2(ix);
2019-12-21 22:51:15 +00:00
fputs("\n", stdout);
2019-12-10 00:45:45 +00:00
}
2020-06-03 03:33:34 +00:00
static void check_exd(void) {
for (const auto &e : symbol_table) {
if (!e.exd) continue;
if (!e.defined) continue;
if (e.absolute && e.value < 0x0100) continue;
if (!e.absolute && lkv == 0 && (e.value + org) < 0x0100) continue;
warnx("%s defined as direct page", e.name.c_str());
}
}
2019-12-10 00:45:45 +00:00
2019-12-15 00:01:12 +00:00
void finish(void) {
resolve();
std::string path = save_file;
2019-12-21 22:51:15 +00:00
if (path.empty()) path = "omf.out";
2019-12-15 18:04:45 +00:00
2019-12-21 22:51:15 +00:00
if (verbose) printf("Saving %s\n", path.c_str());
2019-12-15 00:01:12 +00:00
try {
2019-12-15 18:04:45 +00:00
if (lkv == 0)
2020-11-13 00:24:28 +00:00
save_bin(path, segments.back());
2019-12-15 18:04:45 +00:00
else
2022-12-08 23:37:36 +00:00
save_omf(path, segments, compress, express, ver);
2019-12-15 18:04:45 +00:00