Mac 程序集:段错误与 libc 退出

Mac assembly: segfault with libc exit

我正在研究 x86_64 macOS 10.12 上的程序集。

我正在尝试调用 libc exit() 函数:

.section __TEXT,__text
.globl _main
_main:
    pushq %rbp
    movq %rsp, %rbp
    movl , %edi
    callq _exit

并编译它:

as exit2.s -o exit2.o
ld exit2.o -e _main -lc -o exit

结果是:

Segmentation fault: 11

为什么会这样?

编辑:问题在于链接 libc 和调用约定。

: you crash because you didn't initialize libc. There's probably a NULL pointer somewhere in the data structures that exit(3) checks before actually exiting. e.g. it flushes stdout if needed, and it runs any functions registered with atexit(3).

如果您不希望它完成所有这些工作,则可以直接使用 syscall 指令进行 sys_exit 系统调用,或者 call_exit(2) 它的 libc 包装函数。 (基本情况与 Linux 相同,因为 exit(3)_exit(2) 由 POSIX 标准化:参见


我认为 the tutorial you're following 大部分看起来不错,但也许某些旧版本的 OS X 允许在不调用任何 libc init 的情况下使用 libc 函数(包括 printf?!?)职能。或者他们在编辑构建命令后没有测试他们的代码。 (假设他们进行了测试,也许是动态链接,这会起作用。)


OS X 在汇编中为符号名称添加前缀 _,因此使用 call __exit(两个下划线)来调用 _exit(). (例如 call _printf 调用 C printf 函数)。

_exit(2) 可能 如果你在没有初始化 libc 的情况下调用它就不会崩溃,但是 在没有初始化的情况下调用任何 libc 函数仍然是个坏主意首先调用了 libc init 函数。最好直接进行系统调用(请参阅本教程后面的内容),或者更好的是,使用 gcc hello_asm.S -o hello_asm 构建它以确保 libc 已初始化。然后您可以按照本教程的其余部分进行操作,包括 printf.


不要在静态可执行文件中调用 Mach-O 入口点 _mainmain。 CRT 启动代码还没有运行。通常的约定是称它为进程入口点_start

(注意OSX将CRT起始码放在动态链接器中,所以.

如果您使用 gcc exit2.o -o exit 而不是 ld 链接,则

libc 会为您初始化