diff options
author | Sandra Loosemore <sandra@codesourcery.com> | 2014-02-02 10:57:52 -0800 |
---|---|---|
committer | Sandra Loosemore <sandra@codesourcery.com> | 2014-02-02 10:57:52 -0800 |
commit | 82e9153868751875375955cf3de10f6e008ec6ae (patch) | |
tree | ef42d2a657195899a32e427e3496097179fe02da /bfd/elf32-nios2.c | |
parent | 13075d049d492477dfbf795c305adbab5abb6d81 (diff) | |
download | gdb-82e9153868751875375955cf3de10f6e008ec6ae.zip gdb-82e9153868751875375955cf3de10f6e008ec6ae.tar.gz gdb-82e9153868751875375955cf3de10f6e008ec6ae.tar.bz2 |
Correct Nios II GOT pointer initialization.
2014-02-02 Sandra Loosemore <sandra@codesourcery.com>
bfd/
* elf32-nios2.c (struct elf32_nios2_link_hash_table): Add
h_gp_got field.
(nios2_elf32_relocate_section): Use got_base to adjust
GOT-pointer-relative relocations relative to _gp_got.
(create_got_section): Create _gp_got symbol.
(nios2_elf32_finish_dynamic_symbol): Make _gp_got absolute.
(nios2_elf32_size_dynamic_sections): Set _gp_got offset.
Diffstat (limited to 'bfd/elf32-nios2.c')
-rw-r--r-- | bfd/elf32-nios2.c | 57 |
1 files changed, 43 insertions, 14 deletions
diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c index ba76898..dbe5289 100644 --- a/bfd/elf32-nios2.c +++ b/bfd/elf32-nios2.c @@ -892,6 +892,9 @@ struct elf32_nios2_link_hash_table asection *srelbss; asection *sbss; + /* GOT pointer symbol _gp_got. */ + struct elf_link_hash_entry *h_gp_got; + union { bfd_signed_vma refcount; bfd_vma offset; @@ -2671,6 +2674,7 @@ nios2_elf32_relocate_section (bfd *output_bfd, asection *splt; asection *sreloc = NULL; bfd_vma *local_got_offsets; + bfd_vma got_base; symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); @@ -2681,6 +2685,11 @@ nios2_elf32_relocate_section (bfd *output_bfd, splt = htab->root.splt; local_got_offsets = elf_local_got_offsets (input_bfd); + if (elf32_nios2_hash_table (info)->h_gp_got == NULL) + got_base = 0; + else + got_base = elf32_nios2_hash_table (info)->h_gp_got->root.u.def.value; + for (rel = relocs; rel < relend; rel++) { reloc_howto_type *howto; @@ -3026,10 +3035,11 @@ nios2_elf32_relocate_section (bfd *output_bfd, if (use_plt && info->shared) { off = ((h->plt.offset - 24) / 12 + 3) * 4; - relocation = htab->root.sgotplt->output_offset + off; + relocation = (htab->root.sgotplt->output_offset + off + - got_base); } else - relocation = sgot->output_offset + off; + relocation = sgot->output_offset + off - got_base; /* This relocation does not use the addend. */ rel->r_addend = 0; @@ -3042,8 +3052,7 @@ nios2_elf32_relocate_section (bfd *output_bfd, case R_NIOS2_GOTOFF_LO: case R_NIOS2_GOTOFF_HA: case R_NIOS2_GOTOFF: - /* Relocation is relative to the start of the - global offset table. */ + /* Relocation is relative to the global offset table pointer. */ BFD_ASSERT (sgot != NULL); if (sgot == NULL) @@ -3052,12 +3061,10 @@ nios2_elf32_relocate_section (bfd *output_bfd, break; } - /* Note that sgot->output_offset is not involved in this - calculation. We always want the start of .got. If we - define _GLOBAL_OFFSET_TABLE in a different way, as is - permitted by the ABI, we might have to change this - calculation. */ - relocation -= sgot->output_section->vma; + /* Adjust the relocation to be relative to the GOT pointer. */ + relocation -= (sgot->output_section->vma + + sgot->output_offset - got_base); + switch (howto->type) { case R_NIOS2_GOTOFF_LO: @@ -3127,7 +3134,7 @@ nios2_elf32_relocate_section (bfd *output_bfd, htab->tls_ldm_got.offset |= 1; } - relocation = (htab->root.sgot->output_offset + off); + relocation = htab->root.sgot->output_offset + off - got_base; r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, @@ -3284,7 +3291,7 @@ nios2_elf32_relocate_section (bfd *output_bfd, if ((tls_type & GOT_TLS_GD) && r_type != R_NIOS2_TLS_GD16) off += 8; - relocation = (htab->root.sgot->output_offset + off); + relocation = htab->root.sgot->output_offset + off - got_base; r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, @@ -3489,6 +3496,7 @@ static bfd_boolean create_got_section (bfd *dynobj, struct bfd_link_info *info) { struct elf32_nios2_link_hash_table *htab; + struct elf_link_hash_entry *h; htab = elf32_nios2_hash_table (info); @@ -3500,6 +3508,16 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info) if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt, 4)) return FALSE; + /* The Nios II ABI specifies that GOT-relative relocations are relative + to the linker-created symbol _gp_got, rather than using + _GLOBAL_OFFSET_TABLE_ directly. In particular, the latter always + points to the base of the GOT while _gp_got may include a bias. */ + h = _bfd_elf_define_linkage_sym (dynobj, info, htab->root.sgotplt, + "_gp_got"); + elf32_nios2_hash_table (info)->h_gp_got = h; + if (h == NULL) + return FALSE; + return TRUE; } @@ -4178,9 +4196,10 @@ nios2_elf32_finish_dynamic_symbol (bfd *output_bfd, bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); } - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ + /* Mark _DYNAMIC, _GLOBAL_OFFSET_TABLE_, and _gp_got as absolute. */ if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || h == elf_hash_table (info)->hgot) + || h == elf_hash_table (info)->hgot + || h == elf32_nios2_hash_table (info)->h_gp_got) sym->st_shndx = SHN_ABS; return TRUE; @@ -4846,6 +4865,16 @@ nios2_elf32_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, sym dynamic relocs. */ elf_link_hash_traverse (& htab->root, allocate_dynrelocs, info); + if (elf_hash_table (info)->dynamic_sections_created) + { + /* If the .got section is more than 0x8000 bytes, we add + 0x8000 to the value of _gp_got, so that 16-bit relocations + have a greater chance of working. */ + if (htab->root.sgot->size >= 0x8000 + && elf32_nios2_hash_table (info)->h_gp_got->root.u.def.value == 0) + elf32_nios2_hash_table (info)->h_gp_got->root.u.def.value = 0x8000; + } + /* The check_relocs and adjust_dynamic_symbol entry points have determined the sizes of the various dynamic sections. Allocate memory for them. */ |