【问题标题】:Linux assembly and printfLinux 汇编和 printf
【发布时间】:2012-07-31 21:18:04
【问题描述】:

我尝试用 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

【问题讨论】:

  • 为什么要把一个明明是32位的程序组装成elf64
  • 因为当我不这样做时,我会看到:/usr/bin/ld: i386 architecture of input file ./asemlebr.o is incompatible with i386:x86-64 output
  • 你在哪里写printf?如果您正在考虑调用 C 库中的那个,那将需要更多的工作 - 您需要确保调用库的初始化代码,根据您所在平台的 ABI,并将您的程序与库链接,至少...
  • @twalberg:实际上这可以正常工作。 OP 正在编写main,因此即使在静态可执行文件中,CRT 启动代码也会在调用 main 之前初始化 glibc。在与 glibc 的动态 链接二进制文件中,_start 也是安全的,因为动态链接器使用与在 C++ 库代码中运行静态初始化程序相同的机制调用 glibc 的 init 函数。相关:stackoverflow.com/questions/36861903/… 了解更多关于静态与动态二进制文件以及是否链接 libc 的信息。
  • 这里的主要危险是sys_exit 不会刷新标准输出,但如果它不是 TTY,它将是全缓冲的。

标签: c assembly printf nasm


【解决方案1】:

如果你真的想得到一个 32 位二进制文​​件,就像你的代码头显示的那样,那么你只需要修复该行:

call [printf]

改成:

call printf

当您执行call [printf] 时,您调用的不是 printf,而是第一个 printf 代码字节所指向的地址,该构造 ([address]) 称为 effective address

【讨论】:

    【解决方案2】:

    ia32 上的 Linux 不使用与 amd64 相同的调用约定。由于您的代码使用前者,您必须将其组装为 32 位并与 32 位 libc 链接。在 debian 上,您需要 libc6-dev-i386 软件包。

    您还必须将 'call [printf]' 替换为 'call printf',这是错误的。

    还请注意,当您使用主界面时,您应该从 main 返回,而不是执行退出系统调用以允许 C 运行时关闭代码运行。

    Hello World example for x86-32 with build instructions.

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

    Hello World example for x86-64 with build instructions.

    【讨论】:

      猜你喜欢
      • 2014-08-09
      • 2014-07-19
      • 1970-01-01
      • 1970-01-01
      • 2016-12-31
      • 2019-10-25
      • 1970-01-01
      • 2018-09-23
      • 1970-01-01
      相关资源
      最近更新 更多