Index: lld/trunk/ELF/Symbols.h =================================================================== --- lld/trunk/ELF/Symbols.h +++ lld/trunk/ELF/Symbols.h @@ -346,6 +346,12 @@ // output file's symbol table. It has weak binding and can be substituted. static Elf_Sym Ignored; + // The content for _etext and etext symbols. + static Elf_Sym Etext; + + // The content for _edata and edata symbols. + static Elf_Sym Edata; + // The content for _end and end symbols. static Elf_Sym End; @@ -359,6 +365,8 @@ }; template typename ElfSym::Elf_Sym ElfSym::Ignored; +template typename ElfSym::Elf_Sym ElfSym::Etext; +template typename ElfSym::Elf_Sym ElfSym::Edata; template typename ElfSym::Elf_Sym ElfSym::End; template typename ElfSym::Elf_Sym ElfSym::MipsGp; template Index: lld/trunk/ELF/Symbols.cpp =================================================================== --- lld/trunk/ELF/Symbols.cpp +++ lld/trunk/ELF/Symbols.cpp @@ -214,6 +214,8 @@ } template static void doInitSymbols() { + ElfSym::Etext.setBinding(STB_GLOBAL); + ElfSym::Edata.setBinding(STB_GLOBAL); ElfSym::End.setBinding(STB_GLOBAL); ElfSym::Ignored.setBinding(STB_WEAK); ElfSym::Ignored.setVisibility(STV_HIDDEN); Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -914,20 +914,30 @@ if (!isOutputDynamic()) Symtab.addIgnored("__tls_get_addr"); + auto Define = [this](StringRef Name, StringRef Alias, Elf_Sym &Sym) { + if (Symtab.find(Name)) + Symtab.addAbsolute(Name, Sym); + if (SymbolBody *B = Symtab.find(Alias)) + if (B->isUndefined()) + Symtab.addAbsolute(Alias, Sym); + }; + // 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. // We don't know the final address of _end yet, so just add a symbol here, // and fix ElfSym::End.st_value later. - if (Symtab.find("_end")) - Symtab.addAbsolute("_end", ElfSym::End); - // Define "end" as an alias to "_end" if it is used but not defined. // We don't want to define that unconditionally because we don't want to // break programs that uses "end" as a regular symbol. - if (SymbolBody *B = Symtab.find("end")) - if (B->isUndefined()) - Symtab.addAbsolute("end", ElfSym::End); + // The similar history with _etext/etext and _edata/edata: + // Address of _etext is the first location after the last read-only loadable + // segment. Address of _edata points to the end of the last non SHT_NOBITS + // section. That is how gold/bfd do. We update the values for these symbols + // later, after assigning sections to segments. + Define("_end", "end", ElfSym::End); + Define("_etext", "etext", ElfSym::Etext); + Define("_edata", "edata", ElfSym::Edata); } // Sort input sections by section name suffixes for @@ -1454,6 +1464,17 @@ // Update MIPS _gp absolute symbol so that it points to the static data. if (Config->EMachine == EM_MIPS) ElfSym::MipsGp.st_value = getMipsGpAddr(); + + // _etext points to location after the last read-only loadable segment. + // _edata points to the end of the last non SHT_NOBITS section. + for (OutputSectionBase *Sec : OutputSections) { + if (!(Sec->getFlags() & SHF_ALLOC)) + continue; + if (!(Sec->getFlags() & SHF_WRITE)) + ElfSym::Etext.st_value = Sec->getVA() + Sec->getSize(); + if (Sec->getType() != SHT_NOBITS) + ElfSym::Edata.st_value = Sec->getVA() + Sec->getSize(); + } } template void Writer::writeHeader() { Index: lld/trunk/test/ELF/edata-etext.s =================================================================== --- lld/trunk/test/ELF/edata-etext.s +++ lld/trunk/test/ELF/edata-etext.s @@ -0,0 +1,117 @@ +# 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 + +## This checks that: +## 1) Address of _etext is the first location after the last read-only loadable segment. +## 2) Address of _edata points to the end of the last non SHT_NOBITS section. +## That is how gold/bfd do. At the same time specs says: "If the address of _edata is +## greater than the address of _etext, the address of _end is same as the address +## of _edata." (https://docs.oracle.com/cd/E53394_01/html/E54766/u-etext-3c.html). +## 3) Address of _end is different from _edata because of 2. +# CHECK: Section { +# CHECK: Index: 1 +# CHECK: Name: .text +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x11000 +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Size: 1 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .data +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x12000 +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: Size: 2 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .bss +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x12004 +# CHECK-NEXT: Offset: 0x2002 +# CHECK-NEXT: Size: 6 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: } +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _start +# CHECK-NEXT: Value: 0x11000 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _edata +# CHECK-NEXT: Value: 0x12002 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _end +# CHECK-NEXT: Value: 0x1200A +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _etext +# CHECK-NEXT: Value: 0x11001 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Absolute +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.global _start,_end,_etext,_edata +.text +_start: + nop +.data + .word 1 +.bss + .align 4 + .space 6