5

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.

4

1 回答 1

6

向量.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

不是main.c

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

乐趣.c

void fun ( unsigned int x )
{
}

生成文件

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

因此,如果链接器脚本(memmap 是我使用的名称)看起来像这样

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

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

由于上述所有内容都是 .text,没有 .bss 或 .data,因此链接器采用 ld 命令行上列出的对象并将它们从该地址开始放置...

.text 部分的mbly:

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

因此,要使其正常工作,您必须小心地将引导代码放在命令行的首位。但是您也可以使用链接描述文件来执行此类操作。

顺序似乎很重要,首先列出特定的目标文件,然后是通用的 .text

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
}

我们得到了这个

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

简短的回答是使用 gnu 工具,您使用链接器脚本来操纵事情的最终结果,我假设您希望这些函数位于某个指定位置的 rom 中。我不太明白你在做什么。但是,例如,如果您尝试将一些简单的东西,例如最初在闪存中的 main() 分支,而 main() 在闪存中更深,然后以某种方式通过闪存中更深的任何代码或通过其他方法,然后后来你只擦除和重新编程接近零的东西。你仍然需要一个简单的分支到 main() 第一次。您可以强制我所说的vectors.o位于地址零,然后.text可以在闪存中更深,将代码的所有重置基本上放在那里,然后将其留在闪存中并仅替换零处的东西。

像这样

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
}

给予

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

然后留下 0x10000 的东西并稍后替换 0x00000 的东西。

无论如何,简短的回答是链接描述文件你需要制作一个链接描述文件来把东西放在你想要的地方。gnu 链接器脚本可能会变得非常复杂,我倾向于简单。

如果你想把所有东西都放在其他地址,包括你的向量表,那么可能是这样的:

酒花

.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

和这个

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
}

给了这个

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

然后您可以将向量表更改为例如 0x10000。

如果您要问一个不同的问题,例如引导加载程序位于 0x00000,那么引导加载程序会修改闪存以添加应用程序,例如在 0x20000,然后您想运行该应用程序,有一些更简单的解决方案不一定需要您修改向量表。

于 2013-08-10T02:53:46.647 回答