/* PowerPC64-specific support for 64-bit ELF.
- Copyright (C) 1999-2017 Free Software Foundation, Inc.
+ Copyright (C) 1999-2018 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.
#define LD_R11_0R11 0xe96b0000 /* ld %r11,xxx+16@l(%r11) */
#define BCTR 0x4e800420 /* bctr */
-#define ADDI_R11_R11 0x396b0000 /* addi %r11,%r11,off@l */
-#define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */
-#define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */
+#define ADDI_R11_R11 0x396b0000 /* addi %r11,%r11,off@l */
+#define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */
+#define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */
-#define XOR_R2_R12_R12 0x7d826278 /* xor %r2,%r12,%r12 */
-#define ADD_R11_R11_R2 0x7d6b1214 /* add %r11,%r11,%r2 */
-#define XOR_R11_R12_R12 0x7d8b6278 /* xor %r11,%r12,%r12 */
-#define ADD_R2_R2_R11 0x7c425a14 /* add %r2,%r2,%r11 */
-#define CMPLDI_R2_0 0x28220000 /* cmpldi %r2,0 */
-#define BNECTR 0x4ca20420 /* bnectr+ */
-#define BNECTR_P4 0x4ce20420 /* bnectr+ */
+#define XOR_R2_R12_R12 0x7d826278 /* xor %r2,%r12,%r12 */
+#define ADD_R11_R11_R2 0x7d6b1214 /* add %r11,%r11,%r2 */
+#define XOR_R11_R12_R12 0x7d8b6278 /* xor %r11,%r12,%r12 */
+#define ADD_R2_R2_R11 0x7c425a14 /* add %r2,%r2,%r11 */
+#define CMPLDI_R2_0 0x28220000 /* cmpldi %r2,0 */
+#define BNECTR 0x4ca20420 /* bnectr+ */
+#define BNECTR_P4 0x4ce20420 /* bnectr+ */
#define LD_R12_0R2 0xe9820000 /* ld %r12,xxx+0(%r2) */
#define LD_R11_0R2 0xe9620000 /* ld %r11,xxx+0(%r2) */
-#define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */
+#define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */
-#define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */
-#define LD_R2_0R12 0xe84c0000 /* ld %r2,0(%r12) */
-#define ADD_R2_R2_R12 0x7c426214 /* add %r2,%r2,%r12 */
+#define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */
+#define LD_R2_0R12 0xe84c0000 /* ld %r2,0(%r12) */
+#define ADD_R2_R2_R12 0x7c426214 /* add %r2,%r2,%r12 */
-#define LIS_R2 0x3c400000 /* lis %r2,xxx@ha */
+#define LIS_R2 0x3c400000 /* lis %r2,xxx@ha */
#define ADDIS_R2_R12 0x3c4c0000 /* addis %r2,%r12,xxx@ha */
#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */
#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */
-#define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */
+#define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */
-/* glink call stub instructions. We enter with the index in R0. */
-#define GLINK_CALL_STUB_SIZE (16*4)
+/* __glink_PLTresolve stub instructions. We enter with the index in R0. */
+#define GLINK_PLTRESOLVE_SIZE(htab) \
+ (8u + (htab->opd_abi ? 11 * 4 : 14 * 4))
/* 0: */
/* .quad plt0-1f */
/* __glink: */
static const struct bfd_elf_special_section ppc64_elf_special_sections[]=
{
- { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, 0 },
- { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, 0 },
+ { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
- { STRING_COMMA_LEN (".toc"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
- { STRING_COMMA_LEN (".toc1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".toc"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".toc1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
{ STRING_COMMA_LEN (".tocbss"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
- { NULL, 0, 0, 0, 0 }
+ { NULL, 0, 0, 0, 0 }
};
enum _ppc64_sec_type {
if (dyn.d_tag == DT_PPC64_GLINK)
{
- /* The first glink stub starts at offset 32; see
- comment in ppc64_elf_finish_dynamic_sections. */
- glink_vma = dyn.d_un.d_val + GLINK_CALL_STUB_SIZE - 8 * 4;
+ /* The first glink stub starts at DT_PPC64_GLINK plus 32.
+ See comment in ppc64_elf_finish_dynamic_sections. */
+ glink_vma = dyn.d_un.d_val + 8 * 4;
/* The .glink section usually does not survive the final
link; search for the section (usually .text) where the
glink stubs now reside. */
/* Track dynamic relocs copied for this symbol. */
struct elf_dyn_relocs *dyn_relocs;
- /* Chain of aliases referring to a weakdef. */
- struct ppc_link_hash_entry *weakref;
-
/* Link between function code and descriptor symbols. */
struct ppc_link_hash_entry *oh;
/* Shortcuts to get to dynamic linker sections. */
asection *glink;
+ asection *global_entry;
asection *sfpr;
asection *brlt;
asection *relbrlt;
|| ! bfd_set_section_alignment (dynobj, htab->glink, 3))
return FALSE;
+ /* The part of .glink used by global entry stubs, separate so that
+ it can be aligned appropriately without affecting htab->glink. */
+ htab->global_entry = bfd_make_section_anyway_with_flags (dynobj, ".glink",
+ flags);
+ if (htab->global_entry == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->global_entry, 2))
+ return FALSE;
+
if (!info->no_ld_generated_unwind_info)
{
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
if (eind->oh != NULL)
edir->oh = ppc_follow_link (eind->oh);
- /* If called to transfer flags for a weakdef during processing
- of elf_adjust_dynamic_symbol, don't copy NON_GOT_REF.
- We clear it ourselves for ELIMINATE_COPY_RELOCS. */
- if (!(ELIMINATE_COPY_RELOCS
- && eind->elf.root.type != bfd_link_hash_indirect
- && edir->elf.dynamic_adjusted))
- edir->elf.non_got_ref |= eind->elf.non_got_ref;
-
if (edir->elf.versioned != versioned_hidden)
edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
edir->elf.ref_regular |= eind->elf.ref_regular;
edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
+ edir->elf.non_got_ref |= eind->elf.non_got_ref;
edir->elf.needs_plt |= eind->elf.needs_plt;
edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed;
in order to simplify readonly_dynrelocs and save a field in the
symbol hash entry, but that means dyn_relocs can't be used in any
tests about a specific symbol, or affect other symbol flags which
- are then tested.
- Chain weakdefs so we can get from the weakdef back to an alias.
- The list is circular so that we don't need to use u.weakdef as
- well as this list to look at all aliases. */
+ are then tested. */
if (eind->elf.root.type != bfd_link_hash_indirect)
- {
- struct ppc_link_hash_entry *cur, *add, *next;
-
- add = eind;
- do
- {
- cur = edir->weakref;
- if (cur != NULL)
- {
- do
- {
- /* We can be called twice for the same symbols.
- Don't make multiple loops. */
- if (cur == add)
- return;
- cur = cur->weakref;
- } while (cur != edir);
- }
- next = add->weakref;
- if (cur != add)
- {
- add->weakref = edir->weakref != NULL ? edir->weakref : edir;
- edir->weakref = add;
- }
- add = next;
- } while (add != NULL && add != eind);
- return;
- }
+ return;
/* Copy over any dynamic relocs we may have on the indirect sym. */
if (eind->dyn_relocs != NULL)
len = strlen (name);
dot_name = bfd_alloc (abfd, len + 2);
if (dot_name == NULL)
- return (struct elf_link_hash_entry *) 0 - 1;
+ return (struct elf_link_hash_entry *) -1;
dot_name[0] = '.';
memcpy (dot_name + 1, name, len + 1);
h = _bfd_elf_archive_symbol_lookup (abfd, info, dot_name);
h = NULL;
else
{
- struct ppc_link_hash_entry *eh;
-
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
h = elf_follow_link (h);
- eh = (struct ppc_link_hash_entry *) h;
-
- /* PR15323, ref flags aren't set for references in the same
- object. */
- h->root.non_ir_ref_regular = 1;
- if (eh->is_func && eh->oh != NULL)
- eh->oh->elf.root.non_ir_ref_regular = 1;
if (h == htab->elf.hgot)
sec->has_toc_reloc = 1;
if ((eh->elf.root.type == bfd_link_hash_defined
|| eh->elf.root.type == bfd_link_hash_defweak)
- && (eh->elf.ref_dynamic
+ && ((eh->elf.ref_dynamic && !eh->elf.forced_local)
|| ((eh->elf.def_regular || ELF_COMMON_DEF_P (&eh->elf))
&& ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
&& ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN
a call reloc. Mark the function descriptor too
against garbage collection. */
fdh->elf.mark = 1;
- if (fdh->elf.u.weakdef != NULL)
- fdh->elf.u.weakdef->mark = 1;
+ if (fdh->elf.is_weakalias)
+ weakdef (&fdh->elf)->mark = 1;
eh = fdh;
}
}
/* Return true if we have dynamic relocs against H or any of its weak
- aliases, that apply to read-only sections. */
+ aliases, that apply to read-only sections. Cannot be used after
+ size_dynamic_sections. */
static bfd_boolean
alias_readonly_dynrelocs (struct elf_link_hash_entry *h)
{
if (readonly_dynrelocs (&eh->elf))
return TRUE;
- eh = eh->weakref;
+ eh = (struct ppc_link_hash_entry *) eh->elf.u.alias;
} while (eh != NULL && &eh->elf != h);
return FALSE;
extra work in ld.so when resolving these symbols. */
if (global_entry_stub (h))
{
- if (!alias_readonly_dynrelocs (h))
+ if (!readonly_dynrelocs (h))
{
h->pointer_equality_needed = 0;
/* If we haven't seen a branch reloc then we don't need
return TRUE;
}
else if (!h->needs_plt
- && !alias_readonly_dynrelocs (h))
+ && !readonly_dynrelocs (h))
{
/* If we haven't seen a branch reloc then we don't need a
plt entry. */
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (h->u.weakdef != NULL)
- {
- BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
- || h->u.weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->u.weakdef->root.u.def.section;
- h->root.u.def.value = h->u.weakdef->root.u.def.value;
- if (ELIMINATE_COPY_RELOCS)
- h->non_got_ref = h->u.weakdef->non_got_ref;
+ if (h->is_weakalias)
+ {
+ struct elf_link_hash_entry *def = weakdef (h);
+ BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+ h->root.u.def.section = def->root.u.def.section;
+ h->root.u.def.value = def->root.u.def.value;
+ if (def->root.u.def.section == htab->elf.sdynbss
+ || def->root.u.def.section == htab->elf.sdynrelro)
+ ((struct ppc_link_hash_entry *) h)->dyn_relocs = NULL;
return TRUE;
}
/* If -z nocopyreloc was given, don't generate them either. */
|| info->nocopyreloc
- /* If we didn't find any dynamic relocs in read-only sections, then
+ /* If we don't find any dynamic relocs in read-only sections, then
we'll be keeping the dynamic relocs and avoiding the copy reloc. */
|| (ELIMINATE_COPY_RELOCS && !alias_readonly_dynrelocs (h))
determine the address it must put in the global offset table, so
both the dynamic object and the regular object will refer to the
same memory location for the variable. */
-
- /* We must generate a R_PPC64_COPY reloc to tell the dynamic linker
- to copy the initial value out of the dynamic object and into the
- runtime process image. We need to remember the offset into the
- .rela.bss section we are going to use. */
if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
{
s = htab->elf.sdynrelro;
}
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
{
+ /* We must generate a R_PPC64_COPY reloc to tell the dynamic
+ linker to copy the initial value out of the dynamic object
+ and into the runtime process image. */
srel->size += sizeof (Elf64_External_Rela);
h->needs_copy = 1;
}
/* Make room for the .glink code. */
s = htab->glink;
if (s->size == 0)
- s->size += GLINK_CALL_STUB_SIZE;
+ s->size += GLINK_PLTRESOLVE_SIZE (htab);
if (htab->opd_abi)
{
/* We need bigger stubs past index 32767. */
- if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4)
+ if (s->size >= GLINK_PLTRESOLVE_SIZE (htab) + 32768*2*4)
s->size += 4;
s->size += 2*4;
}
return TRUE;
}
+#define PPC_LO(v) ((v) & 0xffff)
+#define PPC_HI(v) (((v) >> 16) & 0xffff)
+#define PPC_HA(v) PPC_HI ((v) + 0x8000)
+
/* Called via elf_link_hash_traverse from ppc64_elf_size_dynamic_sections
to set up space for global entry stubs. These are put in glink,
after the branch table. */
struct bfd_link_info *info;
struct ppc_link_hash_table *htab;
struct plt_entry *pent;
- asection *s;
+ asection *s, *plt;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
if (htab == NULL)
return FALSE;
- s = htab->glink;
+ s = htab->global_entry;
+ plt = htab->elf.splt;
for (pent = h->plt.plist; pent != NULL; pent = pent->next)
if (pent->plt.offset != (bfd_vma) -1
&& pent->addend == 0)
and we are not generating a shared library or pie, then we
need to define the symbol in the executable on a call stub.
This is to avoid text relocations. */
- s->size = (s->size + 15) & -16;
+ bfd_vma off, stub_align, stub_off, stub_size;
+ unsigned int align_power;
+
+ stub_size = 16;
+ stub_off = s->size;
+ if (htab->params->plt_stub_align >= 0)
+ align_power = htab->params->plt_stub_align;
+ else
+ align_power = -htab->params->plt_stub_align;
+ /* Setting section alignment is delayed until we know it is
+ non-empty. Otherwise the .text output section will be
+ aligned at least to plt_stub_align even when no global
+ entry stubs are needed. */
+ if (s->alignment_power < align_power)
+ s->alignment_power = align_power;
+ stub_align = (bfd_vma) 1 << align_power;
+ if (htab->params->plt_stub_align >= 0
+ || ((((stub_off + stub_size - 1) & -stub_align)
+ - (stub_off & -stub_align))
+ > ((stub_size - 1) & -stub_align)))
+ stub_off = (stub_off + stub_align - 1) & -stub_align;
+ off = pent->plt.offset + plt->output_offset + plt->output_section->vma;
+ off -= stub_off + s->output_offset + s->output_section->vma;
+ /* Note that for --plt-stub-align negative we have a possible
+ dependency between stub offset and size. Break that
+ dependency by assuming the max stub size when calculating
+ the stub offset. */
+ if (PPC_HA (off) == 0)
+ stub_size -= 4;
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = s;
- h->root.u.def.value = s->size;
- s->size += 16;
+ h->root.u.def.value = stub_off;
+ s->size = stub_off + stub_size;
break;
}
return TRUE;
info->flags |= DF_TEXTREL;
info->callbacks->minfo
- (_("%B: dynamic relocation in read-only section `%A'\n"),
- sec->owner, sec);
+ (_("%B: dynamic relocation against `%T' in read-only section `%A'\n"),
+ sec->owner, h->root.root.string, sec);
/* Not an error, just cut short the traversal. */
return FALSE;
/* Allocate global sym .plt and .got entries, and space for global
sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
- /* Stash the end of glink branch table. */
- if (htab->glink != NULL)
- htab->glink->rawsize = htab->glink->size;
if (!htab->opd_abi && !bfd_link_pic (info))
elf_link_hash_traverse (&htab->elf, size_global_entry_stubs, info);
|| s == htab->elf.splt
|| s == htab->elf.iplt
|| s == htab->glink
+ || s == htab->global_entry
|| s == htab->elf.sdynbss
|| s == htab->elf.sdynrelro)
{
continue;
}
+ if (bfd_is_abs_section (s->output_section))
+ _bfd_error_handler (_("warning: discarding dynamic section %s"),
+ s->name);
+
if ((s->flags & SEC_HAS_CONTENTS) == 0)
continue;
#define ALWAYS_USE_FAKE_DEP 0
#define ALWAYS_EMIT_R2SAVE 0
-#define PPC_LO(v) ((v) & 0xffff)
-#define PPC_HI(v) (((v) >> 16) & 0xffff)
-#define PPC_HA(v) PPC_HI ((v) + 0x8000)
-
static inline unsigned int
plt_stub_size (struct ppc_link_hash_table *htab,
struct ppc_stub_hash_entry *stub_entry,
bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab))
/ PLT_ENTRY_SIZE (htab));
- bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8;
+ bfd_vma glinkoff = GLINK_PLTRESOLVE_SIZE (htab) + pltindex * 8;
bfd_vma to, from;
if (pltindex > 32768)
bfd_byte *loc;
bfd_byte *p;
bfd_vma dest, off;
- int size;
Elf_Internal_Rela *r;
asection *plt;
+ stub_entry->group->stub_sec->output_offset
+ stub_entry->group->stub_sec->output_section->vma);
- size = 4;
+ p = loc;
if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
{
bfd_vma r2off = get_r2off (info, stub_entry);
htab->stub_error = TRUE;
return FALSE;
}
- bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
- loc += 4;
- size = 8;
+ bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
+ p += 4;
if (PPC_HA (r2off) != 0)
{
bfd_put_32 (htab->params->stub_bfd,
- ADDIS_R2_R2 | PPC_HA (r2off), loc);
- loc += 4;
- size += 4;
+ ADDIS_R2_R2 | PPC_HA (r2off), p);
+ p += 4;
}
if (PPC_LO (r2off) != 0)
{
bfd_put_32 (htab->params->stub_bfd,
- ADDI_R2_R2 | PPC_LO (r2off), loc);
- loc += 4;
- size += 4;
+ ADDI_R2_R2 | PPC_LO (r2off), p);
+ p += 4;
}
- off -= size - 4;
+ off -= p - loc;
}
- bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
+ bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), p);
+ p += 4;
if (off + (1 << 25) >= (bfd_vma) (1 << 26))
{
r = get_relocs (stub_entry->group->stub_sec, 1);
if (r == NULL)
return FALSE;
- r->r_offset = loc - stub_entry->group->stub_sec->contents;
+ r->r_offset = p - 4 - stub_entry->group->stub_sec->contents;
r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
r->r_addend = dest;
if (stub_entry->h != NULL)
+ htab->brlt->output_section->vma);
off = (dest
- - elf_gp (htab->brlt->output_section->owner)
+ - elf_gp (info->output_bfd)
- htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
}
}
+ p = loc;
if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
{
if (PPC_HA (off) != 0)
{
- size = 16;
bfd_put_32 (htab->params->stub_bfd,
- ADDIS_R12_R2 | PPC_HA (off), loc);
- loc += 4;
+ ADDIS_R12_R2 | PPC_HA (off), p);
+ p += 4;
bfd_put_32 (htab->params->stub_bfd,
- LD_R12_0R12 | PPC_LO (off), loc);
+ LD_R12_0R12 | PPC_LO (off), p);
}
else
- {
- size = 12;
- bfd_put_32 (htab->params->stub_bfd,
- LD_R12_0R2 | PPC_LO (off), loc);
- }
+ bfd_put_32 (htab->params->stub_bfd,
+ LD_R12_0R2 | PPC_LO (off), p);
}
else
{
return FALSE;
}
- bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
- loc += 4;
- size = 16;
+ bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p);
+ p += 4;
if (PPC_HA (off) != 0)
{
- size += 4;
bfd_put_32 (htab->params->stub_bfd,
- ADDIS_R12_R2 | PPC_HA (off), loc);
- loc += 4;
+ ADDIS_R12_R2 | PPC_HA (off), p);
+ p += 4;
bfd_put_32 (htab->params->stub_bfd,
- LD_R12_0R12 | PPC_LO (off), loc);
+ LD_R12_0R12 | PPC_LO (off), p);
}
else
- bfd_put_32 (htab->params->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc);
+ bfd_put_32 (htab->params->stub_bfd, LD_R12_0R2 | PPC_LO (off), p);
if (PPC_HA (r2off) != 0)
{
- size += 4;
- loc += 4;
+ p += 4;
bfd_put_32 (htab->params->stub_bfd,
- ADDIS_R2_R2 | PPC_HA (r2off), loc);
+ ADDIS_R2_R2 | PPC_HA (r2off), p);
}
if (PPC_LO (r2off) != 0)
{
- size += 4;
- loc += 4;
+ p += 4;
bfd_put_32 (htab->params->stub_bfd,
- ADDI_R2_R2 | PPC_LO (r2off), loc);
+ ADDI_R2_R2 | PPC_LO (r2off), p);
}
}
- loc += 4;
- bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, loc);
- loc += 4;
- bfd_put_32 (htab->params->stub_bfd, BCTR, loc);
+ p += 4;
+ bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p);
+ p += 4;
+ bfd_put_32 (htab->params->stub_bfd, BCTR, p);
+ p += 4;
break;
case ppc_stub_plt_call:
}
off = (dest
- - elf_gp (plt->output_section->owner)
+ - elf_gp (info->output_bfd)
- htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r);
else
p = build_plt_stub (htab, stub_entry, loc, off, r);
- size = p - loc;
break;
case ppc_stub_save_res:
return FALSE;
}
- stub_entry->group->stub_sec->size += size;
+ stub_entry->group->stub_sec->size += p - loc;
if (htab->params->emit_stub_syms)
{
plt = htab->elf.iplt;
off += (plt->output_offset
+ plt->output_section->vma
- - elf_gp (plt->output_section->owner)
+ - elf_gp (info->output_bfd)
- htab->sec_info[stub_entry->group->link_sec->id].toc_off);
size = plt_stub_size (htab, stub_entry, off);
off = (br_entry->offset
+ htab->brlt->output_offset
+ htab->brlt->output_section->vma
- - elf_gp (htab->brlt->output_section->owner)
+ - elf_gp (info->output_bfd)
- htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (info->emitrelocations)
output toc base plus 0x8000. Making the input elf_gp an
offset allows us to move the toc as a whole without
recalculating input elf_gp. */
- off = htab->toc_curr - elf_gp (isec->output_section->owner);
+ off = htab->toc_curr - elf_gp (info->output_bfd);
off += TOC_BASE_OFF;
/* Die if someone uses a linker script that doesn't keep input
}
addr = (htab->toc_first_sec->output_offset
+ htab->toc_first_sec->output_section->vma);
- off = addr - elf_gp (isec->output_section->owner) + TOC_BASE_OFF;
+ off = addr - elf_gp (info->output_bfd) + TOC_BASE_OFF;
elf_gp (isec->owner) = off;
return TRUE;
stub_sec->flags &= ~SEC_RELOC;
}
+ if (htab->stub_iteration <= STUB_SHRINK_ITER
+ || htab->brlt->rawsize < htab->brlt->size)
+ htab->brlt->rawsize = htab->brlt->size;
htab->brlt->size = 0;
htab->brlt->reloc_count = 0;
htab->brlt->flags &= ~SEC_RELOC;
if (htab->glink_eh_frame != NULL
&& !bfd_is_abs_section (htab->glink_eh_frame->output_section)
- && htab->glink_eh_frame->output_section->size != 0)
+ && htab->glink_eh_frame->output_section->size > 8)
{
size_t size = 0, align = 4;
if (htab->params->plt_stub_align != 0)
for (group = htab->group; group != NULL; group = group->next)
if (group->stub_sec != NULL)
- group->stub_sec->size = ((group->stub_sec->size
- + (1 << htab->params->plt_stub_align) - 1)
- & -(1 << htab->params->plt_stub_align));
+ {
+ int align = abs (htab->params->plt_stub_align);
+ group->stub_sec->size
+ = (group->stub_sec->size + (1 << align) - 1) & -(1 << align);
+ }
for (group = htab->group; group != NULL; group = group->next)
if (group->stub_sec != NULL
break;
if (group == NULL
+ && (htab->brlt->rawsize == htab->brlt->size
+ || (htab->stub_iteration > STUB_SHRINK_ITER
+ && htab->brlt->rawsize > htab->brlt->size))
&& (htab->glink_eh_frame == NULL
|| htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size))
break;
if (htab == NULL)
return FALSE;
- s = htab->glink;
+ s = htab->global_entry;
for (pent = h->plt.plist; pent != NULL; pent = pent->next)
if (pent->plt.offset != (bfd_vma) -1
&& pent->addend == 0)
}
bfd_put_32 (htab->glink->owner, BCTR, p);
p += 4;
- while (p - htab->glink->contents < GLINK_CALL_STUB_SIZE)
- {
- bfd_put_32 (htab->glink->owner, NOP, p);
- p += 4;
- }
+ BFD_ASSERT (p == htab->glink->contents + GLINK_PLTRESOLVE_SIZE (htab));
/* Build the .glink lazy link call stubs. */
indx = 0;
- while (p < htab->glink->contents + htab->glink->rawsize)
+ while (p < htab->glink->contents + htab->glink->size)
{
if (htab->opd_abi)
{
indx++;
p += 4;
}
-
- /* Build .glink global entry stubs. */
- if (htab->glink->size > htab->glink->rawsize)
- elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
}
+ /* Build .glink global entry stubs. */
+ if (htab->global_entry != NULL && htab->global_entry->size != 0)
+ elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info);
+
if (htab->brlt != NULL && htab->brlt->size != 0)
{
htab->brlt->contents = bfd_zalloc (htab->brlt->owner,
if (htab->params->plt_stub_align != 0)
for (group = htab->group; group != NULL; group = group->next)
if ((stub_sec = group->stub_sec) != NULL)
- stub_sec->size = ((stub_sec->size
- + (1 << htab->params->plt_stub_align) - 1)
- & -(1 << htab->params->plt_stub_align));
+ {
+ int align = abs (htab->params->plt_stub_align);
+ stub_sec->size = (stub_sec->size + (1 << align) - 1) & -(1 << align);
+ }
for (group = htab->group; group != NULL; group = group->next)
if ((stub_sec = group->stub_sec) != NULL)
/* Multi-instruction sequences that access the TOC can be
optimized, eg. addis ra,r2,0; addi rb,ra,x;
- to nop; addi rb,r2,x; */
- howto = ppc64_elf_howto_table[(int) r_type];
+ to nop; addi rb,r2,x; */
switch (r_type)
{
default:
{
bfd_byte *p = contents + (rel->r_offset & ~3);
bfd_put_32 (input_bfd, NOP, p);
+ goto copy_reloc;
}
break;
/* xgettext:c-format */
info->callbacks->minfo
(_("%H: warning: %s unexpected insn %#x.\n"),
- input_bfd, input_section, rel->r_offset, howto->name, insn);
+ input_bfd, input_section, rel->r_offset,
+ ppc64_elf_howto_table[r_type]->name, insn);
else
- bfd_put_32 (input_bfd, NOP, p);
+ {
+ bfd_put_32 (input_bfd, NOP, p);
+ goto copy_reloc;
+ }
}
break;
/* xgettext:c-format */
(_("%H: error: %s not a multiple of %u\n"),
input_bfd, input_section, rel->r_offset,
- howto->name,
+ ppc64_elf_howto_table[r_type]->name,
mask + 1);
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
/* Dynamic relocs are not propagated for SEC_DEBUGGING sections
because such sections are not SEC_ALLOC and thus ld.so will
not process them. */
+ howto = ppc64_elf_howto_table[(int) r_type];
if (unresolved_reloc
&& !((input_section->flags & SEC_DEBUGGING) != 0
&& h->elf.def_dynamic)
of glink rather than the first entry point, which is
what ld.so needs, and now have a bigger stub to
support automatic multiple TOCs. */
- dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 8 * 4;
+ dyn.d_un.d_ptr += GLINK_PLTRESOLVE_SIZE (htab) - 8 * 4;
break;
case DT_PPC64_OPD: