【问题标题】:Empty ASM program got signals空 ASM 程序收到信号
【发布时间】:2016-11-16 00:13:15
【问题描述】:

我正在学习汇编,我正在尝试运行一个非常简单的程序。

section .text
    global start
    global _main

start:
    call _main
    ret

_main:
    push 42
    ret

我在 OSX 64 位上使用 NASM。这是我尝试过的:

$ nasm -f macho64 simple.asm -o simple.o
$ ld simple.o -o a.out
$ ./a.out
dyld: no writable segment
[1]    38021 trace trap  ./a.out
$
$ ld -lc -ldylib1.o -e start simple.o -o a.out
$ ./a.out
[1]    38134 segmentation fault  ./a.out
$
$ ld -macosx_version_min 10.8 -lSystem simple.o -o a.out
[1]    38134 segmentation fault  ./a.out
$

this post 之后,我在代码中添加了section .data

$ nasm -f macho64 simple.asm && ld simple.o && ./a.out
[1]    39119 killed     ./a.out

1) 我怎样才能让我的程序不被杀死?

2) 为什么我的程序会收到这些信号(SIGTRAPSIGSEGVSIGKILL)?

3) 我在哪里可以不问就找到这些答案?到目前为止,我发现的解释确实需要有关组装的先验知识。

编辑

我理解push 42 的错误,谢谢。我的程序在加载ld -macosx_version_min 10.8 -lSystem simple.o 时运行。但是:

  • 在加载ld simple.o时,我仍然有SIGTRAP

  • 我在加载ld -lc -ldylib1.o -e start simple.o时仍然有段错误

  • 当我添加 section .data 并加载 ld simple.o 时,我仍然有一个 SIGKILL

  • 当我添加section .data 并使用ld -macosx_version_min 10.8 -lSystem simple.o 加载时出现总线错误

我想知道为什么我会收到这些信号(以便了解它是如何工作的)。我还想知道为什么我必须指定macosx_version_min,以及我如何在没有朋友告诉我的情况下找到它。

【问题讨论】:

  • ret,引用手册,“将程序控制转移到位于堆栈顶部的返回地址。”那将是 42。
  • 您确定使用 SIGKILL 吗?如果入口点在一个不可执行的页面中,我会期待 SIGSEGV(至少在 Linux 上)。尝试使用strace ./a.out 来跟踪系统调用,包括执行文件的execve。此外,运行gdb ./a.out(或lldb,或您喜欢的任何调试器),并单步执行您的代码,以便查看导致内核传递信号的指令错误和结果。
  • 另外,你的标题是错误的。你的程序绝对不是空的。如果是这样,您只需将零填充作为指令运行,或者 SIGILL,如果执行遇到其他一些未解码为有效指令的字节。

标签: assembly nasm


【解决方案1】:

你的主要问题很简单。在您的短程序中,您在RET 弹出它以跳转到它之前立即将值 42 压入堆栈 - 这会导致segfault,因为它跳转到地址00000042(32 位模式),哪个(在保护模式下)最有可能导致异常。

【讨论】:

    【解决方案2】:

    1) 我怎样才能让我的程序不被杀死?

    这不是 C:你不是 ret 那样。您的代码不是从预先建立的环境中调用的;你应该把你的returning 发给什么?通过发出这样的指令,你的jmp-ing 到当前在%rsp 的堆栈上的任何值,并进入可能在你的进程地址空间之外的区域,因此是 SIGSEGV。

    您必须通过系统调用明确告诉操作系统您的进程已终止其执行。

    此外,ELF 的起点通常是 _start,而不是 start,否则您应该向链接器指明。

    加载 ld -lc -ldylib1.o -e start simple.o 时我仍然有段错误

    不要与 C 链接,除非您符合其执行模型。另外我不明白“使用 ld file.o 加载”是什么意思。

    【讨论】:

    • 如果ld 没有找到名为_start 的符号,则默认为文本段的开头。
    • @PeterCordes 我做了一个非常有力的断言,说 ELF 的起点是_start,我不知道这是否是强制性的(怀疑)。我的意思是,ld 这样做了 - 但如果我写了我的链接器,我可以拒绝链接吗?
    • 是的,当然。如果你不关心与ld 的命令行兼容性,你的链接器可以做任何你想做的事情。就像我说的,ld 的实际行为是退回到 .text 部分的开头: ld: warning: cannot find entry symbol _start;默认为 0000000000400080。您还可以使用ld -e symbol_name 来设置它将查找的符号名称,而不是_start。因此,即使在由ld 链接的非剥离二进制文件中,假设入口点是_start 也不完全安全。要在调试时可靠地设置断点,请使用readelf -a 查找数字地址
    • 我会说这是一个相当冒险的决定:如果您忘记了-e entry,仅仅拥有.text \n .word 0xf0b \n entry: # your code 将导致长时间的调试会话。这个常数看起来很无罪,但事实并非如此。
    • 我并没有说这是一个好主意,我只是解释了ld 的实际行为,一些构建系统可能会依赖它。使用-e 而不是像普通人那样只调用你的入口点_start 通常是一个糟糕的主意。更糟糕的是,如果您 拥有 _start 符号,但它不是入口点。 b _start 将在那里设置断点,但它不会是第一个执行的代码!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多