ARM中的函数

时间:2018-04-13 18:18:27

标签: assembly arm

我是ARM编程的新手,我不知道在我的函数开始时哪些寄存器要推送到堆栈。另外,我在哪里可以找到传递给函数的参数?谢谢!

1 个答案:

答案 0 :(得分:0)

为什么不试试这些工具很容易实现,它们符合调用约定,可以更容易地将您看到的内容与约定语言进行比较。

extern unsigned int more_fun ( unsigned int a, unsigned int b );
unsigned int fun0 ( unsigned int a, unsigned int b )
{
    return(more_fun(a+1,b+2)+3);
}

构建,反汇编和检查(最好是反汇编而不是试图通过编译器生成的汇编语言,但是如果你把-save-temps放在gcc命令行上,你就会得到它们。

arm-none-eabi-gcc -O2 -c so.c -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <fun0>:
   0:   e92d4010    push    {r4, lr}
   4:   e2811002    add r1, r1, #2
   8:   e2800001    add r0, r0, #1
   c:   ebfffffe    bl  0 <more_fun>
  10:   e8bd4010    pop {r4, lr}
  14:   e2800003    add r0, r0, #3
  18:   e12fff1e    bx  lr

当然,如果要调用其他函数,则必须保存返回地址。这表明r0是第二个参数r1,r0是返回值所在的寄存器。与r4有什么关系?这是因为约定要求堆栈64位对齐,以便在调用或返回之前推送或弹出偶数个寄存器(编译器不会始终保持堆栈64位对齐,BTW)。

extern unsigned int more_fun ( unsigned int a, unsigned int b );
unsigned int fun0 ( unsigned int a, unsigned long long b )
{
    return(more_fun(a+1,b+2)+3);
}

32位量很容易,64位他们做这样的事情

00000000 <fun0>:
   0:   e92d4010    push    {r4, lr}
   4:   e2821002    add r1, r2, #2
   8:   e2800001    add r0, r0, #1
   c:   ebfffffe    bl  0 <more_fun>
  10:   e8bd4010    pop {r4, lr}
  14:   e2800003    add r0, r0, #3
  18:   e12fff1e    bx  lr

第一个参数取r0,第二个是64位,所以它们跳过r1并使用r2 / r3,但由于这是从64位调整到32位以调用下一个函数,所以它们只使用r2。作为下一个函数的32位参数,需要在r1中,因此移动。

extern unsigned int more_fun ( unsigned int a, unsigned long long b );
unsigned int fun0 ( unsigned int a, unsigned long long b )
{
    return(more_fun(a+1,b+2)+3);
}

00000000 <fun0>:
   0:   e2922002    adds    r2, r2, #2
   4:   e92d4010    push    {r4, lr}
   8:   e2a33000    adc r3, r3, #0
   c:   e2800001    add r0, r0, #1
  10:   ebfffffe    bl  0 <more_fun>
  14:   e8bd4010    pop {r4, lr}
  18:   e2800003    add r0, r0, #3
  1c:   e12fff1e    bx  lr

r0-r3用于第一个参数,直到它们被消耗,之后它使用堆栈作为参数。如图所示,可以轻松地对函数进行原型设计,以确定您正在处理的编译器正在做什么,然后从中查看规范以查看编译器正在执行的操作。