@@ -91,6 +91,19 @@ class AArch64ABSLongThunk final : public AArch64Thunk {
9191 ThunkSection *tsec = nullptr ;
9292};
9393
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+
94107class AArch64ADRPThunk final : public AArch64Thunk {
95108public:
96109 AArch64ADRPThunk (Ctx &ctx, Symbol &dest, int64_t addend,
@@ -663,6 +676,33 @@ void AArch64ABSLongThunk::addLongMapSyms() {
663676 addSymbol (" $d" , STT_NOTYPE, 8 , *tsec);
664677}
665678
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+
666706// This Thunk has a maximum range of 4Gb, this is sufficient for all programs
667707// using the small code model, including pc-relative ones. At time of writing
668708// clang and gcc do not support the large code model for position independent
@@ -1482,7 +1522,8 @@ Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
14821522
14831523Thunk::~Thunk () = default ;
14841524
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,
14861527 int64_t a) {
14871528 assert (is_contained ({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},
14881529 type));
@@ -1491,6 +1532,9 @@ static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, RelType type, Symbol &s,
14911532 !isAArch64BTILandingPad (ctx, s, a);
14921533 if (ctx.arg .picThunk )
14931534 return std::make_unique<AArch64ADRPThunk>(ctx, s, a, mayNeedLandingPad);
1535+ if (sec.getParent ()->flags & SHF_AARCH64_PURECODE)
1536+ return std::make_unique<AArch64ABSXOLongThunk>(ctx, s, a,
1537+ mayNeedLandingPad);
14941538 return std::make_unique<AArch64ABSLongThunk>(ctx, s, a, mayNeedLandingPad);
14951539}
14961540
@@ -1702,7 +1746,7 @@ std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
17021746
17031747 switch (ctx.arg .emachine ) {
17041748 case EM_AARCH64:
1705- return addThunkAArch64 (ctx, rel.type , s, a);
1749+ return addThunkAArch64 (ctx, isec, rel.type , s, a);
17061750 case EM_ARM:
17071751 return addThunkArm (ctx, isec, rel.type , s, a);
17081752 case EM_AVR:
0 commit comments