diff --git a/examples/reverse.rs b/examples/reverse.rs
index f4bccf065d5be7b1375b7c49da1cec150197844b..757651fe16a180475623553cf571e29ab621d164 100644
--- a/examples/reverse.rs
+++ b/examples/reverse.rs
@@ -20,10 +20,12 @@ const FROM: &[u8] = b"Hello Word!";
 const SIZE: usize = FROM.len();
 
 #[no_mangle]
-fn main() {
+fn main() -> ! {
     let mut to: [u8; SIZE] = [0; SIZE];
     rev(&FROM[..], &mut to);
     unsafe {
         core::ptr::read_volatile(&to);
     }
+
+    loop {}
 }
diff --git a/link.ld b/link.ld
index 011a78c99fb697cd54ca5edb935cc6c26eaff36e..45d9809dd213db3557e6b401b6b34b3c269645b6 100644
--- a/link.ld
+++ b/link.ld
@@ -22,13 +22,20 @@ SECTIONS
 
     .data :
     {
-        *(.data*)
+        __sdata = .;
+        *(.data*);
+        __edata = .;
     }
 
+    /* LMA of .data */
+    __sidata = LOADADDR(.data);
+    
     _BSS_START = .;
     .bss :
     {
-        *(.bss*)
+        __sbss = .;
+        *(.bss*);
+        __ebss = .;
     }
     _BSS_END = .;
 
diff --git a/src/lib.rs b/src/lib.rs
index 7b9304f34965ddda715166907a083a427db14143..48792c97a11cd1944b42985c55dede933adaf8c1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,12 +1,77 @@
 #![feature(lang_items)]
 #![no_std]
-#![no_main]
+
+use core::{mem, ptr, slice};
 
 #[panic_handler]
 fn my_panic(_info: &core::panic::PanicInfo) -> ! {
     loop {}
 }
 
+/// Initializes the `.data` section
+///
+/// # Arguments
+///
+/// - `sdata`. Pointer to the start of the `.data` section.
+/// - `edata`. Pointer to the open/non-inclusive end of the `.data` section.
+///   (The value behind this pointer will not be modified)
+/// - `sidata`. `.data` section Load Memory Address (LMA)
+/// - Use `T` to indicate the alignment of the `.data` section and its LMA.
+///
+/// # Safety
+///
+/// - Must be called exactly once
+/// - `mem::size_of::<T>()` must be non-zero
+/// - `edata >= sdata`
+/// - The `sdata -> edata` region must not overlap with the `sidata -> ...`
+///   region
+/// - `sdata`, `edata` and `sidata` must be `T` aligned.
+pub unsafe fn init_data<T>(mut sdata: *mut T, edata: *mut T, mut sidata: *const T)
+where
+    T: Copy,
+{
+    while sdata < edata {
+        ptr::write(sdata, ptr::read(sidata));
+        sdata = sdata.offset(1);
+        sidata = sidata.offset(1);
+    }
+}
+
+pub unsafe fn run_init_array(init_array_start: &extern "C" fn(), init_array_end: &extern "C" fn()) {
+    let n = (init_array_end as *const _ as usize - init_array_start as *const _ as usize)
+        / mem::size_of::<extern "C" fn()>();
+
+    for f in slice::from_raw_parts(init_array_start, n) {
+        f();
+    }
+}
+
+/// Zeroes the `.bss` section
+///
+/// # Arguments
+///
+/// - `sbss`. Pointer to the start of the `.bss` section.
+/// - `ebss`. Pointer to the open/non-inclusive end of the `.bss` section.
+///   (The value behind this pointer will not be modified)
+/// - Use `T` to indicate the alignment of the `.bss` section.
+///
+/// # Safety
+///
+/// - Must be called exactly once
+/// - `mem::size_of::<T>()` must be non-zero
+/// - `ebss >= sbss`
+/// - `sbss` and `ebss` must be `T` aligned.
+pub unsafe fn zero_bss<T>(mut sbss: *mut T, ebss: *mut T)
+where
+    T: Copy,
+{
+    while sbss < ebss {
+        // NOTE(volatile) to prevent this from being transformed into `memclr`
+        ptr::write_volatile(sbss, mem::zeroed());
+        sbss = sbss.offset(1);
+    }
+}
+
 // The reset vector, a pointer into the reset handler
 #[link_section = ".init"]
 #[no_mangle]
@@ -28,11 +93,11 @@ pub extern "C" fn _start() -> ! {
     }
 
     // Initialize RAM
-    // r0::zero_bss(&mut __sbss, &mut __ebss);
-    // r0::init_data(&mut __sdata, &mut __edata, &__sidata);
-
-    unsafe { main() }
-    loop {}
+    unsafe {
+        zero_bss(&mut __sbss, &mut __ebss);
+        init_data(&mut __sdata, &mut __edata, &__sidata);
+        unsafe { main() }
+    }
 }
 
 #[lang = "eh_personality"]