WIP
This commit is contained in:
parent
5866fc8bc8
commit
a4dfcec1f1
|
@ -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)
|
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
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit b440a35d29dd7cf28eb2911bd2cb3b078b65fb0a
|
147
link.cpp
147
link.cpp
|
@ -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
2
ops.h
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue