[Home] [Tim] [Tina] [Brynn] [Baby Lesher]

DLL Rebasing and Shared Data Sections

Some time ago on the WinDev mailing list, a question came up: can rebased DLLs really share shared memory segments? The answer was hashed out soon enough by the knowledgeable folks on the list, but, being less knowledgeable about such things, I wrote some test code to prove the answer empirically.

Background

The question is based on three little-known facts about Windows dynamically-linked libraries (DLLs). First, the code for DLLs loaded by two processes is shared at the physical memory level. This means that, while Win32 purports to maintain separate virtual address spaces for processes, it can actually map those addresses to the same chunk of virtual memory, as long as the memory isn't being written to. This is an optimization--if two people read the same newspaper, and neither of them alter the newspaper or write on it, there's no reason they can't share a subscription and save on cost. Similarly, letting two processes look at the same piece of readable DLL memory saves on memory cost.

The second point is that the writeable data in DLLs can be shared by designating a portion of the DLL as a shared section. One of the big differences between Windows 3.1 DLLs and DLLs for Windows 95 or NT is that under Windows 3.1, data "owned" by a DLL is shared by all processes that load that DLL. If one process changes a variable in a DLL, that variable is changed for all DLLs. Win32 dictated that each process has its own address space, so each process gets its own, totally separate copy of writeable DLL data it can party on without affecting other processes. But sometimes you want to have processes access the same changeable data. Win32 lets you mark data sections of any executable (EXE or DLL) as "shared", which means that if that executable is loaded more than once, every instance shares the data.

Finally, DLLs are compiled with "preferred" base addresses. When you compile a DLL, the jumps within the DLL have to point to an absolute memory address. However, a DLL doesn't really know at what address it will be loaded by a process at run time. The Win32 loader tries to load each DLL at its own "preferred" base address, but if two DLLs want to be loaded at the same address, it will relocate the second DLL to a different base address. This means that the loader then has to "fix up" or overwrite all the jump addresses within the code of the DLL. This has two bad effects: it slows down the loading process, and it keeps the code for the DLL from being shared among processes, since the code for the second DLL is no longer identical to the code for the first DLL.

Juxtaposing these three points, can data segments be shared among instances of a DLL even when one instance has been relocated?

The Answer

Luckily for those of us that write and rely on Win32 DLLs, the answer appears to be a resounding "Yes!"

The Code

basetest.zip, 29KB - The source code for the testbed application and test DLLs.
rebase_exe.zip, 117KB - Prebuilt executables from basetest.zip

The source code is a very simple Visual C++ 6.0 workspace that illustrates the principle. The workspace consist of three portions:


To show that rebased DLLs can share data in shared sections, copy all three executables to a directory and launch two instances of the application. In each instance, load DLL 1 first and DLL 2 second--note that the "worker" DLL (DLL 1) is loaded at the same address in both apps. Hit "toggle" in one application and "read" in the other. Repeat until you're satisfied that they are sharing data, then close both instances.

Launch two more instances of the application--this time, load DLL 1 first and DLL 2 second in one instance, but reverse the load order in the second application. Note that the worker DLL is relocated in the second instance of the application. However, by using the "toggle" and "read" buttons again, you can see that the DLLs do indeed share data.

[Home] [Tim] [Tina] [Brynn] [Baby Lesher]