July, 2006

  • The Old New Thing

    Christmas gift idea for your favorite glasses-wearing geek


    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. Example 1. Example 2. (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.

  • The Old New Thing

    Just because I don't write about .NET doesn't mean that I don't like it


    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 actual experts. (Such as 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, not me.

    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 managed code. It took me several days of painful optimization to catch up, including 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. Sure, 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.

  • The Old New Thing

    The Seattle Monorail has two trains, and they collided


    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.

  • The Old New Thing

    The efficiency of ordinal-based imports while still being name-based


    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 being name-based.

    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:

    "Hello. 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 address 0x7C8099BD, 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 is there. 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.

  • The Old New Thing

    Handy tip: If you're going to break into vehicles, the police vehicle service center is probably a bad place


    And you probably shouldn't fall asleep in the van you break into.

  • The Old New Thing

    Index to the series on DLL imports and exports


  • The Old New Thing

    Names in the import library are decorated for a reason


    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 decorate differently). 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 is __imp__GetVersion@0. 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 decorated exports?)

  • The Old New Thing

    Real Madrid (i.e., proper football) comes to Seattle


    Hot off the presses. Real Madrid (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.

  • The Old New Thing

    What happens when you get dllimport wrong?


    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 really isn't? 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 warning LNK4217. 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. For example, 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.)

    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.

  • The Old New Thing

    If you know German, the world is, well, slightly more confusing


    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 momentary confusion.

    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?" That's because the German word Beton means "concrete" (the construction material) in English, 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".

Page 1 of 4 (39 items) 1234