From a4dfcec1f10666d3b9f1d8cb07246411120811b3 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Mon, 9 Dec 2019 13:02:15 -0500 Subject: [PATCH] WIP --- .gitmodules | 3 ++ Makefile | 18 +++++-- afp | 1 + link.cpp | 147 ++++++++++++++++++++++++++++++++++++++++------------ ops.h | 2 - script.re2c | 6 +++ 6 files changed, 138 insertions(+), 39 deletions(-) create mode 100644 .gitmodules create mode 160000 afp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8e5ca65 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "afp"] + path = afp + url = https://github.com/ksherlock/afp diff --git a/Makefile b/Makefile index 0f44e56..24b9ad9 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,21 @@ LINK.o = $(LINK.cc) CXXFLAGS = -std=c++17 -g -Wall -Wno-sign-compare CCFLAGS = -g +CPPFLAGS += -I afp/include -.PHONY: all +.PHONY: all clean all: rel-link +clean: + $(RM) -rf rel-link o + $(MAKE) -C afp clean + o: 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 $@ 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/%.o: %.cpp | o - $(CXX) $(CXXFLAGS) -c -o $@ $< + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< %.cpp: %.re2c re2c -W -o $@ $< + +.PHONY: subdirs +subdirs: + $(MAKE) -C afp + + +afp/libafp.a : subdirs diff --git a/afp b/afp new file mode 160000 index 0000000..b440a35 --- /dev/null +++ b/afp @@ -0,0 +1 @@ +Subproject commit b440a35d29dd7cf28eb2911bd2cb3b078b65fb0a diff --git a/link.cpp b/link.cpp index b81fd51..c802c4e 100644 --- a/link.cpp +++ b/link.cpp @@ -3,11 +3,26 @@ #include #include #include +#include +#include + +#include +#include +#include + +#include + +#include + #include "omf.h" +#include "rel.h" void save_omf(const std::string &path, std::vector &segments, bool compress, bool expressload); +/* since span isn't standard yet */ +typedef std::basic_string_view byte_view; + struct symbol { std::string name; @@ -27,10 +42,14 @@ struct pending_reloc : public omf::reloc { std::unordered_map symbol_map; std::vector symbol_table; -reference *find_symbol(const std::string &name) { + +std::vector segments; + +/* nb - pointer may be invalidated by next call */ +symbol *find_symbol(const std::string &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; symbol_map.emplace(name, id); @@ -38,19 +57,22 @@ reference *find_symbol(const std::string &name) { auto &rv = symbol_table.emplace_back(); rv.name = name; rv.id = id; - return *rv; + return &rv; } -uint32_t start = 0; /* starting point of current unit */ -std::vector remap; +struct cookie { + std::string file; + std::vector remap; + uint32_t start = 0; + uint32_t length = 0; +}; - -process_labels(std::span &data) { +void process_labels(byte_view &data, cookie &cookie) { for(;;) { - assert(data.size()) + assert(data.size()); unsigned flag = data[0]; if (flag == 0x00) return; @@ -63,14 +85,14 @@ process_labels(std::span &data) { uint32_t value = data[0] | (data[1] << 8) | (data[2] << 16); data.remove_prefix(3); - reference *e = find_symbol(name); + symbol *e = find_symbol(name); switch (flag & ~0x1f) { case SYMBOL_EXTERNAL: /* map the unit symbol # to a global symbol # */ value &= 0x7fff; - if (remap.size() < value + 1) - remap.resize(value + 1); - remap[value] = e->id; + if (cookie.remap.size() < value + 1) + cookie.remap.resize(value + 1); + cookie.remap[value] = e->id; break; @@ -80,26 +102,30 @@ process_labels(std::span &data) { case SYMBOL_ENTRY: 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; } e->defined = true; - e->file = file; + e->file = cookie.file; if (flag & SYMBOL_ABSOLUTE) { e->absolute = true; e->value = value; } else { e->absolute = false; - e->value = value - 0x8000 + start; + e->value = value - 0x8000 + cookie.start; } break; 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(;;) { assert(data.size()); @@ -112,7 +138,7 @@ process_reloc(std::span &data) { unsigned x = data[3]; data.remove_prefix(4); - offset += start; + offset += cookie.start; bool external = false; unsigned shift = 0; uint32_t value = 0; @@ -139,16 +165,29 @@ process_reloc(std::span &data) { size = 1; break; default: /* bad */ + errx(1, "%s: Unsupported flag: %02x\n", cookie.file.c_str(), flag); + break; } } else { - assert(flag & ~(0x0f|0x10|0x20|0x80) == 0); + assert((flag & ~(0x0f|0x10|0x20|0x80)) == 0); unsigned size = 0; switch(flag & (0x80 + 0x20)) { - case 0: size = 1; - case 0x20: size = 3; - case 0x80: size = 2; + case 0: + size = 1; + 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 */ + errx(1, "%s: Unsupported flag: %02x\n", cookie.file.c_str(), flag); + break; } external = flag & 0x10; @@ -160,7 +199,7 @@ process_reloc(std::span &data) { if (size > 1) value -= 0x8000; - value += start; + value += cookie.start; } @@ -168,9 +207,9 @@ process_reloc(std::span &data) { if (external) { /* x = local symbol # */ - reloc r; - assert(x < remap.size()); - r.id = remap[x]; /* label reference is 0-based */ + pending_reloc r; + assert(x < cookie.remap.size()); + r.id = cookie.remap[x]; /* label reference is 0-based */ r.size = size; r.offset = offset; r.value = value; @@ -181,7 +220,7 @@ process_reloc(std::span &data) { uint32_t value = 0; omf::reloc r; r.size = size; - r.offset = start; + r.offset = cookie.start; /* ???? */ r.value = value; r.shift = shift; @@ -191,6 +230,7 @@ process_reloc(std::span &data) { } } +/* void add_libraries() { auto iter = libs.begin(); 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 */ - 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(;;) { + assert(data.size() >= 6); if (data[0] == 0) break; data.remove_prefix(4); } data.remove_prefix(1); - process_labels(data); - assert(data.length() == 1); + process_labels(data, cookie); + assert(data.size() == 1); /* now relocations */ - process_reloc(rr); + process_reloc(rr, cookie); } -finalize(void) { +void finalize(void) { for (auto &r in relocations) { assert(r.id <= symbol_map.length()); diff --git a/ops.h b/ops.h index 986d59b..737a558 100644 --- a/ops.h +++ b/ops.h @@ -32,9 +32,7 @@ x(RID) x(RTY) x(RAT) x(FIL) -x(AUX) x(CMD) x(ZIP) x(IMP) x(PFX) - diff --git a/script.re2c b/script.re2c index ccda33c..d27e5fc 100644 --- a/script.re2c +++ b/script.re2c @@ -573,6 +573,12 @@ operand: 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: default: