是否可以仅使用 GNU LD 命令行选项创建基本的裸机程序集 bootup/startup 程序
Is it possible to create a basic bare-metal Assembly bootup/startup program using only GNU LD command-line options
是否可以仅使用 GNU LD 命令行选项代替 Cortex-M4 目标的习惯 -T 脚本文件来创建基本的裸机程序集 bootup/startup 程序?
我查看了 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
你的答案就在那里 -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 链接器有点可笑,有时它会插入间隙,您可能有几千字节的程序,而不是像它应该的那样将它线性放置在地址处它会放一些,然后填充一些死的space,然后再放一些,从来没有弄清楚为什么但是对于极其有限的目标,链接描述文件(与命令行)所有其他因素保持不变,不会在输出。
编辑:
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 对象。通过不允许链接器使用 as-built/configured 工具链(或者说 C 库)bootstrap 代码,如果您不将链接器脚本复杂化到调用特定目标文件的程度,则必须提供一个那么命令行上对象的顺序很重要,如果您在 makefile 的 ld 命令行上交换 flash.o 和 blinker02.o,二进制文件将无法工作。你可以设置所有你想要的入口点,但那些是严格用于加载程序的,如果这是裸机,那么入口点是无用的,硬件引导它如何引导,在这种情况下使用 cortex-m地址 0 是要加载到堆栈指针中的值,地址 4 是复位向量的地址(设置了 lsbit,因为这是只有 thumb 的机器,让工具使用特定的 gnu 汇编程序为您完成 thumb_func表示下一个标签是分支目的地址)。
我洒了 cortex-m0 大约一个,因为这是我从中获取这段代码的地方,另外两个是原始的 armv4t 和 armv5t,或者在较新的 arm 文档 "all thumb variants" 中提到的,是最便携的跨 arm 内核的 arm 指令集。使用 cortex-m4,您可以摆脱它,或者将其设为 -m3 或 -m4 以引入 armv7-m thumb2 扩展。
所以简短的回答是
arm-none-eabi-ld -o so.elf -Ttext=0x08000000 -Tbss=0x20000000 so.o
如果您不需要 .data,则足以制作工作二进制文件。
.data 需要更多的东西,链接器脚本,更复杂的 bootstrap,等等。或者你做一个 copy-jump 的事情,将真正的程序编译为 运行仅在 sram 中(不同的入口点全尺寸 arm 样式但在 ram 基地址),然后编写一个 adhoc 工具来获取该二进制文件并将其转换为程序中的 .word 0xabcdef 条目,该程序从闪存复制到 ram 整个 REAL 程序然后分支,那个复制和跳转程序现在只有闪存,没有真正需要的.data 和.bss,可以使用命令行,REAL ram only 程序也可以。我可能已经在那件事上失去了你。
同样,使用命令行时,您不能或不应假定 .bss 已归零,您的 bootstrap 也必须这样做。现在,如果你有 .bss 而没有 .data,那么确保你可以在分支到你的 C 程序入口点之前盲目地将所有启动时的 ram 归零(我同时使用 notmain() 因为至少一个旧的编译器添加了不必要的垃圾到如果它看到 main() 函数,则为二进制文件,并强调通常情况下,名为 main() 的函数没有什么神奇之处。)。
链接器脚本是特定于工具链的,因此没有理由期望 gnu 链接器脚本移植到 Kiel 以移植到 ARM(是的,我知道 ARM 拥有 Kiel 现在指的是 RVCT 或现在的任何东西),等等。所以是第一个.data/.bss 问题。理想情况下,您希望您的工具能够完成工作,因此他们知道 .data 和 .bss 有多位,所以让他们告诉您,您如何让他们告诉您正在正确制作链接器脚本(至少使用 ld),这很棘手, 但它会创建变量,如果你愿意的话,它可以定义诸如 .bss 的起始地址、.bss 的结束地址之类的东西,甚至可以用一些数学方法来减去它们并获得长度,对于 .data 也是如此,然后在 bootstrap 汇编语言中您可以使用起始地址和长度、and/or 起始地址和结束地址将 .bss 内存归零。对于 .data 你需要两个地址,你把它放在闪存中的地方(更多链接描述文件 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 中的值,因此它始终可以在命令行工作,而不是简单的链接描述文件或复杂的等。
是否可以仅使用 GNU LD 命令行选项代替 Cortex-M4 目标的习惯 -T 脚本文件来创建基本的裸机程序集 bootup/startup 程序?
我查看了 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
你的答案就在那里 -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 链接器有点可笑,有时它会插入间隙,您可能有几千字节的程序,而不是像它应该的那样将它线性放置在地址处它会放一些,然后填充一些死的space,然后再放一些,从来没有弄清楚为什么但是对于极其有限的目标,链接描述文件(与命令行)所有其他因素保持不变,不会在输出。
编辑:
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 对象。通过不允许链接器使用 as-built/configured 工具链(或者说 C 库)bootstrap 代码,如果您不将链接器脚本复杂化到调用特定目标文件的程度,则必须提供一个那么命令行上对象的顺序很重要,如果您在 makefile 的 ld 命令行上交换 flash.o 和 blinker02.o,二进制文件将无法工作。你可以设置所有你想要的入口点,但那些是严格用于加载程序的,如果这是裸机,那么入口点是无用的,硬件引导它如何引导,在这种情况下使用 cortex-m地址 0 是要加载到堆栈指针中的值,地址 4 是复位向量的地址(设置了 lsbit,因为这是只有 thumb 的机器,让工具使用特定的 gnu 汇编程序为您完成 thumb_func表示下一个标签是分支目的地址)。
我洒了 cortex-m0 大约一个,因为这是我从中获取这段代码的地方,另外两个是原始的 armv4t 和 armv5t,或者在较新的 arm 文档 "all thumb variants" 中提到的,是最便携的跨 arm 内核的 arm 指令集。使用 cortex-m4,您可以摆脱它,或者将其设为 -m3 或 -m4 以引入 armv7-m thumb2 扩展。
所以简短的回答是
arm-none-eabi-ld -o so.elf -Ttext=0x08000000 -Tbss=0x20000000 so.o
如果您不需要 .data,则足以制作工作二进制文件。
.data 需要更多的东西,链接器脚本,更复杂的 bootstrap,等等。或者你做一个 copy-jump 的事情,将真正的程序编译为 运行仅在 sram 中(不同的入口点全尺寸 arm 样式但在 ram 基地址),然后编写一个 adhoc 工具来获取该二进制文件并将其转换为程序中的 .word 0xabcdef 条目,该程序从闪存复制到 ram 整个 REAL 程序然后分支,那个复制和跳转程序现在只有闪存,没有真正需要的.data 和.bss,可以使用命令行,REAL ram only 程序也可以。我可能已经在那件事上失去了你。
同样,使用命令行时,您不能或不应假定 .bss 已归零,您的 bootstrap 也必须这样做。现在,如果你有 .bss 而没有 .data,那么确保你可以在分支到你的 C 程序入口点之前盲目地将所有启动时的 ram 归零(我同时使用 notmain() 因为至少一个旧的编译器添加了不必要的垃圾到如果它看到 main() 函数,则为二进制文件,并强调通常情况下,名为 main() 的函数没有什么神奇之处。)。
链接器脚本是特定于工具链的,因此没有理由期望 gnu 链接器脚本移植到 Kiel 以移植到 ARM(是的,我知道 ARM 拥有 Kiel 现在指的是 RVCT 或现在的任何东西),等等。所以是第一个.data/.bss 问题。理想情况下,您希望您的工具能够完成工作,因此他们知道 .data 和 .bss 有多位,所以让他们告诉您,您如何让他们告诉您正在正确制作链接器脚本(至少使用 ld),这很棘手, 但它会创建变量,如果你愿意的话,它可以定义诸如 .bss 的起始地址、.bss 的结束地址之类的东西,甚至可以用一些数学方法来减去它们并获得长度,对于 .data 也是如此,然后在 bootstrap 汇编语言中您可以使用起始地址和长度、and/or 起始地址和结束地址将 .bss 内存归零。对于 .data 你需要两个地址,你把它放在闪存中的地方(更多链接描述文件 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 中的值,因此它始终可以在命令行工作,而不是简单的链接描述文件或复杂的等。