llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lld Author: None (llvmbot) <details> <summary>Changes</summary> Backport 026972af9c3cbd85b654b67a5b5c3b754a78a997 8644a2aa0f3540c69464f56b3d538e888b6cbdcb 6efc3774bd8c5fcb105cda73ec27c05ef850dc19 c7231e49099d56fdc5b2207142184a0bf2544ec1 Requested by: @<!-- -->MaskRay --- Full diff: https://github.com/llvm/llvm-project/pull/100883.diff 17 Files Affected: - (modified) lld/ELF/ICF.cpp (+9-9) - (modified) lld/ELF/InputSection.cpp (+2-6) - (modified) lld/ELF/InputSection.h (+12-3) - (modified) lld/ELF/Relocations.cpp (+8-10) - (modified) lld/ELF/Relocations.h (+8-2) - (modified) lld/ELF/ScriptLexer.cpp (-5) - (modified) lld/ELF/SyntheticSections.cpp (+4-8) - (modified) lld/ELF/SyntheticSections.h (+3-2) - (added) lld/test/ELF/linkerscript/diag.test (+49) - (removed) lld/test/ELF/linkerscript/diag1.test (-15) - (removed) lld/test/ELF/linkerscript/diag2.test (-13) - (removed) lld/test/ELF/linkerscript/diag3.test (-13) - (removed) lld/test/ELF/linkerscript/diag4.test (-14) - (removed) lld/test/ELF/linkerscript/diag5.test (-14) - (removed) lld/test/ELF/linkerscript/diag6.test (-7) - (renamed) lld/test/ELF/linkerscript/invalid.test () - (added) lld/test/ELF/linkerscript/unquoted.test (+26) ``````````diff diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp index bfc605c793a92..a6b52d78fa806 100644 --- a/lld/ELF/ICF.cpp +++ b/lld/ELF/ICF.cpp @@ -103,12 +103,12 @@ template <class ELFT> class ICF { void segregate(size_t begin, size_t end, uint32_t eqClassBase, bool constant); template <class RelTy> - bool constantEq(const InputSection *a, ArrayRef<RelTy> relsA, - const InputSection *b, ArrayRef<RelTy> relsB); + bool constantEq(const InputSection *a, Relocs<RelTy> relsA, + const InputSection *b, Relocs<RelTy> relsB); template <class RelTy> - bool variableEq(const InputSection *a, ArrayRef<RelTy> relsA, - const InputSection *b, ArrayRef<RelTy> relsB); + bool variableEq(const InputSection *a, Relocs<RelTy> relsA, + const InputSection *b, Relocs<RelTy> relsB); bool equalsConstant(const InputSection *a, const InputSection *b); bool equalsVariable(const InputSection *a, const InputSection *b); @@ -235,8 +235,8 @@ void ICF<ELFT>::segregate(size_t begin, size_t end, uint32_t eqClassBase, // Compare two lists of relocations. template <class ELFT> template <class RelTy> -bool ICF<ELFT>::constantEq(const InputSection *secA, ArrayRef<RelTy> ra, - const InputSection *secB, ArrayRef<RelTy> rb) { +bool ICF<ELFT>::constantEq(const InputSection *secA, Relocs<RelTy> ra, + const InputSection *secB, Relocs<RelTy> rb) { if (ra.size() != rb.size()) return false; auto rai = ra.begin(), rae = ra.end(), rbi = rb.begin(); @@ -333,8 +333,8 @@ bool ICF<ELFT>::equalsConstant(const InputSection *a, const InputSection *b) { // relocations point to the same section in terms of ICF. template <class ELFT> template <class RelTy> -bool ICF<ELFT>::variableEq(const InputSection *secA, ArrayRef<RelTy> ra, - const InputSection *secB, ArrayRef<RelTy> rb) { +bool ICF<ELFT>::variableEq(const InputSection *secA, Relocs<RelTy> ra, + const InputSection *secB, Relocs<RelTy> rb) { assert(ra.size() == rb.size()); auto rai = ra.begin(), rae = ra.end(), rbi = rb.begin(); @@ -441,7 +441,7 @@ void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> fn) { // hash. template <class RelTy> static void combineRelocHashes(unsigned cnt, InputSection *isec, - ArrayRef<RelTy> rels) { + Relocs<RelTy> rels) { uint32_t hash = isec->eqClass[cnt % 2]; for (RelTy rel : rels) { Symbol &s = isec->file->getRelocTargetSym(rel); diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 12ab1f1eac808..7857d857488c0 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -911,7 +911,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type, // So, we handle relocations for non-alloc sections directly in this // function as a performance optimization. template <class ELFT, class RelTy> -void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) { +void InputSection::relocateNonAlloc(uint8_t *buf, Relocs<RelTy> rels) { const unsigned bits = sizeof(typename ELFT::uint) * 8; const TargetInfo &target = *elf::target; const auto emachine = config->emachine; @@ -1073,11 +1073,7 @@ void InputSectionBase::relocate(uint8_t *buf, uint8_t *bufEnd) { auto *sec = cast<InputSection>(this); // For a relocatable link, also call relocateNonAlloc() to rewrite applicable // locations with tombstone values. - const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>(); - if (rels.areRelocsRel()) - sec->relocateNonAlloc<ELFT>(buf, rels.rels); - else - sec->relocateNonAlloc<ELFT>(buf, rels.relas); + invokeOnRelocs(*sec, sec->relocateNonAlloc<ELFT>, buf); } // For each function-defining prologue, find any calls to __morestack, diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index ec12235f842a9..c89a545e1543f 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -37,11 +37,20 @@ LLVM_LIBRARY_VISIBILITY extern std::vector<Partition> partitions; // Returned by InputSectionBase::relsOrRelas. At least one member is empty. template <class ELFT> struct RelsOrRelas { - ArrayRef<typename ELFT::Rel> rels; - ArrayRef<typename ELFT::Rela> relas; + Relocs<typename ELFT::Rel> rels; + Relocs<typename ELFT::Rela> relas; bool areRelocsRel() const { return rels.size(); } }; +#define invokeOnRelocs(sec, f, ...) \ + { \ + const RelsOrRelas<ELFT> rs = (sec).template relsOrRelas<ELFT>(); \ + if (rs.areRelocsRel()) \ + f(__VA_ARGS__, rs.rels); \ + else \ + f(__VA_ARGS__, rs.relas); \ + } + // This is the base class of all sections that lld handles. Some are sections in // input files, some are sections in the produced output file and some exist // just as a convenience for implementing special ways of combining some @@ -407,7 +416,7 @@ class InputSection : public InputSectionBase { InputSectionBase *getRelocatedSection() const; template <class ELFT, class RelTy> - void relocateNonAlloc(uint8_t *buf, llvm::ArrayRef<RelTy> rels); + void relocateNonAlloc(uint8_t *buf, Relocs<RelTy> rels); // Points to the canonical section. If ICF folds two sections, repl pointer of // one section points to the other. diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 36857d72c647e..713bd15440251 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -475,8 +475,9 @@ class RelocationScanner { uint64_t relOff) const; void processAux(RelExpr expr, RelType type, uint64_t offset, Symbol &sym, int64_t addend) const; - template <class ELFT, class RelTy> void scanOne(RelTy *&i); - template <class ELFT, class RelTy> void scan(ArrayRef<RelTy> rels); + template <class ELFT, class RelTy> + void scanOne(typename Relocs<RelTy>::const_iterator &i); + template <class ELFT, class RelTy> void scan(Relocs<RelTy> rels); }; } // namespace @@ -1433,7 +1434,8 @@ static unsigned handleTlsRelocation(RelType type, Symbol &sym, return 0; } -template <class ELFT, class RelTy> void RelocationScanner::scanOne(RelTy *&i) { +template <class ELFT, class RelTy> +void RelocationScanner::scanOne(typename Relocs<RelTy>::const_iterator &i) { const RelTy &rel = *i; uint32_t symIndex = rel.getSymbol(config->isMips64EL); Symbol &sym = sec->getFile<ELFT>()->getSymbol(symIndex); @@ -1574,7 +1576,7 @@ static void checkPPC64TLSRelax(InputSectionBase &sec, ArrayRef<RelTy> rels) { } template <class ELFT, class RelTy> -void RelocationScanner::scan(ArrayRef<RelTy> rels) { +void RelocationScanner::scan(Relocs<RelTy> rels) { // Not all relocations end up in Sec->Relocations, but a lot do. sec->relocations.reserve(rels.size()); @@ -1592,7 +1594,7 @@ void RelocationScanner::scan(ArrayRef<RelTy> rels) { end = static_cast<const void *>(rels.end()); for (auto i = rels.begin(); i != end;) - scanOne<ELFT>(i); + scanOne<ELFT, RelTy>(i); // Sort relocations by offset for more efficient searching for // R_RISCV_PCREL_HI20 and R_PPC64_ADDR64. @@ -2409,11 +2411,7 @@ template <class ELFT> void elf::checkNoCrossRefs() { if (!isd) continue; parallelForEach(isd->sections, [&](InputSection *sec) { - const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>(); - if (rels.areRelocsRel()) - scanCrossRefs<ELFT>(noxref, osec, sec, rels.rels); - else - scanCrossRefs<ELFT>(noxref, osec, sec, rels.relas); + invokeOnRelocs(*sec, scanCrossRefs<ELFT>, noxref, osec, sec); }); } } diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index 1bee0dedf8587..77d8d52ca3d3f 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -205,6 +205,11 @@ class ThunkCreator { uint32_t pass = 0; }; +template <class RelTy> struct Relocs : ArrayRef<RelTy> { + Relocs() = default; + Relocs(ArrayRef<RelTy> a) : ArrayRef<RelTy>(a) {} +}; + // Return a int64_t to make sure we get the sign extension out of the way as // early as possible. template <class ELFT> @@ -217,14 +222,15 @@ static inline int64_t getAddend(const typename ELFT::Rela &rel) { } template <typename RelTy> -ArrayRef<RelTy> sortRels(ArrayRef<RelTy> rels, SmallVector<RelTy, 0> &storage) { +inline Relocs<RelTy> sortRels(Relocs<RelTy> rels, + SmallVector<RelTy, 0> &storage) { auto cmp = [](const RelTy &a, const RelTy &b) { return a.r_offset < b.r_offset; }; if (!llvm::is_sorted(rels, cmp)) { storage.assign(rels.begin(), rels.end()); llvm::stable_sort(storage, cmp); - rels = storage; + rels = Relocs<RelTy>(storage); } return rels; } diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp index c8c02ab0f3e09..847cd8423b49a 100644 --- a/lld/ELF/ScriptLexer.cpp +++ b/lld/ELF/ScriptLexer.cpp @@ -20,11 +20,6 @@ // in various corner cases. We do not care much about efficiency because // the time spent in parsing linker scripts is usually negligible. // -// Our grammar of the linker script is LL(2), meaning that it needs at -// most two-token lookahead to parse. The only place we need two-token -// lookahead is labels in version scripts, where we need to parse "local :" -// as if "local:". -// // Overall, this lexer works fine for most linker scripts. There might // be room for improving compatibility, but that's probably not at the // top of our todo list. diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 5d3f3df216b85..b40ff0bc3cb03 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3203,10 +3203,10 @@ template <class ELFT> DebugNamesSection<ELFT>::DebugNamesSection() { template <class ELFT> template <class RelTy> void DebugNamesSection<ELFT>::getNameRelocs( - InputSection *sec, ArrayRef<RelTy> rels, - DenseMap<uint32_t, uint32_t> &relocs) { + const InputFile &file, DenseMap<uint32_t, uint32_t> &relocs, + Relocs<RelTy> rels) { for (const RelTy &rel : rels) { - Symbol &sym = sec->file->getRelocTargetSym(rel); + Symbol &sym = file.getRelocTargetSym(rel); relocs[rel.r_offset] = sym.getVA(getAddend<ELFT>(rel)); } } @@ -3216,11 +3216,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::finalizeContents() { auto relocs = std::make_unique<DenseMap<uint32_t, uint32_t>[]>(numChunks); parallelFor(0, numChunks, [&](size_t i) { InputSection *sec = inputSections[i]; - auto rels = sec->template relsOrRelas<ELFT>(); - if (rels.areRelocsRel()) - getNameRelocs(sec, rels.rels, relocs.get()[i]); - else - getNameRelocs(sec, rels.relas, relocs.get()[i]); + invokeOnRelocs(*sec, getNameRelocs, *sec->file, relocs.get()[i]); // Relocate CU offsets with .debug_info + X relocations. OutputChunk &chunk = chunks.get()[i]; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index eaa09ea7194fb..d4169e1e1acaf 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -916,8 +916,9 @@ class DebugNamesSection final : public DebugNamesBaseSection { void writeTo(uint8_t *buf) override; template <class RelTy> - void getNameRelocs(InputSection *sec, ArrayRef<RelTy> rels, - llvm::DenseMap<uint32_t, uint32_t> &relocs); + void getNameRelocs(const InputFile &file, + llvm::DenseMap<uint32_t, uint32_t> &relocs, + Relocs<RelTy> rels); private: static void readOffsets(InputChunk &inputChunk, OutputChunk &chunk, diff --git a/lld/test/ELF/linkerscript/diag.test b/lld/test/ELF/linkerscript/diag.test new file mode 100644 index 0000000000000..fbc24659a5311 --- /dev/null +++ b/lld/test/ELF/linkerscript/diag.test @@ -0,0 +1,49 @@ +# REQUIRES: x86 +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 /dev/null -o 0.o + +#--- 1.lds +SECTIONS { + .text + { *(.text) } + .keep : { *(.keep) } /* + comment line 1 + comment line 2 */ + .temp : { *(.temp) } +} + +# RUN: not ld.lld -shared 0.o -T 1.lds 2>&1 | FileCheck %s --check-prefix=CHECK1 --match-full-lines --strict-whitespace +# CHECK1:{{.*}}:2: malformed number: + +# CHECK1-NEXT:>>> .text + { *(.text) } +# CHECK1-NEXT:>>> ^ + +#--- 2.lds + +UNKNOWN_TAG { + .text : { *(.text) } + .keep : { *(.keep) } + .temp : { *(.temp) } +} + +# RUN: not ld.lld -shared 0.o -T 2.lds 2>&1 | FileCheck %s --check-prefix=CHECK2 --match-full-lines --strict-whitespace +# CHECK2:{{.*}}:2: unknown directive: UNKNOWN_TAG +# CHECK2-NEXT:>>> UNKNOWN_TAG { +# CHECK2-NEXT:>>> ^ + +#--- 3.lds +SECTIONS { + .text : { *(.text) } + .keep : { *(.keep) } + boom ^temp : { *(.temp) } +} +#--- 3a.lds +INCLUDE "3.lds" +#--- 3b.lds +foo = 3; +INCLUDE "3a.lds" + +# RUN: not ld.lld -shared 0.o -T 3.lds 2>&1 | FileCheck %s --check-prefix=CHECK3 --match-full-lines --strict-whitespace +# RUN: not ld.lld -shared 0.o -T 3a.lds 2>&1 | FileCheck %s --check-prefix=CHECK3 --match-full-lines --strict-whitespace +# RUN: not ld.lld -shared 0.o -T 3b.lds 2>&1 | FileCheck %s --check-prefix=CHECK3 --match-full-lines --strict-whitespace +# CHECK3:{{.*}}3.lds:4: malformed number: ^ +# CHECK3-NEXT:>>> boom ^temp : { *(.temp) } +# CHECK3-NEXT:>>> ^ diff --git a/lld/test/ELF/linkerscript/diag1.test b/lld/test/ELF/linkerscript/diag1.test deleted file mode 100644 index 829bc5a1bffaf..0000000000000 --- a/lld/test/ELF/linkerscript/diag1.test +++ /dev/null @@ -1,15 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o -# RUN: not ld.lld -shared %t.o -o /dev/null --script %s 2>&1 | FileCheck -strict-whitespace %s - -SECTIONS { - .text + { *(.text) } - .keep : { *(.keep) } /* - comment line 1 - comment line 2 */ - .temp : { *(.temp) } -} - -CHECK: 6: malformed number: + -CHECK-NEXT: >>> .text + { *(.text) } -CHECK-NEXT: >>> ^ diff --git a/lld/test/ELF/linkerscript/diag2.test b/lld/test/ELF/linkerscript/diag2.test deleted file mode 100644 index aeb623dbb7f4b..0000000000000 --- a/lld/test/ELF/linkerscript/diag2.test +++ /dev/null @@ -1,13 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o -# RUN: not ld.lld -shared %t.o -o /dev/null --script %s 2>&1 | FileCheck -strict-whitespace %s - -UNKNOWN_TAG { - .text : { *(.text) } - .keep : { *(.keep) } - .temp : { *(.temp) } -} - -CHECK: 5: unknown directive: UNKNOWN_TAG -CHECK-NEXT: >>> UNKNOWN_TAG { -CHECK-NEXT: >>> ^ diff --git a/lld/test/ELF/linkerscript/diag3.test b/lld/test/ELF/linkerscript/diag3.test deleted file mode 100644 index 1df8d601db016..0000000000000 --- a/lld/test/ELF/linkerscript/diag3.test +++ /dev/null @@ -1,13 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o -# RUN: not ld.lld -shared %t.o -o /dev/null --script %s 2>&1 | FileCheck -strict-whitespace %s - -SECTIONS { - .text : { *(.text) } - .keep : { *(.keep) } - boom ^temp : { *(.temp) } -} - -# CHECK: 8: malformed number: ^ -# CHECK-NEXT: >>> boom ^temp : { *(.temp) } -# CHECK-NEXT: >>> ^ diff --git a/lld/test/ELF/linkerscript/diag4.test b/lld/test/ELF/linkerscript/diag4.test deleted file mode 100644 index d93a69a95c61d..0000000000000 --- a/lld/test/ELF/linkerscript/diag4.test +++ /dev/null @@ -1,14 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o -# RUN: echo "INCLUDE \"%s\"" > %t.script -# RUN: not ld.lld -shared %t.o -o /dev/null --script %t.script 2>&1 | FileCheck -strict-whitespace %s - -SECTIONS { - .text : { *(.text) } - .keep : { *(.keep) } - boom ^temp : { *(.temp) } -} - -# CHECK: 9: malformed number: ^{{$}} -# CHECK-NEXT: >>> boom ^temp : { *(.temp) } -# CHECK-NEXT: >>> ^ diff --git a/lld/test/ELF/linkerscript/diag5.test b/lld/test/ELF/linkerscript/diag5.test deleted file mode 100644 index 9a2304baa4413..0000000000000 --- a/lld/test/ELF/linkerscript/diag5.test +++ /dev/null @@ -1,14 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o -# RUN: echo "INCLUDE \"%s\"" > %t.script -# RUN: not ld.lld -shared %t.o -o /dev/null --script %t.script 2>&1 | FileCheck -strict-whitespace %s - -SECTIONS { - .text : { *(.text) } - .keep : { *(.keep) } - boom ^temp : { *(.temp) } -} - -# CHECK: 9: malformed number: ^ -# CHECK-NEXT: >>> boom ^temp : { *(.temp) } -# CHECK-NEXT: >>> ^ diff --git a/lld/test/ELF/linkerscript/diag6.test b/lld/test/ELF/linkerscript/diag6.test deleted file mode 100644 index 0ec0400040b54..0000000000000 --- a/lld/test/ELF/linkerscript/diag6.test +++ /dev/null @@ -1,7 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o -# RUN: not ld.lld -shared %t.o -o /dev/null --script %s 2>&1 | FileCheck %s - -SECTIONS /* - -CHECK: error: {{.*}}diag6.test:1: unclosed comment in a linker script diff --git a/lld/test/ELF/invalid-linkerscript.test b/lld/test/ELF/linkerscript/invalid.test similarity index 100% rename from lld/test/ELF/invalid-linkerscript.test rename to lld/test/ELF/linkerscript/invalid.test diff --git a/lld/test/ELF/linkerscript/unquoted.test b/lld/test/ELF/linkerscript/unquoted.test new file mode 100644 index 0000000000000..7dca75fe09ab1 --- /dev/null +++ b/lld/test/ELF/linkerscript/unquoted.test @@ -0,0 +1,26 @@ +# REQUIRES: x86 +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 /dev/null -o 0.o + +#--- empty.lds +#--- 1.lds + +SECTIONS /* +#--- 1a.lds +foo = 3; +INCLUDE "empty.lds" +INCLUDE "1.lds" + +# RUN: not ld.lld -shared 0.o -T 1.lds 2>&1 | FileCheck %s --check-prefix=CHECK1 --match-full-lines --strict-whitespace +# RUN: not ld.lld -shared 0.o -T 1a.lds 2>&1 | FileCheck %s --check-prefix=CHECK1A --match-full-lines --strict-whitespace +# CHECK1:{{.*}}error: 1.lds:1: unclosed comment in a linker script +# CHECK1A:{{.*}}error: 1a.lds:3: unclosed comment in a linker script +#CHECK1A-NEXT:>>> INCLUDE "1.lds" +#CHECK1A-NEXT:>>> ^ + +#--- 2.lds +INCLUDE "empty.lds" +" +# RUN: not ld.lld -shared 0.o -T 2.lds 2>&1 | FileCheck %s --check-prefix=CHECK2 --match-full-lines --strict-whitespace +# CHECK2:{{.*}}error: 2.lds:2: unclosed quote +# CHECK2-NOT:{{.}} `````````` </details> https://github.com/llvm/llvm-project/pull/100883 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits