mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 01:39:21 +02:00
GP-5815 Added ELF Loader GOT allocation support for AARCH64 in support
of object module loading.
This commit is contained in:
parent
8c56fc8e04
commit
438725bafd
5 changed files with 473 additions and 290 deletions
|
@ -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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>ElfGotRelocationContext</code> provides ability to generate a
|
||||||
|
* Global Offset Table (GOT) to facilitate GOT related relocations encountered within
|
||||||
|
* object modules.
|
||||||
|
* <P>
|
||||||
|
* NOTE: This should be considered experimental and has its limitations with GOT size and
|
||||||
|
* placement which could behave improperly for large binaries.
|
||||||
|
*
|
||||||
|
* @param <H> ELF relocation handler class
|
||||||
|
*/
|
||||||
|
public abstract class ElfGotRelocationContext<H extends ElfRelocationHandler>
|
||||||
|
extends ElfRelocationContext<H> {
|
||||||
|
|
||||||
|
private AddressRange allocatedGotLimits;
|
||||||
|
private Address allocatedGotAddress;
|
||||||
|
private Address lastAllocatedGotEntryAddress;
|
||||||
|
private Address nextAllocatedGotEntryAddress;
|
||||||
|
|
||||||
|
private Map<Long, Address> gotMap;
|
||||||
|
|
||||||
|
ElfGotRelocationContext(H handler, ElfLoadHelper loadHelper,
|
||||||
|
Map<ElfSymbol, Address> 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<Long> 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.}
|
||||||
|
* <P>
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>AARCH64_ElfRelocationContext</code> provides ability to generate a
|
||||||
|
* Global Offset Table (GOT) to facilitate GOT related relocations encountered within
|
||||||
|
* object modules.
|
||||||
|
*/
|
||||||
|
class AARCH64_ElfRelocationContext extends ElfGotRelocationContext<AARCH64_ElfRelocationHandler> {
|
||||||
|
|
||||||
|
AARCH64_ElfRelocationContext(AARCH64_ElfRelocationHandler handler, ElfLoadHelper loadHelper,
|
||||||
|
Map<ElfSymbol, Address> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.elf.relocation;
|
package ghidra.app.util.bin.format.elf.relocation;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.elf.*;
|
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.Relocation.Status;
|
||||||
import ghidra.program.model.reloc.RelocationResult;
|
import ghidra.program.model.reloc.RelocationResult;
|
||||||
|
|
||||||
public class AARCH64_ElfRelocationHandler
|
public class AARCH64_ElfRelocationHandler extends
|
||||||
extends AbstractElfRelocationHandler<AARCH64_ElfRelocationType, ElfRelocationContext<?>> {
|
AbstractElfRelocationHandler<AARCH64_ElfRelocationType, AARCH64_ElfRelocationContext> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -46,11 +48,17 @@ public class AARCH64_ElfRelocationHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected RelocationResult relocate(ElfRelocationContext<?> elfRelocationContext,
|
public AARCH64_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
|
||||||
|
Map<ElfSymbol, Address> symbolMap) {
|
||||||
|
return new AARCH64_ElfRelocationContext(this, loadHelper, symbolMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RelocationResult relocate(AARCH64_ElfRelocationContext elfRelocationContext,
|
||||||
ElfRelocation relocation, AARCH64_ElfRelocationType type, Address relocationAddress,
|
ElfRelocation relocation, AARCH64_ElfRelocationType type, Address relocationAddress,
|
||||||
ElfSymbol sym, Address symbolAddr, long symbolValue, String symbolName)
|
ElfSymbol sym, Address symbolAddr, long symbolValue, String symbolName)
|
||||||
throws MemoryAccessException {
|
throws MemoryAccessException {
|
||||||
|
|
||||||
Program program = elfRelocationContext.getProgram();
|
Program program = elfRelocationContext.getProgram();
|
||||||
Memory memory = program.getMemory();
|
Memory memory = program.getMemory();
|
||||||
boolean isBigEndianInstructions =
|
boolean isBigEndianInstructions =
|
||||||
|
@ -58,13 +66,13 @@ public class AARCH64_ElfRelocationHandler
|
||||||
|
|
||||||
long addend = relocation.getAddend(); // will be 0 for REL case
|
long addend = relocation.getAddend(); // will be 0 for REL case
|
||||||
long offset = relocationAddress.getOffset();
|
long offset = relocationAddress.getOffset();
|
||||||
|
|
||||||
int symbolIndex = relocation.getSymbolIndex();
|
int symbolIndex = relocation.getSymbolIndex();
|
||||||
boolean is64bit = true;
|
boolean is64bit = true;
|
||||||
boolean overflowCheck = true; // *_NC type relocations specify "no overflow check"
|
boolean overflowCheck = true; // *_NC type relocations specify "no overflow check"
|
||||||
long newValue = 0;
|
long newValue = 0;
|
||||||
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
int byteLength = 4; // most relocations affect 4-bytes (change if different)
|
||||||
|
|
||||||
// Handle relative relocations that do not require symbolAddr or symbolValue
|
// Handle relative relocations that do not require symbolAddr or symbolValue
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case R_AARCH64_P32_RELATIVE:
|
case R_AARCH64_P32_RELATIVE:
|
||||||
|
@ -84,7 +92,7 @@ public class AARCH64_ElfRelocationHandler
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for unresolved symbolAddr and symbolValue required by remaining relocation types handled below
|
// Check for unresolved symbolAddr and symbolValue required by remaining relocation types handled below
|
||||||
if (handleUnresolvedSymbol(elfRelocationContext, relocation, relocationAddress)) {
|
if (handleUnresolvedSymbol(elfRelocationContext, relocation, relocationAddress)) {
|
||||||
return RelocationResult.FAILURE;
|
return RelocationResult.FAILURE;
|
||||||
|
@ -308,8 +316,7 @@ public class AARCH64_ElfRelocationHandler
|
||||||
|
|
||||||
// LD/ST64: (S+A) & 0xff8
|
// LD/ST64: (S+A) & 0xff8
|
||||||
case R_AARCH64_LDST64_ABS_LO12_NC:
|
case R_AARCH64_LDST64_ABS_LO12_NC:
|
||||||
case R_AARCH64_P32_LDST64_ABS_LO12_NC:
|
case R_AARCH64_P32_LDST64_ABS_LO12_NC: {
|
||||||
case R_AARCH64_LD64_GOT_LO12_NC: {
|
|
||||||
int oldValue = memory.getInt(relocationAddress, isBigEndianInstructions);
|
int oldValue = memory.getInt(relocationAddress, isBigEndianInstructions);
|
||||||
newValue = (int) ((symbolValue + addend) & 0xff8) >> 3;
|
newValue = (int) ((symbolValue + addend) & 0xff8) >> 3;
|
||||||
|
|
||||||
|
@ -330,6 +337,53 @@ public class AARCH64_ElfRelocationHandler
|
||||||
break;
|
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:
|
case R_AARCH64_P32_GLOB_DAT:
|
||||||
is64bit = false;
|
is64bit = false;
|
||||||
case R_AARCH64_GLOB_DAT: {
|
case R_AARCH64_GLOB_DAT: {
|
||||||
|
@ -379,6 +433,10 @@ public class AARCH64_ElfRelocationHandler
|
||||||
return new RelocationResult(Status.APPLIED, byteLength);
|
return new RelocationResult(Status.APPLIED, byteLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long page(long offset) {
|
||||||
|
return offset & ~0xfff;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the new value in memory
|
* Set the new value in memory
|
||||||
* @param memory memory
|
* @param memory memory
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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 {
|
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_NONE(0),
|
||||||
R_AARCH64_P32_ABS32(1), // .word: (S+A)
|
R_AARCH64_P32_ABS32(1), // .word: (S+A)
|
||||||
R_AARCH64_P32_ABS16(2), // .half: (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_JUMP26(20), // B: ((S+A-P) >> 2) & 0x3ffffff.
|
||||||
R_AARCH64_P32_CALL26(21), // BL: ((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_GOT_LD_PREL19(25), // G(GDAT(S))- P
|
||||||
R_AARCH64_P32_ADR_GOT_PAGE(26),
|
R_AARCH64_P32_ADR_GOT_PAGE(26), // ADRP: Page(G(GDAT(S)))-Page(P)
|
||||||
R_AARCH64_P32_LD32_GOT_LO12_NC(27),
|
R_AARCH64_P32_LD32_GOT_LO12_NC(27), // LD/ST: G(GDAT(S))
|
||||||
R_AARCH64_P32_LD32_GOTPAGE_LO14(28),
|
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_PREL21(80),
|
||||||
R_AARCH64_P32_TLSGD_ADR_PAGE21(81),
|
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_ADD_LO12_NC(126),
|
||||||
R_AARCH64_P32_TLSDESC_CALL(127),
|
R_AARCH64_P32_TLSDESC_CALL(127),
|
||||||
|
|
||||||
R_AARCH64_P32_COPY(180), // Copy symbol at runtime.
|
R_AARCH64_P32_COPY(180), // Copy symbol value at runtime.
|
||||||
R_AARCH64_P32_GLOB_DAT(181), // Create GOT entry.
|
R_AARCH64_P32_GLOB_DAT(181), // Relocate GOT entry.
|
||||||
R_AARCH64_P32_JUMP_SLOT(182), // Create PLT entry.
|
R_AARCH64_P32_JUMP_SLOT(182), // Relocate PLT entry.
|
||||||
|
|
||||||
// Adjust by program base.
|
// Adjust by program base.
|
||||||
R_AARCH64_P32_RELATIVE(183),
|
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_LDST16_ABS_LO12_NC(284), // LD/ST16: (S+A) & 0xffe
|
||||||
R_AARCH64_LDST32_ABS_LO12_NC(285), // LD/ST32: (S+A) & 0xffc
|
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_LDST64_ABS_LO12_NC(286), // LD/ST64: (S+A) & 0xff8
|
||||||
R_AARCH64_MOVW_PREL_G0(287),
|
R_AARCH64_MOVW_PREL_G0(287), // S+A-P
|
||||||
R_AARCH64_MOVW_PREL_G0_NC(288),
|
R_AARCH64_MOVW_PREL_G0_NC(288), // S+A-P
|
||||||
R_AARCH64_MOVW_PREL_G1(289),
|
R_AARCH64_MOVW_PREL_G1(289), // S+A-P
|
||||||
R_AARCH64_MOVW_PREL_G1_NC(290),
|
R_AARCH64_MOVW_PREL_G1_NC(290), // S+A-P
|
||||||
R_AARCH64_MOVW_PREL_G2(291),
|
R_AARCH64_MOVW_PREL_G2(291), // S+A-P
|
||||||
R_AARCH64_MOVW_PREL_G2_NC(292),
|
R_AARCH64_MOVW_PREL_G2_NC(292), // S+A-P
|
||||||
R_AARCH64_MOVW_PREL_G3(293),
|
R_AARCH64_MOVW_PREL_G3(293), // S+A-P
|
||||||
R_AARCH64_LDST128_ABS_LO12_NC(299), // LD/ST128: (S+A) & 0xff0
|
R_AARCH64_LDST128_ABS_LO12_NC(299), // LD/ST128: (S+A) & 0xff0
|
||||||
R_AARCH64_MOVW_GOTOFF_G0(300),
|
R_AARCH64_MOVW_GOTOFF_G0(300), // MOV[NZ]: G(GDAT(S)) -GOT
|
||||||
R_AARCH64_MOVW_GOTOFF_G0_NC(301),
|
R_AARCH64_MOVW_GOTOFF_G0_NC(301), // MOVK: G(GDAT(S)) -GOT
|
||||||
R_AARCH64_MOVW_GOTOFF_G1(302),
|
R_AARCH64_MOVW_GOTOFF_G1(302), // MOV[NZ]: G(GDAT(S)) -GOT
|
||||||
R_AARCH64_MOVW_GOTOFF_G1_NC(303),
|
R_AARCH64_MOVW_GOTOFF_G1_NC(303), // MOVK: G(GDAT(S)) -GOT
|
||||||
R_AARCH64_MOVW_GOTOFF_G2(304),
|
R_AARCH64_MOVW_GOTOFF_G2(304), // MOV[NZ]: G(GDAT(S)) -GOT
|
||||||
R_AARCH64_MOVW_GOTOFF_G2_NC(305),
|
R_AARCH64_MOVW_GOTOFF_G2_NC(305), // MOVK: G(GDAT(S)) -GOT
|
||||||
R_AARCH64_MOVW_GOTOFF_G3(306),
|
R_AARCH64_MOVW_GOTOFF_G3(306), // MOV[NZ]: G(GDAT(S)) -GOT
|
||||||
R_AARCH64_GOTREL64(307),
|
R_AARCH64_GOTREL64(307), // S+A-GOT
|
||||||
R_AARCH64_GOTREL32(308),
|
R_AARCH64_GOTREL32(308), // S+A-GOT
|
||||||
R_AARCH64_GOT_LD_PREL19(309),
|
R_AARCH64_GOT_LD_PREL19(309), // G(GDAT(S))- P
|
||||||
R_AARCH64_LD64_GOTOFF_LO15(310),
|
R_AARCH64_LD64_GOTOFF_LO15(310), // LD/ST: G(GDAT(S))- GOT
|
||||||
R_AARCH64_ADR_GOT_PAGE(311),
|
R_AARCH64_ADR_GOT_PAGE(311), // ADRP: Page(G(GDAT(S)))-Page(P)
|
||||||
R_AARCH64_LD64_GOT_LO12_NC(312),
|
R_AARCH64_LD64_GOT_LO12_NC(312), // LD/ST: G(GDAT(S))
|
||||||
R_AARCH64_LD64_GOTPAGE_LO15(313),
|
R_AARCH64_LD64_GOTPAGE_LO15(313), // LD/ST: G(GDAT(S))-Page(GOT)
|
||||||
|
|
||||||
R_AARCH64_TLSGD_ADR_PREL21(512),
|
R_AARCH64_TLSGD_ADR_PREL21(512),
|
||||||
R_AARCH64_TLSGD_ADR_PAGE21(513),
|
R_AARCH64_TLSGD_ADR_PAGE21(513),
|
||||||
|
@ -226,9 +237,9 @@ public enum AARCH64_ElfRelocationType implements ElfRelocationType {
|
||||||
R_AARCH64_TLS_DTPMOD64(1028),
|
R_AARCH64_TLS_DTPMOD64(1028),
|
||||||
R_AARCH64_TLS_DTPREL64(1029),
|
R_AARCH64_TLS_DTPREL64(1029),
|
||||||
R_AARCH64_TLS_TPREL64(1030),
|
R_AARCH64_TLS_TPREL64(1030),
|
||||||
R_AARCH64_TLS_DTPMOD(1028),
|
R_AARCH64_TLS_DTPMOD(1028), // aka R_AARCH64_TLS_DTPMOD64
|
||||||
R_AARCH64_TLS_DTPREL(1029),
|
R_AARCH64_TLS_DTPREL(1029), // aka R_AARCH64_TLS_DTPREL64
|
||||||
R_AARCH64_TLS_TPREL(1030),
|
R_AARCH64_TLS_TPREL(1030), // aka R_AARCH64_TLS_TPREL64
|
||||||
R_AARCH64_TLSDESC(1031),
|
R_AARCH64_TLSDESC(1031),
|
||||||
R_AARCH64_IRELATIVE(1032);
|
R_AARCH64_IRELATIVE(1032);
|
||||||
|
|
||||||
|
|
|
@ -15,31 +15,17 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.bin.format.elf.relocation;
|
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.app.util.bin.format.elf.*;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>X86_64_ElfRelocationContext</code> provides ability to generate a
|
* <code>X86_64_ElfRelocationContext</code> provides ability to generate a
|
||||||
* Global Offset Table (GOT) to facilitate GOT related relocations encountered within
|
* Global Offset Table (GOT) to facilitate GOT related relocations encountered within
|
||||||
* object modules.
|
* object modules.
|
||||||
*/
|
*/
|
||||||
class X86_64_ElfRelocationContext extends ElfRelocationContext<X86_64_ElfRelocationHandler> {
|
class X86_64_ElfRelocationContext extends ElfGotRelocationContext<X86_64_ElfRelocationHandler> {
|
||||||
|
|
||||||
private AddressRange allocatedGotLimits;
|
|
||||||
private Address allocatedGotAddress;
|
|
||||||
private Address lastAllocatedGotEntryAddress;
|
|
||||||
private Address nextAllocatedGotEntryAddress;
|
|
||||||
|
|
||||||
private Map<Long, Address> gotMap;
|
|
||||||
|
|
||||||
X86_64_ElfRelocationContext(X86_64_ElfRelocationHandler handler, ElfLoadHelper loadHelper,
|
X86_64_ElfRelocationContext(X86_64_ElfRelocationHandler handler, ElfLoadHelper loadHelper,
|
||||||
Map<ElfSymbol, Address> symbolMap) {
|
Map<ElfSymbol, Address> symbolMap) {
|
||||||
|
@ -47,75 +33,7 @@ class X86_64_ElfRelocationContext extends ElfRelocationContext<X86_64_ElfRelocat
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getSymbolValue(ElfSymbol symbol) {
|
protected boolean requiresGotEntry(ElfRelocation r) {
|
||||||
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<Long> 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) {
|
|
||||||
|
|
||||||
X86_64_ElfRelocationType type = handler.getRelocationType(r.getType());
|
X86_64_ElfRelocationType type = handler.getRelocationType(r.getType());
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
|
@ -140,164 +58,4 @@ class X86_64_ElfRelocationContext extends ElfRelocationContext<X86_64_ElfRelocat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue