EAX | Multipurpose. Return values from a function are usually stored in EAX. Low 16 bits are referenced as AX. AX can be further subdivided into AL (the low 8 bits), and AH (the upper 8 bits of AX). |
EBX | Multipurpose. Low 16 bits are referenced as BX. BX can be further subdivided into BL (the low 8 bits), and BH (the upper 8 bits of BX). |
ECX | Multipurpose. Often used as a counter, for example, to hold the number of loop iterations that should be performed. Low 16 bits are referenced as CX. CX can be further subdivided into CL (the low 8 bits), and CH (the upper 8 bits of CX). |
EDX | Multipurpose. Low 16 bits are referenced as DX. DX can be further subdivided into DL (the low 8 bits), and DH (the upper 8 bits of DX). |
ESI | Multipurpose. In certain operations that move or compare memory, ESI contains the source address. Low 16 bits are referenced as SI. |
EDI | Multipurpose. In certain operations that move or compare memory, EDI contains the destination address. Low 16 bits are referenced as DI. |
ESP | Stack pointer. Implicitly changed by PUSH, POP, CALL, and RET instructions. |
EBP | Base pointer. Usually points to the current stack frame for a procedure. Procedure parameters are usually at positive offsets from EBP (for example, EBP+8). Local variables are usually at negative offsets (for example, EBP-16). Sometimes, optimizing compilers won't use a stack frame, and use EBP as a multipurpose register. |
EFLAGS | Rarely directly referenced. Instead, instructions implicitly set or clear bitfields within the EFLAGS register to represent a certain state. For example, when the result of a mathe Matical operation is zero, the Zero flag is toggled on in the EFLAGS register. The conditional jump instructions make use of the EFLAGS register. |
FS | 16-bit. Under Win32, the FS register points to a data structure with information pertaining to the current thread. FS is a segment register (segment registers are beyond the scope of this discussion). Intel CPUs have six segment registers, but the Operating system sets the M up and maintains the M. Win32 compilers only need to explicitly refer to the FS segment register, which is used for things like structured exception handling and thread local storage. |
Figure 2 InstructionDemo.CPP
//==========================================
// Matt Pietrek
// Microsoft Systems Journal, February 1998
// Program: InstructionDemo.CPP
// FILE: InstructionDemo.CPP
//==========================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
// Force the Se functions inline (/O2 would normally do this
#pragma intrinsic( memset, strlen, strcmp )
__declspec(thread) int tlsVariable = 0; // Make a thread local variable
int g_myGlobalVariable; // Make a global variable
void MySubProcedure( void );
int main( int argc, char *argv[] )
{
char szBuffer[128];
char *pszString = "Hello";
unsigned long localUnsignedLong = 2;
unsigned char localUnsignedChar = 2;
long localSignedLong = 2;
char localSignedChar = 2;
int i;
g_myGlobalVariable = 0x12345678; // Assignment to global
localSignedLong = localSignedChar; // signed type promotion
// Conditional execution
if ( localUnsignedLong == 2 )
localSignedLong = 1;
else
localSignedLong = 2;
// Using TEST
if ( localUnsignedLong & 0x00040008 )
i = 3;
// AND'ing off bitfields
localUnsignedLong &= 0x01020304;
// OR'ing on bitfields
localSignedLong |= 0x05060708;
// LOOP code
for ( i = 0; i < 4; i++ )
localUnsignedLong += i;
// Procedure invocation
printf( "%u %u %08X %s", localUnsignedLong, argc, &argc, szBuffer );
// Using STOSD / STOSB
memset( szBuffer, 0, sizeof(szBuffer) );
// Using SCASB
i = strlen( szBuffer );
MySubProcedure( );
return 0;
}
void MySubProcedure( void )
{
tlsVariable = 2;
// Use of try/except code
__try
{
g_myGlobalVariable = 2;
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
g_myGlobalVariable = 4;
}
}
Figure 3 InstructionDemo Mixed Source and Assembly
int main( int argc, char *argv[] )
{
401000: PUSH EBP
401001: MOV EBP,ESP
401003: SUB ESP,00000098
401009: PUSH EDI
char *pszString = "Hello";
40100A: MOV DWORD PTR [EBP-0000008C],00406030
unsigned long localUnsignedLong = 2;
401014: MOV DWORD PTR [EBP-00000088],00000002
unsigned char localUnsignedChar = 2;
40101E: MOV BYTE PTR [EBP-00000094],02
long localSignedLong = 2;
401025: MOV DWORD PTR [EBP-00000084],00000002
char localSignedChar = 2;
40102F: MOV BYTE PTR [EBP-00000098],02
g_myGlobalVariable = 0x12345678; // Assignment to global
401036: MOV DWORD PTR [004088E8],12345678
localSignedLong = localSignedChar; // signed type promotion
401040: MOVSX EAX,BYTE PTR [EBP-00000098]
401047: MOV DWORD PTR [EBP-00000084],EAX
// Conditional execution
if ( localUnsignedLong == 2 )
40104D: CMP DWORD PTR [EBP-00000088],02
401054: JNE 00401062
localSignedLong = 1;
401056: MOV DWORD PTR [EBP-00000084],00000001
else
401060: JMP 0040106C
localSignedLong = 2;
401062: MOV DWORD PTR [EBP-00000084],00000002
// Using TEST
if ( localUnsignedLong & 0x00040008 )
40106C: MOV ECX,DWORD PTR [EBP-00000088]
401072: AND ECX,00040008
401078: TEST ECX,ECX
40107A: JE 00401086
i = 3;
40107C: MOV DWORD PTR [EBP-00000090],00000003
// AND'ing off bitfields
localUnsignedLong &= 0x01020304;
401086: MOV EDX,DWORD PTR [EBP-00000088]
40108C: AND EDX,01020304
401092: MOV DWORD PTR [EBP-00000088],EDX
// OR'ing on bitfields
localSignedLong |= 0x05060708;
401098: MOV EAX,DWORD PTR [EBP-00000084]
40109E: OR EAX,05060708
4010A3: MOV DWORD PTR [EBP-00000084],EAX
// LOOP code
for ( i = 0; i < 4; i++ )
4010A9: MOV DWORD PTR [EBP-00000090],00000000
4010B3: JMP 004010C4
4010B5: MOV ECX,DWORD PTR [EBP-00000090]
4010BB: ADD ECX,01
4010BE: MOV DWORD PTR [EBP-00000090],ECX
4010C4: CMP DWORD PTR [EBP-00000090],04
4010CB: JNL 004010E1
localUnsignedLong += i;
4010CD: MOV EDX,DWORD PTR [EBP-00000088]
4010D3: ADD EDX,DWORD PTR [EBP-00000090]
4010D9: MOV DWORD PTR [EBP-00000088],EDX
4010DF: JMP 004010B5
// Procedure invocation
printf( "%u %u %08X %s", localUnsignedLong, argc, &argc, szBuffer );
4010E1: LEA EAX,[EBP-80]
4010E4: PUSH EAX
4010E5: LEA ECX,[EBP+08]
4010E8: PUSH ECX
4010E9: MOV EDX,DWORD PTR [EBP+08]
4010EC: PUSH EDX
4010ED: MOV EAX,DWORD PTR [EBP-00000088]
4010F3: PUSH EAX
4010F4: PUSH 00406038
4010F9: CALL 004011C0
4010FE: ADD ESP,14
// Using STOSD / STOSB
memset( szBuffer, 0, sizeof(szBuffer) );
401101: MOV ECX,00000020
401106: XOR EAX,EAX
401108: LEA EDI,[EBP-80]
40110B: REP STOSD
// Using SCASB
i = strlen( szBuffer );
40110D: LEA EDI,[EBP-80]
401110: OR ECX,FF
401113: XOR EAX,EAX
401115: REPNE SCASB
401117: NOT ECX
401119: ADD ECX,FF
40111C: MOV DWORD PTR [EBP-00000090],ECX
MySubProcedure( );
401122: CALL 0040112E
return 0;
401127: XOR EAX,EAX
}
401129: POP EDI
40112A: MOV ESP,EBP
40112C: POP EBP
40112D: RET
void MySubProcedure( void )
{
40112E: PUSH EBP
40112F: MOV EBP,ESP
401131: PUSH FF
401133: PUSH 00405058
401138: PUSH 004012F8
40113D: MOV EAX,FS:[00000000]
401143: PUSH EAX
401144: MOV DWORD PTR FS:[00000000],ESP
40114B: SUB ESP,08
40114E: PUSH EBX
40114F: PUSH ESI
401150: PUSH EDI
401151: MOV DWORD PTR [EBP-18],ESP
tlsVariable = 2;
401154: MOV EAX,[004088EC]
401159: MOV ECX,DWORD PTR FS:[0000002C]
401160: MOV EDX,DWORD PTR [ECX+EAX*4]
401163: MOV DWORD PTR [EDX+00000004],00000002
__try
{
40116D: MOV DWORD PTR [EBP-04],00000000
g_myGlobalVariable = 2;
401174: MOV DWORD PTR [004088E8],00000002
40117E: MOV DWORD PTR [EBP-04],FFFFFFFF
401185: JMP 004011A1
__except( EXCEPTION_EXECUTE_HANDLER )
401187: MOV EAX,00000001
40118C: RET
40118D: MOV ESP,DWORD PTR [EBP-18]
g_myGlobalVariable = 4;
401190: MOV DWORD PTR [004088E8],00000004
}
40119A: MOV DWORD PTR [EBP-04],FFFFFFFF
}
4011A1: MOV ECX,DWORD PTR [EBP-10]
4011A4: MOV DWORD PTR FS:[00000000],ECX
4011AB: POP EDI
4011AC: POP ESI
4011AD: POP EBX
4011AE: MOV ESP,EBP
4011B0: POP EBP
4011B1: RET