如何在英特尔汇编中添加 2 个无符号的 1 字节数字?

How do I add 2 unsigned 1 byte numbers in Intel assembly?

我刚开始自学编写汇编。

如何在 x86_64 上使用 linux 添加两个 1 字节整数。

学习汇编的一种方法是用高级语言(例如 C)编写您希望处理器执行的操作,然后查看编译器生成的内容。

unsigned char addition (unsigned char a, unsigned char b)
{
  return a+b;
}

有时这会导致一些奇怪但有效的汇编结构:

movzbl  -4(%rbp), %edx   ;a
movzbl  -8(%rbp), %eax   ;b
leal    (%rdx,%rax), %eax  ;return a+b

这一次,LEA指令用于将存储在64位寄存器中的两个8位数字相加,而不是预期的ADD指令。关键是这些寄存器已经使用 MOVZX 指令进行了初始化,该指令将所有未使用的位(直到位 31)填充为 0。使用 Intel 语法编写的相同示例如下所示:

movzx eax,[rbp-8]  ; A -> eax
movzx edx,[rbp-4]  ; B -> edx
lea eax,[rax+rdx]  ; A+B -> eax

在只初始化了32位寄存器的情况下,添加64位寄存器会觉得很奇怪。考虑到第 8 位到第 31 位已使用 MOVZX 指令初始化为 0,因此 RAX 的上半部分发生的任何事情都不重要。 RAX 的低 8 位将包含我们加法的 8 位结果(可能溢出,也可能不溢出)

Visual Studio,当没有启用优化时,生成一个更"predecible"版本的这个函数的汇编版本,你可以研究它,连同它的原始C代码:

注意:这是使用 32 位代码生成编译的。

unsigned char addition (unsigned char a, unsigned char b)
{
00EA10A0  push        ebp  
00EA10A1  mov         ebp,esp  
    return a+b;
00EA10A3  movzx       eax,byte ptr [ebp+8]  
00EA10A7  movzx       ecx,byte ptr [ebp+0Ch]  
00EA10AB  add         eax,ecx  
}
00EA10AD  pop         ebp  
00EA10AE  ret  

两个编译器都尝试使用其完整大小的寄存器,即使实际上只需要其中的一小部分,这导致两者最终都使用 MOVZX 指令将 8 位值加载到更大的寄存器中。使用带符号的字符,您将看到会发生什么。