2016-11-16 5 views
0
extern puts 
global main 

section .text 
main: 
    mov rax, rdi 
label: 
    test rax, rax 
    je exit 
    push rsi 
    mov rdi, [rsi] 
    call puts 
    pop rsi 
    dec rax 
    add rsi, 8 
    jmp label 
exit: 
    pop rsi 
    ret 

このようなnasmコードを書きました。しかし、最後にセグメンテーションフォルトが発生します。なぜセグメンテーションフォルトが発生するのか理解できません。あなたが保存する必要があり(をputs「エラー時に非負成功時に数、またはEOF」の場合)関数からの整数の結果を返すために使用されるようargを使用している間にnasmセグメント化エラーが発生しました

答えて

1

raxは、関数呼び出しに渡って保持されることが保証されていませんputsを呼び出す前にraxの値を入力してください。rsiと同じように、復元してから復元してください。

0

明らかに、Linuxの呼び出し規約 "System V AMD64 ABI"に続くGCC呼び出し規約に従って、64ビットLinux上のGCC環境でコマンドラインパラメータを取得したいとします。

のは、Cにプログラムロジックを翻訳してみましょう:

#include <stdio.h> 

int main (int argc, char** argv) 
{ 
    if (argc != 0) 
    { 
     do 
     { 
      puts (*argv); 
      argc--; 
      argv++; 
     } while (argc); 
    } 
    return; 
} 

ASMプログラムは終了コードを返しません。関数が復帰すると、終了コードはRAXになります。最初の文字列argvがプログラム名を保持しているため、BTW:argcは常に0以上です。

main機能は、「発信者」(コールputs)と「着信音」(GCC環境に戻ります)の両方です。呼び出し元としてputsへの呼び出しの前にRAXRSIを保存し、必要なときに復元する必要があります。呼び出し先保存レジスタは使用されません。これは、作品16

によってスタックを揃えることを忘れないでください:

extern puts 
global main 

section .text 
main:      ; RDI: argc, RSI: argv, stack is unaligned by 8 
    mov rax, rdi 
label: 
    test rax, rax 
    je exit 
    push rbx    ; Push 8 bytes to align the stack before the call 
    push rax    ; Save it (caller-saved) 
    push rsi    ; Save it (caller-saved) 
    mov rdi, [rsi]   ; Argument for puts 
    call puts 
    pop rsi     ; Restore it 
    pop rax     ; Restore it 
    pop rbx     ; "Unalign" the stack 
    dec rax 
    add rsi, 8 
    jmp label 
exit: 
; pop rsi    ; Once too much 
    xor eax, eax   ; RAX = 0 (return 0) 
    ret      ; RAX: return value 
関連する問題