Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -174,17 +174,17 @@ return C->Kind == BytesDataKind; } -static std::string filename(InputSectionBase *S) { - if (!S->File) +static std::string filename(InputFile *File) { + if (!File) return ""; - if (S->File->ArchiveName.empty()) - return S->File->getName(); - return (S->File->ArchiveName + "(" + S->File->getName() + ")").str(); + if (File->ArchiveName.empty()) + return File->getName(); + return (File->ArchiveName + "(" + File->getName() + ")").str(); } bool LinkerScript::shouldKeep(InputSectionBase *S) { for (InputSectionDescription *ID : Opt.KeptSections) { - std::string Filename = filename(S); + std::string Filename = filename(S->File); if (ID->FilePat.match(Filename)) for (SectionPattern &P : ID->SectionPatterns) if (P.SectionPat.match(S->Name)) @@ -284,7 +284,7 @@ if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) continue; - std::string Filename = filename(Sec); + std::string Filename = filename(Sec->File); if (!Cmd->FilePat.match(Filename) || Pat.ExcludedFilePat.match(Filename) || !Pat.SectionPat.match(Sec->Name)) @@ -328,8 +328,8 @@ void LinkerScript::discard(ArrayRef V) { for (InputSectionBase *S : V) { S->Live = false; - if (S == InX::ShStrTab || S == InX::Common || S == InX::Dynamic || - S == InX::DynSymTab || S == InX::DynStrTab) + if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab || + S == InX::DynStrTab) error("discarding " + S->Name + " section is not allowed"); discard(S->DependentSections); } @@ -868,7 +868,7 @@ if (auto *D = dyn_cast(B)) return {D->Section, D->Value, Loc}; if (auto *C = dyn_cast(B)) - return {InX::Common, C->Offset, Loc}; + return {C->Section, C->Offset, Loc}; } error(Loc + ": symbol not found: " + S); return 0; Index: lld/trunk/ELF/MapFile.cpp =================================================================== --- lld/trunk/ELF/MapFile.cpp +++ lld/trunk/ELF/MapFile.cpp @@ -57,7 +57,7 @@ DR->Section->Live) V.push_back(DR); } else if (auto *DC = dyn_cast(B)) { - if (InX::Common) + if (DC->Section) V.push_back(DC); } } @@ -71,8 +71,8 @@ for (Defined *S : Syms) { if (auto *DR = dyn_cast(S)) Ret[DR->Section].push_back(S); - else - Ret[InX::Common].push_back(S); + else if (auto *DC = dyn_cast(S)) + Ret[DC->Section].push_back(S); } // Sort symbols by address. We want to print out symbols in the Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -27,6 +27,7 @@ class ArchiveFile; class BitcodeFile; +class BssSection; class InputFile; class LazyObjFile; template class ObjFile; @@ -173,6 +174,7 @@ // Computed by the writer. uint64_t Offset; uint64_t Size; + BssSection *Section = nullptr; }; // Regular defined symbols read from object file symbol tables. Index: lld/trunk/ELF/Symbols.cpp =================================================================== --- lld/trunk/ELF/Symbols.cpp +++ lld/trunk/ELF/Symbols.cpp @@ -99,11 +99,13 @@ } return VA; } - case SymbolBody::DefinedCommonKind: + case SymbolBody::DefinedCommonKind: { if (!Config->DefineCommon) return 0; - return InX::Common->getParent()->Addr + InX::Common->OutSecOff + - cast(Body).Offset; + auto DC = cast(Body); + return DC.Section->getParent()->Addr + DC.Section->OutSecOff + + DC.Offset; + } case SymbolBody::SharedKind: { auto &SS = cast(Body); if (SS.CopyRelSec) @@ -202,9 +204,9 @@ return nullptr; } - if (isa(this)) { + if (auto *S = dyn_cast(this)) { if (Config->DefineCommon) - return InX::Common->getParent(); + return S->Section->getParent(); return nullptr; } Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -740,7 +740,7 @@ size_t Size = 0; }; -template InputSection *createCommonSection(); +std::vector createCommonSections(); InputSection *createInterpSection(); template MergeInputSection *createCommentSection(); void decompressAndMergeSections(); @@ -754,7 +754,6 @@ static BssSection *Bss; static BssSection *BssRelRo; static BuildIdSection *BuildId; - static InputSection *Common; static SyntheticSection *Dynamic; static StringTableSection *DynStrTab; static SymbolTableBaseSection *DynSymTab; Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -54,35 +54,22 @@ return 0; } -template static std::vector getCommonSymbols() { - std::vector V; - for (Symbol *S : Symtab->getSymbols()) - if (auto *B = dyn_cast(S->body())) - V.push_back(B); - return V; -} - -// Find all common symbols and allocate space for them. -template InputSection *elf::createCommonSection() { +std::vector elf::createCommonSections() { if (!Config->DefineCommon) - return nullptr; + return {}; - // Sort the common symbols by alignment as an heuristic to pack them better. - std::vector Syms = getCommonSymbols(); - if (Syms.empty()) - return nullptr; - - std::stable_sort(Syms.begin(), Syms.end(), - [](const DefinedCommon *A, const DefinedCommon *B) { - return A->Alignment > B->Alignment; - }); + std::vector Ret; + for (Symbol *S : Symtab->getSymbols()) { + auto *Sym = dyn_cast(S->body()); + if (!Sym || !Sym->Live) + continue; - // Allocate space for common symbols. - BssSection *Sec = make("COMMON"); - for (DefinedCommon *Sym : Syms) - if (Sym->Live) - Sym->Offset = Sec->reserveSpace(Sym->Size, Sym->Alignment); - return Sec; + Sym->Section = make("COMMON"); + Sym->Offset = Sym->Section->reserveSpace(Sym->Size, Sym->Alignment); + Sym->Section->File = Sym->getFile(); + Ret.push_back(Sym->Section); + } + return Ret; } // Returns an LLD version string. @@ -2321,7 +2308,6 @@ BssSection *InX::Bss; BssSection *InX::BssRelRo; BuildIdSection *InX::BuildId; -InputSection *InX::Common; SyntheticSection *InX::Dynamic; StringTableSection *InX::DynStrTab; SymbolTableBaseSection *InX::DynSymTab; @@ -2349,11 +2335,6 @@ template void PltSection::addEntry(SymbolBody &Sym); template void PltSection::addEntry(SymbolBody &Sym); -template InputSection *elf::createCommonSection(); -template InputSection *elf::createCommonSection(); -template InputSection *elf::createCommonSection(); -template InputSection *elf::createCommonSection(); - template MergeInputSection *elf::createCommentSection(); template MergeInputSection *elf::createCommentSection(); template MergeInputSection *elf::createCommentSection(); Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -299,9 +299,9 @@ Add(InX::BuildId); } - InX::Common = createCommonSection(); - if (InX::Common) - Add(InX::Common); + auto Commons = createCommonSections(); + for (InputSection *S : Commons) + Add(S); InX::Bss = make(".bss"); Add(InX::Bss); Index: lld/trunk/test/ELF/common.s =================================================================== --- lld/trunk/test/ELF/common.s +++ lld/trunk/test/ELF/common.s @@ -12,13 +12,13 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x201000 // CHECK-NEXT: Offset: -// CHECK-NEXT: Size: 22 +// CHECK-NEXT: Size: 36 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 16 // CHECK: Name: sym1 -// CHECK-NEXT: Value: 0x201004 +// CHECK-NEXT: Value: 0x201000 // CHECK-NEXT: Size: 8 // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: Object @@ -26,7 +26,7 @@ // CHECK-NEXT: Section: .bss // CHECK: Name: sym2 -// CHECK-NEXT: Value: 0x20100C +// CHECK-NEXT: Value: 0x201008 // CHECK-NEXT: Size: 8 // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: Object @@ -34,7 +34,7 @@ // CHECK-NEXT: Section: .bss // CHECK: Name: sym3 -// CHECK-NEXT: Value: 0x201014 +// CHECK-NEXT: Value: 0x201010 // CHECK-NEXT: Size: 2 // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: Object @@ -42,7 +42,7 @@ // CHECK-NEXT: Section: .bss // CHECK: Name: sym4 -// CHECK-NEXT: Value: 0x201000 +// CHECK-NEXT: Value: 0x201020 // CHECK-NEXT: Size: 4 // CHECK-NEXT: Binding: Global // CHECK-NEXT: Type: Object Index: lld/trunk/test/ELF/linkerscript/Inputs/common-filespec1.s =================================================================== --- lld/trunk/test/ELF/linkerscript/Inputs/common-filespec1.s +++ lld/trunk/test/ELF/linkerscript/Inputs/common-filespec1.s @@ -0,0 +1,2 @@ +.comm common_uniq_1,8,8 +.comm common_multiple,16,8 Index: lld/trunk/test/ELF/linkerscript/Inputs/common-filespec2.s =================================================================== --- lld/trunk/test/ELF/linkerscript/Inputs/common-filespec2.s +++ lld/trunk/test/ELF/linkerscript/Inputs/common-filespec2.s @@ -0,0 +1,2 @@ +.comm common_uniq_2,16,16 +.comm common_multiple,32,8 Index: lld/trunk/test/ELF/linkerscript/common-exclude.s =================================================================== --- lld/trunk/test/ELF/linkerscript/common-exclude.s +++ lld/trunk/test/ELF/linkerscript/common-exclude.s @@ -0,0 +1,86 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile0.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec1.s -o %tfile1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec2.s -o %tfile2.o +# RUN: echo "SECTIONS { .common.incl : { *(EXCLUDE_FILE (*file2.o) COMMON) } .common.excl : { *(COMMON) } }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %tfile0.o %tfile1.o %tfile2.o +# RUN: llvm-readobj -s -t %t1 | FileCheck %s + +# Commons from file0 and file1 are not excluded, so they must be in .common.incl +# Commons from file2 are excluded from the first rule and should be caught by +# the second in .common.excl +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .common.incl +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x8 +# CHECK-NEXT: Offset: 0x +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 8 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .common.excl +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x20 +# CHECK-NEXT: Offset: 0x +# CHECK-NEXT: Size: 48 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 16 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK: Symbol { +# CHECK: Name: common_multiple +# CHECK-NEXT: Value: 0x20 +# CHECK-NEXT: Size: 32 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common.excl +# CHECK-NEXT: } +# CHECK: Symbol { +# CHECK: Name: common_uniq_0 +# CHECK-NEXT: Value: 0x8 +# CHECK-NEXT: Size: 4 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common.incl +# CHECK-NEXT: } +# CHECK: Symbol { +# CHECK: Name: common_uniq_1 +# CHECK-NEXT: Value: 0x10 +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common.incl +# CHECK-NEXT: } +# CHECK: Symbol { +# CHECK: Name: common_uniq_2 +# CHECK-NEXT: Value: 0x40 +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common.excl +# CHECK-NEXT: } + +.globl _start +_start: + jmp _start + +.comm common_uniq_0,4,4 +.comm common_multiple,8,8 Index: lld/trunk/test/ELF/linkerscript/common-filespec.s =================================================================== --- lld/trunk/test/ELF/linkerscript/common-filespec.s +++ lld/trunk/test/ELF/linkerscript/common-filespec.s @@ -0,0 +1,105 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile0.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec1.s -o %tfile1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec2.s -o %tfile2.o +# RUN: echo "SECTIONS { .common_0 : { *file0.o(COMMON) } .common_1 : { *file1.o(COMMON) } .common_2 : { *file2.o(COMMON) } }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %tfile0.o %tfile1.o %tfile2.o +# RUN: llvm-readobj -s -t %t1 | FileCheck %s + +# Make sure all 3 sections are allocated and they have sizes and alignments +# corresponding to the commons assigned to them +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .common_0 +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x4 +# CHECK-NEXT: Offset: 0x +# CHECK-NEXT: Size: 4 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .common_1 +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x8 +# CHECK-NEXT: Offset: 0x +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 8 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .common_2 +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x10 +# CHECK-NEXT: Offset: 0x +# CHECK-NEXT: Size: 48 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 16 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } + +# Commons with unique name in each file must be assigned to that file's section. +# For a common with multiple definitions, the largest one wins and it must be +# assigned to the section from the file which provided the winning def +# CHECK: Symbol { +# CHECK: Name: common_multiple +# CHECK-NEXT: Value: 0x10 +# CHECK-NEXT: Size: 32 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common_2 +# CHECK-NEXT: } +# CHECK: Symbol { +# CHECK: Name: common_uniq_0 +# CHECK-NEXT: Value: 0x4 +# CHECK-NEXT: Size: 4 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common_0 +# CHECK-NEXT: } +# CHECK: Symbol { +# CHECK: Name: common_uniq_1 +# CHECK-NEXT: Value: 0x8 +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common_1 +# CHECK-NEXT: } +# CHECK: Symbol { +# CHECK: Name: common_uniq_2 +# CHECK-NEXT: Value: 0x30 +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .common_2 +# CHECK-NEXT: } + +.globl _start +_start: + jmp _start + +.comm common_uniq_0,4,4 +.comm common_multiple,8,8 Index: lld/trunk/test/ELF/linkerscript/common.s =================================================================== --- lld/trunk/test/ELF/linkerscript/common.s +++ lld/trunk/test/ELF/linkerscript/common.s @@ -4,8 +4,6 @@ # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-readobj -s -t %t1 | FileCheck %s -# q2 alignment is greater than q1, so it should have smaller offset -# because of sorting # CHECK: Section { # CHECK: Index: # CHECK: Name: .common @@ -16,7 +14,7 @@ # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x200 # CHECK-NEXT: Offset: 0x -# CHECK-NEXT: Size: 256 +# CHECK-NEXT: Size: 384 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 256 @@ -24,7 +22,7 @@ # CHECK-NEXT: } # CHECK: Symbol { # CHECK: Name: q1 -# CHECK-NEXT: Value: 0x280 +# CHECK-NEXT: Value: 0x200 # CHECK-NEXT: Size: 128 # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: Object @@ -33,7 +31,7 @@ # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: q2 -# CHECK-NEXT: Value: 0x200 +# CHECK-NEXT: Value: 0x300 # CHECK-NEXT: Size: 128 # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: Object Index: lld/trunk/test/ELF/linkerscript/discard-section-err.s =================================================================== --- lld/trunk/test/ELF/linkerscript/discard-section-err.s +++ lld/trunk/test/ELF/linkerscript/discard-section-err.s @@ -22,9 +22,4 @@ # RUN: FileCheck -check-prefix=DYNSTR %s # DYNSTR: discarding .dynstr section is not allowed -# RUN: echo "SECTIONS { /DISCARD/ : { *(COMMON) } }" > %t.script -# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \ -# RUN: FileCheck -check-prefix=COMMON %s -# COMMON: discarding COMMON section is not allowed - .comm foo,4,4 Index: lld/trunk/test/ELF/map-file.s =================================================================== --- lld/trunk/test/ELF/map-file.s +++ lld/trunk/test/ELF/map-file.s @@ -47,7 +47,7 @@ // CHECK-NEXT: 0000000000201014 0000000000000001 4 {{.*}}{{/|\\}}map-file.s.tmp4.a(map-file.s.tmp4.o):(.text) // CHECK-NEXT: 0000000000201014 0000000000000000 0 baz // CHECK-NEXT: 0000000000202000 0000000000000004 16 .bss -// CHECK-NEXT: 0000000000202000 0000000000000004 16 :(COMMON) +// CHECK-NEXT: 0000000000202000 0000000000000004 16 {{.*}}{{/|\\}}map-file.s.tmp1.o:(COMMON) // CHECK-NEXT: 0000000000202000 0000000000000004 0 common // CHECK-NEXT: 0000000000000000 0000000000000008 1 .comment // CHECK-NEXT: 0000000000000000 0000000000000008 1 :(.comment)