[ELF] Define symbols "_end" and "end" if referenced.

These symbols are expected to point to the end of the data segment.

Implements http://llvm.org/pr25528.

Differential Revision: http://reviews.llvm.org/D14833

llvm-svn: 253637
This commit is contained in:
Igor Kudrin 2015-11-20 02:32:35 +00:00
parent dcb5653516
commit b044af50f2
7 changed files with 159 additions and 5 deletions

View File

@ -85,6 +85,7 @@ std::unique_ptr<InputFile> Lazy::getMember() {
}
template <class ELFT> static void doInitSymbols() {
DefinedAbsolute<ELFT>::End.setBinding(STB_GLOBAL);
DefinedAbsolute<ELFT>::IgnoreUndef.setBinding(STB_WEAK);
DefinedAbsolute<ELFT>::IgnoreUndef.setVisibility(STV_HIDDEN);
Undefined<ELFT>::Optional.setVisibility(STV_HIDDEN);

View File

@ -177,9 +177,14 @@ template <class ELFT> class DefinedAbsolute : public Defined<ELFT> {
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)
@ -193,6 +198,9 @@ public:
template <class ELFT>
typename DefinedAbsolute<ELFT>::Elf_Sym DefinedAbsolute<ELFT>::IgnoreUndef;
template <class ELFT>
typename DefinedAbsolute<ELFT>::Elf_Sym DefinedAbsolute<ELFT>::End;
template <class ELFT>
typename DefinedAbsolute<ELFT>::Elf_Sym DefinedAbsolute<ELFT>::MipsGp;

View File

@ -623,6 +623,23 @@ template <class ELFT> void Writer<ELFT>::createSections() {
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<ELFT>::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<ELFT>::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<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
@ -879,6 +896,10 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
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<ELFT>::End.st_value = VA;
// Update MIPS _gp absolute symbol so that it points to the static data.
if (Config->EMachine == EM_MIPS)
DefinedAbsolute<ELFT>::MipsGp.st_value = getMipsGpAddr<ELFT>();

View File

@ -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

29
lld/test/ELF/end-update.s Normal file
View File

@ -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

79
lld/test/ELF/end.s Normal file
View File

@ -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

View File

@ -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: