about summary refs log tree commit diff stats
path: root/subx/016index_addressing.cc
blob: 6e1f63e6c848688f4c64b009ed6111c7ae163759 (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//: operating on memory at the address provided by some register plus optional scale and offset

:(code)
void test_add_r32_to_mem_at_r32_with_sib() {
  Reg[EBX].i = 0x10;
  Reg[EAX].i = 0x2000;
  run(
      "== code 0x1\n"
      // op     ModR/M  SIB   displacement  immediate
      "  01     1c      20                              \n"  // add EBX to *EAX
      // ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB)
      // SIB in binary: 00 (scale 1) 100 (no index) 000 (base EAX)
      "== data 0x2000\n"
      "01 00 00 00\n"  // 0x00000001
  );
  CHECK_TRACE_CONTENTS(
      "run: add EBX to r/m32\n"
      "run: effective address is initially 0x00002000 (EAX)\n"
      "run: effective address is 0x00002000\n"
      "run: storing 0x00000011\n"
  );
}

:(before "End Mod 0 Special-cases(addr)")
case 4:  // exception: mod 0b00 rm 0b100 => incoming SIB (scale-index-base) byte
  addr = effective_address_from_sib(mod);
  break;
:(code)
uint32_t effective_address_from_sib(uint8_t mod) {
  const uint8_t sib = next();
  const uint8_t base = sib&0x7;
  uint32_t addr = 0;
  if (base != EBP || mod != 0) {
    addr = Reg[base].u;
    trace(Callstack_depth+1, "run") << "effective address is initially 0x" << HEXWORD << addr << " (" << rname(base) << ")" << end();
  }
  else {
    // base == EBP && mod == 0
    addr = next32();  // ignore base
    trace(Callstack_depth+1, "run") << "effective address is initially 0x" << HEXWORD << addr << " (disp32)" << end();
  }
  const uint8_t index = (sib>>3)&0x7;
  if (index == ESP) {
    // ignore index and scale
    trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << addr << end();
  }
  else {
    const uint8_t scale = (1 << (sib>>6));
    addr += Reg[index].i*scale;  // treat index register as signed. Maybe base as well? But we'll always ensure it's non-negative.
    trace(Callstack_depth+1, "run") << "effective address is 0x" << HEXWORD << addr << " (after adding " << rname(index) << "*" << NUM(scale) << ")" << end();
  }
  return addr;
}

:(code)
void test_add_r32_to_mem_at_base_r32_index_r32() {
  Reg[EBX].i = 0x10;  // source
  Reg[EAX].i = 0x1ffe;  // dest base
  Reg[ECX].i = 0x2;  // dest index
  run(
      "== code 0x1\n"
      // op     ModR/M  SIB   displacement  immediate
      "  01     1c      08                              \n"  // add EBX to *(EAX+ECX)
      // ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB)
      // SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX)
      "== data 0x2000\n"
      "01 00 00 00\n"  // 0x00000001
  );
  CHECK_TRACE_CONTENTS(
      "run: add EBX to r/m32\n"
      "run: effective address is initially 0x00001ffe (EAX)\n"
      "run: effective address is 0x00002000 (after adding ECX*1)\n"
      "run: storing 0x00000011\n"
  );
}

:(code)
void test_add_r32_to_mem_at_displacement_using_sib() {
  Reg[EBX].i = 0x10;  // source
  run(
      "== code 0x1\n"
      // op     ModR/M  SIB   displacement  immediate
      "  01     1c      25    00 20 00 00               \n"  // add EBX to *0x2000
      // ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB)
      // SIB in binary: 00 (scale 1) 100 (no index) 101 (not EBP but disp32)
      "== data 0x2000\n"
      "01 00 00 00\n"  // 0x00000001
  );
  CHECK_TRACE_CONTENTS(
      "run: add EBX to r/m32\n"
      "run: effective address is initially 0x00002000 (disp32)\n"
      "run: effective address is 0x00002000\n"
      "run: storing 0x00000011\n"
  );
}

//:

:(code)
void test_add_r32_to_mem_at_base_r32_index_r32_plus_disp8() {
  Reg[EBX].i = 0x10;  // source
  Reg[EAX].i = 0x1ff9;  // dest base
  Reg[ECX].i = 0x5;  // dest index
  run(
      "== code 0x1\n"
      // op     ModR/M  SIB   displacement  immediate
      "  01     5c      08    02                        \n"  // add EBX to *(EAX+ECX+2)
      // ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 100 (dest in SIB)
      // SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX)
      "== data 0x2000\n"
      "01 00 00 00\n"  // 0x00000001
  );
  CHECK_TRACE_CONTENTS(
      "run: add EBX to r/m32\n"
      "run: effective address is initially 0x00001ff9 (EAX)\n"
      "run: effective address is 0x00001ffe (after adding ECX*1)\n"
      "run: effective address is 0x00002000 (after adding disp8)\n"
      "run: storing 0x00000011\n"
  );
}

:(before "End Mod 1 Special-cases(addr)")
case 4:  // exception: mod 0b01 rm 0b100 => incoming SIB (scale-index-base) byte
  addr = effective_address_from_sib(mod);
  break;

//:

:(code)
void test_add_r32_to_mem_at_base_r32_index_r32_plus_disp32() {
  Reg[EBX].i = 0x10;  // source
  Reg[EAX].i = 0x1ff9;  // dest base
  Reg[ECX].i = 0x5;  // dest index
  run(
      "== code 0x1\n"
      // op     ModR/M  SIB   displacement  immediate
      "  01     9c      08    02 00 00 00               \n"  // add EBX to *(EAX+ECX+2)
      // ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 100 (dest in SIB)
      // SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX)
      "== data 0x2000\n"
      "01 00 00 00\n"  // 0x00000001
  );
  CHECK_TRACE_CONTENTS(
      "run: add EBX to r/m32\n"
      "run: effective address is initially 0x00001ff9 (EAX)\n"
      "run: effective address is 0x00001ffe (after adding ECX*1)\n"
      "run: effective address is 0x00002000 (after adding disp32)\n"
      "run: storing 0x00000011\n"
  );
}

:(before "End Mod 2 Special-cases(addr)")
case 4:  // exception: mod 0b10 rm 0b100 => incoming SIB (scale-index-base) byte
  addr = effective_address_from_sib(mod);
  break;