diff options
Diffstat (limited to 'ELF/Driver.cpp')
| -rw-r--r-- | ELF/Driver.cpp | 553 | 
1 files changed, 402 insertions, 151 deletions
| diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index c6ca2639236f..a11dbc7cc47f 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -14,14 +14,17 @@  #include "InputFiles.h"  #include "InputSection.h"  #include "LinkerScript.h" +#include "Memory.h"  #include "Strings.h" -#include "SymbolListFile.h"  #include "SymbolTable.h"  #include "Target.h" +#include "Threads.h"  #include "Writer.h" +#include "lld/Config/Version.h"  #include "lld/Driver/Driver.h"  #include "llvm/ADT/StringExtras.h"  #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/CommandLine.h"  #include "llvm/Support/TargetSelect.h"  #include "llvm/Support/raw_ostream.h"  #include <cstdlib> @@ -38,48 +41,59 @@ using namespace lld::elf;  Configuration *elf::Config;  LinkerDriver *elf::Driver; -bool elf::link(ArrayRef<const char *> Args, raw_ostream &Error) { -  HasError = false; +BumpPtrAllocator elf::BAlloc; +StringSaver elf::Saver{BAlloc}; +std::vector<SpecificAllocBase *> elf::SpecificAllocBase::Instances; + +bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, +               raw_ostream &Error) { +  ErrorCount = 0;    ErrorOS = &Error; +  Argv0 = Args[0]; -  Configuration C; -  LinkerDriver D; -  ScriptConfiguration SC; -  Config = &C; -  Driver = &D; -  ScriptConfig = &SC; +  Config = make<Configuration>(); +  Driver = make<LinkerDriver>(); +  ScriptConfig = make<ScriptConfiguration>(); -  Driver->main(Args); -  return !HasError; +  Driver->main(Args, CanExitEarly); +  freeArena(); +  return !ErrorCount;  }  // Parses a linker -m option. -static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) { -  if (S.endswith("_fbsd")) +static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { +  uint8_t OSABI = 0; +  StringRef S = Emul; +  if (S.endswith("_fbsd")) {      S = S.drop_back(5); +    OSABI = ELFOSABI_FREEBSD; +  }    std::pair<ELFKind, uint16_t> Ret =        StringSwitch<std::pair<ELFKind, uint16_t>>(S) -          .Case("aarch64linux", {ELF64LEKind, EM_AARCH64}) +          .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})            .Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM})            .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})            .Case("elf32btsmip", {ELF32BEKind, EM_MIPS})            .Case("elf32ltsmip", {ELF32LEKind, EM_MIPS}) +          .Case("elf32btsmipn32", {ELF32BEKind, EM_MIPS}) +          .Case("elf32ltsmipn32", {ELF32LEKind, EM_MIPS})            .Case("elf32ppc", {ELF32BEKind, EM_PPC})            .Case("elf64btsmip", {ELF64BEKind, EM_MIPS})            .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})            .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) +          .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})            .Case("elf_i386", {ELF32LEKind, EM_386}) -          .Case("elf_x86_64", {ELF64LEKind, EM_X86_64}) +          .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU})            .Default({ELFNoneKind, EM_NONE});    if (Ret.first == ELFNoneKind) {      if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") -      error("Windows targets are not supported on the ELF frontend: " + S); +      error("Windows targets are not supported on the ELF frontend: " + Emul);      else -      error("unknown emulation: " + S); +      error("unknown emulation: " + Emul);    } -  return Ret; +  return std::make_tuple(Ret.first, Ret.second, OSABI);  }  // Returns slices of MB by parsing MB as an archive file. @@ -87,25 +101,28 @@ static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) {  std::vector<MemoryBufferRef>  LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {    std::unique_ptr<Archive> File = -      check(Archive::create(MB), "failed to parse archive"); +      check(Archive::create(MB), +            MB.getBufferIdentifier() + ": failed to parse archive");    std::vector<MemoryBufferRef> V; -  Error Err; +  Error Err = Error::success();    for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { -    Archive::Child C = check(COrErr, "could not get the child of the archive " + -                                         File->getFileName()); +    Archive::Child C = +        check(COrErr, MB.getBufferIdentifier() + +                          ": could not get the child of the archive");      MemoryBufferRef MBRef =          check(C.getMemoryBufferRef(), -              "could not get the buffer for a child of the archive " + -                  File->getFileName()); +              MB.getBufferIdentifier() + +                  ": could not get the buffer for a child of the archive");      V.push_back(MBRef);    }    if (Err) -    Error(Err); +    fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + +          toString(std::move(Err)));    // Take ownership of memory buffers created for members of thin archives.    for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers()) -    OwningMBs.push_back(std::move(MB)); +    make<std::unique_ptr<MemoryBuffer>>(std::move(MB));    return V;  } @@ -114,25 +131,28 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {  // Newly created memory buffers are owned by this driver.  void LinkerDriver::addFile(StringRef Path) {    using namespace sys::fs; -  if (Config->Verbose) -    outs() << Path << "\n";    Optional<MemoryBufferRef> Buffer = readFile(Path);    if (!Buffer.hasValue())      return;    MemoryBufferRef MBRef = *Buffer; +  if (InBinary) { +    Files.push_back(make<BinaryFile>(MBRef)); +    return; +  } +    switch (identify_magic(MBRef.getBuffer())) {    case file_magic::unknown:      readLinkerScript(MBRef);      return;    case file_magic::archive: -    if (WholeArchive) { +    if (InWholeArchive) {        for (MemoryBufferRef MB : getArchiveMembers(MBRef))          Files.push_back(createObjectFile(MB, Path));        return;      } -    Files.push_back(make_unique<ArchiveFile>(MBRef)); +    Files.push_back(make<ArchiveFile>(MBRef));      return;    case file_magic::elf_shared_object:      if (Config->Relocatable) { @@ -143,13 +163,16 @@ void LinkerDriver::addFile(StringRef Path) {      return;    default:      if (InLib) -      Files.push_back(make_unique<LazyObjectFile>(MBRef)); +      Files.push_back(make<LazyObjectFile>(MBRef));      else        Files.push_back(createObjectFile(MBRef));    }  }  Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) { +  if (Config->Verbose) +    outs() << Path << "\n"; +    auto MBOrErr = MemoryBuffer::getFile(Path);    if (auto EC = MBOrErr.getError()) {      error(EC, "cannot open " + Path); @@ -157,7 +180,7 @@ Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) {    }    std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;    MemoryBufferRef MBRef = MB->getMemBufferRef(); -  OwningMBs.push_back(std::move(MB)); // take MB ownership +  make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership    if (Cpio)      Cpio->append(relativeToRoot(Path), MBRef.getBuffer()); @@ -167,11 +190,10 @@ Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) {  // Add a given library by searching it from input search paths.  void LinkerDriver::addLibrary(StringRef Name) { -  std::string Path = searchLibrary(Name); -  if (Path.empty()) -    error("unable to find library -l" + Name); +  if (Optional<std::string> Path = searchLibrary(Name)) +    addFile(*Path);    else -    addFile(Path); +    error("unable to find library -l" + Name);  }  // This function is called on startup. We need this for LTO since @@ -184,12 +206,6 @@ static void initLLVM(opt::InputArgList &Args) {    InitializeAllAsmPrinters();    InitializeAllAsmParsers(); -  // This is a flag to discard all but GlobalValue names. -  // We want to enable it by default because it saves memory. -  // Disable it only when a developer option (-save-temps) is given. -  Driver->Context.setDiscardValueNames(!Config->SaveTemps); -  Driver->Context.enableDebugTypeODRUniquing(); -    // Parse and evaluate -mllvm options.    std::vector<const char *> V;    V.push_back("lld (LLVM option parsing)"); @@ -206,9 +222,6 @@ static void checkOptions(opt::InputArgList &Args) {    if (Config->EMachine == EM_MIPS && Config->GnuHash)      error("the .gnu.hash section is not compatible with the MIPS target."); -  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"); @@ -224,8 +237,8 @@ static void checkOptions(opt::InputArgList &Args) {    }  } -static StringRef -getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") { +static StringRef getString(opt::InputArgList &Args, unsigned Key, +                           StringRef Default = "") {    if (auto *Arg = Args.getLastArg(Key))      return Arg->getValue();    return Default; @@ -254,33 +267,64 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) {    return false;  } -void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { +static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key, +                                uint64_t Default) { +  for (auto *Arg : Args.filtered(OPT_z)) { +    StringRef Value = Arg->getValue(); +    size_t Pos = Value.find("="); +    if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) { +      Value = Value.substr(Pos + 1); +      uint64_t Result; +      if (Value.getAsInteger(0, Result)) +        error("invalid " + Key + ": " + Value); +      return Result; +    } +  } +  return Default; +} + +void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {    ELFOptTable Parser;    opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); + +  // Interpret this flag early because error() depends on them. +  Config->ErrorLimit = getInteger(Args, OPT_error_limit, 20); + +  // Handle -help    if (Args.hasArg(OPT_help)) {      printHelp(ArgsArr[0]);      return;    } -  if (Args.hasArg(OPT_version)) { -    outs() << getVersionString(); + +  // GNU linkers disagree here. Though both -version and -v are mentioned +  // in help to print the version information, GNU ld just normally exits, +  // while gold can continue linking. We are compatible with ld.bfd here. +  if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) +    outs() << getLLDVersion() << "\n"; +  if (Args.hasArg(OPT_version))      return; -  } + +  Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown);    if (const char *Path = getReproduceOption(Args)) {      // Note that --reproduce is a debug option so you can ignore it      // if you are trying to understand the whole picture of the code. -    Cpio.reset(CpioFile::create(Path)); -    if (Cpio) { +    ErrorOr<CpioFile *> F = CpioFile::create(Path); +    if (F) { +      Cpio.reset(*F);        Cpio->append("response.txt", createResponseFile(Args)); -      Cpio->append("version.txt", getVersionString()); -    } +      Cpio->append("version.txt", getLLDVersion() + "\n"); +    } else +      error(F.getError(), +            Twine("--reproduce: failed to open ") + Path + ".cpio");    }    readConfigs(Args);    initLLVM(Args);    createFiles(Args); +  inferMachineType();    checkOptions(Args); -  if (HasError) +  if (ErrorCount)      return;    switch (Config->EKind) { @@ -297,7 +341,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {      link<ELF64BE>(Args);      return;    default: -    error("-m or at least a .o file required"); +    llvm_unreachable("unknown Config->EKind");    }  } @@ -314,10 +358,115 @@ static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) {      if (S == "ignore-all" || S == "ignore-in-object-files")        return UnresolvedPolicy::Ignore;      if (S == "ignore-in-shared-libs" || S == "report-all") -      return UnresolvedPolicy::Error; +      return UnresolvedPolicy::ReportError;      error("unknown --unresolved-symbols value: " + S);    } -  return UnresolvedPolicy::Error; +  return UnresolvedPolicy::ReportError; +} + +static Target2Policy getTarget2Option(opt::InputArgList &Args) { +  if (auto *Arg = Args.getLastArg(OPT_target2)) { +    StringRef S = Arg->getValue(); +    if (S == "rel") +      return Target2Policy::Rel; +    if (S == "abs") +      return Target2Policy::Abs; +    if (S == "got-rel") +      return Target2Policy::GotRel; +    error("unknown --target2 option: " + S); +  } +  return Target2Policy::GotRel; +} + +static bool isOutputFormatBinary(opt::InputArgList &Args) { +  if (auto *Arg = Args.getLastArg(OPT_oformat)) { +    StringRef S = Arg->getValue(); +    if (S == "binary") +      return true; +    error("unknown --oformat value: " + S); +  } +  return false; +} + +static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2, +                   bool Default) { +  if (auto *Arg = Args.getLastArg(K1, K2)) +    return Arg->getOption().getID() == K1; +  return Default; +} + +static DiscardPolicy getDiscardOption(opt::InputArgList &Args) { +  if (Config->Relocatable) +    return DiscardPolicy::None; +  auto *Arg = +      Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none); +  if (!Arg) +    return DiscardPolicy::Default; +  if (Arg->getOption().getID() == OPT_discard_all) +    return DiscardPolicy::All; +  if (Arg->getOption().getID() == OPT_discard_locals) +    return DiscardPolicy::Locals; +  return DiscardPolicy::None; +} + +static StripPolicy getStripOption(opt::InputArgList &Args) { +  if (auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug)) { +    if (Arg->getOption().getID() == OPT_strip_all) +      return StripPolicy::All; +    return StripPolicy::Debug; +  } +  return StripPolicy::None; +} + +static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) { +  uint64_t VA = 0; +  if (S.startswith("0x")) +    S = S.drop_front(2); +  if (S.getAsInteger(16, VA)) +    error("invalid argument: " + stringize(Arg)); +  return VA; +} + +static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) { +  StringMap<uint64_t> Ret; +  for (auto *Arg : Args.filtered(OPT_section_start)) { +    StringRef Name; +    StringRef Addr; +    std::tie(Name, Addr) = StringRef(Arg->getValue()).split('='); +    Ret[Name] = parseSectionAddress(Addr, Arg); +  } + +  if (auto *Arg = Args.getLastArg(OPT_Ttext)) +    Ret[".text"] = parseSectionAddress(Arg->getValue(), Arg); +  if (auto *Arg = Args.getLastArg(OPT_Tdata)) +    Ret[".data"] = parseSectionAddress(Arg->getValue(), Arg); +  if (auto *Arg = Args.getLastArg(OPT_Tbss)) +    Ret[".bss"] = parseSectionAddress(Arg->getValue(), Arg); +  return Ret; +} + +static SortSectionPolicy getSortKind(opt::InputArgList &Args) { +  StringRef S = getString(Args, OPT_sort_section); +  if (S == "alignment") +    return SortSectionPolicy::Alignment; +  if (S == "name") +    return SortSectionPolicy::Name; +  if (!S.empty()) +    error("unknown --sort-section rule: " + S); +  return SortSectionPolicy::Default; +} + +static std::vector<StringRef> getLines(MemoryBufferRef MB) { +  SmallVector<StringRef, 0> Arr; +  MB.getBuffer().split(Arr, '\n'); + +  std::vector<StringRef> Ret; +  for (StringRef S : Arr) { +    S = S.trim(); +    if (!S.empty()) +      Ret.push_back(S); +  } +  return Ret;  }  // Initializes Config members by the command line options. @@ -334,34 +483,37 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {    if (auto *Arg = Args.getLastArg(OPT_m)) {      // Parse ELF{32,64}{LE,BE} and CPU type.      StringRef S = Arg->getValue(); -    std::tie(Config->EKind, Config->EMachine) = parseEmulation(S); +    std::tie(Config->EKind, Config->EMachine, Config->OSABI) = +        parseEmulation(S); +    Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");      Config->Emulation = S;    }    Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);    Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);    Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); -  Config->Demangle = !Args.hasArg(OPT_no_demangle); +  Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);    Config->DisableVerify = Args.hasArg(OPT_disable_verify); -  Config->DiscardAll = Args.hasArg(OPT_discard_all); -  Config->DiscardLocals = Args.hasArg(OPT_discard_locals); -  Config->DiscardNone = Args.hasArg(OPT_discard_none);    Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);    Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);    Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);    Config->FatalWarnings = Args.hasArg(OPT_fatal_warnings); -  Config->GcSections = Args.hasArg(OPT_gc_sections); +  Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false); +  Config->GdbIndex = Args.hasArg(OPT_gdb_index);    Config->ICF = Args.hasArg(OPT_icf);    Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);    Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version); -  Config->Pie = Args.hasArg(OPT_pie); +  Config->Nostdlib = Args.hasArg(OPT_nostdlib); +  Config->OMagic = Args.hasArg(OPT_omagic); +  Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false);    Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);    Config->Relocatable = Args.hasArg(OPT_relocatable); +  Config->Discard = getDiscardOption(Args);    Config->SaveTemps = Args.hasArg(OPT_save_temps); +  Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);    Config->Shared = Args.hasArg(OPT_shared); -  Config->StripAll = Args.hasArg(OPT_strip_all); -  Config->StripDebug = Args.hasArg(OPT_strip_debug); -  Config->Threads = Args.hasArg(OPT_threads); +  Config->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false); +  Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true);    Config->Trace = Args.hasArg(OPT_trace);    Config->Verbose = Args.hasArg(OPT_verbose);    Config->WarnCommon = Args.hasArg(OPT_warn_common); @@ -370,33 +522,47 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {    Config->Entry = getString(Args, OPT_entry);    Config->Fini = getString(Args, OPT_fini, "_fini");    Config->Init = getString(Args, OPT_init, "_init"); -  Config->LtoAAPipeline = getString(Args, OPT_lto_aa_pipeline); -  Config->LtoNewPmPasses = getString(Args, OPT_lto_newpm_passes); +  Config->LTOAAPipeline = getString(Args, OPT_lto_aa_pipeline); +  Config->LTONewPmPasses = getString(Args, OPT_lto_newpm_passes);    Config->OutputFile = getString(Args, OPT_o);    Config->SoName = getString(Args, OPT_soname);    Config->Sysroot = getString(Args, OPT_sysroot);    Config->Optimize = getInteger(Args, OPT_O, 1); -  Config->LtoO = getInteger(Args, OPT_lto_O, 2); -  if (Config->LtoO > 3) +  Config->LTOO = getInteger(Args, OPT_lto_O, 2); +  if (Config->LTOO > 3)      error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O)); -  Config->LtoJobs = getInteger(Args, OPT_lto_jobs, 1); -  if (Config->LtoJobs == 0) -    error("number of threads must be > 0"); +  Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1); +  if (Config->LTOPartitions == 0) +    error("--lto-partitions: number of threads must be > 0"); +  Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u); +  if (Config->ThinLTOJobs == 0) +    error("--thinlto-jobs: number of threads must be > 0");    Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); -  Config->ZExecStack = hasZOption(Args, "execstack"); +  Config->ZExecstack = hasZOption(Args, "execstack");    Config->ZNodelete = hasZOption(Args, "nodelete");    Config->ZNow = hasZOption(Args, "now");    Config->ZOrigin = hasZOption(Args, "origin");    Config->ZRelro = !hasZOption(Args, "norelro"); +  Config->ZStackSize = getZOptionValue(Args, "stack-size", -1); +  Config->ZWxneeded = hasZOption(Args, "wxneeded"); -  if (Config->Relocatable) -    Config->StripAll = false; +  Config->OFormatBinary = isOutputFormatBinary(Args); +  Config->SectionStartMap = getSectionStartMap(Args); +  Config->SortSection = getSortKind(Args); +  Config->Target2 = getTarget2Option(Args); +  Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args); + +  // --omagic is an option to create old-fashioned executables in which +  // .text segments are writable. Today, the option is still in use to +  // create special-purpose programs such as boot loaders. It doesn't +  // make sense to create PT_GNU_RELRO for such executables. +  if (Config->OMagic) +    Config->ZRelro = false; -  // --strip-all implies --strip-debug. -  if (Config->StripAll) -    Config->StripDebug = true; +  if (!Config->Relocatable) +    Config->Strip = getStripOption(Args);    // Config->Pic is true if we are generating position-independent code.    Config->Pic = Config->Pie || Config->Shared; @@ -414,13 +580,15 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {    // Parse --build-id or --build-id=<style>.    if (Args.hasArg(OPT_build_id)) -    Config->BuildId = BuildIdKind::Fnv1; +    Config->BuildId = BuildIdKind::Fast;    if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {      StringRef S = Arg->getValue();      if (S == "md5") {        Config->BuildId = BuildIdKind::Md5; -    } else if (S == "sha1") { +    } else if (S == "sha1" || S == "tree") {        Config->BuildId = BuildIdKind::Sha1; +    } else if (S == "uuid") { +      Config->BuildId = BuildIdKind::Uuid;      } else if (S == "none") {        Config->BuildId = BuildIdKind::None;      } else if (S.startswith("0x")) { @@ -431,21 +599,58 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {      }    } +  for (auto *Arg : Args.filtered(OPT_auxiliary)) +    Config->AuxiliaryList.push_back(Arg->getValue()); +  if (!Config->Shared && !Config->AuxiliaryList.empty()) +    error("-f may not be used without -shared"); +    for (auto *Arg : Args.filtered(OPT_undefined))      Config->Undefined.push_back(Arg->getValue()); -  Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args); -    if (auto *Arg = Args.getLastArg(OPT_dynamic_list))      if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) -      parseDynamicList(*Buffer); +      readDynamicList(*Buffer); + +  if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) +    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) +      Config->SymbolOrderingFile = getLines(*Buffer); + +  // If --retain-symbol-file is used, we'll retail only the symbols listed in +  // the file and discard all others. +  if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) { +    Config->Discard = DiscardPolicy::RetainFile; +    if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) +      for (StringRef S : getLines(*Buffer)) +        Config->RetainSymbolsFile.insert(S); +  }    for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) -    Config->DynamicList.push_back(Arg->getValue()); +    Config->VersionScriptGlobals.push_back( +        {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); + +  // Dynamic lists are a simplified linker script that doesn't need the +  // "global:" and implicitly ends with a "local:*". Set the variables needed to +  // simulate that. +  if (Args.hasArg(OPT_dynamic_list) || Args.hasArg(OPT_export_dynamic_symbol)) { +    Config->ExportDynamic = true; +    if (!Config->Shared) +      Config->DefaultSymbolVersion = VER_NDX_LOCAL; +  }    if (auto *Arg = Args.getLastArg(OPT_version_script))      if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) -      parseVersionScript(*Buffer); +      readVersionScript(*Buffer); +} + +// Returns a value of "-format" option. +static bool getBinaryOption(StringRef S) { +  if (S == "binary") +    return true; +  if (S == "elf" || S == "default") +    return false; +  error("unknown -format value: " + S + +        " (supported formats: elf, default, binary)"); +  return false;  }  void LinkerDriver::createFiles(opt::InputArgList &Args) { @@ -454,14 +659,20 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {      case OPT_l:        addLibrary(Arg->getValue());        break; -    case OPT_alias_script_T:      case OPT_INPUT: -    case OPT_script:        addFile(Arg->getValue());        break; +    case OPT_alias_script_T: +    case OPT_script: +      if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) +        readLinkerScript(*MB); +      break;      case OPT_as_needed:        Config->AsNeeded = true;        break; +    case OPT_format: +      InBinary = getBinaryOption(Arg->getValue()); +      break;      case OPT_no_as_needed:        Config->AsNeeded = false;        break; @@ -472,10 +683,10 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {        Config->Static = false;        break;      case OPT_whole_archive: -      WholeArchive = true; +      InWholeArchive = true;        break;      case OPT_no_whole_archive: -      WholeArchive = false; +      InWholeArchive = false;        break;      case OPT_start_lib:        InLib = true; @@ -486,19 +697,55 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {      }    } -  if (Files.empty() && !HasError) -    error("no input files."); +  if (Files.empty() && ErrorCount == 0) +    error("no input files"); +} -  // If -m <machine_type> was not given, infer it from object files. -  if (Config->EKind == ELFNoneKind) { -    for (std::unique_ptr<InputFile> &F : Files) { -      if (F->EKind == ELFNoneKind) -        continue; -      Config->EKind = F->EKind; -      Config->EMachine = F->EMachine; -      break; -    } +// If -m <machine_type> was not given, infer it from object files. +void LinkerDriver::inferMachineType() { +  if (Config->EKind != ELFNoneKind) +    return; + +  for (InputFile *F : Files) { +    if (F->EKind == ELFNoneKind) +      continue; +    Config->EKind = F->EKind; +    Config->EMachine = F->EMachine; +    Config->OSABI = F->OSABI; +    Config->MipsN32Abi = Config->EMachine == EM_MIPS && isMipsN32Abi(F); +    return;    } +  error("target emulation unknown: -m or at least one .o file required"); +} + +// Parse -z max-page-size=<value>. The default value is defined by +// each target. +static uint64_t getMaxPageSize(opt::InputArgList &Args) { +  uint64_t Val = +      getZOptionValue(Args, "max-page-size", Target->DefaultMaxPageSize); +  if (!isPowerOf2_64(Val)) +    error("max-page-size: value isn't a power of 2"); +  return Val; +} + +// Parses -image-base option. +static uint64_t getImageBase(opt::InputArgList &Args) { +  // Use default if no -image-base option is given. +  // Because we are using "Target" here, this function +  // has to be called after the variable is initialized. +  auto *Arg = Args.getLastArg(OPT_image_base); +  if (!Arg) +    return Config->Pic ? 0 : Target->DefaultImageBase; + +  StringRef S = Arg->getValue(); +  uint64_t V; +  if (S.getAsInteger(0, V)) { +    error("-image-base: number expected, but got " + S); +    return 0; +  } +  if ((V % Config->MaxPageSize) != 0) +    warn("-image-base: address isn't multiple of page size: " + S); +  return V;  }  // Do actual linking. Note that when this function is called, @@ -506,66 +753,70 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {  template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {    SymbolTable<ELFT> Symtab;    elf::Symtab<ELFT>::X = &Symtab; +  Target = createTarget(); +  ScriptBase = Script<ELFT>::X = make<LinkerScript<ELFT>>(); -  std::unique_ptr<TargetInfo> TI(createTarget()); -  Target = TI.get(); -  LinkerScript<ELFT> LS; -  Script<ELFT>::X = &LS; - -  Config->Rela = ELFT::Is64Bits || Config->EMachine == EM_X86_64; +  Config->Rela = +      ELFT::Is64Bits || Config->EMachine == EM_X86_64 || Config->MipsN32Abi;    Config->Mips64EL =        (Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind); - -  // Add entry symbol. Note that AMDGPU binaries have no entry points. -  if (Config->Entry.empty() && !Config->Shared && !Config->Relocatable && -      Config->EMachine != EM_AMDGPU) -    Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; +  Config->MaxPageSize = getMaxPageSize(Args); +  Config->ImageBase = getImageBase(Args);    // Default output filename is "a.out" by the Unix tradition.    if (Config->OutputFile.empty())      Config->OutputFile = "a.out"; +  // Use default entry point name if no name was given via the command +  // line nor linker scripts. For some reason, MIPS entry point name is +  // different from others. +  Config->WarnMissingEntry = +      (!Config->Entry.empty() || (!Config->Shared && !Config->Relocatable)); +  if (Config->Entry.empty() && !Config->Relocatable) +    Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; +    // Handle --trace-symbol.    for (auto *Arg : Args.filtered(OPT_trace_symbol))      Symtab.trace(Arg->getValue()); -  // Set either EntryAddr (if S is a number) or EntrySym (otherwise). -  if (!Config->Entry.empty()) { -    StringRef S = Config->Entry; -    if (S.getAsInteger(0, Config->EntryAddr)) -      Config->EntrySym = Symtab.addUndefined(S); -  } +  // Add all files to the symbol table. This will add almost all +  // symbols that we need to the symbol table. +  for (InputFile *F : Files) +    Symtab.addFile(F); -  // Initialize Config->ImageBase. -  if (auto *Arg = Args.getLastArg(OPT_image_base)) { -    StringRef S = Arg->getValue(); -    if (S.getAsInteger(0, Config->ImageBase)) -      error(Arg->getSpelling() + ": number expected, but got " + S); -    else if ((Config->ImageBase % Target->PageSize) != 0) -      warning(Arg->getSpelling() + ": address isn't multiple of page size"); -  } else { -    Config->ImageBase = Config->Pic ? 0 : Target->DefaultImageBase; -  } +  // If an entry symbol is in a static archive, pull out that file now +  // to complete the symbol table. After this, no new names except a +  // few linker-synthesized ones will be added to the symbol table. +  if (Symtab.find(Config->Entry)) +    Symtab.addUndefined(Config->Entry); -  for (std::unique_ptr<InputFile> &F : Files) -    Symtab.addFile(std::move(F)); -  if (HasError) -    return; // There were duplicate symbols or incompatible files +  // Return if there were name resolution errors. +  if (ErrorCount) +    return;    Symtab.scanUndefinedFlags();    Symtab.scanShlibUndefined(); -  Symtab.scanDynamicList();    Symtab.scanVersionScript(); -  Symtab.scanSymbolVersions(); -  Symtab.addCombinedLtoObject(); -  if (HasError) +  Symtab.addCombinedLTOObject(); +  if (ErrorCount)      return;    for (auto *Arg : Args.filtered(OPT_wrap))      Symtab.wrap(Arg->getValue()); -  // Write the result to the file. +  // Now that we have a complete list of input files. +  // Beyond this point, no new files are added. +  // Aggregate all input sections into one place. +  for (elf::ObjectFile<ELFT> *F : Symtab.getObjectFiles()) +    for (InputSectionBase<ELFT> *S : F->getSections()) +      if (S && S != &InputSection<ELFT>::Discarded) +        Symtab.Sections.push_back(S); +  for (BinaryFile *F : Symtab.getBinaryFiles()) +    for (InputSectionData *S : F->getSections()) +      Symtab.Sections.push_back(cast<InputSection<ELFT>>(S)); + +  // Do size optimizations: garbage collection and identical code folding.    if (Config->GcSections)      markLive<ELFT>();    if (Config->ICF) @@ -573,16 +824,16 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {    // MergeInputSection::splitIntoPieces needs to be called before    // any call of MergeInputSection::getOffset. Do that. -  for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F : -       Symtab.getObjectFiles()) -    for (InputSectionBase<ELFT> *S : F->getSections()) { -      if (!S || S == &InputSection<ELFT>::Discarded || !S->Live) -        continue; -      if (S->Compressed) -        S->uncompress(); -      if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S)) -        MS->splitIntoPieces(); -    } +  forEach(Symtab.Sections.begin(), Symtab.Sections.end(), +          [](InputSectionBase<ELFT> *S) { +            if (!S->Live) +              return; +            if (S->isCompressed()) +              S->uncompress(); +            if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S)) +              MS->splitIntoPieces(); +          }); -  writeResult<ELFT>(&Symtab); +  // Write the result to the file. +  writeResult<ELFT>();  } | 
