diff --git a/lld/ELF/Arch/Hexagon.cpp b/lld/ELF/Arch/Hexagon.cpp index 726e425b36dc6..479131a24dcfc 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 intAttr; + size_t size = 0; +}; +} // namespace + +static HexagonAttributesSection * +mergeAttributesSection(Ctx &ctx, + const SmallVector §ions) { + ctx.in.hexagonAttributes = std::make_unique(ctx); + auto &merged = + static_cast(*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 [ "vendor-name" + // [ . + 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 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)); } diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 4c771e47a0e72..d9639b06ca4bf 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -568,6 +568,7 @@ struct UndefinedDiag { // a partition. struct InStruct { std::unique_ptr attributes; + std::unique_ptr hexagonAttributes; std::unique_ptr riscvAttributes; std::unique_ptr bss; std::unique_ptr bssRelRo; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index a194ae71d559a..21d228eda6470 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -3446,6 +3446,10 @@ template void LinkerDriver::link(opt::InputArgList &args) { if (!ctx.arg.relocatable) combineEhSections(ctx); + // Merge .hexagon.attributes sections. + if (ctx.arg.emachine == EM_HEXAGON) + mergeHexagonAttributesSections(ctx); + // Merge .riscv.attributes sections. if (ctx.arg.emachine == EM_RISCV) mergeRISCVAttributesSections(ctx); diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 6dd20b2f0cbaa..93f15920bfedb 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -245,6 +245,7 @@ template void writeARMCmseImportLib(Ctx &); uint64_t getLoongArchPageDelta(uint64_t dest, uint64_t pc, RelType type); void riscvFinalizeRelax(int passes); void mergeRISCVAttributesSections(Ctx &); +void mergeHexagonAttributesSections(Ctx &); void addArmInputSectionMappingSymbols(Ctx &); void addArmSyntheticSectionMappingSymbol(Defined *); void sortArmMappingSymbols(Ctx &); diff --git a/lld/test/ELF/hexagon-attributes.s b/lld/test/ELF/hexagon-attributes.s new file mode 100644 index 0000000000000..eee820361327f --- /dev/null +++ b/lld/test/ELF/hexagon-attributes.s @@ -0,0 +1,150 @@ +# REQUIRES: hexagon + +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf a.s -o a.o +# RUN: ld.lld -e 0 a.o -o out 2>&1 | count 0 +# RUN: llvm-readelf -S -l --arch-specific out | FileCheck %s --check-prefixes=HDR,CHECK +# RUN: ld.lld -e 0 a.o a.o -o out1 2>&1 | count 0 +# RUN: llvm-readobj --arch-specific out1 | FileCheck %s +# RUN: ld.lld -r a.o a.o -o out1 2>&1 | count 0 +# RUN: llvm-readobj --arch-specific out1 | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf b.s -o b.o +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf c.s -o c.o +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf d.s -o d.o +# RUN: ld.lld a.o b.o c.o -o out2 +# RUN: llvm-readobj --arch-specific out2 | FileCheck %s --check-prefix=CHECK2 +# RUN: ld.lld a.o b.o c.o d.o -o out3 +# RUN: llvm-readobj --arch-specific out3 | FileCheck %s --check-prefix=CHECK3 + +# HDR: Name Type Address Off Size ES Flg Lk Inf Al +# HDR: .hexagon.attributes HEXAGON_ATTRIBUTES 00000000 {{.*}} {{.*}} 00 0 0 1{{$}} + +# HDR: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# HDR: LOAD {{.*}} +# HDR-NEXT: GNU_STACK {{.*}} + +# CHECK: BuildAttributes { +# CHECK-NEXT: FormatVersion: 0x41 +# CHECK-NEXT: Section 1 { +# CHECK-NEXT: SectionLength: 19 +# CHECK-NEXT: Vendor: hexagon +# CHECK-NEXT: Tag: Tag_File (0x1) +# CHECK-NEXT: Size: 7 +# CHECK-NEXT: FileAttributes { +# CHECK-NEXT: Attribute { +# CHECK-NEXT: Tag: 4 +# CHECK-NEXT: TagName: arch +# CHECK-NEXT: Value: 68{{$}} +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: } + +# CHECK2: BuildAttributes { +# CHECK2-NEXT: FormatVersion: 0x41 +# CHECK2-NEXT: Section 1 { +# CHECK2-NEXT: SectionLength: 21 +# CHECK2-NEXT: Vendor: hexagon +# CHECK2-NEXT: Tag: Tag_File (0x1) +# CHECK2-NEXT: Size: 9 +# CHECK2-NEXT: FileAttributes { +# CHECK2-NEXT: Attribute { +# CHECK2-NEXT: Tag: 4 +# CHECK2-NEXT: TagName: arch +# CHECK2-NEXT: Value: 68{{$}} +# CHECK2-NEXT: } +# CHECK2-NEXT: Attribute { +# CHECK2-NEXT: Tag: 5 +# CHECK2-NEXT: TagName: hvx_arch +# CHECK2-NEXT: Value: 68{{$}} +# CHECK2-NEXT: } +# CHECK2-NEXT: } +# CHECK2-NEXT: } +# CHECK2-NEXT: } + +# CHECK3: BuildAttributes { +# CHECK3-NEXT: FormatVersion: 0x41 +# CHECK3-NEXT: Section 1 { +# CHECK3-NEXT: SectionLength: 25 +# CHECK3-NEXT: Vendor: hexagon +# CHECK3-NEXT: Tag: Tag_File (0x1) +# CHECK3-NEXT: Size: 13 +# CHECK3-NEXT: FileAttributes { +# CHECK3-NEXT: Attribute { +# CHECK3-NEXT: Tag: 7 +# CHECK3-NEXT: TagName: hvx_qfloat +# CHECK3-NEXT: Value: 68{{$}} +# CHECK3-NEXT: } +# CHECK3-NEXT: Attribute { +# CHECK3-NEXT: Tag: 9 +# CHECK3-NEXT: TagName: audio +# CHECK3-NEXT: Value: 68{{$}} +# CHECK3-NEXT: } +# CHECK3-NEXT: Attribute { +# CHECK3-NEXT: Tag: 4 +# CHECK3-NEXT: TagName: arch +# CHECK3-NEXT: Value: 68{{$}} +# CHECK3-NEXT: } +# CHECK3-NEXT: Attribute { +# CHECK3-NEXT: Tag: 5 +# CHECK3-NEXT: TagName: hvx_arch +# CHECK3-NEXT: Value: 68{{$}} +# CHECK3-NEXT: } +# CHECK3-NEXT: } +# CHECK3-NEXT: } +# CHECK3-NEXT: } + +#--- a.s +.section .hexagon.attributes,"",@0x70000003 +.byte 0x41 +.long .Lend-.hexagon.attributes-1 +.asciz "hexagon" +.Lbegin: +.byte 1 +.long .Lend-.Lbegin +.byte 4 +.byte 68 +.Lend: + +#--- b.s +.section .hexagon.attributes,"",@0x70000003 +.byte 0x41 +.long .Lend1-.hexagon.attributes-1 +.asciz "hexagon" +.Lbegin1: +.byte 1 +.long .Lend1-.Lbegin1 +.byte 4 +.byte 68 +.Lend1: + +#--- c.s +.section .hexagon.attributes,"",@0x70000003 +.byte 0x41 +.long .Lend2-.hexagon.attributes-1 +.asciz "hexagon" +.Lbegin2: +.byte 1 +.long .Lend2-.Lbegin2 +.byte 4 +.byte 68 +.byte 5 +.byte 68 +.Lend2: + +#--- d.s +.section .hexagon.attributes,"",@0x70000003 +.byte 0x41 +.long .Lend3-.hexagon.attributes-1 +.asciz "hexagon" +.Lbegin3: +.byte 1 +.long .Lend3-.Lbegin3 +.byte 4 +.byte 68 +.byte 7 +.byte 68 +.byte 9 +.byte 68 +.Lend3: