summaryrefslogtreecommitdiff
path: root/lld/ELF/Arch/Hexagon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/Arch/Hexagon.cpp')
-rw-r--r--lld/ELF/Arch/Hexagon.cpp119
1 files changed, 119 insertions, 0 deletions
diff --git a/lld/ELF/Arch/Hexagon.cpp b/lld/ELF/Arch/Hexagon.cpp
index 726e425b36dc..479131a24dcf 100644
--- a/lld/ELF/Arch/Hexagon.cpp
+++ b/lld/ELF/Arch/Hexagon.cpp
@@ -7,11 +7,18 @@
//===----------------------------------------------------------------------===//
#include "InputFiles.h"
+#include "OutputSections.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/ELFAttributes.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/HexagonAttributeParser.h"
+#include "llvm/Support/HexagonAttributes.h"
+#include "llvm/Support/LEB128.h"
using namespace llvm;
using namespace llvm::object;
@@ -415,4 +422,116 @@ int64_t Hexagon::getImplicitAddend(const uint8_t *buf, RelType type) const {
}
}
+namespace {
+class HexagonAttributesSection final : public SyntheticSection {
+public:
+ HexagonAttributesSection(Ctx &ctx)
+ : SyntheticSection(ctx, ".hexagon.attributes", SHT_HEXAGON_ATTRIBUTES, 0,
+ 1) {}
+
+ size_t getSize() const override { return size; }
+ void writeTo(uint8_t *buf) override;
+
+ static constexpr StringRef vendor = "hexagon";
+ DenseMap<unsigned, unsigned> intAttr;
+ size_t size = 0;
+};
+} // namespace
+
+static HexagonAttributesSection *
+mergeAttributesSection(Ctx &ctx,
+ const SmallVector<InputSectionBase *, 0> &sections) {
+ ctx.in.hexagonAttributes = std::make_unique<HexagonAttributesSection>(ctx);
+ auto &merged =
+ static_cast<HexagonAttributesSection &>(*ctx.in.hexagonAttributes);
+
+ // Collect all tags values from attributes section.
+ const auto &attributesTags = HexagonAttrs::getHexagonAttributeTags();
+ for (const InputSectionBase *sec : sections) {
+ HexagonAttributeParser parser;
+ if (Error e = parser.parse(sec->content(), llvm::endianness::little))
+ Warn(ctx) << sec << ": " << std::move(e);
+ for (const auto &tag : attributesTags) {
+ switch (HexagonAttrs::AttrType(tag.attr)) {
+ case HexagonAttrs::ARCH:
+ case HexagonAttrs::HVXARCH:
+ if (auto i = parser.getAttributeValue(tag.attr)) {
+ auto r = merged.intAttr.try_emplace(tag.attr, *i);
+ if (!r.second)
+ if (r.first->second < *i)
+ r.first->second = *i;
+ }
+ continue;
+
+ case HexagonAttrs::HVXIEEEFP:
+ case HexagonAttrs::HVXQFLOAT:
+ case HexagonAttrs::ZREG:
+ case HexagonAttrs::AUDIO:
+ case HexagonAttrs::CABAC:
+ if (auto i = parser.getAttributeValue(tag.attr)) {
+ auto r = merged.intAttr.try_emplace(tag.attr, *i);
+ if (!r.second && r.first->second != *i) {
+ r.first->second |= *i;
+ }
+ }
+ continue;
+ }
+ }
+ }
+
+ // The total size of headers: format-version [ <section-length> "vendor-name"
+ // [ <file-tag> <size>.
+ size_t size = 5 + merged.vendor.size() + 1 + 5;
+ for (auto &attr : merged.intAttr)
+ if (attr.second != 0)
+ size += getULEB128Size(attr.first) + getULEB128Size(attr.second);
+ merged.size = size;
+ return &merged;
+}
+
+void HexagonAttributesSection::writeTo(uint8_t *buf) {
+ const size_t size = getSize();
+ uint8_t *const end = buf + size;
+ *buf = ELFAttrs::Format_Version;
+ write32(ctx, buf + 1, size - 1);
+ buf += 5;
+
+ memcpy(buf, vendor.data(), vendor.size());
+ buf += vendor.size() + 1;
+
+ *buf = ELFAttrs::File;
+ write32(ctx, buf + 1, end - buf);
+ buf += 5;
+
+ for (auto &attr : intAttr) {
+ if (attr.second == 0)
+ continue;
+ buf += encodeULEB128(attr.first, buf);
+ buf += encodeULEB128(attr.second, buf);
+ }
+}
+
+void elf::mergeHexagonAttributesSections(Ctx &ctx) {
+ // Find the first input SHT_HEXAGON_ATTRIBUTES; return if not found.
+ size_t place =
+ llvm::find_if(ctx.inputSections,
+ [](auto *s) { return s->type == SHT_HEXAGON_ATTRIBUTES; }) -
+ ctx.inputSections.begin();
+ if (place == ctx.inputSections.size())
+ return;
+
+ // Extract all SHT_HEXAGON_ATTRIBUTES sections into `sections`.
+ SmallVector<InputSectionBase *, 0> sections;
+ llvm::erase_if(ctx.inputSections, [&](InputSectionBase *s) {
+ if (s->type != SHT_HEXAGON_ATTRIBUTES)
+ return false;
+ sections.push_back(s);
+ return true;
+ });
+
+ // Add the merged section.
+ ctx.inputSections.insert(ctx.inputSections.begin() + place,
+ mergeAttributesSection(ctx, sections));
+}
+
void elf::setHexagonTargetInfo(Ctx &ctx) { ctx.target.reset(new Hexagon(ctx)); }