//被分析的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 # 600ff8 <_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:
00000000004003b0 <__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)
x86_64架构下函数调用过程分析
最新推荐文章于 2022-11-30 16:16:48 发布