ARM匯編

匯編基本知識

高級語言可以通過編譯得到匯編語言,匯編語言再編譯成機器語言,機器語言也可以反匯編成匯編語言。每一條機器指令都有與之對應的匯編指令。在匯編中,大部分指令都是與CPU/內(nèi)存相關(guān)的。

內(nèi)存中除了指令,還有數(shù)據(jù),但是都是0和1組合,CPU是如何區(qū)分的?是通過CPU上的部件PC寄存器來區(qū)分。因為在內(nèi)存里數(shù)據(jù)和指令本質(zhì)沒有區(qū)別,那么要加以區(qū)分就是看是否被PC指向過,CPU將pc指向的內(nèi)存單元的內(nèi)容看做指令。

CPU會先將內(nèi)存中的數(shù)據(jù)存儲到通用寄存器中,然后再對寄存器中的數(shù)據(jù)進行運算


寄存器

針對arm64的CPU來說,
如果寄存器以x開頭,則表明是一個64位的寄存器
如果寄存器以w開頭,則表明是一個32位的寄存器
32位的寄存器是64位寄存器的低32位部分,并不是獨立存在的

ARM64擁有有31個64位的通用寄存器 x0 到 x30,通常用來做數(shù)據(jù)計算的臨時存儲、累加、計數(shù)、地址保存等功能,和其他三個SP、PC、CPSR寄存器。 因為64位CPU可以兼容32位.所以可以只使用64位寄存器的低32位.w0 就是 x0的低32位。

FP(x29):保存棧幀地址,指向方法棧的底部
LR(x30):通常稱X30為程序鏈接寄存器,保存子程序結(jié)束后需要執(zhí)行的下一條指令
SP :保存棧指針,指向方法棧的頂部,使用 SP/WSP來進行對SP寄存器的訪問。

  • X0 - X7:這 8 個寄存器主要用來存儲傳遞參數(shù)。如果參數(shù)超過 8 個,則會通過棧來傳遞;X0 也用來存放上文方法的返回值;
  • X29:即我們通常所說的幀指針FP(Frame Pointer),指向當前方法棧的底部(高地址)。幀指針FP保存的為“上一棧幀地址+返回地址”,其中返回地址就是調(diào)用者執(zhí)行調(diào)用函數(shù)后的下一條指令的地址。
  • X30:即鏈接寄存器 LR(Link Register)。為什么叫做鏈接,是因為這個寄存器會記錄著當前方法的調(diào)用方地址,即當前方法調(diào)用完成時應該返回的位置。例如我們遇到 Crash 要獲取方法堆棧,其本質(zhì)就是不斷的向上遞歸每一個 X30 寄存器的記錄狀態(tài)(也就是棧上 X30 寄存器的內(nèi)容)來找到上層調(diào)用方。
    除了這些通用寄存器,還有一個最重要的 SP 寄存器:
  • SP 寄存器:即我們通常說的棧指針 SP(Stack Pointer)。指向當前方法棧的頂部(低地址),與通用寄存器低 32 位的訪問方法一樣,你也可以通過 WSP 來訪問 SP 的低 32 位。當 SP 移動到棧區(qū)的最低位置(接近于堆區(qū)),則稱之為”爆棧“。
  • PC(Program Counter):程序計數(shù)器,俗稱PC指針,總是指向即將要執(zhí)行的指令,在arm64中,軟件是不能改寫PC寄存器的。因為在內(nèi)存里數(shù)據(jù)和指令本質(zhì)沒有區(qū)別,那么要加以區(qū)分就是看是否被PC指向過,CPU將pc指向的內(nèi)存單元的內(nèi)容看做指令。mov指令不能更改PC寄存器的值,需要通過bl跳轉(zhuǎn)指令來改變PC寄存器的值。
  • CRSP: 狀態(tài)寄存器
  • 浮點和向量寄存器

可以通過register read 寄存器 來打印寄存器地址。

大部分操作系統(tǒng)棧的增長方向都是從上往下(包括iOS/Mac),Stack Pointer指向棧頂部,Frame Pointer指向上一棧幀的Stack Pointer值,通過Frame Pointer就可以遞歸回溯獲取整個調(diào)用棧。


常見命令

  • b:用于不返回的跳轉(zhuǎn)
  • bl:用于子程序跳轉(zhuǎn),要返回地址,返回地址存于LR中。當發(fā)生bl跳轉(zhuǎn)前,會在寄存器 R14 (即LR)中保存當前PC-4,即bl跳轉(zhuǎn)指令的下一條指令的地址。所以在返回時只要 MOV pc,lr 。
  • bl命令可操作PC寄存器
  • callq:方法調(diào)用
  • ldr: 將內(nèi)存中的值讀取到寄存器中
  • cmp: 比較指令
  • str: 將寄存器中的值寫入到內(nèi)存中
  • cbz: 和 0 比較,如果結(jié)果為零就轉(zhuǎn)移(只能跳到后面的指令)
  • cbnz: 和非 0 比較,如果結(jié)果非零就轉(zhuǎn)移(只能跳到后面的指令)
  • ret: 子程序(函數(shù)調(diào)用)返回指令,返回地址已默認保存在寄存器 lr (x30) 中
  • MOV指令:是數(shù)據(jù)傳送指令,也是最基本的編程指令,用于將一個數(shù)據(jù)從源地址傳送到目標地址(寄存器間的數(shù)據(jù)傳送本質(zhì)上也是一樣的)。其特點是不破壞源地址單元的內(nèi)容,只能用于寄存器與寄存器或者寄存器 與常量之間傳值,不能用于內(nèi)存地址。不區(qū)分大小寫,例如mov和MOV是一樣的.
mov x1, x0   將寄存器x0的值復制到寄存器x1中

add x0, x1, x2 將寄存器x1和x2的值相加后保存到寄存器x0中

sub x0, x1, x2 將寄存器x1和x2的值相減后保存到寄存器x0中

and x0, x0, #0x1 將寄存器x0的值和常量1按位與后保存到x0中

orr x0, x0, #0x1 將寄存器x0的值和常量1按位或后保存到寄存器x0中

str x0, [x0, x8] 將寄存器x0中的值保存到棧內(nèi)存 [x0 + x8]處

ldr x0, [x1, x2] 將寄存器x1和寄存器x2的值相加作為地址,取該內(nèi)存地址的值放入寄存器x0中

stp x29, x30, [sp, #0x10] ; 將 x29, x30 的值存入 sp 偏移 16 個字節(jié)的位置

將內(nèi)存區(qū)域的i值+1并賦值給a的步驟如下
mov x0, i   先將i值放到x0寄存器中
add x0, 1   將x0中的值+1
mov a , x0  賦值給x0
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容