//
//===----------------------------------------------------------------------===//
-#include "InputFiles.h"
-#include "OutputSections.h"
-#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
-#include "lld/Common/Filesystem.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Endian.h"
using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-using namespace llvm::object;
namespace {
class ARM final : public TargetInfo {
}
}
-// The Arm Cortex-M Security Extensions (CMSE) splits a system into two parts;
-// the non-secure and secure states with the secure state inaccessible from the
-// non-secure state, apart from an area of memory in secure state called the
-// secure gateway which is accessible from non-secure state. The secure gateway
-// contains one or more entry points which must start with a landing pad
-// instruction SG. Arm recommends that the secure gateway consists only of
-// secure gateway veneers, which are made up of a SG instruction followed by a
-// branch to the destination in secure state. Full details can be found in Arm
-// v8-M Security Extensions Requirements on Development Tools.
-//
-// The CMSE model of software development requires the non-secure and secure
-// states to be developed as two separate programs. The non-secure developer is
-// provided with an import library defining symbols describing the entry points
-// in the secure gateway. No additional linker support is required for the
-// non-secure state.
-//
-// Development of the secure state requires linker support to manage the secure
-// gateway veneers. The management consists of:
-// - Creation of new secure gateway veneers based on symbol conventions.
-// - Checking the address of existing secure gateway veneers.
-// - Warning when existing secure gateway veneers removed.
-//
-// The secure gateway veneers are created in an import library, which is just an
-// ELF object with a symbol table. The import library is controlled by two
-// command line options:
-// --in-implib (specify an input import library from a previous revision of the
-// program).
-// --out-implib (specify an output import library to be created by the linker).
-//
-// The input import library is used to manage consistency of the secure entry
-// points. The output import library is for new and updated secure entry points.
-//
-// The symbol convention that identifies secure entry functions is the prefix
-// __acle_se_ for a symbol called name the linker is expected to create a secure
-// gateway veneer if symbols __acle_se_name and name have the same address.
-// After creating a secure gateway veneer the symbol name labels the secure
-// gateway veneer and the __acle_se_name labels the function definition.
-//
-// The LLD implementation:
-// - Reads an existing import library with importCmseSymbols().
-// - Determines which new secure gateway veneers to create and redirects calls
-// within the secure state to the __acle_se_ prefixed symbol with
-// processArmCmseSymbols().
-// - Models the SG veneers as a synthetic section.
-
-// Initialize symbols. symbols is a parallel array to the corresponding ELF
-// symbol table.
-template <class ELFT> void ObjFile<ELFT>::importCmseSymbols() {
- ArrayRef<Elf_Sym> eSyms = getELFSyms<ELFT>();
- // Error for local symbols. The symbol at index 0 is LOCAL. So skip it.
- for (size_t i = 1, end = firstGlobal; i != end; ++i) {
- errorOrWarn("CMSE symbol '" + CHECK(eSyms[i].getName(stringTable), this) +
- "' in import library '" + toString(this) + "' is not global");
- }
-
- for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) {
- const Elf_Sym &eSym = eSyms[i];
- Defined *sym = reinterpret_cast<Defined *>(make<SymbolUnion>());
-
- // Initialize symbol fields.
- memset(sym, 0, sizeof(Symbol));
- sym->setName(CHECK(eSyms[i].getName(stringTable), this));
- sym->value = eSym.st_value;
- sym->size = eSym.st_size;
- sym->type = eSym.getType();
- sym->binding = eSym.getBinding();
- sym->stOther = eSym.st_other;
-
- if (eSym.st_shndx != SHN_ABS) {
- error("CMSE symbol '" + sym->getName() + "' in import library '" +
- toString(this) + "' is not absolute");
- continue;
- }
-
- if (!(eSym.st_value & 1) || (eSym.getType() != STT_FUNC)) {
- error("CMSE symbol '" + sym->getName() + "' in import library '" +
- toString(this) + "' is not a Thumb function definition");
- continue;
- }
-
- if (symtab.cmseImportLib.count(sym->getName())) {
- error("CMSE symbol '" + sym->getName() +
- "' is multiply defined in import library '" + toString(this) + "'");
- continue;
- }
-
- if (eSym.st_size != ACLESESYM_SIZE) {
- warn("CMSE symbol '" + sym->getName() + "' in import library '" +
- toString(this) + "' does not have correct size of " +
- Twine(ACLESESYM_SIZE) + " bytes");
- }
-
- symtab.cmseImportLib[sym->getName()] = sym;
- }
-}
-
-// Check symbol attributes of the acleSeSym, sym pair.
-// Both symbols should be global/weak Thumb code symbol definitions.
-static std::string checkCmseSymAttributes(Symbol *acleSeSym, Symbol *sym) {
- auto check = [](Symbol *s, StringRef type) -> std::optional<std::string> {
- auto d = dyn_cast_or_null<Defined>(s);
- if (!(d && d->isFunc() && (d->value & 1)))
- return (Twine(toString(s->file)) + ": cmse " + type + " symbol '" +
- s->getName() + "' is not a Thumb function definition")
- .str();
- if (!d->section)
- return (Twine(toString(s->file)) + ": cmse " + type + " symbol '" +
- s->getName() + "' cannot be an absolute symbol")
- .str();
- return std::nullopt;
- };
- for (auto [sym, type] :
- {std::make_pair(acleSeSym, "special"), std::make_pair(sym, "entry")})
- if (auto err = check(sym, type))
- return *err;
- return "";
-}
-
-// Look for [__acle_se_<sym>, <sym>] pairs, as specified in the Cortex-M
-// Security Extensions specification.
-// 1) <sym> : A standard function name.
-// 2) __acle_se_<sym> : A special symbol that prefixes the standard function
-// name with __acle_se_.
-// Both these symbols are Thumb function symbols with external linkage.
-// <sym> may be redefined in .gnu.sgstubs.
-void elf::processArmCmseSymbols() {
- if (!config->cmseImplib)
- return;
- // Only symbols with external linkage end up in symtab, so no need to do
- // linkage checks. Only check symbol type.
- for (Symbol *acleSeSym : symtab.getSymbols()) {
- if (!acleSeSym->getName().startswith(ACLESESYM_PREFIX))
- continue;
- // If input object build attributes do not support CMSE, error and disable
- // further scanning for <sym>, __acle_se_<sym> pairs.
- if (!config->armCMSESupport) {
- error("CMSE is only supported by ARMv8-M architecture or later");
- config->cmseImplib = false;
- break;
- }
-
- // Try to find the associated symbol definition.
- // Symbol must have external linkage.
- StringRef name = acleSeSym->getName().substr(std::strlen(ACLESESYM_PREFIX));
- Symbol *sym = symtab.find(name);
- if (!sym) {
- error(toString(acleSeSym->file) + ": cmse special symbol '" +
- acleSeSym->getName() +
- "' detected, but no associated entry function definition '" + name +
- "' with external linkage found");
- continue;
- }
-
- std::string errMsg = checkCmseSymAttributes(acleSeSym, sym);
- if (!errMsg.empty()) {
- error(errMsg);
- continue;
- }
-
- // <sym> may be redefined later in the link in .gnu.sgstubs
- symtab.cmseSymMap[name] = {acleSeSym, sym};
- }
-
- // If this is an Arm CMSE secure app, replace references to entry symbol <sym>
- // with its corresponding special symbol __acle_se_<sym>.
- parallelForEach(ctx.objectFiles, [&](InputFile *file) {
- MutableArrayRef<Symbol *> syms = file->getMutableSymbols();
- for (size_t i = 0, e = syms.size(); i != e; ++i) {
- StringRef symName = syms[i]->getName();
- if (symtab.cmseSymMap.count(symName))
- syms[i] = symtab.cmseSymMap[symName].acleSeSym;
- }
- });
-}
-
-ArmCmseSGSection::ArmCmseSGSection()
- : SyntheticSection(llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
- llvm::ELF::SHT_PROGBITS,
- /*alignment=*/32, ".gnu.sgstubs") {
- entsize = ACLESESYM_SIZE;
- // The range of addresses used in the CMSE import library should be fixed.
- for (auto &[_, sym] : symtab.cmseImportLib) {
- if (impLibMaxAddr <= sym->value)
- impLibMaxAddr = sym->value + sym->size;
- }
- if (symtab.cmseSymMap.empty())
- return;
- addMappingSymbol();
- for (auto &[_, entryFunc] : symtab.cmseSymMap)
- addSGVeneer(cast<Defined>(entryFunc.acleSeSym),
- cast<Defined>(entryFunc.sym));
- for (auto &[_, sym] : symtab.cmseImportLib) {
- if (!symtab.inCMSEOutImpLib.count(sym->getName()))
- warn("entry function '" + sym->getName() +
- "' from CMSE import library is not present in secure application");
- }
-
- if (!symtab.cmseImportLib.empty() && config->cmseOutputLib.empty()) {
- for (auto &[_, entryFunc] : symtab.cmseSymMap) {
- Symbol *sym = entryFunc.sym;
- if (!symtab.inCMSEOutImpLib.count(sym->getName()))
- warn("new entry function '" + sym->getName() +
- "' introduced but no output import library specified");
- }
- }
-}
-
-void ArmCmseSGSection::addSGVeneer(Symbol *acleSeSym, Symbol *sym) {
- entries.emplace_back(acleSeSym, sym);
- if (symtab.cmseImportLib.count(sym->getName()))
- symtab.inCMSEOutImpLib[sym->getName()] = true;
- // Symbol addresses different, nothing to do.
- if (acleSeSym->file != sym->file ||
- cast<Defined>(*acleSeSym).value != cast<Defined>(*sym).value)
- return;
- // Only secure symbols with values equal to that of it's non-secure
- // counterpart needs to be in the .gnu.sgstubs section.
- ArmCmseSGVeneer *ss = nullptr;
- if (symtab.cmseImportLib.count(sym->getName())) {
- Defined *impSym = symtab.cmseImportLib[sym->getName()];
- ss = make<ArmCmseSGVeneer>(sym, acleSeSym, impSym->value);
- } else {
- ss = make<ArmCmseSGVeneer>(sym, acleSeSym);
- ++newEntries;
- }
- ss->parent = this;
- sgSections.emplace_back(ss);
-}
-
-void ArmCmseSGSection::writeTo(uint8_t *buf) {
- for (ArmCmseSGVeneer *s : sgSections)
- s->writeTo(buf + s->outSecOff - getVA());
-}
-
-void ArmCmseSGSection::addMappingSymbol() {
- addSyntheticLocal("$t", STT_NOTYPE, /*off=*/0, /*size=*/0, *this);
-}
-
-size_t ArmCmseSGSection::getSize() const {
- if (sgSections.empty())
- return (impLibMaxAddr ? impLibMaxAddr - getVA() : 0) + newEntries * entsize;
-
- return entries.size() * entsize;
-}
-
-void ArmCmseSGSection::finalizeContents() {
- if (sgSections.empty())
- return;
-
- auto it =
- std::stable_partition(sgSections.begin(), sgSections.end(),
- [](auto *i) { return i->getAddr().has_value(); });
- std::sort(sgSections.begin(), it, [](auto *a, auto *b) {
- return a->getAddr().value() < b->getAddr().value();
- });
-
- // This is the partition of the veneers with fixed addresses.
- uint64_t addr = (*sgSections.begin())->getAddr().has_value()
- ? (*sgSections.begin())->getAddr().value()
- : getVA();
- // Check if the start address of '.gnu.sgstubs' correspond to the
- // linker-synthesized veneer with the lowest address.
- if ((getVA() & ~1) != (addr & ~1)) {
- error("start address of '.gnu.sgstubs' is different from previous link");
- return;
- }
-
- for (ArmCmseSGVeneer *s : sgSections) {
- if (!s->getAddr().has_value())
- break;
- s->outSecOff = s->getAddr().value() & ~1;
- Defined(s->file, StringRef(), s->sym->binding, s->sym->stOther,
- s->sym->type, (s->outSecOff - getVA()) | 1, entsize, this)
- .overwrite(*s->sym);
- }
- // This is the partition of veneers newly synthesized by the linker.
- size_t off = std::max(getVA(), impLibMaxAddr);
- for (ArmCmseSGVeneer *s : llvm::reverse(sgSections)) {
- if (s->getAddr().has_value())
- break;
- s->outSecOff = off & ~1;
- Defined(s->file, StringRef(), s->sym->binding, s->sym->stOther,
- s->sym->type, (s->outSecOff - getVA()) | 1, entsize, this)
- .overwrite(*s->sym);
- off += s->entsize;
- }
-}
-
-void ArmCmseSGVeneer::writeTo(uint8_t *buf) {
- write16(buf + 0, 0xe97f); // SG
- write16(buf + 2, 0xe97f);
- write16(buf + 4, 0xf000); // B.W S
- write16(buf + 6, 0xb000);
- target->relocateNoSym(buf + 4, R_ARM_THM_JUMP24,
- acleSeSym->getVA() - getVA() - 8);
-}
-
-// Write the CMSE import library to disk.
-// The CMSE import library is a relocatable object with only a symbol table.
-// The symbols are copies of the (absolute) symbols of the secure gateways
-// in the executable output by this link.
-// See ArmĀ® v8-M Security Extensions: Requirements on Development Tools
-// https://developer.arm.com/documentation/ecm0359818/latest
-template <typename ELFT> void elf::writeARMCmseImportLib() {
- StringTableSection *shstrtab =
- make<StringTableSection>(".shstrtab", /*dynamic=*/false);
- StringTableSection *strtab =
- make<StringTableSection>(".strtab", /*dynamic=*/false);
- SymbolTableBaseSection *impSymTab = make<SymbolTableSection<ELFT>>(*strtab);
-
- SmallVector<std::pair<OutputSection *, SyntheticSection *>, 0> osIsPairs;
- osIsPairs.emplace_back(make<OutputSection>(strtab->name, 0, 0), strtab);
- osIsPairs.emplace_back(make<OutputSection>(impSymTab->name, 0, 0), impSymTab);
- osIsPairs.emplace_back(make<OutputSection>(shstrtab->name, 0, 0), shstrtab);
-
- std::sort(symtab.cmseSymMap.begin(), symtab.cmseSymMap.end(),
- [](const auto &a, const auto &b) -> bool {
- return a.second.sym->getVA() < b.second.sym->getVA();
- });
- // Copy the secure gateway entry symbols to the import library symbol table.
- for (auto &p : symtab.cmseSymMap) {
- Defined *d = cast<Defined>(p.second.sym);
- impSymTab->addSymbol(makeDefined(nullptr, d->getName(), d->computeBinding(),
- /*stOther=*/0, STT_FUNC, d->getVA(),
- d->getSize(), nullptr));
- }
-
- size_t idx = 0;
- uint64_t off = sizeof(typename ELFT::Ehdr);
- for (auto &[osec, isec] : osIsPairs) {
- osec->sectionIndex = ++idx;
- osec->recordSection(isec);
- osec->finalizeInputSections();
- osec->shName = shstrtab->addString(osec->name);
- osec->size = isec->getSize();
- isec->finalizeContents();
- osec->offset = alignToPowerOf2(off, osec->addralign);
- off = osec->offset + osec->size;
- }
-
- const uint64_t sectionHeaderOff = alignToPowerOf2(off, config->wordsize);
- const auto shnum = osIsPairs.size() + 1;
- const uint64_t fileSize =
- sectionHeaderOff + shnum * sizeof(typename ELFT::Shdr);
- const unsigned flags =
- config->mmapOutputFile ? 0 : (unsigned)FileOutputBuffer::F_no_mmap;
- unlinkAsync(config->cmseOutputLib);
- Expected<std::unique_ptr<FileOutputBuffer>> bufferOrErr =
- FileOutputBuffer::create(config->cmseOutputLib, fileSize, flags);
- if (!bufferOrErr) {
- error("failed to open " + config->cmseOutputLib + ": " +
- llvm::toString(bufferOrErr.takeError()));
- return;
- }
-
- // Write the ELF Header
- std::unique_ptr<FileOutputBuffer> &buffer = *bufferOrErr;
- uint8_t *const buf = buffer->getBufferStart();
- memcpy(buf, "\177ELF", 4);
- auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf);
- eHdr->e_type = ET_REL;
- eHdr->e_entry = 0;
- eHdr->e_shoff = sectionHeaderOff;
- eHdr->e_ident[EI_CLASS] = ELFCLASS32;
- eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB;
- eHdr->e_ident[EI_VERSION] = EV_CURRENT;
- eHdr->e_ident[EI_OSABI] = config->osabi;
- eHdr->e_ident[EI_ABIVERSION] = 0;
- eHdr->e_machine = EM_ARM;
- eHdr->e_version = EV_CURRENT;
- eHdr->e_flags = config->eflags;
- eHdr->e_ehsize = sizeof(typename ELFT::Ehdr);
- eHdr->e_phnum = 0;
- eHdr->e_shentsize = sizeof(typename ELFT::Shdr);
- eHdr->e_phoff = 0;
- eHdr->e_phentsize = 0;
- eHdr->e_shnum = shnum;
- eHdr->e_shstrndx = shstrtab->getParent()->sectionIndex;
-
- // Write the section header table.
- auto *sHdrs = reinterpret_cast<typename ELFT::Shdr *>(buf + eHdr->e_shoff);
- for (auto &[osec, _] : osIsPairs)
- osec->template writeHeaderTo<ELFT>(++sHdrs);
-
- // Write section contents to a mmap'ed file.
- {
- parallel::TaskGroup tg;
- for (auto &[osec, _] : osIsPairs)
- osec->template writeTo<ELFT>(buf + osec->offset, tg);
- }
-
- if (auto e = buffer->commit())
- fatal("failed to write output '" + buffer->getPath() +
- "': " + toString(std::move(e)));
-}
-
TargetInfo *elf::getARMTargetInfo() {
static ARM target;
return ⌖
}
-template void elf::writeARMCmseImportLib<ELF32LE>();
-template void elf::writeARMCmseImportLib<ELF32BE>();
-template void elf::writeARMCmseImportLib<ELF64LE>();
-template void elf::writeARMCmseImportLib<ELF64BE>();
-
-template void ObjFile<ELF32LE>::importCmseSymbols();
-template void ObjFile<ELF32BE>::importCmseSymbols();
-template void ObjFile<ELF64LE>::importCmseSymbols();
-template void ObjFile<ELF64BE>::importCmseSymbols();
std::unique_ptr<BitcodeCompiler> lto;
std::vector<InputFile *> files;
- std::optional<InputFile *> armCmseImpLib;
public:
SmallVector<std::pair<StringRef, unsigned>, 0> archiveFiles;
llvm::StringRef thinLTOCacheDir;
llvm::StringRef thinLTOIndexOnlyArg;
llvm::StringRef whyExtract;
- llvm::StringRef cmseInputLib;
- llvm::StringRef cmseOutputLib;
StringRef zBtiReport = "none";
StringRef zCetReport = "none";
llvm::StringRef ltoBasicBlockSections;
llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>,
uint64_t>
callGraphProfile;
- bool cmseImplib = false;
bool allowMultipleDefinition;
bool androidPackDynRelocs = false;
bool armHasBlx = false;
bool armHasMovtMovw = false;
bool armJ1J2BranchEncoding = false;
- bool armCMSESupport = false;
bool asNeeded = false;
BsymbolicKind bsymbolic = BsymbolicKind::None;
bool callGraphProfileSort;
if (config->emachine == EM_MIPS && config->gnuHash)
error("the .gnu.hash section is not compatible with the MIPS target");
- if (config->emachine == EM_ARM) {
- if (!config->cmseImplib) {
- if (!config->cmseInputLib.empty())
- error("--in-implib may not be used without --cmse-implib");
- if (!config->cmseOutputLib.empty())
- error("--out-implib may not be used without --cmse-implib");
- }
- } else {
- if (config->cmseImplib)
- error("--cmse-implib is only supported on ARM targets");
- if (!config->cmseInputLib.empty())
- error("--in-implib is only supported on ARM targets");
- if (!config->cmseOutputLib.empty())
- error("--out-implib is only supported on ARM targets");
- }
-
if (config->fixCortexA53Errata843419 && config->emachine != EM_AARCH64)
error("--fix-cortex-a53-843419 is only supported on AArch64 targets");
config->fini = args.getLastArgValue(OPT_fini, "_fini");
config->fixCortexA53Errata843419 = args.hasArg(OPT_fix_cortex_a53_843419) &&
!args.hasArg(OPT_relocatable);
- config->cmseImplib = args.hasArg(OPT_cmse_implib);
- config->cmseInputLib = args.getLastArgValue(OPT_in_implib);
- config->cmseOutputLib = args.getLastArgValue(OPT_out_implib);
config->fixCortexA8 =
args.hasArg(OPT_fix_cortex_a8) && !args.hasArg(OPT_relocatable);
config->fortranCommon =
files.back()->justSymbols = true;
}
break;
- case OPT_in_implib:
- if (armCmseImpLib)
- error("multiple CMSE import libraries not supported");
- else if (std::optional<MemoryBufferRef> mb = readFile(arg->getValue()))
- armCmseImpLib = createObjFile(*mb);
- break;
case OPT_start_group:
if (InputFile::isInGroup)
error("nested --start-group");
llvm::TimeTraceScope timeScope("Parse input files", files[i]->getName());
parseFile(files[i]);
}
- if (armCmseImpLib)
- parseArmCMSEImportLib(*armCmseImpLib);
}
// Now that we have every file, we can decide if we will need a
if (args.hasArg(OPT_exclude_libs))
excludeLibs(args);
- // Record [__acle_se_<sym>, <sym>] pairs for later processing.
- processArmCmseSymbols();
-
// Apply symbol renames for --wrap and combine foo@v1 and foo@@v1.
redirectSymbols(wrapped);
config->armHasMovtMovw = true;
break;
}
-
- // Only ARMv8-M or later architectures have CMSE support.
- std::optional<unsigned> profile =
- attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile);
- if (!profile)
- return;
- if (arch >= ARMBuildAttrs::CPUArch::v8_M_Base &&
- profile == ARMBuildAttrs::MicroControllerProfile)
- config->armCMSESupport = true;
}
InputFile::InputFile(Kind k, MemoryBufferRef m)
// Add symbols in File to the symbol table.
void elf::parseFile(InputFile *file) { invokeELFT(doParseFile, file); }
-template <class ELFT> static void doParseArmCMSEImportLib(InputFile *file) {
- cast<ObjFile<ELFT>>(file)->importCmseSymbols();
-}
-
-void elf::parseArmCMSEImportLib(InputFile *file) {
- invokeELFT(doParseArmCMSEImportLib, file);
-}
-
// Concatenates arguments to construct a string representing an error location.
static std::string createFileLineMsg(StringRef path, unsigned line) {
std::string filename = std::string(path::filename(path));
return makeThreadLocal<InputSection>(*this, sec, name);
}
-// Initialize symbols. symbols is a parallel array to the corresponding ELF
-// symbol table.
+// Initialize this->Symbols. this->Symbols is a parallel array as
+// its corresponding ELF symbol table.
template <class ELFT>
void ObjFile<ELFT>::initializeSymbols(const object::ELFFile<ELFT> &obj) {
ArrayRef<Elf_Sym> eSyms = this->getELFSyms<ELFT>();
// Add symbols in File to the symbol table.
void parseFile(InputFile *file);
-void parseArmCMSEImportLib(InputFile *file);
-
// The root class of input files.
class InputFile {
protected:
return {symbols.get(), numSymbols};
}
- MutableArrayRef<Symbol *> getMutableSymbols() {
- assert(fileKind == BinaryKind || fileKind == ObjKind ||
- fileKind == BitcodeKind);
- return {symbols.get(), numSymbols};
- }
-
// Get filename to use for linker script processing.
StringRef getNameForScript() const;
void initSectionsAndLocalSyms(bool ignoreComdats);
void postParse();
- void importCmseSymbols();
- void redirectCmseSymbols();
private:
void initializeSections(bool ignoreComdats,
}
}
-void LinkerScript::diagnoseMissingSGSectionAddress() const {
- if (!config->cmseImplib || !in.armCmseSGSection->isNeeded())
- return;
-
- OutputSection *sec = findByName(sectionCommands, ".gnu.sgstubs");
- if (sec && !sec->addrExpr && !config->sectionStartMap.count(".gnu.sgstubs"))
- error("no address assigned to the veneers output section " + sec->name);
-}
-
// This function searches for a memory region to place the given output
// section in. If found, a pointer to the appropriate memory region is
// returned in the first member of the pair. Otherwise, a nullptr is returned.
void addOrphanSections();
void diagnoseOrphanHandling() const;
- void diagnoseMissingSGSectionAddress() const;
void adjustOutputSections();
void adjustSectionsAfterSorting();
markSymbol(symtab.find(s));
for (StringRef s : script->referencedSymbols)
markSymbol(symtab.find(s));
- for (auto [symName, _] : symtab.cmseSymMap) {
- markSymbol(symtab.cmseSymMap[symName].sym);
- markSymbol(symtab.cmseSymMap[symName].acleSeSym);
- }
// Mark .eh_frame sections as live because there are usually no relocations
// that point to .eh_frames. Otherwise, the garbage collector would drop
def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
-def cmse_implib: FF<"cmse-implib">,
- HelpText<"Make the output library to be a CMSE secure code import library">;
-
-defm in_implib: EEq<"in-implib",
- "Read an existing CMSE secure code import library and preserve entry function addresses in the "
- "resulting new CMSE secure code import library (optional when creating a CMSE secure image)">,
- MetaVarName<"<file>">;
-
-defm out_implib: EEq<"out-implib",
- "Output the CMSE secure code import library to <file> (required when creating a CMSE secure image)">,
- MetaVarName<"<file>">;
-
defm Tbss: Eq<"Tbss", "Same as --section-start with .bss as the sectionname">;
defm Tdata: Eq<"Tdata", "Same as --section-start with .data as the sectionname">;
class InputFile;
class SharedFile;
-struct ArmCmseEntryFunction {
- Symbol *acleSeSym;
- Symbol *sym;
-};
-
// SymbolTable is a bucket of all known symbols, including defined,
// undefined, or lazy symbols (the last one is symbols in archive
// files whose archive members are not yet loaded).
// is used to uniquify them.
llvm::DenseMap<llvm::CachedHashStringRef, const InputFile *> comdatGroups;
- // The Map of __acle_se_<sym>, <sym> pairs found in the input objects.
- // Key is the <sym> name.
- llvm::SmallMapVector<StringRef, ArmCmseEntryFunction, 1> cmseSymMap;
-
- // Map of symbols defined in the Arm CMSE import library. The linker must
- // preserve the addresses in the output objects.
- llvm::StringMap<Defined *> cmseImportLib;
-
- // True if <sym> from the input Arm CMSE import library is written to the
- // output Arm CMSE import library.
- llvm::StringMap<bool> inCMSEOutImpLib;
-
private:
SmallVector<Symbol *, 0> findByVersion(SymbolVersion ver);
SmallVector<Symbol *, 0> findAllByVersion(SymbolVersion ver,
got.reset();
gotPlt.reset();
igotPlt.reset();
- armCmseSGSection.reset();
ppc64LongBranchTarget.reset();
mipsAbiFlags.reset();
mipsGot.reset();
size_t size = 0;
};
-// Cortex-M Security Extensions. Prefix for functions that should be exported
-// for the non-secure world.
-const char ACLESESYM_PREFIX[] = "__acle_se_";
-const int ACLESESYM_SIZE = 8;
-
-class ArmCmseSGVeneer : public SyntheticSection {
-public:
- ArmCmseSGVeneer(Symbol *sym, Symbol *acleSeSym,
- std::optional<uint64_t> addr = std::nullopt)
- : SyntheticSection(llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
- llvm::ELF::SHT_PROGBITS,
- /*alignment=*/32, ".gnu.sgstubs"),
- sym(sym), acleSeSym(acleSeSym), entAddr{addr} {
- entsize = ACLESESYM_SIZE;
- }
-
- void writeTo(uint8_t *buf) override;
- size_t getSize() const override { return entsize; };
- const std::optional<uint64_t> getAddr() const { return entAddr; };
-
- Symbol *sym;
- Symbol *acleSeSym;
-
-private:
- const std::optional<uint64_t> entAddr;
-};
-
-class ArmCmseSGSection : public SyntheticSection {
-public:
- ArmCmseSGSection();
- bool isNeeded() const override { return !entries.empty(); }
- size_t getSize() const override;
- void writeTo(uint8_t *buf) override;
- void addSGVeneer(Symbol *sym, Symbol *ext_sym);
- void addMappingSymbol();
- void finalizeContents() override;
- void exportEntries(SymbolTableBaseSection *symTab);
- uint64_t impLibMaxAddr = 0;
-
-private:
- SmallVector<std::pair<Symbol *, Symbol *>, 0> entries;
- SmallVector<ArmCmseSGVeneer *, 0> sgSections;
- uint64_t newEntries = 0;
-};
-
// Used to compute outSecOff of .got2 in each object file. This is needed to
// synthesize PLT entries for PPC32 Secure PLT ABI.
class PPC32Got2Section final : public SyntheticSection {
std::unique_ptr<GotSection> got;
std::unique_ptr<GotPltSection> gotPlt;
std::unique_ptr<IgotPltSection> igotPlt;
- std::unique_ptr<SyntheticSection> armCmseSGSection;
std::unique_ptr<PPC64LongBranchTargetSection> ppc64LongBranchTarget;
std::unique_ptr<SyntheticSection> mipsAbiFlags;
std::unique_ptr<MipsGotSection> mipsGot;
return getErrorPlace(loc).loc;
}
-void processArmCmseSymbols();
-
void writePPC32GlinkSection(uint8_t *buf, size_t numEntries);
unsigned getPPCDFormOp(unsigned secondaryOp);
void addPPC64SaveRestore();
uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t expr);
-template <typename ELFT> void writeARMCmseImportLib();
void riscvFinalizeRelax(int passes);
void mergeRISCVAttributesSections();
in.igotPlt = std::make_unique<IgotPltSection>();
add(*in.igotPlt);
- if (config->emachine == EM_ARM) {
- in.armCmseSGSection = std::make_unique<ArmCmseSGSection>();
- add(*in.armCmseSGSection);
- }
-
// _GLOBAL_OFFSET_TABLE_ is defined relative to either .got.plt or .got. Treat
// it as a relocation and ensure the referenced section is created.
if (ElfSym::globalOffsetTable && config->emachine != EM_MIPS) {
if (auto e = buffer->commit())
fatal("failed to write output '" + buffer->getPath() +
"': " + toString(std::move(e)));
-
- if (!config->cmseOutputLib.empty())
- writeARMCmseImportLib<ELFT>();
}
}
removeUnusedSyntheticSections();
script->diagnoseOrphanHandling();
- script->diagnoseMissingSGSectionAddress();
sortSections();
// static symbol table.
finalizeSynthetic(in.symTab.get());
finalizeSynthetic(in.ppc64LongBranchTarget.get());
- finalizeSynthetic(in.armCmseSGSection.get());
}
// Relaxation to delete inter-basic block jumps created by basic block
+++ /dev/null
-/// Because the addresses of __acle_se_\sym_name and \sym_name are equal,
-/// the linker creates a secure gateway in ".gnu.sgstubs".
-.macro cmse_veneer sym_name, sym_type, sym_binding, acle_sym_type, acle_sym_binding
-.align 2
-.\sym_binding \sym_name
-.\acle_sym_binding __acle_se_\sym_name
-.type \sym_name, %\sym_type
-.type __acle_se_\sym_name, %\acle_sym_type
-\sym_name:
-__acle_se_\sym_name:
- nop
-.size \sym_name, .-\sym_name
-.size __acle_se_\sym_name, .-__acle_se_\sym_name
-.endm
-
-/// Because the addresses of __acle_se_\sym_name and \sym_name are not equal,
-/// the linker considers that an inline secure gateway exists and does not
-/// create one.
-.macro cmse_no_veneer sym_name, sym_type, sym_binding, acle_sym_type, acle_sym_binding
-.align 2
-.\sym_binding \sym_name
-.\acle_sym_binding __acle_se_\sym_name
-.type \sym_name, %\sym_type
-.type __acle_se_\sym_name, %\acle_sym_type
-\sym_name:
- sg
- nop
-__acle_se_\sym_name:
- nop
-.size \sym_name, .-\sym_name
-.size __acle_se_\sym_name, .-__acle_se_\sym_name
-.endm
+++ /dev/null
-# REQUIRES: aarch64
-# RUN: yaml2obj %s -o %t.o
-# RUN: not ld.lld --cmse-implib %t.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR_CMSE_IMPLIB
-# RUN: not ld.lld --in-implib=%t.o %t.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR_IN_IMPLIB
-# RUN: not ld.lld --out-implib=out.lib %t.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR_OUT_IMPLIB
-
-# ERR_CMSE_IMPLIB: error: --cmse-implib is only supported on ARM targets
-# ERR_IN_IMPLIB: error: --in-implib is only supported on ARM targets
-# ERR_OUT_IMPLIB: error: --out-implib is only supported on ARM targets
-
-!ELF
-FileHeader:
- Class: ELFCLASS64
- Data: ELFDATA2LSB
- Type: ET_REL
- Machine: EM_AARCH64
+++ /dev/null
-// REQUIRES: arm
-/// Test CMSE diagnostics.
-
-// RUN: rm -rf %t && split-file %s %t && cd %t
-
-/// Test diagnostics emitted during checks of the CMSE import library
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.base lib -o lib.o
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.base app -I %S/Inputs -o app.o
-// RUN: llvm-objcopy --redefine-sym=entry7_duplicate=entry6_duplicate lib.o
-// RUN: not ld.lld --cmse-implib --in-implib=lib.o app.o -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR_IMPLIB
-// RUN: not ld.lld --cmse-implib --in-implib=lib.o --in-implib=lib.o app.o -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR_MULT_INIMPLIB
-// RUN: not ld.lld --in-implib=lib.o app.o -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR_IN_IMPLIB
-// RUN: not ld.lld --out-implib=out.lib app.o -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR_OUT_IMPLIB
-// RUN: not ld.lld --out-implib=out.lib --in-implib=lib.o app.o -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR_IN_IMPLIB,ERR_OUT_IMPLIB
-
-// ERR_IMPLIB: error: CMSE symbol 'entry_not_external' in import library '{{.*}}' is not global
-// ERR_IMPLIB: error: CMSE symbol 'entry_not_absolute' in import library '{{.*}}' is not absolute
-// ERR_IMPLIB: error: CMSE symbol 'entry_not_function' in import library '{{.*}}' is not a Thumb function definition
-// ERR_IMPLIB: error: CMSE symbol 'entry_not_thumb' in import library '{{.*}}' is not a Thumb function definition
-// ERR_IMPLIB: warning: CMSE symbol 'entry5_incorrect_size' in import library '{{.*}}' does not have correct size of 8 bytes
-// ERR_IMPLIB: error: CMSE symbol 'entry6_duplicate' is multiply defined in import library '{{.*}}'
-// ERR_MULT_INIMPLIB: error: multiple CMSE import libraries not supported
-// ERR_IN_IMPLIB: error: --in-implib may not be used without --cmse-implib
-// ERR_OUT_IMPLIB: error: --out-implib may not be used without --cmse-implib
-
-/// CMSE Only supported by ARMv8-M architecture or later.
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv8m.base app -I %S/Inputs -o app1.o
-// RUN: ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o app1 app1.o 2>&1 | FileCheck /dev/null --implicit-check-not=error:
-
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv8m.main app -I %S/Inputs -o app2.o
-// RUN: ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o app2 app2.o 2>&1 | FileCheck /dev/null --implicit-check-not=error:
-
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv8.1m.main app -I %S/Inputs -o app3.o
-// RUN: ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o app3 app3.o 2>&1 | FileCheck /dev/null --implicit-check-not=error:
-
-/// Expect errors for other architectures.
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv9a app -I %S/Inputs -o app4.o
-// RUN: not ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o app4 app4.o 2>&1 | FileCheck %s --check-prefixes=ERR_ARCH
-
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7-m app -I %S/Inputs -o app5.o
-// RUN: not ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o app5 app5.o 2>&1 | FileCheck %s --check-prefixes=ERR_ARCH
-
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv8-m app -I %S/Inputs -o app6.o
-// RUN: not ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o app6 app6.o 2>&1 | FileCheck %s --check-prefixes=ERR_ARCH
-
-/// Invalid triple defaults to v4T. Error.
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumb app -I %S/Inputs -o app7.o
-// RUN: not ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o app7 app7.o 2>&1 | FileCheck %s --check-prefixes=ERR_ARCH
-
-/// No build attributes. Error.
-// RUN: llvm-mc -filetype=obj -triple=thumb app -I %S/Inputs -o app8.o
-// RUN: not ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o app8 app8.o 2>&1 | FileCheck %s --check-prefixes=ERR_ARCH
-
-// ERR_ARCH: CMSE is only supported by ARMv8-M architecture or later
-
-/// Test that the linker diagnoses cases where the linker synthesized veneer addresses
-/// specified by the CMSE input library cannot be placed at the .gnu.sgstubs section address.
-
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.main app -I %S/Inputs -o 1.o
-/// Create a CMSE import library with a secure gateway veneer at 0x10000
-// RUN: ld.lld --cmse-implib --section-start .gnu.sgstubs=0x10000 1.o -o 1 --out-implib=1.lib 2>&1 | FileCheck /dev/null --implicit-check-not=error:
-/// Create a new import library with the secure gateway veneer and .gnu.sgstubs specified at the same address
-// RUN: ld.lld --cmse-implib --section-start .gnu.sgstubs=0x10000 1.o -o 2 --out-implib=2.lib --in-implib=1.lib 2>&1 | FileCheck /dev/null --implicit-check-not=error:
-/// Create a new import library with the secure gateway veneer specified at a same address but .gnu.sgstubs at a higher address.
-// RUN: not ld.lld --cmse-implib --section-start .gnu.sgstubs=0x11000 1.o -o 3 --out-implib=3.lib --in-implib=1.lib 2>&1 | FileCheck %s --check-prefixes=ERR_ADDR
-/// Create a new import library with the secure gateway veneer specified at a same address but .gnu.sgstubs at a lower address.
-// RUN: not ld.lld --cmse-implib --section-start .gnu.sgstubs=0x9000 1.o -o 4 --out-implib=4.lib --in-implib=1.lib 2>&1 | FileCheck %s --check-prefixes=ERR_ADDR
-
-// ERR_ADDR: error: start address of '.gnu.sgstubs' is different from previous link
-
-/// Test that the address of .gnu.sgstubs can be specified via command line or linker script.
-/// Test that the linker errors when the address of .gnu.sgstubs is not specified using either method.
-
-// RUN: ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --script with_sgstubs.script 1.o -o 1 2>&1 | FileCheck /dev/null --implicit-check-not=error:
-// RUN: ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --script wout_sgstubs.script 1.o -o 2 2>&1 | FileCheck /dev/null --implicit-check-not=error:
-// RUN: ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 1.o -o 3 2>&1 | FileCheck /dev/null --implicit-check-not=error:
-// RUN: ld.lld --cmse-implib -Ttext=0x8000 --script with_sgstubs.script 1.o -o 4 2>&1 | FileCheck /dev/null --implicit-check-not=error:
-// RUN: not ld.lld --cmse-implib -Ttext=0x8000 --script wout_sgstubs.script 1.o -o 5 2>&1 | FileCheck %s --check-prefixes=ERR_NOADDR
-
-// RUN: llvm-readelf -S 1 | FileCheck %s --check-prefixes=ADDRCMDLINE
-// RUN: llvm-readelf -S 2 | FileCheck %s --check-prefixes=ADDRCMDLINE
-// RUN: llvm-readelf -S 3 | FileCheck %s --check-prefixes=ADDRCMDLINE
-// RUN: llvm-readelf -S 4 | FileCheck %s --check-prefixes=ADDRLNKSCRIPT
-
-// ERR_NOADDR: error: no address assigned to the veneers output section .gnu.sgstubs
-
-/// Name Type Address Off Size ES Flg Lk Inf Al
-// ADDRCMDLINE: .gnu.sgstubs PROGBITS 00020000 020000 000008 08 AX 0 0 32
-// ADDRLNKSCRIPT: .gnu.sgstubs PROGBITS 00040000 040000 000008 08 AX 0 0 32
-
-/// Test diagnostics emitted during symbol attribute checks.
-
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -I %S/Inputs --triple=thumbv8m.base symattr -o symattr.o
-// RUN: not ld.lld --cmse-implib symattr.o -o /dev/null 2>&1 | FileCheck %s --check-prefixes=ERR_SYMATTR
-
-// ERR_SYMATTR-NOT: __acle_se_valid_{{.*}}
-// ERR_SYMATTR: error: {{.*}}: cmse special symbol '__acle_se_invalid_1' is not a Thumb function definition
-// ERR_SYMATTR: error: {{.*}}: cmse special symbol '__acle_se_invalid_2' is not a Thumb function definition
-// ERR_SYMATTR: error: {{.*}}: cmse entry symbol 'invalid_3' is not a Thumb function definition
-// ERR_SYMATTR: error: {{.*}}: cmse entry symbol 'invalid_4' is not a Thumb function definition
-// ERR_SYMATTR: error: {{.*}}: cmse special symbol '__acle_se_invalid_5' detected, but no associated entry function definition 'invalid_5' with external linkage found
-// ERR_SYMATTR: error: {{.*}}: cmse special symbol '__acle_se_invalid_6' detected, but no associated entry function definition 'invalid_6' with external linkage found
-// ERR_SYMATTR: error: {{.*}}: cmse special symbol '__acle_se_invalid_7' is not a Thumb function definition
-// ERR_SYMATTR: error: {{.*}}: cmse special symbol '__acle_se_invalid_8' detected, but no associated entry function definition 'invalid_8' with external linkage found
-// ERR_SYMATTR: error: {{.*}}: cmse special symbol '__acle_se_invalid_9' cannot be an absolute symbol
-// ERR_SYMATTR: error: {{.*}}: cmse special symbol '__acle_se_invalid_10' cannot be an absolute symbol
-// ERR_SYMATTR: error: {{.*}}: cmse special symbol '__acle_se_invalid_11' is not a Thumb function definition
-// ERR_SYMATTR: error: {{.*}}: cmse entry symbol 'invalid_12' is not a Thumb function definition
-
-/// Test diagnostics emitted when a symbol is removed from a later version of the import library.
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -I %S/Inputs --triple=thumbv8m.base libv1 -o libv1.o
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -I %S/Inputs --triple=thumbv8m.base libv2 -o libv2.o
-// RUN: ld.lld -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --cmse-implib libv1.o --out-implib=libv1.lib -o /dev/null
-// RUN: ld.lld -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --cmse-implib libv2.o --in-implib=libv1.lib --out-implib=libv2.lib -o /dev/null 2>&1 | FileCheck %s --check-prefixes=WARN_MISSING
-// RUN: ld.lld -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 --cmse-implib libv1.o --in-implib=libv2.lib -o /dev/null 2>&1 | FileCheck %s --check-prefixes=WARN_NEWENTRY
-
-// WARN_MISSING: warning: entry function 'foo' from CMSE import library is not present in secure application
-// WARN_NEWENTRY: warning: new entry function 'foo' introduced but no output import library specified
-
-//--- with_sgstubs.script
-SECTIONS {
- .text : { *(.text) }
- .gnu.sgstubs 0x40000 : { *(.gnu.sgstubs*) }
-}
-
-//--- wout_sgstubs.script
-SECTIONS {
- .text : { *(.text) }
-}
-
-//--- app
- .include "arm-cmse-macros.s"
- .text
- .thumb
-
-cmse_veneer entry, function, global, function, global
-
-//--- lib
- .text
- .thumb
-
-/// Symbol not absolute.
- .global entry_not_absolute
- .type entry_not_absolute, STT_FUNC
- .thumb_func
-entry_not_absolute:
- .size entry_not_absolute, 8
-
-/// Symbol not global or weak.
- .local entry_not_external
- .type entry_not_external, STT_FUNC
-entry_not_external=0x1001
- .size entry_not_external, 8
-
-/// Symbol not the function type.
- .global entry_not_function
- .type entry_not_function, STT_NOTYPE
-entry_not_function=0x1001
- .size entry_not_function, 8
-
-/// Symbol not a Thumb code symbol.
- .global entry_not_thumb
- .type entry_not_thumb, STT_FUNC
-entry_not_thumb=0x1000
- .size entry_not_thumb, 8
-
-/// Symbol with incorrect size.
- .global entry5_incorrect_size
- .type entry5_incorrect_size, STT_FUNC
-entry5_incorrect_size=0x1009
- .size entry5_incorrect_size, 6
-
-/// Duplicate symbols.
- .global entry6_duplicate
- .type entry6_duplicate, STT_FUNC
-entry6_duplicate=0x1001
- .size entry6_duplicate, 8
-
-/// entry7_duplicate gets renamed to entry6_duplicate by llvm-objcopy.
- .global entry7_duplicate
- .type entry7_duplicate, STT_FUNC
-entry7_duplicate=0x1009
- .size entry7_duplicate, 8
-
-//--- symattr
-.include "arm-cmse-macros.s"
-
- .text
- .thumb
-
-/// Valid sequences
-/// both sym and __acle_se_sym should be global or weak Thumb code symbols.
- cmse_veneer valid_1, function, global, function, global
- cmse_veneer valid_2, function, weak, function, weak
- cmse_veneer valid_3, function, weak, function, global
- cmse_veneer valid_4, function, global, function, weak
-
-/// Invalid sequences
-/// __acle_se_sym is an object
- cmse_veneer invalid_1, function, global, object, global
- cmse_veneer invalid_2, function, global, object, weak
-/// sym is an object
- cmse_veneer invalid_3, object, global, function, global
- cmse_veneer invalid_4, object, global, function, weak
-/// sym is local
- cmse_veneer invalid_5, function, local, function, global
- cmse_veneer invalid_6, function, local, function, weak
-
-/// __acle_se_invalid_7 not defined.
- .global invalid_7
- .type invalid_7, %function
- .global __acle_se_invalid_7
- .thumb_func
-invalid_7:
-
-/// invalid_8 not defined.
- .global __acle_se_invalid_8
- .thumb_func
-__acle_se_invalid_8:
-
-// Absolute symbols with same values
- .global invalid_9
- .global __acle_se_invalid_9
- .type __acle_se_invalid_9, %function
- .type invalid_9, %function
-__acle_se_invalid_9=0x1001
-invalid_9=0x1001
- .size invalid_9, 0
- .size __acle_se_invalid_9, 0
-
-// Absolute symbols with different values
- .align 2
- .global __acle_se_invalid_10
- .global invalid_10
- .type __acle_se_invalid_10, %function
- .type invalid_10, %function
-__acle_se_invalid_10 = 0x10001
-invalid_10 = 0x10005
- .size invalid_10, 0
- .size __acle_se_invalid_10, 0
-
- .section nonthumb
- .thumb
- .align 2
- .global invalid_11
- .global __acle_se_invalid_11
- .type invalid_11, %function
- .type __acle_se_invalid_11, %function
-invalid_11:
- .size invalid_11, .-invalid_11
-/// Invalid non-thumb function symbol __acle_se_invalid_11
-__acle_se_invalid_11=0x1000
-
- .global invalid_12
- .global __acle_se_invalid_12
- .type invalid_12, %function
- .type __acle_se_invalid_12, %function
-/// Invalid non-thumb function symbol invalid_12
-invalid_12=0x1000
- .thumb
-__acle_se_invalid_12:
- .size __acle_se_invalid_12, .-__acle_se_invalid_12
-
-//--- libv1
-.include "arm-cmse-macros.s"
-
- .text
- .thumb
-
-/// Import library version 1 with foo and bar
- cmse_veneer foo, function, global, function, global
- cmse_veneer bar, function, weak, function, weak
-
-//--- libv2
-.include "arm-cmse-macros.s"
-
- .text
- .thumb
-
-/// Import library version 2 with bar missing.
- cmse_veneer bar, function, weak, function, weak
+++ /dev/null
-// REQUIRES: arm
-/// Test that addresses of secure gateways in an old import library are maintained in new import libraries.
-
-// RUN: rm -rf %t && split-file %s %t && cd %t
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.base app -o app.o
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.base implib-v1 -I %S/Inputs -o 1.o
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.base implib-v2 -I %S/Inputs -o 2.o
-
-// RUN: ld.lld -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o 1 app.o --out-implib=1.lib --cmse-implib 1.o
-// RUN: llvm-readelf -s 1 1.lib | FileCheck %s --check-prefixes=CHECK1
-
-// RUN: ld.lld -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 -o 2 app.o --out-implib=2.lib --in-implib=1.lib --cmse-implib 2.o
-// RUN: llvm-readelf -s 2 2.lib | FileCheck %s --check-prefixes=CHECK2
-
-//--- app
-
- .align 2
- .global secure_entry
- .type secure_entry, %function
-secure_entry:
- nop
- .size secure_entry, .-secure_entry
-
-//--- implib-v1
-
- .include "arm-cmse-macros.s"
-
- .syntax unified
- .text
-
- cmse_veneer foo, function, global, function, global
- cmse_veneer bar, function, weak, function, global
- cmse_no_veneer no_veneer1, function, weak, function, global
- cmse_no_veneer no_veneer2, function, weak, function, weak
-
-//--- implib-v2
-
- .include "arm-cmse-macros.s"
-
- .syntax unified
- .text
-
- cmse_veneer baz, function, weak, function, global
- cmse_veneer foo, function, global, function, global
- cmse_veneer bar, function, weak, function, global
- cmse_veneer qux, function, global, function, global
- cmse_no_veneer no_veneer1, function, weak, function, global
- cmse_no_veneer no_veneer2, function, weak, function, weak
-
-/// Executable 1
-// CHECK1: File:
-// CHECK1: Symbol table '.symtab' contains 13 entries:
-// CHECK1-NEXT: Num: Value Size Type Bind Vis Ndx Name
-// CHECK1-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
-// CHECK1-NEXT: 1: 00020000 0 NOTYPE LOCAL DEFAULT 2 $t
-// CHECK1-NEXT: 2: 00008000 0 NOTYPE LOCAL DEFAULT 1 $t.0
-// CHECK1-NEXT: 3: 00008004 0 NOTYPE LOCAL DEFAULT 1 $t.0
-// CHECK1-NEXT: 4: 00008001 2 FUNC GLOBAL DEFAULT 1 secure_entry
-// CHECK1-NEXT: 5: 00020009 8 FUNC GLOBAL DEFAULT 2 foo
-// CHECK1-NEXT: 6: 00008005 2 FUNC GLOBAL DEFAULT 1 __acle_se_foo
-// CHECK1-NEXT: 7: 00020001 8 FUNC WEAK DEFAULT 2 bar
-// CHECK1-NEXT: 8: 00008009 2 FUNC GLOBAL DEFAULT 1 __acle_se_bar
-// CHECK1-NEXT: 9: 0000800d 8 FUNC WEAK DEFAULT 1 no_veneer1
-// CHECK1-NEXT: 10: 00008013 2 FUNC GLOBAL DEFAULT 1 __acle_se_no_veneer1
-// CHECK1-NEXT: 11: 00008015 8 FUNC WEAK DEFAULT 1 no_veneer2
-// CHECK1-NEXT: 12: 0000801b 2 FUNC WEAK DEFAULT 1 __acle_se_no_veneer2
-
-
-/// Import library 1
-// CHECK1: File:
-// CHECK1: Symbol table '.symtab' contains 5 entries:
-// CHECK1-NEXT: Num: Value Size Type Bind Vis Ndx Name
-// CHECK1-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
-// CHECK1-NEXT: 1: 0000800d 8 FUNC WEAK DEFAULT ABS no_veneer1
-// CHECK1-NEXT: 2: 00008015 8 FUNC WEAK DEFAULT ABS no_veneer2
-// CHECK1-NEXT: 3: 00020001 8 FUNC WEAK DEFAULT ABS bar
-// CHECK1-NEXT: 4: 00020009 8 FUNC GLOBAL DEFAULT ABS foo
-
-/// Executable 2
-// CHECK2: File:
-// CHECK2: Symbol table '.symtab' contains 17 entries:
-// CHECK2-NEXT: Num: Value Size Type Bind Vis Ndx Name
-// CHECK2-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
-// CHECK2-NEXT: 1: 00020000 0 NOTYPE LOCAL DEFAULT 2 $t
-// CHECK2-NEXT: 2: 00008000 0 NOTYPE LOCAL DEFAULT 1 $t.0
-// CHECK2-NEXT: 3: 00008004 0 NOTYPE LOCAL DEFAULT 1 $t.0
-// CHECK2-NEXT: 4: 00008001 2 FUNC GLOBAL DEFAULT 1 secure_entry
-// CHECK2-NEXT: 5: 00020019 8 FUNC WEAK DEFAULT 2 baz
-// CHECK2-NEXT: 6: 00008005 2 FUNC GLOBAL DEFAULT 1 __acle_se_baz
-// CHECK2-NEXT: 7: 00020009 8 FUNC GLOBAL DEFAULT 2 foo
-// CHECK2-NEXT: 8: 00008009 2 FUNC GLOBAL DEFAULT 1 __acle_se_foo
-// CHECK2-NEXT: 9: 00020001 8 FUNC WEAK DEFAULT 2 bar
-// CHECK2-NEXT: 10: 0000800d 2 FUNC GLOBAL DEFAULT 1 __acle_se_bar
-// CHECK2-NEXT: 11: 00020011 8 FUNC GLOBAL DEFAULT 2 qux
-// CHECK2-NEXT: 12: 00008011 2 FUNC GLOBAL DEFAULT 1 __acle_se_qux
-// CHECK2-NEXT: 13: 00008015 8 FUNC WEAK DEFAULT 1 no_veneer1
-// CHECK2-NEXT: 14: 0000801b 2 FUNC GLOBAL DEFAULT 1 __acle_se_no_veneer1
-// CHECK2-NEXT: 15: 0000801d 8 FUNC WEAK DEFAULT 1 no_veneer2
-// CHECK2-NEXT: 16: 00008023 2 FUNC WEAK DEFAULT 1 __acle_se_no_veneer2
-
-
-/// Note that foo retains its address from Import library 1 (0x000020009)
-/// New entry functions, baz and qux, use addresses not used by Import library 1.
-/// Import library 2
-// CHECK2: File:
-// CHECK2: Symbol table '.symtab' contains 7 entries:
-// CHECK2-NEXT: Num: Value Size Type Bind Vis Ndx Name
-// CHECK2-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
-// CHECK2-NEXT: 1: 00008015 8 FUNC WEAK DEFAULT ABS no_veneer1
-// CHECK2-NEXT: 2: 0000801d 8 FUNC WEAK DEFAULT ABS no_veneer2
-// CHECK2-NEXT: 3: 00020001 8 FUNC WEAK DEFAULT ABS bar
-// CHECK2-NEXT: 4: 00020009 8 FUNC GLOBAL DEFAULT ABS foo
-// CHECK2-NEXT: 5: 00020011 8 FUNC GLOBAL DEFAULT ABS qux
-// CHECK2-NEXT: 6: 00020019 8 FUNC WEAK DEFAULT ABS baz
+++ /dev/null
-// REQUIRES: arm
-/// Create a secure app and import library using CMSE.
-/// Create a non-secure app that refers symbols in the import library.
-
-// RUN: rm -rf %t && split-file %s %t && cd %t
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.main cmse-implib.s -o implib.o -I%S/Inputs/
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.main cmse-secure-app.s -o secureapp.o
-/// Create the secure app and import library.
-// RUN: ld.lld -e secure_entry --section-start .gnu.sgstubs=0x1000000 --section-start SECURE1=0x10 --section-start SECURE2=0x2000000 --cmse-implib implib.o secureapp.o --out-implib=implib.lib -o secureapp --gc-sections
-// RUN: llvm-readelf -s implib.lib | FileCheck %s
-// RUN: llvm-objdump -d --no-show-raw-insn secureapp | FileCheck %s --check-prefix=DISS
-
-
-// DISS-LABEL: <__acle_se_entry1>:
-// DISS-NEXT: 10: nop
-
-// DISS-LABEL: <entry2>:
-// DISS-NEXT: 1000000: sg
-// DISS-LABEL: b.w {{.*}} <__acle_se_entry2>
-
-// DISS-LABEL: <entry1>:
-// DISS-NEXT: 1000008: sg
-// DISS-LABEL: b.w {{.*}} <__acle_se_entry1>
-
-// DISS-LABEL: <__acle_se_entry2>:
-// DISS-NEXT: 2000000: nop
-
-// CHECK: Symbol table '.symtab' contains {{.*}} entries:
-// CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
-// CHECK-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
-// CHECK-NEXT: 1: 01000001 8 FUNC GLOBAL DEFAULT ABS entry2
-// CHECK-NEXT: 2: 01000009 8 FUNC GLOBAL DEFAULT ABS entry1
-
-//--- cmse-implib.s
- .include "arm-cmse-macros.s"
-
- .syntax unified
- .section SECURE1, "ax"
-
- cmse_veneer entry1, function, global, function, global
-
- .syntax unified
- .section SECURE2, "ax"
-
- cmse_veneer entry2, function, global, function, global
-
-//--- cmse-secure-app.s
- .text
- .align 2
- // Main entry point.
- .global secure_entry
- .thumb_func
-secure_entry:
- bx lr
- .size secure_entry, .-secure_entry
+++ /dev/null
-// REQUIRES: arm
-/// Test that addresses of existing secure gateway veneers are output in the CMSE import library.
-/// Test that .gnu.sgstubs is size 0 when no linker synthesized secure gateway veneers are created.
-
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.main %s -I %S/Inputs -o %t.o
-// RUN: ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 %t.o -o %t --out-implib=%t.lib
-// RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s
-// RUN: llvm-readelf -S %t | FileCheck %s --check-prefixes=SGSTUBSSIZE
-// RUN: llvm-readelf -s %t.lib | FileCheck %s --check-prefixes=IMPLIBSYMS
-
-// CHECK: Disassembly of section .text:
-
-// CHECK-LABEL: <existing_veneer>:
-// CHECK-NEXT: 8000: sg
-// CHECK-NEXT: 8004: nop
-
-// CHECK-LABEL: <__acle_se_existing_veneer>:
-// CHECK-NEXT: 8006: nop
-
- .include "arm-cmse-macros.s"
-
- cmse_no_veneer existing_veneer, function, global, function, global
-
-/// Name Type Address Off Size ES Flg Lk Inf Al
-// SGSTUBSSIZE: .gnu.sgstubs PROGBITS 00020000 020000 000000 08 AX 0 0 32
-
-// IMPLIBSYMS: Symbol table '.symtab' contains 2 entries:
-// IMPLIBSYMS-NEXT: Num: Value Size Type Bind Vis Ndx Name
-// IMPLIBSYMS-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
-// IMPLIBSYMS-NEXT: 1: 00008001 8 FUNC GLOBAL DEFAULT ABS existing_veneer
+++ /dev/null
-// REQUIRES: arm
-/// Create a secure app and import library using CMSE.
-/// Create a non-secure app that refers symbols in the import library.
-
-// RUN: rm -rf %t && split-file %s %t && cd %t
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.main cmse-implib.s -o implib.o -I%S/Inputs/
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.main cmse-secure-app.s -o secureapp.o
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.main cmse-non-secure-app.s -o nonsecureapp.o
-/// Create the secure app and import library.
-// RUN: ld.lld -e secure_entry --section-start .gnu.sgstubs=0x20000 --cmse-implib implib.o secureapp.o --out-implib=implib.lib -o secureapp
-/// Link the non-secure app against the import library.
-// RUN: ld.lld -e nonsecure_entry -Ttext=0x8000 implib.lib nonsecureapp.o -o nonsecureapp
-// RUN: llvm-readelf -s implib.lib | FileCheck %s
-// RUN: llvm-objdump -d --no-show-raw-insn secureapp | FileCheck %s --check-prefixes=SECUREDISS
-// RUN: llvm-objdump -d --no-show-raw-insn nonsecureapp | FileCheck %s --check-prefixes=NONSECUREDISS
-
-// SECUREDISS-LABEL: <entry>:
-// SECUREDISS-NEXT: 20000: sg
-// SECUREDISS-NEXT: b.w {{.*}} <__acle_se_entry>
-
-// SECUREDISS-LABEL: <__acle_se_entry>:
-// SECUREDISS-NEXT: 20008: nop
-
-// SECUREDISS-LABEL: <secure_entry>:
-// SECUREDISS-NEXT: 2000c: bl {{.*}} <__acle_se_entry>
-// SECUREDISS-NEXT: bx lr
-
-// NONSECUREDISS-LABEL: <nonsecure_entry>:
-// NONSECUREDISS-NEXT: 8000: push {r0, lr}
-// NONSECUREDISS-NEXT: bl 0x20000
-// NONSECUREDISS-NEXT: pop.w {r0, lr}
-// NONSECUREDISS-NEXT: bx lr
-
-// CHECK: Symbol table '.symtab' contains 2 entries:
-// CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
-// CHECK-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
-// CHECK-NEXT: 1: 00020001 8 FUNC GLOBAL DEFAULT ABS entry
-
-//--- cmse-implib.s
- .include "arm-cmse-macros.s"
-
- .syntax unified
- .text
-
- cmse_veneer entry, function, global, function, global
-
-//--- cmse-secure-app.s
- .align 2
- // Main entry point.
- .global secure_entry
- .thumb_func
-secure_entry:
- bl entry
- bx lr
- .size secure_entry, .-secure_entry
-
-//--- cmse-non-secure-app.s
- .align 2
- .global nonsecure_entry
- .thumb
- .thumb_func
- .type nonsecure_entry, %function
-nonsecure_entry:
- push {r0,lr}
- bl entry
- pop {r0,lr}
- bx lr
- .size nonsecure_entry, .-nonsecure_entry
+++ /dev/null
-// REQUIRES: arm
-/// Test that symbol visibilities of <sym, __acle_se_sym> pairs in the objects
-/// are preserved in the executable.
-
-// RUN: llvm-mc -arm-add-build-attributes -filetype=obj --triple=thumbv8m.main %s -I %S/Inputs -o %t.o
-// RUN: ld.lld --cmse-implib -Ttext=0x8000 --section-start .gnu.sgstubs=0x20000 %t.o -o %t
-// RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s
-// RUN: llvm-readelf -s %t | FileCheck %s --check-prefixes=SYM
-
-// CHECK: Disassembly of section .gnu.sgstubs:
-
-// CHECK-LABEL: <weak_qux>:
-// CHECK-NEXT: 20000: sg
-// CHECK-NEXT: b.w {{.*}} <__acle_se_weak_qux>
-// CHECK-EMPTY:
-// CHECK-LABEL: <global_baz>:
-// CHECK-NEXT: 20008: sg
-// CHECK-NEXT: b.w {{.*}} <__acle_se_global_baz>
-// CHECK-EMPTY:
-// CHECK-LABEL: <weak_bar>:
-// CHECK-NEXT: 20010: sg
-// CHECK-NEXT: b.w {{.*}} <__acle_se_weak_bar>
-// CHECK-EMPTY:
-// CHECK-LABEL: <global_foo>:
-// CHECK-NEXT: 20018: sg
-// CHECK-NEXT: b.w {{.*}} <__acle_se_global_foo>
-
-// SYM: 00020019 {{.*}} GLOBAL {{.*}} global_foo
-// SYM: 00008001 {{.*}} GLOBAL {{.*}} __acle_se_global_foo
-// SYM: 00020011 {{.*}} WEAK {{.*}} weak_bar
-// SYM: 00008005 {{.*}} WEAK {{.*}} __acle_se_weak_bar
-// SYM: 00020009 {{.*}} GLOBAL {{.*}} global_baz
-// SYM: 00008009 {{.*}} WEAK {{.*}} __acle_se_global_baz
-// SYM: 00020001 {{.*}} WEAK {{.*}} weak_qux
-// SYM: 0000800d {{.*}} GLOBAL {{.*}} __acle_se_weak_qux
-
- .include "arm-cmse-macros.s"
-
- cmse_veneer global_foo, function, global, function, global
- cmse_veneer weak_bar, function, weak, function, weak
- cmse_veneer global_baz, function, global, function, weak
- cmse_veneer weak_qux, function, weak, function, global