Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -177,9 +177,14 @@ public: static Elf_Sym IgnoreUndef; + // The following symbols must be added early to reserve their places + // in symbol tables. The value of the symbols are set when all sections + // are finalized and their addresses are determined. + + // The content for _end and end symbols. + static Elf_Sym End; + // The content for _gp symbol for MIPS target. - // The symbol has to be added early to reserve a place in symbol tables. - // The value of the symbol is computed later by Writer. static Elf_Sym MipsGp; DefinedAbsolute(StringRef N, const Elf_Sym &Sym) @@ -194,6 +199,9 @@ typename DefinedAbsolute::Elf_Sym DefinedAbsolute::IgnoreUndef; template +typename DefinedAbsolute::Elf_Sym DefinedAbsolute::End; + +template typename DefinedAbsolute::Elf_Sym DefinedAbsolute::MipsGp; template class DefinedCommon : public Defined { Index: lld/trunk/ELF/Symbols.cpp =================================================================== --- lld/trunk/ELF/Symbols.cpp +++ lld/trunk/ELF/Symbols.cpp @@ -85,6 +85,7 @@ } template static void doInitSymbols() { + DefinedAbsolute::End.setBinding(STB_GLOBAL); DefinedAbsolute::IgnoreUndef.setBinding(STB_WEAK); DefinedAbsolute::IgnoreUndef.setVisibility(STV_HIDDEN); Undefined::Optional.setVisibility(STV_HIDDEN); Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -623,6 +623,23 @@ if (!isOutputDynamic()) Symtab.addIgnoredSym("__tls_get_addr"); + // If the "_end" symbol is referenced, it is expected to point to the address + // right after the data segment. Usually, this symbol points to the end + // of .bss section or to the end of .data section if .bss section is absent. + // The order of the sections can be affected by linker script, + // so it is hard to predict which section will be the last one. + // So, if this symbol is referenced, we just add the placeholder here + // and update its value later. + if (Symtab.find("_end")) + Symtab.addAbsoluteSym("_end", DefinedAbsolute::End); + + // If there is an undefined symbol "end", we should initialize it + // with the same value as "_end". In any other case it should stay intact, + // because it is an allowable name for a user symbol. + if (SymbolBody *B = Symtab.find("end")) + if (B->isUndefined()) + Symtab.addAbsoluteSym("end", DefinedAbsolute::End); + // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. for (const std::unique_ptr> &F : Symtab.getObjectFiles()) { @@ -879,6 +896,10 @@ SectionHeaderOff = RoundUpToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4); FileSize = SectionHeaderOff + getNumSections() * sizeof(Elf_Shdr); + // Update "_end" and "end" symbols so that they + // point to the end of the data segment. + DefinedAbsolute::End.st_value = VA; + // Update MIPS _gp absolute symbol so that it points to the static data. if (Config->EMachine == EM_MIPS) DefinedAbsolute::MipsGp.st_value = getMipsGpAddr(); Index: lld/trunk/test/ELF/end-preserve.s =================================================================== --- lld/trunk/test/ELF/end-preserve.s +++ lld/trunk/test/ELF/end-preserve.s @@ -0,0 +1,16 @@ +// Should preserve the value of the "end" symbol if it is defined. +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t +// RUN: llvm-nm %t | FileCheck %s + +// CHECK: 0000000000000005 A end + +.global _start,end +end = 5 +.text +_start: + nop +.bss + .space 6 Index: lld/trunk/test/ELF/end-update.s =================================================================== --- lld/trunk/test/ELF/end-update.s +++ lld/trunk/test/ELF/end-update.s @@ -0,0 +1,29 @@ +// Should set the value of the "end" symbol if it is undefined. +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t +// RUN: llvm-readobj -sections -symbols %t | FileCheck %s + +// CHECK: Sections [ +// CHECK: Name: .bss +// CHECK-NEXT: Type: +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_WRITE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x12000 +// CHECK-NEXT: Offset: +// CHECK-NEXT: Size: 6 +// CHECK: ] +// CHECK: Symbols [ +// CHECK: Name: end +// CHECK-NEXT: Value: 0x12006 +// CHECK: ] + +.global _start,end +.text +_start: + nop +.bss + .space 6 Index: lld/trunk/test/ELF/end.s =================================================================== --- lld/trunk/test/ELF/end.s +++ lld/trunk/test/ELF/end.s @@ -0,0 +1,79 @@ +// Should set the value of the "_end" symbol to the end of the data segment. +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o + +// By default, the .bss section is the latest section of the data segment. +// RUN: ld.lld %t.o -o %t +// RUN: llvm-readobj -sections -symbols %t | FileCheck %s --check-prefix=DEFAULT + +// DEFAULT: Sections [ +// DEFAULT: Name: .bss +// DEFAULT-NEXT: Type: +// DEFAULT-NEXT: Flags [ +// DEFAULT-NEXT: SHF_ALLOC +// DEFAULT-NEXT: SHF_WRITE +// DEFAULT-NEXT: ] +// DEFAULT-NEXT: Address: 0x12002 +// DEFAULT-NEXT: Offset: +// DEFAULT-NEXT: Size: 6 +// DEFAULT: ] +// DEFAULT: Symbols [ +// DEFAULT: Name: _end +// DEFAULT-NEXT: Value: 0x12008 +// DEFAULT: ] + +// If there is no .bss section, "_end" should point to the end of the .data section. +// RUN: echo "SECTIONS { \ +// RUN: /DISCARD/ : { *(.bss) } }" > %t.script +// RUN: ld.lld %t.o --script %t.script -o %t +// RUN: llvm-readobj -sections -symbols %t | FileCheck %s --check-prefix=NOBSS + +// NOBSS: Sections [ +// NOBSS: Name: .data +// NOBSS-NEXT: Type: +// NOBSS-NEXT: Flags [ +// NOBSS-NEXT: SHF_ALLOC +// NOBSS-NEXT: SHF_WRITE +// NOBSS-NEXT: ] +// NOBSS-NEXT: Address: 0x12000 +// NOBSS-NEXT: Offset: +// NOBSS-NEXT: Size: 2 +// NOBSS: ] +// NOBSS: Symbols [ +// NOBSS: Name: _end +// NOBSS-NEXT: Value: 0x12002 +// NOBSS: ] + +// If the layout of the sections is changed, "_end" should point to the end of allocated address space. +// RUN: echo "SECTIONS { \ +// RUN: .bss : { *(.bss) } \ +// RUN: .data : { *(.data) } \ +// RUN: .text : { *(.text) } }" > %t.script +// RUN: ld.lld %t.o --script %t.script -o %t +// RUN: llvm-readobj -sections -symbols %t | FileCheck %s --check-prefix=TEXTATEND + +// TEXTATEND: Sections [ +// TEXTATEND: Name: .text +// TEXTATEND-NEXT: Type: +// TEXTATEND-NEXT: Flags [ +// TEXTATEND-NEXT: SHF_ALLOC +// TEXTATEND-NEXT: SHF_EXECINSTR +// TEXTATEND-NEXT: ] +// TEXTATEND-NEXT: Address: 0x12000 +// TEXTATEND-NEXT: Offset: +// TEXTATEND-NEXT: Size: 1 +// TEXTATEND: ] +// TEXTATEND: Symbols [ +// TEXTATEND: Name: _end +// TEXTATEND-NEXT: Value: 0x12001 +// TEXTATEND: ] + +.global _start,_end +.text +_start: + nop +.data + .word 1 +.bss + .space 6 Index: lld/trunk/test/ELF/entry.s =================================================================== --- lld/trunk/test/ELF/entry.s +++ lld/trunk/test/ELF/entry.s @@ -1,6 +1,6 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 # RUN: not ld.lld %t1 -o %t2 -# RUN: ld.lld %t1 -o %t2 -e _end +# RUN: ld.lld %t1 -o %t2 -e entry # RUN: ld.lld %t1 -o %t2 -e 4096 # RUN: llvm-readobj -file-headers %t2 | FileCheck -check-prefix=DEC %s @@ -13,5 +13,5 @@ # HEX: Entry: 0xCAFE # OCT: Entry: 0x1FF -.globl _end -_end: +.globl entry +entry: