| /* 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 * |