深入理解计算机系统 学习笔记(2)

Hello world,hello blog!

Posted by 吴柚 on April 22, 2019

深入理解计算机系统 学习笔记(2)

  1. 函数调用实例
int swap_add(int* xp,int* yp);
int caller()
{
    int arg1 = 534;
    int arg2 = 1057;
    int sum = swap_add(&arg1 , &arg2);
    int diff = arg1 - arg2;
 
    retur sum * diff;
}
int swap_add(int* xp,int* yp)
{
    int x = * xp;
    int y = * yp;
    *xp = y;
    *yp = x;
    return x + y;
}

(蓝色箭头是“指向”,红色箭头是“偏移量”,绿色箭头是解释说明)

  • arg1和arg2必须存放在栈中,因为我们必须为它们生成地址。swap_add中的变量int x和int y可以存放在寄存器中。

  • 分配在栈上的24个字节,8个用于局部变量,8个用于参数,8个未使用,这是因为GCC认识所有的栈空间都应该是16的整数倍。这样保证数据放的严格对齐。

  • 经过调用swap_add之后栈的信息又恢复到最初的状态。

  1. 许多函数编译后不需要栈帧。如果所有的局部变量都能保存在寄存器中,而且这个函数又不会调用其他函数(叶子过程),那么需要栈的唯一原因就是用来保存返回值。特别是dui’yu所以,虽然C语言中有寄存器变量,但是如果这个函数的变量很少的话,及时不标明这个变量是寄存器,它也会被加载到寄存器中去。

  2. 函数需要栈帧的原因有如下几个:

  • 局部变量太多,不能都放在寄存器中。

  • 有些局部变量是数组或者结构。

  • 函数用&来计算一个局部变量的地址。

  • 函数必须将栈上的某些参数传递给另外一个函数.

  • 在修改一个被调用着保存寄存器之前,函数需要保存其他状态。

  1. 栈破坏检测和栈保护:在C语言中,没有可靠的方法来防止对数组的越界写操作。数组越界,是栈溢出后发现这个错误然后抛出。

echo是一个函数,存放了char buf[8]的一个局部变量。其思想为:

在栈帧中任何局部缓冲区与栈状态之间存储一个特殊的金丝雀(canary)值,也成为哨兵值(guard value)是在程序每次运行时随机产生的。因此如果这个哨兵值改变了说明栈溢出了。

  1. 栈随机化

比如,多次运行下面的代码,本地变量的地址是不变的.

 int main()
{
    int local;
    printf("local at %p\n",&local);
    return 0;
}