私は現在、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章にいます。
I386とx86_64の驚くべき違いが1つあります。それらは、同じシステムコールメカニズムを使用していません。正しいコードは次のとおりです。
movq $60, %rax
movq $2, %rdi ; not %rbx!
syscall
割り込み0x80
は常に32ビットのシステムコールを呼び出します。これは、32ビットアプリケーションを64ビットシステムで実行できるようにするために使用されます。
学習の目的では、64ビットにオンザフライで変換するのではなく、チュートリアルに正確に従うようにする必要があります。他にも、動作に大きな違いがいくつかあります。 i386に慣れたら、その後 x86_64を個別に取得できます。
これを読んでください x86-64でのUNIXおよびLinuxシステムコールの呼び出し規約は何ですか
また、x64システムのsyscallにint 0x80
を使用することは、古い互換性レイヤーであることに注意してください。 x64システムではsyscall
命令を使用する必要があります。
この古い方法は引き続き使用できますが、バイナリをx86モードでコンパイルする必要があります。詳細については、コンパイラ/アセンブラのマニュアルを参照してください。
duskwuff 's answer システムコールのメカニズムが64ビットx86Linuxと32ビットLinuxで異なることを正しく指摘しています。
ただし、この回答はいくつかの理由で不完全で誤解を招く可能性があります。
int 0x80
が非常に遅いという観察 。 Linus Torvalds SYSENTER
/SYSEXIT
命令を使用してソリューションをコード化 (これはPentium Proの時代にIntelによって導入されましたが、バグがあり実用的ではありませんでしたメリット)。したがって、最新の32ビットLinuxシステムは、実際にはint 0x80
ではなくSYSENTER
を使用します。SYSENTER
とSYSEXIT
を使用しません。それら 実際に使用 非常によく似たSYSCALL
/SYSRET
命令。コメントで指摘 のように、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回答 を参照してください。)
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レジスタを上書きします。リターンはラックスです。
/usr/include/asm/unistd_32.h
をチェックするとexitは1
に対応しますが、/usr/include/asm/unistd_64.h
ではexitは60
に対応します。