This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
+
/* This file is based on a preliminary PowerPC ELF ABI. The
information may not match the final PowerPC ELF ABI. It includes
suggestions from the in-progress Embedded PowerPC ABI, and that
information may also not match. */
+#include "sysdep.h"
#include <stdarg.h>
#include "bfd.h"
-#include "sysdep.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
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)];
+
+ /* 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));
+ bfd_set_error (bfd_error_bad_value);
+
+ cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
+ }
}
/* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */
/* A mapping from local symbols to offsets into the various linker
sections added. This is index by the symbol index. */
elf_linker_section_pointers_t **linker_section_pointers;
+
+ /* Flags used to auto-detect plt type. */
+ unsigned int makes_plt_call : 1;
+ unsigned int has_rel16 : 1;
};
#define ppc_elf_tdata(bfd) \
#define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
-enum ppc_elf_plt_type {
- PLT_UNSET,
- PLT_OLD,
- PLT_NEW,
- PLT_VXWORKS
-};
-
/* PPC ELF linker hash table. */
struct ppc_elf_link_hash_table
elf_linker_section_t sdata[2];
asection *sbss;
+ /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */
+ asection *srelplt2;
+
+ /* The .got.plt section (VxWorks only)*/
+ asection *sgotplt;
+
/* Shortcut to .__tls_get_addr. */
struct elf_link_hash_entry *tls_get_addr;
+ /* The bfd that forced an old-style PLT. */
+ bfd *old_bfd;
+
/* TLS local dynamic got entry handling. */
union {
bfd_signed_vma refcount;
/* The type of PLT we have chosen to use. */
enum ppc_elf_plt_type plt_type;
- /* Whether we can use the new PLT layout. */
- unsigned int can_use_new_plt:1;
-
/* Set if we should emit symbols for stubs. */
unsigned int emit_stub_syms:1;
- /* Small local sym to section mapping cache. */
- struct sym_sec_cache sym_sec;
-
- /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */
- asection *srelplt2;
-
- /* The .got.plt section (VxWorks only)*/
- asection *sgotplt;
-
/* True if the target system is VxWorks. */
- int is_vxworks;
+ unsigned int is_vxworks:1;
/* The size of PLT entries. */
int plt_entry_size;
int plt_slot_size;
/* The size of the first PLT entry. */
int plt_initial_entry_size;
+
+ /* Small local sym to section mapping cache. */
+ struct sym_sec_cache sym_sec;
};
/* Get the PPC ELF linker hash table from a link_info structure. */
ret->plt_entry_size = 12;
ret->plt_slot_size = 8;
ret->plt_initial_entry_size = 72;
-
- ret->is_vxworks = 0;
return &ret->elf.root;
}
}
else
{
- bfd_vma addend = r_type == R_PPC_PLTREL24 ? rel->r_addend : 0;
+ bfd_vma addend = 0;
+ if (r_type == R_PPC_PLTREL24)
+ {
+ ppc_elf_tdata (abfd)->makes_plt_call = 1;
+ addend = rel->r_addend;
+ }
h->needs_plt = 1;
if (!update_plt_info (abfd, h, got2, addend))
return FALSE;
case R_PPC_REL16_LO:
case R_PPC_REL16_HI:
case R_PPC_REL16_HA:
- htab->can_use_new_plt = 1;
+ ppc_elf_tdata (abfd)->has_rel16 = 1;
break;
/* These are just markers. */
/* This refers only to functions defined in the shared library. */
case R_PPC_LOCAL24PC:
if (h && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
- htab->plt_type = PLT_OLD;
+ {
+ htab->plt_type = PLT_OLD;
+ htab->old_bfd = abfd;
+ }
break;
/* This relocation describes the C++ object vtable hierarchy.
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_PPC_GNU_VTENTRY:
- if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ BFD_ASSERT (h != NULL);
+ if (h != NULL
+ && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return FALSE;
break;
s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
r_symndx);
if (s == got2)
- htab->plt_type = PLT_OLD;
+ {
+ htab->plt_type = PLT_OLD;
+ htab->old_bfd = abfd;
+ }
}
if (h == NULL || h == htab->elf.hgot)
break;
if (h == htab->elf.hgot)
{
if (htab->plt_type == PLT_UNSET)
- htab->plt_type = PLT_OLD;
+ {
+ htab->plt_type = PLT_OLD;
+ htab->old_bfd = abfd;
+ }
break;
}
/* fall through */
return TRUE;
}
\f
+
+/* Merge object attributes from IBFD into OBFD. Raise an error if
+ there are conflicting attributes. */
+static bfd_boolean
+ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+{
+ obj_attribute *in_attr;
+ obj_attribute *out_attr;
+
+ if (!elf_known_obj_attributes_proc (obfd)[0].i)
+ {
+ /* This is the first object. Copy the attributes. */
+ _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+ /* Use the Tag_null value to indicate the attributes have been
+ initialized. */
+ elf_known_obj_attributes_proc (obfd)[0].i = 1;
+
+ return TRUE;
+ }
+
+ /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge
+ non-conflicting ones. */
+ in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+ out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
+ if (in_attr[Tag_GNU_Power_ABI_FP].i != out_attr[Tag_GNU_Power_ABI_FP].i)
+ {
+ out_attr[Tag_GNU_Power_ABI_FP].type = 1;
+ if (out_attr[Tag_GNU_Power_ABI_FP].i == 0)
+ out_attr[Tag_GNU_Power_ABI_FP].i = in_attr[Tag_GNU_Power_ABI_FP].i;
+ else if (in_attr[Tag_GNU_Power_ABI_FP].i == 0)
+ ;
+ else if (out_attr[Tag_GNU_Power_ABI_FP].i == 1
+ && in_attr[Tag_GNU_Power_ABI_FP].i == 2)
+ _bfd_error_handler
+ (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
+ else if (out_attr[Tag_GNU_Power_ABI_FP].i == 2
+ && in_attr[Tag_GNU_Power_ABI_FP].i == 1)
+ _bfd_error_handler
+ (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
+ else if (in_attr[Tag_GNU_Power_ABI_FP].i > 2)
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
+ in_attr[Tag_GNU_Power_ABI_FP].i);
+ else
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d"), obfd,
+ out_attr[Tag_GNU_Power_ABI_FP].i);
+ }
+
+ /* Merge Tag_compatibility attributes and any common GNU ones. */
+ _bfd_elf_merge_object_attributes (ibfd, obfd);
+
+ return TRUE;
+}
+
/* Merge backend specific data from an object file to the output
object file when linking. */
if (! _bfd_generic_verify_endian_match (ibfd, obfd))
return FALSE;
+ if (!ppc_elf_merge_obj_attributes (ibfd, obfd))
+ return FALSE;
+
new_flags = elf_elfheader (ibfd)->e_flags;
old_flags = elf_elfheader (obfd)->e_flags;
if (!elf_flags_init (obfd))
int
ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
struct bfd_link_info *info,
- int force_old_plt,
+ enum ppc_elf_plt_type plt_style,
int emit_stub_syms)
{
struct ppc_elf_link_hash_table *htab;
htab = ppc_elf_hash_table (info);
if (htab->plt_type == PLT_UNSET)
- htab->plt_type = (force_old_plt || !htab->can_use_new_plt
- ? PLT_OLD : PLT_NEW);
+ {
+ if (plt_style == PLT_OLD)
+ htab->plt_type = PLT_OLD;
+ else
+ {
+ bfd *ibfd;
+ enum ppc_elf_plt_type plt_type = plt_style;
+
+ /* Look through the reloc flags left by ppc_elf_check_relocs.
+ Use the old style bss plt if a file makes plt calls
+ without using the new relocs, and if ld isn't given
+ --secure-plt and we never see REL16 relocs. */
+ if (plt_type == PLT_UNSET)
+ plt_type = PLT_OLD;
+ for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next)
+ if (is_ppc_elf_target (ibfd->xvec))
+ {
+ if (ppc_elf_tdata (ibfd)->has_rel16)
+ plt_type = PLT_NEW;
+ else if (ppc_elf_tdata (ibfd)->makes_plt_call)
+ {
+ plt_type = PLT_OLD;
+ htab->old_bfd = ibfd;
+ break;
+ }
+ }
+ htab->plt_type = plt_type;
+ }
+ }
+ if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW)
+ info->callbacks->info (_("Using bss-plt due to %B"), htab->old_bfd);
htab->emit_stub_syms = emit_stub_syms;
{
struct ppc_elf_link_hash_table *htab;
asection *s;
- unsigned int power_of_two;
#ifdef DEBUG
fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n",
if (!h->non_got_ref)
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. We can't
- do this if there are any small data relocations. */
+ /* 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.
+ We can't do this if there are any small data relocations. This
+ doesn't work on VxWorks, where we can not have dynamic
+ relocations (other than copy and jump slot relocations) in an
+ executable. */
if (ELIMINATE_COPY_RELOCS
- && !ppc_elf_hash_entry (h)->has_sda_refs)
+ && !ppc_elf_hash_entry (h)->has_sda_refs
+ && !htab->is_vxworks)
{
struct ppc_elf_dyn_relocs *p;
for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
h->needs_copy = 1;
}
- /* We need to figure out the alignment required for this symbol. I
- have no idea how ELF linkers handle this. */
- power_of_two = bfd_log2 (h->size);
- if (power_of_two > 4)
- power_of_two = 4;
-
- /* Apply the required alignment. */
- s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
- if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s))
- {
- if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two))
- return FALSE;
- }
-
- /* Define the symbol as being at this point in the section. */
- h->root.u.def.section = s;
- h->root.u.def.value = s->size;
-
- /* Increment the section size to make room for the symbol. */
- s->size += h->size;
-
- return TRUE;
+ return _bfd_elf_adjust_dynamic_copy (h, s);
}
\f
/* Generate a symbol to mark plt call stubs. For non-PIC code the sym is