NickJohnson wrote:Yep, that was the problem. I didn't know the stack was dword aligned in protected mode... why does that have to be true?
All I can say is RTFM
. Intel Software Developer's Manual (vol 2B, "PUSH") describes the operations of the stack in great detail. The stack is not automatically aligned, you can very well write "PUSH AX" with a 32-bit stack, and ESP will go down by two bytes instead of four.
By messing with the D/B flags of your CS and SS descriptors, and by using the 66h operand prefix, it's possible to push a 16-bit value onto a 32-bit stack and vice versa. Doing so would misalign everything after, which is not desirable (performance and also calling conventions).
As far as C calling conventions go, passing a char, short, or int makes no difference to the stack because anything shorter than 32-bits gets sign extended (or maybe zero extended?). So your original code would work, but only if it were called using assembly code that could write directly to the stack.
In C, however, all parameters are sizeof(int) for the sake of stack consistency (and the fact that the compiler has no way of knowing the types of parameters without C++ name mangling). But the processor couldn't care less what sizes you push and pop, this is a C/C++ issue.