From 438725bafd2d4b68614d53fae0ca815501475101 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Fri, 11 Jul 2025 16:17:19 -0400 Subject: [PATCH] GP-5815 Added ELF Loader GOT allocation support for AARCH64 in support of object module loading. --- .../relocation/ElfGotRelocationContext.java | 294 ++++++++++++++++++ .../AARCH64_ElfRelocationContext.java | 62 ++++ .../AARCH64_ElfRelocationHandler.java | 80 ++++- .../relocation/AARCH64_ElfRelocationType.java | 77 +++-- .../X86_64_ElfRelocationContext.java | 250 +-------------- 5 files changed, 473 insertions(+), 290 deletions(-) create mode 100644 Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfGotRelocationContext.java create mode 100644 Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationContext.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfGotRelocationContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfGotRelocationContext.java new file mode 100644 index 0000000000..2f260c0159 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfGotRelocationContext.java @@ -0,0 +1,294 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.elf.relocation; + +import java.util.*; + +import ghidra.app.util.MemoryBlockUtils; +import ghidra.app.util.bin.format.elf.*; +import ghidra.program.model.address.*; +import ghidra.program.model.data.PointerDataType; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.util.*; +import ghidra.util.exception.InvalidInputException; +import ghidra.util.exception.NotFoundException; + +/** + * ElfGotRelocationContext provides ability to generate a + * Global Offset Table (GOT) to facilitate GOT related relocations encountered within + * object modules. + *

+ * NOTE: This should be considered experimental and has its limitations with GOT size and + * placement which could behave improperly for large binaries. + * + * @param ELF relocation handler class + */ +public abstract class ElfGotRelocationContext + extends ElfRelocationContext { + + private AddressRange allocatedGotLimits; + private Address allocatedGotAddress; + private Address lastAllocatedGotEntryAddress; + private Address nextAllocatedGotEntryAddress; + + private Map gotMap; + + ElfGotRelocationContext(H handler, ElfLoadHelper loadHelper, + Map symbolMap) { + super(handler, loadHelper, symbolMap); + } + + @Override + public long getSymbolValue(ElfSymbol symbol) { + long symbolValue = super.getSymbolValue(symbol); + if (symbolValue == 0 && ElfConstants.GOT_SYMBOL_NAME.equals(symbol.getNameAsString())) { + Address gotAddr = symbolMap.get(symbol); + if (gotAddr == null) { + gotAddr = allocateGot(); + } + if (gotAddr != null) { + return gotAddr.getOffset(); + } + } + return symbolValue; + } + + @Override + public long getGOTValue() throws NotFoundException { + try { + return super.getGOTValue(); + } + catch (NotFoundException e) { + Address gotAddr = allocateGot(); + if (gotAddr != null) { + return gotAddr.getOffset(); + } + throw e; + } + } + + private ElfSymbol findGotElfSymbol() { + for (ElfSymbolTable st : getElfHeader().getSymbolTables()) { + for (ElfSymbol s : st.getSymbols()) { + if (ElfConstants.GOT_SYMBOL_NAME.equals(s.getNameAsString())) { + return s; + } + } + } + return null; + } + + private int computeRequiredGotSize() { + // NOTE: GOT allocation calculation assumes all GOT entries correspond to a specific + // symbol and not a computed offset. This assumption may need to be revised based upon + // uses of getGotEntryAddress method + Set uniqueSymbolValues = new HashSet<>(); + for (ElfRelocationTable rt : getElfHeader().getRelocationTables()) { + ElfSymbolTable st = rt.getAssociatedSymbolTable(); + if (st == null) { + continue; + } + for (ElfRelocation r : rt.getRelocations()) { + int symbolIndex = r.getSymbolIndex(); + if (!requiresGotEntry(r) || symbolIndex == 0) { + continue; + } + ElfSymbol elfSymbol = st.getSymbol(symbolIndex); + if (elfSymbol == null) { + continue; + } + long symbolValue = getSymbolValue(elfSymbol); + if (!uniqueSymbolValues.add(symbolValue)) { + System.out.println("Duplicate sym value 0x" + Long.toHexString(symbolValue) + + " for " + elfSymbol.getNameAsString()); + } + } + } + return Math.max(8, uniqueSymbolValues.size() * 8); + } + + /** + * {@return true if the specified relocation type requires a GOT entry.} + *

+ * NOTE: It is very important that all relocations types which invoke + * {@link #getGotEntryAddress(ElfSymbol)} result in this method returning true. Failure to + * do so could result in an under allocation of the GOT memory block. + * @param r relocation type + */ + protected abstract boolean requiresGotEntry(ElfRelocation r); + + private Address allocateGot() { + + if (allocatedGotAddress != null) { + if (allocatedGotAddress == Address.NO_ADDRESS) { + return null; + } + return allocatedGotAddress; + } + + allocatedGotAddress = Address.NO_ADDRESS; + nextAllocatedGotEntryAddress = Address.NO_ADDRESS; + + ElfSymbol gotElfSymbol = findGotElfSymbol(); + + if (gotElfSymbol == null && !getElfHeader().isRelocatable()) { + loadHelper + .log("GOT allocatiom failed. " + ElfConstants.GOT_SYMBOL_NAME + " not defined"); + return null; + } + + if (gotElfSymbol != null && gotElfSymbol.getValue() != 0) { + loadHelper.log( + "GOT allocatiom failed. " + ElfConstants.GOT_SYMBOL_NAME + " already defined"); + return null; + } + + int alignment = getLoadAdapter().getLinkageBlockAlignment(); + int gotSize = computeRequiredGotSize(); + allocatedGotLimits = getLoadHelper().allocateLinkageBlock(alignment, gotSize, + ElfRelocationHandler.GOT_BLOCK_NAME); + if (allocatedGotLimits != null && + allocatedGotLimits.getMinAddress().getOffset() < Integer.MAX_VALUE) { + // NOTE: GOT must fall within first 32-bit segment + if (gotElfSymbol != null) { + // remember where GOT was allocated + try { + loadHelper.createSymbol(allocatedGotLimits.getMinAddress(), + ElfConstants.GOT_SYMBOL_NAME, true, false, null); + } + catch (InvalidInputException e) { + throw new AssertionError("Unexpected exception", e); + } + symbolMap.put(gotElfSymbol, allocatedGotLimits.getMinAddress()); + } + allocatedGotAddress = allocatedGotLimits.getMinAddress(); + nextAllocatedGotEntryAddress = allocatedGotAddress; + gotMap = new HashMap<>(); + loadHelper.log("Created " + ElfRelocationHandler.GOT_BLOCK_NAME + + " block required for GOT relocation processing"); + return allocatedGotAddress; + } + + loadHelper.log("Failed to allocate GOT block required for relocation processing"); + return null; + } + + /** + * Allocate the next section GOT entry location. If GOT has not been allocated an attempt + * will be made to create one. If allocated gotMap will also be established. + * @return Address of GOT entry or {@link Address#NO_ADDRESS} if unable to allocate. + */ + private Address getNextAllocatedGotEntryAddress() { + if (nextAllocatedGotEntryAddress == null) { + if (allocateGot() == null) { + return Address.NO_ADDRESS; // failed to allocate got + } + } + + Address addr = nextAllocatedGotEntryAddress; + if (addr == Address.NO_ADDRESS) { + return Address.NO_ADDRESS; // insufficient space in got + } + + try { + // verify that entry fits in got + int pointerSize = loadHelper.getProgram().getDefaultPointerSize(); + Address lastAddr = nextAllocatedGotEntryAddress.addNoWrap(pointerSize - 1); + if (allocatedGotLimits.contains(lastAddr)) { + // entry fits in got - update and return entry address + lastAllocatedGotEntryAddress = lastAddr; + nextAllocatedGotEntryAddress = lastAllocatedGotEntryAddress.addNoWrap(1); + if (!allocatedGotLimits.contains(nextAllocatedGotEntryAddress)) { + // allocated got space fully consumed + nextAllocatedGotEntryAddress = Address.NO_ADDRESS; + } + return addr; + } + } + catch (AddressOverflowException e) { + // ignore + } + + // insufficient space in got - fail future allocation attempts + nextAllocatedGotEntryAddress = Address.NO_ADDRESS; + return Address.NO_ADDRESS; + } + + /** + * Get or allocate a GOT entry for the specified symbolValue. + * NOTE: This is restricted to object modules only which do not of a GOT. + * @param elfSymbol ELF symbol + * @return GOT entry address or null if unable to allocate + */ + public Address getGotEntryAddress(ElfSymbol elfSymbol) { + long symbolValue = getSymbolValue(elfSymbol); + Address addr = null; + if (gotMap != null) { + addr = gotMap.get(symbolValue); + } + if (addr == null) { + addr = getNextAllocatedGotEntryAddress(); + if (gotMap != null) { + gotMap.put(symbolValue, addr); + } + } + return addr == Address.NO_ADDRESS ? null : addr; + } + + /** + * Flush the section GOT table to a new %got memory block + */ + private void createGot() { + if (lastAllocatedGotEntryAddress == null) { + return; + } + int size = (int) lastAllocatedGotEntryAddress.subtract(allocatedGotAddress) + 1; + try { + MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, false, + ElfRelocationHandler.GOT_BLOCK_NAME, allocatedGotAddress, size, + "NOTE: This block is artificial and allows ELF Relocations to work correctly", + "Elf Loader", true, false, false, loadHelper.getLog()); + + // Mark block as an artificial fabrication + block.setArtificial(true); + + DataConverter converter = + program.getMemory().isBigEndian() ? BigEndianDataConverter.INSTANCE + : LittleEndianDataConverter.INSTANCE; + for (long symbolValue : gotMap.keySet()) { + Address addr = gotMap.get(symbolValue); + byte[] bytes = converter.getBytes(symbolValue); // 8-byte pointer value + block.putBytes(addr, bytes); + loadHelper.createData(addr, PointerDataType.dataType); + } + } + catch (MemoryAccessException e) { + String msg = "Failed to create GOT at " + allocatedGotAddress; + loadHelper.log(msg); + Msg.error(this, msg, e); + } + } + + @Override + public void dispose() { + + // Generate the object module GOT table if required + createGot(); + + super.dispose(); + } +} diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationContext.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationContext.java new file mode 100644 index 0000000000..1f19733a36 --- /dev/null +++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationContext.java @@ -0,0 +1,62 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.elf.relocation; + +import java.util.Map; + +import ghidra.app.util.bin.format.elf.*; +import ghidra.program.model.address.Address; + +/** + * AARCH64_ElfRelocationContext provides ability to generate a + * Global Offset Table (GOT) to facilitate GOT related relocations encountered within + * object modules. + */ +class AARCH64_ElfRelocationContext extends ElfGotRelocationContext { + + AARCH64_ElfRelocationContext(AARCH64_ElfRelocationHandler handler, ElfLoadHelper loadHelper, + Map symbolMap) { + super(handler, loadHelper, symbolMap); + } + + @Override + protected boolean requiresGotEntry(ElfRelocation r) { + + AARCH64_ElfRelocationType type = handler.getRelocationType(r.getType()); + if (type == null) { + return false; + } + + switch (type) { + + // NOTE: There are many more relocation types that require a GOT allocation. + //@formatter:off + + //case R_AARCH64_P32_GOT_LD_PREL19: + case R_AARCH64_P32_ADR_GOT_PAGE: + case R_AARCH64_P32_LD32_GOT_LO12_NC: + //case R_AARCH64_P32_LD32_GOTPAGE_LO14: + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_LD64_GOT_LO12_NC: + return true; + + //@formatter:on + default: + return false; + } + } + +} diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java index aec97b4af7..3e8cb5e6e7 100644 --- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java +++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,6 +15,8 @@ */ package ghidra.app.util.bin.format.elf.relocation; +import java.util.Map; + import org.apache.commons.lang3.StringUtils; import ghidra.app.util.bin.format.elf.*; @@ -25,8 +27,8 @@ import ghidra.program.model.mem.*; import ghidra.program.model.reloc.Relocation.Status; import ghidra.program.model.reloc.RelocationResult; -public class AARCH64_ElfRelocationHandler - extends AbstractElfRelocationHandler> { +public class AARCH64_ElfRelocationHandler extends + AbstractElfRelocationHandler { /** * Constructor @@ -46,11 +48,17 @@ public class AARCH64_ElfRelocationHandler } @Override - protected RelocationResult relocate(ElfRelocationContext elfRelocationContext, + public AARCH64_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper, + Map symbolMap) { + return new AARCH64_ElfRelocationContext(this, loadHelper, symbolMap); + } + + @Override + protected RelocationResult relocate(AARCH64_ElfRelocationContext elfRelocationContext, ElfRelocation relocation, AARCH64_ElfRelocationType type, Address relocationAddress, ElfSymbol sym, Address symbolAddr, long symbolValue, String symbolName) throws MemoryAccessException { - + Program program = elfRelocationContext.getProgram(); Memory memory = program.getMemory(); boolean isBigEndianInstructions = @@ -58,13 +66,13 @@ public class AARCH64_ElfRelocationHandler long addend = relocation.getAddend(); // will be 0 for REL case long offset = relocationAddress.getOffset(); - + int symbolIndex = relocation.getSymbolIndex(); boolean is64bit = true; boolean overflowCheck = true; // *_NC type relocations specify "no overflow check" long newValue = 0; int byteLength = 4; // most relocations affect 4-bytes (change if different) - + // Handle relative relocations that do not require symbolAddr or symbolValue switch (type) { case R_AARCH64_P32_RELATIVE: @@ -84,7 +92,7 @@ public class AARCH64_ElfRelocationHandler default: break; } - + // Check for unresolved symbolAddr and symbolValue required by remaining relocation types handled below if (handleUnresolvedSymbol(elfRelocationContext, relocation, relocationAddress)) { return RelocationResult.FAILURE; @@ -308,8 +316,7 @@ public class AARCH64_ElfRelocationHandler // LD/ST64: (S+A) & 0xff8 case R_AARCH64_LDST64_ABS_LO12_NC: - case R_AARCH64_P32_LDST64_ABS_LO12_NC: - case R_AARCH64_LD64_GOT_LO12_NC: { + case R_AARCH64_P32_LDST64_ABS_LO12_NC: { int oldValue = memory.getInt(relocationAddress, isBigEndianInstructions); newValue = (int) ((symbolValue + addend) & 0xff8) >> 3; @@ -330,6 +337,53 @@ public class AARCH64_ElfRelocationHandler break; } + // ADRP: Page(G(GDAT(S)))-Page(P) + // Page of GOT entry address for S minus page of relocation address + // Set the immediate value of an ADRP to bits [32:12] of X + case R_AARCH64_ADR_GOT_PAGE: + case R_AARCH64_P32_ADR_GOT_PAGE: { + int oldValue = memory.getInt(relocationAddress, isBigEndianInstructions); + Address symbolGotAddress = elfRelocationContext.getGotEntryAddress(sym); + if (symbolGotAddress == null) { + markAsError(program, relocationAddress, type, symbolName, symbolIndex, + "GOT allocation failure", elfRelocationContext.getLog()); + return RelocationResult.FAILURE; + } + newValue = page(symbolGotAddress.getOffset()) - page(relocationAddress.getOffset()); + newValue = (newValue & 0x1fffff000L) >>> 12; + int loBits = (int) newValue & 0x3; + int hiBits = (int) newValue >>> 2; + + newValue = (oldValue & 0x9f00001fL) | (loBits << 29) | (hiBits << 5); + memory.setInt(relocationAddress, (int) newValue, isBigEndianInstructions); + break; + } + + // LD/ST: G(GDAT(S)) + case R_AARCH64_P32_LD32_GOT_LO12_NC: // Set the LD/ST immediate field to bits [11:2] of X + case R_AARCH64_LD64_GOT_LO12_NC: // Set the LD/ST immediate field to bits [11:3] of X + { + int oldValue = memory.getInt(relocationAddress, isBigEndianInstructions); + Address symbolGotAddress = elfRelocationContext.getGotEntryAddress(sym); + if (symbolGotAddress == null) { + markAsError(program, relocationAddress, type, symbolName, symbolIndex, + "GOT allocation failure", elfRelocationContext.getLog()); + return RelocationResult.FAILURE; + } + int lo12bits = (int) (symbolGotAddress.getOffset() & 0xfff); + if (type == AARCH64_ElfRelocationType.R_AARCH64_P32_LD32_GOT_LO12_NC) { + lo12bits &= ~0x3; + } + else { + lo12bits &= ~0x7; + } + + // Bits [21:10] — imm12: 12-bit unsigned immediate offset + newValue = (oldValue & 0xffc003ffL) | (lo12bits << 10); + memory.setInt(relocationAddress, (int) newValue, isBigEndianInstructions); + break; + } + case R_AARCH64_P32_GLOB_DAT: is64bit = false; case R_AARCH64_GLOB_DAT: { @@ -379,6 +433,10 @@ public class AARCH64_ElfRelocationHandler return new RelocationResult(Status.APPLIED, byteLength); } + private long page(long offset) { + return offset & ~0xfff; + } + /** * Set the new value in memory * @param memory memory diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationType.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationType.java index 8b990df668..2a668a0f50 100644 --- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationType.java +++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationType.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,6 +17,17 @@ package ghidra.app.util.bin.format.elf.relocation; public enum AARCH64_ElfRelocationType implements ElfRelocationType { + // Comment macros: + // S - symbol address + // A - addend + // P - relocation address + // X - result of a relocation operation + // PG(expr) = Page(expr) = expr & ~0xFFF + // G(expr) = Address of GOT entry corresponding to expr + // GDAT(expr) = GOT entry for expression expr value + // + // Reference: https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst + R_AARCH64_NONE(0), R_AARCH64_P32_ABS32(1), // .word: (S+A) R_AARCH64_P32_ABS16(2), // .half: (S+A) @@ -40,10 +51,10 @@ public enum AARCH64_ElfRelocationType implements ElfRelocationType { R_AARCH64_P32_JUMP26(20), // B: ((S+A-P) >> 2) & 0x3ffffff. R_AARCH64_P32_CALL26(21), // BL: ((S+A-P) >> 2) & 0x3ffffff. - R_AARCH64_P32_GOT_LD_PREL19(25), - R_AARCH64_P32_ADR_GOT_PAGE(26), - R_AARCH64_P32_LD32_GOT_LO12_NC(27), - R_AARCH64_P32_LD32_GOTPAGE_LO14(28), + R_AARCH64_P32_GOT_LD_PREL19(25), // G(GDAT(S))- P + R_AARCH64_P32_ADR_GOT_PAGE(26), // ADRP: Page(G(GDAT(S)))-Page(P) + R_AARCH64_P32_LD32_GOT_LO12_NC(27), // LD/ST: G(GDAT(S)) + R_AARCH64_P32_LD32_GOTPAGE_LO14(28), // LD/ST: G(GDAT(S))-Page(GOT) R_AARCH64_P32_TLSGD_ADR_PREL21(80), R_AARCH64_P32_TLSGD_ADR_PAGE21(81), @@ -82,9 +93,9 @@ public enum AARCH64_ElfRelocationType implements ElfRelocationType { R_AARCH64_P32_TLSDESC_ADD_LO12_NC(126), R_AARCH64_P32_TLSDESC_CALL(127), - R_AARCH64_P32_COPY(180), // Copy symbol at runtime. - R_AARCH64_P32_GLOB_DAT(181), // Create GOT entry. - R_AARCH64_P32_JUMP_SLOT(182), // Create PLT entry. + R_AARCH64_P32_COPY(180), // Copy symbol value at runtime. + R_AARCH64_P32_GLOB_DAT(181), // Relocate GOT entry. + R_AARCH64_P32_JUMP_SLOT(182), // Relocate PLT entry. // Adjust by program base. R_AARCH64_P32_RELATIVE(183), @@ -127,28 +138,28 @@ public enum AARCH64_ElfRelocationType implements ElfRelocationType { R_AARCH64_LDST16_ABS_LO12_NC(284), // LD/ST16: (S+A) & 0xffe R_AARCH64_LDST32_ABS_LO12_NC(285), // LD/ST32: (S+A) & 0xffc R_AARCH64_LDST64_ABS_LO12_NC(286), // LD/ST64: (S+A) & 0xff8 - R_AARCH64_MOVW_PREL_G0(287), - R_AARCH64_MOVW_PREL_G0_NC(288), - R_AARCH64_MOVW_PREL_G1(289), - R_AARCH64_MOVW_PREL_G1_NC(290), - R_AARCH64_MOVW_PREL_G2(291), - R_AARCH64_MOVW_PREL_G2_NC(292), - R_AARCH64_MOVW_PREL_G3(293), + R_AARCH64_MOVW_PREL_G0(287), // S+A-P + R_AARCH64_MOVW_PREL_G0_NC(288), // S+A-P + R_AARCH64_MOVW_PREL_G1(289), // S+A-P + R_AARCH64_MOVW_PREL_G1_NC(290), // S+A-P + R_AARCH64_MOVW_PREL_G2(291), // S+A-P + R_AARCH64_MOVW_PREL_G2_NC(292), // S+A-P + R_AARCH64_MOVW_PREL_G3(293), // S+A-P R_AARCH64_LDST128_ABS_LO12_NC(299), // LD/ST128: (S+A) & 0xff0 - R_AARCH64_MOVW_GOTOFF_G0(300), - R_AARCH64_MOVW_GOTOFF_G0_NC(301), - R_AARCH64_MOVW_GOTOFF_G1(302), - R_AARCH64_MOVW_GOTOFF_G1_NC(303), - R_AARCH64_MOVW_GOTOFF_G2(304), - R_AARCH64_MOVW_GOTOFF_G2_NC(305), - R_AARCH64_MOVW_GOTOFF_G3(306), - R_AARCH64_GOTREL64(307), - R_AARCH64_GOTREL32(308), - R_AARCH64_GOT_LD_PREL19(309), - R_AARCH64_LD64_GOTOFF_LO15(310), - R_AARCH64_ADR_GOT_PAGE(311), - R_AARCH64_LD64_GOT_LO12_NC(312), - R_AARCH64_LD64_GOTPAGE_LO15(313), + R_AARCH64_MOVW_GOTOFF_G0(300), // MOV[NZ]: G(GDAT(S)) -GOT + R_AARCH64_MOVW_GOTOFF_G0_NC(301), // MOVK: G(GDAT(S)) -GOT + R_AARCH64_MOVW_GOTOFF_G1(302), // MOV[NZ]: G(GDAT(S)) -GOT + R_AARCH64_MOVW_GOTOFF_G1_NC(303), // MOVK: G(GDAT(S)) -GOT + R_AARCH64_MOVW_GOTOFF_G2(304), // MOV[NZ]: G(GDAT(S)) -GOT + R_AARCH64_MOVW_GOTOFF_G2_NC(305), // MOVK: G(GDAT(S)) -GOT + R_AARCH64_MOVW_GOTOFF_G3(306), // MOV[NZ]: G(GDAT(S)) -GOT + R_AARCH64_GOTREL64(307), // S+A-GOT + R_AARCH64_GOTREL32(308), // S+A-GOT + R_AARCH64_GOT_LD_PREL19(309), // G(GDAT(S))- P + R_AARCH64_LD64_GOTOFF_LO15(310), // LD/ST: G(GDAT(S))- GOT + R_AARCH64_ADR_GOT_PAGE(311), // ADRP: Page(G(GDAT(S)))-Page(P) + R_AARCH64_LD64_GOT_LO12_NC(312), // LD/ST: G(GDAT(S)) + R_AARCH64_LD64_GOTPAGE_LO15(313), // LD/ST: G(GDAT(S))-Page(GOT) R_AARCH64_TLSGD_ADR_PREL21(512), R_AARCH64_TLSGD_ADR_PAGE21(513), @@ -226,9 +237,9 @@ public enum AARCH64_ElfRelocationType implements ElfRelocationType { R_AARCH64_TLS_DTPMOD64(1028), R_AARCH64_TLS_DTPREL64(1029), R_AARCH64_TLS_TPREL64(1030), - R_AARCH64_TLS_DTPMOD(1028), - R_AARCH64_TLS_DTPREL(1029), - R_AARCH64_TLS_TPREL(1030), + R_AARCH64_TLS_DTPMOD(1028), // aka R_AARCH64_TLS_DTPMOD64 + R_AARCH64_TLS_DTPREL(1029), // aka R_AARCH64_TLS_DTPREL64 + R_AARCH64_TLS_TPREL(1030), // aka R_AARCH64_TLS_TPREL64 R_AARCH64_TLSDESC(1031), R_AARCH64_IRELATIVE(1032); diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationContext.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationContext.java index 9ee63b228e..cc359b73d2 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationContext.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationContext.java @@ -15,31 +15,17 @@ */ package ghidra.app.util.bin.format.elf.relocation; -import java.util.*; +import java.util.Map; -import ghidra.app.util.MemoryBlockUtils; import ghidra.app.util.bin.format.elf.*; -import ghidra.program.model.address.*; -import ghidra.program.model.data.PointerDataType; -import ghidra.program.model.mem.MemoryAccessException; -import ghidra.program.model.mem.MemoryBlock; -import ghidra.util.*; -import ghidra.util.exception.InvalidInputException; -import ghidra.util.exception.NotFoundException; +import ghidra.program.model.address.Address; /** * X86_64_ElfRelocationContext provides ability to generate a * Global Offset Table (GOT) to facilitate GOT related relocations encountered within * object modules. */ -class X86_64_ElfRelocationContext extends ElfRelocationContext { - - private AddressRange allocatedGotLimits; - private Address allocatedGotAddress; - private Address lastAllocatedGotEntryAddress; - private Address nextAllocatedGotEntryAddress; - - private Map gotMap; +class X86_64_ElfRelocationContext extends ElfGotRelocationContext { X86_64_ElfRelocationContext(X86_64_ElfRelocationHandler handler, ElfLoadHelper loadHelper, Map symbolMap) { @@ -47,75 +33,7 @@ class X86_64_ElfRelocationContext extends ElfRelocationContext uniqueSymbolValues = new HashSet<>(); - for (ElfRelocationTable rt : getElfHeader().getRelocationTables()) { - ElfSymbolTable st = rt.getAssociatedSymbolTable(); - if (st == null) { - continue; - } - for (ElfRelocation r : rt.getRelocations()) { - int symbolIndex = r.getSymbolIndex(); - if (!requiresGotEntry(r) || symbolIndex == 0) { - continue; - } - ElfSymbol elfSymbol = st.getSymbol(symbolIndex); - if (elfSymbol == null) { - continue; - } - long symbolValue = getSymbolValue(elfSymbol); - if (!uniqueSymbolValues.add(symbolValue)) { - System.out.println("Duplicate sym value 0x" + Long.toHexString(symbolValue) + - " for " + elfSymbol.getNameAsString()); - } - } - } - return Math.max(8, uniqueSymbolValues.size() * 8); - } - - private boolean requiresGotEntry(ElfRelocation r) { + protected boolean requiresGotEntry(ElfRelocation r) { X86_64_ElfRelocationType type = handler.getRelocationType(r.getType()); if (type == null) { @@ -140,164 +58,4 @@ class X86_64_ElfRelocationContext extends ElfRelocationContext(); - loadHelper.log("Created " + ElfRelocationHandler.GOT_BLOCK_NAME + - " block required for GOT relocation processing"); - return allocatedGotAddress; - } - - loadHelper.log("Failed to allocate GOT block required for relocation processing"); - return null; - } - - /** - * Allocate the next section GOT entry location. If GOT has not been allocated an attempt - * will be made to create one. If allocated gotMap will also be established. - * @return Address of GOT entry or {@link Address#NO_ADDRESS} if unable to allocate. - */ - private Address getNextAllocatedGotEntryAddress() { - if (nextAllocatedGotEntryAddress == null) { - if (allocateGot() == null) { - return Address.NO_ADDRESS; // failed to allocate got - } - } - - Address addr = nextAllocatedGotEntryAddress; - if (addr == Address.NO_ADDRESS) { - return Address.NO_ADDRESS; // insufficient space in got - } - - try { - // verify that entry fits in got - int pointerSize = loadHelper.getProgram().getDefaultPointerSize(); - Address lastAddr = nextAllocatedGotEntryAddress.addNoWrap(pointerSize - 1); - if (allocatedGotLimits.contains(lastAddr)) { - // entry fits in got - update and return entry address - lastAllocatedGotEntryAddress = lastAddr; - nextAllocatedGotEntryAddress = lastAllocatedGotEntryAddress.addNoWrap(1); - if (!allocatedGotLimits.contains(nextAllocatedGotEntryAddress)) { - // allocated got space fully consumed - nextAllocatedGotEntryAddress = Address.NO_ADDRESS; - } - return addr; - } - } - catch (AddressOverflowException e) { - // ignore - } - - // insufficient space in got - fail future allocation attempts - nextAllocatedGotEntryAddress = Address.NO_ADDRESS; - return Address.NO_ADDRESS; - } - - /** - * Get or allocate a GOT entry for the specified symbolValue. - * NOTE: This is restricted to object modules only which do not of a GOT. - * @param elfSymbol ELF symbol - * @return GOT entry address or null if unable to allocate - */ - public Address getGotEntryAddress(ElfSymbol elfSymbol) { - long symbolValue = getSymbolValue(elfSymbol); - Address addr = null; - if (gotMap != null) { - addr = gotMap.get(symbolValue); - } - if (addr == null) { - addr = getNextAllocatedGotEntryAddress(); - if (gotMap != null) { - gotMap.put(symbolValue, addr); - } - } - return addr == Address.NO_ADDRESS ? null : addr; - } - - /** - * Flush the section GOT table to a new %got memory block - */ - private void createGot() { - if (lastAllocatedGotEntryAddress == null) { - return; - } - int size = (int) lastAllocatedGotEntryAddress.subtract(allocatedGotAddress) + 1; - try { - MemoryBlock block = MemoryBlockUtils.createInitializedBlock(program, false, - ElfRelocationHandler.GOT_BLOCK_NAME, allocatedGotAddress, size, - "NOTE: This block is artificial and allows ELF Relocations to work correctly", - "Elf Loader", true, false, false, loadHelper.getLog()); - - // Mark block as an artificial fabrication - block.setArtificial(true); - - DataConverter converter = - program.getMemory().isBigEndian() ? BigEndianDataConverter.INSTANCE - : LittleEndianDataConverter.INSTANCE; - for (long symbolValue : gotMap.keySet()) { - Address addr = gotMap.get(symbolValue); - byte[] bytes = converter.getBytes(symbolValue); // 8-byte pointer value - block.putBytes(addr, bytes); - loadHelper.createData(addr, PointerDataType.dataType); - } - } - catch (MemoryAccessException e) { - String msg = "Failed to create GOT at " + allocatedGotAddress; - loadHelper.log(msg); - Msg.error(this, msg, e); - } - } - - @Override - public void dispose() { - - // Generate the object module GOT table if required - createGot(); - - super.dispose(); - } }