static
void
relocateInstructionInArm(uint32_t target_addr, uint32_t *orig_instructions,
int
length, uint32_t *trampoline_instructions,
int
*orig_boundaries,
int
*trampoline_boundaries,
int
*count)
{
uint32_t pc;
uint32_t lr;
int
orig_pos;
int
trampoline_pos;
pc = target_addr + 8;
lr = target_addr + length;
trampoline_pos = 0;
for
(orig_pos = 0; orig_pos < length /
sizeof
(uint32_t); ++orig_pos) {
uint32_t instruction;
int
type;
orig_boundaries[*count] = orig_pos *
sizeof
(uint32_t);
trampoline_boundaries[*count] = trampoline_pos *
sizeof
(uint32_t);
++(*count);
instruction = orig_instructions[orig_pos];
type = getTypeInArm(instruction);
if
(type == BLX_ARM || type == BL_ARM || type == B_ARM || type == BX_ARM) {
uint32_t x;
int
top_bit;
uint32_t imm32;
uint32_t value;
if
(type == BLX_ARM || type == BL_ARM) {
trampoline_instructions[trampoline_pos++] = 0xE28FE004;
}
trampoline_instructions[trampoline_pos++] = 0xE51FF004;
if
(type == BLX_ARM) {
x = ((instruction & 0xFFFFFF) << 2) | ((instruction & 0x1000000) >> 23);
}
else
if
(type == BL_ARM || type == B_ARM) {
x = (instruction & 0xFFFFFF) << 2;
}
else
{
x = 0;
}
top_bit = x >> 25;
imm32 = top_bit ? (x | (0xFFFFFFFF << 26)) : x;
if
(type == BLX_ARM) {
value = pc + imm32 + 1;
}
else
{
value = pc + imm32;
}
trampoline_instructions[trampoline_pos++] = value;
}
else
if
(type == ADD_ARM) {
int
rd;
int
rm;
int
r;
rd = (instruction & 0xF000) >> 12;
rm = instruction & 0xF;
for
(r = 12; ; --r) {
if
(r != rd && r != rm) {
break
;
}
}
trampoline_instructions[trampoline_pos++] = 0xE52D0004 | (r << 12);
trampoline_instructions[trampoline_pos++] = 0xE59F0008 | (r << 12);
trampoline_instructions[trampoline_pos++] = (instruction & 0xFFF0FFFF) | (r << 16);
trampoline_instructions[trampoline_pos++] = 0xE49D0004 | (r << 12);
trampoline_instructions[trampoline_pos++] = 0xE28FF000;
trampoline_instructions[trampoline_pos++] = pc;
}
else
if
(type == ADR1_ARM || type == ADR2_ARM || type == LDR_ARM || type == MOV_ARM) {
int
r;
uint32_t value;
r = (instruction & 0xF000) >> 12;
if
(type == ADR1_ARM || type == ADR2_ARM || type == LDR_ARM) {
uint32_t imm32;
imm32 = instruction & 0xFFF;
if
(type == ADR1_ARM) {
value = pc + imm32;
}
else
if
(type == ADR2_ARM) {
value = pc - imm32;
}
else
if
(type == LDR_ARM) {
int
is_add;
is_add = (instruction & 0x800000) >> 23;
if
(is_add) {
value = ((uint32_t *) (pc + imm32))[0];
}
else
{
value = ((uint32_t *) (pc - imm32))[0];
}
}
}
else
{
value = pc;
}
trampoline_instructions[trampoline_pos++] = 0xE51F0000 | (r << 12);
trampoline_instructions[trampoline_pos++] = 0xE28FF000;
trampoline_instructions[trampoline_pos++] = value;
}
else
{
trampoline_instructions[trampoline_pos++] = instruction;
}
pc +=
sizeof
(uint32_t);
}
trampoline_instructions[trampoline_pos++] = 0xe51ff004;
trampoline_instructions[trampoline_pos++] = lr;
}