• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &section_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                                 compat::default_code_model,
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