diff options
Diffstat (limited to 'include/llvm/Object/ELF.h')
-rw-r--r-- | include/llvm/Object/ELF.h | 186 |
1 files changed, 186 insertions, 0 deletions
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 <algorithm> @@ -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<unsigned, 16> &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<unsigned, 16> &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<ELFT>::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<ELFT>::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<class ELFT> +error_code ELFObjectFile<ELFT>::readARMBuildAttributes( + ARMBuildAttrs::ARMGenericBuildAttrInfo &Attrs, + SmallVector<unsigned, 16> &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: <section-length> "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 <uleb128, uleb128> or <uleb128, NTBS>. + 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<class ELFT> +uintptr_t ELFObjectFile<ELFT>::readARMSingleAttribute(uintptr_t ReadPtr, + ARMBuildAttrs::ARMGenericBuildAttrInfo &Attrs, + SmallVector<unsigned, 16> &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 |