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
This commit is contained in:
Rafael Espindola 2015-09-11 22:42:45 +00:00
parent 535ff80354
commit 4340aad144
10 changed files with 42 additions and 20 deletions

View File

@ -19,6 +19,7 @@ struct Configuration {
llvm::StringRef OutputFile;
llvm::StringRef DynamicLinker;
std::string RPath;
bool Shared = false;
};
extern Configuration *Config;

View File

@ -79,6 +79,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
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;

View File

@ -12,3 +12,6 @@ def dynamic_linker : Separate<["-"], "dynamic-linker">,
def rpath : Separate<["-"], "rpath">,
HelpText<"Add a DT_RUNPATH to the output">;
def shared : Flag<["-"], "shared">,
HelpText<"Build a shared object">;

View File

@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "SymbolTable.h"
#include "Config.h"
#include "Error.h"
#include "Symbols.h"
@ -32,6 +33,8 @@ void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
}
template <class ELFT> void SymbolTable::init() {
if (Config->Shared)
return;
EntrySym = new (Alloc) Undefined<ELFT>("_start", Undefined<ELFT>::Synthetic);
resolve<ELFT>(EntrySym);
}

View File

@ -55,6 +55,8 @@ public:
}
SymbolBody *getEntrySym() const {
if (!EntrySym)
return nullptr;
return EntrySym->getReplacement();
}

View File

@ -311,6 +311,10 @@ private:
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 @@ template <class ELFT> void Writer<ELFT>::createSections() {
}
}
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 @@ template <class ELFT> void Writer<ELFT>::createSections() {
// 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 @@ template <class ELFT> void Writer<ELFT>::createSections() {
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 @@ static bool outputSectionHasPHDR(OutputSectionBase<ELFT::Is64Bits> *Sec) {
// 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 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
}
// 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 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
// 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 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
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 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
++PHdrs;
}
if (HasDynamicSegment) {
if (needsDynamicSections()) {
PHdrs->p_type = PT_DYNAMIC;
setValuesFromSection<ELFT>(*PHdrs, DynamicSec);
}

View File

@ -0,0 +1,6 @@
.global bar
.type bar, @function
bar:
.global zed
zed:

View File

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

View File

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