diff --git a/stdio/src/lib.rs b/stdio/src/lib.rs
index a84c5a31935aca70e66fa299b79c174fc8e5703c..c8bdcbdd51e28c1a57dea81b10049e79f44f540c 100644
--- a/stdio/src/lib.rs
+++ b/stdio/src/lib.rs
@@ -8,113 +8,23 @@ extern crate va_list as vl;
 use platform::types::*;
 use vl::VaList as va_list;
 
+mod printf;
+
 pub const BUFSIZ: c_int = 4096;
 
 pub const FILENAME_MAX: c_int = 4096;
 
 pub struct FILE;
 
+#[no_mangle]
 pub static mut stdout: *mut FILE = 1 as *mut FILE;
-pub static mut stderr: *mut FILE = 2 as *mut FILE;
 
 #[no_mangle]
-pub unsafe extern "C" fn vfprintf(file: *mut FILE, format: *const c_char, mut ap: va_list) -> c_int {
-    use core::fmt::Write;
-    use core::slice;
-    use core::str;
-
-    extern "C" {
-        fn strlen(s: *const c_char) -> size_t;
-    }
-
-    let mut w = platform::FileWriter(file as c_int);
-
-    let format = slice::from_raw_parts(format as *const u8, strlen(format));
-
-    let mut i = 0;
-    let mut found_percent = false;
-    while i < format.len() {
-        let b = format[i];
-
-        if found_percent {
-            match b as char {
-                '%' => {
-                    w.write_char('%');
-                    found_percent = false;
-                },
-                'c' => {
-                    let a = ap.get::<u32>();
-
-                    w.write_char(a as u8 as char);
-
-                    found_percent = false;
-                },
-                'd' | 'i' => {
-                    let a = ap.get::<c_int>();
-
-                    w.write_fmt(format_args!("{}", a));
-
-                    found_percent = false;
-                },
-                'n' => {
-                    let _a = ap.get::<c_int>();
-
-                    found_percent = false;
-                },
-                'p' => {
-                    let a = ap.get::<usize>();
-
-                    w.write_fmt(format_args!("0x{:x}", a));
-
-                    found_percent = false;
-                },
-                's' => {
-                    let a = ap.get::<usize>();
-
-                    w.write_str(str::from_utf8_unchecked(
-                            slice::from_raw_parts(a as *const u8, strlen(a as *const c_char))
-                    ));
-
-                    found_percent = false;
-                },
-                'u' => {
-                    let a = ap.get::<c_uint>();
-
-                    w.write_fmt(format_args!("{}", a));
-
-                    found_percent = false;
-                },
-                'x' => {
-                    let a = ap.get::<c_uint>();
-
-                    w.write_fmt(format_args!("{:x}", a));
-
-                    found_percent = false;
-                },
-                'X' => {
-                    let a = ap.get::<c_uint>();
-
-                    w.write_fmt(format_args!("{:X}", a));
-
-                    found_percent = false;
-                },
-                '-' => {},
-                '+' => {},
-                ' ' => {},
-                '#' => {},
-                '0' ... '9' => {},
-                _ => {}
-            }
-        } else if b == b'%' {
-            found_percent = true;
-        } else {
-            w.write_char(b as char);
-        }
-
-        i += 1;
-    }
+pub static mut stderr: *mut FILE = 2 as *mut FILE;
 
-    0
+#[no_mangle]
+pub unsafe extern "C" fn vfprintf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int {
+    printf::printf(platform::FileWriter(file as c_int), format, ap)
 }
 
 #[no_mangle]
diff --git a/stdio/src/printf.rs b/stdio/src/printf.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7dc2f53bbfd3e46ac0335680a845a9f271e93b95
--- /dev/null
+++ b/stdio/src/printf.rs
@@ -0,0 +1,101 @@
+use core::fmt;
+
+use platform::types::*;
+use vl::VaList;
+
+pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaList) -> c_int {
+    use core::fmt::Write;
+    use core::slice;
+    use core::str;
+
+    extern "C" {
+        fn strlen(s: *const c_char) -> size_t;
+    }
+
+    let format = slice::from_raw_parts(format as *const u8, strlen(format));
+
+    let mut i = 0;
+    let mut found_percent = false;
+    while i < format.len() {
+        let b = format[i];
+
+        if found_percent {
+            match b as char {
+                '%' => {
+                    w.write_char('%');
+                    found_percent = false;
+                },
+                'c' => {
+                    let a = ap.get::<u32>();
+
+                    w.write_char(a as u8 as char);
+
+                    found_percent = false;
+                },
+                'd' | 'i' => {
+                    let a = ap.get::<c_int>();
+
+                    w.write_fmt(format_args!("{}", a));
+
+                    found_percent = false;
+                },
+                'n' => {
+                    let _a = ap.get::<c_int>();
+
+                    found_percent = false;
+                },
+                'p' => {
+                    let a = ap.get::<usize>();
+
+                    w.write_fmt(format_args!("0x{:x}", a));
+
+                    found_percent = false;
+                },
+                's' => {
+                    let a = ap.get::<usize>();
+
+                    w.write_str(str::from_utf8_unchecked(
+                        slice::from_raw_parts(a as *const u8, strlen(a as *const c_char))
+                    ));
+
+                    found_percent = false;
+                },
+                'u' => {
+                    let a = ap.get::<c_uint>();
+
+                    w.write_fmt(format_args!("{}", a));
+
+                    found_percent = false;
+                },
+                'x' => {
+                    let a = ap.get::<c_uint>();
+
+                    w.write_fmt(format_args!("{:x}", a));
+
+                    found_percent = false;
+                },
+                'X' => {
+                    let a = ap.get::<c_uint>();
+
+                    w.write_fmt(format_args!("{:X}", a));
+
+                    found_percent = false;
+                },
+                '-' => {},
+                '+' => {},
+                ' ' => {},
+                '#' => {},
+                '0' ... '9' => {},
+                _ => {}
+            }
+        } else if b == b'%' {
+            found_percent = true;
+        } else {
+            w.write_char(b as char);
+        }
+
+        i += 1;
+    }
+
+    0
+}
diff --git a/tests/alloc.c b/tests/alloc.c
index 934f74861b5d7b4c6661cba6e22ceddced51240c..99f11ff75fb8c28a60fc6a7db5ca9f45914369b6 100644
--- a/tests/alloc.c
+++ b/tests/alloc.c
@@ -1,14 +1,12 @@
+#include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 
 int main(int argc, char ** argv) {
-    write(STDERR_FILENO, "malloc\n", 7);
     char * ptr = (char *)malloc(256);
-    write(STDERR_FILENO, "set\n", 4);
+    printf("malloc %p\n", ptr);
     int i;
     for(i = 0; i < 256; i++) {
         ptr[i] = (char)i;
     }
-    write(STDERR_FILENO, "free\n", 5);
     free(ptr);
 }