1. 程式人生 > >x86_64架構下函式呼叫過程分析

x86_64架構下函式呼叫過程分析

//被分析的C程式
int
test1(int a1,int b1)
{
    int c1;
    c1 = a1+b1;
    return c1;
}

int
test2(int a2,char b2)
{
    int c2;
    c2 = test1(30,40);
    return c2;
}


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

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

    return main_c;
}

//通過gcc得到可執行檔案test.out
/* 通過命令:objdump -d test.out > func.txt 得到反彙編檔案; 結合圖1 “典型的儲存空間安排” 去看,可以知道以下各指令依次儲存在正文段中。 */ test.out: file format elf64-x86-64 Disassembly of section .init: 0000000000400390 <_init>: 400390: 48 83 ec 08 sub $0x8,%rsp 400394: 48 8b 05 5d 0c 20 00 mov 0x200c5d(%rip),%rax # 600
ff8 <_DYNAMIC+0x1d0> 40039b: 48 85 c0 test %rax,%rax 40039e: 74 05 je 4003a5 <_init+0x15> 4003a0: e8 2b 00 00 00 callq 4003d0 <__libc_start_main@plt+0x10> 4003a5: 48 83 c4 08 add $0x8,%rsp 4003a9: c3 retq Disassembly of section .plt: 00000000004003
b0 <__libc_start_main@plt-0x10>: 4003b0: ff 35 52 0c 20 00 pushq 0x200c52(%rip) # 601008 <_GLOBAL_OFFSET_TABLE_+0x8> 4003b6: ff 25 54 0c 20 00 jmpq *0x200c54(%rip) # 601010 <_GLOBAL_OFFSET_TABLE_+0x10> 4003bc: 0f 1f 40 00 nopl 0x0(%rax) 00000000004003c0 <__libc_start_main@plt>: 4003c0: ff 25 52 0c 20 00 jmpq *0x200c52(%rip) # 601018 <_GLOBAL_OFFSET_TABLE_+0x18> 4003c6: 68 00 00 00 00 pushq $0x0 4003cb: e9 e0 ff ff ff jmpq 4003b0 <_init+0x20> Disassembly of section .plt.got: 00000000004003d0 <.plt.got>: 4003d0: ff 25 22 0c 20 00 jmpq *0x200c22(%rip) # 600ff8 <_DYNAMIC+0x1d0> 4003d6: 66 90 xchg %ax,%ax Disassembly of section .text: 00000000004003e0 <_start>: 4003e0: 31 ed xor %ebp,%ebp 4003e2: 49 89 d1 mov %rdx,%r9 4003e5: 5e pop %rsi 4003e6: 48 89 e2 mov %rsp,%rdx 4003e9: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 4003ed: 50 push %rax 4003ee: 54 push %rsp 4003ef: 49 c7 c0 d0 05 40 00 mov $0x4005d0,%r8 4003f6: 48 c7 c1 60 05 40 00 mov $0x400560,%rcx 4003fd: 48 c7 c7 17 05 40 00 mov $0x400517,%rdi 400404: e8 b7 ff ff ff callq 4003c0 <__libc_start_main@plt> 400409: f4 hlt 40040a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 0000000000400410 <deregister_tm_clones>: 400410: b8 37 10 60 00 mov $0x601037,%eax 400415: 55 push %rbp 400416: 48 2d 30 10 60 00 sub $0x601030,%rax 40041c: 48 83 f8 0e cmp $0xe,%rax 400420: 48 89 e5 mov %rsp,%rbp 400423: 76 1b jbe 400440 <deregister_tm_clones+0x30> 400425: b8 00 00 00 00 mov $0x0,%eax 40042a: 48 85 c0 test %rax,%rax 40042d: 74 11 je 400440 <deregister_tm_clones+0x30> 40042f: 5d pop %rbp 400430: bf 30 10 60 00 mov $0x601030,%edi 400435: ff e0 jmpq *%rax 400437: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 40043e: 00 00 400440: 5d pop %rbp 400441: c3 retq 400442: 0f 1f 40 00 nopl 0x0(%rax) 400446: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 40044d: 00 00 00 0000000000400450 <register_tm_clones>: 400450: be 30 10 60 00 mov $0x601030,%esi 400455: 55 push %rbp 400456: 48 81 ee 30 10 60 00 sub $0x601030,%rsi 40045d: 48 c1 fe 03 sar $0x3,%rsi 400461: 48 89 e5 mov %rsp,%rbp 400464: 48 89 f0 mov %rsi,%rax 400467: 48 c1 e8 3f shr $0x3f,%rax 40046b: 48 01 c6 add %rax,%rsi 40046e: 48 d1 fe sar %rsi 400471: 74 15 je 400488 <register_tm_clones+0x38> 400473: b8 00 00 00 00 mov $0x0,%eax 400478: 48 85 c0 test %rax,%rax 40047b: 74 0b je 400488 <register_tm_clones+0x38> 40047d: 5d pop %rbp 40047e: bf 30 10 60 00 mov $0x601030,%edi 400483: ff e0 jmpq *%rax 400485: 0f 1f 00 nopl (%rax) 400488: 5d pop %rbp 400489: c3 retq 40048a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 0000000000400490 <__do_global_dtors_aux>: 400490: 80 3d 99 0b 20 00 00 cmpb $0x0,0x200b99(%rip) # 601030 <__TMC_END__> 400497: 75 11 jne 4004aa <__do_global_dtors_aux+0x1a> 400499: 55 push %rbp 40049a: 48 89 e5 mov %rsp,%rbp 40049d: e8 6e ff ff ff callq 400410 <deregister_tm_clones> 4004a2: 5d pop %rbp 4004a3: c6 05 86 0b 20 00 01 movb $0x1,0x200b86(%rip) # 601030 <__TMC_END__> 4004aa: f3 c3 repz retq 4004ac: 0f 1f 40 00 nopl 0x0(%rax) 00000000004004b0 <frame_dummy>: 4004b0: bf 20 0e 60 00 mov $0x600e20,%edi 4004b5: 48 83 3f 00 cmpq $0x0,(%rdi) 4004b9: 75 05 jne 4004c0 <frame_dummy+0x10> 4004bb: eb 93 jmp 400450 <register_tm_clones> 4004bd: 0f 1f 00 nopl (%rax) 4004c0: b8 00 00 00 00 mov $0x0,%eax 4004c5: 48 85 c0 test %rax,%rax 4004c8: 74 f1 je 4004bb <frame_dummy+0xb> 4004ca: 55 push %rbp 4004cb: 48 89 e5 mov %rsp,%rbp 4004ce: ff d0 callq *%rax 4004d0: 5d pop %rbp 4004d1: e9 7a ff ff ff jmpq 400450 <register_tm_clones> 00000000004004d6 <test1>: 4004d6: 55 push %rbp 4004d7: 48 89 e5 mov %rsp,%rbp 4004da: 89 7d ec mov %edi,-0x14(%rbp) 4004dd: 89 75 e8 mov %esi,-0x18(%rbp) 4004e0: 8b 55 ec mov -0x14(%rbp),%edx 4004e3: 8b 45 e8 mov -0x18(%rbp),%eax 4004e6: 01 d0 add %edx,%eax 4004e8: 89 45 fc mov %eax,-0x4(%rbp) 4004eb: 8b 45 fc mov -0x4(%rbp),%eax 4004ee: 5d pop %rbp 4004ef: c3 retq 00000000004004f0 <test2>: 4004f0: 55 push %rbp 4004f1: 48 89 e5 mov %rsp,%rbp 4004f4: 48 83 ec 18 sub $0x18,%rsp 4004f8: 89 7d ec mov %edi,-0x14(%rbp) 4004fb: 89 f0 mov %esi,%eax 4004fd: 88 45 e8 mov %al,-0x18(%rbp) 400500: be 28 00 00 00 mov $0x28,%esi 400505: bf 1e 00 00 00 mov $0x1e,%edi 40050a: e8 c7 ff ff ff callq 4004d6 <test1> 40050f: 89 45 fc mov %eax,-0x4(%rbp) 400512: 8b 45 fc mov -0x4(%rbp),%eax 400515: c9 leaveq 400516: c3 retq 0000000000400517 <main>: 400517: 55 push %rbp 400518: 48 89 e5 mov %rsp,%rbp 40051b: 48 83 ec 20 sub $0x20,%rsp 40051f: 89 7d ec mov %edi,-0x14(%rbp) 400522: 48 89 75 e0 mov %rsi,-0x20(%rbp) 400526: c7 45 f0 02 00 00 00 movl $0x2,-0x10(%rbp) 40052d: c7 45 f4 01 00 00 00 movl $0x1,-0xc(%rbp) 400534: c7 45 f8 03 00 00 00 movl $0x3,-0x8(%rbp) 40053b: be 14 00 00 00 mov $0x14,%esi 400540: bf 0a 00 00 00 mov $0xa,%edi 400545: e8 a6 ff ff ff callq 4004f0 <test2> 40054a: 89 45 fc mov %eax,-0x4(%rbp) 40054d: 8b 45 fc mov -0x4(%rbp),%eax 400550: c9 leaveq 400551: c3 retq 400552: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 400559: 00 00 00 40055c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000400560 <__libc_csu_init>: 400560: 41 57 push %r15 400562: 41 56 push %r14 400564: 41 89 ff mov %edi,%r15d 400567: 41 55 push %r13 400569: 41 54 push %r12 40056b: 4c 8d 25 9e 08 20 00 lea 0x20089e(%rip),%r12 # 600e10 <__frame_dummy_init_array_entry> 400572: 55 push %rbp 400573: 48 8d 2d 9e 08 20 00 lea 0x20089e(%rip),%rbp # 600e18 <__init_array_end> 40057a: 53 push %rbx 40057b: 49 89 f6 mov %rsi,%r14 40057e: 49 89 d5 mov %rdx,%r13 400581: 4c 29 e5 sub %r12,%rbp 400584: 48 83 ec 08 sub $0x8,%rsp 400588: 48 c1 fd 03 sar $0x3,%rbp 40058c: e8 ff fd ff ff callq 400390 <_init> 400591: 48 85 ed test %rbp,%rbp 400594: 74 20 je 4005b6 <__libc_csu_init+0x56> 400596: 31 db xor %ebx,%ebx 400598: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) 40059f: 00 4005a0: 4c 89 ea mov %r13,%rdx 4005a3: 4c 89 f6 mov %r14,%rsi 4005a6: 44 89 ff mov %r15d,%edi 4005a9: 41 ff 14 dc callq *(%r12,%rbx,8) 4005ad: 48 83 c3 01 add $0x1,%rbx 4005b1: 48 39 eb cmp %rbp,%rbx 4005b4: 75 ea jne 4005a0 <__libc_csu_init+0x40> 4005b6: 48 83 c4 08 add $0x8,%rsp 4005ba: 5b pop %rbx 4005bb: 5d pop %rbp 4005bc: 41 5c pop %r12 4005be: 41 5d pop %r13 4005c0: 41 5e pop %r14 4005c2: 41 5f pop %r15 4005c4: c3 retq 4005c5: 90 nop 4005c6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 4005cd: 00 00 00 00000000004005d0 <__libc_csu_fini>: 4005d0: f3 c3 repz retq Disassembly of section .fini: 00000000004005d4 <_fini>: 4005d4: 48 83 ec 08 sub $0x8,%rsp 4005d8: 48 83 c4 08 add $0x8,%rsp 4005dc: c3 retq /* 在對彙編進行分析之前,我們首先簡單介紹一下基本的彙編命令 */ 特殊用途的暫存器: ax:存放函式返回值 bp:存放棧底 sp:存放棧頂 ip:存放下一條執行指令 di,si:依次對應函式的第一個引數、第二個引數..... push %rbp 等價於://先把sp-2,再把rbp值mov進記憶體 sub 0x02,%rsp mov %rbp,(%rsp) pop %rbp 等價於: mov (%rsp),%rbp add 0x02,%rsp call指令:首先將返回地址壓入棧頂,然後跳轉,相當於push和jump ret指令則是將棧頂的返回地址彈出到eip,然後按對應指令繼續執行 leave 等價於: movl %ebp %esp pop %ebp /* 下面我們摘取最熟悉的main函式進行分析 */ 00000000004004d6 <test1>: /* 進入test1後,同樣進行當前棧底入棧儲存,但可以發現存在不同點:rsp不下偏,進行新的棧幀空間開闢。 這是因為test1函式不會繼續呼叫子函式,所以它使用的區域性變數不需要繼續使用。 */ 4004d6: 55 push %rbp 4004d7: 48 89 e5 mov %rsp,%rbp //同樣的,將儲存在暫存器中入參值寫入記憶體進行儲存 4004da: 89 7d ec mov %edi,-0x14(%rbp) 4004dd: 89 75 e8 mov %esi,-0x18(%rbp) //進行運算 4004e0: 8b 55 ec mov -0x14(%rbp),%edx 4004e3: 8b 45 e8 mov -0x18(%rbp),%eax 4004e6: 01 d0 add %edx,%eax 4004e8: 89 45 fc mov %eax,-0x4(%rbp) //ax暫存器被用來儲存函式返回值,所以把返回結果寫入eax暫存器 4004eb: 8b 45 fc mov -0x4(%rbp),%eax /*由於此時rsp沒有下偏開闢新的棧空間,因此rsp指向記憶體地址的值為呼叫函式的棧底, 因此通過pop將棧底暫存器值恢復成被呼叫函式棧底地址 */ 4004ee: 5d pop %rbp //將棧頂的返回地址彈出到eip,然後按對應指令繼續執行 4004ef: c3 retq 00000000004004f0 <test2>: /*當函式被呼叫時,主要工作包括: 1.儲存呼叫函式的棧幀情況,主要是棧底地址,因此需要將當前棧底地址push入棧。 2.儲存呼叫函式棧底後,被呼叫函式即以當前棧頂為棧底,隨後棧底下偏,相當於開闢一段棧空間給被呼叫函式使用。 */ 4004f0: 55 push %rbp //同樣的,進入後首先將棧底地址壓棧 4004f1: 48 89 e5 mov %rsp,%rbp 4004f4: 48 83 ec 18 sub $0x18,%rsp //同樣的,將儲存在暫存器中入參值寫入記憶體進行儲存 4004f8: 89 7d ec mov %edi,-0x14(%rbp) 4004fb: 89 f0 mov %esi,%eax 4004fd: 88 45 e8 mov %al,-0x18(%rbp) /* 如同main函式,test2內部也將呼叫一個子函式,為此將做相同的準備工作,包括: 1.將需要傳遞的引數從右向左依次存入對應的暫存器進行儲存和傳遞; 2.使用callq指令,呼叫test1; 3.callq指令首先把返回地址push壓棧,使得當函式返回時,可從該地址繼續執行,隨後jump至對應的記憶體地址(處於正文段)進行執行。 */ 400500: be 28 00 00 00 mov $0x28,%esi 400505: bf 1e 00 00 00 mov $0x1e,%edi 40050a: e8 c7 ff ff ff callq 4004d6 <test1> //從test1函式返回後,將返回值寫入ax暫存器儲存、傳遞 40050f: 89 45 fc mov %eax,-0x4(%rbp) 400512: 8b 45 fc mov -0x4(%rbp),%eax /*由於此時rsp下偏開闢新的棧空間,因此不能向test1中直接pop,需要使用leaveq命令; leaveq命令首先將rbp值複製給rsp,再pop,同樣的都是將棧底暫存器值恢復成被呼叫函式棧底地址 */ 400515: c9 leaveq //將棧頂的返回地址彈出到eip,然後按對應指令繼續執行 400516: c3 retq 0000000000400517 <main>: 400517: 55 push %rbp //首先把當前棧底壓入棧中,即將當前棧底指向的記憶體地址儲存下來 //下面兩句通過使改變rsp、rbp暫存器值來使棧頂和棧底指向不同的記憶體地址,相當於開闢了一段棧空間供呼叫函式使用,具體開闢多大,在編譯時就已經計算完畢。 400518: 48 89 e5 mov %rsp,%rbp //把rsp所儲存的棧頂地址賦值給rbp暫存器 40051b: 48 83 ec 20 sub $0x20,%rsp //rsp儲存的記憶體地址向下偏移0x20 //下面兩句將main函式的兩個入參分別寫入記憶體,進行儲存 40051f: 89 7d ec mov %edi,-0x14(%rbp) //把edi暫存器值放入rbp下偏0x14的記憶體地址中 400522: 48 89 75 e0 mov %rsi,-0x20(%rbp) //把rsi暫存器值放入rbp下偏0x20的記憶體地址中 //將函式內部定義的區域性變數依次寫入記憶體進行儲存 400526: c7 45 f0 02 00 00 00 movl $0x2,-0x10(%rbp) 40052d: c7 45 f4 01 00 00 00 movl $0x1,-0xc(%rbp) 400534: c7 45 f8 03 00 00 00 movl $0x3,-0x8(%rbp) /* 可以看到main函式即將呼叫子函式test2,為此將做一些準備工作,包括: 1.將需要傳遞的引數從右向左依次存入對應的暫存器進行儲存和傳遞; 2.使用callq指令,呼叫test2; 3.callq指令首先把返回地址push壓棧,使得當函式返回時,可從該地址繼續執行,隨後jump至對應的記憶體地址(處於正文段)進行執行。 */ 40053b: be 14 00 00 00 mov $0x14,%esi 400540: bf 0a 00 00 00 mov $0xa,%edi 400545: e8 a6 ff ff ff callq 4004f0 <test2> //從test2函式返回後,將儲存在ax中的被呼叫函式返回值寫入記憶體儲存 40054a: 89 45 fc mov %eax,-0x4(%rbp) //main函式返回值寫入ax暫存器 40054d: 8b 45 fc mov -0x4(%rbp),%eax //下面與test2中同理 400550: c9 leaveq 400551: c3 retq 400552: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 400559: 00 00 00 40055c: 0f 1f 40 00 nopl 0x0(%rax)