2013-11-02 42 views
-1

我想學習彙編程序,並且被osx和nasm macho32用於將參數傳遞給函數所使用的方法有些困惑。dword和彙編程序中的'堆棧'有什麼區別

我正在按照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! 

然後非常相似的64位版本的OSX,除了改變寄存器的名字,替換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

那麼,你不太明白什麼是dword。說到HLL,它不是一個變量,而是一個類型。所以push doword 1意味着你將一個雙字常量1推入堆棧。只有一個堆棧,並且一個和寄存器eax都被壓入。

寄存器在linux中使用,因爲它們速度更快,尤其是在舊處理器上。 Linux ABI(據我所知,系統V ABI的下降)是很早以前開發的,經常用於性能非常關鍵的系統,當時的差異非常顯着。 OSX intel abi比桌面OSX更重要,比可以忽略的減速更年輕,更簡單易用。在64位處理器中,增加了更多的寄存器,因此更有效地使用它們。