2016-12-28 110 views
0

我读过this tutorial为什么需要链接脚本和启动代码?

我可以按照指南运行代码。但我有问题。

1)为什么我们需要加载地址和运行时地址。据我了解,这是因为我们已经把闪存数据放在闪存上。那么为什么我们不在那里运行应用程序,但需要启动代码将其复制到RAM中?

http://www.bravegnu.org/gnu-eprog/c-startup.html

2)我们为什么需要链接脚本和启动代码在这里。我能不能像下面那样构建C源代码并使用qemu来运行它?

arm-none-eabi-gcc -nostdlib -o sum_array.elf sum_array.c 

非常感谢

回答

0

1)。数据部分包含变量。变量是可变的 - 它们在运行时会发生变化。变量需要在RAM中,以便在运行时可以轻松更改。闪存与RAM不同,在运行时不易更改。 Flash包含.data部分中变量的初始值。启动代码将.data段从闪存复制到RAM以初始化RAM中的运行时变量。

2)链接器脚本:由编译器创建的目标代码尚未位于微控制器的存储器映射中。这是链接器的工作,这就是为什么你需要链接器脚本。链接器脚本被输入到链接器,并提供有关系统内存位置和范围的一些说明。

启动代码:从main开始的C程序不是在真空中运行,而是对环境做出一些假设。例如,它假定在执行main之前初始化的变量已经被初始化。当执行main(即“运行时环境”)时,启动代码是必需的,以实现所有假定的所有事情。堆栈指针是在执行main之前在启动代码中初始化的另一个示例。如果您使用的是C++,则在执行main之前,会从启动代码中调用静态对象的构造函数。

0

1)为什么我们需要load-address和run-time地址。

尽管在大多数情况下可以从内存映射ROM中运行代码,但通常代码在内存中执行得更快。在某些情况下,ROM和应用程序代码可能会有更大的RAM压缩在ROM中,因此可执行代码可能不会简单地从ROM中复制,也可以解压缩 - 允许比可用ROM大得多的应用程序。

在代码存储在非内存映射大容量存储介质(如NAND闪存)中的情况下,它无法在任何情况下直接执行,必须通过某种引导加载程序加载到RAM中。

2)为什么我们需要链接脚本和启动代码。我能不能像下面那样构建C源代码并使用qemu来运行它?

链接描述文件定义您的目标和应用程序的内存布局。由于本教程是针对裸机编程的,因此没有OS为您处理。同样,启动代码至少需要设置一个初始堆栈指针,初始化静态数据并跳转到main。在嵌入式系统中,还需要初始化各种硬件,如PLL,存储器控制器等。

2

您的第一个问题已在指南中得到解答。

当您在操作系统上加载程序时,您的.data节(基本上非零全局变量)会从“binary”加载到内存中的右侧偏移量中,以便当程序启动那些内存位置代表你的变量有这些值。

unsigned int x=5; 
unsigned int y; 

作为一名C程序员,您编写了上面的代码,并且您希望x在您第一次使用时是5?那么,如果从闪存引导,裸机,你没有一个操作系统将这个值复制到你的RAM,有人必须这样做。进一步的所有.data的东西都必须在闪存中,数字5必须在闪存的某个地方,以便它可以复制到RAM。所以你需要一个flash地址和一个ram地址。两个地址为同一件事。

这就开始回答你的第二个问题,对于你编写的每一行C代码,你都假设任何函数都可以调用任何其他函数。你想能够调用函数是吗?而且你希望能够有局部变量,并且你希望上面的变量x为5,并且你可以假设y将为零,但是,幸好编译器开始警告这个问题。通用C的最小启动代码设置了堆栈指针,它允许你调用其他函数,并且有局部变量,并且函数的长度超过一行或两行代码,它将清零.bss,以便上面的y变量是零,它将值5复制到ram中,以便在运行入口点C函数的代码时x已准备就绪。

如果你没有操作系统,那么你必须有代码来做到这一点,是的,有许多许多沙箱和工具链设置为已经有启动和链接脚本的各种平台,以便你可以只是

gcc -O myprog.elf myprog.c 

现在,这并不意味着你可以使系统调用没有... ...系统的printf,FOPEN,等等。但是,如果你下载这些工具链的一个它意味着你不确实有写链接器脚本或引导程序。

但它仍然是有价值的信息,请注意启动代码和链接器脚本也是基于操作系统的程序所必需的,它只是针对您的操作系统的本机编译器假定您将主要为该操作系统编写程序,结果他们在该工具链中提供了链接器脚本和启动代码。