我最近在 x64 上尝试堆栈溢出练习。在 x86 上执行此操作时,我预计垃圾覆盖地址会出现以下情况(例如“AAAA”):
ret,(覆盖的)返回地址将(有效)弹出到 EIP 寄存器中在 x64 中,这似乎有所不同(除了上述步骤中 EIP 与 RIP 的互换之外)。当提供“AAAAAAA”垃圾地址时,处理器似乎会在弹出该地址之前进行一些有效性检查。通过观察,在加载地址之前,似乎要求地址的两个最高有效字节为空。否则,会发生段错误。我相信这是由于 x64 中使用了 48 位寻址,但我的印象是以 0xFFFF 开头的地址也是有效的,但这也会产生段错误。
这是对差异的准确描述吗?为什么这个检查是在数据加载到RIP寄存器之前执行的,而另一个有效性检查是在数据加载到RIP寄存器之后执行的?这些说明之间还有其他差异吗?
编辑:为了澄清我的观察,我注意到当提供 8 字节返回地址时,RIP 仍然指向指令的地址ret,并且 RSP 仍然指向段错误时被覆盖的返回地址。当提供 6 字节返回地址时,当观察到段错误时,覆盖的地址已被弹出到 RIP 中。
采用以下Lua代码(我使用它,因为Lua在被解释之前被编译为字节码):
local myVar = "h";
local function printer()
print(myVar)
end;
printer();
myVar = 7;
printer();
Run Code Online (Sandbox Code Playgroud)
h然后,输出到新线,7.
由于语言的动态类型,我认为由于数据类型的改变,必须在内存中重新分配变量.继续这个假设,myVar必须在脚本的不同部分引用不同的地方.如果是这种情况,那么对我来说有必要printer编译两个版本:一个是预更改,一个是更改后.
我还认为每个变量可能都有一些分配给它的内存位置,并且可以检查给定的内存位置以找到变量值的当前分配位置.如果是这种情况,我想像表这样的引用类型有一个存储到引用位置的引用(双引用)?
那么,是否为可能运行的每个不同版本编译的函数?是否使用指针跟踪变量位置更改?或者是其他一些流程在这里发生?
这个问题哪个处理器将在muticore系统执行硬件中断及其答案似乎把重点放在这个但从操作系统的角度来看,但如何在CPU决定什么内核,能够实现硬件中断之前的OS介入?
在我迄今为止学到的关于分割的内容中:
所以,我的问题是:
基于我所读到的内容,虚拟地址被加载到段寄存器中,然后以某种方式从那里继续转换.在将虚拟地址加载到其中以获取描述符后,段寄存器会发生什么?
据我了解,段寄存器还包含描述符的缓存值.这在翻译过程中如何发挥作用?
系统如何确定要加载哪个段寄存器,假设段选择器最多可以有2 ^ 13个不同的值且只有6个主寄存器?