1

私は本 Computer Systems: A Programmer's Perspective (2nd Edition) と Practice Problem 3.23 を読んでいて、少し混乱しています:

関数 fun_b の全体的な構造は次のとおりです。

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

gcc C コンパイラは、次のアセンブリ コードを生成します。

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

このコードの操作をリバース エンジニアリングしてから、次の操作を行います。

A. アセンブリ コード バージョンを使用して、C コードの欠落部分を埋めます。

私の解決策。

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;
}

本の解決策。

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;
}

leal 関数がこの関数で非典型的な動作をする理由を説明してください。そして、このアセンブリコードがこのステートメントを生成する方法を理解していませんval = (val << 1) | (x & 0x1)

4

2 に答える 2

0

× >>= 1; x に 2 を掛けることを意味し、バイナリでは左にシフトするか、右側に 0 を追加します

x >>= 1; == x * 2; == x +=x;
于 2016-01-18T16:45:00.747 に答える
0

あなたのコードで:

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

ここで、val += valwhich は と等価で(val*2)あり、実質的にval左にシフトされた と等しくなり1ます。

しかし、アセンブリコードが次のようなものである場合にのみ、あなたのソリューションは正しいと思います:

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

ifval + valは別のステートメントであるため、コンパイラは通常、edx ではなく eax レジスタに配置します (これが常に当てはまるかどうかはわかりません)。したがって、指定したコードの場合、可能な解決策は次のとおりです。

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

また

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

また

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

于 2013-05-21T04:27:20.097 に答える