Skip to content

Commit 1eba346

Browse files
committedAug 13, 2021
tinystdio: Use simple globals for stdin/stdout/stderr
This swaps the __iob array for global variables, which conform to the POSIX spec more closely, avoid using array indexing which might generate longer code on some platforms and allow sharing all three in a single location in ROM with symbol aliasing. This changes the tinystdio API/ABI in an incompatible fashion, which applications can use the new PICOLIBC_STDIO_GLOBALS definition to check for. Signed-off-by: Keith Packard <[email protected]>
1 parent 3a3b5c9 commit 1eba346

File tree

8 files changed

+82
-30
lines changed

8 files changed

+82
-30
lines changed
 

‎doc/build.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,14 @@ types and formats.
6464

6565
These options apply when tinystdio is enabled, which is the
6666
default. For stdin/stdout/stderr, the application will need to provide
67-
`__iob`, which is an array of three pointers to FILE structures (which
68-
can be a single shared FILE structure).
67+
`stdin`, `stdout` and `stderr`, which are three pointers to FILE
68+
structures (which can all reference a single shared FILE structure,
69+
and which can be aliases to the same underlying global pointer).
6970

7071
Note that while posix-io support is enabled by default, using it will
7172
require that the underlying system offer the required functions. POSIX
72-
console support offers a built-in `__iob` definition which uses the
73-
same POSIX I/O functions.
73+
console support offers built-in `stdin`, `stdout` and `stderr`
74+
definitions which use the same POSIX I/O functions.
7475

7576
| Option | Default | Description |
7677
| ------ | ------- | ----------- |

‎doc/os.md

+11-7
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ complex file operations so that a minimal system can easily support
1616
the former with only a few functions.
1717

1818
To get stdin/stdout/stderr working, the application needs to define
19-
the '__iob' array, which contains pointers to FILE objects for each of
20-
stdin/stdout/stderr. The __iob array may reside in read-only memory,
21-
but the FILE objects may not. A single FILE object may be used for all
22-
three pointers. The FILE object contains function pointers for putc,
23-
getc, which might be defined as follows:
19+
the `stdin`, `stdout` and `stderr` globals, which contain pointers to
20+
FILE objects. The pointers may reside in read-only memory, but the
21+
FILE objects may not. A single FILE object may be used for all three
22+
pointers, and linker aliases may be used to make all three pointers be
23+
stored in the same location. The FILE object contains function
24+
pointers for putc, getc, which might be defined as follows:
2425

2526
static int
2627
sample_putc(char c, FILE *file)
@@ -69,9 +70,12 @@ supported, can be one of the following:
6970
| _FDEV_SETUP_WRITE | Write | putc |
7071
| _FDEV_SETUP_RW | Read/Write | putc, getc |
7172

72-
Finally, the FILE is used to initialize the __iob array:
73+
Finally, the FILE is used to initialize the `stdin`, `stdout` and
74+
`stderr` values, the latter two of which are simply aliases to `stdin`:
7375

74-
FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio };
76+
FILE *const stdin = &__stdio;
77+
__strong_reference(stdin, stdout);
78+
__strong_reference(stdin, stderr);
7579

7680
### fopen, fdopen
7781

‎dummyhost/iob.c

+11-3
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@
3939
/*
4040
* Dummy stdio hooks. This allows programs to link without requiring
4141
* any system-dependent functions. This is only used if the program
42-
* doesn't provide its own version of __iob
42+
* doesn't provide its own version of stdin, stdout, stderr
4343
*/
4444

4545
static int
4646
dummy_putc(char c, FILE *file)
4747
{
4848
(void) c;
4949
(void) file;
50-
return c;
50+
return (unsigned char) c;
5151
}
5252

5353
static int
@@ -66,4 +66,12 @@ dummy_flush(FILE *file)
6666

6767
static FILE __stdio = FDEV_SETUP_STREAM(dummy_putc, dummy_getc, dummy_flush, _FDEV_SETUP_RW);
6868

69-
FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio };
69+
#ifdef __strong_reference
70+
#define STDIO_ALIAS(x) __strong_reference(stdin, x);
71+
#else
72+
#define STDIO_ALIAS(x) FILE *const x = &__stdio;
73+
#endif
74+
75+
FILE *const stdin = &__stdio;
76+
STDIO_ALIAS(stdout);
77+
STDIO_ALIAS(stderr);

‎newlib/libc/tinystdio/posixiob.c

+12-2
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,18 @@ static struct __file_posix __stdout = {
5858
.write_buf = write_buf
5959
};
6060

61-
FILE *const __posix_iob[3] = { &__stdin.cfile.file, &__stdout.cfile.file, &__stdout.cfile.file };
62-
__weak_reference(__posix_iob,__iob);
61+
FILE *const __posix_stdin = &__stdin.cfile.file;
62+
FILE *const __posix_stdout = &__stdout.cfile.file;
63+
64+
#ifdef __strong_reference
65+
__strong_reference(__posix_stdout, __posix_stderr);
66+
#else
67+
FILE *const __posix_stderr = &__stdout.cfile.file;
68+
#endif
69+
70+
__weak_reference(__posix_stdin,stdin);
71+
__weak_reference(__posix_stdout,stdout);
72+
__weak_reference(__posix_stderr,stderr);
6373

6474
/*
6575
* Add a destructor function to get stdout flushed on

‎newlib/libc/tinystdio/stdio.h

+16-11
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,12 @@
114114
conversion should be performed, but instead any string that aims
115115
to issue a CR-LF sequence must use <tt>"\r\n"</tt> explicitly.
116116
117-
stdin, stdout and stderr are macros which refer to an undefined
118-
array of FILE pointers, __iob. If you want to use this, your
119-
application must define this array and initialize it. It is
120-
declared 'const' so that you can place it in ROM if you don't need
121-
to modify it after startup. FILEs cannot be placed in ROM as they
122-
have values which are modified during runtime.
117+
stdin, stdout and stderr are undefined global FILE pointers. If
118+
you want to use this, your application must define these variables
119+
and initialize them. They are declared 'const' so that you can place
120+
them in ROM if you don't need to modify it after startup. FILEs
121+
cannot be placed in ROM as they have values which are modified
122+
during runtime.
123123
124124
\anchor stdio_without_malloc
125125
<h3>Running stdio without malloc()</h3>
@@ -282,23 +282,30 @@ typedef __FILE FILE;
282282
# define __FILE_defined
283283
#endif
284284

285+
/**
286+
This symbol is defined when stdin/stdout/stderr are global
287+
variables. When undefined, the old __iob array is used which
288+
contains the pointers instead
289+
*/
290+
#define PICOLIBC_STDIO_GLOBALS
291+
285292
/**
286293
Stream that will be used as an input stream by the simplified
287294
functions that don't take a \c stream argument.
288295
*/
289-
#define stdin (__iob[0])
296+
extern FILE *const stdin;
290297

291298
/**
292299
Stream that will be used as an output stream by the simplified
293300
functions that don't take a \c stream argument.
294301
*/
295-
#define stdout (__iob[1])
302+
extern FILE *const stdout;
296303

297304
/**
298305
Stream destined for error output. Unless specifically assigned,
299306
identical to \c stdout.
300307
*/
301-
#define stderr (__iob[2])
308+
extern FILE *const stderr;
302309

303310
/**
304311
\c EOF declares the value that is returned by various standard IO
@@ -388,8 +395,6 @@ extern "C" {
388395
* Doxygen documentation can be found in fdevopen.c.
389396
*/
390397

391-
extern struct __file *const __iob[];
392-
393398
extern FILE *fdevopen(int (*__put)(char, FILE*), int (*__get)(FILE*), int(*__flush)(FILE *));
394399

395400
#endif /* not __DOXYGEN__ */

‎newlib/testsuite/stdio-bits.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,15 @@ static FILE __stdio = {
102102
.flush = ao_flush,
103103
};
104104

105-
FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio };
105+
#ifdef __strong_reference
106+
#define STDIO_ALIAS(x) __strong_reference(stdin, x);
107+
#else
108+
#define STDIO_ALIAS(x) FILE *const x = &__stdio;
109+
#endif
110+
111+
FILE *const stdin = &__stdio;
112+
STDIO_ALIAS(stdout);
113+
STDIO_ALIAS(stderr);
106114

107115
#else
108116
int fstat(int fd, struct stat *statb) { errno = ENOTTY; return -1; }

‎semihost/iob.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,12 @@
3737

3838
static FILE __stdio = FDEV_SETUP_STREAM(sys_semihost_putc, sys_semihost_getc, NULL, _FDEV_SETUP_RW);
3939

40-
FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio };
40+
#ifdef __strong_reference
41+
#define STDIO_ALIAS(x) __strong_reference(stdin, x);
42+
#else
43+
#define STDIO_ALIAS(x) FILE *const x = &__stdio;
44+
#endif
45+
46+
FILE *const stdin = &__stdio;
47+
STDIO_ALIAS(stdout);
48+
STDIO_ALIAS(stderr);

‎semihost/machine/i386/e9_io.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,12 @@ e9_getc(FILE *file)
5454

5555
static FILE __stdio = FDEV_SETUP_STREAM(e9_putc, e9_getc, NULL, _FDEV_SETUP_RW);
5656

57-
FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio };
57+
#ifdef __strong_reference
58+
#define STDIO_ALIAS(x) __strong_reference(stdin, x);
59+
#else
60+
#define STDIO_ALIAS(x) FILE *const x = &__stdio;
61+
#endif
62+
63+
FILE *const stdin = &__stdio;
64+
STDIO_ALIAS(stdout);
65+
STDIO_ALIAS(stderr);

0 commit comments

Comments
 (0)
Please sign in to comment.