#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
-#include "elf/ppc.h"
#include "elf/ppc64.h"
#include "elf64-ppc.h"
stub_name = bfd_malloc (len);
if (stub_name != NULL)
{
- sprintf (stub_name, "%08x_%s+%x",
+ sprintf (stub_name, "%08x.%s+%x",
input_section->id & 0xffffffff,
h->elf.root.root.string,
(int) rel->r_addend & 0xffffffff);
stub_name = bfd_malloc (len);
if (stub_name != NULL)
{
- sprintf (stub_name, "%08x_%x:%x+%x",
+ sprintf (stub_name, "%08x.%x:%x+%x",
input_section->id & 0xffffffff,
sym_sec->id & 0xffffffff,
(int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
/* Copy the extra info we tack onto an elf_link_hash_entry. */
static void
-ppc64_elf_copy_indirect_symbol (struct elf_backend_data *bed ATTRIBUTE_UNUSED,
- struct elf_link_hash_entry *dir,
- struct elf_link_hash_entry *ind)
+ppc64_elf_copy_indirect_symbol
+ (const struct elf_backend_data *bed ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry *dir,
+ struct elf_link_hash_entry *ind)
{
struct ppc_link_hash_entry *edir, *eind;
flagword mask;
return TRUE;
}
+/* Find the function descriptor hash entry from the given function code
+ hash entry FH. Link the entries via their OH fields. */
+static struct ppc_link_hash_entry *
+get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
+{
+ struct ppc_link_hash_entry *fdh = (struct ppc_link_hash_entry *) fh->oh;
+
+ if (fdh == NULL)
+ {
+ const char *fd_name = fh->elf.root.root.string + 1;
+
+ fdh = (struct ppc_link_hash_entry *)
+ elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
+ if (fdh != NULL)
+ {
+ fdh->is_func_descriptor = 1;
+ fdh->oh = &fh->elf;
+ fh->is_func = 1;
+ fh->oh = &fdh->elf;
+ }
+ }
+
+ return fdh;
+}
+
/* Look through the relocs for a section during the first phase, and
calculate needed space in the global offset table, procedure
linkage table, and dynamic reloc sections. */
&& h != NULL
&& h->root.root.string[0] == '.'
&& h->root.root.string[1] != 0)
- {
- struct elf_link_hash_entry *fdh;
+ get_fdh ((struct ppc_link_hash_entry *) h, htab);
- fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
- FALSE, FALSE, FALSE);
- if (fdh != NULL)
- {
- ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
- ((struct ppc_link_hash_entry *) fdh)->oh = h;
- ((struct ppc_link_hash_entry *) h)->is_func = 1;
- ((struct ppc_link_hash_entry *) h)->oh = fdh;
- }
- }
if (opd_sym_map != NULL
&& h == NULL
&& rel + 1 < rel_end
struct bfd_link_info *info;
struct ppc_link_hash_table *htab;
struct plt_entry *ent;
+ struct ppc_link_hash_entry *fh;
+ struct ppc_link_hash_entry *fdh;
+ bfd_boolean force_local;
- if (h->root.type == bfd_link_hash_indirect)
+ fh = (struct ppc_link_hash_entry *) h;
+ if (fh->elf.root.type == bfd_link_hash_indirect)
return TRUE;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ if (fh->elf.root.type == bfd_link_hash_warning)
+ fh = (struct ppc_link_hash_entry *) fh->elf.root.u.i.link;
info = inf;
htab = ppc_hash_table (info);
/* If this is a function code symbol, transfer dynamic linking
information to the function descriptor symbol. */
- if (!((struct ppc_link_hash_entry *) h)->is_func)
+ if (!fh->is_func)
return TRUE;
- if (h->root.type == bfd_link_hash_undefweak
- && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
+ if (fh->elf.root.type == bfd_link_hash_undefweak
+ && (fh->elf.elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR))
htab->have_undefweak = TRUE;
- for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0)
break;
- if (ent != NULL
- && h->root.root.string[0] == '.'
- && h->root.root.string[1] != '\0')
- {
- struct elf_link_hash_entry *fdh = ((struct ppc_link_hash_entry *) h)->oh;
- bfd_boolean force_local;
+ if (ent == NULL
+ || fh->elf.root.root.string[0] != '.'
+ || fh->elf.root.root.string[1] == '\0')
+ return TRUE;
- /* Find the corresponding function descriptor symbol. Create it
- as undefined if necessary. */
+ /* Find the corresponding function descriptor symbol. Create it
+ as undefined if necessary. */
- if (fdh == NULL)
- fdh = elf_link_hash_lookup (&htab->elf, h->root.root.string + 1,
- FALSE, FALSE, TRUE);
+ fdh = get_fdh (fh, htab);
+ if (fdh != NULL)
+ while (fdh->elf.root.type == bfd_link_hash_indirect
+ || fdh->elf.root.type == bfd_link_hash_warning)
+ fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link;
- if (fdh == NULL
- && info->shared
- && (h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak))
+ if (fdh == NULL
+ && info->shared
+ && (fh->elf.root.type == bfd_link_hash_undefined
+ || fh->elf.root.type == bfd_link_hash_undefweak))
+ {
+ bfd *abfd;
+ asymbol *newsym;
+ struct bfd_link_hash_entry *bh;
+
+ abfd = fh->elf.root.u.undef.abfd;
+ newsym = bfd_make_empty_symbol (abfd);
+ newsym->name = fh->elf.root.root.string + 1;
+ newsym->section = bfd_und_section_ptr;
+ newsym->value = 0;
+ newsym->flags = BSF_OBJECT;
+ if (fh->elf.root.type == bfd_link_hash_undefweak)
+ newsym->flags |= BSF_WEAK;
+
+ bh = &fdh->elf.root;
+ if ( !(_bfd_generic_link_add_one_symbol
+ (info, abfd, newsym->name, newsym->flags,
+ newsym->section, newsym->value, NULL, FALSE, FALSE, &bh)))
{
- bfd *abfd;
- asymbol *newsym;
- struct bfd_link_hash_entry *bh;
-
- abfd = h->root.u.undef.abfd;
- newsym = bfd_make_empty_symbol (abfd);
- newsym->name = h->root.root.string + 1;
- newsym->section = bfd_und_section_ptr;
- newsym->value = 0;
- newsym->flags = BSF_OBJECT;
- if (h->root.type == bfd_link_hash_undefweak)
- newsym->flags |= BSF_WEAK;
-
- bh = &fdh->root;
- if ( !(_bfd_generic_link_add_one_symbol
- (info, abfd, newsym->name, newsym->flags,
- newsym->section, newsym->value, NULL, FALSE, FALSE, &bh)))
- {
- return FALSE;
- }
- fdh = (struct elf_link_hash_entry *) bh;
- fdh->elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
- fdh->size = 24;
- fdh->type = STT_OBJECT;
+ return FALSE;
}
+ fdh = (struct ppc_link_hash_entry *) bh;
+ fdh->elf.elf_link_hash_flags &= ~ELF_LINK_NON_ELF;
+ fdh->elf.size = 24;
+ fdh->elf.type = STT_OBJECT;
+ }
- if (fdh != NULL
- && (fdh->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
- && (info->shared
- || (fdh->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- || (fdh->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
- || (fdh->root.type == bfd_link_hash_undefweak
- && ELF_ST_VISIBILITY (fdh->other) == STV_DEFAULT)))
+ if (fdh != NULL
+ && (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0
+ && (info->shared
+ || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+ || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
+ || (fdh->elf.root.type == bfd_link_hash_undefweak
+ && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT)))
+ {
+ if (fdh->elf.dynindx == -1)
+ if (! bfd_elf64_link_record_dynamic_symbol (info, &fdh->elf))
+ return FALSE;
+ fdh->elf.elf_link_hash_flags
+ |= (fh->elf.elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
+ | ELF_LINK_HASH_REF_DYNAMIC
+ | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+ | ELF_LINK_NON_GOT_REF));
+ if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT)
{
- if (fdh->dynindx == -1)
- if (! bfd_elf64_link_record_dynamic_symbol (info, fdh))
- return FALSE;
- fdh->elf_link_hash_flags |= (h->elf_link_hash_flags
- & (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_REF_DYNAMIC
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK
- | ELF_LINK_NON_GOT_REF));
- if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
- {
- fdh->plt.plist = h->plt.plist;
- fdh->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
- }
- ((struct ppc_link_hash_entry *) fdh)->is_func_descriptor = 1;
- ((struct ppc_link_hash_entry *) fdh)->oh = h;
- ((struct ppc_link_hash_entry *) h)->oh = fdh;
+ fdh->elf.plt.plist = fh->elf.plt.plist;
+ fdh->elf.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
}
-
- /* Now that the info is on the function descriptor, clear the
- function code sym info. Any function code syms for which we
- don't have a definition in a regular file, we force local.
- This prevents a shared library from exporting syms that have
- been imported from another library. Function code syms that
- are really in the library we must leave global to prevent the
- linker dragging in a definition from a static library. */
- force_local = (info->shared
- && ((h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0
- || fdh == NULL
- || (fdh->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0
- || (fdh->elf_link_hash_flags
- & ELF_LINK_FORCED_LOCAL) != 0));
- _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+ fdh->is_func_descriptor = 1;
+ fdh->oh = &fh->elf;
+ fh->oh = &fdh->elf;
}
+ /* Now that the info is on the function descriptor, clear the
+ function code sym info. Any function code syms for which we
+ don't have a definition in a regular file, we force local.
+ This prevents a shared library from exporting syms that have
+ been imported from another library. Function code syms that
+ are really in the library we must leave global to prevent the
+ linker dragging in a definition from a static library. */
+ force_local
+ = (info->shared
+ && ((fh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+ || fdh == NULL
+ || (fdh->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0
+ || (fdh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0));
+ _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local);
+
return TRUE;
}
}
if (h->plt.plist != NULL)
- return TRUE;
+ {
+ /* We should never get here, but unfortunately there are versions
+ of gcc out there that improperly (for this ABI) put initialized
+ function pointers, vtable refs and suchlike in read-only
+ sections. Allow them to proceed, but warn that this might
+ break at runtime. */
+ (*_bfd_error_handler)
+ (_("copy reloc against `%s' requires lazy plt linking; "
+ "avoid setting LD_BIND_NOW=1 or upgrade gcc"),
+ h->root.root.string);
+ }
/* This is a reference to a symbol defined by a dynamic object which
is not a function. */
need_edit = FALSE;
offset = 0;
relend = relstart + sec->reloc_count;
- for (rel = relstart; rel < relend; rel++)
+ for (rel = relstart; rel < relend; )
{
enum elf_ppc64_reloc_type r_type;
unsigned long r_symndx;
/* .opd contains a regular array of 24 byte entries. We're
only interested in the reloc pointing to a function entry
point. */
- r_type = ELF64_R_TYPE (rel->r_info);
- if (r_type == R_PPC64_TOC)
- continue;
-
- if (r_type != R_PPC64_ADDR64)
- {
- (*_bfd_error_handler)
- (_("%s: unexpected reloc type %u in .opd section"),
- bfd_archive_filename (ibfd), r_type);
- need_edit = FALSE;
- break;
- }
-
- if (rel + 1 >= relend)
- continue;
- r_type = ELF64_R_TYPE ((rel + 1)->r_info);
- if (r_type != R_PPC64_TOC)
- continue;
-
- if (rel->r_offset != offset)
+ if (rel->r_offset != offset
+ || rel + 1 >= relend
+ || (rel + 1)->r_offset != offset + 8)
{
/* If someone messes with .opd alignment then after a
"ld -r" we might have padding in the middle of .opd.
break;
}
+ if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64
+ || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC)
+ {
+ (*_bfd_error_handler)
+ (_("%s: unexpected reloc type %u in .opd section"),
+ bfd_archive_filename (ibfd), r_type);
+ need_edit = FALSE;
+ break;
+ }
+
r_symndx = ELF64_R_SYM (rel->r_info);
if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
r_symndx, ibfd))
- goto error_free_rel;
+ goto error_ret;
if (sym_sec == NULL || sym_sec->owner == NULL)
{
need_edit = TRUE;
offset += 24;
+ rel += 2;
+ /* Allow for the possibility of a reloc on the third word. */
+ if (rel < relend
+ && rel->r_offset == offset - 8)
+ rel += 1;
}
if (need_edit)
|| !bfd_get_section_contents (ibfd, sec, loc, 0,
sec->_raw_size))
{
+ error_ret:
if (local_syms != NULL
&& symtab_hdr->contents != (unsigned char *) local_syms)
free (local_syms);
- error_free_rel:
if (elf_section_data (sec)->relocs != relstart)
free (relstart);
return FALSE;
offset = 0;
for (rel = relstart; rel < relend; rel++)
{
+ unsigned long r_symndx;
+ asection *sym_sec;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+ r_symndx, ibfd))
+ goto error_ret;
+
if (rel->r_offset == offset)
{
- unsigned long r_symndx;
- asection *sym_sec;
- struct elf_link_hash_entry *h;
- Elf_Internal_Sym *sym;
-
- r_symndx = ELF64_R_SYM (rel->r_info);
- get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
- r_symndx, ibfd);
+ struct ppc_link_hash_entry *fdh = NULL;
+ if (h != NULL)
+ fdh = get_fdh ((struct ppc_link_hash_entry *) h,
+ ppc_hash_table (info));
skip = (sym_sec->owner != ibfd
|| sym_sec->output_section == bfd_abs_section_ptr);
{
/* Arrange for the function descriptor sym
to be dropped. */
- struct ppc_link_hash_entry *fdh;
- struct ppc_link_hash_entry *fh;
-
- fh = (struct ppc_link_hash_entry *) h;
- fdh = (struct ppc_link_hash_entry *) fh->oh;
- if (fdh == NULL)
- {
- const char *fd_name;
- struct ppc_link_hash_table *htab;
-
- fd_name = h->root.root.string + 1;
- htab = ppc_hash_table (info);
- fdh = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, fd_name,
- FALSE, FALSE, FALSE);
- fdh->is_func_descriptor = 1;
- fdh->oh = &fh->elf;
- fh->is_func = 1;
- fh->oh = &fdh->elf;
- }
-
fdh->elf.root.u.def.value = 0;
fdh->elf.root.u.def.section = sym_sec;
}
to this location in the opd section.
We've checked above that opd relocs are
ordered. */
- struct ppc_link_hash_entry *fdh;
- struct ppc_link_hash_entry *fh;
-
- fh = (struct ppc_link_hash_entry *) h;
- fdh = (struct ppc_link_hash_entry *) fh->oh;
- if (fdh == NULL)
- {
- const char *fd_name;
- struct ppc_link_hash_table *htab;
-
- fd_name = h->root.root.string + 1;
- htab = ppc_hash_table (info);
- fdh = (struct ppc_link_hash_entry *)
- elf_link_hash_lookup (&htab->elf, fd_name,
- FALSE, FALSE, FALSE);
- fdh->is_func_descriptor = 1;
- fdh->oh = &fh->elf;
- fh->is_func = 1;
- fh->oh = &fdh->elf;
- }
-
fdh->elf.root.u.def.value = wptr - sec->contents;
}
else
offset += 24;
}
- /* We need to adjust any reloc offsets to point to the
- new opd entries. While we're at it, we may as well
- remove redundant relocs. */
- if (!skip)
+ if (skip)
{
+ BFD_ASSERT (MUST_BE_DYN_RELOC (ELF64_R_TYPE (rel->r_info)));
+ if (info->shared)
+ {
+ /* We won't be needing dynamic relocs here. */
+ struct ppc_dyn_relocs **pp;
+ struct ppc_dyn_relocs *p;
+
+ if (h != NULL)
+ pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+ else if (sym_sec != NULL)
+ pp = ((struct ppc_dyn_relocs **)
+ &elf_section_data (sym_sec)->local_dynrel);
+ else
+ pp = ((struct ppc_dyn_relocs **)
+ &elf_section_data (sec)->local_dynrel);
+ while ((p = *pp) != NULL)
+ {
+ if (p->sec == sec)
+ {
+ p->count -= 1;
+ if (p->count == 0)
+ *pp = p->next;
+ break;
+ }
+ pp = &p->next;
+ }
+ }
+ }
+ else
+ {
+ /* We need to adjust any reloc offsets to point to the
+ new opd entries. While we're at it, we may as well
+ remove redundant relocs. */
rel->r_offset += wptr - rptr;
if (write_rel != rel)
memcpy (write_rel, rel, sizeof (*rel));
struct ppc_branch_hash_entry *br_entry;
struct bfd_link_info *info;
struct ppc_link_hash_table *htab;
- asection *stub_sec;
- bfd *stub_bfd;
bfd_byte *loc;
bfd_byte *p;
unsigned int indx;
info = in_arg;
htab = ppc_hash_table (info);
- stub_sec = stub_entry->stub_sec;
/* Make a note of the offset within the stubs for this entry. */
- stub_entry->stub_offset = stub_sec->_cooked_size;
- loc = stub_sec->contents + stub_entry->stub_offset;
-
- if (htab->emit_stub_syms)
- {
- struct elf_link_hash_entry *h;
- h = elf_link_hash_lookup (&htab->elf, stub_entry->root.string,
- TRUE, FALSE, FALSE);
- if (h == NULL)
- return FALSE;
- h->root.type = bfd_link_hash_defined;
- h->root.u.def.section = stub_entry->stub_sec;
- h->root.u.def.value = stub_entry->stub_offset;
- h->elf_link_hash_flags = (ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK
- | ELF_LINK_FORCED_LOCAL);
- }
-
- stub_bfd = stub_sec->owner;
+ stub_entry->stub_offset = stub_entry->stub_sec->_cooked_size;
+ loc = stub_entry->stub_sec->contents + stub_entry->stub_offset;
htab->stub_count[stub_entry->stub_type - 1] += 1;
switch (stub_entry->stub_type)
/* And this is where we are coming from. */
off -= (stub_entry->stub_offset
- + stub_sec->output_offset
- + stub_sec->output_section->vma);
+ + stub_entry->stub_sec->output_offset
+ + stub_entry->stub_sec->output_section->vma);
if (stub_entry->stub_type != ppc_stub_long_branch_r2off)
size = 4;
r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
- htab->stub_group[stub_entry->id_sec->id].toc_off);
- bfd_put_32 (stub_bfd, STD_R2_40R1, loc);
+ bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
loc += 4;
- bfd_put_32 (stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
+ bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
loc += 4;
- bfd_put_32 (stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
+ bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
loc += 4;
off -= 12;
size = 16;
}
- bfd_put_32 (stub_bfd, B_DOT | (off & 0x3fffffc), loc);
+ bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
BFD_ASSERT (off + (1 << 25) < (bfd_vma) (1 << 26));
break;
indx = off;
if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
{
- bfd_put_32 (stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
+ bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
loc += 4;
- bfd_put_32 (stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
+ bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
size = 16;
}
else
r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
- htab->stub_group[stub_entry->id_sec->id].toc_off);
- bfd_put_32 (stub_bfd, STD_R2_40R1, loc);
+ bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
loc += 4;
- bfd_put_32 (stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
+ bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
loc += 4;
- bfd_put_32 (stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
+ bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
loc += 4;
- bfd_put_32 (stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
+ bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc);
loc += 4;
- bfd_put_32 (stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
+ bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
size = 28;
}
loc += 4;
- bfd_put_32 (stub_bfd, MTCTR_R11, loc);
+ bfd_put_32 (htab->stub_bfd, MTCTR_R11, loc);
loc += 4;
- bfd_put_32 (stub_bfd, BCTR, loc);
+ bfd_put_32 (htab->stub_bfd, BCTR, loc);
break;
case ppc_stub_plt_call:
return FALSE;
}
- p = build_plt_stub (stub_bfd, loc, off);
+ p = build_plt_stub (htab->stub_bfd, loc, off);
size = p - loc;
break;
return FALSE;
}
- stub_sec->_cooked_size += size;
+ stub_entry->stub_sec->_cooked_size += size;
+
+ if (htab->emit_stub_syms
+ && !(stub_entry->stub_type == ppc_stub_plt_call
+ && stub_entry->h->oh->root.type == bfd_link_hash_defined
+ && stub_entry->h->oh->root.u.def.section == stub_entry->stub_sec
+ && stub_entry->h->oh->root.u.def.value == stub_entry->stub_offset))
+ {
+ struct elf_link_hash_entry *h;
+ h = elf_link_hash_lookup (&htab->elf, stub_entry->root.string,
+ TRUE, FALSE, FALSE);
+ if (h == NULL)
+ return FALSE;
+ if (h->root.type == bfd_link_hash_new)
+ {
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = stub_entry->stub_sec;
+ h->root.u.def.value = stub_entry->stub_offset;
+ h->elf_link_hash_flags = (ELF_LINK_HASH_REF_REGULAR
+ | ELF_LINK_HASH_DEF_REGULAR
+ | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+ | ELF_LINK_FORCED_LOCAL);
+ }
+ }
+
return TRUE;
}
/* If a code section has a function that uses the TOC then we need
to use the right TOC (obviously). Also, make sure that .opd gets
- the correct TOC value. */
+ the correct TOC value for R_PPC64_TOC relocs that don't have or
+ can't find their function symbol (shouldn't ever happen now). */
if (isec->has_gp_reloc || (isec->flags & SEC_CODE) == 0)
{
if (elf_gp (isec->owner) != 0)
return FALSE;
}
+ if (htab->emit_stub_syms)
+ {
+ struct elf_link_hash_entry *h;
+ h = elf_link_hash_lookup (&htab->elf, "__glink", TRUE, FALSE, FALSE);
+ if (h == NULL)
+ return FALSE;
+ if (h->root.type == bfd_link_hash_new)
+ {
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = htab->glink;
+ h->root.u.def.value = 0;
+ h->elf_link_hash_flags = (ELF_LINK_HASH_REF_REGULAR
+ | ELF_LINK_HASH_DEF_REGULAR
+ | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+ | ELF_LINK_FORCED_LOCAL);
+ }
+ }
p = htab->glink->contents;
bfd_put_32 (htab->glink->owner, MFCTR_R12, p);
p += 4;
bfd_vma relocation;
bfd_boolean unresolved_reloc;
bfd_boolean warned;
- long insn, mask;
+ unsigned long insn, mask;
struct ppc_stub_hash_entry *stub_entry;
bfd_vma max_br_offset;
bfd_vma from;
r_type = ELF64_R_TYPE (rel->r_info);
r_symndx = ELF64_R_SYM (rel->r_info);
+
+ /* For old style R_PPC64_TOC relocs with a zero symbol, use the
+ symbol of the previous ADDR64 reloc. The symbol gives us the
+ proper TOC base to use. */
+ if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC)
+ && rel != relocs
+ && ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_ADDR64
+ && is_opd)
+ r_symndx = ELF64_R_SYM (rel[-1].r_info);
+
sym = NULL;
sec = NULL;
h = NULL;
}
else
{
- /* It's a global symbol. */
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ RELOC_FOR_GLOBAL_SYMBOL (h, sym_hashes, r_symndx,
+ symtab_hdr, relocation, sec,
+ unresolved_reloc, info,
+ warned);
sym_name = h->root.root.string;
- relocation = 0;
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- sec = h->root.u.def.section;
- if (sec->output_section == NULL)
- /* Set a flag that will be cleared later if we find a
- relocation value for this symbol. output_section
- is typically NULL for symbols satisfied by a shared
- library. */
- unresolved_reloc = TRUE;
- else
- relocation = (h->root.u.def.value
- + sec->output_section->vma
- + sec->output_offset);
- }
- else if (h->root.type == bfd_link_hash_undefweak)
- ;
- else if (!info->executable
- && !info->no_undefined
- && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
- ;
- else
- {
- if (! ((*info->callbacks->undefined_symbol)
- (info, h->root.root.string, input_bfd, input_section,
- rel->r_offset, (!info->shared
- || info->no_undefined
- || ELF_ST_VISIBILITY (h->other)))))
- return FALSE;
- warned = TRUE;
- }
}
/* TLS optimizations. Replace instruction sequences and relocs
if (tls_mask != 0
&& (tls_mask & TLS_TPREL) == 0)
{
- bfd_vma insn;
toctprel:
insn = bfd_get_32 (output_bfd, contents + rel->r_offset - 2);
insn &= 31 << 21;
if (tls_mask != 0
&& (tls_mask & TLS_TPREL) == 0)
{
- bfd_vma insn, rtra;
+ bfd_vma rtra;
insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
if ((insn & ((0x3f << 26) | (31 << 11)))
== ((31 << 26) | (13 << 11)))
if ((insn & 1) == 0)
can_plt_call = 1;
}
+ else if (h != NULL
+ && strcmp (h->root.root.string,
+ ".__libc_start_main") == 0)
+ {
+ /* Allow crt1 branch to go via a toc adjusting stub. */
+ can_plt_call = 1;
+ }
else
{
if (strcmp (input_section->output_section->name,