/* PowerPC-specific support for 32-bit ELF
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005 Free Software Foundation, Inc.
+ 2004, 2005, 2006 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
#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
/* Non-zero if allocating the header left a gap. */
unsigned int got_gap;
- /* Whether to use new plt/got layout or not. */
- unsigned int new_plt:1;
- unsigned int old_plt:1;
+ /* 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;
if (ret == NULL)
return NULL;
- if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd,
- ppc_elf_link_hash_newfunc))
+ if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
+ ppc_elf_link_hash_newfunc,
+ sizeof (struct ppc_elf_link_hash_entry)))
{
free (ret);
return NULL;
return FALSE;
}
- /* Create the section for VxWorks static plt relocations. */
- if (htab->is_vxworks && !info->shared)
- {
- s = bfd_make_section (abfd, ".rela.plt.unloaded");
- flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY
- | SEC_LINKER_CREATED);
- if (s == NULL
- || ! bfd_set_section_flags (abfd, s, flags)
- || ! bfd_set_section_alignment (abfd, s,
- get_elf_backend_data (abfd)->s->log_file_align))
- return FALSE;
- htab->srelplt2 = s;
- }
+ if (htab->is_vxworks
+ && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
+ return FALSE;
htab->relplt = bfd_get_section_by_name (abfd, ".rela.plt");
htab->plt = s = bfd_get_section_by_name (abfd, ".plt");
abort ();
flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED;
+ if (htab->plt_type == PLT_VXWORKS)
+ /* The VxWorks PLT is a loaded section with contents. */
+ flags |= SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY;
return bfd_set_section_flags (abfd, s, flags);
}
is_ppc_elf_target (const struct bfd_target *targ)
{
extern const bfd_target bfd_elf32_powerpc_vec;
+ extern const bfd_target bfd_elf32_powerpc_vxworks_vec;
extern const bfd_target bfd_elf32_powerpcle_vec;
- return targ == &bfd_elf32_powerpc_vec || targ == &bfd_elf32_powerpcle_vec;
+ return (targ == &bfd_elf32_powerpc_vec
+ || targ == &bfd_elf32_powerpc_vxworks_vec
+ || targ == &bfd_elf32_powerpcle_vec);
}
/* Hook called by the linker routine which adds symbols from an object
case R_PPC_REL16_LO:
case R_PPC_REL16_HI:
case R_PPC_REL16_HA:
- htab->new_plt = 1;
+ htab->can_use_new_plt = 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->old_plt = 1;
+ if (h && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
+ htab->plt_type = PLT_OLD;
break;
/* This relocation describes the C++ object vtable hierarchy.
&& got2 != NULL
&& (sec->flags & SEC_CODE) != 0
&& (info->shared || info->pie)
- && !htab->old_plt)
+ && htab->plt_type == PLT_UNSET)
{
/* Old -fPIC gcc code has .long LCTOC1-LCFx just before
the start of a function, which assembles to a REL32
s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
r_symndx);
if (s == got2)
- htab->old_plt = 1;
+ htab->plt_type = PLT_OLD;
}
- /* fall through */
+ if (h == NULL || h == htab->elf.hgot)
+ break;
+ goto dodyn1;
case R_PPC_REL24:
case R_PPC_REL14:
break;
if (h == htab->elf.hgot)
{
- htab->old_plt = 1;
+ if (htab->plt_type == PLT_UNSET)
+ htab->plt_type = PLT_OLD;
break;
}
/* fall through */
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_UADDR32:
case R_PPC_UADDR16:
+ dodyn1:
if (h != NULL && !info->shared)
{
/* We may need a plt entry if the symbol turns out to be
flagword flags;
htab = ppc_elf_hash_table (info);
- if (force_old_plt || !htab->new_plt)
- htab->old_plt = 1;
+
+ if (htab->plt_type == PLT_UNSET)
+ htab->plt_type = (force_old_plt || !htab->can_use_new_plt
+ ? PLT_OLD : PLT_NEW);
htab->emit_stub_syms = emit_stub_syms;
- if (htab->is_vxworks)
- {
- /* The VxWorks PLT is a loaded section with contents. */
- flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED
- | SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY;
+ BFD_ASSERT (htab->plt_type != PLT_VXWORKS);
- if (htab->plt != NULL
- && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags))
- return -1;
- }
- else if (!htab->old_plt)
+ if (htab->plt_type == PLT_NEW)
{
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
&& !bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0))
return -1;
}
- return !htab->old_plt;
+ return htab->plt_type == PLT_NEW;
}
\f
/* Return the section that should be marked against GC for a given
struct ppc_elf_link_hash_table *htab;
htab = ppc_elf_hash_table (info);
- if (!htab->old_plt
+ if (htab->plt_type == PLT_NEW
&& htab->plt != NULL
&& htab->plt->output_section != NULL)
{
allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
{
bfd_vma where;
- unsigned int max_before_header = 32768;
-
- if (htab->old_plt)
- max_before_header = 32764;
+ unsigned int max_before_header;
- if (htab->is_vxworks)
+ if (htab->plt_type == PLT_VXWORKS)
{
where = htab->got->size;
htab->got->size += need;
}
- else if (need <= htab->got_gap)
- {
- where = max_before_header - htab->got_gap;
- htab->got_gap -= need;
- }
else
{
- if (htab->got->size + need > max_before_header
- && htab->got->size <= max_before_header)
+ max_before_header = htab->plt_type == PLT_NEW ? 32768 : 32764;
+ if (need <= htab->got_gap)
{
- htab->got_gap = max_before_header - htab->got->size;
- htab->got->size = max_before_header + htab->got_header_size;
+ where = max_before_header - htab->got_gap;
+ htab->got_gap -= need;
+ }
+ else
+ {
+ if (htab->got->size + need > max_before_header
+ && htab->got->size <= max_before_header)
+ {
+ htab->got_gap = max_before_header - htab->got->size;
+ htab->got->size = max_before_header + htab->got_header_size;
+ }
+ where = htab->got->size;
+ htab->got->size += need;
}
- where = htab->got->size;
- htab->got->size += need;
}
return where;
}
{
asection *s = htab->plt;
- if (!(htab->old_plt || htab->is_vxworks))
+ if (htab->plt_type == PLT_NEW)
{
if (!doneone)
{
s->size += htab->plt_entry_size;
/* After the 8192nd entry, room for two entries
is allocated. */
- if (!htab->is_vxworks
+ if (htab->plt_type == PLT_OLD
&& (s->size - htab->plt_initial_entry_size)
/ htab->plt_entry_size
> PLT_NUM_SINGLE_ENTRIES)
{
htab->relplt->size += sizeof (Elf32_External_Rela);
- if (htab->is_vxworks)
+ if (htab->plt_type == PLT_VXWORKS)
{
/* Allocate space for the unloaded relocations. */
if (!info->shared)
}
}
- if (htab->old_plt)
+ if (htab->plt_type == PLT_OLD)
htab->got_header_size = 16;
- else
+ else if (htab->plt_type == PLT_NEW)
htab->got_header_size = 12;
/* Set up .got offsets for local syms, and space for local dynamic
else
htab->tlsld_got.offset = (bfd_vma) -1;
- if (htab->is_vxworks)
- {
- /* Mark the GOT and PLT symbols as having relocations; they might
- not, but we won't know for sure until we build the GOT in
- finish_dynamic_symbol. */
- if (htab->elf.hgot)
- htab->elf.hgot->indx = -2;
- if (htab->elf.hplt)
- {
- htab->elf.hplt->indx = -2;
- if (htab->plt->flags & SEC_CODE)
- htab->elf.hplt->type = STT_FUNC;
- }
- }
-
/* Allocate space for global sym dynamic relocs. */
elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
- if (htab->got != NULL && !htab->is_vxworks)
+ if (htab->got != NULL && htab->plt_type != PLT_VXWORKS)
{
unsigned int g_o_t = 32768;
if (htab->got->size <= 32768)
{
g_o_t = htab->got->size;
- if (htab->old_plt)
+ if (htab->plt_type == PLT_OLD)
g_o_t += 4;
htab->got->size += htab->got_header_size;
}
if (ent != NULL)
{
- if (!htab->old_plt)
+ if (htab->plt_type == PLT_NEW)
{
tsec = htab->glink;
toff = ent->glink_offset;
insn1 |= 32 << 26; /* lwz */
insn2 = 0x7c631214; /* add 3,3,2 */
rel[1].r_info = ELF32_R_INFO (r_symndx2, R_PPC_NONE);
+ rel[1].r_addend = 0;
r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
+ R_PPC_GOT_TPREL16);
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
/* Was an LD reloc. */
r_symndx = 0;
rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
- rel[1].r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
}
r_type = R_PPC_TPREL16_HA;
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
rel[1].r_info = ELF32_R_INFO (r_symndx,
R_PPC_TPREL16_LO);
rel[1].r_offset += 2;
+ rel[1].r_addend = rel->r_addend;
}
bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - 2);
bfd_put_32 (output_bfd, insn2, contents + offset);
{
struct plt_entry *ent = find_plt_ent (h, got2, addend);
- if (!htab->old_plt)
+ if (htab->plt_type == PLT_NEW)
relocation = (htab->glink->output_section->vma
+ htab->glink->output_offset
+ ent->glink_offset);
}
unresolved_reloc = FALSE;
- if (!htab->old_plt)
+ if (htab->plt_type == PLT_NEW)
relocation = (htab->glink->output_section->vma
+ htab->glink->output_offset
+ ent->glink_offset);
bfd_byte *loc;
bfd_vma reloc_index;
- if (!(htab->old_plt || htab->is_vxworks))
+ if (htab->plt_type == PLT_NEW)
reloc_index = ent->plt.offset / 4;
else
{
reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size)
/ htab->plt_slot_size);
if (reloc_index > PLT_NUM_SINGLE_ENTRIES
- && !htab->is_vxworks)
+ && htab->plt_type == PLT_OLD)
reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
}
/* This symbol has an entry in the procedure linkage table.
Set it up. */
- if (htab->is_vxworks)
+ if (htab->plt_type == PLT_VXWORKS)
{
bfd_vma got_offset;
const bfd_vma *plt_entry;
rela.r_offset = (htab->plt->output_section->vma
+ htab->plt->output_offset
+ ent->plt.offset);
- if (htab->old_plt)
+ if (htab->plt_type == PLT_OLD)
{
/* We don't need to fill in the .plt. The ppc dynamic
linker will fill it in. */
doneone = TRUE;
}
- if (!htab->old_plt)
+ if (htab->plt_type == PLT_NEW)
{
bfd_vma plt;
unsigned char *p;
bfd_vma val;
p += htab->elf.hgot->root.u.def.value;
- if (htab->old_plt && !htab->is_vxworks)
+ if (htab->plt_type == PLT_OLD)
bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, p - 4);
val = 0;
struct ppc_elf_link_hash_table *htab
= (struct ppc_elf_link_hash_table *)ret;
htab->is_vxworks = 1;
+ htab->plt_type = PLT_VXWORKS;
htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE;
htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE;
htab->plt_initial_entry_size = VXWORKS_PLT_INITIAL_ENTRY_SIZE;
return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp);
}
-/* Tweak magic VxWorks symbols as they are written to the output file. */
-static bfd_boolean
-elf_i386_vxworks_link_output_symbol_hook (struct bfd_link_info *info
- ATTRIBUTE_UNUSED,
- const char *name,
- Elf_Internal_Sym *sym,
- asection *input_sec ATTRIBUTE_UNUSED,
- struct elf_link_hash_entry *h
- ATTRIBUTE_UNUSED)
-{
- /* Ignore the first dummy symbol. */
- if (!name)
- return TRUE;
-
- return elf_vxworks_link_output_symbol_hook (name, sym);
-}
-
static void
ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
{
ppc_elf_vxworks_add_symbol_hook
#undef elf_backend_link_output_symbol_hook
#define elf_backend_link_output_symbol_hook \
- elf_i386_vxworks_link_output_symbol_hook
+ elf_vxworks_link_output_symbol_hook
#undef elf_backend_final_write_processing
#define elf_backend_final_write_processing \
ppc_elf_vxworks_final_write_processing