Related
I have tried https://godbolt.org/ and all the different conversions to RISC-V but it still errors.
for example my C code:
#include <stdio.h>
int main(){
printf("test");
return 0;
}
converts to:
main: # #main
addi sp, sp, -16
sw ra, 12(sp) # 4-byte Folded Spill
sw s0, 8(sp) # 4-byte Folded Spill
addi s0, sp, 16
mv a0, zero
sw a0, -16(s0) # 4-byte Folded Spill
sw a0, -12(s0)
lui a0, %hi(.L.str)
addi a0, a0, %lo(.L.str)
call printf
lw a0, -16(s0) # 4-byte Folded Reload
lw s0, 8(sp) # 4-byte Folded Reload
lw ra, 12(sp) # 4-byte Folded Reload
addi sp, sp, 16
ret
.L.str:
.asciz "test"
it gives error at "lui" because it expected 2 arguments but received 3. I tried organizing the code a bit by using .data section and .text section but still no work.
Use la $a0, .L.str instead of your 2-instruction %hi,%lo combo.
Also, use .string instead of .asciz.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have code in assembly form and I want to transform it to С code. So far I am aware of the fact that A decoder is needed. I have download the rtdec but I can not understand how to use it in order to transform the code.
The code is :
.data
A:
.word 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
.word 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17
.word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.word 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
B:
.word 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17
.word 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18
.word 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
.word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
C:
.word
.text
li $8, 0
li $9, 0
li $15, 16
li $16, 4
la $10, A
la $11, B
la $12, C
again:
lw $13, 0($10)
lw $14, 0($11)
add $13, $13, $14
sw $13, 0($12)
addi $10, $10,4
addi $11, $11,4
addi $12, $12,4
addi $9, $9,1
blt $9, $15, again
li $9,0
addi $8, $8,1
blt $8, $16, again
li $v0, 10
syscall
The code uses three registers - $10, $11, and $12 - as the current position pointers in the three arrays A, B, and C. Here's the init sequence:
la $10, A
la $11, B
la $12, C
So $10 follows A, $11 follows B, and $12 follows C. Let's see what else happens to those registers:
lw $13, 0($10) loads the word that $10 is pointing at (the one from A)
lw $14, 0($11) loads the word that $11 is pointing at (the one from B)
sw $13, 0($12) stores a register into C
Finally, all three registers are increased by the word size, which is 4:
addi $10, $10,4
addi $11, $11,4
addi $12, $12,4
That is "move on to the next array element in A, B, and C" logic.
I am a master student and currently doing my summer final project, which is about design a MIPS processor with a FPU and implement in a FPGA.
The instructions that I'm going to implement are depended on the cross-compiler I'm using. So, from a hardware designer point of view, I started the project by first looking the instructions can be generated from the compiler.
For integer design(the main core design), I wrote some C codes, here for example, a simple one:
int main ()
{
int a,b,c;
a=1;
b=2;
c=a+2;
}
A simple addition, the compiler gives assembly codes: (I just posted the assembly codes in main, because I did not plan to run a operating system on my MIPS)
00400168 <main>:
400168: 27bdffe8 addiu sp,sp,-24
40016c: afbe0010 sw s8,16(sp)
400170: 03a0f021 move s8,sp
400174: 24020001 li v0,1
400178: afc20008 sw v0,8(s8)
40017c: 24020002 li v0,2
400180: afc20004 sw v0,4(s8)
400184: 8fc20008 lw v0,8(s8)
400188: 00000000 nop
40018c: 20420002 addi v0,v0,2
400190: afc20000 sw v0,0(s8)
400194: 03c0e821 move sp,s8
400198: 8fbe0010 lw s8,16(sp)
40019c: 27bd0018 addiu sp,sp,24
4001a0: 03e00008 jr ra
I like to understand the assembly code, that can helps me more understand MIPS architecture, and based on the instructions order I can design a hazard detection unit based on the compiler.
We can see from those 4 instruction:
400174: 24020001 li v0,1
400178: afc20008 sw v0,8(s8)
40017c: 24020002 li v0,2
400180: afc20004 sw v0,4(s8)
The compiler loads 1, 2 into variable a, b.
For the integer assembly code, I can understand no problems.
Ok, lets go to the floating point unit, as the same, I wrote a very similar C :
Floating point testing C code
void main ()
{
float a,b,c;
a=1;
b=2;
c=a+b;
}
Now the assembly codes are much different:
00400168 <main>:
400168: 27bdffe8 addiu sp,sp,-24
40016c: afbe0010 sw s8,16(sp)
400170: 03a0f021 move s8,sp
400174: c7808004 lwc1 $f0,-32764(gp)
400178: 00000000 nop
40017c: e7c00008 swc1 $f0,8(s8)
400180: c7808008 lwc1 $f0,-32760(gp)
400184: 00000000 nop
400188: e7c00004 swc1 $f0,4(s8)
40018c: c7c20008 lwc1 $f2,8(s8)
400190: c7c00004 lwc1 $f0,4(s8)
400194: 00000000 nop
400198: 46001000 add.s $f0,$f2,$f0
40019c: e7c00000 swc1 $f0,0(s8)
4001a0: 03c0e821 move sp,s8
4001a4: 8fbe0010 lw s8,16(sp)
4001a8: 27bd0018 addiu sp,sp,24
4001ac: 03e00008 jr ra
4001b0: 00000000 nop
Doesn't like pervious code, those 6 instructions looks like the program load the variable's value from data memory instead using instruction li:
400174: c7808004 lwc1 $f0,-32764(gp)
400178: 00000000 nop
40017c: e7c00008 swc1 $f0,8(s8)
400180: c7808008 lwc1 $f0,-32760(gp)
400184: 00000000 nop
400188: e7c00004 swc1 $f0,4(s8)
Here comes the problem, I just can not figure out what is value stored in -32764(gp) and f0,-32760(gp), because there are not any SW instructions that try to store data into those address.
Here is the fully assembly code generated by compiler:
floatadd: file format elf32-bigmips
Disassembly of section .init:
00400018 <_init>:
400018: 27bdffe0 addiu sp,sp,-32
40001c: afbf0014 sw ra,20(sp)
400020: 0c10003a jal 4000e8 <frame_dummy>
400024: 00000000 nop
400028: 0c10006d jal 4001b4 <__do_global_ctors_aux>
40002c: 00000000 nop
400030: 8fbf0014 lw ra,20(sp)
400034: 27bd0020 addiu sp,sp,32
400038: 03e00008 jr ra
40003c: 00000000 nop
Disassembly of section .text:
00400040 <_ftext>:
400040: 27bdffe0 addiu sp,sp,-32
400044: afb10014 sw s1,20(sp)
400048: 3c110040 lui s1,0x40
40004c: 9222126c lbu v0,4716(s1)
400050: afbf0018 sw ra,24(sp)
400054: 14400019 bnez v0,4000bc <_ftext+0x7c>
400058: afb00010 sw s0,16(sp)
40005c: 3c100040 lui s0,0x40
400060: 8e021260 lw v0,4704(s0)
400064: 00000000 nop
400068: 8c430000 lw v1,0(v0)
40006c: 00000000 nop
400070: 10600009 beqz v1,400098 <_ftext+0x58>
400074: 24420004 addiu v0,v0,4
400078: 0060f809 jalr v1
40007c: ae021260 sw v0,4704(s0)
400080: 8e021260 lw v0,4704(s0)
400084: 00000000 nop
400088: 8c430000 lw v1,0(v0)
40008c: 00000000 nop
400090: 1460fff9 bnez v1,400078 <_ftext+0x38>
400094: 24420004 addiu v0,v0,4
400098: 3c020000 lui v0,0x0
40009c: 24420000 addiu v0,v0,0
4000a0: 10400005 beqz v0,4000b8 <_ftext+0x78>
4000a4: 24020001 li v0,1
4000a8: 3c040040 lui a0,0x40
4000ac: 0c000000 jal 0 <_init-0x400018>
4000b0: 24840244 addiu a0,a0,580
4000b4: 24020001 li v0,1
4000b8: a222126c sb v0,4716(s1)
4000bc: 8fbf0018 lw ra,24(sp)
4000c0: 8fb10014 lw s1,20(sp)
4000c4: 8fb00010 lw s0,16(sp)
4000c8: 03e00008 jr ra
4000cc: 27bd0020 addiu sp,sp,32
004000d0 <call___do_global_dtors_aux>:
4000d0: 27bdffe8 addiu sp,sp,-24
4000d4: afbf0010 sw ra,16(sp)
4000d8: 8fbf0010 lw ra,16(sp)
4000dc: 00000000 nop
4000e0: 03e00008 jr ra
4000e4: 27bd0018 addiu sp,sp,24
004000e8 <frame_dummy>:
4000e8: 3c020000 lui v0,0x0
4000ec: 27bdffe8 addiu sp,sp,-24
4000f0: 3c040040 lui a0,0x40
4000f4: 3c050040 lui a1,0x40
4000f8: 24420000 addiu v0,v0,0
4000fc: afbf0010 sw ra,16(sp)
400100: 24840244 addiu a0,a0,580
400104: 10400003 beqz v0,400114 <frame_dummy+0x2c>
400108: 24a51270 addiu a1,a1,4720
40010c: 0c000000 jal 0 <_init-0x400018>
400110: 00000000 nop
400114: 3c040040 lui a0,0x40
400118: 8c831258 lw v1,4696(a0)
40011c: 3c020000 lui v0,0x0
400120: 10600007 beqz v1,400140 <frame_dummy+0x58>
400124: 24590000 addiu t9,v0,0
400128: 24841258 addiu a0,a0,4696
40012c: 13200004 beqz t9,400140 <frame_dummy+0x58>
400130: 00000000 nop
400134: 8fbf0010 lw ra,16(sp)
400138: 03200008 jr t9
40013c: 27bd0018 addiu sp,sp,24
400140: 8fbf0010 lw ra,16(sp)
400144: 00000000 nop
400148: 03e00008 jr ra
40014c: 27bd0018 addiu sp,sp,24
00400150 <call_frame_dummy>:
400150: 27bdffe8 addiu sp,sp,-24
400154: afbf0010 sw ra,16(sp)
400158: 8fbf0010 lw ra,16(sp)
40015c: 00000000 nop
400160: 03e00008 jr ra
400164: 27bd0018 addiu sp,sp,24
00400168 <main>:
400168: 27bdffe8 addiu sp,sp,-24
40016c: afbe0010 sw s8,16(sp)
400170: 03a0f021 move s8,sp
400174: c7808004 lwc1 $f0,-32764(gp)
400178: 00000000 nop
40017c: e7c00008 swc1 $f0,8(s8)
400180: c7808008 lwc1 $f0,-32760(gp)
400184: 00000000 nop
400188: e7c00004 swc1 $f0,4(s8)
40018c: c7c20008 lwc1 $f2,8(s8)
400190: c7c00004 lwc1 $f0,4(s8)
400194: 00000000 nop
400198: 46001000 add.s $f0,$f2,$f0
40019c: e7c00000 swc1 $f0,0(s8)
4001a0: 03c0e821 move sp,s8
4001a4: 8fbe0010 lw s8,16(sp)
4001a8: 27bd0018 addiu sp,sp,24
4001ac: 03e00008 jr ra
4001b0: 00000000 nop
004001b4 <__do_global_ctors_aux>:
4001b4: 3c020040 lui v0,0x40
4001b8: 2442124c addiu v0,v0,4684
4001bc: 8c44fffc lw a0,-4(v0)
4001c0: 27bdffe0 addiu sp,sp,-32
4001c4: 2403ffff li v1,-1
4001c8: afb00010 sw s0,16(sp)
4001cc: afbf0018 sw ra,24(sp)
4001d0: afb10014 sw s1,20(sp)
4001d4: 10830008 beq a0,v1,4001f8 <__do_global_ctors_aux+0x44>
4001d8: 2450fffc addiu s0,v0,-4
4001dc: 2411ffff li s1,-1
4001e0: 0080f809 jalr a0
4001e4: 2610fffc addiu s0,s0,-4
4001e8: 8e040000 lw a0,0(s0)
4001ec: 00000000 nop
4001f0: 1491fffb bne a0,s1,4001e0 <__do_global_ctors_aux+0x2c>
4001f4: 00000000 nop
4001f8: 8fbf0018 lw ra,24(sp)
4001fc: 8fb10014 lw s1,20(sp)
400200: 8fb00010 lw s0,16(sp)
400204: 03e00008 jr ra
400208: 27bd0020 addiu sp,sp,32
0040020c <call___do_global_ctors_aux>:
40020c: 27bdffe8 addiu sp,sp,-24
400210: afbf0010 sw ra,16(sp)
400214: 8fbf0010 lw ra,16(sp)
400218: 00000000 nop
40021c: 03e00008 jr ra
400220: 27bd0018 addiu sp,sp,24
Disassembly of section .fini:
00400224 <_fini>:
400224: 27bdffe0 addiu sp,sp,-32
400228: afbf0014 sw ra,20(sp)
40022c: 0c100010 jal 400040 <_ftext>
400230: 00000000 nop
400234: 8fbf0014 lw ra,20(sp)
400238: 27bd0020 addiu sp,sp,32
40023c: 03e00008 jr ra
400240: 00000000 nop
I am not good at MIPS assembly, can someone explain where are the floating point variable' value 1 and 2?
About your question
ELF executables can have one or more sections filled with the static data (string, floating point numbers, numbers, whatever) used by the program.
This sections are loaded into memory by the loader with the rest of the program, thereby avoiding intermixing code and data and reducing the code size.
For the ELF on MIPS systems you should refer to this where there is this nice picture:
As you can see $gp is used to address the section .sdata and .sbss, where the initial s stands for small.
All these efforts are taken to minimize code size as by using $gp the compiler can generate 16 bit offsets (versus the 32 bit ones normally used).
Since the offset is signed, $gp is placed in the middle of a (at most) 64 KiB region formed by .sdata + .sbss.
Your floating points value are not coded directly in the instructions because FP instruction does not takes immediates, instead they are saved into a readonly section and loaded from there.
About your purpose
Why in the end do you care about this?
If your goal is to design an implementation of the MIPS ISA, just pick the specific ISA (MIPS32 I? MIPS32 IV? MIPS 64?), get the documents, get the whole picture and implement a microarchitecture for it.
If an instruction is a valid instruction according to your chosen ISA then your implementation must be able to execute it, don't worry about what the compilers are doing, they are grown up, they can take care of them selves and in the end if the code you are executing is broken, who cares? As long it is valid.
These will help you:
MIPS32™ Architecture For Programmers Volume I: Introduction to the MIPS32™ Architecture
MIPS32™ Architecture For Programmers Volume II: The MIPS32™ Instruction Set
Our team is trying to create a compiler that's fed code and produces MIPS assembly from it.
To tackle array declaration at the global scope, we create a label for the array in .text and reserve 4 bytes to hold the address pointing to the start of the array in memory.
.text
arr: .space 4
.data
...
li $t0, N # (where N = number of elements in arr)
li $v0, 9 # Load system instruction to allocate dynamic memory
li $t1, 4 # 4 bytes per element
mult $t0, $t1 # Calculates how big the allocated memory has to be in bytes.
mflo $a0 # Loads this value into $a0
syscall # Allocates memory and returns address into $v0
la $s0, arr # load address of arr into $s0
sw $v0, ($s0) # Save allocated memory address into the space reserved in .text
However, the last instruction doesn't seem to be working properly for us.
This image shows exactly where the error occurs and the state of the registers at that time. I'm unsure why it's causing an error.
Edit: some more information on the error produced, updated to encompass the modified instructions at the end
[00400000] 8fa40000 lw $4, 0($29) ; 183: lw $a0 0($sp) # argc
[00400004] 27a50004 addiu $5, $29, 4 ; 184: addiu $a1 $sp 4 # argv
[00400008] 24a60004 addiu $6, $5, 4 ; 185: addiu $a2 $a1 4 # envp
[0040000c] 00041080 sll $2, $4, 2 ; 186: sll $v0 $a0 2
[00400010] 00c23021 addu $6, $6, $2 ; 187: addu $a2 $a2 $v0
[00400014] 0c100009 jal 0x00400024 [main] ; 188: jal main
[00400018] 00000000 nop ; 189: nop
[0040001c] 3402000a ori $2, $0, 10 ; 191: li $v0 10
[00400020] 0000000c syscall ; 192: syscall # syscall 10 (exit)
[00400024] 34080003 ori $8, $0, 3 ; 9: li $t0, 3 # Load immediate value into register $t0
[00400028] 34020009 ori $2, $0, 9 ; 10: li $v0, 9
[0040002c] 34090004 ori $9, $0, 4 ; 11: li $t1, 4
[00400030] 01090018 mult $8, $9 ; 12: mult $t0, $t1
[00400034] 00002012 mflo $4 ; 13: mflo $a0
[00400038] 0000000c syscall ; 14: syscall
[0040003c] 3c101001 lui $16, 4097 [arr0] ; 15: la $s0, arr0
[00400040] ae020000 sw $2, 0($16) ; 16: sw $v0, ($s0)
PC = 400040
EPC = 40003c
Cause = 1c
BadVAddr = 1004002f
Status = 3000ff12
The last instruction sw $v0, arr0($0) = MEM[$0 + arr0] = $v0 which isn't correct. However you'll be given the amount of memory requested and it is needed to save that memory pointer in a register until scope of program. The assignment might look like this,
arr: .space 4
syscall # Allocates memory and returns address into $v0
la $s0, arr # arr is pointer address
st $v0, 0($s0) # start base address of array
Now arr is base address of 4 bytes of memory holding the address of memory content. For good practice it is important to de-allocate the memory assigned back to OS as,
li $v0,10 # return back to OS
syscall
I needed to translate the follwing C code to MIPS64:
#include <stdio.h>
int main() {
int x;
for (x=0;x<10;x++) {
}
return 0;
}
I used codebench to crosscompile this code to MIPS64. The following code was created:
.file 1 "loop.c"
.section .mdebug.abi32
.previous
.gnu_attribute 4, 1
.abicalls
.option pic0
.text
.align 2
.globl main
.set nomips16
.set nomicromips
.ent main
.type main, #function
main:
.frame $fp,24,$31 # vars= 8, regs= 1/0, args= 0, gp= 8
.mask 0x40000000,-4
.fmask 0x00000000,0
.set noreorder
.set nomacro
addiu $sp,$sp,-24
sw $fp,20($sp)
move $fp,$sp
sw $0,8($fp)
j $L2
nop
$L3:
lw $2,8($fp)
addiu $2,$2,1
sw $2,8($fp)
$L2:
lw $2,8($fp)
slt $2,$2,10
bne $2,$0,$L3
nop
move $2,$0
move $sp,$fp
lw $fp,20($sp)
addiu $sp,$sp,24
j $31
nop
.set macro
.set reorder
.end main
.size main, .-main
.ident "GCC: (Sourcery CodeBench 2012.03-81) 4.6.3"
To check if the code works as expected, I usually use the WINMIPS64 simulator. For one or other reason this simulator does not want to accept this code. It appears that every line of code is wrong. I have been looking at this issue for over a day. I hope someone can help me out with this. What is wrong with this assembly code for the mips64 architecture?
From page 7 of the WINMIPS64 documentation:
The following assembler directives are supported
.data - start of data segment
.text - start of code segment
.code - start of code segment (same as .text)
.org <n> - start address
.space <n> - leave n empty bytes
.asciiz <s> - enters zero terminated ascii string
.ascii <s> - enter ascii string
.align <n> - align to n-byte boundary
.word <n1>,<n2>.. - enters word(s) of data (64-bits)
.byte <n1>,<n2>.. - enter bytes
.word32 <n1>,<n2>.. - enters 32 bit number(s)
.word16 <n1>,<n2>.. - enters 16 bit number(s)
.double <n1>,<n2>.. - enters floating-point number(s)
Get rid of everything that's not in the above list, as it won't run in the simulator.
You'll need to move the .align to before .text
WINMIPS64 expects daddi/daddui instead of addi/addiu, again as per the documentation.
As per the documentation, move $a, $b is not a supported mnemonic. Replace them with daddui $a, $b, 0 instead.
slt needs to be slti.
Finally, the simulator expects an absolute address for j, but you've given it a register. Use jr instead.
At this point I get an infinite loop. This is because the stack pointer doesn't get initialized. The simulator only gives you 0x400 bytes of memory, so go ahead and initialize the stack to 0x400:
.text
daddui $sp,$0,0x400
Now it runs. Since you're running the code by itself, nothing will be in the return register and the final jr $31 will just bring it back to the beginning.
Here's my version:
.align 2
.text
daddui $sp,$0,0x400
main:
daddui $sp,$sp,-24
sw $fp,20($sp)
daddui $fp,$sp,0
sw $0,8($fp)
j $L2
nop
$L3:
lw $2,8($fp)
daddui $2,$2,1
sw $2,8($fp)
$L2:
lw $2,8($fp)
slti $2,$2,10
bne $2,$0,$L3
nop
daddui $2,$0,0
daddui $sp,$fp,0
lw $fp,20($sp)
daddui $sp,$sp,24
jr $31
nop
Consider getting either another compiler or another simulator, because these two clearly hate each other.