mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-28 15:25:35 +08:00
GP-2748 added calling convention for elf entry point
This commit is contained in:
@@ -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 -->
|
||||||
|
|||||||
Reference in New Issue
Block a user