owned this note
owned this note
Published
Linked with GitHub
# Lab2: RISC-V `RV32I[MA]` emulator with ELF support : prime
###### tags: `RISC-V`
## Usage on Ubuntu Linux
[ELF file](https://linux-audit.com/elf-binaries-on-linux-understanding-and-analysis/)
Q1 why os know when we use command "make" under folder rv32emu/, os whould let test1.c be makefiled?
http://linux.vbird.org/linux_basic/0520source_code_and_tarball.php#intro_make
The os would go look up the "makefile" in that folder, then know what to do.
Q2 when I do command
```
riscv-none-gcc -march=rv32i -mabi=ilp32 -O3 -nostdlib prime.c -o prime
```
but I cannot compile prime.c
while it said it cannot find the reference of modsi3, print, putchar
possible A2 https://blog.csdn.net/ce123_zhouwei/article/details/8184606
then we can compile it but cannot output
while doing command `./emu~ prime` whould see nan for branch[tag2]
So I chose to ignore it, using objdump first, then I got the codes below, maybe I need to rewrite prime.c
And that's interesting that it would be fail when I use the command line below`riscv-none-embed-gcc -march=rv32i -mabi=ilp32 -O3 -nostdlib prime.c -o prime`
with the window below.
A:then I understand that it's because I use code in riscv scale, try to compile it by gcc.
```
dc@dc-VirtualBox:~/rv32emu$ riscv-none-embed-gcc -march=rv32i -mabi=ilp32 -O3 -nostdlib prime.c -o prime
/home/dc/riscv-none-embed-gcc/8.2.0-3.1/bin/../lib/gcc/riscv-none-embed/8.2.0/../../../../riscv-none-embed/bin/ld: /tmp/cc4K7mys.o: in function `.L2':
prime.c:(.text+0x6c): undefined reference to `__modsi3'
/home/dc/riscv-none-embed-gcc/8.2.0-3.1/bin/../lib/gcc/riscv-none-embed/8.2.0/../../../../riscv-none-embed/bin/ld: prime.c:(.text+0x94): undefined reference to `__modsi3'
/home/dc/riscv-none-embed-gcc/8.2.0-3.1/bin/../lib/gcc/riscv-none-embed/8.2.0/../../../../riscv-none-embed/bin/ld: prime.c:(.text+0xb0): undefined reference to `__modsi3'
/home/dc/riscv-none-embed-gcc/8.2.0-3.1/bin/../lib/gcc/riscv-none-embed/8.2.0/../../../../riscv-none-embed/bin/ld: prime.c:(.text+0xcc): undefined reference to `__modsi3'
/home/dc/riscv-none-embed-gcc/8.2.0-3.1/bin/../lib/gcc/riscv-none-embed/8.2.0/../../../../riscv-none-embed/bin/ld: prime.c:(.text+0xf4): undefined reference to `__modsi3'
/home/dc/riscv-none-embed-gcc/8.2.0-3.1/bin/../lib/gcc/riscv-none-embed/8.2.0/../../../../riscv-none-embed/bin/ld: /tmp/cc4K7mys.o:prime.c:(.text+0x190): more undefined references to `__modsi3' follow
collect2: error: ld returned 1 exit status
```
:::info
RV32I lacks of FPU, and you need software emulation of floating point support. Thus, link to proper libgcc for these routines.
:::
---
## compare with wrong file
### this file is wrong because I manipulate sp.
[tag2]
And this problem is about sp.
### sp = stack pointer
The default of riscv emulator does not allow we change sp(cauz we would ket it lower than 0). In this case, I got a wrong simulation in the oter code.
This problem I do not fix until I check that file and asking others. I think reading that file is quite time consuming.
Wrong
```
dc@dc-VirtualBox:~/rv32emu$ riscv-none-embed-gcc -O3 -nostdlib prime.c -o prime
dc@dc-VirtualBox:~/rv32emu$ ./emu-rv32i prime
>>> Execution time: 300 ns
>>> Instruction count: 1 (IPS=3333333)
>>> Jumps: 0 (0.00%) - 0 forwards, 0 backwards
>>> Branching T=0 (-nan%) F=0 (-nan%)
```
Right
```
dc@dc-VirtualBox:~/rv32emu$ ./emu-rv32i prime
...
>>> Execution time: 23101 ns
>>> Instruction count: 86 (IPS=3722782)
>>> Jumps: 20 (23.26%) - 0 forwards, 20 backwards
>>> Branching T=19 (95.00%) F=1 (5.00%)
```
We can see that intruction count of wrong file if nly 1, which is impossible. Also, the out put is weird. But branching sometimes may be 0, it would cause a NaNfor percentage.
---
### rewrite prime.c
```cpp
#include <stdio.h>
int _start() {
int i = 0;
for (i = 1; i <= 20; i++)
{
int res = 0;
int j = 0;
int last = i / 2;
if (j<= 1) {
res = 0;
}
else{
for (j = 2; j <= last; j++) {
if ((i%j) == 0) {
res = 0;
break;
}
}
}
if(j<=last)res = 1;
if (res==1){
volatile char* tx = (volatile char*) 0x40002000;
int out = i;
*tx = out;
}
}
return 0;
}
```
The first version I use a recursive way, And calling a function named "IsPrimeNumber". In this case, I would change sp during calling function and recursion. moreover, using array woulg also do some work about sp. Therefore, I should whether change my code or change the setting og emulator.
## Using GNU Toolchain
> I used parameter -O3 to compile for wrong file[name=DC]
#### objdump
wrong
```
dc@dc-VirtualBox:~/rv32emu$ riscv-none-embed-objdump -d prime
prime: file format elf32-littleriscv
Disassembly of section .text:
00010054 <IsPrimeNumber>:
10054: 4785 li a5,1
10056: 00a7df63 bge a5,a0,10074 <IsPrimeNumber+0x20>
1005a: 40155693 srai a3,a0,0x1
1005e: 4709 li a4,2
10060: 00e6d563 bge a3,a4,1006a <IsPrimeNumber+0x16>
10064: 4785 li a5,1
10066: 853e mv a0,a5
10068: 8082 ret
1006a: 02e567b3 rem a5,a0,a4
1006e: dfe5 beqz a5,10066 <IsPrimeNumber+0x12>
10070: 0705 addi a4,a4,1
10072: b7fd j 10060 <IsPrimeNumber+0xc>
10074: 4781 li a5,0
10076: bfc5 j 10066 <IsPrimeNumber+0x12>
00010078 <_start>:
10078: 1141 addi sp,sp,-16
1007a: c422 sw s0,8(sp)
1007c: c226 sw s1,4(sp)
1007e: c04a sw s2,0(sp)
10080: c606 sw ra,12(sp)
10082: 4405 li s0,1
10084: 40002937 lui s2,0x40002
10088: 44d5 li s1,21
1008a: 8522 mv a0,s0
1008c: 37e1 jal 10054 <IsPrimeNumber>
1008e: c509 beqz a0,10098 <_start+0x20>
10090: 0ff47793 andi a5,s0,255
10094: 00f90023 sb a5,0(s2) # 40002000 <__global_pointer$+0x3fff0754>
10098: 0405 addi s0,s0,1
1009a: fe9418e3 bne s0,s1,1008a <_start+0x12>
1009e: 40b2 lw ra,12(sp)
100a0: 4422 lw s0,8(sp)
100a2: 4492 lw s1,4(sp)
100a4: 4902 lw s2,0(sp)
100a6: 4501 li a0,0
100a8: 0141 addi sp,sp,16
100aa: 8082 ret
```
Right
```
dc@dc-VirtualBox:~/rv32emu$ riscv-none-embed-objdump -d prime
prime: file format elf32-littleriscv
Disassembly of section .text:
00010054 <_start>:
10054: 00100793 li a5,1
10058: 40002637 lui a2,0x40002
1005c: 01500693 li a3,21
10060: 0ff7f713 andi a4,a5,255
10064: 00e60023 sb a4,0(a2) # 40002000 <__global_pointer$+0x3fff0788>
10068: 00178793 addi a5,a5,1
1006c: fed79ae3 bne a5,a3,10060 <_start+0xc>
10070: 00000513 li a0,0
10074: 00008067 ret
```
We can see that the instuction count are quite different.
The further one got another funtion, we can recognize it by the label for assembly.
Second, We got a lot of lw & sw instructions in further one. That's because I use recursive method.
Plus, first one got lots of j-type instructions, which give the programmer more difficulty for decoding program.
---
#### headfile
wrong
```
dc@dc-VirtualBox:~/rv32emu$ riscv-none-embed-readelf -h prime
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: RISC-V
Version: 0x1
Entry point address: 0x10078
Start of program headers: 52 (bytes into file)
Start of section headers: 584 (bytes into file)
Flags: 0x1, RVC, soft-float ABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 6
Section header string table index: 5
```
Right
```
dc@dc-VirtualBox:~/rv32emu$ riscv-none-embed-readelf -h prime
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: RISC-V
Version: 0x1
Entry point address: 0x10054
Start of program headers: 52 (bytes into file)
Start of section headers: 500 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 1
Size of section headers: 40 (bytes)
Number of section headers: 6
Section header string table index: 5
```
In this part, they don't have much difference.
I was quite surprised by there both using riscv-machine. Due to the error message upon, I thought it was in other scale.
---
#### size
wrong
```
dc@dc-VirtualBox:~/rv32emu$ riscv-none-embed-size prime
text data bss dec hex filename
88 0 0 88 58 prime
```
right
```
dc@dc-VirtualBox:~/rv32emu$ riscv-none-embed-size prime
text data bss dec hex filename
36 0 0 36 24 prime
```
We can see that text is quite different because they got different instruction count.w
### [Assembly code credit to Soonmyun Jang](https://hackmd.io/tqDdrPv1T--w6vk6JS9Q0w?view)
```
.data
argument: .word 20 # Number to find the prime number
str1: .string " is prime number"
.text
main:
# set number
lw a2, argument
li a3, 0
jal ra, Loop1
# Exit program
li a0, 10
ecall
Loop1:
addi a3, a3, 1
blt a3, a2, IsPrime
ret
IsPrime:
li t3, 2
li t4, 1
div t5, a3, t3
blt a3, t3, Loop1
addi t5, t5, 1
j Loop2
Loop2:
addi t4, t4, 1
bge t4, t5, PrintResult
rem t6, a3, t4
beq t6, zero, Loop1 # return
j Loop2
PrintResult:
mv t0, a3
mv a1, t0
li a0, 1
ecall
la a1, str1
li a0, 4
ecall
j Loop1
```
## Note
for wrong file:
cf auto & handwrite
instructions 36 27
auto : use lots of sw, lw;
no ecall replace with ret
less frequent to use j-type intrusctions(3,4)
more frequent to use branch(5, 3)
more frequent to use system call(4,2)
| | objdump | handwrite |
| -------- | -------- | -------- |
| j-type | 3 | 4 |
| branch | 5 | 3 |
| system call | 4 | 2 |
for right file:
| | objdump | handwrite |
| ----------- | ------- | --------- |
| j-type | 0 | 4 |
| branch | 1 | 3 |
| system call | 1 | 2 |
It so obvious that we got a large improvement for new one.
Though I guess the instruction count do more effort on this job than compiler.
correct steps using this simulation
do riscv-none-embed-gcc -march=rv32i -mabi=ilp32 -O3 -nostdlib prime.c -o prime
then got a elf for riscv
then use that toolchain