【问题标题】:Segmentation Fault when linking assembly program with `ld`将汇编程序与“ld”链接时出现分段错误
【发布时间】:2014-11-29 18:26:14
【问题描述】:

我有一些汇编代码如下:(max.s 文件)

.section .data
d1: .double 12.5
d2: .double 6.5

formatstr: .asciz "Max value is: %lf\n"

.section .text
.globl _start
_start:
    movsd d1,%xmm0
    movsd d2,%xmm1
    ucomisd %xmm1,%xmm0
    ja endif
then:
    movsd %xmm1,%xmm0
endif:
    mov $formatstr,%edi
    mov $1,%eax
    call printf
    call exit

当我编译它时:

as max.s -o max.o
ld -lc -dynamic-linker /lib/ld-linux.so.2 -o max max.o

然后没有发生错误。

但是当我通过./max 运行此文件时,出现以下错误:分段错误

【问题讨论】:

  • 这是一个适用于 64 位 Linux 的程序。因为你没有收到来自ld 的错误,我猜你试图在 32 位系统上构建它。
  • 是的。该代码属于我的老师。他在课堂上编译它,当然它运行了。我回家重用了那个代码但没有用,因为我不认为 32bit 与 64bit 不同
  • 32 位和 64 位之间存在很大差异。在您的情况下,您偶然发现了调用约定:cdecl (32bit - your system )System_V_AMD64 (64bit - teacher's system)

标签: assembly segmentation-fault


【解决方案1】:

问题是您的程序使用了libc 函数:printfexit(除了ld-linux),而没有正确初始化libc

该初始化通常发生在_start 中,由libc 本身在crt0.o 中提供。

您还混合了ix86x86_64 调用约定,并错误地调用了printf(这可能是导致崩溃的直接原因)。在 32 位模式下(您显然正在使用),参数在堆栈上传递,而不是在寄存器中。

正如 Jeff Bell 回答的那样,要么将您的 _start 重命名为 main 并使用 gcc 而不是 ld 来链接您的程序(在修复您的源以使用正确的调用约定之后),或者摆脱 @通过自己实现 printfexit 而不是与 ld-linux-lc 链接来实现 987654336@ 依赖项。

【讨论】:

  • 你能告诉我如何修复我的源以使用正确的调用约定吗?
【解决方案2】:

您在没有传递返回值的情况下调用 exit(3)。从汇编程序中退出 _start 的正常方法是使用 sys_exit 系统调用。

我个人会使用 ma​​in 而不是 _start。这样,您将获得所有初始化和清理,例如刷新 i/o 和调用 exit(3) 免费提供的 on_exit 代码。

(您可以使用自己的 _start 的唯一原因是,如果您想避免使用 libc 以获得更小的可执行文件。这里讨论了如何执行此操作 https://blogs.oracle.com/ksplice/entry/hello_from_a_libc_free)。

【讨论】:

  • 在不传递值的情况下调用exit 会导致退出代码出现随机垃圾,但不会导致SIGSEGV。不过,您的其他建议都很好。
猜你喜欢
  • 1970-01-01
  • 2013-07-31
  • 1970-01-01
  • 2021-02-25
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多