用于ARM的gcc - 移动代码和堆栈

时间:2013-08-10 01:20:46

标签: gcc linker arm cortex-m3

我正在开发一个ARM Cortex-M3(SiLabs)SOC项目。我需要将中断向量[编辑]和代码从闪存底部移开,为“引导加载程序”腾出空间。当核心复位时,引导加载程序从地址0开始出现。它的功能是验证主图像,加载到更高的地址,并可能用新图像替换主图像。

因此,引导加载程序的向量表将为0,后跟其代码。在更高的固定地址(例如8KB)将是主要图像,从其向量表开始。

我找到了this page,它描述了引导加载程序可以使用的向量表偏移寄存器(显然屏蔽了中断)将硬件指向新的向量表。

我的问题是如何将“主”图像链接起来,以便在写入闪存时起作用,从零开始。我不熟悉ARM程序集,但我认为代码不是与位置无关的。

我正在使用SiLabs的Precision32 IDE,它使用gcc作为工具链。我发现了如何添加链接器标志。我的问题是gcc标志将提供对向量表和代码基础的更改。

谢谢。

1 个答案:

答案 0 :(得分:6)

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 )
{
}

生成文件

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命令行中列出的对象,并将它们从该地址开始...

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

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

顺序似乎很重要,先列出特定的目标文件,然后再列出通用的.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中。我完全不明白你在做什么。但是,例如,如果你试图把一些简单的东西像分支一样放在flash中的main(),最初main()在flash中更深,那么无论如何通过闪存中更深层次的代码或通过其他方法,然后之后你只擦除和重新编程零附近的东西。第一次你仍然需要一个简单的分支到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链接器脚本可以变得非常复杂,我倾向于简单。

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

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

和这个

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,那么引导加载程序会修改flash以在0x20000处添加应用程序,然后你想要运行该应用程序,有一些更简单的解决方案,不一定要求你修改向量表的位置。