From 2df0e0e8fe85bb0abb4442f82ff7ca89a364cbbb Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 30 Mar 2026 12:47:43 -0500 Subject: [PATCH 1/5] build: aix add conditonal flags for clang builds Some gcc flags dont work on clang: -mfprnd -mno-popcntb -fno-extern-tls-init So now we conditionally add them when clang is not enabled Also for clang builds we need to pass some additonal flags: -fno-integrated-as -fno-xl-pragma-pack These flags are discuessed in: https://chromium-review.googlesource.com/c/chromium/src/+/7120638 --- common.gypi | 12 ++++++++++++ tools/v8_gypfiles/toolchain.gypi | 22 ++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/common.gypi b/common.gypi index 953a1448d4baa5..488779fb8966eb 100644 --- a/common.gypi +++ b/common.gypi @@ -591,6 +591,18 @@ '-maix64', ], 'conditions': [ + [ 'clang==1', { + 'cflags': [ + '-fno-integrated-as', + '-fno-xl-pragma-pack', + '-mcpu=power9', + ], + 'cflags_cc': [ + '-fno-integrated-as', + '-fno-xl-pragma-pack', + '-mcpu=power9', + ], + }], [ '"<(aix_variant_name)"=="OS400"', { # a.k.a. `IBM i` 'ldflags': [ '-Wl,-blibpath:/QOpenSys/pkgs/lib:/QOpenSys/usr/lib', diff --git a/tools/v8_gypfiles/toolchain.gypi b/tools/v8_gypfiles/toolchain.gypi index b11be560e966e6..5aa9d020a9205f 100644 --- a/tools/v8_gypfiles/toolchain.gypi +++ b/tools/v8_gypfiles/toolchain.gypi @@ -330,11 +330,20 @@ 'conditions': [ ['OS=="aix" or OS=="os400"', { # Work around AIX ceil, trunc and round oddities. - 'cflags': [ '-mcpu=power9 -mfprnd' ], + 'cflags': [ '-mcpu=power9' ], + 'conditions': [ + ['clang==0', { + 'cflags': [ '-mfprnd' ], + }], + ], }], ['OS=="aix" or OS=="os400"', { - # Work around AIX assembler popcntb bug. - 'cflags': [ '-mno-popcntb' ], + 'conditions': [ + ['clang==0', { + # Work around AIX assembler popcntb bug. + 'cflags': [ '-mno-popcntb' ], + }], + ], }], ], }], # ppc64 @@ -593,8 +602,13 @@ '_ALL_SOURCE=1'], 'conditions': [ [ 'v8_target_arch=="ppc64"', { - 'cflags': [ '-maix64', '-fdollars-in-identifiers', '-fno-extern-tls-init' ], + 'cflags': [ '-maix64', '-fdollars-in-identifiers' ], 'ldflags': [ '-maix64 -Wl,-bbigtoc' ], + 'conditions': [ + ['clang==0', { + 'cflags': [ '-fno-extern-tls-init' ], + }], + ], }], ], }], From 9e9308af011deab7fa545f3bc368f60395381670 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 30 Mar 2026 12:55:12 -0500 Subject: [PATCH 2/5] openssl: fix aix implicit declaration due ... to header files not shipping declarations. This seems like a bug in AIX header files because the examples show including the headers but upon inspecting these files there are no declarations for sendmmsg and others: https://www.ibm.com/docs/en/aix/7.2.0?topic=s-sendmmsg-subroutine For now we can claim to not have these functions. Alternatively we can declare these ourselves if we are AIX 7.2 or newer. The actual functions look to be available in libc. GCC also has the same implicit function declaration but it happily moves forward. Clang started making this an explict error in clang 16: https://www.redhat.com/en/blog/new-warnings-and-errors-clang-16 --- deps/openssl/openssl/crypto/bio/bss_dgram.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/openssl/openssl/crypto/bio/bss_dgram.c b/deps/openssl/openssl/crypto/bio/bss_dgram.c index dd14c393d7370f..72f63cb33e5196 100644 --- a/deps/openssl/openssl/crypto/bio/bss_dgram.c +++ b/deps/openssl/openssl/crypto/bio/bss_dgram.c @@ -68,8 +68,8 @@ #undef NO_RECVMMSG #define NO_RECVMMSG #endif -#if defined(_AIX) && !defined(_AIX72) -/* AIX >= 7.2 provides sendmmsg() and recvmmsg(). */ +#if defined(_AIX) +/* Force fallback to sndmsg and recvmsg */ #undef NO_RECVMMSG #define NO_RECVMMSG #endif From 24119b8d0a73a4dbcc3cb54fc9e107a9373bab76 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Mon, 30 Mar 2026 13:21:43 -0500 Subject: [PATCH 3/5] deps: V8: cherry-pick 7107287 Original commit message: aix: add required changes to build with clang Change-Id: Icc78c58831306aa2f227843b0b4ec2321585fa64 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7107287 Reviewed-by: Toon Verwaest Commit-Queue: Clemens Backes Reviewed-by: Leszek Swirski Cr-Commit-Position: refs/heads/main@{#104364} --- common.gypi | 2 +- deps/v8/BUILD.gn | 2 +- deps/v8/src/builtins/ppc/builtins-ppc.cc | 13 +++++++++++++ deps/v8/src/compiler/turboshaft/operations.h | 6 +++--- deps/v8/src/execution/simulator.h | 18 +++++++++++------- deps/v8/src/trap-handler/handler-shared.cc | 4 ++++ 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/common.gypi b/common.gypi index 488779fb8966eb..c943f786e618cd 100644 --- a/common.gypi +++ b/common.gypi @@ -38,7 +38,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.17', + 'v8_embedder_string': '-node.18', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/BUILD.gn b/deps/v8/BUILD.gn index 6432f7342e26a5..75034b69a8a648 100644 --- a/deps/v8/BUILD.gn +++ b/deps/v8/BUILD.gn @@ -1583,7 +1583,7 @@ config("toolchain") { if (v8_current_cpu == "ppc64") { defines += [ "V8_TARGET_ARCH_PPC64" ] cflags += [ "-ffp-contract=off" ] - if (current_os == "aix") { + if (current_os == "aix" and !is_clang) { cflags += [ # Work around AIX ceil, trunc and round oddities. "-mcpu=power5+", diff --git a/deps/v8/src/builtins/ppc/builtins-ppc.cc b/deps/v8/src/builtins/ppc/builtins-ppc.cc index fe0856261e423a..45c59b0ce74f21 100644 --- a/deps/v8/src/builtins/ppc/builtins-ppc.cc +++ b/deps/v8/src/builtins/ppc/builtins-ppc.cc @@ -4219,6 +4219,19 @@ void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, // If return value is on the stack, pop it to registers. if (needs_return_buffer) { + Label done; + if (switch_to_central_stack) { + Label no_stack_change; + __ CmpU64(kOldSPRegister, Operand(0), r0); + __ beq(&no_stack_change); + __ addi(r3, kOldSPRegister, + Operand((kStackFrameExtraParamSlot + 1) * kSystemPointerSize)); + __ b(&done); + __ bind(&no_stack_change); + } + __ addi(r3, sp, + Operand((kStackFrameExtraParamSlot + 1) * kSystemPointerSize)); + __ bind(&done); __ LoadU64(r4, MemOperand(r3, kSystemPointerSize)); __ LoadU64(r3, MemOperand(r3)); } diff --git a/deps/v8/src/compiler/turboshaft/operations.h b/deps/v8/src/compiler/turboshaft/operations.h index c306bd14822054..2059de599c10d5 100644 --- a/deps/v8/src/compiler/turboshaft/operations.h +++ b/deps/v8/src/compiler/turboshaft/operations.h @@ -526,7 +526,7 @@ class InputsRepFactory { }; }; -struct EffectDimensions { +struct __attribute__((packed)) EffectDimensions { // Produced by loads, consumed by operations that should not move before loads // because they change memory. bool load_heap_memory : 1; @@ -621,7 +621,7 @@ static_assert(sizeof(EffectDimensions) == sizeof(EffectDimensions::Bits)); // they become more restricted in their movement. Note that calls are not the // most side-effectful operations, as they do not leave the heap in an // inconsistent state, so they do not need to be marked as raw heap access. -struct OpEffects { +struct __attribute__((packed)) OpEffects { EffectDimensions produces; EffectDimensions consumes; @@ -2878,7 +2878,7 @@ struct ConstantOp : FixedArityOperationT<0, ConstantOp> { // When result_rep is RegisterRepresentation::Compressed(), then the load does // not decompress the value. struct LoadOp : OperationT { - struct Kind { + struct __attribute__((packed)) Kind { // The `base` input is a tagged pointer to a HeapObject. bool tagged_base : 1; // The effective address might be unaligned. This is only set to true if diff --git a/deps/v8/src/execution/simulator.h b/deps/v8/src/execution/simulator.h index 9ba16c3e7de69c..8a6eb8e02c6482 100644 --- a/deps/v8/src/execution/simulator.h +++ b/deps/v8/src/execution/simulator.h @@ -199,13 +199,17 @@ class GeneratedCode { return fn(args...); #else // AIX ABI requires function descriptors (FD). Artificially create a pseudo - // FD to ensure correct dispatch to generated code. The 'volatile' - // declaration is required to avoid the compiler from not observing the - // alias of the pseudo FD to the function pointer, and hence, optimizing the - // pseudo FD declaration/initialization away. - volatile Address function_desc[] = {reinterpret_cast
(fn_ptr_), 0, - 0}; - Signature* fn = reinterpret_cast(function_desc); + // FD to ensure correct dispatch to generated code. + void* function_desc[3]; + Signature* fn; + asm("std %1, 0(%2)\n\t" + "li 0, 0\n\t" + "std 0, 8(%2)\n\t" + "std 0, 16(%2)\n\t" + "mr %0, %2\n\t" + : "=r"(fn) + : "r"(fn_ptr_), "r"(function_desc) + : "memory", "0"); return fn(args...); #endif // V8_OS_ZOS #else diff --git a/deps/v8/src/trap-handler/handler-shared.cc b/deps/v8/src/trap-handler/handler-shared.cc index 443f023fd18b32..23778117637f6a 100644 --- a/deps/v8/src/trap-handler/handler-shared.cc +++ b/deps/v8/src/trap-handler/handler-shared.cc @@ -24,7 +24,11 @@ namespace v8 { namespace internal { namespace trap_handler { +#if defined(V8_OS_AIX) +__thread bool TrapHandlerGuard::is_active_ = 0; +#else thread_local bool TrapHandlerGuard::is_active_ = 0; +#endif size_t gNumCodeObjects = 0; CodeProtectionInfoListEntry* gCodeObjects = nullptr; From 6285b67e35cde4e18c905aeeb31fd6e6fc4a9ebb Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:05:48 -0500 Subject: [PATCH 4/5] aix: fix export script to filter hidden ... visibility for symbols. Without these changes we are getting back linker errors AIX with clang builds: ```text ld: 0711-407 ERROR: Symbol [SYMBOL_NAME] Visibility is not allowed on a reference to an imported symbol. ``` Not including hidden symbols in the export files matches the recomendation by XLC documentation: > When using export lists, it is not recommended to put symbols with > hidden visibility in the lists. ref: https://www.ibm.com/docs/en/openxl-c-and-cpp-aix/17.1.4?topic=libraries-symbol-exports-visibilities --- tools/create_expfile.sh | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/tools/create_expfile.sh b/tools/create_expfile.sh index cac20da721b06a..1599dd2aee6cf2 100755 --- a/tools/create_expfile.sh +++ b/tools/create_expfile.sh @@ -34,18 +34,35 @@ # Symbols for the gtest libraries are excluded as # they are not linked into the node executable. # +set -x echo "Searching $1 to write out expfile to $2" # This special sequence must be at the start of the exp file. echo "#!." > "$2.tmp" # Pull the symbols from the .a files. -find "$1" -name "*.a" | grep -v gtest \ - | xargs nm -Xany -BCpg \ - | awk '{ - if ((($2 == "T") || ($2 == "D") || ($2 == "B")) && - (substr($3,1,1) != ".")) { print $3 } - }' \ - | sort -u >> "$2.tmp" +# Use dump -tov to get visibility information and exclude HIDDEN symbols +# This prevents AIX linker error 0711-407 when addons try to import symbols +# with visibility attributes. +find "$1" -name "*.a" | grep -v gtest | while read f; do + dump -tov -X 32_64 "$f" 2>/dev/null | \ + awk ' + BEGIN { + V["EXPORTED"]=" export" + V["PROTECTED"]=" protected" + V["HIDDEN"]=" hidden" + } + /^\[[0-9]+\]\tm +[^ ]+ +\.(text|data|tdata|bss) +[^ ]+ +(extern|weak) +(EXPORTED|PROTECTED|HIDDEN| ) / { + # Exclude symbols starting with dot, __sinit, __sterm, __[0-9]+__ + # Also exclude HIDDEN symbols to avoid visibility attribute issues + if (!match($NF,/^(\.|__sinit|__sterm|__[0-9]+__)/)) { + visibility = $(NF-1) + if (visibility != "HIDDEN") { + print $NF + } + } + } + ' +done | sort -u >> "$2.tmp" mv -f "$2.tmp" "$2" From 1b406bfb5cee4776dda113ddcef0439d797c9d64 Mon Sep 17 00:00:00 2001 From: Abdirahim Musse <33973272+abmusse@users.noreply.github.com> Date: Fri, 3 Apr 2026 11:50:39 -0500 Subject: [PATCH 5/5] aix: Add weak symbol detection ... in create_expfile.sh AIX export files support the `weak` keyword to mark weak symbols. ref: https://www.ibm.com/docs/en/aix/7.2.0?topic=l-ld-command#ld__a3119106d This helps preserve C++ weak symbol semantics and preventing potential linker conflicts. --- tools/create_expfile.sh | 69 ++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/tools/create_expfile.sh b/tools/create_expfile.sh index 1599dd2aee6cf2..5c2d8d58b1947b 100755 --- a/tools/create_expfile.sh +++ b/tools/create_expfile.sh @@ -5,45 +5,63 @@ # specifically for export so that they can be used # by native add-ons. # -# The raw symbol data is obtained by using nm on +# The raw symbol data is obtained by using dump -tov on # the .a files which make up the node executable. # -# -Xany processes symbols for both 32-bit and -# 64-bit (the default is for 32-bit only). +# dump -tov flags: +# -t: Display symbol table entries +# -o: Display object file headers +# -v: Display visibility information (HIDDEN/EXPORTED/PROTECTED) +# -X 32_64: Process both 32-bit and 64-bit symbols # -# -g selects only exported symbols. +# This approach is similar to CMake's ExportImportList module for AIX: +# https://github.com/Kitware/CMake/blob/45f4742cbfe6c25c7c801e3806c8af04a2c4b09b/Modules/Platform/AIX/ExportImportList#L67-L80 # -# -C, -B and -p ensure that the output is in a -# format that can be easily parsed and converted -# into the required symbol. -# -# -C suppresses the demangling of C++ names. -# -B writes the output in BSD format. -# -p displays the info in a standard portable -# output format. -# -# Only include symbols if they are of the following -# types and don't start with a dot. -# -# T - Global text symbol. -# D - Global data symbol. -# B - Global bss symbol. +# We filter for symbols in .text, .data, .tdata, and .bss sections +# with extern or weak linkage, excluding: +# - Symbols starting with dot (internal/local symbols) +# - __sinit/__sterm (static initialization/termination) +# - __[0-9]+__ (compiler-generated symbols) +# - HIDDEN visibility symbols (to avoid linker error 0711-407) # # The final sort allows removal of any duplicates. # # Symbols for the gtest libraries are excluded as # they are not linked into the node executable. # -set -x echo "Searching $1 to write out expfile to $2" # This special sequence must be at the start of the exp file. echo "#!." > "$2.tmp" # Pull the symbols from the .a files. -# Use dump -tov to get visibility information and exclude HIDDEN symbols +# Use dump -tov to get visibility information and exclude HIDDEN symbols. # This prevents AIX linker error 0711-407 when addons try to import symbols # with visibility attributes. +# +# IMPORTANT: AIX dump -tov output has a visibility column that contains either +# a visibility keyword (HIDDEN/EXPORTED/PROTECTED) or blank spaces when no +# visibility attribute is set. Since AWK splits fields on whitespace, this +# results in different field counts: +# +# With visibility keyword (8 fields after AWK splits): +# [137] m 0x00003290 .text 1 weak HIDDEN ._ZNKSt3__1... +# $1 $2 $3 $4 $5 $6 $7 $8 +# | | └─ Symbol name +# | └─ Visibility (HIDDEN/EXPORTED/PROTECTED) +# └─ Linkage (weak/extern) +# +# Without visibility keyword (7 fields after AWK splits, spaces collapsed): +# [77] m 0x00000000 .text 1 weak ._ZN8simdjson... +# $1 $2 $3 $4 $5 $6 $7 +# | └─ Symbol name +# └─ Linkage (weak/extern) +# +# The awk script handles both cases by using an associative array V[] +# to map field values to their export suffixes. For fields that don't match +# any key in V[], the lookup returns an empty string, which is perfect for +# handling the variable field positions caused by the blank visibility column. +# find "$1" -name "*.a" | grep -v gtest | while read f; do dump -tov -X 32_64 "$f" 2>/dev/null | \ awk ' @@ -51,14 +69,15 @@ find "$1" -name "*.a" | grep -v gtest | while read f; do V["EXPORTED"]=" export" V["PROTECTED"]=" protected" V["HIDDEN"]=" hidden" + V["weak"]=" weak" } - /^\[[0-9]+\]\tm +[^ ]+ +\.(text|data|tdata|bss) +[^ ]+ +(extern|weak) +(EXPORTED|PROTECTED|HIDDEN| ) / { + /^\[[0-9]+\]\tm +[^ ]+ +\.(text|data|tdata|bss) +[^ ]+ +(extern|weak)( +(EXPORTED|PROTECTED|HIDDEN))?/ { # Exclude symbols starting with dot, __sinit, __sterm, __[0-9]+__ # Also exclude HIDDEN symbols to avoid visibility attribute issues if (!match($NF,/^(\.|__sinit|__sterm|__[0-9]+__)/)) { - visibility = $(NF-1) - if (visibility != "HIDDEN") { - print $NF + # Skip if HIDDEN visibility (can be at $(NF-1) or $(NF-2)) + if ($(NF-1) != "HIDDEN" && $(NF-2) != "HIDDEN") { + print $NF V[$(NF-1)] V[$(NF-2)] } } }