diff --git a/configure.ac b/configure.ac
index 03b67a9d..63aeb748 100644
--- a/configure.ac
+++ b/configure.ac
@@ -428,6 +428,7 @@ AC_CHECK_DECLS([memrchr, rawmemchr],[],[],
                [#define _GNU_SOURCE
                 #include <string.h>])
 AC_CHECK_DECLS([powerof2],[],[],[#include <sys/param.h>])
+AC_CHECK_DECLS([mmap],[],[],[#include <sys/mman.h>])
 AC_CHECK_DECLS([mempcpy],[],[],
                [#define _GNU_SOURCE
                 #include <string.h>])
diff --git a/lib/system.h b/lib/system.h
index bbbe06c4..05b5cf8d 100644
--- a/lib/system.h
+++ b/lib/system.h
@@ -40,21 +40,78 @@
 #include <stdlib.h>
 
 /* System dependend headers */
+#if !defined(_WIN32)
 #include <byteswap.h>
 #include <endian.h>
-#include <sys/mman.h>
+#endif
+
+#if defined(_MSC_VER)
+#include <basetsd.h>
+#include <io.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+typedef SSIZE_T ssize_t;
+#else
 #include <sys/param.h>
 #include <unistd.h>
+#endif
+
+#if HAVE_DECL_MMAP
+#include <sys/mman.h>
+#endif
 
 #if defined(HAVE_ERROR_H)
 #include <error.h>
-#elif defined(HAVE_ERR_H)
+#elif defined(HAVE_ERR_H) || defined(_MSC_VER)
 extern int error_message_count;
 void error(int status, int errnum, const char *format, ...);
 #else
 #error "err.h or error.h must be available"
 #endif
 
+#if defined(_MSC_VER)
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#define BYTE_ORDER LITTLE_ENDIAN
+static inline int ftruncate(int fd, off_t length)
+{
+     return _chsize_s(fd, length);
+}
+#endif /* defined(_MSC_VER) */
+
+#if defined(_WIN32)
+static inline uint16_t bswap_16(uint16_t x) {
+  return ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8));
+}
+
+static inline uint32_t bswap_32(uint32_t x) {
+  return (
+    (((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |
+    (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24)
+  );
+}
+
+static inline uint64_t bswap_64(uint64_t x) {
+  return (
+    (((x) & 0xff00000000000000ull) >> 56) |
+    (((x) & 0x00ff000000000000ull) >> 40) |
+    (((x) & 0x0000ff0000000000ull) >> 24) |
+    (((x) & 0x000000ff00000000ull) >> 8)  |
+    (((x) & 0x00000000ff000000ull) << 8)  |
+    (((x) & 0x0000000000ff0000ull) << 24) |
+    (((x) & 0x000000000000ff00ull) << 40) |
+    (((x) & 0x00000000000000ffull) << 56)
+  );
+}
+
+#define htobe64(x) bswap_64(x)
+#define be64toh(x) bswap_64(x)
+
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+#endif /* defined(_WIN32) */
+
 /* error (EXIT_FAILURE, ...) should be noreturn but on some systems it
    isn't.  This may cause warnings about code that should not be reachable.
    So have an explicit error_exit wrapper that is noreturn (because it
diff --git a/lib/system_win32.c b/lib/system_win32.c
new file mode 100644
index 00000000..d9941cc5
--- /dev/null
+++ b/lib/system_win32.c
@@ -0,0 +1,162 @@
+/* Copyright (C) 2022 Yonggang Luo
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include "system.h"
+
+#include <windows.h>
+
+static const struct
+{
+  DWORD winerr;
+  int doserr;
+} doserrors[] =
+
+    {
+        {ERROR_INVALID_FUNCTION, EINVAL},
+        {ERROR_FILE_NOT_FOUND, ENOENT},
+        {ERROR_PATH_NOT_FOUND, ENOENT},
+        {ERROR_TOO_MANY_OPEN_FILES, EMFILE},
+        {ERROR_ACCESS_DENIED, EACCES},
+        {ERROR_INVALID_HANDLE, EBADF},
+        {ERROR_ARENA_TRASHED, ENOMEM},
+        {ERROR_NOT_ENOUGH_MEMORY, ENOMEM},
+        {ERROR_INVALID_BLOCK, ENOMEM},
+        {ERROR_BAD_ENVIRONMENT, E2BIG},
+        {ERROR_BAD_FORMAT, ENOEXEC},
+        {ERROR_INVALID_ACCESS, EINVAL},
+        {ERROR_INVALID_DATA, EINVAL},
+        {ERROR_INVALID_DRIVE, ENOENT},
+        {ERROR_CURRENT_DIRECTORY, EACCES},
+        {ERROR_NOT_SAME_DEVICE, EXDEV},
+        {ERROR_NO_MORE_FILES, ENOENT},
+        {ERROR_LOCK_VIOLATION, EACCES},
+        {ERROR_SHARING_VIOLATION, EACCES},
+        {ERROR_BAD_NETPATH, ENOENT},
+        {ERROR_NETWORK_ACCESS_DENIED, EACCES},
+        {ERROR_BAD_NET_NAME, ENOENT},
+        {ERROR_FILE_EXISTS, EEXIST},
+        {ERROR_CANNOT_MAKE, EACCES},
+        {ERROR_FAIL_I24, EACCES},
+        {ERROR_INVALID_PARAMETER, EINVAL},
+        {ERROR_NO_PROC_SLOTS, EAGAIN},
+        {ERROR_DRIVE_LOCKED, EACCES},
+        {ERROR_BROKEN_PIPE, EPIPE},
+        {ERROR_DISK_FULL, ENOSPC},
+        {ERROR_INVALID_TARGET_HANDLE, EBADF},
+        {ERROR_INVALID_HANDLE, EINVAL},
+        {ERROR_WAIT_NO_CHILDREN, ECHILD},
+        {ERROR_CHILD_NOT_COMPLETE, ECHILD},
+        {ERROR_DIRECT_ACCESS_HANDLE, EBADF},
+        {ERROR_NEGATIVE_SEEK, EINVAL},
+        {ERROR_SEEK_ON_DEVICE, EACCES},
+        {ERROR_DIR_NOT_EMPTY, ENOTEMPTY},
+        {ERROR_NOT_LOCKED, EACCES},
+        {ERROR_BAD_PATHNAME, ENOENT},
+        {ERROR_MAX_THRDS_REACHED, EAGAIN},
+        {ERROR_LOCK_FAILED, EACCES},
+        {ERROR_ALREADY_EXISTS, EEXIST},
+        {ERROR_FILENAME_EXCED_RANGE, ENOENT},
+        {ERROR_NESTING_NOT_ALLOWED, EAGAIN},
+        {ERROR_NOT_ENOUGH_QUOTA, ENOMEM},
+        {ERROR_DELETE_PENDING, ENOENT}};
+
+static void
+_dosmaperr(unsigned long e)
+{
+  int i;
+
+  if (e == 0)
+  {
+    errno = 0;
+    return;
+  }
+
+  for (i = 0; i < sizeof(doserrors) / sizeof(doserrors[0]); i++)
+  {
+    if (doserrors[i].winerr == e)
+    {
+      int doserr = doserrors[i].doserr;
+
+      errno = doserr;
+      return;
+    }
+  }
+
+  errno = EINVAL;
+}
+
+ssize_t
+pread(int fd, void *buf, size_t count, off_t offset)
+{
+  OVERLAPPED overlapped = {0};
+  HANDLE h;
+  DWORD ret;
+
+  h = (HANDLE)_get_osfhandle(fd);
+  if (h == INVALID_HANDLE_VALUE)
+  {
+    errno = EBADF;
+    return -1;
+  }
+
+  overlapped.Offset = offset;
+  if (!ReadFile(h, buf, count, &ret, &overlapped))
+  {
+    if (GetLastError() == ERROR_HANDLE_EOF)
+      return 0;
+
+    _dosmaperr(GetLastError());
+    return -1;
+  }
+
+  return ret;
+}
+
+ssize_t
+pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+  OVERLAPPED overlapped = {0};
+  HANDLE h;
+  DWORD ret;
+
+  h = (HANDLE)_get_osfhandle(fd);
+  if (h == INVALID_HANDLE_VALUE)
+  {
+    errno = EBADF;
+    return -1;
+  }
+
+  overlapped.Offset = offset;
+  if (!WriteFile(h, buf, count, &ret, &overlapped))
+  {
+    _dosmaperr(GetLastError());
+    return -1;
+  }
+
+  return ret;
+}
diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c
index 46afa1f4..8229fd26 100644
--- a/libelf/elf32_updatefile.c
+++ b/libelf/elf32_updatefile.c
@@ -96,7 +96,7 @@ sort_sections (Elf_Scn **scns, Elf_ScnList *list)
   qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
 }
 
-
+#if HAVE_DECL_MMAP
 static inline void
 fill_mmap (size_t offset, char *last_position, char *scn_start,
            char *const shdr_start, char *const shdr_end)
@@ -482,6 +482,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
 
   return 0;
 }
+#endif
 
 
 /* Size of the buffer we use to generate the blocks of fill bytes.  */
diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c
index fe8c640a..d867cd6f 100644
--- a/libelf/elf_begin.c
+++ b/libelf/elf_begin.c
@@ -645,10 +645,12 @@ static struct Elf *
 read_file (int fildes, int64_t offset, size_t maxsize,
 	   Elf_Cmd cmd, Elf *parent)
 {
+#if HAVE_DECL_MMAP
   void *map_address = NULL;
   int use_mmap = (cmd == ELF_C_READ_MMAP || cmd == ELF_C_RDWR_MMAP
 		  || cmd == ELF_C_WRITE_MMAP
 		  || cmd == ELF_C_READ_MMAP_PRIVATE);
+#endif
 
   if (parent == NULL)
     {
@@ -669,7 +671,7 @@ read_file (int fildes, int64_t offset, size_t maxsize,
       /* The parent is already loaded.  Use it.  */
       assert (maxsize != ~((size_t) 0));
     }
-
+#if HAVE_DECL_MMAP
   if (use_mmap)
     {
       if (parent == NULL)
@@ -713,6 +715,7 @@ read_file (int fildes, int64_t offset, size_t maxsize,
 
       return result;
     }
+#endif
 
   /* Otherwise we have to do it the hard way.  We read as much as necessary
      from the file whenever we need information which is not available.  */
@@ -1160,12 +1163,14 @@ elf_begin (int fildes, Elf_Cmd cmd, Elf *ref)
   if (ref != NULL)
     /* Make sure the descriptor is not suddenly going away.  */
     rwlock_rdlock (ref->lock);
+#if defined(F_GETFD)
   else if (unlikely (fcntl (fildes, F_GETFD) == -1 && errno == EBADF))
     {
       /* We cannot do anything productive without a file descriptor.  */
       __libelf_seterrno (ELF_E_INVALID_FILE);
       return NULL;
     }
+#endif
 
   switch (cmd)
     {
diff --git a/libelf/elf_end.c b/libelf/elf_end.c
index 5c451f36..8023b216 100644
--- a/libelf/elf_end.c
+++ b/libelf/elf_end.c
@@ -222,8 +222,10 @@ elf_end (Elf *elf)
       /* The file was read or mapped for this descriptor.  */
       if ((elf->flags & ELF_F_MALLOCED) != 0)
 	free (elf->map_address);
+#if HAVE_DECL_MMAP
       else if ((elf->flags & ELF_F_MMAPPED) != 0)
 	munmap (elf->map_address, elf->maximum_size);
+#endif
     }
 
   rwlock_unlock (elf->lock);
diff --git a/libelf/elf_update.c b/libelf/elf_update.c
index 56af3a1c..e81eb6c9 100644
--- a/libelf/elf_update.c
+++ b/libelf/elf_update.c
@@ -64,7 +64,7 @@ write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
       __libelf_seterrno (ELF_E_WRITE_ERROR);
       return -1;
     }
-
+#if HAVE_DECL_MMAP
   /* Try to map the file if this isn't done yet.  */
   if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP)
     {
@@ -125,6 +125,7 @@ write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
 	size = -1;
     }
   else
+#endif
     {
       /* The file is not mmaped.  */
       if ((class == ELFCLASS32
@@ -145,6 +146,7 @@ write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
       size = -1;
     }
 
+#if HAVE_DECL_MMAP
   /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
      mode bits.  So make sure we restore them afterwards if they were set.
      This is not atomic if someone else chmod's the file while we operate.  */
@@ -156,6 +158,7 @@ write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
       __libelf_seterrno (ELF_E_WRITE_ERROR);
       size = -1;
     }
+#endif
 
   if (size != -1 && elf->parent == NULL)
     elf->maximum_size = size;
diff --git a/libelf/libelf.h b/libelf/libelf.h
index a139e733..2fa3838b 100644
--- a/libelf/libelf.h
+++ b/libelf/libelf.h
@@ -195,9 +195,15 @@ typedef struct
 {
   char *ar_name;		/* Name of archive member.  */
   time_t ar_date;		/* File date.  */
+#if defined(_WIN32)
+  long ar_uid;
+  long ar_gid;
+  unsigned long ar_mode;
+#else
   uid_t ar_uid;			/* User ID.  */
   gid_t ar_gid;			/* Group ID.  */
   mode_t ar_mode;		/* File mode.  */
+#endif
   int64_t ar_size;		/* File size.  */
   char *ar_rawname;		/* Original name of archive member.  */
 } Elf_Arhdr;
diff --git a/libelf/libelfP.h b/libelf/libelfP.h
index d88a613c..14b60bce 100644
--- a/libelf/libelfP.h
+++ b/libelf/libelfP.h
@@ -30,7 +30,11 @@
 #ifndef _LIBELFP_H
 #define _LIBELFP_H 1
 
+#if defined(_WIN32)
+#include "win32/ar.h"
+#else
 #include <ar.h>
+#endif
 #include <gelf.h>
 
 #include <errno.h>
diff --git a/libelf/win32/ar.h b/libelf/win32/ar.h
new file mode 100644
index 00000000..d67fab52
--- /dev/null
+++ b/libelf/win32/ar.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2022 Yonggang Luo
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _AR_H
+#define _AR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ARMAG "!<arch>\n"
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+struct ar_hdr {
+	char ar_name[16];
+	char ar_date[12];
+	char ar_uid[6], ar_gid[6];
+	char ar_mode[8];
+	char ar_size[10];
+	char ar_fmag[2];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
