/* PowerPC-specific support for 32-bit ELF
- Copyright (C) 1994-2018 Free Software Foundation, Inc.
+ Copyright (C) 1994-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
if (mach == 0)
{
s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
- if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents))
+ if (s != NULL
+ && s->size >= 24
+ && bfd_malloc_and_get_section (abfd, s, &contents))
{
unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4);
unsigned int i;
/* Finally we can generate the output section. */
static void
-ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
+ppc_final_write_processing (bfd *abfd)
{
bfd_byte *buffer;
asection *asec;
apuinfo_list_finish ();
}
+
+static bfd_boolean
+ppc_elf_final_write_processing (bfd *abfd)
+{
+ ppc_final_write_processing (abfd);
+ return _bfd_elf_final_write_processing (abfd);
+}
\f
static bfd_boolean
is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off)
of the other TLS bits are set. tls_optimize clears bits when
optimizing to indicate the corresponding GOT entry type is not
needed. If set, TLS_TLS is never cleared. tls_optimize may also
- set TLS_TPRELGD when a GD reloc turns into a TPREL one. We use a
- separate flag rather than setting TPREL just for convenience in
- distinguishing the two cases.
+ set TLS_GDIE when a GD reloc turns into an IE one.
These flags are also kept for local symbols. */
#define TLS_TLS 1 /* Any TLS reloc. */
#define TLS_GD 2 /* GD reloc. */
#define TLS_TPREL 8 /* TPREL reloc, => IE. */
#define TLS_DTPREL 16 /* DTPREL reloc, => LD. */
#define TLS_MARK 32 /* __tls_get_addr call marked. */
-#define TLS_TPRELGD 64 /* TPREL reloc resulting from GD->IE. */
+#define TLS_GDIE 64 /* GOT TPREL reloc resulting from GD->IE. */
unsigned char tls_mask;
/* The above field is also used to mark function symbols. In which
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_PPC_GNU_VTENTRY:
- BFD_ASSERT (h != NULL);
- if (h != NULL
- && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return FALSE;
break;
tls_set = 0;
else
/* GD -> IE */
- tls_set = TLS_TLS | TLS_TPRELGD;
+ tls_set = TLS_TLS | TLS_GDIE;
tls_clear = TLS_GD;
break;
need = 0;
if ((tls_mask & TLS_GD) != 0)
need += 8;
- if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
+ if ((tls_mask & (TLS_TPREL | TLS_GDIE)) != 0)
need += 4;
if ((tls_mask & TLS_DTPREL) != 0)
need += 4;
condition as that for IE, but ld.so needs to differentiate
LD and GD entries. */
if (known && (tls_mask & TLS_TLS) != 0
- && (tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
+ && (tls_mask & (TLS_TPREL | TLS_GDIE)) != 0)
need -= 4;
return need * sizeof (Elf32_External_Rela) / 4;
}
(bfd_link_relocatable (info)) ? " (relocatable)" : "");
#endif
+ if (!is_ppc_elf (input_bfd))
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
got2 = bfd_get_section_by_name (input_bfd, ".got2");
/* Initialize howto table if not already done. */
case R_PPC_GOT_TLSGD16_HI:
case R_PPC_GOT_TLSGD16_HA:
- tls_gd = TLS_TPRELGD;
+ tls_gd = TLS_GDIE;
if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
goto tls_gdld_hi;
break;
case R_PPC_GOT_TLSGD16:
case R_PPC_GOT_TLSGD16_LO:
- tls_gd = TLS_TPRELGD;
+ tls_gd = TLS_GDIE;
if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
goto tls_ldgd_opt;
break;
break;
}
- if ((tls_mask & TLS_TPRELGD) != 0)
+ if ((tls_mask & TLS_GDIE) != 0)
{
/* IE */
r_type = R_PPC_NONE;
{
unsigned int tls_m = ((tls_mask & TLS_TLS) != 0
? tls_mask & (TLS_LD | TLS_GD | TLS_DTPREL
- | TLS_TPREL | TLS_TPRELGD)
+ | TLS_TPREL | TLS_GDIE)
: 0);
if (offp == &htab->tlsld_got.offset)
tls_ty = TLS_TLS | TLS_DTPREL;
tls_m &= ~TLS_DTPREL;
}
- else if ((tls_m & (TLS_TPREL | TLS_TPRELGD)) != 0)
+ else if ((tls_m & (TLS_TPREL | TLS_GDIE)) != 0)
{
tls_ty = TLS_TLS | TLS_TPREL;
tls_m = 0;
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
+ /* Optimize unaligned reloc use. */
+ if ((r_type == R_PPC_ADDR32 && (outrel.r_offset & 3) != 0)
+ || (r_type == R_PPC_UADDR32 && (outrel.r_offset & 3) == 0))
+ r_type ^= R_PPC_ADDR32 ^ R_PPC_UADDR32;
+ if ((r_type == R_PPC_ADDR16 && (outrel.r_offset & 1) != 0)
+ || (r_type == R_PPC_UADDR16 && (outrel.r_offset & 1) == 0))
+ r_type ^= R_PPC_ADDR16 ^ R_PPC_UADDR16;
+
if (skip)
memset (&outrel, 0, sizeof outrel);
else if (!SYMBOL_REFERENCES_LOCAL (info, h))
but ld.so expects buggy relocs.
FIXME: Why not always use a zero index? */
osec = sec->output_section;
- indx = elf_section_data (osec)->dynindx;
- if (indx == 0)
+ if ((osec->flags & SEC_THREAD_LOCAL) != 0)
+ {
+ osec = htab->elf.tls_sec;
+ indx = 0;
+ }
+ else
{
- osec = htab->elf.text_index_section;
indx = elf_section_data (osec)->dynindx;
+ if (indx == 0)
+ {
+ osec = htab->elf.text_index_section;
+ indx = elf_section_data (osec)->dynindx;
+ }
+ BFD_ASSERT (indx != 0);
}
- BFD_ASSERT (indx != 0);
-#ifdef DEBUG
- if (indx == 0)
- printf ("indx=%ld section=%s flags=%08x name=%s\n",
- indx, osec->name, osec->flags,
- h->root.root.string);
-#endif
+
+ /* ld.so doesn't expect buggy TLS relocs.
+ Don't leave the symbol value in the
+ addend for them. */
+ if (IS_PPC_TLS_RELOC (r_type))
+ outrel.r_addend -= osec->vma;
}
outrel.r_info = ELF32_R_INFO (indx, r_type);
addend -= SYM_VAL (sda);
}
+ if (r_type == R_PPC_EMB_RELSDA)
+ break;
+
+ /* The PowerPC Embedded Application Binary Interface
+ version 1.0 insanely chose to specify R_PPC_EMB_SDA21
+ operating on a 24-bit field at r_offset. GNU as and
+ GNU ld have always assumed R_PPC_EMB_SDA21 operates on
+ a 32-bit bit insn at r_offset. Cope with object file
+ producers that possibly comply with the EABI in
+ generating an odd r_offset for big-endian objects. */
+ if (r_type == R_PPC_EMB_SDA21)
+ rel->r_offset &= ~1;
+
insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
if (reg == 0
&& (r_type == R_PPC_VLE_SDA21
goto overflow;
goto copy_reloc;
}
- else if (r_type == R_PPC_EMB_SDA21
- || r_type == R_PPC_VLE_SDA21
- || r_type == R_PPC_VLE_SDA21_LO)
- {
- /* Fill in register field. */
- insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
- }
+ /* Fill in register field. */
+ insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
}
break;
}
else if (htab->plt_type != PLT_NEW)
info->callbacks->einfo
- (_("%P: %H: %s relocation unsupported for bss-plt\n"),
+ (_("%X%P: %H: %s relocation unsupported for bss-plt\n"),
input_bfd, input_section, rel->r_offset,
howto->name);
break;
}
else if (htab->plt_type != PLT_NEW)
info->callbacks->einfo
- (_("%P: %H: %s relocation unsupported for bss-plt\n"),
+ (_("%X%P: %H: %s relocation unsupported for bss-plt\n"),
input_bfd, input_section, rel->r_offset,
howto->name);
break;
bfd_byte *loc;
bfd_vma val;
Elf_Internal_Rela rela;
+ unsigned char *p;
if (!get_sym_h (NULL, &sym, &sym_sec, NULL, &local_syms,
lplt - local_plt, ibfd))
loc = relplt->contents + (relplt->reloc_count++
* sizeof (Elf32_External_Rela));
bfd_elf32_swap_reloca_out (info->output_bfd, &rela, loc);
- }
- if ((ent->glink_offset & 1) == 0)
- {
- unsigned char *p = ((unsigned char *) htab->glink->contents
- + ent->glink_offset);
+ p = (unsigned char *) htab->glink->contents + ent->glink_offset;
write_glink_stub (NULL, ent, htab->elf.iplt, p, info);
- ent->glink_offset |= 1;
}
}
return ppc_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp);
}
-static void
-ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
+static bfd_boolean
+ppc_elf_vxworks_final_write_processing (bfd *abfd)
{
- ppc_elf_final_write_processing (abfd, linker);
- elf_vxworks_final_write_processing (abfd, linker);
+ ppc_final_write_processing (abfd);
+ return elf_vxworks_final_write_processing (abfd);
}
/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so