aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2015-10-23 22:23:05 +1030
committerAlan Modra <amodra@gmail.com>2015-10-23 22:26:25 +1030
commit1cce69b9dc8c58884c3cc4a8928fb234294e6886 (patch)
treead6bb7d70a998457311dd8034c00df20b11699d4 /bfd
parentbe83aa76d2877770c23d7c2bde0319564a8f7e48 (diff)
downloadfsf-binutils-gdb-1cce69b9dc8c58884c3cc4a8928fb234294e6886.zip
fsf-binutils-gdb-1cce69b9dc8c58884c3cc4a8928fb234294e6886.tar.gz
fsf-binutils-gdb-1cce69b9dc8c58884c3cc4a8928fb234294e6886.tar.bz2
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.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog14
-rw-r--r--bfd/elf-bfd.h2
-rw-r--r--bfd/elf-eh-frame.c3
-rw-r--r--bfd/elflink.c102
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 <amodra@gmail.com>
+
+ 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;
}