From 5d446e61d992f105a05aade62d5305fd8a346081 Mon Sep 17 00:00:00 2001 From: Amara Emerson Date: Fri, 3 May 2013 11:36:35 +0000 Subject: Add support for reading ARM ELF build attributes. Build attribute sections can now be read if they exist via ELFObjectFile, and the llvm-readobj tool has been extended with an option to dump this information if requested. Regression tests are also included which exercise these features. Also update the docs with a fixed ARM ABI link and a new link to the Addenda which provides the build attributes specification. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181009 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/CompilerWriterInfo.rst | 4 +- include/llvm/Object/ELF.h | 186 ++++++++++++++ include/llvm/Object/ELF_ARM.h | 339 +++++++++++++++++++++++++ lib/Target/ARM/ARMAsmPrinter.cpp | 16 +- lib/Target/ARM/ARMBuildAttrs.h | 131 ---------- test/Object/Inputs/arm-attributes.elf-arm | Bin 0 -> 1128 bytes test/Object/Inputs/trivial-object-test.elf-arm | Bin 0 -> 662 bytes test/Object/readobj-elf-arm-buildattrs.test | 46 ++++ tools/llvm-readobj/ELFDumper.cpp | 63 +++++ tools/llvm-readobj/ObjDumper.h | 1 + tools/llvm-readobj/llvm-readobj.cpp | 6 + 11 files changed, 652 insertions(+), 140 deletions(-) create mode 100644 include/llvm/Object/ELF_ARM.h delete mode 100644 lib/Target/ARM/ARMBuildAttrs.h create mode 100644 test/Object/Inputs/arm-attributes.elf-arm create mode 100644 test/Object/Inputs/trivial-object-test.elf-arm create mode 100644 test/Object/readobj-elf-arm-buildattrs.test diff --git a/docs/CompilerWriterInfo.rst b/docs/CompilerWriterInfo.rst index e9a7bc876a..35a283ba86 100644 --- a/docs/CompilerWriterInfo.rst +++ b/docs/CompilerWriterInfo.rst @@ -18,7 +18,9 @@ ARM * `ARM documentation `_ (`Processor Cores `_ Cores) -* `ABI `_ +* `ELF ABI `_ + +* `Addenda to the ARM ABI `_ * `ARM C Language Extensions `_ diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index eb2390ab5d..908d8b1db1 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -19,11 +19,13 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" +#include "llvm/Object/ELF_ARM.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include @@ -601,6 +603,7 @@ private: const Elf_Shdr *dot_gnu_version_sec; // .gnu.version const Elf_Shdr *dot_gnu_version_r_sec; // .gnu.version_r const Elf_Shdr *dot_gnu_version_d_sec; // .gnu.version_d + const Elf_Shdr *dot_arm_attributes_sec; // .ARM.attributes // Pointer to SONAME entry in dynamic string table // This is set the first time getLoadName is called. @@ -643,6 +646,11 @@ private: const Elf_Shdr *getRelSection(DataRefImpl Rel) const { return getSection(Rel.w.b); } + // Helper to read a single ARM attribute at the given pointer and return the + // read pointer moved forward to the next attribute location. + uintptr_t readARMSingleAttribute(uintptr_t ReadPtr, + ARMBuildAttrs::ARMGenericBuildAttrInfo &Attrs, + SmallVector &TagSet) const; public: bool isRelocationHasAddend(DataRefImpl Rel) const; @@ -838,6 +846,18 @@ public: return v->getType() == getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits); } + + /// \brief Read the ARM build attributes of this object file. + /// \param Attrs The attributes container to put the attribute values. + /// \param TagsSet A list of attribute tags that were read. + error_code readARMBuildAttributes( + ARMBuildAttrs::ARMGenericBuildAttrInfo &Attrs, + SmallVector &TagsSet) const; + + /// \brief Checks if an ARM build attributes section exists. + bool hasARMBuildAttributes() const { + return dot_arm_attributes_sec ? true : false; + } }; // Iterate through the version definitions, and place each Elf_Verdef @@ -2330,6 +2350,7 @@ ELFObjectFile::ELFObjectFile(MemoryBuffer *Object, error_code &ec) , dot_gnu_version_sec(0) , dot_gnu_version_r_sec(0) , dot_gnu_version_d_sec(0) + , dot_arm_attributes_sec(0) , dt_soname(0) { @@ -2421,6 +2442,13 @@ ELFObjectFile::ELFObjectFile(MemoryBuffer *Object, error_code &ec) dot_gnu_version_r_sec = sh; break; } + case ELF::SHT_ARM_ATTRIBUTES: { + if (dot_arm_attributes_sec != NULL) + // FIXME: Proper error handling. + report_fatal_error("More than one .arm.attributes section!"); + dot_arm_attributes_sec = sh; + break; + } } ++sh; } @@ -2970,6 +2998,164 @@ static inline error_code GetELFSymbolVersion(const ObjectFile *Obj, llvm_unreachable("Object passed to GetELFSymbolVersion() is not ELF"); } +template +error_code ELFObjectFile::readARMBuildAttributes( + ARMBuildAttrs::ARMGenericBuildAttrInfo &Attrs, + SmallVector &TagsSet) const { + if (getArch() != Triple::arm) + return object_error::invalid_file_type; + if (!dot_arm_attributes_sec) + return object_error::parse_failed; + + const char *SecStart = (const char*)base() + + dot_arm_attributes_sec->sh_offset; + const char *SecEnd = SecStart + dot_arm_attributes_sec->sh_size; + char format_version = *SecStart; + if (format_version != ARMBuildAttrs::Format_Version) + return object_error::parse_failed; + + uintptr_t SSectionPtr = (uintptr_t)SecStart + 1; + uintptr_t ReadPtr = SSectionPtr; + // Begin reading section after format-version byte + while (ReadPtr < (uintptr_t)SecEnd) { + // Read a subsection, starting with: "vendor-name" + // For now, we only care about the "aeabi" pseudo-vendor subsection. + uint32_t SSectionLen = *(Elf_Word*)ReadPtr; + ReadPtr += sizeof(uint32_t); + StringRef Vendor((char*)(ReadPtr)); + ReadPtr += Vendor.size() + 1; // Vendor string + NUL byte + + if (Vendor != "aeabi") { + SSectionPtr += SSectionLen; + ReadPtr = SSectionPtr; + continue; //skip to the next sub-section + } + + bool FoundFileTag = false; + uintptr_t SSSectionPtr = ReadPtr; + uint32_t SSSectionLen = *(Elf_Word*)ReadPtr; + // Found aeabi subsection, now find the File scope tag. + while (ReadPtr < SSectionPtr + SSectionLen) { + unsigned n = 0; + uint64_t Tag = decodeULEB128((uint8_t*)ReadPtr, &n); + ReadPtr += n; + SSSectionLen = *(Elf_Word*)ReadPtr; + if (Tag == ARMBuildAttrs::File) { + FoundFileTag = true; + break; + } + // We only handle File scope attributes, skip ahead to the next + // sub-subsection. + SSSectionPtr += SSSectionLen; + ReadPtr = SSSectionPtr; + } + + if (!FoundFileTag) + return object_error::parse_failed; + + ReadPtr += sizeof(uint32_t); + while (ReadPtr < SSSectionPtr + SSSectionLen) { + // Read any number of attributes. + // Attributes are pairs of or . + ReadPtr = readARMSingleAttribute(ReadPtr, Attrs, TagsSet); + } + Attrs.setValid(true); + } + return object_error::success; +} + +#define SWITCH_ARM_ATTR_READ_ULEB(X) case ARMBuildAttrs::X: \ + UlebValue = decodeULEB128((uint8_t*)ReadPtr, &n); \ + ReadPtr += n; \ + Attrs.Tag_##X = UlebValue; \ + TagsSet.push_back(tag); \ + break; + +template +uintptr_t ELFObjectFile::readARMSingleAttribute(uintptr_t ReadPtr, + ARMBuildAttrs::ARMGenericBuildAttrInfo &Attrs, + SmallVector &TagsSet) const { + // The ABI says that tags in the range 0-63 must be handled by tools. + unsigned n = 0; + uint64_t tagInt = decodeULEB128((uint8_t*)ReadPtr, &n); + ARMBuildAttrs::AttrType tag = (ARMBuildAttrs::AttrType)tagInt; + ReadPtr += n; + uint64_t UlebValue = 0; + StringRef StrValue; + switch (tag) { + case ARMBuildAttrs::CPU_arch: // uleb128 + UlebValue = decodeULEB128((uint8_t*)ReadPtr, &n); + ReadPtr += n; + Attrs.Tag_CPU_arch = (ARMBuildAttrs::CPUArch)UlebValue; + TagsSet.push_back(tag); + break; + case ARMBuildAttrs::CPU_raw_name: // NTBS + StrValue = (char*)ReadPtr; + Attrs.Tag_CPU_raw_name = StrValue; + TagsSet.push_back(ARMBuildAttrs::CPU_raw_name); + ReadPtr += StrValue.size() + 1; + break; + case ARMBuildAttrs::CPU_name: //NTBS + StrValue = (char*)ReadPtr; + Attrs.Tag_CPU_name = StrValue; + TagsSet.push_back(ARMBuildAttrs::CPU_name); + ReadPtr += StrValue.size() + 1; + break; + case ARMBuildAttrs::CPU_arch_profile: // uleb128 + UlebValue = decodeULEB128((uint8_t*)ReadPtr, &n); + ReadPtr += n; + Attrs.Tag_CPU_arch_profile = + (ARMBuildAttrs::CPUArchProfile)UlebValue; + TagsSet.push_back(tag); + break; + SWITCH_ARM_ATTR_READ_ULEB(ARM_ISA_use) + SWITCH_ARM_ATTR_READ_ULEB(THUMB_ISA_use) + SWITCH_ARM_ATTR_READ_ULEB(FP_arch) + SWITCH_ARM_ATTR_READ_ULEB(WMMX_arch) + SWITCH_ARM_ATTR_READ_ULEB(Advanced_SIMD_arch) + SWITCH_ARM_ATTR_READ_ULEB(FP_HP_extension) + SWITCH_ARM_ATTR_READ_ULEB(CPU_unaligned_access) + SWITCH_ARM_ATTR_READ_ULEB(MPextension_use) + SWITCH_ARM_ATTR_READ_ULEB(DIV_use) + SWITCH_ARM_ATTR_READ_ULEB(T2EE_use) + SWITCH_ARM_ATTR_READ_ULEB(Virtualization_use) + SWITCH_ARM_ATTR_READ_ULEB(ABI_optimization_goals) + SWITCH_ARM_ATTR_READ_ULEB(ABI_FP_optimization_goals) + SWITCH_ARM_ATTR_READ_ULEB(PCS_config) + SWITCH_ARM_ATTR_READ_ULEB(ABI_PCS_R9_use) + SWITCH_ARM_ATTR_READ_ULEB(ABI_PCS_RW_data) + SWITCH_ARM_ATTR_READ_ULEB(ABI_PCS_RO_data) + SWITCH_ARM_ATTR_READ_ULEB(ABI_PCS_GOT_use) + SWITCH_ARM_ATTR_READ_ULEB(ABI_PCS_wchar_t) + SWITCH_ARM_ATTR_READ_ULEB(ABI_enum_size) + SWITCH_ARM_ATTR_READ_ULEB(ABI_align8_needed) + SWITCH_ARM_ATTR_READ_ULEB(ABI_align8_preserved) + SWITCH_ARM_ATTR_READ_ULEB(ABI_FP_rounding) + SWITCH_ARM_ATTR_READ_ULEB(ABI_FP_denormal) + SWITCH_ARM_ATTR_READ_ULEB(ABI_FP_number_model) + SWITCH_ARM_ATTR_READ_ULEB(ABI_FP_exceptions) + SWITCH_ARM_ATTR_READ_ULEB(ABI_FP_user_exceptions) + SWITCH_ARM_ATTR_READ_ULEB(ABI_HardFP_use) + SWITCH_ARM_ATTR_READ_ULEB(ABI_VFP_args) + default: + // Unhandled build attribute tag, according to the spec we should be able + // to infer the type of the value from (tag % 2) and skip over it. + if (tag & 0x1) { + // Value should be a null terminated byte string + StrValue = (char*)ReadPtr; + ReadPtr += StrValue.size() + 1; + } else { + // Value should be a uleb128 + UlebValue = decodeULEB128((uint8_t*)ReadPtr, &n); + ReadPtr += n; + } + break; + } + return ReadPtr; +} +#undef SWITCH_ARM_ATTR_READ_ULEB + + /// This function returns the hash value for a symbol in the .dynsym section /// Name of the API remains consistent as specified in the libelf /// REF : http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash diff --git a/include/llvm/Object/ELF_ARM.h b/include/llvm/Object/ELF_ARM.h new file mode 100644 index 0000000000..d1fab2aa20 --- /dev/null +++ b/include/llvm/Object/ELF_ARM.h @@ -0,0 +1,339 @@ +//===-- ELF_ARM.h - ARM ELF ABI ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains enumerations and support routines for ARM build attributes +// as defined in ARM ABI addenda document (ABI release 2.08). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ELF_ARM_H +#define LLVM_OBJECT_ELF_ARM_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Endian.h" + +namespace llvm { + +namespace ARMBuildAttrs { +enum SpecialAttr { + // This is for the .cpu asm attr. It translates into one or more + // AttrType (below) entries in the .ARM.attributes section in the ELF. + SEL_CPU +}; + +enum AttrType { + // Rest correspond to ELF/.ARM.attributes + File = 1, + Section = 2, + Symbol = 3, + CPU_raw_name = 4, + CPU_name = 5, + CPU_arch = 6, + CPU_arch_profile = 7, + ARM_ISA_use = 8, + THUMB_ISA_use = 9, + FP_arch = 10, + WMMX_arch = 11, + Advanced_SIMD_arch = 12, + PCS_config = 13, + ABI_PCS_R9_use = 14, + ABI_PCS_RW_data = 15, + ABI_PCS_RO_data = 16, + ABI_PCS_GOT_use = 17, + ABI_PCS_wchar_t = 18, + ABI_FP_rounding = 19, + ABI_FP_denormal = 20, + ABI_FP_exceptions = 21, + ABI_FP_user_exceptions = 22, + ABI_FP_number_model = 23, + ABI_align8_needed = 24, + ABI_align8_preserved = 25, + ABI_enum_size = 26, + ABI_HardFP_use = 27, + ABI_VFP_args = 28, + ABI_WMMX_args = 29, + ABI_optimization_goals = 30, + ABI_FP_optimization_goals = 31, + compatibility = 32, + CPU_unaligned_access = 34, + FP_HP_extension = 36, + ABI_FP_16bit_format = 38, + MPextension_use = 42, // was 70, 2.08 ABI + DIV_use = 44, + nodefaults = 64, + also_compatible_with = 65, + T2EE_use = 66, + conformance = 67, + Virtualization_use = 68, + MPextension_use_old = 70 +}; + +// Magic numbers for .ARM.attributes +enum AttrMagic { + Format_Version = 0x41 +}; + +// Legal Values for CPU_arch, (=6), uleb128 +enum CPUArch { + Pre_v4 = 0, + v4 = 1, // e.g. SA110 + v4T = 2, // e.g. ARM7TDMI + v5T = 3, // e.g. ARM9TDMI + v5TE = 4, // e.g. ARM946E_S + v5TEJ = 5, // e.g. ARM926EJ_S + v6 = 6, // e.g. ARM1136J_S + v6KZ = 7, // e.g. ARM1176JZ_S + v6T2 = 8, // e.g. ARM1156T2F_S + v6K = 9, // e.g. ARM1136J_S + v7 = 10, // e.g. Cortex A8, Cortex M3 + v6_M = 11, // e.g. Cortex M1 + v6S_M = 12, // v6_M with the System extensions + v7E_M = 13, // v7_M with DSP extensions + v8 +}; + +enum CPUArchProfile { // (=7), uleb128 + Not_Applicable = 0, // pre v7, or cross-profile code + ApplicationProfile = (0x41), // 'A' (e.g. for Cortex A8) + RealTimeProfile = (0x52), // 'R' (e.g. for Cortex R4) + MicroControllerProfile = (0x4D), // 'M' (e.g. for Cortex M3) + SystemProfile = (0x53) // 'S' Application or real-time profile +}; + +// The following have a lot of common use cases +enum { + //ARMISAUse (=8), uleb128 and THUMBISAUse (=9), uleb128 + Not_Allowed = 0, + Allowed = 1 +}; + +enum { + // FP_arch (=10), uleb128 (formerly Tag_VFP_arch = 10) + AllowFPv2 = 2, // v2 FP ISA permitted (implies use of the v1 FP ISA) + AllowFPv3A = 3, // v3 FP ISA permitted (implies use of the v2 FP ISA) + AllowFPv3B = 4, // v3 FP ISA permitted, but only D0-D15, S0-S31 + AllowFPv4A = 5, // v4 FP ISA permitted (implies use of v3 FP ISA) + AllowFPv4B = 6, // v4 FP ISA was permitted, but only D0-D15, S0-S31 + AllowV8FP = 7, // ARMv8-A FP ISA permitted + AllowV8FPB = 8 // ARMv8-A FP ISA permitted, but only D0-D15, S0-D31 +}; + +enum { + // Tag_THUMB_ISA_use, (=9), uleb128 + AllowThumb32 = 2 // 32-bit Thumb (implies 16-bit instructions) +}; + +enum { + // Tag_WMMX_arch, (=11), uleb128 + AllowWMMXv1 = 1, // The user permitted this entity to use WMMX v1 + AllowWMMXv2 = 2 // The user permitted this entity to use WMMX v2 +}; + +enum { + // Tag_ABI_FP_denormal, (=20), uleb128 + MightFlushToZero = 0, // Denormal numbers might be flushed to (+) zero + IEEE754Denormal = 1 , // Depends on IEEE 754 denormal numbers + PreserveFPSign = 2 // Sign when flushed-to-zero is preserved +}; + +enum { + // Tag_ABI_FP_number_model, (=23), uleb128 + AllowNormal = 1, // Use IEEE 754 format normal numbers only + AllowRTABI = 2, // numbers, infinities, and one quiet NaN (see [RTABI]) + AllowIEE754 = 3 // this code to use all the IEEE 754-defined FP encodings +}; + +enum { + // Tag_ABI_FP_rounding, (=19), uleb128 + FPRoundingNearest = 0, // Use the IEEE 754 round to nearest rounding mode + FPRoundingRuntime = 1 // Choose the IEEE 754 rounding mode at run time +}; + +enum { + // Tag_DIV_use, (=44), uleb128 + AllowDIVThumb = 0, // Allow SDIV, UDIV on Thumb ISA, e.g. Cortex R4 or M3 + NotAllowedDIV = 1, // Disallow SDIV and UDIV + AllowDIVv7a = 2 // Allow SDIV, UDIV on v7-a with integer div extension +}; + +enum { + // Tag_Virtualization_use, (=42), uleb128 + TrustZone = 1, // Use of the TrustZone extension was permitted + VirtExts = 2, // Use of virtualization extensions (HVC, ERET) permitted + TrustZoneVirtExts = 3 // TrustZone and virtualization extensions permitted +}; + +enum { + // Tag_PCS_config, (=13), uleb128 + PCS_none = 0, // No standard configuration used, or no information recorded + PCS_bare = 1, // Bare platform configuration + PCS_linux = 2, // Linux application configuration + PCS_linux_dso = 3, // Linux DSO configuration + PCS_palm_2004 = 4, // Palm OS 2004 configuration + PCS_palm_future = 5, // Reserved to future Palm OS configuration + PCS_symbian_2004 = 6, // Symbian OS 2004 configuration + PCS_symbian_future = 7 // Reserved to future Symbian OS configuration +}; + +enum { + // Tag_ABI_PCS_R9_use, (=14), uleb128 + PCS_R9_normal = 0, // R9 used as V6 (just another callee-saved register, + // implied by omitting the tag) + PCS_R9_SB = 1, // R9 used as SB, a global Static Base register + PCS_R9_TLS = 2, // R9 used as a Thread Local Storage (TLS) pointer + PCS_R9_none = 3 // R9 not used at all by code associated with + // the attributed entity. +}; + +enum { + // Tag_ABI_PCS_RW_data, (=15), uleb128 + PCS_RW_data_abs = 0, // RW static data permitted to be addressed absolutely + PCS_RW_data_pcrel = 1, // RW static data was only permitted to be + // addressed PC-relative. + PCS_RW_data_sbrel = 2, // RW static data was only permitted to be addressed + // SB-relative. + PCS_RW_data_none = 3 // No permission to use RW static data +}; + +enum { + // Tag_ABI_PCS_RO_data, (=16), uleb128 + PCS_RO_data_abs = 0, // RO static data permitted to be addressed absolutely + PCS_RO_data_pcrel = 1, // RO static data was only permitted to be + // addressed PC-relative. + PCS_RO_data_none = 2 // No permission to use RO static data +}; + +enum { + // Tag_ABI_PCS_GOT_use, (=17), uleb128 + PCS_GOT_none = 0, // No permission to import static data + PCS_GOT_direct = 1, // Permission to address imported data directly + PCS_GOT_indirect = 2 // The user permitted this entity to address imported + // data indirectly (e.g. via a GOT) +}; + +enum { + // Tag_ABI_PCS_wchar_t, (=18), uleb128 + PCS_wchar_t_disallowed = 0, // The user prohibited the use of wchar_t + PCS_wchar_t_2 = 2, // The user intended the size of wchar_t to be 2 + PCS_wchar_t_4 = 4 // The user intended the size of wchar_t to be 4 +}; + +enum { + // Tag_ABI_enum_size, (=26), uleb128 + PCS_enum_size = 1, // Enum values occupy the smallest container big enough + // to hold all their values. + PCS_enum_size_32 = 2, // The user intended Enum containers to be 32-bit + PCS_enum_size_abi32 = 3 // The user intended that every enumeration visible + // across an ABI-complying interface contains a value needing 32 bits to + // encode it; other enums can be containerized. +}; + +enum { + // Tag_ABI_align_needed, (=24), uleb128 + PCS_Align_needed_disallowed = 0, // The user did not permit code to depend + // the alignment of 8-byte data or data with extended (>8-byte) alignment. + PCS_Align_needed_8 = 1, // Code was permitted to depend on the 8-byte + // alignment of 8-byte data items. + PCS_Align_needed_4 = 2, // Code was permitted to depend on the 4-byte + // alignment of 8-byte data items. + PCS_Align_needed_res = 3 // Reserved + // OR: n (in 4..12) Code was permitted to depend on the 8-byte alignment of + // 8-byte data items and the alignment of data items having up to 2^n byte + // extended alignment. +}; + +enum { + // Tag_ABI_align_preserved, (=25), uleb128 + PCS_Align_preserved_none = 0, // The user did not require code to preserve + // 8-byte alignment of 8-byte data objects. + PCS_Align_preserved_8 = 1, // Code was required to preserve 8-byte alignment + // of 8-byte data objects. + PCS_Align_preserved_8sp = 2, // Code was required to preserve 8-byte + // alignment of 8-byte data objects and to ensure (SP MOD 8) = 0 at all + // instruction boundaries (not just at function calls). + PCS_Align_preserved_res = 3 // Reserved + // OR: n (in 4..12) Code was required to preserve the alignments of case 2 + // and the alignment of data items having up to 2^n byte extended alignment +}; + +enum { + // Tag_ABI_HardFP_use, (=27), uleb128 + HardFPImplied = 0, // FP use should be implied by Tag_FP_arch + HardFP_SP_VFP = 1, // Use only SP FP instructions + HardFP_Reserved = 2, // Reserved + HardFP_ImpliedDup = 3 // Deprecated duplicate of the default HardFPImplied +}; + +enum { + // Tag_ABI_VFP_args, (=28), uleb128 + VFPArgs_base = 0, // FP parameter/result passing using AAPCS, base variant + VFPArgs_VFP = 1, // FP parameter/result passing using AAPCS, VFP variant + VFPArgs_toolchain = 2, // FP parameter/result passing to conform to tool + // chain-specific conventions + VFPArgs_baseVFP = 3 // FP parameter/result passing using both base and VFP + //variants. Did not permit non-variadic functions to pass FP params/results. +}; + +/// Contains build ARM aeabi attribute values. +class ARMGenericBuildAttrInfo { +public: + ARMGenericBuildAttrInfo() + : Valid(false) {} + + CPUArch Tag_CPU_arch; + CPUArchProfile Tag_CPU_arch_profile; + std::string Tag_CPU_raw_name; + std::string Tag_CPU_name; + unsigned Tag_ARM_ISA_use; + unsigned Tag_THUMB_ISA_use; + unsigned Tag_FP_arch; + unsigned Tag_WMMX_arch; + unsigned Tag_Advanced_SIMD_arch; + unsigned Tag_FP_HP_extension; + unsigned Tag_CPU_unaligned_access; + unsigned Tag_MPextension_use; + unsigned Tag_DIV_use; + unsigned Tag_T2EE_use; + unsigned Tag_Virtualization_use; + unsigned Tag_ABI_optimization_goals; + unsigned Tag_ABI_FP_optimization_goals; + + //PCS/ABI attributes + unsigned Tag_PCS_config; + unsigned Tag_ABI_PCS_R9_use; + unsigned Tag_ABI_PCS_RW_data; + unsigned Tag_ABI_PCS_RO_data; + unsigned Tag_ABI_PCS_GOT_use; + unsigned Tag_ABI_PCS_wchar_t; + unsigned Tag_ABI_enum_size; + unsigned Tag_ABI_align8_needed; + unsigned Tag_ABI_align8_preserved; + + //FP + unsigned Tag_ABI_FP_rounding; + unsigned Tag_ABI_FP_denormal; + unsigned Tag_ABI_FP_number_model; + unsigned Tag_ABI_FP_exceptions; + unsigned Tag_ABI_FP_user_exceptions; + unsigned Tag_ABI_HardFP_use; + unsigned Tag_ABI_VFP_args; + +private: + bool Valid; + +public: + /// Indicates whether this instance contains valid or default values. + bool isValid() { return Valid; } + void setValid(bool v) { Valid = v; } +}; + +} +} // llvm + +#endif // LLVM_OBJECT_ELF_ARM_H diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp index 13ec208793..2d5dca5c04 100644 --- a/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/ARMAsmPrinter.cpp @@ -15,7 +15,6 @@ #define DEBUG_TYPE "asm-printer" #include "ARMAsmPrinter.h" #include "ARM.h" -#include "ARMBuildAttrs.h" #include "ARMConstantPoolValue.h" #include "ARMMachineFunctionInfo.h" #include "ARMTargetMachine.h" @@ -44,6 +43,7 @@ #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Object/ELF_ARM.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" @@ -90,7 +90,7 @@ namespace { break; /* GAS requires .fpu to be emitted regardless of EABI attribute */ case ARMBuildAttrs::Advanced_SIMD_arch: - case ARMBuildAttrs::VFP_arch: + case ARMBuildAttrs::FP_arch: Streamer.EmitRawText(StringRef("\t.fpu ") + String.lower()); break; } @@ -798,24 +798,24 @@ void ARMAsmPrinter::emitAttributes() { /* VFPv4 + .fpu */ if (Subtarget->hasVFP4()) { - AttrEmitter->EmitAttribute(ARMBuildAttrs::VFP_arch, + AttrEmitter->EmitAttribute(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv4A); if (emitFPU) - AttrEmitter->EmitTextAttribute(ARMBuildAttrs::VFP_arch, "vfpv4"); + AttrEmitter->EmitTextAttribute(ARMBuildAttrs::FP_arch, "vfpv4"); /* VFPv3 + .fpu */ } else if (Subtarget->hasVFP3()) { - AttrEmitter->EmitAttribute(ARMBuildAttrs::VFP_arch, + AttrEmitter->EmitAttribute(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv3A); if (emitFPU) - AttrEmitter->EmitTextAttribute(ARMBuildAttrs::VFP_arch, "vfpv3"); + AttrEmitter->EmitTextAttribute(ARMBuildAttrs::FP_arch, "vfpv3"); /* VFPv2 + .fpu */ } else if (Subtarget->hasVFP2()) { - AttrEmitter->EmitAttribute(ARMBuildAttrs::VFP_arch, + AttrEmitter->EmitAttribute(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv2); if (emitFPU) - AttrEmitter->EmitTextAttribute(ARMBuildAttrs::VFP_arch, "vfpv2"); + AttrEmitter->EmitTextAttribute(ARMBuildAttrs::FP_arch, "vfpv2"); } /* TODO: ARMBuildAttrs::Allowed is not completely accurate, diff --git a/lib/Target/ARM/ARMBuildAttrs.h b/lib/Target/ARM/ARMBuildAttrs.h deleted file mode 100644 index 11bd6a4a8d..0000000000 --- a/lib/Target/ARM/ARMBuildAttrs.h +++ /dev/null @@ -1,131 +0,0 @@ -//===-- ARMBuildAttrs.h - ARM Build Attributes ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains enumerations and support routines for ARM build attributes -// as defined in ARM ABI addenda document (ABI release 2.08). -// -//===----------------------------------------------------------------------===// - -#ifndef __TARGET_ARMBUILDATTRS_H__ -#define __TARGET_ARMBUILDATTRS_H__ - -namespace ARMBuildAttrs { - enum SpecialAttr { - // This is for the .cpu asm attr. It translates into one or more - // AttrType (below) entries in the .ARM.attributes section in the ELF. - SEL_CPU - }; - - enum AttrType { - // Rest correspond to ELF/.ARM.attributes - File = 1, - Section = 2, - Symbol = 3, - CPU_raw_name = 4, - CPU_name = 5, - CPU_arch = 6, - CPU_arch_profile = 7, - ARM_ISA_use = 8, - THUMB_ISA_use = 9, - VFP_arch = 10, - WMMX_arch = 11, - Advanced_SIMD_arch = 12, - PCS_config = 13, - ABI_PCS_R9_use = 14, - ABI_PCS_RW_data = 15, - ABI_PCS_RO_data = 16, - ABI_PCS_GOT_use = 17, - ABI_PCS_wchar_t = 18, - ABI_FP_rounding = 19, - ABI_FP_denormal = 20, - ABI_FP_exceptions = 21, - ABI_FP_user_exceptions = 22, - ABI_FP_number_model = 23, - ABI_align8_needed = 24, - ABI_align8_preserved = 25, - ABI_enum_size = 26, - ABI_HardFP_use = 27, - ABI_VFP_args = 28, - ABI_WMMX_args = 29, - ABI_optimization_goals = 30, - ABI_FP_optimization_goals = 31, - compatibility = 32, - CPU_unaligned_access = 34, - VFP_HP_extension = 36, - ABI_FP_16bit_format = 38, - MPextension_use = 42, // was 70, 2.08 ABI - DIV_use = 44, - nodefaults = 64, - also_compatible_with = 65, - T2EE_use = 66, - conformance = 67, - Virtualization_use = 68, - MPextension_use_old = 70 - }; - - // Magic numbers for .ARM.attributes - enum AttrMagic { - Format_Version = 0x41 - }; - - // Legal Values for CPU_arch, (=6), uleb128 - enum CPUArch { - Pre_v4 = 0, - v4 = 1, // e.g. SA110 - v4T = 2, // e.g. ARM7TDMI - v5T = 3, // e.g. ARM9TDMI - v5TE = 4, // e.g. ARM946E_S - v5TEJ = 5, // e.g. ARM926EJ_S - v6 = 6, // e.g. ARM1136J_S - v6KZ = 7, // e.g. ARM1176JZ_S - v6T2 = 8, // e.g. ARM1156T2F_S - v6K = 9, // e.g. ARM1136J_S - v7 = 10, // e.g. Cortex A8, Cortex M3 - v6_M = 11, // e.g. Cortex M1 - v6S_M = 12, // v6_M with the System extensions - v7E_M = 13 // v7_M with DSP extensions - }; - - enum CPUArchProfile { // (=7), uleb128 - Not_Applicable = 0, // pre v7, or cross-profile code - ApplicationProfile = (0x41), // 'A' (e.g. for Cortex A8) - RealTimeProfile = (0x52), // 'R' (e.g. for Cortex R4) - MicroControllerProfile = (0x4D), // 'M' (e.g. for Cortex M3) - SystemProfile = (0x53) // 'S' Application or real-time profile - }; - - // The following have a lot of common use cases - enum { - //ARMISAUse (=8), uleb128 and THUMBISAUse (=9), uleb128 - Not_Allowed = 0, - Allowed = 1, - - // FP_arch (=10), uleb128 (formerly Tag_VFP_arch = 10) - AllowFPv2 = 2, // v2 FP ISA permitted (implies use of the v1 FP ISA) - AllowFPv3A = 3, // v3 FP ISA permitted (implies use of the v2 FP ISA) - AllowFPv3B = 4, // v3 FP ISA permitted, but only D0-D15, S0-S31 - AllowFPv4A = 5, // v4 FP ISA permitted (implies use of v3 FP ISA) - AllowFPv4B = 6, // v4 FP ISA was permitted, but only D0-D15, S0-S31 - - // Tag_WMMX_arch, (=11), uleb128 - AllowThumb32 = 2, // 32-bit Thumb (implies 16-bit instructions) - - // Tag_WMMX_arch, (=11), uleb128 - AllowWMMXv1 = 2, // The user permitted this entity to use WMMX v2 - - // Tag_ABI_FP_denormal, (=20), uleb128 - PreserveFPSign = 2, // sign when flushed-to-zero is preserved - - // Tag_ABI_FP_number_model, (=23), uleb128 - AllowRTABI = 2, // numbers, infinities, and one quiet NaN (see [RTABI]) - AllowIEE754 = 3 // this code to use all the IEEE 754-defined FP encodings - }; -} - -#endif // __TARGET_ARMBUILDATTRS_H__ diff --git a/test/Object/Inputs/arm-attributes.elf-arm b/test/Object/Inputs/arm-attributes.elf-arm new file mode 100644 index 0000000000..69855d6ea0 Binary files /dev/null and b/test/Object/Inputs/arm-attributes.elf-arm differ diff --git a/test/Object/Inputs/trivial-object-test.elf-arm b/test/Object/Inputs/trivial-object-test.elf-arm new file mode 100644 index 0000000000..adfe96ca6a Binary files /dev/null and b/test/Object/Inputs/trivial-object-test.elf-arm differ diff --git a/test/Object/readobj-elf-arm-buildattrs.test b/test/Object/readobj-elf-arm-buildattrs.test new file mode 100644 index 0000000000..e84570d72a --- /dev/null +++ b/test/Object/readobj-elf-arm-buildattrs.test @@ -0,0 +1,46 @@ +RUN: llvm-readobj -arm-buildattrs %p/Inputs/trivial-object-test.elf-arm \ +RUN: | FileCheck %s -check-prefix=SMALL +RUN: llvm-readobj -arm-buildattrs %p/Inputs/arm-attributes.elf-arm \ +RUN: | FileCheck %s -check-prefix=LARGE + +SMALL: ARMBuildAttributes { +SMALL: Tag_CPU_name: Cortex-A8 +SMALL: Tag_CPU_arch: 10 +SMALL: Tag_ARM_ISA_use: 1 +SMALL: Tag_THUMB_ISA_use: 2 +SMALL: Tag_FP_arch: 3 +SMALL: Tag_Advanced_SIMD_arch: 1 +SMALL: Tag_ABI_FP_denormal: 1 +SMALL: Tag_ABI_FP_exceptions: 1 +SMALL: Tag_ABI_FP_number_model: 3 +SMALL: Tag_ABI_align8_needed: 1 +SMALL: Tag_ABI_align8_preserved: 1 +SMALL: Tag_ABI_HardFP_use: 3 +SMALL: Tag_ABI_VFP_args: 1 +SMALL: Tag_DIV_use: 1 +SMALL: Tag_Virtualization_use: 1 + +LARGE: ARMBuildAttributes { +LARGE: Tag_CPU_name: iwmmxt2 +LARGE: Tag_CPU_arch: 4 +LARGE: Tag_ARM_ISA_use: 1 +LARGE: Tag_THUMB_ISA_use: 1 +LARGE: Tag_WMMX_arch: 2 +LARGE: Tag_Advanced_SIMD_arch: 1 +LARGE: Tag_ABI_PCS_RW_data: 3 +LARGE: Tag_ABI_PCS_GOT_use: 2 +LARGE: Tag_ABI_PCS_wchar_t: 4 +LARGE: Tag_ABI_FP_rounding: 1 +LARGE: Tag_ABI_FP_denormal: 1 +LARGE: Tag_ABI_FP_exceptions: 1 +LARGE: Tag_ABI_FP_number_model: 3 +LARGE: Tag_ABI_align8_needed: 1 +LARGE: Tag_ABI_align8_preserved: 1 +LARGE: Tag_ABI_enum_size: 2 +LARGE: Tag_ABI_HardFP_use: 3 +LARGE: Tag_ABI_VFP_args: 1 +LARGE: Tag_ABI_optimization_goals: 1 +LARGE: Tag_CPU_unaligned_access: 1 +LARGE: Tag_FP_HP_extension: 1 +LARGE: Tag_DIV_use: 1 +LARGE: Tag_T2EE_use: 1 diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index ea1b83f32f..6fa9026399 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -51,6 +51,7 @@ public: virtual void printDynamicTable() LLVM_OVERRIDE; virtual void printNeededLibraries() LLVM_OVERRIDE; virtual void printProgramHeaders() LLVM_OVERRIDE; + virtual void printARMBuildAttributes() LLVM_OVERRIDE; private: typedef ELFObjectFile ELFO; @@ -858,3 +859,65 @@ void ELFDumper::printProgramHeaders() { W.printNumber("Alignment", PI->p_align); } } + +#define LLVM_READOBJ_ARMATTR_NUMCASE(X) case ARMBuildAttrs::X: \ + W.printNumber(" Tag_" #X, BuildAttrs.Tag_##X); \ + break; \ + +#define LLVM_READOBJ_ARMATTR_STRCASE(X) case ARMBuildAttrs::X: \ + W.printString(" Tag_" #X, BuildAttrs.Tag_##X); \ + break; \ + +template +void ELFDumper::printARMBuildAttributes() { + if (Obj->getArch() != Triple::arm || !Obj->hasARMBuildAttributes()) + return; + ARMBuildAttrs::ARMGenericBuildAttrInfo BuildAttrs; + SmallVector AttrsRead; + error_code EC = Obj->readARMBuildAttributes(BuildAttrs, AttrsRead); + if (error(EC)) + return; + + DictScope D(W, "ARMBuildAttributes"); + + for (SmallVector::iterator I = AttrsRead.begin(), + E = AttrsRead.end(); I != E; ++I) { + switch (*I) { + LLVM_READOBJ_ARMATTR_STRCASE(CPU_name) + LLVM_READOBJ_ARMATTR_STRCASE(CPU_raw_name) + LLVM_READOBJ_ARMATTR_NUMCASE(CPU_arch) + LLVM_READOBJ_ARMATTR_NUMCASE(CPU_arch_profile) + LLVM_READOBJ_ARMATTR_NUMCASE(ARM_ISA_use) + LLVM_READOBJ_ARMATTR_NUMCASE(THUMB_ISA_use) + LLVM_READOBJ_ARMATTR_NUMCASE(FP_arch) + LLVM_READOBJ_ARMATTR_NUMCASE(WMMX_arch) + LLVM_READOBJ_ARMATTR_NUMCASE(Advanced_SIMD_arch) + LLVM_READOBJ_ARMATTR_NUMCASE(PCS_config) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_PCS_R9_use) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_PCS_RW_data) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_PCS_RO_data) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_PCS_GOT_use) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_PCS_wchar_t) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_FP_rounding) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_FP_denormal) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_FP_exceptions) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_FP_user_exceptions) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_FP_number_model) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_align8_needed) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_align8_preserved) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_enum_size) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_HardFP_use) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_VFP_args) + LLVM_READOBJ_ARMATTR_NUMCASE(CPU_unaligned_access) + LLVM_READOBJ_ARMATTR_NUMCASE(FP_HP_extension) + LLVM_READOBJ_ARMATTR_NUMCASE(MPextension_use) + LLVM_READOBJ_ARMATTR_NUMCASE(DIV_use) + LLVM_READOBJ_ARMATTR_NUMCASE(T2EE_use) + LLVM_READOBJ_ARMATTR_NUMCASE(Virtualization_use) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_optimization_goals) + LLVM_READOBJ_ARMATTR_NUMCASE(ABI_FP_optimization_goals) + default: + break; + } + } +} diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index 6918e28cb9..9a8f0c157a 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -39,6 +39,7 @@ public: virtual void printDynamicTable() { } virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } + virtual void printARMBuildAttributes() { } protected: StreamWriter& W; diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 2e95b6b551..d5eb85429c 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -128,6 +128,10 @@ namespace opts { // -expand-relocs cl::opt ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); + + // -arm-buildattrs + cl::opt ArmBuildAttrs("arm-buildattrs", + cl::desc("Display ARM ELF build attributes")); } // namespace opts namespace llvm { @@ -221,6 +225,8 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printNeededLibraries(); if (opts::ProgramHeaders) Dumper->printProgramHeaders(); + if (opts::ArmBuildAttrs) + Dumper->printARMBuildAttributes(); } -- cgit v1.2.3