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 62da498a238a..000000000000 Binary files a/lld/test/elf2/Inputs/i686-simple-library.so and /dev/null differ diff --git a/lld/test/elf2/Inputs/shared.s b/lld/test/elf2/Inputs/shared.s new file mode 100644 index 000000000000..1cfebbfaf373 --- /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 61e89cf514a0..46a8df1433af 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 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: ]