具有4个以上寄存器ARM组件的函数调用

时间:2015-11-06 03:56:02

标签: function assembly stack arm gnu

我试图将r0-r5传递给函数check。但是只有寄存器r0-r3通过引用复制。在我的主要功能中,我有这个代码。

    push {lr}
    mov r0, #1
    mov r1, #2
    mov r2, #3
    mov r3, #4
    mov r4, #5
    mov r5, #6
    bl check
    pop {lr}
    bx lr

在我的check函数中,我有这段代码。这是一个单独的文件,也不确定是否重要

    m: .asciz "%d, %d ~ (%d, %d, %d)
    ...
    push {lr}
    ldr r0, =m
    bl printf
    pop {lr}
    bx lr

此输出为2, 3 ~ (4, 33772, 1994545180)。我正在尝试学习装配所以你能用一些谷歌搜索解释答案,我知道我需要使用堆栈但是,我不知道如何使用它,并想了解如何。提前谢谢。

1 个答案:

答案 0 :(得分:1)

你可以尝试一下,看看

void check ( unsigned int, unsigned int, unsigned int, unsigned int, unsigned int );

void call_check ( void )
{
    check(1,2,3,4,5);
}

arm-linux-gnueabi-gcc -c -O2 check.c -o check.o arm-linux-gnueabi-objdump -D check.o

00000000 <call_check>:
   0:   e52de004    push    {lr}        ; (str lr, [sp, #-4]!)
   4:   e3a03005    mov r3, #5
   8:   e24dd00c    sub sp, sp, #12
   c:   e58d3000    str r3, [sp]
  10:   e3a00001    mov r0, #1
  14:   e3a01002    mov r1, #2
  18:   e3a02003    mov r2, #3
  1c:   e3a03004    mov r3, #4
  20:   ebfffffe    bl  0 <check>
  24:   e28dd00c    add sp, sp, #12
  28:   e8bd8000    ldmfd   sp!, {pc}

现在当然可以手动优化,仍然可以正常工作。也许他们保持堆栈在16字节/ 4字/ 64位边界上对齐是否是对堆栈指针进行额外12字节修改的原因?不知道。但除此之外,你可以看到你自然需要保存链接寄存器,因为你正在调用另一个函数。 r0 - r3是显而易见的,然后根据eabi,堆栈中的第一个东西是第5个字的参数值。

同样,对于您的检查功能,您可以简单地让编译器开始使用。如果您查看代码,r0将作为您的第一个参数进入,然后通过将其更改为printf的第一个参数来废弃它。你需要6个参数来传递printf。你需要将它们移动到第一个参数以检查是printf的第二个参数,第二个检查是printf的第三个参数,依此类推。因此代码必须执行该转换(其中两个现在位于堆栈中)。