From fabda4df3a35b710bb52f8151f1b8204bd26cb5a Mon Sep 17 00:00:00 2001 From: John Reiser Date: Wed, 14 Feb 2024 11:43:20 -0800 Subject: [PATCH] R_PPC64_REL24 is reallly "PC-rel. 26 bit, word aligned: Just like R_PPC_REL24 modified: linker.cpp --- src/linker.cpp | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/src/linker.cpp b/src/linker.cpp index a7a27da9..2cb86e78 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -835,18 +835,27 @@ void ElfLinkerPpc64le::relocate1(const Relocation *rel, byte *location, upx_uint /* value will hold relative displacement */ value -= rel->section->offset + rel->offset; - if (strcmp(type, "8") == 0) { + if (strncmp(type, "14", 2) == 0) { // for "14" and "14S" + if (3 & value) + internal_error("unaligned word displacement"); + // FIXME: displacement overflow? + set_le32(location, (0xffff0003 & get_le32(location)) + (0x0000fffc & value)); + } + else if (strncmp(type, "24", 2) == 0) { // for "24" and "24S" + if (3 & value) + internal_error("unaligned word displacement"); + // FIXME: displacement overflow? + set_le32(location, (0xfc000003 & get_le32(location)) + (0x03fffffc & value)); + } + else if (strcmp(type, "8") == 0) { int displ = (signed char) *location + (int) value; if (range_check && (displ < -128 || displ > 127)) internal_error("target out of range (%d) in reloc %s:%x\n", displ, rel->section->name, rel->offset); *location += value; - } else if (strncmp(type, "14", 2) == 0) // for "14" and "14S" - set_le16(location, get_le16(location) + value); + } else if (strcmp(type, "16") == 0) set_le16(location, get_le16(location) + value); - else if (strncmp(type, "24", 2) == 0) // for "24" and "24S" - set_le24(location, get_le24(location) + value); else if (strncmp(type, "32", 2) == 0) // for "32" and "32S" set_le32(location, get_le32(location) + value); else if (strcmp(type, "64") == 0) @@ -869,18 +878,41 @@ void ElfLinkerPpc64::relocate1(const Relocation *rel, byte *location, upx_uint64 return super::relocate1(rel, location, value, type); type += 11; + bool range_check = false; if (strncmp(type, "PC", 2) == 0) { type += 2; + range_check = true; } // We have "R_PPC64_REL" or "R_PPC64_RELPC" as a prefix. /* value will hold relative displacement */ value -= rel->section->offset + rel->offset; - if (strncmp(type, "14", 2) == 0) // for "14" and "14S" - set_be16(2 + location, get_be16(2 + location) + value); - else if (strncmp(type, "24", 2) == 0) // for "24" and "24S" - set_be24(1 + location, get_be24(1 + location) + value); + if (strncmp(type, "14", 2) == 0) { // for "14" and "14S" + if (3 & value) + internal_error("unaligned word displacement"); + // FIXME: displacement overflow? + set_be32(location, (0xffff0003 & get_be32(location)) + (0x0000fffc & value)); + } + else if (strncmp(type, "24", 2) == 0) { // for "24" and "24S" + if (3 & value) + internal_error("unaligned word displacement"); + // FIXME: displacement overflow? + set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value)); + } + else if (strcmp(type, "8") == 0) { + int displ = (signed char) *location + (int) value; + if (range_check && (displ < -128 || displ > 127)) + internal_error("target out of range (%d) in reloc %s:%x\n", displ, rel->section->name, + rel->offset); + *location += value; + } + else if (strcmp(type, "16") == 0) + set_be16(location, get_be16(location) + value); + else if (strncmp(type, "32", 2) == 0) // for "32" and "32S" + set_be32(location, get_be32(location) + value); + else if (strcmp(type, "64") == 0) + set_be64(location, get_be64(location) + value); else super::relocate1(rel, location, value, type); }