基本程序集在Mac上不起作用(x86_64 + Lion)?

时间:2012-06-24 16:59:40

标签: macos assembly x86-64

这是代码(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得到“总线错误”......

2 个答案:

答案 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的启发。