MIPS - MIPS如何为堆栈中的数组分配内存?

时间:2013-10-26 22:11:15

标签: assembly malloc mips computer-architecture

我对MIPS汇编语言很陌生,目前正在上一个关于MIPS编码的计算机体系结构课程。我以前学过其他几种高级编程语言(C,C#,Python),因此在编程方面有一些基础。

我的问题在这里特别问:MIPS如何为堆栈中的数组分配内存?我希望回答这个问题有望让我更好地理解MIPS,因为我仍然在概念化MIPS语言及其架构的概念。我不太明白指针在这方面是如何工作的......

如果有人能花时间帮助这个迷茫的学生,那将是非常棒的! :)

3 个答案:

答案 0 :(得分:17)

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

要在堆上分配空间,需要进行系统调用。在垃圾处理模拟器中,这是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

答案 1 :(得分:0)

与其他架构不同,MIPS没有推入或弹出寄存器/立即指令。因此,您需要自己管理堆栈。实际上,这在mul / div之外的大多数架构中都已指出,您的寄存器没有特定用途,只是建议的使用方式。现在,如果您按需要使用它,例如,如果尝试与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

这里是将其与两个单词推送一起使用的示例。

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。多个堆栈很可爱,尤其是在处理多个目标时。

答案 2 :(得分:0)

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