我对MIPS汇编语言非常陌生,目前正在上一门关于计算机体系结构的课程,其中有很大一部分是关于MIPS编码的。我在过去学习过其他几种高级编程语言(C、C#、Python),因此对编程有一定的了解。
这里我的问题特别问: MIPS如何为堆栈中的数组分配内存?我希望回答这个问题能让我对MIPS有更好的整体理解,因为我仍然对MIPS语言及其体系结构的概念有很多了解。我也不太明白指针在这方面是如何工作的……
如果有人能抽出时间来帮助这个困惑的学生,那就太好了!:)
发布于 2013-10-27 06:37:59
好吧..。您应该知道,像C一样,MIPS本质上有三种不同的内存分配方式。
考虑下面的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 要在堆栈上分配int数组,您可以使用:
#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模拟器中,这是system call 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发布于 2018-10-01 04:24:24
与其他archs不同的是,MIPS没有推入或弹出寄存器/立即指令。因此,您依赖于自己管理堆栈。这实际上是在mul/div之外的大多数arch中注意到的,其中寄存器没有特定的用途,只是建议使用它的方式。现在,如果你想如何使用它,如果你试图与C语言集成,你可能会破坏一些东西。
为了将某些内容推送到堆栈,您需要使用存储指令。这些是sb, sh, sw, swl, swr。字节、半个、字、左字、右字。
addiu $sp, $sp, -4 # push stack 1 word
sw $t0, 0($sp) # place item on newly pushed space为了从堆栈中弹出一些东西,你只需要用addiu来减少它的增量即可。但是,您可能希望使用lb, lh, lw, lwl, lwr从其中加载数据。
lw $t0, 0($sp)
addiu $sp, $sp, 4 # pop stack 1 word下面是一个使用两个单词push的例子。
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)下面是一个使用malloc/calloc的示例。
# 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正如我前面提到的,没有任何东西有明确定义的特定用途,所以如果您愿意,您也可以使用自己的堆栈,而不使用$sp。我展示了使用$t*作为$s*的示例。例如,在强制每个函数拥有自己的堆栈或你能想到的其他用例的情况下,这是有效的。例如,Lua (https://lua.org)在某种程度上做到了这一点。但是,不是MIPS。多个堆栈是可爱的,特别是在处理多个目标时。
编辑:我意识到我遗漏了堆栈帧指针。请注意,如果您的代码与用C编写的代码相链接,则应正确处理堆栈帧指针。
发布于 2021-03-28 16:43:07
在MIPS中,我们手动管理堆栈,因此我们使用存储指令“sb sh sw swl swr”
https://stackoverflow.com/questions/19612459
复制相似问题