# Mu - subx/016index_addressing.cc

      1 //: operating on memory at the address provided by some register plus optional scale and offset
      2
      3 :(scenario add_r32_to_mem_at_r32_with_sib)
      4 % Reg[EBX].i = 0x10;
      5 % Reg[EAX].i = 0x2000;
      6 == 0x1  # code segment
      7 # op  ModR/M  SIB   displacement  immediate
      8   01  1c      20                             # add EBX to *EAX
      9 # ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB)
     10 # SIB in binary: 00 (scale 1) 100 (no index) 000 (base EAX)
     11 == 0x2000  # data segment
     12 01 00 00 00  # 1
     13 +run: add EBX to r/m32
     14 +run: effective address is initially 0x00002000 (EAX)
     15 +run: effective address is 0x00002000
     16 +run: storing 0x00000011
     17
     18 :(before "End Mod 0 Special-cases(addr)")
     19 case 4:  // exception: mod 0b00 rm 0b100 => incoming SIB (scale-index-base) byte
     20   addr = effective_address_from_sib(mod);
     21   break;
     22 :(code)
     23 uint32_t effective_address_from_sib(uint8_t mod) {
     24   const uint8_t sib = next();
     25   const uint8_t base = sib&0x7;
     26   uint32_t addr = 0;
     27   if (base != EBP || mod != 0) {
     28     addr = Reg[base].u;
     29     trace(90, "run") << "effective address is initially 0x" << HEXWORD << addr << " (" << rname(base) << ")" << end();
     30   }
     31   else {
     32     // base == EBP && mod == 0
     33     addr = next32();  // ignore base
     34     trace(90, "run") << "effective address is initially 0x" << HEXWORD << addr << " (disp32)" << end();
     35   }
     36   const uint8_t index = (sib>>3)&0x7;
     37   if (index == ESP) {
     38     // ignore index and scale
     39     trace(90, "run") << "effective address is 0x" << HEXWORD << addr << end();
     40   }
     41   else {
     42     const uint8_t scale = (1 << (sib>>6));
     43     addr += Reg[index].i*scale;  // treat index register as signed. Maybe base as well? But we'll always ensure it's non-negative.
     44     trace(90, "run") << "effective address is 0x" << HEXWORD << addr << " (after adding " << rname(index) << "*" << NUM(scale) << ")" << end();
     45   }
     46   return addr;
     47 }
     48
     49 :(scenario add_r32_to_mem_at_base_r32_index_r32)
     50 % Reg[EBX].i = 0x10;  // source
     51 % Reg[EAX].i = 0x1ffe;  // dest base
     52 % Reg[ECX].i = 0x2;  // dest index
     53 == 0x1  # code segment
     54 # op  ModR/M  SIB   displacement  immediate
     55   01  1c      08                             # add EBX to *(EAX+ECX)
     56 # ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB)
     57 # SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX)
     58 == 0x2000  # data segment
     59 01 00 00 00  # 1
     60 +run: add EBX to r/m32
     61 +run: effective address is initially 0x00001ffe (EAX)
     62 +run: effective address is 0x00002000 (after adding ECX*1)
     63 +run: storing 0x00000011
     64
     65 :(scenario add_r32_to_mem_at_displacement_using_sib)
     66 % Reg[EBX].i = 0x10;  // source
     67 == 0x1  # code segment
     68 # op  ModR/M  SIB   displacement  immediate
     69   01  1c      25    00 20 00 00              # add EBX to *0x2000
     70 # ModR/M in binary: 00 (indirect mode) 011 (src EBX) 100 (dest in SIB)
     71 # SIB in binary: 00 (scale 1) 100 (no index) 101 (not EBP but disp32)
     72 == 0x2000  # data segment
     73 01 00 00 00  # 1
     74 +run: add EBX to r/m32
     75 +run: effective address is initially 0x00002000 (disp32)
     76 +run: effective address is 0x00002000
     77 +run: storing 0x00000011
     78
     79 //:
     80
     81 :(scenario add_r32_to_mem_at_base_r32_index_r32_plus_disp8)
     82 % Reg[EBX].i = 0x10;  // source
     83 % Reg[EAX].i = 0x1ff9;  // dest base
     84 % Reg[ECX].i = 0x5;  // dest index
     85 == 0x1  # code segment
     86 # op  ModR/M  SIB   displacement  immediate
     87   01  5c      08    02                       # add EBX to *(EAX+ECX+2)
     88 # ModR/M in binary: 01 (indirect+disp8 mode) 011 (src EBX) 100 (dest in SIB)
     89 # SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX)
     90 == 0x2000  # data segment
     91 01 00 00 00  # 1
     92 +run: add EBX to r/m32
     93 +run: effective address is initially 0x00001ff9 (EAX)
     94 +run: effective address is 0x00001ffe (after adding ECX*1)
     95 +run: effective address is 0x00002000 (after adding disp8)
     96 +run: storing 0x00000011
     97
     98 :(before "End Mod 1 Special-cases(addr)")
     99 case 4:  // exception: mod 0b01 rm 0b100 => incoming SIB (scale-index-base) byte
    100   addr = effective_address_from_sib(mod);
    101   break;
    102
    103 //:
    104
    105 :(scenario add_r32_to_mem_at_base_r32_index_r32_plus_disp32)
    106 % Reg[EBX].i = 0x10;  // source
    107 % Reg[EAX].i = 0x1ff9;  // dest base
    108 % Reg[ECX].i = 0x5;  // dest index
    109 == 0x1  # code segment
    110 # op  ModR/M  SIB   displacement  immediate
    111   01  9c      08    02 00 00 00              # add EBX to *(EAX+ECX+2)
    112 # ModR/M in binary: 10 (indirect+disp32 mode) 011 (src EBX) 100 (dest in SIB)
    113 # SIB in binary: 00 (scale 1) 001 (index ECX) 000 (base EAX)
    114 == 0x2000  # data segment
    115 01 00 00 00  # 1
    116 +run: add EBX to r/m32
    117 +run: effective address is initially 0x00001ff9 (EAX)
    118 +run: effective address is 0x00001ffe (after adding ECX*1)
    119 +run: effective address is 0x00002000 (after adding disp32)
    120 +run: storing 0x00000011
    121
    122 :(before "End Mod 2 Special-cases(addr)")
    123 case 4:  // exception: mod 0b10 rm 0b100 => incoming SIB (scale-index-base) byte
    124   addr = effective_address_from_sib(mod);
    125   break;