How to print value of a register using spike? - riscv

I have an assembly code for RISCV machine.
I have added an instruction to access floating point control and status register and store floating point flags in register a3. I want to print its value to demonstrate that flag gets set when floating point exception occurs.
I tried using spike. There is an instruction in spike(in debug mode) to print value of a register:
: reg 0 a3
to print value of a3.
But first i have to reach my desired point.
I do not know how will i be able to reach that point.
.file "learn_Assembly.c"
.option nopic
.text
.comm a,4,4
.comm b,4,4
.align 1
.globl main
.type main, #function
main:
addi sp,sp,-32
sd s0,24(sp)
addi s0,sp,32
lui a5,%hi(a)
lui a4,%hi(.LC0)
flw fa5,%lo(.LC0)(a4)
fsw fa5,%lo(a)(a5)
lui a5,%hi(b)
lui a4,%hi(.LC1)
flw fa5,%lo(.LC1)(a4)
fsw fa5,%lo(b)(a5)
lui a5,%hi(a)
flw fa4,%lo(a)(a5)
lui a5,%hi(b)
flw fa5,%lo(b)(a5)
fmul.s fa5,fa4,fa5
frflags a3
fsw fa5,-20(s0)
li a5,0
mv a0,a5
ld s0,24(sp)
addi sp,sp,32
jr ra
.size main, .-main
.section .rodata
.align 2
.LC0:
.word 1082130432
.align 2
.LC1:
.word 1077936128
.ident "GCC: (GNU) 8.2.0"
The other option is to somehow write print it using assembly instruction which i am not sure how to do.

To understand the flow of your program , you could create object dump of your program from compiled elf .
To create elf :-
riscv64-unknown-elf-gcc assmebly_code.s -o executable.elf
Then you could create the object dump by :-
riscv64-unknown-elf-objdump -d executable.elf > executable.dump
executable.dump will contains the program flow like this :-
executable.elf: file format elf64-littleriscv
Disassembly of section .text:
00000000000100b0 <_start>:
100b0: 00002197 auipc gp,0x2
100b4: 35018193 addi gp,gp,848 # 12400 <__global_pointer$>
100b8: 81818513 addi a0,gp,-2024 # 11c18 <_edata>
100bc: 85818613 addi a2,gp,-1960 # 11c58 <_end>
100c0: 8e09 sub a2,a2,a0
100c2: 4581 li a1,0
100c4: 1e6000ef jal ra,102aa <memset>
100c8: 00000517 auipc a0,0x0
100cc: 13850513 addi a0,a0,312 # 10200 <__libc_fini_array>
100d0: 104000ef jal ra,101d4 <atexit>
100d4: 174000ef jal ra,10248 <__libc_init_array>
100d8: 4502 lw a0,0(sp)
100da: 002c addi a1,sp,8
100dc: 4601 li a2,0
100de: 0be000ef jal ra,1019c <main>
100e2: 0fe0006f j 101e0 <exit>
....... ........ .................
....... ........ .................
....... ........ .................
Recognize the required pc with required a3 value .
then on spike use command until to run till that pc value :
: until pc 0 <*required pc*>
Note : Your compiler and assembler names may vary.

You can use until spike instruction to execute until a desired equality is reached:
: until pc 0 2020 (stop when pc=2020)
As explain here (interactive debug).
Once value reached you can use reg to read value you want.

Related

Unclear output by riscv objdump -d

Now I am trying to understand the RISC-V ISA but I have an unclear point about the machine code and assembly.
I have written a C code like this:
int main() {
return 42;
}
Then, I produced the .s file by this command:
$ /opt/riscv/bin/riscv64-unknown-linux-gnu-gcc -S 42.c
The output was:
.file "42.c"
.option nopic
.text
.align 1
.globl main
.type main, #function
main:
addi sp,sp,-16
sd s0,8(sp)
addi s0,sp,16
li a5,42
mv a0,a5
ld s0,8(sp)
addi sp,sp,16
jr ra
.size main, .-main
.ident "GCC: (g5964b5cd727) 11.1.0"
.section .note.GNU-stack,"",#progbits
Now, I run following command to produce an elf.
$ /opt/riscv/bin/riscv64-unknown-linux-gnu-gcc -nostdlib -o 42 42.s
So, a binary file is produced. I tried to read that by objdump like this:
$ /opt/riscv/bin/riscv64-unknown-linux-gnu-objdump -d 42
So the output was like this:
42: file format elf64-littleriscv
Disassembly of section .text:
00000000000100b0 <main>:
100b0: 1141 addi sp,sp,-16
100b2: e422 sd s0,8(sp)
100b4: 0800 addi s0,sp,16
100b6: 02a00793 li a5,42
100ba: 853e mv a0,a5
100bc: 6422 ld s0,8(sp)
100be: 0141 addi sp,sp,16
100c0: 8082 ret
What I don't understand is the meaning of the machine code in objdump output.
For example, the first instruction addi is translated into .....0010011 according to this page, (while this is not an official spec). However, the dumped hex is 1141. 1141 can only represent 2 bytes, but the instruction should be 32-bit, 4bytes.
I guess I am missing some points, but how should I read the output of objdump for riscv?
You can tell objdump to show compressed (16-bit) instructions by using -M no-aliases in this way
riscv64-unknown-elf-objdump -d -M no-aliases
In that case, instructions starting with c. are compressed ones.
Unfortunately that will also disable some other aliases, making the asm less nice to read if you're used to them. You can just look at the number of bytes (2 vs. 4) in the hexdump to see if it's a compressed instruction or not.

Where is segment %fs for static elf images setup?

I'm trying to figure out how the %fs register is initialized
when creating a elf image by hand.
The simple snippet I'd like to run is:
.text
nop
movq %fs:0x28, %rax;
1: jmp 1b
Which should read at offset 0x28 in the %fs segment. Normally this is where the stack canary is stored. Because I create the elf image by hand the %fs segment is not setup at all by my code this fails expectedly(?) .
Here is how I create the elf image:
0000000000000000 <.text>:
0: 90 nop
1: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
8: 00 00
a: eb fe jmp 0xa
I create the .text segment via
echo 9064488b042528000000ebfe | xxd -r -p > r2.bin
Then I convert to elf:
ld -b binary -r -o raw.elf r2.bin
objcopy --rename-section .data=.text --set-section-flags .data=alloc,code,load raw.elf
At that point raw.elf contains my instructions. I then link with
ld -T raw.ld -o out.elf -M --verbose where raw.ld is:
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_entry)
PHDRS {
phdr4000000 PT_LOAD;
}
SECTIONS
{
_entry = 0x4000000;
.text 0x4000000 : { raw.elf (.text) } :phdr4000000
}
I can now start out.elf with gdb:
gdb --args out.elf
and set a breakpoint at 0x4000000:
(gdb)break *0x4000000
(gdb)run
The first nop can be stepped via stepi, however the stack canary read mov %fs:0x28,%rax segfaults.
I suppose that is expected given that maybe the OS is not setting up %fs.
For a simple m.c: int main() { return 0; } program compiled with gcc --static m.c -o m I can read from %fs. Adding:
long can()
{
long v = 0;
__asm__("movq %%fs:0x28, %0;"
: "=r"(val)::);
return v;
}
lets me read from %fs - even though I doubt that %fs:28 is setup because ld.so is not run (it is a static image).
Question:
Can anyone point out where %fs is setup in the c runtime for static images?
You need to call arch_prctl with an ARCH_SET_FS argument before you can use the %fs segment prefix. You will have to allocate the backing store somewhere (brk, mmap, or an otherwise unused part of the stack).
glibc does this in __libc_setup_tls in csu/libc-tls.c for statically linked binaries, hidden behind the TLS_INIT_TP macro.

ARM Assembly Branch Segmentation Fault

I'm new to assembly and I'm currently getting a segmentation fault when executing the following:
.global _start # Provide program starting address to linker
_start: mov R0,#0 # A value of 1 indicates "True"
bl v_bool # Call subroutine to display "True" or "False"
mov R0,#0 # Exit Status code of 0 for "normal completion"
mov R7,#1 # Service command 1 terminates this program
svc 0 # Issue Linux command to terminate program
# Subroutine v_bool wil display "True" or "False" on the monitor
# R0: contains 0 implies false; non-zero implies true
# LR: Contains the return address
# Registers R0 through R7 will be used by v_bool and not saved
v_bool: cmp R0,#0 # Set condition flags for True or False
beq setf
bne sett
mov R2,#6 # Number of characters to be displayed at a time.
mov R0,#1 # Code for stdout (standard output, monitor)
mov R7,#4 # Linux service command code to write.
svc 0 # Call Linux command
bx LR # Return to the calling program
sett: ldr R1,=T_msg
setf: ldr R1,=F_msg
.data
T_msg: .ascii "True " # ASCII string to display if true
F_msg: .ascii "False " # ASCII string to display if false
.end
I've used the debugger to find that the causes of the segmentation fault are the two branches sett and setf, and I understand that this is caused by the program trying to write to an illegal memory location.
However, I do not understand why these branches are not able to write to R1, or what I should do to fix this. Any help is greatly appreciated.
The issue is not the instructions themselves. The problem is, after executing the instruction at, for instance setf, the execution continues on to undefined memory. You need to make sure the execution after setf and sett goes back to the code of v_bool.

cross compiling mips: Linker error: cannot find entry symbol __start;

So Im trying to cross compile simple program written in assembly (using MARS) to mips executable.
# Purpose: First program, Hello World
.text # Define the program instructions.
main: # Label to define the main program.
li $v0,4 #Load 4into $v0 to indicate a print string.
la $a0, greeting #Load the address of the greeting into $a0.
syscall #Print greeting. The print is indicated by
# $v0 having a value of 4, and the string to
# print is stored at the address in $a0.
li $v0,10 #Load a 10 (halt) into $v0.
syscall # The program ends.
.data # Define the program data.
greeting: .asciiz "Hello World" #The string to print.
first I use
mips-linux-as ./HelloWorld.asm -o HelloWorld.o
then
mips-linux-ld HelloWorld.o -o HelloWorld
and I get an error
mips-linux-xld: warning: cannot find entry symbol __start; defaulting to 00000000004000b0
Simply adding _start section does not work I get same error.So I written simple program in C (HelloWorld.c) and generated assembly using gcc with following command
mips-linux-gcc -O2 -S -c HelloWorld.c
and there is no _start section
.file 1 "HelloWorld.c"
.section .mdebug.abi32
.previous
.gnu_attribute 4, 3
.abicalls
.section .rodata.str1.4,"aMS",#progbits,1
.align 2
$LC0:
.ascii "Hello Worldn\000"
.text
.align 2
.globl main
.set nomips16
.ent main
.type main, #function
main:
.frame $sp,32,$31 # vars= 0, regs= 1/0, args= 16, gp= 8
.mask 0x80000000,-4
.fmask 0x00000000,0
.set noreorder
.set nomacro
addiu $sp,$sp,-32
sw $31,28($sp)
lui $28,%hi(__gnu_local_gp)
addiu $28,$28,%lo(__gnu_local_gp)
.cprestore 16
lui $4,%hi($LC0)
lw $25,%call16(printf)($28)
jalr $25
addiu $4,$4,%lo($LC0)
move $2,$0
lw $31,28($sp)
j $31
addiu $sp,$sp,32
.set macro
.set reorder
.end main
.size main, .-main
.ident "GCC: (GNU) 4.4.5-1.5.5p4"
So what Im missing ? I would like to run this program on my mips box.
Try adding this to your asm file
.globl main
.ent main
.type main, #function
However, you will need to use MIPS Linux syscalls, and not MARS syscalls.
Here is a working hello-world executable for MIPS on Linux (not on MARS):
# file hello.s
.data
msg: .ascii "Hello, World!\n"
len = . - msg
.text
.globl __start
__start:
li $v0, 4004 # __NR_write == 4004
li $a0, 1 # argument: STDOUT_FILENO
la $a1, msg # argument: message to write
li $a2, len # argument: size of message
syscall
li $v0, 4001 # __NR_exit == 4001
li $a0, 0 # argument: EXIT_SUCCESS
syscall
On Debian and Ubuntu Linux, install the assembler and linker (for compilation) like this:
$ sudo apt-get install binutils-mips-linux-gnu
On Debian and Ubuntu Linux, install the emulator like this:
$ sudo apt-get install qemu-user
Compile to big endian executable like this:
$ mips-linux-gnu-as -EB -mips1 -o hello.o hello.s
$ mips-linux-gnu-ld -s -m elf32btsmip -o hello hello.o
Run the big endian executable in the emulator like this:
$ qemu-mips ./hello; echo $?
Hello, World!
0
Compile to little endian executable like this:
$ mips-linux-gnu-as -EL -mips1 -o hellol.o hello.s
$ mips-linux-gnu-ld -s -m elf32ltsmip -o hellol hellol.o
Run the little endian executable in the emulator like this:
$ qemu-mipsel ./hellol; echo $?
Hello, World!
0

what's %b1(b one, not b L) in `xorb %b1, %b1`?

I am reading the copy_from_user function, in copy_from_user function, the macro __get_user_asm is used.
there is a mmap syscall in linux, mmap syscall will call function copy_from_user. this function will use the macro __get_user_asm if the size is constant. the content of __get_user_asm is
#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \
asm volatile("1: mov"itype" %2,%"rtype"1\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: mov %3,%0\n" \
" xor"itype" %"rtype"1,%"rtype"1\n" \
" jmp 2b\n" \
".previous\n" \
_ASM_EXTABLE(1b, 3b) \
: "=r" (err), ltype(x) \
: "m" (__m(addr)), "i" (errret), "0" (err))
when i try to translate
__get_user_asm(*(u8 *)dst, (u8 __user *)src, ret, "b", "b", "=q", 1); to the real source,
1: movb %2,%b1\n
2:\n
.section .fixup, "ax" \n
3: mov %3, %0 \n
**xorb %b1, %b1\n**
jmp 2b\n
.previous\n
: "=r" (ret), =q(dst)
:"m"(dst), "i"(1), "0"(ret)
.quad "1b", "2b"\n
.previous\n```
,
there are somewhere i can't understand.
1, in xorb %b1, %b1, what's %b1(b one, not b L)?
2, in jmp 2b, is 2b a label or a memroy address? if 2b is a label, how can i find this lable?
3, what's the function of .quad "1b", "2b"?
where can i get the knowledge that make me to understand the linux kernel source in semantics layer?
Reading the docs for gcc's extended asm, we see that %1 refers to the second parameter (because parameter numbers are zero based). In your example, that's dst.
Adding b (ie %b1) is described here:
Modifier Description Operand masm=att masm=intel
b Print the QImode name of the register. %b0 %al al
jmp 2b means look backward for a label named 2.
The .quad directive is defined here:
.quad expects zero or more bignums, separated by commas. For each
bignum, it emits an 8-byte integer. If the bignum won't fit in 8
bytes, it prints a warning message; and just takes the lowest order 8
bytes of the bignum.
As for where to get info, hopefully the links I have provided help.
XOR any register with itself sets it to zero. So %B1 = 0.

Resources