Invalid operand size in inline assembler instruction on x86-64 with LTO
Oleg Oshmyan
chortos at inbox.lv
Mon Oct 31 21:12:27 UTC 2016
Hi,
GMP 6.1.1 (and probably earlier versions) uses a wrong constraint in the x86 inline assembler code for the MPN_IORD_U macro that blows up (fails to assemble) on x86-64 when compiled using GCC 6 with link-time optimization enabled. The problem occurs when a compile-time constant does not fit in a 32-bit immediate operand, so my guess is that it is specifically triggered by constant propagation across source files.
The code currently uses a constraint that allows any compile-time constant as an immediate operand, but x86-64 supports only 32-bit immediate values (even in 64-bit instructions), whereas the value MPN_IORD_U uses with this constraint may be longer than that. GCC, at least since version 3.1.1, actually provides a constraint just for such an occasion, which allows a compile-time constant as an immediate operand if and only if its value fits in 32 bits. In fact, GCC provides two such constraints: one for signed values (for sign-extending instructions) and one for unsigned values (for zero-extending instructions). MPN_IORD_U is used only with sign-extending instructions (ADD and SUB), so the fix is easy: simply replace the currently used constraint with the signed 32-bit immediate constraint.
I have not investigated whether the same bug appears in other places. GMP currently builds successfully for me with the below patch applied.
Here is a patch:
diff --git a/gmp-impl.h b/gmp-impl.h
index 6987581..dcc233b 100644
--- a/gmp-impl.h
+++ b/gmp-impl.h
@@ -2687,7 +2687,7 @@ __GMP_DECLSPEC mp_bitcnt_t mpn_remove (mp_ptr, mp_size_t *, mp_srcptr, mp_size_t
ASM_L(done) ":\n" \
: "=r" (__ptr_dummy) \
: "0" (ptr), \
- "ri" ((mp_limb_t) (incr)), "n" (sizeof(mp_limb_t)) \
+ "re" ((mp_limb_t) (incr)), "n" (sizeof(mp_limb_t)) \
: "memory"); \
} \
} while (0)
More information about the gmp-bugs
mailing list