X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=63928dc099a5079e0d0575afcaa1ff1ff3db6c1c;hb=e8910a83af41c3dbfd00191b2720d4094f8d9532;hp=5716b8247f8d42a7add0622009ac7117205da1aa;hpb=545fd46b6bb24535905e4bc69b91537fee065bf3;p=binutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 5716b8247f8..63928dc099a 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -37,6 +37,14 @@ #include "elf32-ppc.h" #include "elf-vxworks.h" #include "dwarf2.h" +#include "elf-linux-psinfo.h" + +typedef enum split16_format_type +{ + split16a_type = 0, + split16d_type +} +split16_format_type; /* RELA relocations are used here. */ @@ -44,6 +52,8 @@ 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 **); +static void ppc_elf_vle_split16 + (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type); /* Branch prediction bit for branch taken relocs. */ #define BRANCH_PREDICT_BIT 0x200000 @@ -1392,6 +1402,262 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 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) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 does nothing. */ + HOWTO (R_PPC_VLE_SDA21, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 */ + + /* This reloc does nothing. */ + HOWTO (R_PPC_VLE_SDA21_LO, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC_VLE_SDA21_LO", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* The 16 LSBS relative to _SDA_BASE_ in split16a format. */ + HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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. */ + /* This reloc does nothing. */ + HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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 */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* 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) */ @@ -1512,6 +1778,58 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 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 macro to swap (properly handling endianess) things from the + `elf_internal_prpsinfo' structure to the `elf_external_ppc_prpsinfo32' + structure. + + Note that FROM should be a pointer, and TO should be the explicit type. */ + +#define PPC_LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to) \ + do \ + { \ + H_PUT_8 (abfd, from->pr_state, &to.pr_state); \ + H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \ + H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \ + H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \ + H_PUT_32 (abfd, from->pr_flag, to.pr_flag); \ + H_PUT_32 (abfd, from->pr_uid, to.pr_uid); \ + H_PUT_32 (abfd, from->pr_gid, to.pr_gid); \ + H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \ + H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \ + H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \ + H_PUT_32 (abfd, 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)); \ + } while (0) + /* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ @@ -1550,7 +1868,9 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 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; @@ -1561,7 +1881,9 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 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; @@ -1572,26 +1894,34 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 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; @@ -1628,6 +1958,35 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 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; @@ -1857,10 +2216,10 @@ ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) case 268: /* Linux/PPC. */ /* pr_cursig */ - elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); + elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); + elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); /* pr_reg */ offset = 72; @@ -1883,11 +2242,11 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return FALSE; case 128: /* Linux/PPC elf_prpsinfo. */ - elf_tdata (abfd)->core_pid + elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 16); - elf_tdata (abfd)->core_program + elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); } @@ -1896,7 +2255,7 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) implementations, so strip it off if it exists. */ { - char *command = elf_tdata (abfd)->core_command; + char *command = elf_tdata (abfd)->core->command; int n = strlen (command); if (0 < n && command[n - 1] == ' ') @@ -1906,6 +2265,19 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) 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; + + memset (&data, 0, sizeof (data)); + PPC_LINUX_PRPSINFO32_SWAP_FIELDS (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, ...) { @@ -1952,6 +2324,28 @@ ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) } } +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. */ @@ -2025,6 +2419,70 @@ ppc_elf_additional_program_headers (bfd *abfd, 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 @@ -2625,6 +3083,21 @@ must_be_dyn_reloc (struct bfd_link_info *info, shared lib. */ #define ELIMINATE_COPY_RELOCS 1 +/* Used to track dynamic relocations for local symbols. */ +struct ppc_dyn_relocs +{ + struct ppc_dyn_relocs *next; + + /* The input section of the reloc. */ + asection *sec; + + /* Total number of relocs copied for the input section. */ + unsigned int count : 31; + + /* Whether this entry is for STT_GNU_IFUNC symbols. */ + unsigned int ifunc : 1; +}; + /* PPC ELF linker hash entry. */ struct ppc_elf_link_hash_entry @@ -2732,7 +3205,7 @@ struct ppc_elf_link_hash_table }; /* Rename some of the generic section flags to better document how they - are used here. */ + are used for ppc32. The flags are only valid for ppc32 elf objects. */ /* Nonzero if this section has TLS related relocations. */ #define has_tls_reloc sec_flg0 @@ -2829,13 +3302,13 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) return FALSE; htab = ppc_elf_hash_table (info); - htab->got = s = bfd_get_section_by_name (abfd, ".got"); + htab->got = s = bfd_get_linker_section (abfd, ".got"); if (s == NULL) abort (); if (htab->is_vxworks) { - htab->sgotplt = bfd_get_section_by_name (abfd, ".got.plt"); + htab->sgotplt = bfd_get_linker_section (abfd, ".got.plt"); if (!htab->sgotplt) abort (); } @@ -2849,7 +3322,7 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) return FALSE; } - htab->relgot = bfd_get_section_by_name (abfd, ".rela.got"); + htab->relgot = bfd_get_linker_section (abfd, ".rela.got"); if (!htab->relgot) abort (); @@ -2923,7 +3396,7 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) && !ppc_elf_create_glink (abfd, info)) return FALSE; - htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss"); + htab->dynbss = bfd_get_linker_section (abfd, ".dynbss"); s = bfd_make_section_anyway_with_flags (abfd, ".dynsbss", SEC_ALLOC | SEC_LINKER_CREATED); htab->dynsbss = s; @@ -2932,7 +3405,7 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) if (! info->shared) { - htab->relbss = bfd_get_section_by_name (abfd, ".rela.bss"); + htab->relbss = bfd_get_linker_section (abfd, ".rela.bss"); flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); s = bfd_make_section_anyway_with_flags (abfd, ".rela.sbss", flags); @@ -2946,8 +3419,8 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2)) return FALSE; - htab->relplt = bfd_get_section_by_name (abfd, ".rela.plt"); - htab->plt = s = bfd_get_section_by_name (abfd, ".plt"); + htab->relplt = bfd_get_linker_section (abfd, ".rela.plt"); + htab->plt = s = bfd_get_linker_section (abfd, ".plt"); if (s == NULL) abort (); @@ -3021,7 +3494,7 @@ ppc_elf_copy_indirect_symbol (struct bfd_link_info *info, /* If we were called to copy over info for a weak sym, that's all. You might think dyn_relocs need not be copied over; After all, both syms will be dynamic or both non-dynamic so we're just - moving reloc accounting around. However, ELIMINATE_COPY_RELOCS + moving reloc accounting around. However, ELIMINATE_COPY_RELOCS code in ppc_elf_adjust_dynamic_symbol needs to check for dyn_relocs in read-only sections, and it does so on what is the DIR sym here. */ @@ -3438,6 +3911,10 @@ ppc_elf_check_relocs (bfd *abfd, while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* PR15323, ref flags aren't set for references in the same + object. */ + h->root.non_ir_ref = 1; } /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. @@ -3463,13 +3940,11 @@ ppc_elf_check_relocs (bfd *abfd, if (isym == NULL) return FALSE; - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC - && (!info->shared - || is_branch_reloc (r_type))) + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { struct plt_entry **ifunc; - bfd_vma addend; + /* Set PLT_IFUNC flag for this sym, no GOT entry yet. */ ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, PLT_IFUNC); if (ifunc == NULL) @@ -3478,15 +3953,19 @@ ppc_elf_check_relocs (bfd *abfd, /* STT_GNU_IFUNC symbols must have a PLT entry; In a non-pie executable even when there are no plt calls. */ - addend = 0; - if (r_type == R_PPC_PLTREL24) + if (!info->shared + || is_branch_reloc (r_type)) { - ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (info->shared) - addend = rel->r_addend; + bfd_vma addend = 0; + if (r_type == R_PPC_PLTREL24) + { + ppc_elf_tdata (abfd)->makes_plt_call = 1; + if (info->shared) + addend = rel->r_addend; + } + if (!update_plt_info (abfd, ifunc, got2, addend)) + return FALSE; } - if (!update_plt_info (abfd, ifunc, got2, addend)) - return FALSE; } } @@ -3620,10 +4099,21 @@ ppc_elf_check_relocs (bfd *abfd, } break; + case R_PPC_VLE_SDAREL_LO16A: + case R_PPC_VLE_SDAREL_LO16D: + case R_PPC_VLE_SDAREL_HI16A: + case R_PPC_VLE_SDAREL_HI16D: + case R_PPC_VLE_SDAREL_HA16A: + case R_PPC_VLE_SDAREL_HA16D: case R_PPC_SDAREL16: if (htab->sdata[0].sym == NULL && !create_sdata_sym (info, &htab->sdata[0])) return FALSE; + + if (htab->sdata[1].sym == NULL + && !create_sdata_sym (info, &htab->sdata[1])) + return FALSE; + if (h != NULL) { ppc_elf_hash_entry (h)->has_sda_refs = TRUE; @@ -3631,6 +4121,17 @@ ppc_elf_check_relocs (bfd *abfd, } break; + case R_PPC_VLE_REL8: + case R_PPC_VLE_REL15: + case R_PPC_VLE_REL24: + case R_PPC_VLE_LO16A: + case R_PPC_VLE_LO16D: + case R_PPC_VLE_HI16A: + case R_PPC_VLE_HI16D: + case R_PPC_VLE_HA16A: + case R_PPC_VLE_HA16D: + break; + case R_PPC_EMB_SDA2REL: if (info->shared) { @@ -3647,6 +4148,8 @@ ppc_elf_check_relocs (bfd *abfd, } break; + case R_PPC_VLE_SDA21_LO: + case R_PPC_VLE_SDA21: case R_PPC_EMB_SDA21: case R_PPC_EMB_RELSDA: if (info->shared) @@ -3921,7 +4424,7 @@ ppc_elf_check_relocs (bfd *abfd, if ((info->shared && (must_be_dyn_reloc (info, r_type) || (h != NULL - && (! info->symbolic + && (!SYMBOLIC_BIND (info, h) || h->root.type == bfd_link_hash_defweak || !h->def_regular)))) || (ELIMINATE_COPY_RELOCS @@ -3930,9 +4433,6 @@ ppc_elf_check_relocs (bfd *abfd, && (h->root.type == bfd_link_hash_defweak || !h->def_regular))) { - struct elf_dyn_relocs *p; - struct elf_dyn_relocs **rel_head; - #ifdef DEBUG fprintf (stderr, "ppc_elf_check_relocs needs to " @@ -3956,13 +4456,34 @@ ppc_elf_check_relocs (bfd *abfd, relocations we need for this symbol. */ if (h != NULL) { + struct elf_dyn_relocs *p; + struct elf_dyn_relocs **rel_head; + rel_head = &ppc_elf_hash_entry (h)->dyn_relocs; + p = *rel_head; + if (p == NULL || p->sec != sec) + { + p = bfd_alloc (htab->elf.dynobj, sizeof *p); + if (p == NULL) + return FALSE; + p->next = *rel_head; + *rel_head = p; + p->sec = sec; + p->count = 0; + p->pc_count = 0; + } + p->count += 1; + if (!must_be_dyn_reloc (info, r_type)) + p->pc_count += 1; } else { /* Track dynamic relocs needed for local syms too. We really need local syms available to do this easily. Oh well. */ + struct ppc_dyn_relocs *p; + struct ppc_dyn_relocs **rel_head; + bfd_boolean is_ifunc; asection *s; void *vpp; Elf_Internal_Sym *isym; @@ -3977,25 +4498,24 @@ ppc_elf_check_relocs (bfd *abfd, s = sec; vpp = &elf_section_data (s)->local_dynrel; - rel_head = (struct elf_dyn_relocs **) vpp; - } - - p = *rel_head; - if (p == NULL || p->sec != sec) - { - p = bfd_alloc (htab->elf.dynobj, sizeof *p); - if (p == NULL) - return FALSE; - p->next = *rel_head; - *rel_head = p; - p->sec = sec; - p->count = 0; - p->pc_count = 0; + rel_head = (struct ppc_dyn_relocs **) vpp; + is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC; + p = *rel_head; + if (p != NULL && p->sec == sec && p->ifunc != is_ifunc) + p = p->next; + if (p == NULL || p->sec != sec || p->ifunc != is_ifunc) + { + p = bfd_alloc (htab->elf.dynobj, sizeof *p); + if (p == NULL) + return FALSE; + p->next = *rel_head; + *rel_head = p; + p->sec = sec; + p->ifunc = is_ifunc; + p->count = 0; + } + p->count += 1; } - - p->count += 1; - if (!must_be_dyn_reloc (info, r_type)) - p->pc_count += 1; } break; @@ -4244,6 +4764,24 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) return TRUE; } + +static void +ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents, + bfd_vma offset, bfd_vma relocation, + split16_format_type split16_format) + +{ + bfd_vma insn, top5, bottom11; + + insn = bfd_get_32 (output_bfd, contents + offset); + top5 = relocation >> 11; + top5 = top5 << (split16_format == split16a_type ? 20 : 16); + bottom11 = relocation & 0x7ff; + insn |= top5; + insn |= bottom11; + bfd_put_32 (output_bfd, insn, contents + offset); +} + /* Choose which PLT scheme to use, and set .plt flags appropriately. Returns -1 on error, 0 for old PLT, 1 for new PLT. */ @@ -5401,6 +5939,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) || eh->elf.root.type != bfd_link_hash_undefweak)) { asection *rsec = htab->relgot; + + if (eh->elf.type == STT_GNU_IFUNC) + rsec = htab->reliplt; /* All the entries we allocated need relocs. Except LD only needs one. */ if ((eh->tls_mask & TLS_LD) != 0 @@ -5518,7 +6059,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) for (p = eh->dyn_relocs; p != NULL; p = p->next) { asection *sreloc = elf_section_data (p->sec)->sreloc; - if (!htab->elf.dynamic_sections_created) + if (eh->elf.type == STT_GNU_IFUNC) sreloc = htab->reliplt; sreloc->size += p->count * sizeof (Elf32_External_Rela); } @@ -5582,7 +6123,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Set the contents of the .interp section to the interpreter. */ if (info->executable) { - s = bfd_get_section_by_name (htab->elf.dynobj, ".interp"); + s = bfd_get_linker_section (htab->elf.dynobj, ".interp"); BFD_ASSERT (s != NULL); s->size = sizeof ELF_DYNAMIC_INTERPRETER; s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; @@ -5611,9 +6152,9 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, for (s = ibfd->sections; s != NULL; s = s->next) { - struct elf_dyn_relocs *p; + struct ppc_dyn_relocs *p; - for (p = ((struct elf_dyn_relocs *) + for (p = ((struct ppc_dyn_relocs *) elf_section_data (s)->local_dynrel); p != NULL; p = p->next) @@ -5636,7 +6177,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, else if (p->count != 0) { asection *sreloc = elf_section_data (p->sec)->sreloc; - if (!htab->elf.dynamic_sections_created) + if (p->ifunc) sreloc = htab->reliplt; sreloc->size += p->count * sizeof (Elf32_External_Rela); if ((p->sec->output_section->flags @@ -5681,8 +6222,12 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { *local_got = allocate_got (htab, need); if (info->shared) - htab->relgot->size += (need - * (sizeof (Elf32_External_Rela) / 4)); + { + asection *srel = htab->relgot; + if ((*lgot_masks & PLT_IFUNC) != 0) + srel = htab->reliplt; + srel->size += need * (sizeof (Elf32_External_Rela) / 4); + } } } else @@ -5822,7 +6367,8 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->glink != NULL && htab->glink->size != 0 && htab->glink_eh_frame != NULL - && !bfd_is_abs_section (htab->glink_eh_frame->output_section)) + && !bfd_is_abs_section (htab->glink_eh_frame->output_section) + && _bfd_elf_eh_frame_present (info)) { s = htab->glink_eh_frame; s->size = sizeof (glink_eh_frame_cie) + 20; @@ -5867,7 +6413,8 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { /* Strip these too. */ } - else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) + else if (CONST_STRNEQ (bfd_get_section_name (htab->elf.dynobj, s), + ".rela")) { if (s->size != 0) { @@ -5941,7 +6488,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (!htab->no_tls_get_addr_opt && htab->tls_get_addr != NULL && htab->tls_get_addr->plt.plist != NULL - && !add_dynamic_entry (DT_PPC_TLSOPT, 0)) + && !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS)) return FALSE; } @@ -5970,6 +6517,66 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, } #undef add_dynamic_entry + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->contents != NULL) + { + unsigned char *p = htab->glink_eh_frame->contents; + bfd_vma val; + + memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); + /* CIE length (rewrite in case little-endian). */ + bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p); + p += sizeof (glink_eh_frame_cie); + /* FDE length. */ + val = htab->glink_eh_frame->size - 4 - sizeof (glink_eh_frame_cie); + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* CIE pointer. */ + val = p - htab->glink_eh_frame->contents; + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* Offset to .glink. Set later. */ + p += 4; + /* .glink size. */ + bfd_put_32 (htab->elf.dynobj, htab->glink->size, p); + p += 4; + /* Augmentation. */ + p += 1; + + if (info->shared + && htab->elf.dynamic_sections_created) + { + bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2; + if (adv < 64) + *p++ = DW_CFA_advance_loc + adv; + else if (adv < 256) + { + *p++ = DW_CFA_advance_loc1; + *p++ = adv; + } + else if (adv < 65536) + { + *p++ = DW_CFA_advance_loc2; + bfd_put_16 (htab->elf.dynobj, adv, p); + p += 2; + } + else + { + *p++ = DW_CFA_advance_loc4; + bfd_put_32 (htab->elf.dynobj, adv, p); + p += 4; + } + *p++ = DW_CFA_register; + *p++ = 65; + p++; + *p++ = DW_CFA_advance_loc + 4; + *p++ = DW_CFA_restore_extended; + *p++ = 65; + } + BFD_ASSERT ((bfd_vma) ((p + 3 - htab->glink_eh_frame->contents) & -4) + == htab->glink_eh_frame->size); + } + return TRUE; } @@ -6759,6 +7366,21 @@ _bfd_elf_ppc_at_tprel_transform (unsigned int insn, unsigned int reg) return insn; } +static bfd_boolean +is_insn_ds_form (unsigned int insn) +{ + return ((insn & (0x3f << 26)) == 58u << 26 /* ld,ldu,lwa */ + || (insn & (0x3f << 26)) == 62u << 26 /* std,stdu,stq */ + || (insn & (0x3f << 26)) == 57u << 26 /* lfdp */ + || (insn & (0x3f << 26)) == 61u << 26 /* stfdp */); +} + +static bfd_boolean +is_insn_dq_form (unsigned int insn) +{ + return (insn & (0x3f << 26)) == 56u << 26; /* lq */ +} + /* The RELOCATE_SECTION function is called by the ELF backend linker to handle the relocations for a section. @@ -6804,7 +7426,7 @@ ppc_elf_relocate_section (bfd *output_bfd, Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; Elf_Internal_Rela outrel; - asection *got2, *sreloc = NULL; + asection *got2; bfd_vma *local_got_offsets; bfd_boolean ret = TRUE; bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); @@ -6895,7 +7517,7 @@ ppc_elf_relocate_section (bfd *output_bfd, { if (got2 != NULL && r_type == R_PPC_PLTREL24 - && rel->r_addend >= 32768) + && rel->r_addend != 0) { /* R_PPC_PLTREL24 is rather special. If non-zero, the addend specifies the GOT pointer offset within .got2. */ @@ -7342,6 +7964,7 @@ ppc_elf_relocate_section (bfd *output_bfd, ; else { + BFD_ASSERT (h->dynindx != -1); indx = h->dynindx; unresolved_reloc = FALSE; } @@ -7409,6 +8032,8 @@ ppc_elf_relocate_section (bfd *output_bfd, asection *rsec = htab->relgot; bfd_byte * loc; + if (ifunc != NULL) + rsec = htab->reliplt; outrel.r_offset = (htab->got->output_section->vma + htab->got->output_offset + off); @@ -7611,6 +8236,9 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_UADDR16: goto dodyn; + case R_PPC_VLE_REL8: + case R_PPC_VLE_REL15: + case R_PPC_VLE_REL24: case R_PPC_REL24: case R_PPC_REL14: case R_PPC_REL14_BRTAKEN: @@ -7652,7 +8280,8 @@ ppc_elf_relocate_section (bfd *output_bfd, && !h->def_regular)) { int skip; - bfd_byte * loc; + bfd_byte *loc; + asection *sreloc; #ifdef DEBUG fprintf (stderr, "ppc_elf_relocate_section needs to " "create relocation for %s\n", @@ -7663,14 +8292,11 @@ ppc_elf_relocate_section (bfd *output_bfd, /* When generating a shared object, these relocations are copied into the output file to be resolved at run time. */ + sreloc = elf_section_data (input_section)->sreloc; + if (ifunc) + sreloc = htab->reliplt; if (sreloc == NULL) - { - sreloc = elf_section_data (input_section)->sreloc; - if (!htab->elf.dynamic_sections_created) - sreloc = htab->reliplt; - if (sreloc == NULL) - return FALSE; - } + return FALSE; skip = 0; outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, @@ -7689,6 +8315,7 @@ ppc_elf_relocate_section (bfd *output_bfd, || h->root.type == bfd_link_hash_undefweak)) || !SYMBOL_REFERENCES_LOCAL (info, h)) { + BFD_ASSERT (h->dynindx != -1); unresolved_reloc = FALSE; outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); outrel.r_addend = rel->r_addend; @@ -7886,40 +8513,46 @@ ppc_elf_relocate_section (bfd *output_bfd, unresolved_reloc = TRUE; break; } - BFD_ASSERT (strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 - || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0); + BFD_ASSERT (strcmp (bfd_get_section_name (sec->owner, sec), + ".got") == 0 + || strcmp (bfd_get_section_name (sec->owner, sec), + ".cgot") == 0); addend -= sec->output_section->vma + sec->output_offset + 0x8000; break; case R_PPC_PLTREL24: - if (h == NULL || ifunc != NULL) - break; - /* Relocation is to the entry for this symbol in the - procedure linkage table. */ - { - struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, - info->shared ? addend : 0); - addend = 0; - if (ent == NULL - || htab->plt == NULL) - { - /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ - break; - } + if (h != NULL && ifunc == NULL) + { + struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, + info->shared ? addend : 0); + if (ent == NULL + || htab->plt == NULL) + { + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + } + else + { + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + unresolved_reloc = FALSE; + if (htab->plt_type == PLT_NEW) + relocation = (htab->glink->output_section->vma + + htab->glink->output_offset + + ent->glink_offset); + else + relocation = (htab->plt->output_section->vma + + htab->plt->output_offset + + ent->plt.offset); + } + } - unresolved_reloc = FALSE; - if (htab->plt_type == PLT_NEW) - relocation = (htab->glink->output_section->vma - + htab->glink->output_offset - + ent->glink_offset); - else - relocation = (htab->plt->output_section->vma - + htab->plt->output_offset - + ent->plt.offset); - } + /* R_PPC_PLTREL24 is rather special. If non-zero, the + addend specifies the GOT pointer offset within .got2. + Don't apply it to the relocation field. */ + addend = 0; break; /* Relocate against _SDA_BASE_. */ @@ -7937,7 +8570,7 @@ ppc_elf_relocate_section (bfd *output_bfd, } addend -= SYM_VAL (sda); - name = bfd_get_section_name (abfd, sec->output_section); + name = bfd_get_section_name (output_bfd, sec->output_section); if (! ((CONST_STRNEQ (name, ".sdata") && (name[6] == 0 || name[6] == '.')) || (CONST_STRNEQ (name, ".sbss") @@ -7969,7 +8602,7 @@ ppc_elf_relocate_section (bfd *output_bfd, } addend -= SYM_VAL (sda); - name = bfd_get_section_name (abfd, sec->output_section); + name = bfd_get_section_name (output_bfd, sec->output_section); if (! (CONST_STRNEQ (name, ".sdata2") || CONST_STRNEQ (name, ".sbss2"))) { @@ -7984,9 +8617,53 @@ ppc_elf_relocate_section (bfd *output_bfd, } break; + case R_PPC_VLE_LO16A: + relocation = (relocation + addend) & 0xffff; + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + relocation, split16a_type); + continue; + + case R_PPC_VLE_LO16D: + relocation = (relocation + addend) & 0xffff; + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + relocation, split16d_type); + continue; + + case R_PPC_VLE_HI16A: + relocation = ((relocation + addend) >> 16) & 0xffff; + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + relocation, split16a_type); + continue; + + case R_PPC_VLE_HI16D: + relocation = ((relocation + addend) >> 16) & 0xffff; + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + relocation, split16d_type); + continue; + + case R_PPC_VLE_HA16A: + { + bfd_vma value = relocation + addend; + value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + value, split16a_type); + } + continue; + + case R_PPC_VLE_HA16D: + { + bfd_vma value = relocation + addend; + value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + value, split16d_type); + } + continue; + /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */ case R_PPC_EMB_SDA21: + case R_PPC_VLE_SDA21: case R_PPC_EMB_RELSDA: + case R_PPC_VLE_SDA21_LO: { const char *name; int reg; @@ -7998,7 +8675,7 @@ ppc_elf_relocate_section (bfd *output_bfd, break; } - name = bfd_get_section_name (abfd, sec->output_section); + name = bfd_get_section_name (output_bfd, sec->output_section); if (((CONST_STRNEQ (name, ".sdata") && (name[6] == 0 || name[6] == '.')) || (CONST_STRNEQ (name, ".sbss") @@ -8043,7 +8720,25 @@ ppc_elf_relocate_section (bfd *output_bfd, addend -= SYM_VAL (sda); } - if (r_type == R_PPC_EMB_SDA21) + if (reg == 0 + && (r_type == R_PPC_VLE_SDA21 + || r_type == R_PPC_VLE_SDA21_LO)) + { + /* Use the split20 format. */ + bfd_vma insn, bits12to15, bits21to31; + bfd_vma value = (relocation + rel->r_offset) & 0xffff; + /* Propagate sign bit, if necessary. */ + insn = (value & 0x8000) ? 0x70107800 : 0x70000000; + bits12to15 = value & 0x700; + bits21to31 = value & 0x7ff; + insn |= bits12to15; + insn |= bits21to31; + bfd_put_32 (output_bfd, insn, contents + rel->r_offset); + continue; + } + else if (r_type == R_PPC_EMB_SDA21 + || r_type == R_PPC_VLE_SDA21 + || r_type == R_PPC_VLE_SDA21_LO) { bfd_vma insn; /* Fill in register field. */ @@ -8054,6 +8749,107 @@ ppc_elf_relocate_section (bfd *output_bfd, } break; + case R_PPC_VLE_SDAREL_LO16A: + case R_PPC_VLE_SDAREL_LO16D: + case R_PPC_VLE_SDAREL_HI16A: + case R_PPC_VLE_SDAREL_HI16D: + case R_PPC_VLE_SDAREL_HA16A: + case R_PPC_VLE_SDAREL_HA16D: + { + bfd_vma value; + const char *name; + //int reg; + struct elf_link_hash_entry *sda = NULL; + + if (sec == NULL || sec->output_section == NULL) + { + unresolved_reloc = TRUE; + break; + } + + name = bfd_get_section_name (output_bfd, sec->output_section); + if (((CONST_STRNEQ (name, ".sdata") + && (name[6] == 0 || name[6] == '.')) + || (CONST_STRNEQ (name, ".sbss") + && (name[5] == 0 || name[5] == '.')))) + { + //reg = 13; + sda = htab->sdata[0].sym; + } + else if (CONST_STRNEQ (name, ".sdata2") + || CONST_STRNEQ (name, ".sbss2")) + { + //reg = 2; + sda = htab->sdata[1].sym; + } + else + { + (*_bfd_error_handler) + (_("%B: the target (%s) of a %s relocation is " + "in the wrong output section (%s)"), + input_bfd, + sym_name, + howto->name, + name); + + bfd_set_error (bfd_error_bad_value); + ret = FALSE; + continue; + } + + if (sda != NULL) + { + if (!is_static_defined (sda)) + { + unresolved_reloc = TRUE; + break; + } + } + + value = sda->root.u.def.section->output_section->vma + + sda->root.u.def.section->output_offset; + + if (r_type == R_PPC_VLE_SDAREL_LO16A) + { + value = (value + addend) & 0xffff; + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + value, split16a_type); + } + else if (r_type == R_PPC_VLE_SDAREL_LO16D) + { + value = (value + addend) & 0xffff; + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + value, split16d_type); + } + else if (r_type == R_PPC_VLE_SDAREL_HI16A) + { + value = ((value + addend) >> 16) & 0xffff; + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + value, split16a_type); + } + else if (r_type == R_PPC_VLE_SDAREL_HI16D) + { + value = ((value + addend) >> 16) & 0xffff; + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + value, split16d_type); + } + else if (r_type == R_PPC_VLE_SDAREL_HA16A) + { + value += addend; + value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + value, split16a_type); + } + else if (r_type == R_PPC_VLE_SDAREL_HA16D) + { + value += addend; + value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff); + ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset, + value, split16d_type); + } + } + continue; + /* Relocate against the beginning of the section. */ case R_PPC_SECTOFF: case R_PPC_SECTOFF_LO: @@ -8134,6 +8930,54 @@ ppc_elf_relocate_section (bfd *output_bfd, Bits 0:15 are not used. */ addend += 0x8000; break; + + case R_PPC_ADDR16: + case R_PPC_ADDR16_LO: + case R_PPC_GOT16: + case R_PPC_GOT16_LO: + case R_PPC_SDAREL16: + case R_PPC_SECTOFF: + case R_PPC_SECTOFF_LO: + case R_PPC_DTPREL16: + case R_PPC_DTPREL16_LO: + case R_PPC_TPREL16: + case R_PPC_TPREL16_LO: + case R_PPC_GOT_TLSGD16: + case R_PPC_GOT_TLSGD16_LO: + case R_PPC_GOT_TLSLD16: + case R_PPC_GOT_TLSLD16_LO: + case R_PPC_GOT_DTPREL16: + case R_PPC_GOT_DTPREL16_LO: + case R_PPC_GOT_TPREL16: + case R_PPC_GOT_TPREL16_LO: + { + /* The 32-bit ABI lacks proper relocations to deal with + certain 64-bit instructions. Prevent damage to bits + that make up part of the insn opcode. */ + unsigned int insn, mask, lobit; + + insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); + mask = 0; + if (is_insn_ds_form (insn)) + mask = 3; + else if (is_insn_dq_form (insn)) + mask = 15; + else + break; + lobit = mask & (relocation + addend); + if (lobit != 0) + { + addend -= lobit; + info->callbacks->einfo + (_("%P: %H: error: %s against `%s' not a multiple of %u\n"), + input_bfd, input_section, rel->r_offset, + howto->name, sym_name, mask + 1); + bfd_set_error (bfd_error_bad_value); + ret = FALSE; + } + addend += insn & mask; + } + break; } #ifdef DEBUG @@ -8328,7 +9172,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, htab->plt->contents + ent->plt.offset + 28); /* Fill in the GOT entry corresponding to this PLT slot with - the address immediately after the the "bctr" instruction + the address immediately after the "bctr" instruction in this PLT entry. */ bfd_put_32 (output_bfd, (htab->plt->output_section->vma + htab->plt->output_offset @@ -8548,26 +9392,23 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, fprintf (stderr, "\n"); #endif - /* Mark some specially defined symbols as absolute. */ - if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || (!htab->is_vxworks - && (h == htab->elf.hgot - || strcmp (h->root.root.string, - "_PROCEDURE_LINKAGE_TABLE_") == 0))) - sym->st_shndx = SHN_ABS; - return TRUE; } static enum elf_reloc_type_class -ppc_elf_reloc_type_class (const Elf_Internal_Rela *rela) +ppc_elf_reloc_type_class (const struct bfd_link_info *info, + const asection *rel_sec, + const Elf_Internal_Rela *rela) { + struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); + + if (rel_sec == htab->reliplt) + return reloc_class_ifunc; + switch (ELF32_R_TYPE (rela->r_info)) { case R_PPC_RELATIVE: return reloc_class_relative; - case R_PPC_REL24: - case R_PPC_ADDR24: case R_PPC_JMP_SLOT: return reloc_class_plt; case R_PPC_COPY: @@ -8596,9 +9437,9 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, htab = ppc_elf_hash_table (info); dynobj = elf_hash_table (info)->dynobj; - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + sdyn = bfd_get_linker_section (dynobj, ".dynamic"); if (htab->is_vxworks) - splt = bfd_get_section_by_name (dynobj, ".plt"); + splt = bfd_get_linker_section (dynobj, ".plt"); else splt = NULL; @@ -8990,17 +9831,10 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, unsigned char *p = htab->glink_eh_frame->contents; bfd_vma val; - memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); - /* CIE length (rewrite in case little-endian). */ - bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p); p += sizeof (glink_eh_frame_cie); /* FDE length. */ - val = htab->glink_eh_frame->size - 4 - sizeof (glink_eh_frame_cie); - bfd_put_32 (htab->elf.dynobj, val, p); p += 4; /* CIE pointer. */ - val = p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); p += 4; /* Offset to .glink. */ val = (htab->glink->output_section->vma @@ -9009,45 +9843,6 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, + htab->glink_eh_frame->output_offset); val -= p - htab->glink_eh_frame->contents; bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* .glink size. */ - bfd_put_32 (htab->elf.dynobj, htab->glink->size, p); - p += 4; - /* Augmentation. */ - p += 1; - - if (info->shared - && htab->elf.dynamic_sections_created) - { - bfd_vma adv = (htab->glink->size - GLINK_PLTRESOLVE + 8) >> 2; - if (adv < 64) - *p++ = DW_CFA_advance_loc + adv; - else if (adv < 256) - { - *p++ = DW_CFA_advance_loc1; - *p++ = adv; - } - else if (adv < 65536) - { - *p++ = DW_CFA_advance_loc2; - bfd_put_16 (htab->elf.dynobj, adv, p); - p += 2; - } - else - { - *p++ = DW_CFA_advance_loc4; - bfd_put_32 (htab->elf.dynobj, adv, p); - p += 4; - } - *p++ = DW_CFA_register; - *p++ = 65; - p++; - *p++ = DW_CFA_advance_loc + 4; - *p++ = DW_CFA_restore_extended; - *p++ = 65; - } - BFD_ASSERT ((bfd_vma) ((p + 3 - htab->glink_eh_frame->contents) & -4) - == htab->glink_eh_frame->size); if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME && !_bfd_elf_write_section_eh_frame (output_bfd, info, @@ -9092,7 +9887,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data #define bfd_elf32_bfd_relax_section ppc_elf_relax_section #define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup -#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup +#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup #define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags #define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create #define bfd_elf32_get_synthetic_symtab ppc_elf_get_synthetic_symtab @@ -9113,6 +9908,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections #define elf_backend_fake_sections ppc_elf_fake_sections #define elf_backend_additional_program_headers ppc_elf_additional_program_headers +#define elf_backend_modify_segment_map ppc_elf_modify_segment_map #define elf_backend_grok_prstatus ppc_elf_grok_prstatus #define elf_backend_grok_psinfo ppc_elf_grok_psinfo #define elf_backend_write_core_note ppc_elf_write_core_note @@ -9125,6 +9921,8 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define elf_backend_action_discarded ppc_elf_action_discarded #define elf_backend_init_index_section _bfd_elf_init_1_index_section #define elf_backend_post_process_headers _bfd_elf_set_osabi +#define elf_backend_lookup_section_flags_hook ppc_elf_lookup_section_flags +#define elf_backend_section_processing ppc_elf_section_processing #include "elf32-target.h"