diff --git a/epicardium/meson.build b/epicardium/meson.build
index 4c32b0a08b69922979ece04781b3cf51c2f03a04..c9b128f7289f791bc4c8bbd2040d7b8d10e1d710 100644
--- a/epicardium/meson.build
+++ b/epicardium/meson.build
@@ -85,6 +85,7 @@ elf = executable(
   include_directories: [freertos_includes],
   link_args: [
     '-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map',
+    '-Wl,--defsym=_write=_write_epicardium',
   ],
 )
 
diff --git a/epicardium/modules/serial.c b/epicardium/modules/serial.c
index db188ebe4474e8ac03cf0dbe773bf00e28e49e6e..a7392056f31705e9c6f334f60952ece4dee22d10 100644
--- a/epicardium/modules/serial.c
+++ b/epicardium/modules/serial.c
@@ -49,7 +49,7 @@ int epic_uart_read_char(void)
  */
 int epic_uart_read_str(char *buf, size_t cnt)
 {
-	int i = 0;
+	size_t i = 0;
 
 	for (i = 0; i < cnt; i++) {
 		if (xQueueReceive(read_queue, &buf[i], 0) != pdTRUE) {
@@ -60,6 +60,24 @@ int epic_uart_read_str(char *buf, size_t cnt)
 	return i;
 }
 
+long _write_epicardium(int fd, const char *buf, size_t cnt)
+{
+	/*
+	 * Only print one line at a time.  Insert `\r` between lines so they are
+	 * properly displayed on the serial console.
+	 */
+	size_t i, last = 0;
+	for (i = 0; i < cnt; i++) {
+		if (buf[i] == '\n') {
+			epic_uart_write_str(&buf[last], i - last);
+			epic_uart_write_str("\r", 1);
+			last = i;
+		}
+	}
+	epic_uart_write_str(&buf[last], cnt - last);
+	return cnt;
+}
+
 /* Interrupt handler needed for SDK UART implementation */
 void UART0_IRQHandler(void)
 {