Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 将相同的值推送到堆栈上,ret的行为就会不同_Assembly_X86 - Fatal编程技术网

Assembly 将相同的值推送到堆栈上,ret的行为就会不同

Assembly 将相同的值推送到堆栈上,ret的行为就会不同,assembly,x86,Assembly,X86,在x-86中,如果您从寄存器(例如,%eax)推送一个值,然后返回,据我所知,程序将控制转移到与%eax处的值对应的地址 在程序的另一次运行中,如果您编辑了代码,以便通过不同的方式(例如,取消引用一个寄存器,将该值移动到另一个寄存器,然后推送该寄存器)推送到堆栈上,然后返回,则程序还应将控制权转移到与向右推送的值对应的地址 在程序的两次不同运行中,如果推送的值相等(即使它们不是以相同的方式推送的),那么程序在每次运行中的行为会相同吗 我无法显示我的代码,但我想确保我的概念思维是正确的,因为我的代

在x-86中,如果您从寄存器(例如,%eax)推送一个值,然后返回,据我所知,程序将控制转移到与%eax处的值对应的地址

在程序的另一次运行中,如果您编辑了代码,以便通过不同的方式(例如,取消引用一个寄存器,将该值移动到另一个寄存器,然后推送该寄存器)推送到堆栈上,然后返回,则程序还应将控制权转移到与向右推送的值对应的地址

在程序的两次不同运行中,如果推送的值相等(即使它们不是以相同的方式推送的),那么程序在每次运行中的行为会相同吗

我无法显示我的代码,但我想确保我的概念思维是正确的,因为我的代码在一种情况下会抛出错误,但在另一种情况下不会。谢谢

例1:

例2:


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