首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在ARM程序集函数中访问4个以上的参数?

如何在ARM程序集函数中访问4个以上的参数?
EN

Stack Overflow用户
提问于 2013-02-25 16:22:58
回答 3查看 12K关注 0票数 8

在我的汇编函数中,有6个参数。当我试图访问第四个和第五个参数时,它们是错误的,这是我在手臂皮层-8a上的代码。

代码语言:javascript
复制
push {r4-r8,lr}
ldr r6, [sp]
ldr r7, [sp, #4]

我检查了sp内存,r4-r8有错误的值。但是,如果有3个或更少的参数,sp会给出正确的r4-r8值。我错过了什么吗?

EN

回答 3

Stack Overflow用户

发布于 2013-02-25 19:05:40

为什么不试试呢?

代码语言:javascript
复制
unsigned int fun ( unsigned int, unsigned int, unsigned int, unsigned int, unsigned int );
unsigned int myfun ( void )
{
return(fun(1,2,3,4,5));
}

组装后拆卸

代码语言:javascript
复制
> arm-none-eabi-gcc -O2 -c fun.c -o fun.o
> arm-none-eabi-objdump -D fun.o 

程序集输出

代码语言:javascript
复制
00000000 <myfun>:
   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:   e3a01002    mov r1, #2
  14:   e3a02003    mov r2, #3
  18:   e3a03004    mov r3, #4
  1c:   e3a00001    mov r0, #1
  20:   ebfffffe    bl  0 <fun>
  24:   e28dd00c    add sp, sp, #12
  28:   e49de004    pop {lr}        ; (ldr lr, [sp], #4)
  2c:   e12fff1e    bx  lr

前四个操作数按预期在寄存器r0-r3中。第五个操作数放在堆栈上。为什么编译器为操作数分配12个字节而不是4个字节,即看到函数的mystery...Perhaps更有意义:

代码语言:javascript
复制
unsigned int fun ( unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e )
{
    return(a+b+c+d-e);
}

拆装

代码语言:javascript
复制
arm-none-eabi-gcc -O2 -c fun.c -o fun.o
arm-none-eabi-objdump -D fun.o 

00000000 <fun>:
   0:   e0811000    add r1, r1, r0
   4:   e0812002    add r2, r1, r2
   8:   e59d0000    ldr r0, [sp]
   c:   e0823003    add r3, r2, r3
  10:   e0600003    rsb r0, r0, r3
  14:   e12fff1e    bx  lr

因此,被调用方只知道操作数是堆栈上的第一件事,而不关心调用方创建的堆栈帧。因此,为什么调用方分配12字节而不是4字节,这是一个谜。

代码语言:javascript
复制
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

看到编译器实际实现调用约定,可以更容易理解调用约定本身的读取。或者,如果您在您感兴趣的编译器上为您感兴趣的特定函数原型制作了这样的示例--您不需要阅读约定,您只需让您的调用方或被调用者--不管您感兴趣的是什么--匹配编译器正在为自己做的事情。

票数 12
EN

Stack Overflow用户

发布于 2013-02-25 16:46:05

额外的参数被传递到堆栈上,无论如何SP将它们指向函数的条目。在prolog中,您正在推送要保存的寄存器,这会更改SP,因此需要对其进行解释。

r4、r5、r6、r7、r8和lr是6个寄存器,因此需要将SP偏移量调整为6×4=24个字节。因此,请尝试以下几点:

代码语言:javascript
复制
push {r4-r8,lr}        // 6 regs are pushed
                       // SP is decremented by 6*4 = 24 bytes
ldr r6, [sp, #(0+24)]  // get first stack arg
ldr r7, [sp, #(4+24)]  // get second stack arg

如果您使用SP执行更多操作,例如为堆栈vars分配空间,您可能也必须考虑到这一点。

票数 10
EN

Stack Overflow用户

发布于 2016-06-24 15:30:17

装甲运兵车标准

aapcs.pdf 5.5参数传递包含答案。

这并不是非常容易理解,因为它是一种算法,但回答这个问题的关键部分似乎是:

C.5如果NCRN小于r4,且NSAA等于SP,则在核心寄存器和堆栈之间拆分参数。参数的第一部分被应用到核心寄存器中,从NCRN开始,一直到包括r3。参数的其余部分被复制到堆栈中,从NSAA开始。NCRN设置为r4,NSAA由参数的大小减去寄存器中传递的数量增加。现在已经分配了这个论点。

就像其他人说的,意味着4个寄存器+堆栈。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15071506

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档