Index: binutils/bfd/elf64-ppc.c |
diff --git a/binutils/bfd/elf64-ppc.c b/binutils/bfd/elf64-ppc.c |
index 35757b85d5c35ab372bd7b13a4a42865e8025349..dd2809264719815701414e69be65d226aa7d75fe 100644 |
--- a/binutils/bfd/elf64-ppc.c |
+++ b/binutils/bfd/elf64-ppc.c |
@@ -1,9 +1,9 @@ |
/* PowerPC64-specific support for 64-bit ELF. |
Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, |
- 2009 Free Software Foundation, Inc. |
+ 2009, 2010 Free Software Foundation, Inc. |
Written by Linus Nordberg, Swox AB <info@swox.com>, |
based on elf32-ppc.c by Ian Lance Taylor. |
- Largely rewritten by Alan Modra <amodra@bigpond.net.au> |
+ Largely rewritten by Alan Modra. |
This file is part of BFD, the Binary File Descriptor library. |
@@ -3732,6 +3732,8 @@ struct ppc_link_hash_table |
/* Temp used when calculating TOC pointers. */ |
bfd_vma toc_curr; |
+ bfd *toc_bfd; |
+ asection *toc_first_sec; |
/* Highest input section id. */ |
int top_id; |
@@ -5401,8 +5403,6 @@ opd_entry_value (asection *opd_sec, |
/* No relocs implies we are linking a --just-symbols object. */ |
if (opd_sec->reloc_count == 0) |
{ |
- bfd_vma val; |
- |
if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8)) |
return (bfd_vma) -1; |
@@ -5866,9 +5866,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, |
for (ent = h->plt.plist; ent != NULL; ent = ent->next) |
if (ent->addend == rel->r_addend) |
break; |
- if (ent == NULL) |
- abort (); |
- if (ent->plt.refcount > 0) |
+ if (ent != NULL && ent->plt.refcount > 0) |
ent->plt.refcount -= 1; |
} |
break; |
@@ -7413,10 +7411,13 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) |
if (h != NULL) |
{ |
- if (h->root.type != bfd_link_hash_defined |
- && h->root.type != bfd_link_hash_defweak) |
+ if (h->root.type == bfd_link_hash_defined |
+ || h->root.type == bfd_link_hash_defweak) |
+ value = h->root.u.def.value; |
+ else if (h->root.type == bfd_link_hash_undefweak) |
+ value = 0; |
+ else |
continue; |
- value = h->root.u.def.value; |
} |
else |
/* Symbols referenced by TLS relocs must be of type |
@@ -7429,11 +7430,17 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) |
|| !h->def_dynamic) |
{ |
is_local = TRUE; |
- value += sym_sec->output_offset; |
- value += sym_sec->output_section->vma; |
- value -= htab->elf.tls_sec->vma; |
- ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31) |
- < (bfd_vma) 1 << 32); |
+ if (h != NULL |
+ && h->root.type == bfd_link_hash_undefweak) |
+ ok_tprel = TRUE; |
+ else |
+ { |
+ value += sym_sec->output_offset; |
+ value += sym_sec->output_section->vma; |
+ value -= htab->elf.tls_sec->vma; |
+ ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31) |
+ < (bfd_vma) 1 << 32); |
+ } |
} |
r_type = ELF64_R_TYPE (rel->r_info); |
@@ -8575,8 +8582,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, |
for (ent = *local_plt; ent != NULL; ent = ent->next) |
if (ent->plt.refcount > 0) |
{ |
- asection *s = htab->iplt; |
- |
+ s = htab->iplt; |
ent->plt.offset = s->size; |
s->size += PLT_ENTRY_SIZE; |
@@ -9608,6 +9614,8 @@ ppc64_elf_setup_section_lists (bfd *output_bfd, |
htab->stub_group[id].toc_off = TOC_BASE_OFF; |
elf_gp (output_bfd) = htab->toc_curr = ppc64_elf_toc (output_bfd); |
+ htab->toc_bfd = NULL; |
+ htab->toc_first_sec = NULL; |
/* We can't use output_bfd->section_count here to find the top output |
section index as some sections may have been removed, and |
@@ -9642,11 +9650,21 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec) |
if (!htab->no_multi_toc) |
{ |
- bfd_vma addr = isec->output_offset + isec->output_section->vma; |
- bfd_vma off = addr - htab->toc_curr; |
+ bfd_vma addr, off; |
+ if (htab->toc_bfd != isec->owner) |
+ { |
+ htab->toc_bfd = isec->owner; |
+ htab->toc_first_sec = isec; |
+ } |
+ addr = isec->output_offset + isec->output_section->vma; |
+ off = addr - htab->toc_curr; |
if (off + isec->size > 0x10000) |
- htab->toc_curr = addr; |
+ { |
+ addr = (htab->toc_first_sec->output_offset |
+ + htab->toc_first_sec->output_section->vma); |
+ htab->toc_curr = addr; |
+ } |
elf_gp (isec->owner) = (htab->toc_curr |
- elf_gp (isec->output_section->owner) |
@@ -11018,37 +11036,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
if (tls_mask != 0 |
&& (tls_mask & TLS_TPREL) == 0) |
{ |
- bfd_vma rtra; |
insn = bfd_get_32 (output_bfd, contents + rel->r_offset); |
- if ((insn & ((0x3f << 26) | (31 << 11))) |
- == ((31 << 26) | (13 << 11))) |
- rtra = insn & ((1 << 26) - (1 << 16)); |
- else if ((insn & ((0x3f << 26) | (31 << 16))) |
- == ((31 << 26) | (13 << 16))) |
- rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5); |
- else |
+ insn = _bfd_elf_ppc_at_tls_transform (insn, 13); |
+ if (insn == 0) |
abort (); |
- if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1) |
- /* add -> addi. */ |
- insn = 14 << 26; |
- else if ((insn & (31 << 1)) == 23 << 1 |
- && ((insn & (31 << 6)) < 14 << 6 |
- || ((insn & (31 << 6)) >= 16 << 6 |
- && (insn & (31 << 6)) < 24 << 6))) |
- /* load and store indexed -> dform. */ |
- insn = (32 | ((insn >> 6) & 31)) << 26; |
- else if ((insn & (31 << 1)) == 21 << 1 |
- && (insn & (0x1a << 6)) == 0) |
- /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ |
- insn = (((58 | ((insn >> 6) & 4)) << 26) |
- | ((insn >> 6) & 1)); |
- else if ((insn & (31 << 1)) == 21 << 1 |
- && (insn & ((1 << 11) - (1 << 1))) == 341 << 1) |
- /* lwax -> lwa. */ |
- insn = (58 << 26) | 2; |
- else |
- abort (); |
- insn |= rtra; |
bfd_put_32 (output_bfd, insn, contents + rel->r_offset); |
/* Was PPC64_TLS which sits on insn boundary, now |
PPC64_TPREL16_LO which is at low-order half-word. */ |
@@ -11129,8 +11120,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
insn1 |= 58 << 26; /* ld */ |
insn2 = 0x7c636a14; /* add 3,3,13 */ |
if (offset != (bfd_vma) -1) |
- rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info), |
- R_PPC64_NONE); |
+ rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); |
if ((tls_mask & TLS_EXPLICIT) == 0) |
r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) |
+ R_PPC64_GOT_TPREL16_DS); |
@@ -11229,8 +11219,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
rel->r_info = ELF64_R_INFO (r_symndx, r_type); |
/* Zap the reloc on the _tls_get_addr call too. */ |
BFD_ASSERT (offset == rel[1].r_offset); |
- rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info), |
- R_PPC64_NONE); |
+ rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); |
insn3 = bfd_get_32 (output_bfd, |
contents + offset + 4); |
if (insn3 == NOP |
@@ -11275,8 +11264,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
rel->r_offset = offset + d_offset; |
/* Zap the reloc on the _tls_get_addr call too. */ |
BFD_ASSERT (offset == rel[1].r_offset); |
- rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info), |
- R_PPC64_NONE); |
+ rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE); |
insn2 = 0x38630000; /* addi 3,3,0 */ |
insn3 = bfd_get_32 (output_bfd, |
contents + offset + 4); |
@@ -11533,6 +11521,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
checking whether the function is defined. */ |
else if (h != NULL |
&& h->elf.root.type == bfd_link_hash_undefweak |
+ && h->elf.dynindx == -1 |
&& r_type == R_PPC64_REL24 |
&& relocation == 0 |
&& addend == 0) |
@@ -11770,10 +11759,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
if (off >= (bfd_vma) -2) |
abort (); |
- relocation = got->output_offset + off; |
- |
- /* TOC base (r2) is TOC start plus 0x8000. */ |
- addend = -TOC_BASE_OFF; |
+ relocation = got->output_section->vma + got->output_offset + off; |
+ addend = -(TOCstart + htab->stub_group[input_section->id].toc_off); |
} |
break; |
@@ -11868,6 +11855,22 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
case R_PPC64_TPREL16_HIGHERA: |
case R_PPC64_TPREL16_HIGHEST: |
case R_PPC64_TPREL16_HIGHESTA: |
+ if (h != NULL |
+ && h->elf.root.type == bfd_link_hash_undefweak |
+ && h->elf.dynindx == -1) |
+ { |
+ /* Make this relocation against an undefined weak symbol |
+ resolve to zero. This is really just a tweak, since |
+ code using weak externs ought to check that they are |
+ defined before using them. */ |
+ bfd_byte *p = contents + rel->r_offset - d_offset; |
+ |
+ insn = bfd_get_32 (output_bfd, p); |
+ insn = _bfd_elf_ppc_at_tprel_transform (insn, 13); |
+ if (insn != 0) |
+ bfd_put_32 (output_bfd, insn, p); |
+ break; |
+ } |
addend -= htab->elf.tls_sec->vma + TP_OFFSET; |
if (info->shared) |
/* The TPREL16 relocs shouldn't really be used in shared |
@@ -11950,10 +11953,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
? h->elf.type == STT_GNU_IFUNC |
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))) |
{ |
- Elf_Internal_Rela outrel; |
bfd_boolean skip, relocate; |
asection *sreloc; |
- bfd_byte *loc; |
bfd_vma out_off; |
/* When generating a dynamic object, these relocations |
@@ -12414,9 +12415,6 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, |
if (h->needs_copy) |
{ |
- Elf_Internal_Rela rela; |
- bfd_byte *loc; |
- |
/* This symbol needs a copy reloc. Set it up. */ |
if (h->dynindx == -1 |