diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "InputFiles.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" @@ -377,6 +378,20 @@ write32(loc, val); break; case R_AARCH64_ABS64: + // AArch64 relocations to tagged symbols have extended semantics, as + // described here: + // https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#841extended-semantics-of-r_aarch64_relative. + // tl;dr: encode the symbol's special addend in the place, which is an + // offset to the point where the logical tag is derived from. Quick hack, if + // the addend is within the symbol's bounds, no need to encode the tag + // derivation offset. + if (rel.sym && rel.sym->isTagged() && + (rel.addend < 0 || + rel.addend >= static_cast(rel.sym->getSize()))) + write64(loc, -rel.addend); + else + write64(loc, val); + break; case R_AARCH64_PREL64: write64(loc, val); break; @@ -745,6 +760,12 @@ return true; } +// Tagged symbols have upper address bits that are added by the dynamic loader, +// and thus need the full 64-bit GOT entry. Do not relax such symbols. +static bool needsGotForMemtag(const Relocation &rel) { + return rel.sym->isTagged() && needsGot(rel.expr); +} + void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { uint64_t secAddr = sec.getOutputSection()->addr; if (auto *s = dyn_cast(&sec)) @@ -756,6 +777,12 @@ const uint64_t val = sec.getRelocTargetVA(sec.file, rel.type, rel.addend, secAddr + rel.offset, *rel.sym, rel.expr); + + if (needsGotForMemtag(rel)) { + relocate(loc, rel, val); + continue; + } + switch (rel.expr) { case R_AARCH64_GOT_PAGE_PC: if (i + 1 < size && @@ -950,3 +977,107 @@ } TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); } + +template +static void +addTaggedSymbolReferences(InputSectionBase &sec, + DenseMap &referenceCount) { + assert(sec.type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC); + + const RelsOrRelas rels = sec.relsOrRelas(); + if (rels.areRelocsRel()) + error("non-RELA relocations are not allowed with memtag globals"); + + for (const typename ELFT::Rela &rel : rels.relas) { + Symbol &sym = sec.getFile()->getRelocTargetSym(rel); + // Linker-synthesized symbols such as __executable_start may be referenced + // as tagged in input objfiles, and we don't want them to be tagged. A + // cheap way to exclude them is the type check, but their type is + // STT_NOTYPE. In addition, this save us from checking untaggable symbols, + // like functions or TLS symbols. + if (sym.type != STT_OBJECT) + continue; + // STB_LOCAL symbols can't be referenced from outside the object file, and + // thus don't need to be checked for references from other object files. + if (sym.binding == STB_LOCAL) { + sym.setIsTagged(true); + continue; + } + ++referenceCount[&sym]; + } + sec.markDead(); +} + +// A tagged symbol must be denoted as being tagged by all references and the +// chosen definition. For simplicity, here, it must also be denoted as tagged +// for all definitions. Otherwise: +// +// 1. A tagged definition can be used by an untagged declaration, in which case +// the untagged access may be PC-relative, causing a tag mismatch at +// runtime. +// 2. An untagged definition can be used by a tagged declaration, where the +// compiler has taken advantage of the increased alignment of the tagged +// declaration, but the alignment at runtime is wrong, causing a fault. +// +// Ideally, this isn't a problem, as any TU that imports or exports tagged +// symbols should also be built with tagging. But, to handle these cases, we +// demote the symbol to be untagged. +void lld::elf::createTaggedSymbols(const SmallVector &files) { + assert(config->emachine == EM_AARCH64 && + config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE); + + // First, collect all symbols that are marked as tagged, and count how many + // times they're marked as tagged. + DenseMap taggedSymbolReferenceCount; + for (InputFile* file : files) { + if (file->kind() != InputFile::ObjKind) + continue; + for (InputSectionBase *section : file->getSections()) { + if (!section || section->type != SHT_AARCH64_MEMTAG_GLOBALS_STATIC || + section == &InputSection::discarded) + continue; + invokeELFT(addTaggedSymbolReferences, *section, + taggedSymbolReferenceCount); + } + } + + // Now, go through all the symbols. If the number of declarations + + // definitions to a symbol exceeds the amount of times they're marked as + // tagged, it means we have an objfile that uses the untagged variant of the + // symbol. + for (InputFile *file : files) { + if (file->kind() != InputFile::BinaryKind && + file->kind() != InputFile::ObjKind) + continue; + + for (Symbol *symbol : file->getSymbols()) { + // See `addTaggedSymbolReferences` for more details. + if (symbol->type != STT_OBJECT || + symbol->binding == STB_LOCAL) + continue; + auto it = taggedSymbolReferenceCount.find(symbol); + if (it == taggedSymbolReferenceCount.end()) continue; + unsigned &remainingAllowedTaggedRefs = it->second; + if (remainingAllowedTaggedRefs == 0) { + taggedSymbolReferenceCount.erase(it); + continue; + } + --remainingAllowedTaggedRefs; + } + } + + // `addTaggedSymbolReferences` has already checked that we have RELA + // relocations, the only other way to get written addends is with + // --apply-dynamic-relocs. + if (!taggedSymbolReferenceCount.empty() && config->writeAddends) + error("--apply-dynamic-relocs cannot be used with MTE globals"); + + // Now, `taggedSymbolReferenceCount` should only contain symbols that are + // defined as tagged exactly the same amount as it's referenced, meaning all + // uses are tagged. + for (auto &[symbol, remainingTaggedRefs] : taggedSymbolReferenceCount) { + assert(remainingTaggedRefs == 0 && + "Symbol is defined as tagged more times than it's used"); + symbol->setIsTagged(true); + } +} diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -1556,7 +1556,7 @@ break; // Patch a nop (0x60000000) to a ld. - if (rel.sym->needsTocRestore) { + if (rel.sym->needsTocRestore()) { // gcc/gfortran 5.4, 6.3 and earlier versions do not add nop for // recursive calls even if the function is preemptible. This is not // wrong in the common case where the function is not preempted at diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -786,13 +786,6 @@ return ELF::NT_MEMTAG_LEVEL_NONE; } - if (!config->androidMemtagHeap && !config->androidMemtagStack) { - error("when using --android-memtag-mode, at least one of " - "--android-memtag-heap or " - "--android-memtag-stack is required"); - return ELF::NT_MEMTAG_LEVEL_NONE; - } - if (memtagModeArg == "sync") return ELF::NT_MEMTAG_LEVEL_SYNC; if (memtagModeArg == "async") @@ -2940,6 +2933,12 @@ // partition. copySectionsIntoPartitions(); + if (config->emachine == EM_AARCH64 && + config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE) { + llvm::TimeTraceScope timeScope("Process memory tagged symbols"); + createTaggedSymbols(ctx.objectFiles); + } + // Create synthesized sections such as .got and .plt. This is called before // processSectionCommands() so that they can be placed by SECTIONS commands. invokeELFT(createSyntheticSections,); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -220,6 +220,11 @@ } return rels; } + +// Returns true if Expr refers a GOT entry. Note that this function returns +// false for TLS variables even though they need GOT, because TLS variables uses +// GOT differently than the regular variables. +bool needsGot(RelExpr expr); } // namespace lld::elf #endif diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -53,6 +53,7 @@ #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Support/Endian.h" #include @@ -199,10 +200,7 @@ R_PPC32_PLTREL, R_PPC64_CALL_PLT>(expr); } -// Returns true if Expr refers a GOT entry. Note that this function -// returns false for TLS variables even though they need GOT, because -// TLS variables uses GOT differently than the regular variables. -static bool needsGot(RelExpr expr) { +bool lld::elf::needsGot(RelExpr expr) { return oneof( @@ -859,6 +857,23 @@ RelType type) { Partition &part = isec.getPartition(); + if (sym.isTagged()) { + std::lock_guard lock(relocMutex); + part.relaDyn->addRelativeReloc(target->relativeRel, isec, offsetInSec, sym, + addend, type, expr); + // With MTE globals, we always want to derive the address tag by `ldg`-ing + // the symbol. When we have a RELATIVE relocation though, we no longer have + // a reference to the symbol. Because of this, when we have an addend that + // puts the result of the RELATIVE relocation out-of-bounds of the symbol + // (e.g. the addend is outside of [0, sym.getSize()]), the AArch64 MemtagABI + // says we should store the offset to the start of the symbol in the target + // field. This is described in further detail in: + // https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#841extended-semantics-of-r_aarch64_relative + if (addend < 0 || static_cast(addend) >= sym.getSize()) + isec.relocations.push_back({expr, type, offsetInSec, addend, &sym}); + return; + } + // Add a relative relocation. If relrDyn section is enabled, and the // relocation offset is guaranteed to be even, add the relocation to // the relrDyn section, otherwise add it to the relaDyn section. @@ -1645,6 +1660,10 @@ auto flags = sym.flags.load(std::memory_order_relaxed); if (handleNonPreemptibleIfunc(sym, flags)) return; + + if (sym.isTagged() && sym.isDefined()) + mainPart->memtagDescriptors->addSymbol(sym); + if (!sym.needsDynReloc()) return; sym.allocateAux(); diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -254,8 +254,8 @@ Symbol(Kind k, InputFile *file, StringRef name, uint8_t binding, uint8_t stOther, uint8_t type) : file(file), nameData(name.data()), nameSize(name.size()), type(type), - binding(binding), stOther(stOther), symbolKind(k), - exportDynamic(false) {} + binding(binding), stOther(stOther), symbolKind(k), exportDynamic(false), + archSpecificBit(false) {} void overwrite(Symbol &sym, Kind k) const { if (sym.traced) @@ -279,9 +279,18 @@ // True if defined relative to a section discarded by ICF. uint8_t folded : 1; - // True if a call to this symbol needs to be followed by a restore of the - // PPC64 toc pointer. - uint8_t needsTocRestore : 1; + // Allow reuse of a bit between architecture-exclusive symbol flags. + // - needsTocRestore(): On PPC64, true if a call to this symbol needs to be + // followed by a restore of the toc pointer. + // - isTagged(): On AArch64, true if the symbol needs special relocation and + // metadata semantics because it's tagged, under the AArch64 MemtagABI. + uint8_t archSpecificBit : 1; + bool needsTocRestore() const { return archSpecificBit; } + bool isTagged() const { return archSpecificBit; } + void setNeedsTocRestore(bool v) { archSpecificBit = v; } + void setIsTagged(bool v) { + archSpecificBit = v; + } // True if this symbol is defined by a symbol assignment or wrapped by --wrap. // diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -22,8 +22,10 @@ #include "Config.h" #include "InputSection.h" +#include "Symbols.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Endian.h" @@ -1245,6 +1247,32 @@ size_t getSize() const override; }; +class MemtagDescriptors final : public SyntheticSection { +public: + MemtagDescriptors() + : SyntheticSection(llvm::ELF::SHF_ALLOC, + llvm::ELF::SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC, + /*alignment=*/4, ".memtag.globals.dynamic") {} + void writeTo(uint8_t *buf) override; + // The size of the section is non-computable until all addresses are + // synthetized, because the section's contents contain a sorted + // varint-compressed list of pointers to global variables. We only know the + // final size after `finalizeAddressDependentContent()`. + size_t getSize() const override; + bool updateAllocSize() override; + + void addSymbol(const Symbol &sym) { + symbols.push_back(&sym); + } + + bool isNeeded() const override { + return !symbols.empty(); + } + +private: + SmallVector symbols; +}; + InputSection *createInterpSection(); MergeInputSection *createCommentSection(); template void splitSections(); @@ -1277,6 +1305,7 @@ std::unique_ptr gnuHashTab; std::unique_ptr hashTab; std::unique_ptr memtagAndroidNote; + std::unique_ptr memtagDescriptors; std::unique_ptr packageMetadataNote; std::unique_ptr relaDyn; std::unique_ptr relrDyn; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1453,6 +1453,10 @@ addInt(DT_AARCH64_MEMTAG_MODE, config->androidMemtagMode == NT_MEMTAG_LEVEL_ASYNC); addInt(DT_AARCH64_MEMTAG_HEAP, config->androidMemtagHeap); addInt(DT_AARCH64_MEMTAG_STACK, config->androidMemtagStack); + if (mainPart->memtagDescriptors->isNeeded()) { + addInSec(DT_AARCH64_MEMTAG_GLOBALS, *mainPart->memtagDescriptors); + addInt(DT_AARCH64_MEMTAG_GLOBALSSZ, mainPart->memtagDescriptors->getSize()); + } } } @@ -3900,6 +3904,76 @@ alignTo(config->packageMetadata.size() + 1, 4); } +// Helper function, return the size of the ULEB128 for 'v', optionally writing +// it to `*(buf + offset)` if `buf` is non-null. +static size_t computeOrWriteULEB128(uint64_t v, uint8_t *buf, size_t offset) { + if (buf) + return encodeULEB128(v, buf + offset); + return getULEB128Size(v); +} + +// https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#83encoding-of-sht_aarch64_memtag_globals_dynamic +constexpr uint64_t kMemtagStepSizeBits = 3; +constexpr uint64_t kMemtagGranuleSize = 16; +static size_t createMemtagDescriptors(const SmallVector &symbols, + uint8_t *buf = nullptr) { + size_t sectionSize = 0; + uint64_t lastGlobalEnd = 0; + + for (const Symbol *sym : symbols) { + if (!includeInSymtab(*sym)) + continue; + const uint64_t addr = sym->getVA(); + const uint64_t size = sym->getSize(); + + if (addr <= kMemtagGranuleSize && buf != nullptr) + errorOrWarn("address of the tagged symbol \"" + sym->getName() + + "\" falls in the ELF header. This is indicative of a " + "compiler/linker bug"); + if (addr % kMemtagGranuleSize != 0) + errorOrWarn("address of the tagged symbol \"" + sym->getName() + + "\" at 0x" + Twine::utohexstr(addr) + + "\" is not granule (16-byte) aligned"); + if (size == 0) + errorOrWarn("size of the tagged symbol \"" + sym->getName() + + "\" is not allowed to be zero"); + if (size % kMemtagGranuleSize != 0) + errorOrWarn("size of the tagged symbol \"" + sym->getName() + + "\" (size 0x" + Twine::utohexstr(size) + + ") is not granule (16-byte) aligned"); + + const uint64_t sizeToEncode = size / kMemtagGranuleSize; + const uint64_t stepToEncode = ((addr - lastGlobalEnd) / kMemtagGranuleSize) + << kMemtagStepSizeBits; + if (sizeToEncode < (1 << kMemtagStepSizeBits)) { + sectionSize += computeOrWriteULEB128(stepToEncode | sizeToEncode, buf, sectionSize); + } else { + sectionSize += computeOrWriteULEB128(stepToEncode, buf, sectionSize); + sectionSize += computeOrWriteULEB128(sizeToEncode - 1, buf, sectionSize); + } + lastGlobalEnd = addr + size; + } + + return sectionSize; +} + +bool MemtagDescriptors::updateAllocSize() { + size_t oldSize = getSize(); + std::stable_sort(symbols.begin(), symbols.end(), + [](const Symbol *s1, const Symbol *s2) { + return s1->getVA() < s2->getVA(); + }); + return oldSize != getSize(); +} + +void MemtagDescriptors::writeTo(uint8_t *buf) { + createMemtagDescriptors(symbols, buf); +} + +size_t MemtagDescriptors::getSize() const { + return createMemtagDescriptors(symbols); +} + InStruct elf::in; std::vector elf::partitions; diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -14,6 +14,7 @@ #include "lld/Common/ErrorHandler.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include @@ -233,6 +234,7 @@ void addArmSyntheticSectionMappingSymbol(Defined *); void sortArmMappingSymbols(); void convertArmInstructionstoBE8(InputSection *sec, uint8_t *buf); +void createTaggedSymbols(const SmallVector &files); LLVM_LIBRARY_VISIBILITY extern const TargetInfo *target; TargetInfo *getTarget(); @@ -306,17 +308,17 @@ #endif #define invokeELFT(f, ...) \ switch (config->ekind) { \ - case ELF32LEKind: \ - f(__VA_ARGS__); \ + case lld::elf::ELF32LEKind: \ + f(__VA_ARGS__); \ break; \ - case ELF32BEKind: \ - f(__VA_ARGS__); \ + case lld::elf::ELF32BEKind: \ + f(__VA_ARGS__); \ break; \ - case ELF64LEKind: \ - f(__VA_ARGS__); \ + case lld::elf::ELF64LEKind: \ + f(__VA_ARGS__); \ break; \ - case ELF64BEKind: \ - f(__VA_ARGS__); \ + case lld::elf::ELF64BEKind: \ + f(__VA_ARGS__); \ break; \ default: \ llvm_unreachable("unknown config->ekind"); \ diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -1138,7 +1138,7 @@ void PPC64PltCallStub::addSymbols(ThunkSection &isec) { Defined *s = addSymbol(saver().save("__plt_" + destination.getName()), STT_FUNC, 0, isec); - s->needsTocRestore = true; + s->setNeedsTocRestore(true); s->file = destination.file; } @@ -1182,7 +1182,7 @@ void PPC64R2SaveStub::addSymbols(ThunkSection &isec) { Defined *s = addSymbol(saver().save("__toc_save_" + destination.getName()), STT_FUNC, 0, isec); - s->needsTocRestore = true; + s->setNeedsTocRestore(true); } bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec, diff --git a/lld/ELF/Writer.h b/lld/ELF/Writer.h --- a/lld/ELF/Writer.h +++ b/lld/ELF/Writer.h @@ -46,6 +46,7 @@ }; void addReservedSymbols(); +bool includeInSymtab(const Symbol &b); template uint32_t calcMipsEFlags(); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -347,8 +347,13 @@ if (config->emachine == EM_AARCH64 && config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE) { + if (!config->relocatable && !config->shared && !needsInterpSection()) + error("--android-memtag-mode is incompatible with fully-static " + "executables (-static)"); part.memtagAndroidNote = std::make_unique(); add(*part.memtagAndroidNote); + part.memtagDescriptors = std::make_unique(); + add(*part.memtagDescriptors); } if (config->androidPackDynRelocs) @@ -672,7 +677,7 @@ return true; } -static bool includeInSymtab(const Symbol &b) { +bool lld::elf::includeInSymtab(const Symbol &b) { if (auto *d = dyn_cast(&b)) { // Always include absolute symbols. SectionBase *sec = d->section; @@ -1652,6 +1657,8 @@ changed |= part.relaDyn->updateAllocSize(); if (part.relrDyn) changed |= part.relrDyn->updateAllocSize(); + if (part.memtagDescriptors) + changed |= part.memtagDescriptors->updateAllocSize(); } const Defined *changedSym = script->assignAddresses(); diff --git a/lld/test/ELF/Inputs/aarch64-memtag-globals.s b/lld/test/ELF/Inputs/aarch64-memtag-globals.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/Inputs/aarch64-memtag-globals.s @@ -0,0 +1,382 @@ +#--- input_1.s +## Generated with: +## +## - clang -fsanitize=memtag-globals -O2 -S -fPIC -o - \ +## --target=aarch64-linux-android31 -fno-asynchronous-unwind-tables +## +## contents: +## +## /// Global variables defined here, of various semantics. +## char global[30] = {}; +## __attribute__((no_sanitize("memtag"))) int global_untagged = 0; +## const int const_global = 0; +## static const int hidden_const_global = 0; +## static char hidden_global[12] = {}; +## __attribute__((visibility("hidden"))) int hidden_attr_global = 0; +## __attribute__((visibility("hidden"))) const int hidden_attr_const_global = 0; +## +## /// Should be untagged. +## __thread int tls_global; +## __thread static int hidden_tls_global; +## +## /// Tagged, from the other file. +## extern int global_extern; +## /// Untagged, from the other file. +## extern __attribute__((no_sanitize("memtag"))) int global_extern_untagged; +## /// Tagged, but from a different DSO (i.e. not this or the sister objfile). +## extern int global_extern_outside_this_dso; +## /// Tagged here (because it's non-const), but untagged in the definition found +## /// in the sister objfile as it's marked as const there. +## extern int global_extern_const_definition_but_nonconst_import; +## /// Tagged here, but untagged in the definition found in the sister objfile +## /// (explicitly). +## extern int global_extern_untagged_definition_but_tagged_import; +## +## /// ABS64 relocations. Also, forces symtab entries for local and external +## /// globals. +## char *pointer_to_global = &global[0]; +## char *pointer_inside_global = &global[17]; +## char *pointer_to_global_end = &global[30]; +## char *pointer_past_global_end = &global[48]; +## int *pointer_to_global_untagged = &global_untagged; +## const int *pointer_to_const_global = &const_global; +## /// RELATIVE relocations. +## const int *pointer_to_hidden_const_global = &hidden_const_global; +## char *pointer_to_hidden_global = &hidden_global[0]; +## const int *pointer_to_hidden_attr_global = &hidden_attr_global; +## const int *pointer_to_hidden_attr_const_global = &hidden_attr_const_global; +## /// RELATIVE relocations with special AArch64 MemtagABI semantics, with the +## /// offset ('12' or '16') encoded in the place. +## char *pointer_to_hidden_global_end = &hidden_global[12]; +## char *pointer_past_hidden_global_end = &hidden_global[16]; +## /// ABS64 relocations. +## int *pointer_to_global_extern = &global_extern; +## int *pointer_to_global_extern_untagged = &global_extern_untagged; +## int *pointer_to_global_extern_outside_this_dso = &global_extern_outside_this_dso; +## int *pointer_to_global_extern_const_definition_but_nonconst_import = +## &global_extern_const_definition_but_nonconst_import; +## int *pointer_to_global_extern_untagged_definition_but_tagged_import = +## &global_extern_untagged_definition_but_tagged_import; +## +## int *get_address_to_tls_global() { return &tls_global; } +## int *get_address_to_hidden_tls_global() { return &hidden_tls_global; } + + .text + .file "a.c" + .globl get_address_to_tls_global // -- Begin function get_address_to_tls_global + .p2align 2 + .type get_address_to_tls_global,@function +get_address_to_tls_global: // @get_address_to_tls_global +// %bb.0: // %entry + stp x29, x30, [sp, #-16]! // 16-byte Folded Spill + mov x29, sp + adrp x0, :tlsdesc:tls_global + ldr x1, [x0, :tlsdesc_lo12:tls_global] + add x0, x0, :tlsdesc_lo12:tls_global + .tlsdesccall tls_global + blr x1 + mrs x8, TPIDR_EL0 + add x0, x8, x0 + ldp x29, x30, [sp], #16 // 16-byte Folded Reload + ret +.Lfunc_end0: + .size get_address_to_tls_global, .Lfunc_end0-get_address_to_tls_global + // -- End function + .globl get_address_to_hidden_tls_global // -- Begin function get_address_to_hidden_tls_global + .p2align 2 + .type get_address_to_hidden_tls_global,@function +get_address_to_hidden_tls_global: // @get_address_to_hidden_tls_global +// %bb.0: // %entry + stp x29, x30, [sp, #-16]! // 16-byte Folded Spill + mov x29, sp + adrp x0, :tlsdesc:hidden_tls_global + ldr x1, [x0, :tlsdesc_lo12:hidden_tls_global] + add x0, x0, :tlsdesc_lo12:hidden_tls_global + .tlsdesccall hidden_tls_global + blr x1 + mrs x8, TPIDR_EL0 + add x0, x8, x0 + ldp x29, x30, [sp], #16 // 16-byte Folded Reload + ret +.Lfunc_end1: + .size get_address_to_hidden_tls_global, .Lfunc_end1-get_address_to_hidden_tls_global + // -- End function + .memtag global // @global + .type global,@object + .bss + .globl global + .p2align 4, 0x0 +global: + .zero 32 + .size global, 32 + + .type global_untagged,@object // @global_untagged + .globl global_untagged + .p2align 2, 0x0 +global_untagged: + .word 0 // 0x0 + .size global_untagged, 4 + + .type const_global,@object // @const_global + .section .rodata,"a",@progbits + .globl const_global + .p2align 2, 0x0 +const_global: + .word 0 // 0x0 + .size const_global, 4 + + .hidden hidden_attr_global // @hidden_attr_global + .memtag hidden_attr_global + .type hidden_attr_global,@object + .bss + .globl hidden_attr_global + .p2align 4, 0x0 +hidden_attr_global: + .zero 16 + .size hidden_attr_global, 16 + + .hidden hidden_attr_const_global // @hidden_attr_const_global + .type hidden_attr_const_global,@object + .section .rodata,"a",@progbits + .globl hidden_attr_const_global + .p2align 2, 0x0 +hidden_attr_const_global: + .word 0 // 0x0 + .size hidden_attr_const_global, 4 + + .memtag pointer_to_global // @pointer_to_global + .type pointer_to_global,@object + .data + .globl pointer_to_global + .p2align 4, 0x0 +pointer_to_global: + .xword global + .zero 8 + .size pointer_to_global, 16 + + .memtag pointer_inside_global // @pointer_inside_global + .type pointer_inside_global,@object + .globl pointer_inside_global + .p2align 4, 0x0 +pointer_inside_global: + .xword global+17 + .zero 8 + .size pointer_inside_global, 16 + + .memtag pointer_to_global_end // @pointer_to_global_end + .type pointer_to_global_end,@object + .globl pointer_to_global_end + .p2align 4, 0x0 +pointer_to_global_end: + .xword global+30 + .zero 8 + .size pointer_to_global_end, 16 + + .memtag pointer_past_global_end // @pointer_past_global_end + .type pointer_past_global_end,@object + .globl pointer_past_global_end + .p2align 4, 0x0 +pointer_past_global_end: + .xword global+48 + .zero 8 + .size pointer_past_global_end, 16 + + .memtag pointer_to_global_untagged // @pointer_to_global_untagged + .type pointer_to_global_untagged,@object + .globl pointer_to_global_untagged + .p2align 4, 0x0 +pointer_to_global_untagged: + .xword global_untagged + .zero 8 + .size pointer_to_global_untagged, 16 + + .memtag pointer_to_const_global // @pointer_to_const_global + .type pointer_to_const_global,@object + .globl pointer_to_const_global + .p2align 4, 0x0 +pointer_to_const_global: + .xword const_global + .zero 8 + .size pointer_to_const_global, 16 + + .type hidden_const_global,@object // @hidden_const_global + .section .rodata,"a",@progbits + .p2align 2, 0x0 +hidden_const_global: + .word 0 // 0x0 + .size hidden_const_global, 4 + + .memtag pointer_to_hidden_const_global // @pointer_to_hidden_const_global + .type pointer_to_hidden_const_global,@object + .data + .globl pointer_to_hidden_const_global + .p2align 4, 0x0 +pointer_to_hidden_const_global: + .xword hidden_const_global + .zero 8 + .size pointer_to_hidden_const_global, 16 + + .memtag hidden_global // @hidden_global + .type hidden_global,@object + .local hidden_global + .comm hidden_global,16,16 + .memtag pointer_to_hidden_global // @pointer_to_hidden_global + .type pointer_to_hidden_global,@object + .globl pointer_to_hidden_global + .p2align 4, 0x0 +pointer_to_hidden_global: + .xword hidden_global + .zero 8 + .size pointer_to_hidden_global, 16 + + .memtag pointer_to_hidden_attr_global // @pointer_to_hidden_attr_global + .type pointer_to_hidden_attr_global,@object + .globl pointer_to_hidden_attr_global + .p2align 4, 0x0 +pointer_to_hidden_attr_global: + .xword hidden_attr_global + .zero 8 + .size pointer_to_hidden_attr_global, 16 + + .memtag pointer_to_hidden_attr_const_global // @pointer_to_hidden_attr_const_global + .type pointer_to_hidden_attr_const_global,@object + .globl pointer_to_hidden_attr_const_global + .p2align 4, 0x0 +pointer_to_hidden_attr_const_global: + .xword hidden_attr_const_global + .zero 8 + .size pointer_to_hidden_attr_const_global, 16 + + .memtag pointer_to_hidden_global_end // @pointer_to_hidden_global_end + .type pointer_to_hidden_global_end,@object + .globl pointer_to_hidden_global_end + .p2align 4, 0x0 +pointer_to_hidden_global_end: + .xword hidden_global+12 + .zero 8 + .size pointer_to_hidden_global_end, 16 + + .memtag pointer_past_hidden_global_end // @pointer_past_hidden_global_end + .type pointer_past_hidden_global_end,@object + .globl pointer_past_hidden_global_end + .p2align 4, 0x0 +pointer_past_hidden_global_end: + .xword hidden_global+16 + .zero 8 + .size pointer_past_hidden_global_end, 16 + + .memtag global_extern + .memtag pointer_to_global_extern // @pointer_to_global_extern + .type pointer_to_global_extern,@object + .globl pointer_to_global_extern + .p2align 4, 0x0 +pointer_to_global_extern: + .xword global_extern + .zero 8 + .size pointer_to_global_extern, 16 + + .memtag pointer_to_global_extern_untagged // @pointer_to_global_extern_untagged + .type pointer_to_global_extern_untagged,@object + .globl pointer_to_global_extern_untagged + .p2align 4, 0x0 +pointer_to_global_extern_untagged: + .xword global_extern_untagged + .zero 8 + .size pointer_to_global_extern_untagged, 16 + + .memtag global_extern_outside_this_dso + .memtag pointer_to_global_extern_outside_this_dso // @pointer_to_global_extern_outside_this_dso + .type pointer_to_global_extern_outside_this_dso,@object + .globl pointer_to_global_extern_outside_this_dso + .p2align 4, 0x0 +pointer_to_global_extern_outside_this_dso: + .xword global_extern_outside_this_dso + .zero 8 + .size pointer_to_global_extern_outside_this_dso, 16 + + .memtag global_extern_const_definition_but_nonconst_import + .memtag pointer_to_global_extern_const_definition_but_nonconst_import // @pointer_to_global_extern_const_definition_but_nonconst_import + .type pointer_to_global_extern_const_definition_but_nonconst_import,@object + .globl pointer_to_global_extern_const_definition_but_nonconst_import + .p2align 4, 0x0 +pointer_to_global_extern_const_definition_but_nonconst_import: + .xword global_extern_const_definition_but_nonconst_import + .zero 8 + .size pointer_to_global_extern_const_definition_but_nonconst_import, 16 + + .memtag global_extern_untagged_definition_but_tagged_import + .memtag pointer_to_global_extern_untagged_definition_but_tagged_import // @pointer_to_global_extern_untagged_definition_but_tagged_import + .type pointer_to_global_extern_untagged_definition_but_tagged_import,@object + .globl pointer_to_global_extern_untagged_definition_but_tagged_import + .p2align 4, 0x0 +pointer_to_global_extern_untagged_definition_but_tagged_import: + .xword global_extern_untagged_definition_but_tagged_import + .zero 8 + .size pointer_to_global_extern_untagged_definition_but_tagged_import, 16 + + .type tls_global,@object // @tls_global + .section .tbss,"awT",@nobits + .globl tls_global + .p2align 2, 0x0 +tls_global: + .word 0 // 0x0 + .size tls_global, 4 + + .type hidden_tls_global,@object // @hidden_tls_global + .p2align 2, 0x0 +hidden_tls_global: + .word 0 // 0x0 + .size hidden_tls_global, 4 + + .ident "clang version 17.0.0 (https://github.com/llvm/llvm-project.git 6130c9df99a7a7eb9c6adc118a48f8f2acc534ab)" + .section ".note.GNU-stack","",@progbits + +#--- input_2.s +## Generated with: +## +## - clang -fsanitize=memtag-globals -O2 -S -o - \ +## --target=aarch64-linux-android31 -fno-asynchronous-unwind-tables +## +## contents: +## +## int global_extern; +## static int global_extern_hidden; +## __attribute__((no_sanitize("memtag"))) int global_extern_untagged; +## const int global_extern_const_definition_but_nonconst_import; +## __attribute__((no_sanitize( +## "memtag"))) int global_extern_untagged_definition_but_tagged_import; +## + + .text + .file "b.c" + .memtag global_extern + .type global_extern,@object + .bss + .globl global_extern + .p2align 4, 0x0 +global_extern: + .zero 16 + .size global_extern, 16 + + .type global_extern_untagged,@object + .globl global_extern_untagged + .p2align 2, 0x0 +global_extern_untagged: + .word 0 + .size global_extern_untagged, 4 + + .type global_extern_const_definition_but_nonconst_import,@object + .section .rodata,"a",@progbits + .globl global_extern_const_definition_but_nonconst_import + .p2align 2, 0x0 +global_extern_const_definition_but_nonconst_import: + .word 0 + .size global_extern_const_definition_but_nonconst_import, 4 + + .type global_extern_untagged_definition_but_tagged_import,@object + .bss + .globl global_extern_untagged_definition_but_tagged_import + .p2align 2, 0x0 +global_extern_untagged_definition_but_tagged_import: + .word 0 + .size global_extern_untagged_definition_but_tagged_import, 4 diff --git a/lld/test/ELF/aarch64-memtag-android-abi.s b/lld/test/ELF/aarch64-memtag-android-abi.s --- a/lld/test/ELF/aarch64-memtag-android-abi.s +++ b/lld/test/ELF/aarch64-memtag-android-abi.s @@ -56,11 +56,6 @@ # BAD-MODE: error: unknown --android-memtag-mode value: "asymm", should be one of # BAD-MODE: {async, sync, none} -# RUN: not ld.lld -shared --android-memtag-mode=async 2>&1 | \ -# RUN: FileCheck %s --check-prefix=MISSING-STACK-OR-HEAP -# MISSING-STACK-OR-HEAP: error: when using --android-memtag-mode, at least one of -# MISSING-STACK-OR-HEAP: --android-memtag-heap or --android-memtag-stack is required - .globl _start _start: ret diff --git a/lld/test/ELF/aarch64-memtag-globals.s b/lld/test/ELF/aarch64-memtag-globals.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/aarch64-memtag-globals.s @@ -0,0 +1,184 @@ +# REQUIRES: aarch64 + +# RUN: rm -rf %t + +## Ensure MTE globals doesn't work with REL (only RELA). +# RUN: yaml2obj %s -o %t.rel.o +# RUN: not ld.lld -shared --android-memtag-mode=sync %t.rel.o 2>&1 | FileCheck %s --check-prefix=CHECK-RELA +# CHECK-RELA: non-RELA relocations are not allowed with memtag globals +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_AARCH64 + SectionHeaderStringTable: .strtab +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x4 + Content: '00' + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x10 + Content: '00' + - Name: .memtag.globals.static + Type: SHT_AARCH64_MEMTAG_GLOBALS_STATIC + AddressAlign: 0x1 + - Name: .rel.memtag.globals.static + Type: SHT_REL + Flags: [ SHF_INFO_LINK ] + Link: .symtab + AddressAlign: 0x8 + Info: .memtag.globals.static + Relocations: + - Symbol: four + Type: R_AARCH64_NONE + - Type: SectionHeaderTable + Sections: + - Name: .strtab + - Name: .text + - Name: .data + - Name: .memtag.globals.static + - Name: .rel.memtag.globals.static + - Name: .symtab +Symbols: + - Name: four + Type: STT_OBJECT + Section: .data + Binding: STB_GLOBAL + Value: 0x0 + Size: 0x10 + +## Functional testing for MTE globals. +# RUN: split-file %S/Inputs/aarch64-memtag-globals.s %t +# RUN: llvm-mc --filetype=obj -triple=aarch64-none-linux-android \ +# RUN: %t/input_1.s -o %t1.o +# RUN: llvm-mc --filetype=obj -triple=aarch64-none-linux-android \ +# RUN: %t/input_2.s -o %t2.o +# RUN: ld.lld -shared --android-memtag-mode=sync %t1.o %t2.o -o %t.so + +## Normally relocations are printed before the symbol tables, so reorder it a +## bit to make it easier on matching addresses of relocations up with the +## symbols. +# RUN: llvm-readelf %t.so -s > %t.out +# RUN: llvm-readelf %t.so --section-headers --relocs --memtag >> %t.out +# RUN: FileCheck %s < %t.out +# RUN: llvm-objdump -Dz %t.so | FileCheck %s --check-prefix=CHECK-SPECIAL-RELOCS + +## And ensure that --apply-dynamic-relocs is banned. +# RUN: not ld.lld --apply-dynamic-relocs -shared --android-memtag-mode=sync \ +# RUN: %t1.o %t2.o 2>&1 | FileCheck %s --check-prefix=CHECK-DYNRELOC +# CHECK-DYNRELOC: --apply-dynamic-relocs cannot be used with MTE globals + +## And ensure that fully-static executables are banned. +# RUN: not ld.lld --static --android-memtag-mode=sync \ +# RUN: %t1.o %t2.o 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTATIC +# CHECK-NOSTATIC: --android-memtag-mode is incompatible with fully-static executables (-static) + +# CHECK: Symbol table '.dynsym' contains +# CHECK-DAG: [[#%x,GLOBAL:]] 32 OBJECT GLOBAL DEFAULT [[#]] global{{$}} +# CHECK-DAG: [[#%x,GLOBAL_UNTAGGED:]] 4 OBJECT GLOBAL DEFAULT [[#]] global_untagged{{$}} +# CHECK-DAG: [[#%x,CONST_GLOBAL:]] 4 OBJECT GLOBAL DEFAULT [[#]] const_global{{$}} +# CHECK-DAG: [[#%x,GLOBAL_EXTERN:]] 16 OBJECT GLOBAL DEFAULT [[#]] global_extern{{$}} +# CHECK-DAG: [[#%x,GLOBAL_EXTERN_UNTAGGED:]] 4 OBJECT GLOBAL DEFAULT [[#]] global_extern_untagged{{$}} +# CHECK-DAG: 0 NOTYPE GLOBAL DEFAULT UND global_extern_outside_this_dso{{$}} +# CHECK-DAG: [[#%x,GLOBAL_EXTERN_CONST_DEFINITION_BUT_NONCONST_IMPORT:]] 4 OBJECT GLOBAL DEFAULT [[#]] global_extern_untagged_definition_but_tagged_import{{$}} +# CHECK-DAG: [[#%x,GLOBAL_EXTERN_UNTAGGED_DEFINITION_BUT_TAGGED_IMPORT:]] 4 OBJECT GLOBAL DEFAULT [[#]] global_extern_const_definition_but_nonconst_import{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global{{$}} +# CHECK-DAG: [[#%x,POINTER_INSIDE_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_inside_global{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_END:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_end{{$}} +# CHECK-DAG: [[#%x,POINTER_PAST_GLOBAL_END:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_past_global_end{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_UNTAGGED:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_untagged{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_CONST_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_const_global{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_CONST_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_const_global{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_global{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_GLOBAL_END:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_global_end{{$}} +# CHECK-DAG: [[#%x,POINTER_PAST_HIDDEN_GLOBAL_END:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_past_hidden_global_end{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_ATTR_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_attr_global{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_HIDDEN_ATTR_CONST_GLOBAL:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_hidden_attr_const_global{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN_UNTAGGED:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern_untagged{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN_OUTSIDE_THIS_DSO:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern_outside_this_dso{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN_CONST_DEFINITION_BUT_NONCONST_IMPORT:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern_const_definition_but_nonconst_import{{$}} +# CHECK-DAG: [[#%x,POINTER_TO_GLOBAL_EXTERN_UNTAGGED_DEFINITION_BUT_TAGGED_IMPORT:]] 16 OBJECT GLOBAL DEFAULT [[#]] pointer_to_global_extern_untagged_definition_but_tagged_import{{$}} + +# CHECK: Symbol table '.symtab' contains +# CHECK-DAG: [[#%x,HIDDEN_CONST_GLOBAL:]] 4 OBJECT LOCAL DEFAULT [[#]] hidden_const_global{{$}} +# CHECK-DAG: [[#%x,HIDDEN_GLOBAL:]] 16 OBJECT LOCAL DEFAULT [[#]] hidden_global{{$}} +# CHECK-DAG: [[#%x,HIDDEN_ATTR_GLOBAL:]] 16 OBJECT LOCAL HIDDEN [[#]] hidden_attr_global{{$}} +# CHECK-DAG: [[#%x,HIDDEN_ATTR_CONST_GLOBAL:]] 4 OBJECT LOCAL HIDDEN [[#]] hidden_attr_const_global{{$}} + +# CHECK: Section Headers: +# CHECK: .memtag.globals.dynamic AARCH64_MEMTAG_GLOBALS_DYNAMIC +# CHECK-NOT: .memtag.globals.static +# CHECK-NOT: AARCH64_MEMTAG_GLOBALS_STATIC + +# CHECK: Relocation section '.rela.dyn' +# CHECK-DAG: [[#POINTER_TO_GLOBAL]] {{.*}} R_AARCH64_ABS64 {{.*}} global + 0 +# CHECK-DAG: [[#POINTER_INSIDE_GLOBAL]] {{.*}} R_AARCH64_ABS64 {{.*}} global + 11 +# CHECK-DAG: [[#POINTER_TO_GLOBAL_END]] {{.*}} R_AARCH64_ABS64 {{.*}} global + 1e +# CHECK-DAG: [[#POINTER_PAST_GLOBAL_END]] {{.*}} R_AARCH64_ABS64 {{.*}} global + 30 +# CHECK-DAG: [[#POINTER_TO_GLOBAL_UNTAGGED]] {{.*}} R_AARCH64_ABS64 {{.*}} global_untagged + 0 +# CHECK-DAG: [[#POINTER_TO_CONST_GLOBAL]] {{.*}} R_AARCH64_ABS64 {{.*}} const_global + 0 + +## RELATIVE relocations. +# CHECK-DAG: [[#POINTER_TO_HIDDEN_CONST_GLOBAL]] {{.*}} R_AARCH64_RELATIVE {{0*}}[[#HIDDEN_CONST_GLOBAL]] +# CHECK-DAG: [[#POINTER_TO_HIDDEN_GLOBAL]] {{.*}} R_AARCH64_RELATIVE {{0*}}[[#HIDDEN_GLOBAL]] + +## AArch64 MemtagABI special RELATIVE relocation semantics, where the offset is encoded in the place. +# CHECK-DAG: [[#POINTER_TO_HIDDEN_GLOBAL_END]] {{.*}} R_AARCH64_RELATIVE {{0*}}[[#HIDDEN_GLOBAL + 12]] +# CHECK-SPECIAL-RELOCS: : +# CHECK-SPECIAL-RELOCS-NEXT: .word 0x00000000 +# CHECK-SPECIAL-RELOCS-NEXT: .word 0x00000000 +# CHECK-DAG: [[#POINTER_PAST_HIDDEN_GLOBAL_END]] {{.*}} R_AARCH64_RELATIVE {{0*}}[[#HIDDEN_GLOBAL + 16]] +# CHECK-SPECIAL-RELOCS: : +# CHECK-SPECIAL-RELOCS-NEXT: .word 0xfffffff0 +# CHECK-SPECIAL-RELOCS-NEXT: .word 0xffffffff + +## More ABS64 relocations. +# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern + 0 +# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN_UNTAGGED]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern_untagged + 0 +# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN_OUTSIDE_THIS_DSO]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern_outside_this_dso + 0 +# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN_CONST_DEFINITION_BUT_NONCONST_IMPORT]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern_const_definition_but_nonconst_import + 0 +# CHECK-DAG: [[#POINTER_TO_GLOBAL_EXTERN_UNTAGGED_DEFINITION_BUT_TAGGED_IMPORT]] {{[0-9a-f]+}} R_AARCH64_ABS64 {{[0-9a-f]+}} global_extern_untagged_definition_but_tagged_import + 0 + +# CHECK: Memtag Dynamic Entries +# CHECK-NEXT: AARCH64_MEMTAG_MODE: Synchronous (0) +# CHECK-NEXT: AARCH64_MEMTAG_HEAP: Disabled (0) +# CHECK-NEXT: AARCH64_MEMTAG_STACK: Disabled (0) +# CHECK-NEXT: AARCH64_MEMTAG_GLOBALS: 0x{{[0-9a-f]+}} +# CHECK-NEXT: AARCH64_MEMTAG_GLOBALSSZ: 23 + +# CHECK: Memtag Android Note +# CHECK-NEXT: Tagging Mode: SYNC +# CHECK-NEXT: Heap: Disabled +# CHECK-NEXT: Stack: Disabled + +## Global variable order hopefully isn't too brittle of a test here, but this allows us to make sure +## that we have all the global variables we expect, and no more. +# CHECK: Memtag Global Descriptors: +# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_INSIDE_GLOBAL]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_END]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_PAST_GLOBAL_END]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_UNTAGGED]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_CONST_GLOBAL]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_CONST_GLOBAL]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_GLOBAL]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_ATTR_GLOBAL]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_ATTR_CONST_GLOBAL]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_HIDDEN_GLOBAL_END]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_PAST_HIDDEN_GLOBAL_END]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN_UNTAGGED]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN_OUTSIDE_THIS_DSO]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN_CONST_DEFINITION_BUT_NONCONST_IMPORT]]: 0x10 +# CHECK-NEXT: 0x[[#POINTER_TO_GLOBAL_EXTERN_UNTAGGED_DEFINITION_BUT_TAGGED_IMPORT]]: 0x10 +# CHECK-NEXT: 0x[[#GLOBAL]]: 0x20 +# CHECK-NEXT: 0x[[#HIDDEN_ATTR_GLOBAL]]: 0x10 +# CHECK-NEXT: 0x[[#HIDDEN_GLOBAL]]: 0x10 +# CHECK-NEXT: 0x[[#GLOBAL_EXTERN]]: 0x10 +# CHECK-NOT: 0x