Skip to content

Commit

Permalink
[ELF] Define symbols "_end" and "end" if referenced.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Igor Kudrin committed Nov 20, 2015
1 parent dcb5653 commit b044af5
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 5 deletions.
1 change: 1 addition & 0 deletions lld/ELF/Symbols.cpp
Expand Up @@ -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);
Expand Down
12 changes: 10 additions & 2 deletions lld/ELF/Symbols.h
Expand Up @@ -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)
Expand All @@ -193,6 +198,9 @@ template <class ELFT> class DefinedAbsolute : public Defined<ELFT> {
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;

Expand Down
21 changes: 21 additions & 0 deletions lld/ELF/Writer.cpp
Expand Up @@ -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()) {
Expand Down Expand Up @@ -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>();
Expand Down
16 changes: 16 additions & 0 deletions lld/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
29 changes: 29 additions & 0 deletions lld/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
79 changes: 79 additions & 0 deletions lld/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
6 changes: 3 additions & 3 deletions lld/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
Expand All @@ -13,5 +13,5 @@
# HEX: Entry: 0xCAFE
# OCT: Entry: 0x1FF

.globl _end
_end:
.globl entry
entry:

0 comments on commit b044af5

Please sign in to comment.