/* PowerPC-specific support for 32-bit ELF
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
suggestions from the in-progress Embedded PowerPC ABI, and that
information may also not match. */
+#include <stdarg.h>
#include "bfd.h"
#include "sysdep.h"
#include "bfdlink.h"
return ppc_elf_howto_table[r];
};
+static reloc_howto_type *
+ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0;
+ i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]);
+ i++)
+ if (ppc_elf_howto_raw[i].name != NULL
+ && strcasecmp (ppc_elf_howto_raw[i].name, r_name) == 0)
+ return &ppc_elf_howto_raw[i];
+
+ return NULL;
+}
+
/* Set the howto pointer for a PowerPC ELF reloc. */
static void
static bfd_boolean
ppc_elf_mkobject (bfd *abfd)
{
- bfd_size_type amt = sizeof (struct ppc_elf_obj_tdata);
- abfd->tdata.any = bfd_zalloc (abfd, amt);
if (abfd->tdata.any == NULL)
- return FALSE;
- return TRUE;
+ {
+ bfd_size_type amt = sizeof (struct ppc_elf_obj_tdata);
+ abfd->tdata.any = bfd_zalloc (abfd, amt);
+ if (abfd->tdata.any == NULL)
+ return FALSE;
+ }
+ return bfd_elf_mkobject (abfd);
}
/* Fix bad default arch selected for a 32 bit input bfd when the
return TRUE;
}
+static char *
+ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...)
+{
+ switch (note_type)
+ {
+ default:
+ return NULL;
+
+ case NT_PRPSINFO:
+ {
+ char data[128];
+ va_list ap;
+
+ va_start (ap, note_type);
+ memset (data, 0, 32);
+ strncpy (data + 32, va_arg (ap, const char *), 16);
+ strncpy (data + 48, va_arg (ap, const char *), 80);
+ va_end (ap);
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", note_type, data, sizeof (data));
+ }
+
+ case NT_PRSTATUS:
+ {
+ char data[268];
+ va_list ap;
+ long pid;
+ int cursig;
+ const void *greg;
+
+ va_start (ap, note_type);
+ memset (data, 0, 72);
+ pid = va_arg (ap, long);
+ bfd_put_32 (abfd, pid, data + 24);
+ cursig = va_arg (ap, int);
+ bfd_put_16 (abfd, cursig, data + 12);
+ greg = va_arg (ap, const void *);
+ memcpy (data + 72, greg, 192);
+ memset (data + 264, 0, 4);
+ va_end (ap);
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", note_type, data, sizeof (data));
+ }
+ }
+}
+
/* Return address for Ith PLT stub in section PLT, for relocation REL
or (bfd_vma) -1 if it should not be included. */
need to bump up the number of section headers. */
static int
-ppc_elf_additional_program_headers (bfd *abfd)
+ppc_elf_additional_program_headers (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
asection *s;
int ret = 0;
static const struct bfd_elf_special_section ppc_elf_special_sections[] =
{
- { ".plt", 4, 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR },
- { ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
- { ".sbss2", 6, -2, SHT_PROGBITS, SHF_ALLOC },
- { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
- { ".sdata2", 7, -2, SHT_PROGBITS, SHF_ALLOC },
- { ".tags", 5, 0, SHT_ORDERED, SHF_ALLOC },
- { ".PPC.EMB.apuinfo", 16, 0, SHT_NOTE, 0 },
- { ".PPC.EMB.sbss0", 14, 0, SHT_PROGBITS, SHF_ALLOC },
- { ".PPC.EMB.sdata0", 15, 0, SHT_PROGBITS, SHF_ALLOC },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC },
+ { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC },
+ { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC },
+ { STRING_COMMA_LEN (".PPC.EMB.apuinfo"), 0, SHT_NOTE, 0 },
+ { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC },
+ { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC },
+ { NULL, 0, 0, 0, 0 }
};
/* This is what we want for new plt/got. */
static struct bfd_elf_special_section ppc_alt_plt =
- { ".plt", 4, 0, SHT_PROGBITS, SHF_ALLOC };
+ { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC };
static const struct bfd_elf_special_section *
ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
static bfd_boolean
ppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
asection *asec,
bfd_byte *contents ATTRIBUTE_UNUSED)
{
if (name == NULL)
return FALSE;
- BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ BFD_ASSERT (CONST_STRNEQ (name, ".rela")
&& strcmp (bfd_get_section_name (abfd, sec),
name + 5) == 0);
static asection *
ppc_elf_gc_mark_hook (asection *sec,
- struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info,
Elf_Internal_Rela *rel,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
if (h != NULL)
- {
- switch (ELF32_R_TYPE (rel->r_info))
- {
- case R_PPC_GNU_VTINHERIT:
- case R_PPC_GNU_VTENTRY:
- break;
-
- default:
- switch (h->root.type)
- {
- case bfd_link_hash_defined:
- case bfd_link_hash_defweak:
- return h->root.u.def.section;
-
- case bfd_link_hash_common:
- return h->root.u.c.p->section;
-
- default:
- break;
- }
- }
- }
- else
- return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_PPC_GNU_VTINHERIT:
+ case R_PPC_GNU_VTENTRY:
+ return NULL;
+ }
- return NULL;
+ return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
}
/* Update the got, plt and dynamic reloc reference counts for the
}
else
ent->plt.offset = (bfd_vma) -1;
-
- if (!doneone)
- {
- h->plt.plist = NULL;
- h->needs_plt = 0;
- }
}
+ else
+ ent->plt.offset = (bfd_vma) -1;
+
+ if (!doneone)
+ {
+ h->plt.plist = NULL;
+ h->needs_plt = 0;
+ }
}
else
{
{
/* Strip these too. */
}
- else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
+ else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
{
if (s->size != 0)
{
asection *got2, *sreloc = NULL;
bfd_vma *local_got_offsets;
bfd_boolean ret = TRUE;
+ bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
#ifdef DEBUG
_bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
got2 = bfd_get_section_by_name (input_bfd, ".got2");
- if (info->relocatable)
- {
- if (got2 == NULL)
- return TRUE;
-
- rel = relocs;
- relend = relocs + input_section->reloc_count;
- for (; rel < relend; rel++)
- {
- enum elf_ppc_reloc_type r_type;
-
- r_type = ELF32_R_TYPE (rel->r_info);
- if (r_type == R_PPC_PLTREL24
- && rel->r_addend >= 32768)
- {
- /* R_PPC_PLTREL24 is rather special. If non-zero, the
- addend specifies the GOT pointer offset within .got2. */
- rel->r_addend += got2->output_offset;
- }
- }
- return TRUE;
- }
-
/* Initialize howto table if not already done. */
if (!ppc_elf_howto_table[R_PPC_ADDR32])
ppc_elf_howto_init ();
sym_name = h->root.root.string;
}
+ if (sec != NULL && elf_discarded_section (sec))
+ {
+ /* For relocs against symbols from removed linkonce sections,
+ or sections discarded by a linker script, we just want the
+ section contents zeroed. Avoid any special processing. */
+ howto = NULL;
+ if (r_type < R_PPC_max)
+ howto = ppc_elf_howto_table[r_type];
+ _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+ rel->r_info = 0;
+ rel->r_addend = 0;
+ continue;
+ }
+
+ if (info->relocatable)
+ {
+ if (got2 != NULL
+ && r_type == R_PPC_PLTREL24
+ && rel->r_addend >= 32768)
+ {
+ /* R_PPC_PLTREL24 is rather special. If non-zero, the
+ addend specifies the GOT pointer offset within .got2. */
+ rel->r_addend += got2->output_offset;
+ }
+ continue;
+ }
+
/* TLS optimizations. Replace instruction sequences and relocs
based on information we collected in tls_optimize. We edit
RELOCS so that --emit-relocs will output something sensible
&& (tls_mask & TLS_TPREL) == 0)
{
bfd_vma insn;
- insn = bfd_get_32 (output_bfd, contents + rel->r_offset - 2);
+ 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 - 2);
+ 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);
}
bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
r_type = R_PPC_TPREL16_LO;
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+
/* Was PPC_TLS which sits on insn boundary, now
- PPC_TPREL16_LO which is at insn+2. */
- rel->r_offset += 2;
+ PPC_TPREL16_LO which is at low-order half-word. */
+ rel->r_offset += d_offset;
}
break;
else
{
bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
- rel->r_offset -= 2;
+ rel->r_offset -= d_offset;
r_type = R_PPC_NONE;
}
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
/* OK, it checks out. Replace the call. */
offset = rel[1].r_offset;
insn1 = bfd_get_32 (output_bfd,
- contents + rel->r_offset - 2);
+ contents + rel->r_offset - d_offset);
if ((tls_mask & tls_gd) != 0)
{
/* IE */
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_offset += d_offset;
rel[1].r_addend = rel->r_addend;
}
- bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - 2);
+ bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - d_offset);
bfd_put_32 (output_bfd, insn2, contents + offset);
if (tls_gd == 0)
{
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_UADDR32:
case R_PPC_UADDR16:
- /* r_symndx will be zero only for relocs against symbols
- from removed linkonce sections, or sections discarded by
- a linker script. */
dodyn:
- if (r_symndx == 0)
- break;
- /* Fall thru. */
-
if ((input_section->flags & SEC_ALLOC) == 0)
break;
/* Fall thru. */
if (name == NULL)
return FALSE;
- BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+ BFD_ASSERT (CONST_STRNEQ (name, ".rela")
&& strcmp (bfd_get_section_name (input_bfd,
input_section),
name + 5) == 0);
but ld.so expects buggy relocs. */
osec = sec->output_section;
indx = elf_section_data (osec)->dynindx;
- BFD_ASSERT (indx > 0);
+ if (indx == 0)
+ {
+ osec = htab->elf.text_index_section;
+ indx = elf_section_data (osec)->dynindx;
+ }
+ BFD_ASSERT (indx != 0);
#ifdef DEBUG
- if (indx <= 0)
+ if (indx == 0)
printf ("indx=%ld section=%s flags=%08x name=%s\n",
indx, osec->name, osec->flags,
h->root.root.string);
BFD_ASSERT (sec != NULL);
name = bfd_get_section_name (abfd, sec->output_section);
- if (! ((strncmp (name, ".sdata", 6) == 0
+ if (! ((CONST_STRNEQ (name, ".sdata")
&& (name[6] == 0 || name[6] == '.'))
- || (strncmp (name, ".sbss", 5) == 0
+ || (CONST_STRNEQ (name, ".sbss")
&& (name[5] == 0 || name[5] == '.'))))
{
(*_bfd_error_handler)
BFD_ASSERT (sec != NULL);
name = bfd_get_section_name (abfd, sec->output_section);
- if (! (strncmp (name, ".sdata2", 7) == 0
- || strncmp (name, ".sbss2", 6) == 0))
+ if (! (CONST_STRNEQ (name, ".sdata2")
+ || CONST_STRNEQ (name, ".sbss2")))
{
(*_bfd_error_handler)
(_("%B: the target (%s) of a %s relocation is "
BFD_ASSERT (sec != NULL);
name = bfd_get_section_name (abfd, sec->output_section);
- if (((strncmp (name, ".sdata", 6) == 0
+ if (((CONST_STRNEQ (name, ".sdata")
&& (name[6] == 0 || name[6] == '.'))
- || (strncmp (name, ".sbss", 5) == 0
+ || (CONST_STRNEQ (name, ".sbss")
&& (name[5] == 0 || name[5] == '.'))))
{
reg = 13;
+ sh->root.u.def.section->output_section->vma);
}
- else if (strncmp (name, ".sdata2", 7) == 0
- || strncmp (name, ".sbss2", 6) == 0)
+ else if (CONST_STRNEQ (name, ".sdata2")
+ || CONST_STRNEQ (name, ".sbss2"))
{
reg = 2;
sh = htab->sdata[1].sym;
case R_PPC_ADDR16_HA:
case R_PPC_REL16_HA:
- case R_PPC_GOT16_HA:
- case R_PPC_PLT16_HA:
case R_PPC_SECTOFF_HA:
case R_PPC_TPREL16_HA:
case R_PPC_DTPREL16_HA:
- case R_PPC_GOT_TLSGD16_HA:
- case R_PPC_GOT_TLSLD16_HA:
- case R_PPC_GOT_TPREL16_HA:
- case R_PPC_GOT_DTPREL16_HA:
case R_PPC_EMB_NADDR16_HA:
case R_PPC_EMB_RELST_HA:
/* It's just possible that this symbol is a weak symbol
that's not actually defined anywhere. In that case,
'sec' would be NULL, and we should leave the symbol
alone (it will be set to zero elsewhere in the link). */
- if (sec != NULL)
- /* Add 0x10000 if sign bit in 0:15 is set.
- Bits 0:15 are not used. */
- addend += 0x8000;
+ if (sec == NULL)
+ break;
+ /* Fall thru */
+
+ case R_PPC_PLT16_HA:
+ case R_PPC_GOT16_HA:
+ case R_PPC_GOT_TLSGD16_HA:
+ case R_PPC_GOT_TLSLD16_HA:
+ case R_PPC_GOT_TPREL16_HA:
+ case R_PPC_GOT_DTPREL16_HA:
+ /* Add 0x10000 if sign bit in 0:15 is set.
+ Bits 0:15 are not used. */
+ addend += 0x8000;
break;
}
#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data
#define bfd_elf32_bfd_relax_section ppc_elf_relax_section
#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup
#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags
#define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create
#define elf_backend_additional_program_headers ppc_elf_additional_program_headers
#define elf_backend_grok_prstatus ppc_elf_grok_prstatus
#define elf_backend_grok_psinfo ppc_elf_grok_psinfo
+#define elf_backend_write_core_note ppc_elf_write_core_note
#define elf_backend_reloc_type_class ppc_elf_reloc_type_class
#define elf_backend_begin_write_processing ppc_elf_begin_write_processing
#define elf_backend_final_write_processing ppc_elf_final_write_processing
#define elf_backend_get_sec_type_attr ppc_elf_get_sec_type_attr
#define elf_backend_plt_sym_val ppc_elf_plt_sym_val
#define elf_backend_action_discarded ppc_elf_action_discarded
+#define elf_backend_init_index_section _bfd_elf_init_1_index_section
#include "elf32-target.h"