Question

I'm reading a book Computer Systems: A Programmer's Perspective (2nd Edition) and Practice Problem 3.23 are little confused me:

A function fun_b has the following overall structure:

int fun_b(unsigned x) {
   int val = 0;
   int i;
   for ( ____;_____;_____) {
   }
   return val;
}

The gcc C compiler generates the following assembly code:

x at %ebp+8
1 movl 8(%ebp), %ebx
2 movl $0, %eax
3 movl $0, %ecx
.L13:
5 leal (%eax,%eax), %edx
6 movl %ebx, %eax
7 andl $1, %eax
8 orl  %edx, %eax
9 shrl %ebx   Shift right by 1
10 addl $1, %ecx
11 cmpl $32, %ecx
12 jne .L13

Reverse engineer the operation of this code and then do the following:

A. Use the assembly-code version to fill in the missing parts of the C code.

My solution.

int fun_b(unsigned x) {
   int val = 0;
   int i;
   for ( i = 0 ;i < 32;i++) {
      val  += val; //because leal (%eax,%eax), edx  --> %edx = %eax + %eax
      val = val | x & 0x1;
      x >>= 1;
   }
   return val;
}

Book's solution.

int fun_b(unsigned x) {
  int val = 0;
  int i;
  for (i = 0; i < 32; i++) {
    val = (val << 1) | (x & 0x1);
    x >>= 1;
  }
 return val;
}

Please, explain to me why leal function has non typical behavior in this function. And I dont understand how this assembly code is yielding this statement val = (val << 1) | (x & 0x1)

Was it helpful?

Solution

In your code:

val  += val;
val = val | x & 0x1;

Here, val += val which is equivalent to (val*2) which is effectively equal to val left shifted by 1.

But I think your solution is correct only if the assembly code was something like:

x at %ebp+8
1 movl 8(%ebp), %ebx
2 movl $0, %eax
3 movl $0, %ecx
.L13:
5 addl  %eax, %eax
6 movl %ebx, %edx
7 andl $1, %edx
8 orl  %edx, %eax
9 shrl %ebx   # shift right by 1
10 addl $1, %ecx
11 cmpl $32, %ecx
12 jne .L13

Because if val + val was a separate statement, compiler usually places it in eax register rather than in edx (i'm not sure this is the case always). So, for the code you have given, the possible solutions are:

val = (val << 1) | (x & 0x1);

or

val = (val + val) | (x & 0x1);

or

val = (val * 2) | (x & 0x1);

OTHER TIPS

x >>= 1; means multiplying x by 2 which in binary is shifting to the left or adding 0 at the right side

x >>= 1; == x * 2; == x +=x;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top