[lld] [lld] Support thumb PLTs (PR #86223)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Tue May 28 12:49:46 PDT 2024
================
@@ -279,32 +314,65 @@ static void writePltLong(uint8_t *buf, uint64_t gotPltEntryAddr,
// .plt in the positive direction.
void ARM::writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const {
- // The PLT entry is similar to the example given in Appendix A of ELF for
- // the Arm Architecture. Instead of using the Group Relocations to find the
- // optimal rotation for the 8-bit immediate used in the add instructions we
- // hard code the most compact rotations for simplicity. This saves a load
- // instruction over the long plt sequences.
- const uint32_t pltData[] = {
- 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.got.plt) - L1 - 8
- 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.got.plt) - L1 - 8
- 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.got.plt) - L1 - 8
- };
- uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 8;
- if (!llvm::isUInt<27>(offset)) {
- // We cannot encode the Offset, use the long form.
- writePltLong(buf, sym.getGotPltVA(), pltEntryAddr);
- return;
+ if (!config->armThumbPLTs) {
+ uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 8;
+
+ // The PLT entry is similar to the example given in Appendix A of ELF for
+ // the Arm Architecture. Instead of using the Group Relocations to find the
+ // optimal rotation for the 8-bit immediate used in the add instructions we
+ // hard code the most compact rotations for simplicity. This saves a load
+ // instruction over the long plt sequences.
+ const uint32_t pltData[] = {
+ 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.got.plt) - L1 - 8
+ 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.got.plt) - L1 - 8
+ 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.got.plt) - L1 - 8
+ };
+ if (!llvm::isUInt<27>(offset)) {
+ // We cannot encode the Offset, use the long form.
+ writePltLong(buf, sym.getGotPltVA(), pltEntryAddr);
+ return;
+ }
+ write32(buf + 0, pltData[0] | ((offset >> 20) & 0xff));
+ write32(buf + 4, pltData[1] | ((offset >> 12) & 0xff));
+ write32(buf + 8, pltData[2] | (offset & 0xfff));
+ memcpy(buf + 12, trapInstr.data(), 4); // Pad to 16-byte boundary
+ } else {
+ uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 12;
+ assert(llvm::isUInt<32>(offset) && "This should always fit into a 32-bit offset");
+
+ // A PLT entry will be:
+ //
+ // movw ip, #<lower 16 bits>
+ // movt ip, #<upper 16 bits>
+ // add ip, pc
+ // L1: ldr.w pc, [ip]
+ // b L1
+ //
+ // where ip = r12 = 0xc
+
+ // movw ip, #<lower 16 bits>
+ write16(buf + 2, 0x0c00); // use `ip`
+ relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, offset);
+
+ // movt ip, #<upper 16 bits>
+ write16(buf + 6, 0x0c00); // use `ip`
+ relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, offset);
+
+ write16(buf + 8, 0x44fc); // add ip, pc
+ write16(buf + 10, 0xf8dc); // ldr.w pc, [ip] (bottom half)
+ write16(buf + 12, 0xf000); // ldr.w pc, [ip] (upper half)
+ write16(buf + 14, 0xe7fc); // Branch to previous instruction
}
- write32(buf + 0, pltData[0] | ((offset >> 20) & 0xff));
- write32(buf + 4, pltData[1] | ((offset >> 12) & 0xff));
- write32(buf + 8, pltData[2] | (offset & 0xfff));
- memcpy(buf + 12, trapInstr.data(), 4); // Pad to 16-byte boundary
}
void ARM::addPltSymbols(InputSection &isec, uint64_t off) const {
- addSyntheticLocal("$a", STT_NOTYPE, off, 0, isec);
- addSyntheticLocal("$d", STT_NOTYPE, off + 12, 0, isec);
+ if (!config->armThumbPLTs) {
----------------
MaskRay wrote:
ditto
https://github.com/llvm/llvm-project/pull/86223
More information about the llvm-commits
mailing list