/* 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-2017 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
#include "elf32-ppc.h"
#include "elf-vxworks.h"
#include "dwarf2.h"
+#include "opcode/ppc.h"
typedef enum split16_format_type
{
(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
#define ADD_3_12_2 0x7c6c1214
#define ADD_11_0_11 0x7d605a14
#define B 0x48000000
+#define BA 0x48000002
#define BCL_20_31 0x429f0005
#define BCTR 0x4e800420
#define BEQLR 0x4d820020
/* This reloc does nothing. */
HOWTO (R_PPC_NONE, /* type */
0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 3, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* 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 */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- ppc_elf_addr16_ha_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
26, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_signed, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_PLTREL24", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_COPY", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GLOB_DAT", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_JMP_SLOT", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
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 */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_PLT32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
32, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_PLTREL32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_PLT16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_PLT16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- ppc_elf_addr16_ha_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_PLT16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_SDAREL16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_signed, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_SECTOFF", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_SECTOFF_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_SECTOFF_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- ppc_elf_addr16_ha_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_SECTOFF_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_NADDR32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_signed, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_NADDR16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont,/* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_ADDR16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_NADDR16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- ppc_elf_addr16_ha_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_NADDR16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_SDAI16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_SDA2I16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_SDA2REL", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_SDA21", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_EMB_RELSDA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* src_mask */
0xff, /* dst_mask */
TRUE), /* pcrel_offset */
-
+
/* A relative 15 bit branch. */
HOWTO (R_PPC_VLE_REL15, /* type */
1, /* rightshift */
"R_PPC_VLE_REL15", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0xfe, /* dst_mask */
+ 0xfffe, /* dst_mask */
TRUE), /* pcrel_offset */
- /* A relative 24 bit branch. */
+ /* A relative 24 bit branch. */
HOWTO (R_PPC_VLE_REL24, /* type */
1, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
HOWTO (R_PPC_VLE_LO16A, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- FALSE, /* pc_relative */ /* FIXME: Does this apply to split relocs? */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_VLE_LO16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f00fff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The 16 LSBS in split16d format. */
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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_LO16D", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_LO16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x3e007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_HI16A", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_HI16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f00fff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_HI16D", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_HI16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x3e007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_HA16A", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_HA16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f00fff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_HA16D", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_HA16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x3e007ff, /* 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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_SDA21", /* name */
+ complain_overflow_signed, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_SDA21", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
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 */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_LO16A", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_SDAREL_LO16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f00fff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_LO16D", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_SDAREL_LO16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x3e007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 relative to _SDA_BASE_ in split16a format. */
- HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */
- 0, /* rightshift */
+ HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */
+ 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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_HI16A", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_SDAREL_HI16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f00fff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 relative to _SDA_BASE_ in split16d format. */
- HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */
- 0, /* rightshift */
+ HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */
+ 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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_HI16D", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_SDAREL_HI16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x3e007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */
- HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */
- 0, /* rightshift */
+ HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */
+ 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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_HA16A", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_SDAREL_HA16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f00fff, /* dst_mask */
+ 0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */
- HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */
- 0, /* rightshift */
+ HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */
+ 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 */
- bfd_elf_generic_reloc, /* special_function */
- "R_PPC_VLE_SDAREL_HA16D", /* name */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
+ "R_PPC_VLE_SDAREL_HA16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
- 0x1f07ff, /* dst_mask */
+ 0x3e007ff, /* dst_mask */
FALSE), /* pcrel_offset */
HOWTO (R_PPC_IRELATIVE, /* type */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ complain_overflow_dont, /* complain_on_overflow */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_IRELATIVE", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
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 */
0xffff, /* dst_mask */
TRUE), /* pcrel_offset */
+ /* Like R_PPC_REL16_HA but for split field in addpcis. */
+ HOWTO (R_PPC_REL16DX_HA, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ ppc_elf_addr16_ha_reloc, /* special_function */
+ "R_PPC_REL16DX_HA", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x1fffc1, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
/* GNU extension to record C++ vtable hierarchy. */
HOWTO (R_PPC_GNU_VTINHERIT, /* type */
0, /* rightshift */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_TOC16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
};
+
+/* External 32-bit PPC structure for PRPSINFO. This structure is
+ ABI-defined, thus we choose to use char arrays here in order to
+ avoid dealing with different types in different architectures.
+
+ The PPC 32-bit structure uses int for `pr_uid' and `pr_gid' while
+ most non-PPC architectures use `short int'.
+
+ This structure will ultimately be written in the corefile's note
+ section, as the PRPSINFO. */
+
+struct elf_external_ppc_linux_prpsinfo32
+ {
+ char pr_state; /* Numeric process state. */
+ char pr_sname; /* Char for pr_state. */
+ char pr_zomb; /* Zombie. */
+ char pr_nice; /* Nice val. */
+ char pr_flag[4]; /* Flags. */
+ char pr_uid[4];
+ char pr_gid[4];
+ char pr_pid[4];
+ char pr_ppid[4];
+ char pr_pgrp[4];
+ char pr_sid[4];
+ char pr_fname[16]; /* Filename of executable. */
+ char pr_psargs[80]; /* Initial part of arg list. */
+ };
+
+/* Helper function to copy an elf_internal_linux_prpsinfo in host
+ endian to an elf_external_ppc_linux_prpsinfo32 in target endian. */
+
+static inline void
+swap_ppc_linux_prpsinfo32_out (bfd *obfd,
+ const struct elf_internal_linux_prpsinfo *from,
+ struct elf_external_ppc_linux_prpsinfo32 *to)
+{
+ bfd_put_8 (obfd, from->pr_state, &to->pr_state);
+ bfd_put_8 (obfd, from->pr_sname, &to->pr_sname);
+ bfd_put_8 (obfd, from->pr_zomb, &to->pr_zomb);
+ bfd_put_8 (obfd, from->pr_nice, &to->pr_nice);
+ bfd_put_32 (obfd, from->pr_flag, to->pr_flag);
+ bfd_put_32 (obfd, from->pr_uid, to->pr_uid);
+ bfd_put_32 (obfd, from->pr_gid, to->pr_gid);
+ bfd_put_32 (obfd, from->pr_pid, to->pr_pid);
+ bfd_put_32 (obfd, from->pr_ppid, to->pr_ppid);
+ bfd_put_32 (obfd, from->pr_pgrp, to->pr_pgrp);
+ bfd_put_32 (obfd, from->pr_sid, to->pr_sid);
+ strncpy (to->pr_fname, from->pr_fname, sizeof (to->pr_fname));
+ strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs));
+}
\f
/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */
case BFD_RELOC_NONE: r = R_PPC_NONE; break;
case BFD_RELOC_32: r = R_PPC_ADDR32; break;
case BFD_RELOC_PPC_BA26: r = R_PPC_ADDR24; break;
+ case BFD_RELOC_PPC64_ADDR16_DS:
case BFD_RELOC_16: r = R_PPC_ADDR16; break;
+ case BFD_RELOC_PPC64_ADDR16_LO_DS:
case BFD_RELOC_LO16: r = R_PPC_ADDR16_LO; break;
case BFD_RELOC_HI16: r = R_PPC_ADDR16_HI; break;
case BFD_RELOC_HI16_S: r = R_PPC_ADDR16_HA; break;
case BFD_RELOC_PPC_B16: r = R_PPC_REL14; break;
case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC_REL14_BRTAKEN; break;
case BFD_RELOC_PPC_B16_BRNTAKEN: r = R_PPC_REL14_BRNTAKEN; break;
+ case BFD_RELOC_PPC64_GOT16_DS:
case BFD_RELOC_16_GOTOFF: r = R_PPC_GOT16; break;
+ case BFD_RELOC_PPC64_GOT16_LO_DS:
case BFD_RELOC_LO16_GOTOFF: r = R_PPC_GOT16_LO; break;
case BFD_RELOC_HI16_GOTOFF: r = R_PPC_GOT16_HI; break;
case BFD_RELOC_HI16_S_GOTOFF: r = R_PPC_GOT16_HA; break;
case BFD_RELOC_32_PCREL: r = R_PPC_REL32; break;
case BFD_RELOC_32_PLTOFF: r = R_PPC_PLT32; break;
case BFD_RELOC_32_PLT_PCREL: r = R_PPC_PLTREL32; break;
+ case BFD_RELOC_PPC64_PLT16_LO_DS:
case BFD_RELOC_LO16_PLTOFF: r = R_PPC_PLT16_LO; break;
case BFD_RELOC_HI16_PLTOFF: r = R_PPC_PLT16_HI; break;
case BFD_RELOC_HI16_S_PLTOFF: r = R_PPC_PLT16_HA; break;
case BFD_RELOC_GPREL16: r = R_PPC_SDAREL16; break;
+ case BFD_RELOC_PPC64_SECTOFF_DS:
case BFD_RELOC_16_BASEREL: r = R_PPC_SECTOFF; break;
+ case BFD_RELOC_PPC64_SECTOFF_LO_DS:
case BFD_RELOC_LO16_BASEREL: r = R_PPC_SECTOFF_LO; break;
case BFD_RELOC_HI16_BASEREL: r = R_PPC_SECTOFF_HI; break;
case BFD_RELOC_HI16_S_BASEREL: r = R_PPC_SECTOFF_HA; break;
case BFD_RELOC_CTOR: r = R_PPC_ADDR32; break;
+ case BFD_RELOC_PPC64_TOC16_DS:
case BFD_RELOC_PPC_TOC16: r = R_PPC_TOC16; break;
case BFD_RELOC_PPC_TLS: r = R_PPC_TLS; break;
case BFD_RELOC_PPC_TLSGD: r = R_PPC_TLSGD; break;
case BFD_RELOC_PPC_TLSLD: r = R_PPC_TLSLD; break;
case BFD_RELOC_PPC_DTPMOD: r = R_PPC_DTPMOD32; break;
+ case BFD_RELOC_PPC64_TPREL16_DS:
case BFD_RELOC_PPC_TPREL16: r = R_PPC_TPREL16; break;
+ case BFD_RELOC_PPC64_TPREL16_LO_DS:
case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC_TPREL16_LO; break;
case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC_TPREL16_HI; break;
case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC_TPREL16_HA; break;
case BFD_RELOC_PPC_TPREL: r = R_PPC_TPREL32; break;
+ case BFD_RELOC_PPC64_DTPREL16_DS:
case BFD_RELOC_PPC_DTPREL16: r = R_PPC_DTPREL16; break;
+ case BFD_RELOC_PPC64_DTPREL16_LO_DS:
case BFD_RELOC_PPC_DTPREL16_LO: r = R_PPC_DTPREL16_LO; break;
case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC_DTPREL16_HI; break;
case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC_DTPREL16_HA; break;
case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break;
case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break;
case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break;
+ case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC_REL16DX_HA; break;
case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break;
case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break;
}
arelent *cache_ptr,
Elf_Internal_Rela *dst)
{
+ unsigned int r_type;
+
/* Initialize howto table if not already done. */
if (!ppc_elf_howto_table[R_PPC_ADDR32])
ppc_elf_howto_init ();
- 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)];
+ r_type = ELF32_R_TYPE (dst->r_info);
+ if (r_type >= R_PPC_max)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B: unrecognised PPC reloc number: %d"),
+ abfd, r_type);
+ bfd_set_error (bfd_error_bad_value);
+ r_type = R_PPC_NONE;
+ }
+ cache_ptr->howto = ppc_elf_howto_table[r_type];
/* 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));
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B: invalid relocation type %d"),
+ abfd, r_type);
bfd_set_error (bfd_error_bad_value);
cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
- bfd_vma relocation;
+ enum elf_ppc_reloc_type r_type;
+ long insn;
+ bfd_size_type octets;
+ bfd_vma value;
if (output_bfd != NULL)
{
return bfd_reloc_ok;
}
- if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
- return bfd_reloc_outofrange;
-
- if (bfd_is_com_section (symbol->section))
- relocation = 0;
- else
- relocation = symbol->value;
-
- relocation += symbol->section->output_section->vma;
- relocation += symbol->section->output_offset;
- relocation += reloc_entry->addend;
- if (reloc_entry->howto->pc_relative)
- relocation -= reloc_entry->address;
-
- reloc_entry->addend += (relocation & 0x8000) << 1;
-
- return bfd_reloc_continue;
-}
+ reloc_entry->addend += 0x8000;
+ r_type = reloc_entry->howto->type;
+ if (r_type != R_PPC_REL16DX_HA)
+ return bfd_reloc_continue;
+
+ value = 0;
+ if (!bfd_is_com_section (symbol->section))
+ value = symbol->value;
+ value += (reloc_entry->addend
+ + symbol->section->output_offset
+ + symbol->section->output_section->vma);
+ value -= (reloc_entry->address
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ value >>= 16;
+
+ octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ insn = bfd_get_32 (abfd, (bfd_byte *) data + octets);
+ insn &= ~0x1fffc1;
+ insn |= (value & 0xffc1) | ((value & 0x3e) << 15);
+ bfd_put_32 (abfd, insn, (bfd_byte *) data + octets);
+ return bfd_reloc_ok;
+}
static bfd_reloc_status_type
ppc_elf_unhandled_reloc (bfd *abfd,
PPC32_ELF_DATA);
}
+/* When defaulting arch/mach, decode apuinfo to find a better match. */
+
+bfd_boolean
+_bfd_elf_ppc_set_arch (bfd *abfd)
+{
+ unsigned long mach = 0;
+ asection *s;
+ unsigned char *contents;
+
+ if (abfd->arch_info->bits_per_word == 32
+ && bfd_big_endian (abfd))
+ {
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if ((elf_section_data (s)->this_hdr.sh_flags & SHF_PPC_VLE) != 0)
+ break;
+ if (s != NULL)
+ mach = bfd_mach_ppc_vle;
+ }
+
+ if (mach == 0)
+ {
+ s = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
+ if (s != NULL && bfd_malloc_and_get_section (abfd, s, &contents))
+ {
+ unsigned int apuinfo_size = bfd_get_32 (abfd, contents + 4);
+ unsigned int i;
+
+ for (i = 20; i < apuinfo_size + 20 && i + 4 <= s->size; i += 4)
+ {
+ unsigned int val = bfd_get_32 (abfd, contents + i);
+ switch (val >> 16)
+ {
+ case PPC_APUINFO_PMR:
+ case PPC_APUINFO_RFMCI:
+ if (mach == 0)
+ mach = bfd_mach_ppc_titan;
+ break;
+
+ case PPC_APUINFO_ISEL:
+ case PPC_APUINFO_CACHELCK:
+ if (mach == bfd_mach_ppc_titan)
+ mach = bfd_mach_ppc_e500mc;
+ break;
+
+ case PPC_APUINFO_SPE:
+ case PPC_APUINFO_EFS:
+ case PPC_APUINFO_BRLOCK:
+ if (mach != bfd_mach_ppc_vle)
+ mach = bfd_mach_ppc_e500;
+ break;
+
+ case PPC_APUINFO_VLE:
+ mach = bfd_mach_ppc_vle;
+ break;
+
+ default:
+ mach = -1ul;
+ }
+ }
+ free (contents);
+ }
+ }
+
+ if (mach != 0 && mach != -1ul)
+ {
+ const bfd_arch_info_type *arch;
+
+ for (arch = abfd->arch_info->next; arch; arch = arch->next)
+ if (arch->mach == mach)
+ {
+ abfd->arch_info = arch;
+ break;
+ }
+ }
+ return TRUE;
+}
+
/* Fix bad default arch selected for a 32 bit input bfd when the
- default is 64 bit. */
+ default is 64 bit. Also select arch based on apuinfo. */
static bfd_boolean
ppc_elf_object_p (bfd *abfd)
{
- if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64)
+ if (!abfd->arch_info->the_default)
+ return TRUE;
+
+ if (abfd->arch_info->bits_per_word == 64)
{
Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
BFD_ASSERT (abfd->arch_info->bits_per_word == 32);
}
}
- return TRUE;
+ return _bfd_elf_ppc_set_arch (abfd);
}
/* Function to set whether a module needs the -mrelocatable bit set. */
case 268: /* Linux/PPC. */
/* pr_cursig */
- elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+ elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
/* pr_pid */
- elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24);
+ elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24);
/* pr_reg */
offset = 72;
return FALSE;
case 128: /* Linux/PPC elf_prpsinfo. */
- elf_tdata (abfd)->core_pid
+ elf_tdata (abfd)->core->pid
= bfd_get_32 (abfd, note->descdata + 16);
- elf_tdata (abfd)->core_program
+ elf_tdata (abfd)->core->program
= _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
- elf_tdata (abfd)->core_command
+ elf_tdata (abfd)->core->command
= _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
}
implementations, so strip it off if it exists. */
{
- char *command = elf_tdata (abfd)->core_command;
+ char *command = elf_tdata (abfd)->core->command;
int n = strlen (command);
if (0 < n && command[n - 1] == ' ')
return TRUE;
}
+char *
+elfcore_write_ppc_linux_prpsinfo32
+ (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+ struct elf_external_ppc_linux_prpsinfo32 data;
+
+ swap_ppc_linux_prpsinfo32_out (abfd, prpsinfo, &data);
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", NT_PRPSINFO, &data, sizeof (data));
+}
+
static char *
ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...)
{
}
static flagword
-ppc_elf_lookup_section_flags (char *flag_name)
+ppc_elf_lookup_section_flags (char *flag_name)
{
if (!strcmp (flag_name, "SHF_PPC_VLE"))
return 0;
}
-/* Add the VLE flag if required. */
-
-bfd_boolean
-ppc_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *shdr)
-{
- if (bfd_get_mach (abfd) == bfd_mach_ppc_vle
- && (shdr->sh_flags & SHF_EXECINSTR) != 0)
- shdr->sh_flags |= SHF_PPC_VLE;
-
- return TRUE;
-}
-
/* Return address for Ith PLT stub in section PLT, for relocation REL
or (bfd_vma) -1 if it should not be included. */
return ret;
}
-/* Modify the segment map for VLE executables. */
+/* Modify the segment map for VLE executables. */
bfd_boolean
ppc_elf_modify_segment_map (bfd *abfd,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
- struct elf_segment_map *m, *n;
- bfd_size_type amt;
- unsigned int j, k;
- bfd_boolean sect0_vle, sectj_vle;
+ struct elf_segment_map *m;
/* At this point in the link, output sections have already been sorted by
LMA and assigned to segments. All that is left to do is to ensure
If we find that case, we split the segment.
We maintain the original output section order. */
- for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+ for (m = elf_seg_map (abfd); m != NULL; m = m->next)
{
- if (m->count == 0)
+ struct elf_segment_map *n;
+ bfd_size_type amt;
+ unsigned int j, k;
+ unsigned int p_flags;
+
+ if (m->p_type != PT_LOAD || m->count == 0)
continue;
- sect0_vle = (elf_section_flags (m->sections[0]) & SHF_PPC_VLE) != 0;
- for (j = 1; j < m->count; ++j)
+ for (p_flags = PF_R, j = 0; j != m->count; ++j)
{
- sectj_vle = (elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0;
+ if ((m->sections[j]->flags & SEC_READONLY) == 0)
+ p_flags |= PF_W;
+ if ((m->sections[j]->flags & SEC_CODE) != 0)
+ {
+ p_flags |= PF_X;
+ if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0)
+ p_flags |= PF_PPC_VLE;
+ break;
+ }
+ }
+ if (j != m->count)
+ while (++j != m->count)
+ {
+ unsigned int p_flags1 = PF_R;
- if (sectj_vle != sect0_vle)
- break;
- }
- if (j >= m->count)
+ if ((m->sections[j]->flags & SEC_READONLY) == 0)
+ p_flags1 |= PF_W;
+ if ((m->sections[j]->flags & SEC_CODE) != 0)
+ {
+ p_flags1 |= PF_X;
+ if ((elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0)
+ p_flags1 |= PF_PPC_VLE;
+ if (((p_flags1 ^ p_flags) & PF_PPC_VLE) != 0)
+ break;
+ }
+ p_flags |= p_flags1;
+ }
+ /* If we're splitting a segment which originally contained rw
+ sections then those sections might now only be in one of the
+ two parts. So always set p_flags if splitting, even if we
+ are being called for objcopy with p_flags_valid set. */
+ if (j != m->count || !m->p_flags_valid)
+ {
+ m->p_flags_valid = 1;
+ m->p_flags = p_flags;
+ }
+ if (j == m->count)
continue;
- /* sections 0..j-1 stay in this (current) segment,
+ /* Sections 0..j-1 stay in this (current) segment,
the remainder are put in a new segment.
The scan resumes with the new segment. */
- /* Fix the new segment. */
amt = sizeof (struct elf_segment_map);
amt += (m->count - j - 1) * sizeof (asection *);
n = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
return FALSE;
n->p_type = PT_LOAD;
- n->p_flags = PF_X | PF_R;
- if (sectj_vle)
- n->p_flags |= PF_PPC_VLE;
n->count = m->count - j;
for (k = 0; k < n->count; ++k)
- {
- n->sections[k] = m->sections[j+k];
- m->sections[j+k] = NULL;
- }
+ n->sections[k] = m->sections[j + k];
+ m->count = j;
+ m->p_size_valid = 0;
n->next = m->next;
m->next = n;
-
- /* Fix the current segment */
- m->count = j;
}
return TRUE;
static const struct bfd_elf_special_section ppc_elf_special_sections[] =
{
- { 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 }
+ { 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 (APUINFO_SECTION_NAME), 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. */
head = NULL;
}
-#define APUINFO_SECTION_NAME ".PPC.EMB.apuinfo"
-#define APUINFO_LABEL "APUinfo"
-
/* Scan the input BFDs and create a linked list of
the APUinfo values that will need to be emitted. */
apuinfo_list_init ();
/* Read in the input sections contents. */
- for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next)
+ for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link.next)
{
unsigned long datum;
if (asec == NULL)
continue;
+ /* xgettext:c-format */
error_message = _("corrupt %s section in %B");
length = asec->size;
if (length < 20)
if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0
|| (bfd_bread (buffer, length, ibfd) != length))
{
+ /* xgettext:c-format */
error_message = _("unable to read in %s section from %B");
goto fail;
}
if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4))
{
ibfd = abfd;
+ /* xgettext:c-format */
error_message = _("warning: unable to set size of %s section in %B");
}
}
free (buffer);
if (error_message)
- (*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME);
+ _bfd_error_handler (error_message, ibfd, APUINFO_SECTION_NAME);
}
/* Prevent the output section from accumulating the input sections'
buffer = bfd_malloc (length);
if (buffer == NULL)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("failed to allocate space for new APUinfo section."));
return;
}
}
if (length != asec->size)
- (*_bfd_error_handler) (_("failed to compute new APUinfo section."));
+ _bfd_error_handler (_("failed to compute new APUinfo section."));
if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length))
- (*_bfd_error_handler) (_("failed to install new APUinfo section."));
+ _bfd_error_handler (_("failed to install new APUinfo section."));
free (buffer);
}
count = relplt->size / sizeof (Elf32_External_Rela);
- stub_vma = glink_vma - (bfd_vma) count * 16;
/* If the stubs are those for -shared/-pie then we might have
multiple stubs for each plt entry. If that is the case then
there is no way to associate stubs with their plt entries short
if (s == NULL)
return -1;
+ stub_vma = glink_vma;
names = (char *) (s + count + 1 + (resolv_vma != 0));
- p = relplt->relocation;
- for (i = 0; i < count; i++, p++)
+ p = relplt->relocation + count - 1;
+ for (i = 0; i < count; i++)
{
size_t len;
s->flags |= BSF_GLOBAL;
s->flags |= BSF_SYNTHETIC;
s->section = glink;
+ stub_vma -= 16;
+ if (strcmp ((*p->sym_ptr_ptr)->name, "__tls_get_addr_opt") == 0)
+ stub_vma -= 32;
s->value = stub_vma - glink->vma;
s->name = names;
s->udata.p = NULL;
memcpy (names, "@plt", sizeof ("@plt"));
names += sizeof ("@plt");
++s;
- stub_vma += 16;
+ --p;
}
/* Add a symbol at the start of the glink branch table. */
case R_PPC_TPREL16_LO:
case R_PPC_TPREL16_HI:
case R_PPC_TPREL16_HA:
- return !info->executable;
+ return !bfd_link_executable (info);
}
}
shared lib. */
#define ELIMINATE_COPY_RELOCS 1
+/* Used to track dynamic relocations for local symbols. */
+struct ppc_dyn_relocs
+{
+ struct ppc_dyn_relocs *next;
+
+ /* The input section of the reloc. */
+ asection *sec;
+
+ /* Total number of relocs copied for the input section. */
+ unsigned int count : 31;
+
+ /* Whether this entry is for STT_GNU_IFUNC symbols. */
+ unsigned int ifunc : 1;
+};
+
/* PPC ELF linker hash entry. */
struct ppc_elf_link_hash_entry
/* Nonzero if we have seen a small data relocation referring to this
symbol. */
- unsigned char has_sda_refs;
+ unsigned char has_sda_refs : 1;
+
+ /* Flag use of given relocations. */
+ unsigned char has_addr16_ha : 1;
+ unsigned char has_addr16_lo : 1;
};
#define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent))
{
struct elf_link_hash_table elf;
+ /* Various options passed from the linker. */
+ struct ppc_elf_params *params;
+
/* Short-cuts to get to dynamic linker sections. */
- asection *got;
- asection *relgot;
asection *glink;
- asection *plt;
- asection *relplt;
- asection *iplt;
- asection *reliplt;
- asection *dynbss;
- asection *relbss;
asection *dynsbss;
asection *relsbss;
elf_linker_section_t sdata[2];
/* 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 type of PLT we have chosen to use. */
enum ppc_elf_plt_type plt_type;
- /* Set if we should emit symbols for stubs. */
- unsigned int emit_stub_syms:1;
-
- /* Set if __tls_get_addr optimization should not be done. */
- unsigned int no_tls_get_addr_opt:1;
-
/* True if the target system is VxWorks. */
unsigned int is_vxworks:1;
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, 12, 0, 0, 0 };
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";
return &ret->elf.root;
}
+/* Hook linker params into hash table. */
+
+void
+ppc_elf_link_params (struct bfd_link_info *info, struct ppc_elf_params *params)
+{
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+
+ if (htab)
+ htab->params = params;
+ params->pagesize_p2 = bfd_log2 (params->pagesize);
+}
+
/* Create .got and the related sections. */
static bfd_boolean
ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info)
{
struct ppc_elf_link_hash_table *htab;
- asection *s;
- flagword flags;
if (!_bfd_elf_create_got_section (abfd, info))
return FALSE;
htab = ppc_elf_hash_table (info);
- htab->got = s = bfd_get_linker_section (abfd, ".got");
- if (s == NULL)
- abort ();
-
- if (htab->is_vxworks)
- {
- htab->sgotplt = bfd_get_linker_section (abfd, ".got.plt");
- if (!htab->sgotplt)
- abort ();
- }
- else
+ if (!htab->is_vxworks)
{
/* The powerpc .got has a blrl instruction in it. Mark it
executable. */
- flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- if (!bfd_set_section_flags (abfd, s, flags))
+ flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ if (!bfd_set_section_flags (abfd, htab->elf.sgot, flags))
return FALSE;
}
- htab->relgot = bfd_get_linker_section (abfd, ".rela.got");
- if (!htab->relgot)
- abort ();
+ return TRUE;
+}
+
+/* Create a special linker section, used for R_PPC_EMB_SDAI16 and
+ R_PPC_EMB_SDA2I16 pointers. These sections become part of .sdata
+ and .sdata2. Create _SDA_BASE_ and _SDA2_BASE too. */
+
+static bfd_boolean
+ppc_elf_create_linker_section (bfd *abfd,
+ struct bfd_link_info *info,
+ flagword flags,
+ elf_linker_section_t *lsect)
+{
+ asection *s;
+
+ flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
+
+ s = bfd_make_section_anyway_with_flags (abfd, lsect->name, flags);
+ if (s == NULL)
+ return FALSE;
+ lsect->section = s;
+
+ /* Define the sym on the first section of this name. */
+ s = bfd_get_section_by_name (abfd, lsect->name);
+ lsect->sym = _bfd_elf_define_linkage_sym (abfd, info, s, lsect->sym_name);
+ if (lsect->sym == NULL)
+ return FALSE;
+ lsect->sym->root.u.def.value = 0x8000;
return TRUE;
}
s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags);
htab->glink = s;
if (s == NULL
- || !bfd_set_section_alignment (abfd, s, 4))
+ || !bfd_set_section_alignment (abfd, s,
+ htab->params->ppc476_workaround ? 6 : 4))
return FALSE;
if (!info->no_ld_generated_unwind_info)
flags = SEC_ALLOC | SEC_LINKER_CREATED;
s = bfd_make_section_anyway_with_flags (abfd, ".iplt", flags);
- htab->iplt = s;
+ htab->elf.iplt = s;
if (s == NULL
|| !bfd_set_section_alignment (abfd, s, 4))
return FALSE;
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
s = bfd_make_section_anyway_with_flags (abfd, ".rela.iplt", flags);
- htab->reliplt = s;
+ htab->elf.irelplt = s;
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, 2))
return FALSE;
+
+ if (!ppc_elf_create_linker_section (abfd, info, 0,
+ &htab->sdata[0]))
+ return FALSE;
+
+ if (!ppc_elf_create_linker_section (abfd, info, SEC_READONLY,
+ &htab->sdata[1]))
+ return FALSE;
+
return TRUE;
}
htab = ppc_elf_hash_table (info);
- if (htab->got == NULL
+ if (htab->elf.sgot == NULL
&& !ppc_elf_create_got (abfd, info))
return FALSE;
&& !ppc_elf_create_glink (abfd, info))
return FALSE;
- htab->dynbss = bfd_get_linker_section (abfd, ".dynbss");
s = bfd_make_section_anyway_with_flags (abfd, ".dynsbss",
SEC_ALLOC | SEC_LINKER_CREATED);
htab->dynsbss = s;
if (s == NULL)
return FALSE;
- if (! info->shared)
+ if (! bfd_link_pic (info))
{
- htab->relbss = bfd_get_linker_section (abfd, ".rela.bss");
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
s = bfd_make_section_anyway_with_flags (abfd, ".rela.sbss", flags);
&& !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
return FALSE;
- htab->relplt = bfd_get_linker_section (abfd, ".rela.plt");
- htab->plt = s = bfd_get_linker_section (abfd, ".plt");
- if (s == NULL)
- abort ();
-
+ s = htab->elf.splt;
flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED;
if (htab->plt_type == PLT_VXWORKS)
/* The VxWorks PLT is a loaded section with contents. */
&& edir->elf.dynamic_adjusted))
edir->elf.non_got_ref |= eind->elf.non_got_ref;
- edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
+ if (edir->elf.versioned != versioned_hidden)
+ edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
edir->elf.ref_regular |= eind->elf.ref_regular;
edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
edir->elf.needs_plt |= eind->elf.needs_plt;
/* If we were called to copy over info for a weak sym, that's all.
You might think dyn_relocs need not be copied over; After all,
both syms will be dynamic or both non-dynamic so we're just
- moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
+ moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
code in ppc_elf_adjust_dynamic_symbol needs to check for
dyn_relocs in read-only sections, and it does so on what is the
DIR sym here. */
bfd_vma *valp)
{
if (sym->st_shndx == SHN_COMMON
- && !info->relocatable
+ && !bfd_link_relocatable (info)
&& is_ppc_elf (info->output_bfd)
&& sym->st_size <= elf_gp_size (abfd))
{
*valp = sym->st_size;
}
- if ((abfd->flags & DYNAMIC) == 0
- && (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
- || ELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE))
- elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+ if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC
+ && (abfd->flags & DYNAMIC) == 0
+ && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
+ elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
return TRUE;
}
\f
-static bfd_boolean
-create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect)
-{
- struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
-
- lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name,
- TRUE, FALSE, TRUE);
- if (lsect->sym == NULL)
- return FALSE;
- if (lsect->sym->root.type == bfd_link_hash_new)
- lsect->sym->non_elf = 0;
- lsect->sym->ref_regular = 1;
- _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE);
- return TRUE;
-}
-
-/* Create a special linker section. */
-
-static bfd_boolean
-ppc_elf_create_linker_section (bfd *abfd,
- struct bfd_link_info *info,
- flagword flags,
- elf_linker_section_t *lsect)
-{
- struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
- asection *s;
-
- flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_LINKER_CREATED);
-
- /* Record the first bfd that needs the special sections. */
- if (!htab->elf.dynobj)
- htab->elf.dynobj = abfd;
-
- s = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
- lsect->name,
- flags);
- if (s == NULL
- || !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
- return FALSE;
- lsect->section = s;
-
- return create_sdata_sym (info, lsect);
-}
-
/* Find a linker generated pointer with a given addend and type. */
static elf_linker_section_pointers_t *
/* Allocate a pointer to live in a linker created section. */
static bfd_boolean
-elf_create_pointer_linker_section (bfd *abfd,
- elf_linker_section_t *lsect,
- struct elf_link_hash_entry *h,
- const Elf_Internal_Rela *rel)
+elf_allocate_pointer_linker_section (bfd *abfd,
+ elf_linker_section_t *lsect,
+ struct elf_link_hash_entry *h,
+ const Elf_Internal_Rela *rel)
{
elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL;
elf_linker_section_pointers_t *linker_section_ptr;
linker_section_ptr->lsect = lsect;
*ptr_linker_section_ptr = linker_section_ptr;
+ if (!bfd_set_section_alignment (lsect->section->owner, lsect->section, 2))
+ return FALSE;
linker_section_ptr->offset = lsect->section->size;
lsect->section->size += 4;
|| r_type == R_PPC_ADDR24
|| r_type == R_PPC_ADDR14
|| r_type == R_PPC_ADDR14_BRTAKEN
- || r_type == R_PPC_ADDR14_BRNTAKEN);
+ || r_type == R_PPC_ADDR14_BRNTAKEN
+ || r_type == R_PPC_VLE_REL24);
}
static void
bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: relocation %s cannot be used when making a shared object"),
abfd,
ppc_elf_howto_table[r_type]->name);
asection *got2, *sreloc;
struct elf_link_hash_entry *tga;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
/* Don't do anything special with non-loaded, non-alloced sections.
enum elf_ppc_reloc_type r_type;
struct elf_link_hash_entry *h;
int tls_type;
+ struct plt_entry **ifunc;
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ /* PR15323, ref flags aren't set for references in the same
+ object. */
+ h->root.non_ir_ref = 1;
}
/* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
This shows up in particular in an R_PPC_ADDR32 in the eabi
startup code. */
if (h != NULL
- && htab->got == NULL
+ && htab->elf.sgot == NULL
&& strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
{
if (htab->elf.dynobj == NULL)
tls_type = 0;
r_type = ELF32_R_TYPE (rel->r_info);
+ ifunc = NULL;
if (h == NULL && !htab->is_vxworks)
{
Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
if (isym == NULL)
return FALSE;
- if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
- && (!info->shared
- || is_branch_reloc (r_type)))
+ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{
- struct plt_entry **ifunc;
- bfd_vma addend;
-
+ /* Set PLT_IFUNC flag for this sym, no GOT entry yet. */
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
PLT_IFUNC);
if (ifunc == NULL)
/* STT_GNU_IFUNC symbols must have a PLT entry;
In a non-pie executable even when there are
no plt calls. */
- addend = 0;
- if (r_type == R_PPC_PLTREL24)
+ if (!bfd_link_pic (info)
+ || is_branch_reloc (r_type))
{
- ppc_elf_tdata (abfd)->makes_plt_call = 1;
- if (info->shared)
- addend = rel->r_addend;
+ bfd_vma addend = 0;
+ if (r_type == R_PPC_PLTREL24)
+ {
+ ppc_elf_tdata (abfd)->makes_plt_call = 1;
+ if (bfd_link_pic (info))
+ addend = rel->r_addend;
+ }
+ if (!update_plt_info (abfd, ifunc, got2, addend))
+ return FALSE;
}
- if (!update_plt_info (abfd, ifunc, got2, addend))
- return FALSE;
}
}
case R_PPC_GOT_TPREL16_LO:
case R_PPC_GOT_TPREL16_HI:
case R_PPC_GOT_TPREL16_HA:
- if (!info->executable)
+ if (bfd_link_pic (info))
info->flags |= DF_STATIC_TLS;
tls_type = TLS_TLS | TLS_TPREL;
goto dogottls;
tls_type = TLS_TLS | TLS_DTPREL;
dogottls:
sec->has_tls_reloc = 1;
- /* Fall thru */
+ /* Fall through. */
/* GOT16 relocations */
case R_PPC_GOT16:
case R_PPC_GOT16_HI:
case R_PPC_GOT16_HA:
/* This symbol requires a global offset table entry. */
- if (htab->got == NULL)
+ if (htab->elf.sgot == NULL)
{
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
/* We may also need a plt entry if the symbol turns out to be
an ifunc. */
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
{
if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
return FALSE;
/* Indirect .sdata relocation. */
case R_PPC_EMB_SDAI16:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
}
- if (htab->sdata[0].section == NULL
- && !ppc_elf_create_linker_section (abfd, info, 0,
- &htab->sdata[0]))
- return FALSE;
- if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0],
- h, rel))
+ htab->sdata[0].sym->ref_regular = 1;
+ if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[0],
+ h, rel))
return FALSE;
if (h != NULL)
{
/* Indirect .sdata2 relocation. */
case R_PPC_EMB_SDA2I16:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
}
- if (htab->sdata[1].section == NULL
- && !ppc_elf_create_linker_section (abfd, info, SEC_READONLY,
- &htab->sdata[1]))
- return FALSE;
- if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1],
- h, rel))
+ htab->sdata[1].sym->ref_regular = 1;
+ if (!elf_allocate_pointer_linker_section (abfd, &htab->sdata[1],
+ h, rel))
return FALSE;
if (h != NULL)
{
}
break;
+ case R_PPC_SDAREL16:
+ htab->sdata[0].sym->ref_regular = 1;
+ /* Fall through. */
+
case R_PPC_VLE_SDAREL_LO16A:
case R_PPC_VLE_SDAREL_LO16D:
case R_PPC_VLE_SDAREL_HI16A:
case R_PPC_VLE_SDAREL_HI16D:
case R_PPC_VLE_SDAREL_HA16A:
case R_PPC_VLE_SDAREL_HA16D:
- case R_PPC_SDAREL16:
- if (htab->sdata[0].sym == NULL
- && !create_sdata_sym (info, &htab->sdata[0]))
- return FALSE;
-
- if (htab->sdata[1].sym == NULL
- && !create_sdata_sym (info, &htab->sdata[1]))
- return FALSE;
-
if (h != NULL)
{
ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
break;
case R_PPC_EMB_SDA2REL:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
}
- if (htab->sdata[1].sym == NULL
- && !create_sdata_sym (info, &htab->sdata[1]))
- return FALSE;
+ htab->sdata[1].sym->ref_regular = 1;
if (h != NULL)
{
ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
case R_PPC_VLE_SDA21:
case R_PPC_EMB_SDA21:
case R_PPC_EMB_RELSDA:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
}
- if (htab->sdata[0].sym == NULL
- && !create_sdata_sym (info, &htab->sdata[0]))
- return FALSE;
- if (htab->sdata[1].sym == NULL
- && !create_sdata_sym (info, &htab->sdata[1]))
- return FALSE;
if (h != NULL)
{
ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
case R_PPC_EMB_NADDR16_LO:
case R_PPC_EMB_NADDR16_HI:
case R_PPC_EMB_NADDR16_HA:
- if (info->shared)
+ if (bfd_link_pic (info))
{
bad_shared_reloc (abfd, r_type);
return FALSE;
#ifdef DEBUG
fprintf (stderr, "Reloc requires a PLT entry\n");
#endif
- /* This symbol requires a procedure linkage table entry. We
- actually build the entry in finish_dynamic_symbol,
- because this might be a case of linking PIC code without
- linking in any dynamic objects, in which case we don't
- need to generate a procedure linkage table after all. */
-
+ /* This symbol requires a procedure linkage table entry. */
if (h == NULL)
{
- /* It does not make sense to have a procedure linkage
- table entry for a local symbol. */
- info->callbacks->einfo (_("%P: %H: %s reloc against local symbol\n"),
- abfd, sec, rel->r_offset,
- ppc_elf_howto_table[r_type]->name);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ if (ifunc == NULL)
+ {
+ /* It does not make sense to have a procedure linkage
+ table entry for a non-ifunc local symbol. */
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%H: %s reloc against local symbol\n"),
+ abfd, sec, rel->r_offset,
+ ppc_elf_howto_table[r_type]->name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
}
else
{
if (r_type == R_PPC_PLTREL24)
{
ppc_elf_tdata (abfd)->makes_plt_call = 1;
- if (info->shared)
+ if (bfd_link_pic (info))
addend = rel->r_addend;
}
h->needs_plt = 1;
case R_PPC_REL16_LO:
case R_PPC_REL16_HI:
case R_PPC_REL16_HA:
+ case R_PPC_REL16DX_HA:
ppc_elf_tdata (abfd)->has_rel16 = 1;
break;
htab->plt_type = PLT_OLD;
htab->old_bfd = abfd;
}
+ if (h != NULL && h->type == STT_GNU_IFUNC)
+ {
+ h->needs_plt = 1;
+ if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
+ return FALSE;
+ }
break;
/* This relocation describes the C++ object vtable hierarchy.
case R_PPC_TPREL16_LO:
case R_PPC_TPREL16_HI:
case R_PPC_TPREL16_HA:
- if (!info->executable)
+ if (bfd_link_pic (info))
info->flags |= DF_STATIC_TLS;
goto dodyn;
if (h == NULL
&& got2 != NULL
&& (sec->flags & SEC_CODE) != 0
- && info->shared
+ && bfd_link_pic (info)
&& htab->plt_type == PLT_UNSET)
{
/* Old -fPIC gcc code has .long LCTOC1-LCFx just before
case R_PPC_ADDR16_HA:
case R_PPC_UADDR32:
case R_PPC_UADDR16:
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
{
/* We may need a plt entry if the symbol turns out to be
a function defined in a dynamic object. */
/* We may need a copy reloc too. */
h->non_got_ref = 1;
h->pointer_equality_needed = 1;
+ if (r_type == R_PPC_ADDR16_HA)
+ ppc_elf_hash_entry (h)->has_addr16_ha = 1;
+ if (r_type == R_PPC_ADDR16_LO)
+ ppc_elf_hash_entry (h)->has_addr16_lo = 1;
}
goto dodyn;
case R_PPC_ADDR14:
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_ADDR14_BRNTAKEN:
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
{
/* We may need a plt entry if the symbol turns out to be
a function defined in a dynamic object. */
may need to keep relocations for symbols satisfied by a
dynamic library if we manage to avoid copy relocs for the
symbol. */
- if ((info->shared
+ if ((bfd_link_pic (info)
&& (must_be_dyn_reloc (info, r_type)
|| (h != NULL
- && (! info->symbolic
+ && (!SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
|| !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
- && !info->shared
+ && !bfd_link_pic (info)
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular)))
{
- struct elf_dyn_relocs *p;
- struct elf_dyn_relocs **rel_head;
-
#ifdef DEBUG
fprintf (stderr,
"ppc_elf_check_relocs needs to "
relocations we need for this symbol. */
if (h != NULL)
{
+ struct elf_dyn_relocs *p;
+ struct elf_dyn_relocs **rel_head;
+
rel_head = &ppc_elf_hash_entry (h)->dyn_relocs;
+ p = *rel_head;
+ if (p == NULL || p->sec != sec)
+ {
+ p = bfd_alloc (htab->elf.dynobj, sizeof *p);
+ if (p == NULL)
+ return FALSE;
+ p->next = *rel_head;
+ *rel_head = p;
+ p->sec = sec;
+ p->count = 0;
+ p->pc_count = 0;
+ }
+ p->count += 1;
+ if (!must_be_dyn_reloc (info, r_type))
+ p->pc_count += 1;
}
else
{
/* Track dynamic relocs needed for local syms too.
We really need local syms available to do this
easily. Oh well. */
+ struct ppc_dyn_relocs *p;
+ struct ppc_dyn_relocs **rel_head;
+ bfd_boolean is_ifunc;
asection *s;
void *vpp;
Elf_Internal_Sym *isym;
s = sec;
vpp = &elf_section_data (s)->local_dynrel;
- rel_head = (struct elf_dyn_relocs **) vpp;
- }
-
- p = *rel_head;
- if (p == NULL || p->sec != sec)
- {
- p = bfd_alloc (htab->elf.dynobj, sizeof *p);
- if (p == NULL)
- return FALSE;
- p->next = *rel_head;
- *rel_head = p;
- p->sec = sec;
- p->count = 0;
- p->pc_count = 0;
+ rel_head = (struct ppc_dyn_relocs **) vpp;
+ is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC;
+ p = *rel_head;
+ if (p != NULL && p->sec == sec && p->ifunc != is_ifunc)
+ p = p->next;
+ if (p == NULL || p->sec != sec || p->ifunc != is_ifunc)
+ {
+ p = bfd_alloc (htab->elf.dynobj, sizeof *p);
+ if (p == NULL)
+ return FALSE;
+ p->next = *rel_head;
+ *rel_head = p;
+ p->sec = sec;
+ p->ifunc = is_ifunc;
+ p->count = 0;
+ }
+ p->count += 1;
}
-
- p->count += 1;
- if (!must_be_dyn_reloc (info, r_type))
- p->pc_count += 1;
}
break;
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)
+/* Warn for conflicting Tag_GNU_Power_ABI_FP attributes between IBFD
+ and OBFD, and merge non-conflicting ones. */
+void
+_bfd_elf_ppc_merge_fp_attributes (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
obj_attribute *in_attr, *in_attrs;
obj_attribute *out_attr, *out_attrs;
- 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;
- }
-
in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
- /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge
- non-conflicting ones. */
in_attr = &in_attrs[Tag_GNU_Power_ABI_FP];
out_attr = &out_attrs[Tag_GNU_Power_ABI_FP];
+
if (in_attr->i != out_attr->i)
{
- out_attr->type = 1;
- if (out_attr->i == 0)
- out_attr->i = in_attr->i;
- else if (in_attr->i == 0)
+ int in_fp = in_attr->i & 3;
+ int out_fp = out_attr->i & 3;
+
+ if (in_fp == 0)
;
- else if (out_attr->i == 1 && in_attr->i == 2)
+ else if (out_fp == 0)
+ {
+ out_attr->type = 1;
+ out_attr->i ^= in_fp;
+ }
+ else if (out_fp != 2 && in_fp == 2)
_bfd_error_handler
+ /* xgettext:c-format */
(_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
- else if (out_attr->i == 1 && in_attr->i == 3)
+ else if (out_fp == 2 && in_fp != 2)
_bfd_error_handler
- (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
- obfd, ibfd);
- else if (out_attr->i == 3 && in_attr->i == 1)
+ /* xgettext:c-format */
+ (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
+ else if (out_fp == 1 && in_fp == 3)
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("Warning: %B uses double-precision hard float, "
+ "%B uses single-precision hard float"), obfd, ibfd);
+ else if (out_fp == 3 && in_fp == 1)
_bfd_error_handler
- (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
- ibfd, obfd);
- else if (out_attr->i == 3 && in_attr->i == 2)
+ /* xgettext:c-format */
+ (_("Warning: %B uses double-precision hard float, "
+ "%B uses single-precision hard float"), ibfd, obfd);
+
+ in_fp = in_attr->i & 0xc;
+ out_fp = out_attr->i & 0xc;
+ if (in_fp == 0)
+ ;
+ else if (out_fp == 0)
+ {
+ out_attr->type = 1;
+ out_attr->i ^= in_fp;
+ }
+ else if (out_fp != 2 * 4 && in_fp == 2 * 4)
_bfd_error_handler
- (_("Warning: %B uses soft float, %B uses single-precision hard float"),
- ibfd, obfd);
- else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3))
+ /* xgettext:c-format */
+ (_("Warning: %B uses 64-bit long double, "
+ "%B uses 128-bit long double"), ibfd, obfd);
+ else if (in_fp != 2 * 4 && out_fp == 2 * 4)
_bfd_error_handler
- (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
- else if (in_attr->i > 3)
+ /* xgettext:c-format */
+ (_("Warning: %B uses 64-bit long double, "
+ "%B uses 128-bit long double"), obfd, ibfd);
+ else if (out_fp == 1 * 4 && in_fp == 3 * 4)
_bfd_error_handler
- (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
- in_attr->i);
- else
+ /* xgettext:c-format */
+ (_("Warning: %B uses IBM long double, "
+ "%B uses IEEE long double"), ibfd, obfd);
+ else if (out_fp == 3 * 4 && in_fp == 1 * 4)
_bfd_error_handler
- (_("Warning: %B uses unknown floating point ABI %d"), obfd,
- out_attr->i);
+ /* xgettext:c-format */
+ (_("Warning: %B uses IBM long double, "
+ "%B uses IEEE long double"), obfd, ibfd);
}
+}
+
+/* Merge object attributes from IBFD into OBFD. Warn if
+ there are conflicting attributes. */
+static bfd_boolean
+ppc_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
+{
+ bfd *obfd;
+ obj_attribute *in_attr, *in_attrs;
+ obj_attribute *out_attr, *out_attrs;
+
+ _bfd_elf_ppc_merge_fp_attributes (ibfd, info);
+
+ obfd = info->output_bfd;
+ in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+ out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
/* Check for conflicting Tag_GNU_Power_ABI_Vector attributes and
merge non-conflicting ones. */
out_attr = &out_attrs[Tag_GNU_Power_ABI_Vector];
if (in_attr->i != out_attr->i)
{
- const char *in_abi = NULL, *out_abi = NULL;
-
- switch (in_attr->i)
- {
- case 1: in_abi = "generic"; break;
- case 2: in_abi = "AltiVec"; break;
- case 3: in_abi = "SPE"; break;
- }
+ int in_vec = in_attr->i & 3;
+ int out_vec = out_attr->i & 3;
- switch (out_attr->i)
+ if (in_vec == 0)
+ ;
+ else if (out_vec == 0)
{
- case 1: out_abi = "generic"; break;
- case 2: out_abi = "AltiVec"; break;
- case 3: out_abi = "SPE"; break;
+ out_attr->type = 1;
+ out_attr->i = in_vec;
}
-
- out_attr->type = 1;
- if (out_attr->i == 0)
- out_attr->i = in_attr->i;
- else if (in_attr->i == 0)
- ;
/* For now, allow generic to transition to AltiVec or SPE
without a warning. If GCC marked files with their stack
alignment and used don't-care markings for files which are
not affected by the vector ABI, we could warn about this
case too. */
- else if (out_attr->i == 1)
- out_attr->i = in_attr->i;
- else if (in_attr->i == 1)
+ else if (in_vec == 1)
;
- else if (in_abi == NULL)
+ else if (out_vec == 1)
+ {
+ out_attr->type = 1;
+ out_attr->i = in_vec;
+ }
+ else if (out_vec < in_vec)
_bfd_error_handler
- (_("Warning: %B uses unknown vector ABI %d"), ibfd,
- in_attr->i);
- else if (out_abi == NULL)
+ /* xgettext:c-format */
+ (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
+ obfd, ibfd);
+ else if (out_vec > in_vec)
_bfd_error_handler
- (_("Warning: %B uses unknown vector ABI %d"), obfd,
- in_attr->i);
- else
- _bfd_error_handler
- (_("Warning: %B uses vector ABI \"%s\", %B uses \"%s\""),
- ibfd, obfd, in_abi, out_abi);
+ /* xgettext:c-format */
+ (_("Warning: %B uses AltiVec vector ABI, %B uses SPE vector ABI"),
+ ibfd, obfd);
}
/* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes
out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return];
if (in_attr->i != out_attr->i)
{
- out_attr->type = 1;
- if (out_attr->i == 0)
- out_attr->i = in_attr->i;
- else if (in_attr->i == 0)
+ int in_struct = in_attr->i & 3;
+ int out_struct = out_attr->i & 3;
+
+ if (in_struct == 0 || in_struct == 3)
;
- else if (out_attr->i == 1 && in_attr->i == 2)
- _bfd_error_handler
- (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), obfd, ibfd);
- else if (out_attr->i == 2 && in_attr->i == 1)
- _bfd_error_handler
- (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), ibfd, obfd);
- else if (in_attr->i > 2)
- _bfd_error_handler
- (_("Warning: %B uses unknown small structure return convention %d"), ibfd,
- in_attr->i);
- else
- _bfd_error_handler
- (_("Warning: %B uses unknown small structure return convention %d"), obfd,
- out_attr->i);
+ else if (out_struct == 0)
+ {
+ out_attr->type = 1;
+ out_attr->i = in_struct;
+ }
+ else if (out_struct < in_struct)
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("Warning: %B uses r3/r4 for small structure returns, "
+ "%B uses memory"), obfd, ibfd);
+ else if (out_struct > in_struct)
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("Warning: %B uses r3/r4 for small structure returns, "
+ "%B uses memory"), ibfd, obfd);
}
/* Merge Tag_compatibility attributes and any common GNU ones. */
- _bfd_elf_merge_object_attributes (ibfd, obfd);
+ _bfd_elf_merge_object_attributes (ibfd, info);
return TRUE;
}
object file when linking. */
static bfd_boolean
-ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+ppc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
flagword old_flags;
flagword new_flags;
bfd_boolean error;
return TRUE;
/* Check if we have the same endianness. */
- if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+ if (! _bfd_generic_verify_endian_match (ibfd, info))
return FALSE;
- if (!ppc_elf_merge_obj_attributes (ibfd, obfd))
+ if (!ppc_elf_merge_obj_attributes (ibfd, info))
return FALSE;
new_flags = elf_elfheader (ibfd)->e_flags;
&& (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
{
error = TRUE;
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: compiled with -mrelocatable and linked with "
"modules compiled normally"), ibfd);
}
&& (old_flags & EF_PPC_RELOCATABLE) != 0)
{
error = TRUE;
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: compiled normally and linked with "
"modules compiled with -mrelocatable"), ibfd);
}
if (new_flags != old_flags)
{
error = TRUE;
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: uses different e_flags (0x%lx) fields "
"than previous modules (0x%lx)"),
ibfd, (long) new_flags, (long) old_flags);
}
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 *input_bfd,
+ asection *input_section,
+ unsigned long offset,
+ bfd_byte *loc,
+ bfd_vma value,
+ split16_format_type split16_format,
+ bfd_boolean fixup)
{
- bfd_vma insn, top5, bottom11;
-
- insn = bfd_get_32 (output_bfd, contents + offset);
- top5 = relocation >> 11;
- top5 = top5 << (split16_format == split16a_type ? 20 : 16);
- bottom11 = relocation & 0x7ff;
+ unsigned int insn, opcode, top5;
+
+ insn = bfd_get_32 (input_bfd, loc);
+ opcode = insn & 0xf300f800;
+ if (opcode == E_OR2I_INSN
+ || opcode == E_AND2I_DOT_INSN
+ || opcode == E_OR2IS_INSN
+ || opcode == E_LIS_INSN
+ || opcode == E_AND2IS_DOT_INSN)
+ {
+ if (split16_format != split16a_type)
+ {
+ if (fixup)
+ split16_format = split16a_type;
+ else
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B(%A+0x%lx): expected 16A style relocation on 0x%08x insn"),
+ input_bfd, input_section, offset, opcode);
+ }
+ }
+ else if (opcode == E_ADD2I_DOT_INSN
+ || opcode == E_ADD2IS_INSN
+ || opcode == E_CMP16I_INSN
+ || opcode == E_MULL2I_INSN
+ || opcode == E_CMPL16I_INSN
+ || opcode == E_CMPH16I_INSN
+ || opcode == E_CMPHL16I_INSN)
+ {
+ if (split16_format != split16d_type)
+ {
+ if (fixup)
+ split16_format = split16d_type;
+ else
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B(%A+0x%lx): expected 16D style relocation on 0x%08x insn"),
+ input_bfd, input_section, offset, opcode);
+ }
+ }
+ top5 = value & 0xf800;
+ top5 = top5 << (split16_format == split16a_type ? 5 : 10);
+ insn &= (split16_format == split16a_type ? ~0x1f07ff : ~0x3e007ff);
insn |= top5;
- insn |= bottom11;
- bfd_put_32 (output_bfd, insn, contents + offset);
+ insn |= value & 0x7ff;
+ bfd_put_32 (input_bfd, insn, loc);
}
-
\f
/* Choose which PLT scheme to use, and set .plt flags appropriately.
Returns -1 on error, 0 for old PLT, 1 for new PLT. */
int
ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info,
- enum ppc_elf_plt_type plt_style,
- int emit_stub_syms)
+ struct bfd_link_info *info)
{
struct ppc_elf_link_hash_table *htab;
flagword flags;
htab = ppc_elf_hash_table (info);
- htab->emit_stub_syms = emit_stub_syms;
-
if (htab->plt_type == PLT_UNSET)
{
struct elf_link_hash_entry *h;
- if (plt_style == PLT_OLD)
+ if (htab->params->plt_style == PLT_OLD)
htab->plt_type = PLT_OLD;
- else if (info->shared
+ else if (bfd_link_pic (info)
&& htab->elf.dynamic_sections_created
&& (h = elf_link_hash_lookup (&htab->elf, "_mcount",
FALSE, FALSE, TRUE)) != NULL
else
{
bfd *ibfd;
- enum ppc_elf_plt_type plt_type = plt_style;
+ enum ppc_elf_plt_type plt_type = htab->params->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
--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)
+ for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link.next)
if (is_ppc_elf (ibfd))
{
if (ppc_elf_tdata (ibfd)->has_rel16)
htab->plt_type = plt_type;
}
}
- if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW)
+ if (htab->plt_type == PLT_OLD && htab->params->plt_style == PLT_NEW)
{
if (htab->old_bfd != NULL)
info->callbacks->einfo (_("%P: bss-plt forced due to %B\n"),
| SEC_IN_MEMORY | SEC_LINKER_CREATED);
/* The new PLT is a loaded section. */
- if (htab->plt != NULL
- && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags))
+ if (htab->elf.splt != NULL
+ && !bfd_set_section_flags (htab->elf.dynobj, htab->elf.splt, flags))
return -1;
/* The new GOT is not executable. */
- if (htab->got != NULL
- && !bfd_set_section_flags (htab->elf.dynobj, htab->got, flags))
+ if (htab->elf.sgot != NULL
+ && !bfd_set_section_flags (htab->elf.dynobj, htab->elf.sgot, flags))
return -1;
}
else
const Elf_Internal_Rela *rel, *relend;
asection *got2;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
if ((sec->flags & SEC_ALLOC) == 0)
if (!htab->is_vxworks
&& h == NULL
&& local_got_refcounts != NULL
- && (!info->shared
+ && (!bfd_link_pic (info)
|| is_branch_reloc (r_type)))
{
struct plt_entry **local_plt = (struct plt_entry **)
bfd_vma addend = 0;
struct plt_entry *ent;
- if (r_type == R_PPC_PLTREL24 && info->shared)
+ if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
addend = rel->r_addend;
ent = find_plt_ent (ifunc, got2, addend);
if (ent->plt.refcount > 0)
{
if (h->got.refcount > 0)
h->got.refcount--;
- if (!info->shared)
+ if (!bfd_link_pic (info))
{
struct plt_entry *ent;
case R_PPC_REL32:
if (h == NULL || h == htab->elf.hgot)
break;
- /* Fall thru */
+ /* Fall through. */
case R_PPC_ADDR32:
case R_PPC_ADDR24:
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_UADDR32:
case R_PPC_UADDR16:
- if (info->shared)
+ if (bfd_link_pic (info))
break;
+ /* Fall through. */
case R_PPC_PLT32:
case R_PPC_PLTREL24:
bfd_vma addend = 0;
struct plt_entry *ent;
- if (r_type == R_PPC_PLTREL24 && info->shared)
+ if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
addend = rel->r_addend;
ent = find_plt_ent (&h->plt.plist, got2, addend);
if (ent != NULL && ent->plt.refcount > 0)
generic ELF tls_setup function. */
asection *
-ppc_elf_tls_setup (bfd *obfd,
- struct bfd_link_info *info,
- int no_tls_get_addr_opt)
+ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
{
struct ppc_elf_link_hash_table *htab;
htab = ppc_elf_hash_table (info);
htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
FALSE, FALSE, TRUE);
- if (!no_tls_get_addr_opt)
+ if (htab->plt_type != PLT_NEW)
+ htab->params->no_tls_get_addr_opt = TRUE;
+
+ if (!htab->params->no_tls_get_addr_opt)
{
struct elf_link_hash_entry *opt, *tga;
opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
tga->root.type = bfd_link_hash_indirect;
tga->root.u.i.link = &opt->root;
ppc_elf_copy_indirect_symbol (info, opt, tga);
+ opt->mark = 1;
if (opt->dynindx != -1)
{
/* Use __tls_get_addr_opt in dynamic relocations. */
}
}
else
- no_tls_get_addr_opt = TRUE;
+ htab->params->no_tls_get_addr_opt = TRUE;
}
- htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
if (htab->plt_type == PLT_NEW
- && htab->plt != NULL
- && htab->plt->output_section != NULL)
+ && htab->elf.splt != NULL
+ && htab->elf.splt->output_section != NULL)
{
- elf_section_type (htab->plt->output_section) = SHT_PROGBITS;
- elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE;
+ elf_section_type (htab->elf.splt->output_section) = SHT_PROGBITS;
+ elf_section_flags (htab->elf.splt->output_section) = SHF_ALLOC + SHF_WRITE;
}
return _bfd_elf_tls_setup (obfd, info);
struct ppc_elf_link_hash_table *htab;
int pass;
- if (info->relocatable || !info->executable)
+ if (!bfd_link_executable (info))
return TRUE;
htab = ppc_elf_hash_table (info);
notify relocate_section that optimization can be done, and
adjust got and plt refcounts. */
for (pass = 0; pass < 2; ++pass)
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
Elf_Internal_Sym *locsyms = NULL;
Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
case R_PPC_GOT_TLSLD16:
case R_PPC_GOT_TLSLD16_LO:
expecting_tls_get_addr = 1;
- /* Fall thru */
+ /* Fall through. */
case R_PPC_GOT_TLSLD16_HI:
case R_PPC_GOT_TLSLD16_HA:
case R_PPC_GOT_TLSGD16:
case R_PPC_GOT_TLSGD16_LO:
expecting_tls_get_addr = 1;
- /* Fall thru */
+ /* Fall through. */
case R_PPC_GOT_TLSGD16_HI:
case R_PPC_GOT_TLSGD16_HA:
struct plt_entry *ent;
bfd_vma addend = 0;
- if (info->shared
+ if (bfd_link_pic (info)
&& ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
addend = rel[1].r_addend;
ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
will go to this object, or will remain undefined. */
h->plt.plist = NULL;
h->needs_plt = 0;
+ h->pointer_equality_needed = 0;
}
else
{
- /* After adjust_dynamic_symbol, non_got_ref set in the
- non-shared case means that we have allocated space in
- .dynbss for the symbol and thus dyn_relocs for this
- symbol should be discarded.
- If we get here we know we are making a PLT entry for this
- symbol, and in an executable we'd normally resolve
- relocations against this symbol to the PLT entry. Allow
- dynamic relocs if the reference is weak, and the dynamic
- relocs will not cause text relocation. */
- if (!h->ref_regular_nonweak
- && h->non_got_ref
- && h->type != STT_GNU_IFUNC
+ /* Taking a function's address in a read/write section
+ doesn't require us to define the function symbol in the
+ executable on a plt call stub. A dynamic reloc can
+ be used instead, giving better runtime performance.
+ (Calls via that function pointer don't need to bounce
+ through the plt call stub.) Similarly, use a dynamic
+ reloc for a weak reference when possible, allowing the
+ resolution of the symbol to be set at load time rather
+ than link time. */
+ if ((h->pointer_equality_needed
+ || (!h->ref_regular_nonweak && h->non_got_ref))
&& !htab->is_vxworks
&& !ppc_elf_hash_entry (h)->has_sda_refs
&& !readonly_dynrelocs (h))
- h->non_got_ref = 0;
+ {
+ h->pointer_equality_needed = 0;
+ /* After adjust_dynamic_symbol, non_got_ref set in the
+ non-pic case means that dyn_relocs for this symbol
+ should be discarded. */
+ h->non_got_ref = 0;
+ }
}
+ h->protected_def = 0;
return TRUE;
}
else
only references to the symbol are via the global offset table.
For such cases we need not do anything here; the relocations will
be handled correctly by relocate_section. */
- if (info->shared)
- return TRUE;
+ if (bfd_link_pic (info))
+ {
+ h->protected_def = 0;
+ return TRUE;
+ }
/* If there are no references to this symbol that do not use the
GOT, we don't need to generate a copy reloc. */
if (!h->non_got_ref)
- return TRUE;
+ {
+ h->protected_def = 0;
+ return TRUE;
+ }
+
+ /* Protected variables do not work with .dynbss. The copy in
+ .dynbss won't be used by the shared library with the protected
+ definition for the variable. Editing to PIC, or text relocations
+ are preferable to an incorrect program. */
+ if (h->protected_def)
+ {
+ if (ELIMINATE_COPY_RELOCS
+ && ppc_elf_hash_entry (h)->has_addr16_ha
+ && ppc_elf_hash_entry (h)->has_addr16_lo
+ && htab->params->pic_fixup == 0
+ && info->disable_target_specific_optimizations <= 1)
+ htab->params->pic_fixup = 1;
+ h->non_got_ref = 0;
+ return TRUE;
+ }
+
+ /* If -z nocopyreloc was given, we won't generate them either. */
+ if (info->nocopyreloc)
+ {
+ h->non_got_ref = 0;
+ 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.
if (ppc_elf_hash_entry (h)->has_sda_refs)
s = htab->dynsbss;
+ else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ s = htab->elf.sdynrelro;
else
- s = htab->dynbss;
+ s = htab->elf.sdynbss;
BFD_ASSERT (s != NULL);
/* We must generate a R_PPC_COPY reloc to tell the dynamic linker to
if (ppc_elf_hash_entry (h)->has_sda_refs)
srel = htab->relsbss;
+ else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ srel = htab->elf.sreldynrelro;
else
- srel = htab->relbss;
+ srel = htab->elf.srelbss;
BFD_ASSERT (srel != NULL);
srel->size += sizeof (Elf32_External_Rela);
h->needs_copy = 1;
}
- return _bfd_elf_adjust_dynamic_copy (h, s);
+ return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
\f
/* Generate a symbol to mark plt call stubs. For non-PIC code the sym is
const char *stub;
struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
- if (info->shared)
+ if (bfd_link_pic (info))
stub = ".plt_pic32.";
else
stub = ".plt_call32.";
sh->ref_regular_nonweak = 1;
sh->forced_local = 1;
sh->non_elf = 0;
+ sh->root.linker_def = 1;
}
return TRUE;
}
if (htab->plt_type == PLT_VXWORKS)
{
- where = htab->got->size;
- htab->got->size += need;
+ where = htab->elf.sgot->size;
+ htab->elf.sgot->size += need;
}
else
{
}
else
{
- if (htab->got->size + need > max_before_header
- && htab->got->size <= max_before_header)
+ if (htab->elf.sgot->size + need > max_before_header
+ && htab->elf.sgot->size <= max_before_header)
{
- htab->got_gap = max_before_header - htab->got->size;
- htab->got->size = max_before_header + htab->got_header_size;
+ htab->got_gap = max_before_header - htab->elf.sgot->size;
+ htab->elf.sgot->size = max_before_header + htab->got_header_size;
}
- where = htab->got->size;
- htab->got->size += need;
+ where = htab->elf.sgot->size;
+ htab->elf.sgot->size += need;
}
}
return where;
}
+/* If H is undefined weak, make it dynamic if that makes sense. */
+
+static bfd_boolean
+ensure_undefweak_dynamic (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+
+ if (htab->dynamic_sections_created
+ && h->root.type == bfd_link_hash_undefweak
+ && h->dynindx == -1
+ && !h->forced_local
+ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+ return bfd_elf_link_record_dynamic_symbol (info, h);
+ return TRUE;
+}
+
/* Allocate space in associated reloc sections for dynamic relocs. */
static bfd_boolean
struct ppc_elf_link_hash_entry *eh;
struct ppc_elf_link_hash_table *htab;
struct elf_dyn_relocs *p;
+ bfd_boolean dyn;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
htab = ppc_elf_hash_table (info);
- if (htab->elf.dynamic_sections_created
- || h->type == STT_GNU_IFUNC)
- {
- struct plt_entry *ent;
- bfd_boolean doneone = FALSE;
- bfd_vma plt_offset = 0, glink_offset = 0;
- bfd_boolean dyn;
-
- for (ent = h->plt.plist; ent != NULL; ent = ent->next)
- if (ent->plt.refcount > 0)
- {
- /* Make sure this symbol is output as a dynamic symbol. */
- if (h->dynindx == -1
- && !h->forced_local
- && !h->def_regular
- && htab->elf.dynamic_sections_created)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
- }
-
- dyn = htab->elf.dynamic_sections_created;
- if (info->shared
- || h->type == STT_GNU_IFUNC
- || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
- {
- asection *s = htab->plt;
- if (!dyn || h->dynindx == -1)
- s = htab->iplt;
-
- if (htab->plt_type == PLT_NEW || !dyn || h->dynindx == -1)
- {
- if (!doneone)
- {
- plt_offset = s->size;
- s->size += 4;
- }
- ent->plt.offset = plt_offset;
-
- s = htab->glink;
- if (!doneone || info->shared)
- {
- glink_offset = s->size;
- s->size += GLINK_ENTRY_SIZE;
- if (h == htab->tls_get_addr
- && !htab->no_tls_get_addr_opt)
- s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
- }
- if (!doneone
- && !info->shared
- && h->def_dynamic
- && !h->def_regular)
- {
- h->root.u.def.section = s;
- h->root.u.def.value = glink_offset;
- }
- ent->glink_offset = glink_offset;
-
- if (htab->emit_stub_syms
- && !add_stub_sym (ent, h, info))
- return FALSE;
- }
- else
- {
- if (!doneone)
- {
- /* If this is the first .plt entry, make room
- for the special first entry. */
- if (s->size == 0)
- s->size += htab->plt_initial_entry_size;
-
- /* The PowerPC PLT is actually composed of two
- parts, the first part is 2 words (for a load
- and a jump), and then there is a remaining
- word available at the end. */
- plt_offset = (htab->plt_initial_entry_size
- + (htab->plt_slot_size
- * ((s->size
- - htab->plt_initial_entry_size)
- / htab->plt_entry_size)));
-
- /* If this symbol is not defined in a regular
- file, and we are not generating a shared
- library, then set the symbol to this location
- in the .plt. This is to avoid text
- relocations, and is required to make
- function pointers compare as equal between
- the normal executable and the shared library. */
- if (! info->shared
- && h->def_dynamic
- && !h->def_regular)
- {
- h->root.u.def.section = s;
- h->root.u.def.value = plt_offset;
- }
-
- /* Make room for this entry. */
- s->size += htab->plt_entry_size;
- /* After the 8192nd entry, room for two entries
- is allocated. */
- if (htab->plt_type == PLT_OLD
- && (s->size - htab->plt_initial_entry_size)
- / htab->plt_entry_size
- > PLT_NUM_SINGLE_ENTRIES)
- s->size += htab->plt_entry_size;
- }
- ent->plt.offset = plt_offset;
- }
-
- /* We also need to make an entry in the .rela.plt section. */
- if (!doneone)
- {
- if (!htab->elf.dynamic_sections_created
- || h->dynindx == -1)
- htab->reliplt->size += sizeof (Elf32_External_Rela);
- else
- {
- htab->relplt->size += sizeof (Elf32_External_Rela);
-
- if (htab->plt_type == PLT_VXWORKS)
- {
- /* Allocate space for the unloaded relocations. */
- if (!info->shared
- && htab->elf.dynamic_sections_created)
- {
- if (ent->plt.offset
- == (bfd_vma) htab->plt_initial_entry_size)
- {
- htab->srelplt2->size
- += (sizeof (Elf32_External_Rela)
- * VXWORKS_PLTRESOLVE_RELOCS);
- }
-
- htab->srelplt2->size
- += (sizeof (Elf32_External_Rela)
- * VXWORKS_PLT_NON_JMP_SLOT_RELOCS);
- }
-
- /* Every PLT entry has an associated GOT entry in
- .got.plt. */
- htab->sgotplt->size += 4;
- }
- }
- doneone = TRUE;
- }
- }
- else
- ent->plt.offset = (bfd_vma) -1;
- }
- else
- ent->plt.offset = (bfd_vma) -1;
-
- if (!doneone)
- {
- h->plt.plist = NULL;
- h->needs_plt = 0;
- }
- }
- else
- {
- h->plt.plist = NULL;
- h->needs_plt = 0;
- }
-
eh = (struct ppc_elf_link_hash_entry *) h;
- if (eh->elf.got.refcount > 0)
+ if (eh->elf.got.refcount > 0
+ || (ELIMINATE_COPY_RELOCS
+ && !eh->elf.def_regular
+ && eh->elf.protected_def
+ && eh->has_addr16_ha
+ && eh->has_addr16_lo
+ && htab->params->pic_fixup > 0))
{
- bfd_boolean dyn;
unsigned int need;
- /* Make sure this symbol is output as a dynamic symbol. */
- if (eh->elf.dynindx == -1
- && !eh->elf.forced_local
- && eh->elf.type != STT_GNU_IFUNC
- && htab->elf.dynamic_sections_created)
- {
- if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
- return FALSE;
- }
+ /* Make sure this symbol is output as a dynamic symbol.
+ Undefined weak syms won't yet be marked as dynamic. */
+ if (!ensure_undefweak_dynamic (info, &eh->elf))
+ return FALSE;
need = 0;
if ((eh->tls_mask & TLS_TLS) != 0)
else
{
eh->elf.got.offset = allocate_got (htab, need);
- dyn = htab->elf.dynamic_sections_created;
- if ((info->shared
- || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
+ if ((bfd_link_pic (info)
+ || (htab->elf.dynamic_sections_created
+ && eh->elf.dynindx != -1
+ && !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
&& (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
|| eh->elf.root.type != bfd_link_hash_undefweak))
{
- asection *rsec = htab->relgot;
+ asection *rsec = htab->elf.srelgot;
+
+ if (eh->elf.type == STT_GNU_IFUNC)
+ rsec = htab->elf.irelplt;
/* All the entries we allocated need relocs.
Except LD only needs one. */
if ((eh->tls_mask & TLS_LD) != 0
else
eh->elf.got.offset = (bfd_vma) -1;
- if (eh->dyn_relocs == NULL
- || !htab->elf.dynamic_sections_created)
- return TRUE;
+ if (!htab->elf.dynamic_sections_created
+ && h->type != STT_GNU_IFUNC)
+ eh->dyn_relocs = NULL;
+
+ if (eh->dyn_relocs == NULL)
+ ;
/* In the shared -Bsymbolic case, discard space allocated for
dynamic pc-relative relocs against symbols which turn out to be
defined in regular objects. For the normal shared case, discard
space for relocs that have become local due to symbol visibility
changes. */
-
- if (info->shared)
+ else if (bfd_link_pic (info))
{
/* Relocs that use pc_count are those that appear on a call insn,
or certain REL relocs (see must_be_dyn_reloc) that can be
/* Make sure undefined weak symbols are output as a dynamic
symbol in PIEs. */
- else if (h->dynindx == -1
- && !h->forced_local
- && !h->def_regular)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
- }
+ else if (!ensure_undefweak_dynamic (info, h))
+ return FALSE;
}
}
else if (ELIMINATE_COPY_RELOCS)
{
- /* For the non-shared case, discard space for relocs against
+ /* For the non-pic case, discard space for relocs against
symbols which turn out to need copy relocs or are not
dynamic. */
-
if (!h->non_got_ref
- && !h->def_regular)
+ && !h->def_regular
+ && !(h->protected_def
+ && eh->has_addr16_ha
+ && eh->has_addr16_lo
+ && htab->params->pic_fixup > 0))
{
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
- if (h->dynindx == -1
- && !h->forced_local)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
- }
+ if (!ensure_undefweak_dynamic (info, h))
+ return FALSE;
- /* If that succeeded, we know we'll be keeping all the
- relocs. */
- if (h->dynindx != -1)
- goto keep;
+ if (h->dynindx == -1)
+ eh->dyn_relocs = NULL;
}
-
- eh->dyn_relocs = NULL;
-
- keep: ;
+ else
+ eh->dyn_relocs = NULL;
}
- /* Finally, allocate space. */
+ /* Allocate space. */
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
asection *sreloc = elf_section_data (p->sec)->sreloc;
- if (!htab->elf.dynamic_sections_created)
- sreloc = htab->reliplt;
+ if (eh->elf.type == STT_GNU_IFUNC)
+ sreloc = htab->elf.irelplt;
sreloc->size += p->count * sizeof (Elf32_External_Rela);
}
+ /* Handle PLT relocs. Done last, after dynindx has settled. */
+ dyn = htab->elf.dynamic_sections_created && h->dynindx != -1;
+ if (dyn || h->type == STT_GNU_IFUNC)
+ {
+ struct plt_entry *ent;
+ bfd_boolean doneone = FALSE;
+ bfd_vma plt_offset = 0, glink_offset = 0;
+
+ for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ if (ent->plt.refcount > 0)
+ {
+ asection *s = htab->elf.splt;
+
+ if (!dyn)
+ s = htab->elf.iplt;
+
+ if (htab->plt_type == PLT_NEW || !dyn)
+ {
+ if (!doneone)
+ {
+ plt_offset = s->size;
+ s->size += 4;
+ }
+ ent->plt.offset = plt_offset;
+
+ s = htab->glink;
+ if (!doneone || bfd_link_pic (info))
+ {
+ glink_offset = s->size;
+ s->size += GLINK_ENTRY_SIZE;
+ if (h == htab->tls_get_addr
+ && !htab->params->no_tls_get_addr_opt)
+ s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
+ }
+ if (!doneone
+ && !bfd_link_pic (info)
+ && h->def_dynamic
+ && !h->def_regular)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = glink_offset;
+ }
+ ent->glink_offset = glink_offset;
+
+ if (htab->params->emit_stub_syms
+ && !add_stub_sym (ent, h, info))
+ return FALSE;
+ }
+ else
+ {
+ if (!doneone)
+ {
+ /* If this is the first .plt entry, make room
+ for the special first entry. */
+ if (s->size == 0)
+ s->size += htab->plt_initial_entry_size;
+
+ /* The PowerPC PLT is actually composed of two
+ parts, the first part is 2 words (for a load
+ and a jump), and then there is a remaining
+ word available at the end. */
+ plt_offset = (htab->plt_initial_entry_size
+ + (htab->plt_slot_size
+ * ((s->size
+ - htab->plt_initial_entry_size)
+ / htab->plt_entry_size)));
+
+ /* If this symbol is not defined in a regular
+ file, and we are not generating a shared
+ library, then set the symbol to this location
+ in the .plt. This is to avoid text
+ relocations, and is required to make
+ function pointers compare as equal between
+ the normal executable and the shared library. */
+ if (! bfd_link_pic (info)
+ && h->def_dynamic
+ && !h->def_regular)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = plt_offset;
+ }
+
+ /* Make room for this entry. */
+ s->size += htab->plt_entry_size;
+ /* After the 8192nd entry, room for two entries
+ is allocated. */
+ if (htab->plt_type == PLT_OLD
+ && (s->size - htab->plt_initial_entry_size)
+ / htab->plt_entry_size
+ > PLT_NUM_SINGLE_ENTRIES)
+ s->size += htab->plt_entry_size;
+ }
+ ent->plt.offset = plt_offset;
+ }
+
+ /* We also need to make an entry in the .rela.plt section. */
+ if (!doneone)
+ {
+ if (!dyn)
+ htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
+ else
+ {
+ htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
+
+ if (htab->plt_type == PLT_VXWORKS)
+ {
+ /* Allocate space for the unloaded relocations. */
+ if (!bfd_link_pic (info)
+ && htab->elf.dynamic_sections_created)
+ {
+ if (ent->plt.offset
+ == (bfd_vma) htab->plt_initial_entry_size)
+ {
+ htab->srelplt2->size
+ += (sizeof (Elf32_External_Rela)
+ * VXWORKS_PLTRESOLVE_RELOCS);
+ }
+
+ htab->srelplt2->size
+ += (sizeof (Elf32_External_Rela)
+ * VXWORKS_PLT_NON_JMP_SLOT_RELOCS);
+ }
+
+ /* Every PLT entry has an associated GOT entry in
+ .got.plt. */
+ htab->elf.sgotplt->size += 4;
+ }
+ }
+ doneone = TRUE;
+ }
+ }
+ else
+ ent->plt.offset = (bfd_vma) -1;
+
+ if (!doneone)
+ {
+ h->plt.plist = NULL;
+ h->needs_plt = 0;
+ }
+ }
+ else
+ {
+ h->plt.plist = NULL;
+ h->needs_plt = 0;
+ }
+
return TRUE;
}
/* Set the sizes of the dynamic sections. */
static bfd_boolean
-ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ppc_elf_size_dynamic_sections (bfd *output_bfd,
struct bfd_link_info *info)
{
struct ppc_elf_link_hash_table *htab;
if (elf_hash_table (info)->dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
- if (info->executable)
+ if (bfd_link_executable (info) && !info->nointerp)
{
s = bfd_get_linker_section (htab->elf.dynobj, ".interp");
BFD_ASSERT (s != NULL);
/* Set up .got offsets for local syms, and space for local dynamic
relocs. */
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
{
bfd_signed_vma *local_got;
bfd_signed_vma *end_local_got;
for (s = ibfd->sections; s != NULL; s = s->next)
{
- struct elf_dyn_relocs *p;
+ struct ppc_dyn_relocs *p;
- for (p = ((struct elf_dyn_relocs *)
+ for (p = ((struct ppc_dyn_relocs *)
elf_section_data (s)->local_dynrel);
p != NULL;
p = p->next)
else if (p->count != 0)
{
asection *sreloc = elf_section_data (p->sec)->sreloc;
- if (!htab->elf.dynamic_sections_created)
- sreloc = htab->reliplt;
+ if (p->ifunc)
+ sreloc = htab->elf.irelplt;
sreloc->size += p->count * sizeof (Elf32_External_Rela);
if ((p->sec->output_section->flags
& (SEC_READONLY | SEC_ALLOC))
else
{
*local_got = allocate_got (htab, need);
- if (info->shared)
- htab->relgot->size += (need
- * (sizeof (Elf32_External_Rela) / 4));
+ if (bfd_link_pic (info))
+ {
+ asection *srel = htab->elf.srelgot;
+ if ((*lgot_masks & PLT_IFUNC) != 0)
+ srel = htab->elf.irelplt;
+ srel->size += need * (sizeof (Elf32_External_Rela) / 4);
+ }
}
}
else
for (ent = *local_plt; ent != NULL; ent = ent->next)
if (ent->plt.refcount > 0)
{
- s = htab->iplt;
+ s = htab->elf.iplt;
if (!doneone)
{
ent->plt.offset = plt_offset;
s = htab->glink;
- if (!doneone || info->shared)
+ if (!doneone || bfd_link_pic (info))
{
glink_offset = s->size;
s->size += GLINK_ENTRY_SIZE;
if (!doneone)
{
- htab->reliplt->size += sizeof (Elf32_External_Rela);
+ htab->elf.irelplt->size += sizeof (Elf32_External_Rela);
doneone = TRUE;
}
}
if (htab->tlsld_got.refcount > 0)
{
htab->tlsld_got.offset = allocate_got (htab, 8);
- if (info->shared)
- htab->relgot->size += sizeof (Elf32_External_Rela);
+ if (bfd_link_pic (info))
+ htab->elf.srelgot->size += sizeof (Elf32_External_Rela);
}
else
htab->tlsld_got.offset = (bfd_vma) -1;
- if (htab->got != NULL && htab->plt_type != PLT_VXWORKS)
+ if (htab->elf.sgot != NULL && htab->plt_type != PLT_VXWORKS)
{
unsigned int g_o_t = 32768;
for old plt/got the got size will be 0 to 32764 (not allocated),
or 32780 to 65536 (header allocated). For new plt/got, the
corresponding ranges are 0 to 32768 and 32780 to 65536. */
- if (htab->got->size <= 32768)
+ if (htab->elf.sgot->size <= 32768)
{
- g_o_t = htab->got->size;
+ g_o_t = htab->elf.sgot->size;
if (htab->plt_type == PLT_OLD)
g_o_t += 4;
- htab->got->size += htab->got_header_size;
+ htab->elf.sgot->size += htab->got_header_size;
}
htab->elf.hgot->root.u.def.value = g_o_t;
}
- if (info->shared)
+ if (bfd_link_pic (info))
{
struct elf_link_hash_entry *sda = htab->sdata[0].sym;
- if (sda != NULL
- && !(sda->root.type == bfd_link_hash_defined
- || sda->root.type == bfd_link_hash_defweak))
- {
- sda->root.type = bfd_link_hash_defined;
- sda->root.u.def.section = htab->elf.hgot->root.u.def.section;
- sda->root.u.def.value = htab->elf.hgot->root.u.def.value;
- }
+
+ sda->root.u.def.section = htab->elf.hgot->root.u.def.section;
+ sda->root.u.def.value = htab->elf.hgot->root.u.def.value;
+ }
+ if (info->emitrelocations)
+ {
+ struct elf_link_hash_entry *sda = htab->sdata[0].sym;
+
+ if (sda != NULL && sda->ref_regular)
+ sda->root.u.def.section->flags |= SEC_KEEP;
+ sda = htab->sdata[1].sym;
+ if (sda != NULL && sda->ref_regular)
+ sda->root.u.def.section->flags |= SEC_KEEP;
}
if (htab->glink != NULL
&& htab->elf.dynamic_sections_created)
{
htab->glink_pltresolve = htab->glink->size;
- /* Space for the branch table. */
+ /* Space for the branch table. ??? We don't need entries for
+ non-dynamic symbols in this table. This case can arise with
+ static ifuncs or forced local ifuncs. */
htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
/* Pad out to align the start of PLTresolve. */
- htab->glink->size += -htab->glink->size & 15;
+ htab->glink->size += -htab->glink->size & (htab->params->ppc476_workaround
+ ? 63 : 15);
htab->glink->size += GLINK_PLTRESOLVE;
- if (htab->emit_stub_syms)
+ if (htab->params->emit_stub_syms)
{
struct elf_link_hash_entry *sh;
sh = elf_link_hash_lookup (&htab->elf, "__glink",
sh->ref_regular_nonweak = 1;
sh->forced_local = 1;
sh->non_elf = 0;
+ sh->root.linker_def = 1;
}
sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
TRUE, FALSE, FALSE);
sh->ref_regular_nonweak = 1;
sh->forced_local = 1;
sh->non_elf = 0;
+ sh->root.linker_def = 1;
}
}
}
{
s = htab->glink_eh_frame;
s->size = sizeof (glink_eh_frame_cie) + 20;
- if (info->shared)
+ if (bfd_link_pic (info))
{
s->size += 4;
if (htab->glink->size - GLINK_PLTRESOLVE + 8 >= 256)
if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
- if (s == htab->plt
- || s == htab->got)
+ if (s == htab->elf.splt
+ || s == htab->elf.sgot)
{
/* We'd like to strip these sections if they aren't needed, but if
we've exported dynamic symbols from them we must leave them.
/* Strip this section if we don't need it; see the
comment below. */
}
- else if (s == htab->iplt
+ else if (s == htab->elf.iplt
|| s == htab->glink
|| s == htab->glink_eh_frame
- || s == htab->sgotplt
+ || s == htab->elf.sgotplt
|| s == htab->sbss
- || s == htab->dynbss
- || s == htab->dynsbss
- || s == htab->sdata[0].section
- || s == htab->sdata[1].section)
+ || s == htab->elf.sdynbss
+ || s == htab->elf.sdynrelro
+ || s == htab->dynsbss)
{
/* Strip these too. */
}
+ else if (s == htab->sdata[0].section
+ || s == htab->sdata[1].section)
+ {
+ strip_section = (s->flags & SEC_KEEP) == 0;
+ }
else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s),
".rela"))
{
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
- if (info->executable)
+ if (bfd_link_executable (info))
{
if (!add_dynamic_entry (DT_DEBUG, 0))
return FALSE;
}
- if (htab->plt != NULL && htab->plt->size != 0)
+ if (htab->elf.splt != NULL && htab->elf.splt->size != 0)
{
if (!add_dynamic_entry (DT_PLTGOT, 0)
|| !add_dynamic_entry (DT_PLTRELSZ, 0)
return FALSE;
}
- if (htab->glink != NULL && htab->glink->size != 0)
+ if (htab->plt_type == PLT_NEW
+ && htab->glink != NULL
+ && htab->glink->size != 0)
{
if (!add_dynamic_entry (DT_PPC_GOT, 0))
return FALSE;
- if (!htab->no_tls_get_addr_opt
+ if (!htab->params->no_tls_get_addr_opt
&& htab->tls_get_addr != NULL
&& htab->tls_get_addr->plt.plist != NULL
- && !add_dynamic_entry (DT_PPC_TLSOPT, 0))
+ && !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS))
return FALSE;
}
/* Augmentation. */
p += 1;
- if (info->shared
+ if (bfd_link_pic (info)
&& htab->elf.dynamic_sections_created)
{
bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2;
return TRUE;
}
+/* Arrange to have _SDA_BASE_ or _SDA2_BASE_ stripped from the output
+ if it looks like nothing is using them. */
+
+static void
+maybe_strip_sdasym (bfd *output_bfd, elf_linker_section_t *lsect)
+{
+ struct elf_link_hash_entry *sda = lsect->sym;
+
+ if (sda != NULL && !sda->ref_regular && sda->dynindx == -1)
+ {
+ asection *s;
+
+ s = bfd_get_section_by_name (output_bfd, lsect->name);
+ if (s == NULL || bfd_section_removed_from_list (output_bfd, s))
+ {
+ s = bfd_get_section_by_name (output_bfd, lsect->bss_name);
+ if (s == NULL || bfd_section_removed_from_list (output_bfd, s))
+ {
+ sda->def_regular = 0;
+ /* This is somewhat magic. See elf_link_output_extsym. */
+ sda->ref_dynamic = 1;
+ sda->forced_local = 0;
+ }
+ }
+ }
+}
+
+void
+ppc_elf_maybe_strip_sdata_syms (struct bfd_link_info *info)
+{
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+
+ if (htab != NULL)
+ {
+ maybe_strip_sdasym (info->output_bfd, &htab->sdata[0]);
+ maybe_strip_sdasym (info->output_bfd, &htab->sdata[1]);
+ }
+}
+
+
/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
static bfd_boolean
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 */
0x4e800420, /* bctr */
};
+struct ppc_elf_relax_info
+{
+ unsigned int workaround_size;
+ unsigned int picfixup_size;
+};
+
+/* 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. */
+
static bfd_boolean
ppc_elf_relax_section (bfd *abfd,
asection *isec,
struct bfd_link_info *link_info,
bfd_boolean *again)
{
- struct one_fixup
+ struct one_branch_fixup
{
- struct one_fixup *next;
+ struct one_branch_fixup *next;
asection *tsec;
/* Final link, can use the symbol offset. For a
relocatable link we use the symbol's index. */
bfd_byte *contents = NULL;
Elf_Internal_Sym *isymbuf = NULL;
Elf_Internal_Rela *internal_relocs = NULL;
- Elf_Internal_Rela *irel, *irelend;
- struct one_fixup *fixups = NULL;
+ Elf_Internal_Rela *irel, *irelend = NULL;
+ struct one_branch_fixup *branch_fixups = NULL;
+ struct ppc_elf_relax_info *relax_info = NULL;
unsigned changes = 0;
+ bfd_boolean workaround_change;
struct ppc_elf_link_hash_table *htab;
- bfd_size_type trampoff;
+ bfd_size_type trampbase, trampoff, newsize, picfixup_size;
asection *got2;
bfd_boolean maybe_pasted;
*again = FALSE;
- /* Nothing to do if there are no relocations, and no need to do
- anything with non-alloc or non-code sections. */
+ /* No need to do anything with non-alloc or non-code sections. */
if ((isec->flags & SEC_ALLOC) == 0
|| (isec->flags & SEC_CODE) == 0
- || (isec->flags & SEC_RELOC) == 0
- || isec->reloc_count == 0)
+ || (isec->flags & SEC_LINKER_CREATED) != 0
+ || isec->size < 4)
return TRUE;
/* We cannot represent the required PIC relocs in the output, so don't
do anything. The linker doesn't support mixing -shared and -r
anyway. */
- if (link_info->relocatable && link_info->shared)
- return TRUE;
+ if (bfd_link_relocatable (link_info) && bfd_link_pic (link_info))
+ return TRUE;
+
+ htab = ppc_elf_hash_table (link_info);
+ if (htab == NULL)
+ return TRUE;
+
+ isec->size = (isec->size + 3) & -4;
+ if (isec->rawsize == 0)
+ 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
+ || htab->params->pic_fixup > 0)
+ {
+ if (elf_section_data (isec)->sec_info == NULL)
+ {
+ elf_section_data (isec)->sec_info
+ = bfd_zalloc (abfd, sizeof (struct ppc_elf_relax_info));
+ if (elf_section_data (isec)->sec_info == NULL)
+ return FALSE;
+ }
+ relax_info = elf_section_data (isec)->sec_info;
+ trampbase -= relax_info->workaround_size;
+ }
- trampoff = (isec->size + 3) & (bfd_vma) -4;
maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0
|| strcmp (isec->output_section->name, ".fini") == 0);
/* Space for a branch around any trampolines. */
- if (maybe_pasted)
+ trampoff = trampbase;
+ if (maybe_pasted && trampbase == isec->rawsize)
trampoff += 4;
symtab_hdr = &elf_symtab_hdr (abfd);
-
- /* Get a copy of the native relocations. */
- internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL,
- link_info->keep_memory);
- if (internal_relocs == NULL)
- goto error_return;
-
- htab = ppc_elf_hash_table (link_info);
- got2 = bfd_get_section_by_name (abfd, ".got2");
-
- irelend = internal_relocs + isec->reloc_count;
- for (irel = internal_relocs; irel < irelend; irel++)
+ picfixup_size = 0;
+ if (htab->params->branch_trampolines
+ || htab->params->pic_fixup > 0)
{
- unsigned long r_type = ELF32_R_TYPE (irel->r_info);
- bfd_vma toff, roff;
- asection *tsec;
- struct one_fixup *f;
- size_t insn_offset = 0;
- bfd_vma max_branch_offset, val;
- bfd_byte *hit_addr;
- unsigned long t0;
- struct elf_link_hash_entry *h;
- struct plt_entry **plist;
- unsigned char sym_type;
-
- switch (r_type)
+ /* Get a copy of the native relocations. */
+ if (isec->reloc_count != 0)
{
- case R_PPC_REL24:
- case R_PPC_LOCAL24PC:
- case R_PPC_PLTREL24:
- max_branch_offset = 1 << 25;
- break;
-
- case R_PPC_REL14:
- case R_PPC_REL14_BRTAKEN:
- case R_PPC_REL14_BRNTAKEN:
- max_branch_offset = 1 << 15;
- break;
-
- default:
- continue;
+ internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL,
+ link_info->keep_memory);
+ if (internal_relocs == NULL)
+ goto error_return;
}
- /* Get the value of the symbol referred to by the reloc. */
- h = NULL;
- if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
- {
- /* A local symbol. */
- Elf_Internal_Sym *isym;
-
- /* Read this BFD's local symbols. */
- if (isymbuf == NULL)
- {
- isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
- if (isymbuf == NULL)
- isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
- symtab_hdr->sh_info, 0,
- NULL, NULL, NULL);
- if (isymbuf == 0)
- goto error_return;
- }
- isym = isymbuf + ELF32_R_SYM (irel->r_info);
- if (isym->st_shndx == SHN_UNDEF)
- tsec = bfd_und_section_ptr;
- else if (isym->st_shndx == SHN_ABS)
- tsec = bfd_abs_section_ptr;
- else if (isym->st_shndx == SHN_COMMON)
- tsec = bfd_com_section_ptr;
- else
- tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+ got2 = bfd_get_section_by_name (abfd, ".got2");
- toff = isym->st_value;
- sym_type = ELF_ST_TYPE (isym->st_info);
- }
- else
+ irelend = internal_relocs + isec->reloc_count;
+ for (irel = internal_relocs; irel < irelend; irel++)
{
- /* Global symbol handling. */
- unsigned long indx;
+ unsigned long r_type = ELF32_R_TYPE (irel->r_info);
+ bfd_vma toff, roff;
+ asection *tsec;
+ struct one_branch_fixup *f;
+ size_t insn_offset = 0;
+ bfd_vma max_branch_offset = 0, val;
+ bfd_byte *hit_addr;
+ unsigned long t0;
+ struct elf_link_hash_entry *h;
+ struct plt_entry **plist;
+ unsigned char sym_type;
+
+ switch (r_type)
+ {
+ case R_PPC_REL24:
+ case R_PPC_LOCAL24PC:
+ case R_PPC_PLTREL24:
+ max_branch_offset = 1 << 25;
+ break;
- indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
- h = elf_sym_hashes (abfd)[indx];
+ case R_PPC_REL14:
+ case R_PPC_REL14_BRTAKEN:
+ case R_PPC_REL14_BRNTAKEN:
+ max_branch_offset = 1 << 15;
+ break;
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ case R_PPC_ADDR16_HA:
+ if (htab->params->pic_fixup > 0)
+ break;
+ continue;
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- tsec = h->root.u.def.section;
- toff = h->root.u.def.value;
+ default:
+ continue;
}
- else if (h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak)
+
+ /* Get the value of the symbol referred to by the reloc. */
+ h = NULL;
+ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
{
- tsec = bfd_und_section_ptr;
- toff = link_info->relocatable ? indx : 0;
+ /* A local symbol. */
+ Elf_Internal_Sym *isym;
+
+ /* Read this BFD's local symbols. */
+ if (isymbuf == NULL)
+ {
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL)
+ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (isymbuf == 0)
+ goto error_return;
+ }
+ isym = isymbuf + ELF32_R_SYM (irel->r_info);
+ if (isym->st_shndx == SHN_UNDEF)
+ tsec = bfd_und_section_ptr;
+ else if (isym->st_shndx == SHN_ABS)
+ tsec = bfd_abs_section_ptr;
+ else if (isym->st_shndx == SHN_COMMON)
+ tsec = bfd_com_section_ptr;
+ else
+ tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+
+ toff = isym->st_value;
+ sym_type = ELF_ST_TYPE (isym->st_info);
}
else
- continue;
+ {
+ /* Global symbol handling. */
+ unsigned long indx;
- sym_type = h->type;
- }
+ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
- /* The condition here under which we call find_plt_ent must
- match that in relocate_section. If we call find_plt_ent here
- but not in relocate_section, or vice versa, then the branch
- destination used here may be incorrect. */
- plist = NULL;
- if (h != NULL)
- {
- /* We know is_branch_reloc (r_type) is true. */
- if (h->type == STT_GNU_IFUNC
- || r_type == R_PPC_PLTREL24)
- plist = &h->plt.plist;
- }
- else if (sym_type == STT_GNU_IFUNC
- && elf_local_got_offsets (abfd) != NULL)
- {
- bfd_vma *local_got_offsets = elf_local_got_offsets (abfd);
- struct plt_entry **local_plt = (struct plt_entry **)
- (local_got_offsets + symtab_hdr->sh_info);
- plist = local_plt + ELF32_R_SYM (irel->r_info);
- }
- if (plist != NULL)
- {
- bfd_vma addend = 0;
- struct plt_entry *ent;
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
- if (r_type == R_PPC_PLTREL24 && link_info->shared)
- addend = irel->r_addend;
- ent = find_plt_ent (plist, got2, addend);
- if (ent != NULL)
- {
- if (htab->plt_type == PLT_NEW
- || h == NULL
- || !htab->elf.dynamic_sections_created
- || h->dynindx == -1)
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
{
- tsec = htab->glink;
- toff = ent->glink_offset;
+ tsec = h->root.u.def.section;
+ toff = h->root.u.def.value;
}
- else
+ else if (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak)
{
- tsec = htab->plt;
- toff = ent->plt.offset;
+ tsec = bfd_und_section_ptr;
+ toff = bfd_link_relocatable (link_info) ? indx : 0;
}
- }
- }
-
- /* If the branch and target are in the same section, you have
- no hope of adding stubs. We'll error out later should the
- branch overflow. */
- if (tsec == isec)
- continue;
+ else
+ continue;
- /* There probably isn't any reason to handle symbols in
- SEC_MERGE sections; SEC_MERGE doesn't seem a likely
- attribute for a code section, and we are only looking at
- branches. However, implement it correctly here as a
- reference for other target relax_section functions. */
- if (0 && tsec->sec_info_type == SEC_INFO_TYPE_MERGE)
- {
- /* At this stage in linking, no SEC_MERGE symbol has been
- adjusted, so all references to such symbols need to be
- passed through _bfd_merged_section_offset. (Later, in
- relocate_section, all SEC_MERGE symbols *except* for
- section symbols have been adjusted.)
-
- gas may reduce relocations against symbols in SEC_MERGE
- sections to a relocation against the section symbol when
- the original addend was zero. When the reloc is against
- a section symbol we should include the addend in the
- offset passed to _bfd_merged_section_offset, since the
- location of interest is the original symbol. On the
- other hand, an access to "sym+addend" where "sym" is not
- a section symbol should not include the addend; Such an
- access is presumed to be an offset from "sym"; The
- location of interest is just "sym". */
- if (sym_type == STT_SECTION)
- toff += irel->r_addend;
+ /* 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 (bfd_link_executable (link_info)
+ && 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);
- toff = _bfd_merged_section_offset (abfd, &tsec,
- elf_section_data (tsec)->sec_info,
- toff);
+ 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];
- if (sym_type != STT_SECTION)
- toff += irel->r_addend;
- }
- /* PLTREL24 addends are special. */
- else if (r_type != R_PPC_PLTREL24)
- toff += irel->r_addend;
+ 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;
- /* Attempted -shared link of non-pic code loses. */
- if (tsec->output_section == NULL)
- continue;
+ tls_mask
+ = ((struct ppc_elf_link_hash_entry *) th)->tls_mask;
+ }
- roff = irel->r_offset;
+ /* 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;
+ }
- /* If the branch is in range, no need to do anything. */
- if (tsec != bfd_und_section_ptr
- && (!link_info->relocatable
- /* A relocatable link may have sections moved during
- final link, so do not presume they remain in range. */
- || tsec->output_section == isec->output_section))
- {
- bfd_vma symaddr, reladdr;
+ sym_type = h->type;
+ }
- symaddr = tsec->output_section->vma + tsec->output_offset + toff;
- reladdr = isec->output_section->vma + isec->output_offset + roff;
- if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset)
- continue;
- }
+ if (r_type == R_PPC_ADDR16_HA)
+ {
+ if (h != NULL
+ && !h->def_regular
+ && h->protected_def
+ && ppc_elf_hash_entry (h)->has_addr16_ha
+ && ppc_elf_hash_entry (h)->has_addr16_lo)
+ picfixup_size += 12;
+ continue;
+ }
- /* Look for an existing fixup to this address. */
- for (f = fixups; f ; f = f->next)
- if (f->tsec == tsec && f->toff == toff)
- break;
+ /* The condition here under which we call find_plt_ent must
+ match that in relocate_section. If we call find_plt_ent here
+ but not in relocate_section, or vice versa, then the branch
+ destination used here may be incorrect. */
+ plist = NULL;
+ if (h != NULL)
+ {
+ /* We know is_branch_reloc (r_type) is true. */
+ if (h->type == STT_GNU_IFUNC
+ || r_type == R_PPC_PLTREL24)
+ plist = &h->plt.plist;
+ }
+ else if (sym_type == STT_GNU_IFUNC
+ && elf_local_got_offsets (abfd) != NULL)
+ {
+ bfd_vma *local_got_offsets = elf_local_got_offsets (abfd);
+ struct plt_entry **local_plt = (struct plt_entry **)
+ (local_got_offsets + symtab_hdr->sh_info);
+ plist = local_plt + ELF32_R_SYM (irel->r_info);
+ }
+ if (plist != NULL)
+ {
+ bfd_vma addend = 0;
+ struct plt_entry *ent;
- if (f == NULL)
- {
- size_t size;
- unsigned long stub_rtype;
+ if (r_type == R_PPC_PLTREL24 && bfd_link_pic (link_info))
+ addend = irel->r_addend;
+ ent = find_plt_ent (plist, got2, addend);
+ if (ent != NULL)
+ {
+ if (htab->plt_type == PLT_NEW
+ || h == NULL
+ || !htab->elf.dynamic_sections_created
+ || h->dynindx == -1)
+ {
+ tsec = htab->glink;
+ toff = ent->glink_offset;
+ }
+ else
+ {
+ tsec = htab->elf.splt;
+ toff = ent->plt.offset;
+ }
+ }
+ }
- val = trampoff - roff;
- if (val >= max_branch_offset)
- /* Oh dear, we can't reach a trampoline. Don't try to add
- one. We'll report an error later. */
+ /* If the branch and target are in the same section, you have
+ no hope of adding stubs. We'll error out later should the
+ branch overflow. */
+ if (tsec == isec)
continue;
- if (link_info->shared)
+ /* There probably isn't any reason to handle symbols in
+ SEC_MERGE sections; SEC_MERGE doesn't seem a likely
+ attribute for a code section, and we are only looking at
+ branches. However, implement it correctly here as a
+ reference for other target relax_section functions. */
+ if (0 && tsec->sec_info_type == SEC_INFO_TYPE_MERGE)
{
- size = 4 * ARRAY_SIZE (shared_stub_entry);
- insn_offset = 12;
+ /* At this stage in linking, no SEC_MERGE symbol has been
+ adjusted, so all references to such symbols need to be
+ passed through _bfd_merged_section_offset. (Later, in
+ relocate_section, all SEC_MERGE symbols *except* for
+ section symbols have been adjusted.)
+
+ gas may reduce relocations against symbols in SEC_MERGE
+ sections to a relocation against the section symbol when
+ the original addend was zero. When the reloc is against
+ a section symbol we should include the addend in the
+ offset passed to _bfd_merged_section_offset, since the
+ location of interest is the original symbol. On the
+ other hand, an access to "sym+addend" where "sym" is not
+ a section symbol should not include the addend; Such an
+ access is presumed to be an offset from "sym"; The
+ location of interest is just "sym". */
+ if (sym_type == STT_SECTION)
+ toff += irel->r_addend;
+
+ toff
+ = _bfd_merged_section_offset (abfd, &tsec,
+ elf_section_data (tsec)->sec_info,
+ toff);
+
+ if (sym_type != STT_SECTION)
+ toff += irel->r_addend;
}
- else
+ /* PLTREL24 addends are special. */
+ else if (r_type != R_PPC_PLTREL24)
+ toff += irel->r_addend;
+
+ /* Attempted -shared link of non-pic code loses. */
+ if ((!bfd_link_relocatable (link_info)
+ && tsec == bfd_und_section_ptr)
+ || tsec->output_section == NULL
+ || (tsec->owner != NULL
+ && (tsec->owner->flags & BFD_PLUGIN) != 0))
+ continue;
+
+ roff = irel->r_offset;
+
+ /* If the branch is in range, no need to do anything. */
+ if (tsec != bfd_und_section_ptr
+ && (!bfd_link_relocatable (link_info)
+ /* A relocatable link may have sections moved during
+ final link, so do not presume they remain in range. */
+ || tsec->output_section == isec->output_section))
{
- size = 4 * ARRAY_SIZE (stub_entry);
- insn_offset = 0;
+ bfd_vma symaddr, reladdr;
+
+ symaddr = tsec->output_section->vma + tsec->output_offset + toff;
+ reladdr = isec->output_section->vma + isec->output_offset + roff;
+ if (symaddr - reladdr + max_branch_offset
+ < 2 * max_branch_offset)
+ continue;
}
- stub_rtype = R_PPC_RELAX;
- if (tsec == htab->plt
- || tsec == htab->glink)
+
+ /* Look for an existing fixup to this address. */
+ for (f = branch_fixups; f ; f = f->next)
+ if (f->tsec == tsec && f->toff == toff)
+ break;
+
+ if (f == NULL)
{
- stub_rtype = R_PPC_RELAX_PLT;
- if (r_type == R_PPC_PLTREL24)
- stub_rtype = R_PPC_RELAX_PLTREL24;
- }
+ size_t size;
+ unsigned long stub_rtype;
- /* Hijack the old relocation. Since we need two
- relocations for this use a "composite" reloc. */
- irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
- stub_rtype);
- irel->r_offset = trampoff + insn_offset;
- if (r_type == R_PPC_PLTREL24
- && stub_rtype != R_PPC_RELAX_PLTREL24)
- irel->r_addend = 0;
-
- /* Record the fixup so we don't do it again this section. */
- f = bfd_malloc (sizeof (*f));
- f->next = fixups;
- f->tsec = tsec;
- f->toff = toff;
- f->trampoff = trampoff;
- fixups = f;
-
- trampoff += size;
- changes++;
- }
- else
- {
- val = f->trampoff - roff;
- if (val >= max_branch_offset)
- continue;
+ val = trampoff - roff;
+ if (val >= max_branch_offset)
+ /* Oh dear, we can't reach a trampoline. Don't try to add
+ one. We'll report an error later. */
+ continue;
- /* Nop out the reloc, since we're finalizing things here. */
- irel->r_info = ELF32_R_INFO (0, R_PPC_NONE);
- }
+ if (bfd_link_pic (link_info))
+ {
+ size = 4 * ARRAY_SIZE (shared_stub_entry);
+ insn_offset = 12;
+ }
+ else
+ {
+ size = 4 * ARRAY_SIZE (stub_entry);
+ insn_offset = 0;
+ }
+ stub_rtype = R_PPC_RELAX;
+ if (tsec == htab->elf.splt
+ || tsec == htab->glink)
+ {
+ stub_rtype = R_PPC_RELAX_PLT;
+ if (r_type == R_PPC_PLTREL24)
+ stub_rtype = R_PPC_RELAX_PLTREL24;
+ }
- /* Get the section contents. */
- if (contents == NULL)
- {
- /* Get cached copy if it exists. */
- if (elf_section_data (isec)->this_hdr.contents != NULL)
- contents = elf_section_data (isec)->this_hdr.contents;
+ /* Hijack the old relocation. Since we need two
+ relocations for this use a "composite" reloc. */
+ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+ stub_rtype);
+ irel->r_offset = trampoff + insn_offset;
+ if (r_type == R_PPC_PLTREL24
+ && stub_rtype != R_PPC_RELAX_PLTREL24)
+ irel->r_addend = 0;
+
+ /* Record the fixup so we don't do it again this section. */
+ f = bfd_malloc (sizeof (*f));
+ f->next = branch_fixups;
+ f->tsec = tsec;
+ f->toff = toff;
+ f->trampoff = trampoff;
+ branch_fixups = f;
+
+ trampoff += size;
+ changes++;
+ }
else
{
+ val = f->trampoff - roff;
+ if (val >= max_branch_offset)
+ continue;
+
+ /* Nop out the reloc, since we're finalizing things here. */
+ irel->r_info = ELF32_R_INFO (0, R_PPC_NONE);
+ }
+
+ /* Get the section contents. */
+ if (contents == NULL)
+ {
+ /* Get cached copy if it exists. */
+ if (elf_section_data (isec)->this_hdr.contents != NULL)
+ contents = elf_section_data (isec)->this_hdr.contents;
/* Go get them off disk. */
- if (!bfd_malloc_and_get_section (abfd, isec, &contents))
+ else if (!bfd_malloc_and_get_section (abfd, isec, &contents))
goto error_return;
}
- }
- /* Fix up the existing branch to hit the trampoline. */
- hit_addr = contents + roff;
- switch (r_type)
- {
- case R_PPC_REL24:
- case R_PPC_LOCAL24PC:
- case R_PPC_PLTREL24:
- t0 = bfd_get_32 (abfd, hit_addr);
- t0 &= ~0x3fffffc;
- t0 |= val & 0x3fffffc;
- bfd_put_32 (abfd, t0, hit_addr);
- break;
+ /* Fix up the existing branch to hit the trampoline. */
+ hit_addr = contents + roff;
+ switch (r_type)
+ {
+ case R_PPC_REL24:
+ case R_PPC_LOCAL24PC:
+ case R_PPC_PLTREL24:
+ t0 = bfd_get_32 (abfd, hit_addr);
+ t0 &= ~0x3fffffc;
+ t0 |= val & 0x3fffffc;
+ bfd_put_32 (abfd, t0, hit_addr);
+ break;
- case R_PPC_REL14:
- case R_PPC_REL14_BRTAKEN:
- case R_PPC_REL14_BRNTAKEN:
- t0 = bfd_get_32 (abfd, hit_addr);
- t0 &= ~0xfffc;
- t0 |= val & 0xfffc;
- bfd_put_32 (abfd, t0, hit_addr);
- break;
+ case R_PPC_REL14:
+ case R_PPC_REL14_BRTAKEN:
+ case R_PPC_REL14_BRNTAKEN:
+ t0 = bfd_get_32 (abfd, hit_addr);
+ t0 &= ~0xfffc;
+ t0 |= val & 0xfffc;
+ bfd_put_32 (abfd, t0, hit_addr);
+ break;
+ }
}
- }
-
- /* Write out the trampolines. */
- if (fixups != NULL)
- {
- const int *stub;
- bfd_byte *dest;
- int i, size;
- do
+ while (branch_fixups != NULL)
{
- struct one_fixup *f = fixups;
- fixups = fixups->next;
+ struct one_branch_fixup *f = branch_fixups;
+ branch_fixups = branch_fixups->next;
free (f);
}
- while (fixups);
-
- contents = bfd_realloc_or_free (contents, trampoff);
- if (contents == NULL)
- goto error_return;
-
- isec->size = (isec->size + 3) & (bfd_vma) -4;
- dest = contents + isec->size;
- /* Branch around the trampolines. */
- if (maybe_pasted)
- {
- bfd_vma val = B + trampoff - isec->size;
- bfd_put_32 (abfd, val, dest);
- dest += 4;
- }
- isec->size = trampoff;
+ }
- if (link_info->shared)
- {
- stub = shared_stub_entry;
- size = ARRAY_SIZE (shared_stub_entry);
- }
- else
+ workaround_change = FALSE;
+ newsize = trampoff;
+ if (htab->params->ppc476_workaround
+ && (!bfd_link_relocatable (link_info)
+ || isec->output_section->alignment_power >= htab->params->pagesize_p2))
+ {
+ bfd_vma addr, end_addr;
+ unsigned int crossings;
+ bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
+
+ addr = isec->output_section->vma + isec->output_offset;
+ end_addr = addr + trampoff;
+ addr &= -pagesize;
+ crossings = ((end_addr & -pagesize) - addr) >> htab->params->pagesize_p2;
+ if (crossings != 0)
{
- stub = stub_entry;
- size = ARRAY_SIZE (stub_entry);
+ /* Keep space aligned, to ensure the patch code itself does
+ not cross a page. Don't decrease size calculated on a
+ previous pass as otherwise we might never settle on a layout. */
+ newsize = 15 - ((end_addr - 1) & 15);
+ newsize += crossings * 16;
+ if (relax_info->workaround_size < newsize)
+ {
+ relax_info->workaround_size = newsize;
+ workaround_change = TRUE;
+ }
+ /* Ensure relocate_section is called. */
+ isec->flags |= SEC_RELOC;
}
+ newsize = trampoff + relax_info->workaround_size;
+ }
- 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 (htab->params->pic_fixup > 0)
+ {
+ picfixup_size -= relax_info->picfixup_size;
+ if (picfixup_size != 0)
+ relax_info->picfixup_size += picfixup_size;
+ newsize += relax_info->picfixup_size;
}
+ if (changes != 0 || picfixup_size != 0 || workaround_change)
+ isec->size = newsize;
+
if (isymbuf != NULL
&& symtab_hdr->contents != (unsigned char *) isymbuf)
{
}
}
+ changes += picfixup_size;
if (changes != 0)
{
/* Append sufficient NOP relocs so we can write out relocation
rel_hdr = _bfd_elf_single_rel_hdr (isec);
rel_hdr->sh_size += changes * rel_hdr->sh_entsize;
}
- else if (elf_section_data (isec)->relocs != internal_relocs)
+ else if (internal_relocs != NULL
+ && elf_section_data (isec)->relocs != internal_relocs)
free (internal_relocs);
- *again = changes != 0;
- if (!*again && link_info->relocatable)
- {
- /* 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++;
- }
- }
-
+ *again = changes != 0 || workaround_change;
return TRUE;
error_return:
+ while (branch_fixups != NULL)
+ {
+ struct one_branch_fixup *f = branch_fixups;
+ branch_fixups = branch_fixups->next;
+ free (f);
+ }
if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
free (isymbuf);
if (contents != NULL
+ plt_sec->output_section->vma
+ plt_sec->output_offset);
- if (info->shared)
+ if (bfd_link_pic (info))
{
bfd_vma got = 0;
p += 4;
bfd_put_32 (output_bfd, BCTR, p);
p += 4;
- bfd_put_32 (output_bfd, NOP, p);
+ bfd_put_32 (output_bfd, htab->params->ppc476_workaround ? BA : NOP, p);
p += 4;
}
else
return insn;
}
+static bfd_boolean
+is_insn_ds_form (unsigned int insn)
+{
+ return ((insn & (0x3f << 26)) == 58u << 26 /* ld,ldu,lwa */
+ || (insn & (0x3f << 26)) == 62u << 26 /* std,stdu,stq */
+ || (insn & (0x3f << 26)) == 57u << 26 /* lfdp */
+ || (insn & (0x3f << 26)) == 61u << 26 /* stfdp */);
+}
+
+static bfd_boolean
+is_insn_dq_form (unsigned int insn)
+{
+ return ((insn & (0x3f << 26)) == 56u << 26 /* lq */
+ || ((insn & (0x3f << 26)) == (61u << 26) /* lxv, stxv */
+ && (insn & 3) == 1));
+}
+
/* The RELOCATE_SECTION function is called by the ELF backend linker
to handle the relocations for a section.
struct elf_link_hash_entry **sym_hashes;
struct ppc_elf_link_hash_table *htab;
Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *wrel;
Elf_Internal_Rela *relend;
Elf_Internal_Rela outrel;
- asection *got2, *sreloc = NULL;
+ asection *got2;
bfd_vma *local_got_offsets;
bfd_boolean ret = TRUE;
- bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
+ bfd_vma d_offset = (bfd_big_endian (input_bfd) ? 2 : 0);
bfd_boolean is_vxworks_tls;
+ unsigned int picfixup_size = 0;
+ struct ppc_elf_relax_info *relax_info = NULL;
#ifdef DEBUG
_bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
"%ld relocations%s",
input_bfd, input_section,
(long) input_section->reloc_count,
- (info->relocatable) ? " (relocatable)" : "");
+ (bfd_link_relocatable (info)) ? " (relocatable)" : "");
#endif
got2 = bfd_get_section_by_name (input_bfd, ".got2");
sym_hashes = elf_sym_hashes (input_bfd);
/* We have to handle relocations in vxworks .tls_vars sections
specially, because the dynamic loader is 'weird'. */
- is_vxworks_tls = (htab->is_vxworks && info->shared
+ is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info)
&& !strcmp (input_section->output_section->name,
".tls_vars"));
- rel = relocs;
+ if (input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
+ relax_info = elf_section_data (input_section)->sec_info;
+ rel = wrel = relocs;
relend = relocs + input_section->reloc_count;
- for (; rel < relend; rel++)
+ for (; rel < relend; wrel++, rel++)
{
enum elf_ppc_reloc_type r_type;
bfd_vma addend;
bfd_boolean warned;
unsigned int tls_type, tls_mask, tls_gd;
struct plt_entry **ifunc;
+ struct reloc_howto_struct alt_howto;
+ again:
r_type = ELF32_R_TYPE (rel->r_info);
sym = NULL;
sec = NULL;
}
else
{
+ bfd_boolean ignored;
+
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes,
h, sec, relocation,
- unresolved_reloc, warned);
+ unresolved_reloc, warned, ignored);
sym_name = h->root.root.string;
}
howto = NULL;
if (r_type < R_PPC_max)
howto = ppc_elf_howto_table[r_type];
- RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
- rel, 1, relend, howto, 0, contents);
+
+ _bfd_clear_contents (howto, input_bfd, input_section,
+ contents + rel->r_offset);
+ wrel->r_offset = rel->r_offset;
+ wrel->r_info = 0;
+ wrel->r_addend = 0;
+
+ /* For ld -r, remove relocations in debug sections against
+ sections defined in discarded sections. Not done for
+ non-debug to preserve relocs in .eh_frame which the
+ eh_frame editing code expects to be present. */
+ if (bfd_link_relocatable (info)
+ && (input_section->flags & SEC_DEBUGGING))
+ wrel--;
+
+ continue;
}
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
{
if (got2 != NULL
&& r_type == R_PPC_PLTREL24
- && rel->r_addend >= 32768)
+ && rel->r_addend != 0)
{
/* 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;
+ if (r_type != R_PPC_RELAX_PLT
+ && r_type != R_PPC_RELAX_PLTREL24
+ && r_type != R_PPC_RELAX)
+ goto copy_reloc;
}
/* TLS optimizations. Replace instruction sequences and relocs
{
bfd_vma insn;
- insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
+ insn = bfd_get_32 (input_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 - d_offset);
+ bfd_put_32 (input_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_vma insn;
- insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
insn = _bfd_elf_ppc_at_tls_transform (insn, 2);
if (insn == 0)
abort ();
- bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
r_type = R_PPC_TPREL16_LO;
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+ R_PPC_GOT_TPREL16);
else
{
- bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
rel->r_offset -= d_offset;
+ bfd_put_32 (input_bfd, NOP, contents + rel->r_offset);
r_type = R_PPC_NONE;
}
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
&& branch_reloc_hash_match (input_bfd, rel + 1,
htab->tls_get_addr))
offset = rel[1].r_offset;
+ /* We read the low GOT_TLS insn because we need to keep
+ the destination reg. It may be something other than
+ the usual r3, and moved to r3 before the call by
+ intervening code. */
+ insn1 = bfd_get_32 (input_bfd,
+ contents + rel->r_offset - d_offset);
if ((tls_mask & tls_gd) != 0)
{
/* IE */
- insn1 = bfd_get_32 (output_bfd,
- contents + rel->r_offset - d_offset);
- insn1 &= (1 << 26) - 1;
+ insn1 &= (0x1f << 21) | (0x1f << 16);
insn1 |= 32 << 26; /* lwz */
if (offset != (bfd_vma) -1)
{
rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
insn2 = 0x7c631214; /* add 3,3,2 */
- bfd_put_32 (output_bfd, insn2, contents + offset);
+ bfd_put_32 (input_bfd, insn2, contents + offset);
}
r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
+ R_PPC_GOT_TPREL16);
else
{
/* LE */
- insn1 = 0x3c620000; /* addis 3,2,0 */
+ insn1 &= 0x1f << 21;
+ insn1 |= 0x3c020000; /* addis r,2,0 */
if (tls_gd == 0)
{
/* Was an LD reloc. */
rel[1].r_offset = offset + d_offset;
rel[1].r_addend = rel->r_addend;
insn2 = 0x38630000; /* addi 3,3,0 */
- bfd_put_32 (output_bfd, insn2, contents + offset);
+ bfd_put_32 (input_bfd, insn2, contents + offset);
}
}
- bfd_put_32 (output_bfd, insn1,
+ bfd_put_32 (input_bfd, insn1,
contents + rel->r_offset - d_offset);
if (tls_gd == 0)
{
/* We changed the symbol on an LD reloc. Start over
in order to get h, sym, sec etc. right. */
- rel--;
- continue;
+ goto again;
}
}
break;
insn2 = 0x38630000; /* addi 3,3,0 */
}
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
- bfd_put_32 (output_bfd, insn2, contents + offset);
+ bfd_put_32 (input_bfd, insn2, contents + offset);
/* Zap the reloc on the _tls_get_addr call too. */
BFD_ASSERT (offset == rel[1].r_offset);
rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
rel->r_offset += d_offset;
insn2 = 0x38630000; /* addi 3,3,0 */
- bfd_put_32 (output_bfd, insn2,
+ bfd_put_32 (input_bfd, insn2,
contents + rel->r_offset - d_offset);
/* Zap the reloc on the _tls_get_addr call too. */
BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset);
rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
- rel--;
- continue;
+ goto again;
}
break;
}
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_REL14_BRTAKEN:
branch_bit = BRANCH_PREDICT_BIT;
- /* Fall thru */
+ /* Fall through. */
/* Branch not taken prediction relocations. */
case R_PPC_ADDR14_BRNTAKEN:
{
bfd_vma insn;
- insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
insn &= ~BRANCH_PREDICT_BIT;
insn |= branch_bit;
if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0)
insn ^= BRANCH_PREDICT_BIT;
- bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
break;
}
}
+ if (ELIMINATE_COPY_RELOCS
+ && h != NULL
+ && !h->def_regular
+ && h->protected_def
+ && ppc_elf_hash_entry (h)->has_addr16_ha
+ && ppc_elf_hash_entry (h)->has_addr16_lo
+ && htab->params->pic_fixup > 0)
+ {
+ /* Convert lis;addi or lis;load/store accessing a protected
+ variable defined in a shared library to PIC. */
+ unsigned int insn;
+
+ if (r_type == R_PPC_ADDR16_HA)
+ {
+ insn = bfd_get_32 (input_bfd,
+ contents + rel->r_offset - d_offset);
+ if ((insn & (0x3f << 26)) == (15u << 26)
+ && (insn & (0x1f << 16)) == 0 /* lis */)
+ {
+ bfd_byte *p;
+ bfd_vma off;
+ bfd_vma got_addr;
+
+ p = (contents + input_section->size
+ - relax_info->workaround_size
+ - relax_info->picfixup_size
+ + picfixup_size);
+ off = (p - contents) - (rel->r_offset - d_offset);
+ if (off > 0x1fffffc || (off & 3) != 0)
+ info->callbacks->einfo
+ (_("%H: fixup branch overflow\n"),
+ input_bfd, input_section, rel->r_offset);
+
+ bfd_put_32 (input_bfd, B | off,
+ contents + rel->r_offset - d_offset);
+ got_addr = (htab->elf.sgot->output_section->vma
+ + htab->elf.sgot->output_offset
+ + (h->got.offset & ~1));
+ wrel->r_offset = (p - contents) + d_offset;
+ wrel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_HA);
+ wrel->r_addend = got_addr;
+ insn &= ~0xffff;
+ insn |= ((unsigned int )(got_addr + 0x8000) >> 16) & 0xffff;
+ bfd_put_32 (input_bfd, insn, p);
+
+ /* Convert lis to lwz, loading address from GOT. */
+ insn &= ~0xffff;
+ insn ^= (32u ^ 15u) << 26;
+ insn |= (insn & (0x1f << 21)) >> 5;
+ insn |= got_addr & 0xffff;
+ bfd_put_32 (input_bfd, insn, p + 4);
+
+ bfd_put_32 (input_bfd, B | ((-4 - off) & 0x3ffffff), p + 8);
+ picfixup_size += 12;
+
+ /* Use one of the spare relocs, so --emit-relocs
+ output is reasonable. */
+ memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
+ wrel++, rel++;
+ rel->r_offset = wrel[-1].r_offset + 4;
+ rel->r_info = ELF32_R_INFO (0, R_PPC_ADDR16_LO);
+ rel->r_addend = wrel[-1].r_addend;
+
+ /* Continue on as if we had a got reloc, to output
+ dynamic reloc. */
+ r_type = R_PPC_GOT16_LO;
+ }
+ else
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%H: error: %s with unexpected instruction %x\n"),
+ input_bfd, input_section, rel->r_offset,
+ "R_PPC_ADDR16_HA", insn);
+ }
+ else if (r_type == R_PPC_ADDR16_LO)
+ {
+ insn = bfd_get_32 (input_bfd,
+ contents + rel->r_offset - d_offset);
+ if ((insn & (0x3f << 26)) == 14u << 26 /* addi */
+ || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
+ || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
+ || (insn & (0x3f << 26)) == 36u << 26 /* stw */
+ || (insn & (0x3f << 26)) == 38u << 26 /* stb */
+ || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
+ || (insn & (0x3f << 26)) == 42u << 26 /* lha */
+ || (insn & (0x3f << 26)) == 44u << 26 /* sth */
+ || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
+ || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
+ || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
+ || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
+ || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
+ || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
+ || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
+ && (insn & 3) != 1)
+ || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
+ && ((insn & 3) == 0 || (insn & 3) == 3)))
+ {
+ /* Arrange to apply the reloc addend, if any. */
+ relocation = 0;
+ unresolved_reloc = FALSE;
+ rel->r_info = ELF32_R_INFO (0, r_type);
+ }
+ else
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%H: error: %s with unexpected instruction %x\n"),
+ input_bfd, input_section, rel->r_offset,
+ "R_PPC_ADDR16_LO", insn);
+ }
+ }
+
ifunc = NULL;
if (!htab->is_vxworks)
{
ent = NULL;
if (ifunc != NULL
- && (!info->shared
+ && (!bfd_link_pic (info)
|| is_branch_reloc (r_type)))
{
addend = 0;
- if (r_type == R_PPC_PLTREL24 && info->shared)
+ if (r_type == R_PPC_PLTREL24 && bfd_link_pic (info))
addend = rel->r_addend;
ent = find_plt_ent (ifunc, got2, addend);
}
if (ent != NULL)
{
+ if (bfd_link_pic (info)
+ && ent->sec != got2
+ && htab->plt_type != PLT_NEW
+ && (!htab->elf.dynamic_sections_created
+ || h == NULL
+ || h->dynindx == -1))
+ {
+ /* Uh oh, we are going to create a pic glink stub
+ for an ifunc (here for h == NULL and later in
+ finish_dynamic_symbol for h != NULL), and
+ apparently are using code compiled with
+ -mbss-plt. The difficulty is that -mbss-plt code
+ gives no indication via a magic PLTREL24 addend
+ whether r30 is equal to _GLOBAL_OFFSET_TABLE_ or
+ is pointing into a .got2 section (and how far
+ into .got2). */
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%X%H: unsupported bss-plt -fPIC ifunc %s\n"),
+ input_bfd, input_section, rel->r_offset, sym_name);
+ }
if (h == NULL && (ent->plt.offset & 1) == 0)
{
Elf_Internal_Rela rela;
bfd_byte *loc;
- rela.r_offset = (htab->iplt->output_section->vma
- + htab->iplt->output_offset
+ rela.r_offset = (htab->elf.iplt->output_section->vma
+ + htab->elf.iplt->output_offset
+ ent->plt.offset);
rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
rela.r_addend = relocation;
- loc = htab->reliplt->contents;
- loc += (htab->reliplt->reloc_count++
+ loc = htab->elf.irelplt->contents;
+ loc += (htab->elf.irelplt->reloc_count++
* sizeof (Elf32_External_Rela));
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
{
unsigned char *p = ((unsigned char *) htab->glink->contents
+ ent->glink_offset);
- write_glink_stub (ent, htab->iplt, p, info);
+ write_glink_stub (ent, htab->elf.iplt, p, info);
ent->glink_offset |= 1;
}
unresolved_reloc = FALSE;
if (htab->plt_type == PLT_NEW
|| !htab->elf.dynamic_sections_created
- || h == NULL)
+ || h == NULL
+ || h->dynindx == -1)
relocation = (htab->glink->output_section->vma
+ htab->glink->output_offset
+ (ent->glink_offset & ~1));
else
- relocation = (htab->plt->output_section->vma
- + htab->plt->output_offset
+ relocation = (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ ent->plt.offset);
}
}
{
default:
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %B: unknown relocation type %d for symbol %s\n"),
input_bfd, (int) r_type, sym_name);
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
- continue;
+ goto copy_reloc;
case R_PPC_NONE:
case R_PPC_TLS:
case R_PPC_EMB_MRKREF:
case R_PPC_GNU_VTINHERIT:
case R_PPC_GNU_VTENTRY:
- continue;
+ goto copy_reloc;
/* GOT16 relocations. Like an ADDR16 using the symbol's
address in the GOT as relocation value instead of the
bfd_vma *offp;
unsigned long indx;
- if (htab->got == NULL)
+ if (htab->elf.sgot == NULL)
abort ();
indx = 0;
offp = &htab->tlsld_got.offset;
else if (h != NULL)
{
- bfd_boolean dyn;
- dyn = htab->elf.dynamic_sections_created;
- if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
- || (info->shared
- && SYMBOL_REFERENCES_LOCAL (info, h)))
+ if (!htab->elf.dynamic_sections_created
+ || h->dynindx == -1
+ || SYMBOL_REFERENCES_LOCAL (info, h)
+ || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ && h->root.type == bfd_link_hash_undefweak))
/* This is actually a static link, or it is a
-Bsymbolic link and the symbol is defined
locally, or the symbol was forced to be local
}
/* Generate relocs for the dynamic linker. */
- if ((info->shared || indx != 0)
- && (offp == &htab->tlsld_got.offset
- || h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak))
+ if (indx != 0
+ || (bfd_link_pic (info)
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak
+ || offp == &htab->tlsld_got.offset)))
{
- asection *rsec = htab->relgot;
+ asection *rsec = htab->elf.srelgot;
bfd_byte * loc;
- outrel.r_offset = (htab->got->output_section->vma
- + htab->got->output_offset
+ if (ifunc != NULL)
+ rsec = htab->elf.irelplt;
+ outrel.r_offset = (htab->elf.sgot->output_section->vma
+ + htab->elf.sgot->output_offset
+ off);
outrel.r_addend = 0;
if (tls_ty & (TLS_LD | TLS_GD))
{
outrel.r_addend += relocation;
if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
- outrel.r_addend -= htab->elf.tls_sec->vma;
+ {
+ if (htab->elf.tls_sec == NULL)
+ outrel.r_addend = 0;
+ else
+ outrel.r_addend -= htab->elf.tls_sec->vma;
+ }
}
loc = rsec->contents;
loc += (rsec->reloc_count++
else
{
bfd_vma value = relocation;
+ int tlsopt = (htab->plt_type == PLT_NEW
+ && !htab->params->no_tls_get_addr_opt
+ && htab->tls_get_addr != NULL
+ && htab->tls_get_addr->plt.plist != NULL);
- if (tls_ty == (TLS_TLS | TLS_LD))
- value = 1;
- else if (tls_ty != 0)
+ if (tls_ty != 0)
{
- value -= htab->elf.tls_sec->vma + DTP_OFFSET;
- if (tls_ty == (TLS_TLS | TLS_TPREL))
- value += DTP_OFFSET - TP_OFFSET;
+ if (htab->elf.tls_sec == NULL)
+ value = 0;
+ else
+ {
+ if (tls_ty & TLS_LD)
+ value = 0;
+ else
+ value -= htab->elf.tls_sec->vma + DTP_OFFSET;
+ if ((tls_ty & TLS_TPREL)
+ || (tlsopt && !(tls_ty & TLS_DTPREL)))
+ value += DTP_OFFSET - TP_OFFSET;
+ }
- if (tls_ty == (TLS_TLS | TLS_GD))
+ if (tls_ty & (TLS_LD | TLS_GD))
{
- bfd_put_32 (output_bfd, value,
- htab->got->contents + off + 4);
- value = 1;
+ bfd_put_32 (input_bfd, value,
+ htab->elf.sgot->contents + off + 4);
+ value = !tlsopt;
}
}
- bfd_put_32 (output_bfd, value,
- htab->got->contents + off);
+ bfd_put_32 (input_bfd, value,
+ htab->elf.sgot->contents + off);
}
off += 4;
}
}
- relocation = (htab->got->output_section->vma
- + htab->got->output_offset
+ /* If here for a picfixup, we're done. */
+ if (r_type != ELF32_R_TYPE (rel->r_info))
+ goto copy_reloc;
+
+ relocation = (htab->elf.sgot->output_section->vma
+ + htab->elf.sgot->output_offset
+ off
- SYM_VAL (htab->elf.hgot));
got at entry m+n bears little relation to the entry m. */
if (addend != 0)
info->callbacks->einfo
- (_("%P: %H: non-zero addend on %s reloc against `%s'\n"),
+ /* xgettext:c-format */
+ (_("%H: non-zero addend on %s reloc against `%s'\n"),
input_bfd, input_section, rel->r_offset,
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. */
if (unresolved_reloc)
{
- if (! (*info->callbacks->undefined_symbol) (info,
- h->root.root.string,
- input_bfd,
- input_section,
- rel->r_offset,
- TRUE))
- return FALSE;
- continue;
+ (*info->callbacks->undefined_symbol) (info,
+ h->root.root.string,
+ input_bfd,
+ input_section,
+ rel->r_offset,
+ TRUE);
+ goto copy_reloc;
+ }
+ if (h != NULL && h->type == STT_GNU_IFUNC && bfd_link_pic (info))
+ {
+ /* @local on an ifunc does not really make sense since
+ the ifunc resolver can take you anywhere. More
+ seriously, calls to ifuncs must go through a plt call
+ stub, and for pic the plt call stubs uses r30 to
+ access the PLT. The problem is that a call that is
+ local won't have the +32k reloc addend trick marking
+ -fPIC code, so the linker won't know whether r30 is
+ _GLOBAL_OFFSET_TABLE_ or pointing into a .got2 section. */
+ /* xgettext:c-format */
+ info->callbacks->einfo (_("%X%H: @local call to ifunc %s\n"),
+ input_bfd, input_section, rel->r_offset,
+ h->root.root.string);
}
break;
case R_PPC_DTPREL16_LO:
case R_PPC_DTPREL16_HI:
case R_PPC_DTPREL16_HA:
- addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
break;
/* Relocations that may need to be propagated if this is a shared
code using weak externs ought to check that they are
defined before using them. */
bfd_byte *p = contents + rel->r_offset - d_offset;
- unsigned int insn = bfd_get_32 (output_bfd, p);
+ unsigned int insn = bfd_get_32 (input_bfd, p);
insn = _bfd_elf_ppc_at_tprel_transform (insn, 2);
if (insn != 0)
- bfd_put_32 (output_bfd, insn, p);
+ bfd_put_32 (input_bfd, insn, p);
break;
}
- addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
/* The TPREL16 relocs shouldn't really be used in shared
libs as they will result in DT_TEXTREL being set, but
support them anyway. */
goto dodyn;
case R_PPC_TPREL32:
- addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
goto dodyn;
case R_PPC_DTPREL32:
- addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
goto dodyn;
case R_PPC_DTPMOD32:
case R_PPC_REL16_LO:
case R_PPC_REL16_HI:
case R_PPC_REL16_HA:
+ case R_PPC_REL16DX_HA:
break;
case R_PPC_REL32:
case R_PPC_ADDR14:
case R_PPC_ADDR14_BRTAKEN:
case R_PPC_ADDR14_BRNTAKEN:
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
break;
/* fall through */
|| is_vxworks_tls)
break;
- if ((info->shared
+ if ((bfd_link_pic (info)
&& !(h != NULL
&& ((h->root.type == bfd_link_hash_undefined
&& (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
&& (must_be_dyn_reloc (info, r_type)
|| !SYMBOL_CALLS_LOCAL (info, h)))
|| (ELIMINATE_COPY_RELOCS
- && !info->shared
+ && !bfd_link_pic (info)
&& h != NULL
&& h->dynindx != -1
&& !h->non_got_ref
- && !h->def_regular))
+ && !h->def_regular
+ && !(h->protected_def
+ && ppc_elf_hash_entry (h)->has_addr16_ha
+ && ppc_elf_hash_entry (h)->has_addr16_lo
+ && htab->params->pic_fixup > 0)))
{
int skip;
- bfd_byte * loc;
+ bfd_byte *loc;
+ asection *sreloc;
#ifdef DEBUG
fprintf (stderr, "ppc_elf_relocate_section needs to "
"create relocation for %s\n",
/* When generating a shared object, these relocations
are copied into the output file to be resolved at run
time. */
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (ifunc)
+ sreloc = htab->elf.irelplt;
if (sreloc == NULL)
- {
- sreloc = elf_section_data (input_section)->sreloc;
- if (!htab->elf.dynamic_sections_created)
- sreloc = htab->reliplt;
- if (sreloc == NULL)
- return FALSE;
- }
+ return FALSE;
skip = 0;
outrel.r_offset = _bfd_elf_section_offset (output_bfd, info,
|| h->root.type == bfd_link_hash_undefweak))
|| !SYMBOL_REFERENCES_LOCAL (info, h))
{
+ BFD_ASSERT (h->dynindx != -1);
unresolved_reloc = FALSE;
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
outrel.r_addend = rel->r_addend;
So we'll segfault when trying to run the
indirection function to resolve the reloc. */
info->callbacks->einfo
- (_("%P: %H: relocation %s for indirect "
+ /* xgettext:c-format */
+ (_("%H: relocation %s for indirect "
"function %s unsupported\n"),
input_bfd, input_section, rel->r_offset,
howto->name,
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
if (skip == -1)
- continue;
+ goto copy_reloc;
- /* This reloc will be computed at runtime. We clear the memory
- so that it contains predictable value. */
- if (! skip
- && ((input_section->flags & SEC_ALLOC) != 0
- || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE))
+ /* This reloc will be computed at runtime. Clear the memory
+ so that it contains a predictable value for prelink. */
+ if (!skip)
{
relocation = howto->pc_relative ? outrel.r_offset : 0;
addend = 0;
break;
}
}
+ else if (r_type == R_PPC_DTPMOD32
+ && htab->plt_type == PLT_NEW
+ && !htab->params->no_tls_get_addr_opt
+ && htab->tls_get_addr != NULL
+ && htab->tls_get_addr->plt.plist != NULL)
+ {
+ /* Set up for __tls_get_addr_opt stub when this entry
+ does not have dynamic relocs. */
+ relocation = 0;
+ /* Set up the next word for local dynamic. If it turns
+ out to be global dynamic, the reloc will overwrite
+ this value. */
+ if (rel->r_offset + 8 <= input_section->size)
+ bfd_put_32 (input_bfd, DTP_OFFSET - TP_OFFSET,
+ contents + rel->r_offset + 4);
+ }
+ else if (r_type == R_PPC_DTPREL32
+ && htab->plt_type == PLT_NEW
+ && !htab->params->no_tls_get_addr_opt
+ && htab->tls_get_addr != NULL
+ && htab->tls_get_addr->plt.plist != NULL
+ && rel > relocs
+ && rel[-1].r_info == ELF32_R_INFO (r_symndx, R_PPC_DTPMOD32)
+ && rel[-1].r_offset + 4 == rel->r_offset)
+ {
+ /* __tls_get_addr_opt stub value. */
+ addend += DTP_OFFSET - TP_OFFSET;
+ }
break;
case R_PPC_RELAX_PLT:
if (r_type == R_PPC_RELAX_PLTREL24)
{
- if (info->shared)
+ if (bfd_link_pic (info))
got2_addend = addend;
addend = 0;
}
+ htab->glink->output_offset
+ ent->glink_offset);
else
- relocation = (htab->plt->output_section->vma
- + htab->plt->output_offset
+ relocation = (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ ent->plt.offset);
}
- /* Fall thru */
+ /* Fall through. */
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 (bfd_link_pic (info))
+ {
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset - 4);
+ stub = shared_stub_entry;
+ bfd_put_32 (input_bfd, stub[0], contents + insn_offset - 12);
+ bfd_put_32 (input_bfd, stub[1], contents + insn_offset - 8);
+ bfd_put_32 (input_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 (bfd_link_relocatable (info))
+ relocation = 0;
+
+ /* First insn is HA, second is LO. */
+ insn = *stub++;
+ insn |= ((relocation + 0x8000) >> 16) & 0xffff;
+ bfd_put_32 (input_bfd, insn, contents + insn_offset);
+ insn_offset += 4;
+
+ insn = *stub++;
+ insn |= relocation & 0xffff;
+ bfd_put_32 (input_bfd, insn, contents + insn_offset);
+ insn_offset += 4;
+ size -= 2;
+
+ while (size != 0)
+ {
+ insn = *stub++;
+ --size;
+ bfd_put_32 (input_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;
- 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;
- rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
- rel++;
+ wrel->r_offset = rel->r_offset + d_offset;
+ wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
+ wrel->r_addend = rel->r_addend;
+ memmove (wrel + 1, wrel, (relend - wrel - 1) * sizeof (*wrel));
+ wrel++, rel++;
+ wrel->r_offset += 4;
+ wrel->r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
}
continue;
break;
case R_PPC_PLTREL24:
- if (h == NULL || ifunc != NULL)
- break;
- /* Relocation is to the entry for this symbol in the
- procedure linkage table. */
- {
- struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
- info->shared ? addend : 0);
- addend = 0;
- if (ent == NULL
- || htab->plt == NULL)
- {
- /* We didn't make a PLT entry for this symbol. This
- happens when statically linking PIC code, or when
- using -Bsymbolic. */
- break;
- }
+ if (h != NULL && ifunc == NULL)
+ {
+ struct plt_entry *ent;
- unresolved_reloc = FALSE;
- if (htab->plt_type == PLT_NEW)
- relocation = (htab->glink->output_section->vma
- + htab->glink->output_offset
- + ent->glink_offset);
- else
- relocation = (htab->plt->output_section->vma
- + htab->plt->output_offset
- + ent->plt.offset);
- }
+ ent = find_plt_ent (&h->plt.plist, got2,
+ bfd_link_pic (info) ? addend : 0);
+ if (ent == NULL
+ || htab->elf.splt == NULL)
+ {
+ /* We didn't make a PLT entry for this symbol. This
+ happens when statically linking PIC code, or when
+ using -Bsymbolic. */
+ }
+ else
+ {
+ /* Relocation is to the entry for this symbol in the
+ procedure linkage table. */
+ unresolved_reloc = FALSE;
+ if (htab->plt_type == PLT_NEW)
+ relocation = (htab->glink->output_section->vma
+ + htab->glink->output_offset
+ + ent->glink_offset);
+ else
+ relocation = (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ + ent->plt.offset);
+ }
+ }
+
+ /* R_PPC_PLTREL24 is rather special. If non-zero, the
+ addend specifies the GOT pointer offset within .got2.
+ Don't apply it to the relocation field. */
+ addend = 0;
break;
/* Relocate against _SDA_BASE_. */
addend -= SYM_VAL (sda);
name = bfd_get_section_name (output_bfd, sec->output_section);
- if (! ((CONST_STRNEQ (name, ".sdata")
- && (name[6] == 0 || name[6] == '.'))
- || (CONST_STRNEQ (name, ".sbss")
- && (name[5] == 0 || name[5] == '.'))))
+ if (!(strcmp (name, ".sdata") == 0
+ || strcmp (name, ".sbss") == 0))
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %B: the target (%s) of a %s relocation is "
"in the wrong output section (%s)\n"),
input_bfd,
addend -= SYM_VAL (sda);
name = bfd_get_section_name (output_bfd, sec->output_section);
- if (! (CONST_STRNEQ (name, ".sdata2")
- || CONST_STRNEQ (name, ".sbss2")))
+ if (!(strcmp (name, ".sdata2") == 0
+ || strcmp (name, ".sbss2") == 0))
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %B: the target (%s) of a %s relocation is "
"in the wrong output section (%s)\n"),
input_bfd,
break;
case R_PPC_VLE_LO16A:
- relocation = (relocation + addend) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- relocation, split16a_type);
- continue;
+ relocation = relocation + addend;
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16a_type, htab->params->vle_reloc_fixup);
+ goto copy_reloc;
case R_PPC_VLE_LO16D:
- relocation = (relocation + addend) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- relocation, split16d_type);
- continue;
+ relocation = relocation + addend;
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16d_type, htab->params->vle_reloc_fixup);
+ goto copy_reloc;
case R_PPC_VLE_HI16A:
- relocation = ((relocation + addend) >> 16) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- relocation, split16a_type);
- continue;
+ relocation = (relocation + addend) >> 16;
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16a_type, htab->params->vle_reloc_fixup);
+ goto copy_reloc;
case R_PPC_VLE_HI16D:
- relocation = ((relocation + addend) >> 16) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- relocation, split16d_type);
- continue;
+ relocation = (relocation + addend) >> 16;
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16d_type, htab->params->vle_reloc_fixup);
+ goto copy_reloc;
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);
- }
- continue;
+ relocation = (relocation + addend + 0x8000) >> 16;
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16a_type, htab->params->vle_reloc_fixup);
+ goto copy_reloc;
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);
- }
- continue;
+ relocation = (relocation + addend + 0x8000) >> 16;
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, relocation,
+ split16d_type, htab->params->vle_reloc_fixup);
+ goto copy_reloc;
/* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */
case R_PPC_EMB_SDA21:
{
const char *name;
int reg;
+ unsigned int insn;
struct elf_link_hash_entry *sda = NULL;
if (sec == NULL || sec->output_section == NULL)
}
name = bfd_get_section_name (output_bfd, sec->output_section);
- if (((CONST_STRNEQ (name, ".sdata")
- && (name[6] == 0 || name[6] == '.'))
- || (CONST_STRNEQ (name, ".sbss")
- && (name[5] == 0 || name[5] == '.'))))
+ if (strcmp (name, ".sdata") == 0
+ || strcmp (name, ".sbss") == 0)
{
reg = 13;
sda = htab->sdata[0].sym;
}
- else if (CONST_STRNEQ (name, ".sdata2")
- || CONST_STRNEQ (name, ".sbss2"))
+ else if (strcmp (name, ".sdata2") == 0
+ || strcmp (name, ".sbss2") == 0)
{
reg = 2;
sda = htab->sdata[1].sym;
else
{
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %B: the target (%s) of a %s relocation is "
"in the wrong output section (%s)\n"),
input_bfd,
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
- continue;
+ goto copy_reloc;
}
if (sda != NULL)
addend -= SYM_VAL (sda);
}
+ insn = bfd_get_32 (input_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;
+
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+
+ if (r_type == R_PPC_VLE_SDA21
+ && ((relocation + 0x80000) & 0xffffffff) > 0x100000)
+ 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)
{
- 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 (input_bfd, insn, contents + rel->r_offset);
}
break;
{
bfd_vma value;
const char *name;
- //int reg;
struct elf_link_hash_entry *sda = NULL;
if (sec == NULL || sec->output_section == NULL)
}
name = bfd_get_section_name (output_bfd, sec->output_section);
- if (((CONST_STRNEQ (name, ".sdata")
- && (name[6] == 0 || name[6] == '.'))
- || (CONST_STRNEQ (name, ".sbss")
- && (name[5] == 0 || name[5] == '.'))))
- {
- //reg = 13;
- sda = htab->sdata[0].sym;
- }
- else if (CONST_STRNEQ (name, ".sdata2")
- || CONST_STRNEQ (name, ".sbss2"))
- {
- //reg = 2;
- sda = htab->sdata[1].sym;
- }
+ if (strcmp (name, ".sdata") == 0
+ || strcmp (name, ".sbss") == 0)
+ sda = htab->sdata[0].sym;
+ else if (strcmp (name, ".sdata2") == 0
+ || strcmp (name, ".sbss2") == 0)
+ sda = htab->sdata[1].sym;
else
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: the target (%s) of a %s relocation is "
"in the wrong output section (%s)"),
input_bfd,
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
- continue;
- }
-
- if (sda != NULL)
- {
- if (!is_static_defined (sda))
- {
- unresolved_reloc = TRUE;
- break;
- }
+ goto copy_reloc;
}
- 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)
+ if (sda == NULL || !is_static_defined (sda))
{
- value = (value + addend) & 0xffff;
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16d_type);
+ unresolved_reloc = TRUE;
+ break;
}
- else if (r_type == R_PPC_VLE_SDAREL_HI16A)
+ value = relocation + addend - SYM_VAL (sda);
+
+ if (r_type == R_PPC_VLE_SDAREL_LO16A)
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16a_type,
+ htab->params->vle_reloc_fixup);
+ else if (r_type == R_PPC_VLE_SDAREL_LO16D)
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
+ else if (r_type == R_PPC_VLE_SDAREL_HI16A)
{
- 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 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16a_type,
+ htab->params->vle_reloc_fixup);
}
- else if (r_type == R_PPC_VLE_SDAREL_HI16D)
+ 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, split16d_type);
+ value = value >> 16;
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
}
- else if (r_type == R_PPC_VLE_SDAREL_HA16A)
+ else if (r_type == R_PPC_VLE_SDAREL_HA16A)
{
- value += addend;
- value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
- ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
- value, split16a_type);
+ value = (value + 0x8000) >> 16;
+ ppc_elf_vle_split16 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16a_type,
+ htab->params->vle_reloc_fixup);
}
- else if (r_type == R_PPC_VLE_SDAREL_HA16D)
+ 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 (input_bfd, input_section, rel->r_offset,
+ contents + rel->r_offset, value,
+ split16d_type,
+ htab->params->vle_reloc_fixup);
}
}
- continue;
+ goto copy_reloc;
/* Relocate against the beginning of the section. */
case R_PPC_SECTOFF:
case R_PPC_EMB_RELST_HA:
case R_PPC_EMB_BIT_FLD:
info->callbacks->einfo
+ /* xgettext:c-format */
(_("%P: %B: relocation %s is not yet supported for symbol %s\n"),
input_bfd,
howto->name,
bfd_set_error (bfd_error_invalid_operation);
ret = FALSE;
- continue;
+ goto copy_reloc;
}
/* Do any further special processing. */
case R_PPC_ADDR16_HA:
case R_PPC_REL16_HA:
+ case R_PPC_REL16DX_HA:
case R_PPC_SECTOFF_HA:
case R_PPC_TPREL16_HA:
case R_PPC_DTPREL16_HA:
alone (it will be set to zero elsewhere in the link). */
if (sec == NULL)
break;
- /* Fall thru */
+ /* Fall through. */
case R_PPC_PLT16_HA:
case R_PPC_GOT16_HA:
Bits 0:15 are not used. */
addend += 0x8000;
break;
+
+ case R_PPC_ADDR16:
+ case R_PPC_ADDR16_LO:
+ case R_PPC_GOT16:
+ case R_PPC_GOT16_LO:
+ case R_PPC_SDAREL16:
+ case R_PPC_SECTOFF:
+ case R_PPC_SECTOFF_LO:
+ case R_PPC_DTPREL16:
+ case R_PPC_DTPREL16_LO:
+ case R_PPC_TPREL16:
+ case R_PPC_TPREL16_LO:
+ case R_PPC_GOT_TLSGD16:
+ case R_PPC_GOT_TLSGD16_LO:
+ case R_PPC_GOT_TLSLD16:
+ case R_PPC_GOT_TLSLD16_LO:
+ case R_PPC_GOT_DTPREL16:
+ case R_PPC_GOT_DTPREL16_LO:
+ case R_PPC_GOT_TPREL16:
+ case R_PPC_GOT_TPREL16_LO:
+ {
+ /* The 32-bit ABI lacks proper relocations to deal with
+ certain 64-bit instructions. Prevent damage to bits
+ that make up part of the insn opcode. */
+ unsigned int insn, mask, lobit;
+
+ insn = bfd_get_32 (input_bfd,
+ contents + rel->r_offset - d_offset);
+ mask = 0;
+ if (is_insn_ds_form (insn))
+ mask = 3;
+ else if (is_insn_dq_form (insn))
+ mask = 15;
+ else
+ break;
+ relocation += addend;
+ addend = insn & mask;
+ lobit = mask & relocation;
+ if (lobit != 0)
+ {
+ relocation ^= lobit;
+ info->callbacks->einfo
+ /* xgettext:c-format */
+ (_("%H: error: %s against `%s' not a multiple of %u\n"),
+ input_bfd, input_section, rel->r_offset,
+ howto->name, sym_name, mask + 1);
+ bfd_set_error (bfd_error_bad_value);
+ ret = FALSE;
+ }
+ }
+ break;
}
#ifdef DEBUG
rel->r_offset) != (bfd_vma) -1)
{
info->callbacks->einfo
- (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
+ /* xgettext:c-format */
+ (_("%H: unresolvable %s relocation against symbol `%s'\n"),
input_bfd, input_section, rel->r_offset,
howto->name,
sym_name);
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)) == 10u << 26 /* cmpli */)
+ complain = complain_overflow_bitfield;
+ else if ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+ || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+ || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
+ complain = complain_overflow_unsigned;
+ }
+ if (howto->complain_on_overflow != complain)
+ {
+ alt_howto = *howto;
+ alt_howto.complain_on_overflow = complain;
+ howto = &alt_howto;
+ }
+ }
+
+ if (r_type == R_PPC_REL16DX_HA)
+ {
+ /* Split field reloc isn't handled by _bfd_final_link_relocate. */
+ if (rel->r_offset + 4 > input_section->size)
+ r = bfd_reloc_outofrange;
+ else
+ {
+ unsigned int insn;
+
+ relocation += addend;
+ relocation -= (rel->r_offset
+ + input_section->output_offset
+ + input_section->output_section->vma);
+ relocation >>= 16;
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn &= ~0x1fffc1;
+ insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ r = bfd_reloc_ok;
+ }
+ }
+ else
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel->r_offset, relocation, addend);
if (r != bfd_reloc_ok)
{
if (r == bfd_reloc_overflow)
{
- if (warned)
- continue;
- if (h != NULL
- && h->root.type == bfd_link_hash_undefweak
- && howto->pc_relative)
- {
- /* Assume this is a call protected by other code that
- detect the symbol is undefined. If this is the case,
- we can safely ignore the overflow. If not, the
- program is hosed anyway, and a little warning isn't
- going to help. */
-
- continue;
- }
-
- if (! (*info->callbacks->reloc_overflow) (info,
- (h ? &h->root : NULL),
- sym_name,
- howto->name,
- rel->r_addend,
- input_bfd,
- input_section,
- rel->r_offset))
- return FALSE;
+ overflow:
+ /* On code like "if (foo) foo();" don't report overflow
+ on a branch to zero when foo is undefined. */
+ if (!warned
+ && !(h != NULL
+ && (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined)
+ && is_branch_reloc (r_type)))
+ info->callbacks->reloc_overflow
+ (info, (h ? &h->root : NULL), sym_name, howto->name,
+ rel->r_addend, input_bfd, input_section, rel->r_offset);
}
else
{
info->callbacks->einfo
- (_("%P: %H: %s reloc against `%s': error %d\n"),
+ /* xgettext:c-format */
+ (_("%H: %s reloc against `%s': error %d\n"),
input_bfd, input_section, rel->r_offset,
howto->name, sym_name, (int) r);
ret = FALSE;
}
}
+ copy_reloc:
+ if (wrel != rel)
+ *wrel = *rel;
+ }
+
+ if (wrel != rel)
+ {
+ Elf_Internal_Shdr *rel_hdr;
+ size_t deleted = rel - wrel;
+
+ rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section);
+ rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+ if (rel_hdr->sh_size == 0)
+ {
+ /* It is too late to remove an empty reloc section. Leave
+ one NONE reloc.
+ ??? What is wrong with an empty section??? */
+ rel_hdr->sh_size = rel_hdr->sh_entsize;
+ deleted -= 1;
+ wrel++;
+ }
+ relend = wrel;
+ rel_hdr = _bfd_elf_single_rel_hdr (input_section);
+ rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted;
+ input_section->reloc_count -= deleted;
}
#ifdef DEBUG
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
+ && (!bfd_link_relocatable (info)
+ || (input_section->output_section->alignment_power
+ >= htab->params->pagesize_p2)))
+ {
+ bfd_vma start_addr, end_addr, addr;
+ bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
+
+ if (relax_info->workaround_size != 0)
+ {
+ bfd_byte *p;
+ unsigned int n;
+ bfd_byte fill[4];
+
+ bfd_put_32 (input_bfd, BA, fill);
+ p = contents + input_section->size - relax_info->workaround_size;
+ n = relax_info->workaround_size >> 2;
+ while (n--)
+ {
+ memcpy (p, fill, 4);
+ p += 4;
+ }
+ }
+
+ /* The idea is: Replace the last instruction on a page with a
+ branch to a patch area. Put the insn there followed by a
+ branch back to the next page. Complicated a little by
+ needing to handle moved conditional branches, and by not
+ wanting to touch data-in-text. */
+
+ start_addr = (input_section->output_section->vma
+ + input_section->output_offset);
+ end_addr = (start_addr + input_section->size
+ - relax_info->workaround_size);
+ for (addr = ((start_addr & -pagesize) + pagesize - 4);
+ addr < end_addr;
+ addr += pagesize)
+ {
+ bfd_vma offset = addr - start_addr;
+ Elf_Internal_Rela *lo, *hi;
+ bfd_boolean is_data;
+ bfd_vma patch_off, patch_addr;
+ unsigned int insn;
+
+ /* Do we have a data reloc at this offset? If so, leave
+ the word alone. */
+ is_data = FALSE;
+ lo = relocs;
+ 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 + 3)
+ hi = rel;
+ else
+ {
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_PPC_ADDR32:
+ case R_PPC_UADDR32:
+ case R_PPC_REL32:
+ case R_PPC_ADDR30:
+ is_data = TRUE;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ if (is_data)
+ continue;
+
+ /* Some instructions can be left alone too. Unconditional
+ branches, except for bcctr with BO=0x14 (bctr, bctrl),
+ avoid the icache failure.
+
+ The problem occurs due to prefetch across a page boundary
+ where stale instructions can be fetched from the next
+ page, and the mechanism for flushing these bad
+ instructions fails under certain circumstances. The
+ unconditional branches:
+ 1) Branch: b, bl, ba, bla,
+ 2) Branch Conditional: bc, bca, bcl, bcla,
+ 3) Branch Conditional to Link Register: bclr, bclrl,
+ where (2) and (3) have BO=0x14 making them unconditional,
+ prevent the bad prefetch because the prefetch itself is
+ affected by these instructions. This happens even if the
+ instruction is not executed.
+
+ A bctr example:
+ .
+ . lis 9,new_page@ha
+ . addi 9,9,new_page@l
+ . mtctr 9
+ . bctr
+ . nop
+ . nop
+ . new_page:
+ .
+ The bctr is not predicted taken due to ctr not being
+ ready, so prefetch continues on past the bctr into the
+ new page which might have stale instructions. If they
+ fail to be flushed, then they will be executed after the
+ bctr executes. Either of the following modifications
+ prevent the bad prefetch from happening in the first
+ place:
+ .
+ . lis 9,new_page@ha lis 9,new_page@ha
+ . addi 9,9,new_page@l addi 9,9,new_page@l
+ . mtctr 9 mtctr 9
+ . bctr bctr
+ . nop b somewhere_else
+ . b somewhere_else nop
+ . new_page: new_page:
+ . */
+ insn = bfd_get_32 (input_bfd, contents + offset);
+ if ((insn & (0x3f << 26)) == (18u << 26) /* b,bl,ba,bla */
+ || ((insn & (0x3f << 26)) == (16u << 26) /* bc,bcl,bca,bcla*/
+ && (insn & (0x14 << 21)) == (0x14 << 21)) /* with BO=0x14 */
+ || ((insn & (0x3f << 26)) == (19u << 26)
+ && (insn & (0x3ff << 1)) == (16u << 1) /* bclr,bclrl */
+ && (insn & (0x14 << 21)) == (0x14 << 21)))/* with BO=0x14 */
+ continue;
+
+ patch_addr = (start_addr + input_section->size
+ - relax_info->workaround_size);
+ 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)
+ {
+ asection *sreloc;
+
+ /* 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;
+
+ /* Adjust REL16 addends too. */
+ switch (ELF32_R_TYPE (relend[-1].r_info))
+ {
+ case R_PPC_REL16:
+ case R_PPC_REL16_LO:
+ case R_PPC_REL16_HI:
+ case R_PPC_REL16_HA:
+ relend[-1].r_addend += patch_off - offset;
+ break;
+ default:
+ break;
+ }
+
+ /* If we are building a PIE or shared library with
+ non-PIC objects, perhaps we had a dynamic reloc too?
+ If so, the dynamic reloc must move with the insn. */
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (sreloc != NULL)
+ {
+ Elf32_External_Rela *slo, *shi, *srelend;
+ bfd_vma soffset;
+
+ slo = (Elf32_External_Rela *) sreloc->contents;
+ shi = srelend = slo + sreloc->reloc_count;
+ soffset = (offset + input_section->output_section->vma
+ + input_section->output_offset);
+ while (slo < shi)
+ {
+ Elf32_External_Rela *srel = slo + (shi - slo) / 2;
+ bfd_elf32_swap_reloca_in (output_bfd, (bfd_byte *) srel,
+ &outrel);
+ if (outrel.r_offset < soffset)
+ slo = srel + 1;
+ else if (outrel.r_offset > soffset + 3)
+ shi = srel;
+ else
+ {
+ if (srel + 1 != srelend)
+ {
+ memmove (srel, srel + 1,
+ (srelend - (srel + 1)) * sizeof (*srel));
+ srel = srelend - 1;
+ }
+ outrel.r_offset += patch_off - offset;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (bfd_byte *) srel);
+ break;
+ }
+ }
+ }
+ }
+ 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 (bfd_link_relocatable (info) && rel != NULL)
+ delta = 0;
+ if (!bfd_link_relocatable (info) && 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,
+ (insn & ~0xfffc) | (delta & 0xfffc),
+ contents + patch_off);
+ patch_off += 4;
+ bfd_put_32 (input_bfd,
+ B | ((offset + 4 - patch_off) & 0x3fffffc),
+ contents + patch_off);
+ patch_off += 4;
+ }
+ 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);
+ patch_off += 4;
+ bfd_put_32 (input_bfd,
+ B | ((offset + 4 - patch_off) & 0x3fffffc),
+ contents + patch_off);
+ patch_off += 4;
+ bfd_put_32 (input_bfd,
+ B | ((delta - 8) & 0x3fffffc),
+ contents + patch_off);
+ patch_off += 4;
+ }
+ }
+ else
+ {
+ bfd_put_32 (input_bfd, insn, contents + patch_off);
+ patch_off += 4;
+ bfd_put_32 (input_bfd,
+ B | ((offset + 4 - patch_off) & 0x3fffffc),
+ contents + patch_off);
+ patch_off += 4;
+ }
+ BFD_ASSERT (patch_off <= input_section->size);
+ relax_info->workaround_size = input_section->size - patch_off;
+ }
+ }
+
return ret;
}
\f
got_offset = (reloc_index + 3) * 4;
/* Use the right PLT. */
- plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry
+ plt_entry = bfd_link_pic (info) ? ppc_elf_vxworks_pic_plt_entry
: ppc_elf_vxworks_plt_entry;
/* Fill in the .plt on VxWorks. */
- if (info->shared)
+ if (bfd_link_pic (info))
{
bfd_put_32 (output_bfd,
plt_entry[0] | PPC_HA (got_offset),
- htab->plt->contents + ent->plt.offset + 0);
+ htab->elf.splt->contents + ent->plt.offset + 0);
bfd_put_32 (output_bfd,
plt_entry[1] | PPC_LO (got_offset),
- htab->plt->contents + ent->plt.offset + 4);
+ htab->elf.splt->contents + ent->plt.offset + 4);
}
else
{
bfd_put_32 (output_bfd,
plt_entry[0] | PPC_HA (got_loc),
- htab->plt->contents + ent->plt.offset + 0);
+ htab->elf.splt->contents + ent->plt.offset + 0);
bfd_put_32 (output_bfd,
plt_entry[1] | PPC_LO (got_loc),
- htab->plt->contents + ent->plt.offset + 4);
+ htab->elf.splt->contents + ent->plt.offset + 4);
}
bfd_put_32 (output_bfd, plt_entry[2],
- htab->plt->contents + ent->plt.offset + 8);
+ htab->elf.splt->contents + ent->plt.offset + 8);
bfd_put_32 (output_bfd, plt_entry[3],
- htab->plt->contents + ent->plt.offset + 12);
+ htab->elf.splt->contents + ent->plt.offset + 12);
/* This instruction is an immediate load. The value loaded is
the byte offset of the R_PPC_JMP_SLOT relocation from the
prescaled offset. */
bfd_put_32 (output_bfd,
plt_entry[4] | reloc_index,
- htab->plt->contents + ent->plt.offset + 16);
+ htab->elf.splt->contents + ent->plt.offset + 16);
/* This instruction is a PC-relative branch whose target is
the start of the PLT section. The address of this branch
instruction is 20 bytes beyond the start of this PLT entry.
bfd_put_32 (output_bfd,
(plt_entry[5]
| (-(ent->plt.offset + 20) & 0x03fffffc)),
- htab->plt->contents + ent->plt.offset + 20);
+ htab->elf.splt->contents + ent->plt.offset + 20);
bfd_put_32 (output_bfd, plt_entry[6],
- htab->plt->contents + ent->plt.offset + 24);
+ htab->elf.splt->contents + ent->plt.offset + 24);
bfd_put_32 (output_bfd, plt_entry[7],
- htab->plt->contents + ent->plt.offset + 28);
+ htab->elf.splt->contents + ent->plt.offset + 28);
/* Fill in the GOT entry corresponding to this PLT slot with
- the address immediately after the the "bctr" instruction
+ the address immediately after the "bctr" instruction
in this PLT entry. */
- bfd_put_32 (output_bfd, (htab->plt->output_section->vma
- + htab->plt->output_offset
+ bfd_put_32 (output_bfd, (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ ent->plt.offset + 16),
- htab->sgotplt->contents + got_offset);
+ htab->elf.sgotplt->contents + got_offset);
- if (!info->shared)
+ if (!bfd_link_pic (info))
{
/* Fill in a couple of entries in .rela.plt.unloaded. */
loc = htab->srelplt2->contents
* sizeof (Elf32_External_Rela));
/* Provide the @ha relocation for the first instruction. */
- rela.r_offset = (htab->plt->output_section->vma
- + htab->plt->output_offset
+ rela.r_offset = (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ ent->plt.offset + 2);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_HA);
loc += sizeof (Elf32_External_Rela);
/* Provide the @l relocation for the second instruction. */
- rela.r_offset = (htab->plt->output_section->vma
- + htab->plt->output_offset
+ rela.r_offset = (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ ent->plt.offset + 6);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
R_PPC_ADDR16_LO);
/* Provide a relocation for the GOT entry corresponding to this
PLT slot. Point it at the middle of the .plt entry. */
- rela.r_offset = (htab->sgotplt->output_section->vma
- + htab->sgotplt->output_offset
+ rela.r_offset = (htab->elf.sgotplt->output_section->vma
+ + htab->elf.sgotplt->output_offset
+ got_offset);
rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx,
R_PPC_ADDR32);
address of the PLT entry for this function, as specified
by the ABI. Instead, the offset is set to the address of
the GOT slot for this function. See EABI 4.4.4.1. */
- rela.r_offset = (htab->sgotplt->output_section->vma
- + htab->sgotplt->output_offset
+ rela.r_offset = (htab->elf.sgotplt->output_section->vma
+ + htab->elf.sgotplt->output_offset
+ got_offset);
}
else
{
- asection *splt = htab->plt;
+ asection *splt = htab->elf.splt;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- splt = htab->iplt;
+ splt = htab->elf.iplt;
rela.r_offset = (splt->output_section->vma
+ splt->output_offset
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- loc = (htab->reliplt->contents
- + (htab->reliplt->reloc_count++
+ loc = (htab->elf.irelplt->contents
+ + (htab->elf.irelplt->reloc_count++
* sizeof (Elf32_External_Rela)));
else
- loc = (htab->relplt->contents
+ loc = (htab->elf.srelplt->contents
+ reloc_index * sizeof (Elf32_External_Rela));
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
}
}
else if (h->type == STT_GNU_IFUNC
- && !info->shared)
+ && !bfd_link_pic (info))
{
/* Set the value of ifunc symbols in a non-pie
executable to the glink entry. This is to avoid
|| h->dynindx == -1)
{
unsigned char *p;
- asection *splt = htab->plt;
+ asection *splt = htab->elf.splt;
if (!htab->elf.dynamic_sections_created
|| h->dynindx == -1)
- splt = htab->iplt;
+ splt = htab->elf.iplt;
p = (unsigned char *) htab->glink->contents + ent->glink_offset;
- if (h == htab->tls_get_addr && !htab->no_tls_get_addr_opt)
+ if (h == htab->tls_get_addr && !htab->params->no_tls_get_addr_opt)
{
bfd_put_32 (output_bfd, LWZ_11_3, p);
p += 4;
write_glink_stub (ent, splt, p, info);
- if (!info->shared)
+ if (!bfd_link_pic (info))
/* We only need one non-PIC glink stub. */
break;
}
if (ppc_elf_hash_entry (h)->has_sda_refs)
s = htab->relsbss;
+ else if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ s = htab->elf.sreldynrelro;
else
- s = htab->relbss;
+ s = htab->elf.srelbss;
BFD_ASSERT (s != NULL);
rela.r_offset = SYM_VAL (h);
}
\f
static enum elf_reloc_type_class
-ppc_elf_reloc_type_class (const Elf_Internal_Rela *rela)
+ppc_elf_reloc_type_class (const struct bfd_link_info *info,
+ const asection *rel_sec,
+ const Elf_Internal_Rela *rela)
{
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+
+ if (rel_sec == htab->elf.irelplt)
+ return reloc_class_ifunc;
+
switch (ELF32_R_TYPE (rela->r_info))
{
case R_PPC_RELATIVE:
return reloc_class_relative;
- case R_PPC_REL24:
- case R_PPC_ADDR24:
case R_PPC_JMP_SLOT:
return reloc_class_plt;
case R_PPC_COPY:
struct bfd_link_info *info)
{
asection *sdyn;
- asection *splt;
struct ppc_elf_link_hash_table *htab;
bfd_vma got;
bfd *dynobj;
#endif
htab = ppc_elf_hash_table (info);
- dynobj = elf_hash_table (info)->dynobj;
+ dynobj = htab->elf.dynobj;
sdyn = bfd_get_linker_section (dynobj, ".dynamic");
- if (htab->is_vxworks)
- splt = bfd_get_linker_section (dynobj, ".plt");
- else
- splt = NULL;
got = 0;
if (htab->elf.hgot != NULL)
{
Elf32_External_Dyn *dyncon, *dynconend;
- BFD_ASSERT (htab->plt != NULL && sdyn != NULL);
+ BFD_ASSERT (htab->elf.splt != NULL && sdyn != NULL);
dyncon = (Elf32_External_Dyn *) sdyn->contents;
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
{
case DT_PLTGOT:
if (htab->is_vxworks)
- s = htab->sgotplt;
+ s = htab->elf.sgotplt;
else
- s = htab->plt;
+ s = htab->elf.splt;
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
case DT_PLTRELSZ:
- dyn.d_un.d_val = htab->relplt->size;
+ dyn.d_un.d_val = htab->elf.srelplt->size;
break;
case DT_JMPREL:
- s = htab->relplt;
+ s = htab->elf.srelplt;
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
dyn.d_un.d_ptr = got;
break;
- case DT_RELASZ:
- if (htab->is_vxworks)
- {
- if (htab->relplt)
- dyn.d_un.d_ptr -= htab->relplt->size;
- break;
- }
- continue;
-
default:
if (htab->is_vxworks
&& elf_vxworks_finish_dynamic_entry (output_bfd, &dyn))
}
}
- if (htab->got != NULL)
+ if (htab->elf.sgot != NULL
+ && htab->elf.sgot->output_section != bfd_abs_section_ptr)
{
- if (htab->elf.hgot->root.u.def.section == htab->got
- || htab->elf.hgot->root.u.def.section == htab->sgotplt)
+ if (htab->elf.hgot->root.u.def.section == htab->elf.sgot
+ || htab->elf.hgot->root.u.def.section == htab->elf.sgotplt)
{
unsigned char *p = htab->elf.hgot->root.u.def.section->contents;
}
else
{
+ /* xgettext:c-format */
info->callbacks->einfo (_("%P: %s not defined in linker created %s\n"),
htab->elf.hgot->root.root.string,
- (htab->sgotplt != NULL
- ? htab->sgotplt->name : htab->got->name));
+ (htab->elf.sgotplt != NULL
+ ? htab->elf.sgotplt->name
+ : htab->elf.sgot->name));
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
}
- elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4;
+ elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4;
}
/* Fill in the first entry in the VxWorks procedure linkage table. */
- if (splt && splt->size > 0)
+ if (htab->is_vxworks
+ && htab->elf.splt != NULL
+ && htab->elf.splt->size != 0
+ && htab->elf.splt->output_section != bfd_abs_section_ptr)
{
+ asection *splt = htab->elf.splt;
/* Use the right PLT. */
- const bfd_vma *plt_entry = (info->shared
+ const bfd_vma *plt_entry = (bfd_link_pic (info)
? ppc_elf_vxworks_pic_plt0_entry
: ppc_elf_vxworks_plt0_entry);
- if (!info->shared)
+ if (!bfd_link_pic (info))
{
bfd_vma got_value = SYM_VAL (htab->elf.hgot);
bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24);
bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28);
- if (! info->shared)
+ if (! bfd_link_pic (info))
{
Elf_Internal_Rela rela;
bfd_byte *loc;
loc = htab->srelplt2->contents;
/* Output the @ha relocation for the first instruction. */
- rela.r_offset = (htab->plt->output_section->vma
- + htab->plt->output_offset
+ rela.r_offset = (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ 2);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA);
rela.r_addend = 0;
loc += sizeof (Elf32_External_Rela);
/* Output the @l relocation for the second instruction. */
- rela.r_offset = (htab->plt->output_section->vma
- + htab->plt->output_offset
+ rela.r_offset = (htab->elf.splt->output_section->vma
+ + htab->elf.splt->output_offset
+ 6);
rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO);
rela.r_addend = 0;
p += htab->glink_pltresolve;
endp = htab->glink->contents;
endp += htab->glink->size - GLINK_PLTRESOLVE;
- while (p < endp - 8 * 4)
+ while (p < endp - (htab->params->ppc476_workaround ? 0 : 8 * 4))
{
bfd_put_32 (output_bfd, B + endp - p, p);
p += 4;
+ htab->glink->output_section->vma
+ htab->glink->output_offset);
+ if (htab->params->ppc476_workaround)
+ {
+ /* Ensure that a call stub at the end of a page doesn't
+ result in prefetch over the end of the page into the
+ glink branch table. */
+ bfd_vma pagesize = (bfd_vma) 1 << htab->params->pagesize_p2;
+ bfd_vma page_addr;
+ bfd_vma glink_start = (htab->glink->output_section->vma
+ + htab->glink->output_offset);
+
+ for (page_addr = res0 & -pagesize;
+ page_addr > glink_start;
+ page_addr -= pagesize)
+ {
+ /* We have a plt call stub that may need fixing. */
+ bfd_byte *loc;
+ unsigned int insn;
+
+ loc = htab->glink->contents + page_addr - 4 - glink_start;
+ insn = bfd_get_32 (output_bfd, loc);
+ if (insn == BCTR)
+ {
+ /* By alignment, we know that there must be at least
+ one other call stub before this one. */
+ insn = bfd_get_32 (output_bfd, loc - 16);
+ if (insn == BCTR)
+ bfd_put_32 (output_bfd, B | (-16 & 0x3fffffc), loc);
+ else
+ bfd_put_32 (output_bfd, B | (-20 & 0x3fffffc), loc);
+ }
+ }
+ }
+
/* Last comes the PLTresolve stub. */
- if (info->shared)
+ if (bfd_link_pic (info))
{
bfd_vma bcl;
for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++)
{
- bfd_put_32 (output_bfd, pic_plt_resolve[i], p);
+ unsigned int insn = pic_plt_resolve[i];
+
+ if (htab->params->ppc476_workaround && insn == NOP)
+ insn = BA + 0;
+ bfd_put_32 (output_bfd, insn, p);
p += 4;
}
p -= 4 * ARRAY_SIZE (pic_plt_resolve);
{
for (i = 0; i < ARRAY_SIZE (plt_resolve); i++)
{
- bfd_put_32 (output_bfd, plt_resolve[i], p);
+ unsigned int insn = plt_resolve[i];
+
+ if (htab->params->ppc476_workaround && insn == NOP)
+ insn = BA + 0;
+ bfd_put_32 (output_bfd, insn, p);
p += 4;
}
p -= 4 * ARRAY_SIZE (plt_resolve);
return ret;
}
\f
-#define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec
+#define TARGET_LITTLE_SYM powerpc_elf32_le_vec
#define TARGET_LITTLE_NAME "elf32-powerpcle"
-#define TARGET_BIG_SYM bfd_elf32_powerpc_vec
+#define TARGET_BIG_SYM powerpc_elf32_vec
#define TARGET_BIG_NAME "elf32-powerpc"
#define ELF_ARCH bfd_arch_powerpc
#define ELF_TARGET_ID PPC32_ELF_DATA
#define ELF_MACHINE_CODE EM_PPC
#ifdef __QNXTARGET__
#define ELF_MAXPAGESIZE 0x1000
+#define ELF_COMMONPAGESIZE 0x1000
#else
#define ELF_MAXPAGESIZE 0x10000
+#define ELF_COMMONPAGESIZE 0x10000
#endif
#define ELF_MINPAGESIZE 0x1000
-#define ELF_COMMONPAGESIZE 0x1000
#define elf_info_to_howto ppc_elf_info_to_howto
#ifdef EM_CYGNUS_POWERPC
#endif
#define elf_backend_plt_not_loaded 1
+#define elf_backend_want_dynrelro 1
#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
#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
-#define elf_backend_post_process_headers _bfd_elf_set_osabi
#define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags
-#define elf_backend_section_processing ppc_elf_section_processing
#include "elf32-target.h"
#undef TARGET_LITTLE_NAME
#undef TARGET_BIG_SYM
-#define TARGET_BIG_SYM bfd_elf32_powerpc_freebsd_vec
+#define TARGET_BIG_SYM powerpc_elf32_fbsd_vec
#undef TARGET_BIG_NAME
#define TARGET_BIG_NAME "elf32-powerpc-freebsd"
#undef TARGET_LITTLE_NAME
#undef TARGET_BIG_SYM
-#define TARGET_BIG_SYM bfd_elf32_powerpc_vxworks_vec
+#define TARGET_BIG_SYM powerpc_elf32_vxworks_vec
#undef TARGET_BIG_NAME
#define TARGET_BIG_NAME "elf32-powerpc-vxworks"
#define elf_backend_plt_readonly 1
#undef elf_backend_got_header_size
#define elf_backend_got_header_size 12
+#undef elf_backend_dtrel_excludes_plt
+#define elf_backend_dtrel_excludes_plt 1
#undef bfd_elf32_get_synthetic_symtab