据说位置无关代码只使用相对位置而不是绝对位置,这分别在c和汇编中是如何实现的?
举char test[] = "string";
个例子,如何通过相对地址来引用呢?
在 C 中,与位置无关的代码是编译器实现的一个细节。请参阅您的编译器手册以确定它是否受支持以及如何支持。
在汇编中,与位置无关的代码是指令集架构的一个细节。请参阅您的 CPU 手册以了解如何读取 PC(程序计数器)寄存器、其效率如何,以及将代码地址转换为数据地址时推荐的最佳实践是什么。
现在,由于代码和数据在大多数现代操作系统上被分离到不同的页面中,位置相关数据已不那么流行了。这是实现自包含可执行模块的好方法,但如今最常见的此类事情是病毒。
在 x86 上,与位置无关的代码原则上如下所示:
call 1f
1: popl %ebx
紧随其后的是ebx
用作基指针,其位移等于要访问的数据和popl
指令地址之间的距离。
实际上它通常更复杂,通常可以使用一个小的 thunk 函数来加载 PIC 寄存器,如下所示:
load_ebx:
movl 4(%esp),%ebx
addl $some_offset,%ebx
ret
选择偏移量的地方,使得当 thunk 返回时,ebx
包含指向程序/库中指定特殊点的指针(通常是全局偏移表的开头),然后所有后续ebx
的 -relative 访问可以简单地使用之间的距离所需的数据和指定的特殊点作为偏移量。
在其他拱门上,原则上一切都相似,但可能有更简单的方法来加载程序计数器。许多只是让您将pc
orip
寄存器用作相对寻址模式中的普通寄存器。
在伪代码中,它可能看起来像:
lea str1(pc), r0 ; load address of string relative to the pc (assuming constant strings, maybe)
st r0, test ; save the address in test (test could also be PIC, in which case it could be relative
; to some register)
正如前面的答案所述,很大程度上取决于您的编译器和 CPU 架构。找出答案的一种方法是使用适当的标志(-PIC -S 表示 gcc)进行编译并查看您获得的汇编语言。