I'm trying to learn GCC inline assembly on Linux (x86), and my first experiment was to try and implement integer overflow detection for multiplication. It seems easy enough, but it is having side effects which I don't understand.
So, here I want to multiply two unsigned 8-bit integers, and see if the result overflows. Basically I just load the first operand into the AL register and the other operand into the BL register, and then use the mul
instruction. The result is stored as a 16-bit value in the AX register. So I then copy the value in the AX register to my C variable b
, unless it overflows. If it overflows I set c
to 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)
);
This seems to work fine. If I printf
the value of 'b' I get 250, which is correct. Also, if I change the starting value of 'b' to 26, then after the multiplication c
is set to 1, indicating an overflow because of course (10 * 26 > ~uint8_t(0)). The problem I'm seeing is that the C variable a
is set to 0 after the multiplication (or 1 on an overflow.) I don't understand why a
would be changed at all by anything I'm doing here. It's not even on the list of output variables, so why is my assembly routine affecting the value of a
?
Also, I'm unsure about the clobbered registers list. This list is supposed to inform GCC about any registers which were used during the assembly routine, so that GCC doesn't try to use them incorrectly. I think I need to inform GCC that I used the AL and BL registers, but what about the AX register? It's used implicitly to store the product of two 8-bit integers, so do I need to include it in the list of clobbered registers?