文章总结: 本文介绍了汇编语言的基础知识,重点讲解了寄存器和基本指令。文章通过工厂比喻解释了计算机工作原理:CPU从内存取数据到寄存器处理后再放回内存。详细介绍了x64架构中常用的寄存器(RAX、RBX、RCX等)及其用途,以及寄存器的不同大小(8位、16位、32位、64位)。最后介绍了5条基本汇编指令:MOV(复制)、ADD/SUB(加减法)、JMP(跳转)、CMP(比较)和条件跳转指令,并通过代码示例展示了如何使用这些指令实现循环。
综合评分: null
文章分类: 二进制安全,逆向分析,代码审计
汇编系列第二篇-寄存器和指令
原创
RabbitQ
安全研究站
2025年11月24日 00:08
北京
添加作者微信,加入交流群:
#
1.计算机是怎么工作的?
在学汇编之前,先理解计算机的工作原理,计算机就像一个工厂:
工作流程:
- CPU(工人)要干活
- 先从内存(仓库)取数据到寄存器(手里)
- 在寄存器里处理数据
- 再把结果放回内存
为什么要这样?
- 寄存器超快,但很小(就像人的手,拿东西快但拿不了多少)
- 内存大,但比寄存器慢(就像仓库,能存很多但走过去要时间)
2.什么是寄存器?
寄存器 = CPU 内部的超快速存储
想象你在做算术题:5 + 10
在纸上做(内存):
- 看纸上的5
- 看纸上的10
- 心算
- 写在纸上
在脑子里做(寄存器):
- 记住5
- 记住10
- 马上算出15
- 说出答案
寄存器就是”脑子里记住的数”,超快但数量有限。
x64 的寄存器(只记这些就够了)
x64 有很多寄存器,但常用的就这几个:
| 名字 | 用途 |
| — | — |
| RAX | 累加器,返回值 |
| RBX | 通用 |
| RCX | 计数器、参数1 |
| RDX | 数据、参数2 |
| RSI | 源地址 |
| RDI | 目标地址 |
| RSP | 栈指针 |
| RBP | 栈帧基址 |
现在不用全记住!用到哪个记哪个。
寄存器的大小
在汇编语言中,你经常会听到”8位”、”32位”或”64位”寄存器。对于初学者来说,这些数字有点抽象,但是与其去想复杂的电路,不如把寄存器的大小想象成**”能写数字的纸条长度”**。
这就好比老师给你发了一张用来写答案的纸条,纸条越长,能写下的数字就越大;纸条太短,数字就写不下了(这叫”溢出”)。纸条的长度决定他能写多少东西,而”寄存器的大小”决定了它最大能存多大的数字。
我们来看常见的四种尺寸:
| 大小 | 常见名称 (以 A 为例) | 比喻 | 能存多大的数字? |
| — | — | — | — |
| 8位 | AL | 便利贴 | 0 ~ 255 (存个年龄、考试分数够用了) |
| 16位 | AX | 记事本 | 0 ~ 65,535 (早期电脑的标准,现在较少单独用) |
| 32位 | EAX | A4纸 | 0 ~ 42亿 (绝大多数程序的变量、游戏得分都用它) |
| 64位 | RAX | 长卷轴 | 天文数字 (极大,主要用来存内存地址) |
至于为有这么多的大小,这就好比你要出门买瓶酱油,是开大卡车去,还是骑电动车去?如果你只需要处理一个英文字母(比如 ‘A’ 的编号是 65),用一张”便利贴”(8位 AL)就足够了,不需要动用巨大的 RAX。另外,计算机的发展是循序渐进的,最早的 CPU 只有”便利贴”大小,为了让以前的老软件能在新电脑上跑,这些小尺寸的访问方式被保留了下来。
它们的关系就饿类似于俄罗斯套娃,并不是独立的四个寄存器,而是同一个寄存器的不同部分。
RAX 就像一个巨大的盒子,里面套着 EAX,EAX 里套着 AX,AX 里套着 AL。AL只使用寄存器的最低部分(最右边),RAX:使用寄存器的整体。
代码示例:
mov rax, 100 ; 找那个最大的长卷轴(RAX),在上面写个 100
mov eax, 100 ; 找那个 A4纸大小的区域(EAX),在上面写个 100
mov al, 100 ; 找那个便利贴大小的角落(AL),在上面写个 100
总结:当你看到不同的寄存器名字时,不要被吓到,它们只是代表了不同的容量限制:
AL (8位) = 小存钱罐(存小钱)。
EAX (32位) = 银行账户(存工资)。
RAX (64位) = 国库(存巨款)。
在现代 64 位编程中,我们通常默认使用 RAX (64位) 或 EAX (32位),除非你有非常明确的理由要去操作那些更小的单位。
3.最基本的5条指令
指令1:MOV – 移动(复制)
格式:mov 目标, 源
例子:
mov rax, 5 ; 把数字5放到RAX里,就类似rax = 5;
mov rbx, rax ; 把RAX的值复制到RBX,类似rbx=rax
划重点:mov 是”复制”,不是”移动”!源的值不会消失。另外,这玩意是直接复制过去,不是啥引用之类的
指令2:ADD/SUB – 加法/减法
格式:
add 目标, 源 ; 目标 = 目标 + 源
sub 目标, 源 ; 目标 = 目标 - 源
例子:
mov rax, 5 ; RAX = 5
add rax, 10 ; RAX = RAX + 10 = 15
sub rax, 3 ; RAX = RAX - 3 = 12
指令3:JMP – 跳转
格式:jmp 标签
例子:
mov rax, 1
jmp skip ; 跳到skip标签
mov rax, 2 ; 这行不会执行!
skip:
mov rbx, 3
这玩意就类似于c语言的goto:
jmp skip
等于:
goto skip; (C语言的goto)
用途:实现循环,这块后面再说,不得不说,这帮搞底层的大哥脑瓜子真聪明
指令4:CMP – 比较
格式:cmp 操作数1, 操作数2
例子:
mov rax, 5
cmp rax, 10 ; 比较RAX和10
cmp只是比较,不改变RAX的值- 比较的结果保存在”标志位”里(暂时不用管)
- 通常后面跟条件跳转
指令5:条件跳转
格式:
je 标签 ; Jump if Equal(相等就跳)
jne 标签 ; Jump if Not Equal(不相等就跳)
jg 标签 ; Jump if Greater(大于就跳,不包含等于)
jl 标签 ; Jump if Less(小于就跳,不包含等于)
jge 标签 ; Jump if Greater or Equal(大于等于就跳)
jle 标签 ; Jump if Less or Equal(小于等于就跳)
重要区别:
jg/jl:严格大于/小于(不包含等于)jge/jle:大于等于/小于等于(包含等于)
例子对比:
mov rax, 10
cmp rax, 10
jg greater ; 不会跳(因为10不大于10,只是等于)
jge greater ; 会跳(因为10 >= 10)
来一小段代码感受一下
mov rax, 5
cmp rax, 10 ; 比较RAX和10
jl less ; 如果RAX < 10,跳到less,这个less随便命名,你爱叫啥叫啥,这玩意就是标记一下,跳转到哪块
mov rbx, 1
jmp done
less:
mov rbx, 2
done:
用C语言来理解就是:
if (rax < 10) {
rbx = 2;
} else {
rbx = 1;
}
4.实战:读懂一段简单代码
现在用刚学的知识,读懂这段代码:
mov rax, 0 ; RAX = 0
mov rbx, 10 ; RBX = 10
loop_start:
cmp rax, rbx ; 比较RAX和RBX
jge loop_end ; 如果RAX >= RBX,跳到loop_end
add rax, 1 ; RAX = RAX + 1
jmp loop_start ; 跳回loop_start
loop_end:
等价的C代码:
int rax = 0;
int rbx = 10;
while (rax < rbx) {
rax = rax + 1;
}
这就是循环!不得不说,这帮大哥脑瓜子真好使
先更到这,感谢头几天大哥的赞赏!!
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:安全研究站 RabbitQ《汇编系列第二篇-寄存器和指令》