From 4153b6dbb0f38a16fd5b583761aa811212fbb9a5 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 22 Mar 2016 12:25:08 +0000 Subject: [PATCH] Improve COFF/PE linker garbage collection by preventing the removal of sections containing exported symbols. PR ld/19803 * ldlang.c (lang_add_gc_name): New function. Adds the provided symbol name to the list of gc symbols. (lang_process): Call lang_add_gc_name with entry_symbol_default if entry_symbol.name is NULL. Use lang_add_gc_name to add the init and fini function names. * pe-dll.c (process_def_file_and_drectve): Add exported names to the gc symbol list. * testsuite/ld-pe/pr19803.s: Do not export _testval symbol. * testsuite/ld-pe/pr19803.d: Tweak expected output. --- ld/ChangeLog | 13 ++++++++++++ ld/ldlang.c | 49 ++++++++++++++++++++++---------------------- ld/ldlang.h | 3 +++ ld/pe-dll.c | 3 +++ ld/testsuite/ld-pe/pr19803.d | 12 ++++------- ld/testsuite/ld-pe/pr19803.s | 1 - 6 files changed, 47 insertions(+), 34 deletions(-) diff --git a/ld/ChangeLog b/ld/ChangeLog index 92a71b7..0e16f80 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,5 +1,18 @@ 2016-03-22 Nick Clifton + PR ld/19803 + * ldlang.c (lang_add_gc_name): New function. Adds the provided + symbol name to the list of gc symbols. + (lang_process): Call lang_add_gc_name with entry_symbol_default if + entry_symbol.name is NULL. Use lang_add_gc_name to add the init + and fini function names. + * pe-dll.c (process_def_file_and_drectve): Add exported names to + the gc symbol list. + * testsuite/ld-pe/pr19803.s: Do not export _testval symbol. + * testsuite/ld-pe/pr19803.d: Tweak expected output. + +2016-03-22 Nick Clifton + * configure: Regenerate. 2016-03-21 Nick Clifton diff --git a/ld/ldlang.c b/ld/ldlang.c index e6cc424..2efab24 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -6699,6 +6699,23 @@ lang_list_remove_tail (lang_statement_list_type *destlist, } #endif /* ENABLE_PLUGINS */ +/* Add NAME to the list of garbage collection entry points. */ + +void +lang_add_gc_name (const char * name) +{ + struct bfd_sym_chain *sym; + + if (name == NULL) + return; + + sym = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym)); + + sym->next = link_info.gc_sym_list; + sym->name = name; + link_info.gc_sym_list = sym; +} + void lang_process (void) { @@ -6781,6 +6798,9 @@ lang_process (void) } #endif /* ENABLE_PLUGINS */ + /* Make sure that nobody has tried to add a symbol to this list before now. */ + ASSERT (link_info.gc_sym_list == NULL); + link_info.gc_sym_list = &entry_symbol; if (entry_symbol.name == NULL) @@ -6790,37 +6810,16 @@ lang_process (void) /* entry_symbol is normally initialied by a ENTRY definition in the linker script or the -e command line option. But if neither of these have been used, the target specific backend may still have - provided an entry symbol via a call to lang_default_entry()o. + provided an entry symbol via a call to lang_default_entry(). Unfortunately this value will not be processed until lang_end() is called, long after this function has finished. So detect this case here and add the target's entry symbol to the list of starting points for garbage collection resolution. */ - if (entry_symbol_default != NULL) - { - struct bfd_sym_chain *sym - = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym)); - sym->next = link_info.gc_sym_list; - sym->name = entry_symbol_default; - link_info.gc_sym_list = sym; - } + lang_add_gc_name (entry_symbol_default); } - if (link_info.init_function != NULL) - { - struct bfd_sym_chain *sym - = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym)); - sym->next = link_info.gc_sym_list; - sym->name = link_info.init_function; - link_info.gc_sym_list = sym; - } - if (link_info.fini_function != NULL) - { - struct bfd_sym_chain *sym - = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym)); - sym->next = link_info.gc_sym_list; - sym->name = link_info.fini_function; - link_info.gc_sym_list = sym; - } + lang_add_gc_name (link_info.init_function); + lang_add_gc_name (link_info.fini_function); ldemul_after_open (); if (config.map_file != NULL) diff --git a/ld/ldlang.h b/ld/ldlang.h index c3d1185..65d768b 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -693,4 +693,7 @@ lang_ld_feature (char *); extern void lang_print_memory_usage (void); +extern void +lang_add_gc_name (const char *); + #endif diff --git a/ld/pe-dll.c b/ld/pe-dll.c index a2792e8..a280647 100644 --- a/ld/pe-dll.c +++ b/ld/pe-dll.c @@ -897,6 +897,9 @@ process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info * char *int_name = pe_def_file->exports[i].internal_name; char *name; + /* PR 19803: Make sure that any exported symbol does not get garbage collected. */ + lang_add_gc_name (int_name); + name = xmalloc (strlen (int_name) + 2); if (pe_details->underscored && int_name[0] != '@') { diff --git a/ld/testsuite/ld-pe/pr19803.d b/ld/testsuite/ld-pe/pr19803.d index 1fc6daf..d8d0c55 100644 --- a/ld/testsuite/ld-pe/pr19803.d +++ b/ld/testsuite/ld-pe/pr19803.d @@ -1,17 +1,13 @@ #ld: -shared --out-implib dx.dll.a --gc-sections #objdump: --syms -#notarget: mcore-* arm-epoc-pe +#notarget: mcore-* # -# Check that the target specific entry symbol _DllMainCRTStartup is still +# The MCORE-PE target does not support -shared. +# +# Check that the target specific entry symbol *Startup is still # a defined (sec > 0), public (scl == 2) symbol, even after garbage # collection. -# -# Check that the symbol _testval is undefined (sec == 0) and hidden -# (scl == 106) in the output. It should have been changed to this state when -# garbage collection was performed. #... -.*\(sec 0\)\(fl 0x00\)\(ty 0\)\(scl 106\) \(nx 0\) 0x0+000 _testval -#... .*\(sec 1\)\(fl 0x00\)\(ty 0\)\(scl 2\) \(nx 0\) 0x0+000 .*Startup.* #pass diff --git a/ld/testsuite/ld-pe/pr19803.s b/ld/testsuite/ld-pe/pr19803.s index 290a698..cabb87e 100644 --- a/ld/testsuite/ld-pe/pr19803.s +++ b/ld/testsuite/ld-pe/pr19803.s @@ -8,7 +8,6 @@ DllMainCRTStartup: nop .section .rdata,"dr" - .globl _testval _testval: .long 1 .long 2 -- 2.7.4