GP-2748 added calling convention for elf entry point

This commit is contained in:
James
2023-04-03 15:35:27 +00:00
parent c324e0cd48
commit 6258dd9eee
6 changed files with 140 additions and 27 deletions
@@ -15,12 +15,11 @@
*/ */
package ghidra.app.util.opinion; package ghidra.app.util.opinion;
import java.util.*;
import java.io.*; import java.io.*;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.file.AccessMode; import java.nio.file.AccessMode;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.*;
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream; import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -61,6 +60,7 @@ import utilities.util.FileUtilities;
class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper { class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
public static final String BLOCK_SOURCE_NAME = "Elf Loader"; public static final String BLOCK_SOURCE_NAME = "Elf Loader";
public static final String PROCESS_ENTRY_CALLING_CONVENTION_NAME = "processEntry";
private static final String SEGMENT_NAME_PREFIX = "segment_"; private static final String SEGMENT_NAME_PREFIX = "segment_";
private static final String UNALLOCATED_NAME_PREFIX = "unallocated_"; private static final String UNALLOCATED_NAME_PREFIX = "unallocated_";
@@ -198,8 +198,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
} }
} }
private void createFileBytes(ByteProvider byteProvider, private void createFileBytes(ByteProvider byteProvider, TaskMonitor monitor)
TaskMonitor monitor) throws IOException, CancelledException { throws IOException, CancelledException {
monitor.setMessage("Loading FileBytes..."); monitor.setMessage("Loading FileBytes...");
try (InputStream fileIn = byteProvider.getInputStream(0); try (InputStream fileIn = byteProvider.getInputStream(0);
MonitoredInputStream mis = new MonitoredInputStream(fileIn, monitor)) { MonitoredInputStream mis = new MonitoredInputStream(fileIn, monitor)) {
@@ -212,8 +212,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
} }
private void adjustSegmentAndSectionFileAllocations(ByteProvider byteProvider, private void adjustSegmentAndSectionFileAllocations(ByteProvider byteProvider,
TaskMonitor monitor) TaskMonitor monitor) throws IOException, CancelledException {
throws IOException, CancelledException {
// Identify file ranges not allocated to segments or sections // Identify file ranges not allocated to segments or sections
RangeMap fileMap = new RangeMap(); RangeMap fileMap = new RangeMap();
@@ -287,8 +286,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
String name = UNALLOCATED_NAME_PREFIX + unallocatedIndex++; String name = UNALLOCATED_NAME_PREFIX + unallocatedIndex++;
try { try {
addInitializedMemorySection(null, start, length, addInitializedMemorySection(null, start, length,
AddressSpace.OTHER_SPACE.getMinAddress(), AddressSpace.OTHER_SPACE.getMinAddress(), name, false, false, false, null,
name, false, false, false, null, false, false); false, false);
} }
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
// ignore // ignore
@@ -670,11 +669,25 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
monitor.setMessage("Creating entry points..."); monitor.setMessage("Creating entry points...");
long entry = elf.e_entry(); // already adjusted for pre-link long entry = elf.e_entry(); // already adjusted for pre-link
if (entry != 0) { if (entry != 0 && (elf.isExecutable() || elf.isSharedObject())) {
Address entryAddr = Address entryAddr =
createEntryFunction(ElfLoader.ELF_ENTRY_FUNCTION_NAME, entry, monitor); createEntryFunction(ElfLoader.ELF_ENTRY_FUNCTION_NAME, entry, monitor);
if (entryAddr != null) { if (entryAddr != null) {
addElfHeaderReferenceMarkup(elf.getEntryComponentOrdinal(), entryAddr); addElfHeaderReferenceMarkup(elf.getEntryComponentOrdinal(), entryAddr);
Function entryFunc = program.getFunctionManager().getFunctionAt(entryAddr);
//note: ElfConstants.ELFOSABI_NONE is used when the are no os/abi-specific
//elf extensions, i.e., plain vanilla elf.
//note: this value can also represent "unspecified"
if (entryFunc != null && (elf.e_ident_osabi() == ElfConstants.ELFOSABI_LINUX ||
elf.e_ident_osabi() == ElfConstants.ELFOSABI_NONE)) {
try {
entryFunc.setCallingConvention(PROCESS_ENTRY_CALLING_CONVENTION_NAME);
}
catch (InvalidInputException e) {
//calling convention for process entry not defined in the appropriate cspec
//just skip
}
}
} }
} }
@@ -929,7 +942,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
} }
processRelocationTableEntries(relocationTable, context, relocationSpace, baseOffset, processRelocationTableEntries(relocationTable, context, relocationSpace, baseOffset,
monitor); monitor);
} }
private void processRelocationTableEntries(ElfRelocationTable relocationTable, private void processRelocationTableEntries(ElfRelocationTable relocationTable,
@@ -1520,7 +1533,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
symbolTables.addAll(List.of(elf.getSymbolTables())); symbolTables.addAll(List.of(elf.getSymbolTables()));
symbolTables.addAll(getGnuDebugDataSymbolTables(monitor)); symbolTables.addAll(getGnuDebugDataSymbolTables(monitor));
int totalCount = 0; int totalCount = 0;
for (ElfSymbolTable elfSymbolTable : symbolTables) { for (ElfSymbolTable elfSymbolTable : symbolTables) {
totalCount += elfSymbolTable.getSymbolCount(); totalCount += elfSymbolTable.getSymbolCount();
@@ -1769,8 +1781,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
// Unable to place symbol within relocatable if section missing/stripped // Unable to place symbol within relocatable if section missing/stripped
else if (elf.isRelocatable()) { else if (elf.isRelocatable()) {
log("No Memory for symbol: " + elfSymbol.getFormattedName() + log("No Memory for symbol: " + elfSymbol.getFormattedName() + " - 0x" +
" - 0x" + Long.toHexString(elfSymbol.getValue())); Long.toHexString(elfSymbol.getValue()));
return null; return null;
} }
@@ -1808,8 +1820,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
// SHN_HIPROC 0xff1f // SHN_HIPROC 0xff1f
// SHN_HIRESERVE 0xffff // SHN_HIRESERVE 0xffff
log("Unable to place symbol: " + elfSymbol.getFormattedName() + log("Unable to place symbol: " + elfSymbol.getFormattedName() + " - value=0x" +
" - value=0x" + Long.toHexString(elfSymbol.getValue()) + ", section-index=0x" + Long.toHexString(elfSymbol.getValue()) + ", section-index=0x" +
Integer.toHexString(Short.toUnsignedInt(sectionIndex))); Integer.toHexString(Short.toUnsignedInt(sectionIndex)));
return null; return null;
} }
@@ -2043,8 +2055,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
// Do not add constant symbols to program symbol table // Do not add constant symbols to program symbol table
// define as equate instead // define as equate instead
try { try {
program.getEquateTable() program.getEquateTable().createEquate(name, address.getOffset());
.createEquate(name, address.getOffset());
} }
catch (DuplicateNameException | InvalidInputException e) { catch (DuplicateNameException | InvalidInputException e) {
// ignore // ignore
@@ -2192,8 +2203,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
memory.convertToInitialized(block, (byte) 0); memory.convertToInitialized(block, (byte) 0);
} }
if (program.getDefaultPointerSize() != (elf.is64Bit() ? 8 : 4)) { if (program.getDefaultPointerSize() != (elf.is64Bit() ? 8 : 4)) {
log( log("Unsupported pointer size for indirect linkage at: " + indirectPointerAddr);
"Unsupported pointer size for indirect linkage at: " + indirectPointerAddr);
return null; return null;
} }
if (elf.is64Bit()) { if (elf.is64Bit()) {
@@ -2535,7 +2545,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
// ElfW(Addr) bitmask[maskwords]; // 2 bit Bloom filter on hashval // ElfW(Addr) bitmask[maskwords]; // 2 bit Bloom filter on hashval
addr = addr.add(d.getLength()); addr = addr.add(d.getLength());
DataType bloomDataType = elf.is64Bit() ? QWordDataType.dataType : DWordDataType.dataType; DataType bloomDataType =
elf.is64Bit() ? QWordDataType.dataType : DWordDataType.dataType;
d = listing.createData(addr, d = listing.createData(addr,
new ArrayDataType(bloomDataType, (int) maskwords, bloomDataType.getLength())); new ArrayDataType(bloomDataType, (int) maskwords, bloomDataType.getLength()));
d.setComment(CodeUnit.EOL_COMMENT, "GNU XHash Table - bitmask"); d.setComment(CodeUnit.EOL_COMMENT, "GNU XHash Table - bitmask");
@@ -3050,8 +3061,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
// Create new zeroed segment block with no bytes from file // Create new zeroed segment block with no bytes from file
String blockName = String.format("%s%d", SEGMENT_NAME_PREFIX, i); String blockName = String.format("%s%d", SEGMENT_NAME_PREFIX, i);
MemoryBlock newBlock = memory.createInitializedBlock(blockName, expandStart, MemoryBlock newBlock = memory.createInitializedBlock(blockName, expandStart,
expandSize, (byte) 0, expandSize, (byte) 0, monitor, false);
monitor, false);
newBlock.setSourceName(BLOCK_SOURCE_NAME); newBlock.setSourceName(BLOCK_SOURCE_NAME);
newBlock.setComment("Zero-initialized segment"); newBlock.setComment("Zero-initialized segment");
} }
@@ -3267,9 +3277,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
throw new AssertException("unexpected", e); throw new AssertException("unexpected", e);
} }
} }
Symbol gotSym = Symbol gotSym = SymbolUtilities.getLabelOrFunctionSymbol(program,
SymbolUtilities.getLabelOrFunctionSymbol(program, ElfConstants.GOT_SYMBOL_NAME, ElfConstants.GOT_SYMBOL_NAME, err -> log(err));
err -> log(err));
if (gotSym != null) { if (gotSym != null) {
return gotSym.getAddress().getAddressableWordOffset(); return gotSym.getAddress().getAddressableWordOffset();
} }
@@ -3645,8 +3654,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
finally { finally {
if (block == null) { if (block == null) {
Address end = start.addNoWrap(revisedLength - 1); Address end = start.addNoWrap(revisedLength - 1);
log("Unexpected ELF memory bock load conflict when creating '" + name + log("Unexpected ELF memory bock load conflict when creating '" + name + "' at " +
"' at " + start.toString(true) + "-" + end.toString(true)); start.toString(true) + "-" + end.toString(true));
} }
} }
return block; return block;
@@ -117,6 +117,24 @@
</killedbycall> </killedbycall>
</prototype> </prototype>
</default_proto> </default_proto>
<prototype name="processEntry" extrapop="0" stackshift="0">
<input pointermax="4">
<pentry minsize="1" maxsize="4">
<register name="r0"/>
</pentry>
<pentry minsize="1" maxsize="500" align="4">
<addr offset="0" space="stack"/>
</pentry>
</input>
<output killedbycall="true">
<pentry minsize="1" maxsize="4">
<register name="r0"/>
</pentry>
</output>
<unaffected>
<register name="sp"/>
</unaffected>
</prototype>
<callfixup name="switch8_r3"> <callfixup name="switch8_r3">
<target name="switch8_r3"/> <target name="switch8_r3"/>
@@ -84,5 +84,24 @@
</localrange> </localrange>
</prototype> </prototype>
</default_proto> </default_proto>
<prototype name="processEntry" extrapop="0" stackshift="0">
<input pointermax="4">
<pentry minsize="1" maxsize="4">
<register name="v0"/>
</pentry>
<pentry minsize="1" maxsize="500" align="4">
<addr offset="0" space="stack"/>
</pentry>
</input>
<output killedbycall="true">
<pentry minsize="1" maxsize="4">
<register name="v0"/>
</pentry>
</output>
<unaffected>
<register name="sp"/>
</unaffected>
</prototype>
</compiler_spec> </compiler_spec>
@@ -84,5 +84,23 @@
</localrange> </localrange>
</prototype> </prototype>
</default_proto> </default_proto>
<prototype name="processEntry" extrapop="0" stackshift="0">
<input pointermax="4">
<pentry minsize="1" maxsize="4">
<register name="v0"/>
</pentry>
<pentry minsize="1" maxsize="500" align="4">
<addr offset="0" space="stack"/>
</pentry>
</input>
<output killedbycall="true">
<pentry minsize="1" maxsize="4">
<register name="v0"/>
</pentry>
</output>
<unaffected>
<register name="sp"/>
</unaffected>
</prototype>
</compiler_spec> </compiler_spec>
@@ -215,4 +215,28 @@
<register name="R11"/> <register name="R11"/>
</killedbycall> </killedbycall>
</prototype> </prototype>
<prototype name="processEntry" extrapop="0" stackshift="0">
<input pointermax="8">
<pentry minsize="1" maxsize="8">
<register name="RDX"/>
</pentry>
<pentry minsize="1" maxsize="500" align="8">
<addr offset="0" space="stack"/>
</pentry>
</input>
<output killedbycall="true">
<pentry minsize="1" maxsize="8">
<register name="RAX"/>
</pentry>
</output>
<unaffected>
<register name="RSP"/>
</unaffected>
<!-- Functions with this prototype don't have a return address. But, if we don't specify one, this prototype will
use the default, which is to have the return address on the stack. That conflicts with how this prototype actually
uses the stack, so we set a fake return address at a RBP, which is unspecified at process entry -->
<returnaddress>
<register name="RBP"/>
</returnaddress>
</prototype>
</compiler_spec> </compiler_spec>
@@ -286,6 +286,31 @@
<register name="EAX"/> <register name="EAX"/>
</killedbycall> </killedbycall>
</prototype> </prototype>
<prototype name="processEntry" extrapop="0" stackshift="0">
<input pointermax="4">
<pentry minsize="1" maxsize="4">
<register name="EDX"/>
</pentry>
<pentry minsize="1" maxsize="500" align="4">
<addr offset="0" space="stack"/>
</pentry>
</input>
<output killedbycall="true">
<pentry minsize="1" maxsize="4">
<register name="EAX"/>
</pentry>
</output>
<unaffected>
<register name="ESP"/>
</unaffected>
<!-- Functions with this prototype don't have a return address. But, if we don't specify one, this prototype will
use the default, which is to have the return address on the stack. That conflicts with how this prototype actually
uses the stack, so we set a fake return address at a EBP, which is unspecified at process entry -->
<returnaddress>
<register name="EBP"/>
</returnaddress>
</prototype>
<resolveprototype name="__cdecl/__regparm"> <resolveprototype name="__cdecl/__regparm">
<model name="__cdecl"/> <!-- The default case --> <model name="__cdecl"/> <!-- The default case -->