Saturday, November 05, 2005
Rebase all your library assemblies
Back in the good old Win32 days it was considered a best practice to rebase all your DLLs. Every executable and DLL has a preferred base address. This base address is the memory address in the process address space where the module is loaded. When you create a native DLL with Visual C++, the default base address is set to 0x10000000 (0x00400000 for an executable). I guess that half of all the DLLs in the world are set for this default base address. When two DLLs with the same base address are loaded into the process address space, the first DLL loads at the preferred base address while the second DLL needs to be relocated. This operation is automatically performed by the PE loader of the Windows operating system. However, relocation of DLLs is a very expensive operation. The image of the DLL needs to be placed in memory and every entry in the relocations table must be transformed to reflect the new address range. Needless to say that rebasing all your DLLs greatly improves the startup time of your native applications. Have you ever had a customer on the phone, claiming that your aplication has crashed? Often the only information he or she can give you is a crash address. When you have properly rebased all your DLLs, it is very easy to determine the DLL that caused the crash. When you do not rebase the DLLs in your native applications, it is nearly impossible to determine wich DLL occupied the address space where the crash occured, due to the relocation mechanism. There are two methods to rebase a native DLL. The first method is to use the REBASE.EXE utility that comes with the Win32 SDK. The second method is to modify the preferred base address manually using either the project settings in Visual Studio or the /BASE switch of LINK.EXE. Th following table is the base address relocation scheme that I always use. The first letter of the DLL must match with a letter in the table. The key is to set the load address far enough apart so that you never have to worry about overlapping previously loaded DLLs. A–C 0x60000000 D–F 0x61000000 G–I 0x62000000 J–L 0x63000000 M–O 0x64000000 P–R 0x65000000 S–U 0x66000000 V–X 0x67000000 Y–Z 0x68000000 More information about this topic can be found in this ten year old article. It's an evergreen :-). Managed library assemblies do not contain any native executable code. Therefore you can think that rebasing managed DLLs is completely unnecessary. I strongly believe that it is still a best practice to rebase all your managed DLLs. Although you don't get this tremendous performance gain as with native DLLs, you avoid relocation when you use the NGEN utility on your assemblies. Note that executables do not need to be rebased because there are always loaded first. You cannot use the REBASE.EXE utility on managed modules because afterwards the CLR will not load your assemblies anymore. The only option you have is to manually specify the base address using the project settings in Visual Studio or the /BASEADDRESS compiler switch (VB and C#). The dialog below shows you how to set the base address of a class library created with Visual Studio 2005 (note that the default base address for managed assemblies is 0x40000000).