我正在通过Jonathan Bartlett的书从头开始编程(Link)学习汇编程序,我尝试将32位AT& T语法转换为64位英特尔语法版本。我使用NASM。现在,我正在努力让第3章的第二个程序(返回一个数字序列的最大数量)在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,因为当我退出程序并获得它的返回值
echo $?
它打印0.如果有人对这种神秘行为有任何暗示,我将非常感激。另外,如果你知道一个很好的调试汇编程序代码的工具,请告诉我,因为为了在每个时刻获取寄存器的值而一直重写程序非常烦人......
PS:我知道英特尔语法并不常用于Linux,但我之所以选择它,因为它对我来说看起来更干净,而且Vim中的源代码突出显示NASM比AT& T好得多; - )答案 0 :(得分:1)
mov rdi, [data]
将从内存加载8个字节,因为它的大小为rdi
。但是,您只使用db
声明了1个字节。您可以通过3种方式修复它:
dq 0
定义所有8个字节。movzx rdi, byte [data]
将字节零扩展为qword。mov dil, [data]
和cmp dil, 0
仅加载和比较单个字节。请注意,退出代码仅提供低8位,这就是您没有看到错误的原因。学习使用调试器,这样就可以单步执行代码并检查每个点的寄存器。