私はsyscallの次の定義を読んでいました:
.text
.globl syscall
.type syscall,%function
.align 16
syscall:
movq %rdi, %rax /* Syscall number -> rax. */
movq %rsi, %rdi /* shift arg1 - arg5. */
movq %rdx, %rsi
movq %rcx, %rdx
movq %r8, %r10
movq %r9, %r8
movq 8(%rsp),%r9 /* arg6 is on the stack. */
syscall /* Do the system call. */
cmpq $-4095, %rax /* Check %rax for error. */
jae __syscall_error /* Branch forward if it failed. */
ret /* Return to caller. */
.size syscall,.-syscall
私はそれが行cmpq $-4095 %rax
%raxに-1から-4095までの値が含まれるかどうかを決定します。それはどのようにそれをしますか? cmpq命令は正確に何をしますか?
cmpq $-4095, %rax
は、64ビットレジスタ%raxを即値-4095
と比較します。値は、比較のために64ビットに符号拡張されます。つまり、-4095
には64ビット2の補数表現があります:ffff ffff ffff f001
cmp
命令は、AT&T構文で逆になっている最初のオペランドから2番目のオペランドのsub
(減算)の場合と同じようにフラグレジスタを設定します。事実上、フラグは次の結果に従って設定されます:(RAX - (- 4095))
または(RAX + 4095)
、2の補数で同じです。
設定されるフラグの1つは、carryフラグ(CF)であり、(符号なし)オーバーフローに設定されます。 jae
命令(jump-if-above-or-equal)は、実際にはjnc
(jump-if-not-carry)の「エイリアス」です。言い換えると、(RAX + 4095)
がnotを実行する場合、分岐が実行されます。 2の補数では、これは次の範囲のRAX
の値に当てはまります:[-4095, -1]
。 (2の補数演算がどのようにラップするかを覚えておいてください)。
cmp
およびjae
(またはj<cond>
)を含む手順については、以下で説明します。 インテル®64およびIA-32アーキテクチャーソフトウェア開発者マニュアル、第2巻 。
[E] FLAGSレジスタ(および算術フラグが示すもの)については、 Intel®64およびIA-32アーキテクチャソフトウェア開発者マニュアル、第1巻 のセクション3.4.3で説明されています。