Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -95,6 +95,7 @@ std::vector Phdrs; std::vector Filler; ConstraintKind Constraint = ConstraintKind::NoConstraint; + bool IsEmpty = false; }; // This struct represents one section match pattern in SECTIONS() command. @@ -220,6 +221,8 @@ std::vector *> createInputSectionList(OutputSectionCommand &Cmd); + void addEmptySections(); + // "ScriptConfig" is a bit too long, so define a short name for it. ScriptConfiguration &Opt = *ScriptConfig; Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -440,6 +440,33 @@ return Ret; } +// Convert synthetic symbol to absolute. Used for symbols defined in +// empty sections. Those sections do not exist in final ELF image +template static void makeAbsolute(SymbolBody *Body) { + auto *Synthetic = dyn_cast_or_null>(Body); + if (!Synthetic) + return; + + Symbol *S = Synthetic->symbol(); + uint32_t GotIndex = Synthetic->GotIndex; + unsigned DynsymIndex = Synthetic->DynsymIndex; + + replaceBody>(S, Body->getName(), + static_cast(S->Visibility)); + auto *Regular = cast>(Body); + Regular->GotIndex = GotIndex; + Regular->DynsymIndex = DynsymIndex; +} + +// Convert all section synthetic symbols to absolute. This is +// done for empty sections, which are removed in assignAddresses(). +template +static void makeSymbolsAbsolute(OutputSectionCommand *Cmd) { + for (std::unique_ptr &Base : Cmd->Commands) + if (auto *AssignCmd = dyn_cast(Base.get())) + makeAbsolute(AssignCmd->Sym); +} + template void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { std::vector *> Sections = @@ -448,6 +475,11 @@ return; switchTo(Sections[0]); + // We are to remove all empty sections, so symbols should be + // made absolute. + if (Cmd->IsEmpty) + makeSymbolsAbsolute(Cmd); + // Find the last section output location. We will output orphan sections // there so that end symbols point to the correct location. auto E = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(), @@ -464,51 +496,27 @@ [this](std::unique_ptr &B) { process(*B.get()); }); } -template void LinkerScript::adjustSectionsBeforeSorting() { - // It is common practice to use very generic linker scripts. So for any - // given run some of the output sections in the script will be empty. - // We could create corresponding empty output sections, but that would - // clutter the output. - // We instead remove trivially empty sections. The bfd linker seems even - // more aggressive at removing them. - auto Pos = std::remove_if( - Opt.Commands.begin(), Opt.Commands.end(), - [&](const std::unique_ptr &Base) { - auto *Cmd = dyn_cast(Base.get()); - if (!Cmd) - return false; - std::vector *> Secs = - findSections(*Cmd, *OutputSections); - if (!Secs.empty()) - return false; - for (const std::unique_ptr &I : Cmd->Commands) - if (!isa(I.get())) - return false; - return true; - }); - Opt.Commands.erase(Pos, Opt.Commands.end()); - - // If the output section contains only symbol assignments, create a - // corresponding output section. The bfd linker seems to only create them if - // '.' is assigned to, but creating these section should not have any bad - // consequeces and gives us a section to put the symbol in. - uintX_t Flags = SHF_ALLOC; - uint32_t Type = 0; +template void LinkerScript::addEmptySections() { + auto InsertIt = OutputSections->begin(); for (const std::unique_ptr &Base : Opt.Commands) { - auto *Cmd = dyn_cast(Base.get()); - if (!Cmd) - continue; - std::vector *> Secs = - findSections(*Cmd, *OutputSections); - if (!Secs.empty()) { - Flags = Secs[0]->getFlags(); - Type = Secs[0]->getType(); + OutputSectionCommand *Cmd = dyn_cast(Base.get()); + if (!Cmd || Cmd->Name == "/DISCARD/") continue; - } - auto *OutSec = new OutputSection(Cmd->Name, Type, Flags); - Out::Pool.emplace_back(OutSec); - OutputSections->push_back(OutSec); + bool FoundIt = false; + for (auto It = OutputSections->begin(); It != OutputSections->end(); ++It) + if ((*It)->getName() == Cmd->Name) { + FoundIt = true; + InsertIt = It + 1; + } + + if (!FoundIt) { + Cmd->IsEmpty = true; + OutputSectionBase *EmptySec = new OutputSectionBase( + Cmd->Name, SHT_NULL, SHF_EXCLUDE | SHF_ALLOC); + InsertIt = OutputSections->insert(InsertIt, EmptySec) + 1; + Out::Pool.emplace_back(EmptySec); + } } } @@ -535,7 +543,14 @@ return Assign->Name != "."; } +template static void removeIf(Range &R, Pred P) { + R.erase(std::remove_if(R.begin(), R.end(), P), R.end()); +} + template void LinkerScript::assignAddresses() { + // Temporarily add empty sections to the list of output sections. + addEmptySections(); + // Orphan sections are sections present in the input files which // are not explicitly placed into the output file by the linker script. // We place orphan sections at end of file. @@ -601,6 +616,10 @@ assignOffsets(Cmd); } + removeIf(*OutputSections, [](OutputSectionBase *Sec) { + return Sec->getFlags() & SHF_EXCLUDE; + }); + uintX_t MinVA = std::numeric_limits::max(); for (OutputSectionBase *Sec : *OutputSections) { if (Sec->getFlags() & SHF_ALLOC) Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -724,8 +724,6 @@ compareSectionsNonScript); return; } - Script::X->adjustSectionsBeforeSorting(); - // The order of the sections in the script is arbitrary and may not agree with // compareSectionsNonScript. This means that we cannot easily define a // strict weak ordering. To see why, consider a comparison of a section in the Index: test/ELF/linkerscript/extend-pt-load.s =================================================================== --- test/ELF/linkerscript/extend-pt-load.s +++ test/ELF/linkerscript/extend-pt-load.s @@ -1,57 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o - -# This test demonstrates an odd consequence of the way we handle sections with just symbol -# assignments. - -# First, run a test with no such section. - -# RUN: echo "SECTIONS { \ -# RUN: .text : { *(.text) } \ -# RUN: . = ALIGN(0x1000); \ -# RUN: .data.rel.ro : { *(.data.rel.ro) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t.o -shared -# RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck --check-prefix=CHECK1 %s - -# CHECK1: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX -# CHECK1-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA - -# CHECK1: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x0001bd R E -# CHECK1-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW - -# Then add the section bar. Note how bar is given AX flags, which causes the PT_LOAD to now -# cover the padding bits created by ALIGN. - -# RUN: echo "SECTIONS { \ -# RUN: .text : { *(.text) } \ -# RUN: . = ALIGN(0x1000); \ -# RUN: bar : { HIDDEN(bar_sym = .); } \ -# RUN: .data.rel.ro : { *(.data.rel.ro) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t2 --script %t.script %t.o -shared -# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck --check-prefix=CHECK2 %s - -# CHECK2: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX -# CHECK2-NEXT: bar PROGBITS 0000000000001000 001000 000000 00 AX -# CHECK2-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA - -# CHECK2: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001000 0x001000 R E -# CHECK2-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW - -# If the current behavior becomes a problem we should consider just moving the commands out -# of the section. That is, handle the above like the following test. - -# RUN: echo "SECTIONS { \ -# RUN: .text : { *(.text) } \ -# RUN: . = ALIGN(0x1000); \ -# RUN: HIDDEN(bar_sym = .); \ -# RUN: .data.rel.ro : { *(.data.rel.ro) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t3 --script %t.script %t.o -shared -# RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck --check-prefix=CHECK1 %s - -nop - -.section .data.rel.ro, "aw" -.byte 0 Index: test/ELF/linkerscript/symbol-only.s =================================================================== --- test/ELF/linkerscript/symbol-only.s +++ test/ELF/linkerscript/symbol-only.s @@ -1,20 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - -# RUN: echo "SECTIONS { \ -# RUN: abc : { foo = .; } \ -# RUN: . = ALIGN(0x1000); \ -# RUN: bar : { *(bar) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -shared -# RUN: llvm-objdump -section-headers -t %t1 | FileCheck %s -# CHECK: Sections: -# CHECK-NEXT: Idx Name Size Address -# CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 abc 00000000 [[ADDR:[0-9a-f]*]] -# CHECK-NEXT: 2 bar 00000000 0000000000001000 DATA - -# CHECK: SYMBOL TABLE: -# CHECK: [[ADDR]] abc 00000000 foo - -.section bar, "a" Index: test/ELF/linkerscript/symbols-synthetic.s =================================================================== --- test/ELF/linkerscript/symbols-synthetic.s +++ test/ELF/linkerscript/symbols-synthetic.s @@ -41,6 +41,21 @@ # RUN: }" > %t.script # RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t +# Check symbols inside empty section. Also check section size and address. +# RUN: echo "SECTIONS { \ +# RUN: .aaa : { \ +# RUN: PROVIDE_HIDDEN(_begin_sec = .); \ +# RUN: *(.bbb) \ +# RUN: *(.ccc) \ +# RUN: PROVIDE_HIDDEN(_end_sec = .); \ +# RUN: PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); } \ +# RUN: addr_of_aaa = ADDR(.aaa); \ +# RUN: size_of_aaa = SIZEOF(.aaa); \ +# RUN: align_of_aaa = ALIGNOF(.aaa); \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=EMPTY %s + # SIMPLE: 0000000000000128 .foo 00000000 .hidden _end_sec # SIMPLE-NEXT: 0000000000000120 .foo 00000000 _begin_sec # SIMPLE-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs @@ -58,6 +73,14 @@ # SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end # SIMPLE-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2 +# EMPTY: 00000000000000e8 *ABS* 00000000 .hidden _begin_sec +# EMPTY-NEXT: 00000000000000e8 *ABS* 00000000 .hidden _end_sec +# EMPTY-NEXT: 00000000000000e8 *ABS* 00000000 .hidden _end_sec_abs +# EMPTY-NEXT: 0000000000000128 .text 00000000 _start +# EMPTY-NEXT: 00000000000000e8 *ABS* 00000000 addr_of_aaa +# EMPTY-NEXT: 0000000000000000 *ABS* 00000000 size_of_aaa +# EMPTY-NEXT: 0000000000000001 *ABS* 00000000 align_of_aaa + .global _start _start: nop