是否可以仅使用GNU LD命令行选项创建基本的裸机程序集启动/启动程序

时间:2017-02-02 00:33:56

标签: linker arm cortex-m bare-metal

是否可以仅使用GNU LD命令行选项创建基本的裸机程序集启动/启动程序,以代替Cortex-M4目标的惯用-T脚本文件?

我查看了GNU LD文档并搜索了包括该站点在内的各个位置;但是,我没有找到任何信息表明可以或不可能专门使用GNU链接器的命令行选项。

我尝试管理目标文件布局而没有提供* .ld脚本文件的惯用供应商纯粹是学术性的。这不是功课。我没有请求任何帮助来编写启动汇编代码。我只是在寻找明确的答案或进一步的资源方向。

$ arm-none-eabi-ld bootup.o -o bootup @bootup.ld.cli.file

示例bootup.ld.cli.file内容

--entry 0x0
--Ttext=0x0
--section-start .isr_vector=0x0
--section-start _start=0x4
--section-start .MyCode=0x8c
--Tdata=0x20000000
--Tbss=0x20000000
-M=bootup.map
--print-gc-sections

1 个答案:

答案 0 :(得分:2)

你有答案-Ttext = number -Tdata = number等等没有gnu链接器脚本项它们是gnu命令行项目。请注意命令行上的at符号。

gnu链接器脚本看起来更像这样(尽管大多数都要复杂得多,即使它们不需要)。

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

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

请注意,当您使用-Ttext = address方法时,gnu链接器有点滑稽,有时它会插入您可能有几KB程序的间隙而不是它只是线性地将它放在地址上就像它应该会把一些,然后填充一些死空间,然后再放一些,从来没有想出为什么但是对于极其有限的目标,链接器脚本(vs命令行)所有其他因素保持不变,不会在输出中留下空隙。

编辑:

so.s

.cpu cortex-m0
.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang

.thumb_func
reset:
    b hang
.thumb_func
hang:   b .

flash.s

.cpu cortex-m0
.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang

.thumb_func
reset:
    bl notmain
    b hang

.thumb_func
hang:   b .

.thumb_func
.globl dummy
dummy:
    bx lr

flash.ld

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

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

blinker02.c

void dummy ( unsigned int );

int notmain ( void )
{
    unsigned int ra;
    for(ra=0;ra<100;ra++) dummy(ra);
    return(0);
}

生成文件

ARMGNU = arm-none-eabi

AOPS = --warn -mcpu=cortex-m0
COPS = -Wall -O2 -nostdlib -nostartfiles -ffreestanding  -mcpu=cortex-m0

all : blinker02.bin sols.bin socl.bin

clean:
    rm -f *.bin
    rm -f *.o
    rm -f *.elf
    rm -f *.list

so.o : so.s
    $(ARMGNU)-as $(AOPS) so.s -o so.o

flash.o : flash.s
    $(ARMGNU)-as $(AOPS) flash.s -o flash.o

blinker02.o : blinker02.c
    $(ARMGNU)-gcc $(COPS) -mthumb -c blinker02.c -o blinker02.o

blinker02.bin : flash.ld flash.o blinker02.o
    $(ARMGNU)-ld -o blinker02.elf -T flash.ld flash.o blinker02.o
    $(ARMGNU)-objdump -D blinker02.elf > blinker02.list
    $(ARMGNU)-objcopy blinker02.elf blinker02.bin -O binary

sols.bin : so.o
    $(ARMGNU)-ld -o sols.elf -T flash.ld so.o
    $(ARMGNU)-objdump -D sols.elf > sols.list
    $(ARMGNU)-objcopy sols.elf sols.bin -O binary

socl.bin : so.o
    $(ARMGNU)-ld -o socl.elf -Ttext=0x08000000 -Tbss=0x20000000 so.o
    $(ARMGNU)-objdump -D socl.elf > socl.list
    $(ARMGNU)-objcopy socl.elf socl.bin -O binary

命令行和链接描述文件socl和sols列表文件之间的区别是名称

diff sols.list socl.list
2c2
< sols.elf:     file format elf32-littlearm
---
> socl.elf:     file format elf32-littlearm

不要费心去展示你可能会看到的不同之处。

仅用于汇编,您不必担心无启动文件和其他命令行选项(在gcc上)。使用C对象。通过不允许链接器使用构建/配置的工具链(或者说C库)引导代码,你必须提供一个,如果你不使链接器脚本复杂化到特定目标文件被调出然后排序命令行上的对象很重要,如果你在makefile中的ld命令行上交换flash.o和blinker02.o,二进制文件将不起作用。你可以设置所有你想要的入口点,但那些是严格意义上的装载机,如果这是裸机,它似乎是入口点没用,硬件启动它如何启动,在这种情况下皮质m地址为零是在堆栈指针中加载的值,地址四是复位向量的地址(由于这是一个只有拇指的机器,因此设置为lsbit,让工具使用gnu汇编程序特定的thumb_func为您指示下一个标签是分支目的地地址。)

我将cortex-m0撒成一个,因为这是我从中获取此代码的两个原始armv4t和armv5t,或者在新手臂文档中调用的#34;所有拇指变体&#34;,是最便携的臂臂上的臂指令集。使用你的cortex-m4,你可以摆脱它,或者让它成为-m3或-m4来拉入armv7-m thumb2扩展。

所以简短的回答是

arm-none-eabi-ld -o so.elf -Ttext=0x08000000 -Tbss=0x20000000 so.o

绰绰有余的工作二进制文件假设您不需要.data。

.data需要更多的东西,链接器脚本,更复杂的引导程序等等。或者你做一个复制跳转的事情,编译REAL程序只在sram中运行(不同的入口点全尺寸臂式但是在ram基地址),然后编写一个特殊工具来获取该二进制文件并将其转换为说明.word 0xabcdef条目在一个程序中从flash复制到ram整个REAL程序然后分支,复制和跳转程序现在只是闪存没有.data和.bss真的需要并且可以使用命令行,所以REAL ram only program。我可能已经失去了你那个。

同样,使用命令行你不能或不应该假设.bss为零,你的引导程序也必须这样做。现在,如果你有.bss而没有.data,那么你肯定可以在分支到你的C程序入口点之前盲目地将所有ram归零(我使用notmain())因为至少有一个旧的编译器添加了不必要的垃圾。如果它看到一个main()函数,并强调通常没有关于名为main()的函数的魔力,那么二进制文件。)。

链接器脚本是特定于工具链的,因此没有理由期望gnu链接器脚本移植到Kiel移植到ARM(是的,我知道ARM现在拥有的Kiel指的是RVCT或现在的任何东西),等等。这就是首先是.data / .bss问题。理想情况下,你希望你的工具能够完成工作,所以他们知道bit .data和.bss是如何只是让他们告诉你,你如何让他们告诉你正在制作链接器脚本(至少用ld)并且这很棘手,但它会创建变量,如果您可以定义诸如.bss的起始地址,.bss的结束地址甚至一些数学来减去它们并获得长度,同样对于.data,然后在引导程序汇编语言中你可以将其归零.bss内存使用起始地址和长度,和/或起始地址和结束地址。对于.data,你需要两个地址,你把它放在flash(更多的链接器脚本foo)和它想要进入ram的位置,然后是bootstrap副本的长度。

所以基本上如果你写这段代码

unsigned int x=5;
unsigned int y;

并且您使用命令行链接器脚本,当输入使用这些变量的第一个C函数时,没有任何理由期望x为5或y为0。如果你假设x是5,那么你的程序就会失败。

如果你这样做

unsigned int x;
unsigned int y;
void myfun ( void )
{
   x=5;
   y=0;
}

现在这些赋值是.text中的指令而不是.data中的值,所以它总是工作命令行或不是简单的链接器脚本或复杂等等。