1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Copyright (c) 1994-2006 Sun Microsystems Inc. 6 // All Rights Reserved. 7 // 8 // Redistribution and use in source and binary forms, with or without 9 // modification, are permitted provided that the following conditions are 10 // met: 11 // 12 // - Redistributions of source code must retain the above copyright notice, 13 // this list of conditions and the following disclaimer. 14 // 15 // - Redistribution in binary form must reproduce the above copyright 16 // notice, this list of conditions and the following disclaimer in the 17 // documentation and/or other materials provided with the distribution. 18 // 19 // - Neither the name of Sun Microsystems or the names of contributors may 20 // be used to endorse or promote products derived from this software without 21 // specific prior written permission. 22 // 23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 24 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 27 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 28 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 35 // The original source code covered by the above license above has been 36 // modified significantly by Google Inc. 37 // Copyright 2006-2008 the V8 project authors. All rights reserved. 38 39 // This implements a C++ assembler for dynamically generating machine code. 40 // It is heavily based on the v8 assembler, which has a long history of its 41 // own. Relocation information has been removed, and in general things were 42 // made a bit simpler (and slower). Everything is implemented inline. 43 44 #ifndef TRACELINE_ASSEMBLER_H_ 45 #define TRACELINE_ASSEMBLER_H_ 46 47 #include <windows.h> 48 #include <stdio.h> 49 #include <string> 50 51 #include "logging.h" 52 53 #define ASSERT(x) CHECK(x) 54 55 enum Register { 56 EAX = 0, 57 ECX = 1, 58 EDX = 2, 59 EBX = 3, 60 ESP = 4, 61 EBP = 5, 62 ESI = 6, 63 EDI = 7 64 }; 65 66 enum Condition { 67 overflow = 0, 68 no_overflow = 1, 69 below = 2, 70 above_equal = 3, 71 equal = 4, 72 not_equal = 5, 73 below_equal = 6, 74 above = 7, 75 sign = 8, 76 not_sign = 9, 77 parity_even = 10, 78 parity_odd = 11, 79 less = 12, 80 greater_equal = 13, 81 less_equal = 14, 82 greater = 15, 83 84 // aliases 85 zero = equal, 86 not_zero = not_equal, 87 negative = sign, 88 positive = not_sign 89 }; 90 91 // Labels are used for branching, and marks an offset in the CodeBuffer. 92 // A label can be in 3 states: 93 // - Unused, the label has never be used in an instruction. 94 // - Linked, the label has been referenced (by a jump, for example), but the 95 // target is not yet known, because the label is unbound. 96 // - Bound, the label has been bound so the offset is known. 97 class Label { 98 public: Label()99 Label() { Unuse(); } ~Label()100 ~Label() { ASSERT(!is_linked()); } 101 Unuse()102 void Unuse() { 103 num_ = 0; 104 } 105 is_unused()106 bool is_unused() const { return num_ == 0; } is_bound()107 bool is_bound() const { return num_ == -1; } is_linked()108 bool is_linked() const { return num_ > 0; } 109 binding_pos()110 int binding_pos() const { 111 ASSERT(is_bound()); 112 return table_[0]; 113 } 114 num_links()115 int num_links() const { 116 ASSERT(!is_bound()); 117 return num_; // Will return 0 if unused. 118 } 119 link_pos(int i)120 int link_pos(int i) const { 121 ASSERT(is_linked()); 122 ASSERT(i < num_); 123 return table_[i]; 124 } 125 126 private: bind_to(int pos)127 void bind_to(int pos) { 128 ASSERT(!is_bound()); 129 table_[0] = pos; 130 num_ = -1; 131 } link_to(int pos)132 void link_to(int pos) { 133 ASSERT(!is_bound()); 134 ASSERT(num_ < kTableSize); 135 136 table_[num_] = pos; 137 ++num_; 138 } 139 140 static const int kTableSize = 3; 141 142 // We store all links in a fixed size table. When we're bound, we store the 143 // binding position in the first entry of the table. 144 int table_[kTableSize]; 145 // The number of entries in our table, if we're linked. If 0, then we're 146 // unusued. If -1, then we are bound (and the pos is at table_[0]). 147 int num_; 148 149 friend class CodeBuffer; // For binding, linking, etc 150 }; 151 152 153 enum ScaleFactor { 154 SCALE_TIMES_1 = 0, 155 SCALE_TIMES_2 = 1, 156 SCALE_TIMES_4 = 2, 157 SCALE_TIMES_8 = 3 158 }; 159 160 161 class Operand { 162 public: Operand(const Operand & x)163 explicit Operand(const Operand& x) : len_(x.len_) { 164 memcpy(buf_, x.buf_, sizeof(buf_)); 165 } 166 167 // reg Operand(Register reg)168 explicit Operand(Register reg) { 169 Init(reg); 170 } 171 172 // [disp/r] Operand(int disp)173 explicit Operand(int disp) { 174 Init(disp); 175 } 176 177 // [base + disp/r] Operand(Register base,int disp)178 Operand(Register base, int disp) { 179 Init(base, disp); 180 } 181 182 // [base + index*scale + disp/r] Operand(Register base,Register index,ScaleFactor scale,int disp)183 Operand(Register base, Register index, ScaleFactor scale, int disp) { 184 Init(base, index, scale, disp); 185 } 186 187 // [index*scale + disp/r] Operand(Register index,ScaleFactor scale,int disp)188 Operand(Register index, ScaleFactor scale, int disp) { 189 Init(index, scale, disp); 190 } 191 set_reg(Register reg)192 void set_reg(Register reg) { 193 ASSERT(len_ > 0); 194 buf_[0] = (buf_[0] & ~0x38) | static_cast<char>(reg << 3); 195 } 196 data()197 char* data() { return buf_; } length()198 int length() { return len_; } 199 200 private: 201 // reg Init(Register reg)202 void Init(Register reg) { 203 set_modrm(3, reg); 204 } 205 206 // [disp/r] Init(int disp)207 void Init(int disp) { 208 set_modrm(0, EBP); 209 set_dispr(disp); 210 } 211 212 // [base + disp/r] Init(Register base,int disp)213 void Init(Register base, int disp) { 214 if (disp == 0) { 215 // [base] 216 set_modrm(0, base); 217 if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base); 218 } else if (is_int8(disp)) { 219 // [base + disp8] 220 set_modrm(1, base); 221 if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base); 222 set_disp8(disp); 223 } else { 224 // [base + disp/r] 225 set_modrm(2, base); 226 if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base); 227 set_dispr(disp); 228 } 229 } 230 231 // [base + index*scale + disp/r] Init(Register base,Register index,ScaleFactor scale,int disp)232 void Init(Register base, 233 Register index, 234 ScaleFactor scale, 235 int disp) { 236 ASSERT(index != ESP); // illegal addressing mode 237 if (disp == 0 && base != EBP) { 238 // [base + index*scale] 239 set_modrm(0, ESP); 240 set_sib(scale, index, base); 241 } else if (is_int8(disp)) { 242 // [base + index*scale + disp8] 243 set_modrm(1, ESP); 244 set_sib(scale, index, base); 245 set_disp8(disp); 246 } else { 247 // [base + index*scale + disp/r] 248 set_modrm(2, ESP); 249 set_sib(scale, index, base); 250 set_dispr(disp); 251 } 252 } 253 254 // [index*scale + disp/r] Init(Register index,ScaleFactor scale,int disp)255 void Init(Register index, 256 ScaleFactor scale, 257 int disp) { 258 ASSERT(index != ESP); // illegal addressing mode 259 // We can reduce instruction size by translating instructions of the form: 260 // 8D044510000000 lea eax,[eax*2+0x10] 261 // To the more concise scale=1 version: 262 // 8D440010 lea eax,[eax+eax+0x10] 263 if (scale == SCALE_TIMES_2) { 264 Init(index, index, SCALE_TIMES_1, disp); 265 } else { 266 set_modrm(0, ESP); 267 set_sib(scale, index, EBP); 268 set_dispr(disp); 269 } 270 } 271 272 // Returns true if this Operand is a wrapper for the specified register. is_reg(Register reg)273 bool is_reg(Register reg) const { 274 return ((buf_[0] & 0xF8) == 0xC0) // addressing mode is register only. 275 && ((buf_[0] & 0x07) == reg); // register codes match. 276 } 277 set_modrm(int mod,Register rm)278 void set_modrm(int mod, Register rm) { // reg == 0 279 ASSERT((mod & -4) == 0); 280 buf_[0] = mod << 6 | rm; 281 len_ = 1; 282 } 283 set_sib(ScaleFactor scale,Register index,Register base)284 void set_sib(ScaleFactor scale, Register index, Register base) { 285 ASSERT(len_ == 1); 286 ASSERT((scale & -4) == 0); 287 buf_[1] = scale << 6 | index << 3 | base; 288 len_ = 2; 289 } 290 set_disp8(char disp)291 void set_disp8(char disp) { 292 ASSERT(len_ == 1 || len_ == 2); 293 *reinterpret_cast<char*>(&buf_[len_++]) = disp; 294 } 295 set_dispr(int disp)296 void set_dispr(int disp) { 297 ASSERT(len_ == 1 || len_ == 2); 298 *reinterpret_cast<int*>(&buf_[len_]) = disp; 299 len_ += sizeof(int); 300 } 301 is_int8(int x)302 bool is_int8(int x) { return x >= -128 && x <= 127; } 303 304 // Mutable because reg in ModR/M byte is set by Assembler via set_reg(). 305 char buf_[6]; 306 // The number of bytes in buf_. 307 unsigned int len_; 308 }; 309 310 // A convenient wrapper around a buffer for emitting code or data, etc. 311 class CodeBuffer { 312 public: 313 // Use an externally managed buffer CodeBuffer(char * buf)314 explicit CodeBuffer(char* buf) : pos_(0), buf_(buf) { } 315 data()316 void* data() { return buf_; } size()317 int size() { return pos_; } 318 emit(unsigned char b)319 void emit(unsigned char b) { 320 buf_[pos_++] = b; 321 } emit_word(unsigned short w)322 void emit_word(unsigned short w) { 323 *reinterpret_cast<unsigned short*>(&buf_[pos_]) = w; 324 pos_ += 2; 325 } emit_dword(unsigned int d)326 void emit_dword(unsigned int d) { 327 *reinterpret_cast<unsigned int*>(&buf_[pos_]) = d; 328 pos_ += 4; 329 } 330 emit_bytes(const char * bytes,size_t size)331 void emit_bytes(const char* bytes, size_t size) { 332 for (size_t i = 0; i < size; ++i) 333 emit(bytes[i]); 334 } 335 emit_bytes(const std::string & bytes)336 void emit_bytes(const std::string& bytes) { 337 emit_bytes(bytes.data(), bytes.size()); 338 } 339 put_dword_at(int pos,unsigned int d)340 void put_dword_at(int pos, unsigned int d) { 341 *reinterpret_cast<unsigned int*>(&buf_[pos]) = d; 342 } 343 344 // We pass by value so that we get a copy that we can modify. emit_operand(Register reg,Operand operand)345 void emit_operand(Register reg, Operand operand) { 346 operand.set_reg(reg); 347 memcpy(&buf_[pos_], operand.data(), operand.length()); 348 pos_ += operand.length(); 349 } 350 bind(Label * l)351 void bind(Label* l) { 352 ASSERT(!l->is_bound()); 353 for (int i = 0; i < l->num_links(); ++i) { 354 put_dword_at(l->link_pos(i), pos_ - (l->link_pos(i) + 4)); 355 } 356 l->bind_to(pos_); 357 } 358 359 // TODO deprecate blah_imm and use blah(Immediate) 360 add(Register dst,Register src)361 void add(Register dst, Register src) { 362 emit(0x01); emit(0xc0 | (src << 3) | dst); 363 } add_imm(Register dst,int d)364 void add_imm(Register dst, int d) { 365 if (d >= -128 && d <= 127) { 366 emit(0x83); emit(0xc0 | dst); emit(d & 0xff); 367 } else { 368 emit(0x81); emit(0xc0 | dst); emit_dword(d); 369 } 370 } 371 and_(Register r,unsigned int mask)372 void and_(Register r, unsigned int mask) { 373 emit(0x81); emit(0xe0 | r); emit_dword(mask); 374 } 375 call(Register r)376 void call(Register r) { 377 call(Operand(r)); 378 } call(const Operand & dst)379 void call(const Operand& dst) { 380 emit(0xff); emit_operand(EDX, dst); 381 } 382 cmp(Register r1,Register r2)383 void cmp(Register r1, Register r2) { 384 emit(0x39); emit(0xc0 | (r2 << 3) | r1); 385 } 386 cmp_imm(Register r,int d)387 void cmp_imm(Register r, int d) { 388 if (d >= -128 && d <= 127) { 389 emit(0x83); emit(0xf8 | r); emit(d & 0xff); 390 } else { 391 emit(0x81); emit(0xf8 | r); emit_dword(d); 392 } 393 } 394 fs()395 void fs() { 396 emit(0x64); 397 } 398 399 // Atomically increment the dword at |mem| with the increment amount in the 400 // register |inc|. Will replace |inc| with the old unincremented value. inc_atomic(Register mem,Register inc)401 void inc_atomic(Register mem, Register inc) { 402 // lock xadd [mem], inc 403 emit(0xF0); emit(0x0F); emit(0xC1); emit((inc << 3) | mem); 404 } 405 int3()406 void int3() { 407 emit(0xcc); 408 } 409 jcc(Condition cc,Label * l)410 void jcc(Condition cc, Label* l) { 411 emit(0x0f); emit(0x80 | cc); 412 if (l->is_bound()) { 413 emit_dword(l->binding_pos() - (pos_ + 4)); 414 } else { 415 // Will fix up when the label is bound. 416 l->link_to(pos_); 417 emit_dword(0); 418 } 419 } 420 jmp(Register r)421 void jmp(Register r) { 422 emit(0xff); emit(0xe0 | r); 423 } 424 jmp(Label * l)425 void jmp(Label* l) { 426 if (l->is_bound()) { 427 jmp_rel(l->binding_pos() - (pos_ + 5)); 428 } else { 429 // Will fix up when the label is bound. 430 l->link_to(pos_ + 1); 431 jmp_rel(0); 432 } 433 } 434 jmp_rel(int i)435 void jmp_rel(int i) { 436 emit(0xe9); emit_dword(i); 437 } 438 jmp_rel_short(char c)439 void jmp_rel_short(char c) { 440 emit(0xeb); emit(c); 441 } 442 lea(Register dst,const Operand & src)443 void lea(Register dst, const Operand& src) { 444 emit(0x8d); emit_operand(dst, src); 445 } 446 lodsb()447 void lodsb() { 448 emit(0xac); 449 } lodsd()450 void lodsd() { 451 emit(0xad); 452 } 453 loop(Label * l)454 void loop(Label* l) { 455 ASSERT(l->is_bound()); 456 int pos = l->binding_pos() - (pos_ + 2); 457 ASSERT(pos >= -128 && pos < 0); 458 459 emit(0xe2); emit(pos & 0xff); 460 } 461 mov(Register dst,Register src)462 void mov(Register dst, Register src) { 463 emit(0x89); emit(0xc0 | (src << 3) | dst); 464 } mov(Register dst,const Operand & src)465 void mov(Register dst, const Operand& src) { 466 emit(0x8b); emit_operand(dst, src); 467 } mov_imm(Register r,unsigned int d)468 void mov_imm(Register r, unsigned int d) { 469 emit(0xb8 | r); emit_dword(d); 470 } 471 movsb()472 void movsb() { 473 emit(0xa4); 474 } movsd()475 void movsd() { 476 emit(0xa5); 477 } 478 or_(Register r,unsigned int mask)479 void or_(Register r, unsigned int mask) { 480 emit(0x81); emit(0xc8 | r); emit_dword(mask); 481 } 482 pop(Register r)483 void pop(Register r) { 484 emit(0x58 | r); 485 } pop(const Operand & dst)486 void pop(const Operand& dst) { 487 emit(0x8f); emit_operand(EAX, dst); 488 } 489 push(Register r)490 void push(Register r) { 491 emit(0x50 | r); 492 } push(const Operand & src)493 void push(const Operand& src) { 494 emit(0xff); emit_operand(ESI, src); 495 } push_imm(int i)496 void push_imm(int i) { 497 if (i >= -128 && i <= 127) { 498 emit(0x6a); emit(i & 0xff); 499 } else { 500 emit(0x68); emit_dword(i); 501 } 502 } 503 504 // Puts the cycle counter into edx:eax. rdtsc()505 void rdtsc() { 506 emit(0x0F); emit(0x31); 507 } 508 rep()509 void rep() { 510 emit(0xf3); 511 } 512 ret()513 void ret() { 514 ret(0); 515 } ret(short c)516 void ret(short c) { 517 if (c == 0) { 518 emit(0xc3); 519 } else { 520 emit(0xc2); emit_word(c); 521 } 522 } 523 spin()524 void spin() { 525 jmp_rel_short(-2); 526 } 527 stosb()528 void stosb() { 529 emit(0xaa); 530 } stosd()531 void stosd() { 532 emit(0xab); 533 } 534 sysenter()535 void sysenter() { 536 emit(0x0f); emit(0x34); 537 } 538 539 // Puts a unique cpu identifier into eax, using sidt to fingerprint cores. which_cpu()540 void which_cpu() { 541 // Make space 542 push(EAX); 543 push(EAX); 544 // sidt [esp+2] 545 emit(0x0f); emit(0x01); emit_operand(ECX, Operand(ESP, 2)); 546 pop(EAX); 547 pop(EAX); // sidt address 548 } 549 550 // Puts a unique identifier for the thread we're executing on into eax. which_thread()551 void which_thread() { 552 // mov eax, [fs:0x24] 553 emit(0x64); emit(0xa1); emit_dword(0x24); 554 // TODO: We could do this but it will use an encoding that is 1 byte bigger. 555 // fs(); mov(EAX, Operand(0x24)); 556 } 557 xchg(Register r1,Register r2)558 void xchg(Register r1, Register r2) { 559 if (r1 == EAX) { 560 emit(0x90 | r2); 561 } else if (r2 == EAX) { 562 emit(0x90 | r1); 563 } else { 564 xchg(r1, Operand(r2)); 565 } 566 } xchg(Register r1,const Operand & oper)567 void xchg(Register r1, const Operand& oper) { 568 emit(0x87); emit_operand(r1, oper); 569 } 570 571 private: 572 int pos_; 573 char* buf_; 574 }; 575 576 #endif // TRACELINE_ASSEMBLER_H_ 577