我学习x86汇编是出于我自己的好奇心,想了解底层的东西,我偶然发现了这个很棒的here存储库,其中包含了很多可以从JavaScript shell运行的示例。
当我检查this hello world example时,有一个包含以下内容的链接器脚本:
ENTRY(mystart)
SECTIONS
{
. = 0x7c00;
.text : {
entry.o(.text)
*(.text)
*(.data)
*(.rodata)
__bss_start = .;
/* COMMON vs BSS: https://stackoverflow.com/questions/16835716/bss-vs-common-what-goes-where */
*(.bss)
*(COMMON)
__bss_end = .;
}
/* https://stackoverflow.com/questions/53584666/why-does-gnu-ld-include-a-section-that-does-not-appear-in-the-linker-script */
.sig : AT(ADDR(.text) + 512 - 2)
{
SHORT(0xaa55);
}
/DISCARD/ : {
*(.eh_frame)
}
__stack_bottom = .;
. = . + 0x1000;
__stack_top = .;
}
我不明白为什么它的确切要求?只是为了指定加载地址?我对链接器脚本的一般理解是,当有多个目标文件时,它们更有用,链接器脚本可用于定义如何将多个目标文件的部分组合到单个可执行文件中。
如果在这个例子中我没有指定链接器脚本会怎么样?(肯定至少有2个目标文件-一个来自.s
,另一个来自.c
)
1条答案
按热度按时间im9ewurl1#
请注意,这是一个裸金属示例,意味着没有操作系统。
安装在你电脑上的gnu工具链很可能是一个版本或者是为你的电脑而建的,包括操作系统。
因此,当您apt-get install build-essential然后
gcc hello.c -o hello
时,使用的链接器脚本是已安装工具链的一部分,并且特定于您的发行版Linux。(即使你从源代码构建工具链和libc,它也会检测主机,如果不是作为交叉编译器构建的,它会将该主机的股票引导和链接器脚本设置为默认值)当你找到并安装一个windows的gnu工具链时,隐藏在安装中的链接器脚本是特定于windows的。
但是当你想使用一个工具链作为一个交叉编译器时,在这种情况下,对于裸机,你需要为目标环境链接,这通常意味着带上你自己的链接器脚本,沿着,这一个像往常一样过于复杂,但至少他们提供了一个。
作为x86裸金属并使用x86主机进行开发,您可以(有时)使用本机编译器作为交叉编译器。同样,在arm主机上构建arm也是如此(例如raspberry pi)。
如果没有链接器脚本,当构建交叉编译的东西时,将使用默认脚本,如果你没有为你的目标定制默认脚本,那么你可能会得到一个无法工作的构建。
链接器脚本的工作主要是定义链接器的地址空间。我想要.文本在这个地址我想要.数据在这个地址等等.你可以用命令行而不用链接器脚本来完成这个任务,但是你想得到的越复杂,它就越简单,gnu ld在命令行和链接器脚本之间有一些问题(bug)。第二个原因是对于特定的语言,你有一个 Bootstrap ,一些语言假设需要在 Bootstrap 中得到满足,但是为了方便,你需要链接器作业的地址空间部分,以方便链接器脚本。你让链接器/工具为你做的工作。
所以对于C,假设. data被归零,.data被填充了你在调用代码入口点(通常是main(),但在裸机中你可以做任何想做的事情,通常不想使用那个函数名)之前要求的项目。作为一种省力的装置,你使用一个链接器把所有的项目放在你要求的地方,所以所有的文本和数据都在这里。它修补了函数之间的外部连接。但是现在链接器知道了. txt的位置和大小,例如,如何将其传达给 Bootstrap 代码?gnu和其他工具链提供了一种机制(gnu的解决方案不被期望移植到任何其他工具链,假设所有的链接器脚本语言都是自定义的工具链和不可移植的,所以你必须为每个工具链编写新的和新的 Bootstrap )。您可以在链接器脚本中创建变量,链接器将其填充为您所指定的任何内容,起始地址和结束地址.bss,或者您可以在链接器脚本中进行更多的数学运算,并获得起始地址和大小.bss,然后将该变量导入 Bootstrap 汇编语言代码(不能使用C,这是一个鸡和蛋的问题),现在 Bootstrap 可以将. bss清零。
因此,我称之为 Bootstrap 代码和链接器脚本之间的结合,出于多种原因,它们都是特定于工具链的,汇编语言是由汇编程序定义的,而不是目标,因此没有理由假设x86汇编语言用于一个工具链(这与英特尔与AT&T无关)与另一个工具链汇编程序兼容,第二,链接器脚本语言也不被假定为跨工具链可移植的并且专用于该工具链。因此,您使用的是特定于工具链的语言,以C为例,在调用任何编译代码之前,您必须执行一些任务。构成链接和引导的两个或多个文件是紧密相连的。
请注意,此示例还包含一些引导代码。我会寻找一个更干净的例子真实的汇编与内联,特别是因为有一个汇编语言文件在项目中,C部分本来可以演示C,而不是作为一个脚本内联汇编语言的东西。它似乎链接到一个教程,解释了发生了什么,所以也许所有这一切都解释。
裸金属的一个优点是你可以做任何你想做的事情,你有更少的规则来生活,所以这位作者做到了。我个人并不期望. data被归零,也不使用.data,所以我的非可移植部分,链接器脚本和 Bootstrap 就不那么复杂了。欢迎您使用自己的风格和偏好,感受裸金属编程之美。