gcc - How do I link to external THUMB code? -
i'm writing thumb code embedded core (arm7tdmi) needs linked existing thumb code. i'm using gnu arm embedded toolchain (link). cannot linker treat existing external code thumb; seems think it's arm. existing code i'm linking absolutely static , cannot changed/recompiled (it's plain binary sitting on rom chip, basically).
here example program, multiply.c
, demonstrates issue:
extern int externalfunction(int x); int multiply(int x, int y) { return externalfunction(x * y); }
compiled using:
arm-none-eabi-gcc -o multiply.o -c -o3 multiply.c -march=armv4t -mtune=arm7tdmi -mthumb arm-none-eabi-ld -o linked.o multiply.o -t symbols.txt
where symbols.txt
simple linker script:
sections { .text 0x8000000 : { *(.text) } } externalfunction = 0x8002000;
when objdump -d linked.o
, get:
08000000 <multiply>: 8000000: b510 push {r4, lr} 8000002: 4348 muls r0, r1 8000004: f000 f804 bl 8000010 <__externalfunction_from_thumb> 8000008: bc10 pop {r4} 800000a: bc02 pop {r1} 800000c: 4708 bx r1 800000e: 46c0 nop ; (mov r8, r8) 08000010 <__externalfunction_from_thumb>: 8000010: 4778 bx pc 8000012: 46c0 nop ; (mov r8, r8) 8000014: ea0007f9 b 8002000 <externalfunction>
instead of branching directly 0x8002000, branches stub switches arm mode first , branches 0x8002000 in arm mode. want bl branch directly 0x8002000 , stay in thumb mode, i'd instead:
08000000 <multiply>: 8000000: b510 push {r4, lr} 8000002: 4348 muls r0, r1 8000004: ???? ???? bl 8002000 <__externalfunction> 8000008: bc10 pop {r4} 800000a: bc02 pop {r1} 800000c: 4708 bx r1
abi , calling convention issues aside, how achieve this?
one way make want
branchto.s
.thumb .thumb_func .globl branchto branchto: bx r0
so.c
extern unsigned int externalfunction; extern int branchto ( unsigned int, int ); int fun ( int x ) { return(branchto(externalfunction,x)+3); }
so.ld
sections { .text 0x8000000 : { *(.text) } } externalfunction = 0x8002001;
producing
08000000 <fun>: 8000000: 4b04 ldr r3, [pc, #16] ; (8000014 <fun+0x14>) 8000002: b510 push {r4, lr} 8000004: 0001 movs r1, r0 8000006: 6818 ldr r0, [r3, #0] 8000008: f000 f806 bl 8000018 <branchto> 800000c: 3003 adds r0, #3 800000e: bc10 pop {r4} 8000010: bc02 pop {r1} 8000012: 4708 bx r1 8000014: 08002001 stmdaeq r0, {r0, sp} 08000018 <branchto>: 8000018: 4700 bx r0
ross ridge's solution in comments works
static int (* const externalfunction)(int x) = (int (*)(int)) 0x80002001; int fun ( int x ) { return((* externalfunction)(x)+3); }
but hardcoded address in code not linker script if matters, trying solve , couldnt.
08000000 <fun>: 8000000: b510 push {r4, lr} 8000002: 4b03 ldr r3, [pc, #12] ; (8000010 <fun+0x10>) 8000004: f000 f806 bl 8000014 <fun+0x14> 8000008: 3003 adds r0, #3 800000a: bc10 pop {r4} 800000c: bc02 pop {r1} 800000e: 4708 bx r1 8000010: 80002001 andhi r2, r0, r1 8000014: 4718 bx r3 8000016: 46c0 nop ; (mov r8, r8)
i prefer assembly solution force exact instruction want. naturally if had linked in external function would/should have worked (there exceptions gnu getting @ resolving , arm/thumb in linker).
i dont see gnu bug actually, instead need way in linker script declare variable thumb function address rather generic linker defined variable (likewise arm function address). .thumb_func (or longer function/procedure declaration)
.word branchto .thumb .globl branchto branchto: bx r0 8000018: 0800001c stmdaeq r0, {r2, r3, r4} 0800001c <branchto>: 800001c: 4700 bx r0 .word branchto .thumb .thumb_func .globl branchto branchto: bx r0 8000018: 0800001d stmdaeq r0, {r0, r2, r3, r4} 0800001c <branchto>: 800001c: 4700 bx r0
by reading gnu linker documentation there may hope want
sections { .text0 0x08000000 : { so.o } .text1 0x08002000 (noload) : { ex.o } }
ex.o comming dummy function make happy
int externalfunction ( int x ) { return(x); } 08000000 <fun>: 8000000: b510 push {r4, lr} 8000002: f001 fffd bl 8002000 <externalfunction> 8000006: 3003 adds r0, #3 8000008: bc10 pop {r4} 800000a: bc02 pop {r1} 800000c: 4708 bx r1
and noload keeps dummy function out of binary.
arm-none-eabi-objcopy so.elf -o srec --srec-forces3 so.srec s00a0000736f2e7372656338 s3150800000010b501f0fdff033010bc02bc0847c0461e s315080000104743433a2028474e552920362e322e305c s31508000020004129000000616561626900011f000046 s3150800003000053454000602080109011204140115ca s31008000040011703180119011a011e021e s70500000000fa
note wasnt perfect there garbage got pulled in, perhaps symbols
08000000 <fun>: 8000000: b510 push {r4, lr} 8000002: f001 fffd bl 8002000 <externalfunction> 8000006: 3003 adds r0, #3 8000008: bc10 pop {r4} 800000a: bc02 pop {r1} 800000c: 4708 bx r1 800000e: 46c0 nop ; (mov r8, r8) 8000010: 3a434347 8000014: 4e472820 8000018: 36202955 800001c: 302e322e 8000020: 00294100 8000024: 65610000 8000028: 00696261 800002c: 00001f01 8000030: 54340500 8000034: 08020600 8000038: 12010901 800003c: 15011404 8000040: 18031701 8000044: 1a011901
which can see in srec, 0x08002000 code not there actual external function called.
i go making instruction want or function pointers assignment if dont want asm.
Comments
Post a Comment