|
在源代码文件中,汇编函数里的指令必须和主程序的其余指令分开。为了在 GNU 汇编器中定义函数,必须在程序中把函数名称声明为标签。为汇编器声明函数名称,可以使用 .type 命令:.type func1, @function
func1: 上面定义告诉汇编器,函数从 func1 标签处开始。在函数中,可以访问寄存器和内存位置,可以使用专门特性,如 FPU、MMX 和 SSE。
函数的结束由 RET 指令定义。当执行 RET 时,程序返回到主程序,返回的位置紧跟在调用函数的 CALL 指令后面的指令。
在一般情况下,有两种参参数传递情况最为常见:
函数测试程序:.section .data
precision:
.byte 0x7f, 0x00
.section .bss
.lcomm value, 4
.lcomm result, 4
.section .text
.global _start
_start:
nop
finit
fldcw precision #设置FPU为单精度
movl $10, %ebx
call area
movl $2, %ebx
call area
movl $1, %eax
movl $0, %ebx
int $0x80
.type area, @function #求圆面积函数
area:
fldpi #pi值加载到FPU寄存器堆栈
imull %ebx, %ebx #半径的平方
movl %ebx, value
filds value #半径平方值加载到FPU堆栈顶部
fmulp %st(0), %st(1) #圆面积存于st(1),然后弹st(0)出堆栈,最终结果值存于st(0)中
fstps result #结果出栈后存入全局变量result中
movl result, %eax #将结果值放入EAX
ret #函数返回 三点说明:
1. 函数的放置位置
函数代码可以放在主程序的代码后面,也可以放在前面。在连接源代码时,连接器查找标签为 _start 的代码段作为要执行的第一条指令。可以把任意数量的函数代码放在 _start 之前。
2. 使用寄存器
上面程序中的 area 函数在处理过程中只使用了单一输出寄存器,但更加复杂的函数不会这么做。函数经常使用寄存器处理数据,不能保证函数完成时寄存器状态和函数被调用之前的状态相同。在函数中使用寄存器,要保证在函数返回后寄存器的状态也要得到恢复。所以在调用函数之前,可以使用 PUSH 指令单独地保存特定寄存器,也可以使用 PUSHA 指令同时保存所有寄存器。类似的,可以使用 POP 指令单独地恢复特定寄存器,也可以使用 POPA 指令同时恢复所有寄存器。
3. 全局变量
上面程序中,result 是个全局变量,在主程序里也可以访问它。但使用全局变量来传递参数和返回结果不是常见的程序设计方法,即使在 C 和 C++ 程序设计中也不是。 |
|