Что делает инструкция cmpq?

Я читал следующее определение для 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?

Ответ 1

cmpq $-4095, %rax сравнивает 64-битный регистр% rax с немедленным значением -4095 - значение с расширением знака до 64 бит для целей сравнения. то есть, -4095 имеет представление с 64-битным 2 дополнением: ffff ffff ffff f001

cmp инструкции устанавливают регистр флагов, как это было бы для sub (вычитание) второго операнда от первого - "второго" и "первого", меняющегося в синтаксисе AT & T. Фактически флаги устанавливаются в соответствии с результатом: (RAX - (- 4095)) или (RAX + 4095), являющимся одним и тем же в 2 дополнениях.

Один из установленных флагов - флаг переноса (CF), который установлен на (без знака) переполнении. Инструкция jae (jump-if-above-or-equal) на самом деле является "псевдонимом" для jnc (jump-if-not-carry). Другими словами, ветвь берется, если (RAX + 4095) не несет. В 2 дополнениях это будет верно для значений RAX в диапазоне: [-4095, -1]. (Имейте в виду, как 2 арифметических обертки дополнения).


Инструкции, включая cmp и jae (или j<cond>), описаны в: Руководство разработчика программного обеспечения Intel® 64 и IA-32, том 2.

Регистр [E] FLAGS (и то, что обозначают арифметические флаги) описаны в разделе 3.4.3 Руководство разработчика программного обеспечения Intel® 64 и IA-32 Architect, том 1.