mirror of
https://github.com/ksherlock/wdc-utils.git
synced 2024-09-29 22:57:16 +00:00
link.c now compiles…
This commit is contained in:
parent
174acc708c
commit
c5f2ed5562
265
link.cpp
265
link.cpp
@ -8,10 +8,15 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "obj816.h"
|
#include "obj816.h"
|
||||||
#include "expression.h"
|
#include "expression.h"
|
||||||
@ -23,6 +28,7 @@ struct section {
|
|||||||
std::string name;
|
std::string name;
|
||||||
uint8_t flags = 0;
|
uint8_t flags = 0;
|
||||||
uint32_t org = 0;
|
uint32_t org = 0;
|
||||||
|
uint32_t size = 0;
|
||||||
|
|
||||||
unsigned number = -1;
|
unsigned number = -1;
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
@ -37,6 +43,111 @@ struct symbol {
|
|||||||
int section = -1;
|
int section = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
uint8_t read_8(T &iter) {
|
||||||
|
uint8_t tmp = *iter;
|
||||||
|
++iter;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
uint16_t read_16(T &iter) {
|
||||||
|
uint16_t tmp = 0;
|
||||||
|
|
||||||
|
tmp |= *iter << 0;
|
||||||
|
++iter;
|
||||||
|
tmp |= *iter << 8;
|
||||||
|
++iter;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
uint32_t read_32(T &iter) {
|
||||||
|
uint32_t tmp = 0;
|
||||||
|
|
||||||
|
tmp |= *iter << 0;
|
||||||
|
++iter;
|
||||||
|
tmp |= *iter << 8;
|
||||||
|
++iter;
|
||||||
|
tmp |= *iter << 16;
|
||||||
|
++iter;
|
||||||
|
tmp |= *iter << 24;
|
||||||
|
++iter;
|
||||||
|
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
std::string read_cstring(T &iter) {
|
||||||
|
std::string s;
|
||||||
|
for(;;) {
|
||||||
|
uint8_t c = *iter;
|
||||||
|
++iter;
|
||||||
|
if (!c) break;
|
||||||
|
s.push_back(c);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
std::string read_pstring(T &iter) {
|
||||||
|
std::string s;
|
||||||
|
unsigned size = *iter;
|
||||||
|
++iter;
|
||||||
|
s.reserve(size);
|
||||||
|
while (size--) {
|
||||||
|
uint8_t c = *iter;
|
||||||
|
++iter;
|
||||||
|
s.push_back(c);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<section> read_sections(const std::vector<uint8_t> §ion_data) {
|
||||||
|
|
||||||
|
std::vector<section> sections;
|
||||||
|
auto iter = section_data.begin();
|
||||||
|
while (iter != section_data.end()) {
|
||||||
|
|
||||||
|
section s;
|
||||||
|
|
||||||
|
s.number = read_8(iter);
|
||||||
|
s.flags = read_8(iter);
|
||||||
|
s.size = read_32(iter);
|
||||||
|
s.org = read_32(iter);
|
||||||
|
|
||||||
|
if (!(s.flags & SEC_NONAME)) s.name = read_cstring(iter);
|
||||||
|
|
||||||
|
sections.emplace_back(std::move(s));
|
||||||
|
}
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<symbol> read_symbols(const std::vector<uint8_t> &symbol_data) {
|
||||||
|
|
||||||
|
std::vector<symbol> symbols;
|
||||||
|
|
||||||
|
auto iter = symbol_data.begin();
|
||||||
|
while (iter != symbol_data.end()) {
|
||||||
|
symbol s;
|
||||||
|
s.type = read_8(iter);
|
||||||
|
s.flags = read_8(iter);
|
||||||
|
s.section = read_8(iter);
|
||||||
|
s.offset = s.type == S_UND ? 0 : read_32(iter);
|
||||||
|
s.name = read_cstring(iter);
|
||||||
|
|
||||||
|
|
||||||
|
symbols.emplace_back(std::move(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::unordered_map<std::string, int> section_map;
|
std::unordered_map<std::string, int> section_map;
|
||||||
std::vector<section> sections;
|
std::vector<section> sections;
|
||||||
|
|
||||||
@ -65,28 +176,29 @@ void simplify() {
|
|||||||
|
|
||||||
if (t.tag == OP_SYM) {
|
if (t.tag == OP_SYM) {
|
||||||
const auto &ss = symbols[t.section];
|
const auto &ss = symbols[t.section];
|
||||||
if (ss.type == S_UND) e.undefined = true;
|
switch(ss.type & 0x0f) {
|
||||||
else {
|
case S_UND:
|
||||||
switch(ss.flags & 0x0f) {
|
e.undefined = true;
|
||||||
case SF_REL:
|
break;
|
||||||
t = expr{OP_LOC, ss.offset, ss.section};
|
case S_REL:
|
||||||
|
t = expr{OP_LOC, ss.offset, (uint32_t)ss.section};
|
||||||
delta = true;
|
delta = true;
|
||||||
break;
|
break;
|
||||||
case SF_ABS:
|
case S_ABS:
|
||||||
t = expr{OP_VAL, ss.offset};
|
t = expr{OP_VAL, (uint32_t)ss.offset};
|
||||||
delta = true;
|
delta = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (e.stack.size() > 1) simplify_expression(e);
|
if (e.stack.size() > 1) simplify_expression(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* read and process all sections...
|
* read and process all sections...
|
||||||
* if section > 5, remap based on name.
|
* if section > 5, remap based on name.
|
||||||
@ -97,22 +209,22 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
|
|
||||||
std::array<int, 256> remap_section;
|
std::array<int, 256> remap_section;
|
||||||
|
|
||||||
int current_section = CODE;
|
int current_section = SECT_CODE;
|
||||||
section *section_ptr = §ions[current_section];
|
std::vector<uint8_t> *data_ptr = §ions[current_section].data;
|
||||||
|
|
||||||
std::fill(remap_section.begin(), remap_section.end(), -1);
|
std::fill(remap_section.begin(), remap_section.end(), -1);
|
||||||
remap_section[PAGE0] = PAGE0;
|
remap_section[SECT_PAGE0] = SECT_PAGE0;
|
||||||
remap_section[CODE] = CODE;
|
remap_section[SECT_CODE] = SECT_CODE;
|
||||||
remap_section[KDATA] = KDATA;
|
remap_section[SECT_KDATA] = SECT_KDATA;
|
||||||
remap_section[DATA] = DATA;
|
remap_section[SECT_DATA] = SECT_DATA;
|
||||||
remap_section[UDATA] = UDATA;
|
remap_section[SECT_UDATA] = SECT_UDATA;
|
||||||
|
|
||||||
std::vector<section> local_sections = read_sections(section_data);
|
std::vector<section> local_sections = read_sections(section_data);
|
||||||
std::vector<symbol> local_symbols = read_symbols(symbol_data);
|
std::vector<symbol> local_symbols = read_symbols(symbol_data);
|
||||||
|
|
||||||
// convert local sections to global
|
// convert local sections to global
|
||||||
for (auto &s : local_sections) {
|
for (auto &s : local_sections) {
|
||||||
if (s.number <= UDATA) continue;
|
if (s.number <= SECT_UDATA) continue;
|
||||||
|
|
||||||
auto iter = section_map.find(s.name);
|
auto iter = section_map.find(s.name);
|
||||||
if (iter == section_map.end()) {
|
if (iter == section_map.end()) {
|
||||||
@ -120,9 +232,9 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
remap_section[s.number] = virtual_section;
|
remap_section[s.number] = virtual_section;
|
||||||
s.number = virtual_section;
|
s.number = virtual_section;
|
||||||
sections.emplace_back(s);
|
sections.emplace_back(s);
|
||||||
symbol_map.insert(s.name, virtual_section);
|
symbol_map.emplace(s.name, virtual_section);
|
||||||
} else {
|
} else {
|
||||||
const auto &&s = sections[iter->second];
|
const auto &ss = sections[iter->second];
|
||||||
assert(ss.flags == s.flags); // check org????
|
assert(ss.flags == s.flags); // check org????
|
||||||
remap_section[s.number] = iter->second;
|
remap_section[s.number] = iter->second;
|
||||||
s.number = iter->second;
|
s.number = iter->second;
|
||||||
@ -135,8 +247,8 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
auto iter = symbol_map.find(s.name);
|
auto iter = symbol_map.find(s.name);
|
||||||
if (iter == symbol_map.end()) {
|
if (iter == symbol_map.end()) {
|
||||||
s.section = symbols.size();
|
s.section = symbols.size();
|
||||||
symbol_map.insert(s.name, s.section);
|
symbol_map.emplace(s.name, s.section);
|
||||||
undefined_symbols.insert(s.name);
|
undefined_symbols.emplace(s.name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// already exists...
|
// already exists...
|
||||||
@ -147,7 +259,7 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remap and fudge the offset.
|
// remap and fudge the offset.
|
||||||
if (s.type & 0x0f == S_REL) {
|
if ((s.type & 0x0f) == S_REL) {
|
||||||
int virtual_section = remap_section[s.section];
|
int virtual_section = remap_section[s.section];
|
||||||
assert(virtual_section != -1);
|
assert(virtual_section != -1);
|
||||||
s.section = virtual_section;
|
s.section = virtual_section;
|
||||||
@ -163,7 +275,7 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
|
|
||||||
if (iter == symbol_map.end()) {
|
if (iter == symbol_map.end()) {
|
||||||
unsigned tmp = symbols.size();
|
unsigned tmp = symbols.size();
|
||||||
symbol_map.insert(s.name, tmp);
|
symbol_map.emplace(s.name, tmp);
|
||||||
symbols.emplace_back(s);
|
symbols.emplace_back(s);
|
||||||
} else {
|
} else {
|
||||||
auto &ss = symbols[iter->second];
|
auto &ss = symbols[iter->second];
|
||||||
@ -175,7 +287,7 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// ok if symbols are identical..
|
// ok if symbols are identical..
|
||||||
assert(ss.type == ss.type && ss.flags == s.flags && ss.section == s.section && && ss.offset == s.offset);
|
assert(ss.type == ss.type && ss.flags == s.flags && ss.section == s.section && ss.offset == s.offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,12 +298,12 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
|
|
||||||
auto iter = data.begin();
|
auto iter = data.begin();
|
||||||
for(;;) {
|
for(;;) {
|
||||||
uint8_t *op = read_8(iter);
|
uint8_t op = read_8(iter);
|
||||||
if (op == REC_END) return;
|
if (op == REC_END) return;
|
||||||
|
|
||||||
++iter;
|
++iter;
|
||||||
if (op < 0xf0) {
|
if (op < 0xf0) {
|
||||||
section->data.append(iter, iter + op);
|
data_ptr->insert(data_ptr->end(), iter, iter + op);
|
||||||
iter += op;
|
iter += op;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -199,7 +311,7 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
switch(op) {
|
switch(op) {
|
||||||
case REC_SPACE: {
|
case REC_SPACE: {
|
||||||
uint16_t count = read_16(iter);
|
uint16_t count = read_16(iter);
|
||||||
section->data.append(count, 0);
|
data_ptr->insert(data_ptr->end(), count, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +321,7 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
current_section = remap_section[s];
|
current_section = remap_section[s];
|
||||||
assert(current_section > 0 && current_section < sections.size());
|
assert(current_section > 0 && current_section < sections.size());
|
||||||
|
|
||||||
section_ptr = §ions[current_section];
|
data_ptr = §ions[current_section].data;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,15 +330,16 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case REC_RELEXPR:
|
case REC_RELEXP:
|
||||||
case REC_EXPR: {
|
case REC_EXPR: {
|
||||||
|
|
||||||
expression e;
|
expression e;
|
||||||
e.relative = op == REC_RELEXPR;
|
e.relative = op == REC_RELEXP;
|
||||||
|
|
||||||
e.offset = section_ptr->data.size();
|
e.offset = data_ptr->size();
|
||||||
e.size = read_8(iter);
|
e.size = read_8(iter);
|
||||||
section_ptr->data.append(e.size, 0);
|
|
||||||
|
data_ptr->insert(data_ptr->end(), e.size, 0);
|
||||||
|
|
||||||
/**/
|
/**/
|
||||||
for(;;) {
|
for(;;) {
|
||||||
@ -236,40 +349,40 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
switch(op) {
|
switch(op) {
|
||||||
case OP_VAL: {
|
case OP_VAL: {
|
||||||
uint32_t offset = read_32(iter);
|
uint32_t offset = read_32(iter);
|
||||||
e.stack.emplace_back(op, value);
|
e.stack.emplace_back(op, offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_SYM: {
|
case OP_SYM: {
|
||||||
uint16_t symbol = read_16(iter);
|
uint16_t symbol = read_16(iter);
|
||||||
assert(symbol < local_symbols.size());
|
assert(symbol < local_symbols.size());
|
||||||
auto &s = local_symbols[symbol];
|
auto &s = local_symbols[symbol];
|
||||||
if (s.type == S_UND) {
|
switch (s.type & 0x0f) {
|
||||||
|
case S_UND:
|
||||||
// S_UND indicates it's still undefined globally.
|
// S_UND indicates it's still undefined globally.
|
||||||
e.stack.emplace_back(OP_SYM, 0, s.section); /* section is actually a symbol number */
|
e.stack.emplace_back(OP_SYM, 0, s.section); /* section is actually a symbol number */
|
||||||
e.undefined = true;
|
e.undefined = true;
|
||||||
} else {
|
|
||||||
switch (s.flags & 0x0f) {
|
|
||||||
case SF_REL:
|
|
||||||
e.stack.emplace_back(OP_REL, s.offset, s.section);
|
|
||||||
break;
|
break;
|
||||||
case SF_ABS:
|
case S_REL:
|
||||||
|
e.stack.emplace_back(OP_LOC, s.offset, s.section);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case S_ABS:
|
||||||
e.stack.emplace_back(OP_VAL, s.offset);
|
e.stack.emplace_back(OP_VAL, s.offset);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(!"unsupported symbol flags.");
|
assert(!"unsupported symbol flags.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_LOC: {
|
case OP_LOC: {
|
||||||
uint8_t section = read_8(iter);
|
uint8_t section = read_8(iter);
|
||||||
uint32_t offset = read_32(iter);
|
uint32_t offset = read_32(iter);
|
||||||
int real_section = remap[section];
|
int real_section = remap_section[section];
|
||||||
assert(real_section >= 0);
|
assert(real_section >= 0);
|
||||||
e.stack.emplace_back(op, offset, real_section);
|
e.stack.emplace_back(op, offset, real_section);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case O
|
|
||||||
// operations..
|
// operations..
|
||||||
//unary
|
//unary
|
||||||
case OP_NOT:
|
case OP_NOT:
|
||||||
@ -315,7 +428,71 @@ void one_module(const std::vector<uint8_t> &data, const std::vector<uint8_t> &se
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
|
||||||
|
sections.resize(5);
|
||||||
|
|
||||||
|
sections[SECT_PAGE0].number = SECT_PAGE0;
|
||||||
|
sections[SECT_PAGE0].flags = SEC_DATA | SEC_NONAME | SEC_DIRECT | SEC_REF_ONLY;
|
||||||
|
sections[SECT_PAGE0].name = "page0";
|
||||||
|
|
||||||
|
sections[SECT_CODE].number = SECT_CODE;
|
||||||
|
sections[SECT_CODE].flags = SEC_NONAME;
|
||||||
|
sections[SECT_CODE].name = "code";
|
||||||
|
|
||||||
|
sections[SECT_KDATA].number = SECT_KDATA;
|
||||||
|
sections[SECT_KDATA].flags = SEC_DATA | SEC_NONAME;
|
||||||
|
sections[SECT_KDATA].name = "kdata";
|
||||||
|
|
||||||
|
sections[SECT_DATA].number = SECT_DATA;
|
||||||
|
sections[SECT_DATA].flags = SEC_DATA | SEC_NONAME;
|
||||||
|
sections[SECT_DATA].name = "data";
|
||||||
|
|
||||||
|
sections[SECT_UDATA].number = SECT_UDATA;
|
||||||
|
sections[SECT_UDATA].flags = SEC_DATA | SEC_NONAME | SEC_REF_ONLY;
|
||||||
|
sections[SECT_UDATA].name = "udata";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For each section, [the linker] creates three symbols,
|
||||||
|
* _ROM_BEG_secname, _BEG_secname and _END_secname, which
|
||||||
|
* correspond to the rom location and the execution beginning
|
||||||
|
* and end of the section. These will be used more in the next
|
||||||
|
* two sections of code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// n.b - only for pre-defined sections [?], skip the _ROM_BEG_* symbols...
|
||||||
|
|
||||||
|
static std::string names[] = {
|
||||||
|
"_BEG_PAGE0", "_END_PAGE0",
|
||||||
|
"_BEG_CODE", "_END_CODE",
|
||||||
|
"_BEG_KDATA", "_END_KDATA"
|
||||||
|
"_BEG_DATA", "_END_DATA"
|
||||||
|
"_BEG_UDATA", "_END_UDATA"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
|
||||||
|
// begin is 0.
|
||||||
|
symbol s;
|
||||||
|
s.name = names[i * 2];
|
||||||
|
s.section = i;
|
||||||
|
s.type = S_REL;
|
||||||
|
s.flags = SF_DEF | SF_GBL;
|
||||||
|
symbol_map.emplace(s.name, i * 2);
|
||||||
|
symbols.emplace_back(s);
|
||||||
|
|
||||||
|
// end is undefined...
|
||||||
|
s.name = names[i * 2 + 1];
|
||||||
|
s.section = i * 2 + 1; // symbol number.
|
||||||
|
s.type = S_UND;
|
||||||
|
s.flags = 0;
|
||||||
|
|
||||||
|
symbol_map.emplace(s.name, i * 2 + 1);
|
||||||
|
symbols.emplace_back(s);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -362,9 +539,3 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct section {
|
|
||||||
std::vector<uint8_t> data;
|
|
||||||
uint32_t offset;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user