Skip to content

Commit

Permalink
Add support for reading ARM ELF build attributes.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
aemerson committed May 3, 2013
1 parent 820b3fd commit 5d446e6
Show file tree
Hide file tree
Showing 11 changed files with 652 additions and 140 deletions.
4 changes: 3 additions & 1 deletion docs/CompilerWriterInfo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ ARM

* `ARM documentation <http://www.arm.com/documentation/>`_ (`Processor Cores <http://www.arm.com/documentation/ARMProcessor_Cores/>`_ Cores)

* `ABI <http://www.arm.com/products/DevTools/ABI.html>`_
* `ELF ABI <http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf>`_

* `Addenda to the ARM ABI <http://infocenter.arm.com/help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_addenda.pdf>`_

* `ARM C Language Extensions <http://infocenter.arm.com/help/topic/com.arm.doc.ihi0053a/IHI0053A_acle.pdf>`_

Expand Down
186 changes: 186 additions & 0 deletions include/llvm/Object/ELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -601,6 +603,7 @@ class ELFObjectFile : public ObjectFile {
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.
Expand Down Expand Up @@ -643,6 +646,11 @@ class ELFObjectFile : public ObjectFile {
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;
Expand Down Expand Up @@ -838,6 +846,18 @@ class ELFObjectFile : public ObjectFile {
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
Expand Down Expand Up @@ -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)
{

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 5d446e6

Please sign in to comment.