Repository: wasmerio/wasmer (language: rust)

Issue:
Fix LLVM relocations and SIMD operations on aarch64
Some of the required relocations for LLVM on aarch64 (ELF) are missing. Furthermore, some of the WAST tests related to SIMD instructions fail, for example: 

```
--- STDERR:              wasmer-workspace::compilers wast::spec::simd_lane::llvm::universal ---
Error: Failed directives on tests/wast/spec/simd_lane.wast:
  • expected Core(V128(I8x16([0, 0, 0, 0, 0, 0, 0, 0, -16, -16, -16, -16, -16, -16, -16, -16]))), got I8x16([0, 0, 0, -13, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) (v128 bits: 3302611746816) (357:1)
  • expected Core(V128(I8x16([85, -1, 85, -1, 85, -1, 85, -1, 85, -1, 85, -1, 85, -1, 85, -1]))), got I8x16([0, 0, 0, 0, 0, 85, 85, 0, 0, 85, -1, 0, -1, 0, 85, 0]) (v128 bits: 441365436465578971007971732593049600) (696:1)
```


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index fdedd59560f..8a8655b9228 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -119,7 +119,7 @@ jobs:
             target: aarch64-apple-darwin
             artifact_name: 'wasmer-darwin-arm64'
             use_sccache: false
-            use_llvm: false
+            use_llvm: true
             build_wasm: false
             # [todo] xdoardo: Reinstate when the code we generate for aarch64 is working correctly. 
             llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz'
@@ -573,70 +573,70 @@ jobs:
           if-no-files-found: error
           retention-days: 2
 
-  # linux_riscv64:
-  #   name: Linux riscv64
-  #   runs-on: ubuntu-latest
-  #   steps:
-  #     - uses: actions/checkout@v3
-  #     - uses: dtolnay/rust-toolchain@stable
-  #       with:
-  #         target: riscv64gc-unknown-linux-gnu
-  #     - name: Build cross image
-  #       run: |
-  #         docker build -t wasmer/riscv64 ${GITHUB_WORKSPACE}/.github/cross-linux-riscv64/
-  #       env:
-  #         CROSS_DOCKER_IN_DOCKER: true
-  #     - name: Build Wasmer binary
-  #       run: |
-  #         make build-wasmer
-  #       env:
-  #         CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/riscv64:latest cargo
-  #         CROSS_DOCKER_IN_DOCKER: true
-  #         CARGO_TARGET: riscv64gc-unknown-linux-gnu
-  #         PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig
-  #         PKG_CONFIG_ALLOW_CROSS: true
-  #         ENABLE_LLVM: 0
-  #     - name: Build C API headless
-  #       shell: bash
-  #       run: |
-  #         make package-capi-headless
-  #       env:
-  #         CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/riscv64:latest cargo
-  #         CROSS_DOCKER_IN_DOCKER: true
-  #         CARGO_TARGET: riscv64gc-unknown-linux-gnu
-  #         PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig
-  #         PKG_CONFIG_ALLOW_CROSS: true
-  #         ENABLE_LLVM: 0
-  #         TARGET: riscv64gc-unknown-linux-gnu
-  #         TARGET_DIR: target/riscv64gc-unknown-linux-gnu/release
-  #     - name: Build C API
-  #       run: |
-  #         make build-capi
-  #       env:
-  #         CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/riscv64:latest cargo
-  #         CROSS_DOCKER_IN_DOCKER: true
-  #         CARGO_TARGET: riscv64gc-unknown-linux-gnu
-  #         PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig
-  #         PKG_CONFIG_ALLOW_CROSS: true
-  #         ENABLE_LLVM: 0
-  #     - name: Dist
-  #       run: |
-  #         make distribution
-  #       env:
-  #         CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/riscv64:latest cargo
-  #         CROSS_DOCKER_IN_DOCKER: true
-  #         CARGO_TARGET: riscv64gc-unknown-linux-gnu
-  #         PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig
-  #         PKG_CONFIG_ALLOW_CROSS: true
-  #         TARGET: riscv64gc-unknown-linux-gnu
-  #         TARGET_DIR: target/riscv64gc-unknown-linux-gnu/release
-  #     - name: Upload Artifacts
-  #       uses: actions/upload-artifact@v4
-  #       with:
-  #         name: wasmer-linux-riscv64
-  #         path: dist
-  #         if-no-files-found: error
-  #         retention-days: 2
+  linux_riscv64:
+    name: Linux riscv64
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - uses: dtolnay/rust-toolchain@stable
+        with:
+          target: riscv64gc-unknown-linux-gnu
+      - name: Build cross image
+        run: |
+          docker build -t wasmer/riscv64 ${GITHUB_WORKSPACE}/.github/cross-linux-riscv64/
+        env:
+          CROSS_DOCKER_IN_DOCKER: true
+      - name: Build Wasmer binary
+        run: |
+          make build-wasmer
+        env:
+          CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/riscv64:latest cargo
+          CROSS_DOCKER_IN_DOCKER: true
+          CARGO_TARGET: riscv64gc-unknown-linux-gnu
+          PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig
+          PKG_CONFIG_ALLOW_CROSS: true
+          ENABLE_LLVM: 0
+      - name: Build C API headless
+        shell: bash
+        run: |
+          make package-capi-headless
+        env:
+          CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/riscv64:latest cargo
+          CROSS_DOCKER_IN_DOCKER: true
+          CARGO_TARGET: riscv64gc-unknown-linux-gnu
+          PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig
+          PKG_CONFIG_ALLOW_CROSS: true
+          ENABLE_LLVM: 0
+          TARGET: riscv64gc-unknown-linux-gnu
+          TARGET_DIR: target/riscv64gc-unknown-linux-gnu/release
+      - name: Build C API
+        run: |
+          make build-capi
+        env:
+          CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/riscv64:latest cargo
+          CROSS_DOCKER_IN_DOCKER: true
+          CARGO_TARGET: riscv64gc-unknown-linux-gnu
+          PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig
+          PKG_CONFIG_ALLOW_CROSS: true
+          ENABLE_LLVM: 0
+      - name: Dist
+        run: |
+          make distribution
+        env:
+          CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/riscv64:latest cargo
+          CROSS_DOCKER_IN_DOCKER: true
+          CARGO_TARGET: riscv64gc-unknown-linux-gnu
+          PKG_CONFIG_PATH: /usr/lib/riscv64-linux-gnu/pkgconfig
+          PKG_CONFIG_ALLOW_CROSS: true
+          TARGET: riscv64gc-unknown-linux-gnu
+          TARGET_DIR: target/riscv64gc-unknown-linux-gnu/release
+      - name: Upload Artifacts
+        uses: actions/upload-artifact@v4
+        with:
+          name: wasmer-linux-riscv64
+          path: dist
+          if-no-files-found: error
+          retention-days: 2
 
   release:
     # needs: [setup, build, linux_aarch64, windows_gnu, linux_riscv64]
diff --git a/examples/memory.rs b/examples/memory.rs
index 2ea623bda39..26446387084 100644
--- a/examples/memory.rs
+++ b/examples/memory.rs
@@ -108,8 +108,8 @@ fn main() -> anyhow::Result<()> {
     // see how we can do that:
     println!("Growing memory...");
 
-    // 'wasm-c-api' does not support direct calls to memory.grow()
-    #[cfg(not(feature = "wasm-c-api"))]
+    // 'wamr' does not support direct calls to memory.grow()
+    #[cfg(not(feature = "wamr"))]
     {
         // Here we are requesting two more pages for our memory.
         memory.grow(&mut store, 2)?;
diff --git a/examples/table.rs b/examples/table.rs
index cd74083694e..52e5b9f4589 100644
--- a/examples/table.rs
+++ b/examples/table.rs
@@ -154,7 +154,6 @@ fn main() -> anyhow::Result<()> {
 
 // This test is currently failing with:
 // not implemented: Native function definitions can't be directly called from the host yet
-#[cfg(FALSE)]
 #[test]
 fn test_table() -> anyhow::Result<()> {
     main()
diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs
index 5d76872ec46..c30776406f9 100644
--- a/lib/compiler-llvm/src/config.rs
+++ b/lib/compiler-llvm/src/config.rs
@@ -119,11 +119,13 @@ impl LLVM {
             //  but not in the case of Aarch64, there the ABI is slightly different
             #[allow(clippy::match_single_binding)]
             match target.triple().architecture {
+                Architecture::Aarch64(_) => wasmer_types::OperatingSystem::Darwin,
                 _ => wasmer_types::OperatingSystem::Linux,
             }
         } else {
             target.triple().operating_system
         };
+
         let binary_format = if self.is_pic {
             target.triple().binary_format
         } else {
diff --git a/lib/compiler-llvm/src/object_file.rs b/lib/compiler-llvm/src/object_file.rs
index 06b196326ed..df1641d2706 100644
--- a/lib/compiler-llvm/src/object_file.rs
+++ b/lib/compiler-llvm/src/object_file.rs
@@ -251,6 +251,32 @@ where
                     object::RelocationKind::Elf(object::elf::R_LARCH_ABS64_LO20),
                     0,
                 ) => RelocationKind::LArchAbs64Lo20,
+                (
+                    object::Architecture::Aarch64,
+                    object::RelocationKind::Elf(object::elf::R_AARCH64_ADR_PREL_LO21),
+                    0,
+                ) => RelocationKind::Aarch64AdrPrelLo21,
+                (
+                    object::Architecture::Aarch64,
+                    object::RelocationKind::Elf(object::elf::R_AARCH64_ADR_PREL_PG_HI21),
+                    0,
+                ) => RelocationKind::Aarch64AdrPrelPgHi21,
+                (
+                    object::Architecture::Aarch64,
+                    object::RelocationKind::Elf(object::elf::R_AARCH64_LDST128_ABS_LO12_NC),
+                    0,
+                ) => RelocationKind::Aarch64Ldst128AbsLo12Nc,
+                (
+                    object::Architecture::Aarch64,
+                    object::RelocationKind::Elf(object::elf::R_AARCH64_ADD_ABS_LO12_NC),
+                    0,
+                ) => RelocationKind::Aarch64AddAbsLo12Nc,
+                (
+                    object::Architecture::Aarch64,
+                    object::RelocationKind::Elf(object::elf::R_AARCH64_LDST64_ABS_LO12_NC),
+                    0,
+                ) => RelocationKind::Aarch64Ldst64AbsLo12Nc,
+
                 _ => {
                     return Err(CompileError::Codegen(format!(
                         "unknown relocation {:?}",
diff --git a/lib/compiler-llvm/src/translator/intrinsics.rs b/lib/compiler-llvm/src/translator/intrinsics.rs
index ca48b07e533..3585af37399 100644
--- a/lib/compiler-llvm/src/translator/intrinsics.rs
+++ b/lib/compiler-llvm/src/translator/intrinsics.rs
@@ -1104,10 +1104,6 @@ impl<'ctx> Intrinsics<'ctx> {
         intrinsics
             .throw_trap
             .add_attribute(AttributeLoc::Function, noreturn);
-        //intrinsics
-        //    .func_ref
-        //    .add_attribute(AttributeLoc::Function, intrinsics.readonly);
-
         intrinsics
     }
 }
diff --git a/lib/compiler/src/engine/link.rs b/lib/compiler/src/engine/link.rs
index a3fc64dd2da..7aafeb82de9 100644
--- a/lib/compiler/src/engine/link.rs
+++ b/lib/compiler/src/engine/link.rs
@@ -146,6 +146,59 @@ fn apply_relocation(
                 | read_unaligned(reloc_address as *mut u32);
             write_unaligned(reloc_address as *mut u32, reloc_abs);
         },
+        RelocationKind::Aarch64AdrPrelPgHi21 => unsafe {
+            let (reloc_address, delta) = r.for_address(body, target_func_address as u64);
+
+            let delta = delta as isize;
+            assert!(
+                ((-1 << 32)..(1 << 32)).contains(&delta),
+                "can't generate page-relative relocation with ±4GB `adrp` instruction"
+            );
+
+            let op = read_unaligned(reloc_address as *mut u32);
+            let delta = delta >> 12;
+            let immlo = ((delta as u32) & 0b11) << 29;
+            let immhi = (((delta as u32) >> 2) & 0x7ffff) << 5;
+            let mask = !((0x7ffff << 5) | (0b11 << 29));
+            let op = (op & mask) | immlo | immhi;
+
+            write_unaligned(reloc_address as *mut u32, op);
+        },
+        RelocationKind::Aarch64AdrPrelLo21 => unsafe {
+            let (reloc_address, delta) = r.for_address(body, target_func_address as u64);
+
+            let delta = delta as isize;
+            assert!(
+                ((-1 << 20)..(1 << 20)).contains(&delta),
+                "can't generate an ADR_PREL_LO21 relocation with an immediate larger than 20 bits"
+            );
+
+            let op = read_unaligned(reloc_address as *mut u32);
+            let immlo = ((delta as u32) & 0b11) << 29;
+            let immhi = (((delta as u32) >> 2) & 0x7ffff) << 5;
+            let mask = !((0x7ffff << 5) | (0b11 << 29));
+            let op = (op & mask) | immlo | immhi;
+
+            write_unaligned(reloc_address as *mut u32, op);
+        },
+        RelocationKind::Aarch64AddAbsLo12Nc => unsafe {
+            let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
+            let reloc_delta = (reloc_delta as u32 & 0xfff)
+                | (read_unaligned(reloc_address as *mut u32) & 0xFFC003FF);
+            write_unaligned(reloc_address as *mut u32, reloc_delta);
+        },
+        RelocationKind::Aarch64Ldst128AbsLo12Nc => unsafe {
+            let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
+            let reloc_delta = ((reloc_delta as u32 & 0xfff) >> 4) << 10
+                | (read_unaligned(reloc_address as *mut u32) & 0xFFC003FF);
+            write_unaligned(reloc_address as *mut u32, reloc_delta);
+        },
+        RelocationKind::Aarch64Ldst64AbsLo12Nc => unsafe {
+            let (reloc_address, reloc_delta) = r.for_address(body, target_func_address as u64);
+            let reloc_delta = ((reloc_delta as u32 & 0xfff) >> 3) << 10
+                | (read_unaligned(reloc_address as *mut u32) & 0xFFC003FF);
+            write_unaligned(reloc_address as *mut u32, reloc_delta);
+        },
         kind => panic!(
             "Relocation kind unsupported in the current architecture {}",
             kind
diff --git a/lib/types/src/compilation/relocation.rs b/lib/types/src/compilation/relocation.rs
index 54060c9f6f2..f714542b2bf 100644
--- a/lib/types/src/compilation/relocation.rs
+++ b/lib/types/src/compilation/relocation.rs
@@ -46,6 +46,22 @@ pub enum RelocationKind {
     X86CallPLTRel4,
     /// x86 GOT PC-relative 4-byte
     X86GOTPCRel4,
+
+    /// R_AARCH64_ADR_PREL_LO21
+    Aarch64AdrPrelLo21,
+
+    /// R_AARCH64_ADR_PREL_PG_HI21
+    Aarch64AdrPrelPgHi21,
+
+    /// R_AARCH64_ADD_ABS_LO12_NC
+    Aarch64AddAbsLo12Nc,
+
+    /// R_AARCH64_LDST128_ABS_LO12_NC
+    Aarch64Ldst128AbsLo12Nc,
+
+    /// R_AARCH64_LDST64_ABS_LO12_NC
+    Aarch64Ldst64AbsLo12Nc,
+
     /// Arm32 call target
     Arm32Call,
     /// Arm64 call target
@@ -102,6 +118,11 @@ impl fmt::Display for RelocationKind {
             Self::LArchAbsLo12 => write!(f, "LArchAbsLo12"),
             Self::LArchAbs64Hi12 => write!(f, "LArchAbs64Hi12"),
             Self::LArchAbs64Lo20 => write!(f, "LArchAbs64Lo20"),
+            Self::Aarch64AdrPrelLo21 => write!(f, "Aarch64AdrPrelLo21"),
+            Self::Aarch64AdrPrelPgHi21 => write!(f, "Aarch64AdrPrelPgHi21"),
+            Self::Aarch64AddAbsLo12Nc => write!(f, "Aarch64AddAbsLo12Nc"),
+            Self::Aarch64Ldst128AbsLo12Nc => write!(f, "Aarch64Ldst128AbsLo12Nc"),
+            Self::Aarch64Ldst64AbsLo12Nc => write!(f, "Aarch64Ldst64AbsLo12Nc"),
             // Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"),
         }
     }
@@ -142,7 +163,10 @@ pub trait RelocationLike {
             | RelocationKind::Arm64Movw1
             | RelocationKind::Arm64Movw2
             | RelocationKind::Arm64Movw3
-            | RelocationKind::RiscvPCRelLo12I => {
+            | RelocationKind::RiscvPCRelLo12I
+            | RelocationKind::Aarch64AddAbsLo12Nc
+            | RelocationKind::Aarch64Ldst128AbsLo12Nc
+            | RelocationKind::Aarch64Ldst64AbsLo12Nc => {
                 let reloc_address = start + self.offset() as usize;
                 let reloc_addend = self.addend() as isize;
                 let reloc_abs = target_func_address
@@ -178,7 +202,8 @@ pub trait RelocationLike {
             }
             RelocationKind::Arm64Call
             | RelocationKind::RiscvCall
-            | RelocationKind::RiscvPCRelHi20 => {
+            | RelocationKind::RiscvPCRelHi20
+            | RelocationKind::Aarch64AdrPrelLo21 => {
                 let reloc_address = start + self.offset() as usize;
                 let reloc_addend = self.addend() as isize;
                 let reloc_delta_u32 = target_func_address
@@ -186,6 +211,14 @@ pub trait RelocationLike {
                     .wrapping_add(reloc_addend as u64);
                 (reloc_address, reloc_delta_u32)
             }
+            RelocationKind::Aarch64AdrPrelPgHi21 => {
+                let reloc_address = start + self.offset() as usize;
+                let reloc_addend = self.addend() as isize;
+                let target_page =
+                    (target_func_address.wrapping_add(reloc_addend as u64) & !(0xFFF)) as usize;
+                let pc_page = reloc_address & !(0xFFF);
+                (reloc_address, target_page.wrapping_sub(pc_page) as u64)
+            }
             _ => panic!("Relocation kind unsupported"),
         }
     }


Test patch:
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 8b1545862e6..b12ecc4355a 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -511,8 +511,7 @@ jobs:
             os: macos-14,
             target: aarch64-apple-darwin,
             exe: '',
-            # [todo] xdoardo: Reinstate when the code we generate for aarch64 is working correctly. 
-            # llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz'
+            llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz'
           },
           {
             build: windows-x64,
@@ -765,8 +764,7 @@ jobs:
             os: macos-14,
             target: aarch64-apple-darwin,
             exe: '',
-            # [todo] xdoardo: Reinstate when the code we generate for aarch64 is working correctly. 
-            # llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz'
+            llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/18.x/llvm-darwin-aarch64.tar.xz'
           },
           {
             build: windows-x64,
diff --git a/tests/compilers/artifact.rs b/tests/compilers/artifact.rs
index 334ec9d2af3..53eca021058 100644
--- a/tests/compilers/artifact.rs
+++ b/tests/compilers/artifact.rs
@@ -1,6 +1,4 @@
 use std::{fs, path::PathBuf};
-
-use cfg_if::cfg_if;
 use wasmer::{Engine, Module};
 
 #[test]
@@ -57,6 +55,7 @@ fn artifact_serialization_build() {
 #[test]
 #[cfg(target_arch = "x86_64")]
 fn artifact_deserialization_roundtrip() {
+    use cfg_if::cfg_if;
     // This test is included to make sure we don't break the serialized format
     // by mistake. Otherwise, everything in this test is already tested in
     // `artifact_serialization_roundtrip`.