http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55142
--- Comment #24 from Eric Botcazou <ebotcazou at gcc dot gnu.org> 2012-11-08 16:11:25 UTC --- > I applied i386 change at > > http://gcc.gnu.org/bugzilla/attachment.cgi?id=28591 > > to compile it: > > [hjl@gnu-tools-1 tmp]$ /export/build/gnu/gcc/release/usr/gcc-4.8.0/bin/gcc > -mtune=generic -march=x86-64 -maddress-mode=long -mx32 -O2 -fPIC rtld.c > -std=gnu99 -fgnu89-inline -S > [hjl@gnu-tools-1 tmp]$ egrep ", -[0-9]*\(%rax" rtld.s > movl %ecx, -1073743664(%rax) > movl %ecx, -1073742592(%rax) > movl %edx, -1073743664(%rax) > movl %edx, -1073742592(%rax) > [hjl@gnu-tools-1 tmp]$ > > All those stores should be zero-extended. OK, thanks. Everything is correctly zero-extended until: case PLUS: case MULT: /* FIXME: For addition, we used to permute the conversion and addition operation only if one operand is a constant and converting the constant does not change it or if one operand is a constant and we are using a ptr_extend instruction (POINTERS_EXTEND_UNSIGNED < 0) even if the resulting address may overflow/underflow. We relax the condition to include zero-extend (POINTERS_EXTEND_UNSIGNED > 0) since the other parts of the compiler depend on it. See PR 49721. We can always safely permute them if we are making the address narrower. */ if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode) || (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) && (POINTERS_EXTEND_UNSIGNED != 0 || XEXP (x, 1) == convert_memory_address_addr_space (to_mode, XEXP (x, 1), as)))) return gen_rtx_fmt_ee (GET_CODE (x), to_mode, convert_memory_address_addr_space (to_mode, XEXP (x, 0), as), XEXP (x, 1)); break; It's clear that the distribution is invalid, whatever POINTERS_EXTEND_UNSIGNED is defined to. It becomes valid only under conditions of non-overflow that depend upon the value of POINTERS_EXTEND_UNSIGNED, as stated in the head comment of the function. If POINTERS_EXTEND_UNSIGNED, it's valid if there is no overflow in the address. If POINTERS_EXTEND_UNSIGNED > 0, it's valid if either the constant is positive (and there is no overflow in the address) or the constant is negative and the variable part is sufficiently large. The condition aren't fulfilled here since the constant is very large negative and the variable part small. I think the most robust solution would be to always zero-extend the addresses for -mx32, i.e. output movl %ecx, -1073743664(%eax) even if the address is a PLUS in DImode. Otherwise, we're left with kludges...