- 论坛徽章:
- 7
|
回复 3# liuyt1234
那是因为二楼的解释前半句是对的,(在我的理解看来)后半句是错的(就是关于printf这句)。其实出问题与拷贝了些什么是没有太大的关系的,虽然出问题的是cpy()这个函数,但是导致出段错误的是cpy()里memcpy()的目标而不是源,也就是buf这个变量,这个变量是在main()里传来的,所以我们关心的问题是main()函数,以下是我们使用return时候main()函数的反汇编结果:- 00000000004005d7 <main>:
- int main() {
- 4005d7: 55 push %rbp
- 4005d8: 48 89 e5 mov %rsp,%rbp
- 4005db: 48 83 ec 20 sub $0x20,%rsp
- char buf[10] = {0};
- 4005df: 48 c7 45 f0 00 00 00 movq $0x0,-0x10(%rbp)
- 4005e6: 00
- 4005e7: 66 c7 45 f8 00 00 movw $0x0,-0x8(%rbp)
- int length = 10;
- 4005ed: c7 45 ec 0a 00 00 00 movl $0xa,-0x14(%rbp)
- cpy(buf, &length);
- 4005f4: 48 8d 55 ec lea -0x14(%rbp),%rdx
- 4005f8: 48 8d 45 f0 lea -0x10(%rbp),%rax
- 4005fc: 48 89 d6 mov %rdx,%rsi
- 4005ff: 48 89 c7 mov %rax,%rdi
- 400602: e8 99 ff ff ff callq 4005a0 <cpy>
- printf("buf=%s\n", buf);
- 400607: 48 8d 45 f0 lea -0x10(%rbp),%rax
- 40060b: 48 89 c6 mov %rax,%rsi
- 40060e: bf e5 06 40 00 mov $0x4006e5,%edi
- 400613: b8 00 00 00 00 mov $0x0,%eax
- 400618: e8 53 fe ff ff callq 400470 <printf@plt>
- return -1;
- 40061d: b8 ff ff ff ff mov $0xffffffff,%eax
- }
- 400622: c9 leaveq
- 400623: c3 retq
- 400624: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
- 40062b: 00 00 00
- 40062e: 66 90 xchg %ax,%ax
复制代码 以下是我们使用exit()时的反汇编结果:- 0000000000400617 <main>:
- 400617: 55 push %rbp
- 400618: 48 89 e5 mov %rsp,%rbp
- 40061b: 48 83 ec 20 sub $0x20,%rsp
- 40061f: 48 c7 45 f0 00 00 00 movq $0x0,-0x10(%rbp)
- 400626: 00
- 400627: 66 c7 45 f8 00 00 movw $0x0,-0x8(%rbp)
- 40062d: c7 45 ec 0a 00 00 00 movl $0xa,-0x14(%rbp)
- 400634: 48 8d 55 ec lea -0x14(%rbp),%rdx
- 400638: 48 8d 45 f0 lea -0x10(%rbp),%rax
- 40063c: 48 89 d6 mov %rdx,%rsi
- 40063f: 48 89 c7 mov %rax,%rdi
- 400642: e8 99 ff ff ff callq 4005e0 <cpy>
- 400647: 48 8d 45 f0 lea -0x10(%rbp),%rax
- 40064b: 48 89 c6 mov %rax,%rsi
- 40064e: bf 25 07 40 00 mov $0x400725,%edi
- 400653: b8 00 00 00 00 mov $0x0,%eax
- 400658: e8 43 fe ff ff callq 4004a0 <printf@plt>
- 40065d: bf ff ff ff ff mov $0xffffffff,%edi
- 400662: e8 79 fe ff ff callq 4004e0 <exit@plt>
- 400667: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
- 40066e: 00 00
复制代码 你会看到,printf以前的代码都是一样的,我们的buf变量被分配到了栈的 -0x10处,也就是虽然你申明buf只有10个元素,但是(在我的机器上)你给他拷贝16个元素都不会出现段错误,但是一旦超过16个元素(远没有到36个字符这里),栈就要溢出了,但是栈溢出也不一定会出段错误,push %rbp 这句就是把原来的栈的地址保存在栈上,栈溢出的结果是这个保存在这儿的原来的栈就被冲调了,而我们调用return的时候产生的retq会试图返回到我们原来保存的栈的地址,但是这个地址用来自string里的内容给替换了(之前就说过这个内容是什么我们根本就不用关心,不过因为string被定义为"123456789123456789123456789123456789",去掉前16个字符,是"89123456789123456789",我的系统是64位,64位系统会使用8位的地址,所以替换以后的地址是"89123456",也就是3906085646303836472(前面8个字节对应的64位整数),这个数不知道指到哪儿去了,光对这个程序来说,这个地址不在这个程序的进程空间内,因此肯定是没有权限访问的,于是就段错误了),而另一边,调用exit的时候产生的是 callq 指令,我们知道exit()最终会直接退出系统,在这之前它都不会涉及任何无权访问的内存,因此不会出段错误。 |
|