Skip to content

Commit 8a0b400

Browse files
committed
Fix Linux ARM64 build
Key issues during port: * Different ARM64 vararg calling convention between macOS (DarwinPCS) and Linux (AAPCS64). Fixed CALL_ENTRYPOINT_NOASSERT and DECLARE_ARGS_VARARRAY using va_list.__stack from the official ABI - robust and compiler-independent. However, there is also JavascriptStackWalker.cpp which depends on the exact stack layout and magic constants, especially ArgOffsetFromFramePtr, this part is more fragile. * char is unsigned in Linux ARM64 ABI unlike macOS/Win, breaking int8 code. Make sure __int8 (=char) is always prefixed with signed/unsigned. * arm64/*.S files use Microsoft-style ; comments, unsupported by GNU assembler. These were already converted in amd64/*.S files to //, but I propose a simpler fix to just strip them on the fly during the build with sed. * Missing _GetNativeSigSimdContext based on https://github.com/dotnet/runtime/blob/main/src/coreclr/pal/src/thread/context.cpp#L927 * Cpsr register is PState on Linux * wchar_t/char16_t mismatches when building with ICU. For now solved with #define wcslen PAL_wcslen etc in ChakraICU.h. It builds at least, though some Intl tests are failing. Note: binary with JIT crashes - this must be built with ./build.sh --no-jit. cmake already prints a warning that ARM64 JIT is only supported on Windows.
1 parent 622c745 commit 8a0b400

File tree

18 files changed

+127
-18
lines changed

18 files changed

+127
-18
lines changed

CMakeLists.txt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ if(CC_USES_SYSTEM_ARCH_SH OR NOT CHAKRACORE_BUILD_SH)
5454
set(CC_TARGETS_ARM_SH 1)
5555
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
5656
set(CC_TARGETS_ARM64_SH 1)
57+
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
58+
set(CC_TARGETS_ARM64_SH 1)
5759
endif()
5860
unset(CC_USES_SYSTEM_ARCH_SH CACHE)
5961
endif()
@@ -68,7 +70,7 @@ elseif(CC_TARGETS_ARM64_SH)
6870
add_definitions(-D_ARM64_=1)
6971
add_definitions(-D__arm64__=1)
7072
set(CC_TARGETS_ARM64 1)
71-
set(CMAKE_SYSTEM_PROCESSOr "arm64")
73+
set(CMAKE_SYSTEM_PROCESSOR "arm64")
7274
elseif(CC_TARGETS_X86_SH)
7375
set(CC_TARGETS_X86 1)
7476
set(CMAKE_SYSTEM_PROCESSOR "i386")
@@ -293,6 +295,14 @@ elseif(CC_TARGETS_ARM64)
293295
if(CC_TARGET_OS_OSX)
294296
add_compile_options(-arch arm64)
295297
endif()
298+
if (CC_TARGET_OS_LINUX)
299+
# arm64 .S mostly use ; comments, not accepted by GNU assembler.
300+
# In lieu of converting them all, just strip these comments during build.
301+
set(CMAKE_ASM_COMPILE_OBJECT
302+
"sed -e 's/\;.*//g' <SOURCE> > <OBJECT_DIR>/$$(basename <SOURCE>)"
303+
"<CMAKE_ASM_COMPILER> <DEFINES> <INCLUDES> -I $$(dirname <SOURCE>) <FLAGS> -o <OBJECT> -c <OBJECT_DIR>/$$(basename <SOURCE>)"
304+
)
305+
endif()
296306
else()
297307
message(FATAL_ERROR "Only AMD64, ARM, ARM64 and I386 are supported")
298308
endif()
@@ -522,9 +532,6 @@ else()
522532
endif()
523533

524534
if(CC_TARGETS_ARM64)
525-
if(CC_TARGET_OS_LINUX)
526-
message(WARNING "ARM64 linux build has not yet been tested, this build is unsupported.")
527-
endif()
528535
if(BuildJIT)
529536
message(WARNING "ARM64 Jit not yet functional on platforms other than windows.")
530537
message(WARNING "For use rather than development please build with Jit disabled --no-jit with ./build.sh or -DDISABLE_JIT=1 if using CMake directly")

build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ if [[ $ARCH =~ "x86" ]]; then
620620
elif [[ $ARCH =~ "arm" ]]; then
621621
ARCH="-DCC_TARGETS_ARM_SH=1"
622622
echo "Compile Target : arm"
623-
elif [[ $ARCH =~ "arm64" ]]; then
623+
elif [[ $ARCH =~ "arm64" || $ARCH =~ "aarch64" ]]; then
624624
ARCH="-DCC_TARGETS_ARM64_SH=1"
625625
echo "Compile Target : arm64"
626626
elif [[ $ARCH =~ "amd64" ]]; then
@@ -634,7 +634,7 @@ fi
634634
echo Generating $BUILD_TYPE build
635635
echo $EXTRA_DEFINES
636636
cmake $CMAKE_GEN -DCHAKRACORE_BUILD_SH=ON $CC_PREFIX $CMAKE_ICU $LTO $LTTNG \
637-
$STATIC_LIBRARY $ARCH $TARGET_OS \ $ENABLE_CC_XPLAT_TRACE $EXTRA_DEFINES \
637+
$STATIC_LIBRARY $ARCH $TARGET_OS $ENABLE_CC_XPLAT_TRACE $EXTRA_DEFINES \
638638
-DCMAKE_BUILD_TYPE=$BUILD_TYPE $SANITIZE $NO_JIT $CMAKE_INTL \
639639
$WITHOUT_FEATURES $WB_FLAG $WB_ARGS $CMAKE_EXPORT_COMPILE_COMMANDS \
640640
$LIBS_ONLY_BUILD $VALGRIND $BUILD_RELATIVE_DIRECTORY $CCACHE_NAME
File renamed without changes.

lib/Common/Core/CommonTypedefs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ typedef unsigned long ulong;
2626

2727
typedef signed char sbyte;
2828

29-
typedef __int8 int8;
29+
typedef signed __int8 int8;
3030
typedef __int16 int16;
3131
typedef __int32 int32;
3232
typedef __int64 int64;

lib/Common/arm64.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,9 @@ extern "C" VOID arm64_SAVE_REGISTERS(void*);
3333
*/
3434

3535
const DWORD ReturnAddrOffsetFromFramePtr = 1;
36+
#ifdef __linux__
37+
// Linux ARM64 appears to have some extra 8 byte padding.
38+
const DWORD ArgOffsetFromFramePtr = 4;
39+
#else
3640
const DWORD ArgOffsetFromFramePtr = 2;
41+
#endif

lib/Runtime/Language/Arguments.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313
va_list _vl; \
1414
va_start(_vl, callInfo); \
1515
Js::Var* va = (Js::Var*)_vl
16+
#elif defined(_ARM64_) && defined(__linux__)
17+
// AAPCS64 (Linux ARM64 ABI) reference:
18+
// https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#appendix-variable-argument-lists
19+
#define DECLARE_ARGS_VARARRAY(va, ...) \
20+
va_list _vl; \
21+
va_start(_vl, callInfo); \
22+
Js::Var* va = (Js::Var*)_vl.__stack + 2; \
23+
Assert(*reinterpret_cast<Js::CallInfo*>(va - 1) == callInfo)
1624
#else
1725
// We use a custom calling convention to invoke JavascriptMethod based on
1826
// System ABI. At entry of JavascriptMethod the stack layout is:
@@ -84,8 +92,19 @@ inline int _count_args(const T1&, const T2&, const T3&, const T4&, const T5&, Js
8492
#define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \
8593
entryPoint(function, callInfo, ##__VA_ARGS__)
8694
#elif defined (_ARM64_)
95+
#ifdef __linux__
96+
// Linux ARM64 uses AAPCS64: first 8 args in x0-x7, rest via stack.
97+
// Fill x2-x7 with nulls here to force the expected stack layout:
98+
// [RetAddr] [function] [callInfo] [args...]
99+
#define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \
100+
entryPoint(function, callInfo, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, \
101+
function, callInfo, ##__VA_ARGS__)
102+
#else
103+
// macOS has own bespoke vararg cc (DarwinPCS), varargs always passed via stack.
104+
// Duplicate function/callInfo so they are pushed onto stack as part of varargs.
87105
#define CALL_ENTRYPOINT_NOASSERT(entryPoint, function, callInfo, ...) \
88106
entryPoint(function, callInfo, function, callInfo, ##__VA_ARGS__)
107+
#endif
89108
#else
90109
#error CALL_ENTRYPOINT_NOASSERT not yet implemented
91110
#endif

lib/Runtime/Language/SimdInt32x4Operation.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,12 @@ namespace Js
6363
SIMDValue SIMDInt32x4Operation::OpFromFloat32x4(const SIMDValue& v, bool &throws)
6464
{
6565
SIMDValue result = { 0 };
66-
const int MIN_INT = 0x80000000, MAX_INT = 0x7FFFFFFF;
66+
const float MIN_INT = -2147483648.0f;
67+
const float MAX_INT_PLUS_1 = 2147483648.0f; // exact float
6768

6869
for (uint i = 0; i < 4; i++)
6970
{
70-
if (v.f32[i] >= MIN_INT && v.f32[i] <= MAX_INT)
71+
if (v.f32[i] >= MIN_INT && v.f32[i] < MAX_INT_PLUS_1)
7172
{
7273
result.u32[i] = (int)(v.f32[i]);
7374
}

lib/Runtime/Library/JavascriptError.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ namespace Js
396396

397397
if (FACILITY_CONTROL == HRESULT_FACILITY(hr) || FACILITY_JSCRIPT == HRESULT_FACILITY(hr))
398398
{
399-
#if !(defined(_M_ARM) && defined(__clang__))
399+
#if !((defined(_M_ARM) || defined(_M_ARM64)) && defined(__clang__))
400400
if (argList != nullptr)
401401
#endif
402402
{

lib/Runtime/PlatformAgnostic/ChakraICU.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,20 @@
4646
#include "unicode/upluralrules.h"
4747
#endif // ifdef WINDOWS10_ICU
4848

49+
// Use PAL wrappers for Linux arm64 to fix wchar_t/char16_t mismatches.
50+
// Cannot go before system unicode headers - here is the earliest
51+
// possible point to override these.
52+
#if defined(_ARM64_) && defined(__linux__)
53+
#define wcschr PAL_wcschr
54+
#define wcscmp PAL_wcscmp
55+
#define wcslen PAL_wcslen
56+
#define wcsncmp PAL_wcsncmp
57+
#define wcsrchr PAL_wcsrchr
58+
#define wcsstr PAL_wcsstr
59+
#define wmemcmp PAL_wmemcmp
60+
#define wprintf PAL_wprintf
61+
#endif
62+
4963
// Different assertion code is used in ChakraFull that enforces that messages are char literals
5064
#ifdef _CHAKRACOREBUILD
5165
#define ICU_ERRORMESSAGE(e) u_errorName(e)

lib/Runtime/PlatformAgnostic/ChakraPlatform.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@
2020
#include "PlatformAgnostic/AssemblyCommon.h"
2121

2222
#if !defined(_WIN32) && defined(DEBUG)
23+
// This define from sal.h conflicts with Linux's signal.h
24+
#undef __reserved
2325
#include <signal.h> // raise(SIGINT)
2426
#endif

0 commit comments

Comments
 (0)