@@ -91,6 +91,19 @@ class AArch64ABSLongThunk final : public AArch64Thunk {
91
91
ThunkSection *tsec = nullptr ;
92
92
};
93
93
94
+ // AArch64 long range Thunks compatible with execute-only code.
95
+ class AArch64ABSXOLongThunk final : public AArch64Thunk {
96
+ public:
97
+ AArch64ABSXOLongThunk (Ctx &ctx, Symbol &dest, int64_t addend,
98
+ bool mayNeedLandingPad)
99
+ : AArch64Thunk(ctx, dest, addend, mayNeedLandingPad) {}
100
+ uint32_t size () override { return getMayUseShortThunk () ? 4 : 20 ; }
101
+ void addSymbols (ThunkSection &sec) override ;
102
+
103
+ private:
104
+ void writeLong (uint8_t *buf) override ;
105
+ };
106
+
94
107
class AArch64ADRPThunk final : public AArch64Thunk {
95
108
public:
96
109
AArch64ADRPThunk (Ctx &ctx, Symbol &dest, int64_t addend,
@@ -663,6 +676,33 @@ void AArch64ABSLongThunk::addLongMapSyms() {
663
676
addSymbol (" $d" , STT_NOTYPE, 8 , *tsec);
664
677
}
665
678
679
+ void AArch64ABSXOLongThunk::writeLong (uint8_t *buf) {
680
+ const uint8_t data[] = {
681
+ 0x10 , 0x00 , 0x80 , 0xd2 , // movz x16, :abs_g0_nc:S, lsl #0
682
+ 0x10 , 0x00 , 0xa0 , 0xf2 , // movk x16, :abs_g1_nc:S, lsl #16
683
+ 0x10 , 0x00 , 0xc0 , 0xf2 , // movk x16, :abs_g2_nc:S, lsl #32
684
+ 0x10 , 0x00 , 0xe0 , 0xf2 , // movk x16, :abs_g3:S, lsl #48
685
+ 0x00 , 0x02 , 0x1f , 0xd6 , // br x16
686
+ };
687
+ // If mayNeedLandingPad is true then destination is an
688
+ // AArch64BTILandingPadThunk that defines landingPad.
689
+ assert (!mayNeedLandingPad || landingPad != nullptr );
690
+ uint64_t s = mayNeedLandingPad
691
+ ? landingPad->getVA (ctx, 0 )
692
+ : getAArch64ThunkDestVA (ctx, destination, addend);
693
+ memcpy (buf, data, sizeof (data));
694
+ ctx.target ->relocateNoSym (buf + 0 , R_AARCH64_MOVW_UABS_G0_NC, s);
695
+ ctx.target ->relocateNoSym (buf + 4 , R_AARCH64_MOVW_UABS_G1_NC, s);
696
+ ctx.target ->relocateNoSym (buf + 8 , R_AARCH64_MOVW_UABS_G2_NC, s);
697
+ ctx.target ->relocateNoSym (buf + 12 , R_AARCH64_MOVW_UABS_G3, s);
698
+ }
699
+
700
+ void AArch64ABSXOLongThunk::addSymbols (ThunkSection &sec) {
701
+ addSymbol (ctx.saver .save (" __AArch64AbsXOLongThunk_" + destination.getName ()),
702
+ STT_FUNC, 0 , sec);
703
+ addSymbol (" $x" , STT_NOTYPE, 0 , sec);
704
+ }
705
+
666
706
// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
667
707
// using the small code model, including pc-relative ones. At time of writing
668
708
// clang and gcc do not support the large code model for position independent
@@ -1482,15 +1522,20 @@ Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
1482
1522
1483
1523
Thunk::~Thunk () = default ;
1484
1524
1485
- static std::unique_ptr<Thunk> addThunkAArch64 (Ctx &ctx, RelType type, Symbol &s,
1525
+ static std::unique_ptr<Thunk> addThunkAArch64 (Ctx &ctx, const InputSection &sec,
1526
+ RelType type, Symbol &s,
1486
1527
int64_t a) {
1487
1528
assert (is_contained ({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},
1488
1529
type));
1489
1530
bool mayNeedLandingPad =
1490
1531
(ctx.arg .andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) &&
1491
1532
!isAArch64BTILandingPad (ctx, s, a);
1533
+ bool isPureCode = sec.getParent ()->flags & SHF_AARCH64_PURECODE;
1492
1534
if (ctx.arg .picThunk )
1493
1535
return std::make_unique<AArch64ADRPThunk>(ctx, s, a, mayNeedLandingPad);
1536
+ if (isPureCode)
1537
+ return std::make_unique<AArch64ABSXOLongThunk>(ctx, s, a,
1538
+ mayNeedLandingPad);
1494
1539
return std::make_unique<AArch64ABSLongThunk>(ctx, s, a, mayNeedLandingPad);
1495
1540
}
1496
1541
@@ -1702,7 +1747,7 @@ std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
1702
1747
1703
1748
switch (ctx.arg .emachine ) {
1704
1749
case EM_AARCH64:
1705
- return addThunkAArch64 (ctx, rel.type , s, a);
1750
+ return addThunkAArch64 (ctx, isec, rel.type , s, a);
1706
1751
case EM_ARM:
1707
1752
return addThunkArm (ctx, isec, rel.type , s, a);
1708
1753
case EM_AVR:
0 commit comments