|
|

楼主 |
发表于 2005-6-4 16:46:12
|
显示全部楼层
Post by herberteuler
呵呵,又是指针和数组的区别。先看一段程序:
- int f(int *s[])
- {
- return *s[0];
- }
- int main(void)
- {
- int n1 = 7, n2 = 8;
- int a[][1] = { 7, 8, };
- int *b[] = { &n1, &n2, };
- f(a);
- f(b);
- return 0;
- }
复制代码
再看它的汇编代码(为了适合阅读已经排版):
- .file "x.c"
- .text
- .globl f
- .type f, @function
- f:
- pushl %ebp
- movl %esp, %ebp
- movl 8(%ebp), %eax
- movl (%eax), %eax
- movl (%eax), %eax
- popl %ebp
- ret
- .size f, .-f
- .globl main
- .type main, @function
- main:
- pushl %ebp
- movl %esp, %ebp
- subl $40, %esp
- andl $-16, %esp
- movl $0, %eax
- subl %eax, %esp
- ; n1 = 7
- movl $7, -4(%ebp)
- ; n2 = 8
- movl $8, -8(%ebp)
- ; a[][1] = { 7, 8, }
- movl $7, -16(%ebp)
- movl $8, -12(%ebp)
- ; b[] = { &n1, &n2, }
- leal -4(%ebp), %eax
- movl %eax, -24(%ebp)
- leal -8(%ebp), %eax
- movl %eax, -20(%ebp)
- ; f(a)
- leal -16(%ebp), %eax
- movl %eax, (%esp)
- call f
- ; f(b)
- leal -24(%ebp), %eax
- movl %eax, (%esp)
- call f
- movl $0, %eax
- leave
- ret
- .size main, .-main
- .section .note.GNU-stack,"",@progbits
- .ident "GCC: (GNU) 3.3.5 (Gentoo Linux 3.3.5-r1, ssp-3.3.2-3, pie-8.7.7.1)"
复制代码
可以看到,当用 a 做参数时,程序已经尝试访问(虚拟)地址为 7 的内存了。这当然会有段错误。
此外,全局的指针和数组不同,或者说,下面的声明和定义不是等价的:
- /* 第 1 个文件中 */
- int array[10];
- /* 另一个文件中 */
- extern int *array;
复制代码
原因也是类似的:请看一下编译器产生的汇编代码。
又仔细看了一下这段汇编,虽然不像以前一窍不通,但水平有限,仍有一些不明之处
我尝试做了一些注释,请大侠们看一下我的理解是否正确,顺便我也把我的问题在注释中提出来了
请大侠们不吝赐教,thx
- .file "x.c"
- .text
- .globl f
- .type f, @function
- f:
- pushl %ebp
- movl %esp, %ebp
- movl 8(%ebp), %eax [color=Blue] #8(%ebp)是第一个参数在栈上的位置,把它的地址赋给%eax[/color]
- movl (%eax), %eax [color=Blue]#第一次访问内存[/color]
- movl (%eax), %eax [color=Blue]#第二次访存[/color]
- popl %ebp
- ret
- .size f, .-f
- .globl main
- .type main, @function
- main:
- pushl %ebp
- movl %esp, %ebp
- subl $40, %esp [color=Blue]#为main定义的auto变量预留40B的空间[/color]
- andl $-16, %esp [color=Red]#这句就不怎么懂了,esp和-16相与,字面上是把esp的低4位清零,但这样做的目的是什么呢?[/color]
- movl $0, %eax [color=Red]#接下来的这两步是什么意思?[/color]
- subl %eax, %esp
- ; n1 = 7
- movl $7, -4(%ebp) [color=Blue]#紧跟ebp的是第一个auto变量[/color]
- ; n2 = 8
- movl $8, -8(%ebp) [color=Blue]#第二个auto var[/color]
- ; a[][1] = { 7, 8, }
- movl $7, -16(%ebp) [color=Red]#想不通为什么要把7放在后面?[/color]
- movl $8, -12(%ebp)
- ; b[] = { &n1, &n2, }
- leal -4(%ebp), %eax [color=Blue]#%ebp - 4这个地址上是7,就是把7的地址赋给eax[/color]
- movl %eax, -24(%ebp) [color=Red]#仍想不通为什么7的地址在后而8的在前[/color]
- leal -8(%ebp), %eax
- movl %eax, -20(%ebp)
- ; f(a)
- leal -16(%ebp), %eax [color=Blue]#这两步把7压栈了,所以在函数f中第一次访存movl (%eax), %eax得到的是7,这样第二次访存就会出错[/color]
- movl %eax, (%esp)
- call f
- ; f(b)
- leal -24(%ebp), %eax [color=Blue]#同样的压栈操作,但压的是一个地址,故函数f中第一次访存movl (%eax), %eax得到的是地址,不会出错[/color]
- movl %eax, (%esp)
- call f
- movl $0, %eax
- leave
- ret
- .size main, .-main
- .section .note.GNU-stack,"",@progbits
- .ident "GCC: (GNU) 3.3.5 (Gentoo Linux 3.3.5-r1, ssp-3.3.2-3, pie-8.7.7.1)"
复制代码 |
|