Assembly 将相同的值推送到堆栈上,ret的行为就会不同
在x-86中,如果您从寄存器(例如,%eax)推送一个值,然后返回,据我所知,程序将控制转移到与%eax处的值对应的地址 在程序的另一次运行中,如果您编辑了代码,以便通过不同的方式(例如,取消引用一个寄存器,将该值移动到另一个寄存器,然后推送该寄存器)推送到堆栈上,然后返回,则程序还应将控制权转移到与向右推送的值对应的地址 在程序的两次不同运行中,如果推送的值相等(即使它们不是以相同的方式推送的),那么程序在每次运行中的行为会相同吗 我无法显示我的代码,但我想确保我的概念思维是正确的,因为我的代码在一种情况下会抛出错误,但在另一种情况下不会。谢谢 例1: 例2:Assembly 将相同的值推送到堆栈上,ret的行为就会不同,assembly,x86,Assembly,X86,在x-86中,如果您从寄存器(例如,%eax)推送一个值,然后返回,据我所知,程序将控制转移到与%eax处的值对应的地址 在程序的另一次运行中,如果您编辑了代码,以便通过不同的方式(例如,取消引用一个寄存器,将该值移动到另一个寄存器,然后推送该寄存器)推送到堆栈上,然后返回,则程序还应将控制权转移到与向右推送的值对应的地址 在程序的两次不同运行中,如果推送的值相等(即使它们不是以相同的方式推送的),那么程序在每次运行中的行为会相同吗 我无法显示我的代码,但我想确保我的概念思维是正确的,因为我的代
func2也应该返回到func1,对吗?但是第二个示例不起作用是的,您可以不匹配call/ret并手动执行它们(在大量性能代码中),但是如果您不想中断任何操作,您必须正确地模拟它们(包括它们对堆栈指针所做的操作) 但第二个例子不起作用
push
/ret
相当于jmp
到一个绝对地址。(除性能外:它总是导致分支预测失误,并使call/ret预测器不匹配)
您跳到了正确的位置(大概),但忘记从堆栈中弹出返回地址。因此,您“返回”时ESP指向错误的位置。这很容易导致大多数呼叫者崩溃;他们自己的ret
可能会弹出错误的回信地址
(使用EBP作为帧指针的调用方,在leave
/ret
之前没有访问任何与ESP相关的内容,可能不会注意到。例如,如果调用方的asm是在调试模式下由C编译器生成的。即使如此,现代Linux在调用之前需要16字节堆栈对齐,并且在cal之后进行函数调用使您的func2
中断,其ESP将不再使用16字节对齐堆栈。如果您以这种方式违反ABI,某些libc函数可能会崩溃。)
通常,您会将事情描述为:
calltarget
=push$retaddr
;jmp target
;retaddr:
ret
=pop%tmp
;jmp*%tmp
。它是一个间接分支。
(将ret
视为编写pop%eip
的一种方式)
但是如果一个函数只有一个调用方,则可以对返回地址进行硬编码,并在调用后使用add$esp,4
/jmp,而不是ret
(通过不使用ret
从调用返回,再次破坏未来ret的分支预测)
或者用jmp
替换调用者的call
,并返回jmp
。这实际上使func2
在某些方面成为func1
的一部分。它不能从任何其他地方调用,因为它没有返回地址
获取返回地址(即在跳回之前将其从堆栈中移除)但是忽略它并总是跳转到func1
中的硬编码位置似乎没有什么用处。你的实验不是证明程序的行为不一样吗?除此之外,我不清楚你的第二种情况是什么-尝试并创建一个-你不必复制你正在编写的代码,但你必须发布最短的piece的代码可能会重新创建您的两个场景。嗯,我想我也想知道为什么会发生这种情况。至于代码,我将给出一个刚刚编辑的示例,谢谢!现在更清楚了。从概念上讲,您是对的,所以我仍然认为我们需要更多信息。在将其推到o之前,您确定eax
包含正确的值吗在堆栈中?顺便说一句,你也可以用jump检查一下。@kabanus:我认为这很清楚:他们在调用后用jmp替换了ret
(他们用push/ret模拟了这个过程),使堆栈不平衡。尽管在第二次查看时,他们在func1中隐藏了调用
,因此可能会将其替换为jmp
?IDK。
func1:
/* should push address onto stack when calling */
call func2
...
...
func2:
/* should pop address and transfer control back to func1 */
ret
func1:
...
...
func2:
/* %eax contains value equivalent to address from the first example */
pushl %eax
/* should pop %eax and transfer control to address contained in %eax */
ret