diff options
author | Alan Modra <amodra@gmail.com> | 2012-03-23 09:27:43 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2012-03-23 09:27:43 +0000 |
commit | 051d833a41cabf1bcc879756756901deb6b1c448 (patch) | |
tree | 2cb969716e76459261953767f3ea4df56e29462d | |
parent | 62599110be4d6baae772ce8022801f06137495b9 (diff) | |
download | gdb-051d833a41cabf1bcc879756756901deb6b1c448.zip gdb-051d833a41cabf1bcc879756756901deb6b1c448.tar.gz gdb-051d833a41cabf1bcc879756756901deb6b1c448.tar.bz2 |
* 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.
-rw-r--r-- | bfd/ChangeLog | 10 | ||||
-rw-r--r-- | bfd/bfd-in.h | 3 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 3 | ||||
-rw-r--r-- | bfd/elflink.c | 21 | ||||
-rw-r--r-- | bfd/linker.c | 143 |
5 files changed, 98 insertions, 82 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 854beee..c59bb4c 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,15 @@ 2012-03-23 Alan Modra <amodra@gmail.com> + * 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. + +2012-03-23 Alan Modra <amodra@gmail.com> + PR binutils/13894 * elf64-ppc.c (opd_entry_value): Read full symbol table when sym hashes unavailable. diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index 40ed786..c331f3b 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -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 *); diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index bea3a05..61513f2 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -712,6 +712,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 *); diff --git a/bfd/elflink.c b/bfd/elflink.c index 7f9ec60..3236911 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -9747,23 +9747,12 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) 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); } } diff --git a/bfd/linker.c b/bfd/linker.c index 0404474..2f8ecbb 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -3130,6 +3130,81 @@ _bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED, 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, void *data) && (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; } |