![](/img/trans.png)
[英]Is it possible to force GCC to output the exact bitwise instructions I give it without inline assembly?
[英]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
/ DIV
的MUL
/ IDIV
變體也不計算在內 而不是objdump
荷蘭國際集團執行隨機和審計他們再創造的源泉, 是有可能找到的是GCC目前輸出的x86匯編指令列表?
這個問題的基礎似乎是實際使用的指令子集很少,需要知道逆向工程(這是課程的重點)。 Xeno似乎試圖找到一種有趣的指導方式來表達這一點,
我認為知道大約20-30(不計算變化)是足夠好的,你將很少檢查手冊
雖然我歡迎大家和我一起參加OpenSecurityTraining這個很棒的課程,但問題是關於我提出的從GCC中找出它的方法(如果可能的話)。 不是,人們實際上做了Xeno的任務。 ;)
這個問題的基礎似乎是實際使用的指令子集非常少,需要知道逆向工程
是的,這通常是正確的。 有一些指令GCC將絕不會發出, 就像enter
(因為它比慢得多 push rbp
/ mov rbp, rsp
/ sub rsp, some_constant
在現代的CPU)。
其他舊/模糊的東西,如xlat
和loop
也將被閑置,因為它們並不快,而gcc的-Os
並沒有全力以赴地優化尺寸而不關心性能。 ( clang -Oz
更具侵略性,但IDK如果有人clang -Oz
教它loop
指令。)
當然,gcc永遠不會發出像wrmsr
這樣的特權指令。 有些內在函數( __builtin_...
函數)用於某些非特權指令, 如rdtsc
或cpuid
,它們不是“正常”。
是否可以找到GCC當前輸出的x86匯編指令列表?
這將是gcc機器定義文件。 作為可移植編譯器的GCC具有自己的基於文本的語言,用於描述編譯器指令集的機器定義文件。 (每個指令的作用,它可以使用的尋址模式,以及優化器可以最小化的某種“成本”。)
請參閱gcc-internals文檔 。
這個問題的另一種方法是查看x86指令參考手冊(例如這個HTML提取 ,並查看x86標簽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_u64
是popcnt
或什么都沒有:如果目標不支持該指令,它不會編譯。
當然,這種方法的缺陷是它只有在您已經知道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
cdq
( 在idiv
之前 ) jcxz
/ jecxz
(gcc很少見,VC ++有些常見) setCC
cmpxchg
(同步代碼中); cmovCC
adc
(在32位代碼中進行64位運算時) int3
(通常在函數邊界上發出,通常作為填充int3
) scas
/ cmps
),尤其是舊編譯器上的固定序列 然后就是整個世界的SSE&co ...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.