#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;
+ 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,
_DS relocs bloats all reloc switches in this file. It
doesn't seem to make much sense to use any of these relocs
in data, so testing the insn should be safe. */
- if ((insn & (0x3f << 26)) == (56 << 26))
+ if ((insn & (0x3f << 26)) == (56u << 26))
mask = 15;
if (((relocation + addend) & mask) != 0)
{