匯編(二) -- 寄存器

前言

最近準(zhǔn)備學(xué)習(xí)匯編,然后在B站上看到叫iOS小賢的作者發(fā)的視頻挺不錯(cuò),打算跟著學(xué),文章是看視頻的筆記,最后有原視頻鏈接,想看視頻的可以看看通過(guò)鏈接查看視頻。

寄存器

2990730-13132bfb35556f63.png
  1. 內(nèi)部部件之間由總線連接
  2. 對(duì)程序員來(lái)說(shuō),CPU中最主要部件是寄存器,可以通過(guò)改變寄存器的內(nèi)容來(lái)實(shí)現(xiàn)對(duì)CPU的控制
  3. 不同的CPU,寄存器的個(gè)數(shù)、結(jié)構(gòu)是不相同的(8086是16位結(jié)構(gòu)的CPU)

通用寄存器

  • ARM64擁有有31個(gè)64位的通用寄存器 x0 到 x30,這些寄存器通常用來(lái)存放一般性的數(shù)據(jù),稱為通用寄存器(有時(shí)也有特定用途)

    • 那么w0 到 w28 這些是32位的. 因?yàn)?4位CPU可以兼容32位.所以可以只使用64位寄存器的低32位.
    • 比如 w0 就是 x0的低32位!

模擬器是X86架構(gòu),所以用真機(jī)測(cè)才能看到ARM62的寄存器

屏幕快照 2019-08-04 下午2.18.31.png
  • 通常,CPU會(huì)先將內(nèi)存中的數(shù)據(jù)存儲(chǔ)到通用寄存器中,然后再對(duì)通用寄存器中的數(shù)據(jù)進(jìn)行運(yùn)算
  • 假設(shè)內(nèi)存中有塊紅色內(nèi)存空間的值是3,現(xiàn)在想把它的值加1,并將結(jié)果存儲(chǔ)到藍(lán)色內(nèi)存空間
2990730-853a43b3fc5f733e.png
  • CPU首先會(huì)將紅色內(nèi)存空間的值放到X0寄存器中:mov X0,紅色內(nèi)存空間
  • 然后讓X0寄存器與1相加:add X0,1
  • 最后將值賦值給內(nèi)存空間:mov 藍(lán)色內(nèi)存空間,X0

注:為什么是64位寄存器,因?yàn)镃PU是64位的,總線是64位的,一次通電可以傳遞64位的數(shù)據(jù)給CPU,也就是8個(gè)字節(jié),這個(gè)數(shù)據(jù)CPU存在寄存器中,所以寄存器是64位的。

問(wèn): 每次計(jì)算完又開(kāi)辟內(nèi)存空間存放結(jié)果?
答:匯編里面不存在開(kāi)辟空間,銷毀空間,直接通過(guò)內(nèi)存地址訪問(wèn),和高級(jí)語(yǔ)言不一樣。

pc寄存器(program counter)

  • 為指令指針寄存器,它指示了CPU當(dāng)前要讀取指令的地址
  • 在內(nèi)存或者磁盤上,指令和數(shù)據(jù)沒(méi)有任何區(qū)別,都是二進(jìn)制信息
  • CPU在工作的時(shí)候把有的信息看做指令,有的信息看做數(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 或者通過(guò)快捷鍵:shift+command + m 來(lái)調(diào)用內(nèi)存查看界面

屏幕快照 2019-08-04 下午2.42.44.png

0x102aaa92c - 0x102aaa928 = 4,所以每個(gè)指令戰(zhàn)4個(gè)字節(jié)。

FF 43 00 D1就是指令sub sp, sp, #0x10的二進(jìn)制表現(xiàn)形式。

可以在LLDB輸入ni單步往下走,發(fā)現(xiàn)依然斷點(diǎn)地址依然和pc寄存器一樣的。

屏幕快照 2019-08-04 下午2.45.31.png

輸入register write pc 0x102aaa92c改寫pc寄存器,可以看到跳轉(zhuǎn)到改寫后地址的下一個(gè)寄存器位置。

屏幕快照 2019-08-04 下午2.52.26.png
  • CPU根據(jù)什么將內(nèi)存中的信息看做指令?
  • CPU將pc指向的內(nèi)存單元的內(nèi)容看做指令
  • 如果內(nèi)存中的某段內(nèi)容曾被CPU執(zhí)行過(guò),那么它所在的內(nèi)存單元必然被pc指向過(guò)

bl指令

  • CPU從何處執(zhí)行指令是由pc中的內(nèi)容決定的,我們可以通過(guò)改變pc的內(nèi)容來(lái)控制CPU執(zhí)行目標(biāo)指令
  • ARM64提供了一個(gè)mov指令(傳送指令),可以用來(lái)修改大部分寄存器的值,比如
    • mov x0,#10、mov x1,#20
  • 但是,mov指令不能用于設(shè)置pc的值,ARM64沒(méi)有提供這樣的功能
  • ARM64提供了另外的指令來(lái)修改PC的值,這些指令統(tǒng)稱為轉(zhuǎn)移指令,最簡(jiǎn)單的是bl指令

注:#后面跟個(gè)數(shù)字,叫立即數(shù),

bl指令 -- 練習(xí)

現(xiàn)在有兩段代碼!假設(shè)程序先執(zhí)行A,請(qǐng)寫出指令執(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

我們來(lái)寫試試看,在xcode中創(chuàng)建文件,格式選擇Assembly File

.text告訴編譯器在text段,也就是代碼段,.global表示是全局的。
在.m文件中需要加上方法聲明int A();,這樣編譯才能通過(guò),因?yàn)閍sm.s是源文件,編譯的會(huì)鏈接到全局函數(shù)_A。

屏幕快照 2019-08-04 下午3.07.22.png
屏幕快照 2019-08-04 下午3.46.18.png

在A()打斷點(diǎn)


屏幕快照 2019-08-04 下午3.09.43.png

輸入s進(jìn)入函數(shù)A

屏幕快照 2019-08-04 下午3.15.03.png

我們可以看到x0就是a0,此時(shí)x1是50輸入ni單步往下走,x1變成0

屏幕快照 2019-08-04 下午3.18.41.png

add x1, x0, #0x14是把x0加上14然后賦值給x1,這樣x1就變成b4。

屏幕快照 2019-08-04 下午3.21.36.png

mov x0, x1是把x1的值賦值給x0,這樣x0和x1都是b4。

屏幕快照 2019-08-04 下午3.24.32.png

接下來(lái)bl 0x102df2c00跳轉(zhuǎn)到B函數(shù)。

屏幕快照 2019-08-04 下午3.26.55.png

然后一直輸入ni,會(huì)發(fā)現(xiàn)死循環(huán)了,至于為什么之后會(huì)解釋。

關(guān)于CPU&寄存器的補(bǔ)充

寄存器

CPU除了有控制器、運(yùn)算器還有寄存器。其中寄存器的作用就是進(jìn)行數(shù)據(jù)的臨時(shí)存儲(chǔ)。

CPU的運(yùn)算速度是非常快的,為了性能CPU在內(nèi)部開(kāi)辟一小塊臨時(shí)存儲(chǔ)區(qū)域,并在進(jìn)行運(yùn)算時(shí)先將數(shù)據(jù)從內(nèi)存復(fù)制到這一小塊臨時(shí)存儲(chǔ)區(qū)域中,運(yùn)算時(shí)就在這一小快臨時(shí)存儲(chǔ)區(qū)域內(nèi)進(jìn)行。我們稱這一小塊臨時(shí)存儲(chǔ)區(qū)域?yàn)榧拇嫫鳌?/p>

對(duì)于arm64系的CPU來(lái)說(shuō), 如果寄存器以x開(kāi)頭則表明的是一個(gè)64位的寄存器,如果以w開(kāi)頭則表明是一個(gè)32位的寄存器,在系統(tǒng)中沒(méi)有提供16位和8位的寄存器供訪問(wèn)和使用。其中32位的寄存器是64位寄存器的低32位部分并不是獨(dú)立存在的。

注:如果你改了x0寄存器,w0寄存器也會(huì)改,因?yàn)?2位的寄存器是64位寄存器的低32位部分并不是獨(dú)立存在的。

高速緩存

iPhoneX上搭載的ARM處理器A11它的1級(jí)緩存的容量是64KB,2級(jí)緩存的容量8M.

CPU每執(zhí)行一條指令前都需要從內(nèi)存中將指令讀取到CPU內(nèi)并執(zhí)行。而寄存器的運(yùn)行速度相比內(nèi)存讀寫要快很多,為了性能,CPU還集成了一個(gè)高速緩存存儲(chǔ)區(qū)域.當(dāng)程序在運(yùn)行時(shí),先將要執(zhí)行的指令代碼以及數(shù)據(jù)復(fù)制到高速緩存中去(由操作系統(tǒng)完成).CPU直接從高速緩存依次讀取指令來(lái)執(zhí)行.

數(shù)據(jù)地址寄存器

數(shù)據(jù)地址寄存器
數(shù)據(jù)地址寄存器通常用來(lái)做數(shù)據(jù)計(jì)算的臨時(shí)存儲(chǔ)、做累加、計(jì)數(shù)、地址保存等功能。定義這些寄存器的作用主要是用于在CPU指令中保存操作數(shù),在CPU中當(dāng)做一些常規(guī)變量來(lái)使用。
ARM64中

  • 64位: X0-X30, XZR(零寄存器)
  • 32位: W0-W30, WZR(零寄存器)

注意:
有一種特殊的寄存器段寄存器:CS,DS,SS,ES四個(gè)寄存器來(lái)保存這些段的基地址,這個(gè)屬于Intel架構(gòu)CPU中.在ARM中并沒(méi)有

注:以前內(nèi)存使用段劃分的,現(xiàn)在是平滑狀態(tài),從0到最后,只是文件里面分段,內(nèi)存中不再有段了。

浮點(diǎn)和向量寄存器

因?yàn)楦↑c(diǎn)數(shù)的存儲(chǔ)以及其運(yùn)算的特殊性,CPU中專門提供浮點(diǎn)數(shù)寄存器來(lái)處理浮點(diǎn)數(shù)

2990730-37dee6fae913d736.png
  • 浮點(diǎn)寄存器 64位: D0 - D31 32位: S0 - S31
    現(xiàn)在的CPU支持向量運(yùn)算.(向量運(yùn)算在圖形處理相關(guān)的領(lǐng)域用得非常的多)為了支持向量計(jì)算系統(tǒng)了也提供了眾多的向量寄存器.

  • 向量寄存器 128位:V0-V31

以上講的都是ARM64寄存器,附上8086的寄存器

  • 都是16位的
  • 可以存放2個(gè)字節(jié)
6850908-ef6c9773663b620b.png

參考:
寄存器
關(guān)于CPU&寄存器的補(bǔ)充
匯編(二)
匯編(三)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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