该内容源码参考了 <深入理解计算机系统>[3.10.3]

学习该章节之前,一直有个疑问,Segmentation fault 这样的错误会具体引发的原因是啥, 可不可以从汇编代码的层面进行一个学习和了解. 所有就有了这篇文章, 纯属个人学习研究.

完整的测试源码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*


*/
char* gets(char* s)
{
        int c;
        char *dest  = s;


        // read c char write to dest memory;
        while((c = getchar()) != '\n' && c != EOF)
        {
                *dest++= c;
        }

        if(c == EOF && dest == s)
        {
                return NULL;
        }

        *dest++ ='\0';
        return s;
}


void echo(){
        char buf[8];
        gets(buf);
        puts(buf);
}

int main()
{

        echo();

        return 0;
}

编译过程,
shell>gcc -g  demo.c -o demo


程序编译成功后,随便输入几个字符, 可以正常的回显, 但是超过某个长度就会出现文章开始的问题, 那么新的问题来了,
这个长度是不是就是代码中定义的buf的长度呢,  会不会有其他问题发生,

验证思路:
1 通过汇编代码, 查看寄存器地址中的内容, 直接明了的去观察, 那么就存在一个对比的过程,
  第一遍的时候是正常的输入, 不会发生错误,
  第二遍会输入较长的内容,  对比寄存器中的值.

正常输入时,
在没有输入任何字符的时候, 相关的寄存器的值,
这个是在程序调用getchar() 函数前寄存器的值.

(gdb) i	r ebp
ebp    	       0xbfffea68	0xbfffea68
(gdb) x/16cb 0xbfffea68
0xbfffea68:	120 'x'	-22 '\352'	-1 '\377'	-65 '\277'	100 'd'	-124 '\204'	4 '\004'
8 '\b'
0xbfffea70:	0 '\000'        -106 '\226'	117 'u'	0 '\000'        -112 '\220'	-22 '\352'	-1 '\377
'	-65 '\277'


(gdb) i r esp
esp    	       0xbfffea50	0xbfffea50
(gdb) x/16cb 0xbfffea50
0xbfffea50:	-12 '\364'	-1 '\377'	-118 '\212'	0 '\000'        4 '\004'        -30 '\342'
-118 '\212'	0 '\000'
0xbfffea58:	-120 '\210'	-22 '\352'	-1 '\377'	-65 '\277'	-87 '\251'	-124 '\204'
4 '\004'        8 '\b'

(gdb) i r eax
eax    	       0xbfffea60	0xbfffea60
(gdb) x/16cb 0xbfffea60
0xbfffea60:	37 '%'	-98 '\236'	121 'y'	0 '\000'        28 '\034'	-21 '\353'	-1 '\377'
-65 '\277'
0xbfffea68:	120 'x'	-22 '\352'	-1 '\377'	-65 '\277'	100 'd'	-124 '\204'	4 '\004'
8 '\b'


开始调用getchar() 函数
此时有个隐藏的信息是, gets() 函数中, 参数s的地址是 0xbfffea60, 这个需要知道, 就是这个参数出现了问题,
gdb> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

在输入完成后,
再次查看寄存器的内容,

(gdb) x/16cb 0xbfffea68
0xbfffea68:	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'
0xbfffea70:	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'


(gdb) x/32cb 0xbfffea50
0xbfffea50:	96 '`'	-22 '\352'	-1 '\377'	-65 '\277'	4 '\004'        -30 '\342'	-118 '\2
12'	0 '\000'
0xbfffea58:	-120 '\210'	-22 '\352'	-1 '\377'	-65 '\277'	-87 '\251'	-124 '\204'
4 '\004'        8 '\b'
0xbfffea60:	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'
0xbfffea68:	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'



(gdb) x/16cb 0xbfffea60
0xbfffea60:	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'
0xbfffea68:	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'

对比发现 0xbfffea68 地址中的内容被改写了, 这个地址是程序被调用时的入栈地址, 在gets()函数内部把值改写了,
导致程序返回的时候,出现了问题,


如果用户输入了缓冲区大小内的内容后, 则器寄存器中的值为
(gdb) x/16cb 0xbfffea60
0xbfffea60:	97 'a'	97 'a'	97 'a'	97 'a'	97 'a'	0 '\000'        -1 '\377'	-65 '\277'
0xbfffea68:	120 'x'	-22 '\352'	-1 '\377'	-65 '\277'	100 'd'	-124 '\204'	4 '\004'
8 '\b'
可以发现 0xbfffea68地址中的值和原来的值是一致的, 此时程序退出则是正常的,

具体可以使用的空间的大小的问题, 什么时候,会触发返回地址被改写.

03-31 14:39