GNU MCU Eclipse

Hi All,

Many of you may be familiar with Liviu Ionescu’s project called GNU ARM Eclipse and it’s set of Eclipse plugins for ARM MCU development.

I’m proud to announce that we have been working with Liviu over the past few months in order to help his project support SiFive CPUs and RISC-V in general. As such Liviu has recently rebranded his website to GNU MCU Eclipse and published all of the RISC-V work he has been doing. Please check out his website here:
https://gnu-mcu-eclipse.github.io/

We use Liviu’s plugins in Freedom Studio and are continuing to work with Liviu to ensure that SiFive and RISC-V have the best open source development tools available.

Liviu also maintains a binary distribution of RISC-V GCC and OpenOCD. His current distribution of RISC-V GCC includes newlib-nano, a C standard library which significantly reduces code size of standard library functions such as printf.

For the global_interrupts example targeting the E31 Coreplex Arty FPGA image, simply enabling newlib-nano reduced the application size from 64.78kB to 10kB!

We are looking into incorporating newlib-nano into Freedom-E-SDK as well as our binary gcc distributions. Until then, please feel free to try out newlib-nano using the GNU-MCU-Eclipse distribution linked below:

After installing the GNU-MCU-Eclipse toolchain, you can tell Freedom Studio to use it by clicking Window – Preferences – MCU – RISC-V Toolchain and setting the path to the newly installed toolchain’s bin directory. From there you can enable newlib-nano for a specific project by selecting a project and clicking Project – Properties – C/C++ Build – Settings – Linker – Miscellaneous and checking the box for Use newlib-nano. Then clean and re-build for reduced code size!

4 Likes

A new version of the GNU MCU Eclipse plug-ins was released; it includes a template plug-in to create projects for the SiFive boards:

GNU MCU Eclipse plug-ins v4.2.1-201711101735 released

A new version of the RISC-V Embedded GCC was released; apart from updating to the latest GCC 7.2 for RISC-V, the main improvement is in GDB, which no longer returns the 4096 CSRs together with the general registers.

GNU MCU Eclipse RISC-V Embedded GCC v7.2.0-1-20171109 released

Hi,
I just trying out GNU MCU Eclipse and also your RISCV toolchain. I run into some problems now which I need to sort out.
I understand that your toolchain is not linking libgloss by default. I have a special case where I just want the syscall implementation linked in. My understanding is that I just need to link libgloss with -lgloss. But this didn’t work, I just get linker errors for missing _write, etc. functions. When I dump libgloss.a with objdump it implements all the functions as wrapper around an ecall. What I’m missing?

Yes, you are right, the entire libgloss issue is problematic. Why do you need libgloss? The current RISCV toolchain is not a bare-metal toolchain, it targets applications that run in a Linux-like environment, and for this reason, libgloss indeed makes use of linux calls via ECALLs.

In traditional bare-metal environments, like the ARM toolchain, libgloss is implemented on top of the semihosting API. For the moment the semihosting calls for RISC-V are in design phase. In a future version of the GNU MCU Eclipse toolchain, libgloss will make use of the semihosting calls.

As for the underscore functions, the story is a bit more complicated. Inside newlib, the flow for the stdio function is layered, for example if your application calls write(), internally it calls the reentrant write_r(), which finally calls the user supplied _write().

‘User supplied’ means exactly this, if your application uses stdio calls, it needs to supply the implementation of several functions (on a bare-metal device there is no kernel to handle these calls).

As for the differences between the toolchains, the original RISCV toolchain, due to a misconfiguration, shorcut the above flow, and directly called the linux kernel. The GNU MCU Eclipse toolchain fixed this and the bare-metal applications need to provide the implementations. The next version of the RISC-V toolchain will also use underscore functions.

Since I do not know your application, (Linux vs bare-metal), it is hard to make a sugestion, but if you are interrested in bare-metal application, the easiest way to sort out these problems is to use the Eclipse project template, it already includes implementations for the underscore functions, and the projects are ready to run.

Hi,
in the meantime I have found the problem, it is was just a problem with library ordering. I had to add -lg before -lgloss. It seems that by default all implicitly linked libraries like libg are linked after the explicitly invoked.
Just for completeness I just want to tell you why I want add syscalls:

My project is a own RISC-V implementation running on an FPGA. It contains a boot loader which also implements a simple syscall interface like the proxy kernel in spice (In fact I just copied the syscall interface of riscv-pk into it and adapted it).
The idea was that I can run the same binaries on spike and on the harware, this was a handy feature in the beginning. In the meantime this is not so important anymore, I’m considering removing the the syscall interface to reduce the size of the bootloader.

In general the project is more close to an embedded platform, I did not plan to make it Linux capable. I’m currently in the process of publishing my work, and therefore I want to make it easy for people to get started. So I’m testing your toolchain as one option for a precompiled toolchain. In contrast to the SiFive downloads it is much smaller, I think because it is missing all the Linux stuff. This is nice e.g. for docker containers, etc.

On the other hand I notice the fragmentation in the tool chains. Your variant is a bit different from SiFives. What I’m also missing is any form of “Release notes” for the toolchain. In the past I once in a while updated my toolchain from the original repo and recompiled. It was then always a nice journey to adapt all my code to compile with the new build. In the last months thinks seem to have settled and are more stable.

Today I adapted all my Makefiles that they can work with riscv32-unknown-elf* (which my own builds still use…), riscv64-unknown-elf and now also riscv-none-embed

Nevertheless many thanks for your effforts, generally your toolchain build fits my needs very well.

The linker will only pull object files from a library if they resolve an undefined reference. User specified libraries are included before compiler specified libraries. So suppose you have a hello work program you are trying to link. You add -lgloss to the command line. The linker looks at libgloss first, and sees only an undefined reference to printf which is not in libgloss, so libgloss is ignored. Then it looks at libc.a, finds printf, and now it has an undefined reference to write, but it is at the end of the library list, and so prints an error. To solve this problem you need to force libc.a before libgloss.a, which means you need to specify -lc -lgloss when linking. But because of interdependencies between libgloss and newlib, you might actually need -lc -lgloss -lc -lgloss to get everything right. There are linker options --start-group and --end-group that you can use to simplify this, they will iterate over a group of libraries until nothing changes.

It is usually best to use a specs file rather than manually specify this stuff. I thought GNU MCU Eclipse used specs files, but I don’t have a copy of look at right now. The latest version of riscv-gnu-toolchain does provide a few specs files. They should be in the install dir $target/lib/*specs. So for instance you can give gcc the option --specs=sim.specs and it will automatically link in some libgloss libraries the correct way. If there isn’t a specs file that does exactly what you need, you can make a copy of one, and modify it to do what you need.

Also, as Liviu mentioned, if your target is anything other than a simulator, then calling a syscall it unlikely to do anything useful. The semihosting support is not there yet. I would expect a rom monitor on the board that has routines that libgloss can call, for instance to write a char to the serial line, but apparently no such thing exists for RISC-V yet.

There is an extensive Release notes page, you can reach it by clicking the Continue reading » link in each release page.

It uses specs files for newlib nano.

Since the current RISC-V libgloss makes system calls, it is less useful for bare-metal applications, and I kind of ignored it.

In a future release I’ll update libgloss to use semihosting calls, and also check/update the specs file for it, if necessary.

Yes, I’m aware. My remark was more focused on the original RISC-V toolchain. I think you have also just done your fork on some arbitrary point in time.

Recently I realized that there is an excellent series of blog posts under the title “All Aboard” from Palmer Dabbelt in the SiFive Blog wich discusses a lot of aspects not only about GCC, but also covering the ABI, Linux boot, memory management, etc.

I can only recommend reading it. Anyway, one side effect diving into RISC-V is becoming a GCC expert :slight_smile:

I have found that the pre-compiled libraries included with the GNU MCU Eclipse v7.2.0 pre-built toolchain do not support the medany code model. This code model must be used if you wish to locate an RV64 executable above the memory address 0x80000000, as explained here.

To see the problem compile this hello world program:

#include <stdio.h>

int main () {
  printf("Hello World\n");
}

There is no problem using the following command, which will locate the executable at the default linker script text address 0x10000:

riscv-none-embed-gcc hello.c -o hello.elf -lg -lgloss

(Note that in order to avoid a linker error the -lg -lgloss options are required as explained here.)

But if we try to relocate the program to the HiFiveUnleashed DRAM memory location (0x80000000) we get the following error:

$ riscv-none-embed-gcc hello.c -o hello.elf -lg -lgloss -Ttext=0x80000000 -mcmodel=medany
/scratch/gnu-mcu-eclipse/riscv-none-gcc/7.2.0-3-20180506-1300/bin/../lib/gcc/riscv-none-embed/7.2.0/../../../../riscv-none-embed/lib/rv64imafdc/lp64d/libg.a(lib_a-exit.o): In function `.L0 ':
exit.c:(.text.exit+0xe): relocation truncated to fit: R_RISCV_HI20 against symbol `_global_impure_ptr' defined in .sdata._global_impure_ptr section in /scratch/gnu-mcu-eclipse/riscv-none-gcc/7.2.0-3-20180506-1300/bin/../lib/gcc/riscv-none-embed/7.2.0/../../../../riscv-none-embed/lib/rv64imafdc/lp64d/libg.a(lib_a-impure.o)
/scratch/gnu-mcu-eclipse/riscv-none-gcc/7.2.0-3-20180506-1300/bin/../lib/gcc/riscv-none-embed/7.2.0/../../../../riscv-none-embed/bin/ld: final link failed: Symbol needs debug section which does not exist
collect2: error: ld returned 1 exit status

The problem is that the pre-built library lib/rv64imafdc/lp64d/libg.a was built with -mcmodel=medlow, which means its object files cannot be located at an address above 2GiB. (Note this problem only occurs when building RV64 executables - it is not an issue for RV32 executables.)

The solution is to provide libraries compiled with -mcmodel=medany, as then the object files would be compatible with both the medlow and medany code models. (This has been done with the libraries provided by Microsemi in their SoftConsole product, for example)

I understand that there can be a performance/code size penalty for using the medany code model, but users wishing to optimize for this can build their own libraries if that is important. The prebuilt libraries should try to be as widely compatible as possible.

As I already mentioned, this will avoid linker errors, but if you call any of the IO functions, your device will trap while trying to execute an ECALL.

Suport for semihosting is available in GNU MCU Eclipse OpenOCD, and the projects generated by the SiFive templates can be configured to use semihosting, so there is no need to link with the inapropriate libgloss.

Thanks - I am not familiar with the OpenOCD semihosting and I will look into it.

As for not linking with libgloss, I tried linking with libnosys but found that the symbol names in that precompiled library are missing the leading ‘_’ so they do not link. I saw a reference somewhere that this is intentional and that the ‘_’ functions should be provided by the user, but it seems that should not be necessary for the case where semihosting is being used on the _read, _open, … functions.

In our case, we assume either a Software Execution Environment or semihosting is present to handle the ECALL traps, so libgloss seems to be the correct approach.

semihosting uses EBREAK, not ECALL

no, libnosys should provide exactly the underscore functions expected by newlib. if it does not, most probably libnosys is out of date, or at least out of sync with newlib.

Looks like this may be an error the. Here is what I see in libnosys.a in the 7.2.0-3-20180506-1300 release:

$ riscv-none-embed-nm ./riscv-none-embed/lib/rv32imac/ilp32/libnosys.a | grep " T "
00000000 T _chown
00000000 T close
00000000 T execve
00000000 T fork
...

Note no ‘_’ on the symbols, while for libgloss.a the ‘_’ is present:

]$ riscv-none-embed-nm ./riscv-none-embed/lib/rv32imac/ilp32/libgloss.a | grep " T "
00000000 T nanosleep
00000000 T clock_gettime
00000000 T _access
00000000 T _chdir
00000000 T _chmod
00000000 T _chown
00000000 T _close

Should I file an issue for this?

yes, to the RISC-V project.

It looks like we are just missing two lines in the libnosys configure.in. This was missed when the syscall naming bug was fixed last Fall. Newlib was patched to fix this, but it turns out this also needed a nonobvious libnosys patch. I haven’t done any real testing of this yet.

	libgloss/
	* libnosys/configure.in: Don't define MISSING_SYSCALL_NAMES for riscv.
	* libnosys/configure: Regenerated.

diff --git a/libgloss/libnosys/configure b/libgloss/libnosys/configure
index fbe7db7..b5e5cf1 100755
--- a/libgloss/libnosys/configure
+++ b/libgloss/libnosys/configure
@@ -2033,6 +2033,8 @@ case "${target}" in
 	;;
   powerpcle-*-pe)
 	;;
+  riscv*-*-*)
+	;;
   sh*-*-*)
 	;;
   sparc-sun-sunos*)
diff --git a/libgloss/libnosys/configure.in b/libgloss/libnosys/configure.in
index 1d4846b..7f73236 100644
--- a/libgloss/libnosys/configure.in
+++ b/libgloss/libnosys/configure.in
@@ -67,6 +67,8 @@ case "${target}" in
 	;;
   powerpcle-*-pe)
 	;;
+  riscv*-*-*)
+	;;
   sh*-*-*)
 	;;
   sparc-sun-sunos*)

I just published GNU MCU Eclipse RISC-V Embedded GCC v7.2.0-4-20180606 that fixes the problem:

https://gnu-mcu-eclipse.github.io/blog/2018/06/07/riscv-none-gcc-v7-2-0-4-20180606-released/