- GitHub计算机系统CSAPP课程资源
- 计算机系统课程 笔记总结 CSAPP第二章 信息的表示和处理(2.1-2.2)
- 计算机系统课程 笔记总结 CSAPP第二章 信息的表示和处理(2.3-2.4)
- 计算机系统课程 笔记总结 CSAPP第三章 程序的机器级表示(3.2-3.4)
- 计算机系统课程 笔记总结 CSAPP第三章 程序的机器级表示(3.5-3.7)
- 计算机系统课程 笔记总结 CSAPP第三章 程序的机器级表示(3.8-3.10)
- 计算机系统课程 笔记总结 CSAPP第四章 处理器体系结构(4.1-4.3)
- 计算机系统课程 笔记总结 CSAPP第五章 优化程序性能(5.1-5.14)
- 计算机系统课程 笔记总结 CSAPP第六章 存储器层次结构(6.2-6.6)
- 计算机系统课程 笔记总结 CSAPP第七章 链接(7.1-7.13)
- 计算机系统课程 笔记总结 CSAPP第八章 异常控制流(8.0-8.1)
- 计算机系统课程 笔记总结 CSAPP第八章 异常控制流(8.2-8.4)
- 计算机系统课程 笔记总结 CSAPP第九章 虚拟存储器(9.1-9.5)
- 计算机系统课程 笔记总结 CSAPP第九章 虚拟存储器(9.6-9.10)
目录
3.8 数组分配和访问
3.8.1 基本原则
数据类型T和整形常数N,声明:
- T A[N]
- 在内存中分配 L×N 字节的连续区域(L是数据类型T的大小)
- 起始位置表示为 Xa ,标识符 A 作为数组开头的指针
- 数组元素 i 会被存放在地址为 Xa+L×i的地方
|
|
|
|
|
|
| |
|
| ||
|
|
|
例如,假设E是一个int型的数组,而我们想计算E[i],E的地址存放在寄存器%rdx中,而i存放在寄存器%rcx中。然后,指令
- movl (%rdx, %rcx, 4), %eax
会执行地址计算,读这个内存位置的值。
3.8.2 指针运算
3.8.3 嵌套的数组
|
|
|
|
|
|
|
|
| |
| 二维数组声明:
|
|
| |
|
|
|
| |
|
| |||
|
|
|
|
3.8.4 定长数组
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
|
|
|
| 优化 |
|
| |
|
|
|
|
|
|
| |
|
| 最后一个元素存在 &B[N-1][k] 则 &B[N][k] 为终止地址 | |||||
|
|
|
|
|
|
| |
|
|
|
|
| |||
|
|
|
|
|
|
|
3.8.5 变长数组
例如要访问n×n数组的元素i,j,我们可以写一个如下的函数:
参数n必须在参数A[n][n]之前,这样函数就可以在遇到这个数组的时候计算出数组的维度。
3.9 异质的数据结构
- 结构 structure
- 关键字:struct
- 联合 union
- 关键字:union
3.9.1 结构 struct
- C语言的struct声明创建一个数据类型,将可能不同类型的对象聚合到一个对象中。
- 类似于数组的实现,结构的所有组成部分都存放在内存中一段连续的区域内,而指向结构的指针就是结构第一个字节的地址。
- 编译器维护关于每个结构类型的信息,指示每个字段(field)的字节偏移。
- 它以这些偏移作为内存引用指令中的位移,从而产生对结构元素的引用。
3.9.2 联合 union
|
|
|
|
|
|
|
|
|
|
| |
|
| ||||
|
|
|
|
| |
|
|
|
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
|
| 即:指针/数据 二选一 |
| ||
|
|
|
|
| |
|
|
| 优化空间 | ||
|
|
|
|
|
|
|
|
|
|
|
| |
|
|
| |
|
|
|
|
|
|
|
|
|
| |
|
|
| |
|
|
|
3.9.3 数据对齐
|
|
|
|
|
|
| |
|
|
| |
|
|
|
结构体数组:
7字节留白
|
|
|
|
|
|
| |
|
| 优化空间 | |
|
|
|
3.10 在机器级程序中将控制与数据结合起来
3.10.1 理解指针
特点/原则
- 每个指针都对应一个类型
- 每个指针都有一个值
- 指针用‘&’运算符创建
- ‘*’操作符用于间接引用指针
- 数组与指针紧密联系
- 将指针从一种类型强制转换成另一种类型,只改变它的类型,而不改变它的值
- 指针也可以指向函数(函数指针???)
3.10.2 应用:使用GDB调试器
- quit 退出
- run 运行(在此行给出命令行参数)
- kill 停止程序
- break multstore 在函数multstore入口处设置断点
- break * 0x400540 在地址0x400540处设置断点
- delete 1 删除断点1
- delete 删除所有断点
- stepi 执行1条指令
- stepi 4 执行4条指令
- continue 运行到当前函数返回
- disas 反汇编当前函数
- print $rax 以十进制输出%rax内容
- info frame
- info register
- help
3.10.3 内存越界引用和缓冲区溢出
- gets()函数无法确定是否为保存整个字符串分配了足够的空间
- strcpy, strcat: 任意长度字符串的拷贝
- scanf, fscanf, sscanf, 使用 %s 转换符时
- 缓冲区溢出,返回地址被破坏,程序看起来能工作
- 缓冲区溢出使程序执行它本来不愿意执行的函数,这是最常见的通过计算机网络攻击系统安全的方法
|
|
|
|
|
|
| |
|
|
| |
|
|
|
3.10.4 对抗缓冲区溢出攻击
针对缓冲区溢出攻击:
- 避免溢出漏洞(函数、代码细节)
- fgets代替gets、strncpy代替strcpy
- scanf函数中别用%s(或用%ns代替%s,其中n是一个合适的整数)
- 使用系统级的防护
- 3.10.4.1 栈随机化(随机的栈偏移)
- 程序启动后,在栈中分配随机数量的空间
- 3.10.4.1 栈随机化(随机的栈偏移)
- 将移动整个程序使用的栈空间地址
- 黑客很难预测插入代码的起始地址
- 例如:执行5次内存申请代码
- 每次程序执行,栈都重新定位
- 3.10.4.3 限制可执行代码区域(非可执行代码段)
- 目的:消除攻击者向系统中插入可执行代码的能力
- 在传统的x86中,可以标记存储区为“只读”或“可写的”
- x86-64添加显式“执行”权限
- 将stack标记为不可执行(漏洞利用程序exploit code)
- 3.10.4.2 栈破坏检测(栈金丝雀)
- 编译器使用“栈金丝雀”(stack canaries)
- 在栈中缓冲区(buffer)之后的位置放置特殊的值——金丝雀(canary)
- 退出函数之前,检查是否被破坏
- 用GCC实现
- -fstack-protector
- 该选项现在是默认开启的(早期默认关闭)
- 编译器使用“栈金丝雀”(stack canaries)
另:
3.10.5 支持变长栈帧
有些函数需要的局部存储是变长的(例如alloca函数)
%rbp 帧指针/基指针
base pointer --> bp
|
|
|
|
|
|
| |
|
| ||
|
|
|
- 计算机系统课程 笔记总结 CSAPP第二章 信息的表示和处理(2.1-2.2)
- 计算机系统课程 笔记总结 CSAPP第二章 信息的表示和处理(2.3-2.4)
- 计算机系统课程 笔记总结 CSAPP第三章 程序的机器级表示(3.2-3.4)
- 计算机系统课程 笔记总结 CSAPP第三章 程序的机器级表示(3.5-3.7)
- 计算机系统课程 笔记总结 CSAPP第三章 程序的机器级表示(3.8-3.10)
- 计算机系统课程 笔记总结 CSAPP第四章 处理器体系结构(4.1-4.3)
- 计算机系统课程 笔记总结 CSAPP第五章 优化程序性能(5.1-5.14)
- 计算机系统课程 笔记总结 CSAPP第六章 存储器层次结构(6.2-6.6)
- 计算机系统课程 笔记总结 CSAPP第七章 链接(7.1-7.13)
- 计算机系统课程 笔记总结 CSAPP第八章 异常控制流(8.0-8.1)
- 计算机系统课程 笔记总结 CSAPP第八章 异常控制流(8.2-8.4)
- 计算机系统课程 笔记总结 CSAPP第九章 虚拟存储器(9.1-9.5)
- 计算机系统课程 笔记总结 CSAPP第九章 虚拟存储器(9.6-9.10)
- GitHub计算机系统CSAPP课程资源