前言
最近準(zhǔn)備學(xué)習(xí)匯編尤泽,然后在B站上看到叫iOS小賢的作者發(fā)的視頻挺不錯脆淹,打算跟著學(xué)签杈,文章是看視頻的筆記瘫镇,最后有原視頻鏈接,想看視頻的可以看看通過鏈接查看視頻答姥。
寄存器
- 內(nèi)部部件之間由總線連接
- 對程序員來說铣除,CPU中最主要部件是寄存器,可以通過改變寄存器的內(nèi)容來實現(xiàn)對CPU的控制
- 不同的CPU鹦付,寄存器的個數(shù)尚粘、結(jié)構(gòu)是不相同的(8086是16位結(jié)構(gòu)的CPU)
通用寄存器
-
ARM64擁有有31個64位的通用寄存器 x0 到 x30,這些寄存器通常用來存放一般性的數(shù)據(jù),稱為通用寄存器(有時也有特定用途)
- 那么w0 到 w28 這些是32位的. 因為64位CPU可以兼容32位.所以可以只使用64位寄存器的低32位.
- 比如 w0 就是 x0的低32位!
模擬器是X86架構(gòu)敲长,所以用真機測才能看到ARM62的寄存器
- 通常郎嫁,CPU會先將內(nèi)存中的數(shù)據(jù)存儲到通用寄存器中,然后再對通用寄存器中的數(shù)據(jù)進行運算
- 假設(shè)內(nèi)存中有塊紅色內(nèi)存空間的值是3祈噪,現(xiàn)在想把它的值加1泽铛,并將結(jié)果存儲到藍色內(nèi)存空間
- CPU首先會將紅色內(nèi)存空間的值放到X0寄存器中:mov X0,紅色內(nèi)存空間
- 然后讓X0寄存器與1相加:add X0,1
- 最后將值賦值給內(nèi)存空間:mov 藍色內(nèi)存空間,X0
注:為什么是64位寄存器,因為CPU是64位的钳降,總線是64位的厚宰,一次通電可以傳遞64位的數(shù)據(jù)給CPU,也就是8個字節(jié),這個數(shù)據(jù)CPU存在寄存器中铲觉,所以寄存器是64位的澈蝙。
問: 每次計算完又開辟內(nèi)存空間存放結(jié)果?
答:匯編里面不存在開辟空間撵幽,銷毀空間灯荧,直接通過內(nèi)存地址訪問,和高級語言不一樣盐杂。
pc寄存器(program counter)
- 為指令指針寄存器逗载,它指示了CPU當(dāng)前要讀取指令的地址
- 在內(nèi)存或者磁盤上,指令和數(shù)據(jù)沒有任何區(qū)別链烈,都是二進制信息
- CPU在工作的時候把有的信息看做指令厉斟,有的信息看做數(shù)據(jù),為同樣的信息賦予了不同的意義
- 比如 1110 0000 0000 0011 0000 1000 1010 1010
- 可以當(dāng)做數(shù)據(jù) 0xE003008AA
- 也可以當(dāng)做指令 mov x0, x8
0x102aaa928 <+0>: sub sp, sp, #0x10
左邊是指令地址强衡,右邊是指令擦秽。
Debug -> Debug Workflow -> View Memory 或者通過快捷鍵:shift+command + m 來調(diào)用內(nèi)存查看界面
0x102aaa92c - 0x102aaa928 = 4
,所以每個指令戰(zhàn)4個字節(jié)漩勤。
FF 43 00 D1
就是指令sub sp, sp, #0x10
的二進制表現(xiàn)形式感挥。
可以在LLDB輸入ni
單步往下走,發(fā)現(xiàn)依然斷點地址依然和pc寄存器一樣的越败。
輸入register write pc 0x102aaa92c
改寫pc寄存器触幼,可以看到跳轉(zhuǎn)到改寫后地址的下一個寄存器位置。
- CPU根據(jù)什么將內(nèi)存中的信息看做指令究飞?
- CPU將pc指向的內(nèi)存單元的內(nèi)容看做指令
- 如果內(nèi)存中的某段內(nèi)容曾被CPU執(zhí)行過置谦,那么它所在的內(nèi)存單元必然被pc指向過
bl指令
- CPU從何處執(zhí)行指令是由pc中的內(nèi)容決定的,我們可以通過改變pc的內(nèi)容來控制CPU執(zhí)行目標(biāo)指令
- ARM64提供了一個mov指令(傳送指令)噪猾,可以用來修改大部分寄存器的值霉祸,比如
- mov x0,#10筑累、mov x1,#20
- 但是袱蜡,mov指令不能用于設(shè)置pc的值,ARM64沒有提供這樣的功能
- ARM64提供了另外的指令來修改PC的值慢宗,這些指令統(tǒng)稱為轉(zhuǎn)移指令坪蚁,最簡單的是bl指令
注:#
后面跟個數(shù)字,叫立即數(shù)镜沽,
bl指令 -- 練習(xí)
現(xiàn)在有兩段代碼!假設(shè)程序先執(zhí)行A,請寫出指令執(zhí)行順序.最終寄存器x0的值是多少?
_A:
mov x0,#0xa0
mov x1,#0x00
add x1, x0, #0x14
mov x0,x1
bl _B
mov x0,#0x0
ret
_B:
add x0, x0, #0x10
ret
我們來寫試試看敏晤,在xcode中創(chuàng)建文件,格式選擇Assembly File
.text
告訴編譯器在text段缅茉,也就是代碼段嘴脾,.global
表示是全局的。
在.m文件中需要加上方法聲明int A();
,這樣編譯才能通過译打,因為asm.s是源文件耗拓,編譯的會鏈接到全局函數(shù)_A。
在A()打斷點
輸入s進入函數(shù)A
我們可以看到x0就是a0奏司,此時x1是50輸入ni
單步往下走乔询,x1變成0
add x1, x0, #0x14
是把x0加上14然后賦值給x1,這樣x1就變成b4韵洋。
mov x0, x1
是把x1的值賦值給x0竿刁,這樣x0和x1都是b4。
接下來bl 0x102df2c00
跳轉(zhuǎn)到B函數(shù)搪缨。
然后一直輸入ni食拜,會發(fā)現(xiàn)死循環(huán)了,至于為什么之后會解釋副编。
關(guān)于CPU&寄存器的補充
寄存器
CPU除了有控制器监婶、運算器還有寄存器。其中寄存器的作用就是進行數(shù)據(jù)的臨時存儲齿桃。
CPU的運算速度是非郴蠡蹋快的,為了性能CPU在內(nèi)部開辟一小塊臨時存儲區(qū)域短纵,并在進行運算時先將數(shù)據(jù)從內(nèi)存復(fù)制到這一小塊臨時存儲區(qū)域中带污,運算時就在這一小快臨時存儲區(qū)域內(nèi)進行。我們稱這一小塊臨時存儲區(qū)域為寄存器香到。
對于arm64系的CPU來說鱼冀, 如果寄存器以x開頭則表明的是一個64位的寄存器,如果以w開頭則表明是一個32位的寄存器悠就,在系統(tǒng)中沒有提供16位和8位的寄存器供訪問和使用千绪。其中32位的寄存器是64位寄存器的低32位部分并不是獨立存在的。
注:如果你改了x0寄存器梗脾,w0寄存器也會改荸型,因為32位的寄存器是64位寄存器的低32位部分并不是獨立存在的。
高速緩存
iPhoneX上搭載的ARM處理器A11它的1級緩存的容量是64KB炸茧,2級緩存的容量8M.
CPU每執(zhí)行一條指令前都需要從內(nèi)存中將指令讀取到CPU內(nèi)并執(zhí)行瑞妇。而寄存器的運行速度相比內(nèi)存讀寫要快很多,為了性能,CPU還集成了一個高速緩存存儲區(qū)域.當(dāng)程序在運行時,先將要執(zhí)行的指令代碼以及數(shù)據(jù)復(fù)制到高速緩存中去(由操作系統(tǒng)完成).CPU直接從高速緩存依次讀取指令來執(zhí)行.
數(shù)據(jù)地址寄存器
數(shù)據(jù)地址寄存器
數(shù)據(jù)地址寄存器通常用來做數(shù)據(jù)計算的臨時存儲梭冠、做累加辕狰、計數(shù)、地址保存等功能控漠。定義這些寄存器的作用主要是用于在CPU指令中保存操作數(shù)蔓倍,在CPU中當(dāng)做一些常規(guī)變量來使用。
ARM64中
- 64位: X0-X30, XZR(零寄存器)
- 32位: W0-W30, WZR(零寄存器)
注意:
有一種特殊的寄存器段寄存器:CS,DS,SS,ES四個寄存器來保存這些段的基地址,這個屬于Intel架構(gòu)CPU中.在ARM中并沒有
注:以前內(nèi)存使用段劃分的,現(xiàn)在是平滑狀態(tài)偶翅,從0到最后他去,只是文件里面分段,內(nèi)存中不再有段了倒堕。
浮點和向量寄存器
因為浮點數(shù)的存儲以及其運算的特殊性,CPU中專門提供浮點數(shù)寄存器來處理浮點數(shù)
浮點寄存器 64位: D0 - D31 32位: S0 - S31
現(xiàn)在的CPU支持向量運算.(向量運算在圖形處理相關(guān)的領(lǐng)域用得非常的多)為了支持向量計算系統(tǒng)了也提供了眾多的向量寄存器.向量寄存器 128位:V0-V31
以上講的都是ARM64寄存器灾测,附上8086的寄存器
- 都是16位的
- 可以存放2個字節(jié)