From 4340aad144dab3a60ca373584bb24d660919fa24 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 11 Sep 2015 22:42:45 +0000 Subject: [PATCH] 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 --- lld/ELF/Config.h | 1 + lld/ELF/Driver.cpp | 3 +++ lld/ELF/Options.td | 3 +++ lld/ELF/SymbolTable.cpp | 3 +++ lld/ELF/SymbolTable.h | 2 ++ lld/ELF/Writer.cpp | 24 +++++++++++--------- lld/test/elf2/Inputs/i686-simple-library.so | Bin 1204 -> 0 bytes lld/test/elf2/Inputs/shared.s | 6 +++++ lld/test/elf2/incompatible.s | 14 ++++++------ lld/test/elf2/shared.s | 6 +++-- 10 files changed, 42 insertions(+), 20 deletions(-) delete mode 100755 lld/test/elf2/Inputs/i686-simple-library.so create mode 100644 lld/test/elf2/Inputs/shared.s diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index f8449806eff1..b4faef700131 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -19,6 +19,7 @@ struct Configuration { 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 a2d7022603aa..d1b63260d303 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -79,6 +79,9 @@ void LinkerDriver::link(ArrayRef 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 Inputs; diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 9ab030242406..b3c244be6338 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -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">; diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 1d55c3331e22..708ea545d207 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 @@ void SymbolTable::addFile(std::unique_ptr File) { } template void SymbolTable::init() { + if (Config->Shared) + return; EntrySym = new (Alloc) Undefined("_start", Undefined::Synthetic); resolve(EntrySym); } diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h index 42c49c6fbbce..9c156b54f59d 100644 --- a/lld/ELF/SymbolTable.h +++ b/lld/ELF/SymbolTable.h @@ -55,6 +55,8 @@ public: } SymbolBody *getEntrySym() const { + if (!EntrySym) + return nullptr; return EntrySym->getReplacement(); } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index ef7199c919c3..6d1c94ea8f43 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -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 Buffer; llvm::SpecificBumpPtrAllocator> CAlloc; @@ -604,8 +608,6 @@ template void Writer::createSections() { } } - const std::vector> &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 *> CommonSymbols; @@ -624,7 +626,7 @@ template void Writer::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 void Writer::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 *Sec) { // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. template void Writer::assignAddresses() { - uintX_t VA = VAStart; + uintX_t VA = getVAStart(); uintX_t FileOff = 0; FileOff += sizeof(Elf_Ehdr); @@ -711,7 +713,7 @@ template void Writer::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 void Writer::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>(*Symtab.getFirstELF()); EHdr->e_machine = FirstObj.getEMachine(); EHdr->e_version = EV_CURRENT; - EHdr->e_entry = getSymVA(cast>(Symtab.getEntrySym())); + SymbolBody *Entry = Symtab.getEntrySym(); + EHdr->e_entry = Entry ? getSymVA(cast>(Entry)) : 0; EHdr->e_phoff = ProgramHeaderOff; EHdr->e_shoff = SectionHeaderOff; EHdr->e_ehsize = sizeof(Elf_Ehdr); @@ -788,7 +790,7 @@ template void Writer::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 void Writer::writeHeader() { ++PHdrs; } - if (HasDynamicSegment) { + if (needsDynamicSections()) { PHdrs->p_type = PT_DYNAMIC; setValuesFromSection(*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 62da498a238ae04cdf51f878c63151aba9d86c99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1204 zcma)*%}N|m5QS?TjY*U+5jTM>bRh&a7lycqOYUWi?}$GVzfc{l zWB)Ey;y?bp!L65;_9M?M$+NUhElGM+l~i?F)^ZgYdD;T~a#F9^7wwEk7j?hI=LBk_ zUzFgn&SimTUyu9O_1?yFyc_4o-7j`D{GKg!L$`ZF2GaYiTT?T!w$F%}Jt02sftf9c zPtNRFgReBWCGYlkw{||iy?c0}&d+NLnyH0sR8)0op%~VAI4Vv9@9^?0FRSBWaUC8F zEcDZ=A6Ys${$`=->!CXB>E`EX5P95}TDzC6NySds6Z-*&0-RAWSN1h8uxI@24J_;K zh8BAzuv>KO6Rhj*aqzU3G;lj z@}a*=w&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 c39941d2ca64..e0ad621fbefd 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: ]