mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 11:02:04 +08:00
[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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,);
|
||||
|
||||
@@ -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 differently 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();
|
||||
|
||||
@@ -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 differently than the regular variables.
|
||||
bool needsGot(RelExpr expr);
|
||||
} // namespace lld::elf
|
||||
|
||||
#endif
|
||||
|
||||
@@ -254,8 +254,8 @@ protected:
|
||||
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 @@ public:
|
||||
// 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.
|
||||
//
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 @@ public:
|
||||
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;
|
||||
|
||||
@@ -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"); \
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -46,6 +46,7 @@ struct PhdrEntry {
|
||||
};
|
||||
|
||||
void addReservedSymbols();
|
||||
bool includeInSymtab(const Symbol &b);
|
||||
|
||||
template <class ELFT> uint32_t calcMipsEFlags();
|
||||
|
||||
|
||||
382
lld/test/ELF/Inputs/aarch64-memtag-globals.s
Normal file
382
lld/test/ELF/Inputs/aarch64-memtag-globals.s
Normal file
@@ -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 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 <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,@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
|
||||
@@ -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
|
||||
|
||||
184
lld/test/ELF/aarch64-memtag-globals.s
Normal file
184
lld/test/ELF/aarch64-memtag-globals.s
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user