I won’t list long theories here. Instead, I will show how a real compiler does. I will take GCC as an instance here.
- Branch Code
(1) near call
arm-none-eabi-gcc -fomit-frame-pointer -c test1.c -S -o test1.s
(2) long call
void sub_80077E8(s16 *mempool);
void call_sub_80077E8(s16 *mempool)
thumb → arm: bx pc
arm → thumb: bx 90008b5h
void sub_8007824(s16 *mempool);
void call_sub_8007824(s16 *mempool)
(3) call thumb from arm
(copied from Nintendo’s official SDK)
mov lr,pc here?
arm-none-eabi-gcc -fomit-frame-pointer -s test2A.s test2callA.s
arm-none-eabi-objdump -S a.out
(4) call arm from thumb
(5) function pointer
arm-none-eabi-gcc -fomit-frame-pointer -mthumb -c test3.c -S
arm-none-eabi-gcc -fomit-frame-pointer -mthumb -c test4.c -S
- Arguments, Return Value and Local Variables
(1) at most 4 parameters
arm-none-eabi-gcc -fomit-frame-pointer -mthumb -c test5.c -S
(2) more than 4 parameters
arm-none-eabi-gcc -fomit-frame-pointer -mthumb -c test6.c -S
(3) parameter array
Hint: Is this right?
(4) pointer parameter
Hint: the address is passed to the subroutine instead of the value
Is this right?
(5) multi return values
(only in assembly)
(6) return pointer
Hint: Is this right?
(7) static variables
Hint: what’s the difference from local variables?
(8) global variables
Hint: what’s the difference from static variables?
(9) static global variables
Hint: what’s the difference from global variables?
(10) register variables
Hint: notice the difference between the variable s and i
(11) inline asm
(12) frame pointer
arm-none-eabi-gcc -c test5.c -S
bx pc in THUMB only works from a word-aligned address, and then the next two bytes will also be skipped over. According to GBATEK:
For BX/BLX, when Bit 0 of the value in Rs is zero:
Processor will be switched into ARM mode!
If so, Bit 1 of Rs must be cleared (32bit word aligned).
Thus, BX PC (switch to ARM) may be issued from word-aligned address
only, the destination is PC+4 (ie. the following halfword is skipped).
Basically, reading from the PC register gives you a value that is 2 instructions ahead of the one being executed, because of how the pipeline works. The BX works by actually copying that value back in, so in a roundabout way it jumps 2 instructions = 4 bytes ahead (while also changing the mode). But it has to jump to a word-aligned address because ARM code is word-aligned.
This document is super cool! I don’t know what does it mean “ldr ip, [pc]” at 0x8130. Does pc store a pointer?
I am a newbie of this, so the question may seem to be silly
Can you explain this part to me? Thanks a lot
Thanks, but I still don’t understand the meaning of “ldr ip,[pc]” at 0x8130
For example, if current pc value is 0x00008130, will ip change to 0xe12ff11c? But if so, the next instruction “bx ip” at 0x8134 seems to make a weird jump?
You confuse different concepts:
0x8130 here is an offset. The code will be loaded to ROM region 0x8000000~0x9FFFFFF before running, so the address is 0x8008130.
Oh, sorry for being inaccurate. Actually I know the memory map of a GBA. I just don’t understand the meaning of “ldr ip,[pc]”.
Does it mean “Load 4 bytes to ip from the address contained in pc” ? But if so, how can “bx ip” branch to the right place
It is because entry point address is not set when building. It doesn’t harm because the topic is not specified to GBA. Set the entry point address to 0x8000000 and it will jump to the correct address on GBA.
Oh, thank you
Maybe I should learn something about building
Anyway, thanks a lot