2

私は現在、.cファイルを入力として受け取り、アセンブリコード(X86、AT&T構文)を生成する単純なCコンパイラーを作成しています。配列型のパラメーターを渡して、その正しいアセンブリコードを生成するのに苦労しています。これが私の入力です:

int getIndexOne(int tab[]){
  return tab[1];
}

int main_test(void){
  int t[3];
  t[0] = 0;
  t[1] = 1;
  t[2] = 2;
  return getIndexOne(t);
}

かなり簡単なテスト。これが私の出力です:

getIndexOne:
.LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 16
    movl    %esp, %ebp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movl    %edi, -24(%ebp)
    movl    $1, %eax
    movl    -24(%ebp, %eax, 8), %eax    #trouble over here
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size getIndexOne, .-getIndexOne


falsemain:
.LFB1:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 16
    movl    %esp, %ebp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    pushl   %ebx
    subl    $120, %esp
    movl    $2, -32(%ebp)
    movl    $0, %eax
    movl    $0, -24(%ebp, %eax, 8)
    movl    $1, %eax
    movl    $1, -24(%ebp, %eax, 8)
    movl    $2, %eax
    movl    $2, -24(%ebp, %eax, 8)
    leal    -24(%ebp, %eax, 8), %eax
    movl    %eax, %edi
    call    getIndexOne
    addl    $120, %esp
    popl    %ebx
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size main_test, .-main_test

渡されたアドレスの内容にアクセスできません(リール命令)。どんな助けでも大歓迎です。PS:私のintのサイズは気にしないでください。他の理由で、4バイトではなく8バイトに設定されています。

4

1 に答える 1

2

2つの問題があります。1つは、呼び出し用のスタックをセットアップするときですgetIndexOne

movl    $2, %eax
movl    $2, -24(%ebp, %eax, 8)
leal    -24(%ebp, %eax, 8), %eax   ##<== EAX still holds value of 2!
movl    %eax, %edi                 ##<== wrong address for start of array

EAXコマンドの後でレジスタの内容をクリアしていないため、関数呼び出しのためにレジスタMOVに入力しているアドレスEDIは、配列の先頭ではなく、配列の最後の要素(つまり、2番目の要素)を指しています。の要素値を持つインデックス2

2番目の問題は、getIndexOne関数で発生します。

movl    %edi, -24(%ebp)
movl    $1, %eax
movl    -24(%ebp, %eax, 8), %eax

アドレスをスタックに保存しました。これは問題ありませんが、スタックから値を取得すると、ポインターが返され、2回目に逆参照する必要があることも意味します。現在行っているのは、スタック上のフレームポインタからオフセットされた値を読み戻すだけです...スタックに格納したポインタを逆参照していないため、配列内の値ではありません。言い換えると、ポインタをスタックに格納する必要がある場合は、次のように変更する必要があります(値はすでに存在するため、これは最も効率的な方法ではないと思いますがEDI、何でも):

movl    %edi, -24(%ebp)           ##<== store pointer to the array on the stack
movl    $1, %eax
movl    -24(%ebp), %ecx           ##<== get the pointer back from the stack
movl    (%ecx, %eax, 8), %eax     ##<== dereference the pointer

ちなみに、コンパイラがどのように機能するかはわかりませんが、配列要素にロードしている値を使用して配列にインデックスを付けるのは少し怖いと思います...値がロードされた配列インデックスと一致しない、それはかなりの大混乱を引き起こすでしょう...これはあなたが試みているある種の最適化だと思います-2つの値が一致したときに実行しますか?

于 2012-05-17T15:00:08.547 に答える