爲了方便理解,CPU 能夠簡單認爲是:架構
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
中。
push
和 pop
這一對用於操做「棧」。
「棧」是內存空間中的一段地址,咱們約定是以棧的形式來使用它,而且用 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
注意:由於棧在內存空間中是倒過來的,因此是向下生長的。