1. 沒(méi)錯(cuò)!cxuan 對(duì)匯編下手了

        共 5762字,需瀏覽 12分鐘

         ·

        2021-09-18 19:05


        匯編代碼是計(jì)算機(jī)的一種低級(jí)表示,它是一種低級(jí)語(yǔ)言,可以從字面角度去理解它,包括處理數(shù)據(jù)、管理內(nèi)存、讀寫存儲(chǔ)設(shè)備上的數(shù)據(jù),以及利用網(wǎng)絡(luò)通信等。編譯器生成機(jī)器碼經(jīng)過(guò)了一系列的轉(zhuǎn)換,這些轉(zhuǎn)換遵循編程語(yǔ)言、目標(biāo)機(jī)器的指令集操作系統(tǒng)。

        指令集

        指令集就是指揮計(jì)算機(jī)工作的指令,因?yàn)槌绦蚓褪前凑找欢▓?zhí)行順序排列的指令。因?yàn)橛?jì)算機(jī)的執(zhí)行控制權(quán)由 CPU 操作,所以指令集就是 CPU 中用來(lái)計(jì)算和控制計(jì)算機(jī)的一系列指令的集合。每個(gè) CPU 在產(chǎn)出時(shí)都規(guī)定了與硬件電路相互配合工作的指令集。

        指令集有不少分類,但是一般分為兩種,一種是精簡(jiǎn)指令集,一種是復(fù)雜指令集。具體描述如下

        精簡(jiǎn)指令集

        精簡(jiǎn)指令的英文是 reduced instruction set computer, RISC,原意是精簡(jiǎn)指令集計(jì)算,簡(jiǎn)稱為精簡(jiǎn)指令集,是 CPU 的一種 設(shè)計(jì)模式,可以把 CPU 想象成一家流水線工廠,對(duì)指令數(shù)目尋址方式都做了精簡(jiǎn),使其實(shí)現(xiàn)更容易,指令并行執(zhí)行程度更好,編譯器的效率更高。

        常見的精簡(jiǎn)指令集處理器包括 ARM、AVR、MIPS、PARISC、RISC-V 和 SPARC。

        所以你就能理解

        這本書是講啥的了。

        它主要是基于 MIPS 體系結(jié)構(gòu)把馮諾依曼體系的五大組件進(jìn)行了逐一的硬件實(shí)現(xiàn) + 軟件設(shè)計(jì)介紹,更為重要的是引入了諸多并行計(jì)算的內(nèi)容,這是大部分教材中忽略或者內(nèi)容較少的,會(huì)根據(jù)這個(gè)思路把并行相關(guān)的內(nèi)容,結(jié)合 OpenMP, CUDA 和 Hadoop/Spark 整體融入到新書中,畢竟這是未來(lái)發(fā)展的趨勢(shì)

        還有這本書

        這本書又是講啥的。

        這本書是講 RISC-V 指令集的,因?yàn)橹噶罴牟煌矃^(qū)分了三個(gè)版本,三個(gè)版本???嗯,還有下面這個(gè)

        這本書是講 ARM 指令集的。

        所以一般在看 CASPP 的時(shí)候并發(fā)的看看這本書是非常不錯(cuò)的選擇。

        精簡(jiǎn)指令集一般具有如下特征

        • 統(tǒng)一的指令編碼
        • 通用的寄存器,一般會(huì)區(qū)分整數(shù)和浮點(diǎn)數(shù)
        • 簡(jiǎn)單的尋址模式,復(fù)雜尋址模式被簡(jiǎn)單指令序列來(lái)取代
        • 支持很少偏門的類型,例如 RISC 支持字節(jié)字符串類型。

        復(fù)雜指令集

        復(fù)雜指令集的英文是 Complex Instruction Set Computing, CISC,是一種微處理器指令集架構(gòu),也被譯為復(fù)雜指令集。

        復(fù)雜指令集包括 System/360、VAX、x86 等

        復(fù)雜指令集可以說(shuō)是在精簡(jiǎn)指令集之上作出的改變。

        復(fù)雜指令集的特點(diǎn)是指令數(shù)目多而復(fù)雜,每條指令字長(zhǎng)并不相等,計(jì)算機(jī)必須加以判讀,并為此付出了性能的代價(jià)。

        一般來(lái)說(shuō),提升 CPU 性能的方法有如下這幾種

        • 增加寄存器的大小
        • 增進(jìn)內(nèi)部的并行性
        • 增加高速緩存的大小
        • 增加核心時(shí)脈的速度
        • 加入其他功能,例如 IO 和計(jì)時(shí)器
        • 加入向量處理器
        • 硬件多線程技術(shù)

        比較抽象,我們后面會(huì)組織成文章具體介紹一下。

        C 編譯器會(huì)接收其他操作并把其轉(zhuǎn)換為匯編語(yǔ)言輸出,匯編語(yǔ)言是機(jī)器級(jí)別的代碼表示。我們之前介紹過(guò),C 語(yǔ)言程序的執(zhí)行過(guò)程分為下面這幾步

        下面我們更多的討論都是基于匯編代碼來(lái)討論。

        我們?nèi)粘K佑|的高級(jí)語(yǔ)言,都是經(jīng)過(guò)了層層封裝的結(jié)果,所以我們平常是接觸不到匯編語(yǔ)言的,更不會(huì)用匯編語(yǔ)言來(lái)進(jìn)行編程,這就和你不知道操作系統(tǒng)的存在一樣,但其實(shí)你每個(gè)操作,甚至你雙擊一個(gè)圖標(biāo)都和操作系統(tǒng)有關(guān)系。

        高級(jí)語(yǔ)言的抽象級(jí)別很高,但是經(jīng)過(guò)了層層抽象之后,高級(jí)語(yǔ)言的執(zhí)行效率肯定沒(méi)有匯編語(yǔ)言高,也沒(méi)有匯編語(yǔ)言可靠。

        但是高級(jí)語(yǔ)言有更大的優(yōu)點(diǎn)是其編譯后能夠在不同的機(jī)器上運(yùn)行,匯編語(yǔ)言針對(duì)不同的指令集有不同的表示。并且高級(jí)語(yǔ)言學(xué)習(xí)來(lái)更加通俗易懂,降低計(jì)算機(jī)門檻,讓內(nèi)卷更加嚴(yán)重(當(dāng)然這是開個(gè)玩笑,冒犯到請(qǐng)別當(dāng)真)。

        話不多說(shuō),了解底層必須了解匯編語(yǔ)言。否則一個(gè) synchronized 底層實(shí)現(xiàn)就能夠讓你頭疼不已。而且,天天飄著也不好,遲早要落地。

        了解匯編代碼也有助于我們優(yōu)化程序代碼,分析代碼中隱含的低效率,并且這種優(yōu)化方法一旦優(yōu)化成功,將是量級(jí)的提高,而不是改改 if...else ,使用一個(gè)新特性所能比的。

        機(jī)器級(jí)代碼

        計(jì)算機(jī)系統(tǒng)使用了多種不同形式的抽象,可以通過(guò)一個(gè)簡(jiǎn)單的抽象模型來(lái)隱藏實(shí)現(xiàn)細(xì)節(jié)。對(duì)于機(jī)器級(jí)別的程序來(lái)說(shuō),有兩點(diǎn)非常重要。

        首先第一點(diǎn),定義機(jī)器級(jí)別程序的格式和行為被稱為 指令集體系結(jié)構(gòu)或指令集架構(gòu)(instruction set architecture), ISA。ISA 定義了進(jìn)程狀態(tài)、指令的格式和每一個(gè)指令對(duì)狀態(tài)的影響。大部分的指令集架構(gòu)包括 ISA 用來(lái)描述進(jìn)程的行為就好像是順序執(zhí)行的,一條指令執(zhí)行結(jié)束后,另外一條指令再開始。處理器硬件的描述要更復(fù)雜,它可以同時(shí)并行執(zhí)行許多指令,但是它采用了安全措施來(lái)確保整體行為與 ISA 規(guī)定的順序一致。

        第二點(diǎn),機(jī)器級(jí)別對(duì)內(nèi)存地址的描述就是 虛擬地址(virtual address),它提供了一個(gè)內(nèi)存模型來(lái)表示一個(gè)巨大的字節(jié)數(shù)組。

        編譯器在整個(gè)編譯的過(guò)程中起到了至關(guān)重要的作用,把 C 語(yǔ)言轉(zhuǎn)換為處理器執(zhí)行的基本指令。匯編代碼非常接近于機(jī)器代碼,只不過(guò)與二進(jìn)制機(jī)器代碼相比,匯編代碼的可讀性更強(qiáng),所以理解匯編是理解機(jī)器工作的第一步。

        一些進(jìn)程狀態(tài)對(duì)機(jī)器可見,但是 C 語(yǔ)言程序員卻看不到這些,包括

        • 程序計(jì)數(shù)器(Program counter),它存儲(chǔ)下一條指令的地址,在 x86-64 架構(gòu)中用 %rip 來(lái)表示。

        程序執(zhí)行時(shí),PC 的初始值為程序第一條指令的地址,在順序執(zhí)行程序時(shí), CPU 首先按程序計(jì)數(shù)器所指出的指令地址從內(nèi)存中取出一條指令,然后分析和執(zhí)行該指令,同時(shí)將 PC 的值加 1 并指向下一條要執(zhí)行的指令。

        比如下面一個(gè)例子。

        這是一段數(shù)值進(jìn)行相加的操作,程序啟動(dòng),在經(jīng)過(guò)編譯解析后會(huì)由操作系統(tǒng)把硬盤中的程序復(fù)制到內(nèi)存中,示例中的程序是將 123 和 456 執(zhí)行相加操作,并將結(jié)果輸出到顯示器上。由于使用機(jī)器語(yǔ)言難以描述,所以這是經(jīng)過(guò)翻譯后的結(jié)果,實(shí)際上每個(gè)指令和數(shù)據(jù)都可能分布在不同的地址上,但為了方便說(shuō)明,把組成一條指令的內(nèi)存和數(shù)據(jù)放在了一個(gè)內(nèi)存地址上。

        • 整數(shù)寄存器文件(register file)包含 16 個(gè)命名的位置,用來(lái)存儲(chǔ) 64 位的值。這些寄存器可以存儲(chǔ)地址和整型數(shù)據(jù)。有些寄存器用于跟蹤程序狀態(tài),而另一些寄存器用于保存臨時(shí)數(shù)據(jù),例如過(guò)程的參數(shù)和局部變量,以及函數(shù)要返回的值。這個(gè) 文件 是和磁盤文件無(wú)關(guān)的,它只是 CPU 內(nèi)部的一塊高速存儲(chǔ)單元。有專用的寄存器,也有通用的寄存器用來(lái)存儲(chǔ)操作數(shù)。
        • 條件碼寄存器 用來(lái)保存有關(guān)最近執(zhí)行的算術(shù)或邏輯指令的狀態(tài)信息。這些用于實(shí)現(xiàn)控件或數(shù)據(jù)流中的條件更改,例如實(shí)現(xiàn) if 和 while 語(yǔ)句所需的條件更改。我們都學(xué)過(guò)高級(jí)語(yǔ)言,高級(jí)語(yǔ)言中的條件控制流程主要分為三種:順序執(zhí)行、條件分支、循環(huán)判斷三種,順序執(zhí)行是按照地址的內(nèi)容順序的執(zhí)行指令。條件分支是根據(jù)條件執(zhí)行任意地址的指令。循環(huán)是重復(fù)執(zhí)行同一地址的指令。
          • 順序執(zhí)行的情況比較簡(jiǎn)單,每執(zhí)行一條指令程序計(jì)數(shù)器的值就是 + 1。
          • 條件和循環(huán)分支會(huì)使程序計(jì)數(shù)器的值指向任意的地址,這樣一來(lái),程序便可以返回到上一個(gè)地址來(lái)重復(fù)執(zhí)行同一個(gè)指令,或者跳轉(zhuǎn)到任意指令。

        下面以條件分支為例來(lái)說(shuō)明程序的執(zhí)行過(guò)程(循環(huán)也很相似)

        程序的開始過(guò)程和順序流程是一樣的,CPU 從 0100 處開始執(zhí)行命令,在 0100 和 0101 都是順序執(zhí)行,PC 的值順序+1,執(zhí)行到 0102 地址的指令時(shí),判斷 0106 寄存器的數(shù)值大于 0,跳轉(zhuǎn)(jump)到 0104 地址的指令,將數(shù)值輸出到顯示器中,然后結(jié)束程序,0103 的指令被跳過(guò)了,這就和我們程序中的 if() 判斷是一樣的,在不滿足條件的情況下,指令會(huì)直接跳過(guò)。所以 PC 的執(zhí)行過(guò)程也就沒(méi)有直接+1,而是下一條指令的地址。

        • 一組 向量寄存器用來(lái)存儲(chǔ)一個(gè)或者多個(gè)整數(shù)或者浮點(diǎn)數(shù)值,向量寄存器是對(duì)一維數(shù)據(jù)上進(jìn)行操作。

        機(jī)器指令只會(huì)執(zhí)行非常簡(jiǎn)單的操作,例如將存放在寄存器的兩個(gè)數(shù)進(jìn)行相加,把數(shù)據(jù)從內(nèi)存轉(zhuǎn)移到寄存器中或者是條件分支轉(zhuǎn)移到新的指令地址。編譯器必須生成此類指令的序列,以實(shí)現(xiàn)程序構(gòu)造,例如算術(shù)表達(dá)式求值,循環(huán)或過(guò)程調(diào)用和返回

        認(rèn)識(shí)匯編

        我相信各位應(yīng)該都知道匯編語(yǔ)言的出現(xiàn)背景吧,那就是二進(jìn)制表示數(shù)據(jù),太復(fù)雜太龐大了,為了解決這個(gè)問(wèn)題,出現(xiàn)了匯編語(yǔ)言,匯編語(yǔ)言和機(jī)器指令的區(qū)別就在于表示方法上,匯編使用操作數(shù)來(lái)表示,機(jī)器指令使用二進(jìn)制來(lái)表示,我之前多次提到機(jī)器碼就是匯編,你也不能說(shuō)我錯(cuò),但是不準(zhǔn)確。

        但是匯編適合二進(jìn)制代碼存在轉(zhuǎn)換關(guān)系的。

        匯編代碼需要經(jīng)過(guò) 匯編器 編譯后才產(chǎn)生二進(jìn)制代碼,這個(gè)二進(jìn)制代碼就是目標(biāo)代碼,然后由鏈接器將其連接起來(lái)運(yùn)行。

        匯編語(yǔ)言主要分為以下三類

        • 匯編指令:它是一種機(jī)器碼的助記符,它有對(duì)應(yīng)的機(jī)器碼
        • 偽指令:沒(méi)有對(duì)應(yīng)的機(jī)器碼,由編譯器執(zhí)行,計(jì)算機(jī)并不執(zhí)行
        • 其他符號(hào),比如 +、-、*、/ 等,由編譯器識(shí)別,沒(méi)有對(duì)應(yīng)的機(jī)器碼

        匯編語(yǔ)言的核心是匯編指令,而我們對(duì)匯編的探討也是基于匯編指令展開的。

        與匯編有關(guān)的硬件和概念

        CPU

        CPU 是計(jì)算機(jī)的大腦,它也是整個(gè)計(jì)算機(jī)的核心,它也是執(zhí)行匯編語(yǔ)言的硬件,CPU 的內(nèi)部包含有寄存器,而寄存器是用于存儲(chǔ)指令和數(shù)據(jù)的,匯編語(yǔ)言的本質(zhì)也就是 CPU 內(nèi)部操作數(shù)所執(zhí)行的一系列計(jì)算。

        內(nèi)存

        沒(méi)有內(nèi)存,計(jì)算機(jī)就像是一個(gè)沒(méi)有記憶的人類,只會(huì)永無(wú)休止的重復(fù)性勞動(dòng)。CPU 所需的指令和數(shù)據(jù)都由內(nèi)存來(lái)提供,CPU 指令經(jīng)由內(nèi)存提供,經(jīng)過(guò)一系列計(jì)算后再輸出到內(nèi)存。

        磁盤

        磁盤也是一種存儲(chǔ)設(shè)備,它和內(nèi)存的最大區(qū)別在于永久存儲(chǔ),程序需要在內(nèi)存裝載后才能運(yùn)行,而提供給內(nèi)存的程序都是由磁盤存儲(chǔ)的。

        總線

        一般來(lái)說(shuō),內(nèi)存內(nèi)部會(huì)劃分多個(gè)存儲(chǔ)單元,存儲(chǔ)單元用來(lái)存儲(chǔ)指令和數(shù)據(jù),就像是房子一樣,存儲(chǔ)單元就是房子的門牌號(hào)。而 CPU 與內(nèi)存之間的交互是通過(guò)地址總線來(lái)進(jìn)行的,總線從邏輯上分為三種

        • 地址線
        • 數(shù)據(jù)線
        • 控制線

        • CPU 與存儲(chǔ)器之間的讀寫主要經(jīng)過(guò)以下幾步


        讀操作步驟

        • CPU 通過(guò)地址線發(fā)出需要讀取指令的位置
        • CPU 通過(guò)控制線發(fā)出讀指令
        • 內(nèi)存把數(shù)據(jù)放在數(shù)據(jù)線上返回給 CPU

        寫操作步驟

        • CPU 通過(guò)地址線發(fā)出需要寫出指令的位置
        • CPU 通過(guò)控制線發(fā)出寫指令
        • CPU 把數(shù)據(jù)通過(guò)數(shù)據(jù)線寫入內(nèi)存

        下面我們就來(lái)具體了解一下這三類總線

        地址總線

        通過(guò)我們上面的探討,我們知道 CPU 通過(guò)地址總線來(lái)指定存儲(chǔ)位置的,地址總線上能傳送多少不同的信息,CPU 就可以對(duì)多少個(gè)存儲(chǔ)單元進(jìn)行尋址。

        上圖中 CPU 和內(nèi)存中間信息交換通過(guò)了 10 條地址總線,每一條線能夠傳遞的數(shù)據(jù)都是 0 或 1 ,所以上圖一次 CPU 和內(nèi)存?zhèn)鬟f的數(shù)據(jù)是 2 的十次方。

        所以,如果 CPU 有 N 條地址總線,那么可以說(shuō)這個(gè)地址總線的寬度是 N 。這樣 CPU 可以尋找 2 的 N 次方個(gè)內(nèi)存單元。

        數(shù)據(jù)總線

        CPU 與內(nèi)存或其他部件之間的數(shù)據(jù)傳送是由數(shù)據(jù)總線來(lái)完成的。數(shù)據(jù)總線的寬度決定了 CPU 和外界的數(shù)據(jù)傳輸速度。8 根數(shù)據(jù)總線可以一次傳送一個(gè) 8 位二進(jìn)制數(shù)據(jù)(即一個(gè)字節(jié))。16 根數(shù)據(jù)總線一次可以傳輸兩個(gè)字節(jié),32 根數(shù)據(jù)總線可以一次傳輸四個(gè)字節(jié)。。。。。。

        控制總線

        CPU 與其他部件之間的控制是通過(guò) 控制總線 來(lái)完成的。有多少根控制總線,就意味著 CPU 提供了對(duì)外部器件的多少種控制。所以,控制總線的寬度決定了 CPU 對(duì)外部部件的控制能力。

        一次內(nèi)存的讀取過(guò)程

        內(nèi)存結(jié)構(gòu)

        內(nèi)存 IC 是一個(gè)完整的結(jié)構(gòu),它內(nèi)部也有電源、地址信號(hào)、數(shù)據(jù)信號(hào)、控制信號(hào)和用于尋址的 IC 引腳來(lái)進(jìn)行數(shù)據(jù)的讀寫。下面是一個(gè)虛擬的 IC 引腳示意圖

        圖中 VCC 和 GND 表示電源,A0 - A9 是地址信號(hào)的引腳,D0 - D7 表示的是控制信號(hào)、RD 和 WR 都是好控制信號(hào),我用不同的顏色進(jìn)行了區(qū)分,將電源連接到 VCC 和 GND 后,就可以對(duì)其他引腳傳遞 0 和 1 的信號(hào),大多數(shù)情況下,+5V 表示1,0V 表示 0

        我們都知道內(nèi)存是用來(lái)存儲(chǔ)數(shù)據(jù),那么這個(gè)內(nèi)存 IC 中能存儲(chǔ)多少數(shù)據(jù)呢?D0 - D7 表示的是數(shù)據(jù)信號(hào),也就是說(shuō),一次可以輸入輸出 8 bit = 1 byte 的數(shù)據(jù)。A0 - A9 是地址信號(hào)共十個(gè),表示可以指定 00000 00000 - 11111 11111 共 2 的 10次方 = 1024個(gè)地址。每個(gè)地址都會(huì)存放 1 byte 的數(shù)據(jù),因此我們可以得出內(nèi)存 IC 的容量就是 1 KB。

        如果我們使用的是 512 MB 的內(nèi)存,這就相當(dāng)于是 512000(512 * 1000) 個(gè)內(nèi)存 IC。當(dāng)然,一臺(tái)計(jì)算機(jī)不太可能有這么多個(gè)內(nèi)存 IC ,然而,通常情況下,一個(gè)內(nèi)存 IC 會(huì)有更多的引腳,也就能存儲(chǔ)更多數(shù)據(jù)。

        內(nèi)存讀取過(guò)程

        下面是一次內(nèi)存的讀取過(guò)程。

        來(lái)詳細(xì)描述一下這個(gè)過(guò)程,假設(shè)我們要向內(nèi)存 IC 中寫入 1byte 的數(shù)據(jù)的話,它的過(guò)程是這樣的:

        • 首先給 VCC 接通 +5V 的電源,給 GND 接通 0V 的電源,使用 A0 - A9 來(lái)指定數(shù)據(jù)的存儲(chǔ)場(chǎng)所,然后再把數(shù)據(jù)的值輸入給 D0 - D7 的數(shù)據(jù)信號(hào),并把 WR(write)的值置為 1,執(zhí)行完這些操作后,即可以向內(nèi)存 IC 寫入數(shù)據(jù)
        • 讀出數(shù)據(jù)時(shí),只需要通過(guò) A0 - A9 的地址信號(hào)指定數(shù)據(jù)的存儲(chǔ)場(chǎng)所,然后再將 RD 的值置為 1 即可。
        • 圖中的 RD 和 WR 又被稱為控制信號(hào)。其中當(dāng)WR 和 RD 都為 0 時(shí),無(wú)法進(jìn)行寫入和讀取操作。

        總結(jié)

        此篇文章我們主要探討了指令集、指令集的分類,與匯編有關(guān)的硬件,總線都有哪些,分別的作用都是什么,然后我們以一次內(nèi)存讀取過(guò)程來(lái)連接一下 CPU 和內(nèi)存的交互過(guò)程。

        原創(chuàng)不易,如有幫助還請(qǐng)各位讀者四連(點(diǎn)在、在看、分享、留言),感謝各位大佬





         往期推薦 

        ??

        HTTP 2.0 ,有點(diǎn)炸 !

        從 0 到 100

        這篇 Java 基礎(chǔ),我吹不動(dòng)了

        程序員有未來(lái)嗎?

        這篇零拷貝,牛了牛了

        JVM 基礎(chǔ)面試題總結(jié)


        瀏覽 26
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 三人交性视频 | 刘亦菲一区二区三区免费看 | 国产伦子伦一级A片免费看小说 | 高清无码视频免费看 | 一级免费黄色录像 |