【发布时间】:2010-10-07 17:04:32
【问题描述】:
我正在尝试在 Linux (x86) 上学习 GCC 内联汇编,我的第一个实验是尝试实现用于乘法的整数溢出检测。这似乎很容易,但它有我不明白的副作用。
所以,这里我想将两个无符号的 8 位整数相乘,看看结果是否溢出。基本上我只是将第一个操作数加载到 AL 寄存器中,将另一个操作数加载到 BL 寄存器中,然后使用mul 指令。结果作为 16 位值存储在 AX 寄存器中。所以我然后将 AX 寄存器中的值复制到我的 C 变量b,除非它溢出。如果溢出,我将c 设置为 1。
uint8_t a = 10;
uint8_t b = 25;
uint8_t c = 0; // carry flag
__asm__
(
"clc;" // Clear carry flag
"movb %3, %%al;" // Load b into %al
"movb %2, %%bl;" // Load a into %bl
"mul %%bl;" // Multiply a * b (result is stored in %ax)
"movw %%ax, %0;" // Load result into b
"jnc out;" // Jump to 'out' if the carry flag is not set
"movb $1, %1;" // Set 'c' to 1 to indicate an overflow
"out:"
:"=m"(b), "=m"(c) // Output list
:"ir"(a), "m"(b) // Input list
:"%al", "%bl" // Clobbered registers (not sure about this)
);
这似乎工作正常。如果我printf 'b' 的值,我得到 250,这是正确的。另外,如果我将 'b' 的起始值更改为 26,那么在乘法之后 c 设置为 1,这表明溢出当然是因为 (10 * 26 > ~uint8_t(0))。我看到的问题是 C 变量 a 在乘法后设置为 0(或溢出时设置为 1。)我不明白为什么 a 会被我在这里所做的任何事情改变.它甚至不在输出变量列表中,为什么我的汇编程序会影响a 的值?
另外,我不确定被破坏的寄存器列表。这个列表应该通知 GCC 在汇编例程中使用的任何寄存器,这样 GCC 就不会试图错误地使用它们。我想我需要通知 GCC 我使用了 AL 和 BL 寄存器,但是 AX 寄存器呢?它被隐式用于存储两个 8 位整数的乘积,所以我需要将它包含在被破坏的寄存器列表中吗?
【问题讨论】:
-
不要将值加载到
%al和%bl并标记它们已被破坏,您应该设置约束,以便 gcc 将参数放在正确的寄存器中开始。
标签: c assembly x86 inline-assembly integer-overflow