Labels are a convenient way to reference a specific location in memory. It is basically the only abstraction that we get to make our lives a little easier when programming assembly, because otherwise we would need to manually count memory addresses, which is incredibly tedious. When MARS assembles the program (translates it into binary), labels are replaced by their actual address values.
For reasons that will make sense later, whenever using immediate values in an instruction, the immediate value MUST fit into 16 bits. But that is a problem because memory addresses are 32 bits.
Because of this, we cannot directly load an address from a label into a register (via something like addi $t0, $zero, MY_LABEL). So instead we use the la pseudo instruction, which uses two separate instructions to load the upper 16 bits of the address into the register, and then load the lower 16 bits into the register
This is why we NEED to use la before doing anything else with the label. It is to get that entire memory address into a register.
Once we have the address, we can use the load and store instructions to read/write the value located at the address to. This is like dereferencing a pointer in C.
lw (load word) copies 1 word (4 bytes) from memory into a register, starting from the input address.
sw (store word) is its reverse. It copies a word from a register into memory.
lb (load byte) is the same as lw, but for only copying 1 byte. This is often used when working with individual characters.
sb (store byte) is its reverse, It copies a byte from a register into memory.
.data
MY_NUM: .word 1234
.text
# get the address to the number.
la $t0, MY_NUM # int* t0 = MY_NUM
# get the actual value
lw $t1, 0($t0) # int t1 = *t0
# increment the value, overwrite the old value in memory with the new one.
addi $t1, $t1, 1 # t1 += 1
sw $t1, 0($t0) # *t0 = t1
.data
MY_STRING: .asciiz "Hello, World!\\n"
.text
la $t0, MY_STRING # char* t0 = MY_STRING
# Note how we use lb (load byte), and we only get the first character of the string. A string is just an array of characters.
# We can't store an entire string into a register. Its too large. So we just store a pointer to the start of the string.
# Then we can load individual characters using lb.
lb $t1, 0($t0) # t1 = *t0 = 'H'
lb $t2, 6($t0) # t2 = *(t0+6) = ' '
# fun fact: characters are just numbers too! There is a unique ascii code for each character
# You can find an ascii table on the website, in the "materials" category.
add $t3, $t1, $t2 # t3 = 'H' + ' '
# this is the same as doing 0x20 + 0x46
# the result is 0x68, or the ascii character 'h'
# another fun fact when using i instructions, you can enter a character for your immediate value.
addi $t4, $zero, 'o'
sb $t4, 5($t0) # *(t0+5) = 'o'
# the string in memory now says "Helloo World!\\n"