推送和弹出寄存器内容时如何存储关联数据

时间:2016-12-16 23:35:10

标签: assembly x86

当调用POP时,CPU如何知道放回寄存器的值是什么?

如果是我们PUSH ECX,调用一些修改ECX内容的程序,然后调用POP ECXECX之间push的原始价值如何联系起来popnewList = line.rstrip('\n').split(',')[-2:] 说明?

是否有自动生成的附加指令来存储该值并将其与指令绑定?

2 个答案:

答案 0 :(得分:3)

PUSHPOP是非常简单的说明。他们只是存储或加载和修改ESP。

您可以使用不同的存储指令来播放某些内容,反之亦然。

他们什么也没做,只比你在“操作”部分看到的那样(请参阅英特尔指令集参考的HTML摘录的链接,这是你想知道什么是指令时应该看到的内容)。有关最完整的索引,请参阅here;有关更多链接,请参阅代码Wiki。

由您来确保没有任何内容覆盖您推送以后要检索的内容的堆栈内存。请注意,允许函数修改堆栈中的args,因此您需要重做args的存储以使用相同的args再次调用相同的函数(除非您编写了该函数并且可以保证它不会破坏该内存)

  

是否自动生成其他说明

标准x86 asm语法没有任何伪指令可以汇编到多个机器指令。

典型的RISC系统可以轻松生成将任意32位常数放入寄存器所需的指令对。 MIPS asm语法甚至具有隐式使用寄存器的伪指令!

相反,x86的CISC设计使硬件处理所有这些复杂性。您可以将64位常量放入具有10字节mov rcx, 0x123456789ABCD的寄存器中。

答案 1 :(得分:1)

推送和弹出只是访问堆栈的方法,因此理解堆栈是关键。堆栈只是RAM。例如,对于全局变量,RAM中有一个内存位置(为了参数)专用于该变量。因此,当您访问(RAM版本)变量时,您正在读取和写入固定地址。但是使用局部变量(对于支持递归的语言),对于该函数的每个实例,您需要该变量的新副本。要递归地进行十次调用,您需要十个内存位置来存储该变量的十个副本。堆栈使这一点变得微不足道。您可以将其视为分配和释放内存,例如malloc()free(),但非常简化。

Push和pop就像在C中执行以下操作:

sp--;
*sp = x;
x = *sp; sp++;

CPU一无所知,也不关心保留原始值。您,程序员(间接通过编译器),要求完成的事情,并且在使用堆栈保存寄存器值的情况下,编译器或您直接使用汇编语言将使用push来“保存” “堆栈上的值”,并弹出“从堆栈中恢复值”。

程序员或编译器需要确保对堆栈指针的推送和弹出以及其他修改确保push ecxpop ecx在同一个ram地址上运行。如果这样做,则“如何知道CPU”ecx被写入地址X,并且稍后读取地址X并将值放在ecx中。对于全局变量,该变量的地址M是程序生命周期的固定地址。如果该变量的内容由于某种原因需要在寄存器中,则从M读取然后将其放回M.但是在使用堆栈时,您可以在一段时间内快速分配内存 - 比如说一个函数 - 输入函数,如果你想要32个字节,那么你只需要sp = sp-32,你现在只需要分配32个字节。然后,您可以通过推送(分配4个字节)将“{1}}”保存在堆栈中,或者将其保存在某个地址ecx。然后,在离开该函数之前,您可以阅读sp+8并将该值重新放回sp+8ecx是保存sp+8的地址X.

您可以在进入该函数时或在任何时候ecx,分配4个字节并将push ecx写入该地址X.如果您然后ecx,那么在地址X-4。稍后(如果你保持你的堆栈指针访问配对正确),当你push edx它将来自地址X-4,然后是来自X的pop edx。那么写到地址X-your原始值pop ecx - 现在已回读,ecx将恢复为原始值。