arm - Problems with static local variables with relocatable code -
i building project has relocatable code on bare metal. cortex m3 embedded application. not have dynamic linker , have implemented relocations in startup code.
mostly working local static variables appear incorrectly located. address offset amount executable offset in memory - ie compile code if loaded @ memory location 0 load in memory located @ 0x8000. static local variable have memory address offset 0x8000 not good.
my global variables located got static local variables not in got @ (at least don't appear when run readelf -r
). compiling code -fpic
, linker has -fpic
, -pie
specified. think must missing compile and/or link option either instruct gcc
use got static local variables or instruct use absolute addressing them.
it seems code adds pc location of static local variables.
i think have repeated seeing:
statloc.c unsigned int glob; unsigned int fun ( unsigned int ) { static unsigned int loc; if(a==0) loc=7; return(a+glob+loc); }
arm-none-linux-gnueabi-gcc -mcpu=cortex-m3 -wall -werror -o2 -nostdlib -nostartfiles -ffreestanding -mthumb -fpic -pie -s statloc.c
which gives:
.cpu cortex-m3 .fpu softvfp .thumb .text .align 2 .global fun .thumb .thumb_func fun: ldr r3, .l6 .lpic2: add r3, pc cbnz r0, .l5 ldr r1, .l6+4 movs r2, #7 .lpic1: add r1, pc ldr ip, .l6+8 str r2, [r1, #0] ldr r1, [r3, ip] ldr r3, [r1, #0] adds r0, r0, r3 adds r0, r0, r2 bx lr .l5: ldr ip, .l6+8 ldr r2, .l6+12 ldr r1, [r3, ip] .lpic0: add r2, pc ldr r2, [r2] ldr r3, [r1, #0] adds r0, r0, r3 adds r0, r0, r2 bx lr .l7: .align 2 .l6: .word _global_offset_table_-(.lpic2+4) .word .lanchor0-(.lpic1+4) .word glob(got) .word .lanchor0-(.lpic0+4) .size fun, .-fun .comm glob,4,4 .bss .align 2 .lanchor0 = . + 0 .type loc.823, %object .size loc.823, 4 loc.823: .space 4
i added startup code , compiled binary , disassembled further understand/verify going on.
offset pc .got ldr r3, .l6 add pc r3 holds position independent offset .got add r3, pc offset in got address of glob ldr ip, .l6+8 read absolute address global variable got ldr r1, [r3, ip] read global variable r3 ldr r3, [r1, #0] offset pc static local in .bss ldr r2, .l6+12 add pc r2 holds position independent offset static local in .bss add r2, pc read static local in .bss ldr r2, [r2]
so if change .text loaded , change both .got , .bss loaded relative .text , contents of .got wrong , global variable loaded wrong place.
if change .text loaded, leave .bss linker put , move .got relative .text. global pulled right place , local not
if change .text loaded, change both .got , .bss loaded relative .text , modify .got contents reflect .text loaded, both local , global variable accessed right place.
so loader , gcc/ld need in sync. immediate recommendation not use static local , use global. or dont worry position independent code, cortex-m3 after , resource limited, define memory map front. assume question how make gcc use .got local global, , 1 dont know answer to, taking simple example 1 above can work through many command line options until find 1 changes output.
Comments
Post a Comment