簡介

上一篇文章ARM64彙編基礎中介紹了彙編在iOS開發中的應用以及ARM彙編基礎知識,本文將介紹在C或Objective-C構成的工程中如何嵌入彙編代碼。

注意

在調試ARM彙編時,Xcode的Build對象必須爲真機,如果對象爲模擬器則是x86彙編。

內聯彙編

彙編與C間接通信

在函數中可以直接插入彙編代碼來影響函數的運行邏輯,使用的語法爲編譯指令 __asm__ ,注意插入彙編有可能會被編譯器忽略,因此需要加入 __volatile__ 修飾符保證彙編代碼有效。

下面給出一個簡單的例子,假如我們要實現一個將數值翻一倍的簡單函數。

下面我們採用內聯彙編的形式實現將num的值翻倍的操作。

lsl爲左移指令,x0中存儲的爲入參num的值,由於該函數未發起對其他函數的調用,所以不必保護現場,只有一個int類型入參,需要4byte,由於ARM64下sp尋址時必須按照16byte對齊,所以該函數的調用棧大小爲16byte,所以num變量會存儲在高地址的 sp+12~sp+16 區域,因此在函數返回時會從 sp+12 處取出,我們通過 str 指令將翻倍之後的數值存儲在對應區域即可。

彙編與C直接通信

在上面的例子中,爲了將計算後的值作爲返回值,我們採用了靜態計算變量地址的方式,這裏我們換用另一種方式,將彙編的計算結果直接存儲在C變量中,以下面的函數爲例,將輸入的值翻倍數次。

這裏的x0中存儲的是num,x1存儲的是times,可見從C到彙編的通信是非常自然的;可見彙編的後三行使用了三個冒號,這是內聯彙編與C通信的語法,其中第一行爲輸出指令,第二行爲輸入指令,第三行爲更改的變量列表。對於彙編到C的賦值,只需要在第一行聲明 "=r"(變量標識符) ,在彙編執行完畢後會將%0寄存器(實際上是使用x8, x9寄存器來模擬的,常與臨時值寄存器x12配合使用,使用%0可能會污染x8和x9)的值保存在變量標識符內,如果有多個變量需要賦值,可以使用%1, %2以此類推,有關內聯彙編輸入輸出的基本語法可以看這篇文章 https://www.cnblogs.com/pengdonglin137/p/3328141.html。

使用純彙編實現函數

注意: 由於C++有特殊的name mangling規則,該方法僅適用於C

除了嵌入式內聯彙編外,我們還可以使用匯編文件來直接定義函數,在Xcode中新建文件時,選擇Other組中的彙編文件,即可創建一個彙編文件並將其添加到工程的編譯單元中。

我們採用純彙編來實現一下上面的 double_num_times 函數,在彙編文件中寫入如下代碼。

第一行爲段的固定寫法,段的定義將在後續的教程中詳細介紹,第四行將符號引出到全局,從第五行開始定義了符號 _double_num_times_asm 的功能邏輯,這裏的下劃線是根據C語言的name mangling規則命名的,符號將被映射爲C語言的全局函數符號 double_num_times_asm ,這裏由於 _double_num_times_asm 沒有調用到其他符號,因此不需要處理x29和x30的暫存。

通過上述的彙編代碼,我們已經完成了函數定義,只需要通過一個頭文件聲明一下函數即可。

引入頭文件後,即可正常使用函數。

總結

在Xcode中嵌入彙編代碼主要依賴了C語言支持通過 __asm__ 引入彙編代碼的功能,而直接使用匯編實現函數邏輯則是相當於手動幫助編譯器完成了生成彙編代碼的過程,通過嵌入彙編可以從更大程度上把握程序的運行。

如果感覺這篇文章不錯可以點擊在看:point_down:

相關文章