|
8 | 8 |
|
9 | 9 | #include "InputFiles.h" |
10 | 10 | #include "OutputSections.h" |
| 11 | +#include "RelocScan.h" |
11 | 12 | #include "SymbolTable.h" |
12 | 13 | #include "Symbols.h" |
13 | 14 | #include "SyntheticSections.h" |
@@ -178,6 +179,10 @@ class PPC64 final : public TargetInfo { |
178 | 179 | uint64_t pltEntryAddr) const override; |
179 | 180 | void writeIplt(uint8_t *buf, const Symbol &sym, |
180 | 181 | uint64_t pltEntryAddr) const override; |
| 182 | + template <class ELFT, class RelTy> |
| 183 | + void scanSectionImpl(InputSectionBase &, Relocs<RelTy>); |
| 184 | + template <class ELFT> void scanSection1(InputSectionBase &); |
| 185 | + void scanSection(InputSectionBase &) override; |
181 | 186 | void relocate(uint8_t *loc, const Relocation &rel, |
182 | 187 | uint64_t val) const override; |
183 | 188 | void writeGotHeader(uint8_t *buf) const override; |
@@ -1257,6 +1262,132 @@ static bool isTocOptType(RelType type) { |
1257 | 1262 | } |
1258 | 1263 | } |
1259 | 1264 |
|
| 1265 | +// R_PPC64_TLSGD/R_PPC64_TLSLD is required to mark `bl __tls_get_addr` for |
| 1266 | +// General Dynamic/Local Dynamic code sequences. If a GD/LD GOT relocation is |
| 1267 | +// found but no R_PPC64_TLSGD/R_PPC64_TLSLD is seen, we assume that the |
| 1268 | +// instructions are generated by very old IBM XL compilers. Work around the |
| 1269 | +// issue by disabling GD/LD to IE/LE relaxation. |
| 1270 | +template <class RelTy> |
| 1271 | +static void checkPPC64TLSRelax(InputSectionBase &sec, Relocs<RelTy> rels) { |
| 1272 | + // Skip if sec is synthetic (sec.file is null) or if sec has been marked. |
| 1273 | + if (!sec.file || sec.file->ppc64DisableTLSRelax) |
| 1274 | + return; |
| 1275 | + bool hasGDLD = false; |
| 1276 | + for (const RelTy &rel : rels) { |
| 1277 | + RelType type = rel.getType(false); |
| 1278 | + switch (type) { |
| 1279 | + case R_PPC64_TLSGD: |
| 1280 | + case R_PPC64_TLSLD: |
| 1281 | + return; // Found a marker |
| 1282 | + case R_PPC64_GOT_TLSGD16: |
| 1283 | + case R_PPC64_GOT_TLSGD16_HA: |
| 1284 | + case R_PPC64_GOT_TLSGD16_HI: |
| 1285 | + case R_PPC64_GOT_TLSGD16_LO: |
| 1286 | + case R_PPC64_GOT_TLSLD16: |
| 1287 | + case R_PPC64_GOT_TLSLD16_HA: |
| 1288 | + case R_PPC64_GOT_TLSLD16_HI: |
| 1289 | + case R_PPC64_GOT_TLSLD16_LO: |
| 1290 | + hasGDLD = true; |
| 1291 | + break; |
| 1292 | + } |
| 1293 | + } |
| 1294 | + if (hasGDLD) { |
| 1295 | + sec.file->ppc64DisableTLSRelax = true; |
| 1296 | + Warn(sec.file->ctx) |
| 1297 | + << sec.file |
| 1298 | + << ": disable TLS relaxation due to R_PPC64_GOT_TLS* relocations " |
| 1299 | + "without " |
| 1300 | + "R_PPC64_TLSGD/R_PPC64_TLSLD relocations"; |
| 1301 | + } |
| 1302 | +} |
| 1303 | + |
| 1304 | +template <class ELFT, class RelTy> |
| 1305 | +void PPC64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { |
| 1306 | + RelocScan rs(ctx, &sec); |
| 1307 | + sec.relocations.reserve(rels.size()); |
| 1308 | + checkPPC64TLSRelax<RelTy>(sec, rels); |
| 1309 | + for (auto it = rels.begin(); it != rels.end(); ++it) { |
| 1310 | + const RelTy &rel = *it; |
| 1311 | + uint64_t offset = rel.r_offset; |
| 1312 | + uint32_t symIdx = rel.getSymbol(false); |
| 1313 | + Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIdx); |
| 1314 | + RelType type = rel.getType(false); |
| 1315 | + RelExpr expr = |
| 1316 | + ctx.target->getRelExpr(type, sym, sec.content().data() + offset); |
| 1317 | + if (expr == R_NONE) |
| 1318 | + continue; |
| 1319 | + if (sym.isUndefined() && symIdx != 0 && |
| 1320 | + rs.maybeReportUndefined(cast<Undefined>(sym), offset)) |
| 1321 | + continue; |
| 1322 | + |
| 1323 | + auto addend = getAddend<ELFT>(rel); |
| 1324 | + if (ctx.arg.isPic && type == R_PPC64_TOC) |
| 1325 | + addend += getPPC64TocBase(ctx); |
| 1326 | + |
| 1327 | + // We can separate the small code model relocations into 2 categories: |
| 1328 | + // 1) Those that access the compiler generated .toc sections. |
| 1329 | + // 2) Those that access the linker allocated got entries. |
| 1330 | + // lld allocates got entries to symbols on demand. Since we don't try to |
| 1331 | + // sort the got entries in any way, we don't have to track which objects |
| 1332 | + // have got-based small code model relocs. The .toc sections get placed |
| 1333 | + // after the end of the linker allocated .got section and we do sort those |
| 1334 | + // so sections addressed with small code model relocations come first. |
| 1335 | + if (type == R_PPC64_TOC16 || type == R_PPC64_TOC16_DS) |
| 1336 | + sec.file->ppc64SmallCodeModelTocRelocs = true; |
| 1337 | + |
| 1338 | + // Record the TOC entry (.toc + addend) as not relaxable. See the comment in |
| 1339 | + // PPC64::relocateAlloc(). |
| 1340 | + if (type == R_PPC64_TOC16_LO && sym.isSection() && isa<Defined>(sym) && |
| 1341 | + cast<Defined>(sym).section->name == ".toc") |
| 1342 | + ctx.ppc64noTocRelax.insert({&sym, addend}); |
| 1343 | + |
| 1344 | + if ((type == R_PPC64_TLSGD && expr == R_TLSDESC_CALL) || |
| 1345 | + (type == R_PPC64_TLSLD && expr == R_TLSLD_HINT)) { |
| 1346 | + auto it1 = it; |
| 1347 | + ++it1; |
| 1348 | + if (it1 == rels.end()) { |
| 1349 | + auto diag = Err(ctx); |
| 1350 | + diag << "R_PPC64_TLSGD/R_PPC64_TLSLD may not be the last " |
| 1351 | + "relocation"; |
| 1352 | + printLocation(diag, sec, sym, offset); |
| 1353 | + continue; |
| 1354 | + } |
| 1355 | + |
| 1356 | + // Offset the 4-byte aligned R_PPC64_TLSGD by one byte in the NOTOC |
| 1357 | + // case, so we can discern it later from the toc-case. |
| 1358 | + if (it1->getType(/*isMips64EL=*/false) == R_PPC64_REL24_NOTOC) |
| 1359 | + ++offset; |
| 1360 | + } |
| 1361 | + |
| 1362 | + if (oneof<R_GOTREL, RE_PPC64_TOCBASE, RE_PPC64_RELAX_TOC>(expr)) |
| 1363 | + ctx.in.got->hasGotOffRel.store(true, std::memory_order_relaxed); |
| 1364 | + |
| 1365 | + if (sym.isTls()) { |
| 1366 | + if (unsigned processed = |
| 1367 | + rs.handleTlsRelocation(expr, type, offset, sym, addend)) { |
| 1368 | + it += processed - 1; |
| 1369 | + continue; |
| 1370 | + } |
| 1371 | + } |
| 1372 | + rs.process(expr, type, offset, sym, addend); |
| 1373 | + } |
| 1374 | +} |
| 1375 | + |
| 1376 | +template <class ELFT> void PPC64::scanSection1(InputSectionBase &sec) { |
| 1377 | + auto relocs = sec.template relsOrRelas<ELFT>(); |
| 1378 | + if (relocs.areRelocsCrel()) |
| 1379 | + scanSectionImpl<ELFT>(sec, relocs.crels); |
| 1380 | + else |
| 1381 | + scanSectionImpl<ELFT>(sec, relocs.relas); |
| 1382 | +} |
| 1383 | + |
| 1384 | +void PPC64::scanSection(InputSectionBase &sec) { |
| 1385 | + if (ctx.arg.isLE) |
| 1386 | + scanSection1<ELF64LE>(sec); |
| 1387 | + else |
| 1388 | + scanSection1<ELF64BE>(sec); |
| 1389 | +} |
| 1390 | + |
1260 | 1391 | void PPC64::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { |
1261 | 1392 | RelType type = rel.type; |
1262 | 1393 | bool shouldTocOptimize = isTocOptType(type); |
|
0 commit comments