Skip to content

Commit c7b4984

Browse files
committed
Comments, more cleanup
1 parent e3499e3 commit c7b4984

File tree

10 files changed

+135
-27
lines changed

10 files changed

+135
-27
lines changed

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/CoffObjectWriter.cs

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,30 @@
2424

2525
namespace ILCompiler.ObjectWriter
2626
{
27+
/// <summary>
28+
/// COFF object file format writer for Windows targets.
29+
/// </summary>
30+
/// <remarks>
31+
/// The PE/COFF object format is described in the official specifciation at
32+
/// https://learn.microsoft.com/en-us/windows/win32/debug/pe-format. However,
33+
/// numerous extensions are missing in the specification. The most notable
34+
/// ones are listed below.
35+
///
36+
/// Object files with more than 65279 sections use an extended big object
37+
/// file format that is recognized by the Microsoft linker. Many of the
38+
/// internal file structures are different. The code below denotes it by
39+
/// "BigObj" in parameters and variables.
40+
///
41+
/// Section names longer than 8 bytes need to be written indirectly in the
42+
/// string table. The PE/COFF specification describes the /NNNNNNN syntax
43+
/// for referencing them. However, if the string table gets big enough the
44+
/// syntax no longer works. There's an undocumented //BBBBBB syntax where
45+
/// base64 offset is used instead.
46+
///
47+
/// CodeView debugging format uses 16-bit section index relocations. Once
48+
/// the number of sections exceeds 2^16 the same file format is still used.
49+
/// The linker treats the CodeView relocations symbolically.
50+
/// </remarks>
2751
internal sealed class CoffObjectWriter : ObjectWriter
2852
{
2953
private sealed record SectionDefinition(CoffSectionHeader Header, Stream Stream, List<CoffRelocation> Relocations, string ComdatName, string SymbolName);
@@ -446,24 +470,26 @@ private protected override void EmitUnwindInfo(
446470
MethodExceptionHandlingInfoNode ehInfo = nodeWithCodeInfo.EHInfo;
447471
ISymbolNode associatedDataNode = nodeWithCodeInfo.GetAssociatedDataNode(_nodeFactory) as ISymbolNode;
448472

449-
flags |= ehInfo != null ? FrameInfoFlags.HasEHInfo : 0;
450-
flags |= associatedDataNode != null ? FrameInfoFlags.HasAssociatedData : 0;
473+
flags |= ehInfo is not null ? FrameInfoFlags.HasEHInfo : 0;
474+
flags |= associatedDataNode is not null ? FrameInfoFlags.HasAssociatedData : 0;
451475

452476
xdataSectionWriter.WriteByte((byte)flags);
453477

454-
if (associatedDataNode != null)
478+
if (associatedDataNode is not null)
455479
{
456-
string symbolName = GetMangledName(associatedDataNode);
457-
xdataSectionWriter.EmitSymbolReference(RelocType.IMAGE_REL_BASED_ADDR32NB, symbolName, 0);
480+
xdataSectionWriter.EmitSymbolReference(
481+
RelocType.IMAGE_REL_BASED_ADDR32NB,
482+
GetMangledName(associatedDataNode));
458483
}
459484

460-
if (ehInfo != null)
485+
if (ehInfo is not null)
461486
{
462-
string symbolName = GetMangledName(ehInfo);
463-
xdataSectionWriter.EmitSymbolReference(RelocType.IMAGE_REL_BASED_ADDR32NB, symbolName, 0);
487+
xdataSectionWriter.EmitSymbolReference(
488+
RelocType.IMAGE_REL_BASED_ADDR32NB,
489+
GetMangledName(ehInfo));
464490
}
465491

466-
if (nodeWithCodeInfo.GCInfo != null)
492+
if (nodeWithCodeInfo.GCInfo is not null)
467493
{
468494
xdataSectionWriter.Write(nodeWithCodeInfo.GCInfo);
469495
}
@@ -483,10 +509,6 @@ private protected override void EmitUnwindInfo(
483509
}
484510
}
485511

486-
private protected override void EmitSectionsAndLayout()
487-
{
488-
}
489-
490512
private protected override void EmitObjectFile(string objectFilePath)
491513
{
492514
using var outputFileStream = new FileStream(objectFilePath, FileMode.Create);
@@ -1049,8 +1071,15 @@ private sealed class CoffStringTable : StringTableBuilder
10491071
}
10501072
}
10511073

1074+
/// <summary>
1075+
/// Checksum algorithm used for COMDAT sections. This is similar to standard
1076+
/// CRC32 but starts with 0 as initial value instead of ~0.
1077+
/// </summary>
10521078
private static class JamCrc32
10531079
{
1080+
// NOTE:
1081+
// This can be generated by Crc32ReflectedTable.Generate(0xEDB88320u);
1082+
// We embed the pre-generated version since it's small.
10541083
private static uint[] Table =
10551084
{
10561085
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfNative.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,30 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
namespace ILCompiler.ObjectWriter
44
{
5+
/// <summary>
6+
/// Native constants for the ELF file format.
7+
/// </summary>
58
internal static class ElfNative
69
{
10+
// ELF version
711
public const byte EV_CURRENT = 1;
812

13+
// File type
914
public const ushort ET_REL = 1;
1015

16+
// File bitness
1117
public const byte ELFCLASS32 = 1;
1218
public const byte ELFCLASS64 = 2;
1319

20+
// File endianness
1421
public const byte ELFDATA2LSB = 1;
1522

23+
// Architecture
1624
public const ushort EM_386 = 3;
1725
public const ushort EM_X86_64 = 62;
1826
public const ushort EM_AARCH64 = 183;
1927

28+
// Section header type
2029
public const uint SHT_NULL = 0;
2130
public const uint SHT_PROGBITS = 1;
2231
public const uint SHT_SYMTAB = 2;
@@ -36,6 +45,7 @@ internal static class ElfNative
3645
public const uint SHT_SYMTAB_SHNDX = 18;
3746
public const uint SHT_IA_64_UNWIND = 1879048193;
3847

48+
// Section header flags
3949
public const uint SHF_WRITE = 1;
4050
public const uint SHF_ALLOC = 2;
4151
public const uint SHF_EXECINSTR = 4;
@@ -48,10 +58,12 @@ internal static class ElfNative
4858
public const uint SHF_TLS = 1024;
4959
public const uint SHF_COMPRESSED = 2048;
5060

61+
// Section header special index numbers
5162
public const uint SHN_UNDEF = 0;
5263
public const uint SHN_LORESERVE = 65280;
5364
public const uint SHN_XINDEX = 65535;
5465

66+
// Symbol type
5567
public const byte STT_NOTYPE = 0;
5668
public const byte STT_OBJECT = 1;
5769
public const byte STT_FUNC = 2;
@@ -60,15 +72,18 @@ internal static class ElfNative
6072
public const byte STT_COMMON = 5;
6173
public const byte STT_TLS = 6;
6274

75+
// Symbol visibility
6376
public const byte STV_DEFAULT = 0;
6477
public const byte STV_INTERNAL = 1;
6578
public const byte STV_HIDDEN = 2;
6679
public const byte STV_PROTECTED = 3;
6780

81+
// Symbol binding
6882
public const byte STB_LOCAL = 0;
6983
public const byte STB_GLOBAL = 1;
7084
public const byte STB_WEAK = 2;
7185

86+
// Relocations (x86)
7287
public const uint R_386_NONE = 0;
7388
public const uint R_386_32 = 1;
7489
public const uint R_386_PC32 = 2;
@@ -111,6 +126,7 @@ internal static class ElfNative
111126
public const uint R_386_TLS_DESC = 41;
112127
public const uint R_386_IRELATIVE = 42;
113128

129+
// Relocations (x64)
114130
public const uint R_X86_64_NONE = 0;
115131
public const uint R_X86_64_64 = 1;
116132
public const uint R_X86_64_PC32 = 2;
@@ -151,6 +167,7 @@ internal static class ElfNative
151167
public const uint R_X86_64_IRELATIVE = 37;
152168
public const uint R_X86_64_RELATIVE64 = 38;
153169

170+
// Relocations (arm64)
154171
public const uint R_AARCH64_NONE = 0;
155172
public const uint R_AARCH64_P32_ABS32 = 1;
156173
public const uint R_AARCH64_P32_COPY = 180;

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ElfObjectWriter.cs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@
1313

1414
namespace ILCompiler.ObjectWriter
1515
{
16+
/// <summary>
17+
/// ELF object file format writer for Linux/Unix targets.
18+
/// </summary>
19+
/// <remarks>
20+
/// ELF object format is described by the official specification hosted
21+
/// at https://refspecs.linuxfoundation.org/elf/elf.pdf. Different
22+
/// architectures specify the details in the ABI specification.
23+
///
24+
/// Like COFF there are several quirks related to large number of sections
25+
/// (> 65279). Some of the fields in the ELF file header are moved to the
26+
/// first (NULL) section header. The symbol table that is normally a single
27+
/// section in the file is extended with a second .symtab_shndx section
28+
/// to accomodate the section indexes that don't fit within the regular
29+
/// section number field.
30+
/// </remarks>
1631
internal sealed class ElfObjectWriter : UnixObjectWriter
1732
{
1833
private readonly ushort _machine;
@@ -249,6 +264,9 @@ private protected override void EmitRelocations(int sectionIndex, List<SymbolicR
249264

250265
private void EmitRelocationsX86(int sectionIndex, List<SymbolicRelocation> relocationList)
251266
{
267+
// TODO: We are emitting .rela sections on x86 which is technically wrong. We should be
268+
// using .rel sections with the addend embedded in the data. Since x86 is not an officially
269+
// supported platform this is left for future enhancement.
252270
if (relocationList.Count > 0)
253271
{
254272
Span<byte> relocationEntry = stackalloc byte[12];
@@ -351,10 +369,6 @@ private void EmitRelocationsARM64(int sectionIndex, List<SymbolicRelocation> rel
351369
}
352370
}
353371

354-
private protected override void EmitSectionsAndLayout()
355-
{
356-
}
357-
358372
private protected override void EmitObjectFile(string objectFilePath)
359373
{
360374
using var outputFileStream = new FileStream(objectFilePath, FileMode.Create);

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachNative.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
namespace ILCompiler.ObjectWriter
44
{
5+
/// <summary>
6+
/// Native constants for the Mach-O file format.
7+
/// </summary>
58
internal static class MachNative
69
{
710
public const uint MH_MAGIC_64 = 0xfeedfacf;

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/MachObjectWriter.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,42 @@
1616

1717
namespace ILCompiler.ObjectWriter
1818
{
19+
/// <summary>
20+
/// Mach-O object file format writer for Apple macOS and iOS-like targets.
21+
/// </summary>
22+
/// <remarks>
23+
/// Old version of the Mach-O file format specification is mirrored at
24+
/// https://github.com/aidansteele/osx-abi-macho-file-format-reference.
25+
///
26+
/// There are some notable differences when compared to ELF or COFF:
27+
/// - The maximum number of sections in object file is limited to 255.
28+
/// - Sections are subdivided by their symbols and treated by the
29+
/// linker as subsections (often referred to as atoms by the linker).
30+
///
31+
/// The consequences of these design decisions is the COMDAT sections are
32+
/// modeled in entirely different way. Dead code elimination works on the
33+
/// atom level, so relative relocations within the same section have to be
34+
/// preserved.
35+
///
36+
/// Debug information uses the standard DWARF format. It is, however, not
37+
/// linked into the intermediate executable files. Instead the linker creates
38+
/// a map between the final executable and the object files. Debuggers like
39+
/// lldb then use this map to read the debug information from the object
40+
/// file directly. As a consequence the DWARF information is not generated
41+
/// with relocations for the DWARF sections themselves since it's never
42+
/// needed.
43+
///
44+
/// While Mach-O uses the DWARF exception handling information for unwind
45+
/// tables it also supports a compact representation for common prolog types.
46+
/// Unofficial reference of the format can be found at
47+
/// https://faultlore.com/blah/compact-unwinding/. It's necessary to emit
48+
/// at least the stub entries pointing to the DWARF information but due
49+
/// to limits in the linked file format it's advisable to use the compact
50+
/// encoding whenever possible.
51+
///
52+
/// The Apple linker is extremely picky in which relocation types are allowed
53+
/// inside the DWARF sections, both for debugging and exception handling.
54+
/// </remarks>
1955
internal sealed class MachObjectWriter : UnixObjectWriter
2056
{
2157
private sealed record CompactUnwindCode(string PcStartSymbolName, uint PcLength, uint Code, string LsdaSymbolName = null, string PersonalitySymbolName = null);

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/ObjectWriter.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,9 @@ private protected uint GetVarTypeIndex(bool isStateMachineMoveNextMethod, DebugV
288288
return typeIndex;
289289
}
290290

291-
private protected abstract void EmitSectionsAndLayout();
291+
private protected virtual void EmitSectionsAndLayout()
292+
{
293+
}
292294

293295
private protected abstract void EmitObjectFile(string objectFilePath);
294296

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/SectionData.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ namespace ILCompiler.ObjectWriter
1616
/// Optimized append-only structure for writing sections.
1717
/// </summary>
1818
/// <remarks>
19-
/// Implements a stream of chained buffers. It supports appending existing
20-
/// read-only buffers without copying.
19+
/// The section data are kept in memory as a list of buffers. It supports
20+
/// appending existing read-only buffers without copying (such as buffer
21+
/// from ObjectNode.ObjectData).
2122
/// </remarks>
2223
internal sealed class SectionData
2324
{
@@ -68,6 +69,9 @@ public void AppendPadding(int paddingLength)
6869

6970
public long Length => _length + _appendBuffer.WrittenCount;
7071

72+
/// <summary>
73+
/// Gets a read-only stream accessing the section data.
74+
/// </summary>
7175
public Stream GetReadStream() => new ReadStream(this);
7276

7377
private sealed class ReadStream : Stream

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/SectionWriter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace ILCompiler.ObjectWriter
1111
{
12-
public struct SectionWriter
12+
internal struct SectionWriter
1313
{
1414
private readonly ObjectWriter _objectWriter;
1515
private readonly SectionData _sectionData;

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/StringTableBuilder.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ public void ReserveString(string text)
4242

4343
private void FlushReservedStrings()
4444
{
45-
// TODO: Use CollectionsMarshal.AsSpan
4645
string[] reservedStrings = _reservedStrings.ToArray();
4746

4847
// Pre-sort the string based on their matching suffix

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/ObjectWriter/UnixObjectWriter.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
namespace ILCompiler.ObjectWriter
1414
{
15+
/// <summary>
16+
/// Base implementation for ELF and Mach-O object file format writers. Implements
17+
/// the common code for DWARF debugging and exception handling information.
18+
/// </summary>
1519
internal abstract class UnixObjectWriter : ObjectWriter
1620
{
1721
private sealed record UnixSectionDefinition(string SymbolName, Stream SectionStream);
@@ -115,24 +119,24 @@ private protected override void EmitUnwindInfo(
115119
MethodExceptionHandlingInfoNode ehInfo = nodeWithCodeInfo.EHInfo;
116120
ISymbolNode associatedDataNode = nodeWithCodeInfo.GetAssociatedDataNode(_nodeFactory) as ISymbolNode;
117121

118-
flags |= ehInfo != null ? FrameInfoFlags.HasEHInfo : 0;
119-
flags |= associatedDataNode != null ? FrameInfoFlags.HasAssociatedData : 0;
122+
flags |= ehInfo is not null ? FrameInfoFlags.HasEHInfo : 0;
123+
flags |= associatedDataNode is not null ? FrameInfoFlags.HasAssociatedData : 0;
120124

121125
lsdaSectionWriter.WriteByte((byte)flags);
122126

123-
if (associatedDataNode != null)
127+
if (associatedDataNode is not null)
124128
{
125129
string symbolName = GetMangledName(associatedDataNode);
126130
lsdaSectionWriter.EmitSymbolReference(RelocType.IMAGE_REL_BASED_RELPTR32, symbolName, 0);
127131
}
128132

129-
if (ehInfo != null)
133+
if (ehInfo is not null)
130134
{
131135
string symbolName = GetMangledName(ehInfo);
132136
lsdaSectionWriter.EmitSymbolReference(RelocType.IMAGE_REL_BASED_RELPTR32, symbolName, 0);
133137
}
134138

135-
if (nodeWithCodeInfo.GCInfo != null)
139+
if (nodeWithCodeInfo.GCInfo is not null)
136140
{
137141
lsdaSectionWriter.Write(nodeWithCodeInfo.GCInfo);
138142
}

0 commit comments

Comments
 (0)