Gcc “与”的区别是什么;“加载地址”;及;搬迁地址;?

Gcc “与”的区别是什么;“加载地址”;及;搬迁地址;?,gcc,linker,ld,Gcc,Linker,Ld,关于ld的AT(…)指令,声明: AT(ldadr) AT关键字后面的表达式ldadr指定节的加载地址。默认设置(如果不使用AT关键字)是使加载地址与重新定位地址相同。此功能旨在使ROM映像的构建变得简单。 我一直在搜索,但没有找到“加载地址”和“重新定位地址”的明确定义 我知道,当对象文件链接在一起时,代码被“重新定位”,跳转地址等被重写,以指向组合机器代码中的正确偏移量。那么,“重新定位地址”是一个区段开始的结果目标代码中的偏移量吗?如果是这样的话,一个节的“加载地址”怎么可能是不同的呢

关于
ld
AT(…)
指令,声明:

AT(ldadr)
AT关键字后面的表达式ldadr指定节的加载地址。默认设置(如果不使用AT关键字)是使加载地址与重新定位地址相同。此功能旨在使ROM映像的构建变得简单。

我一直在搜索,但没有找到“加载地址”和“重新定位地址”的明确定义

我知道,当对象文件链接在一起时,代码被“重新定位”,跳转地址等被重写,以指向组合机器代码中的正确偏移量。那么,“重新定位地址”是一个区段开始的结果目标代码中的偏移量吗?如果是这样的话,一个节的“加载地址”怎么可能是不同的呢


如果这两个地址不同,链接器的输出会受到什么影响?

差异至关重要。重新安置地址添加到第节中的所有重新安置地址。所以,若它和加载地址不同,那个么在这一节中并没有什么真正起作用——这一节中的所有relocs都将被解析为错误的值

那么为什么我们需要这样的技术呢?没有太多的应用程序,但假设()在您的体系结构上有0x1000的极快内存

然后,您可以选择两个部分以获得重新定位地址0x1000:

.text0 0x1000 : AT (0x4000) { o1/*.o(.text) }
__load_start_text0 = LOADADDR (.text0);
__load_stop_text0 = LOADADDR (.text0) + SIZEOF (.text0);
.text1 0x1000 : AT (0x4000 + SIZEOF (.text0)) { o2/*.o(.text) }
__load_start_text1 = LOADADDR (.text1);
__load_stop_text1 = LOADADDR (.text1) + SIZEOF (.text1);
. = 0x1000 + MAX (SIZEOF (.text0), SIZEOF (.text1));
现在,在运行时继续,当您需要text1时,请自行管理它,以便从其实际加载地址复制到正确的地址:

extern char __load_start_text1, __load_stop_text1;
memcpy ((char *) 0x1000, &__load_start_text1,
      &__load_stop_text1 - &__load_start_text1);
然后使用它,因为它是在这里自然加载的。这种技术称为叠加


我认为,这个例子非常清楚。

经过一些搜索,我找到了一个更好的答案:

每。。。输出部分有两个地址。第一个是VMA,或 虚拟内存地址。这是该节将在何时提供的地址 将运行输出文件。第二个是LMA,或加载内存地址。 这是将加载节的地址。在大多数情况下 这两个地址将是相同的。这是一个关于他们何时可能会出现的例子 不同的是,将数据段加载到ROM中,然后进行复制 当程序启动时(这种技术通常用于 在基于ROM的系统中初始化全局变量)。在这种情况下 ROM地址将是LMA,RAM地址将是VMA

引自:

这意味着在类似以下的章节声明中:

section [address] [(type)] :
  [AT(lma)]
  [ALIGN(section_align) | ALIGN_WITH_INPUT]
  [SUBALIGN(subsection_align)]
  [constraint]
  {
    output-section-command
    output-section-command
    …
  } [>region] [AT>lma_region] [:phdr :phdr …] [=fillexp]

[address]
[AT(lma)]

Konstantin,谢谢你的例子。我想我能理解:链接代码中的所有跳转、调用等都是按照代码将在“重新定位地址”加载的方式计算的,但在运行时,它实际上是在“加载地址”加载的?那么,“加载地址”实际上是代码出现的对象文件中的偏移量吗?或者对象文件(ELF等)是否包含指令,告诉加载程序在运行时将代码放在内存中的什么位置?为了澄清我的问题,一旦链接器确定了某个节的“加载地址”,这将如何影响输出二进制文件?是的,如果您的目标是UNIX系统,则它是ELF格式的一部分好,我现在明白了。。。对于ELF文件中的每个段,都有一个“程序头”,其中包含文件内的偏移量及其加载地址。查看带有
readelf
vmlinux
Linux内核二进制文件,我可以看到它有3个部分,每个部分超过10个部分。这是否意味着引导加载程序将读取这些ELF头并在指定的“加载地址”加载每个段?实际上从未在os内核中尝试过。我想,内核不使用标准加载程序,引导加载程序可能会忽略ELF头中的某些内容或处理其他内容。我认为试着看看它们在哪里比较简单。非常感谢+1.