簡體   English   中英

是否可以找到GCC可以生成的所有匯編指令的列表?

[英]Is it possible to find a list of all of the assembly instructions that GCC can generate?

在分配給OpenSecurityTraining的Xeno Kovah的x86大會簡介的第一天的作業中,他指出

我們現在知道的說明(24)

NOP PUSH / POP CALL / RET MOV / LEA ADD / SUB JMP / Jcc CMP / TEST和/或/ XOR / NOT SHR / SHL IMUL / DIV REP STOS,REP MOV LEAVE

編寫程序以查找我們尚未涵蓋的指令,並明天報告指令。

他進一步預測了作業,

  • 以后要說明的指示不計算在內: SAL / SAR
  • 跳躍的變化或IMUL / DIVMUL / IDIV變體也不計算在內
  • 額外的禁止指令:任何浮動點(因為我們沒有覆蓋此類中的那些。)
  • 他在視頻中說你不能使用內聯匯編。 (被問及時提到)。

而不是objdump荷蘭國際集團執行隨機和審計他們再創造的源泉, 是有可能找到的是GCC目前輸出的x86匯編指令列表?

這個問題的基礎似乎是實際使用的指令子集很少,需要知道逆向工程(這是課程的重點)。 Xeno似乎試圖找到一種有趣的指導方式來表達這一點,

我認為知道大約20-30(不計算變化)是足夠好的,你將很少檢查手冊

雖然我歡迎大家和我一起參加OpenSecurityTraining這個很棒的課程,但問題是關於我提出的從GCC中找出它的方法(如果可能的話)。 不是,人們實際上做了Xeno的任務。 ;)

這個問題的基礎似乎是實際使用的指令子集非常少,需要知道逆向工程

是的,這通常是正確的。 有一些指令GCC將絕不會發出, 就像enter (因為它比慢得多 push rbp / mov rbp, rsp / sub rsp, some_constant在現代的CPU)。

其他舊/模糊的東西,如xlatloop也將被閑置,因為它們並不快,而gcc的-Os並沒有全力以赴地優化尺寸而不關心性能。 clang -Oz更具侵略性,但IDK如果有人clang -Oz教它loop指令。)

當然,gcc永遠不會發出像wrmsr這樣的特權指令。 有些內在函數( __builtin_...函數)用於某些非特權指令, rdtsccpuid ,它們不是“正常”。


是否可以找到GCC當前輸出的x86匯編指令列表?

這將是gcc機器定義文件。 作為可移植編譯器的GCC具有自己的基於文本的語言,用於描述編譯器指令集的機器定義文件。 (每個指令的作用,它可以使用的尋址模式,以及優化器可以最小化的某種“成本”。)

請參閱gcc-internals文檔


這個問題的另一種方法是查看x86指令參考手冊(例如這個HTML提取 ,並查看標簽wiki中的其他鏈接)並查找尚未看到的那些。 然后編寫一個函數,gcc會發現它很有用。

例如,如果你還沒有看過movsx (符號擴展名),那就寫吧

long long foo(int x) { return x; }

和gcc -O3將發出( 來自Godbolt編譯器資源管理器

    movsx   rax, edi
    ret

或者為了獲得rax符號擴展的cdqe (在AT&T語法中也稱為cltq ,強制gcc在符號擴展之前進行數學運算,因此它可以首先在eax生成結果(使用復制和添加lea )。

long long bar(unsigned x) { return (int)(x+1); }

    lea     eax, [rdi+1]
    cdqe
    ret

   # clang chooses inc edi  /  movsxd rax, edi

另見Matt Godbolt的CppCon2017演講: “我的編譯器最近為我做了什么? 解開編譯器的蓋子“ ,以及如何從GCC / clang組件輸出中消除”噪音“?


讓gcc發出旋轉指令很有意思。 C ++中循環移位(旋轉)操作的最佳實踐 你把它寫成移位/ OR,gcc可以識別為旋轉。

因為C不提供現代CPU可以做的許多事情的標准函數(旋轉,彈出,計數前導/尾隨零),唯一可移植的東西是編寫一個等效函數並讓編譯器識別該模式。 如果你很幸運,gcc和clang可以在使用-mpopcnt進行編譯時將整個循環優化為單個popcnt指令(例如,由-march=haswell啟用)。 如果沒有,你會得到一個愚蠢的慢循環。 可靠的非可移植方式是使用__builtin_popcount() ,如果目標支持,則編譯為popcnt指令,否則進行表查找。 _mm_popcnt_u64popcnt或什么都沒有:如果目標不支持該指令,它不會編譯。


當然,這種方法的缺陷是它只有在您已經知道x86指令集並且任何給定指令是優化編譯器的正確選擇時才有效!

(以及gcc選擇做什么,例如內聯字符串在某些情況下對於短字符串比較rep cmpsb ,雖然我不確定這是最優的。只有rep movs / rep stos rep movs在現代CPU上有“快速字符串”支持。但是我不要以為gcc會使用lods ,或任何帶有rep前綴的“字符串”指令。)

是否可以找到GCC當前輸出的x86匯編指令列表,而不是隨機執行隨機可執行文件並審核它們然后創建源代碼

您可以查看gcc使用的機器描述文件 在其源代碼樹中,查看gcc / config / i386並查看.md文件。 i86的核心是i386.md ; 還有其他用於x86的各種擴展(並且可能包含在針對不同處理器進行優化時使用的啟發式調整)。

警告:這絕對不是一個容易閱讀。

我認為知道大約20-30(不計算變化)是足夠好的,你將很少檢查手冊

這是真的; 根據我進行逆向工程的經驗,99%的代碼總是相同的東西,指令方面; 比了解整個x86指令集更有用的是熟悉程序集習語,尤其是編譯器經常發出的習慣用法。


話雖如此,從我的腦海中,一些非常常見的指令缺失(經常發出並且沒有啟用擴展指令集)是:

  • movzx / movsx
  • inc / dec (gcc很少見, 與VC ++相同
  • neg
  • cdqidiv之前
  • jcxz / jecxz (gcc很少見,VC ++有些常見)
  • setCC
  • cmpxchg (同步代碼中);
  • cmovCC
  • adc (在32位代碼中進行64位運算時)
  • int3 (通常在函數邊界上發出,通常作為填充int3
  • 一些其他字符串指令( scas / cmps ),尤其是舊編譯器上的固定序列

然后就是整個世界的SSE&co ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM