web-dev-qa-db-ja.com

x86_64アセンブリLinuxシステムコールの混乱

私は現在、Linuxでアセンブリ言語を学んでいます。私は「ProgrammingFromthe Ground Up」という本を使用しており、すべての例は32ビットです。私のOSは64ビットで、すべての例を64ビットで実行しようとしています。しかし、私は問題を抱えています:

.section .data

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

これは単にLinuxexitシステムコールを呼び出すだけであるか、そうすべきです。代わりに、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です。 参照 何が間違っているのですか?また、他にどのような問題に注意する必要があり、参照用に何を使用する必要がありますか?あなたが知る必要がある場合に備えて、私はゼロからのプログラミングの第5章にいます。

17
Hudson Worden

I386とx86_64の驚くべき違いが1つあります。それらは、同じシステムコールメカニズムを使用していません。正しいコードは次のとおりです。

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

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

学習の目的では、64ビットにオンザフライで変換するのではなく、チュートリアルに正確に従うようにする必要があります。他にも、動作に大きな違いがいくつかあります。 i386に慣れたら、その後 x86_64を個別に取得できます。

19

これを読んでください x86-64でのUNIXおよびLinuxシステムコールの呼び出し規約は何ですか

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

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

13
zed_0xff

duskwuff 's answer システムコールのメカニズムが64ビットx86Linuxと32ビットLinuxで異なることを正しく指摘しています。

ただし、この回答はいくつかの理由で不完全で誤解を招く可能性があります。

コメントで指摘 のように、SYSENTERは実際には多くの64ビットLinuxシステム、つまり64ビット[〜#〜] amd [〜#〜]システム。

それは確かに紛らわしい状況です。 詳細はこちら ですが、結局のところこれは次のとおりです。

32ビットカーネルの場合、互換性のあるペアはSYSENTER/SYSEXITのみです[AMDとIntel CPU間]

ロングモードの64ビットカーネルの場合のみ…SYSCALL/SYSRETが唯一の互換性のあるペア[AMDとIntel CPU間]

64ビットモードのIntelCPUでは、SYSENTERと同じことを行うため、SYSCALLを使用する必要がないようです。ただし、これはAMDシステムには当てはまりません。

結論:64ビットx86システム上のLinuxでは常にSYSCALLを使用します。これは、x86-64ABIが実際に指定しているものです。 (詳細については、このすばらしい wiki回答 を参照してください。)

7
Dan Lenski

I386とx86_64の間で、カーネルに入るのに使用される命令とシステムコール引数を運ぶために使用されるレジスタの両方を含め、かなり多くの変更がありました。これがあなたと同等のコードです:

.section .data

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

この回答 から関連する質問への引用:

システムコール番号は、Arch/x86/include/asm /unistd_64.hの下のLinuxソースコードにあります。システムコール番号はraxレジスタに渡されます。パラメータは、rdi、rsi、rdx、r10、r8、r9にあります。呼び出しは「syscall」命令で呼び出されます。システムコールはrcxレジスタを上書きします。リターンはラックスです。

4
Adam Zalcman

/usr/include/asm/unistd_32.hをチェックするとexitは1に対応しますが、/usr/include/asm/unistd_64.hではexitは60に対応します。

2
Yerco Antonio