diff --git a/lib/kernel/stdio.h b/lib/kernel/stdio.h
index 3e5bae9b65b27d6008ee758df692da91e2b00b58..c7f9b392acc1aaac194b340560f8c57bbc75cb3f 100644
--- a/lib/kernel/stdio.h
+++ b/lib/kernel/stdio.h
@@ -1,5 +1,6 @@
 #ifndef __LIB_KERNEL_STDIO_H
 #define __LIB_KERNEL_STDIO_H
+#include <stddef.h>
 
 void putbuf (const char *, size_t);
 
diff --git a/userprog/syscall_write.c b/userprog/syscall_write.c
index cf476a75ac71b4cca1b482a88a46d47f4fb97edc..24e70395ab52c0e19a06d5ba57dfe2176bd87354 100644
--- a/userprog/syscall_write.c
+++ b/userprog/syscall_write.c
@@ -3,10 +3,29 @@
  *
  * Authored by Joshua Saxby
  */
+#include <stdio.h>
+#include "lib/kernel/stdio.h"
 #include "system_calls.h"
 #include "threads/interrupt.h"
 
 void syscall_write(struct intr_frame *f) {
-    // TODO: implement me!
-    (void*)0;
+    // first argument is syscall code (already handled)
+    int fd = *((int*)f->esp + 1); // file descriptor is second argument
+    void* buffer = (void*)(*((int*)f->esp + 2)); // buffer is third argument
+    unsigned size = *((unsigned*)((int*)f->esp + 3)); // size to write is fourth
+    printf("syscall_write: fd = %d\n", fd);
+    printf("syscall_write: buffer = '%s'\n", buffer);
+    printf("syscall_write: size = %u\n", size);
+    // writing to stdout or stderr (fd in {1, 2}) is a special case
+    switch (fd) {
+    case 1:
+    // case 2:
+        // TODO: split up output into reasonable-sized chunks
+        putbuf((const char*)buffer, size);
+        f->eax = size;
+        break;
+    default:
+        // XXX: unimplemented for now
+        break;
+    }
 }