2012-08-23 61 views
4

我刚学完ARM架构/程序集。如果SP寄存器保存下一个存储位置的地址来存放数据,那么堆的地址是什么?例如,在C++中,如果你在堆上声明一个对象(例如MyObj example = new MyObj();),那么程序集看起来会是什么样子,从哪里知道example是哪里?什么寄存器指向堆?

+0

这是编译器的实现细节。 http://www.blackhat.com/presentations/bh-usa-07/Ferguson/Whitepaper/bh-usa-07-ferguson-WP.pdf –

+0

寄存器是CPU需要知道的事情。有一个SP寄存器,因为CPU有特殊的硬件,可以自动执行堆栈操作(例如,发生中断时保存上下文)。 CPU不知道或关心堆。 – TJD

+0

堆不是硬件的东西,堆栈是。 heap和堆内的分配与语言和库有关(与硬件无关)。 –

回答

5

在此上下文中的堆栈是由OS/EABI提供的较低级别的结构。这就是为什么有一个传统的注册表。但是,堆是OS提供的更高层次的结构。因此,管理和使用它取决于与您的应用程序和操作系统的协议。在汇编术语中,您将使用该堆通过寄存器取消引用一些地址。

+1

好,所以你说的CPU级别没有真正的堆概念? – Celeritas

+0

是的,就是这样。任何你正在玩(读/写)的内存都必须允许你这么做。这是操作系统的帮助,你可以通过malloc分配一些内存,或者你的应用程序已经告诉操作系统在可执行二进制文件中需要多少内存。然后,当您使用该内存时,您将开始取消引用包含您可以使用的区域地址的寄存器。 – auselen

+0

在ARM上,也没有像堆栈的真正硬件支持。在这方面,它与x86非常不同。 CPU本身并不知道“堆栈”是什么。而且你还需要操作系统支持堆栈区域,因为如果需要的话,内核必须增加你的堆栈。 –

5

SP寄存器通常用于跟踪堆栈中的当前位置。这意味着它总是需要指向堆栈。

同样不能说堆。当您需要访问变量时,该变量的地址将存储在您的应用的指针或其他内存引用中。在需要地址的时候,可以使用寄存器来做参考。但是哪个寄存器的细节不仅依赖于编译器,而且还可能取决于在从相同编译器优化代码之后哪个寄存器可用。

+0

想想看,为什么注册15(或者其他任何适用于ARM)的SP?为什么不登记?这是多快? – Celeritas

+0

为什么不是SP?堆栈需要一个受呼叫和返回影响的专用寄存器,该寄存器是SP。 –

+0

但是有什么区别。你需要一个专用的堆栈寄存器,但不是堆? – Celeritas

0

在ARM的EABI中,R13(SP)指向完全递减堆栈中的最后推送数据。然而,没有必要指出,在任何时候,这样的代码可以是合法的:

考虑到r0指向我们的程序可访问的有效内存位置。

stmfd r0!, {r1-r12, sp, lr} 
ldr r1, [r0] 
mov r2, lr 
sub lr, sp, #4 
str sp, [r4] 
add sp, lr, #4 
ldmfd r0!, {r1-r12, sp, pc} 

ofcourse它没有任何意义,但它是唯一的一点是,如果你可以安全地重新加载SP,LR和其他所有被调用函数保存的寄存器,你可以从头开始他们多,你想一边回忆恢复他们的价值在返回给调用者之前。另一点,堆栈和堆可能不一定相同,堆是malloc/free类型构造的更高级别的抽象,而堆栈仅用于在4个寄存器不足或用于传递函数参数时保存被调用寄存器,数据结构和所有你可以想象的,但堆栈有点难以管理,因为你必须自己跟踪所有的数据,而不是仅仅将一个区域分配给一个指针,然后在完成后释放它。

通常取决于程序和环境,您可以使用各种黑客和东西的优化技术,如明知腐败的一些非暂存寄存器,并摆脱它,但是你必须要管理,在您的来电显示功能,它应该是意识到在随后的函数调用中会被划伤的寄存器,因此EABI只有在将控制转移到另一个程序或接管时才有意义,您可以在CPU上执行您喜欢的任何操作,只需确保将其保留为干净它是在你进入这个地方之前。

1

处理器需要一个特殊的堆栈指针寄存器,因为有时(中断或异常)处理器硬件必须直接修改SP,而不执行任何代码。这对堆没有必要,所以不需要使用特殊寄存器来指向堆。在运行时,操作系统决定特定的代码块在堆中的存储位置,并且可以使用任何寄存器来保存该地址。