Código ARM/Thumb para parches de firmware... ¿Cómo decirle a gcc assembler/linker que BL a absolute addr?
gas (2)
Estoy tratando de escribir un mod de firmware (para firmware existente, para el cual no tengo el código fuente) Todo el código de Thumb.
¿Alguien tiene alguna idea de cómo hacer esto, en gcc as
ensamblador (GAS): Use BL
sin tener que calcular manualmente las compensaciones, cuando BL
a alguna función existente (no en mi código ... pero sé su dirección)
Actualmente, si quiero usar BL
... tengo que: volver a mi código, configurar y agregar todos los bytes que resultarían de ensamblar todas las instrucciones anteriores en la función que estoy escribiendo, agregar la dirección inicial. de mi función a eso (especifico la dirección de inicio de lo que estoy escribiendo, en el script del enlazador) - y luego restar la dirección de la función Firmfunc a la que quiero llamar
Todo esto ... solo para calcular el offset ... para poder escribir un bl
offset ... para llamar a una función de firmware existente? ¡Y si cambio cualquier código antes de ese BL, tengo que hacerlo todo de nuevo manualmente!
Mira ... esta es la razón por la que quiero aprender a usar BX
derecha ... en lugar de BL
Además, no entiendo muy bien el BX. Si utilizo BX para saltar a una dirección absoluta, ¿tengo que aumentar la dirección real en 1, cuando calculo el código de pulgar desde el código de pulgar (para mantener el byte 1 de lsb) ... y la CPU sabrá que es el código de pulgar?
La respuesta aceptada logra el objetivo deseado, pero para abordar la respuesta exactamente como se le pidió, puede usar la directiva .equ para asociar un valor constante con un símbolo, que luego puede usarse como un operando para las instrucciones. Esto hace que el ensamblador sintetice el trampolín si / cuando sea necesario:
equ myFirmwareFunction, 0x12346570
.globl _start
mov r0, #42
b myFirmwareFunction
Lo cual genera el siguiente ensamblaje [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
Si el valor inmediato es lo suficientemente cerca de la PC como para que la compensación encaje en el campo inmediato, entonces se omite el verneer (trampolín) y obtendrá una sola instrucción de bifurcación en la dirección constante especificada.
[1] utilizando la cadena de herramientas codesorcery (2009q1) con: arm-none-eabi-gcc -march=armv7-a -x assembler test.spp -o test.elf -Ttext=0x1000000 -nostdlib
BIG EDIT:
Cambiando la respuesta en base a lo que he aprendido recientemente y una mejor comprensión de la pregunta
En primer lugar, no sé cómo decirle al vinculador que genere un bl en una dirección que es una dirección codificada y que no está en este código. Puede intentar manipular un archivo elf que tenga etiquetas y tal, pero sin código, sin saber si eso engañará al enlazador o no. Tendría que modificar el script del enlazador también. no vale la pena.
su otra pregunta que surgió de esta:
Para ramificar esto funciona bien:
LDR R6, =0x24000
ADD R6, #1 @ (set lsb to 1)
BX R6
o guarde una instrucción y solo haga esto
LDR R6, =0x24001
BX R6
si quieres un enlace de rama y sabes la dirección y estás en modo pulgar y quieres obtener el código del pulgar, entonces
ldr r6,=0x24001
bl thumb_trampoline
;@returns here
...
.thumb_func
thumb_trampoline:
bx r6
Y casi exactamente lo mismo si está comenzando en el modo de brazo, y quiere obtener el código de pulgar en una dirección que ya conoce.
ldr r6,=0x24001
bl arm_trampoline
;@returns here
...
arm_trampoline:
bx r6
Debes saber que puedes eliminar r6 de esta forma (asegúrate de que r6 no esté guardando algún valor que esté siendo utilizado por algún código que invoque este código).
Lo siento mucho por confundirte con la otra respuesta, podría jurar que mov lr, pc sacó el lsbit como un modo, pero no es así.