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