问题标签 [position-independent-code]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
gcc - gcc 和 ld 中与位置无关的可执行文件的 -fPIE 选项是什么?
它将如何更改代码,例如函数调用?
assembly - 如何判断跳跃是绝对的还是相对的?
我正在学习汇编测试,在“位置独立代码”主题中,我发现相对跳跃和绝对跳跃之间的区别令人困惑。我怎么知道它是一种什么样的跳跃?
我明白什么是相对跳跃(从当前行的偏移量)。但是绝对跳跃是什么样的?什么时候发生?
c - 为什么GCC根据文件创建共享对象而不是可执行二进制文件?
我有一个正在建造的图书馆。当我运行以下任一对象时,我的所有对象都会连续编译和链接:
ar rcs lib/libryftts.a $^
gcc -shared $^ -o lib/libryftts.so
在我的 Makefile 中。我也能够成功地将它们安装到/usr/local/lib
当我用 nm 测试文件时,所有功能都在那里。我的问题是,当我跑步gcc testing/test.c -lryftts -o test && file ./test
或gcc testing/test.c lib/libryftts.a -o test && file ./test
它说:
test: ELF 64-bit LSB shared object
而不是test: ELF 64-bit LSB executable
我所期望的。我究竟做错了什么?
c - 如何强制 gcc 在 PIC 代码中直接调用函数?
考虑以下函数:
这是 gcc-fpic
在 amd64 Linux 上生成的代码:
当我使用 编译时-fpic
,gcc 通过 PLT 显式调用以启用符号插入:
然而,这对于位置无关的代码并不是严格需要的,如果我不想支持,可以省略。如有必要,链接器无论如何都会将跳转目标重写为 PLT 符号。
我怎样才能在不更改源代码且不使编译后的代码不适用于共享库的情况下,使函数调用直接转到它们的目标而不是显式地通过 PLT?
c - 为什么用-fpic 和-pie 编译的程序有重定位表?
如果使用以下命令编译一个简单的程序:
并使用以下命令打印重定位条目:
有一堆重定位条目部分(见下文)。
由于 -fpic / -pie 标志导致编译器生成与位置无关的可执行文件,因此我天真的(并且显然不正确)假设是不需要重定位表,因为加载程序可以将可执行映像放置在任何地方而不会出现问题。那么为什么那里有一个重定位表,这是否表明代码实际上不是位置独立的?
assembly - 16 位实模式下的位置无关代码,引导加载/软盘读取
以下源文件分别组装(成原始二进制文件)并分别加载到虚拟软盘的扇区 1 和 2。然后,这张软盘用作 qemu-system-i386 VM 的引导介质。
“引导加载程序”从软盘的第 2 扇区读取“第一个程序”,然后跳转到包含刚刚读取的代码的内存。以下代码按需要工作(即打印“第一个程序”欢迎消息),但我必须ORG 0x001E
在“第一个程序”的源中指定(通过在十六进制编辑器中检查引导加载程序的代码获得)。0x001E 是temp
缓冲区的偏移量,它保存从软盘读取的代码。
“引导程序”:
“第一个程序”:
或者,我可以使用ORG 0x200
and0x200
代替缓冲区temp
(即在引导加载程序之后将程序加载到 RAM 中),但是在创建有用的操作系统时,这些黑客似乎都不可持续。如何避免这种地址硬编码?
c++ - 静态库中的 PIC 性能
我正在使用yaml-cpp
库,默认情况下会生成与位置相关的静态库 ( libyaml-cpp.a
)。我自己的库编译成两个版本,静态和共享。因为我需要共享一个,所以我必须打开 PIC yaml-cpp
(这是最简单的部分)。但是,现在我是否会在静态库中受到性能影响?如果是,有多大?
基本上,我有三个选择:
- 编译
yaml-cpp
两次,一次依赖于位置,一次编译,将适当的一次链接到我的共享和静态库中- 优点:可能是最好的性能,我的共享和静态都使用相同的目标文件(意味着 .cpp 只编译一次)
- 缺点:可能大多数设置,
yaml-cpp
将被编译两次,但这不重要,我不会改变它(经常)
- 编译
yaml-cpp
一次作为 PIC,将其链接到我的共享(PIC)和静态(非 PIC)- 优点:易于设置
- 缺点:源代码需要编译两次(共享(PIC),静态(非PIC))
- 编译
yaml-cpp
一次作为 PIC 并将我的(共享和静态)编译为 PIC- 优点:易于设置
- 缺点:静态性能受到轻微影响?
所以选项 1 似乎是最好的。我的摘要中有任何错误的假设吗?还是我错过了任何其他选择?
平台:amd64
linux - 共享库如何找到 GOT 部分?
当我阅读http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/#id1时, 问题来了:
PIC共享库在进程的虚拟地址空间中加载后如何知道如何引用外部变量?
这是有问题的共享库的代码:
生成目标代码,然后共享对象(库):
shara_func
在共享库中 反汇编:
我看到0x6d4地址处的指令将一些相对于PC的地址移动到rax
,我想这是 GOT 中的条目,GOT 从PC相对引用以在运行时获取外部变量的地址var
(它在运行时解析,具体取决于var
加载的位置) . 然后在0x6db执行指令后,我们将外部变量的实际内容放在rax中,然后将值从rax移动到rsi - 在寄存器中传递的第二个函数参数。
我在想进程内存中只有一个 GOT,但是,看到库引用 GOT 了吗?当共享库(PIC 库)不知道它将在进程内存中加载的位置时,它如何知道进程 GOT 的偏移量?还是每个共享库都有自己加载的 GOT?如果您能澄清我的困惑,我将非常高兴。
c - PIC代码和`ld -r`有什么区别?
我知道两者都用于制作可以放置在不同位置的代码,但是它们是如何工作的,为什么?
c - 如果缺少符号,请使用 `ld -r` 并获取编译错误
我最近开始使用新的 ELF loader。加载程序要求您将应用程序与ld -r
.
问题是 GCC 不再警告我未定义的函数,然后加载器(显然)找不到它们。
如何链接ld -r
,并获取未定义符号方法。
我ld -r
用于搬迁目的,因此包含搬迁的不同方式也适用于我。