INF: Considerations for Programming DATA NONE DLLs

ID Number: Q77365

3.00

WINDOWS

Summary:

The Windows Software Development Kit (SDK) documentation regarding

dynamic-link libraries (DLLs) is not very detailed with regard to some

facets of developing DLLs. In this article, some of the lesser known

considerations for developing DLLs are discussed.

More Information:

The primary reason for using a DATA NONE DLL is to ensure that DS ==

SS. Many of the functions provided with the Microsoft C run-time

libraries expect that DS == SS. Functions with this property have been

removed from the Windows SDK DLL libraries. In DATA SINGLE DLLs, the

DLL will use the application's SS, but the DLL will have its own DS.

DS is then not equal to SS and the C run-time functions (or other

functions expecting DS == SS) may not be used. In DATA NONE DLLs,

however, the DLL uses the application's DS and SS. In applications, DS

== SS; therefore, for a DATA NONE DLL, DS == SS.

While this may sound like a straightforward process, there are some

items declared within a DLL that can create a data segment. Windows

looks at a flag to determine if the DLL has a data segment. If DATA

NONE has been declared, Windows will treat that DLL as a DATA NONE DLL

whether a data segment exists or not. However, the Windows loader uses

information from the linker to determine what segments to load, not

how the flags are set. Therefore, data segments that do exist are

loaded into memory.

When additional data segments are created, because the compiler works

under the assumption that DS == SS, the data segments that are loaded

are not used and waste memory.

When a DATA NONE DLL does have a data segment, Windows will use the

application's DS as it should, but the offset into the data segment is

the offset into the DLL's data segment. Writing to any variable

declared in the DLL will overwrite data in the application's data

segment.

This type of bug is often difficult to track down. When the data

segment is built for the DLL, items are placed in the data segment

from bottom to top. So an integer variable will take up 2 bytes on the

bottom of the DLL's data segment. Writing to this variable will

overwrite 2 bytes at the bottom of the calling application's data

segment. An application's data segment normally contains thousands of

bytes; therefore, this type of error may go unnoticed and will not

cause a GP-fault.

Global variables, static variables, and static text (string literals

such as "Hello") declared in the DLL will create new data segments for

the DATA NONE DLL.

The warning message "RC: Warning RW4002: Non-discardable Segment 2 set

to PRELOAD" is quite common when DLLs are processed by the Resource

Compiler. However, it is not immediately obvious from the text of the

message why this is a problem. This warning is generated when a data

segment has been created but flags have not been defined for that

segment (such as NONE, PRELOAD, or SINGLE). The default setting for

these segments is PRELOAD SINGLE.

After ruling out all the obvious ways that a new data segment can be

created, it is time to look deeper into the heart of the code.

If the DLL uses the Microsoft C run-time code, a global internal

variable is used by the library. This variable is referenced in

LIBENTRY.ASM by the following code:

extern __acrtused:abs

The __acrtused variable informs the linker that the C run-time code

will be used in the DLL. If the C run-time code is not used in the

DLL, this variable may be removed to create a true DATA NONE DLL. This

is done by replacing the C run-time libraries (SDLLCEW, MDLLCEW, and

LDLLCEW) with the appropriate libraries without the C run-time code

(SNOCRTD, MNOCRTD, and LNOCRTD, respectively). Along with these

libraries, the /NOE option must also be used.

If the C run-time is used by the DLL, this variable must be declared

and using the DATA SINGLE declaration is encouraged. Declaring

__acrtused creates a data segment. However, the warning that occurs

when this is done in a DATA NONE DLL may often be ignored.

DATA SINGLE is also encouraged when the DLL contains literal strings.