位置相关代码和位置无关代码有什么区别?
还有我们如何通过示例实现/调用我们自己的静态和动态库?
与位置无关的代码可以在代码加载到内存中的任何位置正确运行。这通常是通过对函数调用使用相对跳转来实现的,相对跳转,跳转地址是从代码流中的当前位置计算出来的,所以代码可能看起来像:“从当前位置跳转 585 字节”或“跳转 5745 字节”从这个模块的基地址”而不是“跳转到地址 0x46fae55”。同样,对于引用内存地址的任何其他指令,必须相对于当前代码位置或相对于在运行时确定的基地址写入。
内存管理单元 (MMU) 和虚拟内存地址的使用使得与位置无关的代码对于可执行文件来说几乎是过时的。但是,共享库必须编写为与位置无关的代码,因为它们可以映射到可执行文件地址空间中的任何位置。
在早期的计算机中,代码是依赖于位置的:每个程序都被构建为加载到特定地址并从其运行。为了同时使用不同的程序运行多个作业,操作员必须仔细安排作业,以便没有两个同时的作业会运行需要相同加载地址的程序。
例如,如果工资单程序和应收账款程序都被构建为在地址 32K 上运行,那么操作员就不能同时运行这两个程序。有时,操作员会保留多个版本的程序,每个版本都针对不同的加载地址构建,以扩展他的选择。
为了使事情更灵活,发明了与位置无关的代码。与位置无关的代码可以从操作员选择加载它的任何地址运行。与位置无关的代码不仅用于协调用户级应用程序的工作,而且还用于操作系统内部。
补充一下 Lie Ryan 的答案——这不是 c 编程语言的问题,而是系统架构的问题。
例如,intel x86 分段架构支持半自动定位独立加载 .com 格式的小型可执行文件,其中操作系统可以将 cs=ds=es=ss 加载到 2^16 个不同的值。
OTOH 的 .exe 格式引入了“重定位”,这意味着在可执行文件中有一个偏移量数组(相对于二进制文件的加载地址),必须添加加载地址:例如。
relocation_table: // list of values to be modified
0022, 0100, ...
.text
0020: xx yy 12 00 mov ax,[0x0012] <-- the "absolute address" 0012 is
// located at address 0022 in the binary -- that has to be added with the real
// location of the the "position-independent" code