From 1cce69b9dc8c58884c3cc4a8928fb234294e6886 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 23 Oct 2015 22:23:05 +1030 Subject: [PATCH] Handle __start_* and __stop_* symbols in --gc-sections PR ld/11133 PR ld/19161 PR ld/19167 * elflink.c (_bfd_elf_gc_mark_hook): Delete code handling __start_* and __stop_* symbol refs. (_bfd_elf_gc_mark_rsec): Add start_stop parameter. Handle __start_* and __stop_* symbol refs here.. (_bfd_elf_gc_mark_reloc): ..and here. * elf-bfd.h (_bfd_elf_gc_mark_hook): Update prototype. * elf-eh-frame.c (_bfd_elf_parse_eh_frame): Update _bfd_elf_gc_mark_rsec call. --- bfd/ChangeLog | 14 ++++++++ bfd/elf-bfd.h | 2 +- bfd/elf-eh-frame.c | 3 +- bfd/elflink.c | 102 ++++++++++++++++++++++++++++++++++------------------- 4 files changed, 82 insertions(+), 39 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 481d972..19723d2 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -2,6 +2,20 @@ PR ld/11133 PR ld/19161 + PR ld/19167 + * elflink.c (_bfd_elf_gc_mark_hook): Delete code handling __start_* + and __stop_* symbol refs. + (_bfd_elf_gc_mark_rsec): Add start_stop parameter. Handle __start_* + and __stop_* symbol refs here.. + (_bfd_elf_gc_mark_reloc): ..and here. + * elf-bfd.h (_bfd_elf_gc_mark_hook): Update prototype. + * elf-eh-frame.c (_bfd_elf_parse_eh_frame): Update + _bfd_elf_gc_mark_rsec call. + +2015-10-23 Alan Modra + + PR ld/11133 + PR ld/19161 * elflink.c (elf_gc_sweep): Revert last patch. (_bfd_elf_gc_mark_hook): Don't set SEC_KEEP here. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index b7ca2d0..2b05089 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -2296,7 +2296,7 @@ extern asection *_bfd_elf_gc_mark_hook extern asection *_bfd_elf_gc_mark_rsec (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn, - struct elf_reloc_cookie *); + struct elf_reloc_cookie *, bfd_boolean *); extern bfd_boolean _bfd_elf_gc_mark_reloc (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn, diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 7d65dae..e303189 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -902,7 +902,8 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, REQUIRE (GET_RELOC (buf)); /* Chain together the FDEs for each section. */ - rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie); + rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, + cookie, NULL); /* RSEC will be NULL if FDE was cleared out as it was belonging to a discarded SHT_GROUP. */ if (rsec) diff --git a/bfd/elflink.c b/bfd/elflink.c index 6dcc431..1cfdd31 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -12066,8 +12066,6 @@ _bfd_elf_gc_mark_hook (asection *sec, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) { - const char *sec_name; - if (h != NULL) { switch (h->root.type) @@ -12079,33 +12077,6 @@ _bfd_elf_gc_mark_hook (asection *sec, case bfd_link_hash_common: return h->root.u.c.p->section; - case bfd_link_hash_undefined: - case bfd_link_hash_undefweak: - /* To work around a glibc bug, keep all XXX input sections - when there is an as yet undefined reference to __start_XXX - or __stop_XXX symbols. The linker will later define such - symbols for orphan input sections that have a name - representable as a C identifier. */ - if (strncmp (h->root.root.string, "__start_", 8) == 0) - sec_name = h->root.root.string + 8; - else if (strncmp (h->root.root.string, "__stop_", 7) == 0) - sec_name = h->root.root.string + 7; - else - sec_name = NULL; - - if (sec_name && *sec_name != '\0') - { - bfd *i; - - for (i = info->input_bfds; i; i = i->link.next) - { - sec = bfd_get_section_by_name (i, sec_name); - if (sec) - return sec; - } - } - break; - default: break; } @@ -12123,7 +12094,8 @@ _bfd_elf_gc_mark_hook (asection *sec, asection * _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, elf_gc_mark_hook_fn gc_mark_hook, - struct elf_reloc_cookie *cookie) + struct elf_reloc_cookie *cookie, + bfd_boolean *start_stop) { unsigned long r_symndx; struct elf_link_hash_entry *h; @@ -12152,6 +12124,38 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, handling copy relocs. */ if (h->u.weakdef != NULL) h->u.weakdef->mark = 1; + + if (start_stop != NULL + && (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak)) + { + /* To work around a glibc bug, mark all XXX input sections + when there is an as yet undefined reference to __start_XXX + or __stop_XXX symbols. The linker will later define such + symbols for orphan input sections that have a name + representable as a C identifier. */ + const char *sec_name = NULL; + if (strncmp (h->root.root.string, "__start_", 8) == 0) + sec_name = h->root.root.string + 8; + else if (strncmp (h->root.root.string, "__stop_", 7) == 0) + sec_name = h->root.root.string + 7; + + if (sec_name != NULL && *sec_name != '\0') + { + bfd *i; + + for (i = info->input_bfds; i != NULL; i = i->link.next) + { + asection *s = bfd_get_section_by_name (i, sec_name); + if (s != NULL && !s->gc_mark) + { + *start_stop = TRUE; + return s; + } + } + } + } + return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); } @@ -12170,15 +12174,39 @@ _bfd_elf_gc_mark_reloc (struct bfd_link_info *info, struct elf_reloc_cookie *cookie) { asection *rsec; + bfd_boolean start_stop = FALSE; - rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie); - if (rsec && !rsec->gc_mark) + rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie, &start_stop); + while (rsec != NULL) { - if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour - || (rsec->owner->flags & DYNAMIC) != 0) - rsec->gc_mark = 1; - else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook)) - return FALSE; + asection *s; + + if (!rsec->gc_mark) + { + if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour + || (rsec->owner->flags & DYNAMIC) != 0) + rsec->gc_mark = 1; + else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook)) + return FALSE; + } + if (!start_stop) + break; + s = bfd_get_next_section_by_name (rsec); + if (s == NULL) + { + bfd *i = rsec->owner; + + if (i != NULL) + { + while ((i = i->link.next) != NULL) + { + s = bfd_get_section_by_name (i, rsec->name); + if (s != NULL) + break; + } + } + } + rsec = s; } return TRUE; } -- 2.7.4