Bug 500295
Summary: | up-to-date binutils--2.18.50.0.9-8.fc10.x86_64 has upstream bug #9938 : " TLS transition from R_386_TLS_GD to R_386_TLS_IE_32 " "/libgcc.a(bid_decimal_globals.o): TLS transition from R_X86_64_TLSGD to R_X86_64_GOTTPOFF against `__bid_IDEC_glbround'" | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Product: | [Fedora] Fedora | Reporter: | Jason Vas Dias <jason.vas.dias> | ||||||||||
Component: | binutils | Assignee: | Nick Clifton <nickc> | ||||||||||
Status: | CLOSED CURRENTRELEASE | QA Contact: | Fedora Extras Quality Assurance <extras-qa> | ||||||||||
Severity: | medium | Docs Contact: | |||||||||||
Priority: | low | ||||||||||||
Version: | 10 | CC: | jakub, jan.kratochvil, jason.vas.dias, nickc | ||||||||||
Target Milestone: | --- | ||||||||||||
Target Release: | --- | ||||||||||||
Hardware: | x86_64 | ||||||||||||
OS: | Linux | ||||||||||||
URL: | http://www.sourceware.org/bugzilla/show_bug.cgi?id=9938 | ||||||||||||
Whiteboard: | |||||||||||||
Fixed In Version: | Doc Type: | Bug Fix | |||||||||||
Doc Text: | Story Points: | --- | |||||||||||
Clone Of: | Environment: | ||||||||||||
Last Closed: | 2009-05-27 11:27:33 UTC | Type: | --- | ||||||||||
Regression: | --- | Mount Type: | --- | ||||||||||
Documentation: | --- | CRM: | |||||||||||
Verified Versions: | Category: | --- | |||||||||||
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||||||||
Cloudforms Team: | --- | Target Upstream Version: | |||||||||||
Embargoed: | |||||||||||||
Attachments: |
|
Description
Jason Vas Dias
2009-05-12 07:00:12 UTC
Incidentally, the problem occurs regardless of whether I do : $ gcc -o ${MY_PROGRAM} ${MY_OBJS} \ -Wl,--whole-archive ${MY_ARCHIVES} ${MY_LIBS} -Wl,--no-whole-archive -lm -ldl -lcrypt -c_nonshared -lc or whether I do : $ gcc -o ${MY_PROGRAM} ${MY_OBJS} \ -Wl,--whole-archive ${MY_ARCHIVES} ${MY_LIBS} -Wl,--no-whole-archive -lm -ldl -lcrypt -lc_nonshared -lc or whether I add "-shared-libgcc" or "-static-libgcc" to $CFLAGS . I meant "adding -Wl,--no-whole-archive" for libgcc.a has no effect for this problem! And ALL the objects in { ${MY_OBJS} , ${MY_ARCHIVES} } are 100% definitely compiled with -fPIC !! It is not actually "all SFIO linked objects" or "all builds linking to same ${MY_ARCHIVES} and ${MY_LIBS} with same headers" - see example successful link below - the problem occurs only for "C" expressions of the form : " typedef struct { int an_int; float /* or double */ a_float } MyStruct_t ; A_Return_Type_t a_function ( MyStruct_t ); A_Return_Type_2_t another_function ( int an_int_p, float a_float_p, ... ) { ... return ( ( A_Return_Type_2 ) a_function ( (MyStruct_t) { .an_int = an_int_p , .a_float = a_float_p } ) ); } " But, since compilations under other Linuxes ( and Solaris ) with GCC 3.4 - 4.4.1 work fine , why must I provide an FC10 workaround for cases which might contain such code ? Example Successful link under FC10 for another generated Database updater : $ gcc -o Dupdate_DG_TEST Dupdate_DG_TEST.build/R_0.o Dupdate_DG_TEST.build/R_0_1.o Dupdate_DG_TEST.build/R_0_2.o Dupdate_DG_TEST.build/set_absent_bit_for.o Dupdate_DG_TEST.build/Clear_Absent_Bits.o Dupdate_DG_TEST.build/day_gui_dg_test_absent_bits_string_for_input_record.o Dupdate_DG_TEST.build/DayGUI_Dg_Test_Set_Updated_Absent_Field_For_Input_Record.o Dupdate_DG_TEST.build/DayGUI_Dg_Test_Clear_Updated_Absent_Fields.o Dupdate_DG_TEST.build/DayGUI_Dg_Test_Initialize_Run.o Dupdate_DG_TEST.build/DayGUI_DG_TEST_Handle_Result_Record.o Dupdate_DG_TEST.build/DayGUI_DG_TEST_Handle_Result_Record_1.o Dupdate_DG_TEST.build/DayGUI_DG_TEST_Handle_Result_Record_2.o Dupdate_DG_TEST.build/DayGUI_DG_TEST_Handle_Result_Record_3.o Dupdate_DG_TEST.build/DayGUI_DG_TEST_Handle_Result_Record_4.o Dupdate_DG_TEST.build/DayGUI_DG_TEST_Handle_Result_Record_5.o Dupdate_DG_TEST.build/DayGUI_DG_TEST_Handle_Result_Record_6.o Dupdate_DG_TEST.build/DayGUI_DG_TEST_Handle_Result_Record_7.o Dupdate_DG_TEST.build/DayGUI_DG_TEST_Handle_Result_Record_8.o Dupdate_DG_TEST.build/Fe_Lists_Are_Equal.o Dupdate_DG_TEST.build/Fe_Lists_Are_Equal_1.o Dupdate_DG_TEST.build/Fe_Lists_Are_Equal_2.o Dupdate_DG_TEST.build/Ff_Lists_Are_Equal.o Dupdate_DG_TEST.build/Ff_Lists_Are_Equal_1.o Dupdate_DG_TEST.build/Ff_Lists_Are_Equal_2.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Update_Transaction.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Update_Transaction_1.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Update_Transaction_1_1.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Update_Transaction_1_2.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Update_Transaction_1_3.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Update_Transaction_1_3_1.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Update_Transaction_1_3_2.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Delete_Transaction.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Delete_Transaction_1.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Delete_Transaction_1_1.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Delete_Transaction_1_2.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Delete_Transaction_1_3.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Create_Transaction.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Create_Transaction_1.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Create_Transaction_1_1.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Create_Transaction_1_2.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Create_Transaction_1_3.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Create_Transaction_1_4.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Print_Selected.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Print_Selected_1.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Print_Selected_1_1.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Print_Selected_1_2.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Print_Selected_1_3.o Dupdate_DG_TEST.build/Dupdate_DG_TEST_Print_Selected_1_4.o /home/jason/D/FC10/orders/usr.env.o /home/jason/D/FC10/DGIO_STDIN_DG_TEST.o /home/jason/D/FC10/DGIO_PIPEIN_DG_TEST.o /home/jason/D/FC10/DG_TEST.o /home/jason/D/FC10/DGIO_STDOUT_DG_TEST.o day_gui_dg_test_completors.o day_gui_dg_test_validators.o DayGUI_Dg_Test_Cymbal_Type_Conversion.build/DayGUI_Cy_Str_16_To_C_Str.o DayGUI_Dg_Test_Cymbal_Type_Conversion.build/DayGUI_C_Str_To_Cy_Str_16.o DayGUI_Dg_Test_Cymbal_Type_Conversion.build/DayGUI_C_Str_To_Cy_Str_16_Assign.o DayGUI_Dg_Test_Cymbal_Type_Conversion.build/day_gui_cy_is_greater_than_str_16.o DayGUI_Dg_Test_Cymbal_Type_Conversion.build/day_gui_cy_is_less_than_str_16.o day_gui_dg_test_cymbal_type_conversion.o DayGUI_Dg_Test_Fc_Tuple_Conversion.build/DayGUI_Cy_Dg_Test_Fc_To_C.o DayGUI_Dg_Test_Fc_Tuple_Conversion.build/DayGUI_C_Dg_Test_Fc_To_Cy.o DayGUI_Dg_Test_Fc_Tuple_Conversion.build/DayGUI_C_Dg_Test_Fc_Assign.o day_gui_dg_test_cymbal_tuple_conversion.o day_gui_gtk_dg_test.o day_gui_gtk_dg_test_where_clause.o day_gui_efs_dg_test.o DG_TEST_Frame.o day_gui_efs_dg_test_where_clause.o -L/lib/../lib64/ -L/home/jason/D/FC10/DayGUI -lDayGUI -Wl,--whole-archive,--export-dynamic,-z,muldefs -L/usr/ds_bin -L/usr/ds_bin/BTREES -L/usr/ds_bin/EASEL/ds_easelhome/lib /usr/ds_bin/libDS.a /usr/ds_bin/libRsys.a /usr/ds_bin/libR_net.a /usr/ds_bin/libR_DC.a /usr/ds_bin/libR_RC.a /usr/ds_bin/libR_MC.a /usr/ds_bin/libEnv.a /usr/ds_bin/BTREES/libcbt.a /usr/ds_bin/EASEL/ds_easelhome/lib/libefm.a /usr/ds_bin/EASEL/ds_easelhome/lib/libgen.a /usr/ds_bin/EASEL/ds_easelhome/lib/libdisplay.a /usr/ds_bin/EASEL/ds_easelhome/lib/libcurses.a /usr/ds_bin/libcdt.a /usr/ds_bin/libstdio.a /usr/ds_bin/libsfio.a /usr/ds_bin/libvmalloc.a -lgtk-x11-2.0 -lgio-2.0 -lpangoft2-1.0 -lgdk-x11-2.0 -lgdk_pixbuf-2.0 -lpangocairo-1.0 -lcairo -latk-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lfreetype -lfontconfig -lcrypt -lm -lresolv -lrt -lpthread -ldl -lc \-Wl,--no-whole-archive -Wl,-R,/home/jason/D/FC10/DayGUI:/lib/../lib64/ Why does it not occur for the last appended link line rather that for the one previous to it ? Because the first link line in this bug report was for a record class that contains 'struct { ... int an_int; float a_float; }' members . Further Clarification of above : Database Record Classes : $ DS Synop -recls TUTU -------------------------------------------------------------------------- RECORD_CLASS: TUTU -------------------------------------------------------------------------- FILE: TUTU.db Source: $D FIELDS: Field 1: TUPLE[UINT(_tiny_),STR] Fa 2: TUPLE[UINT(_tiny_),STR] Fb 3: TUPLE[UINT(_tiny_),DATE] Fc 4: TUPLE[UINT(_tiny_),DATE] Fd $ DS Synop -recls DG_TEST -------------------------------------------------------------------------- RECORD_CLASS: DG_TEST -------------------------------------------------------------------------- FILE: DG_TEST.db Source: $D FIELDS: Field 1: INT(_short_) Fa 2: STR(16) Fb 3: (0->1)TUPLE[INT, STR, DATE_CLOCK] Fc 4: DATE_CLOCK(_yyyymmdd_24_hhmmssf_) Fd 5: LIST[DATE(_yyyymmdd_)] Fe 6: SET{STR} Ff Actually, TUTU was even worse - its 'struct {uint8_t a_tiny_member ; }' fields underwent something like an unwarranted sign extension or treatment as an "signed" or "unsigned long" under FC10 binutils + gcc-4.3.2 , but do not normally under any other known GCC + binutils combination . Please update FC10 gcc + binutils ! thanks, Jason. Note: object were compiled with "-fsigned-char" - but all TUTU fields are definitely declared as "{ unsigned char member ; } " so, since already explicitly unsigned, this should not cause any sign extension errors , and normally does not - but on FC10 gcc-4.3.2 + binutils- 2.18.50.0.9-8.fc10-20080822 , this type seems to cause an access to bid_decimal_globals.o which provokes this unwarranted ld(1) TLS transition exception which is an artefact of an old binutils bug - please backport from upstream fix ! Code which causes ? : { local Bool First_Time_Called = TRUE; (DayGUI_C_Tutu_Fa_To_Cy__tuple__).slot_with_arg_1 = 0u; { (DayGUI_C_Tutu_Fa_To_Cy__tuple__).slot_with_arg_2 = init_byte_seq_box_; } To_Byte_Seq_Boxp__Assign_From_Byte_Seq_Box__( &((DayGUI_C_Tutu_Fa_To_Cy__tuple__).slot_with_arg_2), varstr_for_str( "" ) ); DayGUI_C_Tutu_Fa_To_Cy__tuple_vbl__ = NULL; { DayGUI_C_Tutu_Fa_To_Cy__fa_member1_str__ = init_byte_seq_box_; } To_Byte_Seq_Boxp__Assign_From_Byte_Seq_Box__( &(DayGUI_C_Tutu_Fa_To_Cy__fa_member1_str__), varstr_for_str( "" ) ); { DayGUI_C_Tutu_Fa_To_Cy__fa_member1__ = init_byte_seq_box_; } To_Byte_Seq_Boxp__Assign_From_Byte_Seq_Box__( &(DayGUI_C_Tutu_Fa_To_Cy__fa_member1__), varstr_for_str( "" ) ); First_Time_Called = FALSE; } switch( 1 ){ default: (DayGUI_C_Tutu_Fa_To_Cy__tuple__).slot_with_arg_1 = DayGUI_C_Tutu_Fa_To_Cy__fa_member0_sCP2__; To_Byte_Seq_Boxp__Assign_From_Byte_Seq_Box__( &(DayGUI_C_Tutu_Fa_To_Cy__fa_member1_str__), same( varstr_for_str( DayGUI_C_Tutu_Fa_To_Cy__fa_member1_c_str_sCP2__ ) ) ); To_Byte_Seq_Boxp__Assign_From_Byte_Seq_Box__( &(DayGUI_C_Tutu_Fa_To_Cy__fa_member1__), same( DayGUI_C_Tutu_Fa_To_Cy__fa_member1_str__ ) ); To_Byte_Seq_Boxp__Assign_From_Byte_Seq_Box__( &((DayGUI_C_Tutu_Fa_To_Cy__tuple__).slot_with_arg_2), DayGUI_C_Tutu_Fa_To_Cy__fa_member1__ ); DayGUI_C_Tutu_Fa_To_Cy__tuple_vbl__ = &(DayGUI_C_Tutu_Fa_To_Cy__tuple__); (DayGUI_C_Tutu_Fa_To_Cy__callback_sCP2__)( DayGUI_C_Tutu_Fa_To_Cy__tuple_vbl__, DayGUI_C_Tutu_Fa_To_Cy__arg_sCP2__, DayGUI_C_Tutu_Fa_To_Cy__mctx_sCP2__); } start_of_closing: ; _Return_From__DayGUI_C_Tutu_Fa_To_Cy_AutoVbls_2__Begin; void day_gui_tutu_fa_to_string ( UL_t addr_arg, UL_t mctx, const uint8_t fa_member0, const char* fa_member1 ) { char *s=0; size_t length=0; char fa_member0_str[ 128 ]; length+=sprintf(fa_member0_str, "%hhu",fa_member0)+1; length+=strlen(fa_member1)+1; s = DG_MALLOC( (void*)mctx, length ); sprintf ( s,"%s""%c""%s", fa_member0_str, ' ', fa_member1 ); *((char**)addr_arg)=s; } void day_gui_tutu_fa_from_string ( const char *string, void *mctx, uint8_t* fa_member0, char** fa_member1 ) { char *p=0, *s_copy = DG_STRDUP(mctx, string), *s =s_copy; if( (p = strchr(s, ' ')) != 0 ) *p = '\0'; sscanf(s, "%hhu", fa_member0); if(p) { *p = ' '; s = (p+1); } *(fa_member1) = DG_STRDUP( mctx, s ); DG_FREE(mctx,s_copy); } void day_gui_tutu_fb_to_string ( ... /* AS FOR Fa above */ OK, a binutils patch for this will be forthcoming . As a possibly related issue, why does this code make $? == 89 ? : $ echo <<EOF typedef struct { unsigned char c1, c2, c3, c4; } Struct_A_t; int f( Struct_A_t p){ return( p.c1 & p.c4 ) } extern int strtod( const char *); int main() { return f( (Struct_A_t){ .c1 = strtod(argv[1]?argv[1]:"0"), .c4 = strtod(argv[2]?argv[2]:"1") ); } EOF > t.c $ gcc -o t t.c $ ./t $ echo $? 89 Sorry, should have been : typedef struct { unsigned char c1, c2, c3, c4; } Struct_A_t; int f( Struct_A_t p){ return( p.c1 & p.c2 & p.c3 & p.c4); } extern int strtod( const char *); int main(int argc, char **argv, char **envp) { return f( (Struct_A_t){ .c1 = strtod(argv[1]?argv[1]:"0"), .c2=0, .c3=0, .c4 = strtod(argv[2]?argv[2]:"1") } ); } This does return 0 ! But it won't link with ld(1)'s '--whole-arhive -z muldefs' options, but DOES under a working binutils from upstream CVS >= 2009-04-14 . $ gcc -Wl,--verbose,--whole-archive,-z,muldefs t_FC10 binutils_bug.c ... /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/4.3.2/libgcc.a(bid_decimal_globals.o): TLS transition from R_X86_64_TLSGD to R_X86_64_GOTTPOFF against `__bid_IDEC_glbround' at 0x7 in section `.text' failed /usr/lib/gcc/x86_64-redhat-linux/4.3.2/libgcc.a(bid_decimal_globals.o): could not read symbols: Bad value collect2: ld returned 1 exit status In what language is that? The ressemblance with C is very very low, it obviously doesn't compile and even after fixing syntax errors (missing ;, }, "int argc, const char **argv", there are several fatal bugs: 1) strtod prototype is just wrong, not sure if you meant atoi, but strtod is double strtod (const char *, char **), so the values you get from the calls with broken prototype is just some random value left in %rax/%eax on function exit 2) when you call it without arguments, argv[1] is NULL, but that doesn't imply argv[2] is NULL, that's undefined, typically it will be the first environment string. Regarding earlier comments, the C snippets with ...s are completely useless for anything, normally C code will never reference any of the DFP symbols from libgcc.a, unless either you use decimal floating point, or reference a bid/dfp symbol by hand in the source. If you wish GCC maintainers to look at it, you'd need to prepare a self-contained preprocessed testcase that triggers this. Now, whether I should or should not be passing "-whole-archive" to ld(1) without an ending "-no-whole-archive" for libgcc.a ( yes, it is better practice to use --no-whole-archive for libgcc.a ) but this is not the issue here!! The above command works fine once binutils bug #9938 is fixed, as it is on this Gentoo system : $ gcc -Wl,--whole-archive,-z,muldefs -o t ./binutils_bug.c $ ./t $ echo $? 0 $ gcc -v Using built-in specs. Target: x86_64-pc-linux-gnu Configured with: ../configure --prefix=/usr --enable-languages=c,c++,objc,obj-c++,java,fortran --enable-targets=all --enable-multilib --enable-threads=posix --enable-tls --enable-shared --enable-checking=release --with-build-time-tools=/usr/bin --with-ld=/usr/bin/ld --with-gnu-ld --with-as=/usr/bin/as --with-gnu-as --enable-__cxa_atexit --disable-libunwind-exceptions --with-system-zlib --with-system-gettext --with-system-intl --disable-werror --enable-serial-configure --enable-classpath --enable-java-awt=gtk --with-java-home=/usr/java --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu Thread model: posix gcc version 4.4.1 20090422 (prerelease) (GCC) $ ld -v GNU ld (GNU Binutils) 2.19.51.20090412 OK, self contained test case: $ echo <<EOF typedef struct { unsigned char c1, c2, c3, c4; } Struct_A_t; int f( Struct_A_t p){ return( p.c1 & p.c2 & p.c3 & p.c4); } extern int strtod( const char *); int main(int argc, char **argv, char **envp) { return f( (Struct_A_t){ .c1 = strtod(argv[1]?argv[1]:"0"), .c2=0, .c3=0, .c4 = strtod(argv[2]?argv[2]:"1") } ); } EOF > binutils_bug_500295.c $ gcc -Wl,--whole-archive,-muldefs -o t binutils_bug_500295.c on Fedora 10, fails with : /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/4.3.2/libgcc.a(bid_decimal_globals.o): TLS transition from R_X86_64_TLSGD to R_X86_64_GOTTPOFF against `__bid_IDEC_glbround' at 0x7 in section `.text' failed /usr/lib/gcc/x86_64-redhat-linux/4.3.2/libgcc.a(bid_decimal_globals.o): could not read symbols: Bad value collect2: ld returned 1 exit status On a system where I built gcc-4.4.1 with binutils 2.19.51.20090412, the exact same link line works fine : $ gcc -Wl,--whole-archive,-z,muldefs -o t ./binutils_bug.c $ ./t $ echo $? 0 Moreover, replacing use of "strtod()" in test case with "any function returning int" makes no difference ; it is the code that calls f( ) with a "structure on the stack" argument with members smaller than a "unsigned long" that somehow triggers a reference to bid_decimal_globals.o . As I've been trying to explain, the wrongly assembled bid_decimal_globals.o contains a TLS transition that is wrongly marked as invalid by the Fedora 10 linker, so generates a link error; when bid_decimal_globals.o was built by binutils >= 2.19.51.20090412, the problem does not occur. Anyway, the second argument of strtod() can safely be passed as 0L ( no end-of-string pointer ) as documented. Had I actually cared about what strtod returns, I would have said "strtod(argv[N]?argv[N]:"0",0)" . But it makes absolutely no difference to the bug, which is that the link line fails on Fedora 10 because of binutils bug #9938 - please can you tell me, is Mr. H.J. Lu's patch for #9938 in Fedora binutils ? Because it was he who responded to GCC bug #39508 saying that his code in upstream binutils was probably the cause of that issue, and that his code is fixed with the binutils patch. Is Mr. Lu's patch in Fedora binutils ? Log message: 2009-03-12 H.J. Lu <hongjiu.lu> PR ld/9938 * elf32-i386.c (elf_i386_check_tls_transition): Use strncmp to check ___tls_get_addr. * elf64-x86-64.c (elf64_x86_64_check_tls_transition): Use strncmp to check __tls_get_addr. Patches: http://sources.redhat.com/cgi-bin/cvsweb.cgi/src/bfd/ChangeLog.diff?cvsroot=src&r1=1.4495&r2=1.4496 http://sources.redhat.com/cgi-bin/cvsweb.cgi/src/bfd/elf32-i386.c.diff?cvsroot=src&r1=1.192&r2=1.193 http://sources.redhat.com/cgi-bin/cvsweb.cgi/src/bfd/elf64-x86-64.c.diff?cvsroot=src&r1=1.151&r2=1.152 ------- Additional Comment #15 From H.J. Lu 2009-03-12 17:15 [reply] ------- It is fixed by http://sourceware.org/ml/binutils/2009-03/msg00233.html The same fix can be used in binutils-2.19.50.0.1. PATCH TO FIX : $ gendiff binutils-2.18.50.0.9 .bug9938 diff -up binutils-2.18.50.0.9/bfd/elf64-x86-64.c.bug9938 binutils-2.18.50.0.9/bfd/elf64-x86-64.c --- binutils-2.18.50.0.9/bfd/elf64-x86-64.c.bug9938 2008-08-23 11:39:56.000000000 -0400 +++ binutils-2.18.50.0.9/bfd/elf64-x86-64.c 2009-05-14 07:37:13.000000000 -0400 @@ -827,7 +827,7 @@ elf64_x86_64_check_tls_transition (bfd * && h->root.root.string != NULL && (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32 || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32) - && (strcmp (h->root.root.string, "__tls_get_addr") == 0)); + && (strncmp (h->root.root.string, "__tls_get_addr", 14) == 0)); case R_X86_64_GOTTPOFF: /* Check transition from IE access model: [ The above is the minimally invasive backport of upstream bfd - which incidently now has some really nice "shared bss" features ! please would the Fedora maintainers apply the above patch to make a new binutils-2.18.50.0.10.fc10 , and compile FC10's gcc with it ? Thanks, Jason. Created attachment 343959 [details] test case On FC10: $ bash -x bug9938.sh $ bash -x test_bug9938.sh | less + echo ' typedef struct { unsigned char c1, c2, c3, c4; } Struct_A_t; int f( Struct_A_t p){ return( p.c1 & p.c2 & p.c3 & p.c4); } extern int strtod( const char *); int main(int argc, char **argv, char **envp) { return f( (Struct_A_t){ .c1 = strtod(argv[1]?argv[1]:"0"), .c2=0, .c3=0, .c4 = strtod(argv[2]?argv[2]:"1") } ); }' + gcc -Wl,--verbose,-z,muldefs,--whole-archive -fPIC -o bug9938 bug9938.c ... /usr/bin/ld: /usr/lib/gcc/x86_64-redhat-linux/4.3.2/libgcc.a(bid_decimal_globals.o): TLS transition from R_X86_64_TLSGD to R_X86_64_GOTTPOFF against `__bid_IDEC_glbround' at 0x7 in section `.text' failed /usr/lib/gcc/x86_64-redhat-linux/4.3.2/libgcc.a(bid_decimal_globals.o): could not read symbols: Bad value collect2: ld returned 1 exit status On Gentoo (GCC 4.1.1 GLIBC 2.10 Linux 2.6.30-rc3 x86_64): $ ./bug9938.sh > /dev/null 2>&1 $ echo $? 0 Created attachment 343960 [details]
patch to binutils-2.18.50.0.9/bfd/elf64-x86-64.c
Created attachment 343962 [details] patch to apply bug9938.patch in binutils.spec AHA ! You do not even have to re-compile GCC to fix this bug on Fedora 10 !! not only does the patched & rebuilt binutils binutils-2.18.50.0.9-8.fc10 100% definitely fix this upstream binutils bug, but you don't even need to re-compile gcc to get the test case to pass! On my Gentoo system, I assumed "gcc must have been built with the bad binutils", so I did re-build it before testing the fix . But on Fedora, I just re-built binutils binutils-2.18.50.0.9-8.fc10 with the attached patch #1 ( bug9938.patch ) applied ; the fixed binutils solves the problem and passes the test. So for me, urgency for this bug is now off - but the only reason I raised it in the first place was for the benefit of other Fedora 10 users - particulary those who might try to use my database browser/updater generator ! So please, please could you get this binutils-only fix out in a Fedora 10 update release. Thank You, Jason My comment about the #c11 testcase was meant as an answer to the why does this code make $? == 89 ? question with the answer that the testcase is invalid and it can return anything. While it wouldn't hurt to fix this ld bug (and I'll leave that to Nick), you certainly should fix up your Makefiles, linking in libgcc.a with --whole-archive makes no sense at all, it has corresponding shared library if you want to have a shared library and linking in huge DFP objects into a binary or shared library that is never needed makes no sense at all. E.g. libgcc.a(bid_binarydecimal.o) has > 68KB of code and almost 2MB of .rodata. Yes, I know "linking in huge DFP objects into a binary or shared library that is never needed makes no sense at all" ; but, in my case, it does: my application MUST use the old static .a library linkage override mechanism, that occurs when an object in a .a provides the same definition as an object in a .so ; since my application must use dlopen(), it must ensure that ALL objects that MIGHT be required by a .so that it dlopen-ed() are linked in to the executable, and it also must guarantee that certain objects in executables will ALWAYS override certain GLIBC provided functions ( stdio, malloc ) - it is a condition of using the Daytona database system that standard IO functions are overidden the old way by objects in AT&T AST SFIO and library and that malloc / free are similarly overridden by vmalloc , and that a certain Curses implementation ( actually, the original AT&T UNIX Curses library and AT&T "Enterprise Frame System" override the system curses. and these libraries have their own functions that must be overridden in the executable in order to be used at all ), and yet must still link to modern GLIB + GTK + X-Windows . The only way I have found to guarantee the preceding is to ensure necessary objects are in my library with -Wl,-dy,--whole-archive, and to ensure that the objects that MUST override a system object are NOT in my library and are ONLY in generated executables that use my library, so the executable's symbol table will be the only one where the overridden functions are dynamically exportable . As I mentioned early in this bug report, this problem with Fedora 10 BFD occurred regardless of the presence or absence of '-Wl,--no-whole-archive' at the end of the link line. It is my understanding that putting '-Wl,--no-whole-archive' at the end of the link line cancels --whole-archive mode for any objects or libraries that are automatically appended by gcc - ie. libgcc.a - so while the bug test case does require no '--no-whole-archive' option to trigger, my original "huge link" test case does not - the bug occurs with or without the ld(1) '--no-whole-archive' option at the end of the link command line. OK, here's fixed test case script - though it does not make any actual difference as regards triggering the bug, at least it does not coredump when given certain argv contents: $ bash -x /home/jason/src/test_bug9938.sh + echo ' typedef struct { unsigned char c1, c2, c3, c4; } Struct_A_t; int f( Struct_A_t p){ return( p.c1 & p.c2 & p.c3 & p.c4); } extern int strtod( const char *, char **); int main(int argc, char **argv, char **envp) { return f( (Struct_A_t){ .c1 = strtod(argv[1]?argv[1]:"0",0), .c2=0xff, .c3=0xff, .c4 = strtod(((argc > 1)&&argv[2])?argv[2]:"1",0) } ); }' + gcc -Wl,--verbose,-z,muldefs,--whole-archive -fPIC -o bug9938 bug9938.c GNU ld (GNU Binutils) 2.19.51.20090412 Supported emulations: elf_x86_64 elf_i386 i386linux using internal linker script: ================================================== /* Script for -z combreloc: combine and sort reloc sections */ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") OUTPUT_ARCH(i386:x86-64) ENTRY(_start) ... attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/../../../../lib64/libgcc_s.so succeeded -lgcc_s (/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/../../../../lib64/libgcc_s.so) attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/crtend.o succeeded /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/crtend.o attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/../../../../lib64/crtn.o succeeded /usr/lib/gcc/x86_64-pc-linux-gnu/4.4.1/../../../../lib64/crtn.o + bug9938 Incidentally, NONE of my generated database updater/browser GUI programs ever fails to append '--no-whole-archive' to the end of the link line . The bug occurs with GUIs that use 'int f( A_Struct_t as ) ; f( (A_Struct_t){ .c1=0xff, .c4=0xff } ) ; ' where A_Struct_t contains members whose sizeof() is less than sizeof(long) . The bug test case trigger fragment DOES require NO "--no-whole-archive" to trigger on FC10. I cannot make public more details of the proprietary code linked to by my database updater programs, but I can send an encrypted link map file to interested parties if they are willing to agree to non-disclosure. Nick, any chance of getting the "strncmp(h->root.root.string, "__tls_get_addr", 14)" fix into elf32-i386.c and elf64-x86_64.c soon please ? Created attachment 344228 [details] Shell script that reproduces bug on FC10 : ./test_bug9938.sh Updated to not core dump with (on system with Fixed binutils!): $ ./bug9938 1 2 $ echo $? 0 Hi Jason, I have added a variation of your patch to the latest binutils package release (2.19.51.0.2-19) to resolve this issue. I made two changes: 1) I fixed the similar case in the elf32-i386.c file. 2) I switched from invoking the strncmp function directly to using the CONST_STRNEQ macro which was defined for exactly this kind of situation. Cheers Nick |