Holy cow, I wrote a book!
Yes, I'm talking about Christmas gifts (or "winter solstice gifts"
if you prefer) in July.
I'm one of those people for whom buying Christmas gifts is a brain-wracking
ordeal, and I'm always on the lookout all year round for the "perfect gift".
Last Christmas, a friend of mine gave me
a micro-fiber lens-cleaning cloth
that comes in a pouch you can attach to a keychain.
(I have no affiliation with those two sites;
I just hunted around looking for a picture.)
Best gift ever.
I use it several times a day.
My keychain has only four things on it:
The aforementioned cleaning cloth,
a USB thumb drive,
my car key, and my house key.
And I could do without the thumb drive and car key most days.
But don't take away my cleaning cloth.
Some people have inferred that I don't write about .NET because
I don't like it.
That's not true.
I use it myself.
The reason I don't write about .NET is because
I'm not an expert on it and there are
plenty of other .NET blogs out there,
written by people who are
Maoni Stephens, whose little finger
contains more knowledge about garbage collection
than most people have in their entire brain.)
No point adding to it with my non-expert view.
Indeed, when I hit upon an interesting .NET topic or puzzle,
I usually just forward it off to
Brad for him to put on his blog.
Because people looking for interesting .NET content go to Brad,
The fact that
Rico Mariani was able to
do a literal translation of the original C++ version into C# and blow
the socks off it is a testament to the power and performance of
It took me several days of painful optimization to catch up,
one optimization that introduced a bug,
and then Rico simply had to
do a little tweaking with one hand tied behind his back
to regain the lead.
I eventually won
but look at the cost of that victory.
(I'm told there's one company that has decided against using managed
code because "If Raymond doesn't even want to mention the .NET Framework
then why should we bother to look at it?"
What a strange argument.
I don't mention IPsec;
does that mean you shouldn't use it either?)
But just to dispel the rumor (and to buck both my title and my tag line),
I'm going to declare this week to be .NET week.
All my technical articles this week will be about .NET.
Enjoy it while you can.
Murphy's Law vindicated again.
The Seattle Monorail has two trains, and last year
they managed to collide.
To get this to happen was particularly tricky, since the trains
run on separate tracks, and there is only one spot on the entire
line where a collision could occur—and they found it.
You can read about it in
this Associated Press article that describes the monorail as
a "mile-high, 43-year-old elevated line".
Wow, a mile high.
Those must've been really long ladders to get people down.
It was supposed to resume operation a few weeks ago, but
the reopening was delayed due to a glitch in the emergency-braking system.
We can't get anything right around here.
Reader Tom brought up the interesting point that ordinal-based imports
are slightly faster than name-based, though not by much.
But if even that tiny fraction of a percentage bothers you,
you can still get the benefits of ordinal-based imports while still
People are more familiar with the first half of the "rebase and bind"
duo than the second.
But it's binding that speeds up import table resolution.
When a DLL is "bound" to another DLL, information about the target
DLL is cached in the original DLL.
Specifically, the timestamp of the target (so that the loader can
detect whether the cache is valid),
the ordinal corresponding to the name (the "hint"),
and the address of the ultimate function.
For example, if I had a DLL that linked to kernel32!LocalAlloc
the entry in the DLL would go something like this:
I would like to link to these functions in kernel32.
Oh, and by the way, all the hints I'm about to give you are based
on the Aug 04 00:56:36 2004 version of KERNEL32.DLL.
As for the function LocalAlloc,
I believe that the function resides at
and that you'll find it in kernel32's named export table
in position 247."
When the loader goes to resolve the import,
it checks the timestamp of the target file on the computer with the
one cached in the DLL.
If they match, then it doesn't need to do any look-ups at all;
it justs uses the cached value (0x7C8099BD).
If they don't match (for example, maybe there was a kernel32
hot-fix), it can still use the look-up hint:
Before doing the binary search for LocalAlloc,
it looks directly at slot 247 to see if LocalAlloc
If so, then the cost of the binary search has been avoided,
and the overhead of the look-up over a pure ordinal import is
just one string comparison.
And you probably shouldn't
fall asleep in the van you break into.
When I wrote that
the symbolic name for the imported function table entry for
a function is called __imp__FunctionName,
the statement was "true enough" for the discussion at hand,
but the reality is messier, and
the reason for the messy reality is function name decoration.
When a naive compiler generates a reference to a function,
the reference is
decorated in a manner consistent with its architecture, language,
and calling convention.
(Some time ago,
I discussed some of the decorations you'll see on x86 systems.)
For example, a naive call to the GetVersion function
results in the compiler generating code equivalent to
call _GetVersion@0 (on an x86 system; other architectures
The import library therefore must have an entry for the
symbol _GetVersion@0 in order for the external reference
to be resolved.
To correspond to the stub function whose real name is
_GetVersion@0 is the import table entry whose name
In general, the import table entry name is __imp_
prefixed to the decorated function name.
The fact that names in import libraries are decorated means
that it is doubly crucial that you use the official import library
for the DLL you wish to use rather than trying to manufacture
one with an import library generation tool.
As we noted earlier, the tool won't know whether the ordinal
assigned to a named function was by design or merely coincidental.
But what's more, the tool won't know what decorations to apply
to the function (if the name was exported under an undecorated name).
Consequently, your attempts to call the function
will fail to link since the decorations will most likely not match up.
In that parenthetical, I mentioned exporting under undecorated names.
Doesn't that mean that you can also export with a decorated name?
Yes you can, but as I described earlier,
you probably shouldn't.
For as I noted there, if you export a decorated name, then that
name cannot be located via GetProcAddress unless you
also pass the decorated name to GetProcAddress.
But the decoration schema changes from language to language,
from architecture to architecture, and even from compiler vendor
to compiler vendor,
so even if you manage to pass a decorated name to the
GetProcAddress function, you'll have to wrap it
inside a huge number of #ifdefs so you pass the
correct name for the x86 or ia64 or x64, accordingly,
as well as changing the name depending on whether you're using
the Microsoft C compiler, the Borland C compiler, the Watcom
C compiler, or maybe you're using one of the C++ compilers.
And woe unto you if you hope to call the function from Visual Basic
or C# or some other language that provides interop facilities.
Just export those names undecorated.
Your future customers will thank you.
(Exercise: Why is it okay for the C runtime DLLs to use
Hot off the presses.
(with David Beckham, Ronaldo, and other stars)
will play an exhibition match against D. C. United
in Seah^H^H^H^HQuest Field on Wednesday, August 9th.
I wonder if it'll be anything like
the last soccer match I saw.
At least let's hope they're ready to play instead of
having tired themselves out playing video games.
Tickets go on sale today.
Now that we've learned what the dllimport
declaration specifier does, what if you get it wrong?
If you forget to declare a function as dllimport,
then you're basically making the compiler act like a naive compiler
that doesn't understand dllimport.
When the linker goes to resolve the external reference for
the function, it will use the stub from the import library,
and everything will work as before.
You do miss out on the optimization that dllimport
enables, but the code will still run.
You're just running in naive mode.
(There are still some header files in the Platform SDK that
neglect to use the dllimport declaration specifier.
As a result, anybody who uses those header files to import functions
from the corresponding DLL will be operating in "naive mode".
Hopefully the people responsible for those header files will
recognize themselves in this parenthetical and fix the problem for
a future release of the Platform SDK.)
Now, what about the reverse problem?
What if you declare a function as dllimport when it
The linker detects this since it sees an attempt to import a
__imp__FunctionName symbol and can't find one, though it
can find the normal FunctionName symbol.
When this happens, the linker raises
It recovers from this error by simply manufacturing a fake
__imp__FunctionName variable and initializing it with
the address of the FunctionName function.
In effect, you've imported the function from yourself.
Your code now goes through all the gyrations associated with
calling an imported function unnecessarily; it could have just
called FunctionName directly.
(There are cases where the linker can be a little smarter.
if it sees a call [__imp__FunctionName], it can change
it to call FunctionName + nop.
The nop is necessary because the
call [__imp__FunctionName] instruction is six bytes
long, whereas call FunctionName is only five.
The extra nop gets everything back in sync.)
call FunctionName + nop
Thus, in both cases where you mess up the dllimport
declaration specifier, the linker manages to recover from your mistake,
and your program does run fine, though the patching up did cost you
in code size and efficiency.
(All this discussion is for x86, by the way.
Other architectures have different quirks.)
Next time, more on import libraries, and exposing some "little
white lies" I've been telling.
While it may be true that
if you know Swedish, the world is funnier,
I have to admit that my knowledge of German only served to create
When I saw the headline that
the head of BetonSports was arrested,
I thought to myself,
"Who the heck would have a web site devoted to sports in concrete?"
the German word
Beton means "concrete" (the construction material)
and the German word
Sport means the same as in English.
It took me a few moments to realize that the company's
name is "Bet on Sports".