10

I am trying to retarget printf() function for STM32F411RET microcontroller in ARM GCC toolchain environment which uses Newlib for standard C library.

When I search for how to retarget printf(), many people says I need to implement _write() or _write_r(). And it seems both working.

But I still have questions about them:

  1. When I look through the document of Newlib, it says I can implement write() to output files, but it doesn't look working. It looks like we can implement _write() but this function never be mentioned in the document. What happend to write()? does an underscore make anything different?

  2. In which situation _write_r() is preferable than _wirte()? I don't understand the concept of reenterncy in C. Any examples?

Thanks for reading this.

Bumsik Kim
  • 5,853
  • 3
  • 23
  • 39
  • 2
    Since Standard C doesn't define a `write` function, conforming programs are allowed to define their own function (or variable) named `write` without it changing how `printf` behaves. This means that `printf` can't use a function named `write`, it has to use a function with a name that conforming programs aren't allowed to use, like say `_write`. – Ross Ridge Aug 17 '15 at 02:31
  • 3
    `write()` will work with `open()`; they are standard POSIX type functions. The special files number 0, 1, 2 are for stdin, stdout, stderr (typically). You write the implementation of these for newlib and if the file is >2 then it is some special file which you must index somehow. Ie, the `open()` would have specified a desired file to write to and returned a file number >2. **USER code must not rely on these values**. However, implementers need to define something. – artless noise Aug 17 '15 at 12:53
  • 3
    Not a direct answer to your question but [this printf.c](http://geezer.osdevbrasil.net/osd/libc/printf.c) implementation is very easy to port to microcontrollers. I've used it several times and never had a problem with it except for one caveat: some compilers will optimize `printf` to `puts` and in the process break everything. In this case you can either implement `puts` too or rename printf to something else. – Brian McFarland Aug 18 '15 at 21:06
  • 2
    Pinetwig gave an excellent response below. One important point I'd like to make: "open()", "write()" and friends are *usually thin wrappers around the underlying system calls*. Unlike "printf()" (which is complicated code fully implemented in the C library), "write()" is usually just a minimal C interface to the OS. I'm not sure you want to mess with it... – paulsm4 Aug 24 '15 at 06:44
  • 1
    PS: Here's a good discussion of ["reentrancy'](https://en.wikipedia.org/wiki/Reentrancy_%28computing%29). It's important to note that "reentrancy" is closely related to "thread safety", but *they are not the same*. For example, a subroutine might call itself (or call a nested function that in turn calls it again), and Bad Things can happen if it maintains any "static" data. A good example is ["strtok()"](http://linux.die.net/man/3/strtok), which is neither thread-safe nor reentrant. – paulsm4 Aug 24 '15 at 06:51

1 Answers1

4

For the first question, it's because Newlib wants to avoid name clashes ("namespace clean versions") by prepending an underscore to the name. See also Why do C compilers prepend underscores to external names?

For the second question, see Reentrancy and Reentrant in C?. If you have a multi-threaded program running on your board, and multiple threads can call newlib functions, then you need to use the reentrant versions of the syscalls. You also need to use reentrant syscalls if interrupt handlers can call newlib functions. However, it's perfectly okay to use the reentrant syscalls in a single-threaded application.

For example, if you use non-reentrant syscalls in a multi-threaded application, there's just one single global errno-flag. If errors occur in two or more threads, the global errno value can be overwritten. In the reentrant syscalls, each thread has its own errno-flag (in the _reent-struct - see here for the implementation). Thus, each thread can check for and handle its own errors.

Note: You have to recompile newlib to select what syscall model you want to use. See http://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html#sec_configure_host .

Community
  • 1
  • 1
Pinetwig
  • 673
  • 5
  • 13