Add zero-value relocation optimization

etc
This commit is contained in:
Garhoogin 2023-05-06 16:41:22 -05:00
parent fbb8bd04f9
commit 988ef820ce
5 changed files with 129 additions and 47 deletions

View File

@ -11,6 +11,9 @@
#define R_ARM_JUMP24 29
#define R_ARM_BASE_ABS 31
#define R_TYPE_MASK 0x7F
#define R_ZERO_VALUE 0x80
#define HOOK_TYPE_AREPL 0 //ARM branch-and-link replacement
#define HOOK_TYPE_ANSUB 1 //ARM branch replacement
#define HOOK_TYPE_TREPL 2 //thumb branch-link-exchange replacement
@ -49,7 +52,7 @@ typedef struct HOOK_TABLE_ENTRY_ {
typedef struct RELOCATION_ENTRY_ {
u32 offset : 24; //offset of relocation
u32 type : 8; //type of relocation
u32 value; //value of relocation
u32 value; //value of relocation (optional)
} RELOCATION_ENTRY;
typedef struct RCM_HEADER_ {
@ -67,14 +70,14 @@ typedef void (*RCM_LOAD_CALLBACK) (u32 imageBase);
typedef void (*RCM_UNLOAD_CALLBACK) (u32 imageBase);
#define HOOK_DATA8(addr,b) ((void *) ((HOOK_TYPE_DATA8 << HOOK_SHIFT) | (u32) (addr))), (void *) b
#define HOOK_DATA16(addr,hw) ((void *) ((HOOK_TYPE_DATA16 << HOOK_SHIFT) | (u32) (addr))), (void *) hw
#define HOOK_DATA32(addr,w) ((void *) ((HOOK_TYPE_DATA32 << HOOK_SHIFT) | (u32) (addr))), (void *) w
#define HOOK_DATA8(addr,b) ((void *) ((HOOK_TYPE_DATA8 << HOOK_SHIFT) + (u32) (addr))), (void *) b
#define HOOK_DATA16(addr,hw) ((void *) ((HOOK_TYPE_DATA16 << HOOK_SHIFT) + (u32) (addr))), (void *) hw
#define HOOK_DATA32(addr,w) ((void *) ((HOOK_TYPE_DATA32 << HOOK_SHIFT) + (u32) (addr))), (void *) w
#define HOOK_LOAD(dest) ((void *) ((HOOK_TYPE_LOAD << HOOK_SHIFT))), (void *) dest
#define HOOK_UNLOAD(dest) ((void *) ((HOOK_TYPE_UNLOAD << HOOK_SHIFT))), (void *) dest
#define HOOK_AREPL(addr,dest) ((void *) ((HOOK_TYPE_AREPL << HOOK_SHIFT) | (u32) (addr))), (void *) dest
#define HOOK_ANSUB(addr,dest) ((void *) ((HOOK_TYPE_ANSUB << HOOK_SHIFT) | (u32) (addr))), (void *) dest
#define HOOK_TREPL(addr,dest) ((void *) ((HOOK_TYPE_TREPL << HOOK_SHIFT) | (u32) (addr))), (void *) dest
#define HOOK_AREPL(addr,dest) ((void *) ((HOOK_TYPE_AREPL << HOOK_SHIFT) + (u32) (addr))), (void *) dest
#define HOOK_ANSUB(addr,dest) ((void *) ((HOOK_TYPE_ANSUB << HOOK_SHIFT) + (u32) (addr))), (void *) dest
#define HOOK_TREPL(addr,dest) ((void *) ((HOOK_TYPE_TREPL << HOOK_SHIFT) + (u32) (addr))), (void *) dest
#define HOOK_TNSUB(addr,dest) HOOK_DATA16(addr, 0xB500), HOOK_TREPL(((u32) (addr)) + 2, dest), HOOK_DATA16(((u32) (addr)) + 6, 0xBD00)
//NCP-like synonyms

Binary file not shown.

View File

@ -61,6 +61,21 @@ public class RCMRelocator {
return getSymType(syms, sym) != null;
}
public static int read32(byte[] b, int offset) {
int b0 = ((int) b[offset + 0]) & 0xFF;
int b1 = ((int) b[offset + 1]) & 0xFF;
int b2 = ((int) b[offset + 2]) & 0xFF;
int b3 = ((int) b[offset + 3]) & 0xFF;
return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
}
public static void write32(byte[] b, int offset, int n) {
b[offset + 0] = (byte) ((n >>> 0) & 0xFF);
b[offset + 1] = (byte) ((n >>> 8) & 0xFF);
b[offset + 2] = (byte) ((n >>> 16) & 0xFF);
b[offset + 3] = (byte) ((n >>> 24) & 0xFF);
}
public static void main(String[] args) {
//read arguments. First RCM name, then relocation output from objdump, then symbol output
//from objdump
@ -115,6 +130,7 @@ public class RCMRelocator {
byte[] rcm = Files.readAllBytes(Paths.get(rcmPath));
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //relocation table
ByteArrayOutputStream thunks = new ByteArrayOutputStream(); //thunks (for ARM->THUMB B)
int nRelocations = 0;
try {
//before relocation output, count the number of times each destination address shows up.
Map<Integer, Integer> refCounts = new HashMap<>();
@ -146,7 +162,39 @@ public class RCMRelocator {
boolean isAbs32 = r.type.equals("R_ARM_ABS32") && !isLocal;
if(!(isThumb && isB) && !(isRelative && isLocal) && !isAbs32) {
if(!(!isLocal && r.value == 0)) { //check external relocations for NULL
//let's get smart, try to arrange this so that we may emit a zero-value
int type = Relocation.relocTypeFromString(r.type, r.local);
int orig;
switch (type) {
case Relocation.R_ARM_BASE_ABS:
case Relocation.R_ARM_ABS32:
//we can add to the data in the file.
orig = read32(rcm, r.offset);
orig += r.value;
write32(rcm, r.offset, orig);
r.value -= r.value;
break;
case Relocation.R_ARM_JUMP24:
case Relocation.R_ARM_CALL:
if (isThumb) break; //unavoidable. Value must exist
orig = read32(rcm, r.offset);
int instr = orig;
//partial relocation; adjust value to 0, don't adjust by base
int offset = (orig & 0x00FFFFFF) << 2;
if ((offset & 0x02000000) != 0) offset -= 0x04000000;
offset = ((offset + r.value) >> 2) & 0x00FFFFFF;
orig = (instr & 0xFF000000) | offset;
write32(rcm, r.offset, orig);
r.value -= r.value;
break;
}
baos.write(r.getBytes()); //write relocation as normal
nRelocations++;
} else {
//external relocation points to NULL
//probably means a symbol was not resolved, throw an error
@ -246,7 +294,7 @@ public class RCMRelocator {
//write relocation data
int ofsReloc = rcm.length;
int szReloc = relocBytes.length >>> 3;
int szReloc = nRelocations;
rcm[4] = (byte) (ofsReloc & 0xFF);
rcm[5] = (byte) ((ofsReloc >>> 8) & 0xFF);
rcm[6] = (byte) (szReloc & 0xFF);
@ -270,6 +318,13 @@ public class RCMRelocator {
class Relocation {
public static final int ZERO_VALUE = 0x80;
public static final int R_ARM_CALL = 28;
public static final int R_ARM_ABS32 = 2;
public static final int R_ARM_JUMP24 = 29;
public static final int R_ARM_BASE_ABS = 31;
public static final int R_ARM_V4BX = 40;
public static int relocTypeFromString(String type, boolean local) {
//if local, make the type relative
if(local) {
@ -286,15 +341,15 @@ class Relocation {
switch(type) {
case "R_ARM_CALL":
return 28;
return R_ARM_CALL;
case "R_ARM_ABS32":
return 2;
return R_ARM_ABS32;
case "R_ARM_JUMP24":
return 29;
return R_ARM_JUMP24;
case "R_ARM_V4BX":
return 40;
return R_ARM_V4BX;
case "R_ARM_BASE_ABS":
return 31;
return R_ARM_BASE_ABS;
default:
throw new IllegalStateException("Unknown relocation type " + type);
}
@ -329,8 +384,19 @@ class Relocation {
*/
int w0 = (relocTypeFromString(this.type, this.local) << 24) | this.offset;
int w1 = this.value;
byte[] b;
byte[] b = {
//new zero-value flag: can we optimize?
if (this.value == 0) {
w0 |= (Relocation.ZERO_VALUE << 24);
b = new byte[] {
(byte) (w0 & 0xFF),
(byte) ((w0 >>> 8) & 0xFF),
(byte) ((w0 >>> 16) & 0xFF),
(byte) ((w0 >>> 24) & 0xFF)
};
} else {
b = new byte[] {
(byte) (w0 & 0xFF),
(byte) ((w0 >>> 8) & 0xFF),
(byte) ((w0 >>> 16) & 0xFF),
@ -340,6 +406,8 @@ class Relocation {
(byte) ((w1 >>> 16) & 0xFF),
(byte) ((w1 >>> 24) & 0xFF)
};
}
return b;
}

Binary file not shown.

View File

@ -2,6 +2,11 @@
Revision history:
05/06/2023 Garhoogin:
Add zero-value relocation flag
Allow using external symbols as hook addresses
Removed auxiliary hook entry processing
11/28/2022 Garhoogin:
Add data8 hook type
@ -47,7 +52,7 @@ void LDR_CallLoadCallback(void *pMod) {
int i;
for (i = 0; i < hdr->nHook; i++) {
if(hookTable[i].aux || hookTable[i].type != HOOK_TYPE_LOAD) continue;
if (hookTable[i].type != HOOK_TYPE_LOAD) continue;
RCM_LOAD_CALLBACK callback = (RCM_LOAD_CALLBACK) (hookTable[i].branchDestAddr + base);
callback(base);
}
@ -63,7 +68,7 @@ void LDR_CallUnloadCallback(void *pMod) {
int i;
for (i = 0; i < hdr->nHook; i++) {
if(hookTable[i].aux || hookTable[i].type != HOOK_TYPE_UNLOAD) continue;
if (hookTable[i].type != HOOK_TYPE_UNLOAD) continue;
RCM_UNLOAD_CALLBACK callback = (RCM_UNLOAD_CALLBACK) (hookTable[i].branchDestAddr + base);
callback(base);
}
@ -80,12 +85,14 @@ void LDR_Relocate(void *pMod) {
u16 relocOffset = hdr->relocOffset;
u16 nReloc = hdr->relocSize;
u16 i;
RELOCATION_ENTRY *relocs = (RELOCATION_ENTRY *) (base + relocOffset);
RELOCATION_ENTRY *entry = (RELOCATION_ENTRY *) (base + relocOffset);
for (i = 0; i < nReloc; i++) {
RELOCATION_ENTRY *entry = relocs + i;
int type = entry->type & R_TYPE_MASK;
u32 destAddr = base + entry->offset;
u32 value = entry->value;
int type = entry->type;
u32 value = 0;
if (!(entry->type & R_ZERO_VALUE)) {
value = entry->value;
}
switch (type) {
case R_ARM_ABS32:
@ -115,6 +122,13 @@ void LDR_Relocate(void *pMod) {
*(u32 *) destAddr += value + base;
break;
}
//next relocation. Advance whole relocation for nonzero value
if (entry->type & R_ZERO_VALUE) {
entry = (RELOCATION_ENTRY *) &entry->value;
} else {
entry++;
}
}
}
@ -132,8 +146,6 @@ void LDR_LoadModule(void *pMod) {
//iterate through the hooks and insert patches
HOOK_TABLE_ENTRY *hookTable = hdr->hookTable;
for (i = 0; i < nHook; i++) {
if(hookTable[i].aux) continue;
u32 hookType = hookTable[i].type;
u32 hookDest = hookTable[i].branchDestAddr;
u32 hookSrc = hookTable[i].branchSrcAddr;
@ -199,7 +211,6 @@ void LDR_UnloadModule(void *pMod) {
HOOK_TABLE_ENTRY *hookTable = hdr->hookTable;
for (i = nHook; i >= 0; i--) {
if(hookTable[i].aux) continue;
u16 *patchLocation = (u16 *) (u32) hookTable[i].branchSrcAddr;
int type = hookTable[i].type;