我知道有rules来控制x86中堆栈指针的修改:
超出RSP当前地址的所有内存都被视为易失性:操作系统或调试器可能会在用户调试会话或中断处理程序期间覆盖此内存。因此,在尝试读取或写入堆栈帧的值之前,必须始终设置RSP。
我的问题是,ARM的规则是什么?我正在查看this代码(请参阅下面的摘录),看起来它违反了x86规则(修改内存然后更改了堆栈指针),但这是一个问题在ARM?
mov r4, sp
sub r4, r4, #128
...
mov r3, #116
1: ldr r7, [r2]
add r2, r2, #4
str r7, [r4]
dd r4, r4, #4
sub r3, r3, #4
cmp r3, #0
ne 1b
sub sp, sp, #128
我已经尝试了谷歌搜索,但找到一个描述在内联asm中修改ARM堆栈的规范是......具有挑战性。有一些关于ARM编译器和修改堆栈的文档,但是gcc的规则似乎不同。
答案 0 :(得分:1)
你所说的“规则”有点详细和具体。但是“规则”适用于几乎所有使用一个堆栈的处理器。
作为一般规则,您应该首先移动堆栈指针以“分配”您想要的堆栈空间,这就是您如何防止下一件事物被废弃。然后将其移回去分配。
对于ARM,可能是您链接的代码。您已经在寄存器中存储了寄存器,这是架构参考手册中的第一章(需要在分析或编写汇编语言之前阅读,特别是寄存器上的一张图片)。图片描述的异常模式都有自己的堆栈指针。因此,当例如发生中断时,一些其他堆栈指针用于保存状态,因此您的数据不会被破坏。
用户和系统共享堆栈指针,但这样内核等代码可以访问而不会陷入用户模式。系统不用于例外,因此您的代码不会停止并切换状态并破坏堆栈。
现在,ARM就像福特其他品牌一样。他们制造大型卡车小型卡车,SUV,小型车,爷爷车等.ARM拥有各种各样的处理器核心。 cortex-m适用于微控制器和其他小型狭小空间。它有一个堆栈,当发生异常时,它会为您保存堆栈中的状态,破坏您的数据。所以你指出的代码会很糟糕,因为你为什么要在cortex-m上使用printf?
编译器可以配置为使用或不使用第二个堆栈指针,x86世界用于这个想法(sp和bsp),但它不是必需的。要使(数据)堆栈有用,需要有一个堆栈指针和指令,用于引用堆栈的已使用部分,堆栈指针相对寻址。在某些平台上,您可以访问堆栈指针并使用另一个寄存器(进行复制)来访问堆栈帧,使堆栈指针自由地漫游。无论有没有在一般情况下触摸内联汇编中的堆栈指针是一个非常糟糕的主意,你需要很好地了解你的工具链和需要不断维护的代码,编译器的每个新版本或编译该代码的每个新系统在,你必须亲自检查产生的输出,以确保你的操作是安全的。如果你要达到那个级别,为什么要使用内联asm并烧掉所有这些工时(工作安全?)你会使用asm并在第一时间做出安全可靠的事情。如果您只想为该函数获取更多数据,只需创建一个局部变量,它就会改变sp上的减法,完成。无需内联汇编。如果您希望看到堆栈的末尾,请使用程序集而不是内联汇编。如果你想修改过去的堆栈指针或者因为某种原因而不使用局部变量而快速分配,那么再次使用程序集并在必要的系统上移动堆栈指针,以避免损坏你正在使用的数据。
除了崩溃系统之外,在内联汇编中弄乱堆栈指针并没有多大意义。与arm或x86无关或填空。
他们所做的是使用内联汇编在程序集中编写整个函数。这可能只是他们的构建系统选择的情况,你可以将程序集提供给gnu C编译器(如果使用内联汇编,你必须编写编译器特定代码,所以你已经知道你正在使用什么编译器)并生成一个对象就像你可以用C.还有其他方法,他们可以做到这一点,而不是丑陋。不幸的是,看到这个解决方案并不常见。如果在not-cortex-m上运行,那个代码是安全的,你不能在它的中间添加一个函数调用,因为你会丢弃你的数据,它们会在调用之前移动堆栈指针而不是向上移动像正常的解决方案前面。必须追查作者,询问“为什么他们这样做”的问题。
答案 1 :(得分:0)
ARM没有这样的规则。 CPU(至少Cortex-A / R CPU)在中断的情况下不会自动堆栈寄存器,即使对于Cortex-M,它也可以保证顺序。