目标完成情况
- 两道算法题 --------- 没做
- 侯捷的视频 --------- 看了一点点
- 《深入理解计算机系统》3.10 ---- 看完了
- 《深入理解计算机系统》第7章-----没看
白天所学回忆
今天效率不是很高,没有严格执行作息表,白天主要学了csapp的3.10节,一节主要包含三个部分内容。
1. GDB调试器的使用
GDB调试器的使用需要对汇编语言有基本的认识,可以说是一种面向汇编的调试工具。
可以设置断点,单步执行等等,在观察程序运行的过程中,可以随时反汇编,观察机器代码,可以随时观察所有寄存器的状态。
我在linux下简单练习了一下,最后一个还遇到了未定义的引用的错误,这个问题浪费了我很多时间还没有修复,等到后面看链接的时候,应该能够恍然大悟吧。
2. 缓冲区溢出攻击
这个名词听起来高大上,但是只要理解了函数调用的原理,就很容易理解了。就是说,栈会分配一些空间来存放数据,例如数组,但是如果实际输入的数据量比分配的空间要大,那么就很有可能覆盖本函数调用之前入栈的返回地址,那么就会导致本函数ret之后,进入一个位置的地方,读取一段位置的数据,作为代码,开始执行。
缓冲区溢出攻击,就是利用缓冲区溢出做的攻击,比如说当我们给数组输入数据的时候,我们输入的数据的前几个其实是一段机器代码(病毒)的某种编码,然后,我们通过缓冲区溢出,用我的病毒代码的地址将原先的返回地址覆盖,这样在本函数返回的时候,就会将病毒代码的地址放入程序计数器PC,从而开始执行栈上面的病毒代码。
防止这种攻击主要有三种方法,其中第一种方法想了很久才大概明白,后面两种没有仔细看了。分别是:
- 栈随机化。让每个机器中相同程序的栈分配不同,这样黑客很难猜测栈地址,而且每次最多攻击一台机器。此方法可以暴力破解。
- 栈破坏检测。在分配的空间之上加一个随机数值,然后在每次ret之前检查这个值,如果发生了变化,则说明发生了溢出,那么就不返回,走异常终止的流程。此方法比较有效。
- 限定可执行代码的位置。这样,黑客就无法在栈中植入可执行代码了,但是某些解释性语言可能必须要执行栈中的代码。
3.变长栈帧的实现
这个应该和C++中动态绑定非常类似。我的直觉。
在很早之前的C语言中,分配数组是必须指明数组长度的,也就是说,从C语言源代码中,我能直接确定栈的空间应该是多大,起码我能知道数组空间分配多大。所以栈帧的大小是固定的,编译出来的机器代码,我不用运行,就能够确定每一个栈帧是多大。
而变长数组则不能做到这样,由于数组的长度是个变量,他可能很小,例如是1,也可能很大,例如是100000,所以编译器在生成机器代码的时候,无法直接确定栈帧是多大,那么他是如何实现变长栈帧的呢?就是通过变量,在机器代码层面实现利用某个变量来分配栈空间,在此之前,我们都是编译器或者机器代码都是直接指明一个常数来分配栈空间的。
具体一点的说,就是利用某个寄存器的值,来分配栈空间,而那个寄存器的值,是可变的,是机器代码在执行时期受到外界输入影响的值,本质上就是外界输入的参数。我们常说的“运行时”,其实就是机器代码在执行过程中,会接收外界参数,这些参数是可变的,是运行时的。
这一点和多态中的“运行时绑定”非常类似。我觉得,在我们实现变长数组的时候,基本离实现动态绑定不远了。动态绑定(或者说运行时绑定)就是说,我用一个父类指针来接受参数,但是实际指向什么对象,编译器是不知道的,编译器必须准备一个东西(例如寄存器)来存储机器代码在执行的时候接收的参数,然后机器代码必须能够根据这个输入的参数来分配空间,来执行与这个参数相对应的一些操作。
侯捷C++视频
看了一丢丢,晚上党员会议耽误了。
其实是自己效率低。
不过还是敲了一点代码,对友元函数,操作符重载,全局函数和成员函数的实现有了更具体的认识。
下面上传一下我的csapp第三章思维导图吧。
明天加油。
明日目标
- 两道leetcode(上午一道,下午一道)
- 独立完成侯捷Complex的类实现,并测试。(一上午,顺便看视频)
- 看csapp第7章,看完前3节。(下午和晚上,尽量在linux下编写demo)