首页 > 代码库 > VC++下编译 程序“减肥”

VC++下编译 程序“减肥”

在vc6 和 vs 2008下 编译 以下代码,不更改任何编译设置(vc6  40k , s2008 7k)。

一、vc6下,Release 模式 编译处理。

1、去掉不必要的 链接库  工程(Project)-->设置(Settings)-->链接(link)属性页-->对象库/模块(object/library modules) 去掉所有的lib。

  选择使用 MSVCRT.LIB kernel32.lib user32.lib。 可以忽略不必要的警告,比如 LINK:warning LNK4098: default  lib  "LIBC "  conflicts  with use of other libs; use /NODEFAULTLIB:library

2、工程(Project)-->设置(Settings)-->链接(link)属性页-->在Project Options(工程 选项)

  下面的编辑框里加上一句: /ALIGN:2的n次方  这样做之后指定了程序不是驱动程序,系统可以设定的最值不同。

  

  按照处理之后,生成程序  /ALIGN:4096 (3k)  /ALIGN:16 (1.59k)  /ALIGN:128 (1.87k)。

 

 


 

二、在代码中添加相应的编译设置,达到缩小程序体积的目的。

1、无优化

 

 #include <windows.h>int main(){    MessageBox(NULL,TEXT("hello!"),TEXT("hi"),MB_OK);    return 0;}

 

2、代码中设置

  

#include <windows.h>//自定义加载的库#pragma comment(lib,"kernel32.lib")#pragma comment(lib,"shell32.lib")#pragma comment(lib,"msvcrt.lib")//自定义函数入口#pragma comment(linker,"/ENTRY:EntryPoint")//自定义对齐方式#pragma comment (linker,"/ALIGN:512")#pragma comment(linker,"/FILEALIGN:512")// 优化选项#pragma comment(linker,"/opt:nowin98")#pragma comment(linker,"/opt:ref") //清除从未引用的函数和/或数据#pragma comment (linker, "/OPT:ICF")//从链接器输出中删除冗余COMDAT// 合并区段#pragma comment(linker,"/MERGE:.rdata=http://www.mamicode.com/.data")#pragma comment(linker,"/MERGE:.text=.data")#pragma comment(linker,"/MERGE:.reloc=.data")int WINAPI WinMain( HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow ) ;void EntryPoint(){    ExitProcess(WinMain(GetModuleHandle(NULL), NULL,GetCommandLine(), SW_SHOWNORMAL));    }int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int iShowCmd ){    MessageBox(NULL,TEXT("hello!"),TEXT("hi"),MB_OK);    return 0;}

经过 上述代码优化,可以将 40k的程序 缩小 为 1k 的程序。

 


三、

最简单的窗口程序:

#include <windows.h>int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,hPrevInstance,LPSTR szCmdLine,int iCmdShow){   MessageBox(NULL,"Hello World","Hello",0);   return 0;}

在VC6.0下以Release方式编译,大小为36,864字节(36.0KB)。用CFF Explorer工具查看可执行文件,

  

 

可以看出,文件导入了2个动态库,其中user32.dll仅导入了程序中使用的函数MessageBoxA,kernel32.dll导入了38个函数,显然是WinMain中调用的。

2、把WinMain去掉,自己给定程序入口函数,重写代码如下:

 

 #include <windows.h>#pragma comment(linker,"/ENTRY:EntryPoint")//自定义入口函数void EntryPoint(){   MessageBox(NULL,"Hello World","Hello",0);   ExitProcess(0);}

 

 重新编译,文件大小为16384字节(16.0KB)。再用CFF Explorer工具查看可执行文件,结果如下图所示。

可以看出,虽然仍导入了2个动态库,但kernel32.dll只导入了一个上述代码中调用的函数ExitProcess。导入函数的减少使文件大小减小了约20KB。

 

3、在记事本中打开可执行文件,可以发现文件中存在大量的空字符。

  用CFF Explorer工具查看文件节表信息。文件的节表信息如下图所示。

 

 

可以看出,文件中存在3个节(.text、.rdada、.data),每个节在文件中对齐后的大小和映射到内存后的大小(实际大小)分别由Raw Size和Virtual Size指出。其中.data节实际大小为0x12(18)字节,与"Hello World"和"Hello"这两个字符串的大小(含结束符\0)一致,却占用文件0x1000(4096)字节大小,故文件中存在大量的空字符(数值为0)。

 

4、是否可以修改节的对齐方式,更改文件的大小呢?

  使用链接器/FILEALIGN和/ALIGN选项可以帮我们做到这一点。

  其中/FILEALIGN用来指定节在文件中的对齐方式,/ALIGN用来指定节加载到内存后的对齐方式,对齐字节数必须是2的幂。

  修改后代码如下:

 #include <windows.h>#pragma comment(linker,"/ENTRY:EntryPoint")//自定义入口函数#pragma comment(linker, "/FILEALIGN:16")//指定节的文件对齐方式#pragma comment(linker, "/ALIGN:16")//指定节的内存对齐方式void EntryPoint(){   MessageBox(NULL,"Hello World","Hello",0);   ExitProcess(0);}

  重新编译,文件大小为800字节,程序仍能正常运行。进一步该小/FILEALIGN和/ALIGN的参数,将能编译但无法运行或编译通不过。

 

5、 还能减小文件的体积吗?是的。

  上述说到该文件存在三个节表和相应的三个节,使用链接器/MERGE选项可以把三个节合并,从而进一步压缩文件。

  修改后代码如下:

 #include <windows.h>#pragma comment(linker,"/ENTRY:EntryPoint")//自定义入口函数#pragma comment(linker, "/FILEALIGN:16")//指定节的文件对齐方式#pragma comment(linker, "/ALIGN:16")//指定节的内存对齐方式#pragma comment(linker, "/SECTION:.text,ERW")//指定节属性#pragma comment(linker, "/merge:.rdata=http://www.mamicode.com/.text")//合并节.rdata到.text#pragma comment(linker, "/merge:.data=http://www.mamicode.com/.text")//合并节.rdata到.text#pragma comment(linker, "/IGNORE:4078")//忽略4078错误void EntryPoint(){   MessageBox(NULL,"Hello World","Hello",0);   ExitProcess(0);}

重新编译,文件大小为704字节,相对初始大小(36KB)已有了明显的变化。   

  Section信息 如下:

 

 6、 另外,程序优化有时也能减小文件体积:

‍#pragma comment(linker, "/OPT:REF")//清除从未引用的函数和/或数据

#pragma comment(linker, "/OPT:ICF")//从链接器输出中删除冗余COMDAT

除上述方式外,工程中的一些设置也可以很大程度减小文件体积。

 


 

结束!