Linux汇编与printf

6

我试图写一个简单的汇编程序,其中包含printf函数。我使用nasm -f elf 64进行编译,并使用gcc进行链接。运行后出现了segmentation fault错误。这是什么问题?

[Bits 32]

extern printf
global main

section .data 

hello:
db "Hello", 0xa, 0 

section .text

main:

push hello
call [printf]

add esp, 4

mov eax, 1
mov ebx, 0
int 80h

2
你为什么想要将一个明显是32位的程序组装成elf64呢? - Daniel Kamil Kozar
因为如果我不这样做,我会看到:/usr/bin/ld: i386 architecture of input file ./asemlebr.o is incompatible with i386:x86-64 output - user902691
1
你在哪里写了 printf?如果你想调用 C 库中的 printf,那么需要进行更多的工作 - 你需要确保库的初始化代码被调用,根据所在平台的 ABI 设置堆栈帧和参数,并将程序与库链接起来,至少要做到这些... - twalberg
@twalberg:实际上这个方法可以很好地工作。OP正在编写“main”,因此CRT启动代码将在调用静态可执行文件的main之前初始化glibc。即使在使用glibc的动态链接二进制文件中的_start中,它也是安全的,因为glibc的init函数是由动态链接器使用与运行C ++库代码中的静态初始化程序相同的机制来调用的。相关信息:https://dev59.com/ZFoU5IYBdhLWcg3w_KmO,了解有关静态与动态二进制文件以及链接libc或不链接的更多信息。 - Peter Cordes
这里的主要危险是sys_exit不会刷新标准输出,但如果它不是TTY,则会进行完全缓冲。 - Peter Cordes
2个回答

8

在ia32上的Linux使用的调用约定与amd64上的不同。因为你的代码使用的是前者,所以必须将其汇编为32位,并链接到32位的libc库。在Debian上,你需要安装libc6-dev-i386软件包。

你还必须将 'call [printf]' 替换为 'call printf',那是一个错误。

请注意,由于你正在使用主接口,你应该从main函数中返回,而不是执行退出系统调用,以允许C运行时关闭代码运行。

附带构建说明的x86-32 Hello World示例.

如果你正在使用amd64,你可能想要学习如何编写64位汇编代码。

附带构建说明的x86-64 Hello World示例.


3

如果您真的想要一个32位二进制文件作为代码头文件,那么您只需要修复以下行:

call [printf]

将其更改为:
call printf

当您执行call [printf]时,您并不是在调用printf函数,而是调用第一个printf代码字节指向的地址,这种构造方式([address])被称为有效地址

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