Using newlib in simulators.

J. Johnston
Tue Mar 19 13:54:00 GMT 2002

Recently, I have received two questions regarding newlib and simulators.

"Karthick.P.T" wrote:
> Hi all,
>          I just got to know about newlib.  I went through some little
> documentations of newlib.  Now, I want to use newlib in my simulator,  so
> please could I  get the answers for the following :-
> 1)  Should I write my own system call implementation to use newlib, so that
> I can run the application correctly?
> 2)  If I have to write my implementation for sys calls,  is it just enough
> to write into 17 stubs in newlib?  Or should I do something more to use
> newlib in simulator?
> 3)  Is there any other approach through which I can get library support in
> the simulator?

"Shrikar" wrote

> Hi,
> I am New to this mailing list. I have some basic and small doubts regarding
> Newlib.
> I want to know where can I get the information about adding a new target to
> the newlib ? Also I want know that is it possible to add a "simulated
> target" to newlib ?.
> If  'yes' then how really it differes from adding a regular target ?

I might as well answer both these questions at the same time.

First of all, newlib sits on a OS syscall layer.  Besides the syscall layer,
there is no difference when targetting newlib for a simulator vs a real
target.  This is intentional.  What this means is that you only have to change
the low layer syscalls and you can run the code on various evaluation boards
or just the simulator.

The syscall layer for a new platform belongs in libgloss (sibling to newlib directory). 
There are examples where this is not true, but they are simply historic and you
should ignore them.

For a new platform, you want to add a platform directory in newlib/libc/machine.
In this directory, you want to add your setjmp/longjmp implementation.  See
newlib/libc/machine/fr30 for example.  You need to alter newlib/libc/include/machine/setjmp.h
to add your jmp_buf structure.  Typically, a compiler for your platform will define
a special flag to indicate that platform (e.g. __PLATFORM_X__).  You will see that
platforms key off of such special flags so they may define their version of jmp_buf.

In addition to your machine directory, you want to specify various things like
data endianness, IEEE endianness, and in some cases, special items such as
"doubles are 32-bits".  If you look at newlib/libc/include/sys/config.h you will
see examples of what you need to define.  The IEEE endianness needs to specified
in newlib/libc/include/machine/ieeefp.h.  As before, you can use your __PLATFORM_X__

Now, you have to add your platform to the configuration.  This is easy to do in
newlib/  In there, you will specify your machine directory created
earlier.  Note that are tabs required in some places and you should be careful
to ensure they are used when needed.  See what similar entries use or copy sections 
within the file to make sure you get it right.

Regarding the syscall layer, you have some choices.  Read newlib/libc/include/reent.h
for details.  The choices involve the external names and whether reentrancy is supported.
Look at the mn10300 if you want a standard example.

Now, there is the question about what to put in libgloss for the simulator.  The key
to note is that they are syscalls so the most work you have to do is to figure
out how to code a syscall for the simulator.  If you are the writer of the simulator,
you have complete flexibility.  The only requirement is that the simulator recognizes the
syscall and knows how to extract parameters.  If there isn't a syscall insn in the
insn set, you might try to use a designated trap or interrupt number.  Failing that, you
can steal an unused opcode or even set it up as a write to a special memory location.
It doesn't matter.  The layer is just for the simulator so it can be anything as long
as you adhere to whatever the simulator expects.  You obviously don't want to choose
something likely to be generated by the C compiler or else you will be seeing extraneous
syscalls out of nowhere.  If you are not the writer of the simulator, you will have
to find out what it expects.

Typically, once the simulator recognizes a syscall, it uses a similar call on the
native platform that the simulator is running on.  This may require endianness
reversal, fetching of arguments into temporaries, whatever, depending on the platform
and the host.  For example, a open syscall may just translate to be an open of the
file locally.

Take a look at some of the libgloss libraries in place (e.g. mn10300, m32r).  Note how
they set up a trap or interrupt routine which actually makes a generic syscall.  The open,
close, read, etc.. routines are quite trivial once this is set up and you can copy
them.  In some cases, platforms define special linker scripts (.ld files).  These are
used when the default linker doesn't output what is needed to run programs on the
simulator (e.g. you need a bigger stack than the default given by the linker).
You should try without one first and then see if it is needed.

-- Jeff J.

More information about the Newlib mailing list