例如一段简单的C语言程序:
int mywork(int a[9], int b[9], int c[9])
{
int i;
for ( i=0; i<9; i++)
c[i] =a[i] +b[i];
}
这段代码debug版反汇编后代码很简单,但是里面有许多小细节值得推敲。
int mywork(int a[9], int b[9], int c[9]) ;原c代码
… … ;这里为开始调用函数时当前寄存器数据保存
for ( i = 0 i < 9 i ++)
mov dword ptr [i], 0 ;这里为i初始化,值为0
jmp mywork+xx1h ;进入循环体内部
mov eax, dword ptr [i]
add eax, 1
mov dword ptr [i], eax
mywork+xx1h: cmp dword ptr [i], 9
jge mywork+xx2h ;如果i等于或大于9,跳出循环
c[i] =a[i] +b[i];
mov eax, dowrd ptr [i] ;读入参数i
mov ecx, dword ptr [a] ;这里是读入参数数组a的首地址
mov edx, dword ptr [b] ;这里是读入参数数组b的首地址
mov eax, dword ptr [ecx + eax*4] ;读入a
add eax, dword ptr [edx +eax*4] ; eax = a[i]+b[i]
mov edi, dword ptr [c] ;这里是读入参数数组c的首地址
mov dword ptr [edi+ eax*4], eax ;这里保存计算结果,c[i]= a[i]+b[i]
inc eax jmp mywork+xx1h
mywork+xx2h: … … ;一些数据恢复操作,主要是出栈等
ret
文中用红色标记处两处涉及ptr指令的地方。
第一处为mov eax, dword ptr [i]
本条mov指令的结果是将变量i的值读入到eax寄存器中,至于从i变量存储地址处读取几个字节,由dword修饰符指定(4个字节)。
第二处为mov ecx, dword ptr [a]
这里表示将参数数组a的首地址读入到ecx寄存器中。
同样两个mov 寄存器, dword ptr [变量]操作,为何第一个寄存器eax读入数值,而第二个ecx寄存器读入的为地址呢?
ptr指令会指定并修改当前已分配内存地址的标记,因为i为c语言子函数mywork中定义的int变量,而非外部传入的参数,从而在执行子函数的汇编程序中变量i的值就是保存在dword ptr [i]返回的内存地址中,占用4个字节,所以mov eax, dword ptr [i]指令将源操作数指定的地址中数据(即int变量i的值)读入到eax寄存器中;而第二处中由于数组a的首地址是作为参数传送到mywork中的,在调用mywork前,3个数组参数a、b、c的首地址依次按照c、b、a的顺序被push入栈,并且传递给子函数,因此dword ptr [a]表示数组a作为参数传递给子函数的值,即其起始首地址,并非a[0]的值,从而mov ecx, dword ptr [a]后的结果是把数组a的首地址保存在了ecx中,而非a[0]的值.