newlib’s reentrant system calls will map to non-reentrant by default

newlib’s reentrant system calls will map to non-reentrant by default

2014/05/04 Kernel Programming 0

newlib’s reentrant system calls will map to non-reentrant by default. The reentrant version of open() can be found in newlib-2.1.0/newlib/libc/reent/openr.c

int
_DEFUN (_open_r, (ptr, file, flags, mode),
     struct _reent *ptr _AND
     _CONST char *file _AND
     int flags _AND
     int mode)
{
  int ret;

  errno = 0;
  if ((ret = _open (file, flags, mode)) == -1 && errno != 0)
    ptr->_errno = errno;
  return ret;
}

As you can see, it will call _open which is defined in newlib-2.1.0/newlib/libgloss/libnosys/open.c . So if you don’t write your reentrant functions, it will jump to non-reentrant by default.

For OS developer want to implement reentrant and non-reentrant function, focus on these two directories newlib-2.1.0/newlib/libc/reent/ and newlib-2.1.0/newlib/libgloss/libnosys

Summary:

Let use open() as an example, newlib defined 4 open() function, they are:

1. newlib-2.1.0/libgloss/libnosys/open.c <– defines open()

2. newlib-2.1.0/newlib/libc/reent/openr.c <– defines _open_r() , which will call to _open()

3. newlib-2.1.0/newlib/libc/syscalls/sysopen.c <– defined open() , which will call to _open_r()

4. newlib-2.1.0/libgloss/open.c <– define open(), and don’t call anything

 

!!! If you just add “syscall_dir=syscalls” to configure.host, only 1,2,4 will be compiled.

What is -DMISSING_SYSCALL_NAMES

“-DMISSING_SYSCALL_NAMES” is just use to rename _open to open, _lseek to sleek and etc… Take a look the file newlib-2.1.0/libgloss/libnosys/open.c:

#include "config.h"
#include <_ansi.h>
#include <_syslist.h>
#include <errno.h>
#undef errno
extern int errno;
#include "warning.h"

int
_DEFUN (_open, (file, flags, mode),
        char *file  _AND
        int   flags _AND
        int   mode)
{
  errno = ENOSYS;
  return -1;
}

stub_warning(_open)

It try to define _open, and _open is defined in _syslist.h:

#ifdef MISSING_SYSCALL_NAMES
#define _close close
#define _execve execve
#define _fcntl fcntl
#define _fork fork
#define _fstat fstat
#define _getpid getpid
#define _gettimeofday gettimeofday
#define _isatty isatty
#define _kill kill
#define _link link
#define _lseek lseek
#define _mkdir mkdir
#define _open open
#define _read read
#define _sbrk sbrk
#define _stat stat
#define _times times
#define _unlink unlink
#define _wait wait
#define _write write
#endif

So if you add “MISSING_SYSCALL_NAMES” to compile option, _open will be rename to open. If you added MISSING_SYSCALL_NAMES, try to disassemble the libnosys.a by command “objdump -dS ./i586-peter-elf/libgloss/libnosys/libnosys.a”, you can see _open is compiled as open:

00000000 <open>:
_DEFUN (_open, (file, flags, mode),

What is -DREENTRANT_SYSCALLS_PROVIDED

If you add it to your compile option in configure.host, all file in newlib-2.1.0/newlib/libc/reent/ will not be compile

Ways to add stubs

Based on this document (Howto: Porting newlib – A Simple Guide – Embecosm), there are total 4 alternatives for specifying how to implement the stubs

1. only “syscall_dir=syscalls”

Define namespace clean versions of the system calls by prefixing them with ‘_’ (eg: _open, _close, etc.). Technically, there won’t be true reentrancy at the syscall level, but the library will be namespace clean. When you do this, set “syscall_dir” to “syscalls” in configure.host.

or32-*-*)
syscall_dir=syscalls
;;

_open_r will be compiled into libc.a and _open will be in libnosys.a

2. “syscall_dir=syscalls” and “-DREENTRANT_SYSCALLS_PROVIDED”

Define the reentrant versions of the syscalls directly. (eg: _open_r, _close_r, etc.). Please keep the namespace clean. When you do this, set “syscall_dir” to “syscalls” and add -DREENTRANT_SYSCALLS_PROVIDED to newlib_cflags in configure.host.

If you add these two options in configure.host

or32-*-*)
syscall_dir=syscalls
newlib_cflags="${newlib_cflags} -DREENTRANT_SYSCALLS_PROVIDED"
;;

_open_r will *NOT* be compiled in libc.a and _open will be in libnosys.a. If you look at file newlib-2.1.0/newlib/libc/reent/openr.c, there is “#ifndef REENTRANT_SYSCALLS_PROVIDED”, so if you provide “REENTRANT_SYSCALLS_PROVIDED”, nothing will be compile.

3. “-DMISSING_SYSCALL_NAMES”

Define or otherwise provide the regular versions of the syscalls (eg: open, close, etc.). The library won’t be reentrant nor namespace clean, but at least it will work. When you do this, add -DMISSING_SYSCALL_NAMES to newlib_cflags in configure.host.

or32-*-*)
      newlib_cflags="${newlib_cflags} -DMISSING_SYSCALL_NAMES"
      ;;

_open_r will be compiled in libc.a and open will be in libnosys.a

4. “-DMISSING_SYSCALL_NAMES” and -DREENTRANT_SYSCALLS_PROVIDED”

Define or otherwise provide the regular versions of the sys calls, and do not supply functional interfaces for any of the reentrant calls. With this method, the reentrant syscalls are redefined to directly call the regular system call without the reentrancy argument. When you do this, specify both -DREENTRANT_SYSCALLS_PROVIDED and -DMISSING_SYSCALL_NAMES via newlib_cflags in configure.host and do not specify “syscall_dir”.

or32-*-*)
      newlib_cflags="${newlib_cflags} -DMISSING_SYSCALL_NAMES"
      newlib_cflags="${newlib_cflags} -DREENTRANT_SYSCALLS_PROVIDED"
      ;;

_open_r will *NOT* be compiled in libc.a and open will be in libnosys.a

Something need to be care

There are two case-switches (case “${host}”) in configure.host, add your machine/target to the second one, because the second-case-switch got a “*)”, otherwise it will always flow to “*)”