diff options
-rw-r--r-- | bfd/ChangeLog | 5 | ||||
-rw-r--r-- | bfd/elf32-cris.c | 56 |
2 files changed, 57 insertions, 4 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index ad5228e..d4902da 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,8 @@ +2012-06-18 Hans-Peter Nilsson <hp@axis.com> + + * elf32-cris.c (cris_elf_plt_sym_val): Rewrite to work in presence + of merged .got and .got.plt entries. + 2012-06-18 John Szakmeister <john@szakmeister.net> * elf32-arm.c (elf32_arm_final_link_relocate): Correct return value. diff --git a/bfd/elf32-cris.c b/bfd/elf32-cris.c index 3710d47..58e430e 100644 --- a/bfd/elf32-cris.c +++ b/bfd/elf32-cris.c @@ -2719,16 +2719,64 @@ cris_elf_gc_sweep_hook (bfd *abfd, /* The elf_backend_plt_sym_val hook function. */ static bfd_vma -cris_elf_plt_sym_val (bfd_vma i, const asection *plt, - const arelent *rel ATTRIBUTE_UNUSED) +cris_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED, const asection *plt, + const arelent *rel) { bfd_size_type plt_entry_size; + bfd_size_type pltoffs; + bfd *abfd = plt->owner; + /* Same for CRIS and CRIS v32; see elf_cris_(|pic_)plt_entry(|_v32)[]. */ + bfd_size_type plt_entry_got_offset = 2; + bfd_size_type plt_sec_size; + bfd_size_type got_vma_for_dyn; + asection *got; + + /* FIXME: the .got section should be readily available also when + we're not linking. */ + if ((got = bfd_get_section_by_name (abfd, ".got")) == NULL) + return (bfd_vma) -1; + + plt_sec_size = bfd_section_size (plt->owner, plt); plt_entry_size - = (bfd_get_mach (plt->owner) == bfd_mach_cris_v32 + = (bfd_get_mach (abfd) == bfd_mach_cris_v32 ? PLT_ENTRY_SIZE_V32 : PLT_ENTRY_SIZE); - return plt->vma + (i + 1) * plt_entry_size; + /* Data in PLT is GOT-relative for DYN, but absolute for EXE. */ + got_vma_for_dyn = (abfd->flags & EXEC_P) ? 0 : got->vma; + + /* Because we can have merged GOT entries; a single .got entry for + both GOT and the PLT part of the GOT (.got.plt), the index of the + reloc in .rela.plt is not the same as the index in the PLT. + Instead, we have to hunt down the GOT offset in the PLT that + corresponds to that of this reloc. Unfortunately, we will only + be called for the .rela.plt relocs, so we'll miss synthetic + symbols for .plt entries with merged GOT entries. (FIXME: + fixable by providing our own bfd_elf32_get_synthetic_symtab. + Doesn't seem worthwile at time of this writing.) FIXME: we've + gone from O(1) to O(N) (N number of PLT entries) for finding each + PLT address. Shouldn't matter in practice though. */ + + for (pltoffs = plt_entry_size; + pltoffs < plt_sec_size; + pltoffs += plt_entry_size) + { + bfd_size_type got_offset; + bfd_byte gotoffs_raw[4]; + + if (!bfd_get_section_contents (abfd, (asection *) plt, gotoffs_raw, + pltoffs + plt_entry_got_offset, + sizeof (gotoffs_raw))) + return (bfd_vma) -1; + + got_offset = bfd_get_32 (abfd, gotoffs_raw); + if (got_offset + got_vma_for_dyn == rel->address) + return plt->vma + pltoffs; + } + + /* While it's tempting to BFD_ASSERT that we shouldn't get here, + that'd not be graceful behavior for invalid input. */ + return (bfd_vma) -1; } /* Make sure we emit a GOT entry if the symbol was supposed to have a PLT |