Home | History | Annotate | Download | only in gold
      1 //===-- gold-plugin.cpp - Plugin to gold for Link Time Optimization  ------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This is a gold plugin for LLVM. It provides an LLVM implementation of the
     11 // interface described in http://gcc.gnu.org/wiki/whopr/driver .
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
     16 #include "plugin-api.h"
     17 #include "llvm-c/lto.h"
     18 #include "llvm/ADT/OwningPtr.h"
     19 #include "llvm/Support/Errno.h"
     20 #include "llvm/Support/FileSystem.h"
     21 #include "llvm/Support/MemoryBuffer.h"
     22 #include "llvm/Support/Path.h"
     23 #include "llvm/Support/Program.h"
     24 #include "llvm/Support/ToolOutputFile.h"
     25 #include "llvm/Support/system_error.h"
     26 #include <cerrno>
     27 #include <cstdlib>
     28 #include <cstring>
     29 #include <fstream>
     30 #include <list>
     31 #include <vector>
     32 
     33 // Support Windows/MinGW crazyness.
     34 #ifdef _WIN32
     35 # include <io.h>
     36 # define lseek _lseek
     37 # define read _read
     38 #endif
     39 
     40 using namespace llvm;
     41 
     42 namespace {
     43   ld_plugin_status discard_message(int level, const char *format, ...) {
     44     // Die loudly. Recent versions of Gold pass ld_plugin_message as the first
     45     // callback in the transfer vector. This should never be called.
     46     abort();
     47   }
     48 
     49   ld_plugin_add_symbols add_symbols = NULL;
     50   ld_plugin_get_symbols get_symbols = NULL;
     51   ld_plugin_add_input_file add_input_file = NULL;
     52   ld_plugin_add_input_library add_input_library = NULL;
     53   ld_plugin_set_extra_library_path set_extra_library_path = NULL;
     54   ld_plugin_get_view get_view = NULL;
     55   ld_plugin_message message = discard_message;
     56 
     57   int api_version = 0;
     58   int gold_version = 0;
     59 
     60   struct claimed_file {
     61     void *handle;
     62     std::vector<ld_plugin_symbol> syms;
     63   };
     64 
     65   lto_codegen_model output_type = LTO_CODEGEN_PIC_MODEL_STATIC;
     66   std::string output_name = "";
     67   std::list<claimed_file> Modules;
     68   std::vector<std::string> Cleanup;
     69   lto_code_gen_t code_gen = NULL;
     70 }
     71 
     72 namespace options {
     73   enum generate_bc { BC_NO, BC_ALSO, BC_ONLY };
     74   static bool generate_api_file = false;
     75   static generate_bc generate_bc_file = BC_NO;
     76   static std::string bc_path;
     77   static std::string obj_path;
     78   static std::string extra_library_path;
     79   static std::string triple;
     80   static std::string mcpu;
     81   // Additional options to pass into the code generator.
     82   // Note: This array will contain all plugin options which are not claimed
     83   // as plugin exclusive to pass to the code generator.
     84   // For example, "generate-api-file" and "as"options are for the plugin
     85   // use only and will not be passed.
     86   static std::vector<std::string> extra;
     87 
     88   static void process_plugin_option(const char* opt_)
     89   {
     90     if (opt_ == NULL)
     91       return;
     92     llvm::StringRef opt = opt_;
     93 
     94     if (opt == "generate-api-file") {
     95       generate_api_file = true;
     96     } else if (opt.startswith("mcpu=")) {
     97       mcpu = opt.substr(strlen("mcpu="));
     98     } else if (opt.startswith("extra-library-path=")) {
     99       extra_library_path = opt.substr(strlen("extra_library_path="));
    100     } else if (opt.startswith("mtriple=")) {
    101       triple = opt.substr(strlen("mtriple="));
    102     } else if (opt.startswith("obj-path=")) {
    103       obj_path = opt.substr(strlen("obj-path="));
    104     } else if (opt == "emit-llvm") {
    105       generate_bc_file = BC_ONLY;
    106     } else if (opt == "also-emit-llvm") {
    107       generate_bc_file = BC_ALSO;
    108     } else if (opt.startswith("also-emit-llvm=")) {
    109       llvm::StringRef path = opt.substr(strlen("also-emit-llvm="));
    110       generate_bc_file = BC_ALSO;
    111       if (!bc_path.empty()) {
    112         (*message)(LDPL_WARNING, "Path to the output IL file specified twice. "
    113                    "Discarding %s", opt_);
    114       } else {
    115         bc_path = path;
    116       }
    117     } else {
    118       // Save this option to pass to the code generator.
    119       extra.push_back(opt);
    120     }
    121   }
    122 }
    123 
    124 static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
    125                                         int *claimed);
    126 static ld_plugin_status all_symbols_read_hook(void);
    127 static ld_plugin_status cleanup_hook(void);
    128 
    129 extern "C" ld_plugin_status onload(ld_plugin_tv *tv);
    130 ld_plugin_status onload(ld_plugin_tv *tv) {
    131   // We're given a pointer to the first transfer vector. We read through them
    132   // until we find one where tv_tag == LDPT_NULL. The REGISTER_* tagged values
    133   // contain pointers to functions that we need to call to register our own
    134   // hooks. The others are addresses of functions we can use to call into gold
    135   // for services.
    136 
    137   bool registeredClaimFile = false;
    138 
    139   for (; tv->tv_tag != LDPT_NULL; ++tv) {
    140     switch (tv->tv_tag) {
    141       case LDPT_API_VERSION:
    142         api_version = tv->tv_u.tv_val;
    143         break;
    144       case LDPT_GOLD_VERSION:  // major * 100 + minor
    145         gold_version = tv->tv_u.tv_val;
    146         break;
    147       case LDPT_OUTPUT_NAME:
    148         output_name = tv->tv_u.tv_string;
    149         break;
    150       case LDPT_LINKER_OUTPUT:
    151         switch (tv->tv_u.tv_val) {
    152           case LDPO_REL:  // .o
    153           case LDPO_DYN:  // .so
    154           // FIXME: Replace 3 with LDPO_PIE once that is in a released binutils.
    155           case 3: // position independent executable
    156             output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
    157             break;
    158           case LDPO_EXEC:  // .exe
    159             output_type = LTO_CODEGEN_PIC_MODEL_STATIC;
    160             break;
    161           default:
    162             (*message)(LDPL_ERROR, "Unknown output file type %d",
    163                        tv->tv_u.tv_val);
    164             return LDPS_ERR;
    165         }
    166         // TODO: add an option to disable PIC.
    167         //output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
    168         break;
    169       case LDPT_OPTION:
    170         options::process_plugin_option(tv->tv_u.tv_string);
    171         break;
    172       case LDPT_REGISTER_CLAIM_FILE_HOOK: {
    173         ld_plugin_register_claim_file callback;
    174         callback = tv->tv_u.tv_register_claim_file;
    175 
    176         if ((*callback)(claim_file_hook) != LDPS_OK)
    177           return LDPS_ERR;
    178 
    179         registeredClaimFile = true;
    180       } break;
    181       case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: {
    182         ld_plugin_register_all_symbols_read callback;
    183         callback = tv->tv_u.tv_register_all_symbols_read;
    184 
    185         if ((*callback)(all_symbols_read_hook) != LDPS_OK)
    186           return LDPS_ERR;
    187 
    188         code_gen = lto_codegen_create();
    189       } break;
    190       case LDPT_REGISTER_CLEANUP_HOOK: {
    191         ld_plugin_register_cleanup callback;
    192         callback = tv->tv_u.tv_register_cleanup;
    193 
    194         if ((*callback)(cleanup_hook) != LDPS_OK)
    195           return LDPS_ERR;
    196       } break;
    197       case LDPT_ADD_SYMBOLS:
    198         add_symbols = tv->tv_u.tv_add_symbols;
    199         break;
    200       case LDPT_GET_SYMBOLS:
    201         get_symbols = tv->tv_u.tv_get_symbols;
    202         break;
    203       case LDPT_ADD_INPUT_FILE:
    204         add_input_file = tv->tv_u.tv_add_input_file;
    205         break;
    206       case LDPT_ADD_INPUT_LIBRARY:
    207         add_input_library = tv->tv_u.tv_add_input_file;
    208         break;
    209       case LDPT_SET_EXTRA_LIBRARY_PATH:
    210         set_extra_library_path = tv->tv_u.tv_set_extra_library_path;
    211         break;
    212       case LDPT_GET_VIEW:
    213         get_view = tv->tv_u.tv_get_view;
    214         break;
    215       case LDPT_MESSAGE:
    216         message = tv->tv_u.tv_message;
    217         break;
    218       default:
    219         break;
    220     }
    221   }
    222 
    223   if (!registeredClaimFile) {
    224     (*message)(LDPL_ERROR, "register_claim_file not passed to LLVMgold.");
    225     return LDPS_ERR;
    226   }
    227   if (!add_symbols) {
    228     (*message)(LDPL_ERROR, "add_symbols not passed to LLVMgold.");
    229     return LDPS_ERR;
    230   }
    231 
    232   return LDPS_OK;
    233 }
    234 
    235 /// claim_file_hook - called by gold to see whether this file is one that
    236 /// our plugin can handle. We'll try to open it and register all the symbols
    237 /// with add_symbol if possible.
    238 static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
    239                                         int *claimed) {
    240   lto_module_t M;
    241   const void *view;
    242   OwningPtr<MemoryBuffer> buffer;
    243   if (get_view) {
    244     if (get_view(file->handle, &view) != LDPS_OK) {
    245       (*message)(LDPL_ERROR, "Failed to get a view of %s", file->name);
    246       return LDPS_ERR;
    247     }
    248   } else {
    249     int64_t offset = 0;
    250     // Gold has found what might be IR part-way inside of a file, such as
    251     // an .a archive.
    252     if (file->offset) {
    253       offset = file->offset;
    254     }
    255     if (error_code ec = MemoryBuffer::getOpenFileSlice(
    256             file->fd, file->name, buffer, file->filesize, offset)) {
    257       (*message)(LDPL_ERROR, ec.message().c_str());
    258       return LDPS_ERR;
    259     }
    260     view = buffer->getBufferStart();
    261   }
    262 
    263   if (!lto_module_is_object_file_in_memory(view, file->filesize))
    264     return LDPS_OK;
    265 
    266   M = lto_module_create_from_memory(view, file->filesize);
    267   if (!M) {
    268     if (const char* msg = lto_get_error_message()) {
    269       (*message)(LDPL_ERROR,
    270                  "LLVM gold plugin has failed to create LTO module: %s",
    271                  msg);
    272       return LDPS_ERR;
    273     }
    274     return LDPS_OK;
    275   }
    276 
    277   *claimed = 1;
    278   Modules.resize(Modules.size() + 1);
    279   claimed_file &cf = Modules.back();
    280 
    281   if (!options::triple.empty())
    282     lto_module_set_target_triple(M, options::triple.c_str());
    283 
    284   cf.handle = file->handle;
    285   unsigned sym_count = lto_module_get_num_symbols(M);
    286   cf.syms.reserve(sym_count);
    287 
    288   for (unsigned i = 0; i != sym_count; ++i) {
    289     lto_symbol_attributes attrs = lto_module_get_symbol_attribute(M, i);
    290     if ((attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
    291       continue;
    292 
    293     cf.syms.push_back(ld_plugin_symbol());
    294     ld_plugin_symbol &sym = cf.syms.back();
    295     sym.name = const_cast<char *>(lto_module_get_symbol_name(M, i));
    296     sym.name = strdup(sym.name);
    297     sym.version = NULL;
    298 
    299     int scope = attrs & LTO_SYMBOL_SCOPE_MASK;
    300     switch (scope) {
    301       case LTO_SYMBOL_SCOPE_HIDDEN:
    302         sym.visibility = LDPV_HIDDEN;
    303         break;
    304       case LTO_SYMBOL_SCOPE_PROTECTED:
    305         sym.visibility = LDPV_PROTECTED;
    306         break;
    307       case 0: // extern
    308       case LTO_SYMBOL_SCOPE_DEFAULT:
    309         sym.visibility = LDPV_DEFAULT;
    310         break;
    311       default:
    312         (*message)(LDPL_ERROR, "Unknown scope attribute: %d", scope);
    313         return LDPS_ERR;
    314     }
    315 
    316     int definition = attrs & LTO_SYMBOL_DEFINITION_MASK;
    317     sym.comdat_key = NULL;
    318     switch (definition) {
    319       case LTO_SYMBOL_DEFINITION_REGULAR:
    320         sym.def = LDPK_DEF;
    321         break;
    322       case LTO_SYMBOL_DEFINITION_UNDEFINED:
    323         sym.def = LDPK_UNDEF;
    324         break;
    325       case LTO_SYMBOL_DEFINITION_TENTATIVE:
    326         sym.def = LDPK_COMMON;
    327         break;
    328       case LTO_SYMBOL_DEFINITION_WEAK:
    329         sym.comdat_key = sym.name;
    330         sym.def = LDPK_WEAKDEF;
    331         break;
    332       case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
    333         sym.def = LDPK_WEAKUNDEF;
    334         break;
    335       default:
    336         (*message)(LDPL_ERROR, "Unknown definition attribute: %d", definition);
    337         return LDPS_ERR;
    338     }
    339 
    340     sym.size = 0;
    341 
    342     sym.resolution = LDPR_UNKNOWN;
    343   }
    344 
    345   cf.syms.reserve(cf.syms.size());
    346 
    347   if (!cf.syms.empty()) {
    348     if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) {
    349       (*message)(LDPL_ERROR, "Unable to add symbols!");
    350       return LDPS_ERR;
    351     }
    352   }
    353 
    354   if (code_gen)
    355     lto_codegen_add_module(code_gen, M);
    356 
    357   lto_module_dispose(M);
    358 
    359   return LDPS_OK;
    360 }
    361 
    362 /// all_symbols_read_hook - gold informs us that all symbols have been read.
    363 /// At this point, we use get_symbols to see if any of our definitions have
    364 /// been overridden by a native object file. Then, perform optimization and
    365 /// codegen.
    366 static ld_plugin_status all_symbols_read_hook(void) {
    367   std::ofstream api_file;
    368   assert(code_gen);
    369 
    370   if (options::generate_api_file) {
    371     api_file.open("apifile.txt", std::ofstream::out | std::ofstream::trunc);
    372     if (!api_file.is_open()) {
    373       (*message)(LDPL_FATAL, "Unable to open apifile.txt for writing.");
    374       abort();
    375     }
    376   }
    377 
    378   for (std::list<claimed_file>::iterator I = Modules.begin(),
    379          E = Modules.end(); I != E; ++I) {
    380     if (I->syms.empty())
    381       continue;
    382     (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]);
    383     for (unsigned i = 0, e = I->syms.size(); i != e; i++) {
    384       if (I->syms[i].resolution == LDPR_PREVAILING_DEF) {
    385         lto_codegen_add_must_preserve_symbol(code_gen, I->syms[i].name);
    386 
    387         if (options::generate_api_file)
    388           api_file << I->syms[i].name << "\n";
    389       }
    390     }
    391   }
    392 
    393   if (options::generate_api_file)
    394     api_file.close();
    395 
    396   lto_codegen_set_pic_model(code_gen, output_type);
    397   lto_codegen_set_debug_model(code_gen, LTO_DEBUG_MODEL_DWARF);
    398   if (!options::mcpu.empty())
    399     lto_codegen_set_cpu(code_gen, options::mcpu.c_str());
    400 
    401   // Pass through extra options to the code generator.
    402   if (!options::extra.empty()) {
    403     for (std::vector<std::string>::iterator it = options::extra.begin();
    404          it != options::extra.end(); ++it) {
    405       lto_codegen_debug_options(code_gen, (*it).c_str());
    406     }
    407   }
    408 
    409   if (options::generate_bc_file != options::BC_NO) {
    410     std::string path;
    411     if (options::generate_bc_file == options::BC_ONLY)
    412       path = output_name;
    413     else if (!options::bc_path.empty())
    414       path = options::bc_path;
    415     else
    416       path = output_name + ".bc";
    417     bool err = lto_codegen_write_merged_modules(code_gen, path.c_str());
    418     if (err)
    419       (*message)(LDPL_FATAL, "Failed to write the output file.");
    420     if (options::generate_bc_file == options::BC_ONLY)
    421       exit(0);
    422   }
    423   const char *objPath;
    424   if (lto_codegen_compile_to_file(code_gen, &objPath)) {
    425     (*message)(LDPL_ERROR, "Could not produce a combined object file\n");
    426   }
    427 
    428   lto_codegen_dispose(code_gen);
    429   for (std::list<claimed_file>::iterator I = Modules.begin(),
    430          E = Modules.end(); I != E; ++I) {
    431     for (unsigned i = 0; i != I->syms.size(); ++i) {
    432       ld_plugin_symbol &sym = I->syms[i];
    433       free(sym.name);
    434     }
    435   }
    436 
    437   if ((*add_input_file)(objPath) != LDPS_OK) {
    438     (*message)(LDPL_ERROR, "Unable to add .o file to the link.");
    439     (*message)(LDPL_ERROR, "File left behind in: %s", objPath);
    440     return LDPS_ERR;
    441   }
    442 
    443   if (!options::extra_library_path.empty() &&
    444       set_extra_library_path(options::extra_library_path.c_str()) != LDPS_OK) {
    445     (*message)(LDPL_ERROR, "Unable to set the extra library path.");
    446     return LDPS_ERR;
    447   }
    448 
    449   if (options::obj_path.empty())
    450     Cleanup.push_back(objPath);
    451 
    452   return LDPS_OK;
    453 }
    454 
    455 static ld_plugin_status cleanup_hook(void) {
    456   for (int i = 0, e = Cleanup.size(); i != e; ++i) {
    457     error_code EC = sys::fs::remove(Cleanup[i]);
    458     if (EC)
    459       (*message)(LDPL_ERROR, "Failed to delete '%s': %s", Cleanup[i].c_str(),
    460                  EC.message().c_str());
    461   }
    462 
    463   return LDPS_OK;
    464 }
    465