arm64匯編入門

轉(zhuǎn)載自 #劉坤的技術(shù)博客 : https://blog.cnbluebox.com/blog/2017/07/24/arm64-start/

iOS開發(fā)同學(xué)的arm64匯編入門

在定位某些crash問題的時(shí)候覆获,有時(shí)候遇到一些問題很詭異。有時(shí)候掛在了系統(tǒng)庫里面。這個(gè)時(shí)候定位crash問題往往是比較頭疼的褥符。那么這個(gè)時(shí)候?qū)W會(huì)一些匯編知識(shí)腹暖,利用匯編調(diào)試技巧進(jìn)行調(diào)試可能會(huì)起到意想不到的效果藐握。

學(xué)習(xí)匯編語言不只是幫助定位crash而已穿香,學(xué)習(xí)匯編可以幫助你真正的理解計(jì)算機(jī)野崇。畢竟CPU上跑的就是對(duì)應(yīng)的指令集袜蚕。

0x1 工具

我們面對(duì)的要么是源代碼糟把,要么是二進(jìn)制。因此我們需要一些反匯編的工具來輔助我們進(jìn)行匯編代碼查看牲剃。推薦工具有: – Hopper Disassembler 收費(fèi)應(yīng)用遣疯,看匯編代碼非常方便 – MachOView 開源工具,看Mach-o文件結(jié)構(gòu)非常方便凿傅。

0x2 基本概念

從高級(jí)語言過渡到匯編語言缠犀,重要的是基本概念的轉(zhuǎn)換。匯編里面要學(xué)習(xí)的三個(gè)重要概念聪舒,我認(rèn)為是 寄存器辨液、棧、指令箱残。 arm64架構(gòu)又分為2種執(zhí)行狀態(tài): AArch64 Application LevelAArch32 Application Level, 本文只講AArch64.

0x21 寄存器

如果你還不知道什么是寄存器滔迈,建議先Google一下。 這里不再詳細(xì)說明被辑,寄存器是CPU中的高速存儲(chǔ)單元燎悍,要比內(nèi)存中存取要快的多。

這里說明一下arm64有哪些寄存器:

  • R0 – R30

r0 - r30 是31個(gè)通用整形寄存器盼理。每個(gè)寄存器可以存取一個(gè)64位大小的數(shù)谈山。 當(dāng)使用 x0 - x30訪問時(shí),它就是一個(gè)64位的數(shù)宏怔。當(dāng)使用 w0 - w30訪問時(shí)奏路,訪問的是這些寄存器的低32位,如圖:

image.png

其實(shí)通用寄存器有32個(gè)臊诊,第32個(gè)寄存器x31鸽粉,在指令編碼中,使用來做 zero register, 即ZR, XZR/WZR分別代表64/32位妨猩,zero register的作用就是0潜叛,寫進(jìn)去代表丟棄結(jié)果,拿出來是0.

其中 r29 又被叫做 fp (frame pointer). r30 又被叫做 lr (link register)。其用途會(huì)在下一節(jié)《椡担》中講到销斟。

  • SP

SP寄存器其實(shí)就是 x31,在指令編碼中椒舵,使用 SP/WSP來進(jìn)行對(duì)SP寄存器的訪問蚂踊。

  • PC

PC寄存器中存的是當(dāng)前執(zhí)行的指令的地址。在arm64中笔宿,軟件是不能改寫PC寄存器的犁钟。

  • V0 – V31

V0 - V31 是向量寄存器,也可以說是浮點(diǎn)型寄存器泼橘。它的特點(diǎn)是每個(gè)寄存器的大小是 128 位的涝动。 分別可以用Bn Hn Sn Dn Qn的方式來訪問不同的位數(shù)。如圖:

image.png

Bn Hn Sn Dn Qn可以這樣理解記憶, 基于一個(gè)word是32位炬灭,也就是4Byte大写姿凇:

Bn: 一個(gè)Byte的大小
Hn: half word. 就是16位
Sn: single word. 32位
Dn: double word. 64位
Qn: quad word. 128位

  • SPRs

SPRs是狀態(tài)寄存器,用于存放程序運(yùn)行中一些狀態(tài)標(biāo)識(shí)重归。不同于編程語言里面的if else.在匯編中就需要根據(jù)狀態(tài)寄存器中的一些狀態(tài)來控制分支的執(zhí)行米愿。狀態(tài)寄存器又分為 The Current Program Status Register (CPSR)The Saved Program Status Registers (SPSRs)。 一般都是使用CPSR鼻吮, 當(dāng)發(fā)生異常時(shí)育苟, CPSR會(huì)存入SPSR。當(dāng)異匙的荆恢復(fù)违柏,再拷貝回CPSR

還有一些系統(tǒng)寄存器拓哺,還有 FPSR FPCR是浮點(diǎn)型運(yùn)算時(shí)的狀態(tài)寄存器等勇垛。基本了解上面這些寄存器就可以了士鸥。

0x22 棧

棧就是指令執(zhí)行時(shí)存放臨時(shí)變量的內(nèi)存空間。在學(xué)習(xí)匯編代碼的執(zhí)行過程中谆级,了解棧的結(jié)構(gòu)非常重要烤礁。

先列出一些棧的特性:

  • 棧是從高地址到低地址的, 棧低是高地址肥照,棧頂是低地址脚仔。
  • fp指向當(dāng)前frame的棧底,也就是高地址舆绎。
  • sp指向棧頂鲤脏,也就是地地址。

下面的圖簡(jiǎn)單的描述了從方法A調(diào)用方法B時(shí) 棧是如何劃分的:

image.png

其中3行匯編代碼就是方法B的前三行匯編指令。它們做的事情就是圖中描述的事情 (x29就是fp, x30就是lr):

  • fp, lr保存到 sp - 0x10的地方. 也就是圖中 --> fp_B的位置猎醇。然后將sp設(shè)置為 sp-0x10
  • fp 設(shè)置為當(dāng)前 sp窥突。也就是 --> fp_B的位置。 這一步就設(shè)置了_funcB的 fp了
  • sp 設(shè)置為 sp - 0x30硫嘶。 也就是將sp指向了圖中 --> sp_B 的位置

注: lrlink register中的值阻问,它存的是方法_funcA的執(zhí)行的最后一行指令的下一行。它的作用也很好理解:當(dāng)_funcB執(zhí)行完了之后要返回_funcA繼續(xù)執(zhí)行沦疾,但是計(jì)算機(jī)要如何知道返回到哪執(zhí)行呢称近? 就是靠lr記錄了返回的地址,方法才能得以正常返回哮塞。

說道這里刨秆,那么當(dāng) _funcB執(zhí)行完畢后,是如何把椧涑恢復(fù)到_funcA的過程的呢衡未? 我們直接分析 _funcB的最后3條指令:

mov        sp, fp;              //  sp 設(shè)置為fp, 就是圖中 -->fp_B 的位置
ldp           fp, lr, [sp], #0x10; //  從sp指向的地址中讀取 2個(gè)64位,分別存入fp,lr邻眷。 然后將sp += 0x10
// 這一步執(zhí)行完之后眠屎,fp就執(zhí)行了圖中 -->fp_A. lr恢復(fù)成 _funcA的返回地址。 sp指向了 -->sp_A. 
// 這個(gè)時(shí)候狀態(tài)已經(jīng)完全恢復(fù)到了 _funcA 的環(huán)境
ret;    // 返回指令肆饶,這一步直接執(zhí)行l(wèi)r的指令改衩。

上面描述了方法如何調(diào)用的。我們知道在編程語言里面方法都有入?yún)⒀蹦鳎蟹祷刂档暮健T趨R編里面如何體現(xiàn)呢?

  • 一般來說 arm64上 x0 – x7 分別會(huì)存放方法的前 8 個(gè)參數(shù)
  • 如果參數(shù)個(gè)數(shù)超過了8個(gè)板惑,多余的參數(shù)會(huì)存在棧上橄镜,新方法會(huì)通過棧來讀取。
  • 方法的返回值一般都在 x0 上冯乘。
  • 如果方法返回值是一個(gè)較大的數(shù)據(jù)結(jié)構(gòu)時(shí)洽胶,結(jié)果會(huì)存在 x8 執(zhí)行的地址上。

0x23 指令

在上一級(jí)的內(nèi)容中我們已經(jīng)看到了一些指令裆馒。 匯編指令除了數(shù)量較多姊氓,其基本原理都是比較簡(jiǎn)單的,單拎出來一條指令就是很simple的操作喷好。 比如mov就是一個(gè)賦值翔横。ldr就是一個(gè)取值。

那匯編指令大概可以分為哪幾種呢梗搅?我認(rèn)為了解以下幾種基本指令就可以正常閱讀匯編代碼了禾唁。

0x231 運(yùn)算

  • 算術(shù)運(yùn)算

算術(shù)運(yùn)算就是像 ADD SUB MUL … 等加減乘除運(yùn)算效览,也是很好理解的指令
如:

add x0, x1, x2; // 把 x1 + x2 = x0 這樣一個(gè)操作。
sub sp, sp, 0x30; // 把 sp - 30 存入sp.
cmp x11, #4;  // 相當(dāng)于 subs xzr, x11, #4\.  
              // 如果 x11 - 4 == 0, 那么狀態(tài)寄存器NZCV.Z = 1
              // 如果 x11 - 4 < 0, 那么 NZCV.N = 1

NZCV是狀態(tài)寄存器中存的幾個(gè)狀態(tài)值荡短,分別代表運(yùn)算過程中產(chǎn)生的狀態(tài)丐枉,其中:

  • N, negative condition flag,一般代表運(yùn)算結(jié)果是負(fù)數(shù)
  • Z, zero condition flag, 運(yùn)算結(jié)果為0
  • C, carry condition flag, 無符號(hào)運(yùn)算有溢出時(shí)肢预,C=1矛洞。
  • V, oVerflow condition flag 有符號(hào)運(yùn)算有溢出時(shí),V=1烫映。
  • 邏輯運(yùn)算指令

LSL(邏輯左移) LSR(邏輯右移) ASR(算術(shù)右移) ROR(循環(huán)右移)沼本。
AND(與) ORR(或) EOR(異或)

邏輯位移運(yùn)算通常也可以與算術(shù)運(yùn)算一起用,如:

 add  x14, x4, x27, lsl #1; // 意思是把  (x27 << 1) + x4 = x14;

  • 拓展位數(shù)運(yùn)算

zero extend(高位補(bǔ)0) 和 sign extend(高位填充和符號(hào)位一致锭沟,一般有符號(hào)數(shù)用這個(gè))抽兆。 一般用來補(bǔ)齊位數(shù)。常和算術(shù)運(yùn)算配合一起.
如:

add        w20, w30, w20, uxth  // 取 w20的低16位族淮,無符號(hào)補(bǔ)齊到32位后再進(jìn)行  w30 + w20的運(yùn)算辫红。

  • Mov

0x232 尋址

既然是和內(nèi)存相關(guān)的,那就是兩種祝辣,一種存贴妻,一種取。一般來說
L打頭的基本都是取值指令蝙斜,如 LDR LDP;
S打頭的基本都是存值指令名惩,如 STR STP;

例:

ldr x0, [x1]; // 從`x1`指向的地址里面取出一個(gè) 64 位大小的數(shù)存入 `x0`
ldp x1, x2, [x10, #0x10]; // 從 x10 + 0x10 指向的地址里面取出 2個(gè) 64位的數(shù),分別存入x1, x2
str x5, [sp, #24]; // 把x5的值(64位數(shù)值)存到 sp+24 指向的內(nèi)存地址上
stp x29, x30, [sp, #-16]!; // 把 x29, x30的值存到 sp-16的地址上孕荠,并且把 sp-=16\. 
ldp x29, x30, [sp], #16;  // 從sp地址取出 16 byte數(shù)據(jù)娩鹉,分別存入x29, x30\. 然后 sp+=16;

其中尋址的格式由分為下面這3種類型:

[x10, #0x10]      // signed offset。 意思是從 x10 + 0x10的地址取值
[sp, #-16]!       // pre-index稚伍。  意思是從 sp-16地址取值弯予,取值完后在把 sp-16  writeback 回 sp
[sp], #16         // post-index。 意思是從 sp 地址取值个曙,取值完后在把 sp+16 writeback 回 sp

0x233 跳轉(zhuǎn)

跳轉(zhuǎn)氛圍有返回跳轉(zhuǎn)BL和無返回跳轉(zhuǎn)B锈嫩。 有返回的意思就是會(huì)存lr,因此 BLL也可以理解為LR的意思。

1.存了LR也就意味著可以返回到本方法繼續(xù)執(zhí)行垦搬。一般用于不同方法直接的調(diào)用
2.B相關(guān)的跳轉(zhuǎn)沒有LR祠挫,一般是本方法內(nèi)的跳轉(zhuǎn),如while循環(huán)悼沿,if else等。

跳轉(zhuǎn)相關(guān)的指令還會(huì)有種邏輯運(yùn)算骚灸,就是condition code糟趾。配合狀態(tài)寄存器中的狀態(tài)標(biāo)示,就是代碼分支if else實(shí)現(xiàn)的關(guān)鍵。
condition code有以下這些义郑,表格中還標(biāo)注除了分別是比NZCV的哪個(gè)值:

image.png

如:

cmp x2, #0;         // x2 - 0 = 0蝶柿。  狀態(tài)寄存器標(biāo)識(shí)zero: PSTATE.NZCV.Z = 1
b.ne  0x1000d48f0;  // ne就是個(gè)condition code, 這句的意思是,當(dāng)判斷狀態(tài)寄存器 NZCV.Z != 1才跳轉(zhuǎn)非驮,因此這句不會(huì)跳轉(zhuǎn)

0x1000d4ab0 bl testFuncA;  // 跳轉(zhuǎn)方法交汤,這個(gè)時(shí)候 lr 設(shè)置為 0x1000d4ab4
0x1000d4ab4 orr x8, xzr, #0x1f00000000 // testFuncA執(zhí)行完之后跳回lr就周到了這一行

0x4 小結(jié)

本文簡(jiǎn)單介紹了一些arm64的匯編知識(shí),arm64匯編的學(xué)習(xí)對(duì)于理解iOS代碼的執(zhí)行劫笙,計(jì)算機(jī)的運(yùn)行都有著不少的好處芙扎。我們?cè)谌粘V欣脜R編知識(shí)可以定位一些疑難雜癥的crash問題√畲螅可以從匯編原理出手開一個(gè)個(gè)腦洞戒洼,玩一些黑科技。比如包瘦身允华,靜態(tài)掃描等圈浇。

匯編指令的執(zhí)行是簡(jiǎn)單確定的,不會(huì)像我們調(diào)試其他代碼一眼靴寂,有些詭異問題磷蜀,而匯編每條指令的結(jié)果都是確定的,從這一角度來定位問題往往可以定位到根本原因百炬。

在匯編指令執(zhí)行的世界褐隆,你可以對(duì)代碼執(zhí)行有更深刻的理解,原來一行代碼會(huì)被分解成這么多的指令收壕!因此妓灌,如果你在看完本文后對(duì)于學(xué)習(xí)匯編有了興趣,但是有很多細(xì)節(jié)還不太懂蜜宪,建議你自己用hopper反編譯一些代碼虫埂,自己嘗試一行一行理解每一個(gè)指令的意義,基本看透幾個(gè)方法就可以融匯貫通了圃验。

0x5 參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掉伏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子澳窑,更是在濱河造成了極大的恐慌斧散,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摊聋,死亡現(xiàn)場(chǎng)離奇詭異鸡捐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)麻裁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門箍镜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來源祈,“玉大人,你說我怎么就攤上這事色迂∠闳保” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵歇僧,是天一觀的道長(zhǎng)图张。 經(jīng)常有香客問我,道長(zhǎng)诈悍,這世上最難降的妖魔是什么祸轮? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮写隶,結(jié)果婚禮上倔撞,老公的妹妹穿的比我還像新娘。我一直安慰自己慕趴,他們只是感情好痪蝇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著冕房,像睡著了一般躏啰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耙册,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天给僵,我揣著相機(jī)與錄音,去河邊找鬼详拙。 笑死帝际,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的饶辙。 我是一名探鬼主播蹲诀,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼弃揽!你這毒婦竟也來了脯爪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤矿微,失蹤者是張志新(化名)和其女友劉穎痕慢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涌矢,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掖举,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了娜庇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拇泛。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡滨巴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出俺叭,到底是詐尸還是另有隱情,我是刑警寧澤泰偿,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布熄守,位于F島的核電站,受9級(jí)特大地震影響耗跛,放射性物質(zhì)發(fā)生泄漏裕照。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一调塌、第九天 我趴在偏房一處隱蔽的房頂上張望晋南。 院中可真熱鬧,春花似錦羔砾、人聲如沸负间。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽政溃。三九已至,卻和暖如春态秧,著一層夾襖步出監(jiān)牢的瞬間董虱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工申鱼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愤诱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓捐友,卻偏偏與公主長(zhǎng)得像淫半,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子楚殿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 在定位某些crash問題的時(shí)候撮慨,有時(shí)候遇到一些問題很詭異。有時(shí)候掛在了系統(tǒng)庫里面脆粥。這個(gè)時(shí)候定位crash問題往往是...
    kakukeme閱讀 6,614評(píng)論 0 58
  • 這里主要介紹 iOS 平臺(tái)上 ARM64 架構(gòu)的寄存器和指令以及內(nèi)存堆棧砌溺。 堆棧 在 iOS 中,棻涓簦空間是向下生長(zhǎng)...
    End_楓閱讀 671評(píng)論 0 0
  • 現(xiàn)在iOS設(shè)備幾乎已經(jīng)都是ARM64架構(gòu)规伐,此外,Mac M1芯片的電腦也是基于ARM64架構(gòu)匣缘,本文對(duì)ARM64匯...
    chonglingliu閱讀 2,276評(píng)論 0 1
  • 在定位某些crash問題的時(shí)候猖闪,有時(shí)候遇到一些問題很詭異鲜棠。有時(shí)候掛在了系統(tǒng)庫里面。這個(gè)時(shí)候定位crash問題往往是...
    一川煙草i蓑衣閱讀 1,222評(píng)論 0 2
  • iOS匯編 iOS匯編語音有很多鐘培慌。常見的有8086匯編豁陆、arm匯編、x86匯編等等吵护。 arm匯編 iOS的架構(gòu)從...
    編程怪才_(tái)凌雨畫閱讀 1,767評(píng)論 1 4