diff --git a/compiler-rt/lib/builtins/CMakeLists.txt b/compiler-rt/lib/builtins/CMakeLists.txt index 02e6ecfbdb60e..ebda0c87785c2 100644 --- a/compiler-rt/lib/builtins/CMakeLists.txt +++ b/compiler-rt/lib/builtins/CMakeLists.txt @@ -470,6 +470,10 @@ set(arm_EABI_RT_SOURCES arm/aeabi_ldivmod.S arm/aeabi_uidivmod.S arm/aeabi_uldivmod.S + arm/aeabi_uread4.c + arm/aeabi_uread8.c + arm/aeabi_uwrite4.c + arm/aeabi_uwrite8.c ) set(arm_EABI_CLIB_SOURCES diff --git a/compiler-rt/lib/builtins/arm/aeabi_uread4.c b/compiler-rt/lib/builtins/arm/aeabi_uread4.c new file mode 100644 index 0000000000000..564ae73b085a5 --- /dev/null +++ b/compiler-rt/lib/builtins/arm/aeabi_uread4.c @@ -0,0 +1,24 @@ +//===-- aeabi_uread4.c - ARM EABI Helper — Unaligned 4-Byte Memory Read ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Implements __aeabi_uread4 for unaligned memory accesses. +// Reference: Arm RTABI32 Specification. +// https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#unaligned-memory-access +//===-------------------------------------------------------------------------------------===// + +typedef struct { + char v[4]; +} v4; + +int __aeabi_uread4(void *p) { + union { + v4 v; + int u; + } u; + + u.v = *(v4 *)p; + return u.u; +} diff --git a/compiler-rt/lib/builtins/arm/aeabi_uread8.c b/compiler-rt/lib/builtins/arm/aeabi_uread8.c new file mode 100644 index 0000000000000..b9745191d9764 --- /dev/null +++ b/compiler-rt/lib/builtins/arm/aeabi_uread8.c @@ -0,0 +1,24 @@ +//===-- aeabi_uread8.c - ARM EABI Helper — Unaligned 8-Byte Memory Read----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Implements __aeabi_uread8 for unaligned memory accesses. +// Reference: Arm RTABI32 Specification. +// https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#unaligned-memory-access +//===-------------------------------------------------------------------------------------===// + +typedef struct { + char v[8]; +} v8; + +long long __aeabi_uread8(void *p) { + union { + v8 v; + long long u; + } u; + + u.v = *(v8 *)p; + return u.u; +} diff --git a/compiler-rt/lib/builtins/arm/aeabi_uwrite4.c b/compiler-rt/lib/builtins/arm/aeabi_uwrite4.c new file mode 100644 index 0000000000000..a7312be94a0b0 --- /dev/null +++ b/compiler-rt/lib/builtins/arm/aeabi_uwrite4.c @@ -0,0 +1,26 @@ +//===-- aeabi_uwrite4.c - ARM EABI Helper — Unaligned 4-Byte Memory Write--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Implements __aeabi_uwrite4 for unaligned memory accesses. +// Reference: Arm RTABI32 Specification. +// https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#unaligned-memory-access +//===-------------------------------------------------------------------------------------===// + +typedef struct { + char v[4]; +} v4; + +int __aeabi_uwrite4(int val, void *p) { + union { + v4 v; + int u; + } u; + + u.u = val; + *(v4 *)p = u.v; + + return val; +} diff --git a/compiler-rt/lib/builtins/arm/aeabi_uwrite8.c b/compiler-rt/lib/builtins/arm/aeabi_uwrite8.c new file mode 100644 index 0000000000000..3a29c690b4c80 --- /dev/null +++ b/compiler-rt/lib/builtins/arm/aeabi_uwrite8.c @@ -0,0 +1,26 @@ +//===-- aeabi_uwrite8.c - ARM EABI Helper — Unaligned 8-Byte Memory Write--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Implements __aeabi_uwrite8 for unaligned memory accesses. +// Reference: Arm RTABI32 Specification. +// https://github.com/ARM-software/abi-aa/blob/main/rtabi32/rtabi32.rst#unaligned-memory-access +//===-------------------------------------------------------------------------------------===// + +typedef struct { + char v[8]; +} v8; + +long long __aeabi_uwrite8(long long val, void *p) { + union { + v8 v; + long long u; + } u; + + u.u = val; + *(v8 *)p = u.v; + + return val; +} diff --git a/compiler-rt/test/builtins/Unit/arm/aeabi_unaligned_access_test.c b/compiler-rt/test/builtins/Unit/arm/aeabi_unaligned_access_test.c new file mode 100644 index 0000000000000..a947e097b9c03 --- /dev/null +++ b/compiler-rt/test/builtins/Unit/arm/aeabi_unaligned_access_test.c @@ -0,0 +1,86 @@ +// REQUIRES: arm-target-arch || armv6m-target-arch +// RUN: %clang_builtins %s %librt -o %t && %run %t + +#include +#include +#include + +extern int __aeabi_uread4(void *); +extern int __aeabi_uwrite4(int, void *); +extern long long __aeabi_uread8(void *); +extern long long __aeabi_uwrite8(long long, void *); + +int test_unaligned(void) { + long long target8; + int target4; + const char source[] = "abcdefghijklmno"; + static char dest1[_Countof(source)], dest2[_Countof(source)]; + int i, j; + + for (i = 0; i < 7; i++) { + memcpy(&target8, source + i, 8); + if (__aeabi_uread8(source + i) != target8) { + printf("error in __aeabi_uread8 => output = %llx, expected %llx\n", + __aeabi_uread8(source + i), target8); + return 1; + } + + memcpy(dest1, source, _Countof(source)); + memcpy(dest2, source, _Countof(source)); + target8 = 0x4142434445464748ULL; + if (__aeabi_uwrite8(target8, dest1 + i) != target8) { + printf("error in __aeabi_uwrite8 => output = %llx, expected %llx\n", + __aeabi_uwrite8(target8, dest1 + i), target8); + return 1; + } + memcpy(dest2 + i, &target8, 8); + if (memcmp(dest1, dest2, _Countof(source)) != 0) { + int pos = -1; + printf("error in __aeabi_uwrite8: memcmp failed: buffers differ!\n"); + for (int j = 0; j < 8; ++j) { + if (dest1[j] != dest2[j]) { + pos = j; + break; + } + } + printf("error: 8-byte write mismatch at offset %d\n", pos); + return 1; + } + + memcpy(&target4, source + i, 4); + if (__aeabi_uread4(source + i) != target4) { + printf("error in __aeabi_uread4 => output = %x, expected %x\n", + __aeabi_uread4(source + i), target4); + return 1; + } + + memcpy(dest1, source, _Countof(source)); + memcpy(dest2, source, _Countof(source)); + target4 = 0x414243444; + if (__aeabi_uwrite4(target4, dest1 + i) != target4) { + printf("error in __aeabi_uwrite4 => output = %x, expected %x\n", + __aeabi_uwrite4(target4, dest1 + i), target4); + return 1; + } + memcpy(dest2 + i, &target4, 4); + if (memcmp(dest1, dest2, _Countof(source)) != 0) { + int pos = -1; + printf("error in __aeabi_uwrite4: memcmp failed: buffers differ!\n"); + for (int j = 0; j < 4; ++j) { + if (dest1[j] != dest2[j]) { + pos = j; + break; + } + } + printf("error: 4-byte write mismatch at offset %d\n", pos); + return 1; + } + } + return 0; +} + +int main() { + if (test_unaligned()) + return 1; + return 0; +}