// Copyright 2022 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include // POSIX header provided by Newlib; needed for stat. #include // POSIX header provided by Newlib; needed for times. #include // fpos_t #include "pw_assert/check.h" namespace pw::toolchain { namespace { [[noreturn]] void AbortIfUnsupportedNewlibFunctionIsCalled() { PW_CRASH( "Attempted to invoke an unsupported Newlib function! The stdout and " "stderr FILE objects are not supported."); } } // namespace // Wrap the stdio read, write, seek, and close Newlib functions defined in // libc/stdio/stdio.c. These should never be called, so abort if they are. // // These functions are unconditionally linked, even if they're never called, // because they are assigned as members of the stdout/stderr FILE struct. The // Newlib implementations invoke some of the unsupported OS interface functions. #define PW_WRAP_NEWLIB_FILE_FUNCTION(function, ...) \ extern "C" int __wrap_##function(__VA_ARGS__) { \ AbortIfUnsupportedNewlibFunctionIsCalled(); \ } PW_WRAP_NEWLIB_FILE_FUNCTION(__sread, void*, char*, int) PW_WRAP_NEWLIB_FILE_FUNCTION(__swrite, void*, char*, int) PW_WRAP_NEWLIB_FILE_FUNCTION(__sseek, void*, fpos_t, int) PW_WRAP_NEWLIB_FILE_FUNCTION(__sclose, void*) #undef PW_WRAP_NEWLIB_FILE_FUNCTION // Newlib defines a set of OS interface functions. Most of these should never be // called, since they're used by libc functions not supported in Pigweed (e.g. // fopen or printf). If they're linked into a binary, that indicates that an // unsupported function was called. // // Newlib provides default, nop implementations of these functions. Starting // with arm-none-eabi-gcc 11.3, a warning is issued when any of these defaults // are used. // // Provide implementations for most of the Newlib OS interface functions, which // are documented at https://sourceware.org/newlib/libc.html#Stubs. The default // implementation calls the following function, which is never defined, // resulting in a linker error. [[noreturn]] void AttemptedToInvokeUnsupportedNewlibOsInterfaceFunction(); #define PW_DISABLE_NEWLIB_FUNCTION(function, ...) \ extern "C" int _##function(__VA_ARGS__) { \ AttemptedToInvokeUnsupportedNewlibOsInterfaceFunction(); \ } PW_DISABLE_NEWLIB_FUNCTION(_exit, void) PW_DISABLE_NEWLIB_FUNCTION(close, int) PW_DISABLE_NEWLIB_FUNCTION(execve, char*, char**, char**) PW_DISABLE_NEWLIB_FUNCTION(fork, void) // Provide the minimal fstat implementation recommended by the Newlib // documentation since fstat is called indirectly by snprintf. extern "C" int _fstat(int, struct stat* st) { st->st_mode = S_IFCHR; return 0; } PW_DISABLE_NEWLIB_FUNCTION(getpid, void) // Provide the minimal isatty implementation recommended by the Newlib // documentation since isatty is called indirectly by snprintf. extern "C" int _isatty(int) { return 1; } PW_DISABLE_NEWLIB_FUNCTION(gettimeofday, struct timeval*, struct timezone*) PW_DISABLE_NEWLIB_FUNCTION(kill, int, int) PW_DISABLE_NEWLIB_FUNCTION(link, char*, char*) PW_DISABLE_NEWLIB_FUNCTION(lseek, int, int, int) PW_DISABLE_NEWLIB_FUNCTION(open, const char*, int, int) PW_DISABLE_NEWLIB_FUNCTION(read, int, char*, int) PW_DISABLE_NEWLIB_FUNCTION(sbrk, int) PW_DISABLE_NEWLIB_FUNCTION(stat, char*, struct stat*) PW_DISABLE_NEWLIB_FUNCTION(times, struct tms*) PW_DISABLE_NEWLIB_FUNCTION(unlink, char*) PW_DISABLE_NEWLIB_FUNCTION(wait, int*) PW_DISABLE_NEWLIB_FUNCTION(write, int, char*, int) #undef PW_DISABLE_NEWLIB_FUNCTION } // namespace pw::toolchain