1 // 2 // Copyright 2012-2016 Francisco Jerez 3 // Copyright 2012-2016 Advanced Micro Devices, Inc. 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a 6 // copy of this software and associated documentation files (the "Software"), 7 // to deal in the Software without restriction, including without limitation 8 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 // and/or sell copies of the Software, and to permit persons to whom the 10 // Software is furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 // OTHER DEALINGS IN THE SOFTWARE. 22 // 23 24 /// 25 /// \file 26 /// Generate code using an arbitrary LLVM back-end capable of emitting 27 /// executable code as an ELF object file. 28 /// 29 30 #include "llvm/codegen.hpp" 31 #include "llvm/compat.hpp" 32 #include "llvm/util.hpp" 33 #include "core/error.hpp" 34 35 #include <llvm/Target/TargetMachine.h> 36 #include <llvm/Support/TargetRegistry.h> 37 #include <llvm/Transforms/Utils/Cloning.h> 38 39 #include <libelf.h> 40 #include <gelf.h> 41 42 using namespace clover; 43 using namespace clover::llvm; 44 using ::llvm::TargetMachine; 45 46 namespace { 47 namespace elf { 48 std::unique_ptr<Elf, int (*)(Elf *)> get(const std::vector<char> & code)49 get(const std::vector<char> &code) { 50 // One of the libelf implementations 51 // (http://www.mr511.de/software/english.htm) requires calling 52 // elf_version() before elf_memory(). 53 elf_version(EV_CURRENT); 54 return { elf_memory(const_cast<char *>(code.data()), code.size()), 55 elf_end }; 56 } 57 58 Elf_Scn * get_symbol_table(Elf * elf)59 get_symbol_table(Elf *elf) { 60 size_t section_str_index; 61 elf_getshdrstrndx(elf, §ion_str_index); 62 63 for (Elf_Scn *s = elf_nextscn(elf, NULL); s; s = elf_nextscn(elf, s)) { 64 GElf_Shdr header; 65 if (gelf_getshdr(s, &header) != &header) 66 return nullptr; 67 68 if (!std::strcmp(elf_strptr(elf, section_str_index, header.sh_name), 69 ".symtab")) 70 return s; 71 } 72 73 return nullptr; 74 } 75 76 std::map<std::string, unsigned> get_symbol_offsets(Elf * elf,Elf_Scn * symtab)77 get_symbol_offsets(Elf *elf, Elf_Scn *symtab) { 78 Elf_Data *const symtab_data = elf_getdata(symtab, NULL); 79 GElf_Shdr header; 80 if (gelf_getshdr(symtab, &header) != &header) 81 return {}; 82 83 std::map<std::string, unsigned> symbol_offsets; 84 GElf_Sym symbol; 85 unsigned i = 0; 86 87 while (GElf_Sym *s = gelf_getsym(symtab_data, i++, &symbol)) { 88 const char *name = elf_strptr(elf, header.sh_link, s->st_name); 89 symbol_offsets[name] = s->st_value; 90 } 91 92 return symbol_offsets; 93 } 94 } 95 96 std::map<std::string, unsigned> get_symbol_offsets(const std::vector<char> & code,std::string & r_log)97 get_symbol_offsets(const std::vector<char> &code, std::string &r_log) { 98 const auto elf = elf::get(code); 99 const auto symtab = elf::get_symbol_table(elf.get()); 100 if (!symtab) 101 fail(r_log, build_error(), "Unable to find symbol table."); 102 103 return elf::get_symbol_offsets(elf.get(), symtab); 104 } 105 106 std::vector<char> emit_code(::llvm::Module & mod,const target & target,TargetMachine::CodeGenFileType ft,std::string & r_log)107 emit_code(::llvm::Module &mod, const target &target, 108 TargetMachine::CodeGenFileType ft, 109 std::string &r_log) { 110 std::string err; 111 auto t = ::llvm::TargetRegistry::lookupTarget(target.triple, err); 112 if (!t) 113 fail(r_log, build_error(), err); 114 115 std::unique_ptr<TargetMachine> tm { 116 t->createTargetMachine(target.triple, target.cpu, "", {}, 117 compat::default_reloc_model, 118 ::llvm::CodeModel::Default, 119 ::llvm::CodeGenOpt::Default) }; 120 if (!tm) 121 fail(r_log, build_error(), 122 "Could not create TargetMachine: " + target.triple); 123 124 ::llvm::SmallVector<char, 1024> data; 125 126 { 127 compat::pass_manager pm; 128 ::llvm::raw_svector_ostream os { data }; 129 compat::raw_ostream_to_emit_file fos(os); 130 131 mod.setDataLayout(compat::get_data_layout(*tm)); 132 tm->Options.MCOptions.AsmVerbose = 133 (ft == TargetMachine::CGFT_AssemblyFile); 134 135 if (tm->addPassesToEmitFile(pm, fos, ft)) 136 fail(r_log, build_error(), "TargetMachine can't emit this file"); 137 138 pm.run(mod); 139 } 140 141 return { data.begin(), data.end() }; 142 } 143 } 144 145 module 146 clover::llvm::build_module_native(::llvm::Module &mod, const target &target, 147 const clang::CompilerInstance &c, 148 std::string &r_log) { 149 const auto code = emit_code(mod, target, 150 TargetMachine::CGFT_ObjectFile, r_log); 151 return build_module_common(mod, code, get_symbol_offsets(code, r_log), c); 152 } 153 154 std::string 155 clover::llvm::print_module_native(const ::llvm::Module &mod, 156 const target &target) { 157 std::string log; 158 try { 159 std::unique_ptr<::llvm::Module> cmod { CloneModule(&mod) }; 160 return as_string(emit_code(*cmod, target, 161 TargetMachine::CGFT_AssemblyFile, log)); 162 } catch (...) { 163 return "Couldn't output native disassembly: " + log; 164 } 165 } 166