我对MIPS汇编语言还比较陌生,目前正在修读一门计算机体系结构课程,其中有很大一部分是关于MIPS编码的。我以前学过几种高级编程语言(C、C#、Python),因此对编程有一定的基础。
我的问题是:MIPS如何在堆栈中为数组分配内存?希望回答这个问题能够让我更好地理解MIPS,因为我仍然有些概念混乱,不太明白MIPS语言及其架构的整体思想。我也不太理解指针在这方面是如何工作的......
如果有人能抽出时间来帮助这位困惑的学生,那就太棒了!:)
我对MIPS汇编语言还比较陌生,目前正在修读一门计算机体系结构课程,其中有很大一部分是关于MIPS编码的。我以前学过几种高级编程语言(C、C#、Python),因此对编程有一定的基础。
我的问题是:MIPS如何在堆栈中为数组分配内存?希望回答这个问题能够让我更好地理解MIPS,因为我仍然有些概念混乱,不太明白MIPS语言及其架构的整体思想。我也不太理解指针在这方面是如何工作的......
如果有人能抽出时间来帮助这位困惑的学生,那就太棒了!:)
嗯...你应该知道MIPS和C一样,基本上有三种不同的内存分配方式。
考虑下面的C代码:
int arr[2]; //global variable, allocated in the data segment
int main() {
int arr2[2]; //local variable, allocated on the stack
int *arr3 = malloc(sizeof(int) * 2); //local variable, allocated on the heap
}
MIPS汇编支持所有这些类型的数据。
要在数据段中分配一个int数组,可以使用:
.data
arr: .word 0, 0 #enough space for two words, initialized to 0, arr label points to the first element
要在堆栈上分配一个整数数组,您可以使用:
#save $ra
addi $sp $sp -4 #give 4 bytes to the stack to store the frame pointer
sw $fp 0($sp) #store the old frame pointer
move $fp $sp #exchange the frame and stack pointers
addi $sp $sp -12 #allocate 12 more bytes of storage, 4 for $ra and 8 for our array
sw $ra -4($fp)
# at this point we have allocated space for our array at the address -8($fp)
为了在堆上分配空间,需要进行系统调用。在spim模拟器中,这是系统调用9:
li $a0 8 #enough space for two integers
li $v0 9 #syscall 9 (sbrk)
syscall
# address of the allocated space is now in $v0
addiu $sp, $sp, -4 # push stack 1 word
sw $t0, 0($sp) # place item on newly pushed space
lw $t0, 0($sp)
addiu $sp, $sp, 4 # pop stack 1 word
addiu $sp, $sp, -8 # allocate two words
sw $t0, 0($sp) # push two registers t0 t1
sw $t1, 4($sp)
lw $t1, 4($sp) # pop two registers t0 t1
lw $t0, 0($sp)
addiu $sp, $sp, 8 # deallocate two words
# grab us a quick string
.data
example_str: .asciiz "hello world :^)"
# grab us a function
.text
.globl example
.type test, @function
test:
addiu $sp, $sp, -4 # push stack for 1 word
sw $ra, 0($sp) # save return address
la $a0, example_str # call puts and give it a string
jal puts
nop
lw $ra, 0($sp) # load return address
addiu $sp, $sp, 4 # pop stack for 1 word
jr $ra # return from function to caller
nop
.data
example_arr: .word 0, 0, 0, 0
.text
addiu $sp, $sp, -16
la $t0, example_arr
lw $t1, 0($t0)
sw $t1, 0($sp)
lw $t1, 0($t0)
sw $t1, 4($sp)
lw $t1, 0($t0)
sw $t1, 8($sp)
sw $t1, 12($sp)
# grab us a function
.text
.globl example
.type test, @function
test:
addiu $sp, $sp, -4 # push stack for 1 word
sw $ra, 0($sp) # save return address
li $a0, 4 # allocate 4*4 bytes (16)
li $a1, 4
jal calloc
nop
addiu $sp, $sp, -4 # push stack for 1 word
sw $v0, 0($sp) # save calloc'd buffer
move $t0, $v0 # get the buffer into a temp
li $t1, 1 # fill some temps with numbers
li $t2, 2
li $t3, 3
li $t4, 4
sw $t1, 0($t0) # save some temps to buffer
sw $t2, 4($t0)
sw $t3, 8($t0)
sw $t4, 12($t0)
... do stuff with the buffer ...
lw $a0, 0($sp) # pop buffer from stack
jal free # run it through free
nop
addiu $sp, $sp, 4 # don't forget to decrement
lw $ra, 0($sp) # load return address
addiu $sp, $sp, 4 # pop stack for 1 word
jr $ra # return from function to caller
nop
在MIPS中,我们手动管理堆栈,因此我们使用存储指令“sb sh sw swl swr”
sw 0($sp), 0($t0)
这是一个存储指令,必须有一个寄存器作为源,例如sw $t1, 0($t0)
!即使在 x86 上也不能这样做。我查了一下,即使是 MARS 也不会将其视为伪指令,并将 LW 转换成$at
,所以你需要自己使用lw
。除非你对某种体系结构的知识/经验非常自信,否则请确保你的代码至少可以编译/汇编,即使你没有测试运行它(因为你只显示了一个无法独立工作的片段)。 - Peter Cordes