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 "plugin-api.h" 16 17 #include "llvm-c/lto.h" 18 19 #include "llvm/Support/raw_ostream.h" 20 #include "llvm/System/Path.h" 21 #include "llvm/System/Program.h" 22 23 #include <cerrno> 24 #include <cstdlib> 25 #include <cstring> 26 #include <fstream> 27 #include <list> 28 #include <vector> 29 30 using namespace llvm; 31 32 namespace { 33 ld_plugin_status discard_message(int level, const char *format, ...) { 34 // Die loudly. Recent versions of Gold pass ld_plugin_message as the first 35 // callback in the transfer vector. This should never be called. 36 abort(); 37 } 38 39 ld_plugin_add_symbols add_symbols = NULL; 40 ld_plugin_get_symbols get_symbols = NULL; 41 ld_plugin_add_input_file add_input_file = NULL; 42 ld_plugin_message message = discard_message; 43 44 int api_version = 0; 45 int gold_version = 0; 46 47 bool generate_api_file = false; 48 const char *as_path = NULL; 49 50 struct claimed_file { 51 lto_module_t M; 52 void *handle; 53 std::vector<ld_plugin_symbol> syms; 54 }; 55 56 lto_codegen_model output_type = LTO_CODEGEN_PIC_MODEL_STATIC; 57 std::list<claimed_file> Modules; 58 std::vector<sys::Path> Cleanup; 59 } 60 61 ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, 62 int *claimed); 63 ld_plugin_status all_symbols_read_hook(void); 64 ld_plugin_status cleanup_hook(void); 65 66 extern "C" ld_plugin_status onload(ld_plugin_tv *tv); 67 ld_plugin_status onload(ld_plugin_tv *tv) { 68 // We're given a pointer to the first transfer vector. We read through them 69 // until we find one where tv_tag == LDPT_NULL. The REGISTER_* tagged values 70 // contain pointers to functions that we need to call to register our own 71 // hooks. The others are addresses of functions we can use to call into gold 72 // for services. 73 74 bool registeredClaimFile = false; 75 bool registeredAllSymbolsRead = false; 76 bool registeredCleanup = false; 77 78 for (; tv->tv_tag != LDPT_NULL; ++tv) { 79 switch (tv->tv_tag) { 80 case LDPT_API_VERSION: 81 api_version = tv->tv_u.tv_val; 82 break; 83 case LDPT_GOLD_VERSION: // major * 100 + minor 84 gold_version = tv->tv_u.tv_val; 85 break; 86 case LDPT_LINKER_OUTPUT: 87 switch (tv->tv_u.tv_val) { 88 case LDPO_REL: // .o 89 case LDPO_DYN: // .so 90 output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC; 91 break; 92 case LDPO_EXEC: // .exe 93 output_type = LTO_CODEGEN_PIC_MODEL_STATIC; 94 break; 95 default: 96 (*message)(LDPL_ERROR, "Unknown output file type %d", 97 tv->tv_u.tv_val); 98 return LDPS_ERR; 99 } 100 // TODO: add an option to disable PIC. 101 //output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; 102 break; 103 case LDPT_OPTION: 104 if (strcmp("generate-api-file", tv->tv_u.tv_string) == 0) { 105 generate_api_file = true; 106 } else if (strncmp("as=", tv->tv_u.tv_string, 3) == 0) { 107 if (as_path) { 108 (*message)(LDPL_WARNING, "Path to as specified twice. " 109 "Discarding %s", tv->tv_u.tv_string); 110 } else { 111 as_path = strdup(tv->tv_u.tv_string + 3); 112 } 113 } else { 114 (*message)(LDPL_WARNING, "Ignoring flag %s", tv->tv_u.tv_string); 115 } 116 break; 117 case LDPT_REGISTER_CLAIM_FILE_HOOK: { 118 ld_plugin_register_claim_file callback; 119 callback = tv->tv_u.tv_register_claim_file; 120 121 if ((*callback)(claim_file_hook) != LDPS_OK) 122 return LDPS_ERR; 123 124 registeredClaimFile = true; 125 } break; 126 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK: { 127 ld_plugin_register_all_symbols_read callback; 128 callback = tv->tv_u.tv_register_all_symbols_read; 129 130 if ((*callback)(all_symbols_read_hook) != LDPS_OK) 131 return LDPS_ERR; 132 133 registeredAllSymbolsRead = true; 134 } break; 135 case LDPT_REGISTER_CLEANUP_HOOK: { 136 ld_plugin_register_cleanup callback; 137 callback = tv->tv_u.tv_register_cleanup; 138 139 if ((*callback)(cleanup_hook) != LDPS_OK) 140 return LDPS_ERR; 141 142 registeredCleanup = true; 143 } break; 144 case LDPT_ADD_SYMBOLS: 145 add_symbols = tv->tv_u.tv_add_symbols; 146 break; 147 case LDPT_GET_SYMBOLS: 148 get_symbols = tv->tv_u.tv_get_symbols; 149 break; 150 case LDPT_ADD_INPUT_FILE: 151 add_input_file = tv->tv_u.tv_add_input_file; 152 break; 153 case LDPT_MESSAGE: 154 message = tv->tv_u.tv_message; 155 break; 156 default: 157 break; 158 } 159 } 160 161 if (!registeredClaimFile) { 162 (*message)(LDPL_ERROR, "register_claim_file not passed to LLVMgold."); 163 return LDPS_ERR; 164 } 165 if (!add_symbols) { 166 (*message)(LDPL_ERROR, "add_symbols not passed to LLVMgold."); 167 return LDPS_ERR; 168 } 169 170 return LDPS_OK; 171 } 172 173 /// claim_file_hook - called by gold to see whether this file is one that 174 /// our plugin can handle. We'll try to open it and register all the symbols 175 /// with add_symbol if possible. 176 ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, 177 int *claimed) { 178 void *buf = NULL; 179 if (file->offset) { 180 // Gold has found what might be IR part-way inside of a file, such as 181 // an .a archive. 182 if (lseek(file->fd, file->offset, SEEK_SET) == -1) { 183 (*message)(LDPL_ERROR, 184 "Failed to seek to archive member of %s at offset %d: %s\n", 185 file->name, 186 file->offset, strerror(errno)); 187 return LDPS_ERR; 188 } 189 buf = malloc(file->filesize); 190 if (!buf) { 191 (*message)(LDPL_ERROR, 192 "Failed to allocate buffer for archive member of size: %d\n", 193 file->filesize); 194 return LDPS_ERR; 195 } 196 if (read(file->fd, buf, file->filesize) != file->filesize) { 197 (*message)(LDPL_ERROR, 198 "Failed to read archive member of %s at offset %d: %s\n", 199 file->name, 200 file->offset, 201 strerror(errno)); 202 free(buf); 203 return LDPS_ERR; 204 } 205 if (!lto_module_is_object_file_in_memory(buf, file->filesize)) { 206 free(buf); 207 return LDPS_OK; 208 } 209 } else if (!lto_module_is_object_file(file->name)) 210 return LDPS_OK; 211 212 *claimed = 1; 213 Modules.resize(Modules.size() + 1); 214 claimed_file &cf = Modules.back(); 215 216 cf.M = buf ? lto_module_create_from_memory(buf, file->filesize) : 217 lto_module_create(file->name); 218 free(buf); 219 if (!cf.M) { 220 (*message)(LDPL_ERROR, "Failed to create LLVM module: %s", 221 lto_get_error_message()); 222 return LDPS_ERR; 223 } 224 cf.handle = file->handle; 225 unsigned sym_count = lto_module_get_num_symbols(cf.M); 226 cf.syms.reserve(sym_count); 227 228 for (unsigned i = 0; i != sym_count; ++i) { 229 lto_symbol_attributes attrs = lto_module_get_symbol_attribute(cf.M, i); 230 if ((attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL) 231 continue; 232 233 cf.syms.push_back(ld_plugin_symbol()); 234 ld_plugin_symbol &sym = cf.syms.back(); 235 sym.name = const_cast<char *>(lto_module_get_symbol_name(cf.M, i)); 236 sym.version = NULL; 237 238 int scope = attrs & LTO_SYMBOL_SCOPE_MASK; 239 switch (scope) { 240 case LTO_SYMBOL_SCOPE_HIDDEN: 241 sym.visibility = LDPV_HIDDEN; 242 break; 243 case LTO_SYMBOL_SCOPE_PROTECTED: 244 sym.visibility = LDPV_PROTECTED; 245 break; 246 case 0: // extern 247 case LTO_SYMBOL_SCOPE_DEFAULT: 248 sym.visibility = LDPV_DEFAULT; 249 break; 250 default: 251 (*message)(LDPL_ERROR, "Unknown scope attribute: %d", scope); 252 return LDPS_ERR; 253 } 254 255 int definition = attrs & LTO_SYMBOL_DEFINITION_MASK; 256 switch (definition) { 257 case LTO_SYMBOL_DEFINITION_REGULAR: 258 sym.def = LDPK_DEF; 259 break; 260 case LTO_SYMBOL_DEFINITION_UNDEFINED: 261 sym.def = LDPK_UNDEF; 262 break; 263 case LTO_SYMBOL_DEFINITION_TENTATIVE: 264 sym.def = LDPK_COMMON; 265 break; 266 case LTO_SYMBOL_DEFINITION_WEAK: 267 sym.def = LDPK_WEAKDEF; 268 break; 269 case LTO_SYMBOL_DEFINITION_WEAKUNDEF: 270 sym.def = LDPK_WEAKUNDEF; 271 break; 272 default: 273 (*message)(LDPL_ERROR, "Unknown definition attribute: %d", definition); 274 return LDPS_ERR; 275 } 276 277 // LLVM never emits COMDAT. 278 sym.size = 0; 279 sym.comdat_key = NULL; 280 281 sym.resolution = LDPR_UNKNOWN; 282 } 283 284 cf.syms.reserve(cf.syms.size()); 285 286 if (!cf.syms.empty()) { 287 if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) { 288 (*message)(LDPL_ERROR, "Unable to add symbols!"); 289 return LDPS_ERR; 290 } 291 } 292 293 return LDPS_OK; 294 } 295 296 /// all_symbols_read_hook - gold informs us that all symbols have been read. 297 /// At this point, we use get_symbols to see if any of our definitions have 298 /// been overridden by a native object file. Then, perform optimization and 299 /// codegen. 300 ld_plugin_status all_symbols_read_hook(void) { 301 lto_code_gen_t cg = lto_codegen_create(); 302 303 for (std::list<claimed_file>::iterator I = Modules.begin(), 304 E = Modules.end(); I != E; ++I) 305 lto_codegen_add_module(cg, I->M); 306 307 std::ofstream api_file; 308 if (generate_api_file) { 309 api_file.open("apifile.txt", std::ofstream::out | std::ofstream::trunc); 310 if (!api_file.is_open()) { 311 (*message)(LDPL_FATAL, "Unable to open apifile.txt for writing."); 312 abort(); 313 } 314 } 315 316 // If we don't preserve any symbols, libLTO will assume that all symbols are 317 // needed. Keep all symbols unless we're producing a final executable. 318 if (output_type == LTO_CODEGEN_PIC_MODEL_STATIC) { 319 bool anySymbolsPreserved = false; 320 for (std::list<claimed_file>::iterator I = Modules.begin(), 321 E = Modules.end(); I != E; ++I) { 322 (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]); 323 for (unsigned i = 0, e = I->syms.size(); i != e; i++) { 324 if (I->syms[i].resolution == LDPR_PREVAILING_DEF || 325 (I->syms[i].def == LDPK_COMMON && 326 I->syms[i].resolution == LDPR_RESOLVED_IR)) { 327 lto_codegen_add_must_preserve_symbol(cg, I->syms[i].name); 328 anySymbolsPreserved = true; 329 330 if (generate_api_file) 331 api_file << I->syms[i].name << "\n"; 332 } 333 } 334 } 335 336 if (generate_api_file) 337 api_file.close(); 338 339 if (!anySymbolsPreserved) { 340 // This entire file is unnecessary! 341 lto_codegen_dispose(cg); 342 return LDPS_OK; 343 } 344 } 345 346 lto_codegen_set_pic_model(cg, output_type); 347 lto_codegen_set_debug_model(cg, LTO_DEBUG_MODEL_DWARF); 348 if (as_path) { 349 sys::Path p = sys::Program::FindProgramByName(as_path); 350 lto_codegen_set_assembler_path(cg, p.c_str()); 351 } 352 353 size_t bufsize = 0; 354 const char *buffer = static_cast<const char *>(lto_codegen_compile(cg, 355 &bufsize)); 356 357 std::string ErrMsg; 358 359 sys::Path uniqueObjPath("/tmp/llvmgold.o"); 360 if (uniqueObjPath.createTemporaryFileOnDisk(true, &ErrMsg)) { 361 (*message)(LDPL_ERROR, "%s", ErrMsg.c_str()); 362 return LDPS_ERR; 363 } 364 raw_fd_ostream *objFile = new raw_fd_ostream(uniqueObjPath.c_str(), true, 365 ErrMsg); 366 if (!ErrMsg.empty()) { 367 delete objFile; 368 (*message)(LDPL_ERROR, "%s", ErrMsg.c_str()); 369 return LDPS_ERR; 370 } 371 372 objFile->write(buffer, bufsize); 373 objFile->close(); 374 375 lto_codegen_dispose(cg); 376 377 if ((*add_input_file)(const_cast<char*>(uniqueObjPath.c_str())) != LDPS_OK) { 378 (*message)(LDPL_ERROR, "Unable to add .o file to the link."); 379 (*message)(LDPL_ERROR, "File left behind in: %s", uniqueObjPath.c_str()); 380 return LDPS_ERR; 381 } 382 383 Cleanup.push_back(uniqueObjPath); 384 385 return LDPS_OK; 386 } 387 388 ld_plugin_status cleanup_hook(void) { 389 std::string ErrMsg; 390 391 for (int i = 0, e = Cleanup.size(); i != e; ++i) 392 if (Cleanup[i].eraseFromDisk(false, &ErrMsg)) 393 (*message)(LDPL_ERROR, "Failed to delete '%s': %s", Cleanup[i].c_str(), 394 ErrMsg.c_str()); 395 396 return LDPS_OK; 397 } 398