本文介绍了MacOS 程序集的 64 位系统调用文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm having trouble finding the good documentation for writing 64-bit assembly on MacOS.

64 位 SysV ABI 在 A 部分中说明了以下内容.2.1 和 这篇SO帖子引用了它:

The 64-bit SysV ABI says the following in section A.2.1 and this SO post quotes it:

  • 系统调用是通过 syscall 指令完成的.内核破坏注册 %rcx 和 %r11.

从系统调用返回,寄存器 %rax 包含系统调用.-4095 和 -1 之间的值表示错误,它是 -errno.

Returning from the syscall, register %rax contains the result of the system-call. A value in the range between -4095 and -1 indicates an error, it is -errno.

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

Those two sentences are ok on Linux but are wrong on macOS Sierra with the following code:

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
`
.len equ $-hello.str

使用 NASM 编译:

Compile with 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 上运行:

Run on macOS:

./syscall      # Return value 0
./syscall >&-  # Return value 255 (-1)

我发现:

  • 系统调用返回 errno 并在出错时设置进位标志,而不是在 rax
  • 中返回 -errno
  • rdx 寄存器被 syscall
  • 破坏
  • 在 Linux 上,一切正常
  • A syscall return errno an sets the carry flag on error, instead of returning -errno in rax
  • rdx register is clobbered by syscall
  • On Linux, everything works as expected

为什么 rdx 被破坏了?为什么系统调用不返回 -errno?在哪里可以找到真正的文档?

Why is rdx clobbered? Why doesn't a syscall return -errno? Where can I find the real documentation?

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

The only place I found where someone talks about the carry flag for syscall errors is here

推荐答案

我用过这个:

# 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!
"

.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 只是一个外部链接变量).

and was able to catch return value into eax. Here return value is the number of bytes actually written by write system call. And yes MacOS being a BSD variant it is the carry flag that tells you if the syscall was wrong or not (errno is just an external linkage variable).

# 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!
"
good:
        .asciz "OK
"

.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

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

This will exits with error code one because descriptor 5 was used, if you try descriptor 1 then it will work printing another message and exiting with 0.

这篇关于MacOS 程序集的 64 位系统调用文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 08:03