第三章 机器的程序级表示(下)

数据传送:

当过程P调用过程Q时,P的代码必须首先把参数复制到适当的寄存器中。类似的,当Q返回到P时,P的代码可以访问寄存器中的返回值;

每个过程调用在栈中都有它自己的私有空间,因此,多个未完成调用的局部变量不会相互影响。当过程被调用时分配局部存储,当返回时释放存储;

 

数组的分配和访问:

对于数据类型T和整型常数N,数组表现形式如下:T A[N]。它表示在内存中分配一个L*N字节的连接区域,这里L是数据类型T的字节大小。当然,A也可以用来作为指向数组开头的指针。如:

char A[12];

char *B[8];

声明一个数组 T D[R][C],它的数组元素D[i][j]的内存地址为: D地址 + L( i * C + j )

比如,int A[5][3],其中,C的值即列数3,L即int类型的字节长度4,所以,数据元素A[i][j] 的内存地址为:A数据地址 + 4*(3*i+j)

 

定长数组:当程序要用一个常数作为一个数组的维度或者缓冲区的大小时,最好通过#define声明这个常数与一个名字联系起来,然后在后面一直使用这个名字来替代常数的值。这样,如果需要修改这个值,直接改这个#define声明就好了。如

#define N 16;

typedef int fix_matrix[N][N];

 

变长数组:数组在被分配时才计算出来数组长度大小,一般都是使用malloc这种函数来为这些数组分配存储空间;如,int A[expr1][expr2],如果A数组作为一个函数参数,那么,在调用函数,遇到这个声明的时候,通过对表达式exp1和exp2求值来确定数组的维度;

异质的数据结构:

使用struct来声明,将可能多个不同类型的对象聚合到一个对象中。如:

缓冲区溢出:C对于数组引用不进行任何边界检查,而且局部变量和状态信息都是存放在栈中。这两种情况结合到一起就能导致严重的程序错误,对越界的数组元素的写操作会破坏存储在栈中的状态信息。通常,当栈中分配某个字符数组来保存一个字符串,但是字符串长度超出了为数组分配的空间。

对抗缓冲区溢出攻击机制:

1.栈随机化

2.栈破坏检测;

3.限制可执行代码区域;

上面的方法都是由编译器或操作系统完成的,无需程序员主动关心。

 

posted @ 2018-11-18 16:14  凌晨六点半  阅读(161)  评论(0编辑  收藏  举报