我刚开始学习自动编写程序集。
如何在x86_64上使用linux添加两个1字节整数。
答案 0 :(得分: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.使用英特尔语法编写的相同示例如下:
movzx eax,[rbp-8] ; A -> eax
movzx edx,[rbp-4] ; B -> edx
lea eax,[rax+rdx] ; A+B -> eax
可以认为,当只有32位寄存器被初始化时,添加64位寄存器是很奇怪的。考虑到使用MOVZX
指令将位8到31初始化为0,RAX
的上半部分发生的任何事情都不重要。 RAX的低8位将包含我们添加的8位结果(可能有或没有溢出)
Visual Studio,当没有启用优化时,会生成一个更“可预定”的版本,这个函数的汇编程序版本,你可以学习,以及它的原始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位值加载到更大的寄存器中。使用签名的字符,您将看到会发生什么。