我目前正在编写一个简单的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个字节。
答案 0 :(得分: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
作为旁注,虽然我不确定你的编译器是如何工作的,但我确实认为你使用加载到数组元素中的值来索引数组有点可怕......如果正在加载的值与数组索引不匹配,这会产生相当多的havok ......我猜这是两种值匹配时你试图做的某种类型的优化?