http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52146

             Bug #: 52146
           Summary: [x32] - Wrong code to access addresses 0x80000000 to
                    0xFFFFFFFF
    Classification: Unclassified
           Product: gcc
           Version: 4.6.3
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: steffen-schm...@siemens.com


Created attachment 26596
  --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=26596
C code resulting in wrong instructions when compiled with -mx32 and O1 or
higher

When accessing memory addresses in the region 0x80000000 to 0xFFFFFFFF starting
from optimization -O1 or higher -mx32 GCC seems to generate faulty assembler
instructions.

Using -mx32 GCC will generate code for x86_64 target but using 4 byte pointers
(instead of 8 byte pointers when using -m64). Nonetheless we're running on a
x86_64 64bit machine.

The example shows the problem:
typedef unsigned int uint32_t;
volatile uint32_t * apic_tpr_addr = (uint32_t*)0xfee00080;
*apic_tpr_addr = 0;


GCC -mx32 generates the following assembler instructions:
movl    $0, -18874240

On on x86 32bit system, this instruction would be correct, movl uses signed
addresses as destination when directly accessing memory. On an x86_64 system,
on the other hand, this instruction does not refer to address 0xFEE00080, but
to 0xFFFFFFFFFEE00080, because the signed address is interpreted in 64bit by
the processor, which leads to an error.

GCC -m64 generates the correct instructions:
xorl    %eax, %eax
movabsl    %eax, 4276093056

It seems to be necessary to use movabsl instruction instead of movl.


The problem does not occur by forcing access to memory via a register:
volatile uintptr_t ptr = 0xfee00080;
volatile uint32_t * apic_tpr_addr = (uint32_t*)ptr;
*apic_tpr_addr = 0;

In this case -mx32 GCC generates the follwoing code:
movl    $-18874240, -4(%esp)
movl    -4(%esp), %eax
movl    $0, (%eax)
Here the access to memory is correct, using 32bit register eax

Code generated by -m64 GCC looks similar, but using 64bit addresses and
registers.
movl    $4276093056, %eax
movq    %rax, -8(%rsp)
movq    -8(%rsp), %rax
movl    $0, (%rax)

Reply via email to