I am being asked to create a data segment using the .byte and .word directives to store values the values 0x01, 0x02, 0x03, 0x04 as bytes and the value 0x12345678 as a word. My code would be:
.data
b1: .byte 0x01
b2: .byte 0x02
b3: .byte 0x03
b4: .byte 0x04
w1: .word 0x12345678
Then I want to use the lbu,lhu and lw to load into $t0,$t1,$t2 the values: 0x01, 0x0201 and 0x12345678 respectively.
What I am doing for that is:
lbu $t0,b1 #this works
lhu $t1,0(b2) #this doesn't work, gets an error
lw $t2,w1 #also works
My error is exception and unaligned address in inst/data fetch: 0x10010001. How do I load more than 1 byte as a halfword? Is my declaration of variables in the data segment wrong? Do I maybe want smth like:
byte_array: .byte 0x01,0x02
Thank you all for the help.
CodePudding user response:
You're attempting to load a half word (lhu
) that is declared as a .byte
. That is a size mismatch, which goes to the error you're getting.
But the processor doesn't care about the size mismatch, but rather the alignment. So, if you want to load a half word (two bytes) they must start on an even byte boundary, which isn't the case for your data set up.
lhu $t0, b1
will work, as will lhu $t0,b3
, and lhu $t0,w1
as well because these data are at even addresses. However, b2
and b4
are at odd addresses.
A C compiler would not let you perform the size mismatched loads in the first place, without some serious casting, which would get you back to these unaligned errors on MIPS. Further, an x86 processor would allow the misaligned access, though in some cases those would be slower than the aligned equivalents.
Because misaligned accesses require more hardware and also that compilers can generally avoid these problems using their type systems to prevent them, some designs choose to forgo the extra hardware and MIPS is one of them.
You can also alter the alignment by inserting padding — one extra byte inserted between b1
& b2
would change b2
's alignment allowing to load b2
and b3
using lhu
. Because w1
is declare as a .word
the assembler knows it needs to be word aligned, so inserting that one byte between b1
& b3
will cause w1
to require 3 bytes of additional alignment padding (which the assembler will provide due to the .word
data declaration being used).
When you use this kind of size mismatch, there will also be the issue of endianness. The MIPS simulators will use the same endianness as the underlying processor so you'll generally see little endian behavior when loading 2 bytes. If you declare two .bytes
instead of using one .half
you will have to pick a byte order.