diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -270,6 +270,11 @@ case ELF::EM_RISCV: switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_RISCV_ATTRIBUTES); } break; + case ELF::EM_AARCH64: + switch (Type) { + STRINGIFY_ENUM_CASE(ELF, SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC); + STRINGIFY_ENUM_CASE(ELF, SHT_AARCH64_MEMTAG_GLOBALS_STATIC); + } default: break; } diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -707,6 +707,10 @@ case ELF::EM_MSP430: ECase(SHT_MSP430_ATTRIBUTES); break; + case ELF::EM_AARCH64: + ECase(SHT_AARCH64_MEMTAG_GLOBALS_STATIC); + ECase(SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC); + break; default: // Nothing to do. break; diff --git a/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test b/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test --- a/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test +++ b/llvm/test/tools/llvm-readobj/ELF/AArch64/memtag.test @@ -80,10 +80,10 @@ # INVALID-SAME: Unknown (2) # LLVM: 0x000000007000000D AARCH64_MEMTAG_GLOBALS 0xdeadbeef -# LLVM: 0x000000007000000F AARCH64_MEMTAG_GLOBALSSZ 1234 +# LLVM: 0x000000007000000F AARCH64_MEMTAG_GLOBALSSZ 15 # GNU: 0x000000007000000d (AARCH64_MEMTAG_GLOBALS) 0xdeadbeef0 -# GNU: 0x000000007000000f (AARCH64_MEMTAG_GLOBALSSZ) 1234 +# GNU: 0x000000007000000f (AARCH64_MEMTAG_GLOBALSSZ) 15 # GNU: Displaying notes found in: .note.android.memtag # GNU-NEXT: Owner Data size Description @@ -132,8 +132,8 @@ # NOSTACK: AARCH64_MEMTAG_STACK: Disabled (0) # LLVM: AARCH64_MEMTAG_GLOBALS: 0xdeadbeef0 # GNU: AARCH64_MEMTAG_GLOBALS: 0xdeadbeef0 -# LLVM: AARCH64_MEMTAG_GLOBALSSZ: 1234 -# GNU: AARCH64_MEMTAG_GLOBALSSZ: 1234 +# LLVM: AARCH64_MEMTAG_GLOBALSSZ: 15 +# GNU: AARCH64_MEMTAG_GLOBALSSZ: 15 # LLVM-OK: Memtag Android Note # GNU-OK: Memtag Android Note @@ -146,6 +146,71 @@ # STACK: Stack: Enabled # NOSTACK: Stack: Disabled +## Below is the maths for calculating the hand-written `.memtag.globals.dynamic` section contents. +## This is based on the AArch64 MemtagABI: +## https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#83encoding-of-sht_aarch64_memtag_globals_dynamic +## You may find the following python one-liner helpful to encode your own values: +## `binascii.hexlify(leb128.u.encode(value_to_encode))` +## Remember that a granule is 16 bytes. +## 1. Tagged region of 16 bytes at 0xdead0000 +## - Distance from the end of the last tagged region: 0xdead0000 bytes, 0xdead000 granules +## - Size: 0x10 bytes, 0x1 granules +## - Value to encode: (0xdead000 << 3) + 0x1 = 0x6f568001 +## - ULEB-encoded value: 0x81 0x80 0xda 0xfa 0x06 +## 2. Tagged region of 32 bytes at 0xdead0010 +## - Distance from the end of the last tagged region: 0x0 bytes, 0x0 granules +## - Size: 0x20 bytes, 0x2 granules +## - Value to encode: (0 << 3) + 0x2 == 0x2 +## - ULEB-encoded value: 0x2 +## 3. Tagged region of 64 bytes at 0xdead0100 +## - Distance: 0xdead0100 - 0xdead0010 - 32 = 0xd0 bytes, 0xd granules +## - Size: 0x40 bytes, 0x4 granules. +## - Value to encode: (0xd << 3) + 0x4 = 0x6c +## - ULEB-encoded value: 0x6c +## 4. Tagged region of 0x1000 bytes at 0xdeadf000 +## - Distance: 0xdeadf000 - 0xdead0100 - 64 = 0xeec0 bytes, 0xeec granules +## - Size: 0x1000 bytes, 0x100 granules. +## (note: size of 0x100 granules exceeds the 3-bit size allowance in value to encode, so the +## size needs to go to its own value, minus one). +## - 1st value to encode (distance only): (0xeec << 3) == 0x7760 +## - 1st ULEB-encoded value: 0xe0 0xee 0x01 +## - 2nd value to encode (size only): 0x100 - 1 +## - 2nd ULEB-encoded value: 0xff 0x01 +## 5. Tagged region of 16 bytes at 0xdeae0000 +## - Distance: 0xdeae000 - 0xdeadf000 - 0x1000 = 0x0 bytes, 0x0 granules (regions are adjacent) +## - Size: 0x10 bytes, 0x1 granules +## - Value to encode: (0x0 << 3) + 0x1 +## - ULEB-encoded value: 0x01 +## 6. Tagged region of 16 bytes at 0xdeae0010 +## - Distance: 0x0 (regions are adjacent) +## - Size: 0x10 bytes, 0x1 granules +## - Value to encode: (0x0 << 3) + 0x1 +## - ULEB-encoded value: 0x01 +## 6. Tagged region of 16 bytes at 0xdeae0020 +## - Distance: 0x0 (regions are adjacent) +## - Size: 0x10 bytes, 0x1 granules +## - Value to encode: (0x0 << 3) + 0x1 +## - ULEB-encoded value: 0x01 + +# LLVM-OK: Memtag Global Descriptors: [ +# LLVM-OK-NEXT: 0xDEAD0000: 0x10 +# LLVM-OK-NEXT: 0xDEAD0010: 0x20 +# LLVM-OK-NEXT: 0xDEAD0100: 0x40 +# LLVM-OK-NEXT: 0xDEADF000: 0x1000 +# LLVM-OK-NEXT: 0xDEAE0000: 0x10 +# LLVM-OK-NEXT: 0xDEAE0010: 0x10 +# LLVM-OK-NEXT: 0xDEAE0020: 0x10 +# LLVM-OK-NEXT: ] +# GNU-OK: Memtag Global Descriptors: +# GNU-OK-NEXT: 0xdead0000: 0x10 +# GNU-OK-NEXT: 0xdead0010: 0x20 +# GNU-OK-NEXT: 0xdead0100: 0x40 +# GNU-OK-NEXT: 0xdeadf000: 0x1000 +# GNU-OK-NEXT: 0xdeae0000: 0x10 +# GNU-OK-NEXT: 0xdeae0010: 0x10 +# GNU-OK-NEXT: 0xdeae0020: 0x10 +# GNU-OK-NOT: {{.}} + ######################################### ## --docnum=1 (default) ######################################### @@ -175,17 +240,25 @@ - Tag: DT_AARCH64_MEMTAG_GLOBALS Value: 0xdeadbeef0 - Tag: DT_AARCH64_MEMTAG_GLOBALSSZ - Value: 1234 + Value: 15 - Tag: DT_INIT_ARRAY Value: 0x1000 + - Name: .memtag.globals.dynamic + Type: SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC + Flags: [ SHF_ALLOC ] + Address: 0xdeadbeef0 + AddressAlign: 0x4 + Content: 8180DAFA06026CE0EE01ff01010101 + +######################################### +## Ensure the header is printed, even if there's no relevant dynamic entries, +## and that nothing else is printed. +######################################### # RUN: yaml2obj --docnum=2 %s -o %t # RUN: llvm-readelf --memtag %t | FileCheck %s --check-prefixes=MISSING-GNU # RUN: llvm-readobj --memtag %t | FileCheck %s --check-prefixes=MISSING-LLVM -## Ensure the header is printed, even if there's no relevant dynamic entries, -## and that nothing else is printed. - # MISSING-GNU-NOT: {{.}} # MISSING-GNU: Memtag Dynamic Entries: # MISSING-GNU-NEXT: < none found > @@ -218,3 +291,96 @@ Entries: - Tag: DT_INIT_ARRAY Value: 0x1000 + +######################################### +## Ensure that we fail if DT_AARCH64_MEMTAG_GLOBALSSZ doesn't match the actual +## section size. +######################################### + +# RUN: yaml2obj --docnum=3 %s -o %t \ +# RUN: -D DT_AARCH64_MEMTAG_GLOBALSSZ=0x1337 \ +# RUN: -D GLOBALS_SECTION_CONTENTS=12345678901234567890 +# RUN: llvm-readelf --memtag %t 2>&1 | FileCheck %s --check-prefixes=SIZE-MISMATCH +# RUN: llvm-readobj --memtag %t 2>&1 | FileCheck %s --check-prefixes=SIZE-MISMATCH + +# SIZE-MISMATCH: warning: {{.*}} mismatch between DT_AARCH64_MEMTAG_GLOBALSSZ (0x1337) and +# SIZE-MISMATCH-SAME: SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section size (0xa) + +######################################### +## Ensure that we fail if DT_AARCH64_MEMTAG_GLOBALS doesn't agree with the address of the section. +######################################### + +# RUN: yaml2obj --docnum=3 %s -o %t \ +# RUN: -D DT_AARCH64_MEMTAG_GLOBALS=0xdeadbeef123 \ +# RUN: -D DT_AARCH64_MEMTAG_GLOBALSSZ=10 \ +# RUN: -D GLOBALS_SECTION_CONTENTS=00000000000000000000 +# RUN: llvm-readelf --memtag %t 2>&1 | FileCheck %s --check-prefixes=BAD-SECTION +# RUN: llvm-readobj --memtag %t 2>&1 | FileCheck %s --check-prefixes=BAD-SECTION + +# BAD-SECTION: warning: {{.*}} SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section was unexpectedly at +# BAD-SECTION-SAME: 0xdeadbeef, when DT_AARCH64_MEMTAG_GLOBALS says it should be at 0xdeadbeef123 + +######################################### +## Ensure that we fail if the ULEB-encoded globals stream can't be decoded. +######################################### + +# RUN: yaml2obj --docnum=3 %s -o %t \ +# RUN: -D DT_AARCH64_MEMTAG_GLOBALSSZ=3 \ +# RUN: -D GLOBALS_SECTION_CONTENTS=808080 +# RUN: llvm-readelf --memtag %t 2>&1 | FileCheck %s --check-prefixes=BAD-STREAM1 +# RUN: llvm-readobj --memtag %t 2>&1 | FileCheck %s --check-prefixes=BAD-STREAM1 + +# BAD-STREAM1: warning: {{.*}} error decoding distance uleb, 3 byte(s) into +# BAD-STREAM1-SAME: SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC + +# RUN: yaml2obj --docnum=3 %s -o %t \ +# RUN: -D DT_AARCH64_MEMTAG_GLOBALSSZ=2 \ +# RUN: -D GLOBALS_SECTION_CONTENTS=0080 +# RUN: llvm-readelf --memtag %t 2>&1 | FileCheck %s --check-prefixes=BAD-STREAM2 +# RUN: llvm-readobj --memtag %t 2>&1 | FileCheck %s --check-prefixes=BAD-STREAM2 + +# BAD-STREAM2: warning: {{.*}} error decoding size-only uleb, 1 byte(s) into +# BAD-STREAM2-SAME: SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC + +# RUN: yaml2obj --docnum=3 %s -o %t \ +# RUN: -D SH_OFFSET=0xffff \ +# RUN: -D DT_AARCH64_MEMTAG_GLOBALSSZ=10 \ +# RUN: -D GLOBALS_SECTION_CONTENTS=00000000000000000000 +# RUN: llvm-readelf --memtag %t 2>&1 | FileCheck %s --check-prefixes=UNREADABLE-SECTION +# RUN: llvm-readobj --memtag %t 2>&1 | FileCheck %s --check-prefixes=UNREADABLE-SECTION + +# UNREADABLE-SECTION: couldn't get SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section contents: section +# UNREADABLE-SECTION-SAME: [index 2] has a sh_offset (0xffff) + sh_size (0xa) that is greater than +# UNREADABLE-SECTION-SAME: the file size + +######################################### +## --docnum=3 +######################################### + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_AARCH64 +Sections: + - Name: .dynamic + Type: SHT_DYNAMIC + Entries: + - Tag: DT_AARCH64_MEMTAG_MODE + Value: 0 + - Tag: DT_AARCH64_MEMTAG_HEAP + Value: 0 + - Tag: DT_AARCH64_MEMTAG_STACK + Value: 0 + - Tag: DT_AARCH64_MEMTAG_GLOBALS + Value: [[DT_AARCH64_MEMTAG_GLOBALS=0xdeadbeef]] + - Tag: DT_AARCH64_MEMTAG_GLOBALSSZ + Value: [[DT_AARCH64_MEMTAG_GLOBALSSZ]] + - Name: .memtag.globals.dynamic + Type: SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC + Flags: [ SHF_ALLOC ] + Address: 0xdeadbeef + AddressAlign: 0x4 + Content: [[GLOBALS_SECTION_CONTENTS]] + ShOffset: [[SH_OFFSET=]] diff --git a/llvm/test/tools/llvm-readobj/ELF/machine-specific-section-types.test b/llvm/test/tools/llvm-readobj/ELF/machine-specific-section-types.test --- a/llvm/test/tools/llvm-readobj/ELF/machine-specific-section-types.test +++ b/llvm/test/tools/llvm-readobj/ELF/machine-specific-section-types.test @@ -13,6 +13,10 @@ # RUN: llvm-readobj --section-headers %t-mips.o | FileCheck %s --check-prefix=MIPS-LLVM # RUN: llvm-readelf --section-headers %t-mips.o | FileCheck %s --check-prefix=MIPS-GNU +# RUN: yaml2obj %s --docnum=4 -o %t-aarch64.o +# RUN: llvm-readobj --section-headers %t-aarch64.o | FileCheck %s --check-prefix=AARCH64-LLVM +# RUN: llvm-readelf --section-headers %t-aarch64.o | FileCheck %s --check-prefix=AARCH64-GNU + # ARM-LLVM: Name: exidx # ARM-LLVM: Type: SHT_ARM_EXIDX # ARM-LLVM: Name: preemptmap @@ -49,6 +53,14 @@ # MIPS-GNU: abiflags MIPS_ABIFLAGS # MIPS-GNU: dwarf MIPS_DWARF +# AARCH64-LLVM: Name: .memtag.globals.dynamic +# AARCH64-LLVM: Type: SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC +# AARCH64-LLVM: Name: .memtag.globals.static +# AARCH64-LLVM: Type: SHT_AARCH64_MEMTAG_GLOBALS_STATIC + +# AARCH64-GNU: .memtag.globals.dynamic AARCH64_MEMTAG_GLOBALS_DYNAMIC +# AARCH64-GNU: .memtag.globals.static AARCH64_MEMTAG_GLOBALS_STATIC + --- !ELF FileHeader: Class: ELFCLASS64 @@ -93,3 +105,15 @@ ISA: MIPS64 - Name: dwarf Type: SHT_MIPS_DWARF + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_AARCH64 +Sections: + - Name: .memtag.globals.dynamic + Type: SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC + - Name: .memtag.globals.static + Type: SHT_AARCH64_MEMTAG_GLOBALS_STATIC diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -221,6 +221,7 @@ void printArchSpecificInfo() override; void printStackMap() const override; void printMemtag() override; + ArrayRef getMemtagGlobalsSectionContents(uintptr_t ExpectedAddr); // Hash histogram shows statistics of how efficient the hash was for the // dynamic symbol table. The table shows the number of hash buckets for @@ -309,7 +310,8 @@ virtual void printMemtag( const ArrayRef> DynamicEntries, - const ArrayRef AndroidNoteDesc) = 0; + const ArrayRef AndroidNoteDesc, + const ArrayRef> Descriptors) = 0; virtual void printHashHistogram(const Elf_Hash &HashTable) const; virtual void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) const; @@ -593,7 +595,8 @@ void printStackSizes() override; void printMemtag( const ArrayRef> DynamicEntries, - const ArrayRef AndroidNoteDesc) override; + const ArrayRef AndroidNoteDesc, + const ArrayRef> Descriptors) override; void printHashHistogramStats(size_t NBucket, size_t MaxChain, size_t TotalSyms, ArrayRef Count, bool IsGnu) const override; @@ -700,7 +703,8 @@ void printStackSizes() override; void printMemtag( const ArrayRef> DynamicEntries, - const ArrayRef AndroidNoteDesc) override; + const ArrayRef AndroidNoteDesc, + const ArrayRef> Descriptors) override; void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, DataRegion ShndxTable) const; void printHashHistogramStats(size_t NBucket, size_t MaxChain, @@ -5292,14 +5296,14 @@ return false; for (const auto &KV : Props) OS << " " << KV.first << ": " << KV.second << '\n'; - OS << '\n'; return true; } template void GNUELFDumper::printMemtag( const ArrayRef> DynamicEntries, - const ArrayRef AndroidNoteDesc) { + const ArrayRef AndroidNoteDesc, + const ArrayRef> Descriptors) { OS << "Memtag Dynamic Entries:\n"; if (DynamicEntries.empty()) OS << " < none found >\n"; @@ -5311,6 +5315,15 @@ OS << "Memtag Android Note:\n"; printAndroidNote(OS, ELF::NT_ANDROID_TYPE_MEMTAG, AndroidNoteDesc); } + + if (Descriptors.empty()) + return; + + OS << "Memtag Global Descriptors:\n"; + for (const auto &[Addr, BytesToTag] : Descriptors) { + OS << " 0x" << utohexstr(Addr, /*LowerCase=*/true) << ": 0x" + << utohexstr(BytesToTag, /*LowerCase=*/true) << "\n"; + } } template @@ -5956,19 +5969,62 @@ /*ProcessNoteFn=*/ProcessNote, /*FinishNotesFn=*/[]() {}); } +template +ArrayRef +ELFDumper::getMemtagGlobalsSectionContents(uintptr_t ExpectedAddr) { + for (const typename ELFT::Shdr &Sec : cantFail(Obj.sections())) { + if (Sec.sh_type != SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC) + continue; + if (Sec.sh_addr != ExpectedAddr) { + reportUniqueWarning( + "SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section was unexpectedly at 0x" + + Twine::utohexstr(Sec.sh_addr) + + ", when DT_AARCH64_MEMTAG_GLOBALS says it should be at 0x" + + Twine::utohexstr(ExpectedAddr)); + return ArrayRef(); + } + Expected> Contents = Obj.getSectionContents(Sec); + if (auto E = Contents.takeError()) { + reportUniqueWarning( + "couldn't get SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section contents: " + + toString(std::move(E))); + return ArrayRef(); + } + return Contents.get(); + } + return ArrayRef(); +} + +// Reserve the lower three bits of the first byte of the step distance when +// encoding the memtag descriptors. Found to be the best overall size tradeoff +// when compiling Android T with full MTE globals enabled. +constexpr uint64_t MemtagStepVarintReservedBits = 3; +constexpr uint64_t MemtagGranuleSize = 16; + template void ELFDumper::printMemtag() { if (Obj.getHeader().e_machine != EM_AARCH64) return; std::vector> DynamicEntries; + size_t MemtagGlobalsSz = 0; + uintptr_t MemtagGlobals = 0; for (const typename ELFT::Dyn &Entry : dynamic_table()) { uintX_t Tag = Entry.getTag(); switch (Tag) { + case DT_AARCH64_MEMTAG_GLOBALSSZ: + MemtagGlobalsSz = Entry.getVal(); + DynamicEntries.emplace_back(Obj.getDynamicTagAsString(Tag), + getDynamicEntry(Tag, Entry.getVal())); + break; + case DT_AARCH64_MEMTAG_GLOBALS: + MemtagGlobals = Entry.getVal(); + DynamicEntries.emplace_back(Obj.getDynamicTagAsString(Tag), + getDynamicEntry(Tag, Entry.getVal())); + break; case DT_AARCH64_MEMTAG_MODE: case DT_AARCH64_MEMTAG_HEAP: case DT_AARCH64_MEMTAG_STACK: - case DT_AARCH64_MEMTAG_GLOBALSSZ: - case DT_AARCH64_MEMTAG_GLOBALS: DynamicEntries.emplace_back(Obj.getDynamicTagAsString(Tag), getDynamicEntry(Tag, Entry.getVal())); + break; } } @@ -5987,7 +6043,54 @@ const typename ELFT::Addr) {}, /*ProcessNoteFn=*/FindAndroidNote, /*FinishNotesFn=*/[]() {}); - printMemtag(DynamicEntries, AndroidNoteDesc); + ArrayRef Contents = getMemtagGlobalsSectionContents(MemtagGlobals); + if (Contents.size() != MemtagGlobalsSz) { + reportUniqueWarning( + "mismatch between DT_AARCH64_MEMTAG_GLOBALSSZ (0x" + + Twine::utohexstr(MemtagGlobalsSz) + + ") and SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC section size (0x" + + Twine::utohexstr(Contents.size()) + ")"); + Contents = ArrayRef(); + } + + std::vector> GlobalDescriptors; + uint64_t Address = 0; + // See the AArch64 MemtagABI document for a description of encoding scheme: + // https://github.com/ARM-software/abi-aa/blob/main/memtagabielf64/memtagabielf64.rst#83encoding-of-sht_aarch64_memtag_globals_dynamic + for (size_t I = 0; I < Contents.size();) { + const char *Error = nullptr; + unsigned DecodedBytes = 0; + uint64_t Value = decodeULEB128(Contents.data() + I, &DecodedBytes, + Contents.end(), &Error); + I += DecodedBytes; + if (Error) { + reportUniqueWarning( + "error decoding distance uleb, " + Twine(DecodedBytes) + + " byte(s) into SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC: " + Twine(Error)); + GlobalDescriptors.clear(); + break; + } + uint64_t Distance = Value >> MemtagStepVarintReservedBits; + uint64_t GranulesToTag = Value & ((1 << MemtagStepVarintReservedBits) - 1); + if (GranulesToTag == 0) { + GranulesToTag = decodeULEB128(Contents.data() + I, &DecodedBytes, + Contents.end(), &Error) + + 1; + I += DecodedBytes; + if (Error) { + reportUniqueWarning( + "error decoding size-only uleb, " + Twine(DecodedBytes) + + " byte(s) into SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC: " + Twine(Error)); + GlobalDescriptors.clear(); + break; + } + } + Address += Distance * MemtagGranuleSize; + GlobalDescriptors.emplace_back(Address, GranulesToTag * MemtagGranuleSize); + Address += GranulesToTag * MemtagGranuleSize; + } + + printMemtag(DynamicEntries, AndroidNoteDesc, GlobalDescriptors); } template void GNUELFDumper::printELFLinkerOptions() { @@ -7410,17 +7513,30 @@ template void LLVMELFDumper::printMemtag( const ArrayRef> DynamicEntries, - const ArrayRef AndroidNoteDesc) { - ListScope L(W, "Memtag Dynamic Entries:"); - if (DynamicEntries.empty()) - W.printString("< none found >"); - for (const auto &DynamicEntryKV : DynamicEntries) - W.printString(DynamicEntryKV.first, DynamicEntryKV.second); + const ArrayRef AndroidNoteDesc, + const ArrayRef> Descriptors) { + { + ListScope L(W, "Memtag Dynamic Entries:"); + if (DynamicEntries.empty()) + W.printString("< none found >"); + for (const auto &DynamicEntryKV : DynamicEntries) + W.printString(DynamicEntryKV.first, DynamicEntryKV.second); + } if (!AndroidNoteDesc.empty()) { ListScope L(W, "Memtag Android Note:"); printAndroidNoteLLVMStyle(ELF::NT_ANDROID_TYPE_MEMTAG, AndroidNoteDesc, W); } + + if (Descriptors.empty()) + return; + + { + ListScope L(W, "Memtag Global Descriptors:"); + for (const auto &[Addr, BytesToTag] : Descriptors) { + W.printHex("0x" + utohexstr(Addr), BytesToTag); + } + } } template