Coverage for /Syzygy/core/assembler.h

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%18180.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // This file declares implementation classes to generate assembly code.
  16    :  // The API to the assembler is intentionally very close to the API exposed
  17    :  // by the V8 assembler (see src/ia32/assembler-ia32.* in V8 repository).
  18    :  
  19    :  #ifndef SYZYGY_CORE_ASSEMBLER_H_
  20    :  #define SYZYGY_CORE_ASSEMBLER_H_
  21    :  
  22    :  #include "syzygy/core/register.h"
  23    :  
  24    :  namespace core {
  25    :  
  26    :  // The condition codes by which conditional branches are determined. This enum
  27    :  // is taken from the V8 project, and has the property that the conditions are
  28    :  // defined to be bit-wise ORed into the base conditional branch opcode, and
  29    :  // they can be easily negated/inverted.
  30    :  //
  31    :  // See:
  32    :  //     http://code.google.com/p/v8/source/browse/trunk/src/ia32/assembler-ia32.h
  33    :  enum ConditionCode {
  34    :    // Any value < 0 is considered no_condition
  35    :    kNoCondition  = -1,
  36    :  
  37    :    kOverflow =  0,
  38    :    kNoOverflow =  1,
  39    :    kBelow =  2,
  40    :    kAboveEqual =  3,
  41    :    kEqual =  4,
  42    :    kNotEqual =  5,
  43    :    kBelowEqual =  6,
  44    :    kAbove =  7,
  45    :    kNegative =  8,
  46    :    kPositive =  9,
  47    :    kParityEven = 10,
  48    :    kParityOdd = 11,
  49    :    kLess = 12,
  50    :    kGreaterEqual = 13,
  51    :    kLessEqual = 14,
  52    :    kGreater = 15,
  53    :  
  54    :    // Aliases.
  55    :    kCarry = kBelow,
  56    :    kNotCarry = kAboveEqual,
  57    :    kZero = kEqual,
  58    :    kNotZero = kNotEqual,
  59    :    kSign = kNegative,
  60    :    kNotSign = kPositive,
  61    :  
  62    :    // Extents.
  63    :    kMinConditionCode = 0,
  64    :    kMaxConditionCode = 15
  65    :  };
  66    :  
  67    :  // The conditions on which a loop instruction should branch. These are modeled
  68    :  // in the same manner as ConditionCode (above).
  69    :  enum LoopCode {
  70    :    kLoopOnCounterAndNotZeroFlag = 0,  // LOOPNE and LOOPNZ
  71    :    kLoopOnCounterAndZeroFlag = 1,  // LOOPE and NOOPZ.
  72    :    kLoopOnCounter = 2,  // LOOP.
  73    :  };
  74    :  
  75  E :  inline ConditionCode NegateConditionCode(ConditionCode cc) {
  76  E :    DCHECK_GT(16, cc);
  77  E :    return static_cast<ConditionCode>(cc ^ 1);
  78  E :  }
  79    :  
  80    :  // Selects a scale for the Operand addressing modes.
  81    :  // The values match the encoding in the x86 SIB bytes.
  82    :  enum ScaleFactor {
  83    :    kTimes1 = 0,
  84    :    kTimes2 = 1,
  85    :    kTimes4 = 2,
  86    :    kTimes8 = 3,
  87    :  };
  88    :  
  89    :  // We use the same enum for value sizes.
  90    :  typedef RegisterSize ValueSize;
  91    :  
  92    :  // An instance of this class is an explicit value, which is either
  93    :  // an immediate or a displacement.
  94    :  class ValueImpl {
  95    :   public:
  96    :    ValueImpl();
  97    :    ValueImpl(uint32 value, ValueSize size);
  98    :    ValueImpl(uint32 value, ValueSize size, const void* imm_ref);
  99    :  
 100    :    // @name Accessors.
 101    :    // @{
 102  E :    uint32 value() const { return value_; }
 103  E :    const void* reference() const { return reference_; }
 104  E :    ValueSize size() const { return size_; }
 105    :    // @}
 106    :  
 107    :    // Comparison operator.
 108    :    bool operator==(const ValueImpl& rhs) const;
 109    :  
 110    :   private:
 111    :    uint32 value_;
 112    :    const void* reference_;
 113    :    ValueSize size_;
 114    :  };
 115    :  
 116    :  // Displacements and immediates behave near-identically, but are semantically
 117    :  // slightly different.
 118    :  typedef ValueImpl ImmediateImpl;
 119    :  typedef ValueImpl DisplacementImpl;
 120    :  
 121    :  // An operand implies indirection to memory through one of the myriad
 122    :  // modes supported by IA32.
 123    :  class OperandImpl {
 124    :   public:
 125    :    // A register-indirect mode.
 126    :    explicit OperandImpl(const Register32& base);
 127    :  
 128    :    // A register-indirect with displacement mode.
 129    :    OperandImpl(const Register32& base, const DisplacementImpl& displ);
 130    :  
 131    :    // A displacement-only mode.
 132    :    explicit OperandImpl(const DisplacementImpl& displ);
 133    :  
 134    :    // The full [base + index * scale + displ32] mode.
 135    :    // @note esp cannot be used as an index register.
 136    :    OperandImpl(const Register32& base,
 137    :                const Register32& index,
 138    :                ScaleFactor scale,
 139    :                const DisplacementImpl& displ);
 140    :  
 141    :    // The [base + index * scale] mode.
 142    :    // @note esp cannot be used as an index register.
 143    :    OperandImpl(const Register32& base,
 144    :                const Register32& index,
 145    :                ScaleFactor scale);
 146    :  
 147    :    // The [index * scale + displ32] mode - e.g. no base.
 148    :    // @note esp cannot be used as an index register.
 149    :    OperandImpl(const Register32& index,
 150    :                ScaleFactor scale,
 151    :                const DisplacementImpl& displ);
 152    :  
 153    :    // Low-level constructor, none of the parameters are checked.
 154    :    OperandImpl(RegisterId base,
 155    :                RegisterId index,
 156    :                ScaleFactor scale,
 157    :                const DisplacementImpl& displacement);
 158    :  
 159    :    // @name Accessors.
 160    :    // @{
 161  E :    RegisterId base() const { return base_; }
 162  E :    RegisterId index() const { return index_; }
 163  E :    ScaleFactor scale() const { return scale_; }
 164  E :    const DisplacementImpl& displacement() const { return displacement_; }
 165    :    // @}
 166    :  
 167    :   private:
 168    :    // The base register involved, or none.
 169    :    RegisterId base_;
 170    :    // The index register involved, or none.
 171    :    RegisterId index_;
 172    :    // The scaling factor, must be kTimes1 if no index register.
 173    :    ScaleFactor scale_;
 174    :    // The displacement, if any.
 175    :    DisplacementImpl displacement_;
 176    :  };
 177    :  
 178    :  // The assembler takes care of maintaining an output location (address), and
 179    :  // generating a stream of bytes and references as instructions are assembled.
 180    :  class AssemblerImpl {
 181    :   public:
 182    :    // The assembler pushes instructions and references to
 183    :    // one of these for serialization.
 184    :    class InstructionSerializer {
 185    :     public:
 186    :      virtual void AppendInstruction(uint32 location,
 187    :                                     const uint8* bytes,
 188    :                                     size_t num_bytes,
 189    :                                     const size_t *ref_locations,
 190    :                                     const void* const* refs,
 191    :                                     size_t num_refs) = 0;
 192    :    };
 193    :  
 194    :    // Constructs an assembler that assembles to @p delegate
 195    :    // starting at @p location.
 196    :    AssemblerImpl(uint32 location, InstructionSerializer* serializer);
 197    :  
 198    :    // @name Accessors.
 199    :    // @{
 200  E :    uint32 location() const { return location_; }
 201  E :    void set_location(uint32 location) { location_ = location; }
 202    :    // @}
 203    :  
 204    :    // Emits one or more NOP instructions, their total length being @p size
 205    :    // bytes.
 206    :    // @param size The number of bytes of NOPs to generate.
 207    :    // @note For a generated NOP sequence of optimal performance it is best to
 208    :    //     call nop once rather than successively (ie: the NOP sequence generated
 209    :    //     by nop(x) nop(y) may perform worse than that generated by nop(x + y).
 210    :    void nop(size_t size);
 211    :  
 212    :    // @name Call instructions.
 213    :    // @{
 214    :    void call(const ImmediateImpl& dst);
 215    :    void call(const OperandImpl& dst);
 216    :    // @}
 217    :  
 218    :    // @name Control flow instructions.
 219    :    // @{
 220    :    void j(ConditionCode cc, const ImmediateImpl& dst);
 221    :    void jecxz(const ImmediateImpl& dst);
 222    :    void jmp(const ImmediateImpl& dst);
 223    :    void jmp(const OperandImpl& dst);
 224    :    void l(LoopCode lc, const ImmediateImpl& dst);
 225    :    void ret();
 226    :    void ret(uint16 n);
 227    :    // @}
 228    :  
 229    :    // @name Set flags.
 230    :    // @{
 231    :    void set(ConditionCode cc, const Register32& src);
 232    :    // @}
 233    :  
 234    :    // @name Byte mov varieties.
 235    :    // @{
 236    :    void mov_b(const OperandImpl& dst, const ImmediateImpl& src);
 237    :    void movzx_b(const Register32& dst, const OperandImpl& src);
 238    :    // @}
 239    :  
 240    :    // @name Double-word mov varieties.
 241    :    // @{
 242    :    void mov(const Register32& dst, const Register32& src);
 243    :    void mov(const Register32& dst, const OperandImpl& src);
 244    :    void mov(const OperandImpl& dst, const Register32& src);
 245    :    void mov(const Register32& dst, const ImmediateImpl& src);
 246    :    void mov(const OperandImpl& dst, const ImmediateImpl& src);
 247    :    void mov_fs(const Register32& dst, const OperandImpl& src);
 248    :    void mov_fs(const OperandImpl& dst, const Register32& src);
 249    :    // @}
 250    :  
 251    :    // @name Load effective address.
 252    :    void lea(const Register32& dst, const OperandImpl& src);
 253    :  
 254    :    // @name Stack manipulation.
 255    :    // @{
 256    :    void push(const Register32& src);
 257    :    void push(const ImmediateImpl& src);
 258    :    void push(const OperandImpl& src);
 259    :  
 260    :    void pop(const Register32& dst);
 261    :    void pop(const OperandImpl& dst);
 262    :    // @}
 263    :  
 264    :    // @name Manipulation of flags.
 265    :    // @{
 266    :    void pushfd();
 267    :    void popfd();
 268    :    void lahf();
 269    :    void sahf();
 270    :    // @}
 271    :  
 272    :    // @name Arithmetic operations.
 273    :    // @{
 274    :    void test(const Register8& dst, const Register8& src);
 275    :    void test(const Register8& dst, const ImmediateImpl& src);
 276    :  
 277    :    void test(const Register32& dst, const Register32& src);
 278    :    void test(const Register32& dst, const OperandImpl& src);
 279    :    void test(const OperandImpl& dst, const Register32& src);
 280    :    void test(const Register32& dst, const ImmediateImpl& src);
 281    :    void test(const OperandImpl& dst, const ImmediateImpl& src);
 282    :  
 283    :    void cmp(const Register8& dst, const Register8& src);
 284    :    void cmp(const Register8& dst, const ImmediateImpl& src);
 285    :  
 286    :    void cmp(const Register32& dst, const Register32& src);
 287    :    void cmp(const Register32& dst, const OperandImpl& src);
 288    :    void cmp(const OperandImpl& dst, const Register32& src);
 289    :    void cmp(const Register32& dst, const ImmediateImpl& src);
 290    :    void cmp(const OperandImpl& dst, const ImmediateImpl& src);
 291    :  
 292    :    void add(const Register8& dst, const Register8& src);
 293    :    void add(const Register8& dst, const ImmediateImpl& src);
 294    :  
 295    :    void add(const Register32& dst, const Register32& src);
 296    :    void add(const Register32& dst, const OperandImpl& src);
 297    :    void add(const OperandImpl& dst, const Register32& src);
 298    :    void add(const Register32& dst, const ImmediateImpl& src);
 299    :    void add(const OperandImpl& dst, const ImmediateImpl& src);
 300    :  
 301    :    void sub(const Register8& dst, const Register8& src);
 302    :    void sub(const Register8& dst, const ImmediateImpl& src);
 303    :  
 304    :    void sub(const Register32& dst, const Register32& src);
 305    :    void sub(const Register32& dst, const OperandImpl& src);
 306    :    void sub(const OperandImpl& dst, const Register32& src);
 307    :    void sub(const Register32& dst, const ImmediateImpl& src);
 308    :    void sub(const OperandImpl& dst, const ImmediateImpl& src);
 309    :    // @}
 310    :  
 311    :    // @name Shifting operations.
 312    :    // @{
 313    :    void shl(const Register32& dst, const ImmediateImpl& src);
 314    :    void shr(const Register32& dst, const ImmediateImpl& src);
 315    :    // @}
 316    :  
 317    :    // Exchange contents of two registers.
 318    :    // @param dst The destination register.
 319    :    // @param src The source register.
 320    :    // @note Exchanges involving eax generate shorter byte code.
 321    :    // @note This instruction can be used as a primitive for writing
 322    :    //     synchronization mechanisms as there is an implicit lock taken
 323    :    //     during execution.
 324    :    void xchg(const Register32& dst, const Register32& src);
 325    :    void xchg(const Register16& dst, const Register16& src);
 326    :    void xchg(const Register8& dst, const Register8& src);
 327    :  
 328    :    // @name Aliases
 329    :    // @{
 330  E :    void loop(const ImmediateImpl& dst) { l(kLoopOnCounter, dst); }
 331  E :    void loope(const ImmediateImpl& dst) { l(kLoopOnCounterAndZeroFlag, dst); }
 332  E :    void loopne(const ImmediateImpl& dst) {
 333  E :      l(kLoopOnCounterAndNotZeroFlag, dst);
 334  E :    }
 335    :    // @}
 336    :  
 337    :    // Size of an 8 bit reach branch opcode.
 338    :    static const size_t kShortBranchOpcodeSize;
 339    :    // Size of an 8 bit reach branch.
 340    :    static const size_t kShortBranchSize;
 341    :  
 342    :    // Size of a 32 bit reach branch op code.
 343    :    static const size_t kLongBranchOpcodeSize;
 344    :    // Size of an 8bit reach branch.
 345    :    static const size_t kLongBranchSize;
 346    :  
 347    :    // Size of an 8 bit reach jump opcode.
 348    :    static const size_t kShortJumpOpcodeSize;
 349    :    // Size of an 8 bit reach jump.
 350    :    static const size_t kShortJumpSize;
 351    :  
 352    :    // Size of a 32 bit reach jump op code.
 353    :    static const size_t kLongJumpOpcodeSize;
 354    :    // Size of an 8bit reach jump.
 355    :    static const size_t kLongJumpSize;
 356    :  
 357    :    // The maximum length a single instruction will assemble to.
 358    :    // No instruction on x86 can exceed 15 bytes, per specs.
 359    :    static const size_t kMaxInstructionLength = 15;
 360    :  
 361    :   private:
 362    :    class InstructionBuffer;
 363    :  
 364    :    // @name Nop instruction helpers.
 365    :    // @{
 366    :    // Each of these corresponds to a basic suggested NOP sequence. They
 367    :    // can each be extended by prefixing with 1 or more operand size (0x66)
 368    :    // prefixes. These are not exposed directly as the user should simply
 369    :    // call 'nop' instead.
 370    :    // @param prefix_count The number of operand size prefix bytes to apply.
 371    :    void nop1(size_t prefix_count);
 372    :    void nop4(size_t prefix_count);
 373    :    void nop5(size_t prefix_count);
 374    :    void nop7(size_t prefix_count);
 375    :    void nop8(size_t prefix_count);
 376    :    // @}
 377    :  
 378    :    // Output the instruction data in @p instr to our delegate.
 379    :    void Output(const InstructionBuffer& instr);
 380    :  
 381    :    // Stores the current location of assembly.
 382    :    uint32 location_;
 383    :  
 384    :    // The delegate we push instructions at.
 385    :    InstructionSerializer* serializer_;
 386    :  };
 387    :  
 388    :  }  // namespace core
 389    :  
 390    :  #endif  // SYZYGY_CORE_ASSEMBLER_H_

Coverage information generated Wed Dec 11 11:34:16 2013.