问题
Is it possible in MIPS to change during execution the value of a label, or to create a label with certain value?
I ask this because when using the instruction lw $a0, label($s0)
i want to increment the value of label +4 every time we loop, indicating the new memory address of the array. I am aware I can do lw $a0, label+4($s0)
but the new value of label will not be stored.
Any advise?
回答1:
No. In MIPS you must have a constant outside the parentheses when dereferencing (poor wording). If it were possible to change the value of the label, then it would no longer be constant. To get around this, you could instead do something like
la $t1, label #t1 holds address of label
add $t1, $t1, $s0 #t1 now holds address of label + s0 offset
lw $a0, 0($t1) #load word from t1's location
addi $t1, $t1, 4 #t1 was incremented by 4 bytes now
lw $a0, 0($t1) #load the next word
It might be advisable to use addu if s0 will always be non-negative.
EDIT: You cannot change the value of a label. It is solely an alias for a location in memory. In the text section, it's an alias for the position of the following instruction. In the data section, it's an alias for the location in memory of the following space.
回答2:
I do think the answer should be clarified and reanswered to "Yes". I think there was a miscommunication and a mix-up between "address" and "value".
I currently have an array that I want to navigate to do a bubble sort. In order to know when to stop, I need an index value to compare with an array length that is persistent.
I created the arrayLength
label, and after seeing "no" on this answer, I was stuck for 4 hours trying to change the value of arrayLength
with a value from the user before I remembered store word sw
.
Technically, yes, you can't change the base address of an array, but you can read the next address that follows.
Here is what you can do to get an array length to iterate over an array with a read integer:
li $v0, 5
syscall
.data
.word
.assign 2
arrayLength: 0
.text
sw $v0, arrayLength
lw $t0, arrayLength
At this point, arrayLength
, defined by the user, is taken from $v0
, put in arrayLength
, then stored in $t0
from arrayLength
, and can be used to compare to iterate over the array.
In other words to answer your question, the value of 0 in arrayLength
was overwritten (for our example, lets say 10). So yes, you can overwrite labels all day long. What you cannot do is modify the address of that label.
To my knowledge, once a label is created, it is assigned to an address and the following addresses are allocated depending on how you identify it (.byte
, .half
, .word
, etc.). From there, unless there is some way to delete a label and re-create it, you cannot modify the address. That would cause a LOT of issues with memory management and be very inefficient and complex for no reason.
Now to continue. As a note, if you didn't know, you can predefine an array with .space [number]
. I think each value is by default 32 bits, so 4 bytes (a word). So if you wanted, say 5 items(words), you would do 5 x 4, so .space 20
and you can store 5 words into the array.
In this case, we now assume array
is already created and filled in from our arrayLength
of 10
and we are printing the value at each index, as follows:
add $t1, $zero, $zero #index value 0, our base address index
loop:
li $v0, 1
lw $a0, array($t1)
syscall
addi $t1, $t1, 4 #increase the address index by 4 (each index is 4 bytes long)
addi $t3, 1, $zero #increase the index identifier by 1
blt $t3, arrayLength, loop
#exit
So address index ($t1
) is the literal address location. Each index, i.e: word, is 4 bytes (32 bits) long. So our $t3 is an identifier to say (for example), "Hey, we are at index location 2 of 10," but in reality, we are in address location array + 8
out of array + 40
.
You could probably chuck the index identifier and just make $t3 the value of arrayLength x 4
and do blt $t1, $t3, loop
.
Hope this helps.
来源:https://stackoverflow.com/questions/4082341/mips-assembly-label-value-modification