From 8fcf0dedac588777df63e1fcbbcb3cc3fd2814d1 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Mon, 2 Mar 2026 21:28:05 +0100 Subject: [PATCH] patch type added: PATCH_OBJECT_ARM32_ABS_THM (for R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_ABS) --- src/copapy/_binwrite.py | 1 + src/coparun/runmem.c | 40 ++++++++++++++++++++++++++++++++++++++-- src/coparun/runmem.h | 1 + 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/copapy/_binwrite.py b/src/copapy/_binwrite.py index e1d7c90..1af2ee3 100644 --- a/src/copapy/_binwrite.py +++ b/src/copapy/_binwrite.py @@ -13,6 +13,7 @@ Command = Enum('Command', [('ALLOCATE_DATA', 1), ('COPY_DATA', 2), ('PATCH_OBJECT_ABS', 0x2002), ('PATCH_OBJECT_REL', 0x2003), ('PATCH_OBJECT_ARM32_ABS', 0x2004), + ('PATCH_OBJECT_ARM32_ABS_THM', 0x2006), ('ENTRY_POINT', 7), ('RUN_PROG', 64), ('READ_DATA', 65), ('END_COM', 256), ('FREE_MEMORY', 257), ('DUMP_CODE', 258)]) diff --git a/src/coparun/runmem.c b/src/coparun/runmem.c index e5180e5..b905e97 100644 --- a/src/coparun/runmem.c +++ b/src/coparun/runmem.c @@ -50,6 +50,32 @@ void patch_arm32_abs(uint8_t *patch_addr, uint32_t imm16) *((uint32_t *)patch_addr) = instr; } +void patch_arm_thm_abs(uint8_t *patch_addr, uint32_t imm16) +{ + // Thumb MOVW (T3) / MOVT (T1) encoding + + uint16_t *instr16 = (uint16_t *)patch_addr; + uint16_t first_half = instr16[0]; + uint16_t second_half = instr16[1]; + + // Extract fields from imm16 + uint32_t imm4 = (imm16 >> 12) & 0xF; + uint32_t i = (imm16 >> 11) & 0x1; + uint32_t imm3 = (imm16 >> 8) & 0x7; + uint32_t imm8 = imm16 & 0xFF; + + // Clear bits + first_half &= (uint16_t)(~(0x000F | (1 << 10))); + second_half &= (uint16_t)(~(0x00FF | (0x7 << 12))); + + // Set new fields + first_half |= (uint16_t)((imm4 << 0) | (i << 10)); + second_half |= (uint16_t)(imm8 | (imm3 << 12)); + + instr16[0] = first_half; + instr16[1] = second_half; +} + void patch_arm_thm_jump24(uint8_t *patch_addr, int32_t imm24) { // Read the 32-bit instruction (two halfwords) @@ -77,8 +103,8 @@ void patch_arm_thm_jump24(uint8_t *patch_addr, int32_t imm24) second_half &= 0xD000; // Keep upper 5 bits // Set new imm fields - first_half |= (S << 10) | imm10; - second_half |= (J1 << 13) | (J2 << 11) | imm11; + first_half |= (uint16_t)((S << 10) | imm10); + second_half |= (uint16_t)((J1 << 13) | (J2 << 11) | imm11); // Write back instr16[0] = first_half; @@ -225,6 +251,16 @@ int parse_commands(runmem_t *context, uint8_t *bytes) { patch_arm_thm_jump24(context->executable_memory + offs, value); break; + case PATCH_OBJECT_ARM32_ABS_THM: + offs = *(uint32_t*)bytes; bytes += 4; + patch_mask = *(uint32_t*)bytes; bytes += 4; + patch_scale = *(int32_t*)bytes; bytes += 4; + value = *(int32_t*)bytes; bytes += 4; + LOG("PATCH_OBJECT_ARM32_ABS_THM patch_offs=%i patch_mask=%#08x scale=%i value=%i imm16=%#04x\n", + offs, patch_mask, patch_scale, value, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); + patch_arm_thm_abs(context->executable_memory + offs, (uint32_t)((uintptr_t)(context->data_memory + value) & patch_mask) / (uint32_t)patch_scale); + break; + case ENTRY_POINT: rel_entr_point = *(uint32_t*)bytes; bytes += 4; context->entr_point = (entry_point_t)(context->executable_memory + rel_entr_point); diff --git a/src/coparun/runmem.h b/src/coparun/runmem.h index 371f2f3..17da047 100644 --- a/src/coparun/runmem.h +++ b/src/coparun/runmem.h @@ -26,6 +26,7 @@ #define PATCH_OBJECT_ABS 0x2002 #define PATCH_OBJECT_REL 0x2003 #define PATCH_OBJECT_ARM32_ABS 0x2004 +#define PATCH_OBJECT_ARM32_ABS_THM 0x2006 #define ENTRY_POINT 7 #define RUN_PROG 64 #define READ_DATA 65