In almost all assembly books you’ll find some nice tricks to do fast multiplications. E.g. instead of “imul eax, ebx, 3″ you can do “lea eax, [ebx+ebx*2]“Â (ignoring flag effects). It’s pretty clear how this works. But how can we speed up, say, a division by 3? This is quite important since division is still a really slow operation. If you never thought or heart about this problem before, get pen and paper and try a little bit. It’s an interesting problem.
Archive for August, 2006
Most of the x86 instructions will automatically alter the flags depending on the result. Sometimes this is rather frustrating because you actually what to preserve the flags as long as possible, and sometimes you miss a “mov eax, ecx” which alters the flags. But at least it’s guaranteed that an instruction either sets the flags or it doesn’t touch them, independent of the actual operation… Or is it?
There is the familiy of shift instructions. A “shl eax, cl” will *only* set the sign/zero flags according to the result if cl != 0 (mod 32). Why would anyone want that? Can someone think of a not so artificial situation, where this is useful? And I’m quite sure it is harder to design a processor which handles this special case correctly (let alone pipeline considerations).
Because of this odd behavior, a compiler has to translate
if (a >> b) this(); else that();
to something like
shr eax, cl
test eax, eax
And BTW, the rotate instructions never alter the SF/ZF flags.
I went to Black Hat over Wednesday and Thursday. The presentation most people wanted to see (including me) was Joanna Rutkowska breaking the Vista x64 driver signing that I hate so much. I wanted to see what trick she’d found. I was let down, however, when she presented her technique.
Her trick was to allocate a bunch of memory so that the kernel pages itself and drivers out, uses raw disk access to overwrite the pagefile, then does an uncommon operation that causes her desired code to execute in kernel mode. Sound familiar? This is the same thing I proposed as a reason why x64 driver signing is pointless when I whined about the real reason for driver signing. I’d already thought of it, so it was nothing new to me, like most of the rest of the conference.
Obviously, Joanna thought of it long before I did, so there is nobody to blame for it. Except, I guess, Microsoft.
It’s time for a puzzle again! (submitted by sheepmaster)
Calculate in x86 assembly language the arithmetic mean (a+b)/2 of two signed integers a and b. If you think this is trivial, consider the following edge cases: a = b = 0x7FFFFFFF and a = 0x7FFFFFFF, b = 0×80000000.
Again, the standard rules apply: a and b are in general purpose registers of your choice, the result can be in any register, and any register can be overwritten.
Oh, and by the way, using larger data types isn’t allowed either (that would make things too easy, wouldn’t it?).