--- /dev/null
+//
+// Copyright 2012-2016 Francisco Jerez
+// Copyright 2012-2016 Advanced Micro Devices, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+///
+/// \file
+/// Generate code using an arbitrary LLVM back-end capable of emitting
+/// executable code as an ELF object file.
+///
+
+#include "llvm/codegen.hpp"
+#include "llvm/compat.hpp"
+#include "llvm/util.hpp"
+#include "core/error.hpp"
+
+#include <llvm/Target/TargetMachine.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Transforms/Utils/Cloning.h>
+
+#include <libelf.h>
+#include <gelf.h>
+
+using namespace clover;
+using namespace clover::llvm;
+using ::llvm::TargetMachine;
+
+namespace {
+ namespace elf {
+ std::unique_ptr<Elf, int (*)(Elf *)>
+ get(const std::vector<char> &code) {
+ // One of the libelf implementations
+ // (http://www.mr511.de/software/english.htm) requires calling
+ // elf_version() before elf_memory().
+ elf_version(EV_CURRENT);
+ return { elf_memory(const_cast<char *>(code.data()), code.size()),
+ elf_end };
+ }
+
+ Elf_Scn *
+ get_symbol_table(Elf *elf) {
+ size_t section_str_index;
+ elf_getshdrstrndx(elf, §ion_str_index);
+
+ for (Elf_Scn *s = elf_nextscn(elf, NULL); s; s = elf_nextscn(elf, s)) {
+ GElf_Shdr header;
+ if (gelf_getshdr(s, &header) != &header)
+ return nullptr;
+
+ if (!std::strcmp(elf_strptr(elf, section_str_index, header.sh_name),
+ ".symtab"))
+ return s;
+ }
+
+ return nullptr;
+ }
+
+ std::map<std::string, unsigned>
+ get_symbol_offsets(Elf *elf, Elf_Scn *symtab) {
+ Elf_Data *const symtab_data = elf_getdata(symtab, NULL);
+ GElf_Shdr header;
+ if (gelf_getshdr(symtab, &header) != &header)
+ return {};
+
+ std::map<std::string, unsigned> symbol_offsets;
+ GElf_Sym symbol;
+ unsigned i = 0;
+
+ while (GElf_Sym *s = gelf_getsym(symtab_data, i++, &symbol)) {
+ const char *name = elf_strptr(elf, header.sh_link, s->st_name);
+ symbol_offsets[name] = s->st_value;
+ }
+
+ return symbol_offsets;
+ }
+ }
+
+ std::map<std::string, unsigned>
+ get_symbol_offsets(const std::vector<char> &code, std::string &r_log) {
+ const auto elf = elf::get(code);
+ const auto symtab = elf::get_symbol_table(elf.get());
+ if (!symtab)
+ fail(r_log, compile_error(), "Unable to find symbol table.");
+
+ return elf::get_symbol_offsets(elf.get(), symtab);
+ }
+
+ std::vector<char>
+ emit_code(::llvm::Module &mod, const target &target,
+ TargetMachine::CodeGenFileType ft,
+ std::string &r_log) {
+ std::string err;
+ auto t = ::llvm::TargetRegistry::lookupTarget(target.triple, err);
+ if (!t)
+ fail(r_log, compile_error(), err);
+
+ std::unique_ptr<TargetMachine> tm {
+ t->createTargetMachine(target.triple, target.cpu, "", {},
+ compat::default_reloc_model,
+ ::llvm::CodeModel::Default,
+ ::llvm::CodeGenOpt::Default) };
+ if (!tm)
+ fail(r_log, compile_error(),
+ "Could not create TargetMachine: " + target.triple);
+
+ ::llvm::SmallVector<char, 1024> data;
+
+ {
+ compat::pass_manager pm;
+ ::llvm::raw_svector_ostream os { data };
+ compat::raw_ostream_to_emit_file fos { os };
+
+ mod.setDataLayout(compat::get_data_layout(*tm));
+ tm->Options.MCOptions.AsmVerbose =
+ (ft == TargetMachine::CGFT_AssemblyFile);
+
+ if (tm->addPassesToEmitFile(pm, fos, ft))
+ fail(r_log, compile_error(), "TargetMachine can't emit this file");
+
+ pm.run(mod);
+ }
+
+ return { data.begin(), data.end() };
+ }
+}
+
+module
+clover::llvm::build_module_native(::llvm::Module &mod, const target &target,
+ const clang::CompilerInstance &c,
+ std::string &r_log) {
+ const auto code = emit_code(mod, target,
+ TargetMachine::CGFT_ObjectFile, r_log);
+ return build_module_common(mod, code, get_symbol_offsets(code, r_log), c);
+}
+
+std::string
+clover::llvm::print_module_native(const ::llvm::Module &mod,
+ const target &target) {
+ std::string log;
+ try {
+ std::unique_ptr<::llvm::Module> cmod { CloneModule(&mod) };
+ return as_string(emit_code(*cmod, target,
+ TargetMachine::CGFT_AssemblyFile, log));
+ } catch (...) {
+ return "Couldn't output native disassembly: " + log;
+ }
+}
pmb.populateModulePassManager(pm);
pm.run(mod);
}
-
- std::vector<char>
- emit_code(::llvm::Module &mod, const target &target,
- TargetMachine::CodeGenFileType ft,
- std::string &r_log) {
- std::string err;
- auto t = ::llvm::TargetRegistry::lookupTarget(target.triple, err);
- if (!t)
- fail(r_log, compile_error(), err);
-
- std::unique_ptr<TargetMachine> tm {
- t->createTargetMachine(target.triple, target.cpu, "", {},
- compat::default_reloc_model,
- ::llvm::CodeModel::Default,
- ::llvm::CodeGenOpt::Default) };
- if (!tm)
- fail(r_log, compile_error(),
- "Could not create TargetMachine: " + target.triple);
-
- ::llvm::SmallVector<char, 1024> data;
-
- {
- compat::pass_manager pm;
- ::llvm::raw_svector_ostream os { data };
- compat::raw_ostream_to_emit_file fos { os };
-
- mod.setDataLayout(compat::get_data_layout(*tm));
- tm->Options.MCOptions.AsmVerbose =
- (ft == TargetMachine::CGFT_AssemblyFile);
-
- if (tm->addPassesToEmitFile(pm, fos, ft))
- fail(r_log, compile_error(), "TargetMachine can't emit this file");
-
- pm.run(mod);
- }
-
- return { data.begin(), data.end() };
- }
-
- namespace elf {
- std::unique_ptr<Elf, int (*)(Elf *)>
- get(const std::vector<char> &code) {
- // One of the libelf implementations
- // (http://www.mr511.de/software/english.htm) requires calling
- // elf_version() before elf_memory().
- elf_version(EV_CURRENT);
- return { elf_memory(const_cast<char *>(code.data()), code.size()),
- elf_end };
- }
-
- Elf_Scn *
- get_symbol_table(Elf *elf) {
- size_t section_str_index;
- elf_getshdrstrndx(elf, §ion_str_index);
-
- for (Elf_Scn *s = elf_nextscn(elf, NULL); s; s = elf_nextscn(elf, s)) {
- GElf_Shdr header;
- if (gelf_getshdr(s, &header) != &header)
- return nullptr;
-
- if (!std::strcmp(elf_strptr(elf, section_str_index, header.sh_name),
- ".symtab"))
- return s;
- }
-
- return nullptr;
- }
-
- std::map<std::string, unsigned>
- get_symbol_offsets(Elf *elf, Elf_Scn *symtab) {
- Elf_Data *const symtab_data = elf_getdata(symtab, NULL);
- GElf_Shdr header;
- if (gelf_getshdr(symtab, &header) != &header)
- return {};
-
- std::map<std::string, unsigned> symbol_offsets;
- GElf_Sym symbol;
- unsigned i = 0;
-
- while (GElf_Sym *s = gelf_getsym(symtab_data, i++, &symbol)) {
- const char *name = elf_strptr(elf, header.sh_link, s->st_name);
- symbol_offsets[name] = s->st_value;
- }
-
- return symbol_offsets;
- }
- }
-
- std::map<std::string, unsigned>
- get_symbol_offsets(const std::vector<char> &code,
- std::string &r_log) {
- const auto elf = elf::get(code);
- const auto symtab = elf::get_symbol_table(elf.get());
- if (!symtab)
- fail(r_log, compile_error(), "Unable to find symbol table.");
-
- return elf::get_symbol_offsets(elf.get(), symtab);
- }
-
- module
- build_module_native(::llvm::Module &mod, const target &target,
- const clang::CompilerInstance &c,
- std::string &r_log) {
- const auto code = emit_code(mod, target,
- TargetMachine::CGFT_ObjectFile, r_log);
- return build_module_common(mod, code, get_symbol_offsets(code, r_log), c);
- }
-
- std::string
- print_module_native(const ::llvm::Module &mod, const target &target) {
- std::string log;
- try {
- std::unique_ptr<llvm::Module> cmod { CloneModule(&mod) };
- return as_string(emit_code(*cmod, target,
- TargetMachine::CGFT_AssemblyFile, log));
- } catch (...) {
- return "Couldn't output native disassembly: " + log;
- }
- }
} // End anonymous namespace
module