diff --git a/ci/build.sh b/ci/build.sh
index 74727a3313a1f2ec553b355d19ed44c85b4e60c4..b830ceb0f22b41246e2a867842b1b9e588f7172f 100644
--- a/ci/build.sh
+++ b/ci/build.sh
@@ -167,7 +167,9 @@ done
 # FIXME: https://github.com/rust-lang/rust/issues/58564
 # sparc-unknown-linux-gnu
 RUST_LINUX_NO_CORE_TARGETS="\
+x86_64-unknown-hermit \
 x86_64-unknown-dragonfly \
+aarch64-unknown-hermit \
 aarch64-pc-windows-msvc \
 aarch64-unknown-cloudabi \
 armebv7r-none-eabi \
diff --git a/src/hermit/aarch64.rs b/src/hermit/aarch64.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1a92e3b4fa3412169caf35628d91ccfae399d6e9
--- /dev/null
+++ b/src/hermit/aarch64.rs
@@ -0,0 +1,2 @@
+pub type c_char = u8;
+pub type wchar_t = u32;
diff --git a/src/hermit/mod.rs b/src/hermit/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3e15175a585c5f64f48dd2f0728316c641f0d6f0
--- /dev/null
+++ b/src/hermit/mod.rs
@@ -0,0 +1,83 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// libc port for HermitCore (https://hermitcore.org)
+//
+// Ported by Colin Fink <colin.finck@rwth-aachen.de>
+//       and Stefan Lankes <slankes@eonerc.rwth-aachen.de>
+
+pub type int8_t = i8;
+pub type int16_t = i16;
+pub type int32_t = i32;
+pub type int64_t = i64;
+pub type uint8_t = u8;
+pub type uint16_t = u16;
+pub type uint32_t = u32;
+pub type uint64_t = u64;
+
+pub type c_schar = i8;
+pub type c_uchar = u8;
+pub type c_short = i16;
+pub type c_ushort = u16;
+pub type c_int = i32;
+pub type c_uint = u32;
+pub type c_float = f32;
+pub type c_double = f64;
+pub type c_longlong = i64;
+pub type c_ulonglong = u64;
+pub type intmax_t = i64;
+pub type uintmax_t = u64;
+
+pub type size_t = usize;
+pub type ptrdiff_t = isize;
+pub type intptr_t = isize;
+pub type uintptr_t = usize;
+pub type ssize_t = isize;
+
+pub type c_long = i64;
+pub type c_ulong = u64;
+
+pub type wint_t = u32;
+pub type wctype_t = i64;
+
+pub type regoff_t = size_t;
+pub type off_t = c_long;
+
+cfg_if! {
+    if #[cfg(target_arch = "aarch64")] {
+        mod aarch64;
+        pub use self::aarch64::*;
+    } else if #[cfg(target_arch = "x86_64")] {
+        mod x86_64;
+        pub use self::x86_64::*;
+    } else {
+        // Unknown target_arch
+    }
+}
+
+cfg_if! {
+    if #[cfg(libc_core_cvoid)] {
+        pub use ::ffi::c_void;
+    } else {
+        // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help
+        // enable more optimization opportunities around it recognizing things
+        // like malloc/free.
+        #[repr(u8)]
+        #[allow(missing_copy_implementations)]
+        #[allow(missing_debug_implementations)]
+        pub enum c_void {
+            // Two dummy variants so the #[repr] attribute can be used.
+            #[doc(hidden)]
+            __variant1,
+            #[doc(hidden)]
+            __variant2,
+        }
+    }
+}
diff --git a/src/hermit/x86_64.rs b/src/hermit/x86_64.rs
new file mode 100644
index 0000000000000000000000000000000000000000..76ec3ce823e8fedfc49c9e9118285af65b5d86fb
--- /dev/null
+++ b/src/hermit/x86_64.rs
@@ -0,0 +1,2 @@
+pub type c_char = i8;
+pub type wchar_t = i32;
diff --git a/src/lib.rs b/src/lib.rs
index 2fec61c2c0eac489843d44e218ebf253abf71280..019f072e1784a09418b5513b67029dd37263194f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -106,6 +106,9 @@ cfg_if! {
     } else if #[cfg(unix)] {
         mod unix;
         pub use unix::*;
+    } else if #[cfg(target_os = "hermit")] {
+        mod hermit;
+        pub use hermit::*;
     } else if #[cfg(target_env = "sgx")] {
         mod sgx;
         pub use sgx::*;
diff --git a/src/unix/hermit/mod.rs b/src/unix/hermit/mod.rs
index 0c372f12128e6835ff32bb5dd461cfb9d2fb6000..288cc46a50693c0bca4f43fa37291d75eef478eb 100644
--- a/src/unix/hermit/mod.rs
+++ b/src/unix/hermit/mod.rs
@@ -19,8 +19,6 @@
 pub type c_long = i64;
 pub type c_ulong = u64;
 
-pub type uid_t = u16;
-pub type gid_t = u16;
 pub type speed_t = ::c_uint;
 pub type mode_t = u32;
 pub type dev_t = i16;
@@ -49,6 +47,326 @@ pub type pthread_mutexattr_t = usize;
 pub type pthread_rwlock_t = usize;
 pub type pthread_rwlockattr_t = usize;
 
+s_no_extra_traits! {
+    pub struct dirent {
+        pub d_ino: ::c_long,
+        pub d_off: off_t,
+        pub d_reclen: u16,
+        pub d_name: [::c_char; 256],
+    }
+
+    // Dummy
+    pub struct sockaddr_un {
+        pub sun_family: sa_family_t,
+        pub sun_path: [::c_char; 108],
+    }
+
+    pub struct sockaddr {
+        pub sa_len: u8,
+        pub sa_family: sa_family_t,
+        pub sa_data: [::c_char; 14],
+    }
+
+    pub struct sockaddr_in {
+        pub sin_len: u8,
+        pub sin_family: sa_family_t,
+        pub sin_port: ::in_port_t,
+        pub sin_addr: ::in_addr,
+        pub sin_zero: [::c_char; 8],
+    }
+
+    pub struct fd_set {
+        fds_bits: [::c_ulong; FD_SETSIZE / ULONG_SIZE],
+    }
+
+    pub struct sockaddr_storage {
+        pub s2_len: u8,
+        pub ss_family: sa_family_t,
+        pub s2_data1: [::c_char; 2],
+        pub s2_data2: [u32; 3],
+        pub s2_data3: [u32; 3],
+    }
+
+    pub struct stat {
+        pub st_dev: ::dev_t,
+        pub st_ino: ::ino_t,
+        pub st_mode: ::mode_t,
+        pub st_nlink: ::nlink_t,
+        pub st_uid: ::uid_t,
+        pub st_gid: ::gid_t,
+        pub st_rdev: dev_t,
+        pub st_size: off_t,
+        pub st_atime: time_t,
+        pub st_atime_nsec: ::c_long,
+        pub st_mtime: time_t,
+        pub st_mtime_nsec: ::c_long,
+        pub st_ctime: time_t,
+        pub st_ctime_nsec: ::c_long,
+        pub st_blksize: blksize_t,
+        pub st_blocks: blkcnt_t,
+        pub st_spare4: [::c_long; 2],
+    }
+}
+
+cfg_if! {
+    if #[cfg(feature = "extra_traits")] {
+        impl PartialEq for dirent {
+            fn eq(&self, other: &dirent) -> bool {
+                self.d_ino == other.d_ino
+                    && self.d_off == other.d_off
+                    && self.d_reclen == other.d_reclen
+                    && self
+                    .d_name
+                    .iter()
+                    .zip(other.d_name.iter())
+                    .all(|(a,b)| a == b)
+            }
+        }
+        impl Eq for dirent {}
+        impl ::fmt::Debug for dirent {
+            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+                f.debug_struct("dirent")
+                    .field("d_ino", &self.d_ino)
+                    .field("d_off", &self.d_off)
+                    .field("d_reclen", &self.d_reclen)
+                    // FIXME: .field("d_name", &self.d_name)
+                    .finish()
+            }
+        }
+        impl ::hash::Hash for dirent {
+            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
+                self.d_ino.hash(state);
+                self.d_off.hash(state);
+                self.d_reclen.hash(state);
+                self.d_name.hash(state);
+            }
+        }
+
+        impl PartialEq for sockaddr_un {
+            fn eq(&self, other: &sockaddr_un) -> bool {
+                self.sun_family == other.sun_family
+                    && self
+                    .sun_path
+                    .iter()
+                    .zip(other.sun_path.iter())
+                    .all(|(a,b)| a == b)
+            }
+        }
+        impl Eq for sockaddr_un {}
+        impl ::fmt::Debug for sockaddr_un {
+            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+                f.debug_struct("sockaddr_un")
+                    .field("sun_family", &self.sun_family)
+                    // FIXME: .field("sun_path", &self.sun_path)
+                    .finish()
+            }
+        }
+        impl ::hash::Hash for sockaddr_un {
+            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
+                self.sun_family.hash(state);
+                self.sun_path.hash(state);
+            }
+        }
+
+        impl PartialEq for sockaddr {
+            fn eq(&self, other: &sockaddr) -> bool {
+                self.sa_len == other.sa_len
+                    && self.sa_family == other.sa_family
+                    && self
+                    .sa_data
+                    .iter()
+                    .zip(other.sa_data.iter())
+                    .all(|(a,b)| a == b)
+            }
+        }
+        impl Eq for sockaddr {}
+        impl ::fmt::Debug for sockaddr {
+            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+                f.debug_struct("sockaddr")
+                    .field("sa_len", &self.sa_len)
+                    .field("sa_family", &self.sa_family)
+                    // FIXME: .field("sa_data", &self.sa_data)
+                    .finish()
+            }
+        }
+        impl ::hash::Hash for sockaddr {
+            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
+                self.sa_len.hash(state);
+                self.sa_family.hash(state);
+                self.sa_data.hash(state);
+            }
+        }
+
+        impl PartialEq for sockaddr_in {
+            fn eq(&self, other: &sockaddr_in) -> bool {
+                self.sin_len == other.sin_len
+                    && self.sin_family == other.sin_family
+                    && self.sin_port == other.sin_port
+                    && self.sin_addr == other.sin_addr
+                    && self
+                    .sin_zero
+                    .iter()
+                    .zip(other.sin_zero.iter())
+                    .all(|(a,b)| a == b)
+            }
+        }
+        impl Eq for sockaddr_in {}
+        impl ::fmt::Debug for sockaddr_in {
+            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+                f.debug_struct("sockaddr_in")
+                    .field("sin_len", &self.sin_len)
+                    .field("sin_family", &self.sin_family)
+                    .field("sin_port", &self.sin_port)
+                    .field("sin_addr", &self.sin_addr)
+                    // FIXME: .field("sin_zero", &self.sin_zero)
+                    .finish()
+            }
+        }
+        impl ::hash::Hash for sockaddr_in {
+            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
+                self.sin_len.hash(state);
+                self.sin_family.hash(state);
+                self.sin_port.hash(state);
+                self.sin_addr.hash(state);
+                self.sin_zero.hash(state);
+            }
+        }
+
+        impl PartialEq for fd_set {
+            fn eq(&self, other: &fd_set) -> bool {
+                self.fds_bits
+                    .iter()
+                    .zip(other.fds_bits.iter())
+                    .all(|(a,b)| a == b)
+            }
+        }
+        impl Eq for fd_set {}
+        impl ::fmt::Debug for fd_set {
+            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+                f.debug_struct("fd_set")
+                    // FIXME: .field("fds_bits", &self.fds_bits)
+                    .finish()
+            }
+        }
+        impl ::hash::Hash for fd_set {
+            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
+                self.fds_bits.hash(state);
+            }
+        }
+
+        impl PartialEq for sockaddr_storage {
+            fn eq(&self, other: &sockaddr_storage) -> bool {
+                self.s2_len == other.s2_len
+                    && self.ss_family == other.ss_family
+                    && self.s2_data1
+                    .iter()
+                    .zip(other.s2_data1.iter())
+                    .all(|(a,b)| a == b)
+                    && self.s2_data2
+                    .iter()
+                    .zip(other.s2_data2.iter())
+                    .all(|(a,b)| a == b)
+                    && self.s2_data3
+                    .iter()
+                    .zip(other.s2_data3.iter())
+                    .all(|(a,b)| a == b)
+            }
+        }
+        impl Eq for sockaddr_storage {}
+        impl ::fmt::Debug for sockaddr_storage {
+            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+                f.debug_struct("sockaddr_storage")
+                    .field("s2_len", &self.s2_len)
+                    .field("ss_family", &self.ss_family)
+                    // FIXME: .field("s2_data1", &self.s2_data1)
+                    // FIXME: .field("s2_data2", &self.s2_data2)
+                    // FIXME: .field("s2_data3", &self.s2_data3)
+                    .finish()
+            }
+        }
+        impl ::hash::Hash for sockaddr_storage {
+            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
+                self.s2_len.hash(state);
+                self.ss_family.hash(state);
+                self.s2_data1.hash(state);
+                self.s2_data2.hash(state);
+                self.s2_data3.hash(state);
+            }
+        }
+
+        impl PartialEq for stat {
+            fn eq(&self, other: &stat) -> bool {
+                self.st_dev == other.st_dev
+                    && self.st_ino == other.st_ino
+                    && self.st_mode == other.st_mode
+                    && self.st_nlink == other.st_nlink
+                    && self.st_uid == other.st_uid
+                    && self.st_gid == other.st_gid
+                    && self.st_rdev == other.st_rdev
+                    && self.st_size == other.st_size
+                    && self.st_atime == other.st_atime
+                    && self.st_atime_nsec == other.st_atime_nsec
+                    && self.st_mtime == other.st_mtime
+                    && self.st_mtime_nsec == other.st_mtime_nsec
+                    && self.st_ctime == other.st_ctime
+                    && self.st_ctime_nsec == other.st_ctime_nsec
+                    && self.st_blksize == other.st_blksize
+                    && self.st_blocks == other.st_blocks
+                    && self
+                    .st_spare4
+                    .iter()
+                    .zip(other.st_spare4.iter())
+                    .all(|(a,b)| a == b)
+            }
+        }
+        impl Eq for stat {}
+        impl ::fmt::Debug for stat {
+            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+                f.debug_struct("stat")
+                    .field("st_dev", &self.st_dev)
+                    .field("st_ino", &self.st_ino)
+                    .field("st_mode", &self.st_mode)
+                    .field("st_nlink", &self.st_nlink)
+                    .field("st_uid", &self.st_uid)
+                    .field("st_gid", &self.st_gid)
+                    .field("st_rdev", &self.st_rdev)
+                    .field("st_size", &self.st_size)
+                    .field("st_atime", &self.st_atime)
+                    .field("st_atime_nsec", &self.st_atime_nsec)
+                    .field("st_mtime", &self.st_mtime)
+                    .field("st_mtime_nsec", &self.st_mtime_nsec)
+                    .field("st_ctime", &self.st_ctime)
+                    .field("st_ctime_nsec", &self.st_ctime_nsec)
+                    .field("st_blksize", &self.st_blksize)
+                    .field("st_blocks", &self.st_blocks)
+                    // FIXME: .field("st_spare4", &self.st_spare4)
+                    .finish()
+            }
+        }
+        impl ::hash::Hash for stat {
+            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
+                self.st_dev.hash(state);
+                self.st_ino.hash(state);
+                self.st_mode.hash(state);
+                self.st_nlink.hash(state);
+                self.st_uid.hash(state);
+                self.st_gid.hash(state);
+                self.st_rdev.hash(state);
+                self.st_size.hash(state);
+                self.st_atime.hash(state);
+                self.st_atime_nsec.hash(state);
+                self.st_mtime.hash(state);
+                self.st_mtime_nsec.hash(state);
+                self.st_ctime.hash(state);
+                self.st_ctime_nsec.hash(state);
+                self.st_blksize.hash(state);
+                self.st_blocks.hash(state);
+                self.st_spare4.hash(state);
+            }
+        }
+    }
+}
+
 s! {
     pub struct in_addr {
         pub s_addr: ::in_addr_t,
@@ -70,19 +388,8 @@ s! {
         pub ai_next: *mut addrinfo,
     }
 
-    pub struct dirent {
-        pub d_ino: ::c_long,
-        pub d_off: off_t,
-        pub d_reclen: u16,
-        pub d_name: [::c_char; 256],
-    }
-
     pub struct Dl_info {}
 
-    pub struct fd_set {
-        fds_bits: [::c_ulong; FD_SETSIZE / ULONG_SIZE],
-    }
-
     pub struct lconv {
         pub decimal_point: *mut ::c_char,
         pub thousands_sep: *mut ::c_char,
@@ -141,20 +448,6 @@ s! {
         pub sa_handler: usize,
     }
 
-    pub struct sockaddr {
-        pub sa_len: u8,
-        pub sa_family: sa_family_t,
-        pub sa_data: [::c_char; 14],
-    }
-
-    pub struct sockaddr_in {
-        pub sin_len: u8,
-        pub sin_family: sa_family_t,
-        pub sin_port: ::in_port_t,
-        pub sin_addr: ::in_addr,
-        pub sin_zero: [::c_char; 8],
-    }
-
     pub struct sockaddr_in6 {
         pub sin6_len: u8,
         pub sin6_family: sa_family_t,
@@ -164,40 +457,6 @@ s! {
         pub sin6_scope_id: u32,
     }
 
-    pub struct sockaddr_storage {
-        pub s2_len: u8,
-        pub ss_family: sa_family_t,
-        pub s2_data1: [::c_char; 2],
-        pub s2_data2: [u32; 3],
-        pub s2_data3: [u32; 3],
-    }
-
-    // Dummy
-    pub struct sockaddr_un {
-        pub sun_family: sa_family_t,
-        pub sun_path: [::c_char; 108],
-    }
-
-    pub struct stat {
-        pub st_dev: ::dev_t,
-        pub st_ino: ::ino_t,
-        pub st_mode: ::mode_t,
-        pub st_nlink: ::nlink_t,
-        pub st_uid: ::uid_t,
-        pub st_gid: ::gid_t,
-        pub st_rdev: dev_t,
-        pub st_size: off_t,
-        pub st_atime: time_t,
-        pub st_atime_nsec: ::c_long,
-        pub st_mtime: time_t,
-        pub st_mtime_nsec: ::c_long,
-        pub st_ctime: time_t,
-        pub st_ctime_nsec: ::c_long,
-        pub st_blksize: blksize_t,
-        pub st_blocks: blkcnt_t,
-        pub st_spare4: [::c_long; 2],
-    }
-
     pub struct statvfs {}
 
     pub struct tm {