RISC-V ADDI instruction - riscv

I am currently working on implementing RV32I Base Instruction Set.
I had a question about ADDI instruction. In the manual, how to understand this clause "ADDI rd, rs1, 0 is used to implement the MV rd, rs1 assembler pseudo-instruction."
Does it mean ADDI rd, rs1, 0 is equal to move content of rs1 to register specified by rd?

yes ADDI rd, rs1, 0 performs the operation :
rd <- rs1 + 0, that is rd <- rs1
so ADDI rd, rs1, 0 performs MV rd, rs1
It does not performs a move (copy is a better word) of the content of rs1 to the register specified by rd as mentionned in the question.
It performs a move (copy again) of the content of rs1 to the register rd.
With an example :
ADDI x3, x5, 0 will copy the content of x5 to x3 - and using the same name as above, in this example : rd is x3 and rs1 is x5.

The mv x, y (move) pseudo-instruction is just an alias for addi x, y, 0. That means it's syntactic sugar that is implemented inside the assembler.
Since the mv alias is resolved by the assembler mv doesn't have its own opcode and thus isn't a real instruction. Hence it's called a pseudo-instruction.
Using the mv pseudo-instruction arguably describes the purpose of your code more clearly. Certainly, it's slightly less to type and less to parse for a human.

Yes, ADDI rd, rs1, 0 is the encoding of the MV rd, rs1 instruction.
Many encodings are possible, e.g. XORI rd, rs1, 0 would have the same effect.
The reason for specifying which is the chosen encoding is so a disassembler will output MV rd, rs1 when it sees ADDI rd, rs1, 0, but XORI rd, rs1, 0 will still be disassembled as XORI rd, rs1, 0.
Other instructions have specified encodings, such as NOP being ADDI x0, x0, 0, rather than any of the other instructions which do nothing. Note: register 0 is magic. It always reads as zero, thus writes are lost.
MV instructions set one register's value equal to another register's value, so they would be better described as "copy", as #LiHenyuan wrote.

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.

How to print value of a register using spike?

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.

Understanding how $ works in assembly [duplicate]

len: equ 2
len: db 2
Are they the same, producing a label that can be used instead of 2? If not, then what is the advantage or disadvantage of each declaration form? Can they be used interchangeably?
The first is equate, similar to C's:
#define len 2
in that it doesn't actually allocate any space in the final code, it simply sets the len symbol to be equal to 2. Then, when you use len later on in your source code, it's the same as if you're using the constant 2.
The second is define byte, similar to C's:
int len = 2;
It does actually allocate space, one byte in memory, stores a 2 there, and sets len to be the address of that byte.
Here's some pseudo-assembler code that shows the distinction:
line addr code label instruction
---- ---- -------- ----- -----------
1 0000 org 1234h
2 1234 elen equ 2
3 1234 02 dlen db 2
4 1235 44 02 00 mov ax, elen
5 1238 44 34 12 mov ax, dlen
Line 1 simply sets the assembly address to be 1234h, to make it easier to explain what's happening.
In line 2, no code is generated, the assembler simply loads elen into the symbol table with the value 2. Since no code has been generated, the address does not change.
Then, when you use it on line 4, it loads that value into the register.
Line 3 shows that db is different, it actually allocates some space (one byte) and stores the value in that space. It then loads dlen into the symbol table but gives it the value of that address 1234h rather than the constant value 2.
When you later use dlen on line 5, you get the address, which you would have to dereference to get the actual value 2.
Summary
NASM 2.10.09 ELF output:
db does not have any magic effects: it simply outputs bytes directly to the output object file.
If those bytes happen to be in front of a symbol, the symbol will point to that value when the program starts.
If you are on the text section, your bytes will get executed.
Weather you use db or dw, etc. that does not specify the size of the symbol: the st_size field of the symbol table entry is not affected.
equ makes the symbol in the current line have st_shndx == SHN_ABS magic value in its symbol table entry.
Instead of outputting a byte to the current object file location, it outputs it to the st_value field of the symbol table entry.
All else follows from this.
To understand what that really means, you should first understand the basics of the ELF standard and relocation.
SHN_ABS theory
SHN_ABS tells the linker that:
relocation is not to be done on this symbol
the st_value field of the symbol entry is to be used as a value directly
Contrast this with "regular" symbols, in which the value of the symbol is a memory address instead, and must therefore go through relocation.
Since it does not point to memory, SHN_ABS symbols can be effectively removed from the executable by the linker by inlining them.
But they are still regular symbols on object files and do take up memory there, and could be shared amongst multiple files if global.
Sample usage
section .data
x: equ 1
y: db 2
section .text
global _start
_start:
mov al, x
; al == 1
mov al, [y]
; al == 2
Note that since the symbol x contains a literal value, no dereference [] must be done to it like for y.
If we wanted to use x from a C program, we'd need something like:
extern char x;
printf("%d", &x);
and set on the asm:
global x
Empirical observation of generated output
We can observe what we've said before with:
nasm -felf32 -o equ.o equ.asm
ld -melf_i386 -o equ equ.o
Now:
readelf -s equ.o
contains:
Num: Value Size Type Bind Vis Ndx Name
4: 00000001 0 NOTYPE LOCAL DEFAULT ABS x
5: 00000000 0 NOTYPE LOCAL DEFAULT 1 y
Ndx is st_shndx, so we see that x is SHN_ABS while y is not.
Also see that Size is 0 for y: db in no way told y that it was a single byte wide. We could simply add two db directives to allocate 2 bytes there.
And then:
objdump -dr equ
gives:
08048080 <_start>:
8048080: b0 01 mov $0x1,%al
8048082: a0 88 90 04 08 mov 0x8049088,%al
So we see that 0x1 was inlined into instruction, while y got the value of a relocation address 0x8049088.
Tested on Ubuntu 14.04 AMD64.
Docs
http://www.nasm.us/doc/nasmdoc3.html#section-3.2.4:
EQU defines a symbol to a given constant value: when EQU is used, the source line must contain a label. The action of EQU is to define the given label name to the value of its (only) operand. This definition is absolute, and cannot change later. So, for example,
message db 'hello, world'
msglen equ $-message
defines msglen to be the constant 12. msglen may not then be redefined later. This is not a preprocessor definition either: the value of msglen is evaluated once, using the value of $ (see section 3.5 for an explanation of $) at the point of definition, rather than being evaluated wherever it is referenced and using the value of $ at the point of reference.
See also
Analogous question for GAS: Difference between .equ and .word in ARM Assembly? .equiv seems to be the closes GAS equivalent.
equ: preprocessor time. analogous to #define but most assemblers are lacking an #undef, and can't have anything but an atomic constant of fixed number of bytes on the right hand side, so floats, doubles, lists are not supported with most assemblers' equ directive.
db: compile time. the value stored in db is stored in the binary output by the assembler at a specific offset. equ allows you define constants that normally would need to be either hardcoded, or require a mov operation to get. db allows you to have data available in memory before the program even starts.
Here's a nasm demonstrating db:
; I am a 16 byte object at offset 0.
db '----------------'
; I am a 14 byte object at offset 16
; the label foo makes the assembler remember the current 'tell' of the
; binary being written.
foo:
db 'Hello, World!', 0
; I am a 2 byte filler at offset 30 to help readability in hex editor.
db ' .'
; I am a 4 byte object at offset 16 that the offset of foo, which is 16(0x10).
dd foo
An equ can only define a constant up to the largest the assembler supports
example of equ, along with a few common limitations of it.
; OK
ZERO equ 0
; OK(some assemblers won't recognize \r and will need to look up the ascii table to get the value of it).
CR equ 0xD
; OK(some assemblers won't recognize \n and will need to look up the ascii table to get the value of it).
LF equ 0xA
; error: bar.asm:2: warning: numeric constant 102919291299129192919293122 -
; does not fit in 64 bits
; LARGE_INTEGER equ 102919291299129192919293122
; bar.asm:5: error: expression syntax error
; assemblers often don't support float constants, despite fitting in
; reasonable number of bytes. This is one of the many things
; we take for granted in C, ability to precompile floats at compile time
; without the need to create your own assembly preprocessor/assembler.
; PI equ 3.1415926
; bar.asm:14: error: bad syntax for EQU
; assemblers often don't support list constants, this is something C
; does support using define, allowing you to define a macro that
; can be passed as a single argument to a function that takes multiple.
; eg
; #define RED 0xff, 0x00, 0x00, 0x00
; glVertex4f(RED);
; #undef RED
;RED equ 0xff, 0x00, 0x00, 0x00
the resulting binary has no bytes at all because equ does not pollute the image; all references to an equ get replaced by the right hand side of that equ.

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.

ARM inline asm: exit system call with value read from memory

Problem
I want to execute the exit system call in ARM using inline assembly on a Linux Android device, and I want the exit value to be read from a location in memory.
Example
Without giving this extra argument, a macro for the call looks like:
#define ASM_EXIT() __asm__("mov %r0, #1\n\t" \
"mov %r7, #1\n\t" \
"swi #0")
This works well.
To accept an argument, I adjust it to:
#define ASM_EXIT(var) __asm__("mov %r0, %0\n\t" \
"mov %r7, #1\n\t" \
"swi #0" \
: \
: "r"(var))
and I call it using:
#define GET_STATUS() (*(int*)(some_address)) //gets an integer from an address
ASM_EXIT(GET_STATUS());
Error
invalid 'asm': operand number out of range
I can't explain why I get this error, as I use one input variable in the above snippet (%0/var). Also, I have tried with a regular variable, and still got the same error.
Extended-asm syntax requires writing %% to get a single % in the asm output. e.g. for x86:
asm("inc %eax") // bad: undeclared clobber
asm("inc %%eax" ::: "eax"); // safe but still useless :P
%r7 is treating r7 as an operand number. As commenters have pointed out, just omit the %s, because you don't need them for ARM, even with GNU as.
Unfortunately, there doesn't seem to be a way to request input operands in specific registers on ARM, the way you can for x86. (e.g. "a" constraint means eax specifically).
You can use register int var asm ("r7") to force a var to use a specific register, and then use an "r" constraint and assume it will be in that register. I'm not sure this is always safe, or a good idea, but it appears to work even after inlining. #Jeremy comments that this technique was recommended by the GCC team.
I did get some efficient code generated, which avoids wasting an instruction on a reg-reg move:
See it on the Godbolt Compiler Explorer:
__attribute__((noreturn)) static inline void ASM_EXIT(int status)
{
register int status_r0 asm ("r0") = status;
register int callno_r7 asm ("r7") = 1;
asm volatile("swi #0\n"
:
: "r" (status_r0), "r" (callno_r7)
: "memory" // any side-effects on shared memory need to be done before this, not delayed until after
);
// __builtin_unreachable(); // optionally let GCC know the inline asm doesn't "return"
}
#define GET_STATUS() (*(int*)(some_address)) //gets an integer from an address
void foo(void) { ASM_EXIT(12); }
push {r7} # # gcc is still saving r7 before use, even though it sees the "noreturn" and doesn't generate a return
movs r0, #12 # stat_r0,
movs r7, #1 # callno,
swi #0
# yes, it literally ends here, after the inlined noreturn
void bar(int status) { ASM_EXIT(status); }
push {r7} #
movs r7, #1 # callno,
swi #0 # doesn't touch r0: already there as bar()'s first arg.
Since you always want the value read from memory, you could use an "m" constraint and include a ldr in your inline asm. Then you wouldn't need the register int var asm("r0") trick to avoid a wasted mov for that operand.
The mov r7, #1 might not always be needed either, which is why I used the register asm() syntax for it, too. If gcc wants a 1 constant in a register somewhere else in a function, it can do it in r7 so it's already there for the ASM_EXIT.
Any time the first or last instructions of a GNU C inline asm statement are mov instructions, there's probably a way to remove them with better constraints.

Resources