106f32e7eSjoerg //===-- gold-plugin.cpp - Plugin to gold for Link Time Optimization ------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This is a gold plugin for LLVM. It provides an LLVM implementation of the
1006f32e7eSjoerg // interface described in http://gcc.gnu.org/wiki/whopr/driver .
1106f32e7eSjoerg //
1206f32e7eSjoerg //===----------------------------------------------------------------------===//
1306f32e7eSjoerg
1406f32e7eSjoerg #include "llvm/ADT/Statistic.h"
1506f32e7eSjoerg #include "llvm/Bitcode/BitcodeReader.h"
1606f32e7eSjoerg #include "llvm/Bitcode/BitcodeWriter.h"
17*da58b97aSjoerg #include "llvm/CodeGen/CommandFlags.h"
1806f32e7eSjoerg #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
19*da58b97aSjoerg #include "llvm/Config/llvm-config.h"
2006f32e7eSjoerg #include "llvm/IR/Constants.h"
2106f32e7eSjoerg #include "llvm/IR/DiagnosticPrinter.h"
2206f32e7eSjoerg #include "llvm/LTO/Caching.h"
2306f32e7eSjoerg #include "llvm/LTO/LTO.h"
2406f32e7eSjoerg #include "llvm/Object/Error.h"
25*da58b97aSjoerg #include "llvm/Remarks/HotnessThresholdParser.h"
2606f32e7eSjoerg #include "llvm/Support/CachePruning.h"
2706f32e7eSjoerg #include "llvm/Support/CommandLine.h"
2806f32e7eSjoerg #include "llvm/Support/FileSystem.h"
29*da58b97aSjoerg #include "llvm/Support/Host.h"
3006f32e7eSjoerg #include "llvm/Support/ManagedStatic.h"
3106f32e7eSjoerg #include "llvm/Support/MemoryBuffer.h"
3206f32e7eSjoerg #include "llvm/Support/Path.h"
3306f32e7eSjoerg #include "llvm/Support/TargetSelect.h"
34*da58b97aSjoerg #include "llvm/Support/Threading.h"
3506f32e7eSjoerg #include "llvm/Support/raw_ostream.h"
3606f32e7eSjoerg #include <list>
3706f32e7eSjoerg #include <map>
3806f32e7eSjoerg #include <plugin-api.h>
3906f32e7eSjoerg #include <string>
4006f32e7eSjoerg #include <system_error>
4106f32e7eSjoerg #include <utility>
4206f32e7eSjoerg #include <vector>
4306f32e7eSjoerg
4406f32e7eSjoerg // FIXME: remove this declaration when we stop maintaining Ubuntu Quantal and
4506f32e7eSjoerg // Precise and Debian Wheezy (binutils 2.23 is required)
4606f32e7eSjoerg #define LDPO_PIE 3
4706f32e7eSjoerg
4806f32e7eSjoerg #define LDPT_GET_SYMBOLS_V3 28
4906f32e7eSjoerg
5006f32e7eSjoerg // FIXME: Remove when binutils 2.31 (containing gold 1.16) is the minimum
5106f32e7eSjoerg // required version.
5206f32e7eSjoerg #define LDPT_GET_WRAP_SYMBOLS 32
5306f32e7eSjoerg
5406f32e7eSjoerg using namespace llvm;
5506f32e7eSjoerg using namespace lto;
5606f32e7eSjoerg
57*da58b97aSjoerg static codegen::RegisterCodeGenFlags CodeGenFlags;
58*da58b97aSjoerg
5906f32e7eSjoerg // FIXME: Remove when binutils 2.31 (containing gold 1.16) is the minimum
6006f32e7eSjoerg // required version.
6106f32e7eSjoerg typedef enum ld_plugin_status (*ld_plugin_get_wrap_symbols)(
6206f32e7eSjoerg uint64_t *num_symbols, const char ***wrap_symbol_list);
6306f32e7eSjoerg
6406f32e7eSjoerg static ld_plugin_status discard_message(int level, const char *format, ...) {
6506f32e7eSjoerg // Die loudly. Recent versions of Gold pass ld_plugin_message as the first
6606f32e7eSjoerg // callback in the transfer vector. This should never be called.
6706f32e7eSjoerg abort();
6806f32e7eSjoerg }
6906f32e7eSjoerg
7006f32e7eSjoerg static ld_plugin_release_input_file release_input_file = nullptr;
7106f32e7eSjoerg static ld_plugin_get_input_file get_input_file = nullptr;
7206f32e7eSjoerg static ld_plugin_message message = discard_message;
7306f32e7eSjoerg static ld_plugin_get_wrap_symbols get_wrap_symbols = nullptr;
7406f32e7eSjoerg
7506f32e7eSjoerg namespace {
7606f32e7eSjoerg struct claimed_file {
7706f32e7eSjoerg void *handle;
7806f32e7eSjoerg void *leader_handle;
7906f32e7eSjoerg std::vector<ld_plugin_symbol> syms;
8006f32e7eSjoerg off_t filesize;
8106f32e7eSjoerg std::string name;
8206f32e7eSjoerg };
8306f32e7eSjoerg
8406f32e7eSjoerg /// RAII wrapper to manage opening and releasing of a ld_plugin_input_file.
8506f32e7eSjoerg struct PluginInputFile {
8606f32e7eSjoerg void *Handle;
8706f32e7eSjoerg std::unique_ptr<ld_plugin_input_file> File;
8806f32e7eSjoerg
PluginInputFile__anon7eeef7220111::PluginInputFile8906f32e7eSjoerg PluginInputFile(void *Handle) : Handle(Handle) {
9006f32e7eSjoerg File = std::make_unique<ld_plugin_input_file>();
9106f32e7eSjoerg if (get_input_file(Handle, File.get()) != LDPS_OK)
9206f32e7eSjoerg message(LDPL_FATAL, "Failed to get file information");
9306f32e7eSjoerg }
~PluginInputFile__anon7eeef7220111::PluginInputFile9406f32e7eSjoerg ~PluginInputFile() {
9506f32e7eSjoerg // File would have been reset to nullptr if we moved this object
9606f32e7eSjoerg // to a new owner.
9706f32e7eSjoerg if (File)
9806f32e7eSjoerg if (release_input_file(Handle) != LDPS_OK)
9906f32e7eSjoerg message(LDPL_FATAL, "Failed to release file information");
10006f32e7eSjoerg }
10106f32e7eSjoerg
file__anon7eeef7220111::PluginInputFile10206f32e7eSjoerg ld_plugin_input_file &file() { return *File; }
10306f32e7eSjoerg
10406f32e7eSjoerg PluginInputFile(PluginInputFile &&RHS) = default;
10506f32e7eSjoerg PluginInputFile &operator=(PluginInputFile &&RHS) = default;
10606f32e7eSjoerg };
10706f32e7eSjoerg
10806f32e7eSjoerg struct ResolutionInfo {
10906f32e7eSjoerg bool CanOmitFromDynSym = true;
11006f32e7eSjoerg bool DefaultVisibility = true;
11106f32e7eSjoerg bool CanInline = true;
11206f32e7eSjoerg bool IsUsedInRegularObj = false;
11306f32e7eSjoerg };
11406f32e7eSjoerg
11506f32e7eSjoerg }
11606f32e7eSjoerg
11706f32e7eSjoerg static ld_plugin_add_symbols add_symbols = nullptr;
11806f32e7eSjoerg static ld_plugin_get_symbols get_symbols = nullptr;
11906f32e7eSjoerg static ld_plugin_add_input_file add_input_file = nullptr;
12006f32e7eSjoerg static ld_plugin_set_extra_library_path set_extra_library_path = nullptr;
12106f32e7eSjoerg static ld_plugin_get_view get_view = nullptr;
12206f32e7eSjoerg static bool IsExecutable = false;
12306f32e7eSjoerg static bool SplitSections = true;
12406f32e7eSjoerg static Optional<Reloc::Model> RelocationModel = None;
12506f32e7eSjoerg static std::string output_name = "";
12606f32e7eSjoerg static std::list<claimed_file> Modules;
12706f32e7eSjoerg static DenseMap<int, void *> FDToLeaderHandle;
12806f32e7eSjoerg static StringMap<ResolutionInfo> ResInfo;
12906f32e7eSjoerg static std::vector<std::string> Cleanup;
13006f32e7eSjoerg
13106f32e7eSjoerg namespace options {
13206f32e7eSjoerg enum OutputType {
13306f32e7eSjoerg OT_NORMAL,
13406f32e7eSjoerg OT_DISABLE,
13506f32e7eSjoerg OT_BC_ONLY,
13606f32e7eSjoerg OT_ASM_ONLY,
13706f32e7eSjoerg OT_SAVE_TEMPS
13806f32e7eSjoerg };
13906f32e7eSjoerg static OutputType TheOutputType = OT_NORMAL;
14006f32e7eSjoerg static unsigned OptLevel = 2;
141*da58b97aSjoerg // Currently only affects ThinLTO, where the default is the max cores in the
142*da58b97aSjoerg // system. See llvm::get_threadpool_strategy() for acceptable values.
143*da58b97aSjoerg static std::string Parallelism;
14406f32e7eSjoerg // Default regular LTO codegen parallelism (number of partitions).
14506f32e7eSjoerg static unsigned ParallelCodeGenParallelismLevel = 1;
14606f32e7eSjoerg #ifdef NDEBUG
14706f32e7eSjoerg static bool DisableVerify = true;
14806f32e7eSjoerg #else
14906f32e7eSjoerg static bool DisableVerify = false;
15006f32e7eSjoerg #endif
15106f32e7eSjoerg static std::string obj_path;
15206f32e7eSjoerg static std::string extra_library_path;
15306f32e7eSjoerg static std::string triple;
15406f32e7eSjoerg static std::string mcpu;
15506f32e7eSjoerg // When the thinlto plugin option is specified, only read the function
15606f32e7eSjoerg // the information from intermediate files and write a combined
15706f32e7eSjoerg // global index for the ThinLTO backends.
15806f32e7eSjoerg static bool thinlto = false;
15906f32e7eSjoerg // If false, all ThinLTO backend compilations through code gen are performed
16006f32e7eSjoerg // using multiple threads in the gold-plugin, before handing control back to
16106f32e7eSjoerg // gold. If true, write individual backend index files which reflect
16206f32e7eSjoerg // the import decisions, and exit afterwards. The assumption is
16306f32e7eSjoerg // that the build system will launch the backend processes.
16406f32e7eSjoerg static bool thinlto_index_only = false;
16506f32e7eSjoerg // If non-empty, holds the name of a file in which to write the list of
16606f32e7eSjoerg // oject files gold selected for inclusion in the link after symbol
16706f32e7eSjoerg // resolution (i.e. they had selected symbols). This will only be non-empty
16806f32e7eSjoerg // in the thinlto_index_only case. It is used to identify files, which may
16906f32e7eSjoerg // have originally been within archive libraries specified via
17006f32e7eSjoerg // --start-lib/--end-lib pairs, that should be included in the final
17106f32e7eSjoerg // native link process (since intervening function importing and inlining
17206f32e7eSjoerg // may change the symbol resolution detected in the final link and which
17306f32e7eSjoerg // files to include out of --start-lib/--end-lib libraries as a result).
17406f32e7eSjoerg static std::string thinlto_linked_objects_file;
17506f32e7eSjoerg // If true, when generating individual index files for distributed backends,
17606f32e7eSjoerg // also generate a "${bitcodefile}.imports" file at the same location for each
17706f32e7eSjoerg // bitcode file, listing the files it imports from in plain text. This is to
17806f32e7eSjoerg // support distributed build file staging.
17906f32e7eSjoerg static bool thinlto_emit_imports_files = false;
18006f32e7eSjoerg // Option to control where files for a distributed backend (the individual
18106f32e7eSjoerg // index files and optional imports files) are created.
18206f32e7eSjoerg // If specified, expects a string of the form "oldprefix:newprefix", and
18306f32e7eSjoerg // instead of generating these files in the same directory path as the
18406f32e7eSjoerg // corresponding bitcode file, will use a path formed by replacing the
18506f32e7eSjoerg // bitcode file's path prefix matching oldprefix with newprefix.
18606f32e7eSjoerg static std::string thinlto_prefix_replace;
18706f32e7eSjoerg // Option to control the name of modules encoded in the individual index
18806f32e7eSjoerg // files for a distributed backend. This enables the use of minimized
18906f32e7eSjoerg // bitcode files for the thin link, assuming the name of the full bitcode
19006f32e7eSjoerg // file used in the backend differs just in some part of the file suffix.
19106f32e7eSjoerg // If specified, expects a string of the form "oldsuffix:newsuffix".
19206f32e7eSjoerg static std::string thinlto_object_suffix_replace;
19306f32e7eSjoerg // Optional path to a directory for caching ThinLTO objects.
19406f32e7eSjoerg static std::string cache_dir;
19506f32e7eSjoerg // Optional pruning policy for ThinLTO caches.
19606f32e7eSjoerg static std::string cache_policy;
19706f32e7eSjoerg // Additional options to pass into the code generator.
19806f32e7eSjoerg // Note: This array will contain all plugin options which are not claimed
19906f32e7eSjoerg // as plugin exclusive to pass to the code generator.
20006f32e7eSjoerg static std::vector<const char *> extra;
20106f32e7eSjoerg // Sample profile file path
20206f32e7eSjoerg static std::string sample_profile;
20306f32e7eSjoerg // New pass manager
204*da58b97aSjoerg static bool new_pass_manager = LLVM_ENABLE_NEW_PASS_MANAGER;
20506f32e7eSjoerg // Debug new pass manager
20606f32e7eSjoerg static bool debug_pass_manager = false;
20706f32e7eSjoerg // Directory to store the .dwo files.
20806f32e7eSjoerg static std::string dwo_dir;
20906f32e7eSjoerg /// Statistics output filename.
21006f32e7eSjoerg static std::string stats_file;
211*da58b97aSjoerg // Asserts that LTO link has whole program visibility
212*da58b97aSjoerg static bool whole_program_visibility = false;
21306f32e7eSjoerg
21406f32e7eSjoerg // Optimization remarks filename, accepted passes and hotness options
21506f32e7eSjoerg static std::string RemarksFilename;
21606f32e7eSjoerg static std::string RemarksPasses;
21706f32e7eSjoerg static bool RemarksWithHotness = false;
218*da58b97aSjoerg static Optional<uint64_t> RemarksHotnessThreshold = 0;
21906f32e7eSjoerg static std::string RemarksFormat;
22006f32e7eSjoerg
22106f32e7eSjoerg // Context sensitive PGO options.
22206f32e7eSjoerg static std::string cs_profile_path;
22306f32e7eSjoerg static bool cs_pgo_gen = false;
22406f32e7eSjoerg
process_plugin_option(const char * opt_)22506f32e7eSjoerg static void process_plugin_option(const char *opt_)
22606f32e7eSjoerg {
22706f32e7eSjoerg if (opt_ == nullptr)
22806f32e7eSjoerg return;
22906f32e7eSjoerg llvm::StringRef opt = opt_;
23006f32e7eSjoerg
231*da58b97aSjoerg if (opt.consume_front("mcpu=")) {
232*da58b97aSjoerg mcpu = std::string(opt);
233*da58b97aSjoerg } else if (opt.consume_front("extra-library-path=")) {
234*da58b97aSjoerg extra_library_path = std::string(opt);
235*da58b97aSjoerg } else if (opt.consume_front("mtriple=")) {
236*da58b97aSjoerg triple = std::string(opt);
237*da58b97aSjoerg } else if (opt.consume_front("obj-path=")) {
238*da58b97aSjoerg obj_path = std::string(opt);
23906f32e7eSjoerg } else if (opt == "emit-llvm") {
24006f32e7eSjoerg TheOutputType = OT_BC_ONLY;
24106f32e7eSjoerg } else if (opt == "save-temps") {
24206f32e7eSjoerg TheOutputType = OT_SAVE_TEMPS;
24306f32e7eSjoerg } else if (opt == "disable-output") {
24406f32e7eSjoerg TheOutputType = OT_DISABLE;
24506f32e7eSjoerg } else if (opt == "emit-asm") {
24606f32e7eSjoerg TheOutputType = OT_ASM_ONLY;
24706f32e7eSjoerg } else if (opt == "thinlto") {
24806f32e7eSjoerg thinlto = true;
24906f32e7eSjoerg } else if (opt == "thinlto-index-only") {
25006f32e7eSjoerg thinlto_index_only = true;
251*da58b97aSjoerg } else if (opt.consume_front("thinlto-index-only=")) {
25206f32e7eSjoerg thinlto_index_only = true;
253*da58b97aSjoerg thinlto_linked_objects_file = std::string(opt);
25406f32e7eSjoerg } else if (opt == "thinlto-emit-imports-files") {
25506f32e7eSjoerg thinlto_emit_imports_files = true;
256*da58b97aSjoerg } else if (opt.consume_front("thinlto-prefix-replace=")) {
257*da58b97aSjoerg thinlto_prefix_replace = std::string(opt);
25806f32e7eSjoerg if (thinlto_prefix_replace.find(';') == std::string::npos)
25906f32e7eSjoerg message(LDPL_FATAL, "thinlto-prefix-replace expects 'old;new' format");
260*da58b97aSjoerg } else if (opt.consume_front("thinlto-object-suffix-replace=")) {
261*da58b97aSjoerg thinlto_object_suffix_replace = std::string(opt);
26206f32e7eSjoerg if (thinlto_object_suffix_replace.find(';') == std::string::npos)
26306f32e7eSjoerg message(LDPL_FATAL,
26406f32e7eSjoerg "thinlto-object-suffix-replace expects 'old;new' format");
265*da58b97aSjoerg } else if (opt.consume_front("cache-dir=")) {
266*da58b97aSjoerg cache_dir = std::string(opt);
267*da58b97aSjoerg } else if (opt.consume_front("cache-policy=")) {
268*da58b97aSjoerg cache_policy = std::string(opt);
26906f32e7eSjoerg } else if (opt.size() == 2 && opt[0] == 'O') {
27006f32e7eSjoerg if (opt[1] < '0' || opt[1] > '3')
27106f32e7eSjoerg message(LDPL_FATAL, "Optimization level must be between 0 and 3");
27206f32e7eSjoerg OptLevel = opt[1] - '0';
273*da58b97aSjoerg } else if (opt.consume_front("jobs=")) {
274*da58b97aSjoerg Parallelism = std::string(opt);
275*da58b97aSjoerg if (!get_threadpool_strategy(opt))
276*da58b97aSjoerg message(LDPL_FATAL, "Invalid parallelism level: %s",
277*da58b97aSjoerg Parallelism.c_str());
278*da58b97aSjoerg } else if (opt.consume_front("lto-partitions=")) {
279*da58b97aSjoerg if (opt.getAsInteger(10, ParallelCodeGenParallelismLevel))
28006f32e7eSjoerg message(LDPL_FATAL, "Invalid codegen partition level: %s", opt_ + 5);
28106f32e7eSjoerg } else if (opt == "disable-verify") {
28206f32e7eSjoerg DisableVerify = true;
283*da58b97aSjoerg } else if (opt.consume_front("sample-profile=")) {
284*da58b97aSjoerg sample_profile = std::string(opt);
28506f32e7eSjoerg } else if (opt == "cs-profile-generate") {
28606f32e7eSjoerg cs_pgo_gen = true;
287*da58b97aSjoerg } else if (opt.consume_front("cs-profile-path=")) {
288*da58b97aSjoerg cs_profile_path = std::string(opt);
28906f32e7eSjoerg } else if (opt == "new-pass-manager") {
29006f32e7eSjoerg new_pass_manager = true;
291*da58b97aSjoerg } else if (opt == "legacy-pass-manager") {
292*da58b97aSjoerg new_pass_manager = false;
29306f32e7eSjoerg } else if (opt == "debug-pass-manager") {
29406f32e7eSjoerg debug_pass_manager = true;
295*da58b97aSjoerg } else if (opt == "whole-program-visibility") {
296*da58b97aSjoerg whole_program_visibility = true;
297*da58b97aSjoerg } else if (opt.consume_front("dwo_dir=")) {
298*da58b97aSjoerg dwo_dir = std::string(opt);
299*da58b97aSjoerg } else if (opt.consume_front("opt-remarks-filename=")) {
300*da58b97aSjoerg RemarksFilename = std::string(opt);
301*da58b97aSjoerg } else if (opt.consume_front("opt-remarks-passes=")) {
302*da58b97aSjoerg RemarksPasses = std::string(opt);
30306f32e7eSjoerg } else if (opt == "opt-remarks-with-hotness") {
30406f32e7eSjoerg RemarksWithHotness = true;
305*da58b97aSjoerg } else if (opt.consume_front("opt-remarks-hotness-threshold=")) {
306*da58b97aSjoerg auto ResultOrErr = remarks::parseHotnessThresholdOption(opt);
307*da58b97aSjoerg if (!ResultOrErr)
308*da58b97aSjoerg message(LDPL_FATAL, "Invalid remarks hotness threshold: %s", opt);
309*da58b97aSjoerg else
310*da58b97aSjoerg RemarksHotnessThreshold = *ResultOrErr;
311*da58b97aSjoerg } else if (opt.consume_front("opt-remarks-format=")) {
312*da58b97aSjoerg RemarksFormat = std::string(opt);
313*da58b97aSjoerg } else if (opt.consume_front("stats-file=")) {
314*da58b97aSjoerg stats_file = std::string(opt);
31506f32e7eSjoerg } else {
31606f32e7eSjoerg // Save this option to pass to the code generator.
31706f32e7eSjoerg // ParseCommandLineOptions() expects argv[0] to be program name. Lazily
31806f32e7eSjoerg // add that.
31906f32e7eSjoerg if (extra.empty())
32006f32e7eSjoerg extra.push_back("LLVMgold");
32106f32e7eSjoerg
32206f32e7eSjoerg extra.push_back(opt_);
32306f32e7eSjoerg }
32406f32e7eSjoerg }
32506f32e7eSjoerg }
32606f32e7eSjoerg
32706f32e7eSjoerg static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
32806f32e7eSjoerg int *claimed);
32906f32e7eSjoerg static ld_plugin_status all_symbols_read_hook(void);
33006f32e7eSjoerg static ld_plugin_status cleanup_hook(void);
33106f32e7eSjoerg
33206f32e7eSjoerg extern "C" ld_plugin_status onload(ld_plugin_tv *tv);
onload(ld_plugin_tv * tv)33306f32e7eSjoerg ld_plugin_status onload(ld_plugin_tv *tv) {
33406f32e7eSjoerg InitializeAllTargetInfos();
33506f32e7eSjoerg InitializeAllTargets();
33606f32e7eSjoerg InitializeAllTargetMCs();
33706f32e7eSjoerg InitializeAllAsmParsers();
33806f32e7eSjoerg InitializeAllAsmPrinters();
33906f32e7eSjoerg
34006f32e7eSjoerg // We're given a pointer to the first transfer vector. We read through them
34106f32e7eSjoerg // until we find one where tv_tag == LDPT_NULL. The REGISTER_* tagged values
34206f32e7eSjoerg // contain pointers to functions that we need to call to register our own
34306f32e7eSjoerg // hooks. The others are addresses of functions we can use to call into gold
34406f32e7eSjoerg // for services.
34506f32e7eSjoerg
34606f32e7eSjoerg bool registeredClaimFile = false;
34706f32e7eSjoerg bool RegisteredAllSymbolsRead = false;
34806f32e7eSjoerg
34906f32e7eSjoerg for (; tv->tv_tag != LDPT_NULL; ++tv) {
35006f32e7eSjoerg // Cast tv_tag to int to allow values not in "enum ld_plugin_tag", like, for
35106f32e7eSjoerg // example, LDPT_GET_SYMBOLS_V3 when building against an older plugin-api.h
35206f32e7eSjoerg // header.
35306f32e7eSjoerg switch (static_cast<int>(tv->tv_tag)) {
35406f32e7eSjoerg case LDPT_OUTPUT_NAME:
35506f32e7eSjoerg output_name = tv->tv_u.tv_string;
35606f32e7eSjoerg break;
35706f32e7eSjoerg case LDPT_LINKER_OUTPUT:
35806f32e7eSjoerg switch (tv->tv_u.tv_val) {
35906f32e7eSjoerg case LDPO_REL: // .o
36006f32e7eSjoerg IsExecutable = false;
36106f32e7eSjoerg SplitSections = false;
36206f32e7eSjoerg break;
36306f32e7eSjoerg case LDPO_DYN: // .so
36406f32e7eSjoerg IsExecutable = false;
36506f32e7eSjoerg RelocationModel = Reloc::PIC_;
36606f32e7eSjoerg break;
36706f32e7eSjoerg case LDPO_PIE: // position independent executable
36806f32e7eSjoerg IsExecutable = true;
36906f32e7eSjoerg RelocationModel = Reloc::PIC_;
37006f32e7eSjoerg break;
37106f32e7eSjoerg case LDPO_EXEC: // .exe
37206f32e7eSjoerg IsExecutable = true;
37306f32e7eSjoerg RelocationModel = Reloc::Static;
37406f32e7eSjoerg break;
37506f32e7eSjoerg default:
37606f32e7eSjoerg message(LDPL_ERROR, "Unknown output file type %d", tv->tv_u.tv_val);
37706f32e7eSjoerg return LDPS_ERR;
37806f32e7eSjoerg }
37906f32e7eSjoerg break;
38006f32e7eSjoerg case LDPT_OPTION:
38106f32e7eSjoerg options::process_plugin_option(tv->tv_u.tv_string);
38206f32e7eSjoerg break;
38306f32e7eSjoerg case LDPT_REGISTER_CLAIM_FILE_HOOK: {
38406f32e7eSjoerg ld_plugin_register_claim_file callback;
38506f32e7eSjoerg callback = tv->tv_u.tv_register_claim_file;
38606f32e7eSjoerg
38706f32e7eSjoerg if (callback(claim_file_hook) != LDPS_OK)
38806f32e7eSjoerg return LDPS_ERR;
38906f32e7eSjoerg
39006f32e7eSjoerg registeredClaimFile = true;
39106f32e7eSjoerg } break;
39206f32e7eSjoerg case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: {
39306f32e7eSjoerg ld_plugin_register_all_symbols_read callback;
39406f32e7eSjoerg callback = tv->tv_u.tv_register_all_symbols_read;
39506f32e7eSjoerg
39606f32e7eSjoerg if (callback(all_symbols_read_hook) != LDPS_OK)
39706f32e7eSjoerg return LDPS_ERR;
39806f32e7eSjoerg
39906f32e7eSjoerg RegisteredAllSymbolsRead = true;
40006f32e7eSjoerg } break;
40106f32e7eSjoerg case LDPT_REGISTER_CLEANUP_HOOK: {
40206f32e7eSjoerg ld_plugin_register_cleanup callback;
40306f32e7eSjoerg callback = tv->tv_u.tv_register_cleanup;
40406f32e7eSjoerg
40506f32e7eSjoerg if (callback(cleanup_hook) != LDPS_OK)
40606f32e7eSjoerg return LDPS_ERR;
40706f32e7eSjoerg } break;
40806f32e7eSjoerg case LDPT_GET_INPUT_FILE:
40906f32e7eSjoerg get_input_file = tv->tv_u.tv_get_input_file;
41006f32e7eSjoerg break;
41106f32e7eSjoerg case LDPT_RELEASE_INPUT_FILE:
41206f32e7eSjoerg release_input_file = tv->tv_u.tv_release_input_file;
41306f32e7eSjoerg break;
41406f32e7eSjoerg case LDPT_ADD_SYMBOLS:
41506f32e7eSjoerg add_symbols = tv->tv_u.tv_add_symbols;
41606f32e7eSjoerg break;
41706f32e7eSjoerg case LDPT_GET_SYMBOLS_V2:
41806f32e7eSjoerg // Do not override get_symbols_v3 with get_symbols_v2.
41906f32e7eSjoerg if (!get_symbols)
42006f32e7eSjoerg get_symbols = tv->tv_u.tv_get_symbols;
42106f32e7eSjoerg break;
42206f32e7eSjoerg case LDPT_GET_SYMBOLS_V3:
42306f32e7eSjoerg get_symbols = tv->tv_u.tv_get_symbols;
42406f32e7eSjoerg break;
42506f32e7eSjoerg case LDPT_ADD_INPUT_FILE:
42606f32e7eSjoerg add_input_file = tv->tv_u.tv_add_input_file;
42706f32e7eSjoerg break;
42806f32e7eSjoerg case LDPT_SET_EXTRA_LIBRARY_PATH:
42906f32e7eSjoerg set_extra_library_path = tv->tv_u.tv_set_extra_library_path;
43006f32e7eSjoerg break;
43106f32e7eSjoerg case LDPT_GET_VIEW:
43206f32e7eSjoerg get_view = tv->tv_u.tv_get_view;
43306f32e7eSjoerg break;
43406f32e7eSjoerg case LDPT_MESSAGE:
43506f32e7eSjoerg message = tv->tv_u.tv_message;
43606f32e7eSjoerg break;
43706f32e7eSjoerg case LDPT_GET_WRAP_SYMBOLS:
43806f32e7eSjoerg // FIXME: When binutils 2.31 (containing gold 1.16) is the minimum
43906f32e7eSjoerg // required version, this should be changed to:
44006f32e7eSjoerg // get_wrap_symbols = tv->tv_u.tv_get_wrap_symbols;
44106f32e7eSjoerg get_wrap_symbols =
44206f32e7eSjoerg (ld_plugin_get_wrap_symbols)tv->tv_u.tv_message;
44306f32e7eSjoerg break;
44406f32e7eSjoerg default:
44506f32e7eSjoerg break;
44606f32e7eSjoerg }
44706f32e7eSjoerg }
44806f32e7eSjoerg
44906f32e7eSjoerg if (!registeredClaimFile) {
45006f32e7eSjoerg message(LDPL_ERROR, "register_claim_file not passed to LLVMgold.");
45106f32e7eSjoerg return LDPS_ERR;
45206f32e7eSjoerg }
45306f32e7eSjoerg if (!add_symbols) {
45406f32e7eSjoerg message(LDPL_ERROR, "add_symbols not passed to LLVMgold.");
45506f32e7eSjoerg return LDPS_ERR;
45606f32e7eSjoerg }
45706f32e7eSjoerg
45806f32e7eSjoerg if (!RegisteredAllSymbolsRead)
45906f32e7eSjoerg return LDPS_OK;
46006f32e7eSjoerg
46106f32e7eSjoerg if (!get_input_file) {
46206f32e7eSjoerg message(LDPL_ERROR, "get_input_file not passed to LLVMgold.");
46306f32e7eSjoerg return LDPS_ERR;
46406f32e7eSjoerg }
46506f32e7eSjoerg if (!release_input_file) {
46606f32e7eSjoerg message(LDPL_ERROR, "release_input_file not passed to LLVMgold.");
46706f32e7eSjoerg return LDPS_ERR;
46806f32e7eSjoerg }
46906f32e7eSjoerg
47006f32e7eSjoerg return LDPS_OK;
47106f32e7eSjoerg }
47206f32e7eSjoerg
diagnosticHandler(const DiagnosticInfo & DI)47306f32e7eSjoerg static void diagnosticHandler(const DiagnosticInfo &DI) {
47406f32e7eSjoerg std::string ErrStorage;
47506f32e7eSjoerg {
47606f32e7eSjoerg raw_string_ostream OS(ErrStorage);
47706f32e7eSjoerg DiagnosticPrinterRawOStream DP(OS);
47806f32e7eSjoerg DI.print(DP);
47906f32e7eSjoerg }
48006f32e7eSjoerg ld_plugin_level Level;
48106f32e7eSjoerg switch (DI.getSeverity()) {
48206f32e7eSjoerg case DS_Error:
48306f32e7eSjoerg Level = LDPL_FATAL;
48406f32e7eSjoerg break;
48506f32e7eSjoerg case DS_Warning:
48606f32e7eSjoerg Level = LDPL_WARNING;
48706f32e7eSjoerg break;
48806f32e7eSjoerg case DS_Note:
48906f32e7eSjoerg case DS_Remark:
49006f32e7eSjoerg Level = LDPL_INFO;
49106f32e7eSjoerg break;
49206f32e7eSjoerg }
49306f32e7eSjoerg message(Level, "LLVM gold plugin: %s", ErrStorage.c_str());
49406f32e7eSjoerg }
49506f32e7eSjoerg
check(Error E,std::string Msg="LLVM gold plugin")49606f32e7eSjoerg static void check(Error E, std::string Msg = "LLVM gold plugin") {
49706f32e7eSjoerg handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
49806f32e7eSjoerg message(LDPL_FATAL, "%s: %s", Msg.c_str(), EIB.message().c_str());
49906f32e7eSjoerg return Error::success();
50006f32e7eSjoerg });
50106f32e7eSjoerg }
50206f32e7eSjoerg
check(Expected<T> E)50306f32e7eSjoerg template <typename T> static T check(Expected<T> E) {
50406f32e7eSjoerg if (E)
50506f32e7eSjoerg return std::move(*E);
50606f32e7eSjoerg check(E.takeError());
50706f32e7eSjoerg return T();
50806f32e7eSjoerg }
50906f32e7eSjoerg
51006f32e7eSjoerg /// Called by gold to see whether this file is one that our plugin can handle.
51106f32e7eSjoerg /// We'll try to open it and register all the symbols with add_symbol if
51206f32e7eSjoerg /// possible.
claim_file_hook(const ld_plugin_input_file * file,int * claimed)51306f32e7eSjoerg static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
51406f32e7eSjoerg int *claimed) {
51506f32e7eSjoerg MemoryBufferRef BufferRef;
51606f32e7eSjoerg std::unique_ptr<MemoryBuffer> Buffer;
51706f32e7eSjoerg if (get_view) {
51806f32e7eSjoerg const void *view;
51906f32e7eSjoerg if (get_view(file->handle, &view) != LDPS_OK) {
52006f32e7eSjoerg message(LDPL_ERROR, "Failed to get a view of %s", file->name);
52106f32e7eSjoerg return LDPS_ERR;
52206f32e7eSjoerg }
52306f32e7eSjoerg BufferRef =
52406f32e7eSjoerg MemoryBufferRef(StringRef((const char *)view, file->filesize), "");
52506f32e7eSjoerg } else {
52606f32e7eSjoerg int64_t offset = 0;
52706f32e7eSjoerg // Gold has found what might be IR part-way inside of a file, such as
52806f32e7eSjoerg // an .a archive.
52906f32e7eSjoerg if (file->offset) {
53006f32e7eSjoerg offset = file->offset;
53106f32e7eSjoerg }
53206f32e7eSjoerg ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
53306f32e7eSjoerg MemoryBuffer::getOpenFileSlice(sys::fs::convertFDToNativeFile(file->fd),
53406f32e7eSjoerg file->name, file->filesize, offset);
53506f32e7eSjoerg if (std::error_code EC = BufferOrErr.getError()) {
53606f32e7eSjoerg message(LDPL_ERROR, EC.message().c_str());
53706f32e7eSjoerg return LDPS_ERR;
53806f32e7eSjoerg }
53906f32e7eSjoerg Buffer = std::move(BufferOrErr.get());
54006f32e7eSjoerg BufferRef = Buffer->getMemBufferRef();
54106f32e7eSjoerg }
54206f32e7eSjoerg
54306f32e7eSjoerg *claimed = 1;
54406f32e7eSjoerg
54506f32e7eSjoerg Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(BufferRef);
54606f32e7eSjoerg if (!ObjOrErr) {
54706f32e7eSjoerg handleAllErrors(ObjOrErr.takeError(), [&](const ErrorInfoBase &EI) {
54806f32e7eSjoerg std::error_code EC = EI.convertToErrorCode();
54906f32e7eSjoerg if (EC == object::object_error::invalid_file_type ||
55006f32e7eSjoerg EC == object::object_error::bitcode_section_not_found)
55106f32e7eSjoerg *claimed = 0;
55206f32e7eSjoerg else
55306f32e7eSjoerg message(LDPL_FATAL,
55406f32e7eSjoerg "LLVM gold plugin has failed to create LTO module: %s",
55506f32e7eSjoerg EI.message().c_str());
55606f32e7eSjoerg });
55706f32e7eSjoerg
55806f32e7eSjoerg return *claimed ? LDPS_ERR : LDPS_OK;
55906f32e7eSjoerg }
56006f32e7eSjoerg
56106f32e7eSjoerg std::unique_ptr<InputFile> Obj = std::move(*ObjOrErr);
56206f32e7eSjoerg
56306f32e7eSjoerg Modules.emplace_back();
56406f32e7eSjoerg claimed_file &cf = Modules.back();
56506f32e7eSjoerg
56606f32e7eSjoerg cf.handle = file->handle;
56706f32e7eSjoerg // Keep track of the first handle for each file descriptor, since there are
56806f32e7eSjoerg // multiple in the case of an archive. This is used later in the case of
56906f32e7eSjoerg // ThinLTO parallel backends to ensure that each file is only opened and
57006f32e7eSjoerg // released once.
57106f32e7eSjoerg auto LeaderHandle =
57206f32e7eSjoerg FDToLeaderHandle.insert(std::make_pair(file->fd, file->handle)).first;
57306f32e7eSjoerg cf.leader_handle = LeaderHandle->second;
57406f32e7eSjoerg // Save the filesize since for parallel ThinLTO backends we can only
57506f32e7eSjoerg // invoke get_input_file once per archive (only for the leader handle).
57606f32e7eSjoerg cf.filesize = file->filesize;
57706f32e7eSjoerg // In the case of an archive library, all but the first member must have a
57806f32e7eSjoerg // non-zero offset, which we can append to the file name to obtain a
57906f32e7eSjoerg // unique name.
58006f32e7eSjoerg cf.name = file->name;
58106f32e7eSjoerg if (file->offset)
58206f32e7eSjoerg cf.name += ".llvm." + std::to_string(file->offset) + "." +
58306f32e7eSjoerg sys::path::filename(Obj->getSourceFileName()).str();
58406f32e7eSjoerg
58506f32e7eSjoerg for (auto &Sym : Obj->symbols()) {
58606f32e7eSjoerg cf.syms.push_back(ld_plugin_symbol());
58706f32e7eSjoerg ld_plugin_symbol &sym = cf.syms.back();
58806f32e7eSjoerg sym.version = nullptr;
58906f32e7eSjoerg StringRef Name = Sym.getName();
59006f32e7eSjoerg sym.name = strdup(Name.str().c_str());
59106f32e7eSjoerg
59206f32e7eSjoerg ResolutionInfo &Res = ResInfo[Name];
59306f32e7eSjoerg
59406f32e7eSjoerg Res.CanOmitFromDynSym &= Sym.canBeOmittedFromSymbolTable();
59506f32e7eSjoerg
59606f32e7eSjoerg sym.visibility = LDPV_DEFAULT;
59706f32e7eSjoerg GlobalValue::VisibilityTypes Vis = Sym.getVisibility();
59806f32e7eSjoerg if (Vis != GlobalValue::DefaultVisibility)
59906f32e7eSjoerg Res.DefaultVisibility = false;
60006f32e7eSjoerg switch (Vis) {
60106f32e7eSjoerg case GlobalValue::DefaultVisibility:
60206f32e7eSjoerg break;
60306f32e7eSjoerg case GlobalValue::HiddenVisibility:
60406f32e7eSjoerg sym.visibility = LDPV_HIDDEN;
60506f32e7eSjoerg break;
60606f32e7eSjoerg case GlobalValue::ProtectedVisibility:
60706f32e7eSjoerg sym.visibility = LDPV_PROTECTED;
60806f32e7eSjoerg break;
60906f32e7eSjoerg }
61006f32e7eSjoerg
61106f32e7eSjoerg if (Sym.isUndefined()) {
61206f32e7eSjoerg sym.def = LDPK_UNDEF;
61306f32e7eSjoerg if (Sym.isWeak())
61406f32e7eSjoerg sym.def = LDPK_WEAKUNDEF;
61506f32e7eSjoerg } else if (Sym.isCommon())
61606f32e7eSjoerg sym.def = LDPK_COMMON;
61706f32e7eSjoerg else if (Sym.isWeak())
61806f32e7eSjoerg sym.def = LDPK_WEAKDEF;
61906f32e7eSjoerg else
62006f32e7eSjoerg sym.def = LDPK_DEF;
62106f32e7eSjoerg
62206f32e7eSjoerg sym.size = 0;
62306f32e7eSjoerg sym.comdat_key = nullptr;
62406f32e7eSjoerg int CI = Sym.getComdatIndex();
62506f32e7eSjoerg if (CI != -1) {
62606f32e7eSjoerg StringRef C = Obj->getComdatTable()[CI];
62706f32e7eSjoerg sym.comdat_key = strdup(C.str().c_str());
62806f32e7eSjoerg }
62906f32e7eSjoerg
63006f32e7eSjoerg sym.resolution = LDPR_UNKNOWN;
63106f32e7eSjoerg }
63206f32e7eSjoerg
63306f32e7eSjoerg if (!cf.syms.empty()) {
63406f32e7eSjoerg if (add_symbols(cf.handle, cf.syms.size(), cf.syms.data()) != LDPS_OK) {
63506f32e7eSjoerg message(LDPL_ERROR, "Unable to add symbols!");
63606f32e7eSjoerg return LDPS_ERR;
63706f32e7eSjoerg }
63806f32e7eSjoerg }
63906f32e7eSjoerg
64006f32e7eSjoerg // Handle any --wrap options passed to gold, which are than passed
64106f32e7eSjoerg // along to the plugin.
64206f32e7eSjoerg if (get_wrap_symbols) {
64306f32e7eSjoerg const char **wrap_symbols;
64406f32e7eSjoerg uint64_t count = 0;
64506f32e7eSjoerg if (get_wrap_symbols(&count, &wrap_symbols) != LDPS_OK) {
64606f32e7eSjoerg message(LDPL_ERROR, "Unable to get wrap symbols!");
64706f32e7eSjoerg return LDPS_ERR;
64806f32e7eSjoerg }
64906f32e7eSjoerg for (uint64_t i = 0; i < count; i++) {
65006f32e7eSjoerg StringRef Name = wrap_symbols[i];
65106f32e7eSjoerg ResolutionInfo &Res = ResInfo[Name];
65206f32e7eSjoerg ResolutionInfo &WrapRes = ResInfo["__wrap_" + Name.str()];
65306f32e7eSjoerg ResolutionInfo &RealRes = ResInfo["__real_" + Name.str()];
65406f32e7eSjoerg // Tell LTO not to inline symbols that will be overwritten.
65506f32e7eSjoerg Res.CanInline = false;
65606f32e7eSjoerg RealRes.CanInline = false;
65706f32e7eSjoerg // Tell LTO not to eliminate symbols that will be used after renaming.
65806f32e7eSjoerg Res.IsUsedInRegularObj = true;
65906f32e7eSjoerg WrapRes.IsUsedInRegularObj = true;
66006f32e7eSjoerg }
66106f32e7eSjoerg }
66206f32e7eSjoerg
66306f32e7eSjoerg return LDPS_OK;
66406f32e7eSjoerg }
66506f32e7eSjoerg
freeSymName(ld_plugin_symbol & Sym)66606f32e7eSjoerg static void freeSymName(ld_plugin_symbol &Sym) {
66706f32e7eSjoerg free(Sym.name);
66806f32e7eSjoerg free(Sym.comdat_key);
66906f32e7eSjoerg Sym.name = nullptr;
67006f32e7eSjoerg Sym.comdat_key = nullptr;
67106f32e7eSjoerg }
67206f32e7eSjoerg
67306f32e7eSjoerg /// Helper to get a file's symbols and a view into it via gold callbacks.
getSymbolsAndView(claimed_file & F)67406f32e7eSjoerg static const void *getSymbolsAndView(claimed_file &F) {
67506f32e7eSjoerg ld_plugin_status status = get_symbols(F.handle, F.syms.size(), F.syms.data());
67606f32e7eSjoerg if (status == LDPS_NO_SYMS)
67706f32e7eSjoerg return nullptr;
67806f32e7eSjoerg
67906f32e7eSjoerg if (status != LDPS_OK)
68006f32e7eSjoerg message(LDPL_FATAL, "Failed to get symbol information");
68106f32e7eSjoerg
68206f32e7eSjoerg const void *View;
68306f32e7eSjoerg if (get_view(F.handle, &View) != LDPS_OK)
68406f32e7eSjoerg message(LDPL_FATAL, "Failed to get a view of file");
68506f32e7eSjoerg
68606f32e7eSjoerg return View;
68706f32e7eSjoerg }
68806f32e7eSjoerg
68906f32e7eSjoerg /// Parse the thinlto-object-suffix-replace option into the \p OldSuffix and
69006f32e7eSjoerg /// \p NewSuffix strings, if it was specified.
getThinLTOOldAndNewSuffix(std::string & OldSuffix,std::string & NewSuffix)69106f32e7eSjoerg static void getThinLTOOldAndNewSuffix(std::string &OldSuffix,
69206f32e7eSjoerg std::string &NewSuffix) {
69306f32e7eSjoerg assert(options::thinlto_object_suffix_replace.empty() ||
694*da58b97aSjoerg options::thinlto_object_suffix_replace.find(';') != StringRef::npos);
69506f32e7eSjoerg StringRef SuffixReplace = options::thinlto_object_suffix_replace;
696*da58b97aSjoerg auto Split = SuffixReplace.split(';');
697*da58b97aSjoerg OldSuffix = std::string(Split.first);
698*da58b97aSjoerg NewSuffix = std::string(Split.second);
69906f32e7eSjoerg }
70006f32e7eSjoerg
70106f32e7eSjoerg /// Given the original \p Path to an output file, replace any filename
70206f32e7eSjoerg /// suffix matching \p OldSuffix with \p NewSuffix.
getThinLTOObjectFileName(StringRef Path,StringRef OldSuffix,StringRef NewSuffix)70306f32e7eSjoerg static std::string getThinLTOObjectFileName(StringRef Path, StringRef OldSuffix,
70406f32e7eSjoerg StringRef NewSuffix) {
70506f32e7eSjoerg if (Path.consume_back(OldSuffix))
70606f32e7eSjoerg return (Path + NewSuffix).str();
707*da58b97aSjoerg return std::string(Path);
70806f32e7eSjoerg }
70906f32e7eSjoerg
71006f32e7eSjoerg // Returns true if S is valid as a C language identifier.
isValidCIdentifier(StringRef S)71106f32e7eSjoerg static bool isValidCIdentifier(StringRef S) {
71206f32e7eSjoerg return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
71306f32e7eSjoerg std::all_of(S.begin() + 1, S.end(),
71406f32e7eSjoerg [](char C) { return C == '_' || isAlnum(C); });
71506f32e7eSjoerg }
71606f32e7eSjoerg
isUndefined(ld_plugin_symbol & Sym)71706f32e7eSjoerg static bool isUndefined(ld_plugin_symbol &Sym) {
71806f32e7eSjoerg return Sym.def == LDPK_UNDEF || Sym.def == LDPK_WEAKUNDEF;
71906f32e7eSjoerg }
72006f32e7eSjoerg
addModule(LTO & Lto,claimed_file & F,const void * View,StringRef Filename)72106f32e7eSjoerg static void addModule(LTO &Lto, claimed_file &F, const void *View,
72206f32e7eSjoerg StringRef Filename) {
72306f32e7eSjoerg MemoryBufferRef BufferRef(StringRef((const char *)View, F.filesize),
72406f32e7eSjoerg Filename);
72506f32e7eSjoerg Expected<std::unique_ptr<InputFile>> ObjOrErr = InputFile::create(BufferRef);
72606f32e7eSjoerg
72706f32e7eSjoerg if (!ObjOrErr)
72806f32e7eSjoerg message(LDPL_FATAL, "Could not read bitcode from file : %s",
72906f32e7eSjoerg toString(ObjOrErr.takeError()).c_str());
73006f32e7eSjoerg
73106f32e7eSjoerg unsigned SymNum = 0;
73206f32e7eSjoerg std::unique_ptr<InputFile> Input = std::move(ObjOrErr.get());
73306f32e7eSjoerg auto InputFileSyms = Input->symbols();
73406f32e7eSjoerg assert(InputFileSyms.size() == F.syms.size());
73506f32e7eSjoerg std::vector<SymbolResolution> Resols(F.syms.size());
73606f32e7eSjoerg for (ld_plugin_symbol &Sym : F.syms) {
73706f32e7eSjoerg const InputFile::Symbol &InpSym = InputFileSyms[SymNum];
73806f32e7eSjoerg SymbolResolution &R = Resols[SymNum++];
73906f32e7eSjoerg
74006f32e7eSjoerg ld_plugin_symbol_resolution Resolution =
74106f32e7eSjoerg (ld_plugin_symbol_resolution)Sym.resolution;
74206f32e7eSjoerg
74306f32e7eSjoerg ResolutionInfo &Res = ResInfo[Sym.name];
74406f32e7eSjoerg
74506f32e7eSjoerg switch (Resolution) {
74606f32e7eSjoerg case LDPR_UNKNOWN:
74706f32e7eSjoerg llvm_unreachable("Unexpected resolution");
74806f32e7eSjoerg
74906f32e7eSjoerg case LDPR_RESOLVED_IR:
75006f32e7eSjoerg case LDPR_RESOLVED_EXEC:
75106f32e7eSjoerg case LDPR_PREEMPTED_IR:
75206f32e7eSjoerg case LDPR_PREEMPTED_REG:
75306f32e7eSjoerg case LDPR_UNDEF:
75406f32e7eSjoerg break;
75506f32e7eSjoerg
756*da58b97aSjoerg case LDPR_RESOLVED_DYN:
757*da58b97aSjoerg R.ExportDynamic = true;
758*da58b97aSjoerg break;
759*da58b97aSjoerg
76006f32e7eSjoerg case LDPR_PREVAILING_DEF_IRONLY:
76106f32e7eSjoerg R.Prevailing = !isUndefined(Sym);
76206f32e7eSjoerg break;
76306f32e7eSjoerg
76406f32e7eSjoerg case LDPR_PREVAILING_DEF:
76506f32e7eSjoerg R.Prevailing = !isUndefined(Sym);
76606f32e7eSjoerg R.VisibleToRegularObj = true;
76706f32e7eSjoerg break;
76806f32e7eSjoerg
76906f32e7eSjoerg case LDPR_PREVAILING_DEF_IRONLY_EXP:
77006f32e7eSjoerg R.Prevailing = !isUndefined(Sym);
771*da58b97aSjoerg // Identify symbols exported dynamically, and that therefore could be
772*da58b97aSjoerg // referenced by a shared library not visible to the linker.
773*da58b97aSjoerg R.ExportDynamic = true;
77406f32e7eSjoerg if (!Res.CanOmitFromDynSym)
77506f32e7eSjoerg R.VisibleToRegularObj = true;
77606f32e7eSjoerg break;
77706f32e7eSjoerg }
77806f32e7eSjoerg
77906f32e7eSjoerg // If the symbol has a C identifier section name, we need to mark
78006f32e7eSjoerg // it as visible to a regular object so that LTO will keep it around
78106f32e7eSjoerg // to ensure the linker generates special __start_<secname> and
78206f32e7eSjoerg // __stop_<secname> symbols which may be used elsewhere.
78306f32e7eSjoerg if (isValidCIdentifier(InpSym.getSectionName()))
78406f32e7eSjoerg R.VisibleToRegularObj = true;
78506f32e7eSjoerg
78606f32e7eSjoerg if (Resolution != LDPR_RESOLVED_DYN && Resolution != LDPR_UNDEF &&
78706f32e7eSjoerg (IsExecutable || !Res.DefaultVisibility))
78806f32e7eSjoerg R.FinalDefinitionInLinkageUnit = true;
78906f32e7eSjoerg
79006f32e7eSjoerg if (!Res.CanInline)
79106f32e7eSjoerg R.LinkerRedefined = true;
79206f32e7eSjoerg
79306f32e7eSjoerg if (Res.IsUsedInRegularObj)
79406f32e7eSjoerg R.VisibleToRegularObj = true;
79506f32e7eSjoerg
79606f32e7eSjoerg freeSymName(Sym);
79706f32e7eSjoerg }
79806f32e7eSjoerg
79906f32e7eSjoerg check(Lto.add(std::move(Input), Resols),
80006f32e7eSjoerg std::string("Failed to link module ") + F.name);
80106f32e7eSjoerg }
80206f32e7eSjoerg
recordFile(const std::string & Filename,bool TempOutFile)80306f32e7eSjoerg static void recordFile(const std::string &Filename, bool TempOutFile) {
80406f32e7eSjoerg if (add_input_file(Filename.c_str()) != LDPS_OK)
80506f32e7eSjoerg message(LDPL_FATAL,
80606f32e7eSjoerg "Unable to add .o file to the link. File left behind in: %s",
80706f32e7eSjoerg Filename.c_str());
80806f32e7eSjoerg if (TempOutFile)
80906f32e7eSjoerg Cleanup.push_back(Filename);
81006f32e7eSjoerg }
81106f32e7eSjoerg
81206f32e7eSjoerg /// Return the desired output filename given a base input name, a flag
81306f32e7eSjoerg /// indicating whether a temp file should be generated, and an optional task id.
81406f32e7eSjoerg /// The new filename generated is returned in \p NewFilename.
getOutputFileName(StringRef InFilename,bool TempOutFile,SmallString<128> & NewFilename,int TaskID)81506f32e7eSjoerg static int getOutputFileName(StringRef InFilename, bool TempOutFile,
81606f32e7eSjoerg SmallString<128> &NewFilename, int TaskID) {
81706f32e7eSjoerg int FD = -1;
81806f32e7eSjoerg if (TempOutFile) {
81906f32e7eSjoerg std::error_code EC =
82006f32e7eSjoerg sys::fs::createTemporaryFile("lto-llvm", "o", FD, NewFilename);
82106f32e7eSjoerg if (EC)
82206f32e7eSjoerg message(LDPL_FATAL, "Could not create temporary file: %s",
82306f32e7eSjoerg EC.message().c_str());
82406f32e7eSjoerg } else {
82506f32e7eSjoerg NewFilename = InFilename;
82606f32e7eSjoerg if (TaskID > 0)
82706f32e7eSjoerg NewFilename += utostr(TaskID);
82806f32e7eSjoerg std::error_code EC =
82906f32e7eSjoerg sys::fs::openFileForWrite(NewFilename, FD, sys::fs::CD_CreateAlways);
83006f32e7eSjoerg if (EC)
83106f32e7eSjoerg message(LDPL_FATAL, "Could not open file %s: %s", NewFilename.c_str(),
83206f32e7eSjoerg EC.message().c_str());
83306f32e7eSjoerg }
83406f32e7eSjoerg return FD;
83506f32e7eSjoerg }
83606f32e7eSjoerg
getCGOptLevel()83706f32e7eSjoerg static CodeGenOpt::Level getCGOptLevel() {
83806f32e7eSjoerg switch (options::OptLevel) {
83906f32e7eSjoerg case 0:
84006f32e7eSjoerg return CodeGenOpt::None;
84106f32e7eSjoerg case 1:
84206f32e7eSjoerg return CodeGenOpt::Less;
84306f32e7eSjoerg case 2:
84406f32e7eSjoerg return CodeGenOpt::Default;
84506f32e7eSjoerg case 3:
84606f32e7eSjoerg return CodeGenOpt::Aggressive;
84706f32e7eSjoerg }
84806f32e7eSjoerg llvm_unreachable("Invalid optimization level");
84906f32e7eSjoerg }
85006f32e7eSjoerg
85106f32e7eSjoerg /// Parse the thinlto_prefix_replace option into the \p OldPrefix and
85206f32e7eSjoerg /// \p NewPrefix strings, if it was specified.
getThinLTOOldAndNewPrefix(std::string & OldPrefix,std::string & NewPrefix)85306f32e7eSjoerg static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,
85406f32e7eSjoerg std::string &NewPrefix) {
85506f32e7eSjoerg StringRef PrefixReplace = options::thinlto_prefix_replace;
856*da58b97aSjoerg assert(PrefixReplace.empty() || PrefixReplace.find(';') != StringRef::npos);
857*da58b97aSjoerg auto Split = PrefixReplace.split(';');
858*da58b97aSjoerg OldPrefix = std::string(Split.first);
859*da58b97aSjoerg NewPrefix = std::string(Split.second);
86006f32e7eSjoerg }
86106f32e7eSjoerg
86206f32e7eSjoerg /// Creates instance of LTO.
86306f32e7eSjoerg /// OnIndexWrite is callback to let caller know when LTO writes index files.
86406f32e7eSjoerg /// LinkedObjectsFile is an output stream to write the list of object files for
86506f32e7eSjoerg /// the final ThinLTO linking. Can be nullptr.
createLTO(IndexWriteCallback OnIndexWrite,raw_fd_ostream * LinkedObjectsFile)86606f32e7eSjoerg static std::unique_ptr<LTO> createLTO(IndexWriteCallback OnIndexWrite,
86706f32e7eSjoerg raw_fd_ostream *LinkedObjectsFile) {
86806f32e7eSjoerg Config Conf;
86906f32e7eSjoerg ThinBackend Backend;
87006f32e7eSjoerg
87106f32e7eSjoerg Conf.CPU = options::mcpu;
872*da58b97aSjoerg Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
87306f32e7eSjoerg
87406f32e7eSjoerg // Disable the new X86 relax relocations since gold might not support them.
87506f32e7eSjoerg // FIXME: Check the gold version or add a new option to enable them.
87606f32e7eSjoerg Conf.Options.RelaxELFRelocations = false;
87706f32e7eSjoerg
87806f32e7eSjoerg // Toggle function/data sections.
879*da58b97aSjoerg if (!codegen::getExplicitFunctionSections())
88006f32e7eSjoerg Conf.Options.FunctionSections = SplitSections;
881*da58b97aSjoerg if (!codegen::getExplicitDataSections())
88206f32e7eSjoerg Conf.Options.DataSections = SplitSections;
88306f32e7eSjoerg
884*da58b97aSjoerg Conf.MAttrs = codegen::getMAttrs();
88506f32e7eSjoerg Conf.RelocModel = RelocationModel;
886*da58b97aSjoerg Conf.CodeModel = codegen::getExplicitCodeModel();
88706f32e7eSjoerg Conf.CGOptLevel = getCGOptLevel();
88806f32e7eSjoerg Conf.DisableVerify = options::DisableVerify;
88906f32e7eSjoerg Conf.OptLevel = options::OptLevel;
890*da58b97aSjoerg Conf.PTO.LoopVectorization = options::OptLevel > 1;
891*da58b97aSjoerg Conf.PTO.SLPVectorization = options::OptLevel > 1;
892*da58b97aSjoerg Conf.AlwaysEmitRegularLTOObj = !options::obj_path.empty();
893*da58b97aSjoerg
89406f32e7eSjoerg if (options::thinlto_index_only) {
89506f32e7eSjoerg std::string OldPrefix, NewPrefix;
89606f32e7eSjoerg getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
89706f32e7eSjoerg Backend = createWriteIndexesThinBackend(OldPrefix, NewPrefix,
89806f32e7eSjoerg options::thinlto_emit_imports_files,
89906f32e7eSjoerg LinkedObjectsFile, OnIndexWrite);
900*da58b97aSjoerg } else {
901*da58b97aSjoerg Backend = createInProcessThinBackend(
902*da58b97aSjoerg llvm::heavyweight_hardware_concurrency(options::Parallelism));
90306f32e7eSjoerg }
90406f32e7eSjoerg
90506f32e7eSjoerg Conf.OverrideTriple = options::triple;
90606f32e7eSjoerg Conf.DefaultTriple = sys::getDefaultTargetTriple();
90706f32e7eSjoerg
90806f32e7eSjoerg Conf.DiagHandler = diagnosticHandler;
90906f32e7eSjoerg
91006f32e7eSjoerg switch (options::TheOutputType) {
91106f32e7eSjoerg case options::OT_NORMAL:
91206f32e7eSjoerg break;
91306f32e7eSjoerg
91406f32e7eSjoerg case options::OT_DISABLE:
91506f32e7eSjoerg Conf.PreOptModuleHook = [](size_t Task, const Module &M) { return false; };
91606f32e7eSjoerg break;
91706f32e7eSjoerg
91806f32e7eSjoerg case options::OT_BC_ONLY:
91906f32e7eSjoerg Conf.PostInternalizeModuleHook = [](size_t Task, const Module &M) {
92006f32e7eSjoerg std::error_code EC;
921*da58b97aSjoerg SmallString<128> TaskFilename;
922*da58b97aSjoerg getOutputFileName(output_name, /* TempOutFile */ false, TaskFilename,
923*da58b97aSjoerg Task);
924*da58b97aSjoerg raw_fd_ostream OS(TaskFilename, EC, sys::fs::OpenFlags::OF_None);
92506f32e7eSjoerg if (EC)
92606f32e7eSjoerg message(LDPL_FATAL, "Failed to write the output file.");
92706f32e7eSjoerg WriteBitcodeToFile(M, OS, /* ShouldPreserveUseListOrder */ false);
92806f32e7eSjoerg return false;
92906f32e7eSjoerg };
93006f32e7eSjoerg break;
93106f32e7eSjoerg
93206f32e7eSjoerg case options::OT_SAVE_TEMPS:
93306f32e7eSjoerg check(Conf.addSaveTemps(output_name + ".",
93406f32e7eSjoerg /* UseInputModulePath */ true));
93506f32e7eSjoerg break;
93606f32e7eSjoerg case options::OT_ASM_ONLY:
937*da58b97aSjoerg Conf.CGFileType = CGFT_AssemblyFile;
93806f32e7eSjoerg break;
93906f32e7eSjoerg }
94006f32e7eSjoerg
94106f32e7eSjoerg if (!options::sample_profile.empty())
94206f32e7eSjoerg Conf.SampleProfile = options::sample_profile;
94306f32e7eSjoerg
94406f32e7eSjoerg if (!options::cs_profile_path.empty())
94506f32e7eSjoerg Conf.CSIRProfile = options::cs_profile_path;
94606f32e7eSjoerg Conf.RunCSIRInstr = options::cs_pgo_gen;
94706f32e7eSjoerg
94806f32e7eSjoerg Conf.DwoDir = options::dwo_dir;
94906f32e7eSjoerg
95006f32e7eSjoerg // Set up optimization remarks handling.
95106f32e7eSjoerg Conf.RemarksFilename = options::RemarksFilename;
95206f32e7eSjoerg Conf.RemarksPasses = options::RemarksPasses;
95306f32e7eSjoerg Conf.RemarksWithHotness = options::RemarksWithHotness;
954*da58b97aSjoerg Conf.RemarksHotnessThreshold = options::RemarksHotnessThreshold;
95506f32e7eSjoerg Conf.RemarksFormat = options::RemarksFormat;
95606f32e7eSjoerg
95706f32e7eSjoerg // Use new pass manager if set in driver
95806f32e7eSjoerg Conf.UseNewPM = options::new_pass_manager;
95906f32e7eSjoerg // Debug new pass manager if requested
96006f32e7eSjoerg Conf.DebugPassManager = options::debug_pass_manager;
96106f32e7eSjoerg
962*da58b97aSjoerg Conf.HasWholeProgramVisibility = options::whole_program_visibility;
963*da58b97aSjoerg
96406f32e7eSjoerg Conf.StatsFile = options::stats_file;
96506f32e7eSjoerg return std::make_unique<LTO>(std::move(Conf), Backend,
96606f32e7eSjoerg options::ParallelCodeGenParallelismLevel);
96706f32e7eSjoerg }
96806f32e7eSjoerg
96906f32e7eSjoerg // Write empty files that may be expected by a distributed build
97006f32e7eSjoerg // system when invoked with thinlto_index_only. This is invoked when
97106f32e7eSjoerg // the linker has decided not to include the given module in the
97206f32e7eSjoerg // final link. Frequently the distributed build system will want to
97306f32e7eSjoerg // confirm that all expected outputs are created based on all of the
97406f32e7eSjoerg // modules provided to the linker.
97506f32e7eSjoerg // If SkipModule is true then .thinlto.bc should contain just
97606f32e7eSjoerg // SkipModuleByDistributedBackend flag which requests distributed backend
97706f32e7eSjoerg // to skip the compilation of the corresponding module and produce an empty
97806f32e7eSjoerg // object file.
writeEmptyDistributedBuildOutputs(const std::string & ModulePath,const std::string & OldPrefix,const std::string & NewPrefix,bool SkipModule)97906f32e7eSjoerg static void writeEmptyDistributedBuildOutputs(const std::string &ModulePath,
98006f32e7eSjoerg const std::string &OldPrefix,
98106f32e7eSjoerg const std::string &NewPrefix,
98206f32e7eSjoerg bool SkipModule) {
98306f32e7eSjoerg std::string NewModulePath =
98406f32e7eSjoerg getThinLTOOutputFile(ModulePath, OldPrefix, NewPrefix);
98506f32e7eSjoerg std::error_code EC;
98606f32e7eSjoerg {
98706f32e7eSjoerg raw_fd_ostream OS(NewModulePath + ".thinlto.bc", EC,
98806f32e7eSjoerg sys::fs::OpenFlags::OF_None);
98906f32e7eSjoerg if (EC)
99006f32e7eSjoerg message(LDPL_FATAL, "Failed to write '%s': %s",
99106f32e7eSjoerg (NewModulePath + ".thinlto.bc").c_str(), EC.message().c_str());
99206f32e7eSjoerg
99306f32e7eSjoerg if (SkipModule) {
99406f32e7eSjoerg ModuleSummaryIndex Index(/*HaveGVs*/ false);
99506f32e7eSjoerg Index.setSkipModuleByDistributedBackend();
99606f32e7eSjoerg WriteIndexToFile(Index, OS, nullptr);
99706f32e7eSjoerg }
99806f32e7eSjoerg }
99906f32e7eSjoerg if (options::thinlto_emit_imports_files) {
100006f32e7eSjoerg raw_fd_ostream OS(NewModulePath + ".imports", EC,
100106f32e7eSjoerg sys::fs::OpenFlags::OF_None);
100206f32e7eSjoerg if (EC)
100306f32e7eSjoerg message(LDPL_FATAL, "Failed to write '%s': %s",
100406f32e7eSjoerg (NewModulePath + ".imports").c_str(), EC.message().c_str());
100506f32e7eSjoerg }
100606f32e7eSjoerg }
100706f32e7eSjoerg
100806f32e7eSjoerg // Creates and returns output stream with a list of object files for final
100906f32e7eSjoerg // linking of distributed ThinLTO.
CreateLinkedObjectsFile()101006f32e7eSjoerg static std::unique_ptr<raw_fd_ostream> CreateLinkedObjectsFile() {
101106f32e7eSjoerg if (options::thinlto_linked_objects_file.empty())
101206f32e7eSjoerg return nullptr;
101306f32e7eSjoerg assert(options::thinlto_index_only);
101406f32e7eSjoerg std::error_code EC;
101506f32e7eSjoerg auto LinkedObjectsFile = std::make_unique<raw_fd_ostream>(
101606f32e7eSjoerg options::thinlto_linked_objects_file, EC, sys::fs::OpenFlags::OF_None);
101706f32e7eSjoerg if (EC)
101806f32e7eSjoerg message(LDPL_FATAL, "Failed to create '%s': %s",
101906f32e7eSjoerg options::thinlto_linked_objects_file.c_str(), EC.message().c_str());
102006f32e7eSjoerg return LinkedObjectsFile;
102106f32e7eSjoerg }
102206f32e7eSjoerg
102306f32e7eSjoerg /// Runs LTO and return a list of pairs <FileName, IsTemporary>.
runLTO()102406f32e7eSjoerg static std::vector<std::pair<SmallString<128>, bool>> runLTO() {
102506f32e7eSjoerg // Map to own RAII objects that manage the file opening and releasing
102606f32e7eSjoerg // interfaces with gold. This is needed only for ThinLTO mode, since
102706f32e7eSjoerg // unlike regular LTO, where addModule will result in the opened file
102806f32e7eSjoerg // being merged into a new combined module, we need to keep these files open
102906f32e7eSjoerg // through Lto->run().
103006f32e7eSjoerg DenseMap<void *, std::unique_ptr<PluginInputFile>> HandleToInputFile;
103106f32e7eSjoerg
103206f32e7eSjoerg // Owns string objects and tells if index file was already created.
103306f32e7eSjoerg StringMap<bool> ObjectToIndexFileState;
103406f32e7eSjoerg
103506f32e7eSjoerg std::unique_ptr<raw_fd_ostream> LinkedObjects = CreateLinkedObjectsFile();
103606f32e7eSjoerg std::unique_ptr<LTO> Lto = createLTO(
103706f32e7eSjoerg [&ObjectToIndexFileState](const std::string &Identifier) {
103806f32e7eSjoerg ObjectToIndexFileState[Identifier] = true;
103906f32e7eSjoerg },
104006f32e7eSjoerg LinkedObjects.get());
104106f32e7eSjoerg
104206f32e7eSjoerg std::string OldPrefix, NewPrefix;
104306f32e7eSjoerg if (options::thinlto_index_only)
104406f32e7eSjoerg getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
104506f32e7eSjoerg
104606f32e7eSjoerg std::string OldSuffix, NewSuffix;
104706f32e7eSjoerg getThinLTOOldAndNewSuffix(OldSuffix, NewSuffix);
104806f32e7eSjoerg
104906f32e7eSjoerg for (claimed_file &F : Modules) {
105006f32e7eSjoerg if (options::thinlto && !HandleToInputFile.count(F.leader_handle))
105106f32e7eSjoerg HandleToInputFile.insert(std::make_pair(
105206f32e7eSjoerg F.leader_handle, std::make_unique<PluginInputFile>(F.handle)));
105306f32e7eSjoerg // In case we are thin linking with a minimized bitcode file, ensure
105406f32e7eSjoerg // the module paths encoded in the index reflect where the backends
105506f32e7eSjoerg // will locate the full bitcode files for compiling/importing.
105606f32e7eSjoerg std::string Identifier =
105706f32e7eSjoerg getThinLTOObjectFileName(F.name, OldSuffix, NewSuffix);
105806f32e7eSjoerg auto ObjFilename = ObjectToIndexFileState.insert({Identifier, false});
105906f32e7eSjoerg assert(ObjFilename.second);
106006f32e7eSjoerg if (const void *View = getSymbolsAndView(F))
106106f32e7eSjoerg addModule(*Lto, F, View, ObjFilename.first->first());
106206f32e7eSjoerg else if (options::thinlto_index_only) {
106306f32e7eSjoerg ObjFilename.first->second = true;
106406f32e7eSjoerg writeEmptyDistributedBuildOutputs(Identifier, OldPrefix, NewPrefix,
106506f32e7eSjoerg /* SkipModule */ true);
106606f32e7eSjoerg }
106706f32e7eSjoerg }
106806f32e7eSjoerg
106906f32e7eSjoerg SmallString<128> Filename;
107006f32e7eSjoerg // Note that getOutputFileName will append a unique ID for each task
107106f32e7eSjoerg if (!options::obj_path.empty())
107206f32e7eSjoerg Filename = options::obj_path;
107306f32e7eSjoerg else if (options::TheOutputType == options::OT_SAVE_TEMPS)
1074*da58b97aSjoerg Filename = output_name + ".lto.o";
107506f32e7eSjoerg else if (options::TheOutputType == options::OT_ASM_ONLY)
107606f32e7eSjoerg Filename = output_name;
107706f32e7eSjoerg bool SaveTemps = !Filename.empty();
107806f32e7eSjoerg
107906f32e7eSjoerg size_t MaxTasks = Lto->getMaxTasks();
108006f32e7eSjoerg std::vector<std::pair<SmallString<128>, bool>> Files(MaxTasks);
108106f32e7eSjoerg
108206f32e7eSjoerg auto AddStream =
108306f32e7eSjoerg [&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> {
108406f32e7eSjoerg Files[Task].second = !SaveTemps;
108506f32e7eSjoerg int FD = getOutputFileName(Filename, /* TempOutFile */ !SaveTemps,
108606f32e7eSjoerg Files[Task].first, Task);
108706f32e7eSjoerg return std::make_unique<lto::NativeObjectStream>(
108806f32e7eSjoerg std::make_unique<llvm::raw_fd_ostream>(FD, true));
108906f32e7eSjoerg };
109006f32e7eSjoerg
109106f32e7eSjoerg auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
109206f32e7eSjoerg *AddStream(Task)->OS << MB->getBuffer();
109306f32e7eSjoerg };
109406f32e7eSjoerg
109506f32e7eSjoerg NativeObjectCache Cache;
109606f32e7eSjoerg if (!options::cache_dir.empty())
109706f32e7eSjoerg Cache = check(localCache(options::cache_dir, AddBuffer));
109806f32e7eSjoerg
109906f32e7eSjoerg check(Lto->run(AddStream, Cache));
110006f32e7eSjoerg
110106f32e7eSjoerg // Write empty output files that may be expected by the distributed build
110206f32e7eSjoerg // system.
110306f32e7eSjoerg if (options::thinlto_index_only)
110406f32e7eSjoerg for (auto &Identifier : ObjectToIndexFileState)
110506f32e7eSjoerg if (!Identifier.getValue())
1106*da58b97aSjoerg writeEmptyDistributedBuildOutputs(std::string(Identifier.getKey()),
1107*da58b97aSjoerg OldPrefix, NewPrefix,
1108*da58b97aSjoerg /* SkipModule */ false);
110906f32e7eSjoerg
111006f32e7eSjoerg return Files;
111106f32e7eSjoerg }
111206f32e7eSjoerg
111306f32e7eSjoerg /// gold informs us that all symbols have been read. At this point, we use
111406f32e7eSjoerg /// get_symbols to see if any of our definitions have been overridden by a
111506f32e7eSjoerg /// native object file. Then, perform optimization and codegen.
allSymbolsReadHook()111606f32e7eSjoerg static ld_plugin_status allSymbolsReadHook() {
111706f32e7eSjoerg if (Modules.empty())
111806f32e7eSjoerg return LDPS_OK;
111906f32e7eSjoerg
112006f32e7eSjoerg if (unsigned NumOpts = options::extra.size())
112106f32e7eSjoerg cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
112206f32e7eSjoerg
112306f32e7eSjoerg std::vector<std::pair<SmallString<128>, bool>> Files = runLTO();
112406f32e7eSjoerg
112506f32e7eSjoerg if (options::TheOutputType == options::OT_DISABLE ||
112606f32e7eSjoerg options::TheOutputType == options::OT_BC_ONLY ||
112706f32e7eSjoerg options::TheOutputType == options::OT_ASM_ONLY)
112806f32e7eSjoerg return LDPS_OK;
112906f32e7eSjoerg
113006f32e7eSjoerg if (options::thinlto_index_only) {
113106f32e7eSjoerg llvm_shutdown();
113206f32e7eSjoerg cleanup_hook();
113306f32e7eSjoerg exit(0);
113406f32e7eSjoerg }
113506f32e7eSjoerg
113606f32e7eSjoerg for (const auto &F : Files)
113706f32e7eSjoerg if (!F.first.empty())
1138*da58b97aSjoerg recordFile(std::string(F.first.str()), F.second);
113906f32e7eSjoerg
114006f32e7eSjoerg if (!options::extra_library_path.empty() &&
114106f32e7eSjoerg set_extra_library_path(options::extra_library_path.c_str()) != LDPS_OK)
114206f32e7eSjoerg message(LDPL_FATAL, "Unable to set the extra library path.");
114306f32e7eSjoerg
114406f32e7eSjoerg return LDPS_OK;
114506f32e7eSjoerg }
114606f32e7eSjoerg
all_symbols_read_hook(void)114706f32e7eSjoerg static ld_plugin_status all_symbols_read_hook(void) {
114806f32e7eSjoerg ld_plugin_status Ret = allSymbolsReadHook();
114906f32e7eSjoerg llvm_shutdown();
115006f32e7eSjoerg
115106f32e7eSjoerg if (options::TheOutputType == options::OT_BC_ONLY ||
115206f32e7eSjoerg options::TheOutputType == options::OT_ASM_ONLY ||
115306f32e7eSjoerg options::TheOutputType == options::OT_DISABLE) {
115406f32e7eSjoerg if (options::TheOutputType == options::OT_DISABLE) {
115506f32e7eSjoerg // Remove the output file here since ld.bfd creates the output file
115606f32e7eSjoerg // early.
115706f32e7eSjoerg std::error_code EC = sys::fs::remove(output_name);
115806f32e7eSjoerg if (EC)
115906f32e7eSjoerg message(LDPL_ERROR, "Failed to delete '%s': %s", output_name.c_str(),
116006f32e7eSjoerg EC.message().c_str());
116106f32e7eSjoerg }
116206f32e7eSjoerg exit(0);
116306f32e7eSjoerg }
116406f32e7eSjoerg
116506f32e7eSjoerg return Ret;
116606f32e7eSjoerg }
116706f32e7eSjoerg
cleanup_hook(void)116806f32e7eSjoerg static ld_plugin_status cleanup_hook(void) {
116906f32e7eSjoerg for (std::string &Name : Cleanup) {
117006f32e7eSjoerg std::error_code EC = sys::fs::remove(Name);
117106f32e7eSjoerg if (EC)
117206f32e7eSjoerg message(LDPL_ERROR, "Failed to delete '%s': %s", Name.c_str(),
117306f32e7eSjoerg EC.message().c_str());
117406f32e7eSjoerg }
117506f32e7eSjoerg
117606f32e7eSjoerg // Prune cache
117706f32e7eSjoerg if (!options::cache_dir.empty()) {
117806f32e7eSjoerg CachePruningPolicy policy = check(parseCachePruningPolicy(options::cache_policy));
117906f32e7eSjoerg pruneCache(options::cache_dir, policy);
118006f32e7eSjoerg }
118106f32e7eSjoerg
118206f32e7eSjoerg return LDPS_OK;
118306f32e7eSjoerg }
1184