CPU 提供了什么

为了方便理解,CPU 能够简单认为是:架构

  1. 一堆的寄存器,用于暂时存放数据
  2. 能够执行机器指令,完成运算 / 数据读写 等操做

寄存器

CPU 有不少的寄存器,这里咱们只介绍 指令寄存器 和 通用寄存器。函数

指令寄存器

64 位下,指令寄存器叫 rip (32 位下叫 eip)。
指令寄存器用于存放下一条指令的地址,CPU 的工做模式,就是从 rip 指向的内存地址取一条指令,而后执行这条指令,同时 rip 指向下一条指令,如此循环,就是 CPU 的基本工做。指针

也就意味着,一般模式下 CPU 是按照顺序执行指令的。可是,CPU 也有一些特殊的指令,用于直接修改 rip 的地址。好比,jmp 0xff00 指令,就是把 rip 改成 0xff00,让 CPU 接下来执行内存中 0xff00 这个位置的指令。code

通用寄存器

以 x86_64 来讲,有 16 个“通用”寄存器。“通用”意味着能够听任意的数据,这 16 个寄存器并无什么区别,可是实际上仍是存在一些约定俗称的用法:ip

先看看这 8 个:
(这是原来 32 位架构下就有的,只是 32 位下是 e 开头的)内存

rax: "累加器"(accumulator), 不少加法乘法指令的缺省寄存器,函数返回值通常也放在这里
rbx: "基地址"(base)寄存器, 在内存寻址时存放基地址
rcx: 计数器(counter), 是重复(REP)前缀指令和 LOOP 指令的内定计数器
rdx: 用来放整数除法产生的余数,或者读写I/O端口时,用来存放端口号
rsp: 栈顶指针,指向栈的顶部
rbp: 栈底指针,指向栈的底部,一般用`rbp+偏移量`的形式来定位函数存放在栈中的局部变量
rsi: 字符串操做时,用于存放数据源的地址
rdi: 字符串操做时,用于存放目的地址的,和 rsi 常常搭配一块儿使用,执行字符串的复制等操做

另外还有 8 个,是 64 位架构下新增的:字符串

r8, r9, r10, r11, r12, r13, r14, r15

机器指令

在 CPU 的世界里,只有 0 1 这种二进制的表示,因此指令也是用 0 1 二进制表示的。
然而,二进制对人类并不友好,因此有了汇编这种助记符。变量

算术运算

好比这段加法:循环

add    rax,rdx

好比这个汇编指令,表示:rax = rax + rdx,这就完成了一个加法的运算。
一般咱们用 rax 寄存器来作加法运算,可是其余寄存器同样也能够完成加法运算的,好比:二进制

add    rbx,0x1

这个表示 rbx = rbx + 0x1

这里的加法运算,都是在寄存器上完成的,也就是直接修改的寄存器的值。

跳转指令

好比这段无条件跳转指令

jmp 0x269e001c

CPU 默认是按照顺序执行指令的,跳转指令则是,让 CPU 再也不顺序执行后续的指令,转而执行 0x269e001c 这个内存地址中的指令。
具体来讲,将指令寄存器中的值改成 0x269e001c 便可,即:rip = 0x269e001c

内存读写指令

好比这一对 mov 指令:

mov rbp, [rcx]
mov [rcx], rbp

这里假设 rcx 的值,是一个内存地址,好比:0xff00
第一行 mov 指令,是将内存地址 0xff00 中的值,读取到 rbp 寄存器。
第二行 mov 指令,则是反过来,将 rbp 寄存器的值,写入到内存 0xff00 中。

栈操做

pushpop 这一对用于操做“栈”。
“栈”是内存空间中的一段地址,咱们约定是以栈的形式来使用它,而且用 rsp 寄存器指向栈顶。

栈操做本质也是内存读写操做,只是以栈的方式来使用。

好比这一对:

push   rbp
pop    rbp

第一行是将 rbp 寄存器中的值压入栈,等效于:

sub rsp, 8       // rsp = rsp - 8; 栈顶向下生长 8 byte
mov [rsp], rbp   // rbp 的值写入新的栈顶

第二行则是反过来,栈顶弹出一个值,写入到 rbp 寄存器中,等效于:

mov rbp, [rsp]   // 栈顶的值写入 rbp
add rsp, 8       // rsp = rsp + 8; 栈顶向上缩小 8 byte

注意:由于栈在内存空间中是倒过来的,因此是向下生长的。

相关文章
相关标签/搜索