上一篇讲到子函数调用,这篇讲讲参数传递。先看下面一个小不点程序:test5.c

#include <stdio.h>
void f1(int p1)
{
}
void main()
{
  int d = 4;
  f1(d);
}

   然后编译:arm-linux-gnueabihf-gcc test.c -o test5

   然后看看汇编代码:arm-linux-gnueabihf-objdump -D test5


0000835c <f1>:
1    835c:       b480            push    {r7}

嚯,栈还预留这么多!真奢侈。
2   835e:       b083            sub     sp, #12
3    8360:       af00            add     r7, sp, #0

子函数f1来取主函数通过寄存器r0传过来的参数p1,并把它放到自己的栈上--也是一段内存:
4    8362:       6078            str     r0, [r7, #4]

由于函数f1什么也没干,接下来就恢复盏指针,再恢复r7寄存器并返回:
5    8364:       f107 070c       add.w   r7, r7, #12
6    8368:       46bd            mov     sp, r7
7    836a:       bc80            pop     {r7}

因为,f1自始至终都没有碰这个美少女lr,所以她还是主函数的:
8    836c:       4770            bx      lr
9    836e:       bf00            nop

00008370 <main>:
10    8370:       b580            push    {r7, lr}
11   8372:       b082            sub     sp, #8
12    8374:       af00            add     r7, sp, #0
13    8376:       f04f 0304       mov.w   r3, #4
14   837a:       607b            str     r3, [r7, #4]

把栈上的变量值搬到寄存器r0
15    837c:       6878            ldr     r0, [r7, #4]
16    837e:       f7ff ffed       bl      835c <f1>
17    8382:       f107 0708       add.w   r7, r7, #8
18    8386:       46bd            mov     sp, r7
19   8388:       bd80            pop     {r7, pc}
 20   838a:       bf00            nop

        读者会发现,10行-14行与《从最简单的实例学习ARM 指令集(三)》里的test4.c是一样的。15行是新加的,目的是为了参数传递:

       14行是把变量d的值,从寄存器r3搬到内存里--即栈上:

14   837a:       607b            str     r3, [r7, #4]

       15行是把栈上的变量值搬到寄存器r0,以供子函数f1来取,你说这多折腾哪!直接用r3来传递不就少折腾一次吗,真是的!

15    837c:       6878            ldr     r0, [r7, #4]

      分析到这里,大家就明白了,arm使用寄存器r0来传递参数的。我们知道arm有r0-r16总共17个寄存器,他们都能用来传递参数吗? 看下面的例子:test6.c

#include <stdio.h>
void f1(int p1, int p2, int p3, int p4)
{
}
void main()
{
  int d = 4;
  f1(d, d, d, d);
}

   然后编译:arm-linux-gnueabihf-gcc test.c -o test6

   然后看看汇编代码:arm-linux-gnueabihf-objdump -D test6

0000835c <f1>:
    835c:       b480            push    {r7}
    835e:       b085            sub     sp, #20
    8360:       af00            add     r7, sp, #0
    8362:       60f8            str     r0, [r7, #12]
    8364:       60b9            str     r1, [r7, #8]
    8366:       607a            str     r2, [r7, #4]
    8368:       603b            str     r3, [r7, #0]

    836a:       f107 0714       add.w   r7, r7, #20
    836e:       46bd            mov     sp, r7
    8370:       bc80            pop     {r7}
    8372:       4770            bx      lr

00008374 <main>:
    8374:       b580            push    {r7, lr}
    8376:       b082            sub     sp, #8
    8378:       af00            add     r7, sp, #0
    837a:       f04f 0304       mov.w   r3, #4
    837e:       607b            str     r3, [r7, #4]
    8380:       6878            ldr     r0, [r7, #4]
    8382:       6879            ldr     r1, [r7, #4]
    8384:       687a            ldr     r2, [r7, #4]
    8386:       687b            ldr     r3, [r7, #4]

    8388:       f7ff ffe8       bl      835c <f1>
    838c:       f107 0708       add.w   r7, r7, #8
    8390:       46bd            mov     sp, r7
    8392:       bd80            pop     {r7, pc}

    看看,蓝色文字标注的main函数和f1函数,果然main函数的四个参数(d, d, d, d)是通过r0, r1, r2, r3 传递到子函数f1里的!

     如果参数再多会怎么样?我们在下一篇文章里试试。

Logo

更多推荐