針對體積敏感場合(Shellcode、啟動器、嵌入式),VC++ 連結器提供多種優化選項。本文示範如何透過 #pragma comment(linker,...) 將一個簡單程式從 16KB 壓縮至 712 Bytes(含 PE 標頭)。
// 1. 區段對齊 512 位元組(預設 4096/512)
#pragma comment(linker, "/ALIGN:512")
// 2. 合併區段:.data .rdata 併入 .text(程式碼區)
#pragma comment(linker, "/MERGE:.data=.text")
#pragma comment(linker, "/MERGE:.rdata=.text")
// 3. 指定子系統為 Windows(無主控台視窗)
#pragma comment(linker, "/SUBSYSTEM:WINDOWS")
// 4. 自訂進入點(移除 CRT 啟動樣板碼)
#pragma comment(linker, "/ENTRY:main")
#include <windows.h>
#pragma comment(lib, "kernel32.lib")
#pragma comment(linker, "/ALIGN:512")
#pragma comment(linker, "/MERGE:.data=.text")
#pragma comment(linker, "/MERGE:.rdata=.text")
#pragma comment(linker, "/SUBSYSTEM:WINDOWS")
#pragma comment(linker, "/ENTRY:main")
__declspec(naked) void main()
{
// 直接呼叫匯出函式,不建立堆疊框架
GetProcAddress(LoadLibrary(L"msdxm.ocx"), "RunDllW")();
ExitProcess(0);
}
| 指令 | 預設值 | 優化後 | 說明 |
|---|---|---|---|
| /ALIGN | 4096 (檔案) / 512 (記憶體) | 512 | 減少區段間隙浪費 |
| /MERGE | 獨立區段 | 合併 .data/.rdata 至 .text | 減少區段表與對齊開銷 |
| /SUBSYSTEM | CONSOLE | WINDOWS | 移除主控台附屬結構 |
| /ENTRY | mainCRTStartup / WinMainCRTStartup | main | 跳過 CRT 初始化(需自行處理) |
| __declspec(naked) | 完整函式序言/結語 | 無 | 移除 push ebp/mov ebp,esp 等指令 |