6

这是代码(exit.s):

.section .data,
.section .text,
.globl _start
_start:
    movl $1, %eax
    movl $32, %ebx
    syscall

当我执行" as exit.s -o exit.o && ld exit.o -o exit -e _start && ./exit"

返回是“总线错误:10”,“ echo $?”的输出是 138

我还尝试了这个问题中正确答案的示例:Process command line in Linux 64 bit

仍然得到“总线错误”...

4

2 回答 2

17

首先,您在 Mac OS X 上使用旧的 32 位 Linux 内核调用约定——这绝对行不通。

其次,Mac OS X 中的系统调用以不同的方式构造——它们都有一个前导类标识符一个系统调用号。该类可以是 Mach、BSD 或其他(参见XNU 源代码中的此处),并且向左移动 24 位。正常的 BSD 系统调用具有类2,因此从0x2000000. 类0中的系统调用无效

根据SysV AMD64 ABI的§A.2.1 以及Mac OS X,系统调用 id(连同其在 XNU 上的类!)转到%rax(或%eax在 XNU 上未使用高 32 位时)。第一个论点进入%rdi。接下来去%rsi。等等。%rcx被内核使用并且它的值被破坏,这就是为什么在进行系统调用之前所有函数都libc.dyld将它保存到%r10中(类似于来自的kernel_trapsyscall_sw.h)。

第三,调用 Mach-O 二进制文件中的代码部分,__text而不是.text像在 Linux ELF 中那样,并且也驻留在__TEXT段中,统称为(__TEXT,__text)(如果选择 Mach-O 作为目标对象类型,则nasm自动翻译) - 请参阅Mac OS X ABI Mach-O 文件格式参考. 即使您得到正确的组装说明,将它们放在错误的段/节中也会导致总线错误。您可以使用该指令(请参阅此处以了解指令语法),也可以使用(更简单的)指令,或者您可以完全放弃它,因为假设没有提供任何选项(请参阅手册页)。.text.section __TEXT,__text.text-nasas

ld第四,调用Mach-O 的默认入口点start(尽管您已经知道,它可以通过-e链接器选项进行更改)。

鉴于以上所有内容,您应该将汇编源代码修改为如下所示:

; You could also add one of the following directives for completeness
; .text
; or
; .section __TEXT,__text

.globl start
start:
    movl $0x2000001, %eax
    movl $32, %edi
    syscall

在这里,按预期工作:

$ as -o exit.o exit.s; ld -o exit exit.o
$ ./exit; echo $?
32
于 2012-06-24T18:11:06.683 回答
2

添加更多关于幻数的解释。通过将 Linux 系统调用号应用于我的 NASM,我犯了同样的错误。

来自osfmk/mach/i386/syscall_sw.h中的 xnu 内核源代码(搜索SYSCALL_CLASS_SHIFT)。

/*
 * Syscall classes for 64-bit system call entry.
 * For 64-bit users, the 32-bit syscall number is partitioned
 * with the high-order bits representing the class and low-order
 * bits being the syscall number within that class.
 * The high-order 32-bits of the 64-bit syscall number are unused.
 * All system classes enter the kernel via the syscall instruction.

系统调用是分区的:

#define SYSCALL_CLASS_NONE  0   /* Invalid */
#define SYSCALL_CLASS_MACH  1   /* Mach */  
#define SYSCALL_CLASS_UNIX  2   /* Unix/BSD */
#define SYSCALL_CLASS_MDEP  3   /* Machine-dependent */
#define SYSCALL_CLASS_DIAG  4   /* Diagnostics */

正如我们所见,BSD 系统调用的标记是 2。所以幻数0x2000000构造为:

// 2 << 24
#define SYSCALL_CONSTRUCT_UNIX(syscall_number) \
            ((SYSCALL_CLASS_UNIX << SYSCALL_CLASS_SHIFT) | \
             (SYSCALL_NUMBER_MASK & (syscall_number)))

为什么它最终使用BSD标签,可能Apple从mach内核切换到BSD内核。历史原因。

原始答案的启发。

于 2020-05-24T18:32:36.543 回答