This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c++/52455] New: Symbolic constant treated as extern when -O not specified resulting in undefined symbol at link
- From: "scott at lurndal dot org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Fri, 02 Mar 2012 00:29:23 +0000
- Subject: [Bug c++/52455] New: Symbolic constant treated as extern when -O not specified resulting in undefined symbol at link
- Auto-submitted: auto-generated
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.