1 //: Start allowing us to not specify precise addresses for the start of each
 2 //: segment.
 3 //: This gives up a measure of control in placing code and data.
 4 
 5 //: segment address computation requires setting Mem_offset in test mode to what it'll be in run mode
 6 :(scenario segment_name)
 7 % Mem_offset = CODE_START;
 8 == code
 9 05/add 0x0d0c0b0a/imm32  # add 0x0d0c0b0a to EAX
10 # code starts at 0x08048000 + p_offset, which is 0x54 for a single-segment binary
11 +load: 0x08048054 -> 05
12 +load: 0x08048055 -> 0a
13 +load: 0x08048056 -> 0b
14 +load: 0x08048057 -> 0c
15 +load: 0x08048058 -> 0d
16 +run: add imm32 0x0d0c0b0a to reg EAX
17 +run: storing 0x0d0c0b0a
18 
19 :(before "End Level-2 Transforms")
20 Transform.push_back(compute_segment_starts);
21 
22 :(code)
23 void compute_segment_starts(program& p) {
24   trace(99, "transform") << "-- compute segment addresses" << end();
25   uint32_t p_offset = /*size of ehdr*/0x34 + SIZE(p.segments)*0x20/*size of each phdr*/;
26   for (size_t i = 0;  i < p.segments.size();  ++i) {
27     segment& curr = p.segments.at(i);
28     if (curr.start == 0) {
29       curr.start = CODE_START + i*SEGMENT_SIZE + p_offset;
30       trace(99, "transform") << "segment " << i << " begins at address 0x" << HEXWORD << curr.start << end();
31     }
32     p_offset += size_of(curr);
33     assert(p_offset < SEGMENT_SIZE);  // for now we get less and less available space in each successive segment
34   }
35 }
36 
37 uint32_t size_of(const segment& s) {
38   uint32_t sum = 0;
39   for (int i = 0;  i < SIZE(s.lines);  ++i)
40     sum += num_bytes(s.lines.at(i));
41   return sum;
42 }
43 
44 // Assumes all bitfields are packed.
45 uint32_t num_bytes(const line& inst) {
46   uint32_t sum = 0;
47   for (int i = 0;  i < SIZE(inst.words);  ++i) {
48     const word& curr = inst.words.at(i);
49     if (has_operand_metadata(curr, "disp32") || has_operand_metadata(curr, "imm32"))  // only multi-byte operands
50       sum += 4;
51     // End num_bytes(curr) Special-cases
52     else
53       sum++;
54   }
55   return sum;
56 }
57 
58 //: Dependencies:
59 //: - We'd like to compute segment addresses before setting up global variables,
60 //:   because computing addresses for global variables requires knowing where
61 //:   the data segment starts.
62 //: - We'd like to finish expanding labels before computing segment addresses,
63 //:   because it would make computing the sizes of segments more self-contained
64 //:   (num_bytes).
65 //:
66 //: Decision: compute segment addresses before expanding labels, by being
67 //: aware in this layer of certain operand types that will eventually occupy
68 //: multiple bytes.
69 //:
70 //: The layer to expand labels later hooks into num_bytes() to teach this
71 //: layer that labels occupy zero space in the binary.