Skip to content

Commit 020dff4

Browse files
authored
[libc] Migrate from baremetal stdio.h to generic stdio.h (#152748)
This is a follow up to the RFC here: https://discourse.llvm.org/t/rfc-implementation-of-stdio-on-baremetal/86944 This provides the stdout/stderr/stdin symbols (which now don't have to provided by the user). This allows the user to have access to all functions, currently I've only tested `fprintf` but in theory everything that works in the generic folder should work in the baremetal configuration. All streams are _non-buffered_, which does NOT require flushing. It is based on the CookieFile that already existed
1 parent a97f206 commit 020dff4

File tree

18 files changed

+280
-357
lines changed

18 files changed

+280
-357
lines changed

libc/config/baremetal/aarch64/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ set(TARGET_LIBC_ENTRYPOINTS
124124

125125
# stdio.h entrypoints
126126
libc.src.stdio.asprintf
127+
libc.src.stdio.fopencookie
128+
libc.src.stdio.fprintf
127129
libc.src.stdio.getchar
128130
libc.src.stdio.printf
129131
libc.src.stdio.putchar

libc/config/baremetal/arm/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ set(TARGET_LIBC_ENTRYPOINTS
124124

125125
# stdio.h entrypoints
126126
libc.src.stdio.asprintf
127+
libc.src.stdio.fopencookie
128+
libc.src.stdio.fprintf
127129
libc.src.stdio.getchar
128130
libc.src.stdio.printf
129131
libc.src.stdio.putchar

libc/config/baremetal/riscv/entrypoints.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ set(TARGET_LIBC_ENTRYPOINTS
124124

125125
# stdio.h entrypoints
126126
libc.src.stdio.asprintf
127+
libc.src.stdio.fopencookie
128+
libc.src.stdio.fprintf
127129
libc.src.stdio.getchar
128130
libc.src.stdio.printf
129131
libc.src.stdio.putchar

libc/src/__support/File/CMakeLists.txt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ add_object_library(
2222
libc.src.__support.error_or
2323
)
2424

25+
add_header_library(
26+
cookie_file
27+
HDRS
28+
cookie_file.h
29+
DEPENDS
30+
.file
31+
libc.hdr.errno_macros
32+
libc.hdr.types.cookie_io_functions_t
33+
libc.hdr.types.off_t
34+
libc.src.__support.CPP.new
35+
)
36+
2537
add_object_library(
2638
dir
2739
SRCS
@@ -41,7 +53,11 @@ endif()
4153

4254
add_subdirectory(${LIBC_TARGET_OS})
4355

44-
set(target_file libc.src.__support.File.${LIBC_TARGET_OS}.file)
56+
if(LIBC_TARGET_OS_IS_BAREMETAL)
57+
set(target_file libc.src.__support.File.cookie_file)
58+
else()
59+
set(target_file libc.src.__support.File.${LIBC_TARGET_OS}.file)
60+
endif()
4561
set(target_stdout libc.src.__support.File.${LIBC_TARGET_OS}.stdout)
4662
set(target_stderr libc.src.__support.File.${LIBC_TARGET_OS}.stderr)
4763
set(target_stdin libc.src.__support.File.${LIBC_TARGET_OS}.stdin)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
add_object_library(
2+
stdout
3+
SRCS
4+
stdout.cpp
5+
DEPENDS
6+
libc.hdr.stdio_macros
7+
libc.src.__support.File.cookie_file
8+
libc.src.__support.File.file
9+
libc.src.__support.OSUtil.osutil
10+
)
11+
12+
add_object_library(
13+
stdin
14+
SRCS
15+
stdin.cpp
16+
DEPENDS
17+
libc.hdr.stdio_macros
18+
libc.src.__support.File.cookie_file
19+
libc.src.__support.File.file
20+
libc.src.__support.OSUtil.osutil
21+
)
22+
23+
add_object_library(
24+
stderr
25+
SRCS
26+
stderr.cpp
27+
DEPENDS
28+
libc.hdr.stdio_macros
29+
libc.src.__support.File.cookie_file
30+
libc.src.__support.File.file
31+
libc.src.__support.OSUtil.osutil
32+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===--- Definition of baremetal stderr -----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/stdio_macros.h"
10+
#include "src/__support/File/cookie_file.h"
11+
#include "src/__support/File/file.h"
12+
#include "src/__support/OSUtil/baremetal/io.h"
13+
#include "src/__support/macros/config.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
cookie_io_functions_t io_func = {.read = nullptr,
18+
.write = __llvm_libc_stdio_write,
19+
.seek = nullptr,
20+
.close = nullptr};
21+
#pragma clang diagnostic push
22+
#pragma clang diagnostic ignored "-Wglobal-constructors"
23+
// Buffering is implementation defined. Therefore to save RAM, we use no
24+
// buffering
25+
static CookieFile StdErr(&__llvm_libc_stderr_cookie, io_func, nullptr, 0,
26+
_IONBF, File::mode_flags("w"));
27+
#pragma clang diagnostic pop
28+
File *stderr = &StdErr;
29+
30+
} // namespace LIBC_NAMESPACE_DECL
31+
32+
extern "C" {
33+
FILE *stderr = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdErr);
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===--- Definition of baremetal stdin ------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/stdio_macros.h"
10+
#include "src/__support/File/cookie_file.h"
11+
#include "src/__support/File/file.h"
12+
#include "src/__support/OSUtil/baremetal/io.h"
13+
#include "src/__support/macros/config.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
cookie_io_functions_t io_func = {.read = __llvm_libc_stdio_read,
18+
.write = nullptr,
19+
.seek = nullptr,
20+
.close = nullptr};
21+
#pragma clang diagnostic push
22+
#pragma clang diagnostic ignored "-Wglobal-constructors"
23+
// Buffering is implementation defined. Therefore to save RAM, we use no
24+
// buffering
25+
static CookieFile StdIn(&__llvm_libc_stdin_cookie, io_func, nullptr, 0, _IONBF,
26+
File::mode_flags("r"));
27+
#pragma clang diagnostic pop
28+
File *stdin = &StdIn;
29+
30+
} // namespace LIBC_NAMESPACE_DECL
31+
32+
extern "C" {
33+
FILE *stdin = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdIn);
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===--- Definition of baremetal stdout -----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/stdio_macros.h"
10+
#include "src/__support/File/cookie_file.h"
11+
#include "src/__support/File/file.h"
12+
#include "src/__support/OSUtil/baremetal/io.h"
13+
#include "src/__support/macros/config.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
cookie_io_functions_t io_func = {.read = nullptr,
18+
.write = __llvm_libc_stdio_write,
19+
.seek = nullptr,
20+
.close = nullptr};
21+
#pragma clang diagnostic push
22+
#pragma clang diagnostic ignored "-Wglobal-constructors"
23+
// Buffering is implementation defined. Therefore to save RAM, we use no
24+
// buffering
25+
static CookieFile StdOut(&__llvm_libc_stdout_cookie, io_func, nullptr, 0,
26+
_IONBF, File::mode_flags("w"));
27+
#pragma clang diagnostic pop
28+
File *stdout = &StdOut;
29+
30+
} // namespace LIBC_NAMESPACE_DECL
31+
32+
extern "C" {
33+
FILE *stdout = reinterpret_cast<FILE *>(&LIBC_NAMESPACE::StdOut);
34+
}

libc/src/__support/File/cookie_file.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===--- A platform independent cookie file class -------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "hdr/errno_macros.h"
10+
#include "hdr/types/cookie_io_functions_t.h"
11+
#include "hdr/types/off_t.h"
12+
#include "src/__support/CPP/new.h"
13+
#include "src/__support/File/file.h"
14+
#include "src/__support/macros/config.h"
15+
16+
namespace LIBC_NAMESPACE_DECL {
17+
18+
class CookieFile : public LIBC_NAMESPACE::File {
19+
void *cookie;
20+
cookie_io_functions_t ops;
21+
22+
LIBC_INLINE static FileIOResult cookie_write(File *f, const void *data,
23+
size_t size);
24+
LIBC_INLINE static FileIOResult cookie_read(File *f, void *data, size_t size);
25+
LIBC_INLINE static ErrorOr<off_t> cookie_seek(File *f, off_t offset,
26+
int whence);
27+
LIBC_INLINE static int cookie_close(File *f);
28+
29+
public:
30+
LIBC_INLINE CookieFile(void *c, cookie_io_functions_t cops, uint8_t *buffer,
31+
size_t bufsize, int buffer_mode, File::ModeFlags mode)
32+
: File(&cookie_write, &cookie_read, &CookieFile::cookie_seek,
33+
&cookie_close, buffer, bufsize, buffer_mode,
34+
true /* File owns buffer */, mode),
35+
cookie(c), ops(cops) {}
36+
};
37+
38+
LIBC_INLINE FileIOResult CookieFile::cookie_write(File *f, const void *data,
39+
size_t size) {
40+
auto cookie_file = reinterpret_cast<CookieFile *>(f);
41+
if (cookie_file->ops.write == nullptr)
42+
return 0;
43+
return static_cast<size_t>(cookie_file->ops.write(
44+
cookie_file->cookie, reinterpret_cast<const char *>(data), size));
45+
}
46+
47+
LIBC_INLINE FileIOResult CookieFile::cookie_read(File *f, void *data,
48+
size_t size) {
49+
auto cookie_file = reinterpret_cast<CookieFile *>(f);
50+
if (cookie_file->ops.read == nullptr)
51+
return 0;
52+
return static_cast<size_t>(cookie_file->ops.read(
53+
cookie_file->cookie, reinterpret_cast<char *>(data), size));
54+
}
55+
56+
LIBC_INLINE ErrorOr<off_t> CookieFile::cookie_seek(File *f, off_t offset,
57+
int whence) {
58+
auto cookie_file = reinterpret_cast<CookieFile *>(f);
59+
if (cookie_file->ops.seek == nullptr) {
60+
return Error(EINVAL);
61+
}
62+
off64_t offset64 = offset;
63+
int result = cookie_file->ops.seek(cookie_file->cookie, &offset64, whence);
64+
if (result == 0)
65+
return offset64;
66+
return -1;
67+
}
68+
69+
LIBC_INLINE int CookieFile::cookie_close(File *f) {
70+
auto cookie_file = reinterpret_cast<CookieFile *>(f);
71+
if (cookie_file->ops.close == nullptr)
72+
return 0;
73+
int retval = cookie_file->ops.close(cookie_file->cookie);
74+
if (retval != 0)
75+
return retval;
76+
delete cookie_file;
77+
return 0;
78+
}
79+
80+
} // namespace LIBC_NAMESPACE_DECL

libc/src/__support/OSUtil/baremetal/io.cpp

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,45 +13,6 @@
1313

1414
namespace LIBC_NAMESPACE_DECL {
1515

16-
// These are intended to be provided by the vendor.
17-
//
18-
// The signature of these types and functions intentionally match `fopencookie`
19-
// which allows the following:
20-
//
21-
// ```
22-
// struct __llvm_libc_stdio_cookie { ... };
23-
// ...
24-
// struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie;
25-
// cookie_io_functions_t stdin_func = { .read = __llvm_libc_stdio_read };
26-
// FILE *stdin = fopencookie(&__llvm_libc_stdin_cookie, "r", stdin_func);
27-
// ...
28-
// struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie;
29-
// cookie_io_functions_t stdout_func = { .write = __llvm_libc_stdio_write };
30-
// FILE *stdout = fopencookie(&__llvm_libc_stdout_cookie, "w", stdout_func);
31-
// ...
32-
// struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie;
33-
// cookie_io_functions_t stderr_func = { .write = __llvm_libc_stdio_write };
34-
// FILE *stderr = fopencookie(&__llvm_libc_stderr_cookie, "w", stderr_func);
35-
// ```
36-
//
37-
// At the same time, implementation of functions like `printf` and `scanf` can
38-
// use `__llvm_libc_stdio_read` and `__llvm_libc_stdio_write` directly to avoid
39-
// the extra indirection.
40-
//
41-
// All three symbols `__llvm_libc_stdin_cookie`, `__llvm_libc_stdout_cookie`,
42-
// and `__llvm_libc_stderr_cookie` must be provided, even if they don't point
43-
// at anything.
44-
45-
struct __llvm_libc_stdio_cookie;
46-
47-
extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdin_cookie;
48-
extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stdout_cookie;
49-
extern "C" struct __llvm_libc_stdio_cookie __llvm_libc_stderr_cookie;
50-
51-
extern "C" ssize_t __llvm_libc_stdio_read(void *cookie, char *buf, size_t size);
52-
extern "C" ssize_t __llvm_libc_stdio_write(void *cookie, const char *buf,
53-
size_t size);
54-
5516
ssize_t read_from_stdin(char *buf, size_t size) {
5617
return __llvm_libc_stdio_read(static_cast<void *>(&__llvm_libc_stdin_cookie),
5718
buf, size);

0 commit comments

Comments
 (0)