This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c++/52455] New: Symbolic constant treated as extern when -O not specified resulting in undefined symbol at link


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

             Bug #: 52455
           Summary: Symbolic constant treated as extern when -O not
                    specified resulting in undefined symbol at link
    Classification: Unclassified
           Product: gcc
           Version: 4.7.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
        AssignedTo: unassigned@gcc.gnu.org
        ReportedBy: scott@lurndal.org


AMD64/Linux.  First noticed with 4.4.1.  Tried 4.7.1 to see if it had been
fixed in the meantime (svn trunk as of 1-mar-2012).

An unsigned long long static const private value in a class is used in an
inline function.  When the compilation unit which references the inline
function is compiled without optimization (sans -O), the references to the
static const values are externs (which cause the link-edit step to fail with
unresolved symbols).   When compiled with -O1 or greater, the compiler
correctly inserts the 64-bit constants as literals using movabsq and the
link-edit step succeeds.

If the "?:" syntax in c_test::fault() is replaced with an if statement, the
correct code is generated in both cases.  Which should help point towards the
bug.

Using built-in specs.
COLLECT_GCC=/usr/local/bin/g++-4.6
Target: x86_64-linux-gnu
Configured with: ../gcc_tot/configure -v --enable-languages=c,c++
--prefix=/usr/local --enable-shared --enable-multiarch --enable-linker-build-id
--with-system-zlib --libexecdir=/usr/local/lib --without-included-gettext
--enable-threads=posix --with-gxx-include-dir=/usr/local/include/c++/4.6
--program-suffix=-4.6 --enable-nls --enable-clocale=gnu
--enable-libstdcxx-debug --disable-werror --with-arch-32=i486
--with-tune=generic --enable-checking=release --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-gmp=/usr/local
--with-mpfr=/usr/local --with-mpc=/usr/local/
Thread model: posix
gcc version 4.7.0 20120301 (experimental) (GCC) 
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-o' '/tmp/a.o' '-shared-libgcc'
'-mtune=generic' '-march=x86-64'
 /usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/cc1plus -E -quiet -v -D_GNU_SOURCE
/tmp/a.cpp -mtune=generic -march=x86-64 -fpch-preprocess -o a.ii
ignoring nonexistent directory
"/usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include/c++/4.6
 /usr/local/include/c++/4.6/x86_64-linux-gnu
 /usr/local/include/c++/4.6/backward
 /usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/include
 /usr/local/include
 /usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/include-fixed
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-o' '/tmp/a.o' '-shared-libgcc'
'-mtune=generic' '-march=x86-64'
 /usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/cc1plus -fpreprocessed a.ii -quiet
-dumpbase a.cpp -mtune=generic -march=x86-64 -auxbase-strip /tmp/a.o -version
-o a.s
GNU C++ (GCC) version 4.7.0 20120301 (experimental) (x86_64-linux-gnu)
        compiled by GNU C version 4.7.0 20120301 (experimental), GMP version
5.0.4, MPFR version 3.1.0, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C++ (GCC) version 4.7.0 20120301 (experimental) (x86_64-linux-gnu)
        compiled by GNU C version 4.7.0 20120301 (experimental), GMP version
5.0.4, MPFR version 3.1.0, MPC version 0.9
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: dcdba1f80966b019e0b78518616aba28
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-o' '/tmp/a.o' '-shared-libgcc'
'-mtune=generic' '-march=x86-64'
 as --64 -o /tmp/a.o a.s
COMPILER_PATH=/usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/:/usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/:/usr/local/lib/gcc/x86_64-linux-gnu/:/usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/:/usr/local/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/:/usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/local/lib/gcc/x86_64-linux-gnu/4.7.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-o' '/tmp/a.o' '-shared-libgcc'
'-mtune=generic' '-march=x86-64'

The source files:

a.h
-------------------

class  c_test {
    static const unsigned long long  TEST1 = 0x8000000000000000ull;
    static const unsigned long long  TEST2 = 0x4000000000000000ull;

    unsigned long long   t_value;

public:
    c_test(void)    { t_value = 0; }

    void   fault(bool hard);

    unsigned long long val(void) { return t_value; }
};

inline void
c_test::fault(bool hard)
{
    t_value |= (hard?TEST1:TEST2);
}


a.cpp
----------------------
#include <stdlib.h>
#include <stdio.h>

#include "a.h"

int
main(int argc, const char **argv)
{
    c_test   t;

    t.fault(argc == 2);

    printf("%llz\n", t.val());

    return 0;
}

When compiled without -O:
$ g++ -o a /tmp/a.o
/tmp/a.o: In function `c_test::fault(bool)':
a.cpp:(.text._ZN6c_test5faultEb[c_test::fault(bool)]+0x1d): undefined reference
to `c_test::TEST1'
a.cpp:(.text._ZN6c_test5faultEb[c_test::fault(bool)]+0x26): undefined reference
to `c_test::TEST2'
collect2: ld returned 1 exit status

$ cat /tmp/a.s
        .file   "a.cpp"
        .section       
.text._ZN6c_testC2Ev,"axG",@progbits,_ZN6c_testC5Ev,comdat
        .align 2
        .weak   _ZN6c_testC2Ev
        .type   _ZN6c_testC2Ev, @function
_ZN6c_testC2Ev:
.LFB1:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movq    %rdi, -8(%rbp)
        movq    -8(%rbp), %rax
        movq    $0, (%rax)
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1:
        .size   _ZN6c_testC2Ev, .-_ZN6c_testC2Ev
        .weak   _ZN6c_testC1Ev
        .set    _ZN6c_testC1Ev,_ZN6c_testC2Ev
        .section       
.text._ZN6c_test3valEv,"axG",@progbits,_ZN6c_test3valEv,comdat
        .align 2
        .weak   _ZN6c_test3valEv
        .type   _ZN6c_test3valEv, @function
_ZN6c_test3valEv:
.LFB3:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movq    %rdi, -8(%rbp)
        movq    -8(%rbp), %rax
        movq    (%rax), %rax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE3:
        .size   _ZN6c_test3valEv, .-_ZN6c_test3valEv
        .section       
.text._ZN6c_test5faultEb,"axG",@progbits,_ZN6c_test5faultEb,comdat
        .align 2
        .weak   _ZN6c_test5faultEb
        .type   _ZN6c_test5faultEb, @function
_ZN6c_test5faultEb:
.LFB4:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movq    %rdi, -8(%rbp)
        movl    %esi, %eax
        movb    %al, -12(%rbp)
        movq    -8(%rbp), %rax
        movq    (%rax), %rdx
        cmpb    $0, -12(%rbp)
        je      .L5
        movq    _ZN6c_test5TEST1E(%rip), %rax
        jmp     .L6
.L5:
        movq    _ZN6c_test5TEST2E(%rip), %rax
.L6:
        orq     %rax, %rdx
        movq    -8(%rbp), %rax
        movq    %rdx, (%rax)
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE4:
        .size   _ZN6c_test5faultEb, .-_ZN6c_test5faultEb
        .section        .rodata
.LC0:
        .string "%llz\n"
        .text
        .globl  main
        .type   main, @function
main:
.LFB5:
        .cfi_startproc
        .cfi_personality 0x3,__gxx_personality_v0
        .cfi_lsda 0x3,.LLSDA5
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $32, %rsp
        movl    %edi, -20(%rbp)
        movq    %rsi, -32(%rbp)
        leaq    -16(%rbp), %rax
        movq    %rax, %rdi
        call    _ZN6c_testC1Ev
        cmpl    $2, -20(%rbp)
        sete    %al
        movzbl  %al, %edx
        leaq    -16(%rbp), %rax
        movl    %edx, %esi
        movq    %rax, %rdi
        call    _ZN6c_test5faultEb
        leaq    -16(%rbp), %rax
        movq    %rax, %rdi
        call    _ZN6c_test3valEv
        movq    %rax, %rsi
        movl    $.LC0, %edi
        movl    $0, %eax
.LEHB0:
        call    printf
.LEHE0:
        movl    $0, %eax
        jmp     .L11
.L10:
        movq    %rax, %rdi
.LEHB1:
        call    _Unwind_Resume
.LEHE1:
.L11:
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE5:
        .globl  __gxx_personality_v0
        .section        .gcc_except_table,"a",@progbits
.LLSDA5:
        .byte   0xff
        .byte   0xff
        .byte   0x1
        .uleb128 .LLSDACSE5-.LLSDACSB5
.LLSDACSB5:
        .uleb128 .LEHB0-.LFB5
        .uleb128 .LEHE0-.LEHB0
        .uleb128 .L10-.LFB5
        .uleb128 0
        .uleb128 .LEHB1-.LFB5
        .uleb128 .LEHE1-.LEHB1
        .uleb128 0
        .uleb128 0
.LLSDACSE5:
        .text
        .size   main, .-main
        .ident  "GCC: (GNU) 4.7.0 20120301 (experimental)"
        .section        .note.GNU-stack,"",@progbits

When compiled with -O1:
----------------------
        .file   "a.cpp"
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "%llz\n"
        .text
        .globl  main
        .type   main, @function
main:
.LFB24:
        .cfi_startproc
        subq    $8, %rsp
        .cfi_def_cfa_offset 16
        cmpl    $2, %edi
        movabsq $-9223372036854775808, %rax
        movabsq $4611686018427387904, %rsi
        cmove   %rax, %rsi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        movl    $0, %eax
        addq    $8, %rsp
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
.LFE24:
        .size   main, .-main
        .ident  "GCC: (GNU) 4.7.0 20120301 (experimental)"
        .section        .note.GNU-stack,"",@progbits

/tmp/a.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:   48 83 ec 08             sub    $0x8,%rsp
   4:   83 ff 02                cmp    $0x2,%edi
   7:   48 b8 00 00 00 00 00    mov    $0x8000000000000000,%rax
   e:   00 00 80 
  11:   48 be 00 00 00 00 00    mov    $0x4000000000000000,%rsi
  18:   00 00 40 
  1b:   48 0f 44 f0             cmove  %rax,%rsi
  1f:   bf 00 00 00 00          mov    $0x0,%edi
  24:   b8 00 00 00 00          mov    $0x0,%eax
  29:   e8 00 00 00 00          callq  2e <main+0x2e>
  2e:   b8 00 00 00 00          mov    $0x0,%eax
  33:   48 83 c4 08             add    $0x8,%rsp
  37:   c3                      retq   


This version of c_test::fault will generate the inline literal correctly for
both cases:

inline void
c_test::fault(bool hard)
{
    if (hard) {
        t_value |= TEST1;
    } else {
        t_value |= TEST2;
    }
}

I surmise that there is something funny in the front-end vis-a-vis handling of
the '?:' operators.

I seem to recall working around this in some 3-series compilers (fedora core 4
days) as well.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]