1. 程式人生 > >GCC 內聯彙編

GCC 內聯彙編

[TOC] GNU C 允許在 C 程式碼中嵌入彙編程式碼,這種特性被稱為內聯彙編。使用內聯彙編可以同時發揮 C 和彙編的強大能力。 本文介紹 GCC 的內聯彙編拓展,Clang 編譯器相容大部分 GCC 語言拓展,因此 GNU C 的內聯彙編特性大部分在 Clang 中工作正常。 本文實驗環境如下: ``` Linux Friday 5.8.17-300.fc33.x86_64 #1 SMP Thu Oct 29 15:55:40 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux gcc (GCC) 10.2.1 20201016 (Red Hat 10.2.1-6) ``` 使用 64 位 AT&T 風格 x86 彙編,為了和編譯器自動生成的註釋區分開,我新增的註釋使用`##`風格。 # 基本內聯彙編 基本內聯彙編是 GCC 對內聯彙編最簡陋的支援,它實際上已經沒有任何使用價值了,介紹它只是為了說明使用內聯彙編的基本原理和問題。 基本內聯彙編的語法如下: ```c asm asm_qualifiers ( AssembleInstructions ) ``` `asm_qulifiers`包括以下兩個修飾符: - volatile: 指示編譯器不要對 asm 程式碼段進行優化 - inline: 指示編譯器儘可能小的假設 asm 指令的大小 這兩個修飾符的意義先不用深究,本文會逐步介紹它們的作用。 `asm`不是 ISO C 中的關鍵字,如果我們開啟了 -std=c99 等啟用 ISO C 的編譯選項,程式碼將無法成功編譯。然而,內聯彙編對於許多 ISO C 程式是必須的,GCC 通過 \__asm__ 給程式設計師開了個後門。使用 \_\_asm__ 替代 asm 可以讓程式作為 ISO C 程式成功編譯。volatile 和 inline 也有加 \_\_ 的版本。 `AssembleInstructions`是我們手寫的彙編指令。基本內聯彙編的例子如下: ```c __asm__ __valatile__( "movq %rax, %rdi \n\t" "movq %rbx, %rsi \n\t" ); ``` 編譯器不解析 asm 塊中的指令,直接把它們插入到生成的彙編程式碼中,剩下的任務有彙編器完成。這個過程有些類似於巨集。為了避免我們手寫的彙編程式碼擠在一起,導致指令解析錯誤,通常在每一條指令後面都加上`\n\t`獲得合適的格式。 編譯器不解析 asm 塊中的指令的一個推論是:GCC 對我們插入的指令毫不知情。這相當於我們人為地干涉了 GCC 自動的程式碼生成,如果我們處理不當,很可能導致最終生成的程式碼是錯誤的。考慮以下程式碼段: ```c #