mirror of
https://github.com/Garhoogin/RuntimeCodeModules.git
synced 2025-06-20 17:35:33 -04:00
Add zero-value relocation optimization
etc
This commit is contained in:
parent
fbb8bd04f9
commit
988ef820ce
@ -11,6 +11,9 @@
|
|||||||
#define R_ARM_JUMP24 29
|
#define R_ARM_JUMP24 29
|
||||||
#define R_ARM_BASE_ABS 31
|
#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_AREPL 0 //ARM branch-and-link replacement
|
||||||
#define HOOK_TYPE_ANSUB 1 //ARM branch replacement
|
#define HOOK_TYPE_ANSUB 1 //ARM branch replacement
|
||||||
#define HOOK_TYPE_TREPL 2 //thumb branch-link-exchange replacement
|
#define HOOK_TYPE_TREPL 2 //thumb branch-link-exchange replacement
|
||||||
@ -49,7 +52,7 @@ typedef struct HOOK_TABLE_ENTRY_ {
|
|||||||
typedef struct RELOCATION_ENTRY_ {
|
typedef struct RELOCATION_ENTRY_ {
|
||||||
u32 offset : 24; //offset of relocation
|
u32 offset : 24; //offset of relocation
|
||||||
u32 type : 8; //type of relocation
|
u32 type : 8; //type of relocation
|
||||||
u32 value; //value of relocation
|
u32 value; //value of relocation (optional)
|
||||||
} RELOCATION_ENTRY;
|
} RELOCATION_ENTRY;
|
||||||
|
|
||||||
typedef struct RCM_HEADER_ {
|
typedef struct RCM_HEADER_ {
|
||||||
@ -67,14 +70,14 @@ typedef void (*RCM_LOAD_CALLBACK) (u32 imageBase);
|
|||||||
typedef void (*RCM_UNLOAD_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_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_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_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_LOAD(dest) ((void *) ((HOOK_TYPE_LOAD << HOOK_SHIFT))), (void *) dest
|
||||||
#define HOOK_UNLOAD(dest) ((void *) ((HOOK_TYPE_UNLOAD << 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_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_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_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)
|
#define HOOK_TNSUB(addr,dest) HOOK_DATA16(addr, 0xB500), HOOK_TREPL(((u32) (addr)) + 2, dest), HOOK_DATA16(((u32) (addr)) + 6, 0xBD00)
|
||||||
|
|
||||||
//NCP-like synonyms
|
//NCP-like synonyms
|
||||||
|
Binary file not shown.
@ -61,6 +61,21 @@ public class RCMRelocator {
|
|||||||
return getSymType(syms, sym) != null;
|
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) {
|
public static void main(String[] args) {
|
||||||
//read arguments. First RCM name, then relocation output from objdump, then symbol output
|
//read arguments. First RCM name, then relocation output from objdump, then symbol output
|
||||||
//from objdump
|
//from objdump
|
||||||
@ -115,6 +130,7 @@ public class RCMRelocator {
|
|||||||
byte[] rcm = Files.readAllBytes(Paths.get(rcmPath));
|
byte[] rcm = Files.readAllBytes(Paths.get(rcmPath));
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //relocation table
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //relocation table
|
||||||
ByteArrayOutputStream thunks = new ByteArrayOutputStream(); //thunks (for ARM->THUMB B)
|
ByteArrayOutputStream thunks = new ByteArrayOutputStream(); //thunks (for ARM->THUMB B)
|
||||||
|
int nRelocations = 0;
|
||||||
try {
|
try {
|
||||||
//before relocation output, count the number of times each destination address shows up.
|
//before relocation output, count the number of times each destination address shows up.
|
||||||
Map<Integer, Integer> refCounts = new HashMap<>();
|
Map<Integer, Integer> refCounts = new HashMap<>();
|
||||||
@ -146,7 +162,39 @@ public class RCMRelocator {
|
|||||||
boolean isAbs32 = r.type.equals("R_ARM_ABS32") && !isLocal;
|
boolean isAbs32 = r.type.equals("R_ARM_ABS32") && !isLocal;
|
||||||
if(!(isThumb && isB) && !(isRelative && isLocal) && !isAbs32) {
|
if(!(isThumb && isB) && !(isRelative && isLocal) && !isAbs32) {
|
||||||
if(!(!isLocal && r.value == 0)) { //check external relocations for NULL
|
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
|
baos.write(r.getBytes()); //write relocation as normal
|
||||||
|
nRelocations++;
|
||||||
} else {
|
} else {
|
||||||
//external relocation points to NULL
|
//external relocation points to NULL
|
||||||
//probably means a symbol was not resolved, throw an error
|
//probably means a symbol was not resolved, throw an error
|
||||||
@ -246,7 +294,7 @@ public class RCMRelocator {
|
|||||||
|
|
||||||
//write relocation data
|
//write relocation data
|
||||||
int ofsReloc = rcm.length;
|
int ofsReloc = rcm.length;
|
||||||
int szReloc = relocBytes.length >>> 3;
|
int szReloc = nRelocations;
|
||||||
rcm[4] = (byte) (ofsReloc & 0xFF);
|
rcm[4] = (byte) (ofsReloc & 0xFF);
|
||||||
rcm[5] = (byte) ((ofsReloc >>> 8) & 0xFF);
|
rcm[5] = (byte) ((ofsReloc >>> 8) & 0xFF);
|
||||||
rcm[6] = (byte) (szReloc & 0xFF);
|
rcm[6] = (byte) (szReloc & 0xFF);
|
||||||
@ -270,6 +318,13 @@ public class RCMRelocator {
|
|||||||
|
|
||||||
class Relocation {
|
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) {
|
public static int relocTypeFromString(String type, boolean local) {
|
||||||
//if local, make the type relative
|
//if local, make the type relative
|
||||||
if(local) {
|
if(local) {
|
||||||
@ -286,15 +341,15 @@ class Relocation {
|
|||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case "R_ARM_CALL":
|
case "R_ARM_CALL":
|
||||||
return 28;
|
return R_ARM_CALL;
|
||||||
case "R_ARM_ABS32":
|
case "R_ARM_ABS32":
|
||||||
return 2;
|
return R_ARM_ABS32;
|
||||||
case "R_ARM_JUMP24":
|
case "R_ARM_JUMP24":
|
||||||
return 29;
|
return R_ARM_JUMP24;
|
||||||
case "R_ARM_V4BX":
|
case "R_ARM_V4BX":
|
||||||
return 40;
|
return R_ARM_V4BX;
|
||||||
case "R_ARM_BASE_ABS":
|
case "R_ARM_BASE_ABS":
|
||||||
return 31;
|
return R_ARM_BASE_ABS;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unknown relocation type " + type);
|
throw new IllegalStateException("Unknown relocation type " + type);
|
||||||
}
|
}
|
||||||
@ -329,8 +384,19 @@ class Relocation {
|
|||||||
*/
|
*/
|
||||||
int w0 = (relocTypeFromString(this.type, this.local) << 24) | this.offset;
|
int w0 = (relocTypeFromString(this.type, this.local) << 24) | this.offset;
|
||||||
int w1 = this.value;
|
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 & 0xFF),
|
||||||
(byte) ((w0 >>> 8) & 0xFF),
|
(byte) ((w0 >>> 8) & 0xFF),
|
||||||
(byte) ((w0 >>> 16) & 0xFF),
|
(byte) ((w0 >>> 16) & 0xFF),
|
||||||
@ -340,6 +406,8 @@ class Relocation {
|
|||||||
(byte) ((w1 >>> 16) & 0xFF),
|
(byte) ((w1 >>> 16) & 0xFF),
|
||||||
(byte) ((w1 >>> 24) & 0xFF)
|
(byte) ((w1 >>> 24) & 0xFF)
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
29
source/ldr.c
29
source/ldr.c
@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
Revision history:
|
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:
|
11/28/2022 Garhoogin:
|
||||||
Add data8 hook type
|
Add data8 hook type
|
||||||
|
|
||||||
@ -47,7 +52,7 @@ void LDR_CallLoadCallback(void *pMod) {
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < hdr->nHook; 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);
|
RCM_LOAD_CALLBACK callback = (RCM_LOAD_CALLBACK) (hookTable[i].branchDestAddr + base);
|
||||||
callback(base);
|
callback(base);
|
||||||
}
|
}
|
||||||
@ -63,7 +68,7 @@ void LDR_CallUnloadCallback(void *pMod) {
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < hdr->nHook; 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);
|
RCM_UNLOAD_CALLBACK callback = (RCM_UNLOAD_CALLBACK) (hookTable[i].branchDestAddr + base);
|
||||||
callback(base);
|
callback(base);
|
||||||
}
|
}
|
||||||
@ -80,12 +85,14 @@ void LDR_Relocate(void *pMod) {
|
|||||||
u16 relocOffset = hdr->relocOffset;
|
u16 relocOffset = hdr->relocOffset;
|
||||||
u16 nReloc = hdr->relocSize;
|
u16 nReloc = hdr->relocSize;
|
||||||
u16 i;
|
u16 i;
|
||||||
RELOCATION_ENTRY *relocs = (RELOCATION_ENTRY *) (base + relocOffset);
|
RELOCATION_ENTRY *entry = (RELOCATION_ENTRY *) (base + relocOffset);
|
||||||
for (i = 0; i < nReloc; i++) {
|
for (i = 0; i < nReloc; i++) {
|
||||||
RELOCATION_ENTRY *entry = relocs + i;
|
int type = entry->type & R_TYPE_MASK;
|
||||||
u32 destAddr = base + entry->offset;
|
u32 destAddr = base + entry->offset;
|
||||||
u32 value = entry->value;
|
u32 value = 0;
|
||||||
int type = entry->type;
|
if (!(entry->type & R_ZERO_VALUE)) {
|
||||||
|
value = entry->value;
|
||||||
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case R_ARM_ABS32:
|
case R_ARM_ABS32:
|
||||||
@ -115,6 +122,13 @@ void LDR_Relocate(void *pMod) {
|
|||||||
*(u32 *) destAddr += value + base;
|
*(u32 *) destAddr += value + base;
|
||||||
break;
|
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
|
//iterate through the hooks and insert patches
|
||||||
HOOK_TABLE_ENTRY *hookTable = hdr->hookTable;
|
HOOK_TABLE_ENTRY *hookTable = hdr->hookTable;
|
||||||
for (i = 0; i < nHook; i++) {
|
for (i = 0; i < nHook; i++) {
|
||||||
if(hookTable[i].aux) continue;
|
|
||||||
|
|
||||||
u32 hookType = hookTable[i].type;
|
u32 hookType = hookTable[i].type;
|
||||||
u32 hookDest = hookTable[i].branchDestAddr;
|
u32 hookDest = hookTable[i].branchDestAddr;
|
||||||
u32 hookSrc = hookTable[i].branchSrcAddr;
|
u32 hookSrc = hookTable[i].branchSrcAddr;
|
||||||
@ -199,7 +211,6 @@ void LDR_UnloadModule(void *pMod) {
|
|||||||
|
|
||||||
HOOK_TABLE_ENTRY *hookTable = hdr->hookTable;
|
HOOK_TABLE_ENTRY *hookTable = hdr->hookTable;
|
||||||
for (i = nHook; i >= 0; i--) {
|
for (i = nHook; i >= 0; i--) {
|
||||||
if(hookTable[i].aux) continue;
|
|
||||||
u16 *patchLocation = (u16 *) (u32) hookTable[i].branchSrcAddr;
|
u16 *patchLocation = (u16 *) (u32) hookTable[i].branchSrcAddr;
|
||||||
int type = hookTable[i].type;
|
int type = hookTable[i].type;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user