从C语言调用汇编函数

26

我正在尝试在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

37
有任何建议都将不胜感激:int *ptr; - Sapph
@Sapph +1 但是它并没有帮助 :)) - user173973
12
你的意思是 void*,对吗? - user541686
1
@Lambert:回想起来,这真是太明显了!我感到很羞愧。向您致敬。+1 - Sapph
4个回答

16

push printtext更改为push $printtext

现在您正在从地址printtext加载一个值并将其推送,而不是推送地址。因此,您正在以32位数字形式传递'test',而不是指针,printf尝试将其解释为地址并崩溃。


9

开始学习汇编语言函数的最佳方法之一是先用C语言编写类似的函数,然后使用编译器开关生成汇编列表(-S在gcc中)进行构建。然后您可以研究编译器所做的输出,并根据需要进行修改。

如果您正在调用诸如printf这样使用不同调用约定的函数(由于参数数量可变),则这尤其有用。调用这些函数可能与调用非变量参数函数大不相同。


1
非常有教育意义......但通常也非常误导人。真正的问题在于ABI特定细节,即必须保留哪些寄存器,它们的含义以及它们如何与C ABI交互。我最初走了这条路,然后意识到我的汇编代码不会比编译器生成的代码更好,这恰恰与我想要实现的相反! - bbum

6
问题在于我使用的是:
pushl printtext

相比于
pushl $printtext

感谢大家的帮助,对于浪费你们的时间我感到抱歉:P

1
你在我发布之前就得到了它。恭喜你解决了问题。 :-) - R.. GitHub STOP HELPING ICE

2

在这之后:

push printtext
call printf

您需要:

addl $4, %esp
进一步解释: 因为您正在使用x86 Linux,我假设调用约定要求被调用方清理参数。因为在调用printf之前您推送了一个指针,所以在该函数的ret指令执行后,您的堆栈会多出4个字节。 更新: 是的,好的,我习惯于使用英特尔语法,所以我在脑海中把参数的顺序搞反了。实际上,缺少对espaddl回退并不重要,因为您在ret附近正确地恢复了esp。我的下一个猜测是,您传递给printf的字符串缺少空终止符...让我看看gas做了什么... 更新2: 好的,gas会为您添加空终止符,所以我猜我的第二个想法是错误的。看起来您已经找到了问题,所以这个问题已经无关紧要了。

我有点困惑,因为我习惯于使用英特尔语法,而不是AT&T语法。你实际上想要addl $4,%esp。等一下,让我再看一眼... - asveikau
@void - 也许你可以在十六进制编辑器中检查一下。 你传递给 printf 的字符串是否以空字符结尾? - asveikau
对的,它是$4,%esp。我找到了问题,我应该在堆栈上推送pushl $prittext。 - user173973

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接