* 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.
This commit is contained in:
Alan Modra 2008-03-01 06:52:52 +00:00
parent c03374d554
commit 176a0d42d0
5 changed files with 238 additions and 84 deletions

View File

@ -1,3 +1,17 @@
2008-03-01 Alan Modra <amodra@bigpond.net.au>
* 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 <amodra@bigpond.net.au>
* elf32-spu.c (mark_functions_via_relocs): Don't assume that

View File

@ -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,

View File

@ -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. */

View File

@ -1,3 +1,7 @@
2008-03-01 Alan Modra <amodra@bigpond.net.au>
* ld-powerpc/relbrlt.d: Update. Also check .branch_lt section.
2008-02-27 Catherine Moore <clm@codesourcery.com>
* ld-cris/libdso-10.d: Update expected output for the Dynamic

View File

@ -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 ]*<far2far>:
0*13bf00d0 <far2far>:
[0-9a-f ]*: 4e 80 00 20 blr
\.\.\.
[0-9a-f ]*<huge>:
0*157e00d4 <huge>:
[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 .*