Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -310,10 +310,43 @@ } } -template void assignOffsets(OutputSectionBase *Sec) { +// Linker script may define start and end symbols for special section types, +// like .got, .eh_frame_hdr, .eh_frame and others. Those sections are not a list +// of regular input input sections, therefore our way of defining symbols for +// regular sections will not work. The approach we use for special section types +// is not perfect - it handles only start and end symbols. +template +void addStartEndSymbols(OutputSectionCommand *Cmd, + OutputSectionBase *Sec) { + bool Start = true, LastSymType = Start; + for (std::unique_ptr &Base : Cmd->Commands) { + if (isa(Base.get())) { + if (!Start && !LastSymType) + error("section '" + Sec->getName() + + "' supports only start and end symbols"); + Start = false; + continue; + } + auto *AssignCmd = dyn_cast(Base.get()); + if (!AssignCmd || !AssignCmd->Sym) + continue; + auto *Sym = cast>(AssignCmd->Sym); + Sym->Section = Sec; + Sym->Value = + AssignCmd->Expression(Sec->getVA() + (Start ? 0 : Sec->getSize())) - + Sec->getVA(); + LastSymType = Start; + } +} + +template +void assignOffsets(OutputSectionCommand *Cmd, OutputSectionBase *Sec) { auto *OutSec = dyn_cast>(Sec); if (!OutSec) { Sec->assignOffsets(); + // This section is not regular output section. However linker script may + // have defined start/end symbols for it. This case is handled below. + addStartEndSymbols(Cmd, Sec); return; } @@ -404,19 +437,19 @@ uintX_t TVA = Dot + ThreadBssOffset; TVA = alignTo(TVA, Sec->getAlignment()); Sec->setVA(TVA); - assignOffsets(Sec); + assignOffsets(Cmd, Sec); ThreadBssOffset = TVA - Dot + Sec->getSize(); continue; } if (!(Sec->getFlags() & SHF_ALLOC)) { - Sec->assignOffsets(); + assignOffsets(Cmd, Sec); continue; } Dot = alignTo(Dot, Sec->getAlignment()); Sec->setVA(Dot); - assignOffsets(Sec); + assignOffsets(Cmd, Sec); MinVA = std::min(MinVA, Dot); Dot += Sec->getSize(); } Index: test/ELF/linkerscript/linkerscript-symbols-synthetic.s =================================================================== --- test/ELF/linkerscript/linkerscript-symbols-synthetic.s +++ test/ELF/linkerscript/linkerscript-symbols-synthetic.s @@ -1,36 +1,69 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - # Simple symbol assignment within input section list. The '.' symbol # is not location counter but offset from the beginning of output # section .foo # RUN: echo "SECTIONS { \ # RUN: .foo : { \ # RUN: begin_foo = .; \ -# RUN: PROVIDE(_begin_foo = .); \ +# RUN: PROVIDE(_begin_sec = .); \ # RUN: *(.foo) \ # RUN: end_foo = .; \ -# RUN: PROVIDE_HIDDEN(_end_foo = .); \ +# RUN: PROVIDE_HIDDEN(_end_sec = .); \ # RUN: size_foo_1 = SIZEOF(.foo); \ # RUN: . = ALIGN(0x1000); \ # RUN: begin_bar = .; \ # RUN: *(.bar) \ # RUN: end_bar = .; \ -# RUN: size_foo_2 = SIZEOF(.foo); \ -# RUN: } \ -# RUN: size_foo_3 = SIZEOF(.foo); }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t +# RUN: size_foo_2 = SIZEOF(.foo); } \ +# RUN: size_foo_3 = SIZEOF(.foo); \ +# RUN: .eh_frame_hdr : { \ +# RUN: __eh_frame_hdr_start = .; \ +# RUN: __eh_frame_hdr_start2 = ALIGN(0x10); \ +# RUN: *(.eh_frame_hdr) \ +# RUN: __eh_frame_hdr_end = .; \ +# RUN: __eh_frame_hdr_end2 = ALIGN(0x10); } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t # RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s -# SIMPLE: 0000000000000128 .foo 00000000 .hidden _end_foo -# SIMPLE: 0000000000000120 .foo 00000000 _begin_foo -# SIMPLE-NEXT: 0000000000000120 .foo 00000000 begin_foo -# SIMPLE-NEXT: 0000000000000128 .foo 00000000 end_foo +# The script below contains symbols in the middle of .eh_frame_hdr section. +# We don't support this. +# RUN: echo "SECTIONS { \ +# RUN: .eh_frame_hdr : { \ +# RUN: PROVIDE_HIDDEN(_begin_sec = .); \ +# RUN: __eh_frame_hdr_start = .; \ +# RUN: *(.eh_frame_hdr) \ +# RUN: __eh_frame_hdr_end = .; \ +# RUN: *(.eh_frame_hdr) } \ +# RUN: PROVIDE_HIDDEN(_end_sec = .); \ +# RUN: }" > %t.script +# RUN: not ld.lld -o %t1 --eh-frame-hdr --script %t.script %t 2>&1 | FileCheck --check-prefix=ERROR %s + +# Check that the following script is processed without errors +# RUN: echo "SECTIONS { \ +# RUN: .eh_frame_hdr : { \ +# RUN: PROVIDE_HIDDEN(_begin_sec = .); \ +# RUN: *(.eh_frame_hdr) \ +# RUN: *(.eh_frame_hdr) \ +# RUN: PROVIDE_HIDDEN(_end_sec = .); } \ +# RUN: }" > %t.script +# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t + +# SIMPLE: 0000000000000160 .foo 00000000 .hidden _end_sec +# SIMPLE: 0000000000000158 .foo 00000000 _begin_sec +# SIMPLE-NEXT: 0000000000000158 .foo 00000000 begin_foo +# SIMPLE-NEXT: 0000000000000160 .foo 00000000 end_foo # SIMPLE-NEXT: 0000000000000008 .foo 00000000 size_foo_1 # SIMPLE-NEXT: 0000000000001000 .foo 00000000 begin_bar # SIMPLE-NEXT: 0000000000001004 .foo 00000000 end_bar -# SIMPLE-NEXT: 0000000000000ee4 .foo 00000000 size_foo_2 -# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_3 +# SIMPLE-NEXT: 0000000000000eac .foo 00000000 size_foo_2 +# SIMPLE-NEXT: 0000000000000eac *ABS* 00000000 size_foo_3 +# SIMPLE-NEXT: 0000000000001004 .eh_frame_hdr 00000000 __eh_frame_hdr_start +# SIMPLE-NEXT: 0000000000001010 .eh_frame_hdr 00000000 __eh_frame_hdr_start2 +# SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end +# SIMPLE-NEXT: 0000000000001020 .eh_frame_hdr 00000000 __eh_frame_hdr_end2 +# ERROR: section '.eh_frame_hdr' supports only start and end symbols .global _start _start: @@ -42,4 +75,9 @@ .section .bar,"a" .long 0 -.global _begin_foo, _end_foo +.section .dah,"ax",@progbits + .cfi_startproc + nop + .cfi_endproc + +.global _begin_sec, _end_sec