MacOS程序集的64位系统调用文档

MacOS程序集的64位系统调用文档,macos,assembly,x86-64,system-calls,Macos,Assembly,X86 64,System Calls,我很难找到在MacOS上编写64位程序集的好文档 该文件在第A.2.1节中说明并引用了以下内容: 系统调用通过syscall指令完成。内核破坏 寄存器%rcx和%r11 从系统调用返回的寄存器%rax包含 系统调用。介于-4095和-1之间的值表示错误, 是的,呃,不是 这两句话在Linux上是可以的,但在macOS Sierra上是错误的,代码如下: global _start extern _exit section .text _start: ; Align stack to 16

我很难找到在MacOS上编写64位程序集的好文档

该文件在第A.2.1节中说明并引用了以下内容:

  • 系统调用通过syscall指令完成。内核破坏 寄存器%rcx和%r11

  • 从系统调用返回的寄存器%rax包含 系统调用。介于-4095和-1之间的值表示错误, 是的,呃,不是

这两句话在Linux上是可以的,但在macOS Sierra上是错误的,代码如下:

global _start
extern _exit

section .text
_start:

; Align stack to 16 bytes for libc
and rsp, 0xFFFFFFFFFFFFFFF0

; Call write
mov rdx, 12             ; size
mov rsi, hello          ; buf
mov edi, 1              ; fd
mov rax, 0x2000004      ; write ; replace to mov rax, 0x1 on linux
syscall

jc .err                 ; Jumps on error on macOS, but why?
jnc .ok

.err:
mov rdi, -1
call _exit              ; exit(-1)

.ok:
; Expect rdx to be 12, but it isn't on macOS!
mov rdi, rdx
call _exit              ; exit(rdx)

; String for write
section .data
hello:
.str db `Hello world\n`
.len equ $-hello.str
使用NASM编译:

; MacOS: nasm -f macho64 syscall.asm && ld syscall.o -lc -macosx_version_min 10.12 -e _start -o syscall
; Linux: nasm -f elf64 syscall.asm -o syscall.o && ld syscall.o -lc -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o syscall
在macOS上运行:

./syscall      # Return value 0
./syscall >&-  # Return value 255 (-1)
我发现:

  • 系统调用返回
    errno
    an设置出错时的进位标志,而不是在
    rax
    中返回
    -errno
  • rdx
    寄存器被
    syscall
  • 在Linux上,一切正常
为什么
rdx
?为什么系统调用不返回
-errno
?我在哪里可以找到真正的文档

我发现有人谈论系统调用错误的进位标志的唯一地方是

我使用了这个:

# as hello.asm -o hello.o
# ld hello.o -macosx_version_min 10.13 -e _main -o hello  -lSystem
.section __DATA,__data
str:
  .asciz "Hello world!\n"

.section __TEXT,__text
.globl _main
_main:
  movl $0x2000004, %eax           # preparing system call 4
  movl $1, %edi                   # STDOUT file descriptor is 1
  movq str@GOTPCREL(%rip), %rsi   # The value to print
  movq $13, %rdx                  # the size of the value to print
  syscall

  movl %eax, %edi
  movl $0x2000001, %eax           # exit (return value of the call to write())
  syscall
并且能够将返回值捕获到
eax
。这里的返回值是
write
系统调用实际写入的字节数。是的,MacOS是一个BSD变体,它是一个进位标志,告诉您系统调用是否错误(errno只是一个外部链接变量)


这将以错误代码1退出,因为使用了描述符5,如果您尝试使用描述符1,那么它将打印另一条消息并以0退出。

因为这是标题为a.2 AMD64 Linux内核约定部分的摘录?请阅读这个好问题。我对你的链接做了一个快速编辑,因此它不再声称该部分也适用于*BSD(之前它没有提到OSX,达尔文算是*BSD吗?@Jean BaptisteYunès,你知道FreeBSD或OpenBSD在x86-64上是否使用与Linux或OS X相同的约定吗?)@彼得·考德斯:唉,不同的BSD口味似乎不使用相同的ABI。FreeBSD似乎与Linux兼容。Minix和NetBSD是兼容的。很难找到关于它的信息(很多年以来我都没有读过这些东西,所以可能我只是不知道去哪里搜索)。还有一个相关问题:您的最后一条评论应该是“退出1”,因为您将$1移动到%edi中。
movqstr@GOTPCREL(%rip),%rsi
太荒谬了。只需使用RIP相对LEA来获取您自己的静态数据的地址!您关于退出0的评论是错误的:您实际上传递的是
write()
的返回值,这要么是错误(例如,如果stdout关闭),要么是
13
(写入的字节数)。您也不需要0-终止数据,因为您只使用显式长度函数。然后,您可以让汇编程序为您计算长度,而不必硬编码
13
。请参阅是否有任何官方或广泛认可的MacOS系统调用约定文档,包括进位标志的使用?我在搜索时找不到任何权威性的东西,只有很多“民间传说”。
# hello_asm.s
# as hello_asm.s -o hello_asm.o
# ld hello_asm.o -e _main -o hello_asm
.section __DATA,__data
str:
        .asciz "Hello world!\n"
good:
        .asciz "OK\n"

.section __TEXT,__text
.globl _main
_main:
        movl $0x2000004, %eax           # preparing system call 4
        movl $5, %edi                   # STDOUT file descriptor is 5
        movq str@GOTPCREL(%rip), %rsi   # The value to print
        movq $13, %rdx                  # the size of the value to print
        syscall

        jc err

        movl $0x2000004, %eax           # preparing system call 4
        movl $1, %edi                   # STDOUT file descriptor is 1
        movq good@GOTPCREL(%rip), %rsi  # The value to print
        movq $3, %rdx                   # the size of the value to print
        syscall
        movl $0, %edi
        movl $0x2000001, %eax           # exit 0
        syscall
err:    
        movl $1, %edi
        movl $0x2000001, %eax           # exit 1
        syscall