Reputation: 93
I assemble a simple c program to mips and try to understand the assembly code. By comparing with c code, I almost understand the it but still get some problems.
I use mips-gcc to generate assembly code: $ mips-gcc -S -O2 -fno-delayed-branch -I/usr/include lab3_ex3.c -o lab3_ex3.s
Here is my guess about how the assembly code works:
main
is the entry of the program.
$6
is the address of source array.
$7
is the address of dest array.
$3
is the size of source array.
$2
is the variable k
and is initialized to 0.
$L3
is the loop
$5
and $4
are addresses of source[k]
and dest[k]
.
sw $3,0($5)
is equivalent to store source[k]
in $3
.
lw $3,4($4)
is equivalent to assign source[k]
to dest[k]
.
addiu $2,$2,4
is equivalent to k++
.
bne $3, $0, $L3
means that if source[k]
is zero then exits the loop otherwise jump to lable $L3
.
$L2
just do some clean up work.
Set $2
to zero.
Jump to $31
(return address).
My problems is:
.frame $sp,0,$31
does?lw $3,4($4)
instead of lw $3,0($4)
%lo(source)($6)
means? ($hi and $lo$ registers are used in multiply so why they are used here?)Thanks.
C
int source[] = {3, 1, 4, 1, 5, 9, 0};
int dest[10];
int main ( ) {
int k;
for (k=0; source[k]!=0; k++) {
dest[k] = source[k];
}
return 0;
}
Assembly
.file 1 "lab3_ex3.c"
.section .mdebug.eabi32
.previous
.section .gcc_compiled_long32
.previous
.gnu_attribute 4, 1
.text
.align 2
.globl main
.set nomips16
.ent main
.type main, @function
main:
.frame $sp,0,$31 # vars= 0, regs= 0/0, args= 0, gp= 0
.mask 0x00000000,0
.fmask 0x00000000,0
lui $6,%hi(source)
lw $3,%lo(source)($6)
beq $3,$0,$L2
lui $7,%hi(dest)
addiu $7,$7,%lo(dest)
addiu $6,$6,%lo(source)
move $2,$0
$L3:
addu $5,$7,$2
addu $4,$6,$2
sw $3,0($5)
lw $3,4($4)
addiu $2,$2,4
bne $3,$0,$L3
$L2:
move $2,$0
j $31
.end main
.size main, .-main
.globl source
.data
.align 2
.type source, @object
.size source, 28
source:
.word 3
.word 1
.word 4
.word 1
.word 5
.word 9
.word 0
.comm dest,40,4
.ident "GCC: (GNU) 4.4.1"
Upvotes: 0
Views: 727
Reputation: 887
Firstly, main
, $L3
and $L2
are labels for 3 basic blocks. You are roughly correct about their functions.
Question 1: What is .frame doing
This is not a MIPS instruction. It is metadata describing the (stack) frame for this function:
$sp
, an alias for $29
.$16-$23
.$31
for MIPS calling convention)For more information regarding the MIPS calling convention, see this doc.
Question 2: Why lw $3,4($4) instead of lw $3,0($4)
This is due to an optimization of the loop. Normally, the sequence of loads and stores would be :
You assume that the loop is entirely in $L3
, and that contains load source[k]
and store dest[k]
. It isn't. There are two clues to see this:
main
which does not correspond to any load outside the loop$L3
, the store is before the load. In fact, load source[0]
is performed in the basic-block named main
. Then, the loop in the basic block $L3
is store dest[k];load source[k+1];
. Therefore, the load uses an offset of 4 more than the offset of the store, because it is loading the integer for the next iteration.
Question 3: What is the lo/hi syntax?
This has to do with instruction encodings and pointers. Let us assume a 32-bit architecture, i.e. a pointer is 32 bits. Like most fixed-size instruction ISAs, let us assume that the instruction size is also 32 bits.
Before loading and storing from the source
/dest
arrays, you need to load their pointers into registers $6
and $7
respectively. Therefore, you need an instruction to load a 32-bit constant address into a register. However, a 32-bit instruction must contain a few bits to encode opcodes (which operation the instruction is), destination register etc. Therefore, an instruction has less than 32 bits left to encode constants (called immediates). Therefore, you need two instructions to load a 32-bit constant into a register, each loading 16 bits. The lo
/hi
refer to which half of the constant is loaded.
Example: Assume that dest
is at address 0xabcd1234. There are two instructions to load this value into $7
.
lui $7,%hi(dest)
addiu $7,$7,%lo(dest)
lui
is Load Upper immediate. It loads the top 16 bits of the address of dest
(0xabcd
) into the top 16 bits of $7
. Now, the value of $7
is 0xabcd0000.
addiu
is Add Immediate Unsigned. It adds the lower 16 bits of the address of dest
(0x1234
) with the existing value in $7
to get the new value of $7
. Thus, $7
now holds 0xabcd0000 + 0x1234 = 0xabcd1234, the address of dest
.
Similarly, lw $3,%lo(source)($6)
loads from the address pointed to by $6
(which already holds the top 16 bits of the address of source
) at an offset of %lo(source)
(the bottom 16 bits of that address). Effectively, it loads the first word of source
.
Upvotes: 5