例子:在C的main函数中调用汇编语言写的addone函数,把传入的参数加一然后返回。
汇编里面首先要把用到的寄存器压栈,使用指令global使函数可以在其他文件中调用,顺便说一句,C中的static函数之所以只能在本文件中可用,就是编译后的汇编文件没有用global指令,汇编的返回值放在EAX寄存器中。
汇编文件名是addone.asm,汇编方法在后面,内容如下:
global addone ;
addone: MOV RAX, [RSP + 20] ; stack top + 20 bytes
ADD RAX, 1
RET传入的参数在栈顶以下20个字节处,为什么是20我也不知道,是在C的编译后的汇编中看出来的,C文件文件名calladdone.c,内容如下:
#include <stdio.h>
int main(){
int a = 3;
// printf("before call, a is %d.\n", a);
a = addone(a);
//printf("after call, a is %d.\n", a);
return 0;
}编译后的C文件如下:
.file "calladdone.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $3, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %edi
movl $0, %eax
call addone
movl %eax, -4(%rbp)
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
.section .note.GNU-stack,"",@progbits
中间两句:
subq
$16, %rsp
movl $3, -4(%rbp)
栈顶向低地址增长16字节,又把a=3放在-4($rbp)的地方,就是栈顶向下12的地方,然后调用addone,就是这句:
call
addone
会向栈中压入一个返回地址,我机器64位,所以是8个字节,现在参数a就在栈顶向下20的地方了。(PS:不知道那个16是不是gcc约定好的。。。)
然后编译就可以了,汇编asm文件:
nasm -felf64 addone.asm
我用的汇编器是nasm,64位机器所以汇编选项是-felf64,32位机器汇编选项是-felf,然后后面跟文件名。如果要调试信息可以再加上-g选项。
汇编后生成一个addone.o文件,就是object file了。然后把这个文件和C文件一起编译:
gcc calladdone.c addone.ogcc没有-o选项的话默认生成a.out文件,gdb中运行那个文件,加个断点可以看到a的值确实加了1。把上面C文件中注释去掉,输出如下:
before call, a is 3.
after call, a is 4.
一切正常。
最后贴一下gdb中怎么使用x查看寄存器和栈,在gdb中直接help x就可以看到了:
Examine memory: x/FMT ADDRESS.
ADDRESS is an expression for the memory address to examine.
FMT is a repeat count followed by a format letter and a size letter.
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
t(binary), f(float), a(address), i(instruction), c(char) and s(string).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
The specified number of objects of the specified size are printed
according to the format.
Defaults for format and size letters are those previously used.
Default count is 1. Default address is following last thing printed
with this command or "print".
比如查看栈顶向下20个字(word)可以这么用:x/20w $rsp
查看栈顶向下10个字节(byte)可以这么用:x/10b $rsp
本文展示了如何在C程序中调用汇编语言编写的addone函数,该函数接受一个参数并将其加一。文章详细解释了参数传递的位置、汇编函数的声明以及使用nasm汇编器进行编译的过程。通过gdb调试工具,作者验证了函数调用的正确性。

2310

被折叠的 条评论
为什么被折叠?



