本篇通過(guò)拆解一段很簡(jiǎn)單的匯編代碼來(lái)快速認(rèn)識(shí)匯編,為讀懂鴻蒙匯編打基礎(chǔ).系列篇后續(xù)將逐個(gè)剖析鴻蒙的匯編文件.
匯編很簡(jiǎn)單
第一: 要認(rèn)定匯編語(yǔ)言一定是簡(jiǎn)單的,沒(méi)有高深的東西,無(wú)非就是數(shù)據(jù)的搬來(lái)搬去,運(yùn)行時(shí)數(shù)據(jù)主要待在兩個(gè)地方:內(nèi)存和寄存器。寄存器是CPU內(nèi)部存儲(chǔ)器,離運(yùn)算器最近,所以最快.
第二: 運(yùn)行空間(棧空間)就是CPU打卡上班的地方,內(nèi)核設(shè)計(jì)者規(guī)定誰(shuí)請(qǐng)CPU上班由誰(shuí)提供場(chǎng)地,用戶程序提供的場(chǎng)地叫用戶棧,敏感工作CPU要帶回公司做,公司提供的場(chǎng)地叫內(nèi)核棧,敏感工作叫系統(tǒng)調(diào)用,系統(tǒng)調(diào)用的本質(zhì)理解是CPU要切換工作模式即切換辦公場(chǎng)地。
第三:CPU的工作順序是流水線的,它只認(rèn)指令,而且只去一個(gè)地方(指向代碼段的PC寄存器)拿指令運(yùn)算消化。指令集是告訴外界我CPU能干什么活并提供對(duì)話指令,匯編語(yǔ)言是人和CPU能愉快溝通不擰巴的共識(shí)語(yǔ)言。一一對(duì)應(yīng)了CPU指令,又能確保記性不好的人類(lèi)能模塊化的設(shè)計(jì)idea, 先看一段C編譯成匯編代碼再來(lái)說(shuō)模塊化。
square(c -> 匯編)
//編譯器: armv7-a clang (trunk) //++++++++++++ square(c -> 匯編)++++++++++++++++++++++++ int square(int a,int b){ return a*b; } square(int, int): sub sp, sp, #8 @sp減去8,意思為給square分配??臻g,只用2個(gè)??臻g完成計(jì)算 str r0, [sp, #4] @第一個(gè)參數(shù)入棧 str r1, [sp] @第二個(gè)參數(shù)入棧 ldr r1, [sp, #4] @取出第一個(gè)參數(shù)給r1 ldr r2, [sp] @取出第二個(gè)參數(shù)給r2 mul r0, r1, r2 @執(zhí)行a*b給R0,返回值的工作一直是交給R0的 add sp, sp, #8 @函數(shù)執(zhí)行完了,要釋放申請(qǐng)的??臻g bx lr @子程序返回,等同于mov pc,lr,即跳到調(diào)用處
fp(c -> 匯編)
//++++++++++++ fp(c -> 匯編)++++++++++++++++++++++++ int fp(int b) { int a = 1; return square(a+b,a+b); } fp(int): push {r11, lr} @r11(fp)/lr入棧,保存調(diào)用者main的位置 mov r11, sp @r11用于保存sp值,函數(shù)棧開(kāi)始位置 sub sp, sp, #8 @sp減去8,意思為給fp分配??臻g,只用2個(gè)??臻g完成計(jì)算 str r0, [sp, #4] @先保存參數(shù)值,放在SP+4,此時(shí)r0中存放的是參數(shù) mov r0, #1 @r0=1 str r0, [sp] @再把1也保存在SP的位置 ldr r0, [sp] @把SP的值給R0 ldr r1, [sp, #4] @把SP+4的值給R1 add r1, r0, r1 @執(zhí)行r1=a+b mov r0, r1 @r0=r1,用r0,r1傳參 bl square(int, int)@先mov lr, pc 再mov pc square(int, int) mov sp, r11 @函數(shù)執(zhí)行完了,要釋放申請(qǐng)的棧空間 pop {r11, lr} @彈出r11和lr,lr是專用標(biāo)簽,彈出就自動(dòng)復(fù)制給lr寄存器 bx lr @子程序返回,等同于mov pc,lr,即跳到調(diào)用處
main(c -> 匯編)
//++++++++++++ main(c -> 匯編)++++++++++++++++++++++++ int main() { int sum = 0; for(int a = 0;a < 100; a++){ sum = sum + fp(a); } return sum; } main: push {r11, lr} @r11(fp)/lr入棧,保存調(diào)用者的位置 mov r11, sp @r11用于保存sp值,函數(shù)棧開(kāi)始位置 sub sp, sp, #16 @sp減去16,意思為給main分配??臻g,只用4個(gè)棧空間完成計(jì)算 mov r0, #0 @初始化r0 str r0, [r11, #-4] @執(zhí)行sum = 0 str r0, [sp, #8] @sum將始終占用SP+8的位置 str r0, [sp, #4] @a將始終占用SP+4的位置 b .LBB1_1 @跳到循環(huán)開(kāi)始位置 .LBB1_1: @循環(huán)開(kāi)始位置入口 ldr r0, [sp, #4] @取出a的值給r0 cmp r0, #99 @跟99比較 bgt .LBB1_4 @大于99,跳出循環(huán) mov pc .LBB1_4 b .LBB1_2 @繼續(xù)循環(huán),直接 mov pc .LBB1_2 .LBB1_2: @符合循環(huán)條件入口 ldr r0, [sp, #8] @取出sum的值給r0,sp+8用于寫(xiě)SUM的值 str r0, [sp] @先保存SUM的值,SP的位置用于讀SUM值 ldr r0, [sp, #4] @r0用于傳參,取出A的值給r0作為fp的參數(shù) bl fp(int) @先mov lr, pc再mov pc fp(int) mov r1, r0 @fp的返回值為r0,保存到r1 ldr r0, [sp] @取出SUM的值 add r0, r0, r1 @計(jì)算新sum的值,由R0保存 str r0, [sp, #8] @將新sum保存到SP+8的位置 b .LBB1_3 @無(wú)條件跳轉(zhuǎn),直接 mov pc .LBB1_3 .LBB1_3: @完成a++操作入口 ldr r0, [sp, #4] @SP+4中記錄是a的值,賦給r0 add r0, r0, #1 @r0增加1 str r0, [sp, #4] @把新的a值放回SP+4里去 b .LBB1_1 @跳轉(zhuǎn)到比較 a < 100 處 .LBB1_4: @循環(huán)結(jié)束入口 ldr r0, [sp, #8] @最后SUM的結(jié)果給R0,返回值的工作一直是交給R0的 mov sp, r11 @函數(shù)執(zhí)行完了,要釋放申請(qǐng)的??臻g pop {r11, lr} @彈出r11和lr,lr是專用標(biāo)簽,彈出就自動(dòng)復(fù)制給lr寄存器 bx lr @子程序返回,跳轉(zhuǎn)到lr處等同于 MOV PC, LR
代碼有點(diǎn)長(zhǎng),都加了注釋,如果能直接看懂那么恭喜你,鴻蒙內(nèi)核的6個(gè)匯編文件基于也就懂了。這是以下C文件全貌
文件全貌
#include#include int square(int a,int b){ return a*b; } int fp(int b) { int a = 1; return square(a+b,a+b); } int main() { int sum = 0; for(int a = 0;a < 100; a++){ sum = sum + fp(a); } return sum; }
代碼很簡(jiǎn)單誰(shuí)都能看懂,代碼很典型,具有代表性,有循環(huán),有判斷,有運(yùn)算,有多級(jí)函數(shù)調(diào)用。編譯后的匯編代碼基本和C語(yǔ)言的結(jié)構(gòu)差不太多, 區(qū)別是對(duì)循環(huán)的實(shí)現(xiàn)用了四個(gè)模塊,四個(gè)模塊也好理解: 一個(gè)是開(kāi)始?jí)K(LBB1_1), 一個(gè)符合條件的處理塊(LBB1_2),一個(gè)條件發(fā)生變化塊(LBB1_3),最后收尾塊(LBB1_4).
按塊逐一剖析.
先看最短的那個(gè)
int square(int a,int b){ return a*b; } //編譯成 square(int, int): sub sp, sp, #8 @sp減去8,意思為給square分配棧空間,只用2個(gè)??臻g完成計(jì)算 str r0, [sp, #4] @第一個(gè)參數(shù)入棧 str r1, [sp] @第二個(gè)參數(shù)入棧 ldr r1, [sp, #4] @取出第一個(gè)參數(shù)給r1 ldr r2, [sp] @取出第二個(gè)參數(shù)給r2 mul r0, r1, r2 @執(zhí)行a*b給R0,返回值的工作一直是交給R0的 add sp, sp, #8 @函數(shù)執(zhí)行完了,要釋放申請(qǐng)的??臻g bx lr @子程序返回,等同于mov pc,lr,即跳到調(diào)用處
首先上來(lái)一句 sub sp, sp, #8 等同于 sp = sp - 8 ,CPU運(yùn)行需要場(chǎng)地,這個(gè)場(chǎng)地就是棧 ,SP是指向棧的指針,表示此時(shí)用棧的刻度. 代碼和鴻蒙內(nèi)核用棧方式一樣,都采用了遞減滿棧的方式(FD). 什么是遞減滿棧? 遞減指的是棧底地址高于棧頂?shù)刂?棧的生長(zhǎng)方向是遞減的, 滿棧指的是SP指針永遠(yuǎn)指向棧頂. 每個(gè)函數(shù)都有自己獨(dú)立的棧底和棧頂,之間的空間統(tǒng)稱棧幀.可以理解為分配了一塊 區(qū)域給函數(shù)運(yùn)行,sub sp, sp, #8 代表申請(qǐng)2個(gè)??臻g,一個(gè)??臻g按四個(gè)字節(jié)算. 用完要不要釋放?當(dāng)然要,add sp, sp, #8 就是釋放??臻g. 是一對(duì)的,減了又加回去,空間就歸還了. ldr r1, [sp, #4] 的意思是取出SP+4這個(gè)虛擬地址的值給r1寄存器,而SP的指向并沒(méi)有改變的,還是在棧頂, 為什么要+呢, +就是往回?cái)?shù), 定位到分配的??臻g上.
一定要理解遞減滿棧,這是關(guān)鍵! 否則讀不懂內(nèi)核匯編代碼.
入?yún)⒎绞?/strong>
一般都是通過(guò)寄存器(r0..r10)傳參,fp調(diào)用square之前會(huì)先將參數(shù)給(r0..r10)
add r1, r0, r1 @執(zhí)行r1=a+b mov r0, r1 @r0=r1,用r0,r1傳參 bl square(int, int)@先mov lr, pc 再mov pc square(int, int)
到了square中后,先讓 r0,r1入棧,目的是保存參數(shù)值, 因?yàn)?square中要用r0,r1 ,
str r0, [sp, #4] @先入棧保存第一個(gè)參數(shù) str r1, [sp] @再入棧保存第二個(gè)參數(shù) ldr r1, [sp, #4] @再取出第一個(gè)參數(shù)給r1,(a*b)中a值 ldr r2, [sp] @再取出第二個(gè)參數(shù)給r2,用于計(jì)算 (a*b)中b值
是不是感覺(jué)這段匯編很傻,直接不保存計(jì)算不就完了嗎,這個(gè)是流程問(wèn)題,編譯器統(tǒng)一先保存參數(shù),至于你想怎么用它不管,也管不了. 另外返回值都是默認(rèn)統(tǒng)一給r0保存. square中將(a*b)的結(jié)果給了r0,回到fp中取出R0對(duì)fp來(lái)說(shuō)這就是square的返回值,這是規(guī)定.
函數(shù)調(diào)用main 和 fp 中都需要調(diào)用其他函數(shù),所以都出現(xiàn)了
push {r11, lr} //.... pop {r11, lr}
這哥倆也是成對(duì)出現(xiàn)的,這是函數(shù)調(diào)用的必備裝備,作用是保存和恢復(fù)調(diào)用者的現(xiàn)場(chǎng),例如 main -> fp, fp要保存main的棧幀范圍和指令位置, lr保存的是main函數(shù)執(zhí)行到哪個(gè)指令的位置, r11的作用是指向main的棧頂位置,如此fp執(zhí)行完后return回main的時(shí)候,先mov pc,lr, PC寄存器的值一變, 表示執(zhí)行的代碼就變了,又回到了main的指令和棧幀繼續(xù)未完成的事業(yè).
內(nèi)存和寄存器數(shù)據(jù)怎么搬?
數(shù)據(jù)主要待在兩個(gè)地方:內(nèi)存和寄存器. 寄存器<->寄存器 , 內(nèi)存<->寄存器 , 內(nèi)存<->內(nèi)存 搬運(yùn)指令都不一樣.
str r1, [sp] @ 寄存器->內(nèi)存 ldr r1, [sp, #4] @ 內(nèi)存->寄存器
這又是一對(duì),用于 內(nèi)存<->寄存器之間,熟知的 mov r0, r1 用于 寄存器<->寄存器
編輯:hfy
-
寄存器
+關(guān)注
關(guān)注
31文章
5434瀏覽量
124460 -
cpu
+關(guān)注
關(guān)注
68文章
11080瀏覽量
217040 -
鴻蒙系統(tǒng)
+關(guān)注
關(guān)注
183文章
2642瀏覽量
68086
發(fā)布評(píng)論請(qǐng)先 登錄
評(píng)論