From b65ead9186cd4b70d7756b9e83cc7e3e6ed2b524 Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Tue, 4 Jun 2019 11:44:33 +0000 Subject: [PATCH] [AArch64][ELF][llvm-readobj] Add support for BTI and PAC dynamic tags ELF for the 64-bit Arm Architecture defines two processor-specific dynamic tags: DT_AARCH64_BTI_PLT 0x70000001, d_val DT_AARCH64_PAC_PLT 0x70000003, d_val These presence of these tags indicate that PLT sequences have been protected using Branch Target Identification and Pointer Authentication respectively. The presence of both indicates that the PLT sequences have been protected with both Branch Target Identification and Pointer Authentication. This patch adds the tags and tests for llvm-readobj and yaml2obj. As some of the processor specific dynamic tags overlap, this patch splits them up, keeping their original default value if they were not previously mentioned explicitly in a switch case. Differential Revision: https://reviews.llvm.org/D62596 llvm-svn: 362493 --- include/llvm/BinaryFormat/DynamicTags.def | 13 ++ lib/Object/ELF.cpp | 10 ++ lib/ObjectYAML/ELFYAML.cpp | 10 +- .../elf-dynamic-tags-machine-specific.yaml | 38 ++++++ .../elf-dynamic-tags-machine-specific.test | 22 ++++ .../obj2yaml/dynamic-section-arch-tags.test | 26 +++- tools/llvm-readobj/ELFDumper.cpp | 113 ++++++++++++++++-- 7 files changed, 217 insertions(+), 15 deletions(-) diff --git a/include/llvm/BinaryFormat/DynamicTags.def b/include/llvm/BinaryFormat/DynamicTags.def index 82fe72eefad..c884badab36 100644 --- a/include/llvm/BinaryFormat/DynamicTags.def +++ b/include/llvm/BinaryFormat/DynamicTags.def @@ -6,6 +6,11 @@ // such as DT_HIOS, etc. to allow using this file to in other contexts. // For example we can use it to generate a stringification switch statement. +#ifndef AARCH64_DYNAMIC_TAG +#define AARCH64_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value) +#define AARCH64_DYNAMIC_TAG_DEFINED +#endif + #ifndef HEXAGON_DYNAMIC_TAG #define HEXAGON_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value) #define HEXAGON_DYNAMIC_TAG_DEFINED @@ -107,6 +112,10 @@ DYNAMIC_TAG(VERNEED, 0X6FFFFFFE) // The address of the version dependency // table. DYNAMIC_TAG(VERNEEDNUM, 0X6FFFFFFF) // The number of entries in DT_VERNEED. +// AArch64 specific dynamic table entries +AARCH64_DYNAMIC_TAG(AARCH64_BTI_PLT, 0x70000001) +AARCH64_DYNAMIC_TAG(AARCH64_PAC_PLT, 0x70000003) + // Hexagon specific dynamic table entries HEXAGON_DYNAMIC_TAG(HEXAGON_SYMSZ, 0x70000000) HEXAGON_DYNAMIC_TAG(HEXAGON_VER, 0x70000001) @@ -204,6 +213,10 @@ DYNAMIC_TAG(FILTER, 0x7FFFFFFF) // Shared object to get values from #undef DYNAMIC_TAG_MARKER #undef DYNAMIC_TAG_MARKER_DEFINED #endif +#ifdef AARCH64_DYNAMIC_TAG_DEFINED +#undef AARCH64_DYNAMIC_TAG +#undef AARCH64_DYNAMIC_TAG_DEFINED +#endif #ifdef MIPS_DYNAMIC_TAG_DEFINED #undef MIPS_DYNAMIC_TAG #undef MIPS_DYNAMIC_TAG_DEFINED diff --git a/lib/Object/ELF.cpp b/lib/Object/ELF.cpp index a9c90e01551..f0ef53d2444 100644 --- a/lib/Object/ELF.cpp +++ b/lib/Object/ELF.cpp @@ -434,6 +434,14 @@ std::string ELFFile::getDynamicTagAsString(unsigned Arch, #define DYNAMIC_TAG(n, v) switch (Arch) { + case ELF::EM_AARCH64: + switch (Type) { +#define AARCH64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef AARCH64_DYNAMIC_TAG + } + break; + case ELF::EM_HEXAGON: switch (Type) { #define HEXAGON_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) @@ -461,6 +469,7 @@ std::string ELFFile::getDynamicTagAsString(unsigned Arch, #undef DYNAMIC_TAG switch (Type) { // Now handle all dynamic tags except the architecture specific ones +#define AARCH64_DYNAMIC_TAG(name, value) #define MIPS_DYNAMIC_TAG(name, value) #define HEXAGON_DYNAMIC_TAG(name, value) #define PPC64_DYNAMIC_TAG(name, value) @@ -469,6 +478,7 @@ std::string ELFFile::getDynamicTagAsString(unsigned Arch, #define DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) #include "llvm/BinaryFormat/DynamicTags.def" #undef DYNAMIC_TAG +#undef AARCH64_DYNAMIC_TAG #undef MIPS_DYNAMIC_TAG #undef HEXAGON_DYNAMIC_TAG #undef PPC64_DYNAMIC_TAG diff --git a/lib/ObjectYAML/ELFYAML.cpp b/lib/ObjectYAML/ELFYAML.cpp index 39e59efe00f..1d230700f44 100644 --- a/lib/ObjectYAML/ELFYAML.cpp +++ b/lib/ObjectYAML/ELFYAML.cpp @@ -680,6 +680,7 @@ void ScalarEnumerationTraits::enumeration( assert(Object && "The IO context is not initialized"); // Disable architecture specific tags by default. We might enable them below. +#define AARCH64_DYNAMIC_TAG(name, value) #define MIPS_DYNAMIC_TAG(name, value) #define HEXAGON_DYNAMIC_TAG(name, value) #define PPC64_DYNAMIC_TAG(name, value) @@ -689,6 +690,13 @@ void ScalarEnumerationTraits::enumeration( #define STRINGIFY(X) (#X) #define DYNAMIC_TAG(X, Y) IO.enumCase(Value, STRINGIFY(DT_##X), ELF::DT_##X); switch (Object->Header.Machine) { + case ELF::EM_AARCH64: +#undef AARCH64_DYNAMIC_TAG +#define AARCH64_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef AARCH64_DYNAMIC_TAG +#define AARCH64_DYNAMIC_TAG(name, value) + break; case ELF::EM_MIPS: #undef MIPS_DYNAMIC_TAG #define MIPS_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value) @@ -714,7 +722,7 @@ void ScalarEnumerationTraits::enumeration( #include "llvm/BinaryFormat/DynamicTags.def" break; } - +#undef AARCH64_DYNAMIC_TAG #undef MIPS_DYNAMIC_TAG #undef HEXAGON_DYNAMIC_TAG #undef PPC64_DYNAMIC_TAG diff --git a/test/tools/llvm-readobj/Inputs/elf-dynamic-tags-machine-specific.yaml b/test/tools/llvm-readobj/Inputs/elf-dynamic-tags-machine-specific.yaml index e60034afc80..653a7e9eeb0 100644 --- a/test/tools/llvm-readobj/Inputs/elf-dynamic-tags-machine-specific.yaml +++ b/test/tools/llvm-readobj/Inputs/elf-dynamic-tags-machine-specific.yaml @@ -200,3 +200,41 @@ ProgramHeaders: VAddr: 0x1010 Sections: - Section: .dynamic + +# Fourth document: AARCH64 +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_AARCH64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Address: 0x1000 + Size: 0x10 + Content: "004400550066007700" + - Name: .dynamic + Type: SHT_DYNAMIC + Address: 0x1010 + Entries: + - Tag: DT_HASH + Value: 0x1000 + - Tag: DT_AARCH64_BTI_PLT + Value: 0 + - Tag: DT_AARCH64_PAC_PLT + Value: 0 + - Tag: 0x1234abcd + Value: 0x1 + - Tag: DT_NULL + Value: 0 +ProgramHeaders: + - Type: PT_LOAD + VAddr: 0x1000 + Sections: + - Section: .dynstr + - Section: .dynamic + - Type: PT_DYNAMIC + VAddr: 0x1010 + Sections: + - Section: .dynamic diff --git a/test/tools/llvm-readobj/elf-dynamic-tags-machine-specific.test b/test/tools/llvm-readobj/elf-dynamic-tags-machine-specific.test index 06c8b6d3fbe..1d6c3b33b88 100644 --- a/test/tools/llvm-readobj/elf-dynamic-tags-machine-specific.test +++ b/test/tools/llvm-readobj/elf-dynamic-tags-machine-specific.test @@ -151,3 +151,25 @@ # GNU-PPC-NEXT: 0x0000000070000000 (PPC64_GLINK) 0x1000 # GNU-PPC-NEXT: 0x000000001234abcd (unknown) 0x1 # GNU-PPC-NEXT: 0x0000000000000000 (NULL) 0x0 + +# Test that AARCH64 machine-specific tags can be dumped. +# RUN: yaml2obj --docnum=4 %S/Inputs/elf-dynamic-tags-machine-specific.yaml -o %t.aarch64 +# RUN: llvm-readobj --dynamic-table %t.aarch64 | FileCheck %s --check-prefix=LLVM-AARCH64 +# RUN: llvm-readelf --dynamic-table %t.aarch64 | FileCheck %s --check-prefix=GNU-AARCH64 + +# LLVM-AARCH64: DynamicSection [ (5 entries) +# LLVM-AARCH64-NEXT: Tag Type Name/Value +# LLVM-AARCH64-NEXT: 0x0000000000000004 HASH 0x1000 +# LLVM-AARCH64-NEXT: 0x0000000070000001 AARCH64_BTI_PLT 0 +# LLVM-AARCH64-NEXT: 0x0000000070000003 AARCH64_PAC_PLT 0 +# LLVM-AARCH64-NEXT: 0x000000001234ABCD unknown 0x1 +# LLVM-AARCH64-NEXT: 0x0000000000000000 NULL 0x0 +# LLVM-AARCH64-NEXT:] + +# GNU-AARCH64: Dynamic section at offset {{.*}} contains 5 entries: +# GNU-AARCH64-NEXT: Tag Type Name/Value +# GNU-AARCH64-NEXT: 0x0000000000000004 (HASH) 0x1000 +# GNU-AARCH64-NEXT: 0x0000000070000001 (AARCH64_BTI_PLT) 0 +# GNU-AARCH64-NEXT: 0x0000000070000003 (AARCH64_PAC_PLT) 0 +# GNU-AARCH64-NEXT: 0x000000001234abcd (unknown) 0x1 +# GNU-AARCH64-NEXT: 0x0000000000000000 (NULL) 0x0 diff --git a/test/tools/obj2yaml/dynamic-section-arch-tags.test b/test/tools/obj2yaml/dynamic-section-arch-tags.test index bc932371266..badb9cc3edd 100644 --- a/test/tools/obj2yaml/dynamic-section-arch-tags.test +++ b/test/tools/obj2yaml/dynamic-section-arch-tags.test @@ -249,12 +249,36 @@ Sections: - Tag: DT_PPC64_GLINK Value: 0x0000000000000001 +## Check we can handle AARCH64 specific tags. +# RUN: yaml2obj -docnum=4 %s -o %t2 +# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=AARCH64 + +# AARCH64: - Tag: DT_AARCH64_BTI_PLT +# AARCH64-NEXT: Value: 0x0000000000000000 +# AARCH64-NEXT: - Tag: DT_AARCH64_PAC_PLT +# AARCH64-NEXT: Value: 0x0000000000000000 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_AARCH64 +Sections: + - Name: .dynamic + Type: SHT_DYNAMIC + Entries: + - Tag: DT_AARCH64_BTI_PLT + Value: 0x0000000000000000 + - Tag: DT_AARCH64_PAC_PLT + Value: 0x0000000000000000 + ## Check we can't use a tag from a different architecture, ## even if it has the same numeric value as a valid tag. ## Here for EM_PPC64 we are trying to use DT_HEXAGON_SYMSZ ## instead of DT_PPC64_GLINK. They both have value of 0x70000000. -# RUN: not yaml2obj -docnum=4 %s 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not yaml2obj -docnum=5 %s 2>&1 | FileCheck %s --check-prefix=ERR # ERR: error: invalid hex64 number # ERR-NEXT: - Tag: DT_HEXAGON_SYMSZ diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index f87be61046e..f41adaeaed6 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -1463,6 +1463,17 @@ ELFDumper::ELFDumper(const object::ELFObjectFile *ObjF, static const char *getTypeString(unsigned Arch, uint64_t Type) { #define DYNAMIC_TAG(n, v) switch (Arch) { + + case EM_AARCH64: + switch (Type) { +#define AARCH64_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef AARCH64_DYNAMIC_TAG + } + break; + case EM_HEXAGON: switch (Type) { #define HEXAGON_DYNAMIC_TAG(name, value) \ @@ -1496,6 +1507,7 @@ static const char *getTypeString(unsigned Arch, uint64_t Type) { #undef DYNAMIC_TAG switch (Type) { // Now handle all dynamic tags except the architecture specific ones +#define AARCH64_DYNAMIC_TAG(name, value) #define MIPS_DYNAMIC_TAG(name, value) #define HEXAGON_DYNAMIC_TAG(name, value) #define PPC64_DYNAMIC_TAG(name, value) @@ -1506,6 +1518,7 @@ static const char *getTypeString(unsigned Arch, uint64_t Type) { return #name; #include "llvm/BinaryFormat/DynamicTags.def" #undef DYNAMIC_TAG +#undef AARCH64_DYNAMIC_TAG #undef MIPS_DYNAMIC_TAG #undef HEXAGON_DYNAMIC_TAG #undef PPC64_DYNAMIC_TAG @@ -1783,6 +1796,93 @@ void ELFDumper::printDynamicEntry(raw_ostream &OS, uint64_t Type, uint64_t Value) const { const char *ConvChar = (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64; + + // Handle custom printing of architecture specific tags + switch (ObjF->getELFFile()->getHeader()->e_machine) { + case EM_AARCH64: + switch (Type) { + case DT_AARCH64_BTI_PLT: + case DT_AARCH64_PAC_PLT: + OS << Value; + return; + default: + break; + } + break; + case EM_HEXAGON: + switch (Type) { + case DT_HEXAGON_VER: + OS << Value; + return; + case DT_HEXAGON_SYMSZ: + case DT_HEXAGON_PLT: + OS << format(ConvChar, Value); + return; + default: + break; + } + break; + case EM_MIPS: + switch (Type) { + case DT_MIPS_RLD_VERSION: + case DT_MIPS_LOCAL_GOTNO: + case DT_MIPS_SYMTABNO: + case DT_MIPS_UNREFEXTNO: + OS << Value; + return; + case DT_MIPS_TIME_STAMP: + case DT_MIPS_ICHECKSUM: + case DT_MIPS_IVERSION: + case DT_MIPS_BASE_ADDRESS: + case DT_MIPS_MSYM: + case DT_MIPS_CONFLICT: + case DT_MIPS_LIBLIST: + case DT_MIPS_CONFLICTNO: + case DT_MIPS_LIBLISTNO: + case DT_MIPS_GOTSYM: + case DT_MIPS_HIPAGENO: + case DT_MIPS_RLD_MAP: + case DT_MIPS_DELTA_CLASS: + case DT_MIPS_DELTA_CLASS_NO: + case DT_MIPS_DELTA_INSTANCE: + case DT_MIPS_DELTA_RELOC: + case DT_MIPS_DELTA_RELOC_NO: + case DT_MIPS_DELTA_SYM: + case DT_MIPS_DELTA_SYM_NO: + case DT_MIPS_DELTA_CLASSSYM: + case DT_MIPS_DELTA_CLASSSYM_NO: + case DT_MIPS_CXX_FLAGS: + case DT_MIPS_PIXIE_INIT: + case DT_MIPS_SYMBOL_LIB: + case DT_MIPS_LOCALPAGE_GOTIDX: + case DT_MIPS_LOCAL_GOTIDX: + case DT_MIPS_HIDDEN_GOTIDX: + case DT_MIPS_PROTECTED_GOTIDX: + case DT_MIPS_OPTIONS: + case DT_MIPS_INTERFACE: + case DT_MIPS_DYNSTR_ALIGN: + case DT_MIPS_INTERFACE_SIZE: + case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: + case DT_MIPS_PERF_SUFFIX: + case DT_MIPS_COMPACT_SIZE: + case DT_MIPS_GP_VALUE: + case DT_MIPS_AUX_DYNAMIC: + case DT_MIPS_PLTGOT: + case DT_MIPS_RWPLT: + case DT_MIPS_RLD_MAP_REL: + OS << format(ConvChar, Value); + return; + case DT_MIPS_FLAGS: + printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS); + return; + default: + break; + } + break; + default: + break; + } + switch (Type) { case DT_PLTREL: if (Value == DT_REL) { @@ -1811,22 +1911,12 @@ void ELFDumper::printDynamicEntry(raw_ostream &OS, uint64_t Type, case DT_VERSYM: case DT_GNU_HASH: case DT_NULL: - case DT_MIPS_BASE_ADDRESS: - case DT_MIPS_GOTSYM: - case DT_MIPS_RLD_MAP: - case DT_MIPS_RLD_MAP_REL: - case DT_MIPS_PLTGOT: - case DT_MIPS_OPTIONS: OS << format(ConvChar, Value); break; case DT_RELACOUNT: case DT_RELCOUNT: case DT_VERDEFNUM: case DT_VERNEEDNUM: - case DT_MIPS_RLD_VERSION: - case DT_MIPS_LOCAL_GOTNO: - case DT_MIPS_SYMTABNO: - case DT_MIPS_UNREFEXTNO: OS << Value; break; case DT_PLTRELSZ: @@ -1862,9 +1952,6 @@ void ELFDumper::printDynamicEntry(raw_ostream &OS, uint64_t Type, case DT_RUNPATH: OS << getDynamicString(Value); break; - case DT_MIPS_FLAGS: - printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS); - break; case DT_FLAGS: printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS); break;