GP-3091 ppc64 ELF improvements for 32-bit addressing. Fixed default ELF

GOT markup boundary condition.  Fixed improper EXTERNAL symbols with
.pltgot. prefix and duplication.
This commit is contained in:
ghidra1
2025-07-21 18:13:24 -04:00
parent 0ddd0d7533
commit 4a0e95ecd3
7 changed files with 375 additions and 176 deletions
@@ -216,9 +216,13 @@ public class ClearFlowAndRepairCmd extends BackgroundCommand<Program> {
monitor.checkCancelled();
Symbol[] syms = symTable.getSymbols(addr);
for (Symbol sym : syms) {
// TODO: GP-5872 This code is suspect - should it be restricted to LABELS only.
// Why would we remove a non-default function that had references?
if (sym.getSource() == SourceType.DEFAULT) {
break;
}
// TODO: GP-5872 If one of many labels at a location has a direct reference why
// would we bail when we may have already removed a few that did not.
if (sym.hasReferences()) {
continue;
}
@@ -718,6 +722,11 @@ public class ClearFlowAndRepairCmd extends BackgroundCommand<Program> {
if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) {
continue; // keep imported or user-defined function
}
// TODO: GP-5872 Clearing thunks explicitly created by loader or pattern
// generally have default SourceType and may not have references
// to them. We need to prevent these thunks from getting cleared.
// PowerPC64 ELF extension was forced to rename thunks it created to
// avoid this where the thunk rename has its own set of issues.
}
if (clearOffcut && !destAddrs.contains(blockAddr)) {
@@ -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.
@@ -167,8 +167,7 @@ public class ElfDefaultGotPltMarkup {
// PLT head is unknown. If the binary has not placed external symbols within the PLT
// processing and disassembly of the PLT may be skipped.
long pltgot = elf.adjustAddressForPrelink(
dynamicTable.getDynamicValue(pltGotType));
long pltgot = elf.adjustAddressForPrelink(dynamicTable.getDynamicValue(pltGotType));
Address gotStart = defaultSpace.getAddress(pltgot + imageBaseAdj);
ElfRelocation[] relocations = relocationTable.getRelocations();
@@ -354,7 +353,7 @@ public class ElfDefaultGotPltMarkup {
* Mark-up all GOT entries as pointers within the memory range gotStart to
* gotEnd.
* @param gotStart address for start of GOT
* @param gotEnd address for end of GOT
* @param gotEnd address for end of GOT (inclusive)
* @param monitor task monitor
* @throws CancelledException thrown if task cancelled
*/
@@ -402,21 +401,17 @@ public class ElfDefaultGotPltMarkup {
try {
int pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize();
long gotSizeRemaining = gotEnd.subtract(gotStart) + 1;
long entryOffset = 0;
Address newImageBase = null;
Address nextGotAddr = gotStart;
while (gotEnd.subtract(nextGotAddr) >= pointerSize) {
while (gotSizeRemaining >= pointerSize) {
Address nextGotAddr = gotStart.addNoWrap(entryOffset);
data = createPointer(nextGotAddr, true);
if (data == null) {
break;
}
try {
nextGotAddr = data.getMaxAddress().add(1);
}
catch (AddressOutOfBoundsException e) {
break; // no more room
}
gotSizeRemaining -= pointerSize;
entryOffset += pointerSize;
newImageBase = UglyImageBaseCheck(data, newImageBase);
}
if (newImageBase != null) {
@@ -573,12 +568,6 @@ public class ElfDefaultGotPltMarkup {
}
int pointerSize = program.getDataTypeManager().getDataOrganization().getPointerSize();
Pointer pointer = PointerDataType.dataType.clone(program.getDataTypeManager());
if (elf.is32Bit() && pointerSize != 4) {
pointer = Pointer32DataType.dataType;
}
else if (elf.is64Bit() && pointerSize != 8) {
pointer = Pointer64DataType.dataType;
}
Data data = listing.getDataAt(addr);
if (data == null || !pointer.isEquivalent(data.getDataType())) {
if (data != null) {
@@ -623,7 +612,10 @@ public class ElfDefaultGotPltMarkup {
Program program = pointerData.getProgram();
Memory memory = program.getMemory();
Address refAddr = (Address) pointerData.getValue();
if (memory.contains(refAddr)) {
if (refAddr == null) {
return false;
}
else if (memory.contains(refAddr)) {
return true;
}
Symbol primary = program.getSymbolTable().getPrimarySymbol(refAddr);
@@ -20,6 +20,8 @@ import static ghidra.program.util.FunctionChangeRecord.FunctionChangeType.*;
import java.io.IOException;
import java.util.*;
import javax.help.UnsupportedOperationException;
import db.DBRecord;
import ghidra.program.database.*;
import ghidra.program.database.data.DataTypeManagerDB;
@@ -140,6 +142,9 @@ public class FunctionDB extends DatabaseObject implements Function {
@Override
public void setThunkedFunction(Function referencedFunction) {
if (isExternal()) {
throw new UnsupportedOperationException("External functions may not be a thunk");
}
if ((referencedFunction != null) && !(referencedFunction instanceof FunctionDB)) {
throw new IllegalArgumentException("FunctionDB expected for referenced function");
}
@@ -702,6 +702,7 @@ public interface Function extends Namespace {
* @throws IllegalArgumentException if an attempt is made to thunk a function or another
* thunk which would result in a loop back to this function or if this function is an external
* function, or specified function is from a different program instance.
* @throws UnsupportedOperationException if this method is invoked on an external function.
*/
public void setThunkedFunction(Function thunkedFunction) throws IllegalArgumentException;
@@ -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.
@@ -113,6 +113,8 @@ public interface FunctionManager extends ManagerDB {
* @return new function or null if one or more functions overlap the specified body address set.
* @throws OverlappingFunctionException if the address set of the body overlaps an existing
* function
* @throws UnsupportedOperationException if this method is invoked on an external entryPoint
* address.
*/
public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint,
AddressSetView body, Function thunkedFunction, SourceType source)
@@ -25,7 +25,6 @@ import ghidra.program.model.reloc.Relocation.Status;
import ghidra.program.model.reloc.RelocationResult;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolUtilities;
import ghidra.util.*;
public class PowerPC64_ElfRelocationHandler
extends AbstractElfRelocationHandler<PowerPC64_ElfRelocationType, ElfRelocationContext<?>> {
@@ -46,7 +45,7 @@ public class PowerPC64_ElfRelocationHandler
@Override
public boolean canRelocate(ElfHeader elf) {
return elf.e_machine() == ElfConstants.EM_PPC64 && elf.is64Bit();
return elf.e_machine() == ElfConstants.EM_PPC64;
}
@Override
@@ -62,7 +61,7 @@ public class PowerPC64_ElfRelocationHandler
Program program = elfRelocationContext.getProgram();
Memory memory = program.getMemory();
// NOTE: Based upon glibc source it appears that PowerPC only uses RELA relocations
long addend = relocation.getAddend();
long offset = relocationAddress.getOffset();
@@ -98,7 +97,7 @@ public class PowerPC64_ElfRelocationHandler
break;
default:
}
// Handle relative relocations that do not require symbolAddr or symbolValue
switch (type) {
@@ -106,32 +105,32 @@ public class PowerPC64_ElfRelocationHandler
long value64 = elfRelocationContext.getImageBaseWordAdjustmentOffset() + addend;
memory.setLong(relocationAddress, value64);
return new RelocationResult(Status.APPLIED, 8);
case R_PPC64_TOC:
memory.setLong(relocationAddress, toc);
return new RelocationResult(Status.APPLIED, 8);
case R_PPC64_COPY:
markAsUnsupportedCopy(program, relocationAddress, type, symbolName, symbolIndex,
sym.getSize(), elfRelocationContext.getLog());
return RelocationResult.UNSUPPORTED;
default:
break;
}
// Check for unresolved symbolAddr and symbolValue required by remaining relocation types handled below
if (handleUnresolvedSymbol(elfRelocationContext, relocation, relocationAddress)) {
return RelocationResult.FAILURE;
}
}
int oldValue = memory.getInt(relocationAddress);
int newValue = 0;
int byteLength = 4; // most relocations affect 4-bytes (change if different)
switch (type) {
case R_PPC64_ADDR32:
newValue = (int) (symbolValue + addend);
memory.setInt(relocationAddress, newValue);
@@ -194,10 +193,6 @@ public class PowerPC64_ElfRelocationHandler
memory.setInt(relocationAddress, newValue);
break;
case R_PPC64_REL24:
// attempt to handle Object module case where referenced symbol resides within .opd
symbolValue = fixupOPDSymbolValue(elfRelocationContext, sym);
newValue = (int) ((symbolValue + addend - offset) >> 2);
newValue = ((newValue << 2) & PPC64_LOW24);
newValue = (oldValue & ~PPC64_LOW24) | newValue;
@@ -230,7 +225,7 @@ public class PowerPC64_ElfRelocationHandler
}
if (PowerPC64_ElfExtension
.getPpc64ABIVersion(elfRelocationContext.getElfHeader()) == 1) {
.getPpc64ElfABIVersion(elfRelocationContext.getElfHeader()) == 1) {
// ABI ELFv1 (used by big-endian PPC64) expected to copy full function descriptor
// into .got.plt section where symbolAddr refers to function descriptor
// Copy function descriptor data
@@ -273,38 +268,4 @@ public class PowerPC64_ElfRelocationHandler
return new RelocationResult(Status.APPLIED, byteLength);
}
/**
* This method generates a symbol value with possible substitution for those
* symbols residing within the .opd to refer to the real function instead.
* Care must be taken not to invoke this method for relocations which may be
* applied to call stubs. It is also important that relocations have already
* been applied to the .opd section since we will be using its data for
* locating the real function.
* @param elfRelocationContext ELF relocation context
* @param sym ELF relocation symbol
* @return symbol value
* @throws MemoryAccessException if memory access error occurs
*/
private long fixupOPDSymbolValue(ElfRelocationContext<?> elfRelocationContext, ElfSymbol sym)
throws MemoryAccessException {
Address addr = elfRelocationContext.getSymbolAddress(sym);
if (addr == null) {
return 0;
}
Program program = elfRelocationContext.getProgram();
MemoryBlock block = program.getMemory().getBlock(addr);
if (block == null || !".opd".equals(block.getName())) {
return addr.getOffset();
}
// .opd symbols will get moved to the real function by the extension (see processFunctionDescriptors)
// Call stubs should always use the .opd symbol value and not the function address so we can - this
// distinction can only be made using the relocation type.
byte[] bytes = new byte[8];
block.getBytes(addr, bytes);
boolean bigEndian = elfRelocationContext.getElfHeader().isBigEndian();
DataConverter dataConverter =
bigEndian ? BigEndianDataConverter.INSTANCE : LittleEndianDataConverter.INSTANCE;
return dataConverter.getLong(bytes);
}
}