15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2009 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 1994-2006 Sun Microsystems Inc. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All Rights Reserved. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met: 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Redistributions of source code must retain the above copyright notice, 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this list of conditions and the following disclaimer. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Redistribution in binary form must reproduce the above copyright 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer in the 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// documentation and/or other materials provided with the distribution. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Neither the name of Sun Microsystems or the names of contributors may 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// be used to endorse or promote products derived from this software without 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specific prior written permission. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The original source code covered by the above license above has been 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modified significantly by Google Inc. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2006-2008 the V8 project authors. All rights reserved. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This implements a C++ assembler for dynamically generating machine code. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is heavily based on the v8 assembler, which has a long history of its 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// own. Relocation information has been removed, and in general things were 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// made a bit simpler (and slower). Everything is implemented inline. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef TRACELINE_ASSEMBLER_H_ 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TRACELINE_ASSEMBLER_H_ 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "logging.h" 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASSERT(x) CHECK(x) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum Register { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EAX = 0, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ECX = 1, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EDX = 2, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EBX = 3, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ESP = 4, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EBP = 5, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ESI = 6, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EDI = 7 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum Condition { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) overflow = 0, 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) no_overflow = 1, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) below = 2, 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) above_equal = 3, 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) equal = 4, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) not_equal = 5, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) below_equal = 6, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) above = 7, 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sign = 8, 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) not_sign = 9, 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parity_even = 10, 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parity_odd = 11, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) less = 12, 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) greater_equal = 13, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) less_equal = 14, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) greater = 15, 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // aliases 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zero = equal, 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) not_zero = not_equal, 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) negative = sign, 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) positive = not_sign 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Labels are used for branching, and marks an offset in the CodeBuffer. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A label can be in 3 states: 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Unused, the label has never be used in an instruction. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Linked, the label has been referenced (by a jump, for example), but the 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// target is not yet known, because the label is unbound. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Bound, the label has been bound so the offset is known. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Label { 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Label() { Unuse(); } 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~Label() { ASSERT(!is_linked()); } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Unuse() { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_ = 0; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_unused() const { return num_ == 0; } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_bound() const { return num_ == -1; } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_linked() const { return num_ > 0; } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int binding_pos() const { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(is_bound()); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return table_[0]; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_links() const { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(!is_bound()); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return num_; // Will return 0 if unused. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int link_pos(int i) const { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(is_linked()); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(i < num_); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return table_[i]; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void bind_to(int pos) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(!is_bound()); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_[0] = pos; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) num_ = -1; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void link_to(int pos) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(!is_bound()); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(num_ < kTableSize); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) table_[num_] = pos; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++num_; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kTableSize = 3; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We store all links in a fixed size table. When we're bound, we store the 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // binding position in the first entry of the table. 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int table_[kTableSize]; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The number of entries in our table, if we're linked. If 0, then we're 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // unusued. If -1, then we are bound (and the pos is at table_[0]). 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int num_; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class CodeBuffer; // For binding, linking, etc 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum ScaleFactor { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCALE_TIMES_1 = 0, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCALE_TIMES_2 = 1, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCALE_TIMES_4 = 2, 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SCALE_TIMES_8 = 3 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Operand { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit Operand(const Operand& x) : len_(x.len_) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(buf_, x.buf_, sizeof(buf_)); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reg 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit Operand(Register reg) { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(reg); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [disp/r] 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit Operand(int disp) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(disp); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base + disp/r] 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Operand(Register base, int disp) { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(base, disp); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base + index*scale + disp/r] 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Operand(Register base, Register index, ScaleFactor scale, int disp) { 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(base, index, scale, disp); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [index*scale + disp/r] 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Operand(Register index, ScaleFactor scale, int disp) { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(index, scale, disp); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_reg(Register reg) { 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(len_ > 0); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_[0] = (buf_[0] & ~0x38) | static_cast<char>(reg << 3); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* data() { return buf_; } 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int length() { return len_; } 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reg 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Init(Register reg) { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_modrm(3, reg); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [disp/r] 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Init(int disp) { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_modrm(0, EBP); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_dispr(disp); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base + disp/r] 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Init(Register base, int disp) { 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (disp == 0) { 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base] 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_modrm(0, base); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (is_int8(disp)) { 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base + disp8] 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_modrm(1, base); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_disp8(disp); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base + disp/r] 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_modrm(2, base); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (base == ESP) set_sib(SCALE_TIMES_1, ESP, base); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_dispr(disp); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base + index*scale + disp/r] 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Init(Register base, 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Register index, 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScaleFactor scale, 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int disp) { 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(index != ESP); // illegal addressing mode 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (disp == 0 && base != EBP) { 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base + index*scale] 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_modrm(0, ESP); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_sib(scale, index, base); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (is_int8(disp)) { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base + index*scale + disp8] 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_modrm(1, ESP); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_sib(scale, index, base); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_disp8(disp); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [base + index*scale + disp/r] 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_modrm(2, ESP); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_sib(scale, index, base); 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_dispr(disp); 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [index*scale + disp/r] 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Init(Register index, 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScaleFactor scale, 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int disp) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(index != ESP); // illegal addressing mode 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can reduce instruction size by translating instructions of the form: 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 8D044510000000 lea eax,[eax*2+0x10] 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // To the more concise scale=1 version: 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 8D440010 lea eax,[eax+eax+0x10] 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scale == SCALE_TIMES_2) { 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(index, index, SCALE_TIMES_1, disp); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_modrm(0, ESP); 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_sib(scale, index, EBP); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_dispr(disp); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if this Operand is a wrapper for the specified register. 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_reg(Register reg) const { 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((buf_[0] & 0xF8) == 0xC0) // addressing mode is register only. 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) && ((buf_[0] & 0x07) == reg); // register codes match. 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_modrm(int mod, Register rm) { // reg == 0 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT((mod & -4) == 0); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_[0] = mod << 6 | rm; 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len_ = 1; 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_sib(ScaleFactor scale, Register index, Register base) { 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(len_ == 1); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT((scale & -4) == 0); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_[1] = scale << 6 | index << 3 | base; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len_ = 2; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_disp8(char disp) { 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(len_ == 1 || len_ == 2); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *reinterpret_cast<char*>(&buf_[len_++]) = disp; 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_dispr(int disp) { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(len_ == 1 || len_ == 2); 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *reinterpret_cast<int*>(&buf_[len_]) = disp; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) len_ += sizeof(int); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_int8(int x) { return x >= -128 && x <= 127; } 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mutable because reg in ModR/M byte is set by Assembler via set_reg(). 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char buf_[6]; 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The number of bytes in buf_. 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int len_; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A convenient wrapper around a buffer for emitting code or data, etc. 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class CodeBuffer { 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use an externally managed buffer 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit CodeBuffer(char* buf) : pos_(0), buf_(buf) { } 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void* data() { return buf_; } 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size() { return pos_; } 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void emit(unsigned char b) { 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_[pos_++] = b; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void emit_word(unsigned short w) { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *reinterpret_cast<unsigned short*>(&buf_[pos_]) = w; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos_ += 2; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void emit_dword(unsigned int d) { 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *reinterpret_cast<unsigned int*>(&buf_[pos_]) = d; 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos_ += 4; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void emit_bytes(const char* bytes, size_t size) { 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < size; ++i) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(bytes[i]); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void emit_bytes(const std::string& bytes) { 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit_bytes(bytes.data(), bytes.size()); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void put_dword_at(int pos, unsigned int d) { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *reinterpret_cast<unsigned int*>(&buf_[pos]) = d; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We pass by value so that we get a copy that we can modify. 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void emit_operand(Register reg, Operand operand) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operand.set_reg(reg); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&buf_[pos_], operand.data(), operand.length()); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos_ += operand.length(); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void bind(Label* l) { 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(!l->is_bound()); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < l->num_links(); ++i) { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) put_dword_at(l->link_pos(i), pos_ - (l->link_pos(i) + 4)); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l->bind_to(pos_); 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO deprecate blah_imm and use blah(Immediate) 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void add(Register dst, Register src) { 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x01); emit(0xc0 | (src << 3) | dst); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void add_imm(Register dst, int d) { 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (d >= -128 && d <= 127) { 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x83); emit(0xc0 | dst); emit(d & 0xff); 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x81); emit(0xc0 | dst); emit_dword(d); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void and_(Register r, unsigned int mask) { 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x81); emit(0xe0 | r); emit_dword(mask); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void call(Register r) { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) call(Operand(r)); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void call(const Operand& dst) { 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xff); emit_operand(EDX, dst); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void cmp(Register r1, Register r2) { 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x39); emit(0xc0 | (r2 << 3) | r1); 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void cmp_imm(Register r, int d) { 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (d >= -128 && d <= 127) { 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x83); emit(0xf8 | r); emit(d & 0xff); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x81); emit(0xf8 | r); emit_dword(d); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void fs() { 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x64); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Atomically increment the dword at |mem| with the increment amount in the 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // register |inc|. Will replace |inc| with the old unincremented value. 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void inc_atomic(Register mem, Register inc) { 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // lock xadd [mem], inc 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xF0); emit(0x0F); emit(0xC1); emit((inc << 3) | mem); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void int3() { 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xcc); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void jcc(Condition cc, Label* l) { 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x0f); emit(0x80 | cc); 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (l->is_bound()) { 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit_dword(l->binding_pos() - (pos_ + 4)); 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Will fix up when the label is bound. 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l->link_to(pos_); 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit_dword(0); 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void jmp(Register r) { 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xff); emit(0xe0 | r); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void jmp(Label* l) { 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (l->is_bound()) { 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmp_rel(l->binding_pos() - (pos_ + 5)); 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Will fix up when the label is bound. 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l->link_to(pos_ + 1); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmp_rel(0); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void jmp_rel(int i) { 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xe9); emit_dword(i); 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void jmp_rel_short(char c) { 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xeb); emit(c); 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void lea(Register dst, const Operand& src) { 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x8d); emit_operand(dst, src); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void lodsb() { 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xac); 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void lodsd() { 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xad); 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void loop(Label* l) { 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(l->is_bound()); 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pos = l->binding_pos() - (pos_ + 2); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ASSERT(pos >= -128 && pos < 0); 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xe2); emit(pos & 0xff); 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void mov(Register dst, Register src) { 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x89); emit(0xc0 | (src << 3) | dst); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void mov(Register dst, const Operand& src) { 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x8b); emit_operand(dst, src); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void mov_imm(Register r, unsigned int d) { 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xb8 | r); emit_dword(d); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void movsb() { 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xa4); 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void movsd() { 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xa5); 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void or_(Register r, unsigned int mask) { 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x81); emit(0xc8 | r); emit_dword(mask); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void pop(Register r) { 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x58 | r); 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void pop(const Operand& dst) { 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x8f); emit_operand(EAX, dst); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void push(Register r) { 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x50 | r); 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void push(const Operand& src) { 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xff); emit_operand(ESI, src); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void push_imm(int i) { 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (i >= -128 && i <= 127) { 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x6a); emit(i & 0xff); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x68); emit_dword(i); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Puts the cycle counter into edx:eax. 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void rdtsc() { 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x0F); emit(0x31); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void rep() { 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xf3); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ret() { 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret(0); 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ret(short c) { 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == 0) { 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xc3); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xc2); emit_word(c); 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void spin() { 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) jmp_rel_short(-2); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void stosb() { 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xaa); 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void stosd() { 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0xab); 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void sysenter() { 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x0f); emit(0x34); 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Puts a unique cpu identifier into eax, using sidt to fingerprint cores. 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void which_cpu() { 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make space 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) push(EAX); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) push(EAX); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sidt [esp+2] 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x0f); emit(0x01); emit_operand(ECX, Operand(ESP, 2)); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pop(EAX); 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pop(EAX); // sidt address 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Puts a unique identifier for the thread we're executing on into eax. 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void which_thread() { 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // mov eax, [fs:0x24] 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x64); emit(0xa1); emit_dword(0x24); 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO: We could do this but it will use an encoding that is 1 byte bigger. 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fs(); mov(EAX, Operand(0x24)); 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void xchg(Register r1, Register r2) { 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (r1 == EAX) { 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x90 | r2); 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (r2 == EAX) { 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x90 | r1); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xchg(r1, Operand(r2)); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void xchg(Register r1, const Operand& oper) { 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) emit(0x87); emit_operand(r1, oper); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pos_; 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char* buf_; 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // TRACELINE_ASSEMBLER_H_ 577