0

What does the following do?

testq   %rdx, %rdx
cmovg   %rcx, %rax

I understand that testq is a bitwise and between two registers, but how does it works with the flags? What would this translate into in c? e.g. if %rdx would hold value 0x01, then we'd have 0x01 & 0x01 = 0x01, which would set

ZF = 0, SF = 0, OF = 0.

And for what I could find cmovg is performed if

˜(SF ˆ OF) & ˜ZF

which would resolve to

˜(0 ˆ 0) & ˜0 = ˜(0) & ˜0 = 1 & 1 = 1.

Would this mean that cmovg would be performed and that the corresponding c code would behave for d = %rdx, a = rax and c = rcx:

 if(d > 0){
   a = c;
 }

Or can someone maybe explain this in other words?

Additionally, i've been trying to work this assembly turning it into a corresponding c code. Currently i get a result that ends up like an infinite while loop on the testq %rdx, %rdx with jne .L4. With the content above enclosed. Anyone know what the right solution is? My current solution is this:

p:
        movq    (%rdi), %rdx
        testq   %rdx, %rdx
        je      .L5
        movl    $0, %eax
.L4:
        leaq    (%rax,%rdx), %rcx
        testq   %rdx, %rdx
        cmovg   %rcx, %rax
        addq    $8, %rdi
        movq    (%rdi), %rdx
        testq   %rdx, %rdx
        jne     .L4
        ret
.L5:
        movl    $0, %eax
        ret

Solution (wrong):

#include<stdlib.h>
#include <stdio.h>


int func(int *rdi){
  int rdx = *rdi;
  if(rdx == 0){
    int rax = 0;
    return rax;
  }
  int rax = 0;
    do {
    int rcx = rax + rdx;
    if(rdx > 0){
      rax = rcx;
    }
    rdi += 8;
    rdx = *rdi;
  } while(rdx != 0);

  return rax;

}

  int main(int argc, char const *argv[]) {
    int var = 20;
    int *ip;
    ip = &var;
    func(ip);
  }
Peter
  • 21
  • 1
  • 2
  • 7
  • 1
    Yes, that looks correct. – Jester Oct 04 '17 at 17:14
  • @Jester alright, thanks. I was really in doubt >. – Peter Oct 04 '17 at 17:18
  • 3
    In general, it can be useful to remember that `test %rdx, %rdx` is equivalent to `cmp 0, %rdx` (in backwards AT&T syntax), so if you see a "g" condition code you can easily realize that it means "if *g*reater than *zero*" (where "greater" means `>` for signed values, as opposed to "above" which means `>` for unsigned values). – Matteo Italia Oct 04 '17 at 17:37
  • 1
    @MatteoItalia Ah! thats a really great rule to remember. That'll help. Thanks :) – Peter Oct 04 '17 at 17:39
  • @MatteoItalia i added some additional code that is the whole translation of an assembly program to c. Im pretty sure i messed something up. Got any idea where i went wrong? – Peter Oct 04 '17 at 17:41
  • 1
    Brush up what the parenthesis mean in the AT&T syntax and the solution will become clear ;) – Margaret Bloom Oct 04 '17 at 17:51
  • @AnttiHaapala Apart for AF, every other flag is set the same AFAIK. OF and CF are clear since x-0 never overflows. SF is set to the MSB of x since x-0 = x, same for ZF, and PF is set to XORNOT8(x-0) = XORNOT8(x). Considering that x AND x = x, these are the same results of `test`. Unless I overlooked something, I'm a bit burned-out right now :) – Margaret Bloom Oct 04 '17 at 18:44
  • @MargaretBloom so something like this? (EDITED Solution). – Peter Oct 04 '17 at 18:46
  • 1
    @MargaretBloom: Yes, `test %rdx,%rdx` sets flags identically to `cmp $0, %rdx` (apart from AF). See https://stackoverflow.com/questions/147173/testl-eax-against-eax/38032818#38032818 for reasoning / proof. – Peter Cordes Oct 04 '17 at 18:50
  • 2
    @Peter: So what is this question currently asking? It seems to have morphed into a debug-my-code question without a [mcve]. Single-step your code in gdb or whatever debugger you prefer, and watch registers change (including FLAGS). See the bottom of https://stackoverflow.com/tags/x86/info for gdb tips. If you're stuck on something you don't understand in the debugger, then put that in the question. – Peter Cordes Oct 04 '17 at 18:51
  • @PeterCordes Just an exercise i was doing, i couldnt really make it work - so i asked for some help. On my solution based on the assembly. – Peter Oct 04 '17 at 18:54
  • 3
    Yeah, but now there are at least 2 separate questions in one post. See [ask]; this is not how we like our questions here at SO. If you have an answer for your own question, post it as an *answer*. (Answering your own question is encouraged if you have a good answer.) – Peter Cordes Oct 04 '17 at 18:56
  • I expanded a bit the comment in an answer, which could be the answer to the "original" question. The rest should probably be put in a separated question. – Matteo Italia Oct 04 '17 at 20:42

1 Answers1

7

(moving from the comment, replying to the original question)

if(d > 0){
    a = c;
}

Yes, it's correct. Below I'll try to show how to "decode" this pattern quickly, without having to calculate all the times the flag register values.

Notice: Intel syntax ahead, as it's way clearer for the operands order in comparisons; AT&T is similar but with the operands reversed (and more strange characters spread around).

The "numeric comparison" condition codes are best understood in the context of a "classic" sequence

cmp a, b
jCC label

The CC (condition code) part here refers to the "operator" (as in, >,<, ==) that you are putting in the compare between a and b; so:

  • jg → "jump if a is greater than b";
  • jl → "jump if a is less than b";
  • je → "jump if a is equal to b";
  • jne → "jump if a is not equal to b";
  • ja → "jump if a is above b";
  • jb → "jump if a is below b";
  • ... all the "e" variants (jbe, jae, ...)

(the above/below couple differs from the greater/less couple in that a/b are for comparison between unsigned values, g/l for signed values; also, there are a lot of synonyms, in particular je is a synonymous for jz AKA "jump if zero", and jne for jnz AKA "jump if not zero"; disassemblers may produce jz or je, it's the same)

Now, coming to your case:

  • test reg,reg is perfectly equivalent to cmp reg,0 (apart from the status of AF, which is irrelevant); this is easily understood:
    • test performs an and between the operands and sets the flags according to the result; so, test reg,reg just sets the flags according to reg (anding a number with itself is a nop);
    • cmp b,a calculates b-a and sets the flags according to the result; given that b-0 == b, cmp b,0 just sets the flags according to b, exactly as test b,b.
  • the cmovg is an instance of the cmovCC instruction, with condition code g, i.e. "move if greater".

So, your

test rdx,rdx
cmovg rax,rcx

is equivalent to

cmp rdx,0
cmovg rax,rcx

which plainly reads as "compare rdx with zero, if it's greater move rcx in rax".

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299