Search code examples
assemblymipsspim

How to use pointer correctly in MIPS?


I wrote a program which takes input of a few numbers and loops through every one. Then it should swap the maximum if the current number is bigger than my last max one. If it's at the last number (at the end of my string), it should exit.

I'm trying to debug and I understand, that I didn't really understand how pointers work and when I have to use brackets around my registers.

The code is as follows:

.data
first: .word 5, 6, -128, -5, 260, 34, 3, 20, -1
last: .word 44

max: .space 4  


.text
lw $t0, first
lw $t1, last
lw $t5, max


sw $t5, $t0
loop: 

beq $t0, $t1, ex
addi $t0, $t0, 4
bgt $t0, $t5, swapmax
j loop


swapmax: 
lw $t0, ($t5)

ex: 
lw $t5, max
li $v0, 10
syscall

Where do I need brackets and why?

The program does compile, but I get an error:

attempt to execute non-instruction at 0x800000180

What does this error mean?


Solution

  • What are pointers?

    Pointers are something that point at a memory location. We use pointers to put values in memory locations. For example in C:

    int max;
    int *ptr = &max;
    *ptr = 22; // max = 22
    

    In above example, ptr is pointing at a memory location (max), and we change the value of max through ptr by dereferencing it.

    How to use them correctly in MIPS?

    To understand this, you need to understand the instruction syntax and what operands each instruction takes. Obviously we cannot go through all the instructions in one answer so I will just show you a few so that you get an idea:

    lw register, memory_location
    sw register, memory_location
    la register, memory_location 
    
    • lw loads a word from memory into register. Examples:
    lw $t0, first
    lw $t0, ($t5) # this is like, int t0 = *t5
    
    • sw stores a value from register into memory location. Example:
    sw $t0, max # max = t1
    sw $t0, ($t5) # *t5 = t0
    
    • la will load address of a memory location into a register.
    la $t5, max # int *t5 = &max
    

    Let's see the mistakes in your code now. Here:

    lw $t5, max   
    

    Above will load value of max into $t5. It seems like you created max to store max value. Loading it here seems pointless because it doesn't even contain anything. You want to load it's address using la:

    la $t5, max #load address of max variable into $t5
    

    Moving on we see this instruction:

    sw $t5, $t0
    

    This will not assemble. It will result in an error. sw has first operand(source) as a register, and the second operand is a "memory location", not a register.

    sw register, memory_location
    

    So, if you want to store something, you would do:

    sw $t5, ($t0)       #store value inside $t5 at the 'address' inside $t0.
    
    # Assume:
    # $t5 = 23
    # $t0 = 0x5555
    # After executing this instruction, memory location 0x5555 would have value 23 in it
    

    This was just explanation. In your code above, you assigned $t0 = first. It isn't even pointing to a memory location! However, $t5 will have a memory location if you do la $t5, max.

    So, I assume you wanted to do:

    sw $t0, ($t5)
    # After executing this, 'max' == $t0 because $t5 is pointing at max.
    

    Moving on, we see:

    bgt $t0, $t5, swapmax
    

    As you must already have guessed, this is incorrect. Reason: You are comparing an "address" with a value. "Address" is in $t5, "Value" is in $t0. If you want to get the value inside $t5, you will have to load it first. Maybe using another register:

    lw $t3, ($t5)
    #OR
    lw $t3, max   # same thing, $t5 is pointing at 'max'
    

    These are the obvious mistakes. There maybe logical errors, but this is your code and your program so I will leave it to you to modify your logic as required