Start adding support for creating shared libraries.
They are not fully functional yet, but this implements enough support for lld
itself to read them.
With that, delete the .so binary we were using for tests and start eating our
own dog food.
llvm-svn: 247487
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index f844980..b4faef70 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -19,6 +19,7 @@
llvm::StringRef OutputFile;
llvm::StringRef DynamicLinker;
std::string RPath;
+ bool Shared = false;
};
extern Configuration *Config;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index a2d7022..d1b6326 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -79,6 +79,9 @@
if (!RPaths.empty())
Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":");
+ if (Args.hasArg(OPT_shared))
+ Config->Shared = true;
+
// Create a list of input files.
std::vector<MemoryBufferRef> Inputs;
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 9ab0302..b3c244b 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -12,3 +12,6 @@
def rpath : Separate<["-"], "rpath">,
HelpText<"Add a DT_RUNPATH to the output">;
+
+def shared : Flag<["-"], "shared">,
+ HelpText<"Build a shared object">;
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 1d55c33..708ea54 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "SymbolTable.h"
+#include "Config.h"
#include "Error.h"
#include "Symbols.h"
@@ -32,6 +33,8 @@
}
template <class ELFT> void SymbolTable::init() {
+ if (Config->Shared)
+ return;
EntrySym = new (Alloc) Undefined<ELFT>("_start", Undefined<ELFT>::Synthetic);
resolve<ELFT>(EntrySym);
}
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index 42c49c6..9c156b5 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -55,6 +55,8 @@
}
SymbolBody *getEntrySym() const {
+ if (!EntrySym)
+ return nullptr;
return EntrySym->getReplacement();
}
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index ef7199c..6d1c94e 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -311,6 +311,10 @@
return !SymTabSec.getSymTable().getSharedFiles().empty() &&
!Config->DynamicLinker.empty();
}
+ bool needsDynamicSections() const {
+ return !SymTabSec.getSymTable().getSharedFiles().empty() || Config->Shared;
+ }
+ unsigned getVAStart() const { return Config->Shared ? 0 : VAStart; }
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
@@ -604,8 +608,6 @@
}
}
- const std::vector<std::unique_ptr<SharedFileBase>> &SharedFiles =
- Symtab.getSharedFiles();
BSSSec = getSection(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
// FIXME: Try to avoid the extra walk over all global symbols.
std::vector<DefinedCommon<ELFT> *> CommonSymbols;
@@ -624,7 +626,7 @@
// FIXME: This adds way too much to the dynamic symbol table. We only
// need to add the symbols use by dynamic relocations when producing
// an executable (ignoring --export-dynamic).
- if (!SharedFiles.empty())
+ if (needsDynamicSections())
DynSymSec.addSymbol(Name);
}
@@ -644,7 +646,7 @@
OutputSections.push_back(&SymTabSec);
OutputSections.push_back(&StrTabSec);
- if (!SharedFiles.empty()) {
+ if (needsDynamicSections()) {
if (needsInterpSection())
OutputSections.push_back(&InterpSec);
OutputSections.push_back(&DynSymSec);
@@ -666,7 +668,7 @@
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
template <class ELFT> void Writer<ELFT>::assignAddresses() {
- uintX_t VA = VAStart;
+ uintX_t VA = getVAStart();
uintX_t FileOff = 0;
FileOff += sizeof(Elf_Ehdr);
@@ -711,7 +713,7 @@
}
// Add a PHDR for the dynamic table.
- if (!SymTabSec.getSymTable().getSharedFiles().empty())
+ if (needsDynamicSections())
++NumPhdrs;
FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);
@@ -762,13 +764,13 @@
// FIXME: Generalize the segment construction similar to how we create
// output sections.
const SymbolTable &Symtab = SymTabSec.getSymTable();
- bool HasDynamicSegment = !Symtab.getSharedFiles().empty();
- EHdr->e_type = ET_EXEC;
+ EHdr->e_type = Config->Shared ? ET_DYN : ET_EXEC;
auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab.getFirstELF());
EHdr->e_machine = FirstObj.getEMachine();
EHdr->e_version = EV_CURRENT;
- EHdr->e_entry = getSymVA(cast<DefinedRegular<ELFT>>(Symtab.getEntrySym()));
+ SymbolBody *Entry = Symtab.getEntrySym();
+ EHdr->e_entry = Entry ? getSymVA(cast<DefinedRegular<ELFT>>(Entry)) : 0;
EHdr->e_phoff = ProgramHeaderOff;
EHdr->e_shoff = SectionHeaderOff;
EHdr->e_ehsize = sizeof(Elf_Ehdr);
@@ -788,7 +790,7 @@
PHdrs->p_type = PT_LOAD;
PHdrs->p_flags = PF_R;
PHdrs->p_offset = 0;
- PHdrs->p_vaddr = VAStart;
+ PHdrs->p_vaddr = getVAStart();
PHdrs->p_paddr = PHdrs->p_vaddr;
PHdrs->p_filesz = ProgramHeaderOff + NumPhdrs * sizeof(Elf_Phdr);
PHdrs->p_memsz = PHdrs->p_filesz;
@@ -809,7 +811,7 @@
++PHdrs;
}
- if (HasDynamicSegment) {
+ if (needsDynamicSections()) {
PHdrs->p_type = PT_DYNAMIC;
setValuesFromSection<ELFT>(*PHdrs, DynamicSec);
}
diff --git a/lld/test/elf2/Inputs/i686-simple-library.so b/lld/test/elf2/Inputs/i686-simple-library.so
deleted file mode 100755
index 62da498..0000000
--- a/lld/test/elf2/Inputs/i686-simple-library.so
+++ /dev/null
Binary files differ
diff --git a/lld/test/elf2/Inputs/shared.s b/lld/test/elf2/Inputs/shared.s
new file mode 100644
index 0000000..1cfebbf
--- /dev/null
+++ b/lld/test/elf2/Inputs/shared.s
@@ -0,0 +1,6 @@
+.global bar
+.type bar, @function
+bar:
+
+.global zed
+zed:
diff --git a/lld/test/elf2/incompatible.s b/lld/test/elf2/incompatible.s
index 61e89cf..46a8df1 100644
--- a/lld/test/elf2/incompatible.s
+++ b/lld/test/elf2/incompatible.s
@@ -1,5 +1,6 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %ta.o
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tb.o
+// RUN: lld -flavor gnu2 -shared %tb.o -o %ti686.so
// RUN: llvm-mc -filetype=obj -triple=arm-unknown-linux %s -o %tc.o
// RUN: not lld -flavor gnu2 %ta.o %tb.o -o %t 2>&1 | \
@@ -10,17 +11,16 @@
// RUN: FileCheck --check-prefix=B-AND-C %s
// B-AND-C: b.o is incompatible with {{.*}}c.o
-// FIMME: create the .so ourselves once we are able to
-// RUN: not lld -flavor gnu2 %ta.o %p/Inputs/i686-simple-library.so -o %t 2>&1 | \
+// RUN: not lld -flavor gnu2 %ta.o %ti686.so -o %t 2>&1 | \
// RUN: FileCheck --check-prefix=A-AND-SO %s
-// A-AND-SO: a.o is incompatible with {{.*}}/Inputs/i686-simple-library.so
+// A-AND-SO: a.o is incompatible with {{.*}}i686.so
-// RUN: not lld -flavor gnu2 %tc.o %p/Inputs/i686-simple-library.so -o %t 2>&1 | \
+// RUN: not lld -flavor gnu2 %tc.o %ti686.so -o %t 2>&1 | \
// RUN: FileCheck --check-prefix=C-AND-SO %s
-// C-AND-SO: c.o is incompatible with {{.*}}/Inputs/i686-simple-library.so
+// C-AND-SO: c.o is incompatible with {{.*}}i686.so
-// RUN: not lld -flavor gnu2 %p/Inputs/i686-simple-library.so %tc.o -o %t 2>&1 | \
+// RUN: not lld -flavor gnu2 %ti686.so %tc.o -o %t 2>&1 | \
// RUN: FileCheck --check-prefix=SO-AND-C %s
-// SO-AND-C: /Inputs/i686-simple-library.so is incompatible with {{.*}}c.o
+// SO-AND-C: i686.so is incompatible with {{.*}}c.o
// REQUIRES: x86,arm
diff --git a/lld/test/elf2/shared.s b/lld/test/elf2/shared.s
index c39941d..e0ad621 100644
--- a/lld/test/elf2/shared.s
+++ b/lld/test/elf2/shared.s
@@ -1,5 +1,7 @@
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
-// RUN: lld -flavor gnu2 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -rpath foo -rpath bar %t.o %p/Inputs/i686-simple-library.so -o %t
+// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: lld -flavor gnu2 -shared %t2.o -o %t2.so
+// RUN: lld -flavor gnu2 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -rpath foo -rpath bar %t.o %t2.so -o %t
// RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data %t | FileCheck %s
// REQUIRES: x86
@@ -144,7 +146,7 @@
// CHECK-NEXT: 0x00000005 STRTAB [[DYNSTRADDR]]
// CHECK-NEXT: 0x0000000A STRSZ
// CHECK-NEXT: 0x0000001D RUNPATH foo:bar
-// CHECK-NEXT: 0x00000001 NEEDED SharedLibrary ({{.*}}/Inputs/i686-simple-library.so)
+// CHECK-NEXT: 0x00000001 NEEDED SharedLibrary ({{.*}}2.so)
// CHECK-NEXT: 0x00000000 NULL 0x0
// CHECK-NEXT: ]