2

我目前正在编写一个简单的 C 编译器,它将 .c 文件作为输入并生成汇编代码(X86、AT&T 语法)。我很难传递数组类型参数并为其生成正确的汇编代码。这是我的输入:

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

我无法访问传递地址的内容(leal 指令)。任何帮助将非常感激。PS:不要担心我的整数的大小,由于其他原因,它们被设置为 8 而不是 4 字节。

4

1 回答 1

2

有两个问题,第一个是当您为调用设置堆栈时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) 的索引。

第二个问题出现在您的getIndexOne函数中:

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

您已将地址存储在堆栈中。这很好,但这也意味着当您从堆栈中检索值时,您将获得一个指针,然后必须再次取消引用该指针。您现在正在做的只是从堆栈上的帧指针读回一个值偏移量......这不是数组中的值,因为您没有取消引用存储在堆栈中的指针。换句话说,如果必须将指针存储在堆栈上,则应将其更改为以下内容(我认为这不是最有效的方法,因为值已经在 中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

附带说明一下,虽然我不确定您的编译器是如何工作的,但我确实认为您使用加载到数组元素中的值来索引数组有点可怕......如果值是加载的与数组索引不匹配,这会造成相当多的破坏……我猜这是你在两个值匹配时尝试做的某种优化?

于 2012-05-17T15:00:08.547 回答