|
使用 LIBCTINY.LIB 为 EXE 和 DLL 文件
减肥
原著:Matt Pietrek 逆风编程精品
翻译:crazyd
原文出处:MSDN Magazine January
2001 Reduce EXE and DLL Size with LIBCTINY.LIB
原代码下载:Hood0101.exe
(45KB)
在
October
1996 column 我讨论过一个有关可执行文件大小的问题。那个时候,一个简单的
hello world 程序大约有32KB。在
Visual C ® 编译器更新了两个版本后,文件尺寸问题稍微得到了改善,同样的程序使用
Visual C ® 6.0 编译器现在只有28KB。在那时的专栏里,我使用了一个小的运行库来创建极小的可执行程序。虽然有不少局限,但是对决大多数的程序来说,它们运转得很好。这些局限已经存在相当长的一段时间了,我决心修正它们。同时也提供一个学习如何进一步减少程序的尺寸的鲜为人知的知识。
DLL 和 EXE 的尺寸
在替换运行库之前,我们得先花点时间看看为什么EXE和DLL的大小比你想象的要大。考虑下面标准的
Hello World 程序:
#include <stdio.h>
void main()
{
printf ("Hello World!\n" );
}
使用下列命令编译并产生一个map文件(译者著:如果 CL
不能正确执行,在控制台下先执行\VC98\Bin\VCVARS32.BAT)
Cl /O1 Hello.CPP /link /MAP
首先,查看 .MAP 文件(Figure1展示了一个裁减过的版本),从
main (0001:00000000) 和 printf (0001:0000000C)
的地址来看,可以推断主函数只有 oxC
字节的长度。再看这个文件的最后一行 __chkstk( 0001:00003B10),可以估计可执行代码至少有
0x3B10 字节,其中将近14KB的代码将 Hello World 送到屏幕。
现在,再看看.MAP 文件中的其它行。有些项是有用的,比如,__initstdio
函数支持 printf 将输出写到文件,所以这类支持 stdio
的库函数是有意义的。再如 strlen,它会被printf调用,所以它包含在 .MAP
中就不足为奇了。
不过,我们再看看其它函数,比如
__sbh_heap_init。它是运行库的堆初始化程序, 而Win32的操作系统也提供了一些类似
HeapAlloc 的函数来实现堆分配。虽然C 运行库选择Win32的堆函数可能带来性能上的提高,但是
Visual C
并没有这样做。所以最后在可执行文件上增加了许多不必要的代码。
有些人并不介意运行库实现自己的堆,但这里有更缺乏说服力的例子。看看
map 文件底部的 __crtMessageBoxA
函数,这个函数使得可执行文件可以通过运行库而非 USER32.dll
来调用 MessageBox API。但对于一个简单的hello world 程序来说,是否要调用
MessageBox 是很难预见的。
再看一个例子:函数 __crtLCMapStringA
将字符串转做区域转换。区域支持是微软的责任,但是对大多数程序并不需要。所以就没有必要为区域转换花费开销。
我还可以继续列举那些不必要的东西,不过我已经证明了自己的观点:一个典型的小程序包含了很多不会被使用的代码,对于各个代码片段而言,并没有增加了多少代码的尺寸,但是将它们全部加起来将是相当可观的。 本文章更多内容:1 - 2 - 3 - 4 - 5 - 下一页>> |