这是代码(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
stil得到“总线错误”......
答案 0 :(得分:13)
首先,您在Mac OS X上使用旧的32位Linux内核调用约定 - 这绝对不起作用。
其次,Mac OS X中的系统调用以不同的方式构建 - 它们都具有领先的类标识符和一个系统调用号。该类可以是Mach,BSD或其他东西(参见XNU源中的here),并向左移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_trap
宏的syscall_sw.h
1}})。
第三,Mach-O二进制文件中的代码部分在Linux ELF中称为__text
而不是.text
,并且也驻留在__TEXT
段中,统称为(__TEXT,__text)
(nasm
如果选择Mach-O作为目标对象类型,则会根据需要自动翻译.text
- 请参阅Mac OS X ABI Mach-O File Format Reference。即使您获得正确的装配说明,将它们放在错误的段/部分也会导致总线错误。你可以使用.section __TEXT,__text
指令(参见here指令语法)或者你也可以使用(更简单的).text
指令,或者你可以完全删除它,因为假设没有已向-n
提供了as
选项(请参阅as
的联机帮助页。)
第四,Mach-O ld
的默认入口点称为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
答案 1 :(得分: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
内核。历史原因。
受到original answer的启发。