2018-07-01 05:46:32 +00:00
|
|
|
//: Beginnings of a nicer way to build SubX programs.
|
|
|
|
//: We're going to question every notion, including "Assembly language" and
|
|
|
|
//: "compiler".
|
|
|
|
//: Motto: Abstract nothing, check everything.
|
2018-07-03 17:06:07 +00:00
|
|
|
//:
|
2018-07-11 14:45:45 +00:00
|
|
|
//: Workflow: read 'source' file. Run a series of transforms on it, each
|
|
|
|
//: passing through what it doesn't understand. The final program should be
|
|
|
|
//: just machine code, suitable to write to an ELF binary.
|
2018-07-01 05:46:32 +00:00
|
|
|
|
|
|
|
:(before "End Types")
|
|
|
|
typedef void (*transform_fn)(const string& input, string& output);
|
|
|
|
:(before "End Globals")
|
|
|
|
vector<transform_fn> Transform;
|
|
|
|
|
2018-06-30 16:41:22 +00:00
|
|
|
:(before "End Main")
|
|
|
|
if (is_equal(argv[1], "translate")) {
|
|
|
|
assert(argc > 3);
|
2018-07-01 05:46:32 +00:00
|
|
|
string program;
|
|
|
|
slurp(argv[2], program);
|
|
|
|
perform_all_transforms(program);
|
|
|
|
dump_elf(program, argv[3]);
|
2018-06-30 16:41:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
:(code)
|
2018-07-01 05:46:32 +00:00
|
|
|
void perform_all_transforms(string& program) {
|
|
|
|
string& in = program;
|
|
|
|
string out;
|
|
|
|
for (int t = 0; t < SIZE(Transform); ++t, in.swap(out), out.clear())
|
|
|
|
(*Transform.at(t))(in, out);
|
|
|
|
}
|
|
|
|
|
2018-06-30 16:41:22 +00:00
|
|
|
// write out the current Memory contents from address 1 to End_of_program to a
|
|
|
|
// bare-bones ELF file with a single section/segment and a hard-coded origin address.
|
2018-07-01 05:46:32 +00:00
|
|
|
void dump_elf(const string& program, const char* filename) {
|
2018-07-09 05:57:50 +00:00
|
|
|
initialize_mem();
|
2018-07-01 05:46:32 +00:00
|
|
|
// load program into memory, filtering out comments
|
2018-07-11 03:27:21 +00:00
|
|
|
load_program(program); // Not where 'program' should be loaded for running.
|
|
|
|
// But we're not going to run it right now, so we
|
|
|
|
// can load it anywhere.
|
2018-07-01 05:46:32 +00:00
|
|
|
// dump contents of memory into ELF binary
|
2018-06-30 16:41:22 +00:00
|
|
|
ofstream out(filename, ios::binary);
|
|
|
|
dump_elf_header(out);
|
|
|
|
for (size_t i = 1; i < End_of_program; ++i) {
|
2018-07-09 05:33:15 +00:00
|
|
|
char c = read_mem_u8(i);
|
2018-06-30 16:41:22 +00:00
|
|
|
out.write(&c, sizeof(c));
|
|
|
|
}
|
|
|
|
out.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void dump_elf_header(ostream& out) {
|
|
|
|
char c = '\0';
|
|
|
|
#define O(X) c = (X); out.write(&c, sizeof(c))
|
|
|
|
// host is required to be little-endian
|
|
|
|
#define emit(X) out.write(reinterpret_cast<const char*>(&X), sizeof(X))
|
|
|
|
//// ehdr
|
|
|
|
// e_ident
|
|
|
|
O(0x7f); O(/*E*/0x45); O(/*L*/0x4c); O(/*F*/0x46);
|
|
|
|
O(0x1); // 32-bit format
|
|
|
|
O(0x1); // little-endian
|
|
|
|
O(0x1); O(0x0);
|
|
|
|
for (size_t i = 0; i < 8; ++i) { O(0x0); }
|
|
|
|
// e_type
|
|
|
|
O(0x02); O(0x00);
|
|
|
|
// e_machine
|
|
|
|
O(0x03); O(0x00);
|
|
|
|
// e_version
|
|
|
|
O(0x01); O(0x00); O(0x00); O(0x00);
|
|
|
|
// e_entry
|
2018-07-10 05:43:40 +00:00
|
|
|
int e_entry = CODE_START + /*size of ehdr*/52 + /*size of phdr*/32;
|
2018-06-30 16:41:22 +00:00
|
|
|
emit(e_entry);
|
|
|
|
// e_phoff -- immediately after ELF header
|
|
|
|
int e_phoff = 52;
|
|
|
|
emit(e_phoff);
|
|
|
|
// e_shoff; unused
|
|
|
|
int dummy32 = 0;
|
|
|
|
emit(dummy32);
|
|
|
|
// e_flags; unused
|
|
|
|
emit(dummy32);
|
|
|
|
// e_ehsize
|
|
|
|
uint16_t e_ehsize = 52;
|
|
|
|
emit(e_ehsize);
|
|
|
|
// e_phentsize
|
|
|
|
uint16_t e_phentsize = 0x20;
|
|
|
|
emit(e_phentsize);
|
|
|
|
// e_phnum
|
|
|
|
uint16_t e_phnum = 0x1;
|
|
|
|
emit(e_phnum);
|
|
|
|
// e_shentsize
|
|
|
|
uint16_t dummy16 = 0x0;
|
|
|
|
emit(dummy16);
|
|
|
|
// e_shnum
|
|
|
|
emit(dummy16);
|
|
|
|
// e_shstrndx
|
|
|
|
emit(dummy16);
|
|
|
|
|
|
|
|
//// phdr
|
|
|
|
// p_type
|
|
|
|
uint32_t p_type = 0x1;
|
|
|
|
emit(p_type);
|
|
|
|
// p_offset
|
2018-07-07 06:13:03 +00:00
|
|
|
uint32_t p_offset = /*size of ehdr*/52 + /*size of phdr*/32;
|
2018-06-30 17:47:01 +00:00
|
|
|
emit(p_offset);
|
2018-06-30 16:41:22 +00:00
|
|
|
// p_vaddr
|
2018-07-07 06:37:34 +00:00
|
|
|
emit(e_entry);
|
2018-06-30 16:41:22 +00:00
|
|
|
// p_paddr
|
2018-07-07 06:37:34 +00:00
|
|
|
emit(e_entry);
|
2018-06-30 16:41:22 +00:00
|
|
|
// p_filesz
|
2018-07-07 06:13:03 +00:00
|
|
|
uint32_t size = End_of_program - /*we're not using location 0*/1;
|
2018-07-10 14:18:36 +00:00
|
|
|
assert(size < SEGMENT_SIZE);
|
2018-06-30 16:41:22 +00:00
|
|
|
emit(size);
|
|
|
|
// p_memsz
|
|
|
|
emit(size);
|
|
|
|
// p_flags
|
2018-07-03 23:36:37 +00:00
|
|
|
uint32_t p_flags = 0x5; // r-x
|
2018-06-30 16:41:22 +00:00
|
|
|
emit(p_flags);
|
|
|
|
// p_align
|
2018-07-14 17:40:26 +00:00
|
|
|
uint32_t p_align = 0x4; // p_offset must be congruent to p_paddr/p_vaddr modulo p_align
|
2018-06-30 16:41:22 +00:00
|
|
|
emit(p_align);
|
|
|
|
#undef O
|
2018-07-11 05:39:46 +00:00
|
|
|
#undef emit
|
2018-06-30 16:41:22 +00:00
|
|
|
}
|
|
|
|
|
2018-07-01 05:46:32 +00:00
|
|
|
void slurp(const char* filename, string& out) {
|
|
|
|
ifstream fin(filename);
|
|
|
|
fin >> std::noskipws;
|
|
|
|
ostringstream fout;
|
|
|
|
char c = '\0';
|
|
|
|
while(has_data(fin)) {
|
|
|
|
fin >> c;
|
|
|
|
fout << c;
|
|
|
|
}
|
|
|
|
fout.str().swap(out);
|
|
|
|
}
|
|
|
|
|
2018-07-01 06:05:40 +00:00
|
|
|
:(after "Begin run() For Scenarios")
|
|
|
|
perform_all_transforms(text_bytes);
|
|
|
|
|
2018-06-30 16:41:22 +00:00
|
|
|
:(before "End Includes")
|
|
|
|
using std::ios;
|