ARM/Thumb code for firmware patches…How to tell gcc assembler / linker to BL to absolute addr?

StackOverflow https://stackoverflow.com/questions/9350280

  •  30-04-2021
  •  | 
  •  

Question

I'm trying to write a firmware mod (to existing firmware, for which i don't have source code) All Thumb code.

does anybody have any idea how to do this, in gcc as (GAS) assembler: Use BL without having to manually calculate offsets, when BL'ing to some existing function (not in my code.. but i know its address)

Currently, if i want to use BL ...i have to : -go back in my code -figure out and add all the bytes that would result from assembling all the previous instructions in the function i'm writing -add the begining address of my function to that (i specify the starting address of what i'm writing, in the linker script) -and then substract the address of the firmfunc function i want to call

All this... just to calculate the offset... to be able to write abl offset... to call an existing firmware function? And if i change any code before that BL, i have to do it all over again manually !
See.. this is why i want to learn to use BX right... instead of BL

Also, i don't quite understand the BX. If i use BX to jump to an absolute address, do i have to increase the actual address by 1, when caling Thumb code from Thumb code (to keep the lsb byte 1)... and the CPU will know it's thumb code ?

Was it helpful?

Solution

BIG EDIT:

Changing the answer based on what I have learned recently and a better understanding of the question

First off I dont know how to tell the linker to generate a bl to an address that is a hardcoded address and not actually in this code. You might try to rig up an elf file that has labels and such but dummy or no code, dont know if that will fool the linker or not. You would have to modify the linker script as well. not worth it.

your other question that was spawned from this one:

Arm/Thumb: using BX in Thumb code, to call a Thumb function, or to jump to a Thumb instruction in another function

For branching this works just fine:

LDR R6, =0x24000
ADD R6, #1       @ (set lsb to 1)
BX R6

or save an instruction and just do this

LDR R6, =0x24001
BX R6

if you want to branch link and you know the address and you are in thumb mode and want to get to thumb code then

  ldr r6,=0x24001
  bl thumb_trampoline
  ;@returns here
  ...
.thumb_func
thumb_trampoline:
  bx r6

And almost the exact same if you are starting in arm mode, and want to get to thumb code at an address you already know.

  ldr r6,=0x24001
  bl arm_trampoline
  ;@returns here
  ...
arm_trampoline:
  bx r6

You have to know that you can trash r6 in this way (make sure r6 isnt saving some value being used by some code that called this code).

Very sorry misleading you with the other answer, I could swear that mov lr,pc pulled in the lsbit as a mode, but it doesnt.

OTHER TIPS

The accepted answer achieves the desired goal, but to address the answer exactly as asked you can use the .equ directive to associate a constant vale with a symbol, that can then be used as an operand to instructions. This has the assembler synthesise the trampoline if/when necessary:

equ myFirmwareFunction, 0x12346570
.globl _start
        mov r0, #42
        b   myFirmwareFunction

Which generates the following assembly[1]

01000000 <_start>:
 1000000:   e3a0002a    mov r0, #42 ; 0x2a
 1000004:   eaffffff    b   1000008 <__*ABS*0x12346570_veneer>

01000008 <__*ABS*0x12346570_veneer>:
__*ABS*0x12346570_veneer():
 1000008:   e51ff004    ldr pc, [pc, #-4]   ; 100000c <__*ABS*0x12346570_veneer+0x4>
 100000c:   12346570    data: #0x12345670

If the immediate value is close enough to PC that the offset will fit in the immediate field, then the verneer (trampoline) is skipped and you will get a single branch instruction to the specified constant address.

[1] using the codesorcery (2009q1) toolchain with: arm-none-eabi-gcc -march=armv7-a -x assembler test.spp -o test.elf -Ttext=0x1000000 -nostdlib

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top