从c调用汇编函数

时间:2011-01-13 03:47:48

标签: c linux assembly gas

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

4 个答案:

答案 0 :(得分:16)

push printtext更改为push $printtext

实际上,您正在从地址printtext加载一个值并推送它,而不是推送地址。因此,您将'test'作为32位数而不是指针传递,而printf正试图将其解释为地址并崩溃。

答案 1 :(得分:9)

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

如果您正在调用使用不同调用约定的printf等函数(因为参数数量可变),这将非常有用。调用这些函数可能与调用非varargs函数完全不同。

答案 2 :(得分:6)

问题在于我正在使用

pushl printtext

而不是

pushl $printtext

感谢大家的帮助,抱歉浪费你的时间:P

答案 3 :(得分:2)

之后:

push printtext
call printf

你想:

addl $4, %esp

进一步说明:

因为您正在使用x86 Linux,所以我假设调用约定要求被调用者清理参数。因为你在调用printf之前按下了一个指针,所以在该函数的ret指令发生后,你的堆栈会被4点关闭。

更新

是的,好的,我已经习惯了英特尔语法,所以我在脑子里得到了倒退的顺序。实际上,addl缺少回esp并不重要,因为您正在esp附近正确恢复ret。我的下一个猜测是,你传递给printf的字符串缺少一个空终止符...让我看看gas做了什么......

更新2:

好的,gas null为你终止字符串,所以我想我的第二次预感错了。看起来你发现了这个问题,所以重点是没有意义。