From 720194edb00c456106b98610104c8824b0b6b9a7 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 23 Oct 2006 02:35:38 +0000 Subject: [PATCH] * linker.c (fix_syms): Choose best of previous and next section based on section flags and vma. --- bfd/ChangeLog | 5 +++++ bfd/linker.c | 61 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index b99745081f5..8ab000c9e35 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,8 @@ +2006-10-23 Alan Modra + + * linker.c (fix_syms): Choose best of previous and next + section based on section flags and vma. + 2006-10-21 Kaz Kojima * elf32-sh64.c (sh64_elf_merge_symbol_attribute): Do merging diff --git a/bfd/linker.c b/bfd/linker.c index 257a585c211..8d881c60606 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; } -- 2.30.2