Greetings.

I have discovered what appears to be an optimization bug with '-Os'
in GCC-4.1.0 for the MIPS architecture. It appears that functions
which are declared as 'inline' are being ignored and instead turned
into to function calls which is breaking the dynamic linker loader
for uClibc on MIPS. I apologize for not being able to provide a
simpler test case, but I did my best to isolate the issue. I have
placed a tarball at:

http://www.realitydiluted.com/nptl-uclibc/gcc-4.1.0-size-optimization-error.tar.bz2

that contains the source as well as the object files and final
loader binary for both the '-O1' and '-Os' cases. Hopefully that
will aide in discovering the problem.

First, compiling with '-O1' WORKS. My toolchain is binutils-2.16.1,
latest GCC-4.1.0 from head of CVS and latest snapshot of uClibc.
Compiling the loader with '-Os' results in a dynamic linker that
immediately segfaults.

Two isolated cases appear with the inlined functions on lines 179
and 193 of the 'dl-startup.c' file below.

   167          /* Check the ELF header to make sure everything looks ok.  */
   168          if (!header || header->e_ident[EI_CLASS] != ELFCLASS32 ||
   169                          header->e_ident[EI_VERSION] != EV_CURRENT
   170                          /* Do not use an inline _dl_strncmp here or 
some arches
   171                          * will blow chunks, i.e. those that need to 
relocate all
   172                          * string constants... */
   173                          || header->e_ident[EI_MAG0] != ELFMAG0
   174                          || header->e_ident[EI_MAG1] != ELFMAG1
   175                          || header->e_ident[EI_MAG2] != ELFMAG2
   176                          || header->e_ident[EI_MAG3] != ELFMAG3)
   177          {
   178                  SEND_STDERR("Invalid ELF header\n");
** 179                  _dl_exit(0);
   180          }
   181          SEND_STDERR_DEBUG("ELF header=");
   182          SEND_ADDRESS_STDERR_DEBUG(load_addr, 1);
   183  
   184  
   185          /* Locate the global offset table.  Since this code must be PIC
   186           * we can take advantage of the magic offset register, if we
   187           * happen to know what that is for this architecture.  If not,
   188           * we can always read stuff out of the ELF file to find it... */
   189          got = elf_machine_dynamic();
   190          dpnt = (Elf32_Dyn *) (got + load_addr);
   191          SEND_STDERR_DEBUG("First Dynamic section entry=");
   192          SEND_ADDRESS_STDERR_DEBUG(dpnt, 1);
** 193          _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
   194          tpnt->loadaddr = load_addr;

In the '-O1' case, the functions are inlined as expected and the dynamic
linker functions as expected. When compiled with '-Os', the functions
are not inlined. Instead, they become normal function calls. Below is a snippet of the dissassembly with astericks (*) beside the function
calls.

...
                        header->e_ident[EI_VERSION] != EV_CURRENT
                        /* Do not use an inline _dl_strncmp here or some arches
                        * will blow chunks, i.e. those that need to relocate all
                        * string constants... */
                        || header->e_ident[EI_MAG0] != ELFMAG0
                        || header->e_ident[EI_MAG1] != ELFMAG1
                        || header->e_ident[EI_MAG2] != ELFMAG2
                        || header->e_ident[EI_MAG3] != ELFMAG3)
        {
                SEND_STDERR("Invalid ELF header\n");
                _dl_exit(0);
    5214:       8f998018        lw      t9,-32744(gp)
    5218:       27390e20        addiu   t9,t9,3616
*** 521c:       0320f809        jalr    t9
    5220:       00002021        move    a0,zero
    5224:       8fbc0018        lw      gp,24(sp)
        }
        SEND_STDERR_DEBUG("ELF header=");
        SEND_ADDRESS_STDERR_DEBUG(load_addr, 1);


        /* Locate the global offset table.  Since this code must be PIC
         * we can take advantage of the magic offset register, if we
         * happen to know what that is for this architecture.  If not,
         * we can always read stuff out of the ELF file to find it... */
        got = elf_machine_dynamic();
        dpnt = (Elf32_Dyn *) (got + load_addr);
        SEND_STDERR_DEBUG("First Dynamic section entry=");
        SEND_ADDRESS_STDERR_DEBUG(dpnt, 1);
        _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
    5228:       8f998018        lw      t9,-32744(gp)
    522c:       8f828010        lw      v0,-32752(gp)
    5230:       27b00098        addiu   s0,sp,152
    5234:       02002021        move    a0,s0
    5238:       00002821        move    a1,zero
    523c:       240600e4        li      a2,228
    5240:       27391194        addiu   t9,t9,4500
*** 5244:       0320f809        jalr    t9
    5248:       00528821        addu    s1,v0,s2
    524c:       3c037000        lui     v1,0x7000
...

The segfault occurs immediately after 0x5244 due to an invalid value
being stored in t9. This appears to occur because of the gp being
written with a bogus value at 0x5224. Does anyone have some insight
into what is going on that is causing this erroneous behavior? Thanks.

-Steve

Reply via email to