-1

私はアセンブラを学ぼうとしていますが、関数に引数を渡すためにosxがnasm macho32で使用する方法に多少混乱しています。

私はジェフ・ダンテマンによる「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をスタックにプッシュすることを意味します。スタックは 1 つだけで、one とレジスタ eax の両方がプッシュされます。

レジスターは Linux で使用されます。これは、特に古いプロセッサーでははるかに高速であるためです。Linux ABI (私の知る限り、System V ABI の子孫) はかなり前に開発され、パフォーマンスが重要なシステムでよく使用されていましたが、その違いは非常に重要でした。OSX intel abi は、ごくわずかな速度低下よりも、デスクトップ OSX でより重要なスタックを使用することのはるかに若く、afaik であり、単純です。64 ビット プロセッサでは、より多くのレジスタが追加されるため、より効率的に使用できます。

于 2013-11-02T17:34:24.783 に答える