Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gcc for ARM - move code and stack

I am working on a project for an ARM Cortex-M3 (SiLabs) SOC. I need to move the interrupt vector [edit] and code away from the bottom of flash to make room for a "boot loader". The boot loader starts at address 0 to come up when the core comes out of reset. Its function is to validate the main image, loaded at a higher address and possibly replace that main image with a new one.

Therefore, the boot loader would have its vector table at 0, followed by its code. At a higher, fixed address, say 8KB, would be the main image, starting with its vector table.

I have found this page which describes the Vector Table Offset Register which the boot loader can use (with interrupts masked, obviously) to point the hardware to the new vector table.

My question is how to get the "main" image linked so that it will work when written to flash, starting not at zero. I'm not familiar with ARM assembly but I assume the code is not position independent.

I'm using SiLabs's Precision32 IDE which uses gcc for the toolchain. I've found how to add linker flags. My question is what gcc flag(s) will provide the change to the base of the vector table and code.

Thank you.

like image 437
DoxyLover Avatar asked Aug 10 '13 01:08

DoxyLover


1 Answers

vectors.s

.cpu cortex-m3
.thumb

.word   0x20008000  /* stack top address */
.word   _start      /* Reset */
.word   hang
.word   hang
/* ... */

.thumb_func
hang:   b .

.thumb_func
.globl _start
_start:
    bl notmain
    b hang

notmain.c

extern void fun ( unsigned int );
void notmain ( void )
{
    fun(7);
}

fun.c

void fun ( unsigned int x )
{
}

Makefile

hello.elf : vectors.s fun.c notmain.c memmap
    arm-none-eabi-as vectors.s -o vectors.o
    arm-none-eabi-gcc -Wall  -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -mcpu=cortex-m3 -march=armv7-m -c notmain.c -o notmain.o
    arm-none-eabi-gcc -Wall  -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -mcpu=cortex-m3 -march=armv7-m -c fun.c -o fun.o
    arm-none-eabi-ld -o hello.elf -T memmap vectors.o notmain.o fun.o
    arm-none-eabi-objdump -D hello.elf > hello.list
    arm-none-eabi-objcopy hello.elf -O binary hello.bin

so if the linker script (memmap is the name I used) looks like this

MEMORY
{
   rom : ORIGIN = 0x00000000, LENGTH = 0x40000
   ram : ORIGIN = 0x20000000, LENGTH = 0x8000
}

SECTIONS
{
   .text : { *(.text*) } > rom
   .bss  : { *(.bss*) } > ram
}

since all of the above is .text, no .bss nor .data, the linker takes the objects as listed on the ld command line and places them starting at that address...

mbly of section .text:

00000000 <hang-0x10>:
   0:   20008000    andcs   r8, r0, r0
   4:   00000013    andeq   r0, r0, r3, lsl r0
   8:   00000011    andeq   r0, r0, r1, lsl r0
   c:   00000011    andeq   r0, r0, r1, lsl r0

00000010 <hang>:
  10:   e7fe        b.n 10 <hang>

00000012 <_start>:
  12:   f000 f801   bl  18 <notmain>
  16:   e7fb        b.n 10 <hang>

00000018 <notmain>:
  18:   2007        movs    r0, #7
  1a:   f000 b801   b.w 20 <fun>
  1e:   bf00        nop

00000020 <fun>:
  20:   4770        bx  lr
  22:   bf00        nop

So for this to work you have to be careful to put your bootstrap code first on the command line. But you can also do things like this with a linker script.

the order appears to matter, listing the specific object files first then the generic .text later

MEMORY
{
   romx : ORIGIN = 0x00000000, LENGTH = 0x1000
   romy : ORIGIN = 0x00010000, LENGTH = 0x1000
   ram  : ORIGIN = 0x00030000, LENGTH = 0x1000
   bob  : ORIGIN = 0x00040000, LENGTH = 0x1000
   ted  : ORIGIN = 0x00050000, LENGTH = 0x1000
}

SECTIONS
{
   abc : { vectors.o } > romx
   def : { fun.o } > ted
   .text : { *(.text*) } > romy
   .bss  : { *(.bss*) } > ram
}

and we get this

00000000 <hang-0x10>:
   0:   20008000    andcs   r8, r0, r0
   4:   00000013    andeq   r0, r0, r3, lsl r0
   8:   00000011    andeq   r0, r0, r1, lsl r0
   c:   00000011    andeq   r0, r0, r1, lsl r0

00000010 <hang>:
  10:   e7fe        b.n 10 <hang>

00000012 <_start>:
  12:   f00f fff5   bl  10000 <notmain>
  16:   e7fb        b.n 10 <hang>

Disassembly of section def:

00050000 <fun>:
   50000:   4770        bx  lr
   50002:   bf00        nop

Disassembly of section .text:

00010000 <notmain>:
   10000:   2007        movs    r0, #7
   10002:   f03f bffd   b.w 50000 <fun>
   10006:   bf00        nop

the short answer is with gnu tools you use a linker script to manipulate where things end up, I assume you want these functions to be in the rom at some specified location. I dont quite understand exactly what you are doing. But if for example you are trying to put something simple like the branch to main() in the flash initially with main() being deeper in the flash, then somehow either through whatever code is deeper in the flash or through some other method, then later you erase and reprogram only the stuff near zero. you will still need a simple branch to main() the first time. you can force what I am calling vectors.o to be at address zero then .text can be deeper in the flash putting all of the reset of the code basically there, then leave that in flash and replace just the stuff at zero.

like this

MEMORY
{
   romx : ORIGIN = 0x00000000, LENGTH = 0x1000
   romy : ORIGIN = 0x00010000, LENGTH = 0x1000
   ram  : ORIGIN = 0x00030000, LENGTH = 0x1000
   bob  : ORIGIN = 0x00040000, LENGTH = 0x1000
   ted  : ORIGIN = 0x00050000, LENGTH = 0x1000
}

SECTIONS
{
   abc : { vectors.o } > romx
   .text : { *(.text*) } > romy
   .bss  : { *(.bss*) } > ram
}

giving

00000000 <hang-0x10>:
   0:   20008000    andcs   r8, r0, r0
   4:   00000013    andeq   r0, r0, r3, lsl r0
   8:   00000011    andeq   r0, r0, r1, lsl r0
   c:   00000011    andeq   r0, r0, r1, lsl r0

00000010 <hang>:
  10:   e7fe        b.n 10 <hang>

00000012 <_start>:
  12:   f00f fff7   bl  10004 <notmain>
  16:   e7fb        b.n 10 <hang>

Disassembly of section .text:

00010000 <fun>:
   10000:   4770        bx  lr
   10002:   bf00        nop

00010004 <notmain>:
   10004:   2007        movs    r0, #7
   10006:   f7ff bffb   b.w 10000 <fun>
   1000a:   bf00        nop

then leave the 0x10000 stuff and replace 0x00000 stuff later.

Anyway, the short answer is linker script you need to craft a linker script to put things where you want them. gnu linker scripts can get extremely complicated, I lean toward the simple.

If you want to place everything at some other address, including your vector table, then perhaps something like this:

hop.s

.cpu cortex-m3
.thumb

.word   0x20008000  /* stack top address */
.word   _start      /* Reset */
.word   hang
.word   hang
/* ... */

.thumb_func
hang:   b .

.thumb_func
    ldr r0,=_start
    bx r0

and this

MEMORY
{
   romx : ORIGIN = 0x00000000, LENGTH = 0x1000
   romy : ORIGIN = 0x00010000, LENGTH = 0x1000
   ram  : ORIGIN = 0x00030000, LENGTH = 0x1000
   bob  : ORIGIN = 0x00040000, LENGTH = 0x1000
   ted  : ORIGIN = 0x00050000, LENGTH = 0x1000
}

SECTIONS
{
   abc : { hop.o } > romx
   .text : { *(.text*) } > romy
   .bss  : { *(.bss*) } > ram
}

gives this

Disassembly of section abc:
00000000 <hang-0x10>:
   0:   20008000    andcs   r8, r0, r0
   4:   00010013    andeq   r0, r1, r3, lsl r0
   8:   00000011    andeq   r0, r0, r1, lsl r0
   c:   00000011    andeq   r0, r0, r1, lsl r0

00000010 <hang>:
  10:   e7fe        b.n 10 <hang>
  12:   4801        ldr r0, [pc, #4]    ; (18 <hang+0x8>)
  14:   4700        bx  r0
  16:   00130000
  1a:   20410001

Disassembly of section .text:

00010000 <hang-0x10>:
   10000:   20008000    andcs   r8, r0, r0
   10004:   00010013    andeq   r0, r1, r3, lsl r0
   10008:   00010011    andeq   r0, r1, r1, lsl r0
   1000c:   00010011    andeq   r0, r1, r1, lsl r0

00010010 <hang>:
   10010:   e7fe        b.n 10010 <hang>

00010012 <_start>:
   10012:   f000 f803   bl  1001c <notmain>
   10016:   e7fb        b.n 10010 <hang>

00010018 <fun>:
   10018:   4770        bx  lr
   1001a:   bf00        nop

0001001c <notmain>:
   1001c:   2007        movs    r0, #7
   1001e:   f7ff bffb   b.w 10018 <fun>
   10022:   bf00        nop

then you can change the vector table to 0x10000 for example.

if you are asking a different question like having the bootloader at 0x00000, then the bootloader modifies the flash to add an application say at 0x20000, then you want to run that application, there are simpler solutions that dont necessarily require you to modify the location of the vector table.

like image 200
old_timer Avatar answered Nov 11 '22 06:11

old_timer