01-初识汇编
前言
博主本人从事python开发工作差不多五年了,随着时间的推移,我总是在工作中遇到各种问题让我百思不得其解,再加上博主本身就没有系统学习过任何关于计算机结构的知识,
只是零散看了一些资料。这些知识反而让博主更是疑惑,毕竟知识面太窄了,认知也不够全面。所以从这一篇开始,博主决定老老实实的学习底层,然后慢慢向着逆向方向推进吧。
汇编
关于硬编码的资料
https://blog.51cto.com/u_15127590/4549268
最核心的一句话
相同CPU架构下使用不同OS的情况下,生成的汇编是不一样的,但是机器码是一样的
精简总结:相同CPU、不同OS,汇编不一样,机器码一样
CPU架构,指令集,高级语言,汇编,机器码之间的关系
从抽象到具体的顺序是(设计规范层):
CPU指令架构(ISA)→指令集→汇编→机器码→硬件
ISA(指令集架构)是硬件设计的顶层规范,定义“硬件应该支持哪些指令、如何解码、如何执行”。指令集是ISA的具体实现(如x86指令集是ISA的实例化)。
二者是硬件设计的基础与约束,不直接参与程序执行,而是指导“如何将机器码映射到硬件操作”。
正确位置:位于硬件之前,是硬件设计的“蓝图”
执行流程层:
高级语言 → 汇编语言 → 机器码 → 硬件(CPU)
是程序运行时的动态路径,描述“代码如何被编译/解释并最终由硬件执行”。
正确位置:位于设计规范层之上,是软件到硬件的“执行链路”。
如果合在一起看的话,简单结构应该是这样的:

或者下面这个图:

说实话,上面这两个图我其实很纠结指令集和指令集架构应该放在哪里,因为是决定采用什么架构,然后才能设计对应的的指令集,再然后才是通过指令集映射出机器码,最终弄出对应的硬件。而汇编则是这些资源的使用者
这里我们也可以把这些东西的关系看成施工队(汇编),架构(住宅还是写字楼),指令集(工程图纸),机器码(工程材料)
CPU结构分类
CPU分为两种类型:
- CISC(复杂指令集)
- intel芯片
- RISC(精简指令集)
- ARM芯片
- Mac M1、M2芯片
CISC
所谓复杂指令集,其实可以理解为,一句指令会执行多个动作,比如add eax 1这一句的动作是eax寄存器中的值加1,然后加1后的值重新赋值给eax寄存器。
这个架构的好处就是可以有效减少过多的指令,只不过会导致一条指令的执行时间更长
RISC
而精简指令集则可以理解为,一条指令尽可能的只做一件事情,add RO, RO, #1这里的意思是先将RO寄存器中的值与1相加后,再存入RO寄存器中。这里面共有两条指令。
寄存器
关于寄存器,执行引擎,内存,CPU缓存之间的关系

上图可以知道CPU中包含执行引擎,寄存器和CPU缓存
而数据来源是下面的流程(如果数据在内存中):
执行引擎申请数据资源 → 寄存器收到申请先查找自身是否存在这个资源(如果有则之间给执行引擎) → 自身资源不存在向CPU缓存查找 → CPU缓存也不存在这个资源向内存查找
分类
- 通用寄存器
- 段寄存器
- 指令指针寄存器(x86 EIP、x64 RIP)
- 标准寄存器(x86 eflags、x64 rflags) 状态寄存器
- 控制寄存器(CR0 - CR4,CR3 页表)
- 调试寄存器(DR0 - DR7)
- 描述符寄存器(GDTR、LDTR、IDTR)
- 任务寄存器(TR)
……(x64 CPU有新增寄存器,如型号专属寄存器)
通用寄存器
- eax:函数返回值
rax:六十四位
eax:低三十二位
ax:低十六位
ah:高八位
al:低八位
举例:
ax中存储0x1234,二进制为:0001 0010 0011 0100
如果用al去取ax中的值,则拿到的是0011 0100
而ah拿到的是0001 0010
- ebx:随便用,无限制
- ecx:循环次数;this指针
- edx:随便用,无限制
- ebp、esp:栈底指针与栈顶指针
- esi、edi:拷贝数据用,源地址、目标地址
- EIP:程序计数器,无法直接通过指令操作,比如
mov eip eax,一般用call之类的指令操作
EIP标志位和JCC指令
EIP标志位

图中的标志位从右往左看,0~31位数值,之所以总共是32位,是因为EIP寄存器是32位的
其中我们需要关注的是下面几个:
1. 中断使能标志:中断调试状态下不为0
2. 单步标志
3. 零标志:判断是否为0,用于程序跳转,不同的指令会根据这个标志位不同值进行判断跳转,具体参考JCC指令表格
在我们实际的操作中,因为展示的值是十六进制而不是二进制的值,所以我们在终端调试并且全部清零的状态下看见的值是00000202,
因为中断使能标志在第9位,所以00000202从右往左数,是第二个2代表中断使能标志,二进制表示为:0000 0000 0000 0000 0000 0010 0000 0010
JCC指令

练习
int a = 10;
if (a >= 10){
a = 100;
}
xor eax, eax
mov eax, 10
cmp eax, 10
jge 12345
mov eax, 100

浙公网安备 33010602011771号