https://github.com/akkartik/mu/blob/master/subx/034compute_segment_address.cc
1
2
3
4
5 :(scenario segment_name)
6 == code
7 05/add-to-EAX 0x0d0c0b0a/imm32
8
9 +load: 0x09000054 -> 05
10 +load: 0x09000055 -> 0a
11 +load: 0x09000056 -> 0b
12 +load: 0x09000057 -> 0c
13 +load: 0x09000058 -> 0d
14 +run: add imm32 0x0d0c0b0a to reg EAX
15 +run: storing 0x0d0c0b0a
16
17
18
19
20
21 :(before "End Globals")
22 map<string, int> Segment_index;
23 bool Currently_parsing_named_segment = false;
24 int Currently_parsing_segment_index = -1;
25 :(before "End Reset")
26 Segment_index.clear();
27 Currently_parsing_named_segment = false;
28 Currently_parsing_segment_index = -1;
29
30 :(before "End Segment Parsing Special-cases(segment_title)")
31 if (!starts_with(segment_title, "0x")) {
32 Currently_parsing_named_segment = true;
33 if (!contains_key(Segment_index, segment_title)) {
34 trace(99, "parse") << "new segment '" << segment_title << "'" << end();
35 if (out.segments.empty() && segment_title != "code") {
36 raise << "first segment must be 'code' but is '" << segment_title << "'\n" << end();
37 return;
38 }
39 if (SIZE(out.segments) == 1 && segment_title != "data") {
40 raise << "second segment must be 'data' but is '" << segment_title << "'\n" << end();
41 return;
42 }
43 put(Segment_index, segment_title, SIZE(out.segments));
44 out.segments.push_back(segment());
45 }
46 else {
47 trace(99, "parse") << "appending to segment '" << segment_title << "'" << end();
48 }
49 Currently_parsing_segment_index = get(Segment_index, segment_title);
50 }
51
52 :(before "End flush(p, lines) Special-cases")
53 if (Currently_parsing_named_segment) {
54 assert(!p.segments.empty());
55 trace(99, "parse") << "flushing segment" << end();
56 vector<line>& curr_segment_data = p.segments.at(Currently_parsing_segment_index).lines;
57 curr_segment_data.insert(curr_segment_data.end(), lines.begin(), lines.end());
58 lines.clear();
59 Currently_parsing_named_segment = false;
60 Currently_parsing_segment_index = -1;
61 return;
62 }
63
64 :(scenario repeated_segment_merges_data)
65 == code
66 05/add-to-EAX 0x0d0c0b0a/imm32
67 == code
68 2d/subtract-from-EAX 0xddccbbaa/imm32
69 +parse: new segment 'code'
70 +parse: appending to segment 'code'
71
72 +load: 0x09000054 -> 05
73 +load: 0x09000055 -> 0a
74 +load: 0x09000056 -> 0b
75 +load: 0x09000057 -> 0c
76 +load: 0x09000058 -> 0d
77
78 +load: 0x09000059 -> 2d
79 +load: 0x0900005a -> aa
80 +load: 0x0900005b -> bb
81 +load: 0x0900005c -> cc
82 +load: 0x0900005d -> dd
83
84 :(scenario error_on_missing_segment_header)
85 % Hide_errors = true;
86 05/add-to-EAX 0/imm32
87 +error: input does not start with a '==' section header
88
89 :(scenario error_on_first_segment_not_code)
90 % Hide_errors = true;
91 == data
92 05 00 00 00 00
93 +error: first segment must be 'code' but is 'data'
94
95 :(scenario error_on_second_segment_not_data)
96 % Hide_errors = true;
97 == code
98 05/add-to-EAX 0/imm32
99 == bss
100 05 00 00 00 00
101 +error: second segment must be 'data' but is 'bss'
102
103
104
105 :(before "End Level-2 Transforms")
106 Transform.push_back(compute_segment_starts);
107
108 :(code)
109 void compute_segment_starts(program& p) {
110 trace(99, "transform") << "-- compute segment addresses" << end();
111 uint32_t p_offset = 0x34 + SIZE(p.segments)*0x20;
112 for (size_t i = 0; i < p.segments.size(); ++i) {
113 segment& curr = p.segments.at(i);
114 if (curr.start == 0) {
115 curr.start = CODE_SEGMENT + i*SPACE_FOR_SEGMENT + p_offset;
116 trace(99, "transform") << "segment " << i << " begins at address 0x" << HEXWORD << curr.start << end();
117 }
118 p_offset += size_of(curr);
119 assert(p_offset < SEGMENT_ALIGNMENT);
120 }
121 }
122
123 uint32_t size_of(const segment& s) {
124 uint32_t sum = 0;
125 for (int i = 0; i < SIZE(s.lines); ++i)
126 sum += num_bytes(s.lines.at(i));
127 return sum;
128 }
129
130
131 uint32_t num_bytes(const line& inst) {
132 uint32_t sum = 0;
133 for (int i = 0; i < SIZE(inst.words); ++i)
134 sum += size_of(inst.words.at(i));
135 return sum;
136 }
137
138 int size_of(const word& w) {
139 if (has_operand_metadata(w, "disp32") || has_operand_metadata(w, "imm32"))
140 return 4;
141 else if (has_operand_metadata(w, "disp16"))
142 return 2;
143
144 else
145 return 1;
146 }
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161