阅读经典——《深入理解计算机系统》05

本文讲述三个比较冷门的话题:联合、数据对齐和缓冲区溢出攻击。

  1. 联合体
  2. 数据对齐
  3. 栈帧为什么必须16字节对齐?
  4. 缓冲区溢出攻击

联合体

在C语言中有这么一个不常用的数据类型union,往往被人们遗忘。它就是联合体。

与结构体类似,都是用来封装多种数据类型,但含义不同。结构体会将各个字段按顺序分配各自独立的内存空间。而联合体则是只申请一块内存空间,由所有字段共用。听起来有些不可思议,共用一块内存空间的字段岂不是只能有一个值,那那些字段还怎么区分?下面给出一个使用联合体的经典案例。

我们想要实现一个二叉树结构,所有的内部结点具有左孩子和右孩子,但没有数据;所有的叶子结点既没有左孩子也没有右孩子,但有数据。很容易想到可以用如下的结构体来实现:

struct NODE_S {struct NODE_S *left; struct NODE_S *right; double data; }; 

这样的话每个结点需要16字节,是不是有点浪费?因为总是有一半的空间处于无用状态,当作为内部结点时,data字段为空,当作为叶子结点时,leftright结点都为空。

这时候就可以用联合体来节约空间,原型如下:

union NODE_U {struct {union NODE_U *left; union NODE_U *right; } internal; double data; }; 

这样的话每个结点只需要8个字节了,因为internal大小为8个字节,double大小也是8个字节,取最大值还是8个字节。对于该联合体类型的指针n,我们可以用n->internal.left来访问内部结点的左孩子,也可以用n->data来访问叶子结点。

可是,这个结果仍然不够令人满意,因为我们无法分辨出当前结点是内部结点还是叶子结点。那么我们可以增加一个枚举字段来表示结点类型:

typedef enum { N_LEAF, N_INTERNAL } nodetype_t;struct NODE_T { nodetype_t type; union { struct { struct NODE_T *left; struct NODE_T *right; } internal; double data; } info; }; 

这样一来每个结点需要12个字节了,type字段占用4个字节,info字段占用8个字节。当internaldata占用空间非常大时,该方案可以极大地降低内存消耗。

数据对齐

IA32并不要求数据对齐,但不同的平台有着额外的要求。Linux要求2字节数据类型(例如short)必须2字节对齐(意思是该数据的地址必须是2的整数倍),大于2字节的数据类型必须4字节对齐。而Windows要求K字节数据类型必须K字节对齐,除了long double要求4字节对齐。

对齐的数据有利于提高CPU的存取效率,更详细的说明见参考资料。

值得一提的是,为了对齐数据,结构体中往往会采取增加间隙的措施。例如对于如下结构体:

struct S1 {int i; char c; int j; }; 

如果以完全紧密放置的方式保存的话,内存空间分配如下:

未对齐的数据

这导致j不满足4字节对齐的要求。因此编译器会在c后面插入一个3字节的间隙,如下所示:

对齐的数据

此时所有数据都满足了对齐要求。

栈帧为什么必须16字节对齐?

现在我们来解释上一篇文章《函数调用栈》中提出的问题,栈帧为什么必须16字节对齐。

Intel从Pentium III处理器开始推出的SSE指令集(Streaming SIMD Extensions,单指令多数据流扩展)要求操作对象为16字节对齐的数据。因此,栈帧为了支持该指令集,必须使自己16字节对齐,从而栈帧内部的数据才可能16字节对齐。否则即使数据相对于栈顶对齐,地址也不是16的整数倍。

缓冲区溢出攻击

缓冲区溢出的含义是为缓冲区提供了多于其存储容量的数据,就像往杯子里倒入了过量的水一样。通常情况下,缓冲区溢出的数据只会破坏程序数据,造成意外终止。但是如果有人精心构造溢出数据的内容,那么就有可能获得系统的控制权!例如,对于如下的简单程序:

void echo() { char buf[8]; gets(buf); puts(buf); } 

该函数的功能是读取输入的字符串,并输出。对应的栈帧结构如下:

echo函数的栈帧结构

如果gets函数中给buf赋予了长度超过8的字符串,可以想象,这个字符串将覆盖buf上方的内容。随着字符串长度的增大,echo栈帧中的“保存的%ebx”、“保存的%ebp”,以及调用者的栈帧中的“返回地址”将被依次覆盖。大部分情况下,覆盖会使程序紊乱并出错,从而导致程序终止,但如果有人巧妙地设计覆盖的内容,就实现了所谓的缓冲区溢出攻击。

简单来讲,黑客可以把恶意代码通过buf传入内存,并恰好使返回地址指向恶意代码的起始位置。这样的话,一旦echo函数返回,程序将立即跳转到恶意代码段,如果程序具有管理员权限,恶意代码就有了任意操作整个计算机的能力,后果不堪设想。

当然,时至今日,缓冲器溢出攻击已经不能通过这种简单的方式实现了。人们在编译器、处理器中切断了缓冲区溢出攻击的必经之路。但是,道高一尺魔高一丈,黑客们总能找到系统的漏洞,让系统安全人员防不胜防。正应了那句话:没有绝对安全的系统。在参考资料提到的另一篇博文中,详细讲述了缓冲区溢出攻击的细节,并给出了简单的实现代码,感兴趣的读者可以前往阅读。

参考资料

数据对齐详解 bakari
缓冲区溢出攻击 范志东

作者:金戈大王
链接:https://www.jianshu.com/p/b20c8838b929
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://www.cnblogs.com/zzdbullet/p/9354586.html

深入理解计算机操作系统(六)相关推荐

  1. 【深入理解计算机操作系统】01_计算机系统漫游

    学习总路线 以hello程序的整个生命周期来开始对系统的学习 #include<stdio.h> int main() {printf("hello world!\n" ...

  2. 深入理解计算机操作系统(一)

    目录 1.1 信息就是位加上下文 1.2 程序被其他程序翻译成不同的格式 1.3 了解编译系统如何工作是大有益处的 1.4 处理器读并解释储存在内存中的指令 1.4.1系统的硬件组成 1.4.2 运行 ...

  3. 深入理解计算机操作系统(五)

    阅读经典--<深入理解计算机系统>04 函数调用时的栈结构变化是一个很有趣的话题,本文就来详细剖析这个过程. 栈帧结构 寄存器使用惯例 这段代码的含义? 栈帧结构 在计算机系统概述中我们介 ...

  4. 深入理解计算机操作系统:第2章 信息的表示和处理(学习笔记)

    现代计算机存储和处理的信息都是用二进制表示的,即0和1. 用多个二进制比特位的不同组合和不同解释能够表示数量有限的元素,比如用32位比特的组合则有2^32种可能,因此它能表示从0开始到42949672 ...

  5. 计算机操作系统第三章知识点,深入理解计算机操作系统第三章家庭作业

    3.58 y=y-z; x=x*y; return x ^ (y<<63>>63); 3.59 无符号64位,ux 和 uy 有符号64位,x 和 y 设 x 和 ux 具有相 ...

  6. 深入理解计算机操作系统:链接笔记

    链接的本质 简单版 实际版 可重定位目标文件 可执行目标文件 符号与符号表 静态库 动态库

  7. 深入理解计算机操作系统:链接

    文章目录 链接器的由来: 链接过程的本质: 目标文件的两种视图 可重定位文件概述 ELF头和节头表 可执行文件概述 程序头表和存储器印象 符号和符号表的基本概念 全局符号的强弱特性 多重符号定义举例 ...

  8. 计算机操作系统与生态系统

    规律,世界的运转遵循着一定的规则.比如地球围绕着太阳转,月球围绕着地球转.我们无法理解月球为什么叫月球,因而CPU也是如此,他为什么用的是这个名词而不是别的,这些是一些约定俗成的东西.我们只需要理解他 ...

  9. 简单计算机面试题库及答案_460道Java后端面试高频题答案版【模块六:计算机操作系统】...

    写在前面 1. 计算机操作系统和计算机网络是每个后端开发工程师必须掌握的知识.因为你写的代码最终都是要在操作系统里跑的,弄懂操作系统的原理对你编写高质量代码.调优.排故都有很大的帮助.在这里说一下我作 ...

  10. 计算机操作系统32,计算机操作系统实验指导书32138

    计算机操作系统实验指导书32138 (22页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 14.9 积分 <计算机操作系统>实验指导书程科白素 ...

最新文章

  1. NYOJ 460 项链
  2. 【阿里云OSS】访问控制
  3. 【Github】开源项目xterm.js
  4. linux怎么添加头文件目录下,linux下编写c++,include的那些头文件在什么地方?
  5. jeecg框架日常开发问题解决方法
  6. tensorflow之conv2d
  7. mysql writing to net_mysql 提示 Writing to net_MySQL
  8. 32岁程序员推拿一小时差点丧命!医生说按错这个地方
  9. 第四次作业随笔(计算器第二步)
  10. C# CefSharp 可监听请求等
  11. EPS学习笔记3----------常用地物采集方法(房屋,斜坡,台阶)
  12. R语言中ggplot Theme Assist安装使用教程
  13. Openssl 命令之cer证书转成pem. 利用ptf私钥文件生成公钥
  14. 2019华为软件精英挑战赛总结篇
  15. PCI Expansion ROMs
  16. 万字长文:全面解读新公链新生态
  17. containerd 拉取k8s.gcr.io/pause镜像i/o timeout
  18. 工作随记3:一次交换机环路故障
  19. 腾讯 2022 校招大厂薪资首发,白菜总包接近 40w!
  20. Cox 比例风险模型中HR和置信区间

热门文章

  1. cnblogs上的mysql学习心得
  2. 基于统计语言模型的分词方法
  3. ie6 插入图片img png24 阴影
  4. OpenCV2 图像叠加 给照片加水印
  5. 智能优化算法应用:基于麻雀搜索算法的水文地质参数优化 -附代码
  6. P+XS算法中Dirac comb的解释
  7. 地图相关知识和地图打印色彩差异解决办法
  8. 【空间分析】4 探索性分析
  9. JVM垃圾回收策略与垃圾收集器
  10. Gson源码解析之InstanceCreator简单说明