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 42using namespace clover; 43using namespace clover::llvm; 44using ::llvm::TargetMachine; 45 46namespace { 47 namespace elf { 48 std::unique_ptr<Elf, int (*)(Elf *)> 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 * 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> 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> 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> 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 ::llvm::None, compat::default_code_model, 118 ::llvm::CodeGenOpt::Default) }; 119 if (!tm) 120 fail(r_log, build_error(), 121 "Could not create TargetMachine: " + target.triple); 122 123 ::llvm::SmallVector<char, 1024> data; 124 125 { 126 ::llvm::legacy::PassManager pm; 127 ::llvm::raw_svector_ostream os { data }; 128 129 mod.setDataLayout(tm->createDataLayout()); 130 tm->Options.MCOptions.AsmVerbose = 131 (ft == TargetMachine::CGFT_AssemblyFile); 132 133 if (compat::add_passes_to_emit_file(*tm, pm, os, ft)) 134 fail(r_log, build_error(), "TargetMachine can't emit this file"); 135 136 pm.run(mod); 137 } 138 139 return { data.begin(), data.end() }; 140 } 141} 142 143module 144clover::llvm::build_module_native(::llvm::Module &mod, const target &target, 145 const clang::CompilerInstance &c, 146 std::string &r_log) { 147 const auto code = emit_code(mod, target, 148 TargetMachine::CGFT_ObjectFile, r_log); 149 return build_module_common(mod, code, get_symbol_offsets(code, r_log), c); 150} 151 152std::string 153clover::llvm::print_module_native(const ::llvm::Module &mod, 154 const target &target) { 155 std::string log; 156 try { 157 std::unique_ptr< ::llvm::Module> cmod { compat::clone_module(mod) }; 158 return as_string(emit_code(*cmod, target, 159 TargetMachine::CGFT_AssemblyFile, log)); 160 } catch (...) { 161 return "Couldn't output native disassembly: " + log; 162 } 163} 164