diff --git a/include/native/native.h b/include/native/native.h
new file mode 100644
index 0000000000..12462a261e
--- /dev/null
+++ b/include/native/native.h
@@ -0,0 +1,7 @@
+#if defined(CONFIG_USER_ONLY) && defined(CONFIG_NATIVE_CALL)
+extern char *native_lib_path;
+/* Check if the native-bypass option is enabled. */
+#define native_bypass_enabled() (native_lib_path != NULL)
+#else
+#define native_bypass_enabled() false
+#endif
diff --git a/linux-user/main.c b/linux-user/main.c
index dba67ffa36..4c1d515944 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -60,6 +60,11 @@
 #include "semihosting/semihost.h"
 #endif
 
+#if defined(CONFIG_NATIVE_CALL)
+#include "native/native.h"
+char *native_lib_path;
+#endif
+
 #ifndef AT_FLAGS_PRESERVE_ARGV0
 #define AT_FLAGS_PRESERVE_ARGV0_BIT 0
 #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
@@ -293,6 +298,17 @@ static void handle_arg_set_env(const char *arg)
     free(r);
 }
 
+#if defined(CONFIG_NATIVE_CALL)
+static void handle_arg_native_bypass(const char *arg)
+{
+    if (!g_file_test(arg, G_FILE_TEST_IS_REGULAR)) {
+        fprintf(stderr, "native library %s does not exist\n", arg);
+        exit(EXIT_FAILURE);
+    }
+    native_lib_path = g_strdup(arg);
+}
+#endif
+
 static void handle_arg_unset_env(const char *arg)
 {
     char *r, *p, *token;
@@ -522,6 +538,10 @@ static const struct qemu_argument arg_table[] = {
      "",           "Generate a /tmp/perf-${pid}.map file for perf"},
     {"jitdump",    "QEMU_JITDUMP",     false, handle_arg_jitdump,
      "",           "Generate a jit-${pid}.dump file for perf"},
+#if defined(CONFIG_NATIVE_CALL)
+    {"native-bypass", "QEMU_NATIVE_BYPASS", true, handle_arg_native_bypass,
+     "",           "native bypass for library calls"},
+#endif
     {NULL, NULL, false, NULL, NULL, NULL}
 };
 
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 08162cc966..7034f58373 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -143,6 +143,7 @@
 #include "fd-trans.h"
 #include "tcg/tcg.h"
 #include "cpu_loop-common.h"
+#include "native/native.h"
 
 #ifndef CLONE_IO
 #define CLONE_IO                0x80000000      /* Clone io context */
@@ -8503,6 +8504,40 @@ static int open_hardware(CPUArchState *cpu_env, int fd)
 }
 #endif
 
+#if defined(CONFIG_NATIVE_CALL)
+static int is_ld_so_preload(const char *filename, const char *entry)
+{
+    if (native_bypass_enabled() && !strcmp(filename, entry)) {
+        return 1;
+    }
+    return 0;
+}
+
+/* This function is only called when the "native-bypass" option is provided. */
+static int open_ld_so_preload(CPUArchState *cpu_env, int fd)
+{
+    FILE *fp;
+    char *line = NULL;
+    size_t len = 0;
+    ssize_t read;
+
+    dprintf(fd, "%s\n", native_lib_path);
+    fp = fopen("/etc/ld.so.preload", "r");
+    if (fp == NULL) {
+        return 0;
+    }
+
+    while ((read = getline(&line, &len, fp)) != -1) {
+        dprintf(fd, "%s", line);
+    }
+
+    free(line);
+    fclose(fp);
+
+    return 0;
+}
+#endif
+
 int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
                     int flags, mode_t mode, bool safe)
 {
@@ -8527,6 +8562,9 @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
 #endif
 #if defined(TARGET_M68K)
         { "/proc/hardware", open_hardware, is_proc },
+#endif
+#if defined(CONFIG_NATIVE_CALL)
+        { "/etc/ld.so.preload", open_ld_so_preload, is_ld_so_preload },
 #endif
         { NULL, NULL, NULL }
     };
@@ -9523,6 +9561,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
             return -TARGET_EFAULT;
         }
         ret = get_errno(access(path(p), arg2));
+        if (ret != 0 && native_bypass_enabled()) {
+            if (strcmp(p, "/etc/ld.so.preload") == 0 && arg2 == R_OK) {
+                return 0;
+            }
+        }
         unlock_user(p, arg1, 0);
         return ret;
 #endif
@@ -9532,6 +9575,12 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
             return -TARGET_EFAULT;
         }
         ret = get_errno(faccessat(arg1, p, arg3, 0));
+        if (ret != 0 && native_bypass_enabled()) {
+            if (strcmp(p, "/etc/ld.so.preload") == 0 && arg1 == AT_FDCWD &&
+                arg3 == R_OK) {
+                return 0;
+            }
+        }
         unlock_user(p, arg2, 0);
         return ret;
 #endif
@@ -9541,6 +9590,12 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
             return -TARGET_EFAULT;
         }
         ret = get_errno(faccessat(arg1, p, arg3, arg4));
+        if (ret != 0 && native_bypass_enabled()) {
+            if (strcmp(p, "/etc/ld.so.preload") == 0 && arg1 == AT_FDCWD &&
+                arg3 == R_OK) {
+                return 0;
+            }
+        }
         unlock_user(p, arg2, 0);
         return ret;
 #endif
