From 6f5601c4d0ad43254244f1b624900cdd5afd02ba Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 19 Jun 2019 13:55:59 +0930 Subject: [PATCH] PR24697, R_PPC_EMB_SDA21 relocation PR 24697 * elf32-ppc.c (ppc_elf_relocate_section): Don't read insn for R_PPC_EMB_RELSDA. Mask low bit of R_PPC_EMB_SDA21 r_offset. --- bfd/ChangeLog | 6 ++++++ bfd/elf32-ppc.c | 22 +++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index ea049b1..f40f6ed 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,11 @@ 2019-06-19 Alan Modra + PR 24697 + * elf32-ppc.c (ppc_elf_relocate_section): Don't read insn for + R_PPC_EMB_RELSDA. Mask low bit of R_PPC_EMB_SDA21 r_offset. + +2019-06-19 Alan Modra + * elf64-ppc.c (ppc64_elf_inline_plt): Correct st_other test for functions that require r2 valid to use local entry. (ppc64_elf_size_stubs, ppc64_elf_relocate_section): Likewise. diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index e73539a..df813d3 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -8654,6 +8654,19 @@ ppc_elf_relocate_section (bfd *output_bfd, addend -= SYM_VAL (sda); } + if (r_type == R_PPC_EMB_RELSDA) + break; + + /* The PowerPC Embedded Application Binary Interface + version 1.0 insanely chose to specify R_PPC_EMB_SDA21 + operating on a 24-bit field at r_offset. GNU as and + GNU ld have always assumed R_PPC_EMB_SDA21 operates on + a 32-bit bit insn at r_offset. Cope with object file + producers that possibly comply with the EABI in + generating an odd r_offset for big-endian objects. */ + if (r_type == R_PPC_EMB_SDA21) + rel->r_offset &= ~1; + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); if (reg == 0 && (r_type == R_PPC_VLE_SDA21 @@ -8681,13 +8694,8 @@ ppc_elf_relocate_section (bfd *output_bfd, goto overflow; goto copy_reloc; } - else if (r_type == R_PPC_EMB_SDA21 - || r_type == R_PPC_VLE_SDA21 - || r_type == R_PPC_VLE_SDA21_LO) - { - /* Fill in register field. */ - insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); - } + /* Fill in register field. */ + insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); bfd_put_32 (input_bfd, insn, contents + rel->r_offset); } break; -- 2.7.4