汇编及C/C++汇编调用约定讲解
> 汇编及C/C++汇编调用约定(汇总帖)
> 汇编编译和gdb调试命令列表
> gdb TUI使用方法
> 汇编C语言调用约定(标准函数)
> 汇编C语言调用约定(递归函数)
> C++内存模型以及寄存器指针rsp和rbp
1. 使用C调用约定的汇编语言函数
- 调用函数后的栈看起来像这样:
参数 #N <--- N*4+4(%ebp) ... 参数 2 <--- 12(%ebp) 参数 1 <--- 8(%ebp) 返回地址 <--- 4(%ebp) 旧%ebp <--- (%ebp) 局部变量 1 <--- -4(%ebp) 局部变量 2 <--- -8(%ebp) 和 (%esp)
2. 标准函数
-
进入函数power后(以下并不是一个完整函数,只包含函数的开头部分)
.type power, @function power: pushl %ebp # 标准函数 - 必须在返回前恢复%ebp到其之前的状态,这里将其入栈 # 将栈指针保存到基址指针中,利用基址指针来访问参数和局部变量 # %esp寄存器可能会因局部变量而向下偏移 movl %esp, %ebp ┎ subl $4, %esp # 为本地存储保留空间,即-4(%ebp) ┇ movl 8(%ebp), %ebx ┇ movl 12(%ebp), %ecx ┕ movl %ebx, -4(%ebp) # 存储当前结果,即一个局部变量
注:关于C/Cxxlanguage main函数中栈指针的偏移,见我的另一篇帖子:C++内存模型以及寄存器指针rsp和rbp
-
结束函数power时(以下并不是一个完整函数,只包含函数的结尾部分)
end_power: movl -4(%ebp), %eax # 将返回值存入%eax # 在使用ret将控制权返回给调用它的代码时,必须恢复前一个栈帧 # 即未调用此函数时的%esp和%ebp寄存器状态 # 以下两条指令是开头部分`pushl %ebp ⇤ movl %esp, %ebp`的逆过程 movl %ebp, %esp # 恢复栈指针 popl %ebp # 恢复基址指针 ret
3. 标准函数完整示例
.code32
.section .data
.section .text
.globl _start
_start:
pushl $3
pushl $2
call power
addl $8, %esp
pushl %eax
pushl $2
pushl $5
call power
addl $8, %esp
popl %ebx
addl %eax, %ebx
movl $1, %eax
int $0x80
.type power, @function
power:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %ebx
movl 12(%ebp), %ecx
movl %ebx, -4(%ebp)
power_loop_start:
cmpl $1, %ecx
je end_power
movl -4(%ebp), %eax
imull %ebx, %eax
movl %eax, -4(%ebp)
decl %ecx
jmp power_loop_start
end_power:
movl -4(%ebp), %eax
movl %ebp, %esp
popl %ebp
ret
4. 标准函数调试