On my way into work I decided I would create a repository for various code bits that I had worked on over the years. Nothing proprietary of course, just general functions that have proved useful. Among them was a small helper library that I wrote in MASM32 to help workaround the lack of unsigned integers and longs in VB6.

I had a roughly-done sample application that I had used to remind me of the calling conventions. It thought, ok, I will just polish this up a little bit before publishing it. Unfortunately it wasn’t as simple as that. The final function I had added to that DLL was suddenly causing my program to crash. Yet I know it used to work. As I fiddled with it, even cosmetically, some tests would fail consistently and other succeed. For instance at one point when it was working, I added messagebox before invoking the library, and this change by itself would cause a crash. I recompiled the library and could get it work if the two byte parameters were instead passed in as a single integer. But it would fail if I passed them as two integers. Was this an alignment issue? Isn’t the flat model supposed to take care of that? I was stumped.

Eventually, I came across an old paper titled Writing DLL In Assembler for External Calling in Maple by Dr. Milailovs where he gave me a hint: “In Windows and Linux, registers eax, ecx, and edx can be arbitrarily modified by programs, but other registers including ebx should be preserved…” EBX? Uhh… Stackoverflow agreed.

Here was the original version of the troublesome function:


ParseDword proc inDword:DWORD, inStart:BYTE, inLength:BYTE
    mov eax,inDword    ;initialize register
    or  ebx,0FFFFFFFFh ;initialize mask
    mov cl,inLength    ;get mask size
    shl ebx,cl         ;create invert mask in lower portion of ebx
    not ebx            ;mask now in lower portion of ebx
    mov cl,inStart     ;get desired position of mask
    shl ebx,cl         ;mask of correct size, in correct location
    and eax,ebx        ;apply mask
    shr eax,cl         ;shift result to bit pos 0 for returning
    ret
ParseDword Endp

I definitely was not treating EBX with such reverence here. Could that really be the issue? I’ll humor the idea and use EDX instead:

ParseDword proc inDword:DWORD, inStart:BYTE, inLength:BYTE
    mov eax,inDword    ;initialize register
    or  edx,0FFFFFFFFh ;initialize mask
    mov cl,inLength    ;get mask size
    shl edx,cl         ;create invert mask in lower portion of edx
    not edx            ;mask now in lower portion of edx
    mov cl,inStart     ;get desired position of mask
    shl edx,cl         ;mask of correct size, in correct location
    and eax,edx        ;apply mask
    shr eax,cl         ;shift result to bit pos 0 for returning
    ret
ParseDword Endp

…and it works. Argh. Wow, well I guess it sometimes takes a few hours of debugging to remember something as trivial as that.

Now back to figuring out how I want to layout the repository. (And maybe clean up those code blocks with better formatting.)


Next post: Git via cron

Previous post: Heat wave