arm上的参数列表传递的分析(以android为例)

对于pc上的可变参数列表,比较容易理解:参数全部存储在栈上。所以:va_list p定义一个指针,va_start(p, arg_a)获取参数列表地址,该地址就是va_start第二个参数对应数据之后的地址,,在栈上表现为:arg_a+sizeof(arg_a). 此后根据参数类型,使用va_arg依次从指定的参数列表地址取数据。

但时对于arm上,一个会使用寄存器传递参数的平台,又回怎样处理的呢?

通过写一个简单的示例程序:

 int test(int a, ...){
       va_list p;
       va_start(p, a);
       printf("%d", va_arg(p, int));
       va_end(p);
  }

实际编译后如下:

 

.text:00000BE0 ; test(int, ...)
.text:00000BE0                 EXPORT _Z4testiz
.text:00000BE0 _Z4testiz                               ; CODE XREF: main+8p
.text:00000BE0
.text:00000BE0 var_1C          = -0x1C
.text:00000BE0 varg_r0         = -0x10
.text:00000BE0 varg_r1         = -0xC
.text:00000BE0 varg_r2         = -8
.text:00000BE0 varg_r3         = -4
.text:00000BE0
.text:00000BE0                 PUSH    {R0-R3}
.text:00000BE2                 PUSH    {R0-R2,LR}
.text:00000BE4                 LDR     R0, =(unk_2168 - 0xBEE)
.text:00000BE6                 ADD     R3, SP, #0x20+varg_r2
.text:00000BE8                 LDR     R1, [SP,#0x20+varg_r1]
.text:00000BEA                 ADD     R0, PC          ; format
.text:00000BEC                 STR     R3, [SP,#0x20+var_1C]
.text:00000BEE                 BLX     printf
.text:00000BF2                 ADD     SP, SP, #0xC
.text:00000BF4                 POP     {R3}
.text:00000BF6                 ADD     SP, SP, #0x10
.text:00000BF8                 BX      R3
.text:00000BF8 ; End of function test(int,...)

可以看到粗体部分,进行了2次push。而有所了解得程序员,我们知道一般只会push一次,即后面的那一个——用来保存寄存器状态和返回地址。

那么第一次是干什么呢?显然这和可变参数有关!

arm上使用寄存器传递参数时一般只是用r0~r3,因此,系统直接将其压入栈中!然后和一般函数一样的方式去保护可能会被覆盖的寄存器的状态。

将r0~r3压入栈中之后,如果还有更多的参数,则之前必须(应当)已经压入栈中,那么此时的状态就和pc上的类似了。如下所示

(高地址)

...

arg_5

arg_4

arg_3<---r3

arg_2<---r2

arg_1<---r1

arg_0<---r0

<需要保护的寄存器值>

...

(低地址)

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。