aboutsummaryrefslogtreecommitdiff
path: root/bfd/linker.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2006-10-23 02:35:38 +0000
committerAlan Modra <amodra@gmail.com>2006-10-23 02:35:38 +0000
commit720194edb00c456106b98610104c8824b0b6b9a7 (patch)
tree4a62dfcff064836405dfc334dc6ef1da99932f89 /bfd/linker.c
parent75ee0d67f2df26f6d6f3fbb8d8d5017b1f003c84 (diff)
downloadgdb-720194edb00c456106b98610104c8824b0b6b9a7.zip
gdb-720194edb00c456106b98610104c8824b0b6b9a7.tar.gz
gdb-720194edb00c456106b98610104c8824b0b6b9a7.tar.bz2
* linker.c (fix_syms): Choose best of previous and next
section based on section flags and vma.
Diffstat (limited to 'bfd/linker.c')
-rw-r--r--bfd/linker.c61
1 files changed, 49 insertions, 12 deletions
diff --git a/bfd/linker.c b/bfd/linker.c
index 257a585..8d881c6 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -3092,25 +3092,62 @@ fix_syms (struct bfd_link_hash_entry *h, void *data)
&& (s->output_section->flags & SEC_EXCLUDE) != 0
&& bfd_section_removed_from_list (obfd, s->output_section))
{
- asection *op;
- for (op = s->output_section->prev; op != NULL; op = op->prev)
+ asection *op, *op1;
+
+ 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;
- if (op == NULL)
+
+ /* 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 (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;
if (op == NULL)
op = bfd_abs_section_ptr;
}
- h->u.def.value += s->output_offset + s->output_section->vma;
+ else if (op == NULL)
+ op = op1;
+ else if (((op1->flags ^ op->flags)
+ & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0)
+ {
+ if (((op->flags ^ s->flags)
+ & (SEC_ALLOC | SEC_THREAD_LOCAL)) != 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;
+ }
+
h->u.def.value -= op->vma;
h->u.def.section = op;
}