1553 lines · cpp
1//===- ARM.cpp ------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "InputFiles.h"10#include "OutputSections.h"11#include "SymbolTable.h"12#include "Symbols.h"13#include "SyntheticSections.h"14#include "Target.h"15#include "lld/Common/Filesystem.h"16#include "llvm/BinaryFormat/ELF.h"17#include "llvm/Support/Endian.h"18 19using namespace llvm;20using namespace llvm::support::endian;21using namespace llvm::support;22using namespace llvm::ELF;23using namespace lld;24using namespace lld::elf;25using namespace llvm::object;26 27namespace {28class ARM final : public TargetInfo {29public:30 ARM(Ctx &);31 uint32_t calcEFlags() const override;32 RelExpr getRelExpr(RelType type, const Symbol &s,33 const uint8_t *loc) const override;34 RelType getDynRel(RelType type) const override;35 int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;36 void writeGotPlt(uint8_t *buf, const Symbol &s) const override;37 void writeIgotPlt(uint8_t *buf, const Symbol &s) const override;38 void writePltHeader(uint8_t *buf) const override;39 void writePlt(uint8_t *buf, const Symbol &sym,40 uint64_t pltEntryAddr) const override;41 void addPltSymbols(InputSection &isec, uint64_t off) const override;42 void addPltHeaderSymbols(InputSection &isd) const override;43 bool needsThunk(RelExpr expr, RelType type, const InputFile *file,44 uint64_t branchAddr, const Symbol &s,45 int64_t a) const override;46 uint32_t getThunkSectionSpacing() const override;47 bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;48 void relocate(uint8_t *loc, const Relocation &rel,49 uint64_t val) const override;50 51 DenseMap<InputSection *, SmallVector<const Defined *, 0>> sectionMap;52 53private:54 void encodeAluGroup(uint8_t *loc, const Relocation &rel, uint64_t val,55 int group, bool check) const;56};57enum class CodeState { Data = 0, Thumb = 2, Arm = 4 };58} // namespace59 60ARM::ARM(Ctx &ctx) : TargetInfo(ctx) {61 copyRel = R_ARM_COPY;62 relativeRel = R_ARM_RELATIVE;63 iRelativeRel = R_ARM_IRELATIVE;64 gotRel = R_ARM_GLOB_DAT;65 pltRel = R_ARM_JUMP_SLOT;66 symbolicRel = R_ARM_ABS32;67 tlsGotRel = R_ARM_TLS_TPOFF32;68 tlsModuleIndexRel = R_ARM_TLS_DTPMOD32;69 tlsOffsetRel = R_ARM_TLS_DTPOFF32;70 pltHeaderSize = 32;71 pltEntrySize = 16;72 ipltEntrySize = 16;73 trapInstr = {0xd4, 0xd4, 0xd4, 0xd4};74 needsThunks = true;75 defaultMaxPageSize = 65536;76}77 78uint32_t ARM::calcEFlags() const {79 // The ABIFloatType is used by loaders to detect the floating point calling80 // convention.81 uint32_t abiFloatType = 0;82 83 // Set the EF_ARM_BE8 flag in the ELF header, if ELF file is big-endian84 // with BE-8 code.85 uint32_t armBE8 = 0;86 87 if (ctx.arg.armVFPArgs == ARMVFPArgKind::Base ||88 ctx.arg.armVFPArgs == ARMVFPArgKind::Default)89 abiFloatType = EF_ARM_ABI_FLOAT_SOFT;90 else if (ctx.arg.armVFPArgs == ARMVFPArgKind::VFP)91 abiFloatType = EF_ARM_ABI_FLOAT_HARD;92 93 if (!ctx.arg.isLE && ctx.arg.armBe8)94 armBE8 = EF_ARM_BE8;95 96 // We don't currently use any features incompatible with EF_ARM_EABI_VER5,97 // but we don't have any firm guarantees of conformance. Linux AArch6498 // kernels (as of 2016) require an EABI version to be set.99 return EF_ARM_EABI_VER5 | abiFloatType | armBE8;100}101 102RelExpr ARM::getRelExpr(RelType type, const Symbol &s,103 const uint8_t *loc) const {104 switch (type) {105 case R_ARM_ABS32:106 case R_ARM_MOVW_ABS_NC:107 case R_ARM_MOVT_ABS:108 case R_ARM_THM_MOVW_ABS_NC:109 case R_ARM_THM_MOVT_ABS:110 case R_ARM_THM_ALU_ABS_G0_NC:111 case R_ARM_THM_ALU_ABS_G1_NC:112 case R_ARM_THM_ALU_ABS_G2_NC:113 case R_ARM_THM_ALU_ABS_G3:114 return R_ABS;115 case R_ARM_THM_JUMP8:116 case R_ARM_THM_JUMP11:117 return R_PC;118 case R_ARM_CALL:119 case R_ARM_JUMP24:120 case R_ARM_PC24:121 case R_ARM_PLT32:122 case R_ARM_PREL31:123 case R_ARM_THM_JUMP19:124 case R_ARM_THM_JUMP24:125 case R_ARM_THM_CALL:126 return R_PLT_PC;127 case R_ARM_GOTOFF32:128 // (S + A) - GOT_ORG129 return R_GOTREL;130 case R_ARM_GOT_BREL:131 // GOT(S) + A - GOT_ORG132 return R_GOT_OFF;133 case R_ARM_GOT_PREL:134 case R_ARM_TLS_IE32:135 // GOT(S) + A - P136 return R_GOT_PC;137 case R_ARM_SBREL32:138 return RE_ARM_SBREL;139 case R_ARM_TARGET1:140 return ctx.arg.target1Rel ? R_PC : R_ABS;141 case R_ARM_TARGET2:142 if (ctx.arg.target2 == Target2Policy::Rel)143 return R_PC;144 if (ctx.arg.target2 == Target2Policy::Abs)145 return R_ABS;146 return R_GOT_PC;147 case R_ARM_TLS_GD32:148 return R_TLSGD_PC;149 case R_ARM_TLS_LDM32:150 return R_TLSLD_PC;151 case R_ARM_TLS_LDO32:152 return R_DTPREL;153 case R_ARM_BASE_PREL:154 // B(S) + A - P155 // FIXME: currently B(S) assumed to be .got, this may not hold for all156 // platforms.157 return R_GOTONLY_PC;158 case R_ARM_MOVW_PREL_NC:159 case R_ARM_MOVT_PREL:160 case R_ARM_REL32:161 case R_ARM_THM_MOVW_PREL_NC:162 case R_ARM_THM_MOVT_PREL:163 return R_PC;164 case R_ARM_ALU_PC_G0:165 case R_ARM_ALU_PC_G0_NC:166 case R_ARM_ALU_PC_G1:167 case R_ARM_ALU_PC_G1_NC:168 case R_ARM_ALU_PC_G2:169 case R_ARM_LDR_PC_G0:170 case R_ARM_LDR_PC_G1:171 case R_ARM_LDR_PC_G2:172 case R_ARM_LDRS_PC_G0:173 case R_ARM_LDRS_PC_G1:174 case R_ARM_LDRS_PC_G2:175 case R_ARM_THM_ALU_PREL_11_0:176 case R_ARM_THM_PC8:177 case R_ARM_THM_PC12:178 return RE_ARM_PCA;179 case R_ARM_MOVW_BREL_NC:180 case R_ARM_MOVW_BREL:181 case R_ARM_MOVT_BREL:182 case R_ARM_THM_MOVW_BREL_NC:183 case R_ARM_THM_MOVW_BREL:184 case R_ARM_THM_MOVT_BREL:185 return RE_ARM_SBREL;186 case R_ARM_NONE:187 return R_NONE;188 case R_ARM_TLS_LE32:189 return R_TPREL;190 case R_ARM_V4BX:191 // V4BX is just a marker to indicate there's a "bx rN" instruction at the192 // given address. It can be used to implement a special linker mode which193 // rewrites ARMv4T inputs to ARMv4. Since we support only ARMv4 input and194 // not ARMv4 output, we can just ignore it.195 return R_NONE;196 default:197 Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v198 << ") against symbol " << &s;199 return R_NONE;200 }201}202 203RelType ARM::getDynRel(RelType type) const {204 if ((type == R_ARM_ABS32) || (type == R_ARM_TARGET1 && !ctx.arg.target1Rel))205 return R_ARM_ABS32;206 return R_ARM_NONE;207}208 209void ARM::writeGotPlt(uint8_t *buf, const Symbol &) const {210 write32(ctx, buf, ctx.in.plt->getVA());211}212 213void ARM::writeIgotPlt(uint8_t *buf, const Symbol &s) const {214 // An ARM entry is the address of the ifunc resolver function.215 write32(ctx, buf, s.getVA(ctx));216}217 218// Long form PLT Header that does not have any restrictions on the displacement219// of the .plt from the .got.plt.220static void writePltHeaderLong(Ctx &ctx, uint8_t *buf) {221 write32(ctx, buf + 0, 0xe52de004); // str lr, [sp,#-4]!222 write32(ctx, buf + 4, 0xe59fe004); // ldr lr, L2223 write32(ctx, buf + 8, 0xe08fe00e); // L1: add lr, pc, lr224 write32(ctx, buf + 12, 0xe5bef008); // ldr pc, [lr, #8]225 write32(ctx, buf + 16, 0x00000000); // L2: .word &(.got.plt) - L1 - 8226 write32(ctx, buf + 20, 0xd4d4d4d4); // Pad to 32-byte boundary227 write32(ctx, buf + 24, 0xd4d4d4d4); // Pad to 32-byte boundary228 write32(ctx, buf + 28, 0xd4d4d4d4);229 uint64_t gotPlt = ctx.in.gotPlt->getVA();230 uint64_t l1 = ctx.in.plt->getVA() + 8;231 write32(ctx, buf + 16, gotPlt - l1 - 8);232}233 234// True if we should use Thumb PLTs, which currently require Thumb2, and are235// only used if the target does not have the ARM ISA.236static bool useThumbPLTs(Ctx &ctx) {237 return ctx.arg.armHasThumb2ISA && !ctx.arg.armHasArmISA;238}239 240// The default PLT header requires the .got.plt to be within 128 Mb of the241// .plt in the positive direction.242void ARM::writePltHeader(uint8_t *buf) const {243 if (useThumbPLTs(ctx)) {244 // The instruction sequence for thumb:245 //246 // 0: b500 push {lr}247 // 2: f8df e008 ldr.w lr, [pc, #0x8] @ 0xe <func+0xe>248 // 6: 44fe add lr, pc249 // 8: f85e ff08 ldr pc, [lr, #8]!250 // e: .word .got.plt - .plt - 16251 //252 // At 0x8, we want to jump to .got.plt, the -16 accounts for 8 bytes from253 // `pc` in the add instruction and 8 bytes for the `lr` adjustment.254 //255 uint64_t offset = ctx.in.gotPlt->getVA() - ctx.in.plt->getVA() - 16;256 assert(llvm::isUInt<32>(offset) && "This should always fit into a 32-bit offset");257 write16(ctx, buf + 0, 0xb500);258 // Split into two halves to support endianness correctly.259 write16(ctx, buf + 2, 0xf8df);260 write16(ctx, buf + 4, 0xe008);261 write16(ctx, buf + 6, 0x44fe);262 // Split into two halves to support endianness correctly.263 write16(ctx, buf + 8, 0xf85e);264 write16(ctx, buf + 10, 0xff08);265 write32(ctx, buf + 12, offset);266 267 memcpy(buf + 16, trapInstr.data(), 4); // Pad to 32-byte boundary268 memcpy(buf + 20, trapInstr.data(), 4);269 memcpy(buf + 24, trapInstr.data(), 4);270 memcpy(buf + 28, trapInstr.data(), 4);271 } else {272 // Use a similar sequence to that in writePlt(), the difference is the273 // calling conventions mean we use lr instead of ip. The PLT entry is274 // responsible for saving lr on the stack, the dynamic loader is responsible275 // for reloading it.276 const uint32_t pltData[] = {277 0xe52de004, // L1: str lr, [sp,#-4]!278 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4)279 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4)280 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4)281 };282 283 uint64_t offset = ctx.in.gotPlt->getVA() - ctx.in.plt->getVA() - 4;284 if (!llvm::isUInt<27>(offset)) {285 // We cannot encode the Offset, use the long form.286 writePltHeaderLong(ctx, buf);287 return;288 }289 write32(ctx, buf + 0, pltData[0]);290 write32(ctx, buf + 4, pltData[1] | ((offset >> 20) & 0xff));291 write32(ctx, buf + 8, pltData[2] | ((offset >> 12) & 0xff));292 write32(ctx, buf + 12, pltData[3] | (offset & 0xfff));293 memcpy(buf + 16, trapInstr.data(), 4); // Pad to 32-byte boundary294 memcpy(buf + 20, trapInstr.data(), 4);295 memcpy(buf + 24, trapInstr.data(), 4);296 memcpy(buf + 28, trapInstr.data(), 4);297 }298}299 300void ARM::addPltHeaderSymbols(InputSection &isec) const {301 if (useThumbPLTs(ctx)) {302 addSyntheticLocal(ctx, "$t", STT_NOTYPE, 0, 0, isec);303 addSyntheticLocal(ctx, "$d", STT_NOTYPE, 12, 0, isec);304 } else {305 addSyntheticLocal(ctx, "$a", STT_NOTYPE, 0, 0, isec);306 addSyntheticLocal(ctx, "$d", STT_NOTYPE, 16, 0, isec);307 }308}309 310// Long form PLT entries that do not have any restrictions on the displacement311// of the .plt from the .got.plt.312static void writePltLong(Ctx &ctx, uint8_t *buf, uint64_t gotPltEntryAddr,313 uint64_t pltEntryAddr) {314 write32(ctx, buf + 0, 0xe59fc004); // ldr ip, L2315 write32(ctx, buf + 4, 0xe08cc00f); // L1: add ip, ip, pc316 write32(ctx, buf + 8, 0xe59cf000); // ldr pc, [ip]317 write32(ctx, buf + 12, 0x00000000); // L2: .word Offset(&(.got.plt) - L1 - 8318 uint64_t l1 = pltEntryAddr + 4;319 write32(ctx, buf + 12, gotPltEntryAddr - l1 - 8);320}321 322// The default PLT entries require the .got.plt to be within 128 Mb of the323// .plt in the positive direction.324void ARM::writePlt(uint8_t *buf, const Symbol &sym,325 uint64_t pltEntryAddr) const {326 if (!useThumbPLTs(ctx)) {327 uint64_t offset = sym.getGotPltVA(ctx) - pltEntryAddr - 8;328 329 // The PLT entry is similar to the example given in Appendix A of ELF for330 // the Arm Architecture. Instead of using the Group Relocations to find the331 // optimal rotation for the 8-bit immediate used in the add instructions we332 // hard code the most compact rotations for simplicity. This saves a load333 // instruction over the long plt sequences.334 const uint32_t pltData[] = {335 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.got.plt) - L1 - 8336 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.got.plt) - L1 - 8337 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.got.plt) - L1 - 8338 };339 if (!llvm::isUInt<27>(offset)) {340 // We cannot encode the Offset, use the long form.341 writePltLong(ctx, buf, sym.getGotPltVA(ctx), pltEntryAddr);342 return;343 }344 write32(ctx, buf + 0, pltData[0] | ((offset >> 20) & 0xff));345 write32(ctx, buf + 4, pltData[1] | ((offset >> 12) & 0xff));346 write32(ctx, buf + 8, pltData[2] | (offset & 0xfff));347 memcpy(buf + 12, trapInstr.data(), 4); // Pad to 16-byte boundary348 } else {349 uint64_t offset = sym.getGotPltVA(ctx) - pltEntryAddr - 12;350 assert(llvm::isUInt<32>(offset) && "This should always fit into a 32-bit offset");351 352 // A PLT entry will be:353 //354 // movw ip, #<lower 16 bits>355 // movt ip, #<upper 16 bits>356 // add ip, pc357 // L1: ldr.w pc, [ip]358 // b L1359 //360 // where ip = r12 = 0xc361 362 // movw ip, #<lower 16 bits>363 write16(ctx, buf + 2, 0x0c00); // use `ip`364 relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, offset);365 366 // movt ip, #<upper 16 bits>367 write16(ctx, buf + 6, 0x0c00); // use `ip`368 relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, offset);369 370 write16(ctx, buf + 8, 0x44fc); // add ip, pc371 write16(ctx, buf + 10, 0xf8dc); // ldr.w pc, [ip] (bottom half)372 write16(ctx, buf + 12, 0xf000); // ldr.w pc, [ip] (upper half)373 write16(ctx, buf + 14, 0xe7fc); // Branch to previous instruction374 }375}376 377void ARM::addPltSymbols(InputSection &isec, uint64_t off) const {378 if (useThumbPLTs(ctx)) {379 addSyntheticLocal(ctx, "$t", STT_NOTYPE, off, 0, isec);380 } else {381 addSyntheticLocal(ctx, "$a", STT_NOTYPE, off, 0, isec);382 addSyntheticLocal(ctx, "$d", STT_NOTYPE, off + 12, 0, isec);383 }384}385 386bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,387 uint64_t branchAddr, const Symbol &s,388 int64_t a) const {389 // If s is an undefined weak symbol and does not have a PLT entry then it will390 // be resolved as a branch to the next instruction. If it is hidden, its391 // binding has been converted to local, so we just check isUndefined() here. A392 // undefined non-weak symbol will have been errored.393 if (s.isUndefined() && !s.isInPlt(ctx))394 return false;395 // A state change from ARM to Thumb and vice versa must go through an396 // interworking thunk if the relocation type is not R_ARM_CALL or397 // R_ARM_THM_CALL.398 switch (type) {399 case R_ARM_PC24:400 case R_ARM_PLT32:401 case R_ARM_JUMP24:402 // Source is ARM, all PLT entries are ARM so no interworking required.403 // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 set (Thumb).404 assert(!useThumbPLTs(ctx) &&405 "If the source is ARM, we should not need Thumb PLTs");406 if (s.isFunc() && expr == R_PC && (s.getVA(ctx) & 1))407 return true;408 [[fallthrough]];409 case R_ARM_CALL: {410 uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA(ctx) : s.getVA(ctx);411 return !inBranchRange(type, branchAddr, dst + a) ||412 (!ctx.arg.armHasBlx && (s.getVA(ctx) & 1));413 }414 case R_ARM_THM_JUMP19:415 case R_ARM_THM_JUMP24:416 // Source is Thumb, when all PLT entries are ARM interworking is required.417 // Otherwise we need to interwork if STT_FUNC Symbol has bit 0 clear (ARM).418 if ((expr == R_PLT_PC && !useThumbPLTs(ctx)) ||419 (s.isFunc() && (s.getVA(ctx) & 1) == 0))420 return true;421 [[fallthrough]];422 case R_ARM_THM_CALL: {423 uint64_t dst = (expr == R_PLT_PC) ? s.getPltVA(ctx) : s.getVA(ctx);424 return !inBranchRange(type, branchAddr, dst + a) ||425 (!ctx.arg.armHasBlx && (s.getVA(ctx) & 1) == 0);426 }427 }428 return false;429}430 431uint32_t ARM::getThunkSectionSpacing() const {432 // The placing of pre-created ThunkSections is controlled by the value433 // thunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to434 // place the ThunkSection such that all branches from the InputSections435 // prior to the ThunkSection can reach a Thunk placed at the end of the436 // ThunkSection. Graphically:437 // | up to thunkSectionSpacing .text input sections |438 // | ThunkSection |439 // | up to thunkSectionSpacing .text input sections |440 // | ThunkSection |441 442 // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This443 // is to match the most common expected case of a Thumb 2 encoded BL, BLX or444 // B.W:445 // ARM B, BL, BLX range +/- 32MiB446 // Thumb B.W, BL, BLX range +/- 16MiB447 // Thumb B<cc>.W range +/- 1MiB448 // If a branch cannot reach a pre-created ThunkSection a new one will be449 // created so we can handle the rare cases of a Thumb 2 conditional branch.450 // We intentionally use a lower size for thunkSectionSpacing than the maximum451 // branch range so the end of the ThunkSection is more likely to be within452 // range of the branch instruction that is furthest away. The value we shorten453 // thunkSectionSpacing by is set conservatively to allow us to create 16,384454 // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to455 // one of the Thunks going out of range.456 457 // On Arm the thunkSectionSpacing depends on the range of the Thumb Branch458 // range. On earlier Architectures such as ARMv4, ARMv5 and ARMv6 (except459 // ARMv6T2) the range is +/- 4MiB.460 461 return (ctx.arg.armJ1J2BranchEncoding) ? 0x1000000 - 0x30000462 : 0x400000 - 0x7500;463}464 465bool ARM::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {466 if ((dst & 0x1) == 0)467 // Destination is ARM, if ARM caller then Src is already 4-byte aligned.468 // If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure469 // destination will be 4 byte aligned.470 src &= ~0x3;471 else472 // Bit 0 == 1 denotes Thumb state, it is not part of the range.473 dst &= ~0x1;474 475 int64_t offset = llvm::SignExtend64<32>(dst - src);476 switch (type) {477 case R_ARM_PC24:478 case R_ARM_PLT32:479 case R_ARM_JUMP24:480 case R_ARM_CALL:481 return llvm::isInt<26>(offset);482 case R_ARM_THM_JUMP19:483 return llvm::isInt<21>(offset);484 case R_ARM_THM_JUMP24:485 case R_ARM_THM_CALL:486 return ctx.arg.armJ1J2BranchEncoding ? llvm::isInt<25>(offset)487 : llvm::isInt<23>(offset);488 default:489 return true;490 }491}492 493// Helper to produce message text when LLD detects that a CALL relocation to494// a non STT_FUNC symbol that may result in incorrect interworking between ARM495// or Thumb.496static void stateChangeWarning(Ctx &ctx, uint8_t *loc, RelType relt,497 const Symbol &s) {498 assert(!s.isFunc());499 const ErrorPlace place = getErrorPlace(ctx, loc);500 std::string hint;501 if (!place.srcLoc.empty())502 hint = "; " + place.srcLoc;503 if (s.isSection()) {504 // Section symbols must be defined and in a section. Users cannot change505 // the type. Use the section name as getName() returns an empty string.506 Warn(ctx) << place.loc << "branch and link relocation: " << relt507 << " to STT_SECTION symbol " << cast<Defined>(s).section->name508 << " ; interworking not performed" << hint;509 } else {510 // Warn with hint on how to alter the symbol type.511 Warn(ctx)512 << getErrorLoc(ctx, loc) << "branch and link relocation: " << relt513 << " to non STT_FUNC symbol: " << s.getName()514 << " interworking not performed; consider using directive '.type "515 << s.getName()516 << ", %function' to give symbol type STT_FUNC if interworking between "517 "ARM and Thumb is required"518 << hint;519 }520}521 522// Rotate a 32-bit unsigned value right by a specified amt of bits.523static uint32_t rotr32(uint32_t val, uint32_t amt) {524 assert(amt < 32 && "Invalid rotate amount");525 return (val >> amt) | (val << ((32 - amt) & 31));526}527 528static std::pair<uint32_t, uint32_t> getRemAndLZForGroup(unsigned group,529 uint32_t val) {530 uint32_t rem, lz;531 do {532 lz = llvm::countl_zero(val) & ~1;533 rem = val;534 if (lz == 32) // implies rem == 0535 break;536 val &= 0xffffff >> lz;537 } while (group--);538 return {rem, lz};539}540 541void ARM::encodeAluGroup(uint8_t *loc, const Relocation &rel, uint64_t val,542 int group, bool check) const {543 // ADD/SUB (immediate) add = bit23, sub = bit22544 // immediate field carries is a 12-bit modified immediate, made up of a 4-bit545 // even rotate right and an 8-bit immediate.546 uint32_t opcode = 0x00800000;547 if (val >> 63) {548 opcode = 0x00400000;549 val = -val;550 }551 uint32_t imm, lz;552 std::tie(imm, lz) = getRemAndLZForGroup(group, val);553 uint32_t rot = 0;554 if (lz < 24) {555 imm = rotr32(imm, 24 - lz);556 rot = (lz + 8) << 7;557 }558 if (check && imm > 0xff)559 Err(ctx) << getErrorLoc(ctx, loc) << "unencodeable immediate " << val560 << " for relocation " << rel.type;561 write32(ctx, loc,562 (read32(ctx, loc) & 0xff3ff000) | opcode | rot | (imm & 0xff));563}564 565static void encodeLdrGroup(Ctx &ctx, uint8_t *loc, const Relocation &rel,566 uint64_t val, int group) {567 // R_ARM_LDR_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a568 // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear569 // bottom bit to recover S + A - P.570 if (rel.sym->isFunc())571 val &= ~0x1;572 // LDR (literal) u = bit23573 uint32_t opcode = 0x00800000;574 if (val >> 63) {575 opcode = 0x0;576 val = -val;577 }578 uint32_t imm = getRemAndLZForGroup(group, val).first;579 checkUInt(ctx, loc, imm, 12, rel);580 write32(ctx, loc, (read32(ctx, loc) & 0xff7ff000) | opcode | imm);581}582 583static void encodeLdrsGroup(Ctx &ctx, uint8_t *loc, const Relocation &rel,584 uint64_t val, int group) {585 // R_ARM_LDRS_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a586 // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear587 // bottom bit to recover S + A - P.588 if (rel.sym->isFunc())589 val &= ~0x1;590 // LDRD/LDRH/LDRSB/LDRSH (literal) u = bit23591 uint32_t opcode = 0x00800000;592 if (val >> 63) {593 opcode = 0x0;594 val = -val;595 }596 uint32_t imm = getRemAndLZForGroup(group, val).first;597 checkUInt(ctx, loc, imm, 8, rel);598 write32(ctx, loc,599 (read32(ctx, loc) & 0xff7ff0f0) | opcode | ((imm & 0xf0) << 4) |600 (imm & 0xf));601}602 603void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {604 switch (rel.type) {605 case R_ARM_ABS32:606 case R_ARM_BASE_PREL:607 case R_ARM_GOTOFF32:608 case R_ARM_GOT_BREL:609 case R_ARM_GOT_PREL:610 case R_ARM_REL32:611 case R_ARM_RELATIVE:612 case R_ARM_SBREL32:613 case R_ARM_TARGET1:614 case R_ARM_TARGET2:615 case R_ARM_TLS_GD32:616 case R_ARM_TLS_IE32:617 case R_ARM_TLS_LDM32:618 case R_ARM_TLS_LDO32:619 case R_ARM_TLS_LE32:620 case R_ARM_TLS_TPOFF32:621 case R_ARM_TLS_DTPOFF32:622 write32(ctx, loc, val);623 break;624 case R_ARM_PREL31:625 checkInt(ctx, loc, val, 31, rel);626 write32(ctx, loc, (read32(ctx, loc) & 0x80000000) | (val & ~0x80000000));627 break;628 case R_ARM_CALL: {629 // R_ARM_CALL is used for BL and BLX instructions, for symbols of type630 // STT_FUNC we choose whether to write a BL or BLX depending on the631 // value of bit 0 of Val. With bit 0 == 1 denoting Thumb. If the symbol is632 // not of type STT_FUNC then we must preserve the original instruction.633 assert(rel.sym); // R_ARM_CALL is always reached via relocate().634 bool bit0Thumb = val & 1;635 bool isBlx = (read32(ctx, loc) & 0xfe000000) == 0xfa000000;636 // lld 10.0 and before always used bit0Thumb when deciding to write a BLX637 // even when type not STT_FUNC.638 if (!rel.sym->isFunc() && isBlx != bit0Thumb)639 stateChangeWarning(ctx, loc, rel.type, *rel.sym);640 if (rel.sym->isFunc() ? bit0Thumb : isBlx) {641 // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'642 checkInt(ctx, loc, val, 26, rel);643 write32(ctx, loc,644 0xfa000000 | // opcode645 ((val & 2) << 23) | // H646 ((val >> 2) & 0x00ffffff)); // imm24647 break;648 }649 // BLX (always unconditional) instruction to an ARM Target, select an650 // unconditional BL.651 write32(ctx, loc, 0xeb000000 | (read32(ctx, loc) & 0x00ffffff));652 // fall through as BL encoding is shared with B653 }654 [[fallthrough]];655 case R_ARM_JUMP24:656 case R_ARM_PC24:657 case R_ARM_PLT32:658 checkInt(ctx, loc, val, 26, rel);659 write32(ctx, loc,660 (read32(ctx, loc) & ~0x00ffffff) | ((val >> 2) & 0x00ffffff));661 break;662 case R_ARM_THM_JUMP8:663 // We do a 9 bit check because val is right-shifted by 1 bit.664 checkInt(ctx, loc, val, 9, rel);665 write16(ctx, loc, (read16(ctx, loc) & 0xff00) | ((val >> 1) & 0x00ff));666 break;667 case R_ARM_THM_JUMP11:668 // We do a 12 bit check because val is right-shifted by 1 bit.669 checkInt(ctx, loc, val, 12, rel);670 write16(ctx, loc, (read16(ctx, loc) & 0xf800) | ((val >> 1) & 0x07ff));671 break;672 case R_ARM_THM_JUMP19:673 // Encoding T3: Val = S:J2:J1:imm6:imm11:0674 checkInt(ctx, loc, val, 21, rel);675 write16(ctx, loc,676 (read16(ctx, loc) & 0xfbc0) | // opcode cond677 ((val >> 10) & 0x0400) | // S678 ((val >> 12) & 0x003f)); // imm6679 write16(ctx, loc + 2,680 0x8000 | // opcode681 ((val >> 8) & 0x0800) | // J2682 ((val >> 5) & 0x2000) | // J1683 ((val >> 1) & 0x07ff)); // imm11684 break;685 case R_ARM_THM_CALL: {686 // R_ARM_THM_CALL is used for BL and BLX instructions, for symbols of type687 // STT_FUNC we choose whether to write a BL or BLX depending on the688 // value of bit 0 of Val. With bit 0 == 0 denoting ARM, if the symbol is689 // not of type STT_FUNC then we must preserve the original instruction.690 // PLT entries are always ARM state so we know we need to interwork.691 assert(rel.sym); // R_ARM_THM_CALL is always reached via relocate().692 bool bit0Thumb = val & 1;693 bool useThumb = bit0Thumb || useThumbPLTs(ctx);694 bool isBlx = (read16(ctx, loc + 2) & 0x1000) == 0;695 // lld 10.0 and before always used bit0Thumb when deciding to write a BLX696 // even when type not STT_FUNC.697 if (!rel.sym->isFunc() && !rel.sym->isInPlt(ctx) && isBlx == useThumb)698 stateChangeWarning(ctx, loc, rel.type, *rel.sym);699 if ((rel.sym->isFunc() || rel.sym->isInPlt(ctx)) ? !useThumb : isBlx) {700 // We are writing a BLX. Ensure BLX destination is 4-byte aligned. As701 // the BLX instruction may only be two byte aligned. This must be done702 // before overflow check.703 val = alignTo(val, 4);704 write16(ctx, loc + 2, read16(ctx, loc + 2) & ~0x1000);705 } else {706 write16(ctx, loc + 2, (read16(ctx, loc + 2) & ~0x1000) | 1 << 12);707 }708 if (!ctx.arg.armJ1J2BranchEncoding) {709 // Older Arm architectures do not support R_ARM_THM_JUMP24 and have710 // different encoding rules and range due to J1 and J2 always being 1.711 checkInt(ctx, loc, val, 23, rel);712 write16(ctx, loc,713 0xf000 | // opcode714 ((val >> 12) & 0x07ff)); // imm11715 write16(ctx, loc + 2,716 (read16(ctx, loc + 2) & 0xd000) | // opcode717 0x2800 | // J1 == J2 == 1718 ((val >> 1) & 0x07ff)); // imm11719 break;720 }721 }722 // Fall through as rest of encoding is the same as B.W723 [[fallthrough]];724 case R_ARM_THM_JUMP24:725 // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0726 checkInt(ctx, loc, val, 25, rel);727 write16(ctx, loc,728 0xf000 | // opcode729 ((val >> 14) & 0x0400) | // S730 ((val >> 12) & 0x03ff)); // imm10731 write16(ctx, loc + 2,732 (read16(ctx, loc + 2) & 0xd000) | // opcode733 (((~(val >> 10)) ^ (val >> 11)) & 0x2000) | // J1734 (((~(val >> 11)) ^ (val >> 13)) & 0x0800) | // J2735 ((val >> 1) & 0x07ff)); // imm11736 break;737 case R_ARM_MOVW_ABS_NC:738 case R_ARM_MOVW_PREL_NC:739 case R_ARM_MOVW_BREL_NC:740 write32(ctx, loc,741 (read32(ctx, loc) & ~0x000f0fff) | ((val & 0xf000) << 4) |742 (val & 0x0fff));743 break;744 case R_ARM_MOVT_ABS:745 case R_ARM_MOVT_PREL:746 case R_ARM_MOVT_BREL:747 write32(ctx, loc,748 (read32(ctx, loc) & ~0x000f0fff) | (((val >> 16) & 0xf000) << 4) |749 ((val >> 16) & 0xfff));750 break;751 case R_ARM_THM_MOVT_ABS:752 case R_ARM_THM_MOVT_PREL:753 case R_ARM_THM_MOVT_BREL:754 // Encoding T1: A = imm4:i:imm3:imm8755 756 write16(ctx, loc,757 0xf2c0 | // opcode758 ((val >> 17) & 0x0400) | // i759 ((val >> 28) & 0x000f)); // imm4760 761 write16(ctx, loc + 2,762 (read16(ctx, loc + 2) & 0x8f00) | // opcode763 ((val >> 12) & 0x7000) | // imm3764 ((val >> 16) & 0x00ff)); // imm8765 break;766 case R_ARM_THM_MOVW_ABS_NC:767 case R_ARM_THM_MOVW_PREL_NC:768 case R_ARM_THM_MOVW_BREL_NC:769 // Encoding T3: A = imm4:i:imm3:imm8770 write16(ctx, loc,771 0xf240 | // opcode772 ((val >> 1) & 0x0400) | // i773 ((val >> 12) & 0x000f)); // imm4774 write16(ctx, loc + 2,775 (read16(ctx, loc + 2) & 0x8f00) | // opcode776 ((val << 4) & 0x7000) | // imm3777 (val & 0x00ff)); // imm8778 break;779 case R_ARM_THM_ALU_ABS_G3:780 write16(ctx, loc, (read16(ctx, loc) & ~0x00ff) | ((val >> 24) & 0x00ff));781 break;782 case R_ARM_THM_ALU_ABS_G2_NC:783 write16(ctx, loc, (read16(ctx, loc) & ~0x00ff) | ((val >> 16) & 0x00ff));784 break;785 case R_ARM_THM_ALU_ABS_G1_NC:786 write16(ctx, loc, (read16(ctx, loc) & ~0x00ff) | ((val >> 8) & 0x00ff));787 break;788 case R_ARM_THM_ALU_ABS_G0_NC:789 write16(ctx, loc, (read16(ctx, loc) & ~0x00ff) | (val & 0x00ff));790 break;791 case R_ARM_ALU_PC_G0:792 encodeAluGroup(loc, rel, val, 0, true);793 break;794 case R_ARM_ALU_PC_G0_NC:795 encodeAluGroup(loc, rel, val, 0, false);796 break;797 case R_ARM_ALU_PC_G1:798 encodeAluGroup(loc, rel, val, 1, true);799 break;800 case R_ARM_ALU_PC_G1_NC:801 encodeAluGroup(loc, rel, val, 1, false);802 break;803 case R_ARM_ALU_PC_G2:804 encodeAluGroup(loc, rel, val, 2, true);805 break;806 case R_ARM_LDR_PC_G0:807 encodeLdrGroup(ctx, loc, rel, val, 0);808 break;809 case R_ARM_LDR_PC_G1:810 encodeLdrGroup(ctx, loc, rel, val, 1);811 break;812 case R_ARM_LDR_PC_G2:813 encodeLdrGroup(ctx, loc, rel, val, 2);814 break;815 case R_ARM_LDRS_PC_G0:816 encodeLdrsGroup(ctx, loc, rel, val, 0);817 break;818 case R_ARM_LDRS_PC_G1:819 encodeLdrsGroup(ctx, loc, rel, val, 1);820 break;821 case R_ARM_LDRS_PC_G2:822 encodeLdrsGroup(ctx, loc, rel, val, 2);823 break;824 case R_ARM_THM_ALU_PREL_11_0: {825 // ADR encoding T2 (sub), T3 (add) i:imm3:imm8826 int64_t imm = val;827 uint16_t sub = 0;828 if (imm < 0) {829 imm = -imm;830 sub = 0x00a0;831 }832 checkUInt(ctx, loc, imm, 12, rel);833 write16(ctx, loc, (read16(ctx, loc) & 0xfb0f) | sub | (imm & 0x800) >> 1);834 write16(ctx, loc + 2,835 (read16(ctx, loc + 2) & 0x8f00) | (imm & 0x700) << 4 |836 (imm & 0xff));837 break;838 }839 case R_ARM_THM_PC8:840 // ADR and LDR literal encoding T1 positive offset only imm8:00841 // R_ARM_THM_PC8 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a842 // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear843 // bottom bit to recover S + A - Pa.844 if (rel.sym->isFunc())845 val &= ~0x1;846 checkUInt(ctx, loc, val, 10, rel);847 checkAlignment(ctx, loc, val, 4, rel);848 write16(ctx, loc, (read16(ctx, loc) & 0xff00) | (val & 0x3fc) >> 2);849 break;850 case R_ARM_THM_PC12: {851 // LDR (literal) encoding T2, add = (U == '1') imm12852 // imm12 is unsigned853 // R_ARM_THM_PC12 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a854 // function then addr is 0 (modulo 2) and Pa is 0 (modulo 4) so we can clear855 // bottom bit to recover S + A - Pa.856 if (rel.sym->isFunc())857 val &= ~0x1;858 int64_t imm12 = val;859 uint16_t u = 0x0080;860 if (imm12 < 0) {861 imm12 = -imm12;862 u = 0;863 }864 checkUInt(ctx, loc, imm12, 12, rel);865 write16(ctx, loc, read16(ctx, loc) | u);866 write16(ctx, loc + 2, (read16(ctx, loc + 2) & 0xf000) | imm12);867 break;868 }869 default:870 llvm_unreachable("unknown relocation");871 }872}873 874int64_t ARM::getImplicitAddend(const uint8_t *buf, RelType type) const {875 switch (type) {876 default:877 InternalErr(ctx, buf) << "cannot read addend for relocation " << type;878 return 0;879 case R_ARM_ABS32:880 case R_ARM_BASE_PREL:881 case R_ARM_GLOB_DAT:882 case R_ARM_GOTOFF32:883 case R_ARM_GOT_BREL:884 case R_ARM_GOT_PREL:885 case R_ARM_IRELATIVE:886 case R_ARM_REL32:887 case R_ARM_RELATIVE:888 case R_ARM_SBREL32:889 case R_ARM_TARGET1:890 case R_ARM_TARGET2:891 case R_ARM_TLS_DTPMOD32:892 case R_ARM_TLS_DTPOFF32:893 case R_ARM_TLS_GD32:894 case R_ARM_TLS_IE32:895 case R_ARM_TLS_LDM32:896 case R_ARM_TLS_LE32:897 case R_ARM_TLS_LDO32:898 case R_ARM_TLS_TPOFF32:899 return SignExtend64<32>(read32(ctx, buf));900 case R_ARM_PREL31:901 return SignExtend64<31>(read32(ctx, buf));902 case R_ARM_CALL:903 case R_ARM_JUMP24:904 case R_ARM_PC24:905 case R_ARM_PLT32:906 return SignExtend64<26>(read32(ctx, buf) << 2);907 case R_ARM_THM_JUMP8:908 return SignExtend64<9>(read16(ctx, buf) << 1);909 case R_ARM_THM_JUMP11:910 return SignExtend64<12>(read16(ctx, buf) << 1);911 case R_ARM_THM_JUMP19: {912 // Encoding T3: A = S:J2:J1:imm10:imm6:0913 uint16_t hi = read16(ctx, buf);914 uint16_t lo = read16(ctx, buf + 2);915 return SignExtend64<20>(((hi & 0x0400) << 10) | // S916 ((lo & 0x0800) << 8) | // J2917 ((lo & 0x2000) << 5) | // J1918 ((hi & 0x003f) << 12) | // imm6919 ((lo & 0x07ff) << 1)); // imm11:0920 }921 case R_ARM_THM_CALL:922 if (!ctx.arg.armJ1J2BranchEncoding) {923 // Older Arm architectures do not support R_ARM_THM_JUMP24 and have924 // different encoding rules and range due to J1 and J2 always being 1.925 uint16_t hi = read16(ctx, buf);926 uint16_t lo = read16(ctx, buf + 2);927 return SignExtend64<22>(((hi & 0x7ff) << 12) | // imm11928 ((lo & 0x7ff) << 1)); // imm11:0929 break;930 }931 [[fallthrough]];932 case R_ARM_THM_JUMP24: {933 // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0934 // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)935 uint16_t hi = read16(ctx, buf);936 uint16_t lo = read16(ctx, buf + 2);937 return SignExtend64<24>(((hi & 0x0400) << 14) | // S938 (~((lo ^ (hi << 3)) << 10) & 0x00800000) | // I1939 (~((lo ^ (hi << 1)) << 11) & 0x00400000) | // I2940 ((hi & 0x003ff) << 12) | // imm0941 ((lo & 0x007ff) << 1)); // imm11:0942 }943 // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and944 // MOVT is in the range -32768 <= A < 32768945 case R_ARM_MOVW_ABS_NC:946 case R_ARM_MOVT_ABS:947 case R_ARM_MOVW_PREL_NC:948 case R_ARM_MOVT_PREL:949 case R_ARM_MOVW_BREL_NC:950 case R_ARM_MOVT_BREL: {951 uint64_t val = read32(ctx, buf) & 0x000f0fff;952 return SignExtend64<16>(((val & 0x000f0000) >> 4) | (val & 0x00fff));953 }954 case R_ARM_THM_MOVW_ABS_NC:955 case R_ARM_THM_MOVT_ABS:956 case R_ARM_THM_MOVW_PREL_NC:957 case R_ARM_THM_MOVT_PREL:958 case R_ARM_THM_MOVW_BREL_NC:959 case R_ARM_THM_MOVT_BREL: {960 // Encoding T3: A = imm4:i:imm3:imm8961 uint16_t hi = read16(ctx, buf);962 uint16_t lo = read16(ctx, buf + 2);963 return SignExtend64<16>(((hi & 0x000f) << 12) | // imm4964 ((hi & 0x0400) << 1) | // i965 ((lo & 0x7000) >> 4) | // imm3966 (lo & 0x00ff)); // imm8967 }968 case R_ARM_THM_ALU_ABS_G0_NC:969 case R_ARM_THM_ALU_ABS_G1_NC:970 case R_ARM_THM_ALU_ABS_G2_NC:971 case R_ARM_THM_ALU_ABS_G3:972 return read16(ctx, buf) & 0xff;973 case R_ARM_ALU_PC_G0:974 case R_ARM_ALU_PC_G0_NC:975 case R_ARM_ALU_PC_G1:976 case R_ARM_ALU_PC_G1_NC:977 case R_ARM_ALU_PC_G2: {978 // 12-bit immediate is a modified immediate made up of a 4-bit even979 // right rotation and 8-bit constant. After the rotation the value980 // is zero-extended. When bit 23 is set the instruction is an add, when981 // bit 22 is set it is a sub.982 uint32_t instr = read32(ctx, buf);983 uint32_t val = rotr32(instr & 0xff, ((instr & 0xf00) >> 8) * 2);984 return (instr & 0x00400000) ? -val : val;985 }986 case R_ARM_LDR_PC_G0:987 case R_ARM_LDR_PC_G1:988 case R_ARM_LDR_PC_G2: {989 // ADR (literal) add = bit23, sub = bit22990 // LDR (literal) u = bit23 unsigned imm12991 bool u = read32(ctx, buf) & 0x00800000;992 uint32_t imm12 = read32(ctx, buf) & 0xfff;993 return u ? imm12 : -imm12;994 }995 case R_ARM_LDRS_PC_G0:996 case R_ARM_LDRS_PC_G1:997 case R_ARM_LDRS_PC_G2: {998 // LDRD/LDRH/LDRSB/LDRSH (literal) u = bit23 unsigned imm8999 uint32_t opcode = read32(ctx, buf);1000 bool u = opcode & 0x00800000;1001 uint32_t imm4l = opcode & 0xf;1002 uint32_t imm4h = (opcode & 0xf00) >> 4;1003 return u ? (imm4h | imm4l) : -(imm4h | imm4l);1004 }1005 case R_ARM_THM_ALU_PREL_11_0: {1006 // Thumb2 ADR, which is an alias for a sub or add instruction with an1007 // unsigned immediate.1008 // ADR encoding T2 (sub), T3 (add) i:imm3:imm81009 uint16_t hi = read16(ctx, buf);1010 uint16_t lo = read16(ctx, buf + 2);1011 uint64_t imm = (hi & 0x0400) << 1 | // i1012 (lo & 0x7000) >> 4 | // imm31013 (lo & 0x00ff); // imm81014 // For sub, addend is negative, add is positive.1015 return (hi & 0x00f0) ? -imm : imm;1016 }1017 case R_ARM_THM_PC8:1018 // ADR and LDR (literal) encoding T11019 // From ELF for the ARM Architecture the initial signed addend is formed1020 // from an unsigned field using expression (((imm8:00 + 4) & 0x3ff) – 4)1021 // this trick permits the PC bias of -4 to be encoded using imm8 = 0xff1022 return ((((read16(ctx, buf) & 0xff) << 2) + 4) & 0x3ff) - 4;1023 case R_ARM_THM_PC12: {1024 // LDR (literal) encoding T2, add = (U == '1') imm121025 bool u = read16(ctx, buf) & 0x0080;1026 uint64_t imm12 = read16(ctx, buf + 2) & 0x0fff;1027 return u ? imm12 : -imm12;1028 }1029 case R_ARM_NONE:1030 case R_ARM_V4BX:1031 case R_ARM_JUMP_SLOT:1032 // These relocations are defined as not having an implicit addend.1033 return 0;1034 }1035}1036 1037static bool isArmMapSymbol(const Symbol *b) {1038 return b->getName() == "$a" || b->getName().starts_with("$a.");1039}1040 1041static bool isThumbMapSymbol(const Symbol *s) {1042 return s->getName() == "$t" || s->getName().starts_with("$t.");1043}1044 1045static bool isDataMapSymbol(const Symbol *b) {1046 return b->getName() == "$d" || b->getName().starts_with("$d.");1047}1048 1049void elf::sortArmMappingSymbols(Ctx &ctx) {1050 // For each input section make sure the mapping symbols are sorted in1051 // ascending order.1052 for (auto &kv : static_cast<ARM &>(*ctx.target).sectionMap) {1053 SmallVector<const Defined *, 0> &mapSyms = kv.second;1054 llvm::stable_sort(mapSyms, [](const Defined *a, const Defined *b) {1055 return a->value < b->value;1056 });1057 }1058}1059 1060void elf::addArmInputSectionMappingSymbols(Ctx &ctx) {1061 // Collect mapping symbols for every executable input sections.1062 // The linker generated mapping symbols for all the synthetic1063 // sections are adding into the sectionmap through the function1064 // addArmSyntheitcSectionMappingSymbol.1065 auto §ionMap = static_cast<ARM &>(*ctx.target).sectionMap;1066 for (ELFFileBase *file : ctx.objectFiles) {1067 for (Symbol *sym : file->getLocalSymbols()) {1068 auto *def = dyn_cast<Defined>(sym);1069 if (!def)1070 continue;1071 if (!isArmMapSymbol(def) && !isDataMapSymbol(def) &&1072 !isThumbMapSymbol(def))1073 continue;1074 if (auto *sec = cast_if_present<InputSection>(def->section))1075 if (sec->flags & SHF_EXECINSTR)1076 sectionMap[sec].push_back(def);1077 }1078 }1079}1080 1081// Synthetic sections are not backed by an ELF file where we can access the1082// symbol table, instead mapping symbols added to synthetic sections are stored1083// in the synthetic symbol table. Due to the presence of strip (--strip-all),1084// we can not rely on the synthetic symbol table retaining the mapping symbols.1085// Instead we record the mapping symbols locally.1086void elf::addArmSyntheticSectionMappingSymbol(Defined *sym) {1087 if (!isArmMapSymbol(sym) && !isDataMapSymbol(sym) && !isThumbMapSymbol(sym))1088 return;1089 if (auto *sec = cast_if_present<InputSection>(sym->section))1090 if (sec->flags & SHF_EXECINSTR)1091 static_cast<ARM &>(*sec->file->ctx.target).sectionMap[sec].push_back(sym);1092}1093 1094static void toLittleEndianInstructions(uint8_t *buf, uint64_t start,1095 uint64_t end, uint64_t width) {1096 CodeState curState = static_cast<CodeState>(width);1097 if (curState == CodeState::Arm)1098 for (uint64_t i = start; i < end; i += width)1099 write32le(buf + i, read32be(buf + i));1100 1101 if (curState == CodeState::Thumb)1102 for (uint64_t i = start; i < end; i += width)1103 write16le(buf + i, read16be(buf + i));1104}1105 1106// Arm BE8 big endian format requires instructions to be little endian, with1107// the initial contents big-endian. Convert the big-endian instructions to1108// little endian leaving literal data untouched. We use mapping symbols to1109// identify half open intervals of Arm code [$a, non $a) and Thumb code1110// [$t, non $t) and convert these to little endian a word or half word at a1111// time respectively.1112void elf::convertArmInstructionstoBE8(Ctx &ctx, InputSection *sec,1113 uint8_t *buf) {1114 auto §ionMap = static_cast<ARM &>(*ctx.target).sectionMap;1115 auto it = sectionMap.find(sec);1116 if (it == sectionMap.end())1117 return;1118 1119 SmallVector<const Defined *, 0> &mapSyms = it->second;1120 1121 if (mapSyms.empty())1122 return;1123 1124 CodeState curState = CodeState::Data;1125 uint64_t start = 0, width = 0, size = sec->getSize();1126 for (auto &msym : mapSyms) {1127 CodeState newState = CodeState::Data;1128 if (isThumbMapSymbol(msym))1129 newState = CodeState::Thumb;1130 else if (isArmMapSymbol(msym))1131 newState = CodeState::Arm;1132 1133 if (newState == curState)1134 continue;1135 1136 if (curState != CodeState::Data) {1137 width = static_cast<uint64_t>(curState);1138 toLittleEndianInstructions(buf, start, msym->value, width);1139 }1140 start = msym->value;1141 curState = newState;1142 }1143 1144 // Passed last mapping symbol, may need to reverse1145 // up to end of section.1146 if (curState != CodeState::Data) {1147 width = static_cast<uint64_t>(curState);1148 toLittleEndianInstructions(buf, start, size, width);1149 }1150}1151 1152// The Arm Cortex-M Security Extensions (CMSE) splits a system into two parts;1153// the non-secure and secure states with the secure state inaccessible from the1154// non-secure state, apart from an area of memory in secure state called the1155// secure gateway which is accessible from non-secure state. The secure gateway1156// contains one or more entry points which must start with a landing pad1157// instruction SG. Arm recommends that the secure gateway consists only of1158// secure gateway veneers, which are made up of a SG instruction followed by a1159// branch to the destination in secure state. Full details can be found in Arm1160// v8-M Security Extensions Requirements on Development Tools.1161//1162// The CMSE model of software development requires the non-secure and secure1163// states to be developed as two separate programs. The non-secure developer is1164// provided with an import library defining symbols describing the entry points1165// in the secure gateway. No additional linker support is required for the1166// non-secure state.1167//1168// Development of the secure state requires linker support to manage the secure1169// gateway veneers. The management consists of:1170// - Creation of new secure gateway veneers based on symbol conventions.1171// - Checking the address of existing secure gateway veneers.1172// - Warning when existing secure gateway veneers removed.1173//1174// The secure gateway veneers are created in an import library, which is just an1175// ELF object with a symbol table. The import library is controlled by two1176// command line options:1177// --in-implib (specify an input import library from a previous revision of the1178// program).1179// --out-implib (specify an output import library to be created by the linker).1180//1181// The input import library is used to manage consistency of the secure entry1182// points. The output import library is for new and updated secure entry points.1183//1184// The symbol convention that identifies secure entry functions is the prefix1185// __acle_se_ for a symbol called name the linker is expected to create a secure1186// gateway veneer if symbols __acle_se_name and name have the same address.1187// After creating a secure gateway veneer the symbol name labels the secure1188// gateway veneer and the __acle_se_name labels the function definition.1189//1190// The LLD implementation:1191// - Reads an existing import library with importCmseSymbols().1192// - Determines which new secure gateway veneers to create and redirects calls1193// within the secure state to the __acle_se_ prefixed symbol with1194// processArmCmseSymbols().1195// - Models the SG veneers as a synthetic section.1196 1197// Initialize symbols. symbols is a parallel array to the corresponding ELF1198// symbol table.1199template <class ELFT> void ObjFile<ELFT>::importCmseSymbols() {1200 ArrayRef<Elf_Sym> eSyms = getELFSyms<ELFT>();1201 // Error for local symbols. The symbol at index 0 is LOCAL. So skip it.1202 for (size_t i = 1, end = firstGlobal; i != end; ++i) {1203 Err(ctx) << "CMSE symbol '" << CHECK2(eSyms[i].getName(stringTable), this)1204 << "' in import library '" << this << "' is not global";1205 }1206 1207 for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) {1208 const Elf_Sym &eSym = eSyms[i];1209 Defined *sym = reinterpret_cast<Defined *>(make<SymbolUnion>());1210 1211 // Initialize symbol fields.1212 memset(static_cast<void *>(sym), 0, sizeof(Symbol));1213 sym->setName(CHECK2(eSyms[i].getName(stringTable), this));1214 sym->value = eSym.st_value;1215 sym->size = eSym.st_size;1216 sym->type = eSym.getType();1217 sym->binding = eSym.getBinding();1218 sym->stOther = eSym.st_other;1219 1220 if (eSym.st_shndx != SHN_ABS) {1221 Err(ctx) << "CMSE symbol '" << sym->getName() << "' in import library '"1222 << this << "' is not absolute";1223 continue;1224 }1225 1226 if (!(eSym.st_value & 1) || (eSym.getType() != STT_FUNC)) {1227 Err(ctx) << "CMSE symbol '" << sym->getName() << "' in import library '"1228 << this << "' is not a Thumb function definition";1229 continue;1230 }1231 1232 if (ctx.symtab->cmseImportLib.count(sym->getName())) {1233 Err(ctx) << "CMSE symbol '" << sym->getName()1234 << "' is multiply defined in import library '" << this << "'";1235 continue;1236 }1237 1238 if (eSym.st_size != ACLESESYM_SIZE) {1239 Warn(ctx) << "CMSE symbol '" << sym->getName() << "' in import library '"1240 << this << "' does not have correct size of " << ACLESESYM_SIZE1241 << " bytes";1242 }1243 1244 ctx.symtab->cmseImportLib[sym->getName()] = sym;1245 }1246}1247 1248// Check symbol attributes of the acleSeSym, sym pair.1249// Both symbols should be global/weak Thumb code symbol definitions.1250static std::string checkCmseSymAttributes(Ctx &ctx, Symbol *acleSeSym,1251 Symbol *sym) {1252 auto check = [&](Symbol *s, StringRef type) -> std::optional<std::string> {1253 auto d = dyn_cast_or_null<Defined>(s);1254 if (!(d && d->isFunc() && (d->value & 1)))1255 return (Twine(toStr(ctx, s->file)) + ": cmse " + type + " symbol '" +1256 s->getName() + "' is not a Thumb function definition")1257 .str();1258 if (!d->section)1259 return (Twine(toStr(ctx, s->file)) + ": cmse " + type + " symbol '" +1260 s->getName() + "' cannot be an absolute symbol")1261 .str();1262 return std::nullopt;1263 };1264 for (auto [sym, type] :1265 {std::make_pair(acleSeSym, "special"), std::make_pair(sym, "entry")})1266 if (auto err = check(sym, type))1267 return *err;1268 return "";1269}1270 1271// Look for [__acle_se_<sym>, <sym>] pairs, as specified in the Cortex-M1272// Security Extensions specification.1273// 1) <sym> : A standard function name.1274// 2) __acle_se_<sym> : A special symbol that prefixes the standard function1275// name with __acle_se_.1276// Both these symbols are Thumb function symbols with external linkage.1277// <sym> may be redefined in .gnu.sgstubs.1278void elf::processArmCmseSymbols(Ctx &ctx) {1279 if (!ctx.arg.cmseImplib)1280 return;1281 // Only symbols with external linkage end up in ctx.symtab, so no need to do1282 // linkage checks. Only check symbol type.1283 for (Symbol *acleSeSym : ctx.symtab->getSymbols()) {1284 if (!acleSeSym->getName().starts_with(ACLESESYM_PREFIX))1285 continue;1286 // If input object build attributes do not support CMSE, error and disable1287 // further scanning for <sym>, __acle_se_<sym> pairs.1288 if (!ctx.arg.armCMSESupport) {1289 Err(ctx) << "CMSE is only supported by ARMv8-M architecture or later";1290 ctx.arg.cmseImplib = false;1291 break;1292 }1293 1294 // Try to find the associated symbol definition.1295 // Symbol must have external linkage.1296 StringRef name = acleSeSym->getName().substr(std::strlen(ACLESESYM_PREFIX));1297 Symbol *sym = ctx.symtab->find(name);1298 if (!sym) {1299 Err(ctx) << acleSeSym->file << ": cmse special symbol '"1300 << acleSeSym->getName()1301 << "' detected, but no associated entry function definition '"1302 << name << "' with external linkage found";1303 continue;1304 }1305 1306 std::string errMsg = checkCmseSymAttributes(ctx, acleSeSym, sym);1307 if (!errMsg.empty()) {1308 Err(ctx) << errMsg;1309 continue;1310 }1311 1312 // <sym> may be redefined later in the link in .gnu.sgstubs1313 ctx.symtab->cmseSymMap[name] = {acleSeSym, sym};1314 }1315 1316 // If this is an Arm CMSE secure app, replace references to entry symbol <sym>1317 // with its corresponding special symbol __acle_se_<sym>.1318 parallelForEach(ctx.objectFiles, [&](InputFile *file) {1319 MutableArrayRef<Symbol *> syms = file->getMutableSymbols();1320 for (Symbol *&sym : syms) {1321 StringRef symName = sym->getName();1322 auto it = ctx.symtab->cmseSymMap.find(symName);1323 if (it != ctx.symtab->cmseSymMap.end())1324 sym = it->second.acleSeSym;1325 }1326 });1327}1328 1329ArmCmseSGSection::ArmCmseSGSection(Ctx &ctx)1330 : SyntheticSection(ctx, ".gnu.sgstubs", SHT_PROGBITS,1331 SHF_ALLOC | SHF_EXECINSTR,1332 /*addralign=*/32) {1333 entsize = ACLESESYM_SIZE;1334 // The range of addresses used in the CMSE import library should be fixed.1335 for (auto &[_, sym] : ctx.symtab->cmseImportLib) {1336 if (impLibMaxAddr <= sym->value)1337 impLibMaxAddr = sym->value + sym->size;1338 }1339 if (ctx.symtab->cmseSymMap.empty())1340 return;1341 addMappingSymbol();1342 for (auto &[_, entryFunc] : ctx.symtab->cmseSymMap)1343 addSGVeneer(cast<Defined>(entryFunc.acleSeSym),1344 cast<Defined>(entryFunc.sym));1345 for (auto &[_, sym] : ctx.symtab->cmseImportLib) {1346 if (!ctx.symtab->inCMSEOutImpLib.count(sym->getName()))1347 Warn(ctx)1348 << "entry function '" << sym->getName()1349 << "' from CMSE import library is not present in secure application";1350 }1351 1352 if (!ctx.symtab->cmseImportLib.empty() && ctx.arg.cmseOutputLib.empty()) {1353 for (auto &[_, entryFunc] : ctx.symtab->cmseSymMap) {1354 Symbol *sym = entryFunc.sym;1355 if (!ctx.symtab->inCMSEOutImpLib.count(sym->getName()))1356 Warn(ctx) << "new entry function '" << sym->getName()1357 << "' introduced but no output import library specified";1358 }1359 }1360}1361 1362void ArmCmseSGSection::addSGVeneer(Symbol *acleSeSym, Symbol *sym) {1363 entries.emplace_back(acleSeSym, sym);1364 if (ctx.symtab->cmseImportLib.count(sym->getName()))1365 ctx.symtab->inCMSEOutImpLib[sym->getName()] = true;1366 // Symbol addresses different, nothing to do.1367 if (acleSeSym->file != sym->file ||1368 cast<Defined>(*acleSeSym).value != cast<Defined>(*sym).value)1369 return;1370 // Only secure symbols with values equal to that of it's non-secure1371 // counterpart needs to be in the .gnu.sgstubs section.1372 std::unique_ptr<ArmCmseSGVeneer> ss;1373 auto it = ctx.symtab->cmseImportLib.find(sym->getName());1374 if (it != ctx.symtab->cmseImportLib.end()) {1375 Defined *impSym = it->second;1376 ss = std::make_unique<ArmCmseSGVeneer>(sym, acleSeSym, impSym->value);1377 } else {1378 ss = std::make_unique<ArmCmseSGVeneer>(sym, acleSeSym);1379 ++newEntries;1380 }1381 sgVeneers.emplace_back(std::move(ss));1382}1383 1384void ArmCmseSGSection::writeTo(uint8_t *buf) {1385 for (std::unique_ptr<ArmCmseSGVeneer> &s : sgVeneers) {1386 uint8_t *p = buf + s->offset;1387 write16(ctx, p + 0, 0xe97f); // SG1388 write16(ctx, p + 2, 0xe97f);1389 write16(ctx, p + 4, 0xf000); // B.W S1390 write16(ctx, p + 6, 0xb000);1391 ctx.target->relocateNoSym(p + 4, R_ARM_THM_JUMP24,1392 s->acleSeSym->getVA(ctx) -1393 (getVA() + s->offset + s->size));1394 }1395}1396 1397void ArmCmseSGSection::addMappingSymbol() {1398 addSyntheticLocal(ctx, "$t", STT_NOTYPE, /*off=*/0, /*size=*/0, *this);1399}1400 1401size_t ArmCmseSGSection::getSize() const {1402 if (sgVeneers.empty())1403 return (impLibMaxAddr ? impLibMaxAddr - getVA() : 0) + newEntries * entsize;1404 1405 return entries.size() * entsize;1406}1407 1408void ArmCmseSGSection::finalizeContents() {1409 if (sgVeneers.empty())1410 return;1411 1412 auto it =1413 std::stable_partition(sgVeneers.begin(), sgVeneers.end(),1414 [](auto &i) { return i->getAddr().has_value(); });1415 std::sort(sgVeneers.begin(), it, [](auto &a, auto &b) {1416 return a->getAddr().value() < b->getAddr().value();1417 });1418 // This is the partition of the veneers with fixed addresses.1419 uint64_t addr = (*sgVeneers.begin())->getAddr().has_value()1420 ? (*sgVeneers.begin())->getAddr().value()1421 : getVA();1422 // Check if the start address of '.gnu.sgstubs' correspond to the1423 // linker-synthesized veneer with the lowest address.1424 if ((getVA() & ~1) != (addr & ~1)) {1425 Err(ctx)1426 << "start address of '.gnu.sgstubs' is different from previous link";1427 return;1428 }1429 1430 for (auto [i, s] : enumerate(sgVeneers)) {1431 s->offset = i * s->size;1432 Defined(ctx, file, StringRef(), s->sym->binding, s->sym->stOther,1433 s->sym->type, s->offset | 1, s->size, this)1434 .overwrite(*s->sym);1435 }1436}1437 1438// Write the CMSE import library to disk.1439// The CMSE import library is a relocatable object with only a symbol table.1440// The symbols are copies of the (absolute) symbols of the secure gateways1441// in the executable output by this link.1442// See Arm® v8-M Security Extensions: Requirements on Development Tools1443// https://developer.arm.com/documentation/ecm0359818/latest1444template <typename ELFT> void elf::writeARMCmseImportLib(Ctx &ctx) {1445 auto shstrtab =1446 std::make_unique<StringTableSection>(ctx, ".shstrtab", /*dynamic=*/false);1447 auto strtab =1448 std::make_unique<StringTableSection>(ctx, ".strtab", /*dynamic=*/false);1449 auto impSymTab = std::make_unique<SymbolTableSection<ELFT>>(ctx, *strtab);1450 1451 SmallVector<std::pair<std::unique_ptr<OutputSection>, SyntheticSection *>, 0>1452 osIsPairs;1453 osIsPairs.emplace_back(1454 std::make_unique<OutputSection>(ctx, strtab->name, 0, 0), strtab.get());1455 osIsPairs.emplace_back(1456 std::make_unique<OutputSection>(ctx, impSymTab->name, 0, 0),1457 impSymTab.get());1458 osIsPairs.emplace_back(1459 std::make_unique<OutputSection>(ctx, shstrtab->name, 0, 0),1460 shstrtab.get());1461 1462 llvm::sort(ctx.symtab->cmseSymMap, [&](const auto &a, const auto &b) {1463 return a.second.sym->getVA(ctx) < b.second.sym->getVA(ctx);1464 });1465 // Copy the secure gateway entry symbols to the import library symbol table.1466 for (auto &p : ctx.symtab->cmseSymMap) {1467 Defined *d = cast<Defined>(p.second.sym);1468 impSymTab->addSymbol(makeDefined(1469 ctx, ctx.internalFile, d->getName(), d->computeBinding(ctx),1470 /*stOther=*/0, STT_FUNC, d->getVA(ctx), d->getSize(), nullptr));1471 }1472 1473 size_t idx = 0;1474 uint64_t off = sizeof(typename ELFT::Ehdr);1475 for (auto &[osec, isec] : osIsPairs) {1476 osec->sectionIndex = ++idx;1477 osec->recordSection(isec);1478 osec->finalizeInputSections();1479 osec->shName = shstrtab->addString(osec->name);1480 osec->size = isec->getSize();1481 isec->finalizeContents();1482 osec->offset = alignToPowerOf2(off, osec->addralign);1483 off = osec->offset + osec->size;1484 }1485 1486 const uint64_t sectionHeaderOff = alignToPowerOf2(off, ctx.arg.wordsize);1487 const auto shnum = osIsPairs.size() + 1;1488 const uint64_t fileSize =1489 sectionHeaderOff + shnum * sizeof(typename ELFT::Shdr);1490 const unsigned flags =1491 ctx.arg.mmapOutputFile ? (unsigned)FileOutputBuffer::F_mmap : 0;1492 unlinkAsync(ctx.arg.cmseOutputLib);1493 Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =1494 FileOutputBuffer::create(ctx.arg.cmseOutputLib, fileSize, flags);1495 if (!bufferOrErr) {1496 Err(ctx) << "failed to open " << ctx.arg.cmseOutputLib << ": "1497 << bufferOrErr.takeError();1498 return;1499 }1500 1501 // Write the ELF Header1502 std::unique_ptr<FileOutputBuffer> &buffer = *bufferOrErr;1503 uint8_t *const buf = buffer->getBufferStart();1504 memcpy(buf, "\177ELF", 4);1505 auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf);1506 eHdr->e_type = ET_REL;1507 eHdr->e_entry = 0;1508 eHdr->e_shoff = sectionHeaderOff;1509 eHdr->e_ident[EI_CLASS] = ELFCLASS32;1510 eHdr->e_ident[EI_DATA] = ctx.arg.isLE ? ELFDATA2LSB : ELFDATA2MSB;1511 eHdr->e_ident[EI_VERSION] = EV_CURRENT;1512 eHdr->e_ident[EI_OSABI] = ctx.arg.osabi;1513 eHdr->e_ident[EI_ABIVERSION] = 0;1514 eHdr->e_machine = EM_ARM;1515 eHdr->e_version = EV_CURRENT;1516 eHdr->e_flags = ctx.arg.eflags;1517 eHdr->e_ehsize = sizeof(typename ELFT::Ehdr);1518 eHdr->e_phnum = 0;1519 eHdr->e_shentsize = sizeof(typename ELFT::Shdr);1520 eHdr->e_phoff = 0;1521 eHdr->e_phentsize = 0;1522 eHdr->e_shnum = shnum;1523 eHdr->e_shstrndx = shstrtab->getParent()->sectionIndex;1524 1525 // Write the section header table.1526 auto *sHdrs = reinterpret_cast<typename ELFT::Shdr *>(buf + eHdr->e_shoff);1527 for (auto &[osec, _] : osIsPairs)1528 osec->template writeHeaderTo<ELFT>(++sHdrs);1529 1530 // Write section contents to a mmap'ed file.1531 {1532 parallel::TaskGroup tg;1533 for (auto &[osec, _] : osIsPairs)1534 osec->template writeTo<ELFT>(ctx, buf + osec->offset, tg);1535 }1536 1537 if (auto e = buffer->commit())1538 Err(ctx) << "failed to write output '" << buffer->getPath()1539 << "': " << std::move(e);1540}1541 1542void elf::setARMTargetInfo(Ctx &ctx) { ctx.target.reset(new ARM(ctx)); }1543 1544template void elf::writeARMCmseImportLib<ELF32LE>(Ctx &);1545template void elf::writeARMCmseImportLib<ELF32BE>(Ctx &);1546template void elf::writeARMCmseImportLib<ELF64LE>(Ctx &);1547template void elf::writeARMCmseImportLib<ELF64BE>(Ctx &);1548 1549template void ObjFile<ELF32LE>::importCmseSymbols();1550template void ObjFile<ELF32BE>::importCmseSymbols();1551template void ObjFile<ELF64LE>::importCmseSymbols();1552template void ObjFile<ELF64BE>::importCmseSymbols();1553