dword和汇编程序中的“堆栈”有什么区别

时间:2013-11-02 16:53:01

标签: macos assembly nasm

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

我正在关注Jeff Duntemann撰写的“汇编语言一步一步”一书,并广泛使用互联网将其改为在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

1 个答案:

答案 0 :(得分:1)

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

寄存器在linux中使用,因为它们更快,特别是在旧处理器上。 Linux ABI(据我所知,系统V ABI的下降)是很久以前开发的,并且经常用于性能至关重要的系统,而差异非常显着。 OSX intel abi更年轻,更远,使用堆栈的简单性在桌面OSX中比在可忽略的减速中更重要。在64位处理器中,添加了更多寄存器,因此更有效地使用它们。