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
4

4 回答 4

16

更改push printtextpush $printtext

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

于 2011-01-13T04:16:21.093 回答
9

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

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

于 2011-01-13T03:57:34.880 回答
6

问题是我正在使用

pushl printtext

比较起来

pushl $printtext

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

于 2011-01-13T04:13:57.833 回答
2

在这之后:

push printtext
call printf

你要:

addl $4, %esp

进一步说明:

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

更新:

是的,好的,我习惯了 Intel 语法,所以我在脑海中倒退了参数的顺序。实际上,缺少addlback toesp并不重要,因为您espret. 我的下一个猜测是你传递给的字符串printf缺少一个空终止符......让我看看是什么gas......

更新 2:

好的,gasnull 会为您终止字符串,所以我想我的第二个预感是错误的。看起来您发现了问题,所以这一点没有实际意义。

于 2011-01-13T04:00:45.417 回答