2017-01-17 2 views
-2

UbuntuマシンでNASMとGCCを使って非常に小さなプログラムを作成しようとしているときに、私は何か変わったことに気付きました。i386とx86-64メモリスタックの相違点

次のコードは、64ビットNASMとGCCの下で微細コンパイル:

global main 
    extern puts 

section .text 
    main: 
    push rax 
    mov rdi, message 
    call puts 
    jmp exit 
    exit: 
    ;return stack memory 
    pop rax 
    ret 
    message: 
    db "Hello from NASM!", 0 

しかし、32ビットNASMとGCCの下で(レジスタは変更のみで)同じコードをコンパイルしようとしたとき、それはいずれかの意志結果セグメンテーションフォルトおよび/またはランダムな文字。なぜこうなった? x64アーキテクチャーは、i386と比べてメモリーをスタックに格納する方法が異なりますか?もしそうなら、どのようにこの行動を防ぐことができますか? 32ビットモードで、最も呼び出し規約(cdeclstdcall、などが...)64ビット・モードとは異なり、ないレジスタに、引数がスタックにプッシュされることを期待

+3

呼び出し規約は異なりますか? –

+0

デバッガを使用して、フォルトがどこで発生しているのか調べることができますか? –

+0

先週の言語仕様全体が変更されていない限り、これはC言語ではなくアセンブリ言語です。タグをスパムしないでください! (呼び出すライブラリ関数はこれを変更しません!) – Olaf

答えて

3

、そしてまた、あなたは32ビットモードで同じ出力を生成するためのプログラムについて

lea edx, @message 
push edx 
call puts 
add esp, 4 

:あなたのような何かをする必要がありますので、putsを呼び出した後、スタックポインタを調整する必要があります。私は通常、MASMとGASにアセンブリコードを書くので、NASMの構文が正しいとは限りません。

+1

それは問題だったので、ありがとう!しばらくの間、i386でやったことはありません – Tatu

+1

ほとんどの呼び出し規約で必要なことは本当に問題ではありません。これはCの標準ライブラリ関数なので、cdecl呼び出し規約を使用します。これはあなたの答えが正しいことを意味します。 (それがstdcallだった場合、呼び出された人は呼び出し側ではなくスタックをきれいにするでしょう!) –

+0

@CodyGray確信しましたが、私は一般的なケースの答えを出そうとしていました - たとえば、msを使用する関数標準のC関数の代わりにファストコールを使用すると、ECXで最初の引数を持つことは正しいでしょう –