日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

内联汇编 - 从头开始

發(fā)布時(shí)間:2025/7/25 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内联汇编 - 从头开始 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

FROM: http://www.ibm.com/developerworks/cn/aix/library/au-inline_assembly/

對(duì)于 C/C++ 程序員來(lái)說(shuō),內(nèi)聯(lián)匯編并不是一個(gè)新特性,它可以幫助我們充分利用計(jì)算能力。然而,大多數(shù)程序員很少有機(jī)會(huì)實(shí)際使用該特性。事實(shí)上,內(nèi)聯(lián)匯編只為特定的要求提供服務(wù),在涉及先進(jìn)的高層編程語(yǔ)言時(shí)尤其如此。

本文介紹了 IBM Power 處理器架構(gòu)的兩個(gè)場(chǎng)景。使用本文提供的示例,我們可以發(fā)現(xiàn)在什么地方應(yīng)用了內(nèi)聯(lián)匯編。

場(chǎng)景 1:更好的庫(kù)

C/C++ 編程語(yǔ)言支持邏輯運(yùn)算。在本例中,用戶使用 作為基本單位。用戶編寫(xiě)了一個(gè)算法來(lái)計(jì)算一個(gè) 32 位變量所占用的位數(shù)。

代碼 A: 計(jì)算被占用的位數(shù)

01 inline int bit_taken(int data) 02 { 03 int taken = 0; 04 while (data) { 05 data = (data >> 1); 06 taken++; 07 } 08 return taken; 09 }

此代碼顯示了如何配合使用循環(huán)和移位運(yùn)算。如果用戶采用最高優(yōu)化級(jí)別(-O3 適用于 gcc,-O5 適用于 xlc)編譯代碼,那么用戶可能會(huì)發(fā)現(xiàn)某些優(yōu)化(如展開(kāi),常量數(shù)據(jù)傳播,等等)都是自動(dòng)完成的,它們可以生成世界上速度最快的代碼。但算法的基本思路并沒(méi)有發(fā)生改變。

清單 A:cntlzw 的描述

cntlzw(CountLeading Zeros Word) 指令

目的

將來(lái)自源通用寄存器的前導(dǎo)零的數(shù)量放進(jìn)一個(gè)通用寄存器。

cntlzw 指令能夠獲得前導(dǎo)零的數(shù)量。我們以數(shù)字 15 為例,其二進(jìn)制表示為 0000, 0000, 0000, 0000, 0000, 0000, 0000, 1111,cntlzw 會(huì)告訴大家,總共有 28 個(gè)前導(dǎo)零。經(jīng)過(guò)重新考慮后,用戶決定簡(jiǎn)化其算法,如代碼 B 所示。

代碼 B:計(jì)算內(nèi)聯(lián)匯編所占用的位數(shù)

01 #ifdef __ARCH_PPC__ 02 inline int bit_taken(int data) 03 { 04 int taken; 05 asm("cntlzw %0, %1\n\t" 06 : "=b" (taken) 07 : "b" (data) 08 ); 09 return sizeof(data) * 8 – taken; 10 } 11 #else ... ... 21 #endif

名稱(chēng)為 __ARCH_PPC__ 的宏只包裝適用于 PowerPC 架構(gòu)的新代碼。與代碼 A 相比,新的代碼已經(jīng)刪除了所有循環(huán)或移位。然后,使用者可能會(huì)高興地看到 bit_taken 的性能有所提高。它在 PowerPC 上運(yùn)行得更快。而且,應(yīng)用程序綁定的 bit_taken 甚至表現(xiàn)得更好。

這個(gè)故事并不僅說(shuō)明用戶可以通過(guò)豐富的指令改進(jìn)他的算法,而且還說(shuō)明了內(nèi)聯(lián)匯編是提高性能的最佳助手。通過(guò)將匯編代碼嵌入到 C/C++,可以最大限度地減少用戶修改代碼的工作。

場(chǎng)景 2:原子比較和交換 (CAS)

近日,隨著整個(gè)計(jì)算機(jī)行業(yè)將重點(diǎn)轉(zhuǎn)移到多處理、多線程,不可避免地帶來(lái)了更多的元素(如編程中的同步)。要在多線程環(huán)境中構(gòu)成同步原語(yǔ)(如信號(hào)量和互斥),我們經(jīng)常會(huì)提到被稱(chēng)為比較和交換 (CAS) 的原子操作。清單 B 顯示了 CAS 的偽代碼。

清單 B:CAS 的偽代碼

清單 1.
compare_and_swap (*p, oldval, newval):if (*p == oldval)*p = newval;success;elsefail;

在清單 B 中,首先比較內(nèi)存位置 p (*p) 的內(nèi)容與已知值 oldval(這應(yīng)該是當(dāng)前線程中 *p 的值)。只有當(dāng)它們是相同值時(shí),才會(huì)將 newval 寫(xiě)入 *p。若其他線程之前已經(jīng)修改了內(nèi)存位置,那么比較操作會(huì)失敗。

為了準(zhǔn)確起見(jiàn),CAS 應(yīng)該是原子的。原子性超越了 C/C++ 的處理能力,但可以通過(guò)使用一小段內(nèi)聯(lián)匯編代碼而得到保證。代碼 C 顯示了面向 PowerPC 架構(gòu)實(shí)現(xiàn)的一個(gè)簡(jiǎn)單的 CAS。

代碼 C:在 PowerPC 上的簡(jiǎn)單 CAS 實(shí)現(xiàn)

01 void inline compare_and_swap (volatile int * p, int oldval, int newval) 02 { 03 int fail; 04 __asm__ __volatile__ ( 05 "0: lwarx %0, 0, %1\n\t" 06 " xor. %0, %3, %0\n\t" 07 " bne 1f\n\t" 08 " stwcx. %2, 0, %1\n\t" 09 " bne- 0b\n\t" 10 " isync\n\t" 11 "1: " 12 : "=&r"(fail) 13 : "r"(p), "r"(newval), "r"(oldval) 14 : "cr0"); 15 }

此代碼片段實(shí)現(xiàn)了清單 B 中的偽代碼,但目前它對(duì)于我們來(lái)說(shuō)似乎過(guò)于復(fù)雜。我們將在介紹完基本的語(yǔ)法后再回頭探討它。

但是,歸納我們所述的內(nèi)容,在兩個(gè)條件下通常需要內(nèi)聯(lián)匯編:

  • 代碼優(yōu)化

    若性能要求是至關(guān)重要的,那么內(nèi)聯(lián)匯編可能會(huì)有所幫助。正如我們從場(chǎng)景 1 中可以看到的,調(diào)優(yōu)編譯器選項(xiàng)不會(huì)永遠(yuǎn)都是最佳選擇。一個(gè)便利的內(nèi)聯(lián)匯編代碼片段可以讓用戶大幅提高程序的性能。

  • 硬件操作/OS 服務(wù)

    C/C++ 在場(chǎng)景 2 中的能力是有限的。編譯器總是需要一些時(shí)間來(lái)標(biāo)準(zhǔn)化和實(shí)現(xiàn)最新的特性。因此,為了使用最新的硬件指令、OS 服務(wù)等,我們經(jīng)常求助于內(nèi)聯(lián)匯編。大部分時(shí)間,它都是最佳選擇。

使用內(nèi)聯(lián)匯編可能還有其他原因。但是總的來(lái)說(shuō),內(nèi)聯(lián)匯編在功能和性能方面都可以作為 C/C++ 的一種補(bǔ)充。

內(nèi)聯(lián)匯編的使用

內(nèi)聯(lián)匯編的語(yǔ)法看上去與 C/C++ 完全不同。一個(gè)合理的解釋是,內(nèi)聯(lián)匯編并不是從 C/C++ 程序員的角度進(jìn)行設(shè)計(jì)的,而是從一個(gè)編譯者/匯編者的角度進(jìn)行設(shè)計(jì)的。內(nèi)聯(lián)匯編的一般語(yǔ)句構(gòu)成如清單 C 所示。

清單 C:內(nèi)聯(lián)匯編代碼塊的組成

__asm__ __volatile__(assembly template: output operand list : input operand list: clobber list);

如清單 C 所示,內(nèi)聯(lián)匯編在邏輯上總是由四部分組成:

1. 關(guān)鍵字 asm()__asm__()。修飾符 volatile__volatile__:關(guān)鍵字 asm__asm__ 用于說(shuō)明隨后的字符串是內(nèi)聯(lián)匯編代碼塊。volatile__volatile__ 是可選的,可以將它們添加到 asm 后面,禁止某些編譯器的優(yōu)化。其實(shí),asm__asm__ 幾乎是相同的,惟一的區(qū)別是,當(dāng)預(yù)處理程序宏中使用內(nèi)聯(lián)匯編時(shí),asm 在編譯過(guò)程中可能會(huì)引發(fā)警告。volatile__volatile__ 也是如此。

2. 匯編模板:
匯編模板是括號(hào)內(nèi)的第一個(gè)部分。它包含匯編指令行,這些指令行都包括在雙引號(hào) ("") 中,以行分隔符(\n\t 或 \n)結(jié)束。內(nèi)聯(lián)匯編代碼的語(yǔ)法是相同的,但比一般的匯編代碼簡(jiǎn)單得多。這其中有許多原因。例如,它不需要在匯編模板中定義數(shù)據(jù),因?yàn)樗鼞?yīng)該始終從 C/C++ 變量引用。而且,很少有必要在匯編模板中(為可執(zhí)行文件)創(chuàng)建一個(gè)分段。一般情況下,除了匯編指令,只允許使用一些本地標(biāo)簽。(我們稍后會(huì)討論它們)。

代碼 D:內(nèi)聯(lián)匯編的匯編模板

__asm__ __volatile__ ("lwarx %0, 0, %1 \n\t" : "=&r"(ret) : "r"(p));

代碼 D 顯示了匯編模板的一個(gè)示例。

  • 匯編指令由操作碼 (lwarx) 和操作數(shù) (%0, 0, %1) 組成。
  • 如果一個(gè)指令的操作數(shù)是寄存器/立即類(lèi)型的操作數(shù),那么可以引用它作為一個(gè)帶有百分比前綴編號(hào)的寄存器。 (%0, %1,...)
  • 寄存器的編號(hào)引用了一個(gè)變量,按它在輸入/輸出列表中所代表的順序排列。在代號(hào) D 的示例中,ret 是輸入/輸出列表中第一個(gè)被引用的變量。因此,%0 是寄存器引用。同樣地,寄存器 %1 引用變量 p
  • 在內(nèi)聯(lián)匯編中,只有一些本地標(biāo)簽是合法的。您可能會(huì)在代碼 C 中看到標(biāo)簽,如 01。它們是指令 bne- 0b\n\tbne 1f\n\t 的分支目標(biāo)。(標(biāo)簽的 f 后綴意味著在分支指令后面的標(biāo)簽,而 b 表示前一個(gè)標(biāo)簽)
  • 3. 輸入/輸出操作數(shù)列表
    輸入/輸出列表以冒號(hào) (:) 開(kāi)始。它們的條目用逗號(hào) (,) 隔開(kāi)。該列表在匯編模板中指定變量及其約束。以代碼 D 為例,lwarx 設(shè)置有效地址,即寄存器值 %1 加上一個(gè)立即值 0。它從有效地址讀取一個(gè)單詞并存儲(chǔ)到寄存器 %0。在這里,%0 是一個(gè)輸出操作數(shù),它存儲(chǔ)結(jié)果并被寫(xiě)入列表。而 %1 是一個(gè)輸入。這樣,%0 所引用的 ret 就會(huì)放入輸出列表,而 %1 所引用的 p 則會(huì)放入輸入列表。
    輸入/輸出操作數(shù)列表中列出的每個(gè)變量:

    • 必須有一個(gè)約束。例如,=&r (ret) 的約束是 r,這意味著可能將 ret 分配給任何通用寄存器。
    • 可以有一個(gè)可選的約束修飾符。例如,=&r (ret) 的修飾符是 = &= 表示該變量是只寫(xiě)的。& 表示這個(gè)變量不能與任何輸入操作數(shù)共享相同的寄存器。(早期的亂碼表示在指令使用完輸入操作數(shù)之前,已經(jīng)修改了操作數(shù)。因此,它不能與輸入操作數(shù)共享寄存器。有關(guān)的詳細(xì)信息,請(qǐng)參閱 A guide to inline assembly for C and C++

    各平臺(tái)之間的約束是不同的。通常,產(chǎn)品文檔會(huì)提供更多的實(shí)際詳細(xì)信息。

    4. 破壞列表(Clobber list)
    亂碼列表通知編譯器,有些寄存器或內(nèi)存已因內(nèi)聯(lián)匯編塊造成亂碼。亂碼列表看起來(lái)類(lèi)似于輸入/輸出列表(用冒號(hào)開(kāi)始,并以逗號(hào)分隔)。但只用寄存器名稱(chēng)(如 r1f15)或 內(nèi)存 充當(dāng)其條目。

    在代碼 C 的示例中,內(nèi)聯(lián)匯編代碼隱式地破壞了條件寄存器字段。因此,cr0 寄存器字段被放入破壞列表。如果用戶認(rèn)為代碼更換到了一個(gè)不確定的內(nèi)存空間,那么內(nèi)存也會(huì)出現(xiàn)在列表中。我們?cè)诤竺娴恼鹿?jié)將再次討論破壞列表。

    事實(shí)上,并不是所有在清單 C 中顯示的組件都是必需的。一個(gè)關(guān)鍵字和一個(gè)匯編模板就足以構(gòu)成一個(gè)基本的內(nèi)聯(lián)匯編。其他所有部分都是可選的。

    現(xiàn)在,我們回到代碼 C,進(jìn)一步解釋其指令。

    lwarx %0, 0, %1
    該指令在有效地址 0 + %1 上將內(nèi)存讀取到寄存器 %0(實(shí)際上是 *p)。此外,該指令根據(jù)指令 stwcx 預(yù)約了以后的驗(yàn)證。

    xor. %0, %3, %0
    bne 1f

    該指令會(huì)比較我們剛加載到 %0 的值和 oldval (%3)。當(dāng)它們不相等時(shí),則會(huì)分支跳轉(zhuǎn)到標(biāo)簽 1,這意味著 CAS 運(yùn)算失敗。

    stwcx. %2, 0, %1
    bne- 0b
    stwcx.
    檢查 lwarx 的預(yù)約。如果檢測(cè)成功,它會(huì)將 %2 (newval) 的內(nèi)容寫(xiě)入 0 + %1(p) 的有效地址。如果寫(xiě)入失敗,則會(huì)分支跳轉(zhuǎn)到標(biāo)簽 0,以便進(jìn)行重試。

    isync
    該指令禁止運(yùn)行 iSync 之后的指令,直到 iSync 前的指令已完成。

    表 A 列出了該示例的操作數(shù)列表中的所有條目,以及它們對(duì)應(yīng)于代碼 B 的寄存器編號(hào)。

    表 A:約束、修飾符和代碼 C 的寄存器引用

    條目約束(和修飾符)引用的變量寄存器
    "=&r"(fail)=&r: writable, early clobber, general registerfail%0
    "r"(p)R: general registerp%1
    "r"(newval)R: general registernewval%2
    "r"(oldval)R: general registeroldval%3

    我們可以從代碼中看到,在寫(xiě)回指令 stwcx. 后按照重試步驟進(jìn)行操作。如果其他線程已經(jīng)更新了地址 p 保持,那么重試會(huì)發(fā)現(xiàn) *poldval 是不同的。因此,請(qǐng)控制分支跳轉(zhuǎn)到標(biāo)簽 1 ,也就是說(shuō)控制 CAS 失敗。我們可以通過(guò)比較變量 fail 和 0 來(lái)對(duì)此進(jìn)行判斷。

    lwarxstwcx 在 PowerPC 架構(gòu)中是非常特殊的指令。它們對(duì)于組成原子原語(yǔ)至關(guān)重要。如果您有興趣,可以從 Power ISA 找到有關(guān)的更多信息。[1] 對(duì)于分枝設(shè)施,文獻(xiàn) [2] 提供了最好的解釋。

    常見(jiàn)錯(cuò)誤

    對(duì)于可能會(huì)犯錯(cuò)誤的初學(xué)者來(lái)說(shuō),有一些可供他們始終查看的指南。

    • 不要忘記行分隔符 (\n\t)
    • 不要忘了行的雙引號(hào) ("")
    • 不要混淆 (){}

    我們還遇到過(guò)一些有趣的錯(cuò)誤:

  • 在內(nèi)聯(lián)匯編模板內(nèi)使用預(yù)處理程序宏。

    代碼 E:在內(nèi)聯(lián)匯編模板內(nèi)的宏。

    01 // This is the intention: 02 __asm__ __volatile__( 03 "stswi %0, %1, 4\n\t" 04 :: "b" (t), "b" (b) 05 ); … 01 // Macro, does not work: 02 #define F 4 03 __asm__ __volatile__( 04 "stswi %0, %1, F\n\t" 05 :: "b" (t), "b" (b) 06 );

    出于某種原因,用戶可能想將某個(gè) C/C++ 宏應(yīng)用于內(nèi)聯(lián)匯編模板。具體而言,在上面的示例中,用戶試圖替換一個(gè)立即值。然而,編譯器拒絕執(zhí)行該代碼。事實(shí)上,用戶不應(yīng)該考慮在匯編模板中應(yīng)用任何 C/C++ 預(yù)處理器操作。用戶將 C/C++ 傳入內(nèi)聯(lián)匯編的惟一接口是使用輸入/輸出列表。 代碼 F 顯示了一種可以實(shí)現(xiàn)用戶目標(biāo)的方法。

    代碼 F:被引用為立即值的宏

    01 #define F 4 02 __asm__ __volatile__( 03 "stswi %0, %1, %2\n\t" 04 : : "b" (t), "b" (b), "i"(F) 05 );

    在這里,我們使用操作數(shù)的一個(gè)立即約束來(lái)引用宏。然后,通過(guò)修改宏定義,用戶可以在全局修改常量。

  • 輸出操作數(shù)列表中缺少冒號(hào)。

    在代碼 G 中,stswi 指令意味著它存儲(chǔ)了 4 個(gè)字節(jié),從寄存器 %1 開(kāi)始(具體來(lái)說(shuō),如果 %1 被分配到寄存器 r0,則按順序從 r0、r1、r2、r3...讀出字節(jié))到在 0% 的有效地址。

    對(duì)于內(nèi)聯(lián)匯編代碼,并沒(méi)有輸出操作數(shù),因?yàn)闆](méi)有寄存器存儲(chǔ)結(jié)果,也無(wú)法寫(xiě)入該結(jié)果。而且,輸入操作數(shù)列表中包括所有變量(valuebase)。

    代碼 G:缺少冒號(hào)

    01 // Require input only: 02 int base[5]; 03 int value = 0x7a; 04 __asm__ __volatile__( 05 "stswi %0,%1,4\n\t" 06 : : "b" (value), "b" (base) 07 ); … 01 // But mistaken as output : 02 __asm__ __volatile__( 03 "stswi %0,%1,4\n\t" 04 : "b" (value), "b" (base) 05 );

    在后一種代碼中,用戶不幸地漏了一個(gè)冒號(hào)。現(xiàn)在所有輸出都變成輸入。在這種情況下,編譯器甚至可能沒(méi)有發(fā)出警告。但是,用戶可能最終會(huì)在運(yùn)行時(shí)發(fā)現(xiàn)錯(cuò)誤。雖然這樣的錯(cuò)誤看起來(lái)很小,但它可能會(huì)破壞一切。此外,不容易發(fā)現(xiàn)該錯(cuò)誤,因?yàn)殄e(cuò)誤總是很難找到的,比如在 C/C++ 代碼中混淆 if (a==1)if (a=1)。因此,初學(xué)者應(yīng)多注意冒號(hào)。

    我們將很快將會(huì)繼續(xù)討論這種錯(cuò)誤的更深層次原因。

  • 內(nèi)聯(lián)匯編、編譯器和匯編器

    人們?cè)诰帉?xiě)內(nèi)聯(lián)匯編代碼時(shí)會(huì)發(fā)現(xiàn),最大的挑戰(zhàn)并不是在規(guī)范中找出正確的指令,而是讓輸入/輸出/破壞列表正常工作。有可能出現(xiàn)投訴和問(wèn)題,比如:為什么我們需要這些列表?為什么要有約束和修飾符?等等。

    在這里,我們列出了這類(lèi)問(wèn)題及其答案。我們希望它可以幫助用戶從實(shí)現(xiàn)角度了解有關(guān)的更多信息。為簡(jiǎn)單起見(jiàn),我們只專(zhuān)注于引用 C/C++ 變量的指令和寄存器操作數(shù)。

    Q1:誰(shuí)處理內(nèi)聯(lián)匯編?編譯器還是匯編器?為什么我在編譯時(shí)得到匯編程序錯(cuò)誤?

    A1: 答案是兩者都處理(在大部分的時(shí)間)。一般情況下,匯編器會(huì)在編譯器支持最新指令之前支持這些指令。因此,編譯器必須調(diào)用匯編器來(lái)處理任何無(wú)法識(shí)別的指令。但是,這并不意味著匯編器會(huì)處理一切。變量和寄存器之間的關(guān)聯(lián)是通過(guò)編譯器完成的。(請(qǐng)參閱 Q2 及 Q3。) C/C++ 中的內(nèi)聯(lián)匯編語(yǔ)法檢查也由編譯器完成。但是,匯編指令本身不包括在內(nèi)。因此,如果匯編器在檢查匯編指令時(shí)發(fā)現(xiàn)問(wèn)題,那么它會(huì)報(bào)告錯(cuò)誤。

    Q2:匯編模板中的寄存器如何引用 C++ 變量?

    A2:如 Q1 的答案所示,關(guān)聯(lián)由編譯器完成。在內(nèi)部,由一個(gè)寄存器分配和指派過(guò)程將變量映射為寄存器。在完成此過(guò)程后,匯編模板會(huì)變成一小段真正的匯編代碼。然后,匯編器可以接受并處理它,從而生成最終的二進(jìn)制代碼。

    Q3:我知道寄存器分配和指派會(huì)將寄存器與變量相關(guān)聯(lián)。但是,為什么要提供一個(gè)輸入/輸出列表?

    A3:事實(shí)上,對(duì)于寄存器分配和指派,可能會(huì)要求編譯器提供輸入,比如約束和活躍度(liveness)。如果沒(méi)有內(nèi)聯(lián)匯編,編譯器可以通過(guò)內(nèi)部分析代碼找到這樣的輸入。但是,因?yàn)榫幾g器認(rèn)為內(nèi)聯(lián)匯編塊里面的指令行為是未知的,所以它要求用戶提供額外的信息來(lái)幫助它。
    內(nèi)部的約束可能與硬件有關(guān)。例如,為放入通用寄存器的操作數(shù)設(shè)置約束 r,并為放入浮點(diǎn)寄存器的操作數(shù)設(shè)置約束 f。此外,有時(shí),某些硬件在某些情況下將禁止某些行為。例如,在 PowerPC 中的約束 b(它禁止使用 r0 寄存器)就屬于這一類(lèi)。(請(qǐng)參閱 A guide to inline assembly for C and C++ - Basic, intermediate, and advanced concepts,了解有關(guān)的更多詳細(xì)信息)。從概念上講,用戶應(yīng)該負(fù)責(zé)告訴編譯器 數(shù)據(jù)類(lèi)型、指令的限制 等信息,因?yàn)榫幾g器對(duì)用戶所提供的匯編代碼完全是未知的。
    活躍度可能受到許多方面的影響。最重要的一個(gè)方面是,是讀取、寫(xiě)入變量,還是兩者同時(shí)進(jìn)行。輸入/輸出操作數(shù)列表和某些約束修飾符可以幫助構(gòu)建該信息。(例如,約束修飾符 "+" 說(shuō)明操作數(shù)是 read-write,而 "=" 說(shuō)明它是 write-only。)
    整體而言,輸入/輸出列表用于向編譯器提供信息。

    整體而言,輸入/輸出列表用于向編譯器提供信息。

    Q4:破壞列表又怎么樣呢?我們?yōu)槭裁葱枰?#xff1f;

    A4:在許多現(xiàn)實(shí)世界的平臺(tái)上,機(jī)器指令可能會(huì)隱式地修改寄存器。可以將這視為一種硬件約束。包含寄存器名稱(chēng)的破壞列表可以讓編譯器知道沒(méi)有引用變量的任何其他寄存器是否也被修改了。 而且,如果一個(gè)指令不可預(yù)知地寫(xiě)入一個(gè)意外的內(nèi)存位置,編譯器可能不知道它是否修改了任何已經(jīng)存在于寄存器中的變量。(如果發(fā)生這種情況,會(huì)從內(nèi)存重新加載已經(jīng)存在于寄存器中的變量。)通過(guò)放進(jìn)一個(gè) 內(nèi)存 亂碼,我們通知編譯器要做一些處理,以確保生成的代碼是正確的。(對(duì)于內(nèi)存亂碼, A guide to inline assembly for C and C++ - Basic, intermediate, and advanced concepts 提供了更好的解釋。)

    Q5:為什么不建議使用匯編指令?

    A5:有時(shí),人們認(rèn)為內(nèi)聯(lián)匯編可能具備匯編的完整功能。但是,情況并不總是這樣。例如,如果用戶不知道內(nèi)聯(lián)匯編代碼已經(jīng)嵌入最終可執(zhí)行文件的代碼段,那么使用匯編指令可能會(huì)引起嚴(yán)重的問(wèn)題。

    一個(gè)典型的示例是,用戶希望在匯編模板中定義一個(gè)新的部分 .mysect。編譯器會(huì)計(jì)算出正確的匯編代碼,并將它傳遞給匯編器。但是,正如匯編語(yǔ)法所說(shuō)明的那樣,需要定義一個(gè) .mysect 部分,使用當(dāng)前部分覆蓋它。因此,內(nèi)聯(lián)匯編后面的代碼(這是由編譯器生成的)也會(huì)匯編到 .mysect 部分中,而不是 .text(用于代碼)部分。結(jié)果,該可執(zhí)行文件被完全破壞。

    總之,使用不屬于編譯器的內(nèi)聯(lián)匯編規(guī)范的匯編功能不是一種明智的做法。使用未獲得正式支持的任何內(nèi)容都可能為您的代碼帶來(lái)風(fēng)險(xiǎn)。

    現(xiàn)在,讓我們回到丟失冒號(hào)的問(wèn)題。顯然,失敗的根本原因是我們向編譯器提供了不正確的信息(如活動(dòng)性或約束)。編譯器不會(huì)抱怨,因?yàn)樗粰z查任何列表的正確性(只檢查 C/C++ 語(yǔ)法錯(cuò)誤)。并且匯編器也會(huì)很開(kāi)心,因?yàn)樗惶幚碛泻侠砀袷降闹噶睢5聦?shí)上,編譯器使用了不正確的信息工作。最后,該代碼會(huì)失敗。這個(gè)失敗警告了我們,并且用戶要為自己編寫(xiě)的輸入/輸出/亂碼列表負(fù)責(zé),這非常重要。否則,獲得不可用的代碼就并不奇怪了。

    結(jié)束語(yǔ)

    雖然學(xué)習(xí)內(nèi)聯(lián)匯編的語(yǔ)法并不難,但編寫(xiě)正確的匯編代碼并不僅僅意味著編寫(xiě)正確的匯編指令和嵌入它們。由于編譯器無(wú)法分析內(nèi)聯(lián)匯編塊的內(nèi)部情況,所以內(nèi)聯(lián)匯編用戶應(yīng)該向編譯器提供比普通 C/C++ 代碼更多的信息。這可能很容易出錯(cuò)。無(wú)論如何,您可以利用下面的技巧。

    • 只編寫(xiě)一個(gè)具有單一功能的較短的內(nèi)聯(lián)匯編塊。
    • 查看編譯器文檔中的內(nèi)聯(lián)匯編部分。不要試圖使用不屬于編譯器的內(nèi)聯(lián)匯編規(guī)范的匯編功能。
    • 仔細(xì)選擇指令。弄清楚每一個(gè)細(xì)節(jié)。不要漏掉任何說(shuō)明,比如約束、副作用等。
    • 再次檢查輸入/輸出/亂碼列表,然后再編譯和運(yùn)行您的代碼。特別要檢查是否正確使用了冒號(hào)。

    致謝

    謝謝 IBM CDL Rational Compiler 團(tuán)隊(duì)的同事 Jiang Jian 和 Ji Jinsong。感謝他們對(duì)這篇文章的認(rèn)真審查和意見(jiàn)。

    參考資料

    學(xué)習(xí)

    • A guide to inline assembly for C and C++ Basic, intermediate, and advanced concepts。這是一篇很好的面向 Power/PowerPC 用戶的內(nèi)聯(lián)匯編教程,它涵蓋了許多高級(jí)主題。
    • GCC-Inline-Assembly-HOWTO,gcc 的基本內(nèi)聯(lián)匯編的教程。
    • 在 IBM AIX 7.1 上安裝 IBM XL C/C++:IBM XL C/C++ 是一個(gè)高性能的優(yōu)化編譯器,旨在服務(wù)于 IBM POWER 處理器,并利用處理器的多核和向量特性實(shí)現(xiàn)更好的并行應(yīng)用程序開(kāi)發(fā)。本文將向您講解在 IBM AIX 7.1 操作系統(tǒng)上安裝 XL C/C++ V11 的整個(gè)過(guò)程。
    • IBM XL C/C++ 編譯器中添加的 ISO C11 支持:新的 ISO C 編程語(yǔ)言標(biāo)準(zhǔn)提供了多項(xiàng)功能來(lái)幫助提高編程效率、調(diào)試和提高性能。IBM XL 編譯器正在分階段支持新的 C 標(biāo)準(zhǔn),以便您可以利用有用的功能,比如支持復(fù)數(shù)類(lèi)型對(duì)象初始化的功能、靜態(tài)斷言,以及針對(duì)沒(méi)有返回值的函數(shù)的函數(shù)特性。
    • AIX and UNIX 專(zhuān)區(qū):developerWorks 的“AIX and UNIX 專(zhuān)區(qū)”提供了大量與 AIX 系統(tǒng)管理的所有方面相關(guān)的信息,您可以利用它們來(lái)擴(kuò)展自己的 UNIX 技能。
    • AIX and UNIX 新手入門(mén):訪問(wèn)“AIX and UNIX 新手入門(mén)”頁(yè)面可了解更多關(guān)于 AIX 和 UNIX 的內(nèi)容。
    • AIX and UNIX 專(zhuān)題匯總:AIX and UNIX 專(zhuān)區(qū)已經(jīng)為您推出了很多的技術(shù)專(zhuān)題,為您總結(jié)了很多熱門(mén)的知識(shí)點(diǎn)。我們?cè)诤竺孢€會(huì)繼續(xù)推出很多相關(guān)的熱門(mén)專(zhuān)題給您,為了方便您的訪問(wèn),我們?cè)谶@里為您把本專(zhuān)區(qū)的所有專(zhuān)題進(jìn)行匯總,讓您更方便的找到您需要的內(nèi)容。
    • AIX and UNIX 下載中心:在這里你可以下載到可以運(yùn)行在 AIX 或者是 UNIX 系統(tǒng)上的 IBM 服務(wù)器軟件以及工具,讓您可以提前免費(fèi)試用他們的強(qiáng)大功能。
    • IBM Systems Magazine for AIX 中文版:本雜志的內(nèi)容更加關(guān)注于趨勢(shì)和企業(yè)級(jí)架構(gòu)應(yīng)用方面的內(nèi)容,同時(shí)對(duì)于新興的技術(shù)、產(chǎn)品、應(yīng)用方式等也有很深入的探討。IBM Systems Magazine 的內(nèi)容都是由十分資深的業(yè)內(nèi)人士撰寫(xiě)的,包括 IBM 的合作伙伴、IBM 的主機(jī)工程師以及高級(jí)管理人員。所以,從這些內(nèi)容中,您可以了解到更高層次的應(yīng)用理念,讓您在選擇和應(yīng)用 IBM 系統(tǒng)時(shí)有一個(gè)更好的認(rèn)識(shí)。

    討論

    • 加入 developerWorks 中文社區(qū)。查看開(kāi)發(fā)人員推動(dòng)的博客、論壇、組和維基,并與其他 developerWorks 用戶交流。

    總結(jié)

    以上是生活随笔為你收集整理的内联汇编 - 从头开始的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 精品国产乱码久久久久久闺蜜 | 香港一级淫片免费放 | 日本极品丰满ⅹxxxhd | 黑人性xxx| 女人18毛片水真多 | 久久影院中文字幕 | 性工作者十日谈 | 一级视频片 | 中文字幕一二三四 | 在线免费日本 | 激情五月激情 | 天天干,夜夜爽 | 在线免费观看污 | 午夜精品少妇 | 新久草视频 | 国产日韩一区二区三免费高清 | 69影院在线观看 | 娇妻玩4p被三个男人伺候电影 | 欧美一区二区三区公司 | 国产妇女视频 | 日韩av在线看免费观看 | 亚洲天堂色 | 91精品视频免费在线观看 | 美女免费看片 | 欧美首页 | 日韩aa | 校园伸入裙底揉捏1v1h | 亚洲国产精品99久久 | 欧美国产精品一区二区三区 | 极品超粉嫩尤物69xx | 各种含道具高h调教1v1男男 | 一级视频在线免费观看 | 69久久久| 69网址| 日本青草视频 | ,国产精品国产三级国产 | 先锋资源av在线 | 欧美日韩观看 | 久久久免费 | 丰满少妇被猛烈进入 | 3o一40一50一6o女人毛片 | 久久精品国产99国产精品 | 姐姐你真棒插曲快来救救我电影 | 成人免费视频免费观看 | 日日摸日日操 | 精品久久久久久久久久久国产字幕 | 四季av中文字幕一区 | 中文字幕一区2区3区 | 调教奶奴 | 欧美乱欲视频 | 喷潮在线| 国产精品日韩专区 | 精品乱人伦一区二区三区 | 久久精品国产99精品国产亚洲性色 | 毛片在线免费观看网站 | 无码av免费精品一区二区三区 | 国产日韩在线看 | 久久精品9 | 久久久精品动漫 | 69av导航| 黄色片子免费 | 成 人片 黄 色 大 片 | 国产一级免费看 | 色一情一区二区三区四区 | 免费jizz| 久艹av | 91国产视频在线播放 | 国产精品视频久久久久久 | 国产成人在线观看免费 | 欧美无遮挡 | 极品少妇一区二区三区 | 奇米第四色影视 | 麻豆亚洲av成人无码久久精品 | 欧美乱淫 | 三级男人添奶爽爽爽视频 | 香蕉视频在线观看黄 | 看特级毛片 | 综合欧美亚洲 | 午夜精品久久久久久久第一页按摩 | 欧美一区二区三区黄片 | 9999av| 97视频在线观看免费高清完整版在线观看 | 野花视频在线免费观看 | 蜜桃网站 | 久久精品国产一区二区电影 | 台湾少妇xxxx做受 | 亚洲欧美视频一区二区 | 国产精品九九 | 日韩av一二区 | 国产精选久久久 | 亚洲av无码一区二区三区人妖 | 欧美亚洲精品天堂 | 日韩av免费看 | 国产亚洲网站 | 黄网页在线观看 | www.四虎在线观看 | 国产精品三级久久久久久电影 | 天天操天天干天天操 | av成人天堂 |