汇编语言函数调用过程(转)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
汇编语⾔函数调⽤过程(转)
今天看了Programming from the Ground Up的函数(Page 53)调⽤⼀章,对汇编语⾔函数调⽤有了⼀些了解。
在汇编语⾔中需要调⽤函数时要call这个函数名,函数的执⾏过程如下:
准备执⾏
在主程序中每次调⽤函数时,先依次把各参数以相反的顺序⼊栈;
然后call func_name, 这⾥call要做两件事: ⼀是把函数的返回地址⼊栈,⼆是让指令执⾏指针%eip指向函数开始处。
开始执⾏
现在函数要开始执⾏了,但它执⾏函数代码前还要做⼀点⼩事,⾸先把原来的基地址寄存器%ebp值⼊栈,因为在程序执⾏中%ebp要另作它⽤, 接着堆栈指针%esp的值复制给%ebp, 此后在函数执⾏中%ebp⼀直保持不变,可以由此寻址获得函数参数。
pushl %ebp
movl %esp, %ebp
下⾯开始执⾏函数代码了。
函数先要把它的局部变量保存在栈中,这很简单。
⽐如要保存⼀个long型数据,只要把%esp指针向下移动4个字节(因为栈增长⽅向是由⾼地址到低地址),再根据%esp把该数据移⼊. 下⾯是保存两个局部变量long后的堆栈内容:
Parameter #N <--- N*4+4(%ebp)
...
Parameter 2 <--- 12(%ebp)
Parameter 1 <--- 8(%ebp)
Return Address <--- 4(%ebp)
Old %ebp <--- (%ebp)
Local Variable 1 <--- -4(%ebp)
Local Variable 2 <--- -8(%ebp) and (%esp)
从上可以看出通过%ebp基地址寻址可以访问所有的函数参数和局部变量. 当然也可以不⽤
%ebp⽽⽤其它的寄存器进⾏同样的基地址寻址。
但对于x86结构使⽤%ebp寄存器可能会更
快⼀点。
执⾏结束:
现在函数执⾏要结束了,在它返回之前,还要做下⾯⼏件事:
1. 把函数的返回值存放在通⽤寄存器%eax中,供外部使⽤
2. 把%esp指向函数开始执⾏的位置, 即movl %ebp,%esp
3. 在函数返回ret之前,要还原ebx, 即popl %ebp
movl %ebp, %esp
popl %ebp
ret
从上也可以看出,当%esp指向函数开始执⾏的位置后,局部变量也就没有意义了(因为此时
esp指向的栈地址⾼于那些局部变量的地址)。
函数执结束ret返回后,要把call时push的所有函数参数也pop出来(或者直接在%esp上加参数的个数的4倍,如果不需要再使⽤这些参数值的话)。
addl $8, %esp # 因为有两个参数8个字节
下⾯是⼀段代码power.s,计算2^3+5^2
# ==================== asm code begin ===================
#PURPOSE: Program to illustrate how functions work. This program will compute
#the value of 2^3+5^2
.section .data
.section .text
.global _start
_start:
pushl $3
pushl $2
call power # 调⽤power(2,3)函数
addl $8, %esp # 函数结束后,堆栈指针%esp要返回到参数之前,即加上4*2
pushl %eax # 把第⼀次计算的power(2,3)的结果(保存在%eax中),⼊栈保存
pushl $2
pushl $5
call power #调⽤power(5,2)
addl $8, %esp # 函数结束后,堆栈指针%esp要返回到参数之前,即加上4*2
popl %ebx #从堆栈中取出第⼀次计算的power(2,3)结果,放在%ebx中
addl %eax, %ebx # 两者相加保存在%ebx中
movl $1,%eax
int $0x80
#系统调⽤结束,调⽤号保存在%eax中(为1),返回值保存在%ebx中(为计算结果33) # function long power(long a,long b) =a^b
.type power, @function
power:
pushl %ebp # %ebp⼊栈
movl %esp, %ebp # %ebp中保存%esp值,⽤作下⾯的基地址寻址
subl $4, %esp
movl 8(%ebp) ,%ebx #把参数a的值赋给%ebx
movl 12(%ebp) ,%ecx #把参数b的值赋给%ecx
movl %ebx, -4(%ebp) #下⾯是对a做b次循环计算,把中间结果存放在-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 # 返回值给%ebx
movl %ebp, %esp # %esp回到函数执⾏开始位置
popl %ebp # ret前要还原函数执⾏初的%ebp值
ret
#================= asm code end ====================
#as power.s -o power.o
#ld power.o -o power
#./power
#echo $?
33。