Linux 汇编程序如何初始化包含位置独立的其他变量地址的变量? 代码示例

Linux 汇编程序如何初始化包含位置独立的其他变量地址的变量? 代码示例,linux,assembly,linker,x86-64,Linux,Assembly,Linker,X86 64,在该示例中,我们可以说argv是一个指针数组,其中包含arg0、arg1、arg2和NULL(它们都只是一个指针) 但是,当它被编译为位置独立的代码/可执行文件时,编译时不知道与arg0、arg1、arg2相对应的地址 汇编程序如何初始化argv值,以便在运行时正确加载这些值?Linux共享对象的动态链接支持运行时修复,也称为“重新定位”。(即使在只读.text部分,但是.data已经读写了,所以让它被修改也不奇怪。)您完全正确:正如Peter Cordes已经提到的,您的代码片段将包含重定位。

在该示例中,我们可以说
argv
是一个指针数组,其中包含
arg0
arg1
arg2
NULL
(它们都只是一个指针)

但是,当它被编译为位置独立的代码/可执行文件时,编译时不知道与
arg0
arg1
arg2
相对应的地址


汇编程序如何初始化argv值,以便在运行时正确加载这些值?

Linux共享对象的动态链接支持运行时修复,也称为“重新定位”。(即使在只读
.text
部分,但是.data已经读写了,所以让它被修改也不奇怪。)您完全正确:正如Peter Cordes已经提到的,您的代码片段将包含重定位。这意味着代码并非“真正”独立于位置,但在启动代码之前,指针变量必须“更新”(例如,由操作系统更新)。我怀疑是否有可能在x86代码中初始化指针变量,使其结果“真正”独立于位置。@MartinRosenau:当然,您可以在运行时使用存储指令(在RIP相对LEA之后)初始化它。但是,根据定义,指针变量是一个绝对地址,对于可重定位的可执行/共享对象,在磁盘上的文件中不可能有正确的绝对地址。GCC
-fPIC
将构造使用相对偏移量而不是绝对地址的跳转表,但这不是一个选项,因为您实际上需要一个绝对地址数组作为系统调用的参数。@PeterCordes我明确提到了“x86”因为其他CPU可能有调用约定,其中指针变量不包含绝对地址,而是相对于代码中某个标签的地址。。。使用这样的调用约定,您可以初始化指针变量,并且代码实际上是位置独立的。PIC通常依赖于一个表,一个全局偏移表,该表构建为相对于.data的开头或相对于代码的只读位置固定(正在构建的代码本身是位置独立的,几乎可以在任何地方使用而不会出现问题)。因此,在一个已知位置有一个表,该表中包含动态列表。因此,假设argc是表中的条目3,您向该表添加了3个条目,然后使用该地址,而不是仅拥有该地址,因此这是一个间接层次。只需反汇编fPIC构建的测试程序即可显示这一点
.section .data
  arg0: .asciz "/bin/bash"
  arg1: .asciz "-c"
  arg2: .asciz "ls v* && echo hello"

  # How come these argv values initialized?
  argv: .quad arg0, arg1, arg2, 0

.section .text
.global _start

_start:
  xorl  %edx, %edx
  leaq  arg0(%rip), %rdi
  leaq  argv(%rip), %rsi
  movl  $59, %eax
  syscall