diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index d5f227a84a4ca..3766501821957 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1837,6 +1837,7 @@ supported_targets! {
 
     ("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl),
 
+    ("aarch64-unknown-nto-qnx700", aarch64_unknown_nto_qnx700),
     ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710),
     ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710),
     ("i586-pc-nto-qnx700", i586_pc_nto_qnx700),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs
new file mode 100644
index 0000000000000..ac1bec02ec8ae
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx700.rs
@@ -0,0 +1,38 @@
+use crate::spec::{base, Cc, LinkerFlavor, Lld, Target, TargetOptions};
+
+pub fn target() -> Target {
+    // In QNX, libc does not provide a compatible ABI between versions.
+    // To distinguish between QNX versions, we needed a stable conditional compilation switch,
+    // which is why we needed to implement different targets in the compiler.
+    Target {
+        llvm_target: "aarch64-unknown-unknown".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: Some("ARM64 QNX Neutrino 7.0 RTOS".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(true),
+        },
+        pointer_width: 64,
+        // from: https://llvm.org/docs/LangRef.html#data-layout
+        // e         = little endian
+        // m:e       = ELF mangling: Private symbols get a .L prefix
+        // i8:8:32   = 8-bit-integer, minimum_alignment=8, preferred_alignment=32
+        // i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32
+        // i64:64    = 64-bit-integer, minimum_alignment=64, preferred_alignment=64
+        // i128:128  = 128-bit-integer, minimum_alignment=128, preferred_alignment=128
+        // n32:64    = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently.
+        // S128      = 128 bits are the natural alignment of the stack in bits.
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
+        arch: "aarch64".into(),
+        options: TargetOptions {
+            features: "+v8a".into(),
+            max_atomic_width: Some(128),
+            pre_link_args: TargetOptions::link_args(
+                LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+                &["-Vgcc_ntoaarch64le_cxx"],
+            ),
+            env: "nto70".into(),
+            ..base::nto_qnx::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs
index 0e5a0b9b9a545..65a1863eb391a 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs
@@ -1,35 +1,8 @@
-use crate::spec::{base, Cc, LinkerFlavor, Lld, Target, TargetOptions};
+use crate::spec::Target;
 
 pub fn target() -> Target {
-    Target {
-        llvm_target: "aarch64-unknown-unknown".into(),
-        metadata: crate::spec::TargetMetadata {
-            description: Some("ARM64 QNX Neutrino 7.1 RTOS".into()),
-            tier: Some(3),
-            host_tools: Some(false),
-            std: Some(true),
-        },
-        pointer_width: 64,
-        // from: https://llvm.org/docs/LangRef.html#data-layout
-        // e         = little endian
-        // m:e       = ELF mangling: Private symbols get a .L prefix
-        // i8:8:32   = 8-bit-integer, minimum_alignment=8, preferred_alignment=32
-        // i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32
-        // i64:64    = 64-bit-integer, minimum_alignment=64, preferred_alignment=64
-        // i128:128  = 128-bit-integer, minimum_alignment=128, preferred_alignment=128
-        // n32:64    = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently.
-        // S128      = 128 bits are the natural alignment of the stack in bits.
-        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
-        arch: "aarch64".into(),
-        options: TargetOptions {
-            features: "+v8a".into(),
-            max_atomic_width: Some(128),
-            pre_link_args: TargetOptions::link_args(
-                LinkerFlavor::Gnu(Cc::Yes, Lld::No),
-                &["-Vgcc_ntoaarch64le_cxx"],
-            ),
-            env: "nto71".into(),
-            ..base::nto_qnx::opts()
-        },
-    }
+    let mut base = super::aarch64_unknown_nto_qnx700::target();
+    base.metadata.description = Some("ARM64 QNX Neutrino 7.1 RTOS".into());
+    base.options.env = "nto71".into();
+    base
 }
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 334c75df2315a..e8cb5734d8cea 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -35,7 +35,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
 addr2line = { version = "0.22.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "0.2.153", default-features = false, features = [
+libc = { version = "0.2.156", default-features = false, features = [
     'rustc-dep-of-std',
 ], public = true }
 
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index fc9d7e988835e..7fa147c9754b9 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -1717,7 +1717,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {
     run_path_with_cstr(original, &|original| {
         run_path_with_cstr(link, &|link| {
             cfg_if::cfg_if! {
-                if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
+                if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nto"))] {
                     // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
                     // it implementation-defined whether `link` follows symlinks, so rely on the
                     // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior.
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index 5552e9ac97753..9d091f033e07f 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -19,7 +19,8 @@ use crate::sys::process::process_common::*;
 use crate::{fmt, mem, sys};
 
 cfg_if::cfg_if! {
-    if #[cfg(all(target_os = "nto", target_env = "nto71"))] {
+    // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0
+    if #[cfg(any(target_env = "nto70", target_env = "nto71"))] {
         use crate::thread;
         use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t};
         use crate::time::Duration;
@@ -189,7 +190,8 @@ impl Command {
     #[cfg(not(any(
         target_os = "watchos",
         target_os = "tvos",
-        all(target_os = "nto", target_env = "nto71"),
+        target_env = "nto70",
+        target_env = "nto71"
     )))]
     unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
         cvt(libc::fork())
@@ -199,7 +201,8 @@ impl Command {
     // or closed a file descriptor while the fork() was occurring".
     // Documentation says "... or try calling fork() again". This is what we do here.
     // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html
-    #[cfg(all(target_os = "nto", target_env = "nto71"))]
+    // This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0
+    #[cfg(any(target_env = "nto70", target_env = "nto71"))]
     unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
         use crate::sys::os::errno;
 
@@ -537,7 +540,7 @@ impl Command {
         // or closed a file descriptor while the posix_spawn() was occurring".
         // Documentation says "... or try calling posix_spawn() again". This is what we do here.
         // See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
-        #[cfg(all(target_os = "nto", target_env = "nto71"))]
+        #[cfg(target_os = "nto")]
         unsafe fn retrying_libc_posix_spawnp(
             pid: *mut pid_t,
             file: *const c_char,
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index b3de71f29f394..250af912e072d 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -165,8 +165,15 @@ extern "C" {}
 extern "C" {}
 
 #[cfg(target_os = "nto")]
-#[link(name = "gcc_s")]
-extern "C" {}
+cfg_if::cfg_if! {
+    if #[cfg(target_env = "nto70")] {
+        #[link(name = "gcc")]
+        extern "C" {}
+    } else {
+        #[link(name = "gcc_s")]
+        extern "C" {}
+    }
+}
 
 #[cfg(target_os = "hurd")]
 #[link(name = "gcc_s")]
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 0d79e5f4114e3..a2641b227531a 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -256,6 +256,7 @@ target | std | host | notes
 [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ |  | ARM64 SOLID with TOPPERS/ASP3
 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * |  | ARM64 Nintendo Switch, Horizon
 [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? |  | ARM64 TEEOS |
+[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? |  | ARM64 QNX Neutrino 7.0 RTOS |
 [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | ARM64 QNX Neutrino 7.1 RTOS |
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ |  | ARM64 Hermit
diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md
index 51a397a38d209..1c240d1255a3d 100644
--- a/src/doc/rustc/src/platform-support/nto-qnx.md
+++ b/src/doc/rustc/src/platform-support/nto-qnx.md
@@ -24,6 +24,7 @@ Currently, the following QNX Neutrino versions and compilation targets are suppo
 |----------------------|---------------------|:------------:|:----------------:|
 | 7.1 | AArch64 | ✓ | ✓ |
 | 7.1 | x86_64  | ✓ | ✓ |
+| 7.0 | AArch64 | ? | ✓ |
 | 7.0 | x86     |   | ✓ |
 
 Adding other architectures that are supported by QNX Neutrino is possible.
@@ -43,6 +44,23 @@ When linking `no_std` applications, they must link against `libc.so` (see exampl
 required because applications always link against the `crt` library and `crt` depends on `libc.so`.
 This is done automatically when using the standard library.
 
+### Disabling RELocation Read-Only (RELRO)
+
+While not recommended by default, some QNX kernel setups may require the `RELRO` to be disabled with `-C relro_level=off`, e.g. by adding it to the `.cargo/config.toml` file:
+
+```toml
+[target.aarch64-unknown-nto-qnx700]
+rustflags = ["-C", "relro_level=off"]
+```
+
+If your QNX kernel does not allow it, and `relro` is not disabled, running compiled binary would fail with `syntax error: ... unexpected` or similar.  This is due to kernel trying to interpret compiled binary with `/bin/sh`, and obviously failing.  To verify that this is really the case, run your binary with the `DL_DEBUG=all` env var, and look for this output. If you see it, you should disable `relro` as described above.
+
+```text
+Resolution scope for Executable->/bin/sh:
+        Executable->/bin/sh
+        libc.so.4->/usr/lib/ldqnx-64.so.2
+```
+
 ### Small example application
 
 Small `no_std` example is shown below. Applications using the standard library work as well.
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 6f0a200a08cf3..b0c5eec1fe490 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -54,6 +54,9 @@
 //@ revisions: aarch64_unknown_none_softfloat
 //@ [aarch64_unknown_none_softfloat] compile-flags: --target aarch64-unknown-none-softfloat
 //@ [aarch64_unknown_none_softfloat] needs-llvm-components: aarch64
+//@ revisions: aarch64_unknown_nto_qnx700
+//@ [aarch64_unknown_nto_qnx700] compile-flags: --target aarch64-unknown-nto-qnx700
+//@ [aarch64_unknown_nto_qnx700] needs-llvm-components: aarch64
 //@ revisions: aarch64_unknown_nto_qnx710
 //@ [aarch64_unknown_nto_qnx710] compile-flags: --target aarch64-unknown-nto-qnx710
 //@ [aarch64_unknown_nto_qnx710] needs-llvm-components: aarch64