上一期中我們介紹了一些arm組合語言的程式設計方法,這一期我們介紹一下arm內嵌彙編器並嘗試分析一下openeuler中的一段彙編**。
c/c++編譯器中包含了內嵌彙編器,使用這些內嵌彙編器可以在c或c++**中使用大部分arm指令和thumb指令。內嵌彙編指令中,作為運算元的暫存器和常量可以是c或c++表示式,其型別包含char、short和int型。彙編器將這些量視為無符號數,也就是說如果要使用有符號數其符號位需要程式設計師自己處理。
在使用內嵌彙編指令時,一般不需要指定物理暫存器,編譯器一般會作自動分配。若在內嵌彙編指令中使用物理暫存器,那麼編譯器會在使用前後儲存和恢復這些物理暫存器中的值,從而使得這些物理暫存器表現得像被內嵌彙編指令臨時使用而不影響其他程式執行。但物理暫存器的使用也是有限制的,例如有一些暫存器如sp在做特定用途時編譯器不能恢復它的值,再如不能直接向pc暫存器中寫入值,程式的跳轉只能通過b和bl指令實現。彙編指令使用的暫存器數目不要過多,否則可能會在分配物理暫存器時造成衝突,編譯器發現衝突時會報錯。
內嵌彙編器會對一些指令進行展開操作,如一些乘法指令可能會被展開為一系列加法和移位指令。內嵌彙編器不支援記憶體分配操作,記憶體分配操作需要用c/c++語句完成。
在arm c語言中,內嵌彙編指令的一般格式如下圖所示:
而在arm c++程式中,除了上述格式,還可以使用如下格式:
這種格式不支援在字串中攜帶注釋。下圖展示了乙個使用arm c語言內嵌彙編的例子。在這個例子中,函式中變數x被彙編指令add自加一併返回,編譯器為x自動分配了物理暫存器,1前面的#表示立即數。
下面我們來嘗試具體分析一段openeuler中的彙編**。這段**在openeuler**倉庫的kernel/arch/arm64/kernel/entry.s檔案中可以找到。
上圖中這段**用於task_struct切換時暫存器的儲存與恢復,x0暫存器儲存了切換前task_struct結構體的位址,x1儲存了切換後結構體的位址。我們可以看到這段**首先設定儲存切換前暫存器的記憶體位址(x8暫存器),然後將切換前暫存器編號為x19-x29的暫存器以及lr暫存器都儲存到了以x8中位址為棧底的棧中,其中還包含了切換前sp暫存器中的棧指標。然後**找到了儲存下乙個task_struct相關狀態的棧的棧底位址(也儲存在x8中),將棧中的內容恢復到對應的暫存器中,包括lr暫存器和sp暫存器。在這段**中,load和store指令都使用的是post-indexed定址方式,也就是先使用x8暫存器中的記憶體位址,再將這個位址加上立即數16。
參考文獻
[1] 《arm體系結構程式設計(第二版)》,杜春雷著。
歐幾里得演算法 第二十六期 歐幾里得演算法
今天一同事問 輾轉相除法的數學原理是什麼呢?今天我們就一起來認識認識輾轉相除法。輾轉相除法又稱歐幾里得演算法,是用於求兩個大數的最大公因數的一種方法。這一方法其實類似於中國的 更相減損術 在 九章算術 有言 可半者半之,不可半者,副置分母 子之數,以少減多,更相減損,求其等也。以等數約之。具體做法是...
暑假第二十六測
今天又考的奇差 題解 第一題 這麼簡單一道題我想了好久,智商實在是下線了 includeusing namespace std intmain view code 第二題 我們發現e的長度很小,我們可以在上面做文章,其實每個位置對應的 strlen e 都是一樣的 我們用樹狀陣列維護rt pos l...
演算法 日更 第二十六期 非常基礎的數論
一說到基礎數論,那麼我們就從整除那套理論開始談起。整除 定義 如果a能把b整除,也就是沒有餘數,則我們稱a整除b,亦稱b被a整除,記為a b。其中的 稱為整除符號。性質 自反性 顯然,對於任意正整數n,有n n 傳遞性 若有a b,b c,則有a c 反對稱性 若a b,b a,則有a b 其中性質...