ARM架構下函數調用過程分析

1.被分析的C程序

#include <stdio.h>
#include <stdarg.h>

int
test1(int a1,int b1)
{
    int c1;
    c1 = a1+b1;
    return c1;
}

int
test2(int a2,int a3)
{
    int c1 = 0 ,c2;
    c2 = test1(a2,a3);
    return c1;
}

int 
test3(int n_val,...)
{
    va_list var_arg;
    int i,c;

    va_start(var_arg,n_val);

    for(i=0;i<n_val;i++)
    {
        c = va_arg(var_arg,int);
        printf("arg%d=%d\n",i,c);
    }

    va_end(var_arg);

}

int 
main(int argc,char **argv)
{

    int main_c;
    int x=12,y=1,z=3;
    main_c = test2(10,20);

    test3(1,2,3,4,5,6,7,8,9,10,11);
//  test3(3,110,1,2,3,4,5,6,7,8,9,12,154,12);
//  test3(7,x++,x++,x++,x++,x++,x++,x++);
//  test3(1,2,3);

    return main_c;
}

2.通過arm-linux-gcc得到可執行文件test.out

/*
通過命令:arm-linux-objdump -d test.out > func.txt 得到反彙編文件;
結合本文最下面給出的相關文檔鏈接中的 “典型的存儲空間安排” 去看,可以知道以下各指令依次存儲在正文段中。
*/

/*
在對彙編進行分析之前,我們首先簡單介紹一下基本的彙編命令
*/
fp:棧底寄存器
sp:棧頂寄存器
ldr r0, [pc,#4] ; 把pc+4內存地址的值給r0
str r1, [pc,#4] ; 把r1的值寫入pc+4內存地址
push,pop
lr:鏈接地址寄存器,存放下一條執行指令

/*
下面我們摘取最熟悉的main函數進行分析
*/

000084f8 <test1>:
    84f8:   e52db004    push    {fp}        ; (str fp, [sp, #-4]!)
    84fc:   e28db000    add fp, sp, #0
    8500:   e24dd014    sub sp, sp, #20
    8504:   e50b0010    str r0, [fp, #-16]
    8508:   e50b1014    str r1, [fp, #-20]
    850c:   e51b2010    ldr r2, [fp, #-16]
    8510:   e51b3014    ldr r3, [fp, #-20]
    8514:   e0823003    add r3, r2, r3
    8518:   e50b3008    str r3, [fp, #-8]
    851c:   e51b3008    ldr r3, [fp, #-8]
    8520:   e1a00003    mov r0, r3
    8524:   e28bd000    add sp, fp, #0
    8528:   e8bd0800    pop {fp}
    852c:   e12fff1e    bx  lr

00008530 <test2>:
    8530:   e92d4800    push    {fp, lr}
    8534:   e28db004    add fp, sp, #4
    8538:   e24dd010    sub sp, sp, #16
    853c:   e50b0010    str r0, [fp, #-16]
    8540:   e50b1014    str r1, [fp, #-20]
    8544:   e3a03000    mov r3, #0
    8548:   e50b3008    str r3, [fp, #-8]
    854c:   e51b0010    ldr r0, [fp, #-16]
    8550:   e51b1014    ldr r1, [fp, #-20]
    8554:   ebffffe7    bl  84f8 <test1>
    8558:   e50b000c    str r0, [fp, #-12]
    855c:   e51b3008    ldr r3, [fp, #-8]
    8560:   e1a00003    mov r0, r3
    8564:   e24bd004    sub sp, fp, #4
    8568:   e8bd8800    pop {fp, pc}

0000856c <test3>:
    856c:   e92d000f    push    {r0, r1, r2, r3}
    8570:   e92d4800    push    {fp, lr}
    8574:   e28db004    add fp, sp, #4
    8578:   e24dd010    sub sp, sp, #16
    857c:   e28b3008    add r3, fp, #8
    8580:   e50b3010    str r3, [fp, #-16]
    8584:   e3a03000    mov r3, #0
    8588:   e50b3008    str r3, [fp, #-8]
    858c:   ea00000c    b   85c4 <test3+0x58>
    8590:   e51b3010    ldr r3, [fp, #-16]
    8594:   e2832004    add r2, r3, #4
    8598:   e50b2010    str r2, [fp, #-16]
    859c:   e5933000    ldr r3, [r3]
    85a0:   e50b300c    str r3, [fp, #-12]
    85a4:   e3080690    movw    r0, #34448  ; 0x8690
    85a8:   e3400000    movt    r0, #0
    85ac:   e51b1008    ldr r1, [fp, #-8]
    85b0:   e51b200c    ldr r2, [fp, #-12]
    85b4:   ebffff6b    bl  8368 <_init+0x24>
    85b8:   e51b3008    ldr r3, [fp, #-8]
    85bc:   e2833001    add r3, r3, #1
    85c0:   e50b3008    str r3, [fp, #-8]
    85c4:   e51b2008    ldr r2, [fp, #-8]
    85c8:   e59b3004    ldr r3, [fp, #4]
    85cc:   e1520003    cmp r2, r3
    85d0:   baffffee    blt 8590 <test3+0x24>
    85d4:   e1a00003    mov r0, r3
    85d8:   e24bd004    sub sp, fp, #4
    85dc:   e8bd4800    pop {fp, lr}
    85e0:   e28dd010    add sp, sp, #16
    85e4:   e12fff1e    bx  lr

000085e8 <main>:
    85e8:   e92d4800    push    {fp, lr}
    85ec:   e28db004    add fp, sp, #4
    85f0:   e24dd038    sub sp, sp, #56 ; 0x38
    85f4:   e50b0018    str r0, [fp, #-24]
    85f8:   e50b101c    str r1, [fp, #-28]
    85fc:   e3a0300c    mov r3, #12
    8600:   e50b3008    str r3, [fp, #-8]
    8604:   e3a03001    mov r3, #1
    8608:   e50b300c    str r3, [fp, #-12]
    860c:   e3a03003    mov r3, #3
    8610:   e50b3010    str r3, [fp, #-16]
    8614:   e3a0000a    mov r0, #10
    8618:   e3a01014    mov r1, #20
    861c:   ebffffc3    bl  8530 <test2>
    8620:   e50b0014    str r0, [fp, #-20]
    8624:   e3a03005    mov r3, #5
    8628:   e58d3000    str r3, [sp]
    862c:   e3a03006    mov r3, #6
    8630:   e58d3004    str r3, [sp, #4]
    8634:   e3a03007    mov r3, #7
    8638:   e58d3008    str r3, [sp, #8]
    863c:   e3a03008    mov r3, #8
    8640:   e58d300c    str r3, [sp, #12]
    8644:   e3a03009    mov r3, #9
    8648:   e58d3010    str r3, [sp, #16]
    864c:   e3a0300a    mov r3, #10
    8650:   e58d3014    str r3, [sp, #20]
    8654:   e3a0300b    mov r3, #11
    8658:   e58d3018    str r3, [sp, #24]
    865c:   e3a00001    mov r0, #1
    8660:   e3a01002    mov r1, #2
    8664:   e3a02003    mov r2, #3
    8668:   e3a03004    mov r3, #4
    866c:   ebffffbe    bl  856c <test3>
    8670:   e51b3014    ldr r3, [fp, #-20]
    8674:   e1a00003    mov r0, r3
    8678:   e24bd004    sub sp, fp, #4
    867c:   e8bd8800    pop {fp, pc}


test.out:     file format elf32-littlearm


Disassembly of section .init:

00008344 <_init>:
    8344:   e1a0c00d    mov ip, sp
    8348:   e92ddff0    push    {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
    834c:   e24cb004    sub fp, ip, #4
    8350:   e91baff0    ldmdb   fp, {r4, r5, r6, r7, r8, r9, sl, fp, sp, pc}

Disassembly of section .plt:

00008354 <.plt>:
    8354:   e52de004    push    {lr}        ; (str lr, [sp, #-4]!)
    8358:   e59fe004    ldr lr, [pc, #4]    ; 8364 <_init+0x20>
    835c:   e08fe00e    add lr, pc, lr
    8360:   e5bef008    ldr pc, [lr, #8]!
    8364:   00008418    .word   0x00008418
    8368:   e28fc600    add ip, pc, #0
    836c:   e28cca08    add ip, ip, #32768  ; 0x8000
    8370:   e5bcf418    ldr pc, [ip, #1048]!    ; 0x418
    8374:   e28fc600    add ip, pc, #0
    8378:   e28cca08    add ip, ip, #32768  ; 0x8000
    837c:   e5bcf410    ldr pc, [ip, #1040]!    ; 0x410
    8380:   e28fc600    add ip, pc, #0
    8384:   e28cca08    add ip, ip, #32768  ; 0x8000
    8388:   e5bcf408    ldr pc, [ip, #1032]!    ; 0x408
    838c:   e28fc600    add ip, pc, #0
    8390:   e28cca08    add ip, ip, #32768  ; 0x8000
    8394:   e5bcf400    ldr pc, [ip, #1024]!    ; 0x400
    8398:   e28fc600    add ip, pc, #0
    839c:   e28cca08    add ip, ip, #32768  ; 0x8000
    83a0:   e5bcf3f8    ldr pc, [ip, #1016]!    ; 0x3f8

Disassembly of section .text:

000083a4 <_start>:
    83a4:   e3a0b000    .word   0xe3a0b000
    83a8:   e3a0e000    .word   0xe3a0e000
    83ac:   e49d1004    .word   0xe49d1004
    83b0:   e1a0200d    .word   0xe1a0200d
    83b4:   e52d2004    .word   0xe52d2004
    83b8:   e52d0004    .word   0xe52d0004
    83bc:   e59fc010    .word   0xe59fc010
    83c0:   e52dc004    .word   0xe52dc004
    83c4:   e59f000c    .word   0xe59f000c
    83c8:   e59f300c    .word   0xe59f300c
    83cc:   eaffffee    .word   0xeaffffee
    83d0:   ebffffe7    .word   0xebffffe7
    83d4:   00008680    .word   0x00008680
    83d8:   000085e8    .word   0x000085e8
    83dc:   00008344    .word   0x00008344

000083e0 <deregister_tm_clones>:
    83e0:   e92d4008    push    {r3, lr}
    83e4:   e59f0020    ldr r0, [pc, #32]   ; 840c <deregister_tm_clones+0x2c>
    83e8:   e59f3020    ldr r3, [pc, #32]   ; 8410 <deregister_tm_clones+0x30>
    83ec:   e0603003    rsb r3, r0, r3
    83f0:   e3530006    cmp r3, #6
    83f4:   98bd8008    popls   {r3, pc}
    83f8:   e59f3014    ldr r3, [pc, #20]   ; 8414 <deregister_tm_clones+0x34>
    83fc:   e3530000    cmp r3, #0
    8400:   08bd8008    popeq   {r3, pc}
    8404:   e12fff33    blx r3
    8408:   e8bd8008    pop {r3, pc}
    840c:   000107a4    .word   0x000107a4
    8410:   000107a7    .word   0x000107a7
    8414:   00000000    .word   0x00000000

00008418 <register_tm_clones>:
    8418:   e59f002c    ldr r0, [pc, #44]   ; 844c <register_tm_clones+0x34>
    841c:   e59f102c    ldr r1, [pc, #44]   ; 8450 <register_tm_clones+0x38>
    8420:   e92d4008    push    {r3, lr}
    8424:   e0601001    rsb r1, r0, r1
    8428:   e1a01141    asr r1, r1, #2
    842c:   e0811fa1    add r1, r1, r1, lsr #31
    8430:   e1b010c1    asrs    r1, r1, #1
    8434:   08bd8008    popeq   {r3, pc}
    8438:   e59f3014    ldr r3, [pc, #20]   ; 8454 <register_tm_clones+0x3c>
    843c:   e3530000    cmp r3, #0
    8440:   08bd8008    popeq   {r3, pc}
    8444:   e12fff33    blx r3
    8448:   e8bd8008    pop {r3, pc}
    844c:   000107a4    .word   0x000107a4
    8450:   000107a4    .word   0x000107a4
    8454:   00000000    .word   0x00000000

00008458 <__do_global_dtors_aux>:
    8458:   e59f3034    ldr r3, [pc, #52]   ; 8494 <__do_global_dtors_aux+0x3c>
    845c:   e92d4010    push    {r4, lr}
    8460:   e1a04003    mov r4, r3
    8464:   e5d32000    ldrb    r2, [r3]
    8468:   e3520000    cmp r2, #0
    846c:   18bd8010    popne   {r4, pc}
    8470:   ebffffda    bl  83e0 <deregister_tm_clones>
    8474:   e59f301c    ldr r3, [pc, #28]   ; 8498 <__do_global_dtors_aux+0x40>
    8478:   e3530000    cmp r3, #0
    847c:   0a000001    beq 8488 <__do_global_dtors_aux+0x30>
    8480:   e59f0014    ldr r0, [pc, #20]   ; 849c <__do_global_dtors_aux+0x44>
    8484:   ebffffbd    bl  8380 <_init+0x3c>
    8488:   e3a03001    mov r3, #1
    848c:   e5c43000    strb    r3, [r4]
    8490:   e8bd8010    pop {r4, pc}
    8494:   000107a4    .word   0x000107a4
    8498:   00000000    .word   0x00000000
    849c:   0000869c    .word   0x0000869c

000084a0 <frame_dummy>:
    84a0:   e92d4008    push    {r3, lr}
    84a4:   e59f3038    ldr r3, [pc, #56]   ; 84e4 <frame_dummy+0x44>
    84a8:   e3530000    cmp r3, #0
    84ac:   0a000002    beq 84bc <frame_dummy+0x1c>
    84b0:   e59f0030    ldr r0, [pc, #48]   ; 84e8 <frame_dummy+0x48>
    84b4:   e59f1030    ldr r1, [pc, #48]   ; 84ec <frame_dummy+0x4c>
    84b8:   ebffffb6    bl  8398 <_init+0x54>
    84bc:   e59f002c    ldr r0, [pc, #44]   ; 84f0 <frame_dummy+0x50>
    84c0:   e5903000    ldr r3, [r0]
    84c4:   e3530000    cmp r3, #0
    84c8:   0a000003    beq 84dc <frame_dummy+0x3c>
    84cc:   e59f3020    ldr r3, [pc, #32]   ; 84f4 <frame_dummy+0x54>
    84d0:   e3530000    cmp r3, #0
    84d4:   0a000000    beq 84dc <frame_dummy+0x3c>
    84d8:   e12fff33    blx r3
    84dc:   e8bd4008    pop {r3, lr}
    84e0:   eaffffcc    b   8418 <register_tm_clones>
    84e4:   00000000    .word   0x00000000
    84e8:   0000869c    .word   0x0000869c
    84ec:   000107a8    .word   0x000107a8
    84f0:   000106a8    .word   0x000106a8
    84f4:   00000000    .word   0x00000000

000084f8 <test1>:
    84f8:   e52db004    push    {fp}        ; (str fp, [sp, #-4]!)
    84fc:   e28db000    add fp, sp, #0
    8500:   e24dd014    sub sp, sp, #20
    8504:   e50b0010    str r0, [fp, #-16]
    8508:   e50b1014    str r1, [fp, #-20]
    850c:   e51b2010    ldr r2, [fp, #-16]
    8510:   e51b3014    ldr r3, [fp, #-20]
    8514:   e0823003    add r3, r2, r3
    8518:   e50b3008    str r3, [fp, #-8]
    851c:   e51b3008    ldr r3, [fp, #-8]
    8520:   e1a00003    mov r0, r3
    8524:   e28bd000    add sp, fp, #0
    8528:   e8bd0800    pop {fp}
    852c:   e12fff1e    bx  lr

00008530 <test2>:
    8530:   e92d4800    push    {fp, lr}
    8534:   e28db004    add fp, sp, #4
    8538:   e24dd010    sub sp, sp, #16
    853c:   e50b0010    str r0, [fp, #-16]
    8540:   e50b1014    str r1, [fp, #-20]
    8544:   e3a03000    mov r3, #0
    8548:   e50b3008    str r3, [fp, #-8]
    854c:   e51b0010    ldr r0, [fp, #-16]
    8550:   e51b1014    ldr r1, [fp, #-20]
    8554:   ebffffe7    bl  84f8 <test1>
    8558:   e50b000c    str r0, [fp, #-12]
    855c:   e51b3008    ldr r3, [fp, #-8]
    8560:   e1a00003    mov r0, r3
    8564:   e24bd004    sub sp, fp, #4
    8568:   e8bd8800    pop {fp, pc}

0000856c <test3>:
    856c:   e92d000f    push    {r0, r1, r2, r3}
    8570:   e92d4800    push    {fp, lr}
    8574:   e28db004    add fp, sp, #4
    8578:   e24dd010    sub sp, sp, #16
    857c:   e28b3008    add r3, fp, #8
    8580:   e50b3010    str r3, [fp, #-16]
    8584:   e3a03000    mov r3, #0
    8588:   e50b3008    str r3, [fp, #-8]
    858c:   ea00000c    b   85c4 <test3+0x58>
    8590:   e51b3010    ldr r3, [fp, #-16]
    8594:   e2832004    add r2, r3, #4
    8598:   e50b2010    str r2, [fp, #-16]
    859c:   e5933000    ldr r3, [r3]
    85a0:   e50b300c    str r3, [fp, #-12]
    85a4:   e3080690    movw    r0, #34448  ; 0x8690
    85a8:   e3400000    movt    r0, #0
    85ac:   e51b1008    ldr r1, [fp, #-8]
    85b0:   e51b200c    ldr r2, [fp, #-12]
    85b4:   ebffff6b    bl  8368 <_init+0x24>
    85b8:   e51b3008    ldr r3, [fp, #-8]
    85bc:   e2833001    add r3, r3, #1
    85c0:   e50b3008    str r3, [fp, #-8]
    85c4:   e51b2008    ldr r2, [fp, #-8]
    85c8:   e59b3004    ldr r3, [fp, #4]
    85cc:   e1520003    cmp r2, r3
    85d0:   baffffee    blt 8590 <test3+0x24>
    85d4:   e1a00003    mov r0, r3
    85d8:   e24bd004    sub sp, fp, #4
    85dc:   e8bd4800    pop {fp, lr}
    85e0:   e28dd010    add sp, sp, #16
    85e4:   e12fff1e    bx  lr

000085e8 <main>:
    85e8:   e92d4800    push    {fp, lr}  //將fp、lr壓入棧中保存
    //將fp指向當前棧頂+4,並使sp下偏,爲main函數開闢一段棧空間
    85ec:   e28db004    add fp, sp, #4  
    85f0:   e24dd038    sub sp, sp, #56 ; 0x38

    //下面兩句將main函數的兩個入參分別寫入內存,進行保存
    85f4:   e50b0018    str r0, [fp, #-24]
    85f8:   e50b101c    str r1, [fp, #-28]

    //保存局部變量
    85fc:   e3a0300c    mov r3, #12
    8600:   e50b3008    str r3, [fp, #-8]
    8604:   e3a03001    mov r3, #1
    8608:   e50b300c    str r3, [fp, #-12]
    860c:   e3a03003    mov r3, #3
    8610:   e50b3010    str r3, [fp, #-16]

    /*
    可以看到main函數即將調用子函數test2,爲此將做一些準備工作,包括:
    1.將需要傳遞的參數從左向右依次存入對應的寄存器進行保存和傳遞;
    2.使用bl指令,調用test2;
  */
    8614:   e3a0000a    mov r0, #10
    8618:   e3a01014    mov r1, #20
    861c:   ebffffc3    bl  8530 <test2>

    //將返回值寫入內存
    8620:   e50b0014    str r0, [fp, #-20]

    /*
        對於不定參函數來說,其參數個數無法確定,最開始無法直接分配
        棧空間。當參數個數大於4個時,需要在已經分配棧空間的基礎上從
        第4個參數開始壓棧,而前4個將依次保存在r0~r3寄存器中。
    */
    8624:   e3a03005    mov r3, #5
    8628:   e58d3000    str r3, [sp]
    862c:   e3a03006    mov r3, #6
    8630:   e58d3004    str r3, [sp, #4]
    8634:   e3a03007    mov r3, #7
    8638:   e58d3008    str r3, [sp, #8]
    863c:   e3a03008    mov r3, #8
    8640:   e58d300c    str r3, [sp, #12]
    8644:   e3a03009    mov r3, #9
    8648:   e58d3010    str r3, [sp, #16]
    864c:   e3a0300a    mov r3, #10
    8650:   e58d3014    str r3, [sp, #20]
    8654:   e3a0300b    mov r3, #11
    8658:   e58d3018    str r3, [sp, #24]
    865c:   e3a00001    mov r0, #1
    8660:   e3a01002    mov r1, #2
    8664:   e3a02003    mov r2, #3
    8668:   e3a03004    mov r3, #4
    866c:   ebffffbe    bl  856c <test3>

    8670:   e51b3014    ldr r3, [fp, #-20]
    8674:   e1a00003    mov r0, r3
    8678:   e24bd004    sub sp, fp, #4
    867c:   e8bd8800    pop {fp, pc}

這裏寫圖片描述

3.總結

1.對於程序典型的存儲空間分佈有進一步的理解,可以知道反彙編出的,或者說經過編譯、鏈接後的C程序形成一條條的彙編指令(值得注意的是同樣的C程序,在不同的CPU架構由不同編譯器所得的結果是不一樣)。形成的彙編指令所在的內存地址也已經分配完畢,保存在正文段。
2.隨後,程序開始依照內存地址和機器指令一步步執行程序,通過以上分析,這裏我們重點總結函數嵌套調用過程中棧空間的變化情況。
3.從存儲空間分佈圖可以看到,棧空間是由高地址往低地址生長的。
4.調用函數(如main)調用被調用函數(如test2)前,都將做一些準備工作,主要是將參數存入r0~r3寄存器中。當參數多於4個時,其它參數將採用直接壓棧的方式。從被調用函數的彙編代碼來看,當參數多於4個時,r0~r3寄存器也將馬上被壓入棧中,而參數少於4個時就不壓棧,速度上來看要快一些。
5.當進入被調用函數彙編後,首先會將fp,lr等寄存器值壓棧,保存目前棧幀狀態以便恢復。隨後fp指向當前棧頂,而棧頂下偏一定量,fp、sp的差值即表示爲被調用函數開闢的棧空間。定義的局部變量也在開闢的棧空間內使用。隨後的一系列運算不再展開敘述。

4.相關文檔鏈接

程序典型的存儲空間安排圖:

http://blog.csdn.net/sinat_26551021/article/details/79052470

ARM彙編指令:

http://blog.csdn.net/qqliyunpeng/article/details/45116615

函數調用過程探究:

http://www.cnblogs.com/bangerlee/archive/2012/05/22/2508772.html

x86_64架構下函數調用過程分析:

http://blog.csdn.net/sinat_26551021/article/details/79052541

X86-64寄存器和棧幀:

http://blog.csdn.net/u013737447/article/details/49154509

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章