🌈hello,你好鸭,我是Ethan,一名不断学习的码农,很高兴你能来阅读。
✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!
🔥个人主页:Ethan Yankang
🔥本篇概览:程序的机器级表示全过程解析
目录
[code file](#code file)
[Caller-saved/Callee-saved Register](#Caller-saved/Callee-saved Register)
[Pointer Arithmetic](#Pointer Arithmetic)
[Nested Array](#Nested Array)
[Data Alignment](#Data Alignment)
[BUffer Overflow](#BUffer Overflow)
[Stack Randomization](#Stack Randomization)
[Stack Corruption Detection](#Stack Corruption Detection)
code file
gcc指的是gcc编译器,将源代码翻译成汇编语言。-Og 指的是编译选项,这里是指生成与原始代码整体结构相同的机器语言代码,实际总还会使用**-Og1,-Og2** 来优化程序 ,只是优化后的代码会与源代码严重变形,-o prog便是生成的可执行文件的文件名
下面来看看
源代码文件与汇编语言之间的转化
其中:
这里的以"."开头的行,都是指导汇编器与链接器工作的伪指令。也就是说我们可以完全忽略这些行
删除无关代码后,剩下的汇编代码就是与源文件C代码相关的了,如下------、、
Intelx86-64的处理器包含了16个寄存器
Caller-saved/Callee-saved Register
调用者保存寄存器与被调用者保存寄存器
(保存上下文,恢复原有上下文信息)
其中的addq后面的q表示数据大小,英特尔处理器里面有如下机器位长:
详细解释
下面逐步解释
如图,将函数的参数分别放在如下寄存器里
x->%rdi y->%rsi dest->%rdx
call mult表示调用函数mult2
将乘法的结果放在寄存器%rax里面,
movq %rax ,(%rbx)
之后,该寄存器里面的值放入内存中,该内存的地址为寄存器%rbx里面的值
最后函数返回
register
这里的寄存器用途
Instructions
指令分为操作码、操作数,操作数又有几种类型,分别如下:
指令在内存中就是以0101的序列存储的。该序列也就分为操作码与操作数。
指令执行的源地址、目的地址
以实际例子说明汇编语句与计算机系统的结构对应情况
首先这里的函数参数,地址xp保存在**%rdi** 寄存器里,参数y保存在**%rsi**寄存器里面。
首先CPU将读取地址存在于%rdi寄存器里面的内存处的值放入寄存器%rax里面。
之后再将存在于寄存器%rsi里面的参数y放入内存(%rdi)中,也就是说,该内存处的值被赋予了y。
所以变量都只是内存或者寄存器的代称,我们实际是在操作机器,而C语言中的指针就是内存所对应的地址。
下面是程序运行时的内存分布
有效地址和虚拟地址的关系是什么?
有效地址可以说是虚拟地址的一种具体表现形式。而有效地址到物理地址的转化就是虚拟地址到物理地址的转化。
Pointer Arithmetic
注意这里的伸缩长度与原来的数据类型有关。
从下图可看出,指针就是地址的抽象表示
Nested Array
Structures
声明与访问
都是起始地址加上偏移地址来获取有效地址
Data Alignment
地址对齐优化(起始地址为4的整数倍,编译器会在前面加上空字节长度)
地址对齐的原则是任何K字节的基本对象地址必须是K的整数倍
比如说,short类型的数据对象起始地址必须是2的整数倍
复杂的地址对齐示例
Union
结构体和联合体的内存分布区别
注意联合体的数据类型的特点是所有字段在同一存储空间。一次只能访问一个字段,即联合体里面的字段是互斥 的,以最大的字段占用的存储空间为准
BUffer Overflow
程序运行时栈
Stack Randomization
栈随机化是指程序的栈的地址每次运行都会随机地变化。
如图上面的程序的本地变量每次运行时地址打印处理都会变化
在linux中。栈随机化已经成为了标准行为。
他是地址空间随机化行为的一种,简称ASLR。
采用ASLR,每次运行时程序的不同部分都会被加载到内存的不同区域
Stack Corruption Detection
栈破坏检测
暂时跳过
📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤ 分享👥 留言💬thanks!!!
📚愿大家都能学有所得,功不唐捐!