Skip to content

Commit e1f2198

Browse files
authored
[AOT] Fix for a compatibility issue between AOT and LLVM 14 (#6946)
* [AOT] Fix for a compatibility issue between AOT and LLVM 14 Context: https://releases.llvm.org/14.0.0/tools/lld/docs/ReleaseNotes.html#elf-improvements Context: 16bbf6f After switching to LLVM 14 we noticed that all `arm64` apps which use AOT, crash with the following assertion from the Mono runtime: * Assertion at /__w/1/s/src/mono/mono/mini/tramp-arm64.c:53, condition `((ins >> 24) & 0x1f) == 0x10' not met After investigation, it turns out that one of the LLVM 14 changes for the `aarch64` architecture in the `lld` linker was an optimization which modifies generated code in the following fashion (`-` is the "good" code, `+` is the "bad" one): - 13a44: 30 01 00 b0 adrp x16, 0x38000 <.text+0x148> - 13a48: 10 e2 3e 91 add x16, x16, #4024 // =4024 + 13a44: 1f 20 03 d5 nop + 13a48: 90 ab 12 10 adr x16, #152944 Mono AOT generates a pair of instructions, `adrp` and `add` and, at the runtime, it expects to find the exact code that was generated (runtime disassembles the binary code and looks for specific patterns), but instead it finds a `nop` and an `adr` instructions, which eventually triggers the above assertion. Code is modified in the way described above by the `lld` linker, according to this change in LLVM 14: The AArch64 port now supports adrp+ldr and adrp+add optimizations. --no-relax can suppress the optimization. Until Mono runtime code is fixed, we can work around this issue by passing the `--no-relax` flag to the native linker. * lld in the NDK doesn't support `--no-relax`
1 parent 5ed4a51 commit e1f2198

File tree

1 file changed

+22
-9
lines changed

1 file changed

+22
-9
lines changed

src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.Generic;
44
using System.IO;
55
using System.Linq;
6+
using System.Text;
67
using Java.Interop.Tools.Diagnostics;
78
using Microsoft.Android.Build.Tasks;
89
using Microsoft.Build.Framework;
@@ -252,7 +253,7 @@ protected void GetAotOptions (NdkTools ndk, AndroidTargetArch arch, int level, s
252253
string GetLdFlags(NdkTools ndk, AndroidTargetArch arch, int level, string toolPrefix)
253254
{
254255
var toolchainPath = toolPrefix.Substring (0, toolPrefix.LastIndexOf (Path.DirectorySeparatorChar));
255-
var ldFlags = string.Empty;
256+
var ldFlags = new StringBuilder ();
256257
if (EnableLLVM) {
257258
string androidLibPath = string.Empty;
258259
try {
@@ -291,19 +292,31 @@ string GetLdFlags(NdkTools ndk, AndroidTargetArch arch, int level, string toolPr
291292
libs.Add (Path.Combine (androidLibPath, "libc.so"));
292293
libs.Add (Path.Combine (androidLibPath, "libm.so"));
293294

294-
ldFlags = $"\\\"{string.Join ("\\\";\\\"", libs)}\\\"";
295-
}
295+
ldFlags.Append ($"\\\"{string.Join ("\\\";\\\"", libs)}\\\"");
296+
} else {
297+
if (ldFlags.Length > 0) {
298+
ldFlags.Append (' ');
299+
}
296300

297-
if (!StripLibraries) {
298-
return ldFlags;
301+
//
302+
// This flag is needed for Mono AOT to work correctly with the LLVM 14 `lld` linker due to the following change:
303+
//
304+
// The AArch64 port now supports adrp+ldr and adrp+add optimizations. --no-relax can suppress the optimization.
305+
//
306+
// Without the flag, `lld` will modify AOT-generated code in a way that the Mono runtime doesn't support. Until
307+
// the runtime issue is fixed, we need to pass this flag then.
308+
//
309+
ldFlags.Append ("--no-relax");
299310
}
300311

301-
const string StripFlag = "-s";
302-
if (ldFlags.Length == 0) {
303-
return StripFlag;
312+
if (StripLibraries) {
313+
if (ldFlags.Length > 0) {
314+
ldFlags.Append (' ');
315+
}
316+
ldFlags.Append ("-s");
304317
}
305318

306-
return $"{ldFlags} {StripFlag}";
319+
return ldFlags.ToString ();
307320
}
308321

309322
static string GetNdkToolchainLibraryDir (NdkTools ndk, string binDir, string archDir = null)

0 commit comments

Comments
 (0)