上一篇文章 iOS彙編入門教程 中介紹了彙編在iOS開發中的應用以及ARM彙編基礎知識,本文將介紹在C或Objective-C構成的工程中如何嵌入彙編代碼。html
在調試ARM彙編時,Xcode的Build對象必須爲真機,若是對象爲模擬器則是x86彙編。ios
在函數中能夠直接插入彙編代碼來影響函數的運行邏輯,使用的語法爲編譯指令__asm__
,注意插入彙編有可能會被編譯器忽略,所以須要加入__volatile__
修飾符保證彙編代碼有效。markdown
下面給出一個簡單的例子,假如咱們要實現一個將數值翻一倍的簡單函數。函數
int double_num(int num) { return num * 2; } 複製代碼
下面咱們採用內聯彙編的形式實現將num的值翻倍的操做。oop
int double_num(int num) { __asm__ __volatile__( "lsl x0, x0, 1\n" "str x0, [sp, #12]\n" ); return num; } 複製代碼
lsl爲左移指令,x0中存儲的爲入參num的值,因爲該函數未發起對其餘函數的調用,因此沒必要保護現場,只有一個int類型入參,須要4byte,因爲ARM64下sp尋址時必須按照16byte對齊,因此該函數的調用棧大小爲16byte,因此num變量會存儲在高地址的sp+12~sp+16
區域,所以在函數返回時會從sp+12
處取出,咱們經過str
指令將翻倍以後的數值存儲在對應區域便可。post
在上面的例子中,爲了將計算後的值做爲返回值,咱們採用了靜態計算變量地址的方式,這裏咱們換用另外一種方式,將彙編的計算結果直接存儲在C變量中,如下面的函數爲例,將輸入的值翻倍數次。ui
int double_num_times(int num, int times) { int ret; __asm__ __volatile__( "lsl x0, x0, x1\n" "mov %0, x0" : "=r" (ret) : : ); return ret; } 複製代碼
這裏的x0中存儲的是num,x1存儲的是times,可見從C到彙編的通訊是很是天然的;可見彙編的後三行使用了三個冒號,這是內聯彙編與C通訊的語法,其中第一行爲輸出指令,第二行爲輸入指令,第三行爲更改的變量列表。對於彙編到C的賦值,只須要在第一行聲明"=r" (變量標識符)
,在彙編執行完畢後會將%0寄存器(其實是使用x8, x9寄存器來模擬的,常與臨時值寄存器x12配合使用,使用%0可能會污染x8和x9)的值保存在變量標識符內,若是有多個變量須要賦值,可使用%1, %2以此類推,有關內聯彙編輸入輸出的基本語法能夠看這篇文章。spa
注意: 因爲C++有特殊的name mangling規則,該方法僅適用於C調試
除了嵌入式內聯彙編外,咱們還可使用匯編文件來直接定義函數,在Xcode中新建文件時,選擇Other組中的彙編文件,便可建立一個彙編文件並將其添加到工程的編譯單元中。 code
咱們採用純彙編來實現一下上面的double_num_times
函數,在彙編文件中寫入以下代碼。
; example.s .section __TEXT,__text,regular,pure_instructions .ios_version_min 11, 2 .p2align 2 .global _double_num_times_asm _double_num_times_asm: lsl x0, x0, x1 ret 複製代碼
第一行爲段的固定寫法,段的定義將在後續的教程中詳細介紹,第四行將符號引出到全局,從第五行開始定義了符號_double_num_times_asm
的功能邏輯,這裏的下劃線是根據C語言的name mangling規則命名的,符號將被映射爲C語言的全局函數符號double_num_times_asm
,這裏因爲_double_num_times_asm
沒有調用到其餘符號,所以不須要處理x29和x30的暫存。
經過上述的彙編代碼,咱們已經完成了函數定義,只須要經過一個頭文件聲明一下函數便可。
// example.h int double_num_times_asm(int num, int times); 複製代碼
引入頭文件後,便可正常使用函數。
在Xcode中嵌入彙編代碼主要依賴了C語言支持經過__asm__
引入彙編代碼的功能,而直接使用匯編實現函數邏輯則是至關於手動幫助編譯器完成了生成彙編代碼的過程,經過嵌入彙編能夠從更大程度上把握程序的運行。