从c调用汇编函数
我试图在汇编中使用一个函数,从C项目调用。这个函数应该调用一个libc函数,比如说从c调用汇编函数,c,linux,assembly,gnu-assembler,C,Linux,Assembly,Gnu Assembler,我试图在汇编中使用一个函数,从C项目调用。这个函数应该调用一个libc函数,比如说printf(),但我一直遇到一个分段错误 在.c文件中,我有函数的声明 int do_shit_in_asm() 在我的.asm文件中 .extern printf .section .data printtext: .ascii "test" .section .text .global do_shit_in_asm .type do_shit_in_asm, @
printf()
,但我一直遇到一个分段错误
在.c文件中,我有函数的声明
int do_shit_in_asm()
在我的.asm文件中
.extern printf
.section .data
printtext:
.ascii "test"
.section .text
.global do_shit_in_asm
.type do_shit_in_asm, @function
do_shit_in_asm:
pushl %ebp
movl %esp, %ebp
push printtext
call printf
movl %ebp, %esp
pop %ebp
ret
如有任何指导员意见,将不胜感激
as func.asm -o func.o
gcc prog.c func.o -o prog
开始使用汇编语言函数的最佳方法之一是用C编写一个类似的函数,然后使用编译器开关生成汇编列表(
-S
,在gcc上)。然后,您可以研究编译器的输出,并根据需要进行修改
如果您正在调用使用不同调用约定的函数,如printf
(由于参数数量可变),这一点尤其有用。调用这些函数可能与调用非varargs函数截然不同。在此之后:
push printtext
call printf
你想要:
addl $4, %esp
进一步解释:
因为您使用的是x86 Linux,所以我假设调用约定要求被调用方清理参数。因为您在调用printf
之前按下了一个指针,所以在该函数的ret
指令发生后,堆栈将关闭4
更新:
是的,好吧,我习惯了英特尔的语法,所以我在脑子里把参数的顺序倒过来。实际上,缺少addl
返回esp
并不重要,因为您正在esp
正确地恢复ret
附近的内容。我的下一个猜测是,传递给printf
的字符串缺少空终止符。。。让我看看煤气有什么作用
更新2:
好的,
gas
null为您终止字符串,所以我猜我的第二个直觉是错误的。看起来你发现了这个问题,所以这一点是没有意义的。问题是我正在使用的
pushl printtext
倒不如
pushl $printtext
感谢大家的帮助,也很抱歉浪费了您的时间:p将
推送打印文本
更改为推送$printtext
事实上,您正在从地址
printtext
加载一个值,并按下该值,而不是按下地址。因此,您正在将'test'
作为32位数字而不是指针传递,而printf
试图将其解释为地址并崩溃。+1对于函数名“任何指针都将受到赞赏”:int*ptr@Sapph+1但它没有帮助:)@Sapph:你的意思是void
*,对吧?@Lambert:回想起来,这太明显了!我很惭愧+先生,我很困惑,因为我习惯了英特尔的语法,而不是AT&T。你真的想要addl$4,%esp
等等,让我再看看…@void-也许你可以检查一下十六进制编辑器。您传递给printf的字符串是否以null结尾?是的,它是$4,%esp我发现了问题,我应该在堆栈上按PUSH$PRITTEXT。您在我发布之前就得到了它。恭喜你解决了你的问题。:-)很有教育意义。。。但通常也会产生误导。真正的问题是ABI特定的细节,即必须保留哪些寄存器、它们的含义以及它们如何与C ABI交互。我最初沿着这条路走,然后意识到我的汇编不会比编译器生成的更好,这与我试图实现的正好相反!