From 176a0d42d0d0a1e4957bb5bf3f5186dc6669a6e7 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sat, 1 Mar 2008 06:52:52 +0000 Subject: [PATCH] bfd/ * elf64-ppc.c (build_plt_stub): Add relocs on plt call stubs if emitrelocations. (get_relocs): New function, split out from.. (ppc_build_one_stub): ..here. Add relocs on plt_branch stubs if emitrelocations. Remove indx temp. (ppc_size_one_stub): Count new stub relocs. (ppc64_elf_size_stubs): Count new glink reloc. (ppc64_elf_build_stubs): Emit glink reloc if emitrelocations. (ppc64_elf_finish_dynamic_sections): Output glink relocs. * elf32-ppc.c (ppc_elf_finish_dynamic_sections): Describe non-pic glink code. ld/testsuite/ * ld-powerpc/relbrlt.d: Update. Also check .branch_lt section. --- bfd/ChangeLog | 14 ++ bfd/elf32-ppc.c | 24 ++- bfd/elf64-ppc.c | 262 +++++++++++++++++++++--------- ld/testsuite/ChangeLog | 4 + ld/testsuite/ld-powerpc/relbrlt.d | 18 +- 5 files changed, 238 insertions(+), 84 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 15b939d5863..2589b5ded74 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2008-03-01 Alan Modra + + * elf64-ppc.c (build_plt_stub): Add relocs on plt call stubs + if emitrelocations. + (get_relocs): New function, split out from.. + (ppc_build_one_stub): ..here. Add relocs on plt_branch stubs if + emitrelocations. Remove indx temp. + (ppc_size_one_stub): Count new stub relocs. + (ppc64_elf_size_stubs): Count new glink reloc. + (ppc64_elf_build_stubs): Emit glink reloc if emitrelocations. + (ppc64_elf_finish_dynamic_sections): Output glink relocs. + * elf32-ppc.c (ppc_elf_finish_dynamic_sections): Describe non-pic + glink code. + 2008-02-28 Alan Modra * elf32-spu.c (mark_functions_via_relocs): Don't assume that diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 5e81a2f20e1..47a2e79169f 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -7534,7 +7534,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, * bctr * * # A table of branches, one for each plt entry. - * # The idea is that the plt call stub loads ctr (and r11) with these + * # The idea is that the plt call stub loads ctr and r11 with these * # addresses, so (r11 - res_0) gives the plt index * 4. * res_0: b PLTresolve * res_1: b PLTresolve @@ -7580,6 +7580,28 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, NOP }; + /* + * Non-PIC glink code is a little simpler. + * + * # ith PLT code stub. + * lis 11,(plt+(i-1)*4)@ha + * lwz 11,(plt+(i-1)*4)@l(11) + * mtctr 11 + * bctr + * + * The branch table is the same, then comes + * + * PLTresolve: + * lis 12,(got+4)@ha + * addis 11,11,(-res_0)@ha + * lwz 0,(got+4)@l(12) # got[1] address of dl_runtime_resolve + * addi 11,11,(-res_0)@l # r11 = index * 4 + * mtctr 0 + * add 0,11,11 + * lwz 12,(got+8)@l(12) # got[2] contains the map address + * add 11,0,11 # r11 = index * 12 = reloc offset. + * bctr + */ static const unsigned int plt_resolve[] = { LIS_12, diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 4b98acb9bb3..a1968245abf 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -8245,7 +8245,7 @@ ppc_type_of_stub (asection *input_sec, /* Build a .plt call stub. */ static inline bfd_byte * -build_plt_stub (bfd *obfd, bfd_byte *p, int offset) +build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r) { #define PPC_LO(v) ((v) & 0xffff) #define PPC_HI(v) (((v) >> 16) & 0xffff) @@ -8253,6 +8253,28 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset) if (PPC_HA (offset) != 0) { + if (r != NULL) + { + r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA); + r[1].r_offset = r[0].r_offset + 8; + r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); + r[1].r_addend = r[0].r_addend; + if (PPC_HA (offset + 16) != PPC_HA (offset)) + { + r[2].r_offset = r[1].r_offset + 4; + r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO); + r[2].r_addend = r[0].r_addend; + } + else + { + r[2].r_offset = r[1].r_offset + 8; + r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); + r[2].r_addend = r[0].r_addend + 8; + r[3].r_offset = r[2].r_offset + 4; + r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); + r[3].r_addend = r[0].r_addend + 16; + } + } bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4; @@ -8268,6 +8290,26 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset) } else { + if (r != NULL) + { + r[0].r_offset += 4; + r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); + if (PPC_HA (offset + 16) != PPC_HA (offset)) + { + r[1].r_offset = r[0].r_offset + 4; + r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16); + r[1].r_addend = r[0].r_addend; + } + else + { + r[1].r_offset = r[0].r_offset + 8; + r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); + r[1].r_addend = r[0].r_addend + 16; + r[2].r_offset = r[1].r_offset + 4; + r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); + r[2].r_addend = r[0].r_addend + 8; + } + } bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset), p), p += 4; if (PPC_HA (offset + 16) != PPC_HA (offset)) @@ -8283,6 +8325,32 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset) return p; } +static Elf_Internal_Rela * +get_relocs (asection *sec, int count) +{ + Elf_Internal_Rela *relocs; + struct bfd_elf_section_data *elfsec_data; + + elfsec_data = elf_section_data (sec); + relocs = elfsec_data->relocs; + if (relocs == NULL) + { + bfd_size_type relsize; + relsize = sec->reloc_count * sizeof (*relocs); + relocs = bfd_alloc (sec->owner, relsize); + if (relocs == NULL) + return NULL; + elfsec_data->relocs = relocs; + elfsec_data->rel_hdr.sh_size = (sec->reloc_count + * sizeof (Elf64_External_Rela)); + elfsec_data->rel_hdr.sh_entsize = sizeof (Elf64_External_Rela); + sec->reloc_count = 0; + } + relocs += sec->reloc_count; + sec->reloc_count += count; + return relocs; +} + static bfd_boolean ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) { @@ -8292,10 +8360,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) struct ppc_link_hash_table *htab; bfd_byte *loc; bfd_byte *p; - unsigned int indx; struct plt_entry *ent; bfd_vma dest, off; int size; + Elf_Internal_Rela *r; /* Massage our args to the form they really have. */ stub_entry = (struct ppc_stub_hash_entry *) gen_entry; @@ -8354,26 +8422,9 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (info->emitrelocations) { - Elf_Internal_Rela *relocs, *r; - struct bfd_elf_section_data *elfsec_data; - - elfsec_data = elf_section_data (stub_entry->stub_sec); - relocs = elfsec_data->relocs; - if (relocs == NULL) - { - bfd_size_type relsize; - relsize = stub_entry->stub_sec->reloc_count * sizeof (*relocs); - relocs = bfd_alloc (htab->stub_bfd, relsize); - if (relocs == NULL) - return FALSE; - elfsec_data->relocs = relocs; - elfsec_data->rel_hdr.sh_size = (stub_entry->stub_sec->reloc_count - * sizeof (Elf64_External_Rela)); - elfsec_data->rel_hdr.sh_entsize = sizeof (Elf64_External_Rela); - stub_entry->stub_sec->reloc_count = 0; - } - r = relocs + stub_entry->stub_sec->reloc_count; - stub_entry->stub_sec->reloc_count += 1; + r = get_relocs (stub_entry->stub_sec, 1); + if (r == NULL) + return FALSE; r->r_offset = loc - stub_entry->stub_sec->contents; r->r_info = ELF64_R_INFO (0, R_PPC64_REL24); r->r_addend = dest; @@ -8428,11 +8479,11 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } - off = (stub_entry->target_value - + stub_entry->target_section->output_offset - + stub_entry->target_section->output_section->vma); + dest = (stub_entry->target_value + + stub_entry->target_section->output_offset + + stub_entry->target_section->output_section->vma); - bfd_put_64 (htab->brlt->owner, off, + bfd_put_64 (htab->brlt->owner, dest, htab->brlt->contents + br_entry->offset); if (br_entry->iter == htab->stub_iteration) @@ -8449,7 +8500,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) + htab->brlt->output_offset + htab->brlt->output_section->vma); rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); - rela.r_addend = off; + rela.r_addend = dest; rl = htab->relbrlt->contents; rl += (htab->relbrlt->reloc_count++ @@ -8458,39 +8509,26 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } else if (info->emitrelocations) { - Elf_Internal_Rela *relocs, *r; - struct bfd_elf_section_data *elfsec_data; - - elfsec_data = elf_section_data (htab->brlt); - relocs = elfsec_data->relocs; - if (relocs == NULL) - { - bfd_size_type relsize; - relsize = htab->brlt->reloc_count * sizeof (*relocs); - relocs = bfd_alloc (htab->brlt->owner, relsize); - if (relocs == NULL) - return FALSE; - elfsec_data->relocs = relocs; - elfsec_data->rel_hdr.sh_size - = (stub_entry->stub_sec->reloc_count - * sizeof (Elf64_External_Rela)); - elfsec_data->rel_hdr.sh_entsize - = sizeof (Elf64_External_Rela); - htab->brlt->reloc_count = 0; - } - r = relocs + htab->brlt->reloc_count; - htab->brlt->reloc_count += 1; + r = get_relocs (htab->brlt, 1); + if (r == NULL) + return FALSE; + /* brlt, being SEC_LINKER_CREATED does not go through the + normal reloc processing. Symbols and offsets are not + translated from input file to output file form, so + set up the offset per the output file. */ r->r_offset = (br_entry->offset + htab->brlt->output_offset + htab->brlt->output_section->vma); r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); - r->r_addend = off; + r->r_addend = dest; } } - off = (br_entry->offset - + htab->brlt->output_offset - + htab->brlt->output_section->vma + dest = (br_entry->offset + + htab->brlt->output_offset + + htab->brlt->output_section->vma); + + off = (dest - elf_gp (htab->brlt->output_section->owner) - htab->stub_group[stub_entry->id_sec->id].toc_off); @@ -8504,20 +8542,38 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } - indx = off; + if (info->emitrelocations) + { + r = get_relocs (stub_entry->stub_sec, 1 + (PPC_HA (off) != 0)); + if (r == NULL) + return FALSE; + r[0].r_offset = loc - stub_entry->stub_sec->contents; + if (stub_entry->stub_type == ppc_stub_plt_branch_r2off) + r[0].r_offset += 4; + r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); + r[0].r_addend = dest; + if (PPC_HA (off) != 0) + { + r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA); + r[1].r_offset = r[0].r_offset + 4; + r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); + r[1].r_addend = r[0].r_addend; + } + } + if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) { - if (PPC_HA (indx) != 0) + if (PPC_HA (off) != 0) { size = 16; - bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc); + bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); loc += 4; - bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc); + bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc); } else { size = 12; - bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (indx), loc); + bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc); } } else @@ -8529,17 +8585,17 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc); loc += 4; size = 20; - if (PPC_HA (indx) != 0) + if (PPC_HA (off) != 0) { size += 4; - bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc); + bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); loc += 4; - bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc); + bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc); loc += 4; } else { - bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (indx), loc); + bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc); loc += 4; } @@ -8576,21 +8632,23 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } /* Now build the stub. */ - off = (bfd_vma) -1; + dest = (bfd_vma) -1; for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next) if (ent->addend == stub_entry->addend) { - off = ent->plt.offset; + dest = ent->plt.offset; break; } - if (off >= (bfd_vma) -2) + if (dest >= (bfd_vma) -2) abort (); - off &= ~ (bfd_vma) 1; - off += (htab->plt->output_offset - + htab->plt->output_section->vma - - elf_gp (htab->plt->output_section->owner) - - htab->stub_group[stub_entry->id_sec->id].toc_off); + dest &= ~ (bfd_vma) 1; + dest += (htab->plt->output_offset + + htab->plt->output_section->vma); + + off = (dest + - elf_gp (htab->plt->output_section->owner) + - htab->stub_group[stub_entry->id_sec->id].toc_off); if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) { @@ -8602,7 +8660,18 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; } - p = build_plt_stub (htab->stub_bfd, loc, off); + r = NULL; + if (info->emitrelocations) + { + r = get_relocs (stub_entry->stub_sec, + (2 + (PPC_HA (off) != 0) + + (PPC_HA (off + 16) == PPC_HA (off)))); + if (r == NULL) + return FALSE; + r[0].r_offset = loc - stub_entry->stub_sec->contents; + r[0].r_addend = dest; + } + p = build_plt_stub (htab->stub_bfd, loc, off, r); size = p - loc; break; @@ -8692,6 +8761,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) size -= 4; if (PPC_HA (off + 16) != PPC_HA (off)) size += 4; + if (info->emitrelocations) + { + stub_entry->stub_sec->reloc_count + += 2 + (PPC_HA (off) != 0) + (PPC_HA (off + 16) == PPC_HA (off)); + stub_entry->stub_sec->flags |= SEC_RELOC; + } } else { @@ -8726,7 +8801,6 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (off + (1 << 25) >= (bfd_vma) (1 << 26)) { struct ppc_branch_hash_entry *br_entry; - unsigned int indx; br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table, stub_entry->root.string + 9, @@ -8761,17 +8835,22 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) - elf_gp (htab->brlt->output_section->owner) - htab->stub_group[stub_entry->id_sec->id].toc_off); - indx = off; + if (info->emitrelocations) + { + stub_entry->stub_sec->reloc_count += 1 + (PPC_HA (off) != 0); + stub_entry->stub_sec->flags |= SEC_RELOC; + } + if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) { size = 12; - if (PPC_HA (indx) != 0) + if (PPC_HA (off) != 0) size = 16; } else { size = 20; - if (PPC_HA (indx) != 0) + if (PPC_HA (off) != 0) size += 4; if (PPC_HA (r2off) != 0) @@ -9584,6 +9663,13 @@ ppc64_elf_size_stubs (bfd *output_bfd, bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info); + if (info->emitrelocations + && htab->glink != NULL && htab->glink->size != 0) + { + htab->glink->reloc_count = 1; + htab->glink->flags |= SEC_RELOC; + } + for (stub_sec = htab->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) @@ -9720,12 +9806,19 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, h->non_elf = 0; } } + plt0 = htab->plt->output_section->vma + htab->plt->output_offset - 16; + if (info->emitrelocations) + { + Elf_Internal_Rela *r = get_relocs (htab->glink, 1); + if (r == NULL) + return FALSE; + r->r_offset = (htab->glink->output_offset + + htab->glink->output_section->vma); + r->r_info = ELF64_R_INFO (0, R_PPC64_REL64); + r->r_addend = plt0; + } p = htab->glink->contents; - plt0 = (htab->plt->output_section->vma - + htab->plt->output_offset - - (htab->glink->output_section->vma - + htab->glink->output_offset - + 16)); + plt0 -= htab->glink->output_section->vma + htab->glink->output_offset; bfd_put_64 (htab->glink->owner, plt0, p); p += 8; bfd_put_32 (htab->glink->owner, MFLR_R12, p); @@ -11583,6 +11676,15 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, NULL)) return FALSE; + if (htab->glink != NULL + && htab->glink->reloc_count != 0 + && !_bfd_elf_link_output_relocs (output_bfd, + htab->glink, + &elf_section_data (htab->glink)->rel_hdr, + elf_section_data (htab->glink)->relocs, + NULL)) + return FALSE; + /* We need to handle writing out multiple GOT sections ourselves, since we didn't add them to DYNOBJ. We know dynobj is the first bfd. */ diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 1687ba0d18f..91eb52f99d1 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2008-03-01 Alan Modra + + * ld-powerpc/relbrlt.d: Update. Also check .branch_lt section. + 2008-02-27 Catherine Moore * ld-cris/libdso-10.d: Update expected output for the Dynamic diff --git a/ld/testsuite/ld-powerpc/relbrlt.d b/ld/testsuite/ld-powerpc/relbrlt.d index 172c60f7981..69321ebd3ae 100644 --- a/ld/testsuite/ld-powerpc/relbrlt.d +++ b/ld/testsuite/ld-powerpc/relbrlt.d @@ -1,7 +1,7 @@ #source: relbrlt.s #as: -a64 #ld: -melf64ppc --emit-relocs -#objdump: -dr +#objdump: -Dr .*: file format elf64-powerpc @@ -23,6 +23,7 @@ Disassembly of section \.text: [0-9a-f ]*<.*plt_branch.*>: [0-9a-f ]*: e9 62 80 00 ld r11,-32768\(r2\) +[0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f00d8 [0-9a-f ]*: 7d 69 03 a6 mtctr r11 [0-9a-f ]*: 4e 80 04 20 bctr @@ -32,6 +33,7 @@ Disassembly of section \.text: [0-9a-f ]*<.*plt_branch.*>: [0-9a-f ]*: e9 62 80 08 ld r11,-32760\(r2\) +[0-9a-f ]*: R_PPC64_TOC16_DS \*ABS\*\+0x157f00e0 [0-9a-f ]*: 7d 69 03 a6 mtctr r11 [0-9a-f ]*: 4e 80 04 20 bctr \.\.\. @@ -40,9 +42,19 @@ Disassembly of section \.text: [0-9a-f ]*: 4e 80 00 20 blr \.\.\. -[0-9a-f ]*: +0*13bf00d0 : [0-9a-f ]*: 4e 80 00 20 blr \.\.\. -[0-9a-f ]*: +0*157e00d4 : [0-9a-f ]*: 4e 80 00 20 blr + +Disassembly of section \.branch_lt: + +0*157f00d8 <\.branch_lt>: +[0-9a-f ]*: 00 00 00 00 .* +[0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x13bf00d0 +[0-9a-f ]*: 13 bf 00 d0 .* +[0-9a-f ]*: 00 00 00 00 .* +[0-9a-f ]*: R_PPC64_RELATIVE \*ABS\*\+0x157e00d4 +[0-9a-f ]*: 15 7e 00 d4 .* -- 2.30.2