Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the conditional move doesn't work properly

Tags:

assembly

After I compiling the codes below, the function doesn't seem to work as expected.

int cread(int *xp){

     return (xp?*xp:0);

}

I extract the counterpart in the assembly version as below.

xp in register %edx

movl $0, %eax
testl  %edx, %edx
cmovne (%edx), %eax

Could anyone tell me why the pointer xp still got de-referenced by the cmovne even when the test fails? isn't the ZF set to 1 by testl instruction when %edx is 0?

like image 531
JDein Avatar asked Oct 21 '22 06:10

JDein


1 Answers

The Intel instruction-set manuals seem to indicate that the CMOV operand isn't read if the condition isn't satisfied. (I suspect the "algorithm" for the instruction given in the manual, isn't quite right.)

Apparently, other people disagree; see explicit caveat here:

If the source operand is a memory operand, then it is always read, regardless of whether or not the condition is met. This means that whatever exception would have been generated from the memory read, will get generated. If the memory read would have caused a #GP or #PG, then so be it.

I suspect the reasoning is this: the instruction decoder reads instructions, computes effective addresses, and issues memory reads as early as possible, well before the instruction is fully decoded and ready for execution. So, the read to memory gets scheduled/executed early and causes a trap. It isn't until the CMOV is actually reached by the execution unit that it knows the memory read isn't needed, and starting it that late would make the instruction really slow, as well as complicate the instruction pre-fetch logic.

I only use it in its register-register form, which can't trap.

like image 158
Ira Baxter Avatar answered Dec 15 '22 00:12

Ira Baxter