[lld] ca35a19 - [lld] Synthesize metadata for MTE globals
Mitch Phillips via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 31 08:08:07 PDT 2023
Author: Mitch Phillips
Date: 2023-07-31T17:07:42+02:00
New Revision: ca35a19acab1cf6788c42037bbedeca86e34a455
URL: https://github.com/llvm/llvm-project/commit/ca35a19acab1cf6788c42037bbedeca86e34a455
DIFF: https://github.com/llvm/llvm-project/commit/ca35a19acab1cf6788c42037bbedeca86e34a455.diff
LOG: [lld] Synthesize metadata for MTE globals
As per the ABI at
https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst,
this patch interprets the SHT_AARCH64_MEMTAG_GLOBALS_STATIC section,
which contains R_NONE relocations to tagged globals, and emits a
SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section, with the correct
DT_AARCH64_MEMTAG_GLOBALS and DT_AARCH64_MEMTAG_GLOBALSSZ dynamic
entries. This section describes, in a uleb-encoded stream, global memory
ranges that should be tagged with MTE.
We are also out of bits to spare in the LLD Symbol class. As a result,
I've reused the 'needsTocRestore' bit, which is a PPC64 only feature.
Now, it's also used for 'isTagged' on AArch64.
An entry in SHT_AARCH64_MEMTAG_GLOBALS_STATIC is practically a guarantee
from an objfile that all references to the linked symbol are through the
GOT, and meet correct alignment requirements. As a result, we go through
all symbols and make sure that, for all symbols $SYM, all object files
that reference $SYM also have a SHT_AARCH64_MEMTAG_GLOBALS_STATIC entry
for $SYM. If this isn't the case, we demote the symbol to being
untagged. Symbols that are imported from other DSOs should always be
fine, as they're GOT-referenced (and thus the GOT entry either has the
correct tag or not, depending on whether it's tagged in the defining DSO
or not).
Additionally hand-tested by building {libc, libm, libc++, libm, and libnetd}
on Android with some experimental MTE globals support in the
linker/libc.
Reviewed By: MaskRay, peter.smith
Differential Revision: https://reviews.llvm.org/D152921
Added:
lld/test/ELF/Inputs/aarch64-memtag-globals.s
lld/test/ELF/aarch64-memtag-globals.s
Modified:
lld/ELF/Arch/AArch64.cpp
lld/ELF/Arch/PPC64.cpp
lld/ELF/Driver.cpp
lld/ELF/Relocations.cpp
lld/ELF/Relocations.h
lld/ELF/Symbols.h
lld/ELF/SyntheticSections.cpp
lld/ELF/SyntheticSections.h
lld/ELF/Target.h
lld/ELF/Thunks.cpp
lld/ELF/Writer.cpp
lld/ELF/Writer.h
lld/test/ELF/aarch64-memtag-android-abi.s
Removed:
################################################################################
diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp
index c83a159e3f0530..174a0a3624f776 100644
--- 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 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel,
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<int64_t>(rel.sym->getSize())))
+ write64(loc, -rel.addend);
+ else
+ write64(loc, val);
+ break;
case R_AARCH64_PREL64:
write64(loc, val);
break;
@@ -745,6 +760,12 @@ bool AArch64Relaxer::tryRelaxAdrpLdr(const Relocation &adrpRel,
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<InputSection>(&sec))
@@ -756,6 +777,12 @@ void AArch64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
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 @@ static TargetInfo *getTargetInfo() {
}
TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); }
+
+template <class ELFT>
+static void
+addTaggedSymbolReferences(InputSectionBase &sec,
+ DenseMap<Symbol *, unsigned> &referenceCount) {
+ assert(sec.type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC);
+
+ const RelsOrRelas<ELFT> rels = sec.relsOrRelas<ELFT>();
+ 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<ELFT>()->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<ELFFileBase *, 0> &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<Symbol *, unsigned> 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
index 36b1d0e3c9be44..15c792fd4b4cef 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -1556,7 +1556,7 @@ void PPC64::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
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
index c2059c70e15a3d..8ce2f481f2df6d 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -786,13 +786,6 @@ static int getMemtagMode(opt::InputArgList &args) {
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 @@ void LinkerDriver::link(opt::InputArgList &args) {
// 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.cpp b/lld/ELF/Relocations.cpp
index af15f5a92546e2..9305c959d0f0f6 100644
--- 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 <algorithm>
@@ -199,10 +200,7 @@ static bool needsPlt(RelExpr expr) {
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
diff erently than the regular variables.
-static bool needsGot(RelExpr expr) {
+bool lld::elf::needsGot(RelExpr expr) {
return oneof<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
R_AARCH64_GOT_PAGE, R_LOONGARCH_GOT, R_LOONGARCH_GOT_PAGE_PC>(
@@ -859,6 +857,23 @@ static void addRelativeReloc(InputSectionBase &isec, uint64_t offsetInSec,
RelType type) {
Partition &part = isec.getPartition();
+ if (sym.isTagged()) {
+ std::lock_guard<std::mutex> 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<uint64_t>(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 @@ void elf::postScanRelocations() {
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/Relocations.h b/lld/ELF/Relocations.h
index e36215bd0d936b..0559245a8f2c00 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -220,6 +220,11 @@ ArrayRef<RelTy> sortRels(ArrayRef<RelTy> rels, SmallVector<RelTy, 0> &storage) {
}
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
diff erently than the regular variables.
+bool needsGot(RelExpr expr);
} // namespace lld::elf
#endif
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index bb440530b4df9c..4addb79d125791 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -254,8 +254,8 @@ class Symbol {
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 @@ class Symbol {
// 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.cpp b/lld/ELF/SyntheticSections.cpp
index de25750bf9ebf5..09090835af4a62 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -1453,6 +1453,10 @@ DynamicSection<ELFT>::computeContents() {
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 @@ size_t PackageMetadataNote::getSize() const {
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<const Symbol *, 0> &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<Partition> elf::partitions;
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 38d0c80a073de5..21a3f768ffcf8e 100644
--- 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 @@ class PackageMetadataNote final : public SyntheticSection {
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<const Symbol *, 0> symbols;
+};
+
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
template <class ELFT> void splitSections();
@@ -1277,6 +1305,7 @@ struct Partition {
std::unique_ptr<GnuHashTableSection> gnuHashTab;
std::unique_ptr<HashTableSection> hashTab;
std::unique_ptr<MemtagAndroidNote> memtagAndroidNote;
+ std::unique_ptr<MemtagDescriptors> memtagDescriptors;
std::unique_ptr<PackageMetadataNote> packageMetadataNote;
std::unique_ptr<RelocationBaseSection> relaDyn;
std::unique_ptr<RelrBaseSection> relrDyn;
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 9d4f22dd93f1bf..95109a3f35a5ac 100644
--- 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 <array>
@@ -233,6 +234,7 @@ void addArmInputSectionMappingSymbols();
void addArmSyntheticSectionMappingSymbol(Defined *);
void sortArmMappingSymbols();
void convertArmInstructionstoBE8(InputSection *sec, uint8_t *buf);
+void createTaggedSymbols(const SmallVector<ELFFileBase *, 0> &files);
LLVM_LIBRARY_VISIBILITY extern const TargetInfo *target;
TargetInfo *getTarget();
@@ -306,17 +308,17 @@ inline void write64(void *p, uint64_t v) {
#endif
#define invokeELFT(f, ...) \
switch (config->ekind) { \
- case ELF32LEKind: \
- f<ELF32LE>(__VA_ARGS__); \
+ case lld::elf::ELF32LEKind: \
+ f<llvm::object::ELF32LE>(__VA_ARGS__); \
break; \
- case ELF32BEKind: \
- f<ELF32BE>(__VA_ARGS__); \
+ case lld::elf::ELF32BEKind: \
+ f<llvm::object::ELF32BE>(__VA_ARGS__); \
break; \
- case ELF64LEKind: \
- f<ELF64LE>(__VA_ARGS__); \
+ case lld::elf::ELF64LEKind: \
+ f<llvm::object::ELF64LE>(__VA_ARGS__); \
break; \
- case ELF64BEKind: \
- f<ELF64BE>(__VA_ARGS__); \
+ case lld::elf::ELF64BEKind: \
+ f<llvm::object::ELF64BE>(__VA_ARGS__); \
break; \
default: \
llvm_unreachable("unknown config->ekind"); \
diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index 30559dbe826312..5f543ffdcfaa32 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -1138,7 +1138,7 @@ void PPC64PltCallStub::writeTo(uint8_t *buf) {
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::writeTo(uint8_t *buf) {
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.cpp b/lld/ELF/Writer.cpp
index 368c9aabceae81..255f8c334b969b 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -347,8 +347,13 @@ template <class ELFT> void elf::createSyntheticSections() {
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<MemtagAndroidNote>();
add(*part.memtagAndroidNote);
+ part.memtagDescriptors = std::make_unique<MemtagDescriptors>();
+ add(*part.memtagDescriptors);
}
if (config->androidPackDynRelocs)
@@ -672,7 +677,7 @@ static bool shouldKeepInSymtab(const Defined &sym) {
return true;
}
-static bool includeInSymtab(const Symbol &b) {
+bool lld::elf::includeInSymtab(const Symbol &b) {
if (auto *d = dyn_cast<Defined>(&b)) {
// Always include absolute symbols.
SectionBase *sec = d->section;
@@ -1652,6 +1657,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
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/ELF/Writer.h b/lld/ELF/Writer.h
index a302caad339f62..c69de54f76e9b4 100644
--- a/lld/ELF/Writer.h
+++ b/lld/ELF/Writer.h
@@ -46,6 +46,7 @@ struct PhdrEntry {
};
void addReservedSymbols();
+bool includeInSymtab(const Symbol &b);
template <class ELFT> uint32_t calcMipsEFlags();
diff --git a/lld/test/ELF/Inputs/aarch64-memtag-globals.s b/lld/test/ELF/Inputs/aarch64-memtag-globals.s
new file mode 100644
index 00000000000000..c48083f5550f87
--- /dev/null
+++ b/lld/test/ELF/Inputs/aarch64-memtag-globals.s
@@ -0,0 +1,382 @@
+#--- input_1.s
+## Generated with:
+##
+## - clang <input_file.c> -fsanitize=memtag-globals -O2 -S -fPIC -o - \
+## --target=aarch64-linux-android31 -fno-asynchronous-unwind-tables
+##
+## <input_file.c> 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
diff erent 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, at 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, at 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, at object
+ .bss
+ .globl global
+ .p2align 4, 0x0
+global:
+ .zero 32
+ .size global, 32
+
+ .type global_untagged, at object // @global_untagged
+ .globl global_untagged
+ .p2align 2, 0x0
+global_untagged:
+ .word 0 // 0x0
+ .size global_untagged, 4
+
+ .type const_global, at object // @const_global
+ .section .rodata,"a", at 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, at 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, at object
+ .section .rodata,"a", at 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, at 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, at 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, at 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, at 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, at 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, at 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, at object // @hidden_const_global
+ .section .rodata,"a", at 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, at 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, at object
+ .local hidden_global
+ .comm hidden_global,16,16
+ .memtag pointer_to_hidden_global // @pointer_to_hidden_global
+ .type pointer_to_hidden_global, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at 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, at object // @tls_global
+ .section .tbss,"awT", at nobits
+ .globl tls_global
+ .p2align 2, 0x0
+tls_global:
+ .word 0 // 0x0
+ .size tls_global, 4
+
+ .type hidden_tls_global, at 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","", at progbits
+
+#--- input_2.s
+## Generated with:
+##
+## - clang <input_file.c> -fsanitize=memtag-globals -O2 -S -o - \
+## --target=aarch64-linux-android31 -fno-asynchronous-unwind-tables
+##
+## <input_file.c> 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, at object
+ .bss
+ .globl global_extern
+ .p2align 4, 0x0
+global_extern:
+ .zero 16
+ .size global_extern, 16
+
+ .type global_extern_untagged, at 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, at object
+ .section .rodata,"a", at 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, at 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
index 0e1d5deddbb2fb..e5744483e447e1 100644
--- 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
index 00000000000000..5a92cf7f5112b4
--- /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: <pointer_to_hidden_global_end>:
+# 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: <pointer_past_hidden_global_end>:
+# 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
More information about the llvm-commits
mailing list