从c调用汇编函数

从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, @

我试图在汇编中使用一个函数,从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, @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交互。我最初沿着这条路走,然后意识到我的汇编不会比编译器生成的更好,这与我试图实现的正好相反!