Skip to content

Commit 5e80e3e

Browse files
authored
[NativeAOT] ARM: Implement the EABI (#97604)
* ObjWriter/ARM: Emit EABI attributes section * Initial implementation of ARM EHABI * Add VPOP unwinding and optimized POP codes * Handle edge cases, add comments * Claim conformance with the Version5 EABI * Use array pool instead of direct allocation * Remove unused code * ARM: Produce unwind sections for each code section
1 parent a258bb9 commit 5e80e3e

File tree

14 files changed

+693
-64
lines changed

14 files changed

+693
-64
lines changed

src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp

+34-2
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,28 @@ struct Registers_REGDISPLAY : REGDISPLAY
355355
void setFP(uint32_t value, uint32_t location) { pR11 = (PTR_UIntNative)location;}
356356
};
357357

358+
struct ArmUnwindCursor : public libunwind::AbstractUnwindCursor
359+
{
360+
Registers_REGDISPLAY *_registers;
361+
public:
362+
ArmUnwindCursor(Registers_REGDISPLAY *registers) : _registers(registers) {}
363+
virtual bool validReg(int num) { return _registers->validRegister(num); }
364+
virtual unw_word_t getReg(int num) { return _registers->getRegister(num); }
365+
virtual void setReg(int num, unw_word_t value, unw_word_t location) { _registers->setRegister(num, value, location); }
366+
virtual unw_word_t getRegLocation(int num) {abort();}
367+
virtual bool validFloatReg(int num) { return _registers->validFloatRegister(num); }
368+
virtual unw_fpreg_t getFloatReg(int num) { return _registers->getFloatRegister(num); }
369+
virtual void setFloatReg(int num, unw_fpreg_t value) { _registers->setFloatRegister(num, value); }
370+
virtual int step(bool stage2 = false) {abort();}
371+
virtual void getInfo(unw_proc_info_t *) {abort();}
372+
virtual void jumpto() {abort();}
373+
virtual bool isSignalFrame() { return false; }
374+
virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off) {abort();}
375+
virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false) {abort();}
376+
virtual const char *getRegisterName(int num) {abort();}
377+
virtual void saveVFPAsX() {abort();}
378+
};
379+
358380
inline bool Registers_REGDISPLAY::validRegister(int num) const {
359381
if (num == UNW_REG_SP || num == UNW_ARM_SP)
360382
return true;
@@ -798,7 +820,14 @@ bool UnwindHelpers::StepFrame(REGDISPLAY *regs, unw_word_t start_ip, uint32_t fo
798820
}
799821

800822
#elif defined(_LIBUNWIND_ARM_EHABI)
801-
PORTABILITY_ASSERT("StepFrame");
823+
size_t len = 0;
824+
size_t off = 0;
825+
const uint32_t *ehtp = decode_eht_entry(reinterpret_cast<const uint32_t *>(unwind_info), &off, &len);
826+
ArmUnwindCursor unwindCursor((Registers_REGDISPLAY*)regs);
827+
if (_Unwind_VRS_Interpret((_Unwind_Context *)&unwindCursor, ehtp, off, len) != _URC_CONTINUE_UNWIND)
828+
{
829+
return false;
830+
}
802831
#else
803832
PORTABILITY_ASSERT("StepFrame");
804833
#endif
@@ -853,7 +882,10 @@ bool UnwindHelpers::GetUnwindProcInfo(PCODE pc, UnwindInfoSections &uwInfoSectio
853882
}
854883

855884
#elif defined(_LIBUNWIND_ARM_EHABI)
856-
PORTABILITY_ASSERT("GetUnwindProcInfo");
885+
if (uwInfoSections.arm_section == 0 || !uc.getInfoFromEHABISection(pc, uwInfoSections))
886+
{
887+
return false;
888+
}
857889
#else
858890
PORTABILITY_ASSERT("GetUnwindProcInfo");
859891
#endif

src/coreclr/tools/Common/Compiler/DependencyAnalysis/ObjectNodeSection.cs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public enum SectionType
1010
Executable,
1111
Uninitialized,
1212
Debug,
13+
UnwindData,
1314
}
1415

1516
/// <summary>

src/coreclr/tools/Common/Compiler/DependencyAnalysis/Relocation.cs

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ public enum RelocType
5353
IMAGE_REL_AARCH64_TLSLE_ADD_TPREL_HI12 = 0x10B,
5454
IMAGE_REL_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 0x10C,
5555

56+
// Linux arm32
57+
IMAGE_REL_ARM_PREL31 = 0x10D,
58+
5659
//
5760
// Relocations for R2R image production
5861
//
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace ILCompiler.ObjectWriter
5+
{
6+
/// <summary>
7+
/// JIT enum used in the CFI code blob.
8+
/// </summary>
9+
internal enum CFI_OPCODE
10+
{
11+
CFI_ADJUST_CFA_OFFSET, // Offset is adjusted relative to the current one.
12+
CFI_DEF_CFA_REGISTER, // New register is used to compute CFA
13+
CFI_REL_OFFSET, // Register is saved at offset from the current CFA
14+
CFI_DEF_CFA // Take address from register and add offset to it.
15+
}
16+
}

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

-8
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,6 @@ public DwarfFde(
3636
PersonalitySymbolName = personalitySymbolName;
3737
}
3838

39-
private enum CFI_OPCODE
40-
{
41-
CFI_ADJUST_CFA_OFFSET, // Offset is adjusted relative to the current one.
42-
CFI_DEF_CFA_REGISTER, // New register is used to compute CFA
43-
CFI_REL_OFFSET, // Register is saved at offset from the current CFA
44-
CFI_DEF_CFA // Take address from register and add offset to it.
45-
}
46-
4739
/// <summary>
4840
/// Convert JIT version of CFI blob into the the DWARF byte code form.
4941
/// </summary>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Buffers;
6+
using System.Buffers.Binary;
7+
using System.Collections.Generic;
8+
using System.Diagnostics;
9+
using System.IO;
10+
using System.Text;
11+
12+
using static ILCompiler.ObjectWriter.EabiNative;
13+
14+
namespace ILCompiler.ObjectWriter
15+
{
16+
/// <summary>
17+
/// Builder class for constructing the .ARM.attributes table that
18+
/// describes the parameters of the emitted ARM code for use by the
19+
/// linker or debugger.
20+
/// </summary>
21+
internal sealed class EabiAttributesBuilder
22+
{
23+
private readonly SectionWriter _sectionWriter;
24+
private long _sectionSizePosition;
25+
private byte[] _sectionSize;
26+
private long _subsectionSizePosition;
27+
private byte[] _subsectionSize;
28+
29+
public EabiAttributesBuilder(SectionWriter sectionWriter)
30+
{
31+
_sectionWriter = sectionWriter;
32+
33+
// Version
34+
_sectionWriter.WriteByte(0x41);
35+
}
36+
37+
public void StartSection(string vendor)
38+
{
39+
Debug.Assert(_sectionSize is null);
40+
Debug.Assert(_subsectionSize is null);
41+
42+
_sectionSizePosition = _sectionWriter.Position;
43+
_sectionSize = new byte[4];
44+
_sectionWriter.EmitData(_sectionSize);
45+
46+
_sectionWriter.WriteUtf8String(vendor);
47+
48+
_sectionWriter.WriteByte((byte)Tag_File);
49+
50+
_subsectionSizePosition = _sectionWriter.Position;
51+
_subsectionSize = new byte[4];
52+
_sectionWriter.EmitData(_subsectionSize);
53+
}
54+
55+
public void EndSection()
56+
{
57+
Debug.Assert(_sectionSize is not null);
58+
Debug.Assert(_subsectionSize is not null);
59+
60+
BinaryPrimitives.WriteUInt32LittleEndian(_subsectionSize, (uint)(_sectionWriter.Position - _subsectionSizePosition));
61+
BinaryPrimitives.WriteUInt32LittleEndian(_sectionSize, (uint)(_sectionWriter.Position - _sectionSizePosition));
62+
63+
_sectionSize = null;
64+
_subsectionSize = null;
65+
}
66+
67+
public void WriteAttribute(uint tag, ulong value)
68+
{
69+
Debug.Assert(_subsectionSize is not null);
70+
71+
_sectionWriter.WriteULEB128(tag);
72+
_sectionWriter.WriteULEB128(value);
73+
}
74+
75+
public void WriteAttribute(uint tag, string value)
76+
{
77+
Debug.Assert(_subsectionSize is not null);
78+
79+
_sectionWriter.WriteULEB128(tag);
80+
_sectionWriter.WriteUtf8String(value);
81+
}
82+
}
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
6+
namespace ILCompiler.ObjectWriter
7+
{
8+
/// <summary>
9+
/// Native constants and enumerations for ARM EABI binary format.
10+
/// </summary>
11+
internal static class EabiNative
12+
{
13+
public const uint Tag_File = 1;
14+
public const uint Tag_CPU_raw_name = 4;
15+
public const uint Tag_CPU_name = 5;
16+
public const uint Tag_CPU_arch = 6;
17+
public const uint Tag_CPU_arch_profile = 7;
18+
public const uint Tag_ARM_ISA_use = 8;
19+
public const uint Tag_THUMB_ISA_use = 9;
20+
public const uint Tag_FP_arch = 10;
21+
public const uint Tag_ABI_PCS_R9_use = 14;
22+
public const uint Tag_ABI_PCS_RW_data = 15;
23+
public const uint Tag_ABI_PCS_RO_data = 16;
24+
public const uint Tag_ABI_PCS_GOT_use = 17;
25+
public const uint Tag_ABI_PCS_wchar_t = 18;
26+
public const uint Tag_ABI_FP_rounding = 19;
27+
public const uint Tag_ABI_FP_denormal = 20;
28+
public const uint Tag_ABI_FP_exceptions = 21;
29+
public const uint Tag_ABI_FP_user_exceptions = 22;
30+
public const uint Tag_ABI_FP_number_model = 23;
31+
public const uint Tag_ABI_align_needed = 24;
32+
public const uint Tag_ABI_align_preserved = 25;
33+
public const uint Tag_ABI_enum_size = 26;
34+
public const uint Tag_ABI_optimization_goals = 30;
35+
public const uint Tag_CPU_unaligned_access = 34;
36+
public const uint Tag_ABI_FP_16bit_format = 38;
37+
public const uint Tag_conformance = 67;
38+
}
39+
}

0 commit comments

Comments
 (0)