/* PowerPC-specific support for 32-bit ELF
- Copyright (C) 1994-2014 Free Software Foundation, Inc.
+ Copyright (C) 1994-2016 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
#include "elf32-ppc.h"
#include "elf-vxworks.h"
#include "dwarf2.h"
-#include "elf-linux-psinfo.h"
typedef enum split16_format_type
{
/* This reloc does nothing. */
HOWTO (R_PPC_NONE, /* type */
0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 3, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
0xffff, /* dst_mask */
TRUE), /* pcrel_offset */
+ /* Like R_PPC_REL16_HA but for split field in addpcis. */
+ HOWTO (R_PPC_REL16DX_HA, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ ppc_elf_addr16_ha_reloc, /* special_function */
+ "R_PPC_REL16DX_HA", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x1fffc1, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
/* GNU extension to record C++ vtable hierarchy. */
HOWTO (R_PPC_GNU_VTINHERIT, /* type */
0, /* rightshift */
char pr_psargs[80]; /* Initial part of arg list. */
};
-/* Helper macro to swap (properly handling endianess) things from the
- `elf_internal_prpsinfo' structure to the `elf_external_ppc_prpsinfo32'
- structure.
-
- Note that FROM should be a pointer, and TO should be the explicit type. */
-
-#define PPC_LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to) \
- do \
- { \
- H_PUT_8 (abfd, from->pr_state, &to.pr_state); \
- H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \
- H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \
- H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \
- H_PUT_32 (abfd, from->pr_flag, to.pr_flag); \
- H_PUT_32 (abfd, from->pr_uid, to.pr_uid); \
- H_PUT_32 (abfd, from->pr_gid, to.pr_gid); \
- H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \
- H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \
- H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \
- H_PUT_32 (abfd, from->pr_sid, to.pr_sid); \
- strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname)); \
- strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \
- } while (0)
+/* Helper function to copy an elf_internal_linux_prpsinfo in host
+ endian to an elf_external_ppc_linux_prpsinfo32 in target endian. */
+static inline void
+swap_ppc_linux_prpsinfo32_out (bfd *obfd,
+ const struct elf_internal_linux_prpsinfo *from,
+ struct elf_external_ppc_linux_prpsinfo32 *to)
+{
+ bfd_put_8 (obfd, from->pr_state, &to->pr_state);
+ bfd_put_8 (obfd, from->pr_sname, &to->pr_sname);
+ bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb);
+ bfd_put_8 (obfd, from->pr_nice, &to->pr_nice);
+ bfd_put_32 (obfd, from->pr_flag, to->pr_flag);
+ bfd_put_32 (obfd, from->pr_uid, to->pr_uid);
+ bfd_put_32 (obfd, from->pr_gid, to->pr_gid);
+ bfd_put_32 (obfd, from->pr_pid, to->pr_pid);
+ bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid);
+ bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp);
+ bfd_put_32 (obfd, from->pr_sid, to->pr_sid);
+ strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname));
+ strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs));
+}
\f
/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */
case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break;
case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break;
case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break;
+ case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC_REL16DX_HA; break;
case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break;
case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break;
}
arelent *cache_ptr,
Elf_Internal_Rela *dst)
{
+ unsigned int r_type;
+
/* Initialize howto table if not already done. */
if (!ppc_elf_howto_table[R_PPC_ADDR32])
ppc_elf_howto_init ();
- BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max);
- cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)];
+ r_type = ELF32_R_TYPE (dst->r_info);
+ if (r_type >= R_PPC_max)
+ {
+ (*_bfd_error_handler) (_("%B: unrecognised PPC reloc number: %d"),
+ abfd, r_type);
+ bfd_set_error (bfd_error_bad_value);
+ r_type = R_PPC_NONE;
+ }
+ cache_ptr->howto = ppc_elf_howto_table[r_type];
/* Just because the above assert didn't trigger doesn't mean that
ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation. */
if (!cache_ptr->howto)
{
(*_bfd_error_handler) (_("%B: invalid relocation type %d"),
- abfd, ELF32_R_TYPE (dst->r_info));
+ abfd, r_type);
bfd_set_error (bfd_error_bad_value);
cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
- bfd_vma relocation;
+ enum elf_ppc_reloc_type r_type;
+ long insn;
+ bfd_size_type octets;
+ bfd_vma value;
if (output_bfd != NULL)
{
return bfd_reloc_ok;
}
- if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
- return bfd_reloc_outofrange;
-
- if (bfd_is_com_section (symbol->section))
- relocation = 0;
- else
- relocation = symbol->value;
-
- relocation += symbol->section->output_section->vma;
- relocation += symbol->section->output_offset;
- relocation += reloc_entry->addend;
- if (reloc_entry->howto->pc_relative)
- relocation -= reloc_entry->address;
-
- reloc_entry->addend += (relocation & 0x8000) << 1;
-
- return bfd_reloc_continue;
+ reloc_entry->addend += 0x8000;
+ r_type = reloc_entry->howto->type;
+ if (r_type != R_PPC_REL16DX_HA)
+ return bfd_reloc_continue;
+
+ value = 0;
+ if (!bfd_is_com_section (symbol->section))
+ value = symbol->value;
+ value += (reloc_entry->addend
+ + symbol->section->output_offset
+ + symbol->section->output_section->vma);
+ value -= (reloc_entry->address
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ value >>= 16;
+
+ octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+ insn &= ~0x1fffc1;
+ insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
+ bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
+ return bfd_reloc_ok;
}
static bfd_reloc_status_type
}
char *
-elfcore_write_ppc_linux_prpsinfo32 (bfd *abfd, char *buf, int *bufsiz,
- const struct elf_internal_linux_prpsinfo *prpsinfo)
+elfcore_write_ppc_linux_prpsinfo32
+ (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const struct elf_internal_linux_prpsinfo *prpsinfo)
{
struct elf_external_ppc_linux_prpsinfo32 data;
- memset (&data, 0, sizeof (data));
- PPC_LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
-
+ swap_ppc_linux_prpsinfo32_out (abfd, prpsinfo, &data);
return elfcore_write_note (abfd, buf, bufsiz,
"CORE", NT_PRPSINFO, &data, sizeof (data));
}
}
count = relplt->size / sizeof (Elf32_External_Rela);
- stub_vma = glink_vma - (bfd_vma) count * 16;
/* If the stubs are those for -shared/-pie then we might have
multiple stubs for each plt entry. If that is the case then
there is no way to associate stubs with their plt entries short
if (s == NULL)
return -1;
+ stub_vma = glink_vma;
names = (char *) (s + count + 1 + (resolv_vma != 0));
- p = relplt->relocation;
- for (i = 0; i < count; i++, p++)
+ p = relplt->relocation + count - 1;
+ for (i = 0; i < count; i++)
{
size_t len;
s->flags |= BSF_GLOBAL;
s->flags |= BSF_SYNTHETIC;
s->section = glink;
+ stub_vma -= 16;
+ if (strcmp ((*p->sym_ptr_ptr)->name, "__tls_get_addr_opt") == 0)
+ stub_vma -= 32;
s->value = stub_vma - glink->vma;
s->name = names;
s->udata.p = NULL;
memcpy (names, "@plt", sizeof ("@plt"));
names += sizeof ("@plt");
++s;
- stub_vma += 16;
+ --p;
}
/* Add a symbol at the start of the glink branch table. */
case R_PPC_TPREL16_LO:
case R_PPC_TPREL16_HI:
case R_PPC_TPREL16_HA:
- return !info->executable;
+ return !bfd_link_executable (info);
}
}
/* Nonzero if we have seen a small data relocation referring to this
symbol. */
- unsigned char has_sda_refs;
+ unsigned char has_sda_refs : 1;
+
+ /* Flag use of given relocations. */
+ unsigned char has_addr16_ha : 1;
+ unsigned char has_addr16_lo : 1;
};
#define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
ppc_elf_link_hash_table_create (bfd *abfd)
{
struct ppc_elf_link_hash_table *ret;
- static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12 };
+ static struct ppc_elf_params default_params = { PLT_OLD, 0, 1, 0, 0, 12, 0 };
ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
if (ret == NULL)
if (s == NULL)
return FALSE;
- if (! info->shared)
+ if (! bfd_link_pic (info))
{
htab->relbss = bfd_get_linker_section (abfd, ".rela.bss");
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
bfd_vma *valp)
{
if (sym->st_shndx == SHN_COMMON
- && !info->relocatable
+ && !bfd_link_relocatable (info)
&& is_ppc_elf (info->output_bfd)
&& sym->st_size <= elf_gp_size (abfd))
{
|| ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
&& (abfd->flags & DYNAMIC) == 0
&& bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
- elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+ elf_tdata (info->output_bfd)->has_gnu_symbols = elf_gnu_symbol_any;
return TRUE;
}
asection *got2, *sreloc;
struct elf_link_hash_entry *tga;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
/* Don't do anything special with non-loaded, non-alloced sections.
enum elf_ppc_reloc_type r_type;
struct elf_link_hash_entry *h;
int tls_type;
+ struct plt_entry **ifunc;
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
tls_type = 0;
r_type = ELF32_R_TYPE (rel->r_info);
+ ifunc = NULL;
if (h == NULL && !htab->is_vxworks)
{
Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
- struct plt_entry **ifunc;
-
/* Set PLT_IFUNC flag for this sym, no GOT entry yet. */
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
PLT_IFUNC);
/* STT_GNU_IFUNC symbols must have a PLT entry;
In a non-pie executable even when there are
no plt calls. */
- if (!info->shared
+ if (!bfd_link_pic (info)
|| is_branch_reloc (r_type))
{
bfd_vma addend = 0;
if (r_type == R_PPC_PLTREL24)
{
ppc_elf_tdata (abfd)->makes_plt_call = 1;
- if (info->shared)
+ if (bfd_link_pic (info))
addend = rel->r_addend;
}
if (!update_plt_info (abfd, ifunc, got2, addend))
case R_PPC_GOT_TPREL16_LO:
case R_PPC_GOT_TPREL16_HI:
case R_PPC_GOT_TPREL16_HA:
- if (info->shared)
+ if (bfd_link_pic (info))
info->flags |= DF_STATIC_TLS;
tls_type = TLS_TLS | TLS_TPREL;
goto dogottls;
/* We may also need a plt entry if the symbol turns out to be
an ifunc. */
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
{
if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
return FALSE;
/* Indirect .sdata relocation. */
case R_PPC_EMB_SDAI16:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
/* Indirect .sdata2 relocation. */
case R_PPC_EMB_SDA2I16:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
break;
case R_PPC_EMB_SDA2REL:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
case R_PPC_VLE_SDA21:
case R_PPC_EMB_SDA21:
case R_PPC_EMB_RELSDA:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
case R_PPC_EMB_NADDR16_LO:
case R_PPC_EMB_NADDR16_HI:
case R_PPC_EMB_NADDR16_HA:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
#ifdef DEBUG
fprintf (stderr, "Reloc requires a PLT entry\n");
#endif
- /* This symbol requires a procedure linkage table entry. We
- actually build the entry in finish_dynamic_symbol,
- because this might be a case of linking PIC code without
- linking in any dynamic objects, in which case we don't
- need to generate a procedure linkage table after all. */
-
+ /* This symbol requires a procedure linkage table entry. */
if (h == NULL)
{
- /* It does not make sense to have a procedure linkage
- table entry for a local symbol. */
- info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"),
- abfd, sec, rel->r_offset,
- ppc_elf_howto_table[r_type]->name);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ if (ifunc == NULL)
+ {
+ /* It does not make sense to have a procedure linkage
+ table entry for a non-ifunc local symbol. */
+ info->callbacks->einfo
+ (_("%P: %H: %s reloc against local symbol\n"),
+ abfd, sec, rel->r_offset,
+ ppc_elf_howto_table[r_type]->name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
}
else
{
if (r_type == R_PPC_PLTREL24)
{
ppc_elf_tdata (abfd)->makes_plt_call = 1;
- if (info->shared)
+ if (bfd_link_pic (info))
addend = rel->r_addend;
}
h->needs_plt = 1;
case R_PPC_REL16_LO:
case R_PPC_REL16_HI:
case R_PPC_REL16_HA:
+ case R_PPC_REL16DX_HA:
ppc_elf_tdata (abfd)->has_rel16 = 1;
break;
}
if (h != NULL && h->type == STT_GNU_IFUNC)
{
- if (info->shared)
+ if (bfd_link_pic (info))
{
- info->callbacks->einfo (_("%P: %H: @local call to ifunc %s\n"),
- abfd, sec, rel->r_offset,
- h->root.root.string);
+ info->callbacks->einfo
+ (_("%P: %H: @local call to ifunc %s\n"),
+ abfd, sec, rel->r_offset,
+ h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
case R_PPC_TPREL16_LO:
case R_PPC_TPREL16_HI:
case R_PPC_TPREL16_HA:
- if (info->shared)
+ if (bfd_link_pic (info))
info->flags |= DF_STATIC_TLS;
goto dodyn;
if (h == NULL
&& got2 != NULL
&& (sec->flags & SEC_CODE) != 0
- && info->shared
+ && bfd_link_pic (info)
&& htab->plt_type == PLT_UNSET)
{
/* Old -fPIC gcc code has .long LCTOC1-LCFx just before
case R_PPC_ADDR16_HA:
case R_PPC_UADDR32:
case R_PPC_UADDR16:
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
{
/* We may need a plt entry if the symbol turns out to be
a function defined in a dynamic object. */
/* We may need a copy reloc too. */
h->non_got_ref = 1;
h->pointer_equality_needed = 1;
+ if (r_type == R_PPC_ADDR16_HA)
+ ppc_elf_hash_entry (h)->has_addr16_ha = 1;
+ if (r_type == R_PPC_ADDR16_LO)
+ ppc_elf_hash_entry (h)->has_addr16_lo = 1;
}
goto dodyn;
case R_PPC_ADDR14:
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_ADDR14_BRNTAKEN:
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
{
/* We may need a plt entry if the symbol turns out to be
a function defined in a dynamic object. */
may need to keep relocations for symbols satisfied by a
dynamic library if we manage to avoid copy relocs for the
symbol. */
- if ((info->shared
+ if ((bfd_link_pic (info)
&& (must_be_dyn_reloc (info, r_type)
|| (h != NULL
&& (!SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
|| !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
- && !info->shared
+ && !bfd_link_pic (info)
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular)))
if (htab->params->plt_style == PLT_OLD)
htab->plt_type = PLT_OLD;
- else if (info->shared
+ else if (bfd_link_pic (info)
&& htab->elf.dynamic_sections_created
&& (h = elf_link_hash_lookup (&htab->elf, "_mcount",
FALSE, FALSE, TRUE)) != NULL
const Elf_Internal_Rela *rel, *relend;
asection *got2;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
if ((sec->flags & SEC_ALLOC) == 0)
if (!htab->is_vxworks
&& h == NULL
&& local_got_refcounts != NULL
- && (!info->shared
+ && (!bfd_link_pic (info)
|| is_branch_reloc (r_type)))
{
struct plt_entry **local_plt = (struct plt_entry **)
bfd_vma addend = 0;
struct plt_entry *ent;
- if (r_type == R_PPC_PLTREL24 && info->shared)
+ if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
addend = rel->r_addend;
ent = find_plt_ent (ifunc, got2, addend);
if (ent->plt.refcount > 0)
{
if (h->got.refcount > 0)
h->got.refcount--;
- if (!info->shared)
+ if (!bfd_link_pic (info))
{
struct plt_entry *ent;
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_UADDR32:
case R_PPC_UADDR16:
- if (info->shared)
+ if (bfd_link_pic (info))
break;
case R_PPC_PLT32:
bfd_vma addend = 0;
struct plt_entry *ent;
- if (r_type == R_PPC_PLTREL24 && info->shared)
+ if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
addend = rel->r_addend;
ent = find_plt_ent (&h->plt.plist, got2, addend);
if (ent != NULL && ent->plt.refcount > 0)
htab = ppc_elf_hash_table (info);
htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
FALSE, FALSE, TRUE);
+ if (htab->plt_type != PLT_NEW)
+ htab->params->no_tls_get_addr_opt = TRUE;
+
if (!htab->params->no_tls_get_addr_opt)
{
struct elf_link_hash_entry *opt, *tga;
struct ppc_elf_link_hash_table *htab;
int pass;
- if (info->relocatable || !info->executable)
+ if (!bfd_link_executable (info))
return TRUE;
htab = ppc_elf_hash_table (info);
struct plt_entry *ent;
bfd_vma addend = 0;
- if (info->shared
+ if (bfd_link_pic (info)
&& ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
addend = rel[1].r_addend;
ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
&& !readonly_dynrelocs (h))
h->non_got_ref = 0;
}
+ h->protected_def = 0;
return TRUE;
}
else
only references to the symbol are via the global offset table.
For such cases we need not do anything here; the relocations will
be handled correctly by relocate_section. */
- if (info->shared)
- return TRUE;
+ if (bfd_link_pic (info))
+ {
+ h->protected_def = 0;
+ return TRUE;
+ }
/* If there are no references to this symbol that do not use the
GOT, we don't need to generate a copy reloc. */
if (!h->non_got_ref)
- return TRUE;
+ {
+ h->protected_def = 0;
+ return TRUE;
+ }
+
+ /* Protected variables do not work with .dynbss. The copy in
+ .dynbss won't be used by the shared library with the protected
+ definition for the variable. Editing to PIC, or text relocations
+ are preferable to an incorrect program. */
+ if (h->protected_def)
+ {
+ if (ELIMINATE_COPY_RELOCS
+ && ppc_elf_hash_entry (h)->has_addr16_ha
+ && ppc_elf_hash_entry (h)->has_addr16_lo
+ && htab->params->pic_fixup == 0
+ && info->disable_target_specific_optimizations <= 1)
+ htab->params->pic_fixup = 1;
+ h->non_got_ref = 0;
+ return TRUE;
+ }
+
+ /* If -z nocopyreloc was given, we won't generate them either. */
+ if (info->nocopyreloc)
+ {
+ h->non_got_ref = 0;
+ return TRUE;
+ }
/* If we didn't find any dynamic relocs in read-only sections, then
we'll be keeping the dynamic relocs and avoiding the copy reloc.
const char *stub;
struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
- if (info->shared)
+ if (bfd_link_pic (info))
stub = ".plt_pic32.";
else
stub = ".plt_call32.";
sh->ref_regular_nonweak = 1;
sh->forced_local = 1;
sh->non_elf = 0;
+ sh->root.linker_def = 1;
}
return TRUE;
}
}
dyn = htab->elf.dynamic_sections_created;
- if (info->shared
+ if (bfd_link_pic (info)
|| h->type == STT_GNU_IFUNC
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
{
ent->plt.offset = plt_offset;
s = htab->glink;
- if (!doneone || info->shared)
+ if (!doneone || bfd_link_pic (info))
{
glink_offset = s->size;
s->size += GLINK_ENTRY_SIZE;
s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
}
if (!doneone
- && !info->shared
+ && !bfd_link_pic (info)
&& h->def_dynamic
&& !h->def_regular)
{
relocations, and is required to make
function pointers compare as equal between
the normal executable and the shared library. */
- if (! info->shared
+ if (! bfd_link_pic (info)
&& h->def_dynamic
&& !h->def_regular)
{
if (htab->plt_type == PLT_VXWORKS)
{
/* Allocate space for the unloaded relocations. */
- if (!info->shared
+ if (!bfd_link_pic (info)
&& htab->elf.dynamic_sections_created)
{
if (ent->plt.offset
}
eh = (struct ppc_elf_link_hash_entry *) h;
- if (eh->elf.got.refcount > 0)
+ if (eh->elf.got.refcount > 0
+ || (ELIMINATE_COPY_RELOCS
+ && !eh->elf.def_regular
+ && eh->elf.protected_def
+ && eh->has_addr16_ha
+ && eh->has_addr16_lo
+ && htab->params->pic_fixup > 0))
{
bfd_boolean dyn;
unsigned int need;
{
eh->elf.got.offset = allocate_got (htab, need);
dyn = htab->elf.dynamic_sections_created;
- if ((info->shared
+ if ((bfd_link_pic (info)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
&& (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
|| eh->elf.root.type != bfd_link_hash_undefweak))
space for relocs that have become local due to symbol visibility
changes. */
- if (info->shared)
+ if (bfd_link_pic (info))
{
/* Relocs that use pc_count are those that appear on a call insn,
or certain REL relocs (see must_be_dyn_reloc) that can be
dynamic. */
if (!h->non_got_ref
- && !h->def_regular)
+ && !h->def_regular
+ && !(h->protected_def
+ && eh->has_addr16_ha
+ && eh->has_addr16_lo
+ && htab->params->pic_fixup > 0))
{
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (elf_hash_table (info)->dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
- if (info->executable)
+ if (bfd_link_executable (info) && !info->nointerp)
{
s = bfd_get_linker_section (htab->elf.dynobj, ".interp");
BFD_ASSERT (s != NULL);
else
{
*local_got = allocate_got (htab, need);
- if (info->shared)
+ if (bfd_link_pic (info))
{
asection *srel = htab->relgot;
if ((*lgot_masks & PLT_IFUNC) != 0)
ent->plt.offset = plt_offset;
s = htab->glink;
- if (!doneone || info->shared)
+ if (!doneone || bfd_link_pic (info))
{
glink_offset = s->size;
s->size += GLINK_ENTRY_SIZE;
if (htab->tlsld_got.refcount > 0)
{
htab->tlsld_got.offset = allocate_got (htab, 8);
- if (info->shared)
+ if (bfd_link_pic (info))
htab->relgot->size += sizeof (Elf32_External_Rela);
}
else
htab->elf.hgot->root.u.def.value = g_o_t;
}
- if (info->shared)
+ if (bfd_link_pic (info))
{
struct elf_link_hash_entry *sda = htab->sdata[0].sym;
sh->ref_regular_nonweak = 1;
sh->forced_local = 1;
sh->non_elf = 0;
+ sh->root.linker_def = 1;
}
sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
TRUE, FALSE, FALSE);
sh->ref_regular_nonweak = 1;
sh->forced_local = 1;
sh->non_elf = 0;
+ sh->root.linker_def = 1;
}
}
}
{
s = htab->glink_eh_frame;
s->size = sizeof (glink_eh_frame_cie) + 20;
- if (info->shared)
+ if (bfd_link_pic (info))
{
s->size += 4;
if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256)
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
- if (info->executable)
+ if (bfd_link_executable (info))
{
if (!add_dynamic_entry (DT_DEBUG, 0))
return FALSE;
/* Augmentation. */
p += 1;
- if (info->shared
+ if (bfd_link_pic (info)
&& htab->elf.dynamic_sections_created)
{
bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2;
struct ppc_elf_relax_info
{
unsigned int workaround_size;
+ unsigned int picfixup_size;
};
/* This function implements long branch trampolines, and the ppc476
struct bfd_link_info *link_info,
bfd_boolean *again)
{
- struct one_fixup
+ struct one_branch_fixup
{
- struct one_fixup *next;
+ struct one_branch_fixup *next;
asection *tsec;
/* Final link, can use the symbol offset. For a
relocatable link we use the symbol's index. */
Elf_Internal_Sym *isymbuf = NULL;
Elf_Internal_Rela *internal_relocs = NULL;
Elf_Internal_Rela *irel, *irelend = NULL;
- struct one_fixup *fixups = NULL;
+ struct one_branch_fixup *branch_fixups = NULL;
struct ppc_elf_relax_info *relax_info = NULL;
unsigned changes = 0;
bfd_boolean workaround_change;
struct ppc_elf_link_hash_table *htab;
- bfd_size_type trampbase, trampoff, newsize;
+ bfd_size_type trampbase, trampoff, newsize, picfixup_size;
asection *got2;
bfd_boolean maybe_pasted;
/* We cannot represent the required PIC relocs in the output, so don't
do anything. The linker doesn't support mixing -shared and -r
anyway. */
- if (link_info->relocatable && link_info->shared)
+ if (bfd_link_relocatable (link_info) && bfd_link_pic (link_info))
return TRUE;
htab = ppc_elf_hash_table (link_info);
|| isec->sec_info_type == SEC_INFO_TYPE_TARGET);
isec->sec_info_type = SEC_INFO_TYPE_TARGET;
- if (htab->params->ppc476_workaround)
+ if (htab->params->ppc476_workaround
+ || htab->params->pic_fixup > 0)
{
if (elf_section_data (isec)->sec_info == NULL)
{
trampoff += 4;
symtab_hdr = &elf_symtab_hdr (abfd);
-
- if (htab->params->branch_trampolines)
+ picfixup_size = 0;
+ if (htab->params->branch_trampolines
+ || htab->params->pic_fixup > 0)
{
/* Get a copy of the native relocations. */
if (isec->reloc_count != 0)
unsigned long r_type = ELF32_R_TYPE (irel->r_info);
bfd_vma toff, roff;
asection *tsec;
- struct one_fixup *f;
+ struct one_branch_fixup *f;
size_t insn_offset = 0;
- bfd_vma max_branch_offset, val;
+ bfd_vma max_branch_offset = 0, val;
bfd_byte *hit_addr;
unsigned long t0;
struct elf_link_hash_entry *h;
max_branch_offset = 1 << 15;
break;
+ case R_PPC_ADDR16_HA:
+ if (htab->params->pic_fixup > 0)
+ break;
+ continue;
+
default:
continue;
}
|| h->root.type == bfd_link_hash_undefweak)
{
tsec = bfd_und_section_ptr;
- toff = link_info->relocatable ? indx : 0;
+ toff = bfd_link_relocatable (link_info) ? indx : 0;
}
else
continue;
/* If this branch is to __tls_get_addr then we may later
optimise away the call. We won't be needing a long-
branch stub in that case. */
- if (link_info->executable
- && !link_info->relocatable
+ if (bfd_link_executable (link_info)
&& h == htab->tls_get_addr
&& irel != internal_relocs)
{
sym_type = h->type;
}
+ if (r_type == R_PPC_ADDR16_HA)
+ {
+ if (h != NULL
+ && !h->def_regular
+ && h->protected_def
+ && ppc_elf_hash_entry (h)->has_addr16_ha
+ && ppc_elf_hash_entry (h)->has_addr16_lo)
+ picfixup_size += 12;
+ continue;
+ }
+
/* The condition here under which we call find_plt_ent must
match that in relocate_section. If we call find_plt_ent here
but not in relocate_section, or vice versa, then the branch
bfd_vma addend = 0;
struct plt_entry *ent;
- if (r_type == R_PPC_PLTREL24 && link_info->shared)
+ if (r_type == R_PPC_PLTREL24 && bfd_link_pic (link_info))
addend = irel->r_addend;
ent = find_plt_ent (plist, got2, addend);
if (ent != NULL)
toff += irel->r_addend;
/* Attempted -shared link of non-pic code loses. */
- if ((!link_info->relocatable
+ if ((!bfd_link_relocatable (link_info)
&& tsec == bfd_und_section_ptr)
|| tsec->output_section == NULL
|| (tsec->owner != NULL
/* If the branch is in range, no need to do anything. */
if (tsec != bfd_und_section_ptr
- && (!link_info->relocatable
+ && (!bfd_link_relocatable (link_info)
/* A relocatable link may have sections moved during
final link, so do not presume they remain in range. */
|| tsec->output_section == isec->output_section))
}
/* Look for an existing fixup to this address. */
- for (f = fixups; f ; f = f->next)
+ for (f = branch_fixups; f ; f = f->next)
if (f->tsec == tsec && f->toff == toff)
break;
one. We'll report an error later. */
continue;
- if (link_info->shared)
+ if (bfd_link_pic (link_info))
{
size = 4 * ARRAY_SIZE (shared_stub_entry);
insn_offset = 12;
/* Record the fixup so we don't do it again this section. */
f = bfd_malloc (sizeof (*f));
- f->next = fixups;
+ f->next = branch_fixups;
f->tsec = tsec;
f->toff = toff;
f->trampoff = trampoff;
- fixups = f;
+ branch_fixups = f;
trampoff += size;
changes++;
}
}
- while (fixups != NULL)
+ while (branch_fixups != NULL)
{
- struct one_fixup *f = fixups;
- fixups = fixups->next;
+ struct one_branch_fixup *f = branch_fixups;
+ branch_fixups = branch_fixups->next;
free (f);
}
}
workaround_change = FALSE;
newsize = trampoff;
if (htab->params->ppc476_workaround
- && (!link_info->relocatable
+ && (!bfd_link_relocatable (link_info)
|| isec->output_section->alignment_power >= htab->params->pagesize_p2))
{
bfd_vma addr, end_addr;
newsize = trampoff + relax_info->workaround_size;
}
- if (changes || workaround_change)
+ if (htab->params->pic_fixup > 0)
+ {
+ picfixup_size -= relax_info->picfixup_size;
+ if (picfixup_size != 0)
+ relax_info->picfixup_size += picfixup_size;
+ newsize += relax_info->picfixup_size;
+ }
+
+ if (changes != 0 || picfixup_size != 0 || workaround_change)
isec->size = newsize;
if (isymbuf != NULL
}
}
+ changes += picfixup_size;
if (changes != 0)
{
/* Append sufficient NOP relocs so we can write out relocation
return TRUE;
error_return:
- while (fixups != NULL)
+ while (branch_fixups != NULL)
{
- struct one_fixup *f = fixups;
- fixups = fixups->next;
+ struct one_branch_fixup *f = branch_fixups;
+ branch_fixups = branch_fixups->next;
free (f);
}
if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
+ plt_sec->output_section->vma
+ plt_sec->output_offset);
- if (info->shared)
+ if (bfd_link_pic (info))
{
bfd_vma got = 0;
static bfd_boolean
is_insn_dq_form (unsigned int insn)
{
- return (insn & (0x3f << 26)) == 56u << 26; /* lq */
+ return ((insn & (0x3f << 26)) == 56u << 26 /* lq */
+ || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */
+ && (insn & 3) == 1));
}
/* The RELOCATE_SECTION function is called by the ELF backend linker
struct elf_link_hash_entry **sym_hashes;
struct ppc_elf_link_hash_table *htab;
Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *wrel;
Elf_Internal_Rela *relend;
Elf_Internal_Rela outrel;
asection *got2;
bfd_boolean ret = TRUE;
bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
bfd_boolean is_vxworks_tls;
+ unsigned int picfixup_size = 0;
+ struct ppc_elf_relax_info *relax_info = NULL;
#ifdef DEBUG
_bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
"%ld relocations%s",
input_bfd, input_section,
(long) input_section->reloc_count,
- (info->relocatable) ? " (relocatable)" : "");
+ (bfd_link_relocatable (info)) ? " (relocatable)" : "");
#endif
got2 = bfd_get_section_by_name (input_bfd, ".got2");
sym_hashes = elf_sym_hashes (input_bfd);
/* We have to handle relocations in vxworks .tls_vars sections
specially, because the dynamic loader is 'weird'. */
- is_vxworks_tls = (htab->is_vxworks && info->shared
+ is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info)
&& !strcmp (input_section->output_section->name,
".tls_vars"));
- rel = relocs;
+ if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
+ relax_info = elf_section_data (input_section)->sec_info;
+ rel = wrel = relocs;
relend = relocs + input_section->reloc_count;
- for (; rel < relend; rel++)
+ for (; rel < relend; wrel++, rel++)
{
enum elf_ppc_reloc_type r_type;
bfd_vma addend;
struct plt_entry **ifunc;
struct reloc_howto_struct alt_howto;
+ again:
r_type = ELF32_R_TYPE (rel->r_info);
sym = NULL;
sec = NULL;
howto = NULL;
if (r_type < R_PPC_max)
howto = ppc_elf_howto_table[r_type];
- RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
- rel, 1, relend, howto, 0, contents);
+
+ _bfd_clear_contents (howto, input_bfd, input_section,
+ contents + rel->r_offset);
+ wrel->r_offset = rel->r_offset;
+ wrel->r_info = 0;
+ wrel->r_addend = 0;
+
+ /* For ld -r, remove relocations in debug sections against
+ sections defined in discarded sections. Not done for
+ non-debug to preserve relocs in .eh_frame which the
+ eh_frame editing code expects to be present. */
+ if (bfd_link_relocatable (info)
+ && (input_section->flags & SEC_DEBUGGING))
+ wrel--;
+
+ continue;
}
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
{
if (got2 != NULL
&& r_type == R_PPC_PLTREL24
if (r_type != R_PPC_RELAX_PLT
&& r_type != R_PPC_RELAX_PLTREL24
&& r_type != R_PPC_RELAX)
- continue;
+ goto copy_reloc;
}
/* TLS optimizations. Replace instruction sequences and relocs
{
bfd_vma insn;
- insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+ insn = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
insn &= 31 << 21;
insn |= 0x3c020000; /* addis 0,2,0 */
- bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
+ bfd_put_32 (output_bfd, insn,
+ contents + rel->r_offset - d_offset);
r_type = R_PPC_TPREL16_HA;
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
}
+ R_PPC_GOT_TPREL16);
else
{
- bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
rel->r_offset -= d_offset;
+ bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
r_type = R_PPC_NONE;
}
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
&& branch_reloc_hash_match (input_bfd, rel + 1,
htab->tls_get_addr))
offset = rel[1].r_offset;
+ /* We read the low GOT_TLS insn because we need to keep
+ the destination reg. It may be something other than
+ the usual r3, and moved to r3 before the call by
+ intervening code. */
+ insn1 = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
if ((tls_mask & tls_gd) != 0)
{
/* IE */
- insn1 = bfd_get_32 (output_bfd,
- contents + rel->r_offset - d_offset);
- insn1 &= (1 << 26) - 1;
+ insn1 &= (0x1f << 21) | (0x1f << 16);
insn1 |= 32 << 26; /* lwz */
if (offset != (bfd_vma) -1)
{
else
{
/* LE */
- insn1 = 0x3c620000; /* addis 3,2,0 */
+ insn1 &= 0x1f << 21;
+ insn1 |= 0x3c020000; /* addis r,2,0 */
if (tls_gd == 0)
{
/* Was an LD reloc. */
{
/* We changed the symbol on an LD reloc. Start over
in order to get h, sym, sec etc. right. */
- rel--;
- continue;
+ goto again;
}
}
break;
/* Zap the reloc on the _tls_get_addr call too. */
BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset);
rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
- rel--;
- continue;
+ goto again;
}
break;
}
}
}
+ if (ELIMINATE_COPY_RELOCS
+ && h != NULL
+ && !h->def_regular
+ && h->protected_def
+ && ppc_elf_hash_entry (h)->has_addr16_ha
+ && ppc_elf_hash_entry (h)->has_addr16_lo
+ && htab->params->pic_fixup > 0)
+ {
+ /* Convert lis;addi or lis;load/store accessing a protected
+ variable defined in a shared library to PIC. */
+ unsigned int insn;
+
+ if (r_type == R_PPC_ADDR16_HA)
+ {
+ insn = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
+ if ((insn & (0x3f << 26)) == (15u << 26)
+ && (insn & (0x1f << 16)) == 0 /* lis */)
+ {
+ bfd_byte *p;
+ bfd_vma off;
+ bfd_vma got_addr;
+
+ p = (contents + input_section->size
+ - relax_info->workaround_size
+ - relax_info->picfixup_size
+ + picfixup_size);
+ off = (p - contents) - (rel->r_offset - d_offset);
+ if (off > 0x1fffffc || (off & 3) != 0)
+ info->callbacks->einfo
+ (_("%P: %H: fixup branch overflow\n"),
+ input_bfd, input_section, rel->r_offset);
+
+ bfd_put_32 (output_bfd, B | off,
+ contents + rel->r_offset - d_offset);
+ got_addr = (htab->got->output_section->vma
+ + htab->got->output_offset
+ + (h->got.offset & ~1));
+ wrel->r_offset = (p - contents) + d_offset;
+ wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA);
+ wrel->r_addend = got_addr;
+ insn &= ~0xffff;
+ insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff;
+ bfd_put_32 (output_bfd, insn, p);
+
+ /* Convert lis to lwz, loading address from GOT. */
+ insn &= ~0xffff;
+ insn ^= (32u ^ 15u) << 26;
+ insn |= (insn & (0x1f << 21)) >> 5;
+ insn |= got_addr & 0xffff;
+ bfd_put_32 (output_bfd, insn, p + 4);
+
+ bfd_put_32 (output_bfd, B | ((-4 - off) & 0x3ffffff), p + 8);
+ picfixup_size += 12;
+
+ /* Use one of the spare relocs, so --emit-relocs
+ output is reasonable. */
+ memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
+ wrel++, rel++;
+ rel->r_offset = wrel[-1].r_offset + 4;
+ rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO);
+ rel->r_addend = wrel[-1].r_addend;
+
+ /* Continue on as if we had a got reloc, to output
+ dynamic reloc. */
+ r_type = R_PPC_GOT16_LO;
+ }
+ else
+ info->callbacks->einfo
+ (_("%P: %H: error: %s with unexpected instruction %x\n"),
+ input_bfd, input_section, rel->r_offset,
+ "R_PPC_ADDR16_HA", insn);
+ }
+ else if (r_type == R_PPC_ADDR16_LO)
+ {
+ insn = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
+ if ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+ || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
+ || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
+ || (insn & (0x3f << 26)) == 36u << 26 /* stw */
+ || (insn & (0x3f << 26)) == 38u << 26 /* stb */
+ || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
+ || (insn & (0x3f << 26)) == 42u << 26 /* lha */
+ || (insn & (0x3f << 26)) == 44u << 26 /* sth */
+ || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
+ || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
+ || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
+ || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
+ || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
+ || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
+ || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
+ && (insn & 3) != 1)
+ || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+ && ((insn & 3) == 0 || (insn & 3) == 3)))
+ {
+ /* Arrange to apply the reloc addend, if any. */
+ relocation = 0;
+ unresolved_reloc = FALSE;
+ rel->r_info = ELF32_R_INFO (0, r_type);
+ }
+ else
+ info->callbacks->einfo
+ (_("%P: %H: error: %s with unexpected instruction %x\n"),
+ input_bfd, input_section, rel->r_offset,
+ "R_PPC_ADDR16_LO", insn);
+ }
+ }
+
ifunc = NULL;
if (!htab->is_vxworks)
{
ent = NULL;
if (ifunc != NULL
- && (!info->shared
+ && (!bfd_link_pic (info)
|| is_branch_reloc (r_type)))
{
addend = 0;
- if (r_type == R_PPC_PLTREL24 && info->shared)
+ if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
addend = rel->r_addend;
ent = find_plt_ent (ifunc, got2, addend);
}
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
- continue;
+ goto copy_reloc;
case R_PPC_NONE:
case R_PPC_TLS:
case R_PPC_EMB_MRKREF:
case R_PPC_GNU_VTINHERIT:
case R_PPC_GNU_VTENTRY:
- continue;
+ goto copy_reloc;
/* GOT16 relocations. Like an ADDR16 using the symbol's
address in the GOT as relocation value instead of the
{
bfd_boolean dyn;
dyn = htab->elf.dynamic_sections_created;
- if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
- || (info->shared
+ if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+ || (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, h)))
/* This is actually a static link, or it is a
-Bsymbolic link and the symbol is defined
}
/* Generate relocs for the dynamic linker. */
- if ((info->shared || indx != 0)
+ if ((bfd_link_pic (info) || indx != 0)
&& (offp == &htab->tlsld_got.offset
|| h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
{
outrel.r_addend += relocation;
if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
- outrel.r_addend -= htab->elf.tls_sec->vma;
+ {
+ if (htab->elf.tls_sec == NULL)
+ outrel.r_addend = 0;
+ else
+ outrel.r_addend -= htab->elf.tls_sec->vma;
+ }
}
loc = rsec->contents;
loc += (rsec->reloc_count++
value = 1;
else if (tls_ty != 0)
{
- value -= htab->elf.tls_sec->vma + DTP_OFFSET;
- if (tls_ty == (TLS_TLS | TLS_TPREL))
- value += DTP_OFFSET - TP_OFFSET;
+ if (htab->elf.tls_sec == NULL)
+ value = 0;
+ else
+ {
+ value -= htab->elf.tls_sec->vma + DTP_OFFSET;
+ if (tls_ty == (TLS_TLS | TLS_TPREL))
+ value += DTP_OFFSET - TP_OFFSET;
+ }
if (tls_ty == (TLS_TLS | TLS_GD))
{
}
}
+ /* If here for a picfixup, we're done. */
+ if (r_type != ELF32_R_TYPE (rel->r_info))
+ goto copy_reloc;
+
relocation = (htab->got->output_section->vma
+ htab->got->output_offset
+ off
rel->r_offset,
TRUE))
return FALSE;
- continue;
+ goto copy_reloc;
}
break;
case R_PPC_DTPREL16_LO:
case R_PPC_DTPREL16_HI:
case R_PPC_DTPREL16_HA:
- addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
break;
/* Relocations that may need to be propagated if this is a shared
bfd_put_32 (output_bfd, insn, p);
break;
}
- addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
/* The TPREL16 relocs shouldn't really be used in shared
libs as they will result in DT_TEXTREL being set, but
support them anyway. */
goto dodyn;
case R_PPC_TPREL32:
- addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
goto dodyn;
case R_PPC_DTPREL32:
- addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
goto dodyn;
case R_PPC_DTPMOD32:
case R_PPC_REL16_LO:
case R_PPC_REL16_HI:
case R_PPC_REL16_HA:
+ case R_PPC_REL16DX_HA:
break;
case R_PPC_REL32:
case R_PPC_ADDR14:
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_ADDR14_BRNTAKEN:
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
break;
/* fall through */
|| is_vxworks_tls)
break;
- if ((info->shared
+ if ((bfd_link_pic (info)
&& !(h != NULL
&& ((h->root.type == bfd_link_hash_undefined
&& (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
&& (must_be_dyn_reloc (info, r_type)
|| !SYMBOL_CALLS_LOCAL (info, h)))
|| (ELIMINATE_COPY_RELOCS
- && !info->shared
+ && !bfd_link_pic (info)
&& h != NULL
&& h->dynindx != -1
&& !h->non_got_ref
- && !h->def_regular))
+ && !h->def_regular
+ && !(h->protected_def
+ && ppc_elf_hash_entry (h)->has_addr16_ha
+ && ppc_elf_hash_entry (h)->has_addr16_lo
+ && htab->params->pic_fixup > 0)))
{
int skip;
bfd_byte *loc;
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
if (skip == -1)
- continue;
+ goto copy_reloc;
/* This reloc will be computed at runtime. We clear the memory
so that it contains predictable value. */
if (r_type == R_PPC_RELAX_PLTREL24)
{
- if (info->shared)
+ if (bfd_link_pic (info))
got2_addend = addend;
addend = 0;
}
size_t insn_offset = rel->r_offset;
unsigned int insn;
- if (info->shared)
+ if (bfd_link_pic (info))
{
relocation -= (input_section->output_section->vma
+ input_section->output_offset
}
relocation += addend;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
relocation = 0;
/* First insn is HA, second is LO. */
relocs to describe this relocation. */
BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE);
/* The relocs are at the bottom 2 bytes */
- rel[0].r_offset += d_offset;
- memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
- rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
- rel[1].r_offset += 4;
- rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
- rel++;
+ wrel->r_offset = rel->r_offset + d_offset;
+ wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
+ wrel->r_addend = rel->r_addend;
+ memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel));
+ wrel++, rel++;
+ wrel->r_offset += 4;
+ wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
}
continue;
case R_PPC_PLTREL24:
if (h != NULL && ifunc == NULL)
{
- struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
- info->shared ? addend : 0);
+ struct plt_entry *ent;
+
+ ent = find_plt_ent (&h->plt.plist, got2,
+ bfd_link_pic (info) ? addend : 0);
if (ent == NULL
|| htab->plt == NULL)
{
relocation = relocation + addend;
ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
relocation, split16a_type);
- continue;
+ goto copy_reloc;
case R_PPC_VLE_LO16D:
relocation = relocation + addend;
ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
relocation, split16d_type);
- continue;
+ goto copy_reloc;
case R_PPC_VLE_HI16A:
relocation = (relocation + addend) >> 16;
ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
relocation, split16a_type);
- continue;
+ goto copy_reloc;
case R_PPC_VLE_HI16D:
relocation = (relocation + addend) >> 16;
ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
relocation, split16d_type);
- continue;
+ goto copy_reloc;
case R_PPC_VLE_HA16A:
relocation = (relocation + addend + 0x8000) >> 16;
ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
relocation, split16a_type);
- continue;
+ goto copy_reloc;
case R_PPC_VLE_HA16D:
relocation = (relocation + addend + 0x8000) >> 16;
ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
relocation, split16d_type);
- continue;
+ goto copy_reloc;
/* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */
case R_PPC_EMB_SDA21:
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
- continue;
+ goto copy_reloc;
}
if (sda != NULL)
if (r_type == R_PPC_VLE_SDA21
&& ((relocation + 0x80000) & 0xffffffff) > 0x100000)
goto overflow;
- continue;
+ goto copy_reloc;
}
else if (r_type == R_PPC_EMB_SDA21
|| r_type == R_PPC_VLE_SDA21
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
- continue;
+ goto copy_reloc;
}
if (sda != NULL)
value, split16d_type);
}
}
- continue;
+ goto copy_reloc;
/* Relocate against the beginning of the section. */
case R_PPC_SECTOFF:
bfd_set_error (bfd_error_invalid_operation);
ret = FALSE;
- continue;
+ goto copy_reloc;
}
/* Do any further special processing. */
case R_PPC_ADDR16_HA:
case R_PPC_REL16_HA:
+ case R_PPC_REL16DX_HA:
case R_PPC_SECTOFF_HA:
case R_PPC_TPREL16_HA:
case R_PPC_DTPREL16_HA:
that make up part of the insn opcode. */
unsigned int insn, mask, lobit;
- insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+ insn = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
mask = 0;
if (is_insn_ds_form (insn))
mask = 3;
mask = 15;
else
break;
- lobit = mask & (relocation + addend);
+ relocation += addend;
+ addend = insn & mask;
+ lobit = mask & relocation;
if (lobit != 0)
{
- addend -= lobit;
+ relocation ^= lobit;
info->callbacks->einfo
(_("%P: %H: error: %s against `%s' not a multiple of %u\n"),
input_bfd, input_section, rel->r_offset,
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
}
- addend += insn & mask;
}
break;
}
}
}
- r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
- rel->r_offset, relocation, addend);
+ if (r_type == R_PPC_REL16DX_HA)
+ {
+ /* Split field reloc isn't handled by _bfd_final_link_relocate. */
+ if (rel->r_offset + 4 > input_section->size)
+ r = bfd_reloc_outofrange;
+ else
+ {
+ unsigned int insn;
+
+ relocation += addend;
+ relocation -= (rel->r_offset
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ relocation >>= 16;
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn &= ~0x1fffc1;
+ insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ r = bfd_reloc_ok;
+ }
+ }
+ else
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel->r_offset, relocation, addend);
if (r != bfd_reloc_ok)
{
if (r == bfd_reloc_overflow)
{
overflow:
- if (warned)
- continue;
- if (h != NULL
- && h->root.type == bfd_link_hash_undefweak
- && howto->pc_relative)
+ /* On code like "if (foo) foo();" don't report overflow
+ on a branch to zero when foo is undefined. */
+ if (!warned
+ && !(h != NULL
+ && (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined)
+ && is_branch_reloc (r_type)))
{
- /* Assume this is a call protected by other code that
- detect the symbol is undefined. If this is the case,
- we can safely ignore the overflow. If not, the
- program is hosed anyway, and a little warning isn't
- going to help. */
-
- continue;
+ if (!((*info->callbacks->reloc_overflow)
+ (info, (h ? &h->root : NULL), sym_name,
+ howto->name, rel->r_addend,
+ input_bfd, input_section, rel->r_offset)))
+ return FALSE;
}
-
- if (! (*info->callbacks->reloc_overflow) (info,
- (h ? &h->root : NULL),
- sym_name,
- howto->name,
- rel->r_addend,
- input_bfd,
- input_section,
- rel->r_offset))
- return FALSE;
}
else
{
ret = FALSE;
}
}
+ copy_reloc:
+ if (wrel != rel)
+ *wrel = *rel;
+ }
+
+ if (wrel != rel)
+ {
+ Elf_Internal_Shdr *rel_hdr;
+ size_t deleted = rel - wrel;
+
+ rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section);
+ rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+ if (rel_hdr->sh_size == 0)
+ {
+ /* It is too late to remove an empty reloc section. Leave
+ one NONE reloc.
+ ??? What is wrong with an empty section??? */
+ rel_hdr->sh_size = rel_hdr->sh_entsize;
+ deleted -= 1;
+ wrel++;
+ }
+ relend = wrel;
+ rel_hdr = _bfd_elf_single_rel_hdr (input_section);
+ rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+ input_section->reloc_count -= deleted;
}
#ifdef DEBUG
if (htab->params->ppc476_workaround
&& input_section->sec_info_type == SEC_INFO_TYPE_TARGET
- && (!info->relocatable
+ && (!bfd_link_relocatable (info)
|| (input_section->output_section->alignment_power
>= htab->params->pagesize_p2)))
{
- struct ppc_elf_relax_info *relax_info;
bfd_vma start_addr, end_addr, addr;
bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
- relax_info = elf_section_data (input_section)->sec_info;
if (relax_info->workaround_size != 0)
{
bfd_byte *p;
prevent the bad prefetch from happening in the first
place:
.
- . lis 9,new_page@ha lis 9,new_page@ha
- . addi 9,9,new_page@l addi 9,9,new_page@l
- . mtctr 9 mtctr 9
- . bctr bctr
+ . lis 9,new_page@ha lis 9,new_page@ha
+ . addi 9,9,new_page@l addi 9,9,new_page@l
+ . mtctr 9 mtctr 9
+ . bctr bctr
. nop b somewhere_else
- . b somewhere_else nop
- . new_page: new_page:
+ . b somewhere_else nop
+ . new_page: new_page:
. */
insn = bfd_get_32 (input_bfd, contents + offset);
if ((insn & (0x3f << 26)) == (18u << 26) /* b,bl,ba,bla */
&& rel->r_offset >= offset
&& rel->r_offset < offset + 4)
{
+ asection *sreloc;
+
/* If the insn we are patching had a reloc, adjust the
reloc r_offset so that the reloc applies to the moved
location. This matters for -r and --emit-relocs. */
relend[-1] = tmp;
}
relend[-1].r_offset += patch_off - offset;
+
+ /* Adjust REL16 addends too. */
+ switch (ELF32_R_TYPE (relend[-1].r_info))
+ {
+ case R_PPC_REL16:
+ case R_PPC_REL16_LO:
+ case R_PPC_REL16_HI:
+ case R_PPC_REL16_HA:
+ relend[-1].r_addend += patch_off - offset;
+ break;
+ default:
+ break;
+ }
+
+ /* If we are building a PIE or shared library with
+ non-PIC objects, perhaps we had a dynamic reloc too?
+ If so, the dynamic reloc must move with the insn. */
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (sreloc != NULL)
+ {
+ Elf32_External_Rela *slo, *shi, *srelend;
+ bfd_vma soffset;
+
+ slo = (Elf32_External_Rela *) sreloc->contents;
+ shi = srelend = slo + sreloc->reloc_count;
+ soffset = (offset + input_section->output_section->vma
+ + input_section->output_offset);
+ while (slo < shi)
+ {
+ Elf32_External_Rela *srel = slo + (shi - slo) / 2;
+ bfd_elf32_swap_reloca_in (output_bfd, (bfd_byte *) srel,
+ &outrel);
+ if (outrel.r_offset < soffset)
+ slo = srel + 1;
+ else if (outrel.r_offset > soffset + 3)
+ shi = srel;
+ else
+ {
+ if (srel + 1 != srelend)
+ {
+ memmove (srel, srel + 1,
+ (srelend - (srel + 1)) * sizeof (*srel));
+ srel = srelend - 1;
+ }
+ outrel.r_offset += patch_off - offset;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (bfd_byte *) srel);
+ break;
+ }
+ }
+ }
}
else
rel = NULL;
bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
delta += offset - patch_off;
- if (info->relocatable && rel != NULL)
+ if (bfd_link_relocatable (info) && rel != NULL)
delta = 0;
- if (!info->relocatable && rel != NULL)
+ if (!bfd_link_relocatable (info) && rel != NULL)
{
enum elf_ppc_reloc_type r_type;
got_offset = (reloc_index + 3) * 4;
/* Use the right PLT. */
- plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry
+ plt_entry = bfd_link_pic (info) ? ppc_elf_vxworks_pic_plt_entry
: ppc_elf_vxworks_plt_entry;
/* Fill in the .plt on VxWorks. */
- if (info->shared)
+ if (bfd_link_pic (info))
{
bfd_put_32 (output_bfd,
plt_entry[0] | PPC_HA (got_offset),
+ ent->plt.offset + 16),
htab->sgotplt->contents + got_offset);
- if (!info->shared)
+ if (!bfd_link_pic (info))
{
/* Fill in a couple of entries in .rela.plt.unloaded. */
loc = htab->srelplt2->contents
}
}
else if (h->type == STT_GNU_IFUNC
- && !info->shared)
+ && !bfd_link_pic (info))
{
/* Set the value of ifunc symbols in a non-pie
executable to the glink entry. This is to avoid
write_glink_stub (ent, splt, p, info);
- if (!info->shared)
+ if (!bfd_link_pic (info))
/* We only need one non-PIC glink stub. */
break;
}
if (splt && splt->size > 0)
{
/* Use the right PLT. */
- const bfd_vma *plt_entry = (info->shared
+ const bfd_vma *plt_entry = (bfd_link_pic (info)
? ppc_elf_vxworks_pic_plt0_entry
: ppc_elf_vxworks_plt0_entry);
- if (!info->shared)
+ if (!bfd_link_pic (info))
{
bfd_vma got_value = SYM_VAL (htab->elf.hgot);
bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24);
bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28);
- if (! info->shared)
+ if (! bfd_link_pic (info))
{
Elf_Internal_Rela rela;
bfd_byte *loc;
}
/* Last comes the PLTresolve stub. */
- if (info->shared)
+ if (bfd_link_pic (info))
{
bfd_vma bcl;
#define ELF_MACHINE_CODE EM_PPC
#ifdef __QNXTARGET__
#define ELF_MAXPAGESIZE 0x1000
+#define ELF_COMMONPAGESIZE 0x1000
#else
#define ELF_MAXPAGESIZE 0x10000
+#define ELF_COMMONPAGESIZE 0x10000
#endif
#define ELF_MINPAGESIZE 0x1000
-#define ELF_COMMONPAGESIZE 0x1000
#define elf_info_to_howto ppc_elf_info_to_howto
#ifdef EM_CYGNUS_POWERPC