# 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