@@ -336,8 +336,7 @@ static bool isAbsoluteValue(const Symbol &Sym) {
336
336
337
337
// Returns true if Expr refers a PLT entry.
338
338
static bool needsPlt (RelExpr Expr) {
339
- return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC,
340
- R_GOT_PLT, R_AARCH64_GOT_PAGE_PC_PLT>(Expr);
339
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT>(Expr);
341
340
}
342
341
343
342
// Returns true if Expr refers a GOT entry. Note that this function
@@ -346,16 +345,15 @@ static bool needsPlt(RelExpr Expr) {
346
345
static bool needsGot (RelExpr Expr) {
347
346
return isRelExprOneOf<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE,
348
347
R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
349
- R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, R_GOT_FROM_END,
350
- R_GOT_PLT>(Expr);
348
+ R_GOT_PC, R_GOT_FROM_END>(Expr);
351
349
}
352
350
353
351
// True if this expression is of the form Sym - X, where X is a position in the
354
352
// file (PC, or GOT for example).
355
353
static bool isRelExpr (RelExpr Expr) {
356
354
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
357
355
R_PPC_CALL, R_PPC_CALL_PLT, R_AARCH64_PAGE_PC,
358
- R_AARCH64_PLT_PAGE_PC, R_RELAX_GOT_PC>(Expr);
356
+ R_RELAX_GOT_PC>(Expr);
359
357
}
360
358
361
359
// Returns true if a given relocation can be computed at link-time.
@@ -373,16 +371,16 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym,
373
371
if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF,
374
372
R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF,
375
373
R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD,
376
- R_AARCH64_GOT_PAGE_PC, R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC ,
377
- R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
374
+ R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC ,
375
+ R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
378
376
R_TLSGD_GOT_FROM_END, R_TLSGD_PC, R_PPC_CALL_PLT,
379
377
R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT,
380
378
R_TLSLD_HINT, R_TLSIE_HINT>(E))
381
379
return true ;
382
380
383
381
// These never do, except if the entire file is position dependent or if
384
382
// only the low bits are used.
385
- if (E == R_GOT || E == R_GOT_PLT || E == R_PLT || E == R_TLSDESC)
383
+ if (E == R_GOT || E == R_PLT || E == R_TLSDESC)
386
384
return Target->usesOnlyLowPageBits (Type) || !Config->Pic ;
387
385
388
386
if (Sym.IsPreemptible )
@@ -428,14 +426,8 @@ static RelExpr toPlt(RelExpr Expr) {
428
426
return R_PPC_CALL_PLT;
429
427
case R_PC:
430
428
return R_PLT_PC;
431
- case R_AARCH64_PAGE_PC:
432
- return R_AARCH64_PLT_PAGE_PC;
433
- case R_AARCH64_GOT_PAGE_PC:
434
- return R_AARCH64_GOT_PAGE_PC_PLT;
435
429
case R_ABS:
436
430
return R_PLT;
437
- case R_GOT:
438
- return R_GOT_PLT;
439
431
default :
440
432
return Expr;
441
433
}
@@ -767,14 +759,7 @@ static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
767
759
template <class ELFT > static void addGotEntry (Symbol &Sym) {
768
760
In.Got ->addEntry (Sym);
769
761
770
- RelExpr Expr;
771
- if (Sym.isTls ())
772
- Expr = R_TLS;
773
- else if (Sym.isGnuIFunc ())
774
- Expr = R_PLT;
775
- else
776
- Expr = R_ABS;
777
-
762
+ RelExpr Expr = Sym.isTls () ? R_TLS : R_ABS;
778
763
uint64_t Off = Sym.getGotOffset ();
779
764
780
765
// If a GOT slot value can be calculated at link-time, which is now,
@@ -969,6 +954,15 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
969
954
getLocation (Sec, Sym, Offset));
970
955
}
971
956
957
+ struct IRelativeReloc {
958
+ RelType Type;
959
+ InputSectionBase *Sec;
960
+ uint64_t Offset;
961
+ Symbol *Sym;
962
+ };
963
+
964
+ static std::vector<IRelativeReloc> IRelativeRelocs;
965
+
972
966
template <class ELFT , class RelTy >
973
967
static void scanReloc (InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
974
968
RelTy *End) {
@@ -1011,32 +1005,29 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
1011
1005
if (Config->EMachine == EM_PPC64 && isPPC64SmallCodeModelTocReloc (Type))
1012
1006
Sec.File ->PPC64SmallCodeModelTocRelocs = true ;
1013
1007
1014
- // Strengthen or relax relocations.
1015
- //
1016
- // GNU ifunc symbols must be accessed via PLT because their addresses
1017
- // are determined by runtime.
1008
+ if (Sym.isGnuIFunc () && !Config->ZText && Config->WarnIfuncTextrel ) {
1009
+ warn (" using ifunc symbols when text relocations are allowed may produce "
1010
+ " a binary that will segfault, if the object file is linked with "
1011
+ " old version of glibc (glibc 2.28 and earlier). If this applies to "
1012
+ " you, consider recompiling the object files without -fPIC and "
1013
+ " without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to "
1014
+ " turn off this warning." +
1015
+ getLocation (Sec, Sym, Offset));
1016
+ }
1017
+
1018
+ // Relax relocations.
1018
1019
//
1019
- // On the other hand, if we know that a PLT entry will be resolved within
1020
- // the same ELF module, we can skip PLT access and directly jump to the
1021
- // destination function. For example, if we are linking a main exectuable,
1022
- // all dynamic symbols that can be resolved within the executable will
1023
- // actually be resolved that way at runtime, because the main exectuable
1024
- // is always at the beginning of a search list. We can leverage that fact.
1025
- if (Sym.isGnuIFunc ()) {
1026
- if (!Config->ZText && Config->WarnIfuncTextrel ) {
1027
- warn (" using ifunc symbols when text relocations are allowed may produce "
1028
- " a binary that will segfault, if the object file is linked with "
1029
- " old version of glibc (glibc 2.28 and earlier). If this applies to "
1030
- " you, consider recompiling the object files without -fPIC and "
1031
- " without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to "
1032
- " turn off this warning." +
1033
- getLocation (Sec, Sym, Offset));
1034
- }
1035
- Expr = toPlt (Expr);
1036
- } else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue (Sym)) {
1037
- Expr = Target->adjustRelaxExpr (Type, RelocatedAddr, Expr);
1038
- } else if (!Sym.IsPreemptible ) {
1039
- Expr = fromPlt (Expr);
1020
+ // If we know that a PLT entry will be resolved within the same ELF module, we
1021
+ // can skip PLT access and directly jump to the destination function. For
1022
+ // example, if we are linking a main exectuable, all dynamic symbols that can
1023
+ // be resolved within the executable will actually be resolved that way at
1024
+ // runtime, because the main exectuable is always at the beginning of a search
1025
+ // list. We can leverage that fact.
1026
+ if (!Sym.IsPreemptible && !Sym.isGnuIFunc ()) {
1027
+ if (Expr == R_GOT_PC && !isAbsoluteValue (Sym))
1028
+ Expr = Target->adjustRelaxExpr (Type, RelocatedAddr, Expr);
1029
+ else
1030
+ Expr = fromPlt (Expr);
1040
1031
}
1041
1032
1042
1033
// This relocation does not require got entry, but it is relative to got and
@@ -1056,28 +1047,136 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
1056
1047
return ;
1057
1048
}
1058
1049
1059
- // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
1060
- if (needsPlt (Expr) && !Sym.isInPlt ()) {
1061
- if (Sym.isGnuIFunc () && !Sym.IsPreemptible )
1062
- addPltEntry<ELFT>(In.Iplt , In.IgotPlt , In.RelaIplt , Target->IRelativeRel ,
1063
- Sym);
1064
- else
1050
+ // Non-preemptible ifuncs require special handling. First, handle the usual
1051
+ // case where the symbol isn't one of these.
1052
+ if (!Sym.isGnuIFunc () || Sym.IsPreemptible ) {
1053
+ // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
1054
+ if (needsPlt (Expr) && !Sym.isInPlt ())
1065
1055
addPltEntry<ELFT>(In.Plt , In.GotPlt , In.RelaPlt , Target->PltRel , Sym);
1066
- }
1067
1056
1068
- // Create a GOT slot if a relocation needs GOT.
1069
- if (needsGot (Expr)) {
1070
- if (Config->EMachine == EM_MIPS) {
1071
- // MIPS ABI has special rules to process GOT entries and doesn't
1072
- // require relocation entries for them. A special case is TLS
1073
- // relocations. In that case dynamic loader applies dynamic
1074
- // relocations to initialize TLS GOT entries.
1075
- // See "Global Offset Table" in Chapter 5 in the following document
1076
- // for detailed description:
1077
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
1078
- In.MipsGot ->addEntry (*Sec.File , Sym, Addend, Expr);
1079
- } else if (!Sym.isInGot ()) {
1080
- addGotEntry<ELFT>(Sym);
1057
+ // Create a GOT slot if a relocation needs GOT.
1058
+ if (needsGot (Expr)) {
1059
+ if (Config->EMachine == EM_MIPS) {
1060
+ // MIPS ABI has special rules to process GOT entries and doesn't
1061
+ // require relocation entries for them. A special case is TLS
1062
+ // relocations. In that case dynamic loader applies dynamic
1063
+ // relocations to initialize TLS GOT entries.
1064
+ // See "Global Offset Table" in Chapter 5 in the following document
1065
+ // for detailed description:
1066
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
1067
+ In.MipsGot ->addEntry (*Sec.File , Sym, Addend, Expr);
1068
+ } else if (!Sym.isInGot ()) {
1069
+ addGotEntry<ELFT>(Sym);
1070
+ }
1071
+ }
1072
+ } else {
1073
+ // Handle a reference to a non-preemptible ifunc. These are special in a
1074
+ // few ways:
1075
+ //
1076
+ // - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have
1077
+ // a fixed value. But assuming that all references to the ifunc are
1078
+ // GOT-generating or PLT-generating, the handling of an ifunc is
1079
+ // relatively straightforward. We create a PLT entry in Iplt, which is
1080
+ // usually at the end of .plt, which makes an indirect call using a
1081
+ // matching GOT entry in IgotPlt, which is usually at the end of .got.plt.
1082
+ // The GOT entry is relocated using an IRELATIVE relocation in RelaIplt,
1083
+ // which is usually at the end of .rela.plt. Unlike most relocations in
1084
+ // .rela.plt, which may be evaluated lazily without -z now, dynamic
1085
+ // loaders evaluate IRELATIVE relocs eagerly, which means that for
1086
+ // IRELATIVE relocs only, GOT-generating relocations can point directly to
1087
+ // .got.plt without requiring a separate GOT entry.
1088
+ //
1089
+ // - Despite the fact that an ifunc does not have a fixed value, compilers
1090
+ // that are not passed -fPIC will assume that they do, and will emit
1091
+ // direct (non-GOT-generating, non-PLT-generating) relocations to the
1092
+ // symbol. This means that if a direct relocation to the symbol is
1093
+ // seen, the linker must set a value for the symbol, and this value must
1094
+ // be consistent no matter what type of reference is made to the symbol.
1095
+ // This can be done by creating a PLT entry for the symbol in the way
1096
+ // described above and making it canonical, that is, making all references
1097
+ // point to the PLT entry instead of the resolver. In lld we also store
1098
+ // the address of the PLT entry in the dynamic symbol table, which means
1099
+ // that the symbol will also have the same value in other modules.
1100
+ // Because the value loaded from the GOT needs to be consistent with
1101
+ // the value computed using a direct relocation, a non-preemptible ifunc
1102
+ // may end up with two GOT entries, one in .got.plt that points to the
1103
+ // address returned by the resolver and is used only by the PLT entry,
1104
+ // and another in .got that points to the PLT entry and is used by
1105
+ // GOT-generating relocations.
1106
+ //
1107
+ // - The fact that these symbols do not have a fixed value makes them an
1108
+ // exception to the general rule that a statically linked executable does
1109
+ // not require any form of dynamic relocation. To handle these relocations
1110
+ // correctly, the IRELATIVE relocations are stored in an array which a
1111
+ // statically linked executable's startup code must enumerate using the
1112
+ // linker-defined symbols __rela?_iplt_{start,end}.
1113
+ //
1114
+ // - An absolute relocation to a non-preemptible ifunc (such as a global
1115
+ // variable containing a pointer to the ifunc) needs to be relocated in
1116
+ // the exact same way as a GOT entry, so we can avoid needing to make the
1117
+ // PLT entry canonical by translating such relocations into IRELATIVE
1118
+ // relocations in the RelaIplt.
1119
+ if (!Sym.isInPlt ()) {
1120
+ // Create PLT and GOTPLT slots for the symbol.
1121
+ Sym.IsInIplt = true ;
1122
+
1123
+ // Create a copy of the symbol to use as the target of the IRELATIVE
1124
+ // relocation in the IgotPlt. This is in case we make the PLT canonical
1125
+ // later, which would overwrite the original symbol.
1126
+ //
1127
+ // FIXME: Creating a copy of the symbol here is a bit of a hack. All
1128
+ // that's really needed to create the IRELATIVE is the section and value,
1129
+ // so ideally we should just need to copy those.
1130
+ auto *DirectSym = make<Defined>(cast<Defined>(Sym));
1131
+ addPltEntry<ELFT>(In.Iplt , In.IgotPlt , In.RelaIplt , Target->IRelativeRel ,
1132
+ *DirectSym);
1133
+ Sym.PltIndex = DirectSym->PltIndex ;
1134
+ }
1135
+ if (Expr == R_ABS && Addend == 0 && (Sec.Flags & SHF_WRITE)) {
1136
+ // We might be able to represent this as an IRELATIVE. But we don't know
1137
+ // yet whether some later relocation will make the symbol point to a
1138
+ // canonical PLT, which would make this either a dynamic RELATIVE (PIC) or
1139
+ // static (non-PIC) relocation. So we keep a record of the information
1140
+ // required to process the relocation, and after scanRelocs() has been
1141
+ // called on all relocations, the relocation is resolved by
1142
+ // addIRelativeRelocs().
1143
+ IRelativeRelocs.push_back ({Type, &Sec, Offset, &Sym});
1144
+ return ;
1145
+ }
1146
+ if (needsGot (Expr)) {
1147
+ // Redirect GOT accesses to point to the Igot.
1148
+ //
1149
+ // This field is also used to keep track of whether we ever needed a GOT
1150
+ // entry. If we did and we make the PLT canonical later, we'll need to
1151
+ // create a GOT entry pointing to the PLT entry for Sym.
1152
+ Sym.GotInIgot = true ;
1153
+ } else if (!needsPlt (Expr)) {
1154
+ // Make the ifunc's PLT entry canonical by changing the value of its
1155
+ // symbol to redirect all references to point to it.
1156
+ unsigned EntryOffset = Sym.PltIndex * Target->PltEntrySize ;
1157
+ if (Config->ZRetpolineplt )
1158
+ EntryOffset += Target->PltHeaderSize ;
1159
+
1160
+ auto &D = cast<Defined>(Sym);
1161
+ D.Section = In.Iplt ;
1162
+ D.Value = EntryOffset;
1163
+ D.Size = 0 ;
1164
+ // It's important to set the symbol type here so that dynamic loaders
1165
+ // don't try to call the PLT as if it were an ifunc resolver.
1166
+ D.Type = STT_FUNC;
1167
+
1168
+ if (Sym.GotInIgot ) {
1169
+ // We previously encountered a GOT generating reference that we
1170
+ // redirected to the Igot. Now that the PLT entry is canonical we must
1171
+ // clear the redirection to the Igot and add a GOT entry. As we've
1172
+ // changed the symbol type to STT_FUNC future GOT generating references
1173
+ // will naturally use this GOT entry.
1174
+ //
1175
+ // We don't need to worry about creating a MIPS GOT here because ifuncs
1176
+ // aren't a thing on MIPS.
1177
+ Sym.GotInIgot = false ;
1178
+ addGotEntry<ELFT>(Sym);
1179
+ }
1081
1180
}
1082
1181
}
1083
1182
@@ -1107,6 +1206,21 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
1107
1206
scanRelocs<ELFT>(S, S.rels <ELFT>());
1108
1207
}
1109
1208
1209
+ // Figure out which representation to use for any absolute relocs to
1210
+ // non-preemptible ifuncs that we visited during scanRelocs().
1211
+ void elf::addIRelativeRelocs () {
1212
+ for (IRelativeReloc &R : IRelativeRelocs) {
1213
+ if (R.Sym ->Type == STT_GNU_IFUNC)
1214
+ In.RelaIplt ->addReloc (
1215
+ {Target->IRelativeRel , R.Sec , R.Offset , true , R.Sym , 0 });
1216
+ else if (Config->Pic )
1217
+ addRelativeReloc (R.Sec , R.Offset , R.Sym , 0 , R_ABS, R.Type );
1218
+ else
1219
+ R.Sec ->Relocations .push_back ({R_ABS, R.Type , R.Offset , 0 , R.Sym });
1220
+ }
1221
+ IRelativeRelocs.clear ();
1222
+ }
1223
+
1110
1224
static bool mergeCmp (const InputSection *A, const InputSection *B) {
1111
1225
// std::merge requires a strict weak ordering.
1112
1226
if (A->OutSecOff < B->OutSecOff )
0 commit comments