C 表示式中的彙編指令

2021-09-29 14:52:43 字數 4672 閱讀 3862

asm 為 gcc 中的關鍵字,asm 表示式為在 c**中巢狀彙編指令,該表示式只是單純的替換出彙編**,並不對彙編**的含義進行解析。

asm 表示式有兩種形式,第二種asm-qualifiers包含了goto語句。

第一種形式為常見的用法,assemblertemplate 和 outputoperands 必須存在, 其中 clobbers 存在需要 inputoperands 也出現。

asm asm-qualifiers ( assemblertemplate 

: outputoperands

[ : inputoperands

[ : clobbers ] ])

asm asm-qualifiers ( assemblertemplate

: : inputoperands

: clobbers

: gotolabels)

qualifiers 的型別

引數彙編指令由乙個字串給出,多條彙編指令結合在一起使用的時候,中間以\r\t隔開,如

asm("inc %0\n\tinc %0" : "=r"(res) : "0"(res));

# 11 "asm.c" 1

inc %rax

inc %rax

# 0 "" 2

需要轉義的字元:%,=,,|

故在att彙編中,對暫存器進行操作的需要雙 %%, 如inc %%rax.

運算元之間用逗號分隔。 每個運算元具有以下格式:

[ [asmsymbolicname] ] constraint (cvariablename)
第乙個引數為增加可讀性使用的,現在我們有**如下

int64_t res;

int64_t num = 1;

asm("movq %[num], %[res]" : [res] "=r"(res) : [num] "m"(num));

asm("movq %1, %0" : "=r"(res) : "m"(num));

asm("movq %1, %0" : "=m"(res) : "m"(num));

asm("movq %1, %0" : "=r"(res) : "r"(num));

// 對應的彙編**, 只保留asm表示式中的**

# 13 "asm.c" 1

movq -16(%rbp), %rax // asm-1

# 0 "" 2

# 15 "asm.c" 1

movq -16(%rbp), %rax // asm-2

# 0 "" 2

# 17 "asm.c" 1

movq -16(%rbp), -8(%rbp) // asm-3

# 0 "" 2

# 19 "asm.c" 1

movq %rax, %rax // asm-4

# 0 "" 2

使用名稱替換和數字替換效果一樣,見 asm-1 和 asm-2

約束的用法,這裡使用比較簡單通用的的兩種情況,r為通過暫存器定址操作,m通過記憶體定址操作,所以看到當約束了r就對應暫存器的操作。

結果儲存在 res 也就是 cvariablename 中

輸入運算元使c變數和表示式中的值可用於彙編**。

[ [asmsymbolicname] ] constraint (cexpression)
int64_t res = 3;

int64_t num = 1;

asm("addq %1, %0" : "=g"(res) : "0"(num));

// 輸入輸出位置相同

movq $3, -8(%rbp)

movq $1, -16(%rbp)

movq -16(%rbp), %rax

# 32 "asm.c" 1

addq %rax, %rax

# 0 "" 2

破壞列表,主要用於指示編譯器生成的彙編指令。

從asm表示式中看到輸出運算元中列出條目的更改編譯器是可以確定的,但內聯彙編**可能不僅對輸出進行了修改。 例如,計算可能需要其他暫存器,或者處理器可能會由於特定匯程式設計序指令而破壞暫存器的值。 為了將這些更改通知編譯器,在clobber列表中列出這些會產生***的條目。 破壞列表條目可以是暫存器名稱,也可以是特殊的破壞列表項(在下面列出)。 每個內容列表條目都是乙個字串常量,用雙引號引起來並用逗號分隔。

編譯器為了破壞列表項的值受到破壞,當這些條目是暫存器時,不對其進行使用;為特殊引數時,重新重新整理得到最新的值。

約束名說明

whitespace

空白字元被忽略

m允許使用記憶體運算元,以及機器通常支援的任何型別的位址

o允許使用記憶體運算元,但前提是位址是可偏移的

v允許使用記憶體運算元,不可偏移的記憶體位址,與 "o'互斥

r允許在通用暫存器中使用的暫存器運算元,其中可以指定暫存器,如 a(%rax), b(%rbx)

i允許使用立即整數運算元

n允許使用具有已知數值的立即整數運算元, 『i』, 『j』, 『k』, … 『p』 更應該使用 n

f允許使用浮點立即數

g允許使用任何暫存器,記憶體或立即數整數運算元,但非通用暫存器除外

x允許任何運算元, 『0』, 『1』, 『2』, … 『9』

p允許使用有效記憶體位址的運算元

識別符號說明

=表示此運算元是由該指令寫入的:先前的值將被丟棄並由新資料替換

+表示該運算元由指令讀取和寫入

&表示(在特定替代方法中)此運算元是早期指令運算元,它是在使用輸入運算元完成指令之前寫入的,故輸入運算元部分不能分配與輸出運算元相同的暫存器

%表示該運算元與後續運算元的可交換指令

x86 的記憶體屏障指令。

// 避免編譯器的優化,宣告此處記憶體可能發生破壞

#define barrier() asm volatile("" ::: "memory")

// 在32位的cpu下,lock 指令為鎖匯流排,加上一條記憶體操作指令就達到了記憶體屏障的作用,64位的cpu已經有新增的 *fence 指令可以使用

// mb() 執行乙個記憶體屏障作用的指令,為指定cpu操作;破壞列表宣告 cc memory 指示避免編譯器進行優化

#ifdef config_x86_32

#define mb() asm volatile(alternative("lock; addl $0,-4(%%esp)", "mfence", \

x86_feature_xmm2) ::: "memory", "cc")

#define rmb() asm volatile(alternative("lock; addl $0,-4(%%esp)", "lfence", \

x86_feature_xmm2) ::: "memory", "cc")

#define wmb() asm volatile(alternative("lock; addl $0,-4(%%esp)", "sfence", \

x86_feature_xmm2) ::: "memory", "cc")

#else

#define mb() asm volatile("mfence":::"memory")

#define rmb() asm volatile("lfence":::"memory")

#define wmb() asm volatile("sfence" ::: "memory")

#endif

x86 下獲取 current 的值

declare_per_cpu(struct task_struct *, current_task);

#define this_cpu_read_stable(var) percpu_stable_op("mov", var)

static __always_inline struct task_struct *get_current(void)

#define percpu_stable_op(op, var) \

( \

pfo_ret__; \

})

current_task 為乙個 struct task_struct 型別的指標,追蹤巨集呼叫,在x86-64 下命中了 case 8: 的彙編**, 展開的**為

asm("mov" "q ""%%""gs" ":" "%" "p1"",%0" : "=r" (pfo_ret__) : "p" (&(current_task)));

// 變換一下為

asm("movq %%gs:%p1, %0" : "=r"(pfo_ret__) : "p"(&(current_task)));

這行**的含義為將 約束輸入部分必須為有效的位址(p約束), 將cpu id(通過段暫存器gs和偏移通過gdt得到,這裡後文分析了)通過暫存器(r約束)賦值給 pfo_ret__.

C 中的表示式

表示式是在運算元和運算子的基礎上構造而成。表示式的運算子指明了向運算元應用的運算。運算子的示例包括 和new。運算元的示例包括文字 字段 區域性變數和表示式。如果表示式包含多個運算子,那麼是運算子的優先順序決定了各個運算子的計算順序。例如,表示式 x y z相當於計算x y z 因為 運算子的優先順...

C 中的表示式

基礎概念 組合運算子和運算物件 優先順序與結合律 運算物件轉換 型別轉換 運算子過載 之類 左值和右值 算術運算子 一元負號對布林值的運算不起作用 邏輯和關係運算子 邏輯與和邏輯或運算子 邏輯非運算子 關係運算子 賦值運算子 賦值運算滿足右結合律 賦值運算優先順序較低 注意 切勿混淆相等運算子和相等...

C 中的Lambda表示式

c 11開始支援lambda表示式 原文 一段簡單的code 我也不是文藝的人,對於lambda的歷史,以及lambda與c 的那段淵源,我也不是很熟悉,技術人,講究拿 說事。複製 如下 include using namespace std int main return 0 當我第一次看到這段 ...