Skip to content

[CoreCLR] Load bootstrap configuration from binary blobs - #13034

Open
simonrozsival wants to merge 17 commits into
simonrozsival-binary-blob-remapping-elffrom
simonrozsival-coreclr-elf-bootstrap-blobs
Open

simonrozsival wants to merge 17 commits into
simonrozsival-binary-blob-remapping-elffrom
simonrozsival-coreclr-elf-bootstrap-blobs

Conversation

@simonrozsival

@simonrozsival simonrozsival commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Pull Request
title and
description
should follow the
commit-messages.md workflow documentation, and in particular should include:

  • Useful description of why the change is necessary.
  • Links to issues fixed
  • Unit tests

Why: CoreCLR startup configuration was embedded as app-specific native globals, separate from the read-only ELF carrying JNI remapping. This layer generates validated XCFG v1 bootstrap data early and assembles it late with final remapping in the same per-ABI libbinary_blobs.so. Empty remapping produces a bootstrap-only single-symbol ELF with presence stamp true; NativeAOT remains remapping-only and emits no library for empty remapping. The assembly-store SO remains separate. App-specific CoreCLR LLVM globals become generic linker placeholders; no app-specific Java configuration bytes are generated. CoreCLR generation requires a nonblank bootstrap output path, with no legacy fallback. Direct-task tests assert XCFG content, and redundant legacy cases were removed. Removing generic LLVM generation is deferred to a follow-up PR.

The package-manager generation target uses its completion stamp for freshness, invalidates it when the bootstrap is missing, deletes it before output-producing tasks run, and recreates it only after successful completion. The combined ELF task retains lower-layer stamp invalidation before output mutations. Both packaging paths preserve the lower layer's rejection of external native inputs targeting reserved libbinary_blobs.so; SDK-generated blob items remain separate and allowed.

Stack/ABI handshake: Prerequisite #13033 supplies multi-symbol ELF writing, independent BLBB v1 raw/Zstd-22 envelopes, optional remapping lookup, and required native BinaryBlobLoader::load returning a decoded {data, size} body with process-lifetime backing. CoreCLR calls load("coreclr_bootstrap") at the start of JNI_OnLoad, before early consumers or CLR creation; its retained loader resolves optional remapping_data once later. XCFG v1 has an 84-byte little-endian header with contiguous environment/system/runtime-property, DSO-cache, preload-index and UTF-8 string-pool sections. The producer validates layout, hash ordering, strings, preload references and required runtime-property slots. ABI metadata is validated upfront and each ELF is validated/written sequentially. Startup trusts build-time invariants rather than rescanning tables or NUL terminators; it copies the fixed header once into a typed struct, retains mapped tables, and bounds on-demand accesses and allocations. Debug override files retain precedence. Default payloads remain raw; compression uses the existing private switch. No issue is closed by this stacked PR.

Latest restack: upper ac5810cda6ea6056eb8f52024f929f69948da5f8 is based exactly on lower 6e564a248d615d9d4c9cfe2eb751b84bcbf6b3a3, including parent #12844 head 31f99c7f06f18cc5cd28c687bb2d35693b6d6279. All 17 upper patches replay unchanged. The parent fixes native test fixture path separators and disposal of the legacy XML input stream; native APIs, wire format, stamp contracts and raw defaults are unchanged.

Current-head validation (macOS):

  • make all — passed, Debug SDK, 0 errors.
  • make all CONFIGURATION=Release MSBUILD_ARGS='-p:RunAnalyzers=false' — passed, Release SDK, 0 errors; the local API-37 preview otherwise triggers unrelated RS0016 analyzer diagnostics. The legacy task assembly also rebuilt successfully in this workspace.
  • ./dotnet-local.sh test bin/TestDebug/net11.0/Microsoft.Android.Build.Tasks.Tests.dll --arch arm64 --filter 'FullyQualifiedName~CoreClrBootstrapBlobTests|FullyQualifiedName~AssemblyStoreElfWriterTests|FullyQualifiedName~TypeMapProguardTargetsTests' --logger 'console;verbosity=quiet' — 129 passed, 4 skipped.
  • ./dotnet-local.sh test bin/TestDebug/net10.0/Xamarin.Android.Build.Tests.dll --arch arm64 --filter 'FullyQualifiedName~GenerateJniRemappingNativeCodeTests|Name~UnchangedCoreClrBootstrapDoesNotRegenerateOnNextBuild|FullyQualifiedName~GenerateNativeApplicationConfigSourcesTests|FullyQualifiedName~GeneratePackageManagerJavaTests' --logger 'console;verbosity=quiet' — 18/18 passed, legacy XML generation, XCFG task contract and incremental recovery coverage.
  • ./dotnet-local.sh test bin/TestDebug/MSBuildDeviceIntegration/net10.0/MSBuildDeviceIntegration.dll --arch arm64 --filter 'Name~BuildWithoutRemappingKeepsOnlyCoreClrBootstrap|Name~MamRemappingTransitionsUpdatePackages|Name~MultiRidUsesOneR8Mapping|Name~ReservedBinaryBlobLibraryNameIsRejected' --logger 'console;verbosity=quiet' — 14/14 passed: APK/AAB, multi-RID, no-map, collision rejection, aliases, no-op, partial-output failure/stamp invalidation/retry, recovery and Clean. These are host-side build tests; no device calls were made. Windows execution was not performed; macOS results are not Windows evidence. No manual CI retry was requested.

Prior runtime validation on lower 58c264dc8dcfb90fe29a666db24db98989de951c, upper acf33f4e831497c81249c9aba36f29e238bb1d6f:

  • ADB_TARGET='-s emulator-5594' ANDROID_SERIAL=emulator-5594 ./dotnet-local.sh test bin/TestDebug/MSBuildDeviceIntegration/net10.0/MSBuildDeviceIntegration.dll --arch arm64 --filter 'Name~BuildWithoutRemappingKeepsOnlyCoreClrBootstrap|Name~MamRemappingTransitionsUpdatePackages|Name~MultiRidUsesOneR8Mapping|Name~CoreClrLargeBootstrapStartsInDebug' --logger 'console;verbosity=quiet' — 11/11 passed, including >64 KiB/5,000-property Debug/D8 startup.
  • ADB_TARGET='-s emulator-5594' ANDROID_SERIAL=emulator-5594 ./dotnet-local.sh test bin/TestRelease/MSBuildDeviceIntegration/net10.0/MSBuildDeviceIntegration.dll --arch arm64 --filter 'Name~ObfuscatedMembersRun|Name~NativeAotEmptyExplicitRemappingRuns' --logger 'console;verbosity=quiet' — 5/5 passed: Release/R8 CoreCLR and NativeAOT raw/Zstd startup and explicit-empty NativeAOT startup. These runtime results were not rerun on the latest head.

Both existing review threads were replied to and resolved. The removed lower remapping-blob fixture stays removed. Prior runtime validation used only the owned emulator, stopped afterward; no physical device or A16 benchmark was used. Native stack membership and base-branch chain were preserved without metadata recreation.

Copilot AI balanced review requested due to automatic review settings October 7, 2026 19:15
@simonrozsival
simonrozsival added this pull request to stack #13035 October 7, 2026 19:16

Copilot AI 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.

🟡 Changes recommended

Unresolved bootstrap validation and build-incrementality issues block approval.

2 open findings
What changed in this PR

Moves CoreCLR startup configuration from app-specific native globals into per-ABI binary blobs alongside JNI remapping. The assembly store remains separate, and NativeAOT remains remapping-only.

Changes:

  • Generate, validate, and package CoreCLR bootstrap data.
  • Load configuration during JNI_OnLoad and reuse the library handle for managed remapping.
  • Add serialization, packaging, cleanup, and large-configuration startup tests.
File Description
tests/​MSBuildDeviceIntegration/​Tests/​R8RuntimeRemappingTests.cs Tests startup with 5,000 runtime properties.
tests/​MSBuildDeviceIntegration/​Tests/​R8RuntimeRemappingBuildTests.cs Tests bootstrap packaging, recovery, and cleanup.
src/​Xamarin.Android.Build.Tasks/​Xamarin.Android.Common.targets Integrates bootstrap generation and output tracking.
src/​Xamarin.Android.Build.Tasks/​Xamarin.Android.Build.Tasks.csproj Includes the shared bootstrap serializer.
src/​Xamarin.Android.Build.Tasks/​Utilities/​ApplicationConfigNativeAssemblyGenerator.cs Builds bootstrap data and generic native placeholders.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​Utilities/​EnvironmentHelper.cs Reads bootstrap configuration in tests.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​Tasks/​GenerateNativeApplicationConfigSourcesTests.cs Tests binary configuration generation.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​BuildTest3.cs Reads preload expectations from bootstrap data.
src/​Xamarin.Android.Build.Tasks/​Tests/​Xamarin.Android.Build.Tests/​BuildTest.cs Reads assembly counts from bootstrap data.
src/​Xamarin.Android.Build.Tasks/​Tasks/​GenerateNativeApplicationConfigSources.cs Writes the bootstrap intermediate.
src/​Xamarin.Android.Build.Tasks/​Microsoft.Android.Sdk/​targets/​Microsoft.Android.Sdk.R8JniRemapping.targets Passes bootstrap data into blob packaging.
src/​native/​clr/​runtime-base/​android-system.cc Reads environment and system properties from bootstrap data.
src/​native/​clr/​libnet-android.map.txt Exports the shared-handle accessor.
src/​native/​clr/​include/​runtime-base/​monodroid-dl.hh Uses the bootstrap-backed native-library cache.
src/​native/​clr/​include/​runtime-base/​coreclr-bootstrap.hh Declares bootstrap state and accessors.
src/​native/​clr/​host/​host.cc Initializes and consumes bootstrap configuration.
src/​native/​clr/​host/​host-jni.cc Exposes the retained blob-library handle.
src/​native/​clr/​host/​coreclr-bootstrap.cc Loads, bounds-checks, and decompresses bootstrap data.
src/​native/​clr/​host/​CMakeLists.txt Compiles the bootstrap loader.
src/​Mono.Android/​Microsoft.Android.Runtime/​BinaryJniRemappingLookup.cs Reuses CoreCLR’s native library handle.
src/​Microsoft.Android.Build.Tasks/​Utilities/​JniRemappingBinaryBlob.cs Shares envelope generation between payload types.
src/​Microsoft.Android.Build.Tasks/​Utilities/​CoreClrBootstrapBlob.cs Serializes and validates bootstrap data.
src/​Microsoft.Android.Build.Tasks/​Tests/​Microsoft.Android.Build.Tasks.Tests/​GenerateJniRemappingBinaryBlobsTests.cs Tests multi-ABI packaging, compression, and malformed input.
src/​Microsoft.Android.Build.Tasks/​Tasks/​GenerateJniRemappingBinaryBlobs.cs Packages bootstrap and remapping symbols together.
Documentation/​docs-mobile/​messages/​xa4325.md Documents bootstrap-related build failures.

🧠 Review effort: Balanced

Comment thread src/Microsoft.Android.Build.Tasks/Utilities/CoreClrBootstrapBlob.cs Outdated
Comment thread src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets Outdated
@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-elf-bootstrap-blobs branch 13 times, most recently from 8568b14 to f8eae88 Compare October 8, 2026 14:40
simonrozsival and others added 11 commits October 8, 2026 19:30
Keep per-app CoreCLR startup data out of the generated native app
configuration.  Emit a validated bootstrap intermediate and assemble it
with JNI remapping as separate symbols in the same read-only ELF.

Load and bound the bootstrap payload during JNI_OnLoad, retaining its
DSO handle for managed remapping.  Preserve NativeAOT remapping and
validate packaging, preload aliases, incremental builds, and startup.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Move DSO cache ordering into the producer validator and avoid redundant eager bootstrap scans in JNI_OnLoad. Keep bounded mapped reads and allocation safeguards for native consumers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copy the fixed-size, build-validated header once into a typed layout and use named fields while leaving the mapped tables in place.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Move the mapped-property search into CoreClrBootstrap while preserving AndroidSystem debug bundled-property precedence and value-length behavior.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Move the mapped environment and system-property setup together into CoreClrBootstrap, leaving AndroidSystem to apply Debug override files afterward.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
simonrozsival and others added 6 commits October 8, 2026 19:30
Verify the bootstrap-only ELF and presence stamp, and update packaging and startup tests for the required CoreCLR library while NativeAOT omits empty remapping.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the bootstrap-only library in CoreCLR packages while NativeAOT removes its remapping-only library when obfuscation is disabled.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Share DSO hash/sort logic, use the XCFG intermediate for direct-task assertions, remove obsolete LLVM-config assertions and redundant CoreCLR empty-remap cases.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove the fallback that emitted app-specific LLVM configuration when the CoreCLR bootstrap path was absent. Validate the required output before generating anything and update direct task tests to exercise XCFG instead of legacy globals.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use the generation stamp as the incremental output when bootstrap bytes retain their timestamp. Invalidate the stamp if the CoreCLR bootstrap intermediate is deleted, and exercise edit/no-op and missing-file recovery.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove the prior package-manager completion stamp before any generation task mutates outputs. Recreate the stamp only after Java, XCFG and native source generation finish successfully.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@simonrozsival
simonrozsival force-pushed the simonrozsival-coreclr-elf-bootstrap-blobs branch from f8eae88 to ac5810c Compare October 8, 2026 17:43

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants