.so文件是否还包含label的信息
Does the .so file still contain infomation about label
编译器在哪个编译阶段将label
替换为实际的addr
我理解像 jmp abc
这样的指令,其中 abc
只是一个注释,最终会被替换为实际地址,对吗?
最终的 .so
文件是否仍然包含有关 label
的信息,或者 label
在加载到内存中时被替换为实际的 addr
?
最终的可执行文件必须包含所有地址,否则将无法运行。
要记住有静态链接和动态链接(例如使用共享库)。在静态链接二进制文件的情况下,所有地址都已解析。如果动态链接地址在加载期间解析,而二进制文件具有重定位信息,动态链接器将其替换为实际地址。但是到了一天结束时,内存中加载的二进制文件就有了所有地址。
In what phase of compilation does the compiler replace label into
actual addr
编译器在知道目标地址后可以用实际地址替换。例如,这是对同一编译单元中函数的调用。
当目标地址在编译单元之外并且编译器无法访问时,编译器会在目标文件中留下重定位信息。链接器同时将其替换为内存中的实际地址。
TL;DR - 你的问题很难回答,因为它混合了一些概念。对于典型的 assembler 标签,我们使用 PC 相关标签,标签在 assemble 时间解析。对于其他'external'个标签,情况较多,具体情况视情况而定。
在几乎所有 CPU 上,尤其是 ARM 上,有四种概念性的寻址方式。
- PC相对地址。当前指令 +/- 偏移量。
- 绝对地址。这就是您在概念上想到的那个。
- 注册计算地址。在 运行 时间计算。
ldr pc, [rn, #xx]
- Table 基于寻址。全局偏移量 table 等。很像寄存器计算地址。
ldr pc, [Rbase, Rindex, lsl #2]
前两个适合一条指令并且非常有效。第一个是最理想的,因为代码可以在 任何 地址执行,只要它保持其原始布局(即,您不通过拆分代码来加载它)。
上面的table中,还有'build time'和'run time'的概念。区别在于 linker 和 loader 之间的区别。您已标记此 'linux' 并引用 'so' 或共享库。此外,您指的是 assembler 'labels'。它们是非常相似的概念,但可以有所不同,因为它们将是上述四个 类 寻址之一。
通常在 assembler 中,标签与 PC 相关。除了保持代码块的连续性外,PC relative 没有额外的结构要实现。如果 assembler 是 'module'(编译单元,用于编译)或由 assembler 处理并生成 'object',它将使用PC 相对寻址。
对象格式可以用外部地址注释,assembler 输出这些地址的方式有很多选择。它们通常由 'psuedo-ops' 控制。那是目标文件中的注释(具有定义格式的单独部分);这种形式的说明是半完整的。它可能准备使用偏移量table,使用基于寄存器的计算(如r9
+常量)等
对于典型的链接情况(在构建时完成),我们将使用 PC 相对或绝对。如果我们将我们的二进制文件固定为仅在一个地址的 运行,则 assembler 可以设置绝对寻址并通过链接解决这些问题。在这种情况下,二进制文件必须加载到固定地址。 assembler 'modules' 或目标文件可以完全粘合在一起以解决所有问题。然后就没有 'load' 时间修复了。其他决定因素是 code/data 是否分开,以及系统是否正在使用 MMU。通常希望保持代码不变,以便许多进程可以使用相同的 RAM/ROM 页,但它们将具有不同的数据。除了内存效率之外,这还可以提供某种形式的安全性(尽管它不是非常健壮),它将防止意外的代码覆盖,并将以 SIGSEGV 的形式提供调试帮助。
可以编写一个 PC 相关的初始化例程,该例程将进行修复以在您自己的二进制文件中创建 table。所以一个'loader'只是确定你在运行ning的位置,然后进行计算。对于 静态 共享库,您通常知道您将要 运行 的库,但不知道它们在哪里。对于动态 共享库,您可能甚至在编译时都不知道您要运行.
的库是什么
A Linux 发行版可以使用任何一个。如果您有某种标准的 Linux 桌面发行版,(Ubuntu/Debian、Redhat 等)。您将拥有一些基于 ARM ELF LSB 和动态共享库的东西。您需要使用 assembler 伪操作来支持这种类型的寻址或使用编译器为您完成。共享库中的所有 'labels' 中的大部分将与 PC 相关并且不会显示。有些标签可能出于调试原因 (man strip
) 而显示,有些标签绝对需要在 运行 时解析地址。
我也问过一个问题,我之前发现相关,如果您想了解更多,Using GCC pre-processor as an assembler... So the key concept is that the assembler is generally 'two pass' and needs to do these local address fix ups. Then this question asks a 2nd level Concept A/B where we are adding shared libraries. The online book Linkers and Loaders 是一个很好的资源。
另请参阅:
- Static linked shared libraries
- Thumb start function
编译器在哪个编译阶段将label
替换为实际的addr
我理解像 jmp abc
这样的指令,其中 abc
只是一个注释,最终会被替换为实际地址,对吗?
最终的 .so
文件是否仍然包含有关 label
的信息,或者 label
在加载到内存中时被替换为实际的 addr
?
最终的可执行文件必须包含所有地址,否则将无法运行。
要记住有静态链接和动态链接(例如使用共享库)。在静态链接二进制文件的情况下,所有地址都已解析。如果动态链接地址在加载期间解析,而二进制文件具有重定位信息,动态链接器将其替换为实际地址。但是到了一天结束时,内存中加载的二进制文件就有了所有地址。
In what phase of compilation does the compiler replace label into actual addr
编译器在知道目标地址后可以用实际地址替换。例如,这是对同一编译单元中函数的调用。
当目标地址在编译单元之外并且编译器无法访问时,编译器会在目标文件中留下重定位信息。链接器同时将其替换为内存中的实际地址。
TL;DR - 你的问题很难回答,因为它混合了一些概念。对于典型的 assembler 标签,我们使用 PC 相关标签,标签在 assemble 时间解析。对于其他'external'个标签,情况较多,具体情况视情况而定。
在几乎所有 CPU 上,尤其是 ARM 上,有四种概念性的寻址方式。
- PC相对地址。当前指令 +/- 偏移量。
- 绝对地址。这就是您在概念上想到的那个。
- 注册计算地址。在 运行 时间计算。
ldr pc, [rn, #xx]
- Table 基于寻址。全局偏移量 table 等。很像寄存器计算地址。
ldr pc, [Rbase, Rindex, lsl #2]
前两个适合一条指令并且非常有效。第一个是最理想的,因为代码可以在 任何 地址执行,只要它保持其原始布局(即,您不通过拆分代码来加载它)。
上面的table中,还有'build time'和'run time'的概念。区别在于 linker 和 loader 之间的区别。您已标记此 'linux' 并引用 'so' 或共享库。此外,您指的是 assembler 'labels'。它们是非常相似的概念,但可以有所不同,因为它们将是上述四个 类 寻址之一。
通常在 assembler 中,标签与 PC 相关。除了保持代码块的连续性外,PC relative 没有额外的结构要实现。如果 assembler 是 'module'(编译单元,用于编译)或由 assembler 处理并生成 'object',它将使用PC 相对寻址。
对象格式可以用外部地址注释,assembler 输出这些地址的方式有很多选择。它们通常由 'psuedo-ops' 控制。那是目标文件中的注释(具有定义格式的单独部分);这种形式的说明是半完整的。它可能准备使用偏移量table,使用基于寄存器的计算(如r9
+常量)等
对于典型的链接情况(在构建时完成),我们将使用 PC 相对或绝对。如果我们将我们的二进制文件固定为仅在一个地址的 运行,则 assembler 可以设置绝对寻址并通过链接解决这些问题。在这种情况下,二进制文件必须加载到固定地址。 assembler 'modules' 或目标文件可以完全粘合在一起以解决所有问题。然后就没有 'load' 时间修复了。其他决定因素是 code/data 是否分开,以及系统是否正在使用 MMU。通常希望保持代码不变,以便许多进程可以使用相同的 RAM/ROM 页,但它们将具有不同的数据。除了内存效率之外,这还可以提供某种形式的安全性(尽管它不是非常健壮),它将防止意外的代码覆盖,并将以 SIGSEGV 的形式提供调试帮助。
可以编写一个 PC 相关的初始化例程,该例程将进行修复以在您自己的二进制文件中创建 table。所以一个'loader'只是确定你在运行ning的位置,然后进行计算。对于 静态 共享库,您通常知道您将要 运行 的库,但不知道它们在哪里。对于动态 共享库,您可能甚至在编译时都不知道您要运行.
的库是什么A Linux 发行版可以使用任何一个。如果您有某种标准的 Linux 桌面发行版,(Ubuntu/Debian、Redhat 等)。您将拥有一些基于 ARM ELF LSB 和动态共享库的东西。您需要使用 assembler 伪操作来支持这种类型的寻址或使用编译器为您完成。共享库中的所有 'labels' 中的大部分将与 PC 相关并且不会显示。有些标签可能出于调试原因 (man strip
) 而显示,有些标签绝对需要在 运行 时解析地址。
我也问过一个问题,我之前发现相关,如果您想了解更多,Using GCC pre-processor as an assembler... So the key concept is that the assembler is generally 'two pass' and needs to do these local address fix ups. Then this question asks a 2nd level Concept A/B where we are adding shared libraries. The online book Linkers and Loaders 是一个很好的资源。
另请参阅:
- Static linked shared libraries
- Thumb start function