NASM 汇编 64 位 Linux 中的比较

Comparisons in NASM Assembly 64bit Linux


我正在通过 Jonathan Bartlett 的书 Programming from the Ground Up (Link) 学习汇编程序,我尝试将 32 位 AT&T 语法转换为 64 位 Intel 语法版本.我使用 NASM。现在我正在努力让第 3 章的第二个程序(return 数字序列的最大数量)在 64 位英特尔上工作。我修改了很多代码,最终设法缩小了问题的范围:这是两个数字的比较和条件跳转。这是一个演示问题的非常简单的版本:

section .data
  data: db 0

section .text
  global _start

_start:
  mov rdi, [data] ; if I exit here, the return value (=rdi) is 0
  cmp rdi, 0
  je  .equals     ; this is not executed
  jz  .equals     ; this neither
  jmp .notEquals

.equals:
  mov rax, 60
  mov rdi, 1
  syscall

.notEquals:       ; this is the result I get
  mov rax, 60
  mov rdi, 2
  syscall

我从内存中读取了一个数字(数据,数字为0)。但是当我把这个 0 和 0 进行比较时,计算机显然看到了我看不到的差异。我确定此时 rdi 包含 0 因为当我在那里退出程序并得到它的 return 值

echo $?

它打印 0。如果有人对这种神秘行为有任何提示,我将不胜感激。另外,如果你知道一个很好的调试汇编代码的工具,也请告诉我,因为每次都重写程序只是为了获取寄存器的值是非常烦人的...

PS:我知道 Intel 语法不常用于 Linux 但我选择它是因为它对我来说看起来更干净,而且 Vim 中的源代码突出显示很多NASM 比 AT&T 更好 ;-)

mov rdi, [data] 将从内存中加载 8 个字节,因为这是 rdi 的大小。但是,您仅使用 db 声明了 1 个字节。您可以通过 3 种方式修复它:

  1. 使用dq 0定义所有8个字节。
  2. 使用 movzx rdi, byte [data] 将字节零扩展为 qword。
  3. 使用 mov dil, [data]cmp dil, 0 仅加载和比较单个字节。

请注意,退出代码仅提供低 8 位,这就是您看不到错误的原因。学习改用调试器,这样您就可以单步执行代码并检查每个点的寄存器。