为什么我不能直接将字节移动到64位寄存器?

ant*_*oyo 4 assembly x86-64

为什么我不能直接将一个字节从内存移动到Intel x86-64汇编中的64位寄存器?

例如,这段代码:

extern printf

global main

segment .text

main:
    enter   2, 0

    mov     byte [rbp - 1], 'A'
    mov     byte [rbp - 2], 'B'

    mov     r12, [rbp - 1]
    mov     r13, [rbp - 2]             

    xor     rax, rax           
    mov     rdi, Format                                                                                             
    mov     rsi, r12                                                                                                
    mov     rdx, r13                                                                                                
    call    printf                                                                                                  

    leave                                                                                                           
    ret                                                                                                             

segment .data                                                                                                       
Format:     db "%d %d", 10, 0
Run Code Online (Sandbox Code Playgroud)

打印:

65 16706
Run Code Online (Sandbox Code Playgroud)

我需要将移动字节更改为寄存器r12和r13,以使代码正常工作:

xor     rax, rax
mov     al, byte [rbp - 1]
mov     r12, rax
xor     rax, rax
mov     al, byte [rbp - 2]
mov     r13, rax
Run Code Online (Sandbox Code Playgroud)

现在,它打印出预期的内容:

65 66
Run Code Online (Sandbox Code Playgroud)

为什么我们需要这样做?

有更简单的方法吗?

谢谢.

Jes*_*ter 7

根据需要使用零或符号扩展名移动.

例如:movzx eax, byte [rbp - 1]零延伸到RAX.

movsx rax, byte [rbp - 1] 签名扩展到RAX.

  • 你可以毫无问题地使用8位寄存器.`mov [rbp-1],r12b` (2认同)
  • 更好:`movzx eax,byte [rbp - 1]`通过让隐式置零处理高位32b来避免无用的REX前缀.另见[我对Maslutin答案的评论](/sf/ask/1583493831/#comment76757843_43812936)更好的顺序是在`call`之前用2字节加载到`ebx`(如r12/r13中调用保存),然后从BL/BH解包到printf args. (2认同)