/* PowerPC-specific support for 32-bit ELF
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
- Free Software Foundation, Inc.
+ Copyright (C) 1994-2014 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type ppc_elf_unhandled_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
-static void ppc_elf_vle_split16
- (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type);
/* Branch prediction bit for branch taken relocs. */
#define BRANCH_PREDICT_BIT 0x200000
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_NONE", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR32", /* name */
FALSE, /* partial_inplace */
26, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR24", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR14", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR14_BRTAKEN",/* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR14_BRNTAKEN",/* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_GOT16_HI", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_GOT16_HA", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_COPY", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_GLOB_DAT", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_JMP_SLOT", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_RELATIVE", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_UADDR32", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL32", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PLT32", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PLTREL32", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PLT16_HI", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_PLT16_HA", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_SECTOFF", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_SECTOFF_HI", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_SECTOFF_HA", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_NADDR32", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_NADDR16", /* name */
FALSE, /* partial_inplace */
HOWTO (R_PPC_VLE_LO16A, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_LO16A", /* name */
FALSE, /* partial_inplace */
HOWTO (R_PPC_VLE_LO16D, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_LO16D", /* name */
FALSE, /* partial_inplace */
/* Bits 16-31 split16a format. */
HOWTO (R_PPC_VLE_HI16A, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_HI16A", /* name */
FALSE, /* partial_inplace */
/* Bits 16-31 split16d format. */
HOWTO (R_PPC_VLE_HI16D, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_HI16D", /* name */
FALSE, /* partial_inplace */
/* Bits 16-31 (High Adjusted) in split16a format. */
HOWTO (R_PPC_VLE_HA16A, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_HA16A", /* name */
FALSE, /* partial_inplace */
/* Bits 16-31 (High Adjusted) in split16d format. */
HOWTO (R_PPC_VLE_HA16D, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_HA16D", /* name */
FALSE, /* partial_inplace */
0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
- /* This reloc does nothing. */
- HOWTO (R_PPC_VLE_SDA21, /* type */
+ /* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i
+ instructions. If the register base is 0 then the linker changes
+ the e_add16i to an e_li instruction. */
+ HOWTO (R_PPC_VLE_SDA21, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDA21", /* name */
FALSE, /* partial_inplace */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
- /* This reloc does nothing. */
+ /* Like R_PPC_VLE_SDA21 but ignore overflow. */
HOWTO (R_PPC_VLE_SDA21_LO, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDA21_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0, /* dst_mask */
+ 0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The 16 LSBS relative to _SDA_BASE_ in split16a format. */
HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_LO16A", /* name */
FALSE, /* partial_inplace */
FALSE), /* pcrel_offset */
/* The 16 LSBS relative to _SDA_BASE_ in split16d format. */
- /* This reloc does nothing. */
HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_LO16D", /* name */
FALSE, /* partial_inplace */
/* Bits 16-31 relative to _SDA_BASE_ in split16a format. */
HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_HI16A", /* name */
FALSE, /* partial_inplace */
/* Bits 16-31 relative to _SDA_BASE_ in split16d format. */
HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_HI16D", /* name */
FALSE, /* partial_inplace */
/* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */
HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_HA16A", /* name */
FALSE, /* partial_inplace */
/* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */
HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_HA16D", /* name */
FALSE, /* partial_inplace */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_IRELATIVE", /* name */
FALSE, /* partial_inplace */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL16", /* name */
FALSE, /* partial_inplace */
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, 4096 };
ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
if (ret == NULL)
ret->elf.init_plt_offset.offset = 0;
ret->elf.init_plt_offset.glist = NULL;
+ ret->params = &default_params;
+
ret->sdata[0].name = ".sdata";
ret->sdata[0].sym_name = "_SDA_BASE_";
ret->sdata[0].bss_name = ".sbss";
}
static void
-ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents,
- bfd_vma offset, bfd_vma relocation,
- split16_format_type split16_format)
+ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *loc,
+ bfd_vma value,
+ split16_format_type split16_format)
{
- bfd_vma insn, top5, bottom11;
+ unsigned int insn, top5;
- insn = bfd_get_32 (output_bfd, contents + offset);
- top5 = relocation >> 11;
- top5 = top5 << (split16_format == split16a_type ? 20 : 16);
- bottom11 = relocation & 0x7ff;
+ insn = bfd_get_32 (output_bfd, loc);
+ top5 = value & 0xf800;
+ top5 = top5 << (split16_format == split16a_type ? 9 : 5);
insn |= top5;
- insn |= bottom11;
- bfd_put_32 (output_bfd, insn, contents + offset);
+ insn |= value & 0x7ff;
+ bfd_put_32 (output_bfd, insn, loc);
}
\f
0x429f0005, /* bcl 20, 31, .Lxxx */
0x7d8802a6, /* mflr 12 */
0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */
- 0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */
+ 0x398c0000, /* addi 12, 12, (xxx-.Lxxx)@l */
0x7c0803a6, /* mtlr 0 */
0x7d8903a6, /* mtctr 12 */
0x4e800420, /* bctr */
/* This function implements long branch trampolines, and the ppc476
icache bug workaround. Any section needing trampolines or patch
space for the workaround has its size extended so that we can
- add trampolines at the end of the section. FIXME: We write out
- trampoline templates here and later modify them in
- relocate_section. We'd save a realloc if we left writing the
- templates to relocate_section. */
+ add trampolines at the end of the section. */
static bfd_boolean
ppc_elf_relax_section (bfd *abfd,
do anything. The linker doesn't support mixing -shared and -r
anyway. */
if (link_info->relocatable && link_info->shared)
- return TRUE;
+ return TRUE;
htab = ppc_elf_hash_table (link_info);
if (htab == NULL)
isec->rawsize = isec->size;
trampbase = isec->size;
+ BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE
+ || isec->sec_info_type == SEC_INFO_TYPE_TARGET);
+ isec->sec_info_type = SEC_INFO_TYPE_TARGET;
+
if (htab->params->ppc476_workaround)
{
if (elf_section_data (isec)->sec_info == NULL)
{
- BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE);
- isec->sec_info_type = SEC_INFO_TYPE_TARGET;
elf_section_data (isec)->sec_info
= bfd_zalloc (abfd, sizeof (struct ppc_elf_relax_info));
if (elf_section_data (isec)->sec_info == NULL)
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
+ && h == htab->tls_get_addr
+ && irel != internal_relocs)
+ {
+ unsigned long t_symndx = ELF32_R_SYM (irel[-1].r_info);
+ unsigned long t_rtype = ELF32_R_TYPE (irel[-1].r_info);
+ unsigned int tls_mask = 0;
+
+ /* The previous reloc should be one of R_PPC_TLSGD or
+ R_PPC_TLSLD, or for older object files, a reloc
+ on the __tls_get_addr arg setup insn. Get tls
+ mask bits from the symbol on that reloc. */
+ if (t_symndx < symtab_hdr->sh_info)
+ {
+ bfd_vma *local_got_offsets = elf_local_got_offsets (abfd);
+
+ if (local_got_offsets != NULL)
+ {
+ struct plt_entry **local_plt = (struct plt_entry **)
+ (local_got_offsets + symtab_hdr->sh_info);
+ char *lgot_masks = (char *)
+ (local_plt + symtab_hdr->sh_info);
+ tls_mask = lgot_masks[t_symndx];
+ }
+ }
+ else
+ {
+ struct elf_link_hash_entry *th
+ = elf_sym_hashes (abfd)[t_symndx - symtab_hdr->sh_info];
+
+ while (th->root.type == bfd_link_hash_indirect
+ || th->root.type == bfd_link_hash_warning)
+ th = (struct elf_link_hash_entry *) th->root.u.i.link;
+
+ tls_mask
+ = ((struct ppc_elf_link_hash_entry *) th)->tls_mask;
+ }
+
+ /* The mask bits tell us if the call will be
+ optimised away. */
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
+ && (t_rtype == R_PPC_TLSGD
+ || t_rtype == R_PPC_GOT_TLSGD16
+ || t_rtype == R_PPC_GOT_TLSGD16_LO))
+ continue;
+ if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
+ && (t_rtype == R_PPC_TLSLD
+ || t_rtype == R_PPC_GOT_TLSLD16
+ || t_rtype == R_PPC_GOT_TLSLD16_LO))
+ continue;
+ }
+
sym_type = h->type;
}
workaround_change = FALSE;
newsize = trampoff;
- if (htab->params->ppc476_workaround)
+ if (htab->params->ppc476_workaround
+ && (!link_info->relocatable
+ || isec->output_section->alignment_power >= htab->params->pagesize_p2))
{
bfd_vma addr, end_addr;
unsigned int crossings;
- unsigned int pagesize = htab->params->pagesize;
+ bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
addr = isec->output_section->vma + isec->output_offset;
end_addr = addr + trampoff - 1;
addr &= -pagesize;
- crossings = ((end_addr & -pagesize) - addr) / pagesize;
+ crossings = ((end_addr & -pagesize) - addr) >> htab->params->pagesize_p2;
if (crossings != 0)
{
/* Keep space aligned, to ensure the patch code itself does
{
relax_info->workaround_size = newsize;
workaround_change = TRUE;
- if (contents == NULL)
- {
- if (elf_section_data (isec)->this_hdr.contents != NULL)
- contents = elf_section_data (isec)->this_hdr.contents;
- else if (!bfd_malloc_and_get_section (abfd, isec, &contents))
- goto error_return;
- }
}
/* Ensure relocate_section is called. */
isec->flags |= SEC_RELOC;
newsize = trampoff + relax_info->workaround_size;
}
- if (changes || workaround_change)
- {
- contents = bfd_realloc_or_free (contents, newsize);
- if (contents == NULL)
- goto error_return;
-
- /* Branch around the trampolines. */
- if (maybe_pasted)
- {
- bfd_vma val = B + newsize - isec->rawsize;
- bfd_put_32 (abfd, val, contents + isec->rawsize);
- }
- }
-
- /* Write out the trampolines. */
- if (changes)
- {
- const int *stub;
- bfd_byte *dest;
- int i, size;
-
- dest = contents + trampbase;
- if (maybe_pasted && trampbase == isec->rawsize)
- dest += 4;
-
- if (link_info->shared)
- {
- stub = shared_stub_entry;
- size = ARRAY_SIZE (shared_stub_entry);
- }
- else
- {
- stub = stub_entry;
- size = ARRAY_SIZE (stub_entry);
- }
-
- i = 0;
- while (dest < contents + trampoff)
- {
- bfd_put_32 (abfd, stub[i], dest);
- i++;
- if (i == size)
- i = 0;
- dest += 4;
- }
- BFD_ASSERT (i == 0);
- }
-
if (changes || workaround_change)
isec->size = newsize;
if (contents != NULL
&& elf_section_data (isec)->this_hdr.contents != contents)
{
- if (!changes && !workaround_change && !link_info->keep_memory)
+ if (!changes && !link_info->keep_memory)
free (contents);
else
{
free (internal_relocs);
*again = changes != 0 || workaround_change;
- if (!*again && link_info->relocatable && htab->params->branch_trampolines)
- {
- /* Convert the internal relax relocs to external form. */
- for (irel = internal_relocs; irel < irelend; irel++)
- if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX)
- {
- unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
-
- /* Rewrite the reloc and convert one of the trailing nop
- relocs to describe this relocation. */
- BFD_ASSERT (ELF32_R_TYPE (irelend[-1].r_info) == R_PPC_NONE);
- /* The relocs are at the bottom 2 bytes */
- irel[0].r_offset += 2;
- memmove (irel + 1, irel, (irelend - irel - 1) * sizeof (*irel));
- irel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
- irel[1].r_offset += 4;
- irel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
- irel++;
- }
- }
-
return TRUE;
error_return:
bfd_boolean warned;
unsigned int tls_type, tls_mask, tls_gd;
struct plt_entry **ifunc;
+ struct reloc_howto_struct alt_howto;
r_type = ELF32_R_TYPE (rel->r_info);
sym = NULL;
addend specifies the GOT pointer offset within .got2. */
rel->r_addend += got2->output_offset;
}
- continue;
+ if (r_type != R_PPC_RELAX_PLT
+ && r_type != R_PPC_RELAX_PLTREL24
+ && r_type != R_PPC_RELAX)
+ continue;
}
/* TLS optimizations. Replace instruction sequences and relocs
howto->name,
sym_name);
}
- break;
+ break;
- /* Relocations that need no special processing. */
+ /* Relocations that need no special processing. */
case R_PPC_LOCAL24PC:
/* It makes no sense to point a local relocation
at a symbol not in this object. */
/* Fall thru */
case R_PPC_RELAX:
- if (info->shared)
- relocation -= (input_section->output_section->vma
- + input_section->output_offset
- + rel->r_offset - 4);
-
{
- unsigned long t0;
- unsigned long t1;
-
- t0 = bfd_get_32 (output_bfd, contents + rel->r_offset);
- t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4);
+ const int *stub;
+ size_t size;
+ size_t insn_offset = rel->r_offset;
+ unsigned int insn;
- /* We're clearing the bits for R_PPC_ADDR16_HA
- and R_PPC_ADDR16_LO here. */
- t0 &= ~0xffff;
- t1 &= ~0xffff;
+ if (info->shared)
+ {
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset - 4);
+ stub = shared_stub_entry;
+ bfd_put_32 (output_bfd, stub[0], contents + insn_offset - 12);
+ bfd_put_32 (output_bfd, stub[1], contents + insn_offset - 8);
+ bfd_put_32 (output_bfd, stub[2], contents + insn_offset - 4);
+ stub += 3;
+ size = ARRAY_SIZE (shared_stub_entry) - 3;
+ }
+ else
+ {
+ stub = stub_entry;
+ size = ARRAY_SIZE (stub_entry);
+ }
- /* t0 is HA, t1 is LO */
relocation += addend;
- t0 |= ((relocation + 0x8000) >> 16) & 0xffff;
- t1 |= relocation & 0xffff;
-
- bfd_put_32 (output_bfd, t0, contents + rel->r_offset);
- bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4);
+ if (info->relocatable)
+ relocation = 0;
+
+ /* First insn is HA, second is LO. */
+ insn = *stub++;
+ insn |= ((relocation + 0x8000) >> 16) & 0xffff;
+ bfd_put_32 (output_bfd, insn, contents + insn_offset);
+ insn_offset += 4;
+
+ insn = *stub++;
+ insn |= relocation & 0xffff;
+ bfd_put_32 (output_bfd, insn, contents + insn_offset);
+ insn_offset += 4;
+ size -= 2;
+
+ while (size != 0)
+ {
+ insn = *stub++;
+ --size;
+ bfd_put_32 (output_bfd, insn, contents + insn_offset);
+ insn_offset += 4;
+ }
/* Rewrite the reloc and convert one of the trailing nop
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 += 2;
+ 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;
break;
case R_PPC_VLE_LO16A:
- relocation = (relocation + addend) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- relocation, split16a_type);
+ relocation = relocation + addend;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ relocation, split16a_type);
continue;
case R_PPC_VLE_LO16D:
- relocation = (relocation + addend) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- relocation, split16d_type);
+ relocation = relocation + addend;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ relocation, split16d_type);
continue;
case R_PPC_VLE_HI16A:
- relocation = ((relocation + addend) >> 16) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- relocation, split16a_type);
+ relocation = (relocation + addend) >> 16;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ relocation, split16a_type);
continue;
case R_PPC_VLE_HI16D:
- relocation = ((relocation + addend) >> 16) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- relocation, split16d_type);
+ relocation = (relocation + addend) >> 16;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ relocation, split16d_type);
continue;
case R_PPC_VLE_HA16A:
- {
- bfd_vma value = relocation + addend;
- value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16a_type);
- }
+ relocation = (relocation + addend + 0x8000) >> 16;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ relocation, split16a_type);
continue;
case R_PPC_VLE_HA16D:
- {
- bfd_vma value = relocation + addend;
- value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16d_type);
- }
+ relocation = (relocation + addend + 0x8000) >> 16;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ relocation, split16d_type);
continue;
/* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */
{
const char *name;
int reg;
+ unsigned int insn;
struct elf_link_hash_entry *sda = NULL;
if (sec == NULL || sec->output_section == NULL)
addend -= SYM_VAL (sda);
}
+ insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
if (reg == 0
&& (r_type == R_PPC_VLE_SDA21
|| r_type == R_PPC_VLE_SDA21_LO))
{
- /* Use the split20 format. */
- bfd_vma insn, bits12to15, bits21to31;
- bfd_vma value = (relocation + rel->r_offset) & 0xffff;
- /* Propagate sign bit, if necessary. */
- insn = (value & 0x8000) ? 0x70107800 : 0x70000000;
- bits12to15 = value & 0x700;
- bits21to31 = value & 0x7ff;
- insn |= bits12to15;
- insn |= bits21to31;
- bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
- continue;
+ relocation = relocation + addend;
+ addend = 0;
+
+ /* Force e_li insn, keeping RT from original insn. */
+ insn &= 0x1f << 21;
+ insn |= 28u << 26;
+
+ /* We have an li20 field, bits 17..20, 11..15, 21..31. */
+ /* Top 4 bits of value to 17..20. */
+ insn |= (relocation & 0xf0000) >> 5;
+ /* Next 5 bits of the value to 11..15. */
+ insn |= (relocation & 0xf800) << 5;
+ /* And the final 11 bits of the value to bits 21 to 31. */
+ insn |= relocation & 0x7ff;
+
+ /* Use _bfd_final_link_relocate to report overflow,
+ but do so with a value that won't modify the insn. */
+ if (relocation + 0x80000 > 0x100000)
+ addend = 0x100000;
+ relocation = 0;
}
else if (r_type == R_PPC_EMB_SDA21
|| r_type == R_PPC_VLE_SDA21
|| r_type == R_PPC_VLE_SDA21_LO)
{
- bfd_vma insn; /* Fill in register field. */
-
- insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+ /* Fill in register field. */
insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
- bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
}
+ bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
}
break;
}
}
- value = sda->root.u.def.section->output_section->vma
- + sda->root.u.def.section->output_offset;
-
- if (r_type == R_PPC_VLE_SDAREL_LO16A)
- {
- value = (value + addend) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16a_type);
- }
- else if (r_type == R_PPC_VLE_SDAREL_LO16D)
+ value = (sda->root.u.def.section->output_section->vma
+ + sda->root.u.def.section->output_offset
+ + addend);
+
+ if (r_type == R_PPC_VLE_SDAREL_LO16A)
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ value, split16a_type);
+ else if (r_type == R_PPC_VLE_SDAREL_LO16D)
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ value, split16d_type);
+ else if (r_type == R_PPC_VLE_SDAREL_HI16A)
{
- value = (value + addend) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16d_type);
+ value = value >> 16;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ value, split16a_type);
}
- else if (r_type == R_PPC_VLE_SDAREL_HI16A)
+ else if (r_type == R_PPC_VLE_SDAREL_HI16D)
{
- value = ((value + addend) >> 16) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16a_type);
+ value = value >> 16;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ value, split16d_type);
}
- else if (r_type == R_PPC_VLE_SDAREL_HI16D)
+ else if (r_type == R_PPC_VLE_SDAREL_HA16A)
{
- value = ((value + addend) >> 16) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16d_type);
+ value = (value + 0x8000) >> 16;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ value, split16a_type);
}
- else if (r_type == R_PPC_VLE_SDAREL_HA16A)
+ else if (r_type == R_PPC_VLE_SDAREL_HA16D)
{
- value += addend;
- value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16a_type);
- }
- else if (r_type == R_PPC_VLE_SDAREL_HA16D)
- {
- value += addend;
- value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16d_type);
+ value = (value + 0x8000) >> 16;
+ ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+ value, split16d_type);
}
}
continue;
ret = FALSE;
}
- r = _bfd_final_link_relocate (howto,
- input_bfd,
- input_section,
- contents,
- rel->r_offset,
- relocation,
- addend);
+ /* 16-bit fields in insns mostly have signed values, but a
+ few insns have 16-bit unsigned values. Really, we should
+ have different reloc types. */
+ if (howto->complain_on_overflow != complain_overflow_dont
+ && howto->dst_mask == 0xffff
+ && (input_section->flags & SEC_CODE) != 0)
+ {
+ enum complain_overflow complain = complain_overflow_signed;
+
+ if ((elf_section_flags (input_section) & SHF_PPC_VLE) == 0)
+ {
+ unsigned int insn;
+
+ insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+ if ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+ || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+ || (insn & (0x3f << 26)) == 26u << 26 /* xori */
+ || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+ complain = complain_overflow_unsigned;
+ }
+ if (howto->complain_on_overflow != complain)
+ {
+ alt_howto = *howto;
+ alt_howto.complain_on_overflow = complain;
+ howto = &alt_howto;
+ }
+ }
+
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel->r_offset, relocation, addend);
if (r != bfd_reloc_ok)
{
fprintf (stderr, "\n");
#endif
+ if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET
+ && input_section->size != input_section->rawsize
+ && (strcmp (input_section->output_section->name, ".init") == 0
+ || strcmp (input_section->output_section->name, ".fini") == 0))
+ {
+ /* Branch around the trampolines. */
+ unsigned int insn = B + input_section->size - input_section->rawsize;
+ bfd_put_32 (input_bfd, insn, contents + input_section->rawsize);
+ }
+
if (htab->params->ppc476_workaround
- && input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
+ && input_section->sec_info_type == SEC_INFO_TYPE_TARGET
+ && (!info->relocatable
+ || (input_section->output_section->alignment_power
+ >= htab->params->pagesize_p2)))
{
struct ppc_elf_relax_info *relax_info;
bfd_vma start_addr, end_addr, addr;
- unsigned int pagesize = htab->params->pagesize;
+ 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)
the word alone. */
is_data = FALSE;
lo = relocs;
- hi = lo + input_section->reloc_count;
+ hi = relend;
+ rel = NULL;
while (lo < hi)
{
rel = lo + (hi - lo) / 2;
if (rel->r_offset < offset)
lo = rel + 1;
- else if (rel->r_offset > offset)
+ else if (rel->r_offset > offset + 3)
hi = rel;
else
{
patch_addr = (patch_addr + 15) & -16;
patch_off = patch_addr - start_addr;
bfd_put_32 (input_bfd, B + patch_off - offset, contents + offset);
+
+ if (rel != NULL
+ && rel->r_offset >= offset
+ && rel->r_offset < offset + 4)
+ {
+ /* 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. */
+ if (rel + 1 != relend)
+ {
+ Elf_Internal_Rela tmp = *rel;
+
+ /* Keep the relocs sorted by r_offset. */
+ memmove (rel, rel + 1, (relend - (rel + 1)) * sizeof (*rel));
+ relend[-1] = tmp;
+ }
+ relend[-1].r_offset += patch_off - offset;
+ }
+ else
+ rel = NULL;
+
if ((insn & (0x3f << 26)) == (16u << 26) /* bc */
&& (insn & 2) == 0 /* relative */)
{
bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
delta += offset - patch_off;
+ if (info->relocatable && rel != NULL)
+ delta = 0;
+ if (!info->relocatable && rel != NULL)
+ {
+ enum elf_ppc_reloc_type r_type;
+
+ r_type = ELF32_R_TYPE (relend[-1].r_info);
+ if (r_type == R_PPC_REL14_BRTAKEN)
+ insn |= BRANCH_PREDICT_BIT;
+ else if (r_type == R_PPC_REL14_BRNTAKEN)
+ insn &= ~BRANCH_PREDICT_BIT;
+ else
+ BFD_ASSERT (r_type == R_PPC_REL14);
+
+ if ((r_type == R_PPC_REL14_BRTAKEN
+ || r_type == R_PPC_REL14_BRNTAKEN)
+ && delta + 0x8000 < 0x10000
+ && (bfd_signed_vma) delta < 0)
+ insn ^= BRANCH_PREDICT_BIT;
+ }
if (delta + 0x8000 < 0x10000)
{
bfd_put_32 (input_bfd,
}
else
{
+ if (rel != NULL)
+ {
+ unsigned int r_sym = ELF32_R_SYM (relend[-1].r_info);
+
+ relend[-1].r_offset += 8;
+ relend[-1].r_info = ELF32_R_INFO (r_sym, R_PPC_REL24);
+ }
bfd_put_32 (input_bfd,
(insn & ~0xfffc) | 8,
contents + patch_off);
#define elf_backend_can_gc_sections 1
#define elf_backend_can_refcount 1
#define elf_backend_rela_normal 1
+#define elf_backend_caches_rawsize 1
#define bfd_elf32_mkobject ppc_elf_mkobject
#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data