Index: bfd/elf32-ppc.c |
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c |
index 3d0a2d939d6a7305c6796f5d9dfaf9871e2e8b49..47c92ba0b7e30254916eb911b2d309fa1154e601 100644 |
--- a/bfd/elf32-ppc.c |
+++ b/bfd/elf32-ppc.c |
@@ -37,6 +37,7 @@ |
#include "elf32-ppc.h" |
#include "elf-vxworks.h" |
#include "dwarf2.h" |
+#include "elf-linux-psinfo.h" |
typedef enum split16_format_type |
{ |
@@ -1415,7 +1416,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { |
0, /* src_mask */ |
0xff, /* dst_mask */ |
TRUE), /* pcrel_offset */ |
- |
+ |
/* A relative 15 bit branch. */ |
HOWTO (R_PPC_VLE_REL15, /* type */ |
1, /* rightshift */ |
@@ -1431,7 +1432,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { |
0xfe, /* dst_mask */ |
TRUE), /* pcrel_offset */ |
- /* A relative 24 bit branch. */ |
+ /* A relative 24 bit branch. */ |
HOWTO (R_PPC_VLE_REL24, /* type */ |
1, /* rightshift */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
@@ -1451,14 +1452,14 @@ static reloc_howto_type ppc_elf_howto_raw[] = { |
0, /* rightshift */ |
2, /* size (0 = byte, 1 = short, 2 = long) */ |
32, /* bitsize */ |
- FALSE, /* pc_relative */ /* FIXME: Does this apply to split relocs? */ |
+ 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 */ |
- 0x1f00fff, /* dst_mask */ |
+ 0x1f007ff, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
/* The 16 LSBS in split16d format. */ |
@@ -1488,7 +1489,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { |
"R_PPC_VLE_HI16A", /* name */ |
FALSE, /* partial_inplace */ |
0, /* src_mask */ |
- 0x1f00fff, /* dst_mask */ |
+ 0x1f007ff, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
/* Bits 16-31 split16d format. */ |
@@ -1518,7 +1519,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { |
"R_PPC_VLE_HA16A", /* name */ |
FALSE, /* partial_inplace */ |
0, /* src_mask */ |
- 0x1f00fff, /* dst_mask */ |
+ 0x1f007ff, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
/* Bits 16-31 (High Adjusted) in split16d format. */ |
@@ -1578,7 +1579,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { |
"R_PPC_VLE_SDAREL_LO16A", /* name */ |
FALSE, /* partial_inplace */ |
0, /* src_mask */ |
- 0x1f00fff, /* dst_mask */ |
+ 0x1f007ff, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
/* The 16 LSBS relative to _SDA_BASE_ in split16d format. */ |
@@ -1609,7 +1610,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { |
"R_PPC_VLE_SDAREL_HI16A", /* name */ |
FALSE, /* partial_inplace */ |
0, /* src_mask */ |
- 0x1f00fff, /* dst_mask */ |
+ 0x1f007ff, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
/* Bits 16-31 relative to _SDA_BASE_ in split16d format. */ |
@@ -1639,7 +1640,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { |
"R_PPC_VLE_SDAREL_HA16A", /* name */ |
FALSE, /* partial_inplace */ |
0, /* src_mask */ |
- 0x1f00fff, /* dst_mask */ |
+ 0x1f007ff, /* dst_mask */ |
FALSE), /* pcrel_offset */ |
/* Bits 16-31 (HA) relative to _SDA_BASE split16d format. */ |
@@ -1777,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. */ |
@@ -1815,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; |
@@ -1826,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; |
@@ -1837,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; |
@@ -2151,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; |
@@ -2177,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); |
} |
@@ -2190,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] == ' ') |
@@ -2200,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, ...) |
{ |
@@ -2247,7 +2325,7 @@ ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) |
} |
static flagword |
-ppc_elf_lookup_section_flags (char *flag_name) |
+ppc_elf_lookup_section_flags (char *flag_name) |
{ |
if (!strcmp (flag_name, "SHF_PPC_VLE")) |
@@ -2341,7 +2419,7 @@ ppc_elf_additional_program_headers (bfd *abfd, |
return ret; |
} |
-/* Modify the segment map for VLE executables. */ |
+/* Modify the segment map for VLE executables. */ |
bfd_boolean |
ppc_elf_modify_segment_map (bfd *abfd, |
@@ -2358,7 +2436,7 @@ ppc_elf_modify_segment_map (bfd *abfd, |
If we find that case, we split the segment. |
We maintain the original output section order. */ |
- for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) |
+ for (m = elf_seg_map (abfd); m != NULL; m = m->next) |
{ |
if (m->count == 0) |
continue; |
@@ -3005,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 |
@@ -3401,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. */ |
@@ -3818,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. |
@@ -3843,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) |
@@ -3858,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; |
} |
} |
@@ -4325,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 |
@@ -4334,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 " |
@@ -4360,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; |
@@ -4381,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; |
@@ -5823,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 |
@@ -5940,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); |
} |
@@ -6033,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) |
@@ -6058,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 |
@@ -6103,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 |
@@ -6365,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; |
} |
@@ -7243,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. |
@@ -7288,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); |
@@ -7355,10 +7493,12 @@ ppc_elf_relocate_section (bfd *output_bfd, |
} |
else |
{ |
+ bfd_boolean ignored; |
+ |
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, |
r_symndx, symtab_hdr, sym_hashes, |
h, sec, relocation, |
- unresolved_reloc, warned); |
+ unresolved_reloc, warned, ignored); |
sym_name = h->root.root.string; |
} |
@@ -7379,7 +7519,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. */ |
@@ -7826,6 +7966,7 @@ ppc_elf_relocate_section (bfd *output_bfd, |
; |
else |
{ |
+ BFD_ASSERT (h->dynindx != -1); |
indx = h->dynindx; |
unresolved_reloc = FALSE; |
} |
@@ -7893,6 +8034,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); |
@@ -8139,7 +8282,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", |
@@ -8150,14 +8294,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, |
@@ -8176,6 +8317,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; |
@@ -8382,33 +8524,37 @@ ppc_elf_relocate_section (bfd *output_bfd, |
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_. */ |
@@ -8786,6 +8932,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 |
@@ -8980,7 +9174,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 |
@@ -9204,14 +9398,19 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, |
} |
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: |