15

I'm quite new to the MIPS assembly language and am currently taking a class on computer architecture which has a large section on MIPS coding. I've studied several other high-level programming languages (C, C#, Python) in the past so have some bases in programming.

My question here specifically asks: How does MIPS allocate memory for arrays in the stack? I'm hoping that answering this question will hopefully give me a better total understanding of MIPS as I'm still a bit lot on conceptualizing the idea of the MIPS language and it's architecture. I don't quite understand how pointers work in this whole regard either...

Would be brilliant if someone could take the time to help out this confused student! :)

4

3 回答 3

25

嗯.. 你应该知道 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 

要在堆栈上分配一个 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 模拟器中,这是系统调用 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
于 2013-10-26T22:37:59.267 回答
2

与其他拱门不同,MIPS 没有推送或弹出寄存器/立即指令。所以你依靠自己管理堆栈。这实际上在 mul/div 之外的大多数拱门中都有说明,您的寄存器没有特定用途,只是建议的使用方式。现在,如果您随心所欲地使用它,例如,如果您尝试与 C 集成,则会破坏某些东西。

为了将某些东西压入堆栈,您需要使用存储指令。这些是sb, sh, sw, swl, swr。byte, half, word, word left, word right分别。

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 编写的内容相关联,那么您正确处理堆栈帧指针。

于 2018-09-30T20:24:24.153 回答
0

在 MIPS 中,我们手动管理堆栈,因此我们使用存储指令“sb sh sw swl swr”</p>

于 2021-03-28T08:43:07.283 回答