X86 为什么可以';你不能直接设置指令指针吗?

X86 为什么可以';你不能直接设置指令指针吗?,x86,cpu-registers,program-counter,X86,Cpu Registers,Program Counter,表示“程序员不能直接访问IP寄存器。” 直接指使用mov和add等指令 为什么不呢?这背后的原因是什么?技术限制是什么?您不能直接访问它,因为没有合法的用例。任意更改指令eip将使分支预测变得非常困难,并可能引发一系列安全问题 您可以使用jmp、call或ret编辑eip。您无法使用正常操作直接读取或写入eip 将eip设置到寄存器就像jmp eax一样简单。您还可以执行推送eax;ret,它将eax的值推送到堆栈,然后返回(即弹出和跳转)。第三个选项是calleax,它调用eax中的地址 阅读

表示“程序员不能直接访问IP寄存器。”

直接指使用mov和add等指令


为什么不呢?这背后的原因是什么?技术限制是什么?

您不能直接访问它,因为没有合法的用例。任意更改指令
eip
将使分支预测变得非常困难,并可能引发一系列安全问题

您可以使用
jmp
call
ret
编辑
eip
。您无法使用正常操作直接读取或写入
eip

eip
设置到寄存器就像
jmp eax
一样简单。您还可以执行
推送eax;ret
,它将
eax
的值推送到堆栈,然后返回(即弹出和跳转)。第三个选项是
calleax
,它调用eax中的地址

阅读可以这样做:

call get_eip
  get_eip:
pop eax ; eax now contains the address of this instruction

我认为这意味着IP寄存器不能像访问其他寄存器那样直接访问。程序员可以明确地向IP写入,例如通过发出跳转指令。

jmp
将设置
EIP
寄存器

此代码将eip设置为00401000:

mov eax, 00401000
jmp eax ;set Eip to 00401000
以及获取
EIP

call GetEIP
.
.
GetEIP:
mov eax, [esp]
ret

这可能是x86的一种设计。手臂可以。不过,这很不寻常

它允许一个非常紧凑的函数序言/尾声,以及用一条指令推送或弹出多个寄存器的能力:
push{r5,lr}
输入,并
pop{r5,pc}
返回。(将链接寄存器的保存值弹出到程序计数器中)

然而,它使高性能/无序的ARM实现变得不那么方便,并且在AARC64中被放弃


因此,这是可能的,但会占用其中一个寄存器。32位ARM有16个整数寄存器(包括PC),因此寄存器编号需要4位在ARM机器代码中编码。另一个寄存器几乎总是绑定为堆栈指针,因此ARM有14个通用整数寄存器。(LR可以保存到堆栈中,因此它可以并被用作函数体内的通用寄存器)

现代x86的大部分是从8086继承而来的。它采用相当紧凑的可变长度指令编码设计,只有8个寄存器,机器代码中每个src和dst寄存器只需要3位

在最初的8086中,它们不是非常通用的,在16位模式下,SP相对寻址是不可能的,因此基本上有两个寄存器(SP和BP)用于堆栈。这样就只剩下6个通用寄存器,如果其中一个是PC而不是通用寄存器,那么可用寄存器将大大减少,从而大大增加典型代码中的溢出/重新加载量


AMD64增加了r8-r15和RIP相对寻址模式<代码>lea rsi、[rip+任意],以及直接访问静态数据和常量的rip相对寻址模式,是高效位置无关代码所需的全部。间接JMP指令完全足以写入RIP

允许使用任意指令读取或写入PC实际上没有什么好处,因为您始终可以使用整数寄存器和间接跳转执行相同的操作。x86-64的R15与RIP完全相同,这几乎是一个纯粹的缺点,尤其是对于作为编译器目标的体系结构性能而言。(到2000年AMD64被设计时,手写的asm怪异的东西已经非常罕见了。)


因此,AMD64确实是x86第一次有可能获得一个完全公开的程序计数器,比如ARM,但是有很多理由不这样做。

也许你可以用它做同样的事情:
jmp XXX
@mystical,这是可能的,但是你可以间接访问它。另请参阅,以及相关问题。是的,没错。你经常会看到像
jmp[eax]
jmp[esp+4]
这样的东西用来实现动态调用或调用表。
mov-eax,offset-get\u-ip
会起作用吗?mov eax,$怎么样?不可否认,我已经很久没有写汇编语言了。你的第一段是假的。ARM64放弃了这一点,但这并没有使ARM32变得不可能。部分分支预测需要在指令解码之前进行,以避免获取气泡。在解码时,检测EIP是目标寄存器并将其标记为分支并不特别困难。因为安全性不依赖于扫描指令流来检测分支指令,所以没有任何安全含义。任何关于指令缓存、分支预测和其他奇特内容的解释在我看来都是可疑的,原因很简单:x86是作为微控制器体系结构诞生的,它没有这些虚饰。这并不是说他们剥夺了ip访问权,因为这使得向超标量体系结构过渡变得困难——它从一开始就不存在。可能他们没有添加它,因为已经有
jmp
来设置它,并且没有足够的令人信服的用例来添加特定的指令来读取它,或者从通用指令的mod reg rm字节中窃取宝贵的位;有一个非常真实的用例,它是标签的替代品。如果无法直接读取并保存eip,则需要计算字节数。能够获取指令指针,而无需根据相对“调用”进行公式化。如何在不使用标签而不计算字节数或编写自己的高级语言自动计算字节数的情况下实现这一点?@Dmitry:您必须知道跳转的位置,因此您需要一个绝对数字地址,或者您需要使用标签。(或cou)