在x86-64 Tour of Intel Manuals中,我读到了
也许最令人惊讶的事实是,诸如
MOV EAX, EBX自动将指令的高32位归零的指令RAX.
同一来源引用的英特尔文档(3.4.1.1 64位手动基本架构中的通用寄存器)告诉我们:
- 64位操作数在目标通用寄存器中生成64位结果.
- 32位操作数生成32位结果,在目标通用寄存器中零扩展为64位结果.
- 8位和16位操作数生成8位或16位结果.目标通用寄存器的高56位或48位(分别)不会被操作修改.如果8位或16位操作的结果用于64位地址计算,则将寄存器显式符号扩展为完整的64位.
在x86-32和x86-64汇编中,16位指令如
mov ax, bx
Run Code Online (Sandbox Code Playgroud)
不要表现出这种"奇怪"的行为,即eax的上层词被归零.
因此:引入这种行为的原因是什么?乍一看似乎不合逻辑(但原因可能是我习惯了x86-32汇编的怪癖).
正如广泛宣传的那样,现代x86_64处理器具有64位寄存器,可以以向后兼容的方式用作32位寄存器,16位寄存器甚至8位寄存器,例如:
0x1122334455667788
================ rax (64 bits)
======== eax (32 bits)
==== ax (16 bits)
== ah (8 bits)
== al (8 bits)
Run Code Online (Sandbox Code Playgroud)
这样的方案可以从字面上理解,即,总是可以使用指定的名称仅访问寄存器的一部分用于读取或写入目的,并且这将是高度逻辑的.实际上,对于高达32位的所有内容都是如此:
mov eax, 0x11112222 ; eax = 0x11112222
mov ax, 0x3333 ; eax = 0x11113333 (works, only low 16 bits changed)
mov al, 0x44 ; eax = 0x11113344 (works, only low 8 bits changed)
mov ah, 0x55 ; eax = 0x11115544 (works, only high 8 bits changed)
xor ah, ah ; eax = 0x11110044 (works, only high 8 …Run Code Online (Sandbox Code Playgroud) GCC 4.4.3生成了以下x86_64程序集.令我困惑的部分是mov %eax,%eax.将寄存器移到自身?为什么?
23b6c: 31 c9 xor %ecx,%ecx ; the 0 value for shift
23b6e: 80 7f 60 00 cmpb $0x0,0x60(%rdi) ; is it shifted?
23b72: 74 03 je 23b77
23b74: 8b 4f 64 mov 0x64(%rdi),%ecx ; is shifted so load shift value to ecx
23b77: 48 8b 57 38 mov 0x38(%rdi),%rdx ; map base
23b7b: 48 03 57 58 add 0x58(%rdi),%rdx ; plus offset to value
23b7f: 8b 02 mov (%rdx),%eax ; load map_used value to eax …Run Code Online (Sandbox Code Playgroud) 我正在x86-64 NASM中做一个项目,遇到了以下说明:
mov rdi, rdi
Run Code Online (Sandbox Code Playgroud)
我的教授在编译器的输出中写道。
我到处搜索,但是找不到为什么需要这样做的提法。它会影响标志,还是我不理解的聪明之处?
为了提供一些上下文,它在循环使用递减同一寄存器之前就存在于循环中sub。