找回密码
 立即注册
首页 业界区 安全 深入理解计算机系统 学习笔记03

深入理解计算机系统 学习笔记03

游瞠离 4 天前
程序的机器级表示

程序编码
  1. gcc -Og -o p p1.c p2.c
复制代码

  • -Og: 告诉编译器会生成符合C代码的机器代码优化等级,较高级别的优化选项有-O1、-O2
  1. gcc -Og -S mcstore.c
复制代码

  • -S: 运行编译器,产生一个汇编文件.s(通常还会继续调用汇编器产生目标代码文件.o)
  1. gcc -Og -c mstore.c
复制代码

  • -c: 编译并汇编该代码,产生目标文件mstore.o(它是二进制格式的,无法直接查看)
.o结尾的已经是字节序列了。
Q1:如何展示程序的字节表示?
反汇编器程序:根据机器代码产生一种类似汇编代码的格式。
  1. objdump -d mstore.o
复制代码
反汇编器只基于机器代码中的字节序列确定汇编代码,而不用访问该程序的源代码。
2025-06-04 20:25:24 星期三
第三章看得很粗糙。
下面整理一下第三章我看过的、并认为有收获的,有意思的,记录下来。
首先,我们编写的程序是如何变成二进制字节的?
以C语言为例。
我们编写好的.c文件会通过预处理器先进行宏替换。
预处理器主要是做一些文本替换的工作,如#include ,预处理器会将这个命令替换成头文件的内容;又或者说,#define INT_MAX 65535,预处理器但凡碰到INT_MAX都会把它替换成65535。
预处理完成后,由编译器将.c文件编译成汇编语言文件.s。
汇编语言再经过汇编器处理会生成.o文件,这就是二进制文件了。
(反汇编器可以基于字节序列确定汇编代码)
最后,由链接器将不同文件的二进制文件链接到一起形成.exe。
整个第三章讲的基本都是机器指令。
感觉没什么用(个人拙见)。
不过还是有些收获的。
x86_64的栈是由高地址向低地址扩展的。

long x1;
long x2;
如果上述两句C语言代码是函数体中的局部变量,那栈会先开辟一段空间,栈区地址是从高到低的。x1会被放在低地址上,x2会被放在高地址上。
1.png

但是我发现在DevC++上编译的不太一样,很明显x1在高地址,x2在低地址。
额,我也解释不清楚。
可能GCC优化了,毕竟这本书可能是老了。
第二点是字节对齐
  1. struct S3{
  2. char c;
  3. int i[2];
  4. double v;
  5. }
复制代码
像这样一段程序,char占1个字节,int占4个字节,数组也就占8个字节,double占8个字节。
因为字节对齐的缘故,char的偏移地址是0,数组的偏移地址为4,因为字节对齐会对齐成2、4、8的整数倍???v的偏移地址16。
对齐原则:任何K字节的基本对象的地址必须是K的倍数。
最后是内存越界引用和缓冲区溢出。
缓冲区溢出是栈在函数调用时开辟了一个缓冲区空间,如果这个缓冲区溢出,那就可能导致提前压入栈中的返回地址的值被覆盖,那程序怎么返回呢?
针对缓冲区溢出,现在的系统都采用

  • 栈随机化:每次运行程序得到的栈地址都不一样,神奇吧
  • 栈破坏检测:在溢出区的上头有个金丝雀,相当于标志位吧,如果发生溢出,那这个金丝雀的值就会被覆盖,一旦它发生了变化,程序就会报错。
  • 支持变长栈帧:x86_64代码使用一个寄存器作为栈指针
最后是浮点代码,讨论的东西和浮点数有关。
说是将浮点数转换成整数时会发生截断,这个截断会把值向0进行舍入。
OK,大概就是这样。
看得比较粗糙,对一些东西也比较模糊,不知道这一章有啥用。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册