一、参数和局部变量的布局:
_cdecl调用约定,stdcall约定,函数参数入栈:(从右往左)(只有pascal是从左往右)
00401000:
push 6
push 5
call 00401010 ;add函数首地址
add esp ,8 ;平衡栈
xor eax,eax
retn
nop
add()函数代码
00401010:
mov eax,dword ptr [esp+8]
mov ecx,dword ptr [esp+4]
add eax,ecx
retn
优化处理:
enter:xxx,0(push ebp,mov ebp,esp,sub esp,xxx);创建空间放局部变量
leave:(add esp,xxx,pop ebp);恢复现场
ret 8(参数个数乘4h)
ebp寻址找参数,在ebp处进行,ebp+8h(第一个参数),ebp+Ch(第二个参数)
esp寻址找参数,在retn处进行,esp+4h(第一个参数),esp+8h(第二个参数)
32位的情况下:栈传递参数
64位的情况下:rdi,rsi,rdx,rcx,r8,r9寄存器用完,再栈传递参数
参数的调用偏移是正的,局部变量的调用偏移是负的
(push reg = sub esp,4)(pop reg = add esp,4)
实践下手撕汇编:
image.png
image.png
二、全局变量的布局:
一般放在内存区域中(通常是.data,具有可读写的权限):
mov eax,dword ptr [4084C0h];直接调用全局变量,其中4084C0h是全局变量的地址
三、数组的布局:
mov eax,[407040h+eax](基址+偏移量)
四、控制语句:
test指令,cmp指令,有时会有dec指令(自减):
转移指令一览:一般用于条件判断时和循环时
call:调用
jmp:无条件跳转
jo:溢出跳转(OF=1),对应于jno
jb:低于/进位跳转(CF=1),对应jnb(bottom)
ja:高于跳转,对应jna(tall)
jbe:低于等于跳转
jae:高于等于跳转
je/jz:相等跳转(ZF=1),对应jne/jnz
js:符号为负跳转(SF=1),对应jns
jl:小于跳转,对应jnl(low)
jle:小于等于跳转
jg:大于跳转,对应jng(big,great,large)
jge:大于等于跳转
nop:不跳转,空指针
在Maximize Speed优化下:lea相当于一条算数指令
汇编除法优化:转成乘法运算,右移多少位,就是除以2的多少次方,数学公式表示:
x/2^n = x>>n(x>=0),x/2^n = (x+(2^n-1))>>n(x<0)
有符号位移位运算:sar
无符号位移位运算:shr
C字符串:\0作为结束标志
mov eax,[401000h];直接寻址,传的是地址里面的数据
mov eax,[ecx];寄存器间接寻址,传的是寄存器中存的地址里面的数据
lea eax,[401000h];将值401000h写入eax寄存器
x64:类似于32位,稍有不同~等待更新
一般来说都有main,没有时可能是/MT模式,此时找call cs:exit,该处上面的call 就是main函数
x64的exe文件是利用RCX,RDX,R8,R9先进行传参,不够再调用栈来存。
rdi演化成了rbp。
网友评论