x86-64架构单操作数addq指令功能及关联%rdx的技术疑问
嘿,这个问题我当初啃《深入理解计算机系统(第3版)》的时候也卡过一会儿,咱们一步步掰扯清楚~
1. 单操作数addq指令的含义
在x86-64架构里,单操作数形式的addq属于累加器寻址的指令类型,它的行为其实隐含了一个固定操作数——64位累加器%rax。简单说就是:把%rax里的数值,加到你指定的那个操作数(可以是寄存器或者内存地址)上,然后把结果存回这个操作数。
举两个直观的例子:
addq %rdx:等价于双操作数的addq %rax, %rdx,也就是%rdx = %rdx + %rax,执行后%rdx的数值会增加addq 0x20(%rdi):把%rax的值加到内存地址%rdi + 0x20对应的64位数据里,结果再写回这个内存位置
不过说实话,这种单操作数形式在现代手写汇编里很少用,因为双操作数形式(比如addq %rax, %rdx)更清晰,能直接看出谁加谁,不容易搞混。
2. 为什么单操作数addq没显式提%rdx却让它自增?
你遇到的这个困惑,大概率是书中讲解数组遍历或者内存访问的场景导致的——我猜要么是你混淆了指令功能,要么是书中的上下文描述简化了步骤:
首先明确一点:单操作数addq本身绝对不会隐含修改%rdx。x86-64里没有任何单操作数addq会自动让%rdx自增,除非你把%rdx当成了显式操作数(比如前面例子里的addq %rdx,它会让%rdx加上%rax的值,从而数值增加)。
如果书中说%rdx自增了,那大概率是另有一条指令负责这件事,只是这条指令和addq挨在一起,书中把它们的功能放在一起说明,导致你误解了。比如CSAPP里常见的数组求和汇编代码,大概是这样的:
sum_loop: addq (%rdx), %rax # 双操作数addq:把%rdx指向的数组元素加到累加器%rax(sum) addq $8, %rdx # 双操作数addq:让%rdx自增8,指向下一个64位数组元素 subq $1, %rcx # 循环计数器减1 jne sum_loop # 没循环完就继续
这里%rdx自增是第二条addq $8, %rdx的功劳,和第一条addq没关系。可能你把两条addq指令搞混了,或者书中描述的时候简化成了“执行addq并移动指针”,让你误以为是同一条指令的功能。
还有一种极小的可能:如果书中涉及字符串操作指令(比如addsb这类字节加法指令),这类指令会隐含使用%rsi/%rdi作为地址寄存器,还会自动递增/递减,但addq是64位通用加法,没有对应的字符串操作变种,所以这种情况可以直接排除。
内容的提问来源于stack exchange,提问作者Student222

