diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs
index 86892cb97c19bcb7fdc5868a20f01fad1ad3ff7a..866643ebec07c765a4d7ab0ffcf2adb4f50f664d 100644
--- a/src/header/stdlib/mod.rs
+++ b/src/header/stdlib/mod.rs
@@ -388,12 +388,12 @@ pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: size_
             _ => 63,
         };
 
-        random::X_PTR = (state as *mut u32).offset(1);
+        random::X_PTR = (state.cast::<[u8; 4]>()).offset(1);
         random::seed(seed);
         random::save_state();
         // TODO: unlock?
 
-        old_state as _
+        old_state.cast::<_>()
     }
 }
 
@@ -763,12 +763,18 @@ pub unsafe extern "C" fn random() -> c_long {
     random::ensure_x_ptr_init();
 
     if random::N == 0 {
-        *random::X_PTR = random::lcg31_step(*random::X_PTR);
-        k = *random::X_PTR;
+        let x_old = u32::from_ne_bytes(*random::X_PTR);
+        let x_new = random::lcg31_step(x_old);
+        *random::X_PTR = x_new.to_ne_bytes();
+        k = x_new;
     } else {
-        *random::X_PTR.add(usize::from(random::I)) += *random::X_PTR.add(usize::from(random::J));
+        // The non-u32-aligned way of saying x[i] += x[j]...
+        let x_i_old = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::I)));
+        let x_j = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::J)));
+        let x_i_new = x_i_old.wrapping_add(x_j);
+        *random::X_PTR.add(usize::from(random::I)) = x_i_new.to_ne_bytes();
 
-        k = *random::X_PTR.add(usize::from(random::I)) >> 1;
+        k = x_i_new >> 1;
 
         random::I += 1;
         if random::I == random::N {
@@ -916,9 +922,9 @@ pub unsafe extern "C" fn setstate(state: *mut c_char) -> *mut c_char {
 
     // TODO: lock?
     let old_state = random::save_state();
-    random::load_state(state as *mut u32);
+    random::load_state(state.cast::<_>());
     // TODO: unlock?
-    old_state as _
+    old_state.cast::<_>()
 }
 
 #[no_mangle]
diff --git a/src/header/stdlib/random.rs b/src/header/stdlib/random.rs
index b390d5e487b8d3754cc8564ae170e86ce1167067..f08155924ea6993478352a69833d46f14e4b374b 100644
--- a/src/header/stdlib/random.rs
+++ b/src/header/stdlib/random.rs
@@ -24,14 +24,20 @@ pub static mut N: u8 = 31;
 pub static mut I: u8 = 3;
 pub static mut J: u8 = 0;
 
-/* Unlike in C, we can't take the address of the initializing array
- * outside of a function. */
-pub static mut X_PTR: *mut u32 = ptr::null_mut();
+/* As such, random() and related functions work on u32 values, but POSIX
+ * allows the user to supply a custom state data array as a `char *`
+ * with no requirements on alignment. Thus, we must assume the worst in
+ * terms of alignment and convert back and forth from [u8; 4].
+ *
+ * Also, unlike in C, we can't take the address of the initializing
+ * array outside of a function. */
+pub static mut X_PTR: *mut [u8; 4] = ptr::null_mut();
 
 // To be called in any function that may read from X_PTR
 pub unsafe fn ensure_x_ptr_init() {
     if X_PTR.is_null() {
-        X_PTR = &mut X_INIT[1];
+        let x_u32_ptr: *mut u32 = &mut X_INIT[1];
+        X_PTR = x_u32_ptr.cast::<[u8; 4]>();
     }
 }
 
@@ -43,24 +49,26 @@ pub fn lcg64_step(x: u64) -> u64 {
     6364136223846793005_u64.wrapping_mul(x).wrapping_add(1_u64)
 }
 
-pub unsafe fn save_state() -> *mut u32 {
+pub unsafe fn save_state() -> *mut [u8; 4] {
     ensure_x_ptr_init();
-    *X_PTR.offset(-1) = (u32::from(N) << 16) | (u32::from(I) << 8) | u32::from(J);
+
+    let stash_value: u32 = (u32::from(N) << 16) | (u32::from(I) << 8) | u32::from(J);
+    *X_PTR.offset(-1) = stash_value.to_ne_bytes();
     X_PTR.offset(-1)
 }
 
-pub unsafe fn load_state(state_ptr: *mut u32) {
-    let prev_x = *state_ptr;
+pub unsafe fn load_state(state_ptr: *mut [u8; 4]) {
+    let stash_value = u32::from_ne_bytes(*state_ptr);
     X_PTR = state_ptr.offset(1);
 
     /* This calculation of N does not have a bit mask in the musl
      * original, in principle resulting in a u16, but obtaining a value
      * larger than 63 can probably be dismissed as pathological. */
-    N = u8::try_from((prev_x >> 16) & 0xff).unwrap();
+    N = u8::try_from((stash_value >> 16) & 0xff).unwrap();
 
     // I and J calculations are straight from musl
-    I = u8::try_from((prev_x >> 8) & 0xff).unwrap();
-    J = u8::try_from(prev_x & 0xff).unwrap();
+    I = u8::try_from((stash_value >> 8) & 0xff).unwrap();
+    J = u8::try_from(stash_value & 0xff).unwrap();
 }
 
 pub unsafe fn seed(seed: c_uint) {
@@ -69,7 +77,7 @@ pub unsafe fn seed(seed: c_uint) {
     let mut s = seed as u64;
 
     if N == 0 {
-        *X_PTR = s as u32;
+        *X_PTR = (s as u32).to_ne_bytes();
     } else {
         I = if N == 31 || N == 7 { 3 } else { 1 };
 
@@ -80,10 +88,10 @@ pub unsafe fn seed(seed: c_uint) {
 
             // Conversion will always succeed (value is a 32-bit right-
             // shift of a 64-bit integer).
-            *X_PTR.add(k) = u32::try_from(s >> 32).unwrap();
+            *X_PTR.add(k) = u32::try_from(s >> 32).unwrap().to_ne_bytes();
         }
 
         // ensure X contains at least one odd number
-        *X_PTR |= 1;
+        *X_PTR = (u32::from_ne_bytes(*X_PTR) | 1).to_ne_bytes();
     }
 }