MIPS32全局变量地址重叠致覆盖的原因及内存机制问询
问题
在以下MIPS32代码执行时:
la $t0, suma sw $t2, ($t0) lw $a1, ($t0) la $t1, najmanji sh $t4, ($t1)
第二条la指令加载的符号najmanji地址与suma完全相同,导致最后一条sh指令执行后suma被覆盖。为何两个不同符号地址会相同?对应的内存分配机制是怎样的?
附完整代码:
.section .data .global niz niz: .short 12, 3, -9, 1200, -2400, 490, 800, -23, 5 , 22 .section .rodata .global str str: .string "Suma: %d\nNajmanji: %d\n" .section .bss .global suma suma: .word .global najmanji najmanji: .short .section .text .global main main: addiu $t0, $0, 10 // size addu $t1, $0, $0 // i = 0 addu $t2, $0, $0 // suma_ = 0 la $t3, niz // &niz lh $t4, ($t3) // najmanji_ = niz[0] while: slt $t5, $t1, $t0 beq $t5, $0, iskoci sll $t6, $t1, 1 addu $t6, $t3, $t6 lh $t6, ($t6) addu $t2, $t2, $t6 slt $t7, $t6, $t4 beq $t7, $0, preskoci addu $t4, $0, $t6 preskoci: addiu $t1, $t1, 1 j while iskoci: la $t0, suma sw $t2, ($t0) lw $a1, ($t0) la $t1, najmanji sh $t4, ($t1) lh $a2, ($t1) la $a0, str addiu $sp, $sp, -24 sw $ra, 20($sp) jal printf lw $ra, 20($sp) addiu $sp, $sp, 24 addu $v0, $0, $0 jr $ra
原因与内存分配机制解析
1. 符号地址重叠的直接原因
你在.bss段中使用的.word和.short指令用法错误:在GNU MIPS汇编器中,.word不带操作数时,仅定义一个符号标签,不会为该符号分配实际内存空间;同理,.short不带操作数也只是定义标签,不分配空间。
这会导致汇编器将suma和najmanji两个符号都映射到.bss段的同一个起始地址,最终出现地址重叠——执行sh $t4, ($t1)时,数据会写入与suma相同的内存位置,自然覆盖之前sw指令写入的suma值。
2. .bss段的内存分配机制
.bss段专门存储未初始化的全局/静态变量,其分配流程分为两步:
- 汇编阶段:汇编器仅记录
.bss段中每个符号的内存大小需求,不会在目标文件中预留实际存储空间(区别于.data段的已初始化变量)。 - 链接/加载阶段:链接器会为
.bss段分配一块连续内存区域,程序启动时加载器会自动将该区域清零。
要正确为.bss段的符号分配独立内存,需使用.space指令明确指定预留字节数:
.section .bss .global suma suma: .space 4 # 为suma分配4字节(1个word)的空间 .global najmanji najmanji: .space 2 # 为najmanji分配2字节(1个short)的空间
这样汇编器和链接器会为两个符号分配不重叠的独立地址。
3. 打印结果仍正确的原因
你提到最终打印结果正确,是因为在执行sh $t4, ($t1)之前,已经通过lw $a1, ($t0)将suma的值加载到了$a1寄存器中。后续的内存覆盖只会改变suma的内存值,不会影响已存放在$a1里的内容,因此printf调用时能正确输出求和结果。
内容的提问来源于stack exchange,提问作者kesetovic
相关产品推荐
相关产品推荐

