This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
mapping of stripped section syms
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org
- Date: Fri, 23 Mar 2012 19:56:27 +1030
- Subject: mapping of stripped section syms
FDPR sometimes gets confused due to GNU ld's stripping of empty output
sections. A recent case involved libstdc++.so and an empty
.tm_clone_table where the section symbol happened to be converted to
the .tbss section symbol. I think it's better that we convert -q
output reloc section symbols the same way fix_syms maps other symbols
in deleted sections.
I'll also be committing another patch that disables stripping of
output sections when -q is in effect, which of course makes this patch
irrelevant. However, I still think it's worth committing this change
to remove these uses of text_index_section and data_index_section,
sections that have more to do with dynamic relocs than these relocs.
* linker.c (_bfd_nearby_section): New function, split out from..
(fix_syms): ..here.
* bfd-in.h (_bfd_nearby_section): Declare.
* bfd-in2.h: Regenerate.
* elflink.c (elf_link_input_bfd): Don't use text_index_section or
data_index_section with ld -q or ld -r output relocs against
stripped output sections. Instead use _bfd_nearby_section.
Index: bfd/linker.c
===================================================================
RCS file: /cvs/src/src/bfd/linker.c,v
retrieving revision 1.92
diff -u -p -r1.92 linker.c
--- bfd/linker.c 13 Feb 2012 18:08:50 -0000 1.92
+++ bfd/linker.c 23 Mar 2012 04:32:15 -0000
@@ -3130,6 +3130,81 @@ _bfd_generic_section_already_linked (bfd
return FALSE;
}
+/* Choose a neighbouring section to S in OBFD that will be output, or
+ the absolute section if ADDR is out of bounds of the neighbours. */
+
+asection *
+_bfd_nearby_section (bfd *obfd, asection *s, bfd_vma addr)
+{
+ asection *next, *prev, *best;
+
+ /* Find preceding kept section. */
+ for (prev = s->prev; prev != NULL; prev = prev->prev)
+ if ((prev->flags & SEC_EXCLUDE) == 0
+ && !bfd_section_removed_from_list (obfd, prev))
+ break;
+
+ /* Find following kept section. Start at prev->next because
+ other sections may have been added after S was removed. */
+ if (s->prev != NULL)
+ next = s->prev->next;
+ else
+ next = s->owner->sections;
+ for (; next != NULL; next = next->next)
+ if ((next->flags & SEC_EXCLUDE) == 0
+ && !bfd_section_removed_from_list (obfd, next))
+ break;
+
+ /* Choose better of two sections, based on flags. The idea
+ is to choose a section that will be in the same segment
+ as S would have been if it was kept. */
+ best = next;
+ if (prev == NULL)
+ {
+ if (next == NULL)
+ best = bfd_abs_section_ptr;
+ }
+ else if (next == NULL)
+ best = prev;
+ else if (((prev->flags ^ next->flags)
+ & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
+ {
+ if (((next->flags ^ s->flags)
+ & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
+ /* We prefer to choose a loaded section. Section S
+ doesn't have SEC_LOAD set (it being excluded, that
+ part of the flag processing didn't happen) so we
+ can't compare that flag to those of NEXT and PREV. */
+ || ((prev->flags & SEC_LOAD) != 0
+ && (next->flags & SEC_LOAD) == 0))
+ best = prev;
+ }
+ else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0)
+ {
+ if (((next->flags ^ s->flags) & SEC_READONLY) != 0)
+ best = prev;
+ }
+ else if (((prev->flags ^ next->flags) & SEC_CODE) != 0)
+ {
+ if (((next->flags ^ s->flags) & SEC_CODE) != 0)
+ best = prev;
+ }
+ else
+ {
+ /* Flags we care about are the same. Prefer the following
+ section if that will result in a positive valued sym. */
+ if (addr < next->vma)
+ best = prev;
+ }
+
+ /* Refuse to choose a section for which we are out of bounds. */
+ /* ??? This may make most of the above moot. */
+ if (addr < best->vma || addr > best->vma + best->size)
+ best = bfd_abs_section_ptr;
+
+ return best;
+}
+
/* Convert symbols in excluded output sections to use a kept section. */
static bfd_boolean
@@ -3146,74 +3221,10 @@ fix_syms (struct bfd_link_hash_entry *h,
&& (s->output_section->flags & SEC_EXCLUDE) != 0
&& bfd_section_removed_from_list (obfd, s->output_section))
{
- asection *op, *op1;
+ asection *op;
h->u.def.value += s->output_offset + s->output_section->vma;
-
- /* Find preceding kept section. */
- for (op1 = s->output_section->prev; op1 != NULL; op1 = op1->prev)
- if ((op1->flags & SEC_EXCLUDE) == 0
- && !bfd_section_removed_from_list (obfd, op1))
- break;
-
- /* Find following kept section. Start at prev->next because
- other sections may have been added after S was removed. */
- if (s->output_section->prev != NULL)
- op = s->output_section->prev->next;
- else
- op = s->output_section->owner->sections;
- for (; op != NULL; op = op->next)
- if ((op->flags & SEC_EXCLUDE) == 0
- && !bfd_section_removed_from_list (obfd, op))
- break;
-
- /* Choose better of two sections, based on flags. The idea
- is to choose a section that will be in the same segment
- as S would have been if it was kept. */
- if (op1 == NULL)
- {
- if (op == NULL)
- op = bfd_abs_section_ptr;
- }
- else if (op == NULL)
- op = op1;
- else if (((op1->flags ^ op->flags)
- & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
- {
- if (((op->flags ^ s->flags)
- & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
- /* We prefer to choose a loaded section. Section S
- doesn't have SEC_LOAD set (it being excluded, that
- part of the flag processing didn't happen) so we
- can't compare that flag to those of OP and OP1. */
- || ((op1->flags & SEC_LOAD) != 0
- && (op->flags & SEC_LOAD) == 0))
- op = op1;
- }
- else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0)
- {
- if (((op->flags ^ s->flags) & SEC_READONLY) != 0)
- op = op1;
- }
- else if (((op1->flags ^ op->flags) & SEC_CODE) != 0)
- {
- if (((op->flags ^ s->flags) & SEC_CODE) != 0)
- op = op1;
- }
- else
- {
- /* Flags we care about are the same. Prefer the following
- section if that will result in a positive valued sym. */
- if (h->u.def.value < op->vma)
- op = op1;
- }
-
- /* Refuse to choose a section for which we are out of bounds. */
- /* ??? This may make most of the above moot. */
- if (h->u.def.value < op->vma
- || h->u.def.value > op->vma + op->size)
- op = bfd_abs_section_ptr;
-
+ op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value);
h->u.def.value -= op->vma;
h->u.def.section = op;
}
Index: bfd/bfd-in.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in.h,v
retrieving revision 1.159
diff -u -p -r1.159 bfd-in.h
--- bfd/bfd-in.h 24 Oct 2011 11:23:40 -0000 1.159
+++ bfd/bfd-in.h 23 Mar 2012 04:32:00 -0000
@@ -705,6 +705,9 @@ extern int bfd_get_sign_extend_vma
extern struct bfd_section *_bfd_elf_tls_setup
(bfd *, struct bfd_link_info *);
+extern struct bfd_section *
+_bfd_nearby_section (bfd *, struct bfd_section *, bfd_vma);
+
extern void _bfd_fix_excluded_sec_syms
(bfd *, struct bfd_link_info *);
Index: bfd/elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.433
diff -u -p -r1.433 elflink.c
--- bfd/elflink.c 8 Feb 2012 10:12:20 -0000 1.433
+++ bfd/elflink.c 23 Mar 2012 04:32:11 -0000
@@ -9747,23 +9747,12 @@ elf_link_input_bfd (struct elf_final_lin
r_symndx = osec->target_index;
if (r_symndx == STN_UNDEF)
{
- struct elf_link_hash_table *htab;
- asection *oi;
-
- htab = elf_hash_table (finfo->info);
- oi = htab->text_index_section;
- if ((osec->flags & SEC_READONLY) == 0
- && htab->data_index_section != NULL)
- oi = htab->data_index_section;
-
- if (oi != NULL)
- {
- irela->r_addend += osec->vma - oi->vma;
- r_symndx = oi->target_index;
- }
+ irela->r_addend += osec->vma;
+ osec = _bfd_nearby_section (output_bfd, osec,
+ osec->vma);
+ irela->r_addend -= osec->vma;
+ r_symndx = osec->target_index;
}
-
- BFD_ASSERT (r_symndx != STN_UNDEF);
}
}
--
Alan Modra
Australia Development Lab, IBM