注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

BCB-DG's Blog

...

 
 
 

日志

 
 

Minimizing Executable Image Sizes  

2008-02-26 08:10:13|  分类: VNC |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

Source From http://www.mvps.org/user32/nocrt.html

Introduction

This document describes some methods on how to minimize the size of images - be they dll's or exe's. The methods include elimination of the c-runtime stubs, and compiler & linker settings. The compiler and linker I concentrate on is MSVC 6 - most of the tips apply also to MSVC 5. While many of the concepts presented here apply to other development enviroments the actual command line parameters and #pragmas will obviously be different - check your enviroments documentation.

Doing without the C-Runtime

The c-runtime is a library of functions that do stuff for you the programmer. These functions are platform independent, and act as an abstraction layer between your program and the operating system. This has some drawbacks:

  • Bugs. While most c-runtimes are well tested, each layer you add to an application introduces the possibility of more bugs
  • It takes up space. You application must either include the code for the c-runtime functions it uses, or use a c0runtime in a shared dll.
  • The abstraction layer is not necessairly simpler than the OS - merely platform independent. Many tasks can be accomplished in less lines of code using raw OS API calls than using the c-runtime functions
  • Using the c-runtime also hides from you many of the capabilities of the OS that have the potential to make your program simpler, and drastically increase performance.

If, like me, you find these to be unacceptable tradeoffs, there are a couple of things you must do to eliminate the c-runtime completely from your application

  • Stop using c-runtime functions. Some functions you can use (the string, and memory manipulation functions) as they are available in intrinsic form, or the OS API provides direct equilavents. More work might be required to replace other runtime calls, especially where the OS does not provide an equilavent service.
  • Implement a couple of runtime functions that the C++ compiler assumes exists. new, delete and _purecall may be necessary for c++ modules. You will need to provide the application with an entrypoint.
  • Some compiler switches may need to be changed to make the generated object files link properly in a no-crt enviroment.
  • Change the linker settings to prevent the linker from including the runtime libraries
  • NB: Note that the c-runtime startup code is responsibile for initializing all global scope objects. Do not use global scope objects that require initialization in a no-runtime application as they will be in an undefined state (or - hopefully - prevent the application from linking successfully).

Functions you can use

The following functions are available in intrinsic form by the compiler. Beware though that the instrinsic forms of these may not be as optimised as the library form.

  • memcmp
  • memcpy
  • memset
  • strcmp
  • strcpy
  • strlen
  • strcat
  • strset



 


Required Functions

The c++ compiler absolutely requires that you implement __purecall, new and delete. If C++ exception ahndling is enabled more are required that I have no clue how to write. Either don't use C++ exceptions, or find the .obj files that implement these functions and link them into your project.

A simple implementation of these functions:

void* __cdecl operator new(unsigned int cb)  {    return HeapAlloc(GetProcessHeap(),0,cb);  }    void __cdecl operator delete(void* pv)  {    if(pv)      HeapFree(GetProcessHead(),0,pv);  }    extern "C" int _cdecl _purecall(void)  {    return 0;  }    

In addition to the C++ functions listed above you will need to provide your application with a new entry point. Typically an application starts at a functions called main, WinMain, or DllMain. These functions are actually called from the c-runtimes real entry point. Here are the prototypes and real names of an applications entry point:

EXTERN_C int WINAPI mainCRTStartup();    EXTERN_C int WINAPI WinMainCRTStartup();    EXTERN_C BOOL WINAPI _DllMainCRTStartup(    HINSTANCE hInstDll,         // handle to the DLL module    DWORD fdwReason,            // reason for calling function    LPVOID lpvReserved,         // reserved  );  

Application Termination

Normally, when the code path leaves the main( or WinMain() functions, the application exits. This is because the default implementation of the above functions calls ExitProcess. If you do not call ExitProcess then your application will not close untill all threads have exited cleanly.

Example Implementation

As a debugging aid it is usefull to implement the entrypoint function in a manner similar to the c-runtimes.

EXTERN_C int WINAPI WinMainCRTStartup()  {    HINSTANCE hInstance = GetModuleHandle(NULL);    LPSTR lpszCmdLine = GetCommandLine();    int r = WinMain(hInstance,NULL,lpszCmdLine,SW_SHOWDEFAULT);    ExitProcess(r);    return r; // this will never be reached.  }    


 


Compiler Switches

The following table describes the compiler switches that should be set to ensure successful compilation using MSVC++ 6

Switch Action Description
/GX delete This switch enables C++ exception handling which requires a number of functions related to unwinding the stack.
/GZ delete This switch enables some advanced debugging features. With these features enabled the linker will look for a function called _chkstk.
/Oi add Add this switch to ensure that intrinsic functions are enabled.
/Zl add Usually the compiler embeds a "defaultlib" refrence to the c-runtime in the .obj file. This switch (do not confuse with the /ZI switch) ensures that defaultlib entries are not written to the generated OBJs.



Linker Switches

The following switches are optional if the compiler is set correctly. However, if just one badly compiled obj file is in the project then the c-runtimes standard entry point may be invoked. If you suspect this is the case you might want to set one, or both of these switches.

Switch Action Description
/nodefaultlib add This switch is not really necessary if you compile with /Zl, as there should be no default libraries to ignore. If however you use a 3rd party library, or any old obj files that do include a defaultlib entry, then the linker will silently ignore your custom entry point, unless you use the following switch
/entry:function add Use this if you wish to use a non-standard name for your entry point. This is a good idea if you are linking to a 3rd party library or object code that contains defaultlib directives, as the linker, if given half a chance, will use the runtime libraries entry point if it can find it.
/opt:nowin98 add The MSVC 6 linker defaults to a 4Kb section padding in PE files as an optimizaton to speed load times on Windows 98. Very small projects will benefit with a file size saving of about 16Kb.


More MSVC 6 Linker settings

Microsofts linkers prior to 6.00 produced PE iamges with file level section alignments of 512 bytes. Link 6.00 aligns sections in a file on 4Kb boundries to optimise loading of the image under 98. For compatability reasons 98 must load files with the old alignment (but will do so with a performance hit), and, if you are targetting NT you can use the old 512 byte padding without any performance deficit at all. The linker switch you must add to the link line is: (the second line details how the command might be embedded as a linker option in a .C file.

// linker options can be embedded directly in .cpp code thus:  #if defined(_MSC_VER) && _MSC_VER >= 1200  #pragma comment(linker, "/OPT:NOWIN98" )  #endif  


 

  评论这张
 
阅读(687)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017