工作学习笔记——CSAPP第三章

  最近在读《深入理解计算机系统》(CSAPP)的第三章——程序的机器语言表示。之前这块内容也有所接触,对书中提到的一些细节问题倒更感兴趣一些。


一、可变长数组  

  刚开始学习C语言时,都会被教到,声明数组时,数组的维数只能使用常量,也就是只能声明定长数组。如果数据个数不定的话,就要使用malloc动态分配。当时只是死记硬背,并没有想想这是什么道理。工作中了解到,函数中声明的数组一般存储在栈上,数组元素通过栈指针加偏移量和下标偏移来访问。那时就已经有些困惑,栈上空间的分配只是将sp寄存器减一个数,如果这个数是存储在寄存器或者内存中的话,不是就可以做到声明函数上的变长数组了么?C库中有一个函数alloca,与malloc的区别就是,申请的内存是分配在栈上的,这个不也意味着栈上的变长数组是可能的?

  c数组维数不支持变量这种说法,可能是c编译器初期为降低编译器设计难度而采取的一种限制。CSAPP中提到,C99标准已经明确定义了变长数组,新的gcc编译器也实现了这块内容,我们已经可以写这样的语句了

  int arrary[m][n];

  不过这种数组只能在函数内部使用,如果传递到函数外的话,结果可能是灾难性的。因为函数一退出,给函数分配的变量栈空间也随之销毁了。另外,即使是VC2010,也不支持c99的这种定义。


二、栈帧寄存器ebp是否必要

  在一些介绍函数调用栈的文章中,经常会提到栈帧寄存器ebp,它的值其实就是函数刚刚调用时的esp的值。函数执行过程中,使用ebp加偏移量来对参数、函数局部变量进行访问。调试时也可以根据ebp的值还原出当前函数调用栈。不直接使用esp的原因,一是函数执行过程中esp值可能发生变化,一是方便调试。但是函数执行过程中,esp的值何时变化总是没想清楚,调用子函数不必说,子函数退出时自然会恢复esp。难道是编译器会在函数执行过程中随时分配变量,就像C++那样在函数中间声明变量?从CSAPP对x86-64的介绍来看,这可能又是一个编译器为降低实现难度而采取的策略,因为x86-64程序中,rbp已经作为通用寄存器使用,函数调用过程中不再设专门的栈帧寄存器。并且函数使用的空间统一在函数调用开始出分配,调用过程中esp不再变化。通过网上查找到的资料来看,不使用栈帧寄存器的程序也是可以支持调试的。其实即使是x86,gcc也早就有个选项,好像叫做no-stack-frame-point,来指明程序不使用栈帧寄存器。


三、x86、x86-64

Intel设计的x86,AMD学过来用。Intel自家的IA64,市场不欢迎。反倒是AMD在x86基础上设计的x86-64流行起来,搞得Intel又反过来学。这段历史也很有趣。

你可能感兴趣的:(工作,gcc,存储,语言,编译器,X86)