汇编语言知多少(三): 函数调用
2018-10-25 本文已影响132人
Lin__Chuan
接着上一篇文章, 这篇主要讲汇编程序中函数的调用.
call 和 ret 指令: 函数的调用.
- call 标号 : 将下一条指令的偏移地址入栈后, 转到标号处执行指令
- ret : 将栈顶的值出栈, 赋值给 ip.
下面是代码的一部分, 功能是 调用 print '函数', 打印字符串
; 代码段
code segment
start:
; 手动设置ds, ss 的值
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
; 业务逻辑
call print
; 程序退出
mov ah, 4ch
int 21h
; 如果这里程序不退出, 它会继续向下执行 print 这个函数, 'print' 在这里只是相当于一个标志
print:
; ds: dx 告知字符串地址
lea dx, string
mov ah, 9h ; 功能号 9h 指在屏幕上显示字符串
int 21h ; 执行 DOS 系统功能调用.
ret
code ends
end start
我需要说明的几点
-
call print,
print
这里就是一个标号(函数名),call
将下一条指令的偏移地址入栈后, 转到 print 处执行指令, 这个下一条指令
就是mov ah, 4ch
. - 当 print 处的代码执行完后, 每个函数都会有一个 ret 指令, 这个指令会将栈顶的值出栈, 栈顶的值就是
mov ah, 4ch
这条指令的偏移地址, 赋值给 ip. 导致 print 函数执行完后, 可以继续向下执行其他的指令.
函数调用的整个流程
assume cs:code, ds:data, ss:stack
; 栈段
stack segment
db 100 dup(0)
stack ends
; 数据段
data segment
db 100 dup(0)
data ends
; 代码段
code segment
start:
; 手动设置ds、ss的值
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov si, 1
mov di, 2
mov bx, 3
mov bp, 4
; 业务逻辑
push 1
push 2
call sum
add sp, 4
; 退出
mov ax, 4c00h
int 21h
; 返回值放ax寄存器
; 传递2个参数(放入栈中)
sum:
; 保护bp
push bp
; 保存sp之前的值:指向bp以前的值
mov bp, sp
; 预留10个字节的空间给局部变量
sub sp, 10
; 保护可能会用到的寄存器
push si
push di
push bx
; 给局部变量空间填充int 3(CCCC)
; stosw的作用:将ax的值拷贝到es:di中,同时di的值会+2
mov ax, 0cccch
; 让es等于ss
mov bx, ss
mov es, bx
; 让di等于bp-10(局部变量地址最小的区域)
mov di, bp
sub di, 10
; cx决定了stosw的执行次数
mov cx, 5
rep stosw
; rep的作用:重复执行某个指令(执行次数由cx决定)
; -------- 业务逻辑 - begin
; 定义2个局部变量
mov word ptr ss:[bp-2], 3
mov word ptr ss:[bp-4], 4
mov ax, ss:[bp-2]
add ax, ss:[bp-4]
mov ss:[bp-6], ax
; 访问栈中的参数
mov ax, ss:[bp+4]
add ax, ss:[bp+6]
add ax, ss:[bp-6]
; -------- 业务逻辑 - end
; 恢复寄存器的值
pop bx
pop di
pop si
; 恢复sp
mov sp, bp
; 恢复bp
pop bp
ret
code ends
end start
说明
- 1.push 参数
- 2.push 函数的返回地址
- 3.push bp (保留bp之前的值,方便以后恢复)
- 4.mov bp, sp (保留sp之前的值,方便以后恢复), SP 栈顶指针寄存器, BP, 基址指针寄存器
- 5.sub sp,空间大小 (分配空间给局部变量)
- 6.保护可能要用到的寄存器
- 7.使用CC ( int 3) 填充局部变量的空间
- 8.--------执行业务逻辑--------
- 9.恢复寄存器之前的值
- 10.mov sp, bp (恢复sp之前的值)
- 11.pop bp (恢复bp之前的值)
- 12.ret (将函数的返回地址出栈,执行下一条指令)
- 13.恢复栈平衡 (add sp,参数所占的空间)
- 栈平衡: 函数调用前后的栈顶指针要一致. 栈如果不平衡, 栈空间迟早会被用完.
- 栈平衡分内平栈 和 外平栈
栈帧 (Stack Frame Layout)
栈帧是一个函数执行的环境, 包括参数, 局部变量, 返回地址

- 由 下 到 上地址逐渐减小
- 栈帧 3 调用 栈帧2, 栈帧2 调用 栈帧 1, 栈帧1 执行完后, 被释放, SP, BP 逐渐增大

注意: 方向和上面是相反的.
