Reputation: 11
I ve old embedded system, with ARM cpu core, I dumped ROM, extracted with binwalk, and loaded on IDA pro. I found in some routine routine, BX not with LR but with general purpose register(R2, R3 etc..)in pseudo code became like some this "memory[0xCC1232](a3, v4)" it is example. I thought that it is like ARM compiler build C pointer function. could it be? Anyway my main question is this, how can I found this subroutine (memoryx..)with only rom dump?because the address is ram address, so without ram dump, can't I find reference to this subroutine?I thought to find routine that write value to this particular address, but it is almost impossible thank you
Upvotes: 1
Views: 1209
Reputation: 71506
Depending on the compiler settings and what core is being targetted, bx without lr is very common, if not required as the older cores pop (ldmia usually) of lr does not work for switching between arm and thumb modes so the compilers will generate pop to like r3 then bx r3.
extern unsigned int more_fun ( void );
unsigned int fun ( void )
{
return(more_fun()+1);
}
00000000 <fun>:
0: b510 push {r4, lr}
2: f7ff fffe bl 0 <more_fun>
6: 3001 adds r0, #1
8: bc10 pop {r4}
a: bc02 pop {r1}
c: 4708 bx r1
e: 46c0 nop ; (mov r8, r8)
vs
00000000 <fun>:
0: b508 push {r3, lr}
2: f7ff fffe bl 0 <more_fun>
6: 3001 adds r0, #1
8: bd08 pop {r3, pc}
a: bf00 nop
r4 vs r3 as the dummy register doesn't matter here; it is interesting that the compiler does this, but they are just being used to make the stack aligned, not to preserve the register.
This is thumb mode of course, arm mode:
00000000 <fun>:
0: e92d4010 push {r4, lr}
4: ebfffffe bl 0 <more_fun>
8: e8bd4010 pop {r4, lr}
c: e2800001 add r0, r0, #1
10: e12fff1e bx lr
You would expect to see lr used with a bx lr.
Or this for newer, but gcc at least defaults to thumb mode and you have to force it to generate arm code like this:
00000000 <fun>:
0: e92d4010 push {r4, lr}
4: ebfffffe bl 0 <more_fun>
8: e2800001 add r0, r0, #1
c: e8bd8010 pop {r4, pc}
As far as finding what is in ram you have to do more work and it might not be possible. If this is an embedded system and everything is in non-volatile memory (flash/rom/etc) then at some point if code is in ram then it is copied or decompressed or other into ram before being branched to. On the other hand you may have disassembled some code that is there to be able to call code in ram but that code in ram may come from a download, basically some external source that is not ultimately on board/chip. Like a bootloader that has code to download a program over the uart and then branch to it, doesn't mean that code is used normally and certainly means you can't predict or know what that code is going to be, much less find it and disassemble it.
A bx of not lr can be used by hand to launch into such code if I download into 0x20000000 and somehow know this is thumb code not arm then I need to orr the address with a 1 in some way then bx to that, sometimes you do that with a register, sometimes not.
You will also see a bx used by the linker to patch up something far away or for changing modes:
unsigned int more_fun ( void )
{
return(3);
}
The linker adds the trampoline for you:
00000000 <fun>:
0: e92d4010 push {r4, lr}
4: eb000003 bl 18 <__more_fun_from_arm>
8: e8bd4010 pop {r4, lr}
c: e2800001 add r0, r0, #1
10: e12fff1e bx lr
00000014 <more_fun>:
14: 2003 movs r0, #3
16: 4770 bx lr
00000018 <__more_fun_from_arm>:
18: e59fc000 ldr r12, [pc] ; 20 <__more_fun_from_arm+0x8>
1c: e12fff1c bx r12
20: 00000015 andeq r0, r0, r5, lsl r0
24: 00000000 andeq r0, r0, r0
and in this case used r12.
Upvotes: 1
Reputation: 3888
In general case, it is not possible to determine actual jump address without disassembling and analysing code. However, several tips and tricks are possible.
BX LR
. You can find all or most subroutine entry points just by scanning through ROM, suspecting that entry point to next subroutine is next to 'BX LR' of previous. To determine if specific subroutine is called indirectly try to search if its plain address exist somewhere in ROM, or it is loaded with 'MOVW'+'MOVT' pair. This give you idea where it may be used.An example RAM initialisation code taken from GNAT's runtime:
movw r0,#:lower16:__data_start ; __data_start points to RAM
movt r0,#:upper16:__data_start ; (often it is start of RAM)
movw r1,#:lower16:__data_words
movw r2,#:lower16:__data_load ; __data_load points to ROM
movt r2,#:upper16:__data_load ; right after code and readonly data
cbz r1,1f
0: ldr r4,[r2],#4
str r4,[r0],#4
subs r1,r1,#1
bne 0b
1:
Upvotes: 0