-1

我正在尝试学习汇编程序,并且对 osx 使用 nasm macho32 将参数传递给函数的方法感到有些困惑。

我正在关注 Jeff Duntemann 的“Assembly Language Step By Step”一书,并广泛使用互联网对其进行了修改,使其可以在 32 位和 64 位的 osx 上运行。

所以从书中的 linux 版本开始

section .data           ; Section containing initialised data
    EatMsg db "Eat at Joe's!",10
    EatLen equ $-EatMsg 
section .bss            ; Section containing uninitialised data
section .text           ; Section containing code
global start            ; Linker needs this to find the entry point!

start:
    nop
    mov eax, 4          ; Specify sys_write syscall
    mov ebx, 1          ; Specify File Descriptor 1: Standard Output
    mov ecx, EatMsg     ; Pass offset of the message
    mov edx, EatLen     ; Pass the length of the message
    int 0x80                ; Make syscall to output the text to stdout

    mov eax, 1          ; Specify Exit syscall
    mov ebx, 0          ; Return a code of zero
    int 0x80                ; Make syscall to terminate the program

    section .data       ; Section containing initialised data
        EatMsg db "Eat at Joe's!", 0x0a
        EatLen equ $-EatMsg 
    section .bss        ; Section containing uninitialised data
    section .text       ; Section containing code
    global start        ; Linker needs this to find the entry point!

然后非常相似的是 osx 的 64 位版本,除了更改寄存器名称,替换 int 80H(我理解这有点过时)并将 0x2000000 添加到移动到 eax 的值(丝毫不理解这一点)没有改变不大。

section .data           ; Section containing initialised data
    EatMsg db "Eat at Joe's!", 0x0a
    EatLen equ $-EatMsg 
section .bss            ; Section containing uninitialised data
section .text           ; Section containing code
global start            ; Linker needs this to find the entry point!

start:
    mov rax, 0x2000004  ; Specify sys_write syscall
    mov rdi, 1          ; Specify File Descriptor 1: Standard Output
    mov rsi, EatMsg     ; Pass offset of the message
    mov rdx, EatLen     ; Pass the length of the message
    syscall             ; Make syscall to output the text to stdout

    mov rax, 0x2000001  ; Specify Exit syscall
    mov rdi, 0          ; Return a code of zero
    syscall             ; Make syscall to terminate the program

另一方面,32 位 mac 版本则完全不同。我可以看到我们正在将参数推送到堆栈 dword,所以我的问题是(对于长序言感到抱歉)eax 被推送到的堆栈和 dword 之间有什么区别,为什么我们只使用寄存器而不是64位版本(和linux)的堆栈?

   section .data        ; Section containing initialised data
    EatMsg db "Eat at Joe's!", 0x0a
    EatLen equ $-EatMsg 
section .bss            ; Section containing uninitialised data
section .text           ; Section containing code
global start            ; Linker needs this to find the entry point!

start:
    mov eax, 0x4        ; Specify sys_write syscall
    push dword EatLen   ; Pass the length of the message
    push dword EatMsg   ; Pass offset of the message
    push dword 1        ; Specify File Descriptor 1: Standard Output
    push eax
    int 0x80            ; Make syscall to output the text to stdout
    add esp, 16         ; Move back the stack pointer

    mov eax, 0x1        ; Specify Exit syscall
    push dword 0        ; Return a code of zero
    push eax
    int 0x80            ; Make syscall to terminate the program
4

1 回答 1

1

好吧,你不太明白什么是dword. 说HLL,它不是一个变量,而是一个类型。所以push doword 1意味着你将一个双字常量推1入堆栈。只有一个堆栈,堆栈和寄存器 eax 都被压入其中。

在 linux 中使用寄存器是因为它们速度更快,尤其是在旧处理器上。Linux ABI(据我所知,它是 System V ABI 的后裔)是很久以前开发的,并且经常用于性能至关重要且差异非常显着的系统中。OSX intel abi 更年轻,更容易使用堆栈,这在桌面 OSX 中比可忽略的减速更重要。在 64 位处理器中,添加的寄存器更多,因此使用它们的效率更高。

于 2013-11-02T17:34:24.783 回答