1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "gtest/gtest.h"
18 
19 #include <sys/mman.h>
20 
21 #include <iterator>
22 #include <string>
23 
24 #include "berberis/assembler/machine_code.h"
25 #include "berberis/assembler/x86_32.h"
26 #include "berberis/assembler/x86_64.h"
27 #include "berberis/base/bit_util.h"
28 #include "berberis/base/logging.h"
29 #include "berberis/test_utils/scoped_exec_region.h"
30 
31 #if defined(__i386__)
32 using CodeEmitter = berberis::x86_32::Assembler;
33 #elif defined(__amd64__)
34 using CodeEmitter = berberis::x86_64::Assembler;
35 #else
36 #error "Unsupported platform"
37 #endif
38 
39 namespace berberis {
40 
Callee()41 int Callee() {
42   return 239;
43 }
44 
FloatFunc(float f1,float f2)45 float FloatFunc(float f1, float f2) {
46   return f1 - f2;
47 }
48 
CompareCode(const uint8_t * code_template_begin,const uint8_t * code_template_end,const MachineCode & code)49 inline bool CompareCode(const uint8_t* code_template_begin,
50                         const uint8_t* code_template_end,
51                         const MachineCode& code) {
52   if ((code_template_end - code_template_begin) != static_cast<intptr_t>(code.install_size())) {
53     ALOGE("Code size mismatch: %zd != %u",
54           code_template_end - code_template_begin,
55           code.install_size());
56     return false;
57   }
58 
59   if (memcmp(code_template_begin, code.AddrAs<uint8_t>(0), code.install_size()) != 0) {
60     ALOGE("Code mismatch");
61     MachineCode code2;
62     code2.AddSequence(code_template_begin, code_template_end - code_template_begin);
63     std::string code_str1, code_str2;
64     code.AsString(&code_str1);
65     code2.AsString(&code_str2);
66     ALOGE("assembler generated\n%s\nshall be\n%s", code_str1.c_str(), code_str2.c_str());
67     return false;
68   }
69   return true;
70 }
71 
72 #if defined(__i386__)
73 
74 namespace x86_32 {
75 
AssemblerTest()76 bool AssemblerTest() {
77   MachineCode code;
78   CodeEmitter assembler(&code);
79   assembler.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 4});
80   assembler.CmpXchgl({.base = Assembler::esp, .disp = 4}, Assembler::eax);
81   assembler.Subl(Assembler::esp, 16);
82   assembler.Movl({.base = Assembler::esp}, Assembler::eax);
83   assembler.Push(Assembler::esp);
84   assembler.Push(0xcccccccc);
85   assembler.Pushl({.base = Assembler::esp, .disp = 0x428});
86   assembler.Popl({.base = Assembler::esp, .disp = 0x428});
87   assembler.Movl(Assembler::ecx, 0xcccccccc);
88   assembler.Call(Assembler::ecx);
89   assembler.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 8});
90   assembler.Addl(Assembler::esp, 24);
91   assembler.Ret();
92   assembler.Finalize();
93 
94   // clang-format off
95   static const uint8_t code_template[] = {
96     0x8b, 0x44, 0x24, 0x04,                    // mov     0x4(%esp),%eax
97     0x0f, 0xb1, 0x44, 0x24, 0x04,              // cmpxchg 0x4(%esp),%eax
98     0x83, 0xec, 0x10,                          // sub     $16, %esp
99     0x89, 0x04, 0x24,                          // mov     %eax,(%esp)
100     0x54,                                      // push    %esp
101     0x68, 0xcc, 0xcc, 0xcc, 0xcc,              // push    $cccccccc
102     0xff, 0xb4, 0x24, 0x28, 0x04, 0x00, 0x00,  // pushl   0x428(%esp)
103     0x8f, 0x84, 0x24, 0x28, 0x04, 0x00, 0x00,  // popl    0x428(%esp)
104     0xb9, 0xcc, 0xcc, 0xcc, 0xcc,              // mov     $cccccccc, %ecx
105     0xff, 0xd1,                                // call    *%ecx
106     0x8b, 0x44, 0x24, 0x08,                    // mov     0x8(%esp),%eax
107     0x83, 0xc4, 0x18,                          // add     $24, %esp
108     0xc3                                       //  ret
109   };
110   // clang-format on
111 
112   if (sizeof(code_template) != code.install_size()) {
113     ALOGE("Code size mismatch: %zu != %u", sizeof(code_template), code.install_size());
114     return false;
115   }
116 
117   if (memcmp(code_template, code.AddrAs<uint8_t>(0), code.install_size()) != 0) {
118     ALOGE("Code mismatch");
119     MachineCode code2;
120     code2.Add(code_template);
121     std::string code_str1, code_str2;
122     code.AsString(&code_str1);
123     code2.AsString(&code_str2);
124     ALOGE("assembler generated\n%s\nshall be\n%s", code_str1.c_str(), code_str2.c_str());
125     return false;
126   }
127 
128   return true;
129 }
130 
LabelTest()131 bool LabelTest() {
132   MachineCode code;
133   CodeEmitter as(&code);
134   Assembler::Label skip, skip2, back, end;
135   as.Call(bit_cast<const void*>(&Callee));
136   as.Jmp(skip);
137   as.Movl(Assembler::eax, 2);
138   as.Bind(&skip);
139   as.Addl(Assembler::eax, 8);
140   as.Jmp(skip2);
141   as.Bind(&back);
142   as.Addl(Assembler::eax, 12);
143   as.Jmp(end);
144   as.Bind(&skip2);
145   as.Jmp(back);
146   as.Bind(&end);
147   as.Ret();
148   as.Finalize();
149 
150   ScopedExecRegion exec(&code);
151 
152   int result = exec.get<int()>()();
153   return result == 239 + 8 + 12;
154 }
155 
CondTest1()156 bool CondTest1() {
157   MachineCode code;
158   CodeEmitter as(&code);
159   as.Movl(Assembler::eax, 0xcccccccc);
160   as.Movl(Assembler::edx, {.base = Assembler::esp, .disp = 4});  // arg1.
161   as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 8});  // arg2.
162   as.Cmpl(Assembler::edx, Assembler::ecx);
163   as.Setcc(Assembler::Condition::kEqual, Assembler::eax);
164   as.Ret();
165   as.Finalize();
166 
167   ScopedExecRegion exec(&code);
168 
169   using TestFunc = uint32_t(int, int);
170   auto target_func = exec.get<TestFunc>();
171   uint32_t result = target_func(1, 2);
172   if (result != 0xcccccc00) {
173     ALOGE("Bug in seteq(not equal): %x", result);
174     return false;
175   }
176   result = target_func(-1, -1);
177   if (result != 0xcccccc01) {
178     ALOGE("Bug in seteq(equal): %x", result);
179     return false;
180   }
181   return true;
182 }
183 
CondTest2()184 bool CondTest2() {
185   MachineCode code;
186   CodeEmitter as(&code);
187   as.Movl(Assembler::edx, {.base = Assembler::esp, .disp = 4});  // arg1.
188   as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 8});  // arg2.
189   as.Xorl(Assembler::eax, Assembler::eax);
190   as.Testb(Assembler::edx, Assembler::ecx);
191   as.Setcc(Assembler::Condition::kNotZero, Assembler::eax);
192   as.Xchgl(Assembler::eax, Assembler::ecx);
193   as.Xchgl(Assembler::ecx, Assembler::eax);
194   as.Ret();
195   as.Finalize();
196 
197   ScopedExecRegion exec(&code);
198 
199   using TestFunc = uint32_t(int, int);
200   auto target_func = exec.get<TestFunc>();
201   uint32_t result = target_func(0x11, 1);
202   if (result != 0x1) {
203     ALOGE("Bug in testb(not zero): %x", result);
204     return false;
205   }
206   result = target_func(0x11, 0x8);
207   if (result != 0x0) {
208     ALOGE("Bug in testb(zero): %x", result);
209     return false;
210   }
211   return true;
212 }
213 
JccTest()214 bool JccTest() {
215   MachineCode code;
216   CodeEmitter as(&code);
217   Assembler::Label equal, above, below, done;
218   as.Movl(Assembler::edx, {.base = Assembler::esp, .disp = 4});  // arg1.
219   as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 8});  // arg2.
220   as.Cmpl(Assembler::edx, Assembler::ecx);
221   as.Jcc(Assembler::Condition::kEqual, equal);
222   as.Jcc(Assembler::Condition::kBelow, below);
223   as.Jcc(Assembler::Condition::kAbove, above);
224 
225   as.Movl(Assembler::eax, 13);
226   as.Jmp(done);
227 
228   as.Bind(&equal);
229   as.Movl(Assembler::eax, 0u);
230   as.Jmp(done);
231 
232   as.Bind(&below);
233   as.Movl(Assembler::eax, -1);
234   as.Jmp(done);
235 
236   as.Bind(&above);
237   as.Movl(Assembler::eax, 1);
238   as.Jmp(done);
239 
240   as.Bind(&done);
241   as.Ret();
242   as.Finalize();
243 
244   ScopedExecRegion exec(&code);
245 
246   using TestFunc = int(int, int);
247   auto target_func = exec.get<TestFunc>();
248   int result = target_func(1, 1);
249   if (result != 0) {
250     ALOGE("Bug in jcc(equal): %x", result);
251     return false;
252   }
253   result = target_func(1, 0);
254   if (result != 1) {
255     ALOGE("Bug in jcc(above): %x", result);
256     return false;
257   }
258   result = target_func(0, 1);
259   if (result != -1) {
260     ALOGE("Bug in jcc(below): %x", result);
261     return false;
262   }
263   return true;
264 }
265 
ShiftTest()266 bool ShiftTest() {
267   MachineCode code;
268   CodeEmitter as(&code);
269   as.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 4});
270   as.Shll(Assembler::eax, int8_t{2});
271   as.Shrl(Assembler::eax, int8_t{1});
272   as.Movl(Assembler::ecx, 3);
273   as.ShllByCl(Assembler::eax);
274   as.Ret();
275   as.Finalize();
276 
277   ScopedExecRegion exec(&code);
278 
279   using TestFunc = uint32_t(uint32_t);
280   uint32_t result = exec.get<TestFunc>()(22);
281   return result == (22 << 4);
282 }
283 
LogicTest()284 bool LogicTest() {
285   MachineCode code;
286   CodeEmitter as(&code);
287   as.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 4});
288   as.Movl(Assembler::ecx, 0x1);
289   as.Xorl(Assembler::eax, Assembler::ecx);
290   as.Movl(Assembler::ecx, 0xf);
291   as.Andl(Assembler::eax, Assembler::ecx);
292   as.Ret();
293   as.Finalize();
294 
295   ScopedExecRegion exec(&code);
296 
297   using TestFunc = uint32_t(uint32_t);
298   uint32_t result = exec.get<TestFunc>()(239);
299   return result == ((239 ^ 1) & 0xf);
300 }
301 
BsrTest()302 bool BsrTest() {
303   MachineCode code;
304   CodeEmitter as(&code);
305 
306   as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 4});
307   as.Movl(Assembler::edx, 239);
308   as.Bsrl(Assembler::eax, Assembler::ecx);
309   as.Cmovl(Assembler::Condition::kZero, Assembler::eax, Assembler::edx);
310   as.Ret();
311   as.Finalize();
312 
313   ScopedExecRegion exec(&code);
314 
315   using TestFunc = uint32_t(uint32_t arg);
316   auto func = exec.get<TestFunc>();
317   return func(0) == 239 && func(1 << 15) == 15;
318 }
319 
CallFPTest()320 bool CallFPTest() {
321   MachineCode code;
322   CodeEmitter as(&code);
323   as.Push(0x3f800000);
324   as.Push(0x40000000);
325   as.Call(bit_cast<const void*>(&FloatFunc));
326   as.Fstps({.base = Assembler::esp});
327   as.Pop(Assembler::eax);
328   as.Addl(Assembler::esp, 4);
329   as.Ret();
330   as.Finalize();
331 
332   ScopedExecRegion exec(&code);
333 
334   using TestFunc = uint32_t();
335   uint32_t result = exec.get<TestFunc>()();
336   return result == 0x3f800000;
337 }
338 
XmmTest()339 bool XmmTest() {
340   MachineCode code;
341   CodeEmitter as(&code);
342   as.Movl(Assembler::eax, 0x3f800000);
343   as.Movd(Assembler::xmm0, Assembler::eax);
344   as.Movl(Assembler::eax, 0x40000000);
345   as.Movd(Assembler::xmm5, Assembler::eax);
346   as.Addss(Assembler::xmm0, Assembler::xmm5);
347   as.Movd(Assembler::eax, Assembler::xmm0);
348   as.Ret();
349   as.Finalize();
350 
351   ScopedExecRegion exec(&code);
352 
353   using TestFunc = uint32_t();
354   uint32_t result = exec.get<TestFunc>()();
355   return result == 0x40400000;
356 }
357 
ReadGlobalTest()358 bool ReadGlobalTest() {
359   MachineCode code;
360   CodeEmitter as(&code);
361   static const uint32_t kData[] __attribute__((aligned(16))) =  // NOLINT
362       {0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff};
363   as.Movsd(Assembler::xmm0, {.disp = bit_cast<int32_t>(&kData)});
364   as.Movdqa(Assembler::xmm1, {.disp = bit_cast<int32_t>(&kData)});
365   as.Movl(Assembler::eax, {.base = Assembler::esp, .disp = 4});
366   as.Movl(Assembler::ecx, {.base = Assembler::esp, .disp = 8});
367   as.Movsd({.base = Assembler::eax}, Assembler::xmm0);
368   as.Movdqu({.base = Assembler::ecx}, Assembler::xmm1);
369 
370   as.Ret();
371   as.Finalize();
372 
373   ScopedExecRegion exec(&code);
374 
375   using TestFunc = void(void*, void*);
376   uint8_t res1[8];
377   uint8_t res2[16];
378   exec.get<TestFunc>()(res1, res2);
379 
380   return (memcmp(res1, kData, 8) == 0) && (memcmp(res2, kData, 16) == 0);
381 }
382 
383 }  // namespace x86_32
384 
385 #elif defined(__amd64__)
386 
387 namespace x86_64 {
388 
AssemblerTest()389 bool AssemblerTest() {
390   MachineCode code;
391   CodeEmitter assembler(&code);
392   assembler.Movq(Assembler::rax, Assembler::rdi);
393   assembler.Subq(Assembler::rsp, 16);
394   assembler.Movq({.base = Assembler::rsp}, Assembler::rax);
395   assembler.Movq({.base = Assembler::rsp, .disp = 8}, Assembler::rax);
396   assembler.Movl({.base = Assembler::rax, .disp = 16}, 239);
397   assembler.Movq(Assembler::r11, {.base = Assembler::rsp});
398   assembler.Addq(Assembler::rsp, 16);
399   assembler.Ret();
400   assembler.Finalize();
401 
402   // clang-format off
403   static const uint8_t code_template[] = {
404     0x48, 0x89, 0xf8,               // mov %rdi, %rax
405     0x48, 0x83, 0xec, 0x10,         // sub $0x10, %rsp
406     0x48, 0x89, 0x04, 0x24,         // mov rax, (%rsp)
407     0x48, 0x89, 0x44, 0x24, 0x08,   // mov rax, 8(%rsp)
408     0xc7, 0x40, 0x10, 0xef, 0x00,   // movl $239, 0x10(%rax)
409     0x00, 0x00,
410     0x4c, 0x8b, 0x1c, 0x24,         // mov (%rsp), r11
411     0x48, 0x83, 0xc4, 0x10,         // add $0x10, %rsp
412     0xc3                            // ret
413   };
414   // clang-format on
415 
416   if (sizeof(code_template) != code.install_size()) {
417     ALOGE("Code size mismatch: %zu != %u", sizeof(code_template), code.install_size());
418     return false;
419   }
420 
421   if (memcmp(code_template, code.AddrAs<uint8_t>(0), code.install_size()) != 0) {
422     ALOGE("Code mismatch");
423     MachineCode code2;
424     code2.Add(code_template);
425     std::string code_str1, code_str2;
426     code.AsString(&code_str1);
427     code2.AsString(&code_str2);
428     ALOGE("assembler generated\n%s\nshall be\n%s", code_str1.c_str(), code_str2.c_str());
429     return false;
430   }
431   return true;
432 }
433 
LabelTest()434 bool LabelTest() {
435   MachineCode code;
436   CodeEmitter as(&code);
437   Assembler::Label skip, skip2, back, end;
438   as.Call(bit_cast<const void*>(&Callee));
439   as.Jmp(skip);
440   as.Movl(Assembler::rax, 2);
441   as.Bind(&skip);
442   as.Addb(Assembler::rax, {end});
443   as.Jmp(skip2);
444   as.Bind(&back);
445   as.Addl(Assembler::rax, 12);
446   as.Jmp(end);
447   as.Bind(&skip2);
448   as.Jmp(back);
449   as.Bind(&end);
450   as.Ret();
451   as.Finalize();
452 
453   ScopedExecRegion exec(&code);
454 
455   using TestFunc = int();
456   int result = exec.get<TestFunc>()();
457   return result == uint8_t(239 + 0xc3) + 12;
458 }
459 
CondTest1()460 bool CondTest1() {
461   MachineCode code;
462   CodeEmitter as(&code);
463   as.Movl(Assembler::rax, 0xcccccccc);
464   as.Cmpl(Assembler::rdi, Assembler::rsi);
465   as.Setcc(Assembler::Condition::kEqual, Assembler::rax);
466   as.Ret();
467   as.Finalize();
468 
469   ScopedExecRegion exec(&code);
470 
471   std::string code_str;
472   code.AsString(&code_str);
473   using TestFunc = uint32_t(int, int);
474   auto target_func = exec.get<TestFunc>();
475   uint32_t result;
476   result = target_func(1, 2);
477   if (result != 0xcccccc00) {
478     ALOGE("Bug in seteq(not equal): %x", result);
479     return false;
480   }
481   result = target_func(-1, -1);
482   if (result != 0xcccccc01) {
483     ALOGE("Bug in seteq(equal): %x", result);
484     return false;
485   }
486   return true;
487 }
488 
CondTest2()489 bool CondTest2() {
490   MachineCode code;
491   CodeEmitter as(&code);
492   as.Movl(Assembler::rdx, Assembler::rdi);  // arg1.
493   as.Movl(Assembler::rcx, Assembler::rsi);  // arg2.
494   as.Xorl(Assembler::rax, Assembler::rax);
495   as.Testb(Assembler::rdx, Assembler::rcx);
496   as.Setcc(Assembler::Condition::kNotZero, Assembler::rax);
497   as.Xchgq(Assembler::rax, Assembler::rcx);
498   as.Xchgq(Assembler::rcx, Assembler::rax);
499   as.Xchgq(Assembler::rcx, Assembler::r11);
500   as.Xchgq(Assembler::r11, Assembler::rcx);
501   as.Ret();
502   as.Finalize();
503 
504   ScopedExecRegion exec(&code);
505 
506   using TestFunc = uint32_t(int, int);
507   auto target_func = exec.get<TestFunc>();
508   uint32_t result = target_func(0x11, 1);
509   if (result != 0x1) {
510     printf("Bug in testb(not zero): %x", result);
511     return false;
512   }
513   result = target_func(0x11, 0x8);
514   if (result != 0x0) {
515     printf("Bug in testb(zero): %x", result);
516     return false;
517   }
518   return true;
519 }
520 
JccTest()521 bool JccTest() {
522   MachineCode code;
523   CodeEmitter as(&code);
524   Assembler::Label equal, above, below, done;
525   as.Cmpl(Assembler::rdi, Assembler::rsi);
526   as.Jcc(Assembler::Condition::kEqual, equal);
527   as.Jcc(Assembler::Condition::kBelow, below);
528   as.Jcc(Assembler::Condition::kAbove, above);
529 
530   as.Movl(Assembler::rax, 13);
531   as.Jmp(done);
532 
533   as.Bind(&equal);
534   as.Movq(Assembler::rax, 0);
535   as.Jmp(done);
536 
537   as.Bind(&below);
538   as.Movl(Assembler::rax, -1);
539   as.Jmp(done);
540 
541   as.Bind(&above);
542   as.Movl(Assembler::rax, 1);
543   as.Jmp(done);
544 
545   as.Bind(&done);
546   as.Ret();
547   as.Finalize();
548 
549   ScopedExecRegion exec(&code);
550 
551   using TestFunc = int(int, int);
552   auto target_func = exec.get<TestFunc>();
553   int result;
554   result = target_func(1, 1);
555   if (result != 0) {
556     ALOGE("Bug in jcc(equal): %x", result);
557     return false;
558   }
559   result = target_func(1, 0);
560   if (result != 1) {
561     ALOGE("Bug in jcc(above): %x", result);
562     return false;
563   }
564   result = target_func(0, 1);
565   if (result != -1) {
566     ALOGE("Bug in jcc(below): %x", result);
567     return false;
568   }
569   return true;
570 }
571 
ReadWriteTest()572 bool ReadWriteTest() {
573   MachineCode code;
574   CodeEmitter as(&code);
575 
576   as.Movq(Assembler::rax, 0);
577   as.Movb(Assembler::rax, {.base = Assembler::rdi});
578   as.Movl(Assembler::rcx, {.base = Assembler::rsi});
579   as.Addl(Assembler::rax, Assembler::rcx);
580   as.Movl({.base = Assembler::rsi}, Assembler::rax);
581   as.Ret();
582   as.Finalize();
583 
584   ScopedExecRegion exec(&code);
585 
586   using TestFunc = uint32_t(uint8_t*, uint32_t*);
587   uint8_t p1[4] = {0x12, 0x34, 0x56, 0x78};
588   uint32_t p2 = 0x239;
589   uint32_t result = exec.get<TestFunc>()(p1, &p2);
590   return (result == 0x239 + 0x12) && (p2 == result);
591 }
592 
CallFPTest()593 bool CallFPTest() {
594   MachineCode code;
595   CodeEmitter as(&code);
596   as.Movl(Assembler::rax, 0x40000000);
597   as.Movd(Assembler::xmm0, Assembler::rax);
598   as.Movl(Assembler::rax, 0x3f800000);
599   as.Movd(Assembler::xmm1, Assembler::rax);
600   as.Call(bit_cast<const void*>(&FloatFunc));
601   as.Movd(Assembler::rax, Assembler::xmm0);
602   as.Ret();
603   as.Finalize();
604 
605   ScopedExecRegion exec(&code);
606 
607   using TestFunc = uint32_t();
608   uint32_t result = exec.get<TestFunc>()();
609   return result == 0x3f800000;
610 }
611 
XmmTest()612 bool XmmTest() {
613   MachineCode code;
614   CodeEmitter as(&code);
615   as.Movl(Assembler::rax, 0x40000000);
616   as.Movd(Assembler::xmm0, Assembler::rax);
617   as.Movl(Assembler::rax, 0x3f800000);
618   as.Movd(Assembler::xmm11, Assembler::rax);
619   as.Addss(Assembler::xmm0, Assembler::xmm11);
620   as.Movaps(Assembler::xmm12, Assembler::xmm0);
621   as.Addss(Assembler::xmm0, Assembler::xmm12);
622   as.Movapd(Assembler::xmm14, Assembler::xmm1);
623   as.Movd(Assembler::rax, Assembler::xmm0);
624   as.Ret();
625   as.Finalize();
626 
627   ScopedExecRegion exec(&code);
628 
629   using TestFunc = uint32_t();
630   uint32_t result = exec.get<TestFunc>()();
631   return result == 0x40c00000;
632 }
633 
XmmMemTest()634 bool XmmMemTest() {
635   MachineCode code;
636   CodeEmitter as(&code);
637 
638   as.Movsd(Assembler::xmm0, {.base = Assembler::rdi});
639   as.Movaps(Assembler::xmm12, Assembler::xmm0);
640   as.Addsd(Assembler::xmm12, Assembler::xmm12);
641   as.Movsd({.base = Assembler::rdi}, Assembler::xmm12);
642   as.Movq(Assembler::rax, Assembler::xmm0);
643   as.Ret();
644   as.Finalize();
645 
646   ScopedExecRegion exec(&code);
647 
648   double d = 239.0;
649   char bits[16], *p = bits + 5;
650   memcpy(p, &d, sizeof(d));
651 
652   using TestFunc = uint64_t(char* p);
653   uint64_t result = exec.get<TestFunc>()(p);
654   uint64_t doubled = *reinterpret_cast<uint64_t*>(p);
655   return result == 0x406de00000000000ULL && doubled == 0x407de00000000000ULL;
656 }
657 
MovsxblRexTest()658 bool MovsxblRexTest() {
659   MachineCode code;
660   CodeEmitter as(&code);
661 
662   as.Xorl(Assembler::rdx, Assembler::rdx);
663   as.Movl(Assembler::rsi, 0xdeadff);
664   // CodeEmitter should use REX prefix to encode SIL.
665   // Without REX DH is used.
666   as.Movsxbl(Assembler::rax, Assembler::rsi);
667   as.Ret();
668   as.Finalize();
669 
670   ScopedExecRegion exec(&code);
671 
672   using TestFunc = uint32_t();
673   uint32_t result = exec.get<TestFunc>()();
674 
675   return result == 0xffffffff;
676 }
677 
MovzxblRexTest()678 bool MovzxblRexTest() {
679   MachineCode code;
680   CodeEmitter as(&code);
681 
682   as.Xorl(Assembler::rdx, Assembler::rdx);
683   as.Movl(Assembler::rsi, 0xdeadff);
684   // CodeEmitter should use REX prefix to encode SIL.
685   // Without REX DH is used.
686   as.Movzxbl(Assembler::rax, Assembler::rsi);
687   as.Ret();
688   as.Finalize();
689 
690   ScopedExecRegion exec(&code);
691 
692   using TestFunc = uint32_t();
693   uint32_t result = exec.get<TestFunc>()();
694 
695   return result == 0x000000ff;
696 }
697 
ShldlRexTest()698 bool ShldlRexTest() {
699   MachineCode code;
700   CodeEmitter as(&code);
701 
702   as.Movl(Assembler::rdx, 0x12345678);
703   // If most-significant bit is not encoded correctly with REX
704   // RAX can be used instead R8 and R10 can be used instead RDX.
705   // Init them all:
706   as.Xorl(Assembler::r8, Assembler::r8);
707   as.Movl(Assembler::rax, 0xdeadbeef);
708   as.Movl(Assembler::r10, 0xdeadbeef);
709 
710   as.Shldl(Assembler::r8, Assembler::rdx, int8_t{8});
711   as.Movl(Assembler::rcx, 8);
712   as.ShldlByCl(Assembler::r8, Assembler::rdx);
713 
714   as.Movl(Assembler::rax, Assembler::r8);
715 
716   as.Ret();
717   as.Finalize();
718 
719   ScopedExecRegion exec(&code);
720 
721   using TestFunc = uint32_t();
722   uint32_t result = exec.get<TestFunc>()();
723 
724   return result == 0x1212;
725 }
726 
ShrdlRexTest()727 bool ShrdlRexTest() {
728   MachineCode code;
729   CodeEmitter as(&code);
730 
731   as.Movl(Assembler::rdx, 0x12345678);
732   // If most-significant bit is not encoded correctly with REX
733   // RAX can be used instead R8 and R10 can be used instead RDX.
734   // Init them all:
735   as.Xorl(Assembler::r8, Assembler::r8);
736   as.Movl(Assembler::rax, 0xdeadbeef);
737   as.Movl(Assembler::r10, 0xdeadbeef);
738 
739   as.Shrdl(Assembler::r8, Assembler::rdx, int8_t{8});
740   as.Movl(Assembler::rcx, 8);
741   as.ShrdlByCl(Assembler::r8, Assembler::rdx);
742 
743   as.Movl(Assembler::rax, Assembler::r8);
744 
745   as.Ret();
746   as.Finalize();
747 
748   ScopedExecRegion exec(&code);
749 
750   using TestFunc = uint32_t();
751   uint32_t result = exec.get<TestFunc>()();
752 
753   return result == 0x78780000;
754 }
755 
ReadGlobalTest()756 bool ReadGlobalTest() {
757   MachineCode code;
758   CodeEmitter as(&code);
759   static const uint32_t kData[] __attribute__((aligned(16))) =  // NOLINT
760       {0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff};
761   // We couldn't read data from arbitrary address on x86_64, need address in first 2GiB.
762   void* data =
763       mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
764   // Copy our global there.
765   memcpy(data, kData, 16);
766   int32_t data_offset = static_cast<int32_t>(bit_cast<intptr_t>(data));
767   as.Movsd(Assembler::xmm0, {.disp = data_offset});
768   as.Movdqa(Assembler::xmm1, {.disp = data_offset});
769   as.Movsd({.base = Assembler::rdi}, Assembler::xmm0);
770   as.Movdqu({.base = Assembler::rsi}, Assembler::xmm1);
771 
772   as.Ret();
773   as.Finalize();
774 
775   ScopedExecRegion exec(&code);
776 
777   using TestFunc = void(void*, void*);
778   uint8_t res1[8];
779   uint8_t res2[16];
780   exec.get<TestFunc>()(res1, res2);
781 
782   munmap(data, 4096);
783 
784   return (memcmp(res1, kData, 8) == 0) && (memcmp(res2, kData, 16) == 0);
785 }
786 
MemShiftTest()787 bool MemShiftTest() {
788   MachineCode code;
789   CodeEmitter as(&code);
790 
791   as.Push(Assembler::rdi);
792   as.Movl(Assembler::rcx, 1);
793   as.ShrlByCl({.base = Assembler::rsp});
794   as.Addl(Assembler::rcx, 1);
795   as.Movq(Assembler::rdi, Assembler::rsp);
796   as.ShllByCl({.base = Assembler::rdi});
797   as.Pop(Assembler::rax);
798 
799   as.Ret();
800   as.Finalize();
801 
802   ScopedExecRegion exec(&code);
803 
804   using TestFunc = int(int x);
805   int result = exec.get<TestFunc>()(0x10);
806 
807   return result == 0x20;
808 }
809 
810 }  // namespace x86_64
811 
812 #endif
813 
814 #if defined(__i386__) || defined(__amd64__)
815 
816 #if defined(__i386__)
817 
818 extern "C" const uint8_t berberis_gnu_as_output_start[] asm(
819     "berberis_gnu_as_output_start_x86_32");
820 extern "C" const uint8_t berberis_gnu_as_output_end[] asm(
821     "berberis_gnu_as_output_end_x86_32");
822 
823 namespace x86_32 {
824 void GenInsnsCommon(CodeEmitter* as);
825 void GenInsnsArch(CodeEmitter* as);
826 }  // namespace x86_32
827 
828 #else
829 
830 extern "C" const uint8_t berberis_gnu_as_output_start[] asm(
831     "berberis_gnu_as_output_start_x86_64");
832 extern "C" const uint8_t berberis_gnu_as_output_end[] asm(
833     "berberis_gnu_as_output_end_x86_64");
834 
835 namespace x86_64 {
836 void GenInsnsCommon(CodeEmitter* as);
837 void GenInsnsArch(CodeEmitter* as);
838 }  // namespace x86_64
839 
840 #endif
841 
ExhaustiveTest()842 bool ExhaustiveTest() {
843   MachineCode code;
844   CodeEmitter as(&code);
845 
846 #if defined(__i386__)
847   berberis::x86_32::GenInsnsCommon(&as);
848   berberis::x86_32::GenInsnsArch(&as);
849 #else
850   berberis::x86_64::GenInsnsCommon(&as);
851   berberis::x86_64::GenInsnsArch(&as);
852 #endif
853   as.Finalize();
854 
855   return CompareCode(berberis_gnu_as_output_start, berberis_gnu_as_output_end, code);
856 }
857 
MixedAssembler()858 bool MixedAssembler() {
859   MachineCode code;
860   x86_32::Assembler as32(&code);
861   x86_64::Assembler as64(&code);
862   x86_32::Assembler::Label lbl32;
863   x86_64::Assembler::Label lbl64;
864 
865   as32.Jmp(lbl32);
866   as32.Xchgl(x86_32::Assembler::eax, x86_32::Assembler::eax);
867   as64.Jmp(lbl64);
868   as64.Xchgl(x86_64::Assembler::rax, x86_64::Assembler::rax);
869   as32.Bind(&lbl32);
870   as32.Movl(x86_32::Assembler::eax, {.disp = 0});
871   as64.Bind(&lbl64);
872   as32.Finalize();
873   as64.Finalize();
874 
875   // clang-format off
876   static const uint8_t code_template[] = {
877     0xe9, 0x08, 0x00, 0x00, 0x00,              // jmp lbl32
878     0x90,                                      // xchg %eax, %eax == nop
879     0xe9, 0x07, 0x00, 0x00, 0x00,              // jmp lbl64
880     0x87, 0xc0,                                // xchg %eax, %eax != nop
881                                                // lbl32:
882     0xa1, 0x00, 0x00, 0x00, 0x00               // movabs %eax, 0x0
883                                                // lbl64:
884   };
885   // clang-format on
886 
887   return CompareCode(std::begin(code_template), std::end(code_template), code);
888 }
889 #endif
890 
891 }  // namespace berberis
892 
TEST(Assembler,AssemblerTest)893 TEST(Assembler, AssemblerTest) {
894 #if defined(__i386__)
895   EXPECT_TRUE(berberis::x86_32::AssemblerTest());
896   EXPECT_TRUE(berberis::x86_32::LabelTest());
897   EXPECT_TRUE(berberis::x86_32::CondTest1());
898   EXPECT_TRUE(berberis::x86_32::CondTest2());
899   EXPECT_TRUE(berberis::x86_32::JccTest());
900   EXPECT_TRUE(berberis::x86_32::ShiftTest());
901   EXPECT_TRUE(berberis::x86_32::LogicTest());
902   EXPECT_TRUE(berberis::x86_32::CallFPTest());
903   EXPECT_TRUE(berberis::x86_32::XmmTest());
904   EXPECT_TRUE(berberis::x86_32::BsrTest());
905   EXPECT_TRUE(berberis::x86_32::ReadGlobalTest());
906   EXPECT_TRUE(berberis::ExhaustiveTest());
907   EXPECT_TRUE(berberis::MixedAssembler());
908 #elif defined(__amd64__)
909   EXPECT_TRUE(berberis::x86_64::AssemblerTest());
910   EXPECT_TRUE(berberis::x86_64::LabelTest());
911   EXPECT_TRUE(berberis::x86_64::CondTest1());
912   EXPECT_TRUE(berberis::x86_64::CondTest2());
913   EXPECT_TRUE(berberis::x86_64::JccTest());
914   EXPECT_TRUE(berberis::x86_64::ReadWriteTest());
915   EXPECT_TRUE(berberis::x86_64::CallFPTest());
916   EXPECT_TRUE(berberis::x86_64::XmmTest());
917   EXPECT_TRUE(berberis::x86_64::XmmMemTest());
918   EXPECT_TRUE(berberis::x86_64::MovsxblRexTest());
919   EXPECT_TRUE(berberis::x86_64::MovzxblRexTest());
920   EXPECT_TRUE(berberis::x86_64::ShldlRexTest());
921   EXPECT_TRUE(berberis::x86_64::ShrdlRexTest());
922   EXPECT_TRUE(berberis::x86_64::ReadGlobalTest());
923   EXPECT_TRUE(berberis::x86_64::MemShiftTest());
924   EXPECT_TRUE(berberis::ExhaustiveTest());
925   EXPECT_TRUE(berberis::MixedAssembler());
926 #endif
927 }
928