【问题标题】:In Arm what order are parameters stored on the stack?在 Arm 中,参数存储在堆栈中的顺序是什么?
【发布时间】:2012-01-18 22:15:44
【问题描述】:

这是一道作业题。我正在尝试调用FOO(A,B,C,D,E,F) 形式的函数。前四个参数在寄存器r0-r3 中。最后两个在r7r6(分别)所以它们是倒退的。如何将参数推送到堆栈上,以便它们按正确的顺序排列?

STMFD sp! {r0-r3} 然后是STMFD sp! {r7, r6, lr}?我正在使用一个完整的降序堆栈。

this site 上的图表是否正确,因为如果最低的寄存器首先存储,STMFD r13!, {r4-r7} 不应该是r4 的位置r7 的位置?

【问题讨论】:

  • 你不能只交换寄存器值然后 stmfd r0-r3, r6,r7,lr 吗?
  • @MichaelDorgan:我认为这只是作业设定的人为约定。当没有结构返回时,ARM ABI(至少对于 iPhone)按 r0,r1,r2,r3,[sp],[sp,4],[sp,8],... 的顺序传递参数。 r6,r7 只是两个通用的持久寄存器。

标签: assembly stack arm


【解决方案1】:

在 ARM 中,寄存器列表的顺序无关紧要。它总是从最低的寄存器开始存储(R0, R1, R2, ...) 以下都是等价的(如果被汇编器接受的话):

STMFD SP!, {R0-R3}
STMFD SP!, {R3, R2, R1, R0}
STMFD SP!, {R1-R2, R0, R3}

【讨论】:

  • 如果是一个完整的降序堆栈,这意味着 R0 将在最高地址,R1 低地址,甚至 R2 低地址等?但前提是它们是使用一个 STMFD 推送的,例如STMFD sp! {R0-R3} 不同于做 STMFD sp! {R0} STMFD sp! {R1} STMFD sp! {R2} STMFD sp! {R3}
  • @quest4knoledge:不,不管STMxx的寻址方式,R0总是最低的。如果不确定,请阅读 ARM ARM,它包含如何执行 LDMxx/STMxx 的伪代码。
  • 好吧,我误解了你的意思“它总是从最低的寄存器开始存储”我以为你的意思是最低的寄存器会首先被存储,然后第二低的进入堆栈(因此是在较低的地址)。所以最低的寄存器首先被存储,因为它将位于堆栈的顶部(堆栈的顶部被认为是较低的地址)?
  • @quest4knoledge:只是最低的地址。栈顶在哪里无关紧要。
【解决方案2】:

为什么不试试呢?

unsigned int foo ( unsigned int a, unsigned int b, unsigned int c,
unsigned int d, unsigned int e, unsigned int f )
{

    return(a+b+c+d+e-f);

}

使用当前的 gcc 提供

00000000 <foo>:
   0:   e0810000    add r0, r1, r0
   4:   e080c002    add ip, r0, r2
   8:   e08c1003    add r1, ip, r3
   c:   e59d3000    ldr r3, [sp]
  10:   e59d2004    ldr r2, [sp, #4]
  14:   e0810003    add r0, r1, r3
  18:   e0620000    rsb r0, r2, r0
  1c:   e12fff1e    bx  lr

llvm 给出:

00000000 <foo>:
   0:   e0810000    add r0, r1, r0
   4:   e59d1000    ldr r1, [sp]
   8:   e0800002    add r0, r0, r2
   c:   e59d2004    ldr r2, [sp, #4]
  10:   e0800003    add r0, r0, r3
  14:   e0800001    add r0, r0, r1
  18:   e0400002    sub r0, r0, r2
  1c:   e1a0f00e    mov pc, lr

由于这是作业,我将由您决定是否可以使用带有多个寄存器的单个 stm/push 指令(如其他答案中所述,您不能使用多个寄存器控制堆栈上的顺序)或多个 stm/push 指令,每个指令一个寄存器。 (或弄清楚如何制作一个显示答案的测试程序)

了解约定是好的,但是您可以在不完整阅读约定的情况下回答此类问题,使用遵循约定的一两个编译器。基本上不要假设你从一些反汇编中了解有关约定的一切,例如你没有告诉我们 a,b,c,d,e,f 是否是 64 位整数、双浮点数、字节、半字、字等。多少堆栈上的东西肯定会受到影响,但是,以什么顺序以及是否可以使用带有多个寄存器的 stm/push 指令来获得它,可能会是一致的。

编辑:

是的,该网页是正确的,您需要获取并阅读 ARM ARM(现在每个系列都有单独的 ARM ARM(ARM 架构参考手册))。这些具有用伪代码等定义的指令。在这种情况下:

The registers are stored in sequence, the lowest-numbered register to the lowest
memory address (start_address), through to the highest-numbered register to the
highest memory address (end_address).

【讨论】:

  • “问机器”的问题是你不知道你使用的东西(无论是 CPU、编译器、DLL 还是其他)的行为是否会匹配下一个版本的行为。尤其是在进行前沿开发时:“我们修复了那个错误”。
【解决方案3】:

我认为肯尼的答案是正确的。

如果您还没有,我还找到了一些关于该主题的文档:ARM describes the most common calling convention hereThis website 还提供了 C 和 ASM 之间调用的详细信息(这反过来说明了调用约定)。

【讨论】:

  • 您的意思是“ARM 描述了最常见的……”;对于 IBM 可能声称的所有信用,ARM 它不是 ;-)
【解决方案4】:

寄存器按从低到高的顺序传输,因此 R15(如果在列表中)将始终最后传输。最低的寄存器也被传输到/从最低的内存地址。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    • 2012-11-18
    • 2012-01-31
    • 2013-07-28
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    相关资源
    最近更新 更多