Anders Lassen
Anders Lassen

Reputation: 659

x86-64 Assembly to C

I tried translating this into C, but I'm stuck at the displacement of the memory address (%rdi):

program:
  movq  (%rdi), %rax
  testq %rax, %rax
  je L1
  addq  $8, %rdi
  movq  %rax, %rdx
L3:
  cmpq  %rdx, %rax
  cmovl %rdx, %rax
  addq  $8, %rdi
  movq  -8(%rdi), %rdx
  testq %rdx, %rdx
  jne L3
L1:
  ret

I've come up with following so far:

int func(int *x){
    int ret = *x;
    if(ret != 0){
        x+=8; //is this true?
        y = ret;
        while(y!=0){
            if(ret<y){
                ret = y;
            }
            y=?? //What should this say?
        }
    }
    return ret;

Possible solution (waiting for someone to confirm):

int func(int *x){
  int ret = *x;
  if(ret!=0){
    ++x;
    int y = ret;
    while(y != 0){
      if(ret < y){
        ret = y;
      }
      ++x;
      y = x[-1];
    }
  }
  return ret;
}

Upvotes: 0

Views: 904

Answers (1)

Ped7g
Ped7g

Reputation: 16626

   x+=8; //is this true?

No. x is int *, and on your current target platform int is 64 bit wide, which is 8 bytes. In assembly you have raw pointer to bytes, as memory is addressable by bytes, so the add rdi,8 is in C like x = (int*)(((int8_t*)x)+8); which can be shortened to ++x;

And if movq (%rdi), %rdx is rdx = x[0]; // or " = *x;", then movq -8(%rdi), %rdx is rdx = x[-1];

The remaining C part looks unfinished.

Warning, spoiler is following!

it will search through the x array until zero value is found (terminator), and keep updating ret with smallest value found.

And it looks like my spoiler was wrong, the compare is probably the other way. Just to make sure, run both original asm in debugger, and your C, to see if they do the same thing. Also watching assembly in debugger single-stepping over instructions, checking how values in registers evolve, is often lot more descriptive and visual, than any long discussion. :) Sorry for not being sure, but the AT&T syntax is driving me nuts.

BTW, my "C" translation would look probably like this (let's say the asm is searching for "max" value in array, not "min" (I'm still only ~90% sure)):

int64_t func(int64_t *x) {
    if (0 == *x) return 0;
    int64_t ret = *x;
    do {
        if (ret < *x) ret = *x;
        ++x;
    } while (0 != *x);
    return ret;
}

Which gets translated by gcc v7.2 as (I had to change the int to int64_t to have 64b int):

func(long*):
  movq (%rdi), %rax
  testq %rax, %rax
  je .L1
  movq %rax, %rdx
.L3:
  cmpq %rdx, %rax
  cmovl %rdx, %rax
  addq $8, %rdi
  movq (%rdi), %rdx
  testq %rdx, %rdx
  jne .L3
.L1:
  rep ret

Which is almost identical to original assembly.

Upvotes: 2

Related Questions