CACAO
ObjectFileWriterPass.cpp
Go to the documentation of this file.
1 /* src/vm/jit/compiler2/ObjectFileWriterPass.cpp - ObjectFileWriterPass
2 
3  Copyright (C) 2013
4  CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 
6  This file is part of CACAO.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2, or (at
11  your option) any later version.
12 
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  02110-1301, USA.
22 
23 */
24 
31 
33 
34 #include "toolbox/logging.hpp"
35 
36 #include "vm/jit/jit.hpp"
37 #include "vm/jit/code.hpp"
38 #include "vm/rt-timing.hpp"
39 
40 #if defined(ENABLE_DISASSEMBLER)
41 
42 #if !defined(WITH_BINUTILS_DISASSEMBLER)
43 #error ObjectFileWriterPass requires binutils bfd library.
44 #endif
45 
46 #include <bfd.h>
47 #include <string>
48 
49 #endif // defined(ENABLE_DISASSEMBLER)
50 
51 #define DEBUG_NAME "compiler2/ObjectFileWriter"
52 
53 #if defined(ENABLE_DISASSEMBLER)
54 RT_REGISTER_TIMER(obj_writter_timer,"objectwriter","object writer execution time")
55 #endif
56 
57 namespace {
58 
59 #if defined(ENABLE_DISASSEMBLER)
60 template<typename T>
61 inline void check_bfd_error(T* t) {
62  if (!t) {
63  // error
64  ABORT_MSG("ObjectFileWriterPass Error", "Error: " << bfd_errmsg(bfd_get_error()));
65  }
66 }
67 inline void check_bfd_error(bfd_boolean b) {
68  if (b == FALSE) {
69  // error
70  ABORT_MSG("ObjectFileWriterPass Error", "Error: " << bfd_errmsg(bfd_get_error()));
71  }
72 }
73 #endif // defined(ENABLE_DISASSEMBLER)
74 
75 } // end anonymous namespace
76 
77 namespace cacao {
78 namespace jit {
79 namespace compiler2 {
80 
81 #define FAKE_DATASEC
83 #if defined(ENABLE_DISASSEMBLER)
84  RT_TIMER_START(obj_writter_timer);
85  Method *M = JD.get_Method();
86  //CodeGenPass *CG = get_Pass<CodeGenPass>();
87  codeinfo* code = JD.get_jitdata()->code;
88 
89  const char* bfd_arch = "i386:x86-64";
90  const char* bfd_target = "elf64-x86-64";
91  std::string symbol_name(M->get_name_utf8().begin(),M->get_name_utf8().size());
92  std::string class_name(M->get_class_name_utf8().begin(),M->get_class_name_utf8().size());
93  std::string filename = class_name + "." + symbol_name + ".o";
94  //JD.get_Method()->get_MethodDescriptor().
95  //
96  LOG("Object file name: " << filename.c_str() << nl);
97  LOG(".text symbol name: " << symbol_name.c_str() << nl);
98 
99  #if 0
100  if (DEBUG_COND_N(3)) {
101  const char ** target_list = bfd_target_list();
102  while (*target_list) {
103  LOG("target: " << *target_list << nl);
104  ++target_list;
105  }
106  }
107  if (DEBUG_COND_N(3)) {
108  const char ** arch_list = bfd_arch_list();
109  while (*arch_list) {
110  LOG("arch: " << *arch_list << nl);
111  ++arch_list;
112  }
113  }
114  #endif
115  // open file
116  LOG2("open file" << nl);
117  bfd *abfd = bfd_openw(filename.c_str(),bfd_target);
118  check_bfd_error(abfd);
119 
120  // set architecture
121  LOG2("set architecture" << nl);
122  const bfd_arch_info_type *arch_info = bfd_scan_arch (bfd_arch);
123  check_bfd_error(arch_info);
124 
125  bfd_set_arch_info(abfd,arch_info);
126  // set format
127  bfd_set_format(abfd, bfd_object);
128 
129  // get section lengths
130  std::size_t dseglen = code->entrypoint - code->mcode;
131  std::size_t codelen = code->mcodelength - dseglen;
132  //dseglen =0;
133 
134  // create data_section
135  asection *data_section = NULL;
136  if (dseglen) {
137  LOG2("create data_section" << nl);
138  data_section = bfd_make_section_anyway_with_flags(abfd, ".rodata",
139  SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA );
140  check_bfd_error(data_section);
141  // set data_section size
142  LOG2("set data_section size" << nl);
143  check_bfd_error(bfd_set_section_size(abfd, data_section, dseglen));
144  // set alignment
145  data_section->alignment_power = 2;
146  }
147 
148  // create code_section
149  LOG2("create code_section" << nl);
150  asection *code_section = bfd_make_section_anyway_with_flags(abfd, ".text",
151  SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE );
152  check_bfd_error(code_section);
153  // set code_section size
154  LOG2("set code_section size" << nl);
155  #ifdef FAKE_DATASEC
156  if (dseglen) {
157  codelen = 8 + dseglen + codelen;
158  }
159  #endif
160  check_bfd_error(bfd_set_section_size(abfd, code_section,codelen));
161  // set alignment
162  code_section->alignment_power = 2;
163 
164  #if 0
165  // create relocation entries
166  reloc_howto_type* howto = bfd_reloc_type_lookup(abfd, BFD_RELOC_32_PCREL);
167  arelent reloc_entry = {
168  0,
169  4,
170  0,
171  howto
172  };
173  char *err;
174  bfd_install_relocation(
175  abfd,
176  &reloc_entry,
177  NULL,
178  8,
179  //code_section,
180  data_section,
181  &err);
182  #if 0
183  bfd_reloc_status_type bfd_install_relocation
184  (bfd *abfd,
185  arelent *reloc_entry,
186  void *data, bfd_vma data_start,
187  asection *input_section,
188  char **error_message);
189  #endif
190  #endif
191 
192  // create symbol
193  LOG2("create symbol" << nl);
194  asymbol *new_smbl = bfd_make_empty_symbol (abfd);
195  new_smbl->name = symbol_name.c_str();
196  new_smbl->section = code_section;
197  new_smbl->flags = BSF_GLOBAL;
198 
199  // symbol list
200  asymbol *ptrs[2];
201  ptrs[0] = new_smbl;
202  ptrs[1] = 0;
203 
204  // insert symbol list
205  LOG2("insert symbol list" << nl);
206  check_bfd_error(bfd_set_symtab(abfd, ptrs, 1));
207 
208  // set contents
209  // this starts writing so do it at the end
210  if (dseglen) {
211  LOG2("set data_section contents" << nl);
212  check_bfd_error(bfd_set_section_contents(abfd,
213  data_section, code->mcode,0,dseglen));
214  }
215  LOG2("set code_section contents" << nl);
216  #ifdef FAKE_DATASEC
217  if (dseglen) {
218  alloc::vector<u1>::type buffer(codelen);
219  buffer[0] = 0xe9; // jmp rel32
220  buffer[1] = ((dseglen + 3) >> 0) & 0xff;
221  buffer[2] = ((dseglen + 3) >> 8) & 0xff;
222  buffer[3] = ((dseglen + 3) >>16) & 0xff;
223  buffer[4] = ((dseglen + 3) >>32) & 0xff;
224  // copy dataseg
225  memcpy(&buffer[8],code->mcode,dseglen);
226  // copy codeseg
227  memcpy(&buffer[8+dseglen],code->entrypoint,codelen - (dseglen + 8));
228  check_bfd_error(bfd_set_section_contents(abfd,
229  code_section, &buffer.front(),0,codelen));
230  } else
231  #endif
232  check_bfd_error(bfd_set_section_contents(abfd,
233  code_section, code->entrypoint,0,codelen));
234 
235  // close file
236  bfd_close(abfd);
237 
238  RT_TIMER_STOP(obj_writter_timer);
239 #endif // defined(ENABLE_DISASSEMBLER)
240  return true;
241 }
242 
243 // pass usage
246  return PU;
247 }
248 
249 // the address of this variable is used to identify the pass
250 char ObjectFileWriterPass::ID = 0;
251 
252 Option<bool> ObjectFileWriterPass::enabled("ObjectFileWriterPass","compiler2: enable ObjectFileWriterPass",false,::cacao::option::xx_root());
253 
254 // register pass
255 static PassRegistry<ObjectFileWriterPass> X("ObjectFileWriterPass");
256 
257 } // end namespace compiler2
258 } // end namespace jit
259 } // end namespace cacao
260 
261 
262 /*
263  * These are local overrides for various environment variables in Emacs.
264  * Please do not remove this and leave it at the end of the file, where
265  * Emacs will automagically detect them.
266  * ---------------------------------------------------------------------
267  * Local variables:
268  * mode: c++
269  * indent-tabs-mode: t
270  * c-basic-offset: 4
271  * tab-width: 4
272  * End:
273  * vim:noexpandtab:sw=4:ts=4:
274  */
const Utf8String & get_name_utf8() const
Definition: MethodC2.hpp:85
#define RT_TIMER_STOP(var)
Stop the timer var.
Definition: rt-timing.hpp:695
size_t size() const
Definition: utf8.hpp:161
codeinfo * code
Definition: jit.hpp:128
CodeGenPass TODO: more info.
Definition: CodeGenPass.hpp:49
#define RT_TIMER_START(var)
Start the timer var.
Definition: rt-timing.hpp:694
s4 mcodelength
Definition: code.hpp:85
#define DEBUG_COND_N(VERBOSE)
Definition: Debug.hpp:112
virtual PassUsage & get_PassUsage(PassUsage &PA) const
Set the requirements for the pass.
jitdata * get_jitdata() const
Definition: JITData.hpp:51
u1 * mcode
Definition: code.hpp:83
#define RT_REGISTER_TIMER(var, name, description)
Register a new (toplevel) timer.
Definition: rt-timing.hpp:681
std::vector< T, Allocator< T > > type
Definition: vector.hpp:38
Stores the interdependencies of a pass.
Definition: PassUsage.hpp:55
#define LOG2(STMT)
Definition: logging.hpp:93
OStream & err()
Definition: OStream.cpp:33
This file contains the real-time timing utilities.
#define LOG(STMT)
Analogous to DEBUG.
Definition: logging.hpp:91
virtual bool run(JITData &JD)
Run the Pass.
const Utf8String & get_class_name_utf8() const
Definition: MethodC2.hpp:86
byte_iterator begin() const
Definition: utf8.hpp:106
OptionPrefix & xx_root()
Definition: Option.cpp:39
const Method & M
#define ABORT_MSG(EXPR_SHORT, EXPR_LONG)
Definition: logging.hpp:133
static PassRegistry< BasicBlockSchedulingPass > X("BasicBlockSchedulingPass")
Nl nl
Definition: OStream.cpp:56
void add_requires()
PassName is required.
Definition: PassUsage.hpp:78
u1 * entrypoint
Definition: code.hpp:84