diff --git a/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc b/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc index e37614b660c32f..b1a437d8b57ead 100644 --- a/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc +++ b/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosamd64.inc @@ -33,7 +33,12 @@ C_FUNC(\Name): .endm .macro ALTERNATE_ENTRY Name +#if defined(__APPLE__) + .alt_entry C_FUNC(\Name) + .private_extern C_FUNC(\Name) +#else .global C_FUNC(\Name) +#endif C_FUNC(\Name): .endm diff --git a/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosarm64.inc b/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosarm64.inc index fc19d451640f43..a02a770aa3b0af 100644 --- a/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosarm64.inc +++ b/src/coreclr/nativeaot/Runtime/unix/unixasmmacrosarm64.inc @@ -24,8 +24,11 @@ C_FUNC(\Name): .endm .macro ALTERNATE_ENTRY Name +#if defined(__APPLE__) + .alt_entry C_FUNC(\Name) + .private_extern C_FUNC(\Name) +#else .global C_FUNC(\Name) -#if !defined(__APPLE__) .hidden C_FUNC(\Name) #endif C_FUNC(\Name): diff --git a/src/coreclr/pal/inc/unixasmmacrosarm64.inc b/src/coreclr/pal/inc/unixasmmacrosarm64.inc index 976cc825f2eb40..4997e18b39858a 100644 --- a/src/coreclr/pal/inc/unixasmmacrosarm64.inc +++ b/src/coreclr/pal/inc/unixasmmacrosarm64.inc @@ -17,7 +17,12 @@ .endm .macro PATCH_LABEL Name +#if defined(__APPLE__) + .alt_entry C_FUNC(\Name) + .private_extern C_FUNC(\Name) +#else .global C_FUNC(\Name) +#endif C_FUNC(\Name): .endm diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs index cecffda8bfe537..89dbcb463a2bf8 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs @@ -43,6 +43,17 @@ public bool IsStandardSection } } + /// + /// Returns true if the section contains regular data (as opposed to code, debug info or unwinding data) + /// + public bool IsDataSection + { + get + { + return Type is SectionType.ReadOnly or SectionType.Writeable or SectionType.Uninitialized; + } + } + public static readonly ObjectNodeSection XDataSection = new ObjectNodeSection("xdata", SectionType.ReadOnly); public static readonly ObjectNodeSection DataSection = new ObjectNodeSection("data", SectionType.Writeable); public static readonly ObjectNodeSection ReadOnlyDataSection = new ObjectNodeSection("rdata", SectionType.ReadOnly); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachNative.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachNative.cs index 9c4f07c866cfc7..f9cda2cfc482a6 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachNative.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachNative.cs @@ -96,6 +96,7 @@ internal static class MachNative public const byte N_INDR = 0xA; public const byte N_SECT = 0xE; public const byte N_PBUD = 0xC; + public const byte N_PEXT = 0x10; // Symbol descriptor flags public const ushort REFERENCE_FLAG_UNDEFINED_NON_LAZY = 0; @@ -106,6 +107,7 @@ internal static class MachNative public const ushort REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY = 5; public const ushort REFERENCED_DYNAMICALLY = 0x10; public const ushort N_NO_DEAD_STRIP = 0x20; + public const ushort N_ALT_ENTRY = 0x200; public const ushort N_WEAK_REF = 0x40; public const ushort N_WEAK_DEF = 0x80; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs index 3001640249d44b..3398489039b52b 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs @@ -113,7 +113,7 @@ private protected override void EmitSectionsAndLayout() Name = $"lsection{sectionIndex}", Section = section, Value = section.VirtualAddress, - Descriptor = 0, + Descriptor = (ushort)(section.KeepDataLayout ? N_NO_DEAD_STRIP : 0), Type = N_SECT, }; _symbolTable.Add(machSymbol); @@ -355,6 +355,7 @@ private protected override void CreateSection(ObjectNodeSection section, string { Log2Alignment = 1, Flags = flags, + KeepDataLayout = section.IsDataSection }; int sectionIndex = _sections.Count; @@ -472,6 +473,10 @@ private protected override void EmitSymbolTable( // Sort and insert all defined symbols var sortedDefinedSymbols = new List(definedSymbols.Count); + // We emit a local N_NO_DEAD_STRIP symbol for the beginning of all sections marked with + // KeepDataLayout to ensure the final layout is kept intact by the linker. This works in + // tandem with setting the N_ALT_ENTRY flag for all other symbols in the same section in + // the loop below. foreach ((string name, SymbolDefinition definition) in definedSymbols) { MachSection section = _sections[definition.SectionIndex]; @@ -483,8 +488,8 @@ private protected override void EmitSymbolTable( Name = name, Section = section, Value = section.VirtualAddress + (ulong)definition.Value, - Descriptor = N_NO_DEAD_STRIP, - Type = N_SECT | N_EXT, + Descriptor = (ushort)(section.KeepDataLayout || definition.AltEntry ? N_ALT_ENTRY | N_NO_DEAD_STRIP : N_NO_DEAD_STRIP), + Type = (byte)(N_SECT | N_EXT | (definition.Global ? 0 : N_PEXT)), }); } sortedDefinedSymbols.Sort((symA, symB) => string.CompareOrdinal(symA.Name, symB.Name)); @@ -496,7 +501,7 @@ private protected override void EmitSymbolTable( } _dySymbolTable.ExternalSymbolsIndex = _dySymbolTable.LocalSymbolsCount; - _dySymbolTable.ExternalSymbolsCount = (uint)definedSymbols.Count; + _dySymbolTable.ExternalSymbolsCount = (uint)sortedDefinedSymbols.Count; uint savedSymbolIndex = symbolIndex; foreach (string externSymbol in undefinedSymbols) @@ -883,6 +888,7 @@ private sealed class MachSection public bool IsInFile => Size > 0 && Type != S_ZEROFILL && Type != S_GB_ZEROFILL && Type != S_THREAD_LOCAL_ZEROFILL; public bool IsDwarfSection { get; } + public bool KeepDataLayout { get; set; } public IList Relocations => relocationCollection ??= new List(); public Stream Stream => dataStream; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ObjectWriter.cs index b3203d08b0d6fd..1549b8710ffea7 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ObjectWriter.cs @@ -18,7 +18,7 @@ namespace ILCompiler.ObjectWriter { public abstract class ObjectWriter { - private protected sealed record SymbolDefinition(int SectionIndex, long Value, int Size = 0, bool Global = false); + private protected sealed record SymbolDefinition(int SectionIndex, long Value, int Size = 0, bool Global = false, bool AltEntry = false); private protected sealed record SymbolicRelocation(long Offset, RelocType Type, string SymbolName, long Addend = 0); private protected sealed record BlockToRelocate(int SectionIndex, long Offset, byte[] Data, Relocation[] Relocations); @@ -246,11 +246,12 @@ protected internal void EmitSymbolDefinition( string symbolName, long offset = 0, int size = 0, - bool global = false) + bool global = false, + bool altEntry = false) { _definedSymbols.Add( symbolName, - new SymbolDefinition(sectionIndex, offset, size, global)); + new SymbolDefinition(sectionIndex, offset, size, global, altEntry)); } /// @@ -414,14 +415,17 @@ private void EmitObject(string objectFilePath, IReadOnlyCollection