[ELF] - -pie/--pic-executable option implemented

-pie
--pic-executable

Create a position independent executable.  This is currently only
 supported on ELF platforms.  Position independent executables are
 similar to shared libraries in that they are relocated by the
 dynamic linker to the virtual address the OS chooses for them
 (which can vary between invocations).  Like normal dynamically
 linked executables they can be executed and symbols defined in the
 executable cannot be overridden by shared libraries.

Differential revision: http://reviews.llvm.org/D18183

llvm-svn: 263693
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index f1a90f2..b75a599 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -68,6 +68,8 @@
   bool Mips64EL = false;
   bool NoUndefined;
   bool NoinhibitExec;
+  bool Pic;
+  bool Pie;
   bool PrintGcSections;
   bool Rela;
   bool Relocatable;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index fa12154..eff2e8d 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -144,6 +144,9 @@
   if (Config->EMachine == EM_AMDGPU && !Config->Entry.empty())
     error("-e option is not valid for AMDGPU.");
 
+  if (Config->Pie && Config->Shared)
+    error("-shared and -pie may not be used together");
+
   if (!Config->Relocatable)
     return;
 
@@ -153,6 +156,8 @@
     error("-r and --gc-sections may not be used together");
   if (Config->ICF)
     error("-r and --icf may not be used together");
+  if (Config->Pie)
+    error("-r and -pie may not be used together");
 }
 
 static StringRef
@@ -238,6 +243,7 @@
   Config->ICF = Args.hasArg(OPT_icf);
   Config->NoUndefined = Args.hasArg(OPT_no_undefined);
   Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);
+  Config->Pie = Args.hasArg(OPT_pie);
   Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
   Config->Relocatable = Args.hasArg(OPT_relocatable);
   Config->SaveTemps = Args.hasArg(OPT_save_temps);
@@ -261,6 +267,8 @@
   Config->ZOrigin = hasZOption(Args, "origin");
   Config->ZRelro = !hasZOption(Args, "norelro");
 
+  Config->Pic = Config->Pie || Config->Shared;
+
   if (Config->Relocatable)
     Config->StripAll = false;
 
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 741013f..1eb0643 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -97,6 +97,9 @@
 def o : JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
   HelpText<"Path to file to write output">;
 
+def pie : Flag<["-"], "pie">,
+  HelpText<"Create a position independent executable">;
+
 def print_gc_sections: Flag<["--"], "print-gc-sections">,
   HelpText<"List removed unused sections">;
 
@@ -159,6 +162,7 @@
 def alias_init_init : Joined<["-"], "init=">, Alias<init>;
 def alias_l__library : Joined<["--"], "library=">, Alias<l>;
 def alias_o_output : Joined<["--"], "output=">, Alias<o>;
+def alias_pie_pic_executable: Flag<["--"], "pic-executable">, Alias<pie>;
 def alias_rpath_rpath : Joined<["-"], "rpath=">, Alias<rpath>;
 def alias_relocatable_r : Flag<["-"], "r">, Alias<relocatable>;
 def alias_shared_Bshareable : Flag<["-"], "Bshareable">, Alias<shared>;
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index b66882a..a1ec843 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -122,7 +122,7 @@
     fatal("target not found: " + ErrMsg);
 
   TargetOptions Options;
-  Reloc::Model R = Config->Shared ? Reloc::PIC_ : Reloc::Static;
+  Reloc::Model R = Config->Pic ? Reloc::PIC_ : Reloc::Static;
   std::unique_ptr<TargetMachine> TM(
       TheTarget->createTargetMachine(TripleStr, "", "", Options, R));
 
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index dae9f51..e76e0a9 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -270,7 +270,7 @@
   return false;
 }
 
-uint64_t TargetInfo::getVAStart() const { return Config->Shared ? 0 : VAStart; }
+uint64_t TargetInfo::getVAStart() const { return Config->Pic ? 0 : VAStart; }
 
 bool TargetInfo::needsCopyRelImpl(uint32_t Type) const { return false; }
 
@@ -329,7 +329,7 @@
   // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
   // R_386_JMP_SLOT, etc).
   if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(&S))
-    if (!Config->Shared && SS->Sym.getType() == STT_FUNC &&
+    if (!Config->Pic && SS->Sym.getType() == STT_FUNC &&
         !refersToGotEntry(Type))
       return Plt_Implicit;
 
@@ -439,7 +439,7 @@
 void X86TargetInfo::writePltZero(uint8_t *Buf) const {
   // Executable files and shared object files have
   // separate procedure linkage tables.
-  if (Config->Shared) {
+  if (Config->Pic) {
     const uint8_t V[] = {
         0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
         0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp   *8(%ebx)
@@ -471,7 +471,7 @@
   memcpy(Buf, Inst, sizeof(Inst));
 
   // jmp *foo@GOT(%ebx) or jmp *foo_in_GOT
-  Buf[1] = Config->Shared ? 0xa3 : 0x25;
+  Buf[1] = Config->Pic ? 0xa3 : 0x25;
   uint32_t Got = UseLazyBinding ? Out<ELF32LE>::GotPlt->getVA()
                                 : Out<ELF32LE>::Got->getVA();
   write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index a8b1f9b..377eed4 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -82,7 +82,7 @@
     return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty();
   }
   bool isOutputDynamic() const {
-    return !Symtab.getSharedFiles().empty() || Config->Shared;
+    return !Symtab.getSharedFiles().empty() || Config->Pic;
   }
 
   void ensureBss();
@@ -417,7 +417,7 @@
         continue;
       }
 
-      bool Dynrel = Config->Shared && !Target->isRelRelative(Type) &&
+      bool Dynrel = Config->Pic && !Target->isRelRelative(Type) &&
                     !Target->isSizeRel(Type);
       if (Preemptible || Dynrel) {
         uint32_t DynType;
@@ -466,8 +466,7 @@
     // We can however do better than just copying the incoming relocation. We
     // can process some of it and and just ask the dynamic linker to add the
     // load address.
-    if (!Config->Shared || Target->isRelRelative(Type) ||
-        Target->isSizeRel(Type))
+    if (!Config->Pic || Target->isRelRelative(Type) || Target->isSizeRel(Type))
       continue;
 
     uintX_t Addend = getAddend<ELFT>(RI);
@@ -1439,7 +1438,7 @@
 }
 
 static uint16_t getELFType() {
-  if (Config->Shared)
+  if (Config->Pic)
     return ET_DYN;
   if (Config->Relocatable)
     return ET_REL;
diff --git a/lld/test/ELF/driver.test b/lld/test/ELF/driver.test
index cf6601a..1b0552c 100644
--- a/lld/test/ELF/driver.test
+++ b/lld/test/ELF/driver.test
@@ -37,6 +37,14 @@
 # RUN: not ld.lld -r --icf=all %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR4 %s
 # ERR4: -r and --icf may not be used together
 
+## Attempt to use -r and -pie together
+# RUN: not ld.lld -r -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR5 %s
+# ERR5: -r and -pie may not be used together
+
+## Attempt to use -shared and -pie together
+# RUN: not ld.lld -shared -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR6 %s
+# ERR6: -shared and -pie may not be used together
+
 .globl _start
 _start:
   nop
diff --git a/lld/test/ELF/dynsym-pie.s b/lld/test/ELF/dynsym-pie.s
new file mode 100644
index 0000000..9d3a9ff
--- /dev/null
+++ b/lld/test/ELF/dynsym-pie.s
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+# RUN: ld.lld -pie %t -o %t.out
+# RUN: llvm-readobj -t -dyn-symbols %t.out | FileCheck %s
+
+# CHECK:      DynamicSymbols [
+# 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: ]
+
+.text
+.globl _start
+_start:
+
+.global default
+default:
+
+.global protected
+protected:
+
+.global hidden
+hidden:
+
+.global internal
+internal:
+
+.global protected_with_hidden
+.protected
+protected_with_hidden:
diff --git a/lld/test/ELF/local-got-pie.s b/lld/test/ELF/local-got-pie.s
new file mode 100644
index 0000000..e846bd4
--- /dev/null
+++ b/lld/test/ELF/local-got-pie.s
@@ -0,0 +1,36 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t -pie
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+.globl _start
+_start:
+ call foo@gotpcrel
+
+ .hidden foo
+ .global foo
+foo:
+ nop
+
+// 0x20A0 - 1001 - 5 = 4250
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+// DISASM-NEXT:   1000: {{.*}} callq 4251
+// DISASM:      foo:
+// DISASM-NEXT:   1005: {{.*}} nop
+
+// CHECK:      Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x20A0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 8
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x20A0 R_X86_64_RELATIVE - 0x1005
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
diff --git a/lld/test/ELF/noplt-pie.s b/lld/test/ELF/noplt-pie.s
new file mode 100644
index 0000000..1eb8493
--- /dev/null
+++ b/lld/test/ELF/noplt-pie.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -o %t2.so
+# RUN: ld.lld %t1.o %t2.so -o %t.out
+# RUN: llvm-readobj -s -r %t.out | FileCheck %s
+
+# CHECK: Section {
+# CHECK-NOT: Name: .plt
+
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     0x120B0 R_X86_64_GLOB_DAT bar 0x0
+# CHECK-NEXT:     0x120B8 R_X86_64_GLOB_DAT zed 0x0
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.global _start
+_start:
+ movq bar@GOTPCREL(%rip), %rcx
+ movq zed@GOTPCREL(%rip), %rcx
diff --git a/lld/test/ELF/pie.s b/lld/test/ELF/pie.s
new file mode 100644
index 0000000..4cf1743
--- /dev/null
+++ b/lld/test/ELF/pie.s
@@ -0,0 +1,102 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld -pie %t1.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+
+## Test --pic-executable alias
+# RUN: ld.lld --pic-executable %t1.o -o %t
+# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+
+# CHECK:      ElfHeader {
+# CHECK-NEXT:  Ident {
+# CHECK-NEXT:    Magic: (7F 45 4C 46)
+# CHECK-NEXT:    Class: 64-bit
+# CHECK-NEXT:    DataEncoding: LittleEndian
+# CHECK-NEXT:    FileVersion: 1
+# CHECK-NEXT:    OS/ABI: SystemV
+# CHECK-NEXT:    ABIVersion: 0
+# CHECK-NEXT:    Unused: (00 00 00 00 00 00 00)
+# CHECK-NEXT:  }
+# CHECK-NEXT:  Type: SharedObject
+# CHECK-NEXT:  Machine: EM_X86_64
+# CHECK-NEXT:  Version: 1
+# CHECK-NEXT:  Entry: 0x1000
+# CHECK-NEXT:  ProgramHeaderOffset: 0x40
+# CHECK-NEXT:  SectionHeaderOffset: 0x1110
+# CHECK-NEXT:  Flags [
+# CHECK-NEXT:  ]
+# CHECK-NEXT:  HeaderSize: 64
+# CHECK-NEXT:  ProgramHeaderEntrySize: 56
+# CHECK-NEXT:  ProgramHeaderCount: 7
+# CHECK-NEXT:  SectionHeaderEntrySize: 64
+# CHECK-NEXT:  SectionHeaderCount: 9
+# CHECK-NEXT:  StringTableSectionIndex: 7
+# CHECK-NEXT: }
+
+# CHECK:      ProgramHeaders [
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_PHDR
+# CHECK-NEXT:    Offset: 0x40
+# CHECK-NEXT:    VirtualAddress: 0x40
+# CHECK-NEXT:    PhysicalAddress: 0x40
+# CHECK-NEXT:    FileSize: 392
+# CHECK-NEXT:    MemSize: 392
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 8
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD
+# CHECK-NEXT:    Offset: 0x0
+# CHECK-NEXT:    VirtualAddress: 0x0
+# CHECK-NEXT:    PhysicalAddress: 0x0
+# CHECK-NEXT:    FileSize: 497
+# CHECK-NEXT:    MemSize: 497
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 4096
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD
+# CHECK-NEXT:    Offset: 0x1000
+# CHECK-NEXT:    VirtualAddress: 0x1000
+# CHECK-NEXT:    PhysicalAddress: 0x1000
+# CHECK-NEXT:    FileSize: 0
+# CHECK-NEXT:    MemSize: 0
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:      PF_X
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 4096
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_LOAD
+# CHECK-NEXT:    Offset: 0x1000
+# CHECK-NEXT:    VirtualAddress: 0x1000
+# CHECK-NEXT:    PhysicalAddress: 0x1000
+# CHECK-NEXT:    FileSize: 112
+# CHECK-NEXT:    MemSize: 112
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:      PF_W
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 4096
+# CHECK-NEXT:  }
+# CHECK-NEXT:  ProgramHeader {
+# CHECK-NEXT:    Type: PT_DYNAMIC
+# CHECK-NEXT:    Offset: 0x1000
+# CHECK-NEXT:    VirtualAddress: 0x1000
+# CHECK-NEXT:    PhysicalAddress: 0x1000
+# CHECK-NEXT:    FileSize: 112
+# CHECK-NEXT:    MemSize: 112
+# CHECK-NEXT:    Flags [
+# CHECK-NEXT:      PF_R
+# CHECK-NEXT:      PF_W
+# CHECK-NEXT:    ]
+# CHECK-NEXT:    Alignment: 8
+# CHECK-NEXT:  }
+
+.globl _start
+_start:
diff --git a/lld/test/ELF/plt-i686.s b/lld/test/ELF/plt-i686.s
index 4947e0e..bdb8818 100644
--- a/lld/test/ELF/plt-i686.s
+++ b/lld/test/ELF/plt-i686.s
@@ -7,7 +7,8 @@
 // RUN: ld.lld -shared %t.o %t2.so -o %t
 // RUN: llvm-readobj -s -r %t | FileCheck --check-prefix=CHECKSHARED %s
 // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMSHARED %s
-
+// RUN: ld.lld -pie %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMPIE %s
 // REQUIRES: x86
 
 // CHECK:      Name: .plt
@@ -147,6 +148,21 @@
 // DISASMSHARED-NEXT:  1046: 68 08 00 00 00     pushl $8
 // DISASMSHARED-NEXT:  104b: e9 d0 ff ff ff     jmp -48 <.plt>
 
+// DISASMPIE:      Disassembly of section .plt:
+// DISASMPIE-NEXT: .plt:
+// DISASMPIE-NEXT:   1020:	ff b3 04 00 00 00 pushl 4(%ebx)
+// DISASMPIE-NEXT:   1026:	ff a3 08 00 00 00 jmpl *8(%ebx)
+// DISASMPIE-NEXT:   102c:	90 nop
+// DISASMPIE-NEXT:   102d:	90 nop
+// DISASMPIE-NEXT:   102e:	90 nop
+// DISASMPIE-NEXT:   102f:	90 nop
+// DISASMPIE-NEXT:   1030:	ff a3 0c 30 00 00 jmpl *12300(%ebx)
+// DISASMPIE-NEXT:   1036:	68 00 00 00 00 pushl $0
+// DISASMPIE-NEXT:   103b:	e9 e0 ff ff ff jmp -32 <.plt>
+// DISASMPIE-NEXT:   1040:	ff a3 10 30 00 00 jmpl *12304(%ebx)
+// DISASMPIE-NEXT:   1046:	68 08 00 00 00 pushl $8
+// DISASMPIE-NEXT:   104b:	e9 d0 ff ff ff jmp -48 <.plt>
+
 local:
 .long 0
 
diff --git a/lld/test/ELF/relative-dynamic-reloc-pie.s b/lld/test/ELF/relative-dynamic-reloc-pie.s
new file mode 100644
index 0000000..1c3c6ab
--- /dev/null
+++ b/lld/test/ELF/relative-dynamic-reloc-pie.s
@@ -0,0 +1,25 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %t.pie
+# RUN: llvm-readobj -r -dyn-symbols %t.pie | FileCheck %s
+
+## Test that we create R_X86_64_RELATIVE relocations with -pie.
+# CHECK:      Relocations [
+# CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:     0x1001 R_X86_64_RELATIVE - 0x1001
+# CHECK-NEXT:     0x1009 R_X86_64_RELATIVE - 0x1009
+# CHECK-NEXT:     0x1011 R_X86_64_RELATIVE - 0x100A
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+.globl _start
+_start:
+nop
+
+foo:
+ .quad foo
+
+.hidden bar
+.global bar
+bar:
+ .quad bar
+ .quad bar + 1
diff --git a/lld/test/ELF/undef.s b/lld/test/ELF/undef.s
index 52dabf1..e0705a5 100644
--- a/lld/test/ELF/undef.s
+++ b/lld/test/ELF/undef.s
@@ -1,5 +1,6 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
 # RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s
+# RUN: not ld.lld -pie %t -o %t2 2>&1 | FileCheck %s
 # CHECK: undefined symbol: bar in {{.*}}
 # CHECK: undefined symbol: foo in {{.*}}
 # REQUIRES: x86