2011-12-14 6 views
14

現在、私はLinuxでアセンブリ言語を学んでいます。私は本書「Programming From the Ground Up」を使用しており、すべての例は32ビットです。私のOSは64ビットで、64ビットですべての例を実行しようとしています。しかし、私は問題を抱えています:x86_64アセンブリLinuxシステムコールコンフュージョン

.section .data 

.section .text 
.global _start 
_start: 
movq $60, %rax 
movq $2, %rbx 
int $0x80 

これは単にLinuxのexitシステムコールを呼び出すだけです。代わりにSEG FAULTが発生し、代わりにこれを実行すると、

.section .data 

.section .text 
.global _start 
_start: 
movq $1, %rax 
movq $2, %rbx 
int $0x80 

が動作します。明らかに、問題は私が%raxに移動する価値です。 2番目の例で使用している$ 1という値は、 'Programming From the Ground Up'がインターネット上の複数のソースを使っていると言われていますが、64ビットシステムコール番号は$ 60だと言われています。 Reference 何が間違っていますか?また、私は他にどのような問題に気を付けるべきですか?あなたが知る必要がある場合に備えて、私は第5章のProgramming From The Ground Upにいます。

答えて

15

i386とx86_64の驚くべき違いは、同じシステムコールメカニズムを使用していないことです。正しいコードは次のとおり

movq $60, %rax 
movq $2, %rdi ; not %rbx! 
syscall 

割り込み0x80は常に32ビットのシステムコールを呼び出します。これは、32ビットアプリケーションを64ビットシステムで実行できるようにするために使用されます。

学習目的のために、チュートリアルを64ビットに変換するのではなく、正確にチュートリアルに従うようにしてください。他の重要な動作上の違いがいくつかあります。 i386に慣れたら、、次にを選択すると、x86_64を個別に取得できます。

+0

私はおそらくそれをやり遂げるつもりです。ご回答いただきありがとうございます。 –

+0

'%rbx'ではなく、最初のシステムコール引数に'%rdi'を使うべきです。 –

+0

それをキャッチするためにありがとう - 固定。 – duskwuff

10

このWhat are the calling conventions for UNIX & Linux system calls on x86-64

を読んで、x64システム上でシステムコールのためint 0x80を使用すると、古い互換性レイヤであることに注意してください。 x64システムでsyscall命令を使用する必要があります。

この古い方法を使用することはできますが、バイナリをx86モードでコンパイルする必要があります。詳しくは、コンパイラ/アセンブラのマニュアルを参照してください。

+0

x86_64 Linuxは実際には 'sysenter'ではなく' syscall'を使用していると指摘して嬉しいです!私は[2つの間の混乱を説明するために長い答えを書いた](// stackoverflow.com/a/31510342/20789)。 –

4

i386とx86_64の間では、カーネルに入るための命令とシステムコールの引数を保持するために使用されるレジスタの両方を含むかなりの変更がありました。

.section .data 

.section .text 
.global _start 
_start: 
movq $60, %rax 
movq $2, %rdi 
syscall 

は、関連する質問にthis answerから引用:ここにあなたのコードと同等です

番号はアーチ/ x86の/含める/ ASM/unistd_64.hの下にLinuxのソースコードであるシステムコール。 syscall番号はraxレジスタに渡されます。パラメータはrdi、rsi、rdx、r10、r8、r9です。呼び出しは "syscall"命令で呼び出されます。 syscallはrcxレジスタを上書きします。リターンはraxです。

+0

シェルコーダーのハンドブックでもやっています。しかし、私のOSも64ビットです.nasm-option -f elf32でアセンブルし、-melf_i386とリンクしています。私はgdbを使用してデバッガを使用しています(ただし、64でコンパイルされていて、バイナリをロードした後にプロンプ​​トが表示されますが、EDBの中で、gdbの中で実行されていますが、エラーは同じです):命令後のsegfault int 0x80.And私はEXIT.Iだけを見て、(r)axレジスタは、0x01の代わりに0x3cを含む必要があります(64ビットのためのsyscallファイルが使用されるため)が、私は想像することはできません、理由はint 0x80後の命令called.Anyone知っている、 なぜ ? – icbytes

2

あなたが/usr/include/asm/unistd_32.h終了を確認した場合1に対応するが、 に/usr/include/asm/unistd_64.hの出口は60に対応しています。

4

duskwuffanswerシステムコールのメカニズムは、64ビットx86 Linuxと32ビットLinuxでは正しく異なります。

しかし、この答えはカップルの理由で不完全で誤解を招く:

SYSENTERは、実際に多くの64ビットのLinuxシステム -namely 64ビットAMDシステムでは動作しません。

これは明らかに混乱する状況です。ロングで64ビットカーネル用の32ビットカーネルについて

、SYSENTER/SYSEXIT [AMDとIntelのCPU間]のみ対応ペアある

gory details are hereが、何それはこれであるためにダウンしていますモードのみ... SYSCALL/SYSRETは[AMDとIntelのCPU間]のみ対応ペアある

64ビットモードでインテル CPU上で、あなたが阿波を得ることができることが表示されますyはSYSENTERを使用しています。これはSYSCALLと同じことですが、AMDシステムではそうではありません。

ボトムライン:64ビットx86システムのLinuxでは、常にSYSCALLを使用してください。。これは、x86-64 ABIが実際に指定しているものです。 (詳細はwiki answerを参照してください)

関連する問題