mirror of
https://github.com/ksherlock/wdc-utils.git
synced 2024-12-12 19:30:38 +00:00
move most disassembler logic to separate class.
This commit is contained in:
parent
fefdbb5ad0
commit
2cd1ad1ce5
5
Makefile
5
Makefile
@ -2,7 +2,7 @@ LINK.o = $(LINK.cc)
|
|||||||
CXXFLAGS = -std=c++11 -g
|
CXXFLAGS = -std=c++11 -g
|
||||||
CCFLAGS = -g
|
CCFLAGS = -g
|
||||||
|
|
||||||
OBJS = dumpobj.o disassembler.o
|
OBJS = dumpobj.o disassembler.o zrdz_disassembler.o
|
||||||
|
|
||||||
#UNAME_S := $(shell uname -s)
|
#UNAME_S := $(shell uname -s)
|
||||||
#ifeq ($(UNAME_S),MINGW64_NT-10.0)
|
#ifeq ($(UNAME_S),MINGW64_NT-10.0)
|
||||||
@ -16,7 +16,8 @@ dumpobj : $(OBJS)
|
|||||||
|
|
||||||
|
|
||||||
disassembler.o : disassembler.cpp disassembler.h
|
disassembler.o : disassembler.cpp disassembler.h
|
||||||
dumpobj.o : dumpobj.cpp disassembler.h
|
zrdz_disassembler.o : zrdz_disassembler.cpp zrdz_disassembler.h disassembler.h
|
||||||
|
dumpobj.o : dumpobj.cpp zrdz_disassembler.h disassembler.h
|
||||||
mingw/err.o : mingw/err.c mingw/err.h
|
mingw/err.o : mingw/err.c mingw/err.h
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
@ -333,8 +333,21 @@ static constexpr const int modes[] =
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr const int kOpcodeTab = 20;
|
||||||
|
constexpr const int kOperandTab = 30;
|
||||||
|
constexpr const int kCommentTab = 80;
|
||||||
|
|
||||||
static std::string to_x(uint32_t x, unsigned bytes, char prefix = 0) {
|
|
||||||
|
void indent_to(std::string &line, unsigned position) {
|
||||||
|
if (line.length() < position)
|
||||||
|
line.resize(position, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
disassembler::~disassembler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string disassembler::to_x(uint32_t x, unsigned bytes, char prefix) {
|
||||||
std::string s;
|
std::string s;
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
if (prefix) s.push_back(prefix);
|
if (prefix) s.push_back(prefix);
|
||||||
@ -356,20 +369,68 @@ static std::string to_x(uint32_t x, unsigned bytes, char prefix = 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void disassembler::emit(const std::string &label) {
|
||||||
|
fputs(label.c_str(), stdout);
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disassembler::emit(const std::string &label, const std::string &opcode) {
|
||||||
|
std::string tmp;
|
||||||
|
tmp = label;
|
||||||
|
|
||||||
|
int column = tmp.length();
|
||||||
|
|
||||||
|
if (!opcode.empty()) {
|
||||||
|
do {
|
||||||
|
tmp.push_back(' ');
|
||||||
|
column++;
|
||||||
|
} while (column < kOpcodeTab);
|
||||||
|
tmp += opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp.push_back('\n');
|
||||||
|
fputs(tmp.c_str(), stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void disassembler::emit(const std::string &label, const std::string &opcode, const std::string &operand) {
|
||||||
|
|
||||||
|
std::string tmp;
|
||||||
|
tmp = label;
|
||||||
|
|
||||||
|
int column = tmp.length();
|
||||||
|
|
||||||
|
if (!opcode.empty()) {
|
||||||
|
do {
|
||||||
|
tmp.push_back(' ');
|
||||||
|
column++;
|
||||||
|
} while (column < kOpcodeTab);
|
||||||
|
tmp += opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
column = tmp.length();
|
||||||
|
if (!operand.empty()) {
|
||||||
|
do {
|
||||||
|
tmp.push_back(' ');
|
||||||
|
column++;
|
||||||
|
} while (column < kOperandTab);
|
||||||
|
tmp += operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp.push_back('\n');
|
||||||
|
fputs(tmp.c_str(), stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void disassembler::reset() {
|
void disassembler::reset() {
|
||||||
_arg = 0;
|
_arg = 0;
|
||||||
_st = 0;
|
_st = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const int kOpcodeTab = 20;
|
|
||||||
constexpr const int kOperandTab = 30;
|
|
||||||
constexpr const int kCommentTab = 80;
|
|
||||||
|
|
||||||
void indent_to(std::string &line, unsigned position) {
|
|
||||||
if (line.length() < position)
|
|
||||||
line.resize(position, ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void disassembler::dump() {
|
void disassembler::dump() {
|
||||||
@ -430,6 +491,7 @@ void disassembler::dump(const std::string &expr, unsigned size) {
|
|||||||
|
|
||||||
void disassembler::flush() {
|
void disassembler::flush() {
|
||||||
if (_st) dump();
|
if (_st) dump();
|
||||||
|
check_labels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ class disassembler {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
disassembler() = default;
|
disassembler() = default;
|
||||||
|
virtual ~disassembler();
|
||||||
|
|
||||||
void operator()(uint8_t byte);
|
void operator()(uint8_t byte);
|
||||||
void operator()(const std::string &expr, unsigned size);
|
void operator()(const std::string &expr, unsigned size);
|
||||||
@ -53,6 +54,17 @@ class disassembler {
|
|||||||
else _next_label = -1;
|
else _next_label = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string to_x(uint32_t value, unsigned bytes, char prefix = 0);
|
||||||
|
|
||||||
|
static void emit(const std::string &label);
|
||||||
|
static void emit(const std::string &label, const std::string &opcode);
|
||||||
|
static void emit(const std::string &label, const std::string &opcode, const std::string &operand);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual int32_t next_label(int32_t pc) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
419
dumpobj.cpp
419
dumpobj.cpp
@ -14,7 +14,7 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
#include "obj816.h"
|
#include "obj816.h"
|
||||||
#include "disassembler.h"
|
#include "zrdz_disassembler.h"
|
||||||
|
|
||||||
#ifndef O_BINARY
|
#ifndef O_BINARY
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
@ -40,13 +40,6 @@ enum class endian {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//extern unsigned init_flags(bool longM, bool longX);
|
|
||||||
//void dump(const std::vector<uint8_t> &data, unsigned &pc);
|
|
||||||
//extern void disasm(const std::vector<uint8_t> &data, unsigned &flags, unsigned &pc);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void swap_if(T &t, std::false_type) {}
|
void swap_if(T &t, std::false_type) {}
|
||||||
|
|
||||||
@ -77,9 +70,9 @@ void usage() {
|
|||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct Header {
|
struct Header {
|
||||||
uint32_t h_magic; /* magic number for detection */
|
uint32_t magic; /* magic number for detection */
|
||||||
uint16_t h_version; /* version number of object format */
|
uint16_t version; /* version number of object format */
|
||||||
uint8_t h_filtyp; /* file type, object or library */
|
uint8_t filetype; /* file type, object or library */
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
@ -150,26 +143,6 @@ std::string read_pstring(T &iter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct symbol {
|
|
||||||
std::string name;
|
|
||||||
uint8_t type = S_UND;
|
|
||||||
uint8_t flags = 0;
|
|
||||||
uint8_t section = 0xff;
|
|
||||||
uint32_t offset = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct section {
|
|
||||||
std::string name;
|
|
||||||
uint8_t number = 0;
|
|
||||||
uint8_t flags = 0;
|
|
||||||
uint32_t size = 0;
|
|
||||||
uint32_t org = 0;
|
|
||||||
|
|
||||||
// for disassembly tracking...
|
|
||||||
uint32_t pc = 0;
|
|
||||||
std::vector<symbol> symbols;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<section> read_sections(const std::vector<uint8_t> §ion_data) {
|
std::vector<section> read_sections(const std::vector<uint8_t> §ion_data) {
|
||||||
|
|
||||||
std::vector<section> sections;
|
std::vector<section> sections;
|
||||||
@ -185,9 +158,7 @@ std::vector<section> read_sections(const std::vector<uint8_t> §ion_data) {
|
|||||||
|
|
||||||
if (!(s.flags & SEC_NONAME)) s.name = read_cstring(iter);
|
if (!(s.flags & SEC_NONAME)) s.name = read_cstring(iter);
|
||||||
|
|
||||||
if (sections.size() < s.number) sections.resize(s.number);
|
sections.emplace_back(std::move(s));
|
||||||
if (sections.size() == s.number) sections.emplace_back(std::move(s));
|
|
||||||
else sections[s.number] = std::move(s);
|
|
||||||
}
|
}
|
||||||
return sections;
|
return sections;
|
||||||
}
|
}
|
||||||
@ -213,111 +184,6 @@ std::vector<symbol> read_symbols(const std::vector<uint8_t> &symbol_data) {
|
|||||||
return symbols;
|
return symbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<symbol> labels_for_section(const std::vector<symbol> &symbols, unsigned section) {
|
|
||||||
std::vector<symbol> out;
|
|
||||||
std::copy_if(symbols.begin(), symbols.end(), std::back_inserter(out),
|
|
||||||
[section](const symbol &s) { return s.section == section && s.type != S_UND; }
|
|
||||||
);
|
|
||||||
|
|
||||||
std::sort(out.begin(), out.end(), [](const symbol &a, const symbol &b){
|
|
||||||
return a.offset > b.offset;
|
|
||||||
});
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol find_symbol(const std::vector<symbol> &symbols, unsigned section, unsigned offset) {
|
|
||||||
auto iter = std::find_if(symbols.begin(), symbols.end(), [section, offset](const symbol &s){
|
|
||||||
return s.section == section && s.offset == offset && s.type != S_UND;
|
|
||||||
});
|
|
||||||
if (iter != symbols.end()) return *iter;
|
|
||||||
return symbol{};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void place_labels(std::vector<symbol> &labels, uint32_t pc) {
|
|
||||||
while (!labels.empty()) {
|
|
||||||
auto &label = labels.back();
|
|
||||||
if (label.offset > pc) return;
|
|
||||||
if (label.offset == pc) {
|
|
||||||
printf("%s:\n", label.name.c_str());
|
|
||||||
} else {
|
|
||||||
warnx("Unable to place label %s (offset $%04x)", label.name.c_str(), label.offset);
|
|
||||||
}
|
|
||||||
labels.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void emit(const std::string &label) {
|
|
||||||
fputs(label.c_str(), stdout);
|
|
||||||
//fputc(':', stdout); // special case.
|
|
||||||
fputc('\n', stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void emit(const std::string &label, const std::string &opcode) {
|
|
||||||
fputs(label.c_str(), stdout);
|
|
||||||
|
|
||||||
int column = label.length();
|
|
||||||
|
|
||||||
if (!opcode.empty()) {
|
|
||||||
do {
|
|
||||||
putc(' ', stdout);
|
|
||||||
column++;
|
|
||||||
} while (column < 20);
|
|
||||||
fputs(opcode.c_str(), stdout);
|
|
||||||
}
|
|
||||||
fputc('\n', stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void emit(const std::string &label, const std::string &opcode, const std::string &operand) {
|
|
||||||
fputs(label.c_str(), stdout);
|
|
||||||
int column = label.length();
|
|
||||||
|
|
||||||
if (!opcode.empty()) {
|
|
||||||
|
|
||||||
do {
|
|
||||||
putc(' ', stdout);
|
|
||||||
column++;
|
|
||||||
} while (column < 20);
|
|
||||||
fputs(opcode.c_str(), stdout);
|
|
||||||
column += opcode.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!operand.empty()) {
|
|
||||||
do {
|
|
||||||
putc(' ', stdout);
|
|
||||||
column++;
|
|
||||||
} while (column < 30);
|
|
||||||
fputs(operand.c_str(), stdout);
|
|
||||||
column += operand.length();
|
|
||||||
}
|
|
||||||
fputc('\n', stdout);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string to_x(uint32_t x, unsigned bytes, char prefix = 0) {
|
|
||||||
std::string s;
|
|
||||||
char buffer[16];
|
|
||||||
if (prefix) s.push_back(prefix);
|
|
||||||
|
|
||||||
if (x > 0xff && bytes < 4) bytes = 4;
|
|
||||||
if (x > 0xffff && bytes < 6) bytes = 6;
|
|
||||||
if (x > 0xffffff && bytes < 8) bytes = 8;
|
|
||||||
|
|
||||||
memset(buffer, '0', sizeof(buffer));
|
|
||||||
int i = 16;
|
|
||||||
while (x) {
|
|
||||||
buffer[--i] = "0123456789abcdef"[x & 0x0f];
|
|
||||||
x >>= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
s.append(buffer + 16 - bytes, buffer + 16);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dump_obj(const char *name, int fd)
|
bool dump_obj(const char *name, int fd)
|
||||||
{
|
{
|
||||||
static const char *kSections[] = { "PAGE0", "CODE", "KDATA", "DATA", "UDATA" };
|
static const char *kSections[] = { "PAGE0", "CODE", "KDATA", "DATA", "UDATA" };
|
||||||
@ -356,16 +222,6 @@ bool dump_obj(const char *name, int fd)
|
|||||||
if (ok != h.h_namlen) errx(EX_DATAERR, "%s", name);
|
if (ok != h.h_namlen) errx(EX_DATAERR, "%s", name);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
printf("name: %s\n", oname.data());
|
|
||||||
printf("record size : $%04x\n", h.h_recsize);
|
|
||||||
printf("section size : $%04x\n", h.h_secsize);
|
|
||||||
printf("symbol size : $%04x\n", h.h_symsize);
|
|
||||||
printf("option size : $%04x\n", h.h_optsize);
|
|
||||||
printf("number sections: $%04x\n", h.h_num_secs);
|
|
||||||
printf("number symbols : $%04x\n", h.h_num_syms);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// records [until record_eof]
|
// records [until record_eof]
|
||||||
|
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
@ -385,168 +241,19 @@ bool dump_obj(const char *name, int fd)
|
|||||||
ok = read(fd, symbol_data.data(), h.h_symsize);
|
ok = read(fd, symbol_data.data(), h.h_symsize);
|
||||||
if (ok != h.h_symsize) errx(EX_DATAERR, "%s symbols truncated", name);
|
if (ok != h.h_symsize) errx(EX_DATAERR, "%s symbols truncated", name);
|
||||||
|
|
||||||
std::vector<symbol> symbols = read_symbols(symbol_data);
|
zrdz_disassembler d(read_sections(section_data), read_symbols(symbol_data));
|
||||||
std::vector<section> sections = read_sections(section_data);
|
|
||||||
|
|
||||||
disassembler d;
|
|
||||||
|
|
||||||
uint8_t op = REC_END;
|
uint8_t op = REC_END;
|
||||||
unsigned section = SECT_CODE; // default section = CODE
|
unsigned section = SECT_CODE; // default section = CODE
|
||||||
unsigned line = 0;
|
unsigned line = 0;
|
||||||
std::string file;
|
std::string file;
|
||||||
|
|
||||||
if (sections.size() < 5) sections.resize(5);
|
|
||||||
for (int i = 0; i < 5; ++i)
|
|
||||||
if (sections[i].name.empty()) sections[i].name = kSections[i];
|
|
||||||
|
|
||||||
|
d.front_matter(std::string(oname.data()));
|
||||||
/* custom sections... */
|
|
||||||
if (sections.size() > 5) {
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
for (auto iter = sections.begin() + 5; iter != sections.end(); ++iter) {
|
|
||||||
std::string attr;
|
|
||||||
|
|
||||||
bool comma = false;
|
|
||||||
int flags = iter->flags;
|
|
||||||
if (flags & SEC_OFFSET) {
|
|
||||||
if (comma) attr += ", ";
|
|
||||||
attr += "SEC_OFFSET $";
|
|
||||||
attr += to_x(iter->org, 4);
|
|
||||||
comma = true;
|
|
||||||
}
|
|
||||||
if (flags & SEC_INDIRECT) {
|
|
||||||
if (comma) attr += ", ";
|
|
||||||
attr += "SEC_INDIRECT $";
|
|
||||||
attr += to_x(iter->org, 4);
|
|
||||||
comma = true;
|
|
||||||
}
|
|
||||||
#define _(x) if (flags & x) { if (comma) attr += ", "; attr += #x; comma = true; }
|
|
||||||
_(SEC_STACKED)
|
|
||||||
_(SEC_REF_ONLY)
|
|
||||||
_(SEC_CONST)
|
|
||||||
_(SEC_DIRECT)
|
|
||||||
_(SEC_NONAME)
|
|
||||||
_(SEC_DATA)
|
|
||||||
#undef _
|
|
||||||
|
|
||||||
emit(iter->name, "section", attr);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
emit("", "MODULE", std::string(oname.data()));
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
d.set_pc(0);
|
|
||||||
d.set_code(true);
|
|
||||||
|
|
||||||
|
|
||||||
bool newline = false;
|
|
||||||
|
|
||||||
for (const auto &s : symbols) {
|
|
||||||
if (s.type != S_UND) continue;
|
|
||||||
emit("", "extern", s.name);
|
|
||||||
newline = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &s : symbols) {
|
|
||||||
if (s.type == S_UND) continue;
|
|
||||||
if (s.type == S_ABS) continue; // ? equ/gequ
|
|
||||||
// only if s.type == S_REL?
|
|
||||||
sections[s.section].symbols.push_back(s);
|
|
||||||
|
|
||||||
if (s.flags & SF_GBL) {
|
|
||||||
emit("", "public", s.name);
|
|
||||||
newline = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (newline) printf("\n");
|
|
||||||
|
|
||||||
for (auto §ion : sections) {
|
|
||||||
std::sort(section.symbols.begin(), section.symbols.end(), [](const symbol &a, const symbol &b){
|
|
||||||
return a.offset > b.offset;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// print out any reference-only sections and symbols.
|
|
||||||
for (auto §ion : sections) {
|
|
||||||
if ((section.flags & SEC_REF_ONLY) == 0) continue;
|
|
||||||
if (section.size == 0) continue;
|
|
||||||
|
|
||||||
emit("", section.name);
|
|
||||||
|
|
||||||
if (section.org) emit("",".org", to_x(section.org,4,'$'));
|
|
||||||
uint32_t pc = section.org;
|
|
||||||
|
|
||||||
auto &symbols = section.symbols;
|
|
||||||
while (!symbols.empty()) {
|
|
||||||
auto &s = symbols.back();
|
|
||||||
|
|
||||||
if (s.offset > pc) {
|
|
||||||
emit("","ds", std::to_string(s.offset - pc));
|
|
||||||
pc = s.offset;
|
|
||||||
}
|
|
||||||
emit(s.name);
|
|
||||||
symbols.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pc < section.size)
|
|
||||||
emit("","ds",std::to_string(section.size - pc));
|
|
||||||
|
|
||||||
emit("","ends");
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// print equates.
|
|
||||||
// doesn the section matter?
|
|
||||||
newline = false;
|
|
||||||
for (const auto &s : symbols) {
|
|
||||||
if (s.type == (ST_EQU << 4) + S_ABS) {
|
|
||||||
emit(s.name,"gequ", to_x(s.offset, 4, '$'));
|
|
||||||
newline = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (newline) printf("\n");
|
|
||||||
|
|
||||||
|
|
||||||
d.set_label_callback([§ion, §ions](int32_t offset) -> int32_t {
|
|
||||||
auto &symbols = sections[section].symbols;
|
|
||||||
|
|
||||||
if (offset >= 0) {
|
|
||||||
|
|
||||||
while(!symbols.empty()) {
|
|
||||||
auto &s = symbols.back();
|
|
||||||
if (s.offset > offset) return s.offset;
|
|
||||||
if (s.offset == offset) {
|
|
||||||
emit(s.name);
|
|
||||||
} else {
|
|
||||||
std::string tmp = "; ";
|
|
||||||
tmp += s.name;
|
|
||||||
tmp += " = $";
|
|
||||||
tmp += to_x(s.offset, 4);
|
|
||||||
emit("", tmp);
|
|
||||||
}
|
|
||||||
symbols.pop_back();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (symbols.empty()) return -1;
|
|
||||||
return symbols.back().offset;
|
|
||||||
});
|
|
||||||
|
|
||||||
//std::vector<symbol> labels = labels_for_section(symbols, section);
|
|
||||||
|
|
||||||
|
|
||||||
emit("", "CODE", "; section 1");
|
|
||||||
|
|
||||||
auto iter = data.begin();
|
auto iter = data.begin();
|
||||||
while (iter != data.end()) {
|
while (iter != data.end()) {
|
||||||
|
|
||||||
//place_labels(labels, d.pc());
|
|
||||||
|
|
||||||
op = read_8(iter);
|
op = read_8(iter);
|
||||||
if (op == 0) break;
|
if (op == 0) break;
|
||||||
@ -554,7 +261,6 @@ bool dump_obj(const char *name, int fd)
|
|||||||
auto end = iter + op;
|
auto end = iter + op;
|
||||||
while (iter != end) {
|
while (iter != end) {
|
||||||
d(*iter++);
|
d(*iter++);
|
||||||
//place_labels(labels, d.pc());
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -587,41 +293,18 @@ bool dump_obj(const char *name, int fd)
|
|||||||
uint8_t section = read_8(iter);
|
uint8_t section = read_8(iter);
|
||||||
uint32_t offset = read_32(iter);
|
uint32_t offset = read_32(iter);
|
||||||
|
|
||||||
std::string name;
|
std::string name = d.location_name(section, offset);
|
||||||
|
stack.emplace_back(std::move(name));
|
||||||
symbol s = find_symbol(symbols, section, offset);
|
|
||||||
if (s.type) {
|
|
||||||
name = s.name;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (section < sizeof(kSections) / sizeof(kSections[0]))
|
|
||||||
name = kSections[section];
|
|
||||||
else {
|
|
||||||
snprintf(buffer, sizeof(buffer), "section%d", section);
|
|
||||||
name = buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (offset) {
|
|
||||||
snprintf(buffer, sizeof(buffer), "+$%04x", offset);
|
|
||||||
name += buffer;
|
|
||||||
}
|
|
||||||
stack.push_back(name);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_VAL:
|
case OP_VAL:
|
||||||
snprintf(buffer, sizeof(buffer), "$%04x", read_32(iter));
|
stack.push_back(d.to_x(read_32(iter), 4, '$'));
|
||||||
stack.push_back(buffer);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_SYM: {
|
case OP_SYM: {
|
||||||
uint16_t symbol = read_16(iter);
|
uint16_t symbol = read_16(iter);
|
||||||
if (symbol < symbols.size()) stack.push_back(symbols[symbol].name);
|
stack.emplace_back(d.symbol_name(symbol));
|
||||||
else {
|
|
||||||
snprintf(buffer, sizeof(buffer), "symbol $%02x", symbol);
|
|
||||||
stack.push_back(buffer);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,45 +378,45 @@ bool dump_obj(const char *name, int fd)
|
|||||||
switch(op) {
|
switch(op) {
|
||||||
case D_LONGA_ON:
|
case D_LONGA_ON:
|
||||||
d.set_m(true);
|
d.set_m(true);
|
||||||
emit("", "longa", "on");
|
d.emit("", "longa", "on");
|
||||||
break;
|
break;
|
||||||
case D_LONGA_OFF:
|
case D_LONGA_OFF:
|
||||||
d.set_m(false);
|
d.set_m(false);
|
||||||
emit("", "longa", "off");
|
d.emit("", "longa", "off");
|
||||||
break;
|
break;
|
||||||
case D_LONGI_ON:
|
case D_LONGI_ON:
|
||||||
d.set_x(true);
|
d.set_x(true);
|
||||||
emit("", "longi", "on");
|
d.emit("", "longi", "on");
|
||||||
break;
|
break;
|
||||||
case D_LONGI_OFF:
|
case D_LONGI_OFF:
|
||||||
d.set_x(false);
|
d.set_x(false);
|
||||||
emit("", "longi", "off");
|
d.emit("", "longi", "off");
|
||||||
break;
|
break;
|
||||||
case D_C_FILE: {
|
case D_C_FILE: {
|
||||||
file = read_cstring(iter);
|
file = read_cstring(iter);
|
||||||
line = read_16(iter);
|
line = read_16(iter);
|
||||||
std::string tmp = file + ", " + std::to_string(line);
|
std::string tmp = file + ", " + std::to_string(line);
|
||||||
emit("", ".file", tmp);
|
d.emit("", ".file", tmp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case D_C_LINE: {
|
case D_C_LINE: {
|
||||||
line = read_16(iter);
|
line = read_16(iter);
|
||||||
emit("",".line", std::to_string(line));
|
d.emit("",".line", std::to_string(line));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case D_C_BLOCK: {
|
case D_C_BLOCK: {
|
||||||
uint16_t block = read_16(iter);
|
uint16_t block = read_16(iter);
|
||||||
emit("",".block", std::to_string(line));
|
d.emit("",".block", std::to_string(line));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case D_C_ENDBLOCK: {
|
case D_C_ENDBLOCK: {
|
||||||
uint16_t line = read_16(iter);
|
uint16_t line = read_16(iter);
|
||||||
emit("",".endblock", std::to_string(line));
|
d.emit("",".endblock", std::to_string(line));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case D_C_FUNC: {
|
case D_C_FUNC: {
|
||||||
uint16_t arg = read_16(iter);
|
uint16_t arg = read_16(iter);
|
||||||
emit("",".function", std::to_string(line));
|
d.emit("",".function", std::to_string(line));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case D_C_ENDFUNC: {
|
case D_C_ENDFUNC: {
|
||||||
@ -744,7 +427,7 @@ bool dump_obj(const char *name, int fd)
|
|||||||
tmp = std::to_string(line) + ", "
|
tmp = std::to_string(line) + ", "
|
||||||
+ std::to_string(local_offset) + ", "
|
+ std::to_string(local_offset) + ", "
|
||||||
+ std::to_string(arg_offset);
|
+ std::to_string(arg_offset);
|
||||||
emit("",".endfunc", tmp);
|
d.emit("",".endfunc", tmp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -761,11 +444,11 @@ bool dump_obj(const char *name, int fd)
|
|||||||
|
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
tmp = name + ", " + std::to_string(size) + ", " + std::to_string(tag);
|
tmp = name + ", " + std::to_string(size) + ", " + std::to_string(tag);
|
||||||
emit("", opname, tmp);
|
d.emit("", opname, tmp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case D_C_EOS: {
|
case D_C_EOS: {
|
||||||
emit("", ".eos");
|
d.emit("", ".eos");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,7 +474,7 @@ bool dump_obj(const char *name, int fd)
|
|||||||
|
|
||||||
if (version == 0) {
|
if (version == 0) {
|
||||||
std::string svalue;
|
std::string svalue;
|
||||||
svalue = symbols[value].name;
|
svalue = d.symbol_name(value);
|
||||||
|
|
||||||
attr = name + ", " + svalue;
|
attr = name + ", " + svalue;
|
||||||
}
|
}
|
||||||
@ -827,7 +510,7 @@ bool dump_obj(const char *name, int fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
emit("", opname, attr);
|
d.emit("", opname, attr);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -842,33 +525,15 @@ bool dump_obj(const char *name, int fd)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case REC_SECT: {
|
case REC_SECT: {
|
||||||
d.flush();
|
|
||||||
uint8_t sec = read_8(iter);
|
uint8_t sec = read_8(iter);
|
||||||
//printf("\t.sect\t%d\n", sec);
|
d.set_section(sec);
|
||||||
if (sec != section) {
|
|
||||||
|
|
||||||
if (sec >= sections.size()) {
|
|
||||||
warnx("Undefined section %d", sec);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto &s = sections[sec];
|
|
||||||
emit("", "ends", std::string("; end section ") + std::to_string(section));
|
|
||||||
printf("\n");
|
|
||||||
emit("", s.name, std::string("; section ") + std::to_string(sec));
|
|
||||||
|
|
||||||
sections[section].pc = d.pc();
|
|
||||||
section = sec;
|
|
||||||
d.set_pc(s.pc);
|
|
||||||
d.recalc_next_label();
|
|
||||||
d.set_code((s.flags & SEC_DATA) == 0);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case REC_ORG: {
|
case REC_ORG: {
|
||||||
d.flush();
|
d.flush();
|
||||||
uint32_t org = read_32(iter);
|
uint32_t org = read_32(iter);
|
||||||
emit("", ".org", to_x(org, 4, '$'));
|
d.emit("", ".org", d.to_x(org, 4, '$'));
|
||||||
d.set_pc(org);
|
d.set_pc(org);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -877,7 +542,7 @@ bool dump_obj(const char *name, int fd)
|
|||||||
d.flush();
|
d.flush();
|
||||||
uint16_t count = read_16(iter);
|
uint16_t count = read_16(iter);
|
||||||
// todo -- need to coordinate with label printer/disassembler.
|
// todo -- need to coordinate with label printer/disassembler.
|
||||||
emit("", "ds", to_x(count, 4, '$'));
|
d.emit("", "ds", d.to_x(count, 4, '$'));
|
||||||
d.set_pc(d.pc() + count);
|
d.set_pc(d.pc() + count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -893,23 +558,13 @@ bool dump_obj(const char *name, int fd)
|
|||||||
errx(EX_DATAERR, "%s: unknown opcode %02x", name, op);
|
errx(EX_DATAERR, "%s: unknown opcode %02x", name, op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// dump any unfinished business.
|
|
||||||
d.flush();
|
|
||||||
|
|
||||||
//place_labels(labels, d.pc());
|
|
||||||
/*
|
d.back_matter();
|
||||||
for(auto &label : labels) {
|
|
||||||
warnx("Unable to place label %s (offset $%04x)", label.name.c_str(), label.offset);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
emit("", "ends");
|
|
||||||
printf("\n");
|
|
||||||
emit("", "endmod");
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
if (iter != data.end() || op != REC_END) errx(EX_DATAERR, "%s records ended early", name);
|
if (iter != data.end() || op != REC_END) errx(EX_DATAERR, "%s records ended early", name);
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (flags._S) {
|
if (flags._S) {
|
||||||
printf("; sections\n");
|
printf("; sections\n");
|
||||||
for (auto &s : sections) {
|
for (auto &s : sections) {
|
||||||
@ -925,7 +580,7 @@ bool dump_obj(const char *name, int fd)
|
|||||||
s.name.c_str(), s.type, s.flags, s.section, s.offset);
|
s.name.c_str(), s.type, s.flags, s.section, s.offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1006,15 +661,15 @@ void dump(const char *name) {
|
|||||||
if (ok != sizeof(h))
|
if (ok != sizeof(h))
|
||||||
errx(EX_DATAERR, "%s is not an object file", name);
|
errx(EX_DATAERR, "%s is not an object file", name);
|
||||||
|
|
||||||
le_to_host(h.h_magic);
|
le_to_host(h.magic);
|
||||||
le_to_host(h.h_version);
|
le_to_host(h.version);
|
||||||
le_to_host(h.h_filtyp);
|
le_to_host(h.filetype);
|
||||||
|
|
||||||
if (h.h_magic != MOD_MAGIC || h.h_version != 1 || h.h_filtyp > 2)
|
if (h.magic != MOD_MAGIC || h.version != 1 || h.filetype > 2)
|
||||||
errx(EX_DATAERR, "%s is not an object file", name);
|
errx(EX_DATAERR, "%s is not an object file", name);
|
||||||
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
if (h.h_filtyp == 2) dump_lib(name, fd);
|
if (h.filetype == 2) dump_lib(name, fd);
|
||||||
|
|
||||||
// files may contain multiple modules.
|
// files may contain multiple modules.
|
||||||
while (dump_obj(name, fd)) /* ... */;
|
while (dump_obj(name, fd)) /* ... */;
|
||||||
|
5
obj816.h
5
obj816.h
@ -1,3 +1,6 @@
|
|||||||
|
#ifndef __obj816_h__
|
||||||
|
#define __obj816_h__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
@ -174,3 +177,5 @@ enum {SECT_PAGE0, SECT_CODE, SECT_KDATA, SECT_DATA, SECT_UDATA };
|
|||||||
/**************************************************/
|
/**************************************************/
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#endif
|
322
zrdz_disassembler.cpp
Normal file
322
zrdz_disassembler.cpp
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
#include "zrdz_disassembler.h"
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static constexpr const int equ_type = (ST_EQU << 4) | S_ABS;
|
||||||
|
|
||||||
|
zrdz_disassembler::zrdz_disassembler(std::vector<section> &§ions, std::vector<symbol> &&symbols) :
|
||||||
|
_symbols(std::move(symbols))
|
||||||
|
{
|
||||||
|
|
||||||
|
// do not sort _symbols ... order matters for lookup by entry number.
|
||||||
|
#if 0
|
||||||
|
// sort by section / address.
|
||||||
|
std::sort(_symbols.begin(), _symbols.end(), [](const symbol &a, const symbol &b){
|
||||||
|
if (a.section < b.section) return true;
|
||||||
|
if (a.section == b.section && a.offset < b.offset) return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (auto &s : sections) {
|
||||||
|
if (s.number >= _sections.size()) _sections.resize(s.number + 1);
|
||||||
|
_sections[s.number].valid = true;
|
||||||
|
_sections[s.number].pc = s.org;
|
||||||
|
_sections[s.number] = std::move(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &s : _symbols) {
|
||||||
|
|
||||||
|
if (s.type == S_UND) continue;
|
||||||
|
|
||||||
|
if (s.section >= _sections.size()) {
|
||||||
|
warnx("invalid section %d for symbol %s", s.section, s.name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto &e = _sections[s.section];
|
||||||
|
if (!e.valid) {
|
||||||
|
warnx("invalid section %d for symbol %s", s.section, s.name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (s.type == equ_type) continue;
|
||||||
|
e.symbols.emplace_back(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sections.size() < 5) _sections.resize(5);
|
||||||
|
_sections[SECT_PAGE0].name = "page0";
|
||||||
|
_sections[SECT_CODE].name = "code";
|
||||||
|
_sections[SECT_KDATA].name = "kdata";
|
||||||
|
_sections[SECT_DATA].name = "data";
|
||||||
|
_sections[SECT_UDATA].name = "udata";
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// now place equates at the end...
|
||||||
|
for (auto &s : _symbols) {
|
||||||
|
if (s.type != equ_type) continue;
|
||||||
|
auto &sec = _sections[s.section];
|
||||||
|
sec.symbols.emplace_back(s);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
zrdz_disassembler::~zrdz_disassembler() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void zrdz_disassembler::front_matter(const std::string &module) {
|
||||||
|
emit("", "module", module);
|
||||||
|
putchar('\n');
|
||||||
|
print_externs();
|
||||||
|
|
||||||
|
// reference-only sections.
|
||||||
|
for (auto &e : _sections) {
|
||||||
|
if (!e.valid) continue;
|
||||||
|
|
||||||
|
if ((e.flags & SEC_REF_ONLY) == 0) continue;
|
||||||
|
if (e.size == 0 && e.symbols.empty()) continue;
|
||||||
|
|
||||||
|
e.processed = true;
|
||||||
|
print_section(e);
|
||||||
|
print_globals(e.number);
|
||||||
|
print_equs(e.number);
|
||||||
|
|
||||||
|
if (e.org) emit("", ".org", to_x(e.org, 4, '$'));
|
||||||
|
uint32_t pc = e.org;
|
||||||
|
|
||||||
|
|
||||||
|
for (; !e.symbols.empty(); e.symbols.pop_back()) {
|
||||||
|
auto &s = e.symbols.back();
|
||||||
|
|
||||||
|
if (s.offset > pc) {
|
||||||
|
emit("","ds", std::to_string(s.offset - pc));
|
||||||
|
pc = s.offset;
|
||||||
|
}
|
||||||
|
emit(s.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pc < e.size)
|
||||||
|
emit("","ds",std::to_string(e.size - pc));
|
||||||
|
|
||||||
|
emit("", "ends");
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
set_section(1);
|
||||||
|
/*
|
||||||
|
emit("","code");
|
||||||
|
print_globals(1);
|
||||||
|
print_equs(1);
|
||||||
|
_sections[1].processed = true;
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void zrdz_disassembler::back_matter() {
|
||||||
|
|
||||||
|
flush();
|
||||||
|
_section = -1;
|
||||||
|
|
||||||
|
|
||||||
|
// todo -- print remaining symbols.
|
||||||
|
// todo -- print any empty sections?
|
||||||
|
|
||||||
|
emit("", "ends");
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
for (auto &e : _sections) {
|
||||||
|
if (e.processed) continue;
|
||||||
|
if (!e.valid) continue;
|
||||||
|
|
||||||
|
print_section(e);
|
||||||
|
print_globals(e.number);
|
||||||
|
print_equs(e.number);
|
||||||
|
emit("","ends");
|
||||||
|
e.processed = true;
|
||||||
|
// ...check for symbols?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
emit("", "endmod");
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void zrdz_disassembler::print_externs() {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::string> tmp;
|
||||||
|
|
||||||
|
for (auto &s : _symbols) {
|
||||||
|
if (s.type == S_UND) tmp.push_back(s.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp.empty()) return;
|
||||||
|
std::sort(tmp.begin(), tmp.end());
|
||||||
|
for (const auto &s : tmp) emit("", "extern", s);
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void zrdz_disassembler::print_globals(int section) {
|
||||||
|
|
||||||
|
std::vector<std::string> tmp;
|
||||||
|
|
||||||
|
for (auto &s : _symbols) {
|
||||||
|
if (s.section == section && s.flags & SF_GBL) tmp.push_back(s.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp.empty()) return;
|
||||||
|
std::sort(tmp.begin(), tmp.end());
|
||||||
|
for (const auto &s : tmp) emit("", "public", s);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void zrdz_disassembler::print_equs(int section) {
|
||||||
|
|
||||||
|
std::vector<symbol> tmp;
|
||||||
|
|
||||||
|
std::copy_if(_symbols.begin(), _symbols.end(), std::back_inserter(tmp),
|
||||||
|
[=](const symbol &s) { return s.section == section && s.type == equ_type; }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tmp.empty()) return;
|
||||||
|
std::sort(tmp.begin(), tmp.end(),
|
||||||
|
[](const symbol &a, const symbol &b) { return a.name < b.name; }
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const auto &s : tmp) emit(s.name, "gequ", to_x(s.offset, 4, '$'));
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void zrdz_disassembler::print_section(const entry &e) {
|
||||||
|
std::string attr;
|
||||||
|
bool comma = false;
|
||||||
|
|
||||||
|
|
||||||
|
if (e.processed || e.number < 5) {
|
||||||
|
emit("", e.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.flags & SEC_OFFSET) {
|
||||||
|
if (comma) attr += ", ";
|
||||||
|
attr += "SEC_OFFSET $";
|
||||||
|
attr += to_x(e.org, 4);
|
||||||
|
comma = true;
|
||||||
|
}
|
||||||
|
if (e.flags & SEC_INDIRECT) {
|
||||||
|
if (comma) attr += ", ";
|
||||||
|
attr += "SEC_INDIRECT $";
|
||||||
|
attr += to_x(e.org, 4);
|
||||||
|
comma = true;
|
||||||
|
}
|
||||||
|
#define _(x) if (e.flags & x) { if (comma) attr += ", "; attr += #x; comma = true; }
|
||||||
|
_(SEC_STACKED)
|
||||||
|
_(SEC_REF_ONLY)
|
||||||
|
_(SEC_CONST)
|
||||||
|
_(SEC_DIRECT)
|
||||||
|
_(SEC_NONAME)
|
||||||
|
_(SEC_DATA)
|
||||||
|
#undef _
|
||||||
|
|
||||||
|
emit(e.name, "section", attr);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void zrdz_disassembler::set_section(int section) {
|
||||||
|
if (section == _section) return;
|
||||||
|
if (section >= _sections.size()) {
|
||||||
|
warnx("Invalid section %d", section);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &e = _sections[section];
|
||||||
|
if (!e.valid) {
|
||||||
|
warnx("Invalid section %d", section);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_section >= 0) {
|
||||||
|
flush();
|
||||||
|
_sections[_section].pc = pc();
|
||||||
|
emit("", "ends");
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
print_section(e);
|
||||||
|
|
||||||
|
if (!e.processed) {
|
||||||
|
print_globals(section);
|
||||||
|
print_equs(section);
|
||||||
|
e.processed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_section = section;
|
||||||
|
set_pc(e.pc);
|
||||||
|
set_code((e.flags & SEC_DATA) == 0);
|
||||||
|
recalc_next_label();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32_t zrdz_disassembler::next_label(int32_t pc) {
|
||||||
|
if (_section < 0) return -1;
|
||||||
|
|
||||||
|
auto &symbols = _sections[_section].symbols;
|
||||||
|
if (pc >= 0) {
|
||||||
|
|
||||||
|
for(; !symbols.empty(); symbols.pop_back()) {
|
||||||
|
auto &s = symbols.back();
|
||||||
|
if (s.offset > pc) return s.offset;
|
||||||
|
if (s.offset == pc) emit(s.name);
|
||||||
|
else {
|
||||||
|
warnx("Unable to place symbol %s at offset $%04x in section %d",
|
||||||
|
s.name.c_str(), s.offset, _section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (symbols.empty()) return -1;
|
||||||
|
return symbols.back().offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string zrdz_disassembler::location_name(unsigned section, uint32_t offset) const {
|
||||||
|
|
||||||
|
if (section >= _sections.size()) {
|
||||||
|
warnx("Invalid section %d", section);
|
||||||
|
return "$";
|
||||||
|
}
|
||||||
|
auto &e = _sections[section];
|
||||||
|
if (!e.valid) {
|
||||||
|
warnx("Invalid section %d", section);
|
||||||
|
return "$";
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo -- need to verify relative/absolute value
|
||||||
|
|
||||||
|
auto iter = std::find_if(_symbols.begin(), _symbols.end(), [=](const symbol &s){
|
||||||
|
if (s.type == equ_type) return false;
|
||||||
|
if (s.type == S_UND) return false;
|
||||||
|
return s.section == section && s.offset == offset;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (iter != _symbols.end()) return iter->name;
|
||||||
|
|
||||||
|
//fallback to section name + offset
|
||||||
|
std::string tmp = e.name;
|
||||||
|
if (tmp.empty()) tmp = "section" + std::to_string(section);
|
||||||
|
if (offset) tmp += "+$" + to_x(offset, 4);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string zrdz_disassembler::symbol_name(unsigned entry) const {
|
||||||
|
if (entry >= _symbols.size()) {
|
||||||
|
warnx("Invalid symbol %d", entry);
|
||||||
|
return "$";
|
||||||
|
}
|
||||||
|
return _symbols[entry].name;
|
||||||
|
}
|
74
zrdz_disassembler.h
Normal file
74
zrdz_disassembler.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef __zrdz_disassembler_h__
|
||||||
|
#define __zrdz_disassembler_h__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "disassembler.h"
|
||||||
|
#include "obj816.h"
|
||||||
|
|
||||||
|
struct symbol {
|
||||||
|
std::string name;
|
||||||
|
uint8_t type = S_UND;
|
||||||
|
uint8_t flags = 0;
|
||||||
|
uint8_t section = 0xff;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct section {
|
||||||
|
std::string name;
|
||||||
|
uint8_t number = 0;
|
||||||
|
uint8_t flags = 0;
|
||||||
|
uint32_t size = 0;
|
||||||
|
uint32_t org = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class zrdz_disassembler final : public disassembler {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
zrdz_disassembler(std::vector<section> &&, std::vector<symbol> &&);
|
||||||
|
virtual ~zrdz_disassembler();
|
||||||
|
|
||||||
|
//int section() const { return _section; }
|
||||||
|
void set_section(int);
|
||||||
|
|
||||||
|
void front_matter(const std::string &module_name);
|
||||||
|
void back_matter();
|
||||||
|
|
||||||
|
std::string location_name(unsigned section, uint32_t offset) const;
|
||||||
|
std::string symbol_name(unsigned entry) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual int32_t next_label(int32_t pc) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
struct entry : public section {
|
||||||
|
using section::section;
|
||||||
|
using section::operator=;
|
||||||
|
|
||||||
|
bool processed = false;
|
||||||
|
bool valid = false;
|
||||||
|
std::vector<symbol> symbols;
|
||||||
|
uint32_t pc = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<symbol> _symbols;
|
||||||
|
std::vector<entry> _sections;
|
||||||
|
|
||||||
|
int _section = -1;
|
||||||
|
|
||||||
|
|
||||||
|
void print_section(const entry &e);
|
||||||
|
void print_externs();
|
||||||
|
void print_globals(int section);
|
||||||
|
void print_equs(int section);
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user