x86_64架構下函式呼叫過程分析
阿新 • • 發佈:2019-01-26
//被分析的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)