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