Lines Matching +full:non +full:- +full:secure

1 //===- ARM.cpp ------------------------------------------------------------===//
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
80 // Set the EF_ARM_BE8 flag in the ELF header, if ELF file is big-endian
81 // with BE-8 code.
84 if (config->armVFPArgs == ARMVFPArgKind::Base ||
85 config->armVFPArgs == ARMVFPArgKind::Default)
87 else if (config->armVFPArgs == ARMVFPArgKind::VFP)
90 if (!config->isLE && config->armBe8)
125 // (S + A) - GOT_ORG
128 // GOT(S) + A - GOT_ORG
132 // GOT(S) + A - P
137 return config->target1Rel ? R_PC : R_ABS;
139 if (config->target2 == Target2Policy::Rel)
141 if (config->target2 == Target2Policy::Abs)
151 // B(S) + A - P
201 if ((type == R_ARM_ABS32) || (type == R_ARM_TARGET1 && !config->target1Rel))
207 write32(buf, in.plt->getVA());
218 write32(buf + 0, 0xe52de004); // str lr, [sp,#-4]!
222 write32(buf + 16, 0x00000000); // L2: .word &(.got.plt) - L1 - 8
223 write32(buf + 20, 0xd4d4d4d4); // Pad to 32-byte boundary
224 write32(buf + 24, 0xd4d4d4d4); // Pad to 32-byte boundary
226 uint64_t gotPlt = in.gotPlt->getVA();
227 uint64_t l1 = in.plt->getVA() + 8;
228 write32(buf + 16, gotPlt - l1 - 8);
234 return config->armHasThumb2ISA && !config->armHasArmISA;
247 // e: .word .got.plt - .plt - 16
249 // At 0x8, we want to jump to .got.plt, the -16 accounts for 8 bytes from
252 uint64_t offset = in.gotPlt->getVA() - in.plt->getVA() - 16;
253 assert(llvm::isUInt<32>(offset) && "This should always fit into a 32-bit offset");
264 memcpy(buf + 16, trapInstr.data(), 4); // Pad to 32-byte boundary
274 0xe52de004, // L1: str lr, [sp,#-4]!
275 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4)
276 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4)
277 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4)
280 uint64_t offset = in.gotPlt->getVA() - in.plt->getVA() - 4;
290 memcpy(buf + 16, trapInstr.data(), 4); // Pad to 32-byte boundary
314 write32(buf + 12, 0x00000000); // L2: .word Offset(&(.got.plt) - L1 - 8
316 write32(buf + 12, gotPltEntryAddr - l1 - 8);
325 uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 8;
329 // optimal rotation for the 8-bit immediate used in the add instructions we
333 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.got.plt) - L1 - 8
334 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.got.plt) - L1 - 8
335 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.got.plt) - L1 - 8
345 memcpy(buf + 12, trapInstr.data(), 4); // Pad to 16-byte boundary
347 uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 12;
348 assert(llvm::isUInt<32>(offset) && "This should always fit into a 32-bit offset");
390 // undefined non-weak symbol will have been errored.
410 (!config->armHasBlx && (s.getVA() & 1));
423 (!config->armHasBlx && (s.getVA() & 1) == 0);;
430 // The placing of pre-created ThunkSections is controlled by the value
440 // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This
443 // ARM B, BL, BLX range +/- 32MiB
444 // Thumb B.W, BL, BLX range +/- 16MiB
445 // Thumb B<cc>.W range +/- 1MiB
446 // If a branch cannot reach a pre-created ThunkSection a new one will be
457 // ARMv6T2) the range is +/- 4MiB.
459 return (config->armJ1J2BranchEncoding) ? 0x1000000 - 0x30000
460 : 0x400000 - 0x7500;
465 // Destination is ARM, if ARM caller then Src is already 4-byte aligned.
473 int64_t offset = dst - src;
484 return config->armJ1J2BranchEncoding ? llvm::isInt<25>(offset)
492 // a non STT_FUNC symbol that may result in incorrect interworking between ARM
504 " to STT_SECTION symbol " + cast<Defined>(s).section->name +
509 toString(relt) + " to non STT_FUNC symbol: " + s.getName() +
518 // Rotate a 32-bit unsigned value right by a specified amt of bits.
521 return (val >> amt) | (val << ((32 - amt) & 31));
533 } while (group--);
540 // immediate field carries is a 12-bit modified immediate, made up of a 4-bit
541 // even rotate right and an 8-bit immediate.
545 val = -val;
551 imm = rotr32(imm, 24 - lz);
562 // R_ARM_LDR_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a
564 // bottom bit to recover S + A - P.
565 if (rel.sym->isFunc())
571 val = -val;
580 // R_ARM_LDRS_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a
582 // bottom bit to recover S + A - P.
583 if (rel.sym->isFunc())
589 val = -val;
632 if (!rel.sym->isFunc() && isBlx != bit0Thumb)
634 if (rel.sym->isFunc() ? bit0Thumb : isBlx) {
655 // We do a 9 bit check because val is right-shifted by 1 bit.
660 // We do a 12 bit check because val is right-shifted by 1 bit.
689 if (!rel.sym->isFunc() && !rel.sym->isInPlt() && isBlx == useThumb)
691 if ((rel.sym->isFunc() || rel.sym->isInPlt()) ? !useThumb : isBlx) {
692 // We are writing a BLX. Ensure BLX destination is 4-byte aligned. As
700 if (!config->armJ1J2BranchEncoding) {
819 imm = -imm;
830 // R_ARM_THM_PC8 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a
832 // bottom bit to recover S + A - Pa.
833 if (rel.sym->isFunc())
842 // R_ARM_THM_PC12 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a
844 // bottom bit to recover S + A - Pa.
845 if (rel.sym->isFunc())
850 imm12 = -imm12;
912 if (!config->armJ1J2BranchEncoding) {
934 // MOVT is in the range -32768 <= A < 32768
968 // 12-bit immediate is a modified immediate made up of a 4-bit even
969 // right rotation and 8-bit constant. After the rotation the value
970 // is zero-extended. When bit 23 is set the instruction is an add, when
974 return (instr & 0x00400000) ? -val : val;
983 return u ? imm12 : -imm12;
993 return u ? (imm4h | imm4l) : -(imm4h | imm4l);
1005 return (hi & 0x00f0) ? -imm : imm;
1011 // this trick permits the PC bias of -4 to be encoded using imm8 = 0xff
1012 return ((((read16(buf) & 0xff) << 2) + 4) & 0x3ff) - 4;
1017 return u ? imm12 : -imm12;
1028 return b->getName() == "$a" || b->getName().starts_with("$a.");
1032 return s->getName() == "$t" || s->getName().starts_with("$t.");
1036 return b->getName() == "$d" || b->getName().starts_with("$d.");
1045 return a->value < b->value;
1056 for (Symbol *sym : file->getLocalSymbols()) {
1063 if (auto *sec = cast_if_present<InputSection>(def->section))
1064 if (sec->flags & SHF_EXECINSTR)
1072 // in the synthetic symbol table. Due to the presence of strip (--strip-all),
1078 if (auto *sec = cast_if_present<InputSection>(sym->section))
1079 if (sec->flags & SHF_EXECINSTR)
1096 // the initial contents big-endian. Convert the big-endian instructions to
1098 // identify half open intervals of Arm code [$a, non $a) and Thumb code
1099 // [$t, non $t) and convert these to little endian a word or half word at a
1111 uint64_t start = 0, width = 0, size = sec->getSize();
1124 toLittleEndianInstructions(buf, start, msym->value, width);
1126 start = msym->value;
1138 // The Arm Cortex-M Security Extensions (CMSE) splits a system into two parts;
1139 // the non-secure and secure states with the secure state inaccessible from the
1140 // non-secure state, apart from an area of memory in secure state called the
1141 // secure gateway which is accessible from non-secure state. The secure gateway
1143 // instruction SG. Arm recommends that the secure gateway consists only of
1144 // secure gateway veneers, which are made up of a SG instruction followed by a
1145 // branch to the destination in secure state. Full details can be found in Arm
1146 // v8-M Security Extensions Requirements on Development Tools.
1148 // The CMSE model of software development requires the non-secure and secure
1149 // states to be developed as two separate programs. The non-secure developer is
1151 // in the secure gateway. No additional linker support is required for the
1152 // non-secure state.
1154 // Development of the secure state requires linker support to manage the secure
1156 // - Creation of new secure gateway veneers based on symbol conventions.
1157 // - Checking the address of existing secure gateway veneers.
1158 // - Warning when existing secure gateway veneers removed.
1160 // The secure gateway veneers are created in an import library, which is just an
1163 // --in-implib (specify an input import library from a previous revision of the
1165 // --out-implib (specify an output import library to be created by the linker).
1167 // The input import library is used to manage consistency of the secure entry
1168 // points. The output import library is for new and updated secure entry points.
1170 // The symbol convention that identifies secure entry functions is the prefix
1171 // __acle_se_ for a symbol called name the linker is expected to create a secure
1173 // After creating a secure gateway veneer the symbol name labels the secure
1177 // - Reads an existing import library with importCmseSymbols().
1178 // - Determines which new secure gateway veneers to create and redirects calls
1179 // within the secure state to the __acle_se_ prefixed symbol with
1181 // - Models the SG veneers as a synthetic section.
1199 sym->setName(CHECK(eSyms[i].getName(stringTable), this));
1200 sym->value = eSym.st_value;
1201 sym->size = eSym.st_size;
1202 sym->type = eSym.getType();
1203 sym->binding = eSym.getBinding();
1204 sym->stOther = eSym.st_other;
1207 error("CMSE symbol '" + sym->getName() + "' in import library '" +
1213 error("CMSE symbol '" + sym->getName() + "' in import library '" +
1218 if (symtab.cmseImportLib.count(sym->getName())) {
1219 error("CMSE symbol '" + sym->getName() +
1225 warn("CMSE symbol '" + sym->getName() + "' in import library '" +
1230 symtab.cmseImportLib[sym->getName()] = sym;
1237 auto check = [](Symbol *s, StringRef type) -> std::optional<std::string> {
1239 if (!(d && d->isFunc() && (d->value & 1)))
1240 return (Twine(toString(s->file)) + ": cmse " + type + " symbol '" +
1241 s->getName() + "' is not a Thumb function definition")
1243 if (!d->section)
1244 return (Twine(toString(s->file)) + ": cmse " + type + " symbol '" +
1245 s->getName() + "' cannot be an absolute symbol")
1256 // Look for [__acle_se_<sym>, <sym>] pairs, as specified in the Cortex-M
1264 if (!config->cmseImplib)
1269 if (!acleSeSym->getName().starts_with(ACLESESYM_PREFIX))
1273 if (!config->armCMSESupport) {
1274 error("CMSE is only supported by ARMv8-M architecture or later");
1275 config->cmseImplib = false;
1281 StringRef name = acleSeSym->getName().substr(std::strlen(ACLESESYM_PREFIX));
1284 error(toString(acleSeSym->file) + ": cmse special symbol '" +
1285 acleSeSym->getName() +
1301 // If this is an Arm CMSE secure app, replace references to entry symbol <sym>
1304 MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
1306 StringRef symName = syms[i]->getName();
1336 if (impLibMaxAddr <= sym->value)
1337 impLibMaxAddr = sym->value + sym->size;
1346 if (!symtab.inCMSEOutImpLib.count(sym->getName()))
1347 warn("entry function '" + sym->getName() +
1348 "' from CMSE import library is not present in secure application");
1351 if (!symtab.cmseImportLib.empty() && config->cmseOutputLib.empty()) {
1354 if (!symtab.inCMSEOutImpLib.count(sym->getName()))
1355 warn("new entry function '" + sym->getName() +
1363 if (symtab.cmseImportLib.count(sym->getName()))
1364 symtab.inCMSEOutImpLib[sym->getName()] = true;
1366 if (acleSeSym->file != sym->file ||
1369 // Only secure symbols with values equal to that of it's non-secure
1372 if (symtab.cmseImportLib.count(sym->getName())) {
1373 Defined *impSym = symtab.cmseImportLib[sym->getName()];
1374 ss = make<ArmCmseSGVeneer>(sym, acleSeSym, impSym->value);
1384 uint8_t *p = buf + s->offset;
1389 target->relocateNoSym(p + 4, R_ARM_THM_JUMP24,
1390 s->acleSeSym->getVA() -
1391 (getVA() + s->offset + s->size));
1401 return (impLibMaxAddr ? impLibMaxAddr - getVA() : 0) + newEntries * entsize;
1412 [](auto *i) { return i->getAddr().has_value(); });
1414 return a->getAddr().value() < b->getAddr().value();
1417 uint64_t addr = (*sgVeneers.begin())->getAddr().has_value()
1418 ? (*sgVeneers.begin())->getAddr().value()
1421 // linker-synthesized veneer with the lowest address.
1429 s->offset = i * s->size;
1430 Defined(file, StringRef(), s->sym->binding, s->sym->stOther, s->sym->type,
1431 s->offset | 1, s->size, this)
1432 .overwrite(*s->sym);
1438 // The symbols are copies of the (absolute) symbols of the secure gateways
1440 // See ArmĀ® v8-M Security Extensions: Requirements on Development Tools
1450 osIsPairs.emplace_back(make<OutputSection>(strtab->name, 0, 0), strtab);
1451 osIsPairs.emplace_back(make<OutputSection>(impSymTab->name, 0, 0), impSymTab);
1452 osIsPairs.emplace_back(make<OutputSection>(shstrtab->name, 0, 0), shstrtab);
1455 [](const auto &a, const auto &b) -> bool {
1456 return a.second.sym->getVA() < b.second.sym->getVA();
1458 // Copy the secure gateway entry symbols to the import library symbol table.
1461 impSymTab->addSymbol(makeDefined(
1462 ctx.internalFile, d->getName(), d->computeBinding(),
1463 /*stOther=*/0, STT_FUNC, d->getVA(), d->getSize(), nullptr));
1469 osec->sectionIndex = ++idx;
1470 osec->recordSection(isec);
1471 osec->finalizeInputSections();
1472 osec->shName = shstrtab->addString(osec->name);
1473 osec->size = isec->getSize();
1474 isec->finalizeContents();
1475 osec->offset = alignToPowerOf2(off, osec->addralign);
1476 off = osec->offset + osec->size;
1479 const uint64_t sectionHeaderOff = alignToPowerOf2(off, config->wordsize);
1484 config->mmapOutputFile ? 0 : (unsigned)FileOutputBuffer::F_no_mmap;
1485 unlinkAsync(config->cmseOutputLib);
1487 FileOutputBuffer::create(config->cmseOutputLib, fileSize, flags);
1489 error("failed to open " + config->cmseOutputLib + ": " +
1496 uint8_t *const buf = buffer->getBufferStart();
1499 eHdr->e_type = ET_REL;
1500 eHdr->e_entry = 0;
1501 eHdr->e_shoff = sectionHeaderOff;
1502 eHdr->e_ident[EI_CLASS] = ELFCLASS32;
1503 eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB;
1504 eHdr->e_ident[EI_VERSION] = EV_CURRENT;
1505 eHdr->e_ident[EI_OSABI] = config->osabi;
1506 eHdr->e_ident[EI_ABIVERSION] = 0;
1507 eHdr->e_machine = EM_ARM;
1508 eHdr->e_version = EV_CURRENT;
1509 eHdr->e_flags = config->eflags;
1510 eHdr->e_ehsize = sizeof(typename ELFT::Ehdr);
1511 eHdr->e_phnum = 0;
1512 eHdr->e_shentsize = sizeof(typename ELFT::Shdr);
1513 eHdr->e_phoff = 0;
1514 eHdr->e_phentsize = 0;
1515 eHdr->e_shnum = shnum;
1516 eHdr->e_shstrndx = shstrtab->getParent()->sectionIndex;
1519 auto *sHdrs = reinterpret_cast<typename ELFT::Shdr *>(buf + eHdr->e_shoff);
1521 osec->template writeHeaderTo<ELFT>(++sHdrs);
1527 osec->template writeTo<ELFT>(buf + osec->offset, tg);
1530 if (auto e = buffer->commit())
1531 fatal("failed to write output '" + buffer->getPath() +