以下讨论,基于Mips o32 ABI, 个人感觉x86下也很类似。
源程序如下:
/* test.c */
int main(void)
{
char *a=(char *)malloc(4);
char *b="xxx";
char c[4]="xxx";
a[0]='x';
b[0]='x';
c[0]='x';
c++;
}
运行mips-elf-gcc -c test.c
运行mips-elf-objdump -D test.o | less
反汇编代码如下:
Disassembly of section .text:
00000000 <main>:
0: 27bdffd8 addiu sp,sp,-40
4: afbf0024 sw ra,36(sp)
8: afbe0020 sw s8,32(sp)
c: 03a0f021 move s8,sp
10: 24040004 li a0,4
14: 0c000000 jal 0 <main>
18: 00000000 nop
1c: afc20010 sw v0,16(s8)
20: 3c020000 lui v0,0x0
24: 24420000 addiu v0,v0,0
28: afc20014 sw v0,20(s8)
2c: 3c020000 lui v0,0x0
30: 8c420000 lw v0,0(v0)
34: 00000000 nop
38: afc20018 sw v0,24(s8)
3c: 8fc30010 lw v1,16(s8)
40: 24020078 li v0,120
44: a0620000 sb v0,0(v1)
48: 8fc30014 lw v1,20(s8)
4c: 24020078 li v0,120
50: a0620000 sb v0,0(v1)
54: 24020078 li v0,120
58: a3c20018 sb v0,24(s8)
5c: 03c0e821 move sp,s8
60: 8fbf0024 lw ra,36(sp)
64: 8fbe0020 lw s8,32(sp)
68: 27bd0028 addiu sp,sp,40
6c: 03e00008 jr ra
70: 00000000 nop
Disassembly of section .data:
Disassembly of section .rodata:
00000000 <.rodata>:
0: 78787800 0x78787800
堆栈布局如下:
------
| | sp+40
------
| ra | 36
------
| s8 | 32
------
| | 28
------
| c | 24
------
| b | 20
------
| a | 16
------
| | 12
------
| | 8
------
| | 4
------
| | sp
------
可以看出,由于a,b,c都是内部变量,因此是保存在栈中的。
16(s8)中存放着指针a,a指向有malloc在堆上分配的空间(heap)。
20(s8)中存放着指针b,b指向只读数据段.rodata中的字符串"xxx"。
24(s8)是字符串数组c的起始位置,依次存放了从.rodata中加载的字符串"xxx"。
因此,
a[0]='x'; 是针对堆空间的写操作,是正确的。
b[0]='x'; 是针对只读空间的写操作,是错误的。
c[0]='x'; 是针对栈空间的写操作,是正确的。
c++;
数组c的名字只是一个地址常量24(s8),并没有在栈中或其他内存中保存c值,所以是错误的。