Skip to content

Guard unused llvm-libunwind symbols to avoid duplicates on Android#128667

Merged
jkotas merged 2 commits into
dotnet:mainfrom
sbomer:libunwind-ifdef
May 29, 2026
Merged

Guard unused llvm-libunwind symbols to avoid duplicates on Android#128667
jkotas merged 2 commits into
dotnet:mainfrom
sbomer:libunwind-ifdef

Conversation

@sbomer
Copy link
Copy Markdown
Member

@sbomer sbomer commented May 27, 2026

NativeAOT uses llvm-libunwind's internal C++ classes directly
(DwarfInstructions, CompactUnwinder, UnwindCursor, LocalAddressSpace)
and does not call the public unw_* C API. These symbols conflict with
platform libunwind on Android NDK r29.

Add a _LIBUNWIND_NATIVEAOT define that guards out the public API
symbols NativeAOT does not use:

  • libunwind.cpp: all unw_* functions, unw_local_addr_space, and
    the LocalAddressSpace::sThisAddressSpace singleton
  • AddressSpace.hpp: sThisAddressSpace static member declaration
  • Unwind-EHABI.cpp: the C++ exception dispatch functions are also
    guarded because they depend on the now-guarded unw_* functions
    and would cause undefined symbol errors on ARM32

Switch UnixNativeCodeManager to use a new UnwindHelpers::FindUnwindSections()
accessor instead of the now-guarded sThisAddressSpace singleton. This
delegates to the existing file-local LocalAddressSpace instance in
UnwindHelpers.cpp

Fixes #121172

@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

@sbomer sbomer requested review from am11 and jkotas May 27, 2026 21:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the NativeAOT build of the vendored llvm-libunwind to avoid duplicate symbol conflicts (notably on Android NDK r29) by compiling out libunwind’s public unw_* entrypoints and related exception-dispatch code that NativeAOT doesn’t use, and by routing NativeAOT’s unwind-section discovery through a runtime-owned helper instead of libunwind’s LocalAddressSpace::sThisAddressSpace singleton.

Changes:

  • Add _LIBUNWIND_NATIVEAOT and use it to guard out unw_* APIs (and the LocalAddressSpace::sThisAddressSpace singleton) in libunwind.cpp, plus dependent EHABI exception-dispatch exports in Unwind-EHABI.cpp.
  • Introduce UnwindHelpers::FindUnwindSections() and switch UnixNativeCodeManager to use it (avoiding the now-guarded sThisAddressSpace).
  • Record the patch application in llvm-libunwind-version.txt and enable the new define in the NativeAOT runtime CMake configuration.
Show a summary per file
File Description
src/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Guards EHABI exception-dispatch exports when _LIBUNWIND_NATIVEAOT is set to avoid references to removed __unw_* APIs.
src/native/external/llvm-libunwind/src/libunwind.cpp Guards the public unw_* API surface and the LocalAddressSpace::sThisAddressSpace singleton under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind/src/AddressSpace.hpp Guards the LocalAddressSpace::sThisAddressSpace static member declaration under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind-version.txt Notes the applied commit associated with this local patch.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.h Declares the new UnwindHelpers::FindUnwindSections accessor.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp Implements FindUnwindSections by delegating to the existing file-scope _addressSpace.
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp Replaces use of LocalAddressSpace::sThisAddressSpace.findUnwindSections with UnwindHelpers::FindUnwindSections.
src/coreclr/nativeaot/Runtime/CMakeLists.txt Defines _LIBUNWIND_NATIVEAOT=1 for Unix NativeAOT builds to enable the guarding behavior.

Copilot's findings

  • Files reviewed: 8/8 changed files
  • Comments generated: 0

@am11
Copy link
Copy Markdown
Member

am11 commented May 27, 2026

If it's a negative if !defined(_LIBUNWIND_NATIVEAOT) check everywhere, we can just delete the code it skips. The idea of this local copy is we apply the patches and keep track of them for possible upstream.

Comment thread src/native/external/llvm-libunwind/src/AddressSpace.hpp Outdated
Comment thread src/native/external/llvm-libunwind/src/libunwind.cpp
Comment thread src/native/external/llvm-libunwind/src/libunwind.cpp
@jkotas
Copy link
Copy Markdown
Member

jkotas commented May 27, 2026

we can just delete the code it skips. The idea of this local copy is we apply the patches and keep track of them for possible upstream.

Deleting the code creates more conflicts during updates. We won't be able to upstream the deletion either. I think ifdefing is better.

Comment thread src/native/external/llvm-libunwind-version.txt Outdated
Comment thread src/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Outdated
Comment thread src/coreclr/nativeaot/Runtime/CMakeLists.txt Outdated
Copilot AI review requested due to automatic review settings May 28, 2026 20:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

sbomer and others added 2 commits May 28, 2026 16:55
NativeAOT uses llvm-libunwind's internal C++ classes directly
(DwarfInstructions, CompactUnwinder, UnwindCursor, LocalAddressSpace)
and does not call the public unw_* C API. These symbols conflict with
platform libunwind on Android NDK r29.

Add a _LIBUNWIND_NATIVEAOT define that guards out the public API
symbols NativeAOT does not use:
- libunwind.cpp: wrap the entire file (except debug logging) in
  #if !defined(_LIBUNWIND_NATIVEAOT) as a purely additive patch,
  making it resilient to upstream llvm-libunwind updates
- Unwind-EHABI.cpp: the C++ exception dispatch functions are also
  guarded because they depend on the now-guarded unw_* functions
  and would cause undefined symbol errors on ARM32

Switch UnixNativeCodeManager to use a new UnwindHelpers::FindUnwindSections()
accessor instead of the now-guarded sThisAddressSpace singleton. This
delegates to the existing file-local LocalAddressSpace instance in
UnwindHelpers.cpp.

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reference fde4a5b (Guard unused llvm-libunwind symbols).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sbomer
Copy link
Copy Markdown
Member Author

sbomer commented May 29, 2026

@jkotas can you please help merge this without squashing?

@jkotas jkotas merged commit ad724f5 into dotnet:main May 29, 2026
164 of 171 checks passed
@github-project-automation github-project-automation Bot moved this to Done in AppModel May 29, 2026
@sbomer sbomer deleted the libunwind-ifdef branch May 29, 2026 16:58
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-preview6 milestone May 30, 2026
Copilot AI added a commit that referenced this pull request Jun 1, 2026
Split the single #if !defined(_LIBUNWIND_NATIVEAOT) guard into two blocks
so that _Unwind_VRS_Get, _Unwind_VRS_Get_Internal, _Unwind_VRS_Set,
_Unwind_VRS_Pop, and ValueAsBitPattern are compiled into the NativeAOT
build. These helpers are called by _Unwind_VRS_Interpret which is the
ARM32 EHABI managed-frame unwinding path in NativeAOT.

PR #128667 accidentally included them inside the guard, causing the
linker to resolve them against libgcc_s.so.1 instead of the in-tree
implementations that understand the NativeAOT ArmUnwindCursor shim,
resulting in SIGSEGV during ARM32 stack unwinding.

The genuinely-unused C++ exception dispatch functions (__aeabi_unwind_cpp_pr*,
unwind_phase1/2, _Unwind_RaiseException, _Unwind_ForcedUnwind, etc.) that
depend on __unw_step and other libunwind.cpp public API remain guarded.

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
Copilot AI added a commit that referenced this pull request Jun 1, 2026
… _LIBUNWIND_NATIVEAOT guard

PR #128667 accidentally excluded _Unwind_VRS_Get/Set/Pop (and their
__unw_get/set_reg/__unw_save_vfp_as_X dependencies) from the NativeAOT
build while leaving _Unwind_VRS_Interpret (their caller) in place.
The linker resolved the exported VRS symbols from libgcc_s.so.1 which
treats ArmUnwindCursor* as a real libgcc context → SIGSEGV on ARM32.

Unwind-EHABI.cpp: Split single NATIVEAOT guard into two blocks so
ValueAsBitPattern and _Unwind_VRS_Set/Get_Internal/Get/Pop sit between
the two guards (always compiled).

libunwind.cpp: Split single NATIVEAOT guard into smaller inner guards
keeping __unw_get_reg, __unw_set_reg, __unw_get_fpreg, __unw_set_fpreg,
__unw_save_vfp_as_X unconditional so they are compiled for NativeAOT.
The singleton, __unw_init_local, __unw_step, __unw_resume, DWARF/FDE
functions, and Apple dynamic sections remain behind the guard.

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
@MichalStrehovsky
Copy link
Copy Markdown
Member

This broke uwinding on arm32. The failure mode is a rather mysterious sigsegv, but pulling down a binary from a failed test run and running nm -D seems to indicate we're linking dynamically against some of GCC's libunwind (@GCC_3.5):

007ca06c D DotNetRuntimeDebugHeader@@V1.0
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
         U _Unwind_VRS_Get@GCC_3.5
         U _Unwind_VRS_Pop@GCC_3.5
         U _Unwind_VRS_Set@GCC_3.5
         U __aeabi_unwind_cpp_pr0@GCC_3.5
         U __aeabi_unwind_cpp_pr1@GCC_3.5
         U __aeabi_unwind_cpp_pr2@GCC_3.5
         U __clock_gettime64@GLIBC_2.34
         U __clock_nanosleep_time64@GLIBC_2.34
         U __cxa_atexit@GLIBC_2.4
         w __cxa_finalize@GLIBC_2.4
         U __errno_location@GLIBC_2.4
         U __fcntl_time64@GLIBC_2.34
         U __fstat64_time64@GLIBC_2.34
         U __getdelim@GLIBC_2.4
         ... redacted for brevity

Copilot is trying to do something at #128830.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[NAOT][android] Application linking breaks with NDK r29 because of duplicated libunwind symbols

5 participants