|
7 | 7 | //===----------------------------------------------------------------------===//
|
8 | 8 |
|
9 | 9 | #include "InputFiles.h"
|
| 10 | +#include "OutputSections.h" |
10 | 11 | #include "SymbolTable.h"
|
11 | 12 | #include "Symbols.h"
|
12 | 13 | #include "SyntheticSections.h"
|
@@ -174,19 +175,17 @@ class PPC64 final : public TargetInfo {
|
174 | 175 | RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
|
175 | 176 | RelExpr adjustGotPcExpr(RelType type, int64_t addend,
|
176 | 177 | const uint8_t *loc) const override;
|
177 |
| - void relaxGot(uint8_t *loc, const Relocation &rel, |
178 |
| - uint64_t val) const override; |
179 |
| - void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, |
180 |
| - uint64_t val) const override; |
181 |
| - void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, |
182 |
| - uint64_t val) const override; |
183 |
| - void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, |
184 |
| - uint64_t val) const override; |
185 |
| - void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, |
186 |
| - uint64_t val) const override; |
| 178 | + void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
| 179 | + void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override; |
187 | 180 |
|
188 | 181 | bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end,
|
189 | 182 | uint8_t stOther) const override;
|
| 183 | + |
| 184 | +private: |
| 185 | + void relaxTlsGdToIe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
| 186 | + void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
| 187 | + void relaxTlsLdToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
| 188 | + void relaxTlsIeToLe(uint8_t *loc, const Relocation &rel, uint64_t val) const; |
190 | 189 | };
|
191 | 190 | } // namespace
|
192 | 191 |
|
@@ -362,7 +361,8 @@ getRelaTocSymAndAddend(InputSectionBase *tocSec, uint64_t offset) {
|
362 | 361 | // ld/lwa 3, 0(3) # load the value from the address
|
363 | 362 | //
|
364 | 363 | // Returns true if the relaxation is performed.
|
365 |
| -bool elf::tryRelaxPPC64TocIndirection(const Relocation &rel, uint8_t *bufLoc) { |
| 364 | +static bool tryRelaxPPC64TocIndirection(const Relocation &rel, |
| 365 | + uint8_t *bufLoc) { |
366 | 366 | assert(config->tocOptimize);
|
367 | 367 | if (rel.addend < 0)
|
368 | 368 | return false;
|
@@ -393,7 +393,8 @@ bool elf::tryRelaxPPC64TocIndirection(const Relocation &rel, uint8_t *bufLoc) {
|
393 | 393 | return false;
|
394 | 394 |
|
395 | 395 | // Add PPC64TocOffset that will be subtracted by PPC64::relocate().
|
396 |
| - target->relaxGot(bufLoc, rel, tocRelative + ppc64TocOffset); |
| 396 | + static_cast<const PPC64 &>(*target).relaxGot(bufLoc, rel, |
| 397 | + tocRelative + ppc64TocOffset); |
397 | 398 | return true;
|
398 | 399 | }
|
399 | 400 |
|
@@ -1512,6 +1513,87 @@ void PPC64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
|
1512 | 1513 | }
|
1513 | 1514 | }
|
1514 | 1515 |
|
| 1516 | +void PPC64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { |
| 1517 | + uint64_t secAddr = sec.getOutputSection()->addr; |
| 1518 | + if (auto *s = dyn_cast<InputSection>(&sec)) |
| 1519 | + secAddr += s->outSecOff; |
| 1520 | + uint64_t lastPPCRelaxedRelocOff = -1; |
| 1521 | + for (const Relocation &rel : sec.relocations) { |
| 1522 | + uint8_t *loc = buf + rel.offset; |
| 1523 | + const uint64_t val = |
| 1524 | + sec.getRelocTargetVA(sec.file, rel.type, rel.addend, |
| 1525 | + secAddr + rel.offset, *rel.sym, rel.expr); |
| 1526 | + switch (rel.expr) { |
| 1527 | + case R_PPC64_RELAX_GOT_PC: { |
| 1528 | + // The R_PPC64_PCREL_OPT relocation must appear immediately after |
| 1529 | + // R_PPC64_GOT_PCREL34 in the relocations table at the same offset. |
| 1530 | + // We can only relax R_PPC64_PCREL_OPT if we have also relaxed |
| 1531 | + // the associated R_PPC64_GOT_PCREL34 since only the latter has an |
| 1532 | + // associated symbol. So save the offset when relaxing R_PPC64_GOT_PCREL34 |
| 1533 | + // and only relax the other if the saved offset matches. |
| 1534 | + if (rel.type == R_PPC64_GOT_PCREL34) |
| 1535 | + lastPPCRelaxedRelocOff = rel.offset; |
| 1536 | + if (rel.type == R_PPC64_PCREL_OPT && rel.offset != lastPPCRelaxedRelocOff) |
| 1537 | + break; |
| 1538 | + relaxGot(loc, rel, val); |
| 1539 | + break; |
| 1540 | + } |
| 1541 | + case R_PPC64_RELAX_TOC: |
| 1542 | + // rel.sym refers to the STT_SECTION symbol associated to the .toc input |
| 1543 | + // section. If an R_PPC64_TOC16_LO (.toc + addend) references the TOC |
| 1544 | + // entry, there may be R_PPC64_TOC16_HA not paired with |
| 1545 | + // R_PPC64_TOC16_LO_DS. Don't relax. This loses some relaxation |
| 1546 | + // opportunities but is safe. |
| 1547 | + if (ppc64noTocRelax.count({rel.sym, rel.addend}) || |
| 1548 | + !tryRelaxPPC64TocIndirection(rel, loc)) |
| 1549 | + relocate(loc, rel, val); |
| 1550 | + break; |
| 1551 | + case R_PPC64_CALL: |
| 1552 | + // If this is a call to __tls_get_addr, it may be part of a TLS |
| 1553 | + // sequence that has been relaxed and turned into a nop. In this |
| 1554 | + // case, we don't want to handle it as a call. |
| 1555 | + if (read32(loc) == 0x60000000) // nop |
| 1556 | + break; |
| 1557 | + |
| 1558 | + // Patch a nop (0x60000000) to a ld. |
| 1559 | + if (rel.sym->needsTocRestore) { |
| 1560 | + // gcc/gfortran 5.4, 6.3 and earlier versions do not add nop for |
| 1561 | + // recursive calls even if the function is preemptible. This is not |
| 1562 | + // wrong in the common case where the function is not preempted at |
| 1563 | + // runtime. Just ignore. |
| 1564 | + if ((rel.offset + 8 > sec.rawData.size() || |
| 1565 | + read32(loc + 4) != 0x60000000) && |
| 1566 | + rel.sym->file != sec.file) { |
| 1567 | + // Use substr(6) to remove the "__plt_" prefix. |
| 1568 | + errorOrWarn(getErrorLocation(loc) + "call to " + |
| 1569 | + lld::toString(*rel.sym).substr(6) + |
| 1570 | + " lacks nop, can't restore toc"); |
| 1571 | + break; |
| 1572 | + } |
| 1573 | + write32(loc + 4, 0xe8410018); // ld %r2, 24(%r1) |
| 1574 | + } |
| 1575 | + relocate(loc, rel, val); |
| 1576 | + break; |
| 1577 | + case R_RELAX_TLS_GD_TO_IE: |
| 1578 | + case R_RELAX_TLS_GD_TO_IE_GOT_OFF: |
| 1579 | + relaxTlsGdToIe(loc, rel, val); |
| 1580 | + break; |
| 1581 | + case R_RELAX_TLS_GD_TO_LE: |
| 1582 | + relaxTlsGdToLe(loc, rel, val); |
| 1583 | + break; |
| 1584 | + case R_RELAX_TLS_LD_TO_LE_ABS: |
| 1585 | + relaxTlsLdToLe(loc, rel, val); |
| 1586 | + break; |
| 1587 | + case R_RELAX_TLS_IE_TO_LE: |
| 1588 | + relaxTlsIeToLe(loc, rel, val); |
| 1589 | + break; |
| 1590 | + default: |
| 1591 | + relocate(loc, rel, val); |
| 1592 | + break; |
| 1593 | + } |
| 1594 | + } |
| 1595 | +} |
| 1596 | + |
1515 | 1597 | // The prologue for a split-stack function is expected to look roughly
|
1516 | 1598 | // like this:
|
1517 | 1599 | // .Lglobal_entry_point:
|
|
0 commit comments