mirror of
https://github.com/ksherlock/merlin-utils.git
synced 2024-12-26 21:30:47 +00:00
WIP
This commit is contained in:
parent
5866fc8bc8
commit
a4dfcec1f1
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "afp"]
|
||||
path = afp
|
||||
url = https://github.com/ksherlock/afp
|
18
Makefile
18
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
|
||||
|
1
afp
Submodule
1
afp
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit b440a35d29dd7cf28eb2911bd2cb3b078b65fb0a
|
147
link.cpp
147
link.cpp
@ -3,11 +3,26 @@
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#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 "rel.h"
|
||||
|
||||
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 {
|
||||
std::string name;
|
||||
@ -27,10 +42,14 @@ struct pending_reloc : public omf::reloc {
|
||||
std::unordered_map<std::string, unsigned> symbol_map;
|
||||
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);
|
||||
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<unsigned> remap;
|
||||
struct cookie {
|
||||
std::string file;
|
||||
std::vector<unsigned> 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());
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user