119 lines
3.2 KiB
C
119 lines
3.2 KiB
C
/*
|
|
* Offset = 0xD8010
|
|
*
|
|
* 00 0D 80 10
|
|
* Bits 31-24 23-16 15-8 7-0
|
|
* 0000 0000 0000 1101 1000 0000 0001 0000
|
|
*
|
|
* Bits 31-25 24 23 22 21-12 11-2 10
|
|
* 0000000 0 0 0 0011011000 0000000100 00
|
|
* S I1 I2 H L
|
|
*
|
|
* J1 = ~I1 ^ S = 1
|
|
* J2 = ~I2 ^ S = 1
|
|
* https://web.eecs.umich.edu/~prabal/teaching/eecs373-f10/readings/ARMv7-M_ARM.pdf
|
|
* A.6.7.18
|
|
*/
|
|
|
|
#include <assert.h>
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
#define FIXED2_BL 0x3
|
|
#define FIXED2_B 0x2
|
|
/*---------------------------------------------------------------------------*/
|
|
typedef union {
|
|
struct {
|
|
unsigned last1 : 1;
|
|
unsigned imm11l : 11;
|
|
unsigned imm10h : 10;
|
|
unsigned i2 : 1;
|
|
unsigned i1 : 1;
|
|
unsigned s : 1;
|
|
unsigned msb7 : 7;
|
|
} o;
|
|
int v;
|
|
} bl_offset_t;
|
|
|
|
typedef union {
|
|
struct {
|
|
unsigned imm11l : 11;
|
|
unsigned j2 : 1;
|
|
unsigned fixed1 : 1;
|
|
unsigned j1 : 1;
|
|
unsigned fixed2 : 2;
|
|
unsigned imm10h : 10;
|
|
unsigned s : 1;
|
|
unsigned msb5 : 5;
|
|
} i;
|
|
unsigned v;
|
|
} bl_instruction_t;
|
|
/*---------------------------------------------------------------------------*/
|
|
/*
|
|
* Provide the address shown in the disassembler for the instruction to
|
|
* calculate for. When the code executes this will be PC.
|
|
* Provide the address of the function (branch traget / btarget) the code
|
|
* should branch to.
|
|
* The return value will be an encode instruction ready to be an instruction
|
|
* that can be patched into an ARM binary with a hex editor.
|
|
* Why would you use this?
|
|
* If you want to branch to a different function with the same (or at least
|
|
* comptabile) signature, you can replace the branch instruction and
|
|
* alter the code. This particular instruction is a little trickier than
|
|
* direct branch instructions.
|
|
*/
|
|
static unsigned
|
|
bl_encode_common(unsigned pc, unsigned target, unsigned fixed2)
|
|
{
|
|
bl_offset_t offset;
|
|
bl_instruction_t final_instr;
|
|
|
|
pc += 4; /* Due to arm pipeline */
|
|
pc &= 0xfffffffe; /* 2 byte alignment */
|
|
|
|
offset.v = target - pc;
|
|
assert(offset.v < 16 * 1024 * 1024 && offset.v > -16 * 1024 * 1024);
|
|
final_instr.v = 0;
|
|
|
|
/* bits 27-31 = 0b11110 */
|
|
final_instr.i.msb5 = 0x1e;
|
|
|
|
/* bit 26 = S */
|
|
final_instr.i.s = offset.o.s;
|
|
|
|
/* imm10h, bits 16-25 */
|
|
final_instr.i.imm10h = offset.o.imm10h;
|
|
|
|
/* static */
|
|
final_instr.i.fixed2 = fixed2;
|
|
|
|
/* j1 */
|
|
final_instr.i.j1 = (offset.o.i1 ^ 0x1) ^ offset.o.s;
|
|
|
|
/* static */
|
|
final_instr.i.fixed1 = 0x1;
|
|
|
|
/* j2 */
|
|
final_instr.i.j2 = (offset.o.i2 ^ 0x1) ^ offset.o.s;
|
|
|
|
/* imm11l */
|
|
final_instr.i.imm11l = offset.o.imm11l;
|
|
|
|
unsigned v = final_instr.v;
|
|
v = v >> 16 | v << 16;
|
|
|
|
return v;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
unsigned
|
|
bl_encode(unsigned pc, unsigned target)
|
|
{
|
|
return bl_encode_common(pc, target, FIXED2_BL);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
unsigned
|
|
b_encode(unsigned pc, unsigned target)
|
|
{
|
|
return bl_encode_common(pc, target, FIXED2_B);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|