tec*_*ury 1 c assembly gcc x86-64
我正在从《计算机系统:程序员的视角》学习 x86-64 汇编,并且遇到了一个练习,要求将一行 C 代码转换为(两个)等效的汇编指令。该代码是关于使用指针将一种类型的变量复制到另一种类型的变量。
指针变量声明如下:
src_t *sp; //src_t and dest_t are typedefs
dest_t *dp;
Run Code Online (Sandbox Code Playgroud)
需要翻译的C代码是:
*dp = (dest_t)*sp;
Run Code Online (Sandbox Code Playgroud)
假设指针sp和分别dp存储在寄存器%rdi和%rsi中,并且我们应该设置%rax(例如 、%eax或%ax)的“适当部分”%al来进行中间数据复制(因为 x86-64 不允许源和目标同时复制)是内存引用)。
现在,当src_tisunsigned char和dest_tis 时long,我为其编写了以下汇编代码:
movzbq (%rdi), %rax //move a byte into %rax with zero extension
movq %rax, (%rsi) //move 8 bytes of 'long' data
Run Code Online (Sandbox Code Playgroud)
但这本书以及Godboltgcc (与 一起使用-O3)都说它应该是
movzbl (%rdi), %eax
movq %rax, (%rsi)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,该字节仅(?)零扩展为 4 个字节(%eax4 个字节长),但我读到如果我们确实喜欢
movl %edx, %rax
Run Code Online (Sandbox Code Playgroud)
那么%rax的高4个字节也将被设置为0。
我有两个问题:
movl %edx, %rax,movl %edx, %eax即后一种情况高4字节是否也设置为0?movzbq (%rdi), %rax,movzbl (%rdi), %eaxiemovzbl也将较高的 4 个字节设置为零(如movl),即使我们没有提到完整的寄存器(%rax),而只提到其中的一部分(%eax)?一般来说,在 x86_64 上,任何以 32 位通用寄存器为目标的指令(任何 %eXX 或 %rNd 寄存器)也会将相应 64 位寄存器的高 32 位设置为 0。 32 位目标 0 将其扩展为 64 位。
来自英特尔 IA32 软件开发人员手册(第 3.4.1.1 节):
在 64 位模式下,操作数大小决定目标通用寄存器中的有效位数量:
- 64 位操作数在目标通用寄存器中生成 64 位结果。
- 32 位操作数生成 32 位结果,并在目标通用寄存器中零扩展为 64 位结果。
- 8 位和 16 位操作数生成 8 位或 16 位结果。该操作不会修改目标通用寄存器的高 56 位或 48 位(分别)。如果 8 位或 16 位运算的结果用于 64 位地址计算,请显式将寄存器符号扩展为完整的 64 位。
| 归档时间: |
|
| 查看次数: |
2046 次 |
| 最近记录: |