The Old New Thing
Practical development throughout the evolution of Windows.
Latest posts

Understanding errors in classical linking: The delay-load catch-22

Wrapping up our week of understanding the classical model for linking, we'll put together all the little pieces we've learned this week to puzzle out a linker problem: The delay-load catch-22. You do some code cleanup, then rebuild your project, and you get LNK4199: /DELAYLOAD:SHLWAPI ignored; no imports found from SHLWAPI What does this error mean? It means that you passed a DLL via the /DELAYLOAD command line switch which your program doesn't actually use, so the linker is saying, "Um, you said to treat this DLL special, but I don't see that DLL." "Oh, right," you say to yourself. "I got rid of a c...

Understanding the classical model for linking: Sometimes you don’t want a symbol to come along for a ride

Continuing our study of the classical model for linking, let's take another look at the trick of taking symbols along for the ride. The technique of taking symbols along for the ride is quite handy if that's what you want, but sometimes you don't actually want it. For example, a symbol taken along for the ride may create conflicts or create unwanted dependencies. Here's an example: Suppose you have a library called stuff.lib where you put functions that are used by various modules in different projects. One of the files in your library might look like this: // filedatestuff.cpp BOOL GetFileCreationTimeW(...

The enduring cultural fascination with Queen’s Bohemian Rhapsody

Bohemian Rhapsody was not part of my world growing up, so I view the continuing cultural fascination with the piece with detached confusion. The hallmark of cultural preoccupation is the fact that the Wikipedia entry deconstructs the piece moment by moment, clocking in at over 2000 words, far in excess of the Wikipedia recommendation of a 60-word summary for a 6-minute piece (10 words per minute). And longer than the entire Wikipedia page for Ruth Bader Ginsburg.

Understanding the classical model for linking: You can override an LIB with another LIB, and a LIB with an OBJ, but you can’t override an OBJ

If you study the classical model for linking, you'll see that OBJ files provided directly to the linker have a special property: They are added to the module even if nobody requests a symbol from them. OBJs bundled into a library are pulled into the module only if they are needed to resolve a needed symbol request. If nobody needs a symbol in the OBJ, then the OBJ doesn't get added to the module. On the other hand, OBJs handed directly to the linker get added to the module whether anybody wants them or not. Last time, we learned about the along for the ride technique which lets you pull components into a modu...

Understanding the classical model for linking: Taking symbols along for the ride

Last time, we learned the basics of the classical model for linking. Today, we'll look at the historical background for that model, and how the model is exploited by libraries. In the classical model, compilers and assemblers consume source code and spit out an OBJ file. They do as much as they can, but eventually they get stuck because they don't have the entire module at their disposal. To record the work remaining to be done, the OBJ file contains various sections: a data section, a code section (historically and confusingly called text), an uninitialized data section, and so on. The linker resolves symbol...

Understanding the classical model for linking, groundwork: The algorithm

The classical model for linking goes like this: Each OBJ file contains two lists of symbols. Provided symbols: These are symbols the OBJ contains definitions for. Needed symbols: These are symbols the OBJ would like the definitions for. (The official terms for these are exported and imported, but I will use provided and needed to avoid confusion with the concepts of exported and imported functions in DLLs, and because provided and needed more clearly captures what the two lists are for.) Naturally, there is other bookkeeping information in there. For example, for provided symbols, not only is the...

What’s the guidance on when to use rundll32? Easy: Don’t use it

Occasionally, a customer will ask, "What is Rundll32.exe and when should I use it instead of just writing a standalone exe?" The guidance is very simple: Don't use rundll32. Just write your standalone exe. Rundll32 is a leftover from Windows 95, and it has been deprecated since at least Windows Vista because it violates a lot of modern engineering guidelines. If you run something via Rundll32, then you lose the ability to tailor the execution environment to the thing you're running. Instead, the environment is set up for whatever Rundll32 requests. You get the idea. Note also that Rundll32 ass...

Why does my program run really slow or even crash (or stop crashing, or crash differently) if running under a debugger?

More than once, a customer has noticed that running the exact same program under the debugger rather than standalone causes it to change behavior. And not just in the "oh, the timing of various operations changed to hit different race conditions" but in much more fundamental ways like "my program runs really slow" or "my program crashes in a totally different location" or (even more frustrating) "my bug goes away". What's going on? I'm not even switching between the retail and debug versions of my program, so I'm not a victim of changing program semantics in the debug build. When a program is running under ...

A few stray notes on Windows patching and hot patching

Miscellaneous notes, largely unorganized.