This commit is contained in:
Kelvin Sherlock 2019-12-09 13:02:15 -05:00
parent 5866fc8bc8
commit a4dfcec1f1
6 changed files with 138 additions and 39 deletions

3
.gitmodules vendored Normal file
View File

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

View File

@ -1,16 +1,21 @@
LINK.o = $(LINK.cc) LINK.o = $(LINK.cc)
CXXFLAGS = -std=c++17 -g -Wall -Wno-sign-compare CXXFLAGS = -std=c++17 -g -Wall -Wno-sign-compare
CCFLAGS = -g CCFLAGS = -g
CPPFLAGS += -I afp/include
.PHONY: all .PHONY: all clean
all: rel-link all: rel-link
clean:
$(RM) -rf rel-link o
$(MAKE) -C afp clean
o: o:
mkdir $< mkdir $<
rel-link: o/link.o o/mapped_file.o o/omf.o rel-link: o/link.o o/mapped_file.o o/omf.o afp/libafp.a
$(LINK.o) $^ $(LDLIBS) -o $@ $(LINK.o) $^ $(LDLIBS) -o $@
o/mapped_file.o : mapped_file.cpp mapped_file.h unique_resource.h o/mapped_file.o : mapped_file.cpp mapped_file.h unique_resource.h
@ -18,7 +23,14 @@ o/link.o : link.cpp mapped_file.h omf.h
o/omf.o : omf.cpp omf.h o/omf.o : omf.cpp omf.h
o/%.o: %.cpp | o o/%.o: %.cpp | o
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
%.cpp: %.re2c %.cpp: %.re2c
re2c -W -o $@ $< re2c -W -o $@ $<
.PHONY: subdirs
subdirs:
$(MAKE) -C afp
afp/libafp.a : subdirs

1
afp Submodule

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

147
link.cpp
View File

@ -3,11 +3,26 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include <string_view>
#include <system_error>
#include <cstdint>
#include <cassert>
#include <cstdio>
#include <err.h>
#include <afp/finder_info.h>
#include "omf.h" #include "omf.h"
#include "rel.h"
void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool compress, bool expressload); void save_omf(const std::string &path, std::vector<omf::segment> &segments, bool compress, bool expressload);
/* since span isn't standard yet */
typedef std::basic_string_view<uint8_t> byte_view;
struct symbol { struct symbol {
std::string name; std::string name;
@ -27,10 +42,14 @@ struct pending_reloc : public omf::reloc {
std::unordered_map<std::string, unsigned> symbol_map; std::unordered_map<std::string, unsigned> symbol_map;
std::vector<symbol> symbol_table; std::vector<symbol> symbol_table;
reference *find_symbol(const std::string &name) {
std::vector<omf::segment> segments;
/* nb - pointer may be invalidated by next call */
symbol *find_symbol(const std::string &name) {
auto iter = symbol_map.find(name); auto iter = symbol_map.find(name);
if (iter != symbol_map.end()) return &symbol_table[*iter - 1]; if (iter != symbol_map.end()) return &symbol_table[iter->second - 1];
unsigned id = symbol_table.size() + 1; unsigned id = symbol_table.size() + 1;
symbol_map.emplace(name, id); symbol_map.emplace(name, id);
@ -38,19 +57,22 @@ reference *find_symbol(const std::string &name) {
auto &rv = symbol_table.emplace_back(); auto &rv = symbol_table.emplace_back();
rv.name = name; rv.name = name;
rv.id = id; rv.id = id;
return *rv; return &rv;
} }
uint32_t start = 0; /* starting point of current unit */ struct cookie {
std::vector<unsigned> remap; std::string file;
std::vector<unsigned> remap;
uint32_t start = 0;
uint32_t length = 0;
};
void process_labels(byte_view &data, cookie &cookie) {
process_labels(std::span &data) {
for(;;) { for(;;) {
assert(data.size()) assert(data.size());
unsigned flag = data[0]; unsigned flag = data[0];
if (flag == 0x00) return; if (flag == 0x00) return;
@ -63,14 +85,14 @@ process_labels(std::span &data) {
uint32_t value = data[0] | (data[1] << 8) | (data[2] << 16); uint32_t value = data[0] | (data[1] << 8) | (data[2] << 16);
data.remove_prefix(3); data.remove_prefix(3);
reference *e = find_symbol(name); symbol *e = find_symbol(name);
switch (flag & ~0x1f) { switch (flag & ~0x1f) {
case SYMBOL_EXTERNAL: case SYMBOL_EXTERNAL:
/* map the unit symbol # to a global symbol # */ /* map the unit symbol # to a global symbol # */
value &= 0x7fff; value &= 0x7fff;
if (remap.size() < value + 1) if (cookie.remap.size() < value + 1)
remap.resize(value + 1); cookie.remap.resize(value + 1);
remap[value] = e->id; cookie.remap[value] = e->id;
break; break;
@ -80,26 +102,30 @@ process_labels(std::span &data) {
case SYMBOL_ENTRY: case SYMBOL_ENTRY:
if (e->defined) { if (e->defined) {
warnx("%s previously defined (%s)", e->name, e->file); warnx("%s previously defined (%s)", e->name.c_str(), e->file.c_str());
break; break;
} }
e->defined = true; e->defined = true;
e->file = file; e->file = cookie.file;
if (flag & SYMBOL_ABSOLUTE) { if (flag & SYMBOL_ABSOLUTE) {
e->absolute = true; e->absolute = true;
e->value = value; e->value = value;
} else { } else {
e->absolute = false; e->absolute = false;
e->value = value - 0x8000 + start; e->value = value - 0x8000 + cookie.start;
} }
break; break;
default: default:
errx(1, "%s: Unsupported flag: %02x\n", cookie.file.c_str(), flag);
break;
} }
} }
} }
process_reloc(std::span &data) { void process_reloc(byte_view &data, cookie &cookie) {
auto &seg_data = segments.back().data;
for(;;) { for(;;) {
assert(data.size()); assert(data.size());
@ -112,7 +138,7 @@ process_reloc(std::span &data) {
unsigned x = data[3]; unsigned x = data[3];
data.remove_prefix(4); data.remove_prefix(4);
offset += start; offset += cookie.start;
bool external = false; bool external = false;
unsigned shift = 0; unsigned shift = 0;
uint32_t value = 0; uint32_t value = 0;
@ -139,16 +165,29 @@ process_reloc(std::span &data) {
size = 1; size = 1;
break; break;
default: /* bad */ default: /* bad */
errx(1, "%s: Unsupported flag: %02x\n", cookie.file.c_str(), flag);
break;
} }
} else { } else {
assert(flag & ~(0x0f|0x10|0x20|0x80) == 0); assert((flag & ~(0x0f|0x10|0x20|0x80)) == 0);
unsigned size = 0; unsigned size = 0;
switch(flag & (0x80 + 0x20)) { switch(flag & (0x80 + 0x20)) {
case 0: size = 1; case 0:
case 0x20: size = 3; size = 1;
case 0x80: size = 2; assert(offset + 0 < cookie.length);
break;
case 0x20:
size = 3;
assert(offset + 2 < cookie.length);
break;
case 0x80:
size = 2;
assert(offset + 1 < cookie.length);
break;
default: /* bad size */ default: /* bad size */
errx(1, "%s: Unsupported flag: %02x\n", cookie.file.c_str(), flag);
break;
} }
external = flag & 0x10; external = flag & 0x10;
@ -160,7 +199,7 @@ process_reloc(std::span &data) {
if (size > 1) value -= 0x8000; if (size > 1) value -= 0x8000;
value += start; value += cookie.start;
} }
@ -168,9 +207,9 @@ process_reloc(std::span &data) {
if (external) { if (external) {
/* x = local symbol # */ /* x = local symbol # */
reloc r; pending_reloc r;
assert(x < remap.size()); assert(x < cookie.remap.size());
r.id = remap[x]; /* label reference is 0-based */ r.id = cookie.remap[x]; /* label reference is 0-based */
r.size = size; r.size = size;
r.offset = offset; r.offset = offset;
r.value = value; r.value = value;
@ -181,7 +220,7 @@ process_reloc(std::span &data) {
uint32_t value = 0; uint32_t value = 0;
omf::reloc r; omf::reloc r;
r.size = size; r.size = size;
r.offset = start; r.offset = cookie.start; /* ???? */
r.value = value; r.value = value;
r.shift = shift; r.shift = shift;
@ -191,6 +230,7 @@ process_reloc(std::span &data) {
} }
} }
/*
void add_libraries() { void add_libraries() {
auto iter = libs.begin(); auto iter = libs.begin();
auto end = libs.end(); auto end = libs.end();
@ -201,29 +241,68 @@ void add_libraries() {
} }
} }
*/
void process_unit(const std::string &path) {
process_unit(span data) { cookie cookie;
/* skip over relocs, do symbols first */ /* skip over relocs, do symbols first */
remap.clear();
span rr = data;
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());
}
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());
}
omf::segment &seg = segments.back();
seg.data.append(mf.data(), mf.data() + offset);
byte_view data(mf.data() + offset, mf.size() - offset);
cookie.start = seg.data.size();
cookie.length = offset;
cookie.file = path;
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 */
for(;;) { for(;;) {
assert(data.size() >= 6);
if (data[0] == 0) break; if (data[0] == 0) break;
data.remove_prefix(4); data.remove_prefix(4);
} }
data.remove_prefix(1); data.remove_prefix(1);
process_labels(data); process_labels(data, cookie);
assert(data.length() == 1); assert(data.size() == 1);
/* now relocations */ /* now relocations */
process_reloc(rr); process_reloc(rr, cookie);
} }
finalize(void) { void finalize(void) {
for (auto &r in relocations) { for (auto &r in relocations) {
assert(r.id <= symbol_map.length()); assert(r.id <= symbol_map.length());

2
ops.h
View File

@ -32,9 +32,7 @@ x(RID)
x(RTY) x(RTY)
x(RAT) x(RAT)
x(FIL) x(FIL)
x(AUX)
x(CMD) x(CMD)
x(ZIP) x(ZIP)
x(IMP) x(IMP)
x(PFX) x(PFX)

View File

@ -573,6 +573,12 @@ operand:
break; break;
case CMD_LEN:
/* Puts "LABEL" in symbol dictionary a san ENTry whose value is equal to the number of bytes of the last linked file. */
break;
case CMD_POS:
case CMD_ASM: case CMD_ASM:
default: default: