about summary refs log tree commit diff stats
path: root/subx/021translate.cc
blob: f658f6db61e5cd8197331d5c81ff817365000627 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//: 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.
//:
//: Workflow: read 'source' file as a single string. Run a series of
//: transforms on it, each converting to a new string. The final string should
//: be just machine code and comments, suitable to pass to load_program().

:(before "End Types")
typedef void (*transform_fn)(const string& input, string& output);
:(before "End Globals")
vector<transform_fn> Transform;

:(before "End Main")
if (is_equal(argv[1], "translate")) {
  assert(argc > 3);
  string program;
  slurp(argv[2], program);
  perform_all_transforms(program);
  dump_elf(program, argv[3]);
}

:(code)
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);
}

// 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.
void dump_elf(const string& program, const char* filename) {
  initialize_mem();
  // load program into memory, filtering out comments
  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.
  // dump contents of memory into ELF binary
  ofstream out(filename, ios::binary);
  dump_elf_header(out);
  for (size_t i = 1;  i < End_of_program;  ++i) {
    char c = read_mem_u8(i);
    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
  int e_entry = CODE_START + /*size of ehdr*/52 + /*size of phdr*/32;
  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
  uint32_t p_offset = /*size of ehdr*/52 + /*size of phdr*/32;
  emit(p_offset);
  // p_vaddr
  emit(e_entry);
  // p_paddr
  emit(e_entry);
  // p_filesz
  uint32_t size = End_of_program - /*we're not using location 0*/1;
  assert(size < SEGMENT_SIZE);
  emit(size);
  // p_memsz
  emit(size);
  // p_flags
  uint32_t p_flags = 0x5;  // r-x
  emit(p_flags);
  // p_align
  uint32_t p_align = 0x1000;
  emit(p_align);
#undef O
}

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);
}

:(after "Begin run() For Scenarios")
perform_all_transforms(text_bytes);

:(before "End Includes")
using std::ios;