From 0d54d2d7c38c2a1c7257df3732fd79ce614b8665 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Mon, 25 Jul 2022 08:38:40 -0400 Subject: [PATCH] GP-713 added support for ELF PowerPC R_PPC_EMB_SDA21 relocation. Also revised PowerPC cspecs in support of EABI. --- .../PowerPC/data/languages/ppc_32_be.cspec | 6 +- .../PowerPC/data/languages/ppc_32_le.cspec | 7 +- .../PowerPC/data/languages/ppc_isa.sinc | 25 +- .../elf/extend/PowerPC64_ElfExtension.java | 13 +- .../elf/extend/PowerPC_ElfExtension.java | 5 + .../PowerPC64_ElfRelocationConstants.java | 38 +++ .../PowerPC_ElfRelocationConstants.java | 79 ++++++ .../PowerPC_ElfRelocationHandler.java | 228 +++++++++++++++++- 8 files changed, 379 insertions(+), 22 deletions(-) diff --git a/Ghidra/Processors/PowerPC/data/languages/ppc_32_be.cspec b/Ghidra/Processors/PowerPC/data/languages/ppc_32_be.cspec index 7e90bd5390..ded16f678d 100644 --- a/Ghidra/Processors/PowerPC/data/languages/ppc_32_be.cspec +++ b/Ghidra/Processors/PowerPC/data/languages/ppc_32_be.cspec @@ -87,6 +87,9 @@ + + + @@ -105,7 +108,8 @@ - + + diff --git a/Ghidra/Processors/PowerPC/data/languages/ppc_32_le.cspec b/Ghidra/Processors/PowerPC/data/languages/ppc_32_le.cspec index d1699dc0c7..1e36de335d 100644 --- a/Ghidra/Processors/PowerPC/data/languages/ppc_32_le.cspec +++ b/Ghidra/Processors/PowerPC/data/languages/ppc_32_le.cspec @@ -87,6 +87,9 @@ + + + @@ -105,7 +108,9 @@ - + + + diff --git a/Ghidra/Processors/PowerPC/data/languages/ppc_isa.sinc b/Ghidra/Processors/PowerPC/data/languages/ppc_isa.sinc index 10f0cc691c..3148135f19 100644 --- a/Ghidra/Processors/PowerPC/data/languages/ppc_isa.sinc +++ b/Ghidra/Processors/PowerPC/data/languages/ppc_isa.sinc @@ -1733,12 +1733,20 @@ define pcodeop stdcixOp; } # binutils-descr: "lq", OP(56), OP_MASK, POWER4, PPC476, {RTQ, DQ, RAQ} -define pcodeop lqOp; # ISA-cmt: lq - Load Quadword # ISA-info: lq - Form "DQ" Page 751 Category "LSQ" # binutils: power4.d: +0: e0 83 00 00 lq r4,0\(r3\) # binutils: power4.d: +4: e0 83 00 00 lq r4,0\(r3\) -:lq RT,A,DQ is $(NOTVLE) & OP=56 & RT & A & DQ & BITS_0_3=0 { RT = lqOp(RT,A); } +:lq RT,A,DQ is $(NOTVLE) & OP=56 & RT & Dp & A & DQ & BITS_0_3=0 & regp [regpset = Dp+1;] { + ea:$(REGISTER_SIZE) = A + sext(DQ:2 << 4); +@if ENDIAN == "big" + RT = *:$(REGISTER_SIZE) ea; + regp = *:$(REGISTER_SIZE) (ea + $(REGISTER_SIZE)); +@else + RT = *:$(REGISTER_SIZE) (ea + $(REGISTER_SIZE)); + regp = *:$(REGISTER_SIZE) ea; +@endif +} define pcodeop lvepxOp; :lvepx RT,A,B is OP=31 & RT & A & B & XOP_1_10=295 & BIT_0=0 { RT = lvepxOp(RT,A,B); } @@ -2038,7 +2046,6 @@ define pcodeop stfdpOp; } # binutils-descr: "stq", DSO(62,2), DS_MASK, POWER4, PPC476, {RSQ, DS, RA0} -define pcodeop stqOp; # ISA-cmt: stq - Store Quadword # ISA-info: stq - Form "DS" Page 751 Category "LSQ" # binutils: power4.d: +50: f8 c7 00 02 stq r6,0\(r7\) @@ -2046,9 +2053,15 @@ define pcodeop stqOp; # binutils: power4.d: +58: f8 c7 ff f2 stq r6,-16\(r7\) # binutils: power4.d: +5c: f8 c7 80 02 stq r6,-32768\(r7\) # binutils: power4.d: +60: f8 c7 7f f2 stq r6,32752\(r7\) -:stq S,RA_OR_ZERO,DS is $(NOTVLE) & OP=62 & S & RA_OR_ZERO & DS & BITS_0_1=2 { - EA:$(REGISTER_SIZE) = RA_OR_ZERO + sext(DS:2 << 2); - *:16 EA = stqOp(S,RA_OR_ZERO,DS:2); +:stq RS,RA_OR_ZERO,DS is $(NOTVLE) & OP=62 & RS & Dp & RA_OR_ZERO & DS & BITS_0_1=2 & regp [regpset = Dp+1;] { + ea:$(REGISTER_SIZE) = RA_OR_ZERO + sext(DS:2 << 2); +@if ENDIAN == "big" + *:$(REGISTER_SIZE) ea = RS; + *:$(REGISTER_SIZE) (ea + $(REGISTER_SIZE)) = regp; +@else + *:$(REGISTER_SIZE) (ea + $(REGISTER_SIZE)) = RS; + *:$(REGISTER_SIZE) ea = regp; +@endif } define pcodeop stvepxOp; diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java index 288615404b..e0f7f9cb5a 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC64_ElfExtension.java @@ -47,11 +47,22 @@ public class PowerPC64_ElfExtension extends ElfExtension { public static final ElfDynamicType DT_PPC64_OPDSZ = new ElfDynamicType(0x70000002, "DT_PPC64_OPDSZ", "Specify the size of the .opd section", ElfDynamicValueType.ADDRESS); public static final ElfDynamicType DT_PPC64_OPT = new ElfDynamicType(0x70000003, "DT_PPC64_OPT", - "Specify whether various optimisations are possible", ElfDynamicValueType.VALUE); + "Specify whether various optimizations are possible", ElfDynamicValueType.VALUE); // PPC64 ABI Version Flag Bits contained within ElfHeader e_flags private static final int EF_PPC64_ABI = 3; + // DT_PPC64_OPT bits + private static final int PPC64_OPT_TLS = 1; + private static final int PPC64_OPT_MULTI_TOC = 2; + private static final int PPC64_OPT_LOCALENTRY = 4; + + // ELFv2 ABI symbol st_other bits + // STO_PPC64_LOCAL specifies the number of instructions between a + // function's global entry point and local entry point + private static final int STO_PPC64_LOCAL_BIT = 5; + private static final int STO_PPC64_LOCAL_MASK = 0xE0; + public static final String TOC_BASE = "TOC_BASE"; // injected symbol to mark global TOC_BASE @Override diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java index 771edcac6b..0b7af29eca 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/extend/PowerPC_ElfExtension.java @@ -46,6 +46,11 @@ public class PowerPC_ElfExtension extends ElfExtension { public static final ElfDynamicType DT_PPC_OPT = new ElfDynamicType(0x70000001, "DT_PPC_OPT", "Specify that tls descriptors should be optimized", ElfDynamicValueType.VALUE); + // ELF header flags + private static final int EF_PPC_EMB = 0x80000000; // PowerPC embedded flag + private static final int EF_PPC_RELOCATABLE = 0x00010000; + private static final int EF_PPC_RELOCATABLE_LIB = 0x00008000; + // Program header (segment) flags private static final int PF_PPC_VLE = 0x10000000; diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationConstants.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationConstants.java index 5e80f900f0..a0c691b6b1 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationConstants.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationConstants.java @@ -122,6 +122,44 @@ public class PowerPC64_ElfRelocationConstants { public static final int R_PPC64_DTPREL16_HIGHEST = 105; // half16 #highest(@dtprel) public static final int R_PPC64_DTPREL16_HIGHESTA = 106; // half16 #highesta(@dtprel) + public static final int R_PPC64_PLTSEQ_NOTOC = 121; + public static final int R_PPC64_PLTCALL_NOTOC = 122; + public static final int R_PPC64_PCREL_OPT = 123; + + public static final int R_PPC64_D34 = 128; + public static final int R_PPC64_D34_LO = 129; + public static final int R_PPC64_D34_HI30 = 130; + public static final int R_PPC64_D34_HA30 = 131; + public static final int R_PPC64_PCREL34 = 132; + public static final int R_PPC64_GOT_PCREL34 = 133; + public static final int R_PPC64_PLT_PCREL34 = 134; + public static final int R_PPC64_PLT_PCREL34_NOTOC = 135; + public static final int R_PPC64_ADDR16_HIGHER34 = 136; + public static final int R_PPC64_ADDR16_HIGHERA34 = 137; + public static final int R_PPC64_ADDR16_HIGHEST34 = 138; + public static final int R_PPC64_ADDR16_HIGHESTA34 = 139; + public static final int R_PPC64_REL16_HIGHER34 = 140; + public static final int R_PPC64_REL16_HIGHERA34 = 141; + public static final int R_PPC64_REL16_HIGHEST34 = 142; + public static final int R_PPC64_REL16_HIGHESTA34 = 143; + public static final int R_PPC64_D28 = 144; + public static final int R_PPC64_PCREL28 = 145; + public static final int R_PPC64_TPREL34 = 146; + public static final int R_PPC64_DTPREL34 = 147; + public static final int R_PPC64_GOT_TLSGD_PCREL34 = 148; + public static final int R_PPC64_GOT_TLSLD_PCREL34 = 149; + public static final int R_PPC64_GOT_TPREL_PCREL34 = 150; + public static final int R_PPC64_GOT_DTPREL_PCREL34 = 151; + + public static final int R_PPC64_REL16_HIGH = 240; + public static final int R_PPC64_REL16_HIGHA = 241; + public static final int R_PPC64_REL16_HIGHER = 242; + public static final int R_PPC64_REL16_HIGHERA = 243; + public static final int R_PPC64_REL16_HIGHEST = 244; + public static final int R_PPC64_REL16_HIGHESTA = 245; + + public static final int R_PPC64_JMP_IREL = 247; + // Masks for manipulating Power PC relocation targets public static final int PPC64_WORD32 = 0xFFFFFFFF; public static final int PPC64_WORD30 = 0xFFFFFFFC; diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationConstants.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationConstants.java index efdaedf5c8..6c3554eae4 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationConstants.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationConstants.java @@ -58,6 +58,85 @@ public class PowerPC_ElfRelocationConstants { public static final int R_PPC_SECTOFF_HA = 36; // half16 #ha(R + A) public static final int R_PPC_ADDR30 = 37; // word30 (S + A - P) >> 2 + public static final int R_POWERPC_TLS = 67; + public static final int R_POWERPC_DTPMOD = 68; + public static final int R_POWERPC_TPREL16 = 69; + public static final int R_POWERPC_TPREL16_LO = 70; + public static final int R_POWERPC_TPREL16_HI = 71; + public static final int R_POWERPC_TPREL16_HA = 72; + public static final int R_POWERPC_TPREL = 73; + public static final int R_POWERPC_DTPREL16 = 74; + public static final int R_POWERPC_DTPREL16_LO = 75; + public static final int R_POWERPC_DTPREL16_HI = 76; + public static final int R_POWERPC_DTPREL16_HA = 77; + public static final int R_POWERPC_DTPREL = 78; + public static final int R_POWERPC_GOT_TLSGD16 = 79; + public static final int R_POWERPC_GOT_TLSGD16_LO = 80; + public static final int R_POWERPC_GOT_TLSGD16_HI = 81; + public static final int R_POWERPC_GOT_TLSGD16_HA = 82; + public static final int R_POWERPC_GOT_TLSLD16 = 83; + public static final int R_POWERPC_GOT_TLSLD16_LO = 84; + public static final int R_POWERPC_GOT_TLSLD16_HI = 85; + public static final int R_POWERPC_GOT_TLSLD16_HA = 86; + public static final int R_POWERPC_GOT_TPREL16 = 87; + public static final int R_POWERPC_GOT_TPREL16_LO = 88; + public static final int R_POWERPC_GOT_TPREL16_HI = 89; + public static final int R_POWERPC_GOT_TPREL16_HA = 90; + public static final int R_POWERPC_GOT_DTPREL16 = 91; + public static final int R_POWERPC_GOT_DTPREL16_LO = 92; + public static final int R_POWERPC_GOT_DTPREL16_HI = 93; + public static final int R_POWERPC_GOT_DTPREL16_HA = 94; + public static final int R_PPC_TLSGD = 95; + public static final int R_PPC_TLSLD = 96; + + public static final int R_PPC_EMB_NADDR32 = 101; // uword32 (A - S) + public static final int R_PPC_EMB_NADDR16 = 102; // uhalf16 (A - S) + public static final int R_PPC_EMB_NADDR16_LO = 103; // uhalf16 #lo(A - S) + public static final int R_PPC_EMB_NADDR16_HI = 104; // uhalf16 #hi(A - S) + public static final int R_PPC_EMB_NADDR16_HA = 105; // uhalf16 #ha(A - S) + public static final int R_PPC_EMB_SDAI16 = 106; // uhalf16 T + public static final int R_PPC_EMB_SDA2I16 = 107; // uhalf16 U + public static final int R_PPC_EMB_SDA2REL = 108; // uhalf16 S + A - _SDA2_BASE_ + public static final int R_PPC_EMB_SDA21 = 109; // ulow21 + public static final int R_PPC_EMB_MRKREF = 110; // none + public static final int R_PPC_EMB_RELSEC16 = 111; // uhalf16 V + A + public static final int R_PPC_EMB_RELST_LO = 112; // uhalf16 #lo(W + A) + public static final int R_PPC_EMB_RELST_HI = 113; // uhalf16 #hi(W + A) + public static final int R_PPC_EMB_RELST_HA = 114; // uhalf16 #ha(W + A) + public static final int R_PPC_EMB_BIT_FLD = 115; // uword32 + public static final int R_PPC_EMB_RELSDA = 116; // uhalf16 + + public static final int R_POWERPC_PLTSEQ = 119; + public static final int R_POWERPC_PLTCALL = 120; + + public static final int R_PPC_VLE_REL8 = 216; + public static final int R_PPC_VLE_REL15 = 217; + public static final int R_PPC_VLE_REL24 = 218; + public static final int R_PPC_VLE_LO16A = 219; + public static final int R_PPC_VLE_LO16D = 220; + public static final int R_PPC_VLE_HI16A = 221; + public static final int R_PPC_VLE_HI16D = 222; + public static final int R_PPC_VLE_HA16A = 223; + public static final int R_PPC_VLE_HA16D = 224; + public static final int R_PPC_VLE_SDA21 = 225; + public static final int R_PPC_VLE_SDA21_LO = 226; + public static final int R_PPC_VLE_SDAREL_LO16A = 227; + public static final int R_PPC_VLE_SDAREL_LO16D = 228; + public static final int R_PPC_VLE_SDAREL_HI16A = 229; + public static final int R_PPC_VLE_SDAREL_HI16D = 230; + public static final int R_PPC_VLE_SDAREL_HA16A = 231; + public static final int R_PPC_VLE_SDAREL_HA16D = 232; + + public static final int R_POWERPC_REL16DX_HA = 246; + public static final int R_POWERPC_IRELATIVE = 248; + public static final int R_POWERPC_REL16 = 249; + public static final int R_POWERPC_REL16_LO = 250; + public static final int R_POWERPC_REL16_HI = 251; + public static final int R_POWERPC_REL16_HA = 252; + public static final int R_POWERPC_GNU_VTINHERIT = 253; + public static final int R_POWERPC_GNU_VTENTRY = 254; + public static final int R_PPC_TOC16 = 255; + // Masks for manipulating Power PC relocation targets public static final int PPC_WORD32 = 0xFFFFFFFF; public static final int PPC_WORD30 = 0xFFFFFFFC; diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java index 87b62bfb14..5fde5de741 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java @@ -15,14 +15,22 @@ */ package ghidra.app.util.bin.format.elf.relocation; +import java.math.BigInteger; +import java.util.Map; + +import com.google.common.base.Predicate; + import ghidra.app.util.bin.format.elf.*; import ghidra.app.util.bin.format.elf.extend.PowerPC_ElfExtension; -import ghidra.program.model.address.Address; +import ghidra.app.util.importer.MessageLog; +import ghidra.program.model.address.*; import ghidra.program.model.lang.Language; +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.ContextChangeException; import ghidra.program.model.listing.Program; -import ghidra.program.model.mem.Memory; -import ghidra.program.model.mem.MemoryAccessException; -import ghidra.util.exception.NotFoundException; +import ghidra.program.model.mem.*; +import ghidra.program.model.symbol.*; +import ghidra.util.exception.*; public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler { @@ -31,16 +39,25 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler { return elf.e_machine() == ElfConstants.EM_PPC && elf.is32Bit(); } + @Override + public PowerPC_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper, + ElfRelocationTable relocationTable, Map symbolMap) { + return new PowerPC_ElfRelocationContext(this, loadHelper, relocationTable, symbolMap); + } + @Override public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, Address relocationAddress) throws MemoryAccessException, NotFoundException { - ElfHeader elf = elfRelocationContext.getElfHeader(); + PowerPC_ElfRelocationContext ppcRelocationContext = + (PowerPC_ElfRelocationContext) elfRelocationContext; + + ElfHeader elf = ppcRelocationContext.getElfHeader(); if (elf.e_machine() != ElfConstants.EM_PPC || !elf.is32Bit()) { return; } - Program program = elfRelocationContext.getProgram(); + Program program = ppcRelocationContext.getProgram(); Memory memory = program.getMemory(); int type = relocation.getType(); @@ -49,12 +66,12 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler { } int symbolIndex = relocation.getSymbolIndex(); - Language language = elfRelocationContext.getProgram().getLanguage(); + Language language = ppcRelocationContext.getProgram().getLanguage(); if (!"PowerPC".equals(language.getProcessor().toString()) || language.getLanguageDescription().getSize() != 32) { markAsError(program, relocationAddress, Long.toString(type), null, "Unsupported language for 32-bit PowerPC relocation", - elfRelocationContext.getLog()); + ppcRelocationContext.getLog()); } // NOTE: Based upon glibc source it appears that PowerPC only uses RELA relocations @@ -72,7 +89,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler { // // // Relocation addend already includes original symbol value but needs to account // // for any image base adjustment -// symbolValue = (int) elfRelocationContext.getImageBaseWordAdjustmentOffset(); +// symbolValue = (int) ppcRelocationContext.getImageBaseWordAdjustmentOffset(); // } // else { Address symbolAddr = (elfRelocationContext.getSymbolAddress(sym)); @@ -162,7 +179,7 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler { memory.setInt(relocationAddress, newValue); break; case PowerPC_ElfRelocationConstants.R_PPC_RELATIVE: - newValue = (int) elfRelocationContext.getImageBaseWordAdjustmentOffset() + addend; + newValue = (int) ppcRelocationContext.getImageBaseWordAdjustmentOffset() + addend; memory.setInt(relocationAddress, newValue); break; case PowerPC_ElfRelocationConstants.R_PPC_REL32: @@ -202,15 +219,200 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler { // not too far away since a fabricated GOT would be in the same block // and we may only have room in the plt for two instructions. markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName, - elfRelocationContext.getLog()); + ppcRelocationContext.getLog()); } break; + case PowerPC_ElfRelocationConstants.R_PPC_EMB_SDA21: + // NOTE: PPC EABI V1.0 specifies this relocation on a 24-bit field address while + // GNU assumes a 32-bit field address. We cope with this difference by + // forcing a 32-bit alignment of the relocation address. + long alignedRelocOffset = relocationAddress.getOffset() & ~3; + relocationAddress = relocationAddress.getNewAddress(alignedRelocOffset); + + oldValue = memory.getInt(relocationAddress); + + Address symAddr = ppcRelocationContext.getSymbolAddress(sym); + MemoryBlock block = memory.getBlock(symAddr); + Integer sdaBase = null; + Integer gprID = null; + + if (block != null) { + String blockName = block.getName(); + if (".sdata".equals(blockName) || ".sbss".equals(blockName)) { + sdaBase = ppcRelocationContext.getSDABase(); + gprID = 13; + } + else if (".sdata2".equals(blockName) || ".sbss2".equals(blockName)) { + sdaBase = ppcRelocationContext.getSDA2Base(); + gprID = 2; + } + else if (".PPC.EMB.sdata0".equals(blockName) || + ".PPC.EMB.sbss0".equals(blockName)) { + sdaBase = 0; + gprID = 0; + } + else if (MemoryBlock.EXTERNAL_BLOCK_NAME.equals(blockName)) { + markAsError(program, relocationAddress, type, sym.getNameAsString(), + "Unsupported relocation for external symbol", + ppcRelocationContext.getLog()); + break; + } + } + if (gprID == null || sdaBase == null) { + markAsError(program, relocationAddress, type, sym.getNameAsString(), + "Failed to identfy appropriate data block", ppcRelocationContext.getLog()); + break; + } + + newValue = (symbolValue - sdaBase + addend) & 0xffff; + newValue |= gprID << 16; + newValue |= oldValue & 0xffe00000; + memory.setInt(relocationAddress, newValue); + break; + default: markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName, - elfRelocationContext.getLog()); + ppcRelocationContext.getLog()); break; } + } + + /** + * PowerPC_ElfRelocationContext provides extended relocation context.. + */ + private static class PowerPC_ElfRelocationContext extends ElfRelocationContext { + + private Integer sdaBase; + private Integer sda2Base; + + protected PowerPC_ElfRelocationContext(ElfRelocationHandler handler, + ElfLoadHelper loadHelper, ElfRelocationTable relocationTable, + Map symbolMap) { + super(handler, loadHelper, relocationTable, symbolMap); + } + + /** + * Get or establish _SDA_BASE_ value and apply as r13 context value to all memory blocks + * with execute permission. + * @return _SDA_BASE_ offset or null if unable to determine or establish + */ + Integer getSDABase() { + if (sdaBase != null) { + if (sdaBase == -1) { + return null; + } + return sdaBase; + } + sdaBase = getBaseOffset("_SDA_BASE_", ".sdata", ".sbss"); + if (sdaBase == -1) { + getLog().appendMsg("ERROR: failed to establish _SDA_BASE_"); + return null; + } + setRegisterContext("r13", BigInteger.valueOf(sdaBase), b -> b.isExecute()); + return sdaBase; + } + + /** + * Get or establish _SDA2_BASE_ value and apply as r2 context value to all memory blocks + * with execute permission. + * @return _SDA2_BASE_ offset or null if unable to determine or establish + */ + Integer getSDA2Base() { + if (sda2Base != null) { + if (sda2Base == -1) { + return null; + } + return sda2Base; + } + sda2Base = getBaseOffset("_SDA2_BASE_", ".sdata2", ".sbss2"); + if (sda2Base == -1) { + getLog().appendMsg("ERROR: failed to establish _SDA2_BASE_"); + return null; + } + setRegisterContext("r2", BigInteger.valueOf(sda2Base), b -> b.isExecute()); + return sda2Base; + } + + /** + * Apply register context to all memory blocks which satisfy blockPredicate check. + * @param regName register name + * @param value context value + * @param blockPredicate determine which memory blocks get context applied + */ + private void setRegisterContext(String regName, BigInteger value, + Predicate blockPredicate) { + Register reg = program.getRegister(regName); + for (MemoryBlock block : program.getMemory().getBlocks()) { + if (block.isExecute()) { + try { + program.getProgramContext().setValue(reg, block.getStart(), block.getEnd(), + value); + } + catch (ContextChangeException e) { + throw new AssertException(e); // no instructions should exist yet + } + } + } + } + + /** + * Establish base offset from symbol or range of specified memory blocks. + * @param symbolName base symbol name + * @param blockNames block names which may be used to establish base range + * @return base offset or -1 on failure + */ + private Integer getBaseOffset(String symbolName, String... blockNames) { + + MessageLog log = getLog(); + + Symbol baseSymbol = SymbolUtilities.getLabelOrFunctionSymbol(program, symbolName, + msg -> log.appendMsg(msg)); + if (baseSymbol != null) { + int baseOffset = (int) baseSymbol.getAddress().getOffset(); + String absString = ""; + if (baseSymbol.isPinned()) { + absString = "absolute "; + } + log.appendMsg( + "Using " + absString + symbolName + " of 0x" + Integer.toHexString(baseOffset)); + return baseOffset; + } + + Memory mem = program.getMemory(); + AddressSpace defaultSpace = program.getAddressFactory().getDefaultAddressSpace(); + AddressSet blockSet = new AddressSet(); + for (String blockName : blockNames) { + MemoryBlock block = mem.getBlock(blockName); + if (block != null) { + if (!block.getStart().getAddressSpace().equals(defaultSpace)) { + log.appendMsg("ERROR: " + blockName + " not in default space"); + return -1; + } + blockSet.add(block.getStart(), block.getEnd()); + } + } + if (blockSet.isEmpty()) { + return -1; + } + + Address baseAddr = blockSet.getMinAddress(); + long range = blockSet.getMaxAddress().subtract(baseAddr) + 1; + if (range > Short.MAX_VALUE) { + // use aligned midpoint of range + baseAddr = baseAddr.add((range / 2) & ~0x0f); + } + + try { + program.getSymbolTable().createLabel(baseAddr, symbolName, SourceType.ANALYSIS); + } + catch (InvalidInputException e) { + throw new AssertException(e); + } + + int baseOffset = (int) baseAddr.getOffset(); + log.appendMsg("Defined " + symbolName + " of 0x" + Integer.toHexString(baseOffset)); + return baseOffset; + } } - }