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

@sbomersbomer commented May 27, 2026

Copy link
Copy Markdown
Member

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 jkotasMay 27, 2026 21:32

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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
FileDescription
src/native/external/llvm-libunwind/src/Unwind-EHABI.cppGuards EHABI exception-dispatch exports when _LIBUNWIND_NATIVEAOT is set to avoid references to removed __unw_* APIs.
src/native/external/llvm-libunwind/src/libunwind.cppGuards the public unw_* API surface and the LocalAddressSpace::sThisAddressSpace singleton under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind/src/AddressSpace.hppGuards the LocalAddressSpace::sThisAddressSpace static member declaration under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind-version.txtNotes the applied commit associated with this local patch.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.hDeclares the new UnwindHelpers::FindUnwindSections accessor.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cppImplements FindUnwindSections by delegating to the existing file-scope _addressSpace.
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cppReplaces use of LocalAddressSpace::sThisAddressSpace.findUnwindSections with UnwindHelpers::FindUnwindSections.
src/coreclr/nativeaot/Runtime/CMakeLists.txtDefines _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

am11 commented May 27, 2026

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind/src/AddressSpace.hpp Outdated
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
@jkotas

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind-version.txt Outdated
Comment threadsrc/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/CMakeLists.txt Outdated
CopilotAI review requested due to automatic review settings May 28, 2026 20:08

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

sbomerand 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
MemberAuthor

@jkotas can you please help merge this without squashing?

@jkotas
jkotas merged commit ad724f5 into dotnet:mainMay 29, 2026
164 of 171 checks passed
@sbomer
sbomer deleted the libunwind-ifdef branch May 29, 2026 16:58
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone May 30, 2026
CopilotAI 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>
CopilotAI 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 freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

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

@sbomer@am11@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Guard unused llvm-libunwind symbols to avoid duplicates on Android by sbomer · Pull Request #128667 · dotnet/runtime · GitHub
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

@sbomersbomer commented May 27, 2026

Copy link
Copy Markdown
Member

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 jkotasMay 27, 2026 21:32

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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
FileDescription
src/native/external/llvm-libunwind/src/Unwind-EHABI.cppGuards EHABI exception-dispatch exports when _LIBUNWIND_NATIVEAOT is set to avoid references to removed __unw_* APIs.
src/native/external/llvm-libunwind/src/libunwind.cppGuards the public unw_* API surface and the LocalAddressSpace::sThisAddressSpace singleton under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind/src/AddressSpace.hppGuards the LocalAddressSpace::sThisAddressSpace static member declaration under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind-version.txtNotes the applied commit associated with this local patch.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.hDeclares the new UnwindHelpers::FindUnwindSections accessor.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cppImplements FindUnwindSections by delegating to the existing file-scope _addressSpace.
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cppReplaces use of LocalAddressSpace::sThisAddressSpace.findUnwindSections with UnwindHelpers::FindUnwindSections.
src/coreclr/nativeaot/Runtime/CMakeLists.txtDefines _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

am11 commented May 27, 2026

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind/src/AddressSpace.hpp Outdated
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
@jkotas

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind-version.txt Outdated
Comment threadsrc/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/CMakeLists.txt Outdated
CopilotAI review requested due to automatic review settings May 28, 2026 20:08

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

sbomerand 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
MemberAuthor

@jkotas can you please help merge this without squashing?

@jkotas
jkotas merged commit ad724f5 into dotnet:mainMay 29, 2026
164 of 171 checks passed
@sbomer
sbomer deleted the libunwind-ifdef branch May 29, 2026 16:58
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone May 30, 2026
CopilotAI 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>
CopilotAI 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 freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

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

@sbomer@am11@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Guard unused llvm-libunwind symbols to avoid duplicates on Android by sbomer · Pull Request #128667 · dotnet/runtime · GitHub
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

@sbomersbomer commented May 27, 2026

Copy link
Copy Markdown
Member

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 jkotasMay 27, 2026 21:32

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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
FileDescription
src/native/external/llvm-libunwind/src/Unwind-EHABI.cppGuards EHABI exception-dispatch exports when _LIBUNWIND_NATIVEAOT is set to avoid references to removed __unw_* APIs.
src/native/external/llvm-libunwind/src/libunwind.cppGuards the public unw_* API surface and the LocalAddressSpace::sThisAddressSpace singleton under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind/src/AddressSpace.hppGuards the LocalAddressSpace::sThisAddressSpace static member declaration under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind-version.txtNotes the applied commit associated with this local patch.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.hDeclares the new UnwindHelpers::FindUnwindSections accessor.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cppImplements FindUnwindSections by delegating to the existing file-scope _addressSpace.
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cppReplaces use of LocalAddressSpace::sThisAddressSpace.findUnwindSections with UnwindHelpers::FindUnwindSections.
src/coreclr/nativeaot/Runtime/CMakeLists.txtDefines _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

am11 commented May 27, 2026

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind/src/AddressSpace.hpp Outdated
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
@jkotas

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind-version.txt Outdated
Comment threadsrc/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/CMakeLists.txt Outdated
CopilotAI review requested due to automatic review settings May 28, 2026 20:08

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

sbomerand 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
MemberAuthor

@jkotas can you please help merge this without squashing?

@jkotas
jkotas merged commit ad724f5 into dotnet:mainMay 29, 2026
164 of 171 checks passed
@sbomer
sbomer deleted the libunwind-ifdef branch May 29, 2026 16:58
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone May 30, 2026
CopilotAI 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>
CopilotAI 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 freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

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

@sbomer@am11@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Guard unused llvm-libunwind symbols to avoid duplicates on Android by sbomer · Pull Request #128667 · dotnet/runtime · GitHub
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

@sbomersbomer commented May 27, 2026

Copy link
Copy Markdown
Member

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 jkotasMay 27, 2026 21:32

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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
FileDescription
src/native/external/llvm-libunwind/src/Unwind-EHABI.cppGuards EHABI exception-dispatch exports when _LIBUNWIND_NATIVEAOT is set to avoid references to removed __unw_* APIs.
src/native/external/llvm-libunwind/src/libunwind.cppGuards the public unw_* API surface and the LocalAddressSpace::sThisAddressSpace singleton under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind/src/AddressSpace.hppGuards the LocalAddressSpace::sThisAddressSpace static member declaration under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind-version.txtNotes the applied commit associated with this local patch.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.hDeclares the new UnwindHelpers::FindUnwindSections accessor.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cppImplements FindUnwindSections by delegating to the existing file-scope _addressSpace.
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cppReplaces use of LocalAddressSpace::sThisAddressSpace.findUnwindSections with UnwindHelpers::FindUnwindSections.
src/coreclr/nativeaot/Runtime/CMakeLists.txtDefines _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

am11 commented May 27, 2026

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind/src/AddressSpace.hpp Outdated
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
@jkotas

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind-version.txt Outdated
Comment threadsrc/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/CMakeLists.txt Outdated
CopilotAI review requested due to automatic review settings May 28, 2026 20:08

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

sbomerand 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
MemberAuthor

@jkotas can you please help merge this without squashing?

@jkotas
jkotas merged commit ad724f5 into dotnet:mainMay 29, 2026
164 of 171 checks passed
@sbomer
sbomer deleted the libunwind-ifdef branch May 29, 2026 16:58
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone May 30, 2026
CopilotAI 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>
CopilotAI 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 freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

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

@sbomer@am11@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Guard unused llvm-libunwind symbols to avoid duplicates on Android by sbomer · Pull Request #128667 · dotnet/runtime · GitHub
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

@sbomersbomer commented May 27, 2026

Copy link
Copy Markdown
Member

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 jkotasMay 27, 2026 21:32

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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
FileDescription
src/native/external/llvm-libunwind/src/Unwind-EHABI.cppGuards EHABI exception-dispatch exports when _LIBUNWIND_NATIVEAOT is set to avoid references to removed __unw_* APIs.
src/native/external/llvm-libunwind/src/libunwind.cppGuards the public unw_* API surface and the LocalAddressSpace::sThisAddressSpace singleton under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind/src/AddressSpace.hppGuards the LocalAddressSpace::sThisAddressSpace static member declaration under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind-version.txtNotes the applied commit associated with this local patch.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.hDeclares the new UnwindHelpers::FindUnwindSections accessor.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cppImplements FindUnwindSections by delegating to the existing file-scope _addressSpace.
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cppReplaces use of LocalAddressSpace::sThisAddressSpace.findUnwindSections with UnwindHelpers::FindUnwindSections.
src/coreclr/nativeaot/Runtime/CMakeLists.txtDefines _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

am11 commented May 27, 2026

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind/src/AddressSpace.hpp Outdated
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
@jkotas

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind-version.txt Outdated
Comment threadsrc/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/CMakeLists.txt Outdated
CopilotAI review requested due to automatic review settings May 28, 2026 20:08

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

sbomerand 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
MemberAuthor

@jkotas can you please help merge this without squashing?

@jkotas
jkotas merged commit ad724f5 into dotnet:mainMay 29, 2026
164 of 171 checks passed
@sbomer
sbomer deleted the libunwind-ifdef branch May 29, 2026 16:58
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone May 30, 2026
CopilotAI 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>
CopilotAI 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 freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

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

@sbomer@am11@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Guard unused llvm-libunwind symbols to avoid duplicates on Android by sbomer · Pull Request #128667 · dotnet/runtime · GitHub
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

@sbomersbomer commented May 27, 2026

Copy link
Copy Markdown
Member

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 jkotasMay 27, 2026 21:32

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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
FileDescription
src/native/external/llvm-libunwind/src/Unwind-EHABI.cppGuards EHABI exception-dispatch exports when _LIBUNWIND_NATIVEAOT is set to avoid references to removed __unw_* APIs.
src/native/external/llvm-libunwind/src/libunwind.cppGuards the public unw_* API surface and the LocalAddressSpace::sThisAddressSpace singleton under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind/src/AddressSpace.hppGuards the LocalAddressSpace::sThisAddressSpace static member declaration under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind-version.txtNotes the applied commit associated with this local patch.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.hDeclares the new UnwindHelpers::FindUnwindSections accessor.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cppImplements FindUnwindSections by delegating to the existing file-scope _addressSpace.
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cppReplaces use of LocalAddressSpace::sThisAddressSpace.findUnwindSections with UnwindHelpers::FindUnwindSections.
src/coreclr/nativeaot/Runtime/CMakeLists.txtDefines _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

am11 commented May 27, 2026

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind/src/AddressSpace.hpp Outdated
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
@jkotas

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind-version.txt Outdated
Comment threadsrc/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/CMakeLists.txt Outdated
CopilotAI review requested due to automatic review settings May 28, 2026 20:08

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

sbomerand 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
MemberAuthor

@jkotas can you please help merge this without squashing?

@jkotas
jkotas merged commit ad724f5 into dotnet:mainMay 29, 2026
164 of 171 checks passed
@sbomer
sbomer deleted the libunwind-ifdef branch May 29, 2026 16:58
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone May 30, 2026
CopilotAI 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>
CopilotAI 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 freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

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

@sbomer@am11@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Guard unused llvm-libunwind symbols to avoid duplicates on Android by sbomer · Pull Request #128667 · dotnet/runtime · GitHub
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

@sbomersbomer commented May 27, 2026

Copy link
Copy Markdown
Member

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 jkotasMay 27, 2026 21:32

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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
FileDescription
src/native/external/llvm-libunwind/src/Unwind-EHABI.cppGuards EHABI exception-dispatch exports when _LIBUNWIND_NATIVEAOT is set to avoid references to removed __unw_* APIs.
src/native/external/llvm-libunwind/src/libunwind.cppGuards the public unw_* API surface and the LocalAddressSpace::sThisAddressSpace singleton under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind/src/AddressSpace.hppGuards the LocalAddressSpace::sThisAddressSpace static member declaration under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind-version.txtNotes the applied commit associated with this local patch.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.hDeclares the new UnwindHelpers::FindUnwindSections accessor.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cppImplements FindUnwindSections by delegating to the existing file-scope _addressSpace.
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cppReplaces use of LocalAddressSpace::sThisAddressSpace.findUnwindSections with UnwindHelpers::FindUnwindSections.
src/coreclr/nativeaot/Runtime/CMakeLists.txtDefines _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

am11 commented May 27, 2026

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind/src/AddressSpace.hpp Outdated
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
@jkotas

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind-version.txt Outdated
Comment threadsrc/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/CMakeLists.txt Outdated
CopilotAI review requested due to automatic review settings May 28, 2026 20:08

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

sbomerand 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
MemberAuthor

@jkotas can you please help merge this without squashing?

@jkotas
jkotas merged commit ad724f5 into dotnet:mainMay 29, 2026
164 of 171 checks passed
@sbomer
sbomer deleted the libunwind-ifdef branch May 29, 2026 16:58
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone May 30, 2026
CopilotAI 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>
CopilotAI 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 freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

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

@sbomer@am11@jkotas@MichalStrehovsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Guard unused llvm-libunwind symbols to avoid duplicates on Android by sbomer · Pull Request #128667 · dotnet/runtime · GitHub
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

@sbomersbomer commented May 27, 2026

Copy link
Copy Markdown
Member

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 jkotasMay 27, 2026 21:32

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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
FileDescription
src/native/external/llvm-libunwind/src/Unwind-EHABI.cppGuards EHABI exception-dispatch exports when _LIBUNWIND_NATIVEAOT is set to avoid references to removed __unw_* APIs.
src/native/external/llvm-libunwind/src/libunwind.cppGuards the public unw_* API surface and the LocalAddressSpace::sThisAddressSpace singleton under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind/src/AddressSpace.hppGuards the LocalAddressSpace::sThisAddressSpace static member declaration under _LIBUNWIND_NATIVEAOT.
src/native/external/llvm-libunwind-version.txtNotes the applied commit associated with this local patch.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.hDeclares the new UnwindHelpers::FindUnwindSections accessor.
src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cppImplements FindUnwindSections by delegating to the existing file-scope _addressSpace.
src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cppReplaces use of LocalAddressSpace::sThisAddressSpace.findUnwindSections with UnwindHelpers::FindUnwindSections.
src/coreclr/nativeaot/Runtime/CMakeLists.txtDefines _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

am11 commented May 27, 2026

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind/src/AddressSpace.hpp Outdated
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
Comment threadsrc/native/external/llvm-libunwind/src/libunwind.cpp
@jkotas

Copy link
Copy Markdown
Member

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 threadsrc/native/external/llvm-libunwind-version.txt Outdated
Comment threadsrc/native/external/llvm-libunwind/src/Unwind-EHABI.cpp Outdated
Comment threadsrc/coreclr/nativeaot/Runtime/CMakeLists.txt Outdated
CopilotAI review requested due to automatic review settings May 28, 2026 20:08

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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.

sbomerand 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
MemberAuthor

@jkotas can you please help merge this without squashing?

@jkotas
jkotas merged commit ad724f5 into dotnet:mainMay 29, 2026
164 of 171 checks passed
@sbomer
sbomer deleted the libunwind-ifdef branch May 29, 2026 16:58
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-preview6 milestone May 30, 2026
CopilotAI 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>
CopilotAI 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 freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

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

@sbomer@am11@jkotas@MichalStrehovsky