diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
commit | 1c98619801a5705c688e683be3ef9d70169a0686 (patch) | |
tree | 8422105cd1a94c368315f2db16b9ac746cf7c000 /ELF/Driver.cpp | |
parent | f4f3ce4613680903220815690ad79fc7ba0a2e26 (diff) |
Notes
Diffstat (limited to 'ELF/Driver.cpp')
-rw-r--r-- | ELF/Driver.cpp | 463 |
1 files changed, 358 insertions, 105 deletions
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index f00d97851e4a..c6ca2639236f 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -10,119 +10,218 @@ #include "Driver.h" #include "Config.h" #include "Error.h" +#include "ICF.h" #include "InputFiles.h" +#include "InputSection.h" +#include "LinkerScript.h" +#include "Strings.h" +#include "SymbolListFile.h" #include "SymbolTable.h" #include "Target.h" #include "Writer.h" -#include "llvm/ADT/STLExtras.h" +#include "lld/Driver/Driver.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" +#include <cstdlib> #include <utility> using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::sys; using namespace lld; -using namespace lld::elf2; +using namespace lld::elf; -Configuration *elf2::Config; -LinkerDriver *elf2::Driver; +Configuration *elf::Config; +LinkerDriver *elf::Driver; + +bool elf::link(ArrayRef<const char *> Args, raw_ostream &Error) { + HasError = false; + ErrorOS = &Error; -void elf2::link(ArrayRef<const char *> Args) { Configuration C; LinkerDriver D; + ScriptConfiguration SC; Config = &C; Driver = &D; - Driver->main(Args.slice(1)); + ScriptConfig = &SC; + + Driver->main(Args); + return !HasError; } +// Parses a linker -m option. static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) { - if (S == "elf32btsmip") - return {ELF32BEKind, EM_MIPS}; - if (S == "elf32ltsmip") - return {ELF32LEKind, EM_MIPS}; - if (S == "elf32ppc" || S == "elf32ppc_fbsd") - return {ELF32BEKind, EM_PPC}; - if (S == "elf64ppc" || S == "elf64ppc_fbsd") - return {ELF64BEKind, EM_PPC64}; - if (S == "elf_i386") - return {ELF32LEKind, EM_386}; - if (S == "elf_x86_64") - return {ELF64LEKind, EM_X86_64}; - if (S == "aarch64linux") - return {ELF64LEKind, EM_AARCH64}; - if (S == "i386pe" || S == "i386pep" || S == "thumb2pe") - error("Windows targets are not supported on the ELF frontend: " + S); - error("Unknown emulation: " + S); + if (S.endswith("_fbsd")) + S = S.drop_back(5); + + std::pair<ELFKind, uint16_t> Ret = + StringSwitch<std::pair<ELFKind, uint16_t>>(S) + .Case("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("elf32ppc", {ELF32BEKind, EM_PPC}) + .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) + .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) + .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) + .Case("elf_i386", {ELF32LEKind, EM_386}) + .Case("elf_x86_64", {ELF64LEKind, EM_X86_64}) + .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); + else + error("unknown emulation: " + S); + } + return Ret; } // Returns slices of MB by parsing MB as an archive file. // Each slice consists of a member file in the archive. -static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB) { - ErrorOr<std::unique_ptr<Archive>> FileOrErr = Archive::create(MB); - error(FileOrErr, "Failed to parse archive"); - std::unique_ptr<Archive> File = std::move(*FileOrErr); +std::vector<MemoryBufferRef> +LinkerDriver::getArchiveMembers(MemoryBufferRef MB) { + std::unique_ptr<Archive> File = + check(Archive::create(MB), "failed to parse archive"); std::vector<MemoryBufferRef> V; - for (const ErrorOr<Archive::Child> &C : File->children()) { - error(C, "Could not get the child of the archive " + File->getFileName()); - ErrorOr<MemoryBufferRef> MbOrErr = C->getMemoryBufferRef(); - error(MbOrErr, "Could not get the buffer for a child of the archive " + - File->getFileName()); - V.push_back(*MbOrErr); + Error Err; + for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { + Archive::Child C = check(COrErr, "could not get the child of the archive " + + File->getFileName()); + MemoryBufferRef MBRef = + check(C.getMemoryBufferRef(), + "could not get the buffer for a child of the archive " + + File->getFileName()); + V.push_back(MBRef); } + if (Err) + Error(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)); + return V; } // Opens and parses a file. Path has to be resolved already. // Newly created memory buffers are owned by this driver. void LinkerDriver::addFile(StringRef Path) { - using namespace llvm::sys::fs; + using namespace sys::fs; if (Config->Verbose) - llvm::outs() << Path << "\n"; - auto MBOrErr = MemoryBuffer::getFile(Path); - error(MBOrErr, "cannot open " + Path); - std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; - MemoryBufferRef MBRef = MB->getMemBufferRef(); - OwningMBs.push_back(std::move(MB)); // take MB ownership + outs() << Path << "\n"; + + Optional<MemoryBufferRef> Buffer = readFile(Path); + if (!Buffer.hasValue()) + return; + MemoryBufferRef MBRef = *Buffer; switch (identify_magic(MBRef.getBuffer())) { case file_magic::unknown: - readLinkerScript(&Alloc, MBRef); + readLinkerScript(MBRef); return; case file_magic::archive: if (WholeArchive) { for (MemoryBufferRef MB : getArchiveMembers(MBRef)) - Files.push_back(createObjectFile(MB)); + Files.push_back(createObjectFile(MB, Path)); return; } Files.push_back(make_unique<ArchiveFile>(MBRef)); return; case file_magic::elf_shared_object: + if (Config->Relocatable) { + error("attempted static link of dynamic object " + Path); + return; + } Files.push_back(createSharedFile(MBRef)); return; default: - Files.push_back(createObjectFile(MBRef)); + if (InLib) + Files.push_back(make_unique<LazyObjectFile>(MBRef)); + else + Files.push_back(createObjectFile(MBRef)); + } +} + +Optional<MemoryBufferRef> LinkerDriver::readFile(StringRef Path) { + auto MBOrErr = MemoryBuffer::getFile(Path); + if (auto EC = MBOrErr.getError()) { + error(EC, "cannot open " + Path); + return None; } + std::unique_ptr<MemoryBuffer> &MB = *MBOrErr; + MemoryBufferRef MBRef = MB->getMemBufferRef(); + OwningMBs.push_back(std::move(MB)); // take MB ownership + + if (Cpio) + Cpio->append(relativeToRoot(Path), MBRef.getBuffer()); + + return MBRef; +} + +// 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); + else + addFile(Path); +} + +// This function is called on startup. We need this for LTO since +// LTO calls LLVM functions to compile bitcode files to native code. +// Technically this can be delayed until we read bitcode files, but +// we don't bother to do lazily because the initialization is fast. +static void initLLVM(opt::InputArgList &Args) { + InitializeAllTargets(); + InitializeAllTargetMCs(); + 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)"); + for (auto *Arg : Args.filtered(OPT_mllvm)) + V.push_back(Arg->getValue()); + cl::ParseCommandLineOptions(V.size(), V.data()); } // Some command line options or some combinations of them are not allowed. // This function checks for such errors. static void checkOptions(opt::InputArgList &Args) { - // Traditional linkers can generate re-linkable object files instead - // of executables or DSOs. We don't support that since the feature - // does not seem to provide more value than the static archiver. - if (Args.hasArg(OPT_relocatable)) - error("-r option is not supported. Use 'ar' command instead."); - // The MIPS ABI as of 2016 does not support the GNU-style symbol lookup // table which is a relatively new feature. if (Config->EMachine == EM_MIPS && Config->GnuHash) - error("The .gnu.hash section is not compatible with the MIPS target."); + 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"); + + if (Config->Relocatable) { + if (Config->Shared) + error("-r and -shared may not be used together"); + if (Config->GcSections) + error("-r and --gc-sections may not be used together"); + if (Config->ICF) + error("-r and --icf may not be used together"); + if (Config->Pie) + error("-r and -pie may not be used together"); + } } static StringRef @@ -132,6 +231,22 @@ getString(opt::InputArgList &Args, unsigned Key, StringRef Default = "") { return Default; } +static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) { + int V = Default; + if (auto *Arg = Args.getLastArg(Key)) { + StringRef S = Arg->getValue(); + if (S.getAsInteger(10, V)) + error(Arg->getSpelling() + ": number expected, but got " + S); + } + return V; +} + +static const char *getReproduceOption(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_reproduce)) + return Arg->getValue(); + return getenv("LLD_REPRODUCE"); +} + static bool hasZOption(opt::InputArgList &Args, StringRef Key) { for (auto *Arg : Args.filtered(OPT_z)) if (Key == Arg->getValue()) @@ -140,12 +255,33 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) { } void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { - initSymbols(); + ELFOptTable Parser; + opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); + if (Args.hasArg(OPT_help)) { + printHelp(ArgsArr[0]); + return; + } + if (Args.hasArg(OPT_version)) { + outs() << getVersionString(); + return; + } + + 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) { + Cpio->append("response.txt", createResponseFile(Args)); + Cpio->append("version.txt", getVersionString()); + } + } - opt::InputArgList Args = parseArgs(&Alloc, ArgsArr); readConfigs(Args); + initLLVM(Args); createFiles(Args); checkOptions(Args); + if (HasError) + return; switch (Config->EKind) { case ELF32LEKind: @@ -165,6 +301,25 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { } } +static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) { + if (Args.hasArg(OPT_noinhibit_exec)) + return UnresolvedPolicy::Warn; + if (Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs")) + return UnresolvedPolicy::NoUndef; + if (Config->Relocatable) + return UnresolvedPolicy::Ignore; + + if (auto *Arg = Args.getLastArg(OPT_unresolved_symbols)) { + StringRef S = Arg->getValue(); + if (S == "ignore-all" || S == "ignore-in-object-files") + return UnresolvedPolicy::Ignore; + if (S == "ignore-in-shared-libs" || S == "report-all") + return UnresolvedPolicy::Error; + error("unknown --unresolved-symbols value: " + S); + } + return UnresolvedPolicy::Error; +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) @@ -185,38 +340,66 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { 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->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->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec); - Config->NoUndefined = Args.hasArg(OPT_no_undefined); + 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->PrintGcSections = Args.hasArg(OPT_print_gc_sections); + Config->Relocatable = Args.hasArg(OPT_relocatable); + Config->SaveTemps = Args.hasArg(OPT_save_temps); 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->Trace = Args.hasArg(OPT_trace); Config->Verbose = Args.hasArg(OPT_verbose); + Config->WarnCommon = Args.hasArg(OPT_warn_common); Config->DynamicLinker = getString(Args, OPT_dynamic_linker); 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->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) + 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->ZCombreloc = !hasZOption(Args, "nocombreloc"); 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"); - if (auto *Arg = Args.getLastArg(OPT_O)) { - StringRef Val = Arg->getValue(); - if (Val.getAsInteger(10, Config->Optimize)) - error("Invalid optimization level"); - } + if (Config->Relocatable) + Config->StripAll = false; + + // --strip-all implies --strip-debug. + if (Config->StripAll) + Config->StripDebug = true; + + // Config->Pic is true if we are generating position-independent code. + Config->Pic = Config->Pie || Config->Shared; if (auto *Arg = Args.getLastArg(OPT_hash_style)) { StringRef S = Arg->getValue(); @@ -226,19 +409,52 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { } else if (S == "both") { Config->GnuHash = true; } else if (S != "sysv") - error("Unknown hash style: " + S); + error("unknown hash style: " + S); + } + + // Parse --build-id or --build-id=<style>. + if (Args.hasArg(OPT_build_id)) + Config->BuildId = BuildIdKind::Fnv1; + if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) { + StringRef S = Arg->getValue(); + if (S == "md5") { + Config->BuildId = BuildIdKind::Md5; + } else if (S == "sha1") { + Config->BuildId = BuildIdKind::Sha1; + } else if (S == "none") { + Config->BuildId = BuildIdKind::None; + } else if (S.startswith("0x")) { + Config->BuildId = BuildIdKind::Hexstring; + Config->BuildIdVector = parseHex(S.substr(2)); + } else { + error("unknown --build-id style: " + S); + } } 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); + + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) + Config->DynamicList.push_back(Arg->getValue()); + + if (auto *Arg = Args.getLastArg(OPT_version_script)) + if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) + parseVersionScript(*Buffer); } void LinkerDriver::createFiles(opt::InputArgList &Args) { for (auto *Arg : Args) { switch (Arg->getOption().getID()) { case OPT_l: - addFile(searchLibrary(Arg->getValue())); + addLibrary(Arg->getValue()); break; + case OPT_alias_script_T: case OPT_INPUT: case OPT_script: addFile(Arg->getValue()); @@ -261,75 +477,112 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { case OPT_no_whole_archive: WholeArchive = false; break; + case OPT_start_lib: + InLib = true; + break; + case OPT_end_lib: + InLib = false; + break; } } - if (Files.empty()) + if (Files.empty() && !HasError) 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; + } + } } +// Do actual linking. Note that when this function is called, +// all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { SymbolTable<ELFT> Symtab; - Target.reset(createTarget()); - - if (!Config->Shared) { - // Add entry symbol. - // - // There is no entry symbol for AMDGPU binaries, so skip adding one to avoid - // having and undefined symbol. - if (Config->Entry.empty() && Config->EMachine != EM_AMDGPU) - Config->Entry = (Config->EMachine == EM_MIPS) ? "__start" : "_start"; - - // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol - // is magical and is used to produce a R_386_GOTPC relocation. - // The R_386_GOTPC relocation value doesn't actually depend on the - // symbol value, so it could use an index of STN_UNDEF which, according - // to the spec, means the symbol value is 0. - // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in - // the object file. - // The situation is even stranger on x86_64 where the assembly doesn't - // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as - // an undefined symbol in the .o files. - // Given that the symbol is effectively unused, we just create a dummy - // hidden one to avoid the undefined symbol error. - Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_"); - } + elf::Symtab<ELFT>::X = &Symtab; + + 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->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"; + + // Default output filename is "a.out" by the Unix tradition. + if (Config->OutputFile.empty()) + Config->OutputFile = "a.out"; + + // 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()) { - // Set either EntryAddr (if S is a number) or EntrySym (otherwise). StringRef S = Config->Entry; if (S.getAsInteger(0, Config->EntryAddr)) Config->EntrySym = Symtab.addUndefined(S); } - if (Config->EMachine == EM_MIPS) { - // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between - // start of function and gp pointer into GOT. Use 'strong' variant of - // the addIgnored to prevent '_gp_disp' substitution. - Config->MipsGpDisp = Symtab.addIgnoredStrong("_gp_disp"); - - // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer - // so that it points to an absolute address which is relative to GOT. - // See "Global Data Symbols" in Chapter 6 in the following document: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - Symtab.addAbsolute("_gp", ElfSym<ELFT>::MipsGp); + // 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; } for (std::unique_ptr<InputFile> &F : Files) Symtab.addFile(std::move(F)); + if (HasError) + return; // There were duplicate symbols or incompatible files - for (StringRef S : Config->Undefined) - Symtab.addUndefinedOpt(S); + Symtab.scanUndefinedFlags(); + Symtab.scanShlibUndefined(); + Symtab.scanDynamicList(); + Symtab.scanVersionScript(); + Symtab.scanSymbolVersions(); + + Symtab.addCombinedLtoObject(); + if (HasError) + return; for (auto *Arg : Args.filtered(OPT_wrap)) Symtab.wrap(Arg->getValue()); - if (Config->OutputFile.empty()) - Config->OutputFile = "a.out"; - // Write the result to the file. - Symtab.scanShlibUndefined(); if (Config->GcSections) - markLive<ELFT>(&Symtab); + markLive<ELFT>(); + if (Config->ICF) + doIcf<ELFT>(); + + // 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(); + } + writeResult<ELFT>(&Symtab); } |