blob: e42ef1cc885db0d86ec52937b628909e9817cf7c [file] [log] [blame]
/* PowerPC-specific support for 32-bit ELF
Copyright (C) 1994-2016 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* This file is based on a preliminary PowerPC ELF ABI. The
information may not match the final PowerPC ELF ABI. It includes
suggestions from the in-progress Embedded PowerPC ABI, and that
information may also not match. */
#include "sysdep.h"
#include <stdarg.h>
#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/ppc.h"
#include "elf32-ppc.h"
#include "elf-vxworks.h"
#include "dwarf2.h"
typedef enum split16_format_type
{
split16a_type = 0,
split16d_type
}
split16_format_type;
/* RELA relocations are used here. */
static bfd_reloc_status_type ppc_elf_addr16_ha_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type ppc_elf_unhandled_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
/* Branch prediction bit for branch taken relocs. */
#define BRANCH_PREDICT_BIT 0x200000
/* Mask to set RA in memory instructions. */
#define RA_REGISTER_MASK 0x001f0000
/* Value to shift register by to insert RA. */
#define RA_REGISTER_SHIFT 16
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
/* For old-style PLT. */
/* The number of single-slot PLT entries (the rest use two slots). */
#define PLT_NUM_SINGLE_ENTRIES 8192
/* For new-style .glink and .plt. */
#define GLINK_PLTRESOLVE 16*4
#define GLINK_ENTRY_SIZE 4*4
#define TLS_GET_ADDR_GLINK_SIZE 12*4
/* VxWorks uses its own plt layout, filled in by the static linker. */
/* The standard VxWorks PLT entry. */
#define VXWORKS_PLT_ENTRY_SIZE 32
static const bfd_vma ppc_elf_vxworks_plt_entry
[VXWORKS_PLT_ENTRY_SIZE / 4] =
{
0x3d800000, /* lis r12,0 */
0x818c0000, /* lwz r12,0(r12) */
0x7d8903a6, /* mtctr r12 */
0x4e800420, /* bctr */
0x39600000, /* li r11,0 */
0x48000000, /* b 14 <.PLT0resolve+0x4> */
0x60000000, /* nop */
0x60000000, /* nop */
};
static const bfd_vma ppc_elf_vxworks_pic_plt_entry
[VXWORKS_PLT_ENTRY_SIZE / 4] =
{
0x3d9e0000, /* addis r12,r30,0 */
0x818c0000, /* lwz r12,0(r12) */
0x7d8903a6, /* mtctr r12 */
0x4e800420, /* bctr */
0x39600000, /* li r11,0 */
0x48000000, /* b 14 <.PLT0resolve+0x4> 14: R_PPC_REL24 .PLTresolve */
0x60000000, /* nop */
0x60000000, /* nop */
};
/* The initial VxWorks PLT entry. */
#define VXWORKS_PLT_INITIAL_ENTRY_SIZE 32
static const bfd_vma ppc_elf_vxworks_plt0_entry
[VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] =
{
0x3d800000, /* lis r12,0 */
0x398c0000, /* addi r12,r12,0 */
0x800c0008, /* lwz r0,8(r12) */
0x7c0903a6, /* mtctr r0 */
0x818c0004, /* lwz r12,4(r12) */
0x4e800420, /* bctr */
0x60000000, /* nop */
0x60000000, /* nop */
};
static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
[VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] =
{
0x819e0008, /* lwz r12,8(r30) */
0x7d8903a6, /* mtctr r12 */
0x819e0004, /* lwz r12,4(r30) */
0x4e800420, /* bctr */
0x60000000, /* nop */
0x60000000, /* nop */
0x60000000, /* nop */
0x60000000, /* nop */
};
/* For executables, we have some additional relocations in
.rela.plt.unloaded, for the kernel loader. */
/* The number of non-JMP_SLOT relocations per PLT0 slot. */
#define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3
/* The number of relocations in the PLTResolve slot. */
#define VXWORKS_PLTRESOLVE_RELOCS 2
/* The number of relocations in the PLTResolve slot when when creating
a shared library. */
#define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0
/* Some instructions. */
#define ADDIS_11_11 0x3d6b0000
#define ADDIS_11_30 0x3d7e0000
#define ADDIS_12_12 0x3d8c0000
#define ADDI_11_11 0x396b0000
#define ADD_0_11_11 0x7c0b5a14
#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
#define CMPWI_11_0 0x2c0b0000
#define LIS_11 0x3d600000
#define LIS_12 0x3d800000
#define LWZU_0_12 0x840c0000
#define LWZ_0_12 0x800c0000
#define LWZ_11_3 0x81630000
#define LWZ_11_11 0x816b0000
#define LWZ_11_30 0x817e0000
#define LWZ_12_3 0x81830000
#define LWZ_12_12 0x818c0000
#define MR_0_3 0x7c601b78
#define MR_3_0 0x7c030378
#define MFLR_0 0x7c0802a6
#define MFLR_12 0x7d8802a6
#define MTCTR_0 0x7c0903a6
#define MTCTR_11 0x7d6903a6
#define MTLR_0 0x7c0803a6
#define NOP 0x60000000
#define SUB_11_11_12 0x7d6c5850
/* Offset of tp and dtp pointers from start of TLS block. */
#define TP_OFFSET 0x7000
#define DTP_OFFSET 0x8000
/* The value of a defined global symbol. */
#define SYM_VAL(SYM) \
((SYM)->root.u.def.section->output_section->vma \
+ (SYM)->root.u.def.section->output_offset \
+ (SYM)->root.u.def.value)
static reloc_howto_type *ppc_elf_howto_table[R_PPC_max];
static reloc_howto_type ppc_elf_howto_raw[] = {
/* This reloc does nothing. */
HOWTO (R_PPC_NONE, /* type */
0, /* rightshift */
3, /* size (0 = byte, 1 = short, 2 = long) */
0, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_NONE", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
/* A standard 32 bit relocation. */
HOWTO (R_PPC_ADDR32, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* An absolute 26 bit branch; the lower two bits must be zero.
FIXME: we don't check that, we just clear them. */
HOWTO (R_PPC_ADDR24, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
26, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR24", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x3fffffc, /* dst_mask */
FALSE), /* pcrel_offset */
/* A standard 16 bit relocation. */
HOWTO (R_PPC_ADDR16, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* A 16 bit relocation without overflow. */
HOWTO (R_PPC_ADDR16_LO, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont,/* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The high order 16 bits of an address. */
HOWTO (R_PPC_ADDR16_HI, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The high order 16 bits of an address, plus 1 if the contents of
the low 16 bits, treated as a signed number, is negative. */
HOWTO (R_PPC_ADDR16_HA, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_ADDR16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* An absolute 16 bit branch; the lower two bits must be zero.
FIXME: we don't check that, we just clear them. */
HOWTO (R_PPC_ADDR14, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR14", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xfffc, /* dst_mask */
FALSE), /* pcrel_offset */
/* An absolute 16 bit branch, for which bit 10 should be set to
indicate that the branch is expected to be taken. The lower two
bits must be zero. */
HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR14_BRTAKEN",/* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xfffc, /* dst_mask */
FALSE), /* pcrel_offset */
/* An absolute 16 bit branch, for which bit 10 should be set to
indicate that the branch is not expected to be taken. The lower
two bits must be zero. */
HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_ADDR14_BRNTAKEN",/* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xfffc, /* dst_mask */
FALSE), /* pcrel_offset */
/* A relative 26 bit branch; the lower two bits must be zero. */
HOWTO (R_PPC_REL24, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
26, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL24", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x3fffffc, /* dst_mask */
TRUE), /* pcrel_offset */
/* A relative 16 bit branch; the lower two bits must be zero. */
HOWTO (R_PPC_REL14, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL14", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xfffc, /* dst_mask */
TRUE), /* pcrel_offset */
/* A relative 16 bit branch. Bit 10 should be set to indicate that
the branch is expected to be taken. The lower two bits must be
zero. */
HOWTO (R_PPC_REL14_BRTAKEN, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL14_BRTAKEN", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xfffc, /* dst_mask */
TRUE), /* pcrel_offset */
/* A relative 16 bit branch. Bit 10 should be set to indicate that
the branch is not expected to be taken. The lower two bits must
be zero. */
HOWTO (R_PPC_REL14_BRNTAKEN, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL14_BRNTAKEN",/* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xfffc, /* dst_mask */
TRUE), /* pcrel_offset */
/* Like R_PPC_ADDR16, but referring to the GOT table entry for the
symbol. */
HOWTO (R_PPC_GOT16, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_GOT16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for
the symbol. */
HOWTO (R_PPC_GOT16_LO, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_GOT16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for
the symbol. */
HOWTO (R_PPC_GOT16_HI, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_GOT16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for
the symbol. */
HOWTO (R_PPC_GOT16_HA, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_GOT16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC_REL24, but referring to the procedure linkage table
entry for the symbol. */
HOWTO (R_PPC_PLTREL24, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
26, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PLTREL24", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x3fffffc, /* dst_mask */
TRUE), /* pcrel_offset */
/* This is used only by the dynamic linker. The symbol should exist
both in the object being run and in some shared library. The
dynamic linker copies the data addressed by the symbol from the
shared library into the object, because the object being
run has to have the data at some particular address. */
HOWTO (R_PPC_COPY, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_COPY", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC_ADDR32, but used when setting global offset table
entries. */
HOWTO (R_PPC_GLOB_DAT, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_GLOB_DAT", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Marks a procedure linkage table entry for a symbol. */
HOWTO (R_PPC_JMP_SLOT, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_JMP_SLOT", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
/* Used only by the dynamic linker. When the object is run, this
longword is set to the load address of the object, plus the
addend. */
HOWTO (R_PPC_RELATIVE, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_RELATIVE", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC_REL24, but uses the value of the symbol within the
object rather than the final value. Normally used for
_GLOBAL_OFFSET_TABLE_. */
HOWTO (R_PPC_LOCAL24PC, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
26, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_LOCAL24PC", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x3fffffc, /* dst_mask */
TRUE), /* pcrel_offset */
/* Like R_PPC_ADDR32, but may be unaligned. */
HOWTO (R_PPC_UADDR32, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_UADDR32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC_ADDR16, but may be unaligned. */
HOWTO (R_PPC_UADDR16, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_UADDR16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 32-bit PC relative */
HOWTO (R_PPC_REL32, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
TRUE), /* pcrel_offset */
/* 32-bit relocation to the symbol's procedure linkage table.
FIXME: not supported. */
HOWTO (R_PPC_PLT32, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PLT32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
/* 32-bit PC relative relocation to the symbol's procedure linkage table.
FIXME: not supported. */
HOWTO (R_PPC_PLTREL32, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PLTREL32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
TRUE), /* pcrel_offset */
/* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for
the symbol. */
HOWTO (R_PPC_PLT16_LO, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PLT16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for
the symbol. */
HOWTO (R_PPC_PLT16_HI, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PLT16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for
the symbol. */
HOWTO (R_PPC_PLT16_HA, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_PLT16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* A sign-extended 16 bit value relative to _SDA_BASE_, for use with
small data items. */
HOWTO (R_PPC_SDAREL16, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_SDAREL16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 16-bit section relative relocation. */
HOWTO (R_PPC_SECTOFF, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_SECTOFF", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 16-bit lower half section relative relocation. */
HOWTO (R_PPC_SECTOFF_LO, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_SECTOFF_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 16-bit upper half section relative relocation. */
HOWTO (R_PPC_SECTOFF_HI, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_SECTOFF_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 16-bit upper half adjusted section relative relocation. */
HOWTO (R_PPC_SECTOFF_HA, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_SECTOFF_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Marker relocs for TLS. */
HOWTO (R_PPC_TLS,
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_TLS", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
HOWTO (R_PPC_TLSGD,
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_TLSGD", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
HOWTO (R_PPC_TLSLD,
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_TLSLD", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
/* Computes the load module index of the load module that contains the
definition of its TLS sym. */
HOWTO (R_PPC_DTPMOD32,
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_DTPMOD32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Computes a dtv-relative displacement, the difference between the value
of sym+add and the base address of the thread-local storage block that
contains the definition of sym, minus 0x8000. */
HOWTO (R_PPC_DTPREL32,
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_DTPREL32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* A 16 bit dtprel reloc. */
HOWTO (R_PPC_DTPREL16,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_DTPREL16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like DTPREL16, but no overflow. */
HOWTO (R_PPC_DTPREL16_LO,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_DTPREL16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like DTPREL16_LO, but next higher group of 16 bits. */
HOWTO (R_PPC_DTPREL16_HI,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_DTPREL16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like DTPREL16_HI, but adjust for low 16 bits. */
HOWTO (R_PPC_DTPREL16_HA,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_DTPREL16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Computes a tp-relative displacement, the difference between the value of
sym+add and the value of the thread pointer (r13). */
HOWTO (R_PPC_TPREL32,
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_TPREL32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* A 16 bit tprel reloc. */
HOWTO (R_PPC_TPREL16,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_TPREL16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like TPREL16, but no overflow. */
HOWTO (R_PPC_TPREL16_LO,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_TPREL16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like TPREL16_LO, but next higher group of 16 bits. */
HOWTO (R_PPC_TPREL16_HI,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_TPREL16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like TPREL16_HI, but adjust for low 16 bits. */
HOWTO (R_PPC_TPREL16_HA,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_TPREL16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Allocates two contiguous entries in the GOT to hold a tls_index structure,
with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset
to the first entry. */
HOWTO (R_PPC_GOT_TLSGD16,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TLSGD16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_TLSGD16, but no overflow. */
HOWTO (R_PPC_GOT_TLSGD16_LO,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TLSGD16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_TLSGD16_LO, but next higher group of 16 bits. */
HOWTO (R_PPC_GOT_TLSGD16_HI,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TLSGD16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_TLSGD16_HI, but adjust for low 16 bits. */
HOWTO (R_PPC_GOT_TLSGD16_HA,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TLSGD16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Allocates two contiguous entries in the GOT to hold a tls_index structure,
with values (sym+add)@dtpmod and zero, and computes the offset to the
first entry. */
HOWTO (R_PPC_GOT_TLSLD16,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TLSLD16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_TLSLD16, but no overflow. */
HOWTO (R_PPC_GOT_TLSLD16_LO,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TLSLD16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_TLSLD16_LO, but next higher group of 16 bits. */
HOWTO (R_PPC_GOT_TLSLD16_HI,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TLSLD16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_TLSLD16_HI, but adjust for low 16 bits. */
HOWTO (R_PPC_GOT_TLSLD16_HA,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TLSLD16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes
the offset to the entry. */
HOWTO (R_PPC_GOT_DTPREL16,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_DTPREL16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_DTPREL16, but no overflow. */
HOWTO (R_PPC_GOT_DTPREL16_LO,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_DTPREL16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_DTPREL16_LO, but next higher group of 16 bits. */
HOWTO (R_PPC_GOT_DTPREL16_HI,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_DTPREL16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_DTPREL16_HI, but adjust for low 16 bits. */
HOWTO (R_PPC_GOT_DTPREL16_HA,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_DTPREL16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the
offset to the entry. */
HOWTO (R_PPC_GOT_TPREL16,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TPREL16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_TPREL16, but no overflow. */
HOWTO (R_PPC_GOT_TPREL16_LO,
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TPREL16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_TPREL16_LO, but next higher group of 16 bits. */
HOWTO (R_PPC_GOT_TPREL16_HI,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TPREL16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Like GOT_TPREL16_HI, but adjust for low 16 bits. */
HOWTO (R_PPC_GOT_TPREL16_HA,
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_unhandled_reloc, /* special_function */
"R_PPC_GOT_TPREL16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The remaining relocs are from the Embedded ELF ABI, and are not
in the SVR4 ELF ABI. */
/* 32 bit value resulting from the addend minus the symbol. */
HOWTO (R_PPC_EMB_NADDR32, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_NADDR32", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 16 bit value resulting from the addend minus the symbol. */
HOWTO (R_PPC_EMB_NADDR16, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_NADDR16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 16 bit value resulting from the addend minus the symbol. */
HOWTO (R_PPC_EMB_NADDR16_LO, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont,/* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_ADDR16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The high order 16 bits of the addend minus the symbol. */
HOWTO (R_PPC_EMB_NADDR16_HI, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_NADDR16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The high order 16 bits of the result of the addend minus the address,
plus 1 if the contents of the low 16 bits, treated as a signed number,
is negative. */
HOWTO (R_PPC_EMB_NADDR16_HA, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_EMB_NADDR16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 16 bit value resulting from allocating a 4 byte word to hold an
address in the .sdata section, and returning the offset from
_SDA_BASE_ for that relocation. */
HOWTO (R_PPC_EMB_SDAI16, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_SDAI16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 16 bit value resulting from allocating a 4 byte word to hold an
address in the .sdata2 section, and returning the offset from
_SDA2_BASE_ for that relocation. */
HOWTO (R_PPC_EMB_SDA2I16, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_SDA2I16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with
small data items. */
HOWTO (R_PPC_EMB_SDA2REL, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_SDA2REL", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit
signed offset from the appropriate base, and filling in the register
field with the appropriate register (0, 2, or 13). */
HOWTO (R_PPC_EMB_SDA21, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_SDA21", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Relocation not handled: R_PPC_EMB_MRKREF */
/* Relocation not handled: R_PPC_EMB_RELSEC16 */
/* Relocation not handled: R_PPC_EMB_RELST_LO */
/* Relocation not handled: R_PPC_EMB_RELST_HI */
/* Relocation not handled: R_PPC_EMB_RELST_HA */
/* Relocation not handled: R_PPC_EMB_BIT_FLD */
/* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling
in the 16 bit signed offset from the appropriate base, and filling in the
register field with the appropriate register (0, 2, or 13). */
HOWTO (R_PPC_EMB_RELSDA, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_EMB_RELSDA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* A relative 8 bit branch. */
HOWTO (R_PPC_VLE_REL8, /* type */
1, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
8, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_REL8", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xff, /* dst_mask */
TRUE), /* pcrel_offset */
/* A relative 15 bit branch. */
HOWTO (R_PPC_VLE_REL15, /* type */
1, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
15, /* bitsize */
TRUE, /* pc_relative */
1, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_REL15", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xfe, /* dst_mask */
TRUE), /* pcrel_offset */
/* A relative 24 bit branch. */
HOWTO (R_PPC_VLE_REL24, /* type */
1, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
24, /* bitsize */
TRUE, /* pc_relative */
1, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_REL24", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1fffffe, /* dst_mask */
TRUE), /* pcrel_offset */
/* The 16 LSBS in split16a format. */
HOWTO (R_PPC_VLE_LO16A, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_LO16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f007ff, /* 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) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_LO16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 split16a format. */
HOWTO (R_PPC_VLE_HI16A, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_HI16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 split16d format. */
HOWTO (R_PPC_VLE_HI16D, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_HI16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (High Adjusted) in split16a format. */
HOWTO (R_PPC_VLE_HA16A, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_HA16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (High Adjusted) in split16d format. */
HOWTO (R_PPC_VLE_HA16D, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_HA16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 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) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDA21", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* 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) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDA21_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_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) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_LO16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* The 16 LSBS relative to _SDA_BASE_ in split16d format. */
HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_LO16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 relative to _SDA_BASE_ in split16a format. */
HOWTO (R_PPC_VLE_SDAREL_HI16A, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_HI16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 relative to _SDA_BASE_ in split16d format. */
HOWTO (R_PPC_VLE_SDAREL_HI16D, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_HI16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (HA) relative to _SDA_BASE split16a format. */
HOWTO (R_PPC_VLE_SDAREL_HA16A, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_HA16A", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f007ff, /* dst_mask */
FALSE), /* pcrel_offset */
/* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */
HOWTO (R_PPC_VLE_SDAREL_HA16D, /* type */
16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_VLE_SDAREL_HA16D", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0x1f07ff, /* dst_mask */
FALSE), /* pcrel_offset */
HOWTO (R_PPC_IRELATIVE, /* type */
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
32, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_IRELATIVE", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
/* A 16 bit relative relocation. */
HOWTO (R_PPC_REL16, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL16", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
TRUE), /* pcrel_offset */
/* A 16 bit relative relocation without overflow. */
HOWTO (R_PPC_REL16_LO, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont,/* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL16_LO", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
TRUE), /* pcrel_offset */
/* The high order 16 bits of a relative address. */
HOWTO (R_PPC_REL16_HI, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_REL16_HI", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0xffff, /* dst_mask */
TRUE), /* pcrel_offset */
/* The high order 16 bits of a relative address, plus 1 if the contents of
the low 16 bits, treated as a signed number, is negative. */
HOWTO (R_PPC_REL16_HA, /* type */
16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_REL16_HA", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
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 */
0, /* size (0 = byte, 1 = short, 2 = long) */
0, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
NULL, /* special_function */
"R_PPC_GNU_VTINHERIT", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
/* GNU extension to record C++ vtable member usage. */
HOWTO (R_PPC_GNU_VTENTRY, /* type */
0, /* rightshift */
0, /* size (0 = byte, 1 = short, 2 = long) */
0, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
NULL, /* special_function */
"R_PPC_GNU_VTENTRY", /* name */
FALSE, /* partial_inplace */
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
/* Phony reloc to handle AIX style TOC entries. */
HOWTO (R_PPC_TOC16, /* type */
0, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_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));
}
/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */
static void
ppc_elf_howto_init (void)
{
unsigned int i, type;
for (i = 0;
i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]);
i++)
{
type = ppc_elf_howto_raw[i].type;
if (type >= (sizeof (ppc_elf_howto_table)
/ sizeof (ppc_elf_howto_table[0])))
abort ();
ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i];
}
}
static reloc_howto_type *
ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
bfd_reloc_code_real_type code)
{
enum elf_ppc_reloc_type r;
/* Initialize howto table if not already done. */
if (!ppc_elf_howto_table[R_PPC_ADDR32])
ppc_elf_howto_init ();
switch (code)
{
default:
return NULL;
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_BA16: r = R_PPC_ADDR14; break;
case BFD_RELOC_PPC_BA16_BRTAKEN: r = R_PPC_ADDR14_BRTAKEN; break;
case BFD_RELOC_PPC_BA16_BRNTAKEN: r = R_PPC_ADDR14_BRNTAKEN; break;
case BFD_RELOC_PPC_B26: r = R_PPC_REL24; 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_24_PLT_PCREL: r = R_PPC_PLTREL24; break;
case BFD_RELOC_PPC_COPY: r = R_PPC_COPY; break;
case BFD_RELOC_PPC_GLOB_DAT: r = R_PPC_GLOB_DAT; break;
case BFD_RELOC_PPC_LOCAL24PC: r = R_PPC_LOCAL24PC; 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_PPC_DTPREL: r = R_PPC_DTPREL32; break;
case BFD_RELOC_PPC_GOT_TLSGD16: r = R_PPC_GOT_TLSGD16; break;
case BFD_RELOC_PPC_GOT_TLSGD16_LO: r = R_PPC_GOT_TLSGD16_LO; break;
case BFD_RELOC_PPC_GOT_TLSGD16_HI: r = R_PPC_GOT_TLSGD16_HI; break;
case BFD_RELOC_PPC_GOT_TLSGD16_HA: r = R_PPC_GOT_TLSGD16_HA; break;
case BFD_RELOC_PPC_GOT_TLSLD16: r = R_PPC_GOT_TLSLD16; break;
case BFD_RELOC_PPC_GOT_TLSLD16_LO: r = R_PPC_GOT_TLSLD16_LO; break;
case BFD_RELOC_PPC_GOT_TLSLD16_HI: r = R_PPC_GOT_TLSLD16_HI; break;
case BFD_RELOC_PPC_GOT_TLSLD16_HA: r = R_PPC_GOT_TLSLD16_HA; break;
case BFD_RELOC_PPC_GOT_TPREL16: r = R_PPC_GOT_TPREL16; break;
case BFD_RELOC_PPC_GOT_TPREL16_LO: r = R_PPC_GOT_TPREL16_LO; break;
case BFD_RELOC_PPC_GOT_TPREL16_HI: r = R_PPC_GOT_TPREL16_HI; break;
case BFD_RELOC_PPC_GOT_TPREL16_HA: r = R_PPC_GOT_TPREL16_HA; break;
case BFD_RELOC_PPC_GOT_DTPREL16: r = R_PPC_GOT_DTPREL16; break;
case BFD_RELOC_PPC_GOT_DTPREL16_LO: r = R_PPC_GOT_DTPREL16_LO; break;
case BFD_RELOC_PPC_GOT_DTPREL16_HI: r = R_PPC_GOT_DTPREL16_HI; break;
case BFD_RELOC_PPC_GOT_DTPREL16_HA: r = R_PPC_GOT_DTPREL16_HA; break;
case BFD_RELOC_PPC_EMB_NADDR32: r = R_PPC_EMB_NADDR32; break;
case BFD_RELOC_PPC_EMB_NADDR16: r = R_PPC_EMB_NADDR16; break;
case BFD_RELOC_PPC_EMB_NADDR16_LO: r = R_PPC_EMB_NADDR16_LO; break;
case BFD_RELOC_PPC_EMB_NADDR16_HI: r = R_PPC_EMB_NADDR16_HI; break;
case BFD_RELOC_PPC_EMB_NADDR16_HA: r = R_PPC_EMB_NADDR16_HA; break;
case BFD_RELOC_PPC_EMB_SDAI16: r = R_PPC_EMB_SDAI16; break;
case BFD_RELOC_PPC_EMB_SDA2I16: r = R_PPC_EMB_SDA2I16; break;
case BFD_RELOC_PPC_EMB_SDA2REL: r = R_PPC_EMB_SDA2REL; break;
case BFD_RELOC_PPC_EMB_SDA21: r = R_PPC_EMB_SDA21; break;
case BFD_RELOC_PPC_EMB_MRKREF: r = R_PPC_EMB_MRKREF; break;
case BFD_RELOC_PPC_EMB_RELSEC16: r = R_PPC_EMB_RELSEC16; break;
case BFD_RELOC_PPC_EMB_RELST_LO: r = R_PPC_EMB_RELST_LO; break;
case BFD_RELOC_PPC_EMB_RELST_HI: r = R_PPC_EMB_RELST_HI; break;
case BFD_RELOC_PPC_EMB_RELST_HA: r = R_PPC_EMB_RELST_HA; break;
case BFD_RELOC_PPC_EMB_BIT_FLD: r = R_PPC_EMB_BIT_FLD; break;
case BFD_RELOC_PPC_EMB_RELSDA: r = R_PPC_EMB_RELSDA; break;
case BFD_RELOC_PPC_VLE_REL8: r = R_PPC_VLE_REL8; break;
case BFD_RELOC_PPC_VLE_REL15: r = R_PPC_VLE_REL15; break;
case BFD_RELOC_PPC_VLE_REL24: r = R_PPC_VLE_REL24; break;
case BFD_RELOC_PPC_VLE_LO16A: r = R_PPC_VLE_LO16A; break;
case BFD_RELOC_PPC_VLE_LO16D: r = R_PPC_VLE_LO16D; break;
case BFD_RELOC_PPC_VLE_HI16A: r = R_PPC_VLE_HI16A; break;
case BFD_RELOC_PPC_VLE_HI16D: r = R_PPC_VLE_HI16D; break;
case BFD_RELOC_PPC_VLE_HA16A: r = R_PPC_VLE_HA16A; break;
case BFD_RELOC_PPC_VLE_HA16D: r = R_PPC_VLE_HA16D; break;
case BFD_RELOC_PPC_VLE_SDA21: r = R_PPC_VLE_SDA21; break;
case BFD_RELOC_PPC_VLE_SDA21_LO: r = R_PPC_VLE_SDA21_LO; break;
case BFD_RELOC_PPC_VLE_SDAREL_LO16A:
r = R_PPC_VLE_SDAREL_LO16A;
break;
case BFD_RELOC_PPC_VLE_SDAREL_LO16D:
r = R_PPC_VLE_SDAREL_LO16D;
break;
case BFD_RELOC_PPC_VLE_SDAREL_HI16A:
r = R_PPC_VLE_SDAREL_HI16A;
break;
case BFD_RELOC_PPC_VLE_SDAREL_HI16D:
r = R_PPC_VLE_SDAREL_HI16D;
break;
case BFD_RELOC_PPC_VLE_SDAREL_HA16A:
r = R_PPC_VLE_SDAREL_HA16A;
break;
case BFD_RELOC_PPC_VLE_SDAREL_HA16D:
r = R_PPC_VLE_SDAREL_HA16D;
break;
case BFD_RELOC_16_PCREL: r = R_PPC_REL16; 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;
}
return ppc_elf_howto_table[r];
};
static reloc_howto_type *
ppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
const char *r_name)
{
unsigned int i;
for (i = 0;
i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]);
i++)
if (ppc_elf_howto_raw[i].name != NULL
&& strcasecmp (ppc_elf_howto_raw[i].name, r_name) == 0)
return &ppc_elf_howto_raw[i];
return NULL;
}
/* Set the howto pointer for a PowerPC ELF reloc. */
static void
ppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
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 ();
r_type = ELF32_R_TYPE (dst->r_info);
if (r_type >= R_PPC_max)
{
(*_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, r_type);
bfd_set_error (bfd_error_bad_value);
cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE];
}
}
/* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */
static bfd_reloc_status_type
ppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED,
arelent *reloc_entry,
asymbol *symbol,
void *data ATTRIBUTE_UNUSED,
asection *input_section,
bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
enum elf_ppc_reloc_type r_type;
long insn;
bfd_size_type octets;
bfd_vma value;
if (output_bfd != NULL)
{
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
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,
arelent *reloc_entry,
asymbol *symbol,
void *data,
asection *input_section,
bfd *output_bfd,
char **error_message)
{
/* If this is a relocatable link (output_bfd test tells us), just
call the generic function. Any adjustment will be done at final
link time. */
if (output_bfd != NULL)
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
if (error_message != NULL)
{
static char buf[60];
sprintf (buf, _("generic linker can't handle %s"),
reloc_entry->howto->name);
*error_message = buf;
}
return bfd_reloc_dangerous;
}
/* Sections created by the linker. */
typedef struct elf_linker_section
{
/* Pointer to the bfd section. */
asection *section;
/* Section name. */
const char *name;
/* Associated bss section name. */
const char *bss_name;
/* Associated symbol name. */
const char *sym_name;
/* Associated symbol. */
struct elf_link_hash_entry *sym;
} elf_linker_section_t;
/* Linked list of allocated pointer entries. This hangs off of the
symbol lists, and provides allows us to return different pointers,
based on different addend's. */
typedef struct elf_linker_section_pointers
{
/* next allocated pointer for this symbol */
struct elf_linker_section_pointers *next;
/* offset of pointer from beginning of section */
bfd_vma offset;
/* addend used */
bfd_vma addend;
/* which linker section this is */
elf_linker_section_t *lsect;
} elf_linker_section_pointers_t;
struct ppc_elf_obj_tdata
{
struct elf_obj_tdata elf;
/* A mapping from local symbols to offsets into the various linker
sections added. This is index by the symbol index. */
elf_linker_section_pointers_t **linker_section_pointers;
/* Flags used to auto-detect plt type. */
unsigned int makes_plt_call : 1;
unsigned int has_rel16 : 1;
};
#define ppc_elf_tdata(bfd) \
((struct ppc_elf_obj_tdata *) (bfd)->tdata.any)
#define elf_local_ptr_offsets(bfd) \
(ppc_elf_tdata (bfd)->linker_section_pointers)
#define is_ppc_elf(bfd) \
(bfd_get_flavour (bfd) == bfd_target_elf_flavour \
&& elf_object_id (bfd) == PPC32_ELF_DATA)
/* Override the generic function because we store some extras. */
static bfd_boolean
ppc_elf_mkobject (bfd *abfd)
{
return bfd_elf_allocate_object (abfd, sizeof (struct ppc_elf_obj_tdata),
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. Also select arch based on apuinfo. */
static bfd_boolean
ppc_elf_object_p (bfd *abfd)
{
if (!abfd->arch_info->the_default)
return TRUE;
if (abfd->arch_info->bits_per_word == 64)
{
Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd);
if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32)
{
/* Relies on arch after 64 bit default being 32 bit default. */
abfd->arch_info = abfd->arch_info->next;
BFD_ASSERT (abfd->arch_info->bits_per_word == 32);
}
}
return _bfd_elf_ppc_set_arch (abfd);
}
/* Function to set whether a module needs the -mrelocatable bit set. */
static bfd_boolean
ppc_elf_set_private_flags (bfd *abfd, flagword flags)
{
BFD_ASSERT (!elf_flags_init (abfd)
|| elf_elfheader (abfd)->e_flags == flags);
elf_elfheader (abfd)->e_flags = flags;
elf_flags_init (abfd) = TRUE;
return TRUE;
}
/* Support for core dump NOTE sections. */
static bfd_boolean
ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
{
int offset;
unsigned int size;
switch (note->descsz)
{
default:
return FALSE;
case 268: /* Linux/PPC. */
/* pr_cursig */
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);
/* pr_reg */
offset = 72;
size = 192;
break;
}
/* Make a ".reg/999" section. */
return _bfd_elfcore_make_pseudosection (abfd, ".reg",
size, note->descpos + offset);
}
static bfd_boolean
ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
{
switch (note->descsz)
{
default:
return FALSE;
case 128: /* Linux/PPC elf_prpsinfo. */
elf_tdata (abfd)->core->pid
= bfd_get_32 (abfd, note->descdata + 16);
elf_tdata (abfd)->core->program
= _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
elf_tdata (abfd)->core->command
= _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
}
/* Note that for some reason, a spurious space is tacked
onto the end of the args in some (at least one anyway)
implementations, so strip it off if it exists. */
{
char *command = elf_tdata (abfd)->core->command;
int n = strlen (command);
if (0 < n && command[n - 1] == ' ')
command[n - 1] = '\0';
}
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, ...)
{
switch (note_type)
{
default:
return NULL;
case NT_PRPSINFO:
{
char data[128];
va_list ap;
va_start (ap, note_type);
memset (data, 0, sizeof (data));
strncpy (data + 32, va_arg (ap, const char *), 16);
strncpy (data + 48, va_arg (ap, const char *), 80);
va_end (ap);
return elfcore_write_note (abfd, buf, bufsiz,
"CORE", note_type, data, sizeof (data));
}
case NT_PRSTATUS:
{
char data[268];
va_list ap;
long pid;
int cursig;
const void *greg;
va_start (ap, note_type);
memset (data, 0, 72);
pid = va_arg (ap, long);
bfd_put_32 (abfd, pid, data + 24);
cursig = va_arg (ap, int);
bfd_put_16 (abfd, cursig, data + 12);
greg = va_arg (ap, const void *);
memcpy (data + 72, greg, 192);
memset (data + 264, 0, 4);
va_end (ap);
return elfcore_write_note (abfd, buf, bufsiz,
"CORE", note_type, data, sizeof (data));
}
}
}
static flagword
ppc_elf_lookup_section_flags (char *flag_name)
{
if (!strcmp (flag_name, "SHF_PPC_VLE"))
return 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. */
static bfd_vma
ppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED,
const asection *plt ATTRIBUTE_UNUSED,
const arelent *rel)
{
return rel->address;
}
/* Handle a PowerPC specific section when reading an object file. This
is called when bfd_section_from_shdr finds a section with an unknown
type. */
static bfd_boolean
ppc_elf_section_from_shdr (bfd *abfd,
Elf_Internal_Shdr *hdr,
const char *name,
int shindex)
{
asection *newsect;
flagword flags;
if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
return FALSE;
newsect = hdr->bfd_section;
flags = bfd_get_section_flags (abfd, newsect);
if (hdr->sh_flags & SHF_EXCLUDE)
flags |= SEC_EXCLUDE;
if (hdr->sh_type == SHT_ORDERED)
flags |= SEC_SORT_ENTRIES;
bfd_set_section_flags (abfd, newsect, flags);
return TRUE;
}
/* Set up any other section flags and such that may be necessary. */
static bfd_boolean
ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
Elf_Internal_Shdr *shdr,
asection *asect)
{
if ((asect->flags & SEC_SORT_ENTRIES) != 0)
shdr->sh_type = SHT_ORDERED;
return TRUE;
}
/* If we have .sbss2 or .PPC.EMB.sbss0 output sections, we
need to bump up the number of section headers. */
static int
ppc_elf_additional_program_headers (bfd *abfd,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
asection *s;
int ret = 0;
s = bfd_get_section_by_name (abfd, ".sbss2");
if (s != NULL && (s->flags & SEC_ALLOC) != 0)
++ret;
s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0");
if (s != NULL && (s->flags & SEC_ALLOC) != 0)
++ret;
return ret;
}
/* 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;
/* 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
there is no mixing of VLE & non-VLE sections in a text segment.
If we find that case, we split the segment.
We maintain the original output section order. */
for (m = elf_seg_map (abfd); m != NULL; m = m->next)
{
if (m->count == 0)
continue;
sect0_vle = (elf_section_flags (m->sections[0]) & SHF_PPC_VLE) != 0;
for (j = 1; j < m->count; ++j)
{
sectj_vle = (elf_section_flags (m->sections[j]) & SHF_PPC_VLE) != 0;
if (sectj_vle != sect0_vle)
break;
}
if (j >= m->count)
continue;
/* 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);
if (n == NULL)
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->next = m->next;
m->next = n;
/* Fix the current segment */
m->count = j;
}
return TRUE;
}
/* Add extra PPC sections -- Note, for now, make .sbss2 and
.PPC.EMB.sbss0 a normal section, and not a bss section so
that the linker doesn't crater when trying to make more than
2 sections. */
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 (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. */
static struct bfd_elf_special_section ppc_alt_plt =
{ STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC };
static const struct bfd_elf_special_section *
ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
{
const struct bfd_elf_special_section *ssect;
/* See if this is one of the special sections. */
if (sec->name == NULL)
return NULL;
ssect = _bfd_elf_get_special_section (sec->name, ppc_elf_special_sections,
sec->use_rela_p);
if (ssect != NULL)
{
if (ssect == ppc_elf_special_sections && (sec->flags & SEC_LOAD) != 0)
ssect = &ppc_alt_plt;
return ssect;
}
return _bfd_elf_get_sec_type_attr (abfd, sec);
}
/* Very simple linked list structure for recording apuinfo values. */
typedef struct apuinfo_list
{
struct apuinfo_list *next;
unsigned long value;
}
apuinfo_list;
static apuinfo_list *head;
static bfd_boolean apuinfo_set;
static void
apuinfo_list_init (void)
{
head = NULL;
apuinfo_set = FALSE;
}
static void
apuinfo_list_add (unsigned long value)
{
apuinfo_list *entry = head;
while (entry != NULL)
{
if (entry->value == value)
return;
entry = entry->next;
}
entry = bfd_malloc (sizeof (* entry));
if (entry == NULL)
return;
entry->value = value;
entry->next = head;
head = entry;
}
static unsigned
apuinfo_list_length (void)
{
apuinfo_list *entry;
unsigned long count;
for (entry = head, count = 0;
entry;
entry = entry->next)
++ count;
return count;
}
static inline unsigned long
apuinfo_list_element (unsigned long number)
{
apuinfo_list * entry;
for (entry = head;
entry && number --;
entry = entry->next)
;
return entry ? entry->value : 0;
}
static void
apuinfo_list_finish (void)
{
apuinfo_list *entry;
for (entry = head; entry;)
{
apuinfo_list *next = entry->next;
free (entry);
entry = next;
}
head = NULL;
}
/* Scan the input BFDs and create a linked list of
the APUinfo values that will need to be emitted. */
static void
ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info)
{
bfd *ibfd;
asection *asec;
char *buffer = NULL;
bfd_size_type largest_input_size = 0;
unsigned i;
unsigned long length;
const char *error_message = NULL;
if (link_info == NULL)
return;
apuinfo_list_init ();
/* Read in the input sections contents. */
for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link.next)
{
unsigned long datum;
asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME);
if (asec == NULL)
continue;
error_message = _("corrupt %s section in %B");
length = asec->size;
if (length < 20)
goto fail;
apuinfo_set = TRUE;
if (largest_input_size < asec->size)
{
if (buffer)
free (buffer);
largest_input_size = asec->size;
buffer = bfd_malloc (largest_input_size);
if (!buffer)
return;
}
if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0
|| (bfd_bread (buffer, length, ibfd) != length))
{
error_message = _("unable to read in %s section from %B");
goto fail;
}
/* Verify the contents of the header. Note - we have to
extract the values this way in order to allow for a
host whose endian-ness is different from the target. */
datum = bfd_get_32 (ibfd, buffer);
if (datum != sizeof APUINFO_LABEL)
goto fail;
datum = bfd_get_32 (ibfd, buffer + 8);
if (datum != 0x2)
goto fail;
if (strcmp (buffer + 12, APUINFO_LABEL) != 0)
goto fail;
/* Get the number of bytes used for apuinfo entries. */
datum = bfd_get_32 (ibfd, buffer + 4);
if (datum + 20 != length)
goto fail;
/* Scan the apuinfo section, building a list of apuinfo numbers. */
for (i = 0; i < datum; i += 4)
apuinfo_list_add (bfd_get_32 (ibfd, buffer + 20 + i));
}
error_message = NULL;
if (apuinfo_set)
{
/* Compute the size of the output section. */
unsigned num_entries = apuinfo_list_length ();
/* Set the output section size, if it exists. */
asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME);
if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4))
{
ibfd = abfd;
error_message = _("warning: unable to set size of %s section in %B");
}
}
fail:
if (buffer)
free (buffer);
if (error_message)
(*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME);
}
/* Prevent the output section from accumulating the input sections'
contents. We have already stored this in our linked list structure. */
static bfd_boolean
ppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED,
struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
asection *asec,
bfd_byte *contents ATTRIBUTE_UNUSED)
{
return apuinfo_set && strcmp (asec->name, APUINFO_SECTION_NAME) == 0;
}
/* Finally we can generate the output section. */
static void
ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
{
bfd_byte *