Help to deal with the toolchain for the processor RISC-V

(Anton) #1

Hey. Installed GNU MCU Eclipse RISC-V Embedded GCC v8.2.0-2.2 20190521. Use riscv-none-embed-as.exe for a simple program. But the results are a little surprised.
When processing code

.section .text
start: add x3, x1, x2
bne x2, x3, 8

The result is:

1 .section .text
3 0000 B3812000 start: add x3, x1, x2
4 0004 63043100 bne x2, x3, 8
4 6F000000
5 000c 63143100 beq x2, x3, 8
5 6F000000

although according to the specification it should be like this:

4 0004 63143100 bne x2, x3, 8
5 000c 63043100 beq x2, x3, 8

yes, and what is 6f000000?
Second question. Why when I write another constant in the beq instruction, the result of the machine instruction does not change and remains the same as for the constant 8?
If instead of a constant I use the label start, then the command generally turns into xE31E31FE.
To assemble using this command:

riscv-none-embed-as -al -o a main.S -fPIC -march = rv32i -mabi = ilp32


(Jim Wilson) #2

“bne x2,x3,8” is asking for a branch to an absolute address 8, but bne is pc-relative, and can’t accept an absolute address as a target, so the assembler changes this to an inverted branch around a jump instruction. If you want to branch to pc+8, then use “bne x2 , x3, .+8”, but in the presence of linker relaxation that might not go where you want if the instruction after it is converted to a compressed instruction, so it is always best to use a label as a target of a branch instruction.

as -al provides a listing file that shows the instructions in the original file, along with the output they generate, but won’t show you macro expansion or relocations, etc. as -al just blindly copies the input file to the output file and adds raw bytes from the output. It isn’t very useful for a target like riscv where we have lots of macros and relocations. You will get much better results if you use objdump instead.

rohan:2011$ riscv32-unknown-elf-objdump -dr a

a: file format elf32-littleriscv

Disassembly of section .text:

00000000 :
0: 002081b3 add gp,ra,sp
4: 00310463 beq sp,gp,c <start+0xc>
8: 0000006f j 8 <start+0x8>

Your question does show that there is a endianness bug in the as -al output. The 6F000000 should instead be 0000006F. This shows up correctly in the objdump output. I will add that to my list of bugs to look at.

(Anton) #3
  1. How to enable / disable linker relaxation?
  2. What is the difference between my toolchain RISC-V Embedded GCC v8.2.0-2.2 20190521 and your riscv32-unknown-elf-objdump?
  3. What file format produces as? elf? or just .o?
  4. When I write

.section .text
bne x2, x3, .8

riscv-none-embed-objdump prints:

0: 00310463 beq sp, gp, 8 <start + 0x8>

Why does he turn instructions into beq?

(Jim Wilson) #4

-mno-relax should be accepted by gcc, and passed to the linker. Or you can pass --no-relax directly to the linker, using -Wl,–no-relax if using gcc to call the linker.

There should be no significant difference between the objdump you have and the one I have. The issue here is that ‘as -al’ doesn’t do what you think it does, and you should use objdump instead.

The ELF specification defines executable files and object files which are similar but not exactly the same. The assembler produces ELF object files, which are conventionally named something.o.

Your testcase has “.8” which isn’t correct. It should be “.+8”. With “.8”, the assembler assumes this is a label, and since this is an undefined label with an unknown address which can’t be assumed to be in range of a branch instruction, it gets converted to an inverted branch followed by a jump, as a jump has a longer range than branch. The inverted branch is why you get beq instead of bne.
rohan:2021$ cat tmp.s
.section .text
bne x2, x3, .8
rohan:2022$ riscv32-unknown-elf-as tmp.s
rohan:2023$ riscv32-unknown-elf-objdump -dr a.out

a.out: file format elf32-littleriscv

Disassembly of section .text:

00000000 :
0: 00310463 beq sp,gp,8 <start+0x8>
4: ffdff06f j 0

If you want code that makes sense, stop writing branches to addresses, and only ever use a label name in the branch, where the label is defined in the code. This is a much better way to write code.

rohan:2026$ cat tmp.s
.section .text
bne x2, x3, 1f
rohan:2027$ riscv32-unknown-elf-as tmp.s
rohan:2028$ riscv32-unknown-elf-objdump -dr a.out

a.out: file format elf32-littleriscv

Disassembly of section .text:

00000000 :
0: 00311463 bne sp,gp,8 <.L1^B1>
4: 00000013 nop