mc2lib
x86_64.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2016, Marco Elver
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the
15  * distribution.
16  *
17  * * Neither the name of the software nor the names of its contributors
18  * may be used to endorse or promote products derived from this
19  * software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 #ifndef MC2LIB_CODEGEN_OPS_X86_64_HPP_
35 #define MC2LIB_CODEGEN_OPS_X86_64_HPP_
36 
37 #include <cstdint>
38 #include <stdexcept>
39 
40 #include "strong.hpp"
41 
42 namespace mc2lib {
43 namespace codegen {
44 namespace strong {
45 
47  std::size_t Return(void *code, std::size_t len) const override;
48 
49  std::size_t Delay(std::size_t length, void *code,
50  std::size_t len) const override;
51 
52  std::size_t Read(types::Addr addr, types::InstPtr start, void *code,
53  std::size_t len, types::InstPtr *at) const override;
54 
55  std::size_t ReadAddrDp(types::Addr addr, types::InstPtr start, void *code,
56  std::size_t len, types::InstPtr *at) const override;
57 
58  std::size_t Write(types::Addr addr, types::WriteID write_id,
59  types::InstPtr start, void *code, std::size_t len,
60  types::InstPtr *at) const override;
61 
62  std::size_t ReadModifyWrite(types::Addr addr, types::WriteID write_id,
63  types::InstPtr start, void *code, std::size_t len,
64  types::InstPtr *at) const override;
65 
66  std::size_t CacheFlush(types::Addr addr, void *code,
67  std::size_t len) const override;
68 };
69 
70 inline std::size_t Backend_X86_64::Return(void *code, std::size_t len) const {
71  assert(len >= 1);
72  // ASM> retq ;
73  *static_cast<char *>(code) = 0xc3;
74  return 1;
75 }
76 
77 inline std::size_t Backend_X86_64::Delay(std::size_t length, void *code,
78  std::size_t len) const {
79  char *cnext = static_cast<char *>(code);
80 
81  assert(len >= length);
82  for (std::size_t i = 0; i < length; ++i) {
83  // ASM> nop ;
84  *cnext++ = 0x90;
85  }
86 
87  assert((cnext - static_cast<char *>(code)) ==
88  static_cast<std::ptrdiff_t>(length));
89  return length;
90 }
91 
92 inline std::size_t Backend_X86_64::Read(types::Addr addr, types::InstPtr start,
93  void *code, std::size_t len,
94  types::InstPtr *at) const {
95  char *cnext = static_cast<char *>(code);
96  std::size_t expected_len = 0;
97 
98  if (addr <= static_cast<types::Addr>(0xffffffff)) {
99  switch (sizeof(types::WriteID)) {
100  case 1:
101  // ASM @0> movzbl addr, %eax ;
102  expected_len = 8;
103  assert(len >= expected_len);
104  *at = start;
105 
106  // @0
107  *cnext++ = 0x0f;
108  *cnext++ = 0xb6;
109  *cnext++ = 0x04;
110  *cnext++ = 0x25;
111  *reinterpret_cast<std::uint32_t *>(cnext) =
112  static_cast<std::uint32_t>(addr);
113  cnext += sizeof(std::uint32_t);
114  break;
115 
116  default:
117  throw std::logic_error("Not supported");
118  }
119  } else {
120  switch (sizeof(types::WriteID)) {
121  case 1:
122  // ASM @0> movabs addr, %al ;
123  expected_len = 9;
124  assert(len >= expected_len);
125  *at = start;
126 
127  // @0
128  *cnext++ = 0xa0;
129  break;
130 
131  case 2:
132  // ASM @0> movabs addr, %ax ;
133  expected_len = 10;
134  assert(len >= expected_len);
135  *at = start;
136 
137  // @0
138  *cnext++ = 0x66;
139  *cnext++ = 0xa1;
140  break;
141 
142  default:
143  throw std::logic_error("Not supported");
144  }
145 
146  *reinterpret_cast<std::uint64_t *>(cnext) =
147  static_cast<std::uint64_t>(addr);
148  cnext += sizeof(std::uint64_t);
149  }
150 
151  assert((cnext - static_cast<char *>(code)) ==
152  static_cast<std::ptrdiff_t>(expected_len));
153  return expected_len;
154 }
155 
156 inline std::size_t Backend_X86_64::ReadAddrDp(types::Addr addr,
157  types::InstPtr start, void *code,
158  std::size_t len,
159  types::InstPtr *at) const {
160  char *cnext = static_cast<char *>(code);
161  std::size_t expected_len = 0;
162 
163  // ASM @0> xor %rax, %rax
164  expected_len = 3;
165  assert(len >= expected_len);
166 
167  // @0
168  *cnext++ = 0x48;
169  *cnext++ = 0x31;
170  *cnext++ = 0xc0;
171 
172  if (addr <= static_cast<types::Addr>(0xffffffff)) {
173  switch (sizeof(types::WriteID)) {
174  case 1:
175  // ASM @3> movzbl addr(%rax), %eax ;
176  expected_len = 10;
177  assert(len >= expected_len);
178  *at = start + 3;
179 
180  // @3
181  *cnext++ = 0x0f;
182  *cnext++ = 0xb6;
183  *cnext++ = 0x80;
184  *reinterpret_cast<std::uint32_t *>(cnext) =
185  static_cast<std::uint32_t>(addr);
186  cnext += sizeof(std::uint32_t);
187  break;
188 
189  default:
190  throw std::logic_error("Not supported");
191  }
192  } else {
193  // ASM @03> movabs addr, %rdx ;
194  // @0d> add %rdx, %rax ;
195  expected_len = 19;
196  assert(len >= expected_len);
197  *at = start + 0x10;
198 
199  // @03
200  *cnext++ = 0x48;
201  *cnext++ = 0xba;
202  *reinterpret_cast<std::uint64_t *>(cnext) =
203  static_cast<std::uint64_t>(addr);
204  cnext += sizeof(std::uint64_t);
205 
206  // @0d
207  *cnext++ = 0x48;
208  *cnext++ = 0x01;
209  *cnext++ = 0xd0;
210 
211  switch (sizeof(types::WriteID)) {
212  case 1:
213  // ASM @10> movzbl (%rax), %eax ;
214  // @10
215  *cnext++ = 0x0f;
216  *cnext++ = 0xb6;
217  *cnext++ = 0x00;
218  break;
219 
220  case 2:
221  // ASM @10> movzwl (%rax), %eax ;
222  // @10
223  *cnext++ = 0x0f;
224  *cnext++ = 0xb7;
225  *cnext++ = 0x00;
226  break;
227 
228  default:
229  throw std::logic_error("Not supported");
230  }
231  }
232 
233  assert((cnext - static_cast<char *>(code)) ==
234  static_cast<std::ptrdiff_t>(expected_len));
235  return expected_len;
236 }
237 
238 inline std::size_t Backend_X86_64::Write(types::Addr addr,
239  types::WriteID write_id,
240  types::InstPtr start, void *code,
241  std::size_t len,
242  types::InstPtr *at) const {
243  char *cnext = static_cast<char *>(code);
244  std::size_t expected_len = 0;
245 
246  assert(write_id != 0);
247 
248  if (addr <= static_cast<types::Addr>(0xffffffff)) {
249  switch (sizeof(types::WriteID)) {
250  case 1:
251  // ASM @0> movb write_id, addr ;
252  expected_len = 8;
253  assert(len >= expected_len);
254  *at = start;
255 
256  // @0
257  *cnext++ = 0xc6;
258  *cnext++ = 0x04;
259  *cnext++ = 0x25;
260 
261  *reinterpret_cast<std::uint32_t *>(cnext) =
262  static_cast<std::uint32_t>(addr);
263  cnext += sizeof(std::uint32_t);
264 
265  *reinterpret_cast<types::WriteID *>(cnext) = write_id;
266  cnext += sizeof(types::WriteID);
267  break;
268 
269  default:
270  throw std::logic_error("Not supported");
271  }
272  } else {
273  switch (sizeof(types::WriteID)) {
274  case 1:
275  // ASM @0> movabs addr, %rax ;
276  // @a> movb write_id, (%rax) ;
277  expected_len = 13;
278  assert(len >= expected_len);
279  *at = start + 0xa;
280 
281  // @0
282  *cnext++ = 0x48;
283  *cnext++ = 0xb8;
284  *reinterpret_cast<std::uint64_t *>(cnext) =
285  static_cast<std::uint64_t>(addr);
286  cnext += sizeof(std::uint64_t);
287 
288  // @a
289  *cnext++ = 0xc6;
290  *cnext++ = 0x00;
291  *reinterpret_cast<types::WriteID *>(cnext) = write_id;
292  cnext += sizeof(types::WriteID);
293  break;
294 
295  case 2:
296  // ASM @0> movabs addr, %rax ;
297  // @a> mov write_id, %edx ;
298  // @f> mov %dx, (%rax) ;
299  expected_len = 18;
300  assert(len >= expected_len);
301  *at = start + 0xf;
302 
303  // @0
304  *cnext++ = 0x48;
305  *cnext++ = 0xb8;
306  *reinterpret_cast<std::uint64_t *>(cnext) =
307  static_cast<std::uint64_t>(addr);
308  cnext += sizeof(std::uint64_t);
309 
310  // @a
311  *cnext++ = 0xba;
312  *reinterpret_cast<std::uint32_t *>(cnext) = write_id;
313  cnext += sizeof(std::uint32_t);
314 
315  // @f
316  *cnext++ = 0x66;
317  *cnext++ = 0x89;
318  *cnext++ = 0x10;
319  break;
320 
321  default:
322  throw std::logic_error("Not supported");
323  }
324  }
325 
326  assert((cnext - static_cast<char *>(code)) ==
327  static_cast<std::ptrdiff_t>(expected_len));
328  return expected_len;
329 }
330 
332  types::WriteID write_id,
333  types::InstPtr start,
334  void *code, std::size_t len,
335  types::InstPtr *at) const {
336  char *cnext = static_cast<char *>(code);
337  std::size_t expected_len = 0;
338 
339  assert(write_id != 0);
340 
341  switch (sizeof(types::WriteID)) {
342  case 1:
343  // ASM @0> mov write_id, %al
344  expected_len = 2;
345  assert(len >= expected_len);
346 
347  // @0
348  *cnext++ = 0xb0;
349  *reinterpret_cast<types::WriteID *>(cnext) = write_id;
350  cnext += sizeof(types::WriteID);
351  break;
352 
353  case 2:
354  // ASM @0> mov write_id, %eax
355  expected_len = 5;
356  assert(len >= expected_len);
357 
358  // @0
359  *cnext++ = 0xb8;
360  *reinterpret_cast<std::uint32_t *>(cnext) = write_id;
361  cnext += sizeof(std::uint32_t);
362  break;
363 
364  default:
365  throw std::logic_error("Not supported");
366  }
367 
368  if (addr <= static_cast<types::Addr>(0xffffffff)) {
369  switch (sizeof(types::WriteID)) {
370  case 1:
371  // ASM @2> mov addr, %edx
372  // @7> lock xchg %al, (%rdx)
373  expected_len = 10;
374  assert(len >= expected_len);
375  *at = start + 0x7;
376 
377  // @2
378  *cnext++ = 0xba;
379  *reinterpret_cast<std::uint32_t *>(cnext) =
380  static_cast<std::uint32_t>(addr);
381  cnext += sizeof(std::uint32_t);
382 
383  // @7
384  *cnext++ = 0xf0;
385  *cnext++ = 0x86;
386  *cnext++ = 0x02;
387  break;
388 
389  default:
390  throw std::logic_error("Not supported");
391  }
392  } else {
393  switch (sizeof(types::WriteID)) {
394  case 1:
395  // ASM @2> movabs addr, %rdx ;
396  // @c> lock xchg %al, (%rdx) ;
397  expected_len = 15;
398  assert(len >= expected_len);
399  *at = start + 0xc;
400 
401  // @2
402  *cnext++ = 0x48;
403  *cnext++ = 0xba;
404  *reinterpret_cast<std::uint64_t *>(cnext) =
405  static_cast<std::uint64_t>(addr);
406  cnext += sizeof(std::uint64_t);
407 
408  // @c
409  *cnext++ = 0xf0;
410  *cnext++ = 0x86;
411  *cnext++ = 0x02;
412  break;
413 
414  case 2:
415  // ASM @5> movabs addr, %rdx ;
416  // @f> lock xchg %ax, (%rdx) ;
417  expected_len = 19;
418  assert(len >= expected_len);
419  *at = start + 0xf;
420 
421  // @2
422  *cnext++ = 0x48;
423  *cnext++ = 0xba;
424  *reinterpret_cast<std::uint64_t *>(cnext) =
425  static_cast<std::uint64_t>(addr);
426  cnext += sizeof(std::uint64_t);
427 
428  // @c
429  *cnext++ = 0x66;
430  *cnext++ = 0xf0;
431  *cnext++ = 0x87;
432  *cnext++ = 0x02;
433  break;
434 
435  default:
436  throw std::logic_error("Not supported");
437  }
438  }
439 
440  assert((cnext - static_cast<char *>(code)) ==
441  static_cast<std::ptrdiff_t>(expected_len));
442  return expected_len;
443 }
444 
445 inline std::size_t Backend_X86_64::CacheFlush(types::Addr addr, void *code,
446  std::size_t len) const {
447  char *cnext = static_cast<char *>(code);
448  std::size_t expected_len = 0;
449 
450  if (addr <= static_cast<types::Addr>(0xffffffff)) {
451  // ASM @0> clflush addr ;
452  expected_len = 8;
453  assert(len >= expected_len);
454 
455  // @0
456  *cnext++ = 0x0f;
457  *cnext++ = 0xae;
458  *cnext++ = 0x3c;
459  *cnext++ = 0x25;
460  *reinterpret_cast<std::uint32_t *>(cnext) =
461  static_cast<std::uint32_t>(addr);
462  cnext += sizeof(std::uint32_t);
463  } else {
464  // ASM @0> mov addr, %rdx ;
465  // @a> clflush (%rdx) ;
466  expected_len = 13;
467  assert(len >= expected_len);
468 
469  // @0
470  *cnext++ = 0x48;
471  *cnext++ = 0xba;
472  *reinterpret_cast<std::uint64_t *>(cnext) =
473  static_cast<std::uint64_t>(addr);
474  cnext += sizeof(std::uint64_t);
475 
476  // @a
477  *cnext++ = 0x0f;
478  *cnext++ = 0xae;
479  *cnext++ = 0x3a;
480  }
481 
482  assert((cnext - static_cast<char *>(code)) ==
483  static_cast<std::ptrdiff_t>(expected_len));
484  return expected_len;
485 }
486 
487 } // namespace strong
488 } // namespace codegen
489 } // namespace mc2lib
490 
491 #endif /* MC2LIB_CODEGEN_OPS_X86_64_HPP_ */
492 
493 /* vim: set ts=2 sts=2 sw=2 et : */
std::size_t CacheFlush(types::Addr addr, void *code, std::size_t len) const override
Definition: x86_64.hpp:445
Definition: cats.hpp:47
Types< true >::InstPtr InstPtr
Instruction pointer type.
Definition: types.hpp:81
Definition: strong.hpp:54
std::size_t Delay(std::size_t length, void *code, std::size_t len) const override
Definition: x86_64.hpp:77
std::size_t Write(types::Addr addr, types::WriteID write_id, types::InstPtr start, void *code, std::size_t len, types::InstPtr *at) const override
Definition: x86_64.hpp:238
Types< true >::WriteID WriteID
Write ID type.
Definition: types.hpp:86
std::size_t ReadModifyWrite(types::Addr addr, types::WriteID write_id, types::InstPtr start, void *code, std::size_t len, types::InstPtr *at) const override
Definition: x86_64.hpp:331
Types< true >::Addr Addr
Address type.
Definition: types.hpp:66
std::size_t Read(types::Addr addr, types::InstPtr start, void *code, std::size_t len, types::InstPtr *at) const override
Definition: x86_64.hpp:92
std::size_t ReadAddrDp(types::Addr addr, types::InstPtr start, void *code, std::size_t len, types::InstPtr *at) const override
Definition: x86_64.hpp:156
std::size_t Return(void *code, std::size_t len) const override
Definition: x86_64.hpp:70