不,EIP / IP 无法直接访问,但在位置相关代码中,它是链接时间常量,因此您可以使用附近(或远处)的符号作为立即数。
mov eax, nearby_label ; in position-dependent code
nearby_label:
要以位置无关的 32 位代码获取 EIP 或 IP:
call _here
_here: pop eax
; eax now holds the PC.
在比 Pentium Pro(或可能是 PIII)更新的 CPU 上,call rel32rel32=0 是特殊情况,不会影响返回地址预测器堆栈 http://blog.stuffedcow.net/2018/04/ras-microbenchmarks/#call0。因此,这在现代 x86 上既高效又紧凑,并且是 clang 用于 32 位位置无关代码的方式。
在旧的 32 位 Pentium Pro CPU 上,这会导致调用/返回预测器堆栈不平衡,因此更喜欢调用实际返回的函数,以避免对最多 15 个左右的未来分支进行错误预测ret
父函数中的说明。 (除非你不打算返回,或者很少返回,这并不重要。)不过,返回地址预测器堆栈将恢复。
get_retaddr_ppro:
mov eax, [esp]
ret ; keeps the return-address predictor stack balanced
; even on CPUs where call +0 isn't a no-op.
在 x86-64 模式下,可以使用 RIP-relative 直接读取 RIPlea
.
default rel ; NASM directive: use RIP-relative by default
lea rax, [_here] ; RIP + 0
_here:
MASM 或 GNU.intel_syntax
: lea rax, [rip]
AT&T 语法:lea 0(%rip), %rax