diff --git a/Cargo.lock b/Cargo.lock
index b5492d7c1970520bbd3be63fb90d46729124892b..7e7ba2db3554c0d83da482bb281cbe91a72ffe7c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -80,6 +80,7 @@ name = "crt0"
 version = "0.1.0"
 dependencies = [
  "platform 0.1.0",
+ "stdio 0.1.0",
 ]
 
 [[package]]
diff --git a/include/bits/stdio.h b/include/bits/stdio.h
index a4e2578d5d279f5cbb9e461e86468d2f431574af..b20ee2bd9b6d4963b7bc338dbe4c8166ae2baa6b 100644
--- a/include/bits/stdio.h
+++ b/include/bits/stdio.h
@@ -3,9 +3,6 @@
 
 #define EOF (-1)
 #define BUFSIZ 1024
-#define stdin __stdin()
-#define stdout __stdout()
-#define stderr __stderr()
 
 int fprintf(FILE * stream, const char * fmt, ...);
 int printf(const char * fmt, ...);
diff --git a/src/crt0/Cargo.toml b/src/crt0/Cargo.toml
index 0b82f468c56f684aad936630d5614da27536f88c..9133360068f67e4df8a953d5bb00bb2f87f22622 100644
--- a/src/crt0/Cargo.toml
+++ b/src/crt0/Cargo.toml
@@ -9,3 +9,4 @@ crate-type = ["staticlib"]
 
 [dependencies]
 platform = { path = "../platform" }
+stdio = { path = "../stdio" }
diff --git a/src/crt0/src/lib.rs b/src/crt0/src/lib.rs
index c9f1a84c1e223ecc3120a154464989724644e3f2..c9cc2739a4a7e877d23f07f507fb83569111d58e 100644
--- a/src/crt0/src/lib.rs
+++ b/src/crt0/src/lib.rs
@@ -10,6 +10,7 @@
 
 extern crate alloc;
 extern crate platform;
+extern crate stdio;
 
 use alloc::Vec;
 use core::ptr;
@@ -89,6 +90,11 @@ pub unsafe extern "C" fn _start_rust(sp: &'static Stack) -> ! {
     platform::inner_environ.push(ptr::null_mut());
     platform::environ = platform::inner_environ.as_mut_ptr();
 
+    // Initialize stdin/stdout/stderr, see https://github.com/rust-lang/rust/issues/51718
+    stdio::stdin = stdio::default_stdin.get();
+    stdio::stdout = stdio::default_stdout.get();
+    stdio::stderr = stdio::default_stderr.get();
+
     platform::exit(main(
         argc,
         argv as *const *const c_char,
diff --git a/src/stdio/src/default.rs b/src/stdio/src/default.rs
index c9bb96f1ca7b057755035156e149bd283639bb56..5928254178e5e64c90978b81c2c28c0e59486578 100644
--- a/src/stdio/src/default.rs
+++ b/src/stdio/src/default.rs
@@ -1,37 +1,23 @@
 use super::{constants, BUFSIZ, FILE, UNGET};
 use core::cell::UnsafeCell;
+use core::ptr;
 use core::sync::atomic::AtomicBool;
 
-struct GlobalFile(UnsafeCell<FILE>);
+pub struct GlobalFile(UnsafeCell<FILE>);
 impl GlobalFile {
     const fn new(file: FILE) -> Self {
         GlobalFile(UnsafeCell::new(file))
     }
-    fn get(&self) -> *mut FILE {
+    pub fn get(&self) -> *mut FILE {
         self.0.get()
     }
 }
 // statics need to be Sync
 unsafe impl Sync for GlobalFile {}
 
-#[no_mangle]
-pub extern "C" fn __stdin() -> *mut FILE {
-    default_stdin.get()
-}
-
-#[no_mangle]
-pub extern "C" fn __stdout() -> *mut FILE {
-    default_stdout.get()
-}
-
-#[no_mangle]
-pub extern "C" fn __stderr() -> *mut FILE {
-    default_stderr.get()
-}
-
 lazy_static! {
     #[allow(non_upper_case_globals)]
-    static ref default_stdin: GlobalFile = GlobalFile::new(FILE {
+    pub static ref default_stdin: GlobalFile = GlobalFile::new(FILE {
         flags: constants::F_PERM | constants::F_NOWR,
         read: None,
         write: None,
@@ -43,7 +29,7 @@ lazy_static! {
     });
 
     #[allow(non_upper_case_globals)]
-    static ref default_stdout: GlobalFile = GlobalFile::new(FILE {
+    pub static ref default_stdout: GlobalFile = GlobalFile::new(FILE {
         flags: constants::F_PERM | constants::F_NORD,
         read: None,
         write: None,
@@ -55,7 +41,7 @@ lazy_static! {
     });
 
     #[allow(non_upper_case_globals)]
-    static ref default_stderr: GlobalFile = GlobalFile::new(FILE {
+    pub static ref default_stderr: GlobalFile = GlobalFile::new(FILE {
         flags: constants::F_PERM | constants::F_NORD,
         read: None,
         write: None,
@@ -66,3 +52,10 @@ lazy_static! {
         lock: AtomicBool::new(false),
     });
 }
+
+#[no_mangle]
+pub static mut stdin: *mut FILE = ptr::null_mut();
+#[no_mangle]
+pub static mut stdout: *mut FILE = ptr::null_mut();
+#[no_mangle]
+pub static mut stderr: *mut FILE = ptr::null_mut();
diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs
index c2af6d3b618222bd05a955d5d890881fd8c70b96..ef75bc4f075d9f184d3a856753aeac24b43479dc 100644
--- a/src/stdio/src/lib.rs
+++ b/src/stdio/src/lib.rs
@@ -643,7 +643,7 @@ pub extern "C" fn getc(stream: &mut FILE) -> c_int {
 /// Get a single char from `stdin`
 #[no_mangle]
 pub extern "C" fn getchar() -> c_int {
-    fgetc(unsafe { &mut *__stdin() })
+    fgetc(unsafe { &mut *stdin })
 }
 
 /// Get a char from a stream without locking the stream
@@ -676,14 +676,14 @@ pub extern "C" fn getc_unlocked(stream: &mut FILE) -> c_int {
 /// Get a char from `stdin` without locking `stdin`
 #[no_mangle]
 pub extern "C" fn getchar_unlocked() -> c_int {
-    getc_unlocked(unsafe { &mut *__stdin() })
+    getc_unlocked(unsafe { &mut *stdin })
 }
 
 /// Get a string from `stdin`
 #[no_mangle]
 pub extern "C" fn gets(s: *mut c_char) -> *mut c_char {
     use core::i32;
-    fgets(s, i32::MAX, unsafe { &mut *__stdin() })
+    fgets(s, i32::MAX, unsafe { &mut *stdin })
 }
 
 /// Get an integer from `stream`
@@ -740,7 +740,7 @@ pub extern "C" fn putc(c: c_int, stream: &mut FILE) -> c_int {
 /// Put a character `c` into `stdout`
 #[no_mangle]
 pub extern "C" fn putchar(c: c_int) -> c_int {
-    fputc(c, unsafe { &mut *__stdout() })
+    fputc(c, unsafe { &mut *stdout })
 }
 
 /// Put a character `c` into `stream` without locking `stream`
@@ -768,13 +768,13 @@ pub extern "C" fn putc_unlocked(c: c_int, stream: &mut FILE) -> c_int {
 /// Put a character `c` into `stdout` without locking `stdout`
 #[no_mangle]
 pub extern "C" fn putchar_unlocked(c: c_int) -> c_int {
-    putc_unlocked(c, unsafe { &mut *__stdout() })
+    putc_unlocked(c, unsafe { &mut *stdout })
 }
 
 /// Put a string `s` into `stdout`
 #[no_mangle]
 pub extern "C" fn puts(s: *const c_char) -> c_int {
-    let ret = (fputs(s, unsafe { &mut *__stdout() }) > 0) || (putchar_unlocked(b'\n' as c_int) > 0);
+    let ret = (fputs(s, unsafe { &mut *stdout }) > 0) || (putchar_unlocked(b'\n' as c_int) > 0);
     if ret {
         0
     } else {
@@ -918,7 +918,7 @@ pub unsafe extern "C" fn vfprintf(file: &mut FILE, format: *const c_char, ap: va
 
 #[no_mangle]
 pub unsafe extern "C" fn vprintf(format: *const c_char, ap: va_list) -> c_int {
-    vfprintf(&mut *__stdout(), format, ap)
+    vfprintf(&mut *stdout, format, ap)
 }
 
 #[no_mangle]
@@ -947,7 +947,7 @@ pub unsafe extern "C" fn vfscanf(file: &mut FILE, format: *const c_char, ap: va_
 
 #[no_mangle]
 pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int {
-    vfscanf(&mut *__stdin(), format, ap)
+    vfscanf(&mut *stdin, format, ap)
 }
 
 #[no_mangle]
diff --git a/src/unistd/src/getopt.rs b/src/unistd/src/getopt.rs
index 044d70c37944481402a4968da295f24722d960d7..29d77b4df65dd1286ffa495615f63442321b042a 100644
--- a/src/unistd/src/getopt.rs
+++ b/src/unistd/src/getopt.rs
@@ -70,10 +70,10 @@ unsafe fn parse_arg(
 
     let print_error = |desc: &[u8]| {
         // NOTE: we don't use fprintf to get around the usage of va_list
-        stdio::fputs(*argv as _, &mut *stdio::__stderr());
-        stdio::fputs(desc.as_ptr() as _, &mut *stdio::__stderr());
-        stdio::fputc(*current_arg as _, &mut *stdio::__stderr());
-        stdio::fputc(b'\n' as _, &mut *stdio::__stderr());
+        stdio::fputs(*argv as _, &mut *stdio::stderr);
+        stdio::fputs(desc.as_ptr() as _, &mut *stdio::stderr);
+        stdio::fputc(*current_arg as _, &mut *stdio::stderr);
+        stdio::fputc(b'\n' as _, &mut *stdio::stderr);
     };
 
     match find_option(*current_arg, optstring) {
diff --git a/src/wchar/src/lib.rs b/src/wchar/src/lib.rs
index 02c679cd278e2d2677a0bb774940c3df5bae5495..fdeb25becf2cf2ea04225931205aadb0048da213 100644
--- a/src/wchar/src/lib.rs
+++ b/src/wchar/src/lib.rs
@@ -203,7 +203,7 @@ pub unsafe extern "C" fn putwc(wc: wchar_t, stream: *mut FILE) -> wint_t {
 
 #[no_mangle]
 pub unsafe extern "C" fn putwchar(wc: wchar_t) -> wint_t {
-    fputwc(wc, &mut *__stdout())
+    fputwc(wc, &mut *stdout)
 }
 
 // #[no_mangle]
diff --git a/tests/expected/unistd/stat.stderr b/tests/expected/unistd/stat.stderr
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/tests/expected/unistd/stat.stdout b/tests/expected/unistd/stat.stdout
deleted file mode 100644
index 74f3a92e9e722dee5974f364e346a28394f72720..0000000000000000000000000000000000000000
--- a/tests/expected/unistd/stat.stdout
+++ /dev/null
@@ -1,4 +0,0 @@
-144
-st_mode: 33188
-st_size: 383
-st_blksize: 4096