簡體   English   中英

檢測C ++二進制文件是否已優化

[英]Detect if C++ binary is optimized

是否有標記或其他可靠的方法來檢測編譯的C ++二進制文件是否經過優化編譯?

我可以使用特定於編譯器的解決方案。


編輯:這是針對構建部署系統的,它可能會意外地部署未正確構建的二進制文件。 一個不漏水的解決方案是不可能的,但是如果可以在某些時候被發現,它將節省一些痛苦(和金錢)。

編譯器通常是gcc,有時是sun,如果有MSVC解決方案,我不想為了社區的利益而將其排除在外。

最新版本的GCC可以報告使用哪些標志來編譯二進制文件 (第三個項目符號點)。

有一個相關的命令行開關(--fverbose-asm),“僅將匯編程序輸出文件中的信息記錄為注釋,因此信息永遠不會到達目標文件。” --frecord-gcc-switches開關“導致用來調用要記錄到正在創建的目標文件中的編譯器的命令行。”

可能的啟發式解決方案

如果給我這個任務,它將證明這是一個合理的任務。 我將對可執行文件反匯編中的模式執行“頻率分析”。 作為一名程序員,我乍一看就能區分優化和未優化(調試)代碼。 我將嘗試使決策過程正式化,在Visual Studio和x86平台上,未優化exe中常見的典型功能是:

  • 具有完整序言/結尾的功能(基於ebp的堆棧框架)
  • 內存中有很多移動(所有變量都放在內存中)

這絕對不是100%,但是如果使用更長的exe,我希望結果會非常可靠。

我假設對於其他x86平台(包括GCC),規則將是相似的(如果不相同的話);對於其他平台,可以找到相似的規則。

其他啟發式方法(如運行時庫的檢測)也可能起作用,具體取決於編譯器設置。

任務聽起來很傻

也就是說,我認為這樣的任務“很臭”,在大多數情況下,完全避免它是明智的。 如果您提供執行此任務的真正原因,則很有可能會找到一些明智的解決方案。

我們使用的技術只是創建一個僅在構建調試時才會出現在每個庫中的符號:

// included_by_everything.h
#ifdef (_DEBUG)
extern "C" __declspec( dllexport ) void WasBuiltInDebug() {}
#else
// nothing!
#endif

然后在運行時(或在Perforce觸發器中)加載每個模塊時,我們可以通過簡單地尋找該符號來詢問二進制文件是否已調試:

bool IsDebugDLL( HMODULE DllHandle )
{
  // this system call returns a nonzero address if it can 
  // find the symbol, and NULL otherwise:
  return GetProcAddress( DllHandle , "WasBuiltInDebug" );
}

在Windows上,您可以檢查調試信息是否已從二進制文件中刪除。 如果檢查二進制圖像的COFF標頭,則在距COFF標頭18字節的偏移量處有一個2字節的標志塊,稱為特性。 如果旗

 IMAGE_FILE_DEBUG_STRIPPED = 0x0200

設置,然后從映像文件中刪除調試信息。

這可以通過從文件偏移量0x52讀取2個字節來完成,並檢查該標志是否已設置。

可以如下檢查標志

 short flag_block;

 FILE * p_image_file = fopen (...); 

 fseek(p_image_file,0x52,SEEK_SET);

 fread(&flag_block,2,1,p_image_file);

 if(flag_block & 0x0200 > 0)
    then debug info is stripped

您可以從Microsoft找到Windows PE格式的文檔 ,該文檔對其進行了更詳細的描述,以便您計算要讀取的字節偏移量等。

您沒有提到特定的平台,因此答案可能是肯定的。 但是對於大多數常見平台,答案是否定的。


對於Microsoft C ++,如果可執行文件引用了運行時DLL的調試版本,則可以假定優化已關閉。 但是,這不是保證。

以我的經驗, 如果您不了解編譯器,則唯一可靠的方法是檢查反匯編本身。 首先嘗試使用您喜歡的工具轉儲所有字符串,並在鏈接的庫名稱和導出的符號中尋找線索。 失敗的話,尋找常見的指令序列,這些指令序列在優化后(例如堆棧框架序言)以及有序且易於理解的寄存器使用情況后會被丟棄。 如果像ollydbg這樣的工具對於函數的開始位置和結束位置感到困惑,則很有可能會在啟用優化的情況下編譯二進制文件。

檢查反編譯器的輸出也可能會有所幫助。 上次我檢查時,它們並不比反匯編程序更好,但此后情況可能有所改善。

如果您還沒有做類似的事情,我會感到驚訝,但是:

如果您“信任”構建系統,請將用於構建的選項放入可以從正在運行的程序中提取的字符串中。 (即來自--version或About對話框)

這不會檢測到由於構建系統損壞而導致的非優化目標文件進入構建的問題,但是它可以使您輕松地區分開發人員版本和發布版本。

然后,您的發布過程可以包括檢查版本,以確保其未調試/未優化。

我很確定沒有辦法。 除非您對內部函數有特定的了解,否則可以檢查代碼序列是否最佳。

也許您可以使用其他指標來確定您是否正在部署正確的二進制文件。 例如

  • 調試信息:也許您的發行二進制文件不同,因為它們沒有調試信息? 您可以使用elfdump或gdb進行檢查。
  • 剝離:如果剝離發行版二進制文件,則可以使用“文件”進行檢查

暫無
暫無

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

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