@@ -326,7 +326,7 @@ class PPC64PCRelPLTStub final : public Thunk {
326
326
327
327
// A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
328
328
// alignment. This gives a possible 26 bits of 'reach'. If the call offset is
329
- // larger then that we need to emit a long-branch thunk. The target address
329
+ // larger than that we need to emit a long-branch thunk. The target address
330
330
// of the callee is stored in a table to be accessed TOC-relative. Since the
331
331
// call must be local (a non-local call will have a PltCallStub instead) the
332
332
// table stores the address of the callee's local entry point. For
@@ -337,6 +337,8 @@ class PPC64LongBranchThunk : public Thunk {
337
337
uint32_t size () override { return 16 ; }
338
338
void writeTo (uint8_t *buf) override ;
339
339
void addSymbols (ThunkSection &isec) override ;
340
+ bool isCompatibleWith (const InputSection &isec,
341
+ const Relocation &rel) const override ;
340
342
341
343
protected:
342
344
PPC64LongBranchThunk (Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
@@ -365,6 +367,24 @@ class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
365
367
}
366
368
};
367
369
370
+ // A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
371
+ // alignment. This gives a possible 26 bits of 'reach'. If the caller and
372
+ // callee do not use toc and the call offset is larger than 26 bits,
373
+ // we need to emit a pc-rel based long-branch thunk. The target address of
374
+ // the callee is computed with a PC-relative offset.
375
+ class PPC64PCRelLongBranchThunk final : public Thunk {
376
+ public:
377
+ PPC64PCRelLongBranchThunk (Symbol &dest, int64_t addend)
378
+ : Thunk(dest, addend) {
379
+ alignment = 16 ;
380
+ }
381
+ uint32_t size () override { return 16 ; }
382
+ void writeTo (uint8_t *buf) override ;
383
+ void addSymbols (ThunkSection &isec) override ;
384
+ bool isCompatibleWith (const InputSection &isec,
385
+ const Relocation &rel) const override ;
386
+ };
387
+
368
388
} // end anonymous namespace
369
389
370
390
Defined *Thunk::addSymbol (StringRef name, uint8_t type, uint64_t value,
@@ -937,6 +957,33 @@ void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
937
957
isec);
938
958
}
939
959
960
+ bool PPC64LongBranchThunk::isCompatibleWith (const InputSection &isec,
961
+ const Relocation &rel) const {
962
+ return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
963
+ }
964
+
965
+ void PPC64PCRelLongBranchThunk::writeTo (uint8_t *buf) {
966
+ int64_t offset = destination.getVA () - getThunkTargetSym ()->getVA ();
967
+ if (!isInt<34 >(offset))
968
+ fatal (" offset overflow 34 bits, please compile using the large code model" );
969
+ uint64_t paddi = PADDI_R12_NO_DISP | (((offset >> 16 ) & 0x3ffff ) << 32 ) |
970
+ (offset & 0xffff );
971
+
972
+ writePrefixedInstruction (buf + 0 , paddi); // paddi r12, 0, func@pcrel, 1
973
+ write32 (buf + 8 , MTCTR_R12); // mtctr r12
974
+ write32 (buf + 12 , BCTR); // bctr
975
+ }
976
+
977
+ void PPC64PCRelLongBranchThunk::addSymbols (ThunkSection &isec) {
978
+ addSymbol (saver.save (" __long_branch_pcrel_" + destination.getName ()),
979
+ STT_FUNC, 0 , isec);
980
+ }
981
+
982
+ bool PPC64PCRelLongBranchThunk::isCompatibleWith (const InputSection &isec,
983
+ const Relocation &rel) const {
984
+ return rel.type == R_PPC64_REL24_NOTOC;
985
+ }
986
+
940
987
Thunk::Thunk (Symbol &d, int64_t a) : destination(d), addend(a), offset(0 ) {}
941
988
942
989
Thunk::~Thunk () = default ;
@@ -1057,12 +1104,15 @@ static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {
1057
1104
: (Thunk *)make<PPC64PltCallStub>(s);
1058
1105
1059
1106
// This check looks at the st_other bits of the callee. If the value is 1
1060
- // then the callee clobbers the TOC and we need an R2 save stub.
1061
- if ((s.stOther >> 5 ) == 1 )
1107
+ // then the callee clobbers the TOC and we need an R2 save stub when RelType
1108
+ // is R_PPC64_REL14 or R_PPC64_REL24.
1109
+ if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5 ) == 1 )
1062
1110
return make<PPC64R2SaveStub>(s);
1063
1111
1064
- if (type == R_PPC64_REL24_NOTOC && (s.stOther >> 5 ) > 1 )
1065
- return make<PPC64R12SetupStub>(s);
1112
+ if (type == R_PPC64_REL24_NOTOC)
1113
+ return (s.stOther >> 5 ) > 1
1114
+ ? (Thunk *)make<PPC64R12SetupStub>(s)
1115
+ : (Thunk *)make<PPC64PCRelLongBranchThunk>(s, a);
1066
1116
1067
1117
if (config->picThunk )
1068
1118
return make<PPC64PILongBranchThunk>(s, a);
0 commit comments