Question

I was doing some experimenting with machine code in MSVC++ and created a function that would allow me to build mov operations around registers with signed displacements. All went well until I had my function build off of mov [esp-4], eax. Suddenly, my program started crashing. After having a peek in the disassembly, I noticed something rather strange. For this mov op dereferencing an offset from the ESP register, an additional byte was being placed between the parameter byte and the signed displacement. This byte always seemed to be 0x24. So out of curiosity, I disassembled the following __asm block and got some interesting results:

mov [eax - 4], eax
mov [ecx - 4], eax
mov [edx - 4], eax
mov [ebx - 4], eax
mov [esp - 4], eax
mov [ebp - 4], eax
mov [esi - 4], eax
mov [edi - 4], eax

The machine code translated the above into:

89 40 FC
89 41 FC
89 42 FC
89 43 FC
89 44 24 FC      <--- WAT!
89 45 FC
89 46 FC
89 47 FC

I typed hex 24 into Windows calculator and switched it to binary. The result was 00100100. What this appears to be is two dummy bits followed by the ESP register twice.

Can anyone shed some light on why this is happening? I think this goes beyond weird quirks of the MS C++ compiler and straight into the realm of legacy functionality from the '70s or '80s ('90s?), but I can't find any online references as to why ESP is an exception for this flavor of mov operation. Thanks!

Was it helpful?

Solution

[esp] can not be encoded using a modr/m byte only, it needs a SIB byte. See Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte in the intel instruction set reference. The 44 value of modr/m encodes that the other operand is eax and that a SIB byte and a displacement byte follows. SIB value of 24 encodes [esp], see Table 2-3. 32-Bit Addressing Forms with the SIB Byte.

The SIB can encode all the other variants too, but since that is 1 byte longer, the assembler doesn't use that form. Here is the list for reference:

89 44 20 FC mov [eax-0x4],eax
89 44 21 FC mov [ecx-0x4],eax
89 44 22 FC mov [edx-0x4],eax
89 44 23 FC mov [ebx-0x4],eax
89 44 24 FC mov [esp-0x4],eax
89 44 25 FC mov [ebp-0x4],eax
89 44 26 FC mov [esi-0x4],eax
89 44 27 FC mov [edi-0x4],eax

This, by itself, shouldn't cause your crash, but randomly trying to overwrite stuff in memory may.

OTHER TIPS

If you look at the second byte of the instruction, you see an incrementing sequence of 3 bit values, 0 through 7, which represent register operands, except for 4. The value of 4 is used for more generic operand types and Intel chose to put esp in the generic list, since ebp is used more often for stack based references.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top