Skip to content

Commit

Permalink
[NativeAOT] 32-bit platform ObjWriter and bit rot fixes (#96890)
Browse files Browse the repository at this point in the history
* Use PC-relative relocations for ARMEmitter.EmitMOV(dest, symbol)

* Fix handling of signed offsets in IMAGE_REL_BASED_THUMB_BRANCH24 calculations

* Generate position independent code in NativeAOT on linux-arm

* Handle ARM32 in DwarfCie

* Fix relocations emitted in 32-bit ELF for x86/arm32; apply correct addends to account for R2R ABI differences; use inline addend for 32-bit platforms; mark function symbols as Thumb code on ARM

* ELF/ARM32: Emit thumb mapping symbols for executable sections

* Try to revert ARMEmitter.EmitMOV

* Convert IMAGE_REL_BASED_THUMB_MOV32_PCREL to ELF with the same offset as R2R

* Unoptimal, but working, version of INLINE_GET_TLS_VAR for ARM32

* Use PC-relative relocations for ARMEmitter.EmitMOV(dest, symbol)

* Fat function pointers are not function symbols as far as ELF is concerned; the should not get the symbol size or the Thumb bit

* Fix some bits and pieces of the ARM unwinding code

* Don't try to use ObjWriter package on unsupported platforms

* Generate valid ARM32 DWARF unwind info in JIT

* Handle negative offsets in CFI_REL_OFFSET conversion (unused at the moment)

* Add linux-arm support to cross-compile targets

* Update src/coreclr/nativeaot/Runtime/unix/unixasmmacrosarm.inc

Co-authored-by: Jan Kotas <jkotas@microsoft.com>

* Update ObjectWriter.cs

Co-authored-by: Michal Strehovský <MichalStrehovsky@users.noreply.github.com>

* Fix the order of register push in CFI unwind codes on ARM.

* Make jit-format happy without making the code look ugly

---------

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Co-authored-by: Michal Strehovský <MichalStrehovsky@users.noreply.github.com>
  • Loading branch information
3 people committed Jan 17, 2024
1 parent f2c3541 commit 1a985d9
Show file tree
Hide file tree
Showing 16 changed files with 210 additions and 156 deletions.
33 changes: 14 additions & 19 deletions src/coreclr/jit/unwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,17 +165,11 @@ void Compiler::unwindPushPopCFI(regNumber reg)
#endif
;

createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, REGSIZE_BYTES);
if (relOffsetMask & genRegMask(reg))
{
#ifndef TARGET_ARM
createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, REGSIZE_BYTES);
#endif
createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg));
}
else
{
createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, REGSIZE_BYTES);
}
}

typedef jitstd::vector<CFI_CODE> CFICodeVector;
Expand Down Expand Up @@ -203,19 +197,20 @@ void Compiler::unwindBegPrologCFI()

void Compiler::unwindPushPopMaskCFI(regMaskTP regMask, bool isFloat)
{
regMaskTP regBit = isFloat ? genRegMask(REG_FP_FIRST) : 1;
#if TARGET_ARM
regNumber regNum = isFloat ? REG_PREV(REG_FP_LAST) : REG_INT_LAST;
regMaskTP regBit = isFloat ? genRegMask(regNum) | genRegMask(REG_NEXT(regNum)) : genRegMask(regNum);
#else
regNumber regNum = isFloat ? REG_FP_LAST : REG_INT_LAST;
regMaskTP regBit = genRegMask(regNum);
#endif

regNumber regNum = isFloat ? REG_FP_FIRST : REG_FIRST;
for (; regNum < REG_COUNT;)
for (; regMask != 0 && regBit != RBM_NONE;)
{
if (regBit > regMask)
{
break;
}

if (regBit & regMask)
{
unwindPushPopCFI(regNum);
regMask &= ~regBit;
}

#if TARGET_ARM
Expand All @@ -224,11 +219,11 @@ void Compiler::unwindPushPopMaskCFI(regMaskTP regMask, bool isFloat)
// because LLVM only know about D0-D31.
// As such pairs Sx,Sx+1 are referenced as D0-D15 registers in DWARF
// For that we process registers in pairs.
regNum = isFloat ? REG_NEXT(REG_NEXT(regNum)) : REG_NEXT(regNum);
regBit <<= isFloat ? 2 : 1;
regBit >>= isFloat ? 2 : 1;
regNum = isFloat ? REG_PREV(REG_PREV(regNum)) : REG_PREV(regNum);
#else
regNum = REG_NEXT(regNum);
regBit <<= 1;
regBit >>= 1;
regNum = REG_PREV(regNum);
#endif
}
}
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/jit/unwindarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,6 @@ void Compiler::unwindPushMaskInt(regMaskTP maskInt)
if (generateCFIUnwindCodes())
{
// If we are pushing LR, we should give unwind codes in terms of caller's PC
if (maskInt & RBM_LR)
{
maskInt = (maskInt & ~RBM_LR) | RBM_PC;
}
unwindPushPopMaskCFI(maskInt, false);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@ The .NET Foundation licenses this file to you under the MIT license.
<CrossCompileArch Condition="$(CrossCompileRid.EndsWith('-x64'))">x86_64</CrossCompileArch>
<CrossCompileArch Condition="$(CrossCompileRid.EndsWith('-arm64')) and '$(_IsApplePlatform)' != 'true'">aarch64</CrossCompileArch>
<CrossCompileArch Condition="$(CrossCompileRid.EndsWith('-arm64')) and '$(_IsApplePlatform)' == 'true'">arm64</CrossCompileArch>
<CrossCompileArch Condition="$(CrossCompileRid.EndsWith('-arm'))">arm</CrossCompileArch>

<CrossCompileAbi>gnu</CrossCompileAbi>
<CrossCompileAbi Condition="$(CrossCompileRid.EndsWith('-arm'))">gnueabihf</CrossCompileAbi>

<TargetTriple />
<TargetTriple Condition="'$(CrossCompileArch)' != ''">$(CrossCompileArch)-linux-gnu</TargetTriple>
<TargetTriple Condition="'$(CrossCompileArch)' != ''">$(CrossCompileArch)-linux-$(CrossCompileAbi)</TargetTriple>
<TargetTriple Condition="'$(CrossCompileArch)' != '' and ($(CrossCompileRid.StartsWith('linux-musl')) or $(CrossCompileRid.StartsWith('alpine')))">$(CrossCompileArch)-alpine-linux-musl</TargetTriple>
<TargetTriple Condition="'$(CrossCompileArch)' != '' and $(CrossCompileRid.StartsWith('linux-bionic'))">$(CrossCompileArch)-linux-android21</TargetTriple>
<TargetTriple Condition="'$(CrossCompileArch)' != '' and ($(CrossCompileRid.StartsWith('freebsd')))">$(CrossCompileArch)-unknown-freebsd12</TargetTriple>
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,6 @@ bool UnixNativeCodeManager::FindMethodInfo(PTR_VOID ControlPC,
pMethodInfo->unwind_info = procInfo.unwind_info;

uintptr_t lsda = procInfo.lsda;
#if defined(HOST_ARM)
// libunwind fills by reference not by value for ARM
lsda = *((uintptr_t *)lsda);
#endif

PTR_UInt8 p = dac_cast<PTR_UInt8>(lsda);

Expand Down
140 changes: 77 additions & 63 deletions src/coreclr/nativeaot/Runtime/unix/UnwindHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,136 +339,155 @@ struct Registers_REGDISPLAY : REGDISPLAY
#endif // TARGET_X86
#if defined(TARGET_ARM)

class Registers_arm_rt: public libunwind::Registers_arm {
public:
Registers_arm_rt() { abort(); };
Registers_arm_rt(void *registers) { regs = (REGDISPLAY *)registers; };
uint32_t getRegister(int num);
struct Registers_REGDISPLAY : REGDISPLAY
{
inline static int getArch() { return libunwind::REGISTERS_ARM; }
inline static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; }

bool validRegister(int num) const;
bool validFloatRegister(int num) { return false; };
bool validVectorRegister(int num) const { return false; };

uint32_t getRegister(int num) const;
void setRegister(int num, uint32_t value, uint32_t location);
uint32_t getRegisterLocation(int regNum) const { abort();}
unw_fpreg_t getFloatRegister(int num) { abort();}
void setFloatRegister(int num, unw_fpreg_t value) {abort();}
bool validVectorRegister(int num) const { abort();}
uint32_t getVectorRegister(int num) const {abort();};
void setVectorRegister(int num, uint32_t value) {abort();};
void jumpto() { abort();};
uint32_t getSP() const { return regs->SP;}
void setSP(uint32_t value, uint32_t location) { regs->SP = value;}
uint32_t getIP() const { return regs->IP;}

double getFloatRegister(int num) const {abort();}
void setFloatRegister(int num, double value) {abort();}

libunwind::v128 getVectorRegister(int num) const {abort();}
void setVectorRegister(int num, libunwind::v128 value) {abort();}

uint32_t getSP() const { return SP;}
void setSP(uint32_t value, uint32_t location) { SP = value;}
uint32_t getIP() const { return IP;}
void setIP(uint32_t value, uint32_t location)
{ regs->IP = value; regs->pIP = (PTR_UIntNative)location; }
void saveVFPAsX() {abort();};
private:
REGDISPLAY *regs;
{ IP = value; pIP = (PTR_UIntNative)location; }
uint32_t getFP() const { return *pR11;}
void setFP(uint32_t value, uint32_t location) { pR11 = (PTR_UIntNative)location;}
};

inline uint32_t Registers_arm_rt::getRegister(int regNum) {
inline bool Registers_REGDISPLAY::validRegister(int num) const {
if (num == UNW_REG_SP || num == UNW_ARM_SP)
return true;

if (num == UNW_ARM_LR)
return true;

if (num == UNW_REG_IP || num == UNW_ARM_IP)
return true;

if (num >= UNW_ARM_R0 && num <= UNW_ARM_R12)
return true;

return false;
}

inline uint32_t Registers_REGDISPLAY::getRegister(int regNum) const {
if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
return regs->SP;
return SP;

if (regNum == UNW_ARM_LR)
return *regs->pLR;
return *pLR;

if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
return regs->IP;
return IP;

switch (regNum)
{
case (UNW_ARM_R0):
return *regs->pR0;
return *pR0;
case (UNW_ARM_R1):
return *regs->pR1;
return *pR1;
case (UNW_ARM_R2):
return *regs->pR2;
return *pR2;
case (UNW_ARM_R3):
return *regs->pR3;
return *pR3;
case (UNW_ARM_R4):
return *regs->pR4;
return *pR4;
case (UNW_ARM_R5):
return *regs->pR5;
return *pR5;
case (UNW_ARM_R6):
return *regs->pR6;
return *pR6;
case (UNW_ARM_R7):
return *regs->pR7;
return *pR7;
case (UNW_ARM_R8):
return *regs->pR8;
return *pR8;
case (UNW_ARM_R9):
return *regs->pR9;
return *pR9;
case (UNW_ARM_R10):
return *regs->pR10;
return *pR10;
case (UNW_ARM_R11):
return *regs->pR11;
return *pR11;
case (UNW_ARM_R12):
return *regs->pR12;
return *pR12;
}

PORTABILITY_ASSERT("unsupported arm register");
}

void Registers_arm_rt::setRegister(int num, uint32_t value, uint32_t location)
void Registers_REGDISPLAY::setRegister(int num, uint32_t value, uint32_t location)
{

if (num == UNW_REG_SP || num == UNW_ARM_SP) {
regs->SP = (uintptr_t )value;
SP = (uintptr_t )value;
return;
}

if (num == UNW_ARM_LR) {
regs->pLR = (PTR_UIntNative)location;
pLR = (PTR_UIntNative)location;
return;
}

if (num == UNW_REG_IP || num == UNW_ARM_IP) {
regs->IP = value;
IP = value;
/* the location could be NULL, we could try to recover
pointer to value in stack from pLR */
if ((!location) && (regs->pLR) && (*regs->pLR == value))
regs->pIP = regs->pLR;
if ((!location) && pLR && (*pLR == value))
pIP = pLR;
else
regs->pIP = (PTR_UIntNative)location;
pIP = (PTR_UIntNative)location;
return;
}

switch (num)
{
case (UNW_ARM_R0):
regs->pR0 = (PTR_UIntNative)location;
pR0 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R1):
regs->pR1 = (PTR_UIntNative)location;
pR1 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R2):
regs->pR2 = (PTR_UIntNative)location;
pR2 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R3):
regs->pR3 = (PTR_UIntNative)location;
pR3 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R4):
regs->pR4 = (PTR_UIntNative)location;
pR4 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R5):
regs->pR5 = (PTR_UIntNative)location;
pR5 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R6):
regs->pR6 = (PTR_UIntNative)location;
pR6 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R7):
regs->pR7 = (PTR_UIntNative)location;
pR7 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R8):
regs->pR8 = (PTR_UIntNative)location;
pR8 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R9):
regs->pR9 = (PTR_UIntNative)location;
pR9 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R10):
regs->pR10 = (PTR_UIntNative)location;
pR10 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R11):
regs->pR11 = (PTR_UIntNative)location;
pR11 = (PTR_UIntNative)location;
break;
case (UNW_ARM_R12):
regs->pR12 = (PTR_UIntNative)location;
pR12 = (PTR_UIntNative)location;
break;
default:
PORTABILITY_ASSERT("unsupported arm register");
Expand Down Expand Up @@ -788,13 +807,8 @@ bool UnwindHelpers::StepFrame(REGDISPLAY *regs, unw_word_t start_ip, uint32_t fo
uintptr_t pc = regs->GetIP();
bool isSignalFrame = false;

#if defined(TARGET_ARM)
DwarfInstructions<LocalAddressSpace, Registers_arm_rt> dwarfInst;
int stepRet = dwarfInst.stepWithDwarf(_addressSpace, pc, unwind_info, *(Registers_arm_rt*)regs, isSignalFrame, /* stage2 */ false);
#else
DwarfInstructions<LocalAddressSpace, Registers_REGDISPLAY> dwarfInst;
int stepRet = dwarfInst.stepWithDwarf(_addressSpace, pc, unwind_info, *(Registers_REGDISPLAY*)regs, isSignalFrame, /* stage2 */ false);
#endif

if (stepRet != UNW_STEP_SUCCESS)
{
Expand All @@ -819,7 +833,7 @@ bool UnwindHelpers::GetUnwindProcInfo(PCODE pc, UnwindInfoSections &uwInfoSectio
#if defined(TARGET_AMD64)
libunwind::UnwindCursor<LocalAddressSpace, Registers_x86_64> uc(_addressSpace);
#elif defined(TARGET_ARM)
libunwind::UnwindCursor<LocalAddressSpace, Registers_arm_rt> uc(_addressSpace);
libunwind::UnwindCursor<LocalAddressSpace, Registers_arm> uc(_addressSpace);
#elif defined(TARGET_ARM64)
libunwind::UnwindCursor<LocalAddressSpace, Registers_arm64> uc(_addressSpace);
#elif defined(HOST_X86)
Expand Down
17 changes: 11 additions & 6 deletions src/coreclr/nativeaot/Runtime/unix/unixasmmacrosarm.inc
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,18 @@ C_FUNC(\Name):
ldr r0, 2f
1:
add r0, pc, r0
bl __tls_get_addr(PLT)
// push data at the end of text section
.pushsection .text.tlsvar, "aM", %progbits, 4
.balign 4
bl __tls_get_addr
b 3f

// Inline data
// LLVM assembler has no concept of subsections and this is not expressible as
// cross-section relocation.
.p2align 2
2:
.4byte \Var@TLSGD + (. - 1b - 4)
.popsection
.extern \Var
.type \Var, tls_object
.long \Var(TLSGD) + (2b - 1b - 4)
3:
.endm

.macro INLINE_GETTHREAD
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ public void EmitReloc(ISymbolNode symbol, RelocType relocType, int delta = 0)
case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24:
case RelocType.IMAGE_REL_BASED_ARM64_BRANCH26:
case RelocType.IMAGE_REL_BASED_THUMB_MOV32:
case RelocType.IMAGE_REL_BASED_THUMB_MOV32_PCREL:
case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21:
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12L:
case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A:
Expand Down
Loading

0 comments on commit 1a985d9

Please sign in to comment.