Flags
flag就像寄存器恳谎,除了每個只保持1位,不是1(true)就是0(false)。每個標(biāo)志是一個大寄存器的一部分尝蠕。所以有人會叫Flags寄存器或eFlag寄存器侦香,每個位是一個flag,你沒需記憶這些flag纺阔,只需要了解這些flag的基本含義即可。
指針
匯編中寄存器是一個指針這個說法,對于大部分通用寄存器是成立的撞蚕。但寄存器并不是只能存儲內(nèi)存地址,也可以緩存變量實際的值,當(dāng)他們被當(dāng)作指針使用的時候过牙,即指向存儲數(shù)據(jù)的地址甥厦,當(dāng)指針指向某個數(shù)據(jù)時,意味著該指針持有該數(shù)據(jù)值的地址寇钉,也就是指針存儲的值就是該數(shù)據(jù)的地址刀疙。
備注:
- ip,sp扫倡,bp是16位的版本
- eip谦秧,esp,ebp是32位的版本
- rip撵溃,rsp疚鲤,rbp是64位的版本
要將一個寄存器作為指針,可以將寄存器的名稱包裹在符號“[ ]”里面,例如“rax”就可以變成“[rax]”
mov rax,rbx
上面的示例是加載rbx寄存器中的數(shù)據(jù)值到rax寄存器中
mov rax,[rbx]
例如:加載rbx寄存器指向的數(shù)據(jù)值到rax寄存器中,注意下面的指令并不是加載rbx的值到rax,rbx的值是什么?要牢記是此處寄存器的值始終一個指向某個保存著數(shù)據(jù)值的內(nèi)存地址,因此mov指令將到存儲在rbx寄存器中的地址缘挑,并從該地址拉出該數(shù)據(jù)值,并將該值賦給rax寄存器集歇。
我們將會討論rip指針和說明一下什么是控制流(Control Flow)
控制流
我們將會討論rip指針和說明一下什么是控制流(Control Flow),可以這么說,rip指針說是程序執(zhí)行的跟蹤器卖哎。
默認(rèn)情況下鬼悠,所有代碼都從上到下運(yùn)行,程序流的方向稱為控制流(Control-Flow)亏娜。每條指令后焕窝,其增量1,從而使控制流從上到下自然地流動维贺。以下面的hello world編譯代碼為示例
從指令move rax它掂,1開始,我們假設(shè)這個位置的內(nèi)存地址用K表示溯泣,當(dāng)該條指令執(zhí)行行rip指針會轉(zhuǎn)換1虐秋,用于指向嚇一跳待執(zhí)行的指令的內(nèi)存地址,示例中的
rip = k
rip = k + 1
rip = k + 2
rip = k + 3
rip = k + 4
這只是一種讓讀者理解的偽代碼垃沦,不是實際的匯編代碼的一部分客给。某些指令執(zhí)行后,可能另類rip指針遞增2肢簿,或遞增3靶剑,而不應(yīng)僅增加1蜻拨,所以上面的偽代碼不一定準(zhǔn)確的,只是用于表示這里最簡單的一種控制流的模式桩引。
我們發(fā)現(xiàn)hello-world的匯編嗲嗎是從頂往底執(zhí)行的缎讼,這是一個默認(rèn)的控制流
jmp指令
這一節(jié)將看一下jump,正如其名那樣就是“跳轉(zhuǎn)”的意思,只要jmp指令后家可用的label名稱就能跳轉(zhuǎn)到代碼的不同部分。它們用于更改程序流的執(zhí)行順序坑匠。jmp一般格式為:
jmp label
例如:
這個就等價于下面高級語言中的while 無限循環(huán)
while(true){
.....
}
當(dāng)調(diào)用jmp指令,它跳轉(zhuǎn)到到某個內(nèi)存地址時會把該label的內(nèi)存地址的值加載到rip寄存器中血崭,因此,本質(zhì)上您是在調(diào)用jmp然后調(diào)用諸如jmp _start之類的東西厘灼。 它實際上只是將_start標(biāo)簽的內(nèi)存加載到rip寄存器中(上面的例子其實就是無限地在寄存器刷新_start標(biāo)簽所在的內(nèi)存地址)夹纫。
備注:濫用jmp,可能會令你墮入回調(diào)的地獄。
cmp
cmp指令其實就是通過比較允許程序根據(jù)某些條件采用不同的策略去執(zhí)行不能的指令,如果結(jié)合jmp指令能夠?qū)崿F(xiàn)復(fù)制的回調(diào)效果设凹。cmp的一般格式是
cmp 寄存器名稱,寄存器名稱/值
例子:
cmp rax,rbx
cmp rax 117;
cmp會產(chǎn)生的結(jié)果捷凄,寄存器中特定的flag位就會被設(shè)定,例如
- x=y,ZF標(biāo)記就會被重置為ZF=1
- x≠y,ZF標(biāo)記就會被重置為ZF=0
最后,不論你進(jìn)行什么比較围来,都將會重置SF標(biāo)記
- x-y,SF標(biāo)記就會根據(jù)msb(x-y)的運(yùn)算結(jié)果而定
備注:不需要記住所有這些cmp指令和flag標(biāo)記的相關(guān)性
條件性跳轉(zhuǎn)
比較之后匈睁,可以進(jìn)行條件跳轉(zhuǎn)监透,條件跳轉(zhuǎn)基于標(biāo)志的狀態(tài)
代碼中的條件跳轉(zhuǎn)就像_jumps一樣編寫,但是“ jmp”被替換為條件跳轉(zhuǎn)的符號航唆。
例子:
如果rax寄存器指向的數(shù)據(jù)值等于23這行代碼會跳轉(zhuǎn)到標(biāo)簽"_fckU"
cmp rax,43
je _fckU
如果rax寄存器指向的數(shù)據(jù)值大于rbx寄存器指向的數(shù)據(jù)值胀蛮,這行代碼會跳轉(zhuǎn)到標(biāo)簽"_fckH"
cmp rax,rbx
jg _fckH
Call指令
call和jmp大致上是相同的。然而當(dāng)使用“call”指令時糯钙,可以使用“ ret”返回調(diào)用的原先的位置.
在下面的示例中粪狼,是使用call 調(diào)用_printHello標(biāo)記的section內(nèi)部的代碼,打印“Hello,World!",然后在_printHello的section內(nèi)部執(zhí)行到ret指令,會返回到原先_start標(biāo)記內(nèi)部的位置任岸,并且繼續(xù)執(zhí)行下面的“mov rax,72”的指令再榄。這種調(diào)用機(jī)制叫“子程序調(diào)用(subroutine)”