Home | History | Annotate | Download | only in libenc
      1 /*
      2  * Copyright (C) 2012 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 <stdio.h>
     18 #include <assert.h>
     19 #include <limits.h>
     20 #include "enc_base.h"
     21 #include "enc_wrapper.h"
     22 #include "dec_base.h"
     23 #include "utils/Log.h"
     24 
     25 //#define PRINT_ENCODER_STREAM
     26 bool dump_x86_inst = false;
     27 //map_reg
     28 const RegName map_of_regno_2_regname[] = {
     29     RegName_EAX,    RegName_EBX,    RegName_ECX,    RegName_EDX,
     30     RegName_EDI,    RegName_ESI,    RegName_ESP,    RegName_EBP,
     31     RegName_XMM0,   RegName_XMM1,   RegName_XMM2,   RegName_XMM3,
     32     RegName_XMM4,   RegName_XMM5,   RegName_XMM6,   RegName_XMM7,
     33     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
     34     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
     35     RegName_Null,
     36     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
     37     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
     38     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null,
     39     RegName_Null,   RegName_Null,   //SCRATCH
     40     RegName_Null,   RegName_Null,   RegName_Null,   RegName_Null
     41 };
     42 
     43 //getRegSize, getAliasReg:
     44 //OpndSize, RegName, OpndExt: enum enc_defs.h
     45 inline void add_r(EncoderBase::Operands & args, int physicalReg, OpndSize sz, OpndExt ext = OpndExt_None) {
     46     RegName reg = map_of_regno_2_regname[physicalReg];
     47     if (sz != getRegSize(reg)) {
     48        reg = getAliasReg(reg, sz);
     49     }
     50     args.add(EncoderBase::Operand(reg, ext));
     51 }
     52 inline void add_m(EncoderBase::Operands & args, int baseReg, int disp, OpndSize sz, OpndExt ext = OpndExt_None) {
     53     args.add(EncoderBase::Operand(sz,
     54                                   map_of_regno_2_regname[baseReg],
     55                                   RegName_Null, 0,
     56                                   disp, ext));
     57 }
     58 inline void add_m_scale(EncoderBase::Operands & args, int baseReg, int indexReg, int scale,
     59                         OpndSize sz, OpndExt ext = OpndExt_None) {
     60     args.add(EncoderBase::Operand(sz,
     61                                   map_of_regno_2_regname[baseReg],
     62                                   map_of_regno_2_regname[indexReg], scale,
     63                                   0, ext));
     64 }
     65 inline void add_m_disp_scale(EncoderBase::Operands & args, int baseReg, int disp, int indexReg, int scale,
     66                         OpndSize sz, OpndExt ext = OpndExt_None) {
     67     args.add(EncoderBase::Operand(sz,
     68                                   map_of_regno_2_regname[baseReg],
     69                                   map_of_regno_2_regname[indexReg], scale,
     70                                   disp, ext));
     71 }
     72 
     73 inline void add_fp(EncoderBase::Operands & args, unsigned i, bool dbl) {
     74     return args.add((RegName)( (dbl ? RegName_FP0D : RegName_FP0S) + i));
     75 }
     76 inline void add_imm(EncoderBase::Operands & args, OpndSize sz, int value, bool is_signed) {
     77     //assert(n_size != imm.get_size());
     78     args.add(EncoderBase::Operand(sz, value,
     79              is_signed ? OpndExt_Signed : OpndExt_Zero));
     80 }
     81 
     82 #define MAX_DECODED_STRING_LEN 1024
     83 char tmpBuffer[MAX_DECODED_STRING_LEN];
     84 
     85 void printOperand(const EncoderBase::Operand & opnd) {
     86     unsigned int sz;
     87     if(!dump_x86_inst) return;
     88     sz = strlen(tmpBuffer);
     89     if(opnd.size() != OpndSize_32) {
     90         sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s ",
     91                        getOpndSizeString(opnd.size()));
     92     }
     93     if(opnd.is_mem()) {
     94         if(opnd.scale() != 0) {
     95             sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz,
     96                            "%d(%s,%s,%d)", opnd.disp(),
     97                            getRegNameString(opnd.base()),
     98                            getRegNameString(opnd.index()), opnd.scale());
     99         } else {
    100             sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%d(%s)",
    101                            opnd.disp(), getRegNameString(opnd.base()));
    102         }
    103     }
    104     if(opnd.is_imm()) {
    105         sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "#%x",
    106                        (int)opnd.imm());
    107     }
    108     if(opnd.is_reg()) {
    109         sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s",
    110                        getRegNameString(opnd.reg()));
    111     }
    112 }
    113 //TODO: the order of operands
    114 //to make the printout have the same order as assembly in .S
    115 //I reverse the order here
    116 void printDecoderInst(Inst & decInst) {
    117     unsigned int sz;
    118     if(!dump_x86_inst) return;
    119     sz = strlen(tmpBuffer);
    120     sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s ",
    121                    EncoderBase::toStr(decInst.mn));
    122     for(unsigned int k = 0; k < decInst.argc; k++) {
    123         if(k > 0) {
    124             sz = strlen(tmpBuffer);
    125             sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, ", ");
    126         }
    127         printOperand(decInst.operands[decInst.argc-1-k]);
    128     }
    129     ALOGE("%s", tmpBuffer);
    130 }
    131 void printOperands(EncoderBase::Operands& opnds) {
    132     unsigned int sz;
    133     if(!dump_x86_inst) return;
    134     for(unsigned int k = 0; k < opnds.count(); k++) {
    135         if(k > 0) {
    136             sz = strlen(tmpBuffer);
    137             sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, ", ");
    138         }
    139         printOperand(opnds[opnds.count()-1-k]);
    140     }
    141 }
    142 void printEncoderInst(Mnemonic m, EncoderBase::Operands& opnds) {
    143     if(!dump_x86_inst) return;
    144     snprintf(tmpBuffer, MAX_DECODED_STRING_LEN, "--- ENC %s ",
    145              EncoderBase::toStr(m));
    146     printOperands(opnds);
    147     ALOGE("%s", tmpBuffer);
    148 }
    149 int decodeThenPrint(char* stream_start) {
    150     if(!dump_x86_inst) return 0;
    151     snprintf(tmpBuffer, MAX_DECODED_STRING_LEN, "--- INST @ %p: ",
    152              stream_start);
    153     Inst decInst;
    154     unsigned numBytes = DecoderBase::decode(stream_start, &decInst);
    155     printDecoderInst(decInst);
    156     return numBytes;
    157 }
    158 
    159 extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm(Mnemonic m, OpndSize size, int imm, char * stream) {
    160     EncoderBase::Operands args;
    161     //assert(imm.get_size() == size_32);
    162     add_imm(args, size, imm, true/*is_signed*/);
    163     char* stream_start = stream;
    164     stream = (char *)EncoderBase::encode(stream, m, args);
    165 #ifdef PRINT_ENCODER_STREAM
    166     printEncoderInst(m, args);
    167     decodeThenPrint(stream_start);
    168 #endif
    169     return stream;
    170 }
    171 extern "C" ENCODER_DECLARE_EXPORT unsigned encoder_get_inst_size(char * stream) {
    172     Inst decInst;
    173     unsigned numBytes = DecoderBase::decode(stream, &decInst);
    174     return numBytes;
    175 }
    176 
    177 extern "C" ENCODER_DECLARE_EXPORT unsigned encoder_get_cur_operand_offset(int opnd_id)
    178 {
    179     return (unsigned)EncoderBase::getOpndLocation(opnd_id);
    180 }
    181 
    182 extern "C" ENCODER_DECLARE_EXPORT char * encoder_update_imm(int imm, char * stream) {
    183     Inst decInst;
    184     unsigned numBytes = DecoderBase::decode(stream, &decInst);
    185     EncoderBase::Operands args;
    186     //assert(imm.get_size() == size_32);
    187     add_imm(args, decInst.operands[0].size(), imm, true/*is_signed*/);
    188     char* stream_next = (char *)EncoderBase::encode(stream, decInst.mn, args);
    189 #ifdef PRINT_ENCODER_STREAM
    190     printEncoderInst(decInst.mn, args);
    191     decodeThenPrint(stream);
    192 #endif
    193     return stream_next;
    194 }
    195 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem(Mnemonic m, OpndSize size,
    196                int disp, int base_reg, bool isBasePhysical, char * stream) {
    197     EncoderBase::Operands args;
    198     add_m(args, base_reg, disp, size);
    199     char* stream_start = stream;
    200     stream = (char *)EncoderBase::encode(stream, m, args);
    201 #ifdef PRINT_ENCODER_STREAM
    202     printEncoderInst(m, args);
    203     decodeThenPrint(stream_start);
    204 #endif
    205     return stream;
    206 }
    207 extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg(Mnemonic m, OpndSize size,
    208                int reg, bool isPhysical, LowOpndRegType type, char * stream) {
    209     EncoderBase::Operands args;
    210     if(m == Mnemonic_IDIV || m == Mnemonic_MUL || m == Mnemonic_IMUL) {
    211       add_r(args, 0/*eax*/, size);
    212       add_r(args, 3/*edx*/, size);
    213     }
    214     add_r(args, reg, size);
    215     char* stream_start = stream;
    216     stream = (char *)EncoderBase::encode(stream, m, args);
    217 #ifdef PRINT_ENCODER_STREAM
    218     printEncoderInst(m, args);
    219     decodeThenPrint(stream_start);
    220 #endif
    221     return stream;
    222 }
    223 //both operands have same size
    224 extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg_reg(Mnemonic m, OpndSize size,
    225                    int reg, bool isPhysical,
    226                    int reg2, bool isPhysical2, LowOpndRegType type, char * stream) {
    227     if((m == Mnemonic_MOV || m == Mnemonic_MOVQ) && reg == reg2) return stream;
    228     EncoderBase::Operands args;
    229     add_r(args, reg2, size); //destination
    230     if(m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL || m == Mnemonic_SAR)
    231       add_r(args, reg, OpndSize_8);
    232     else
    233       add_r(args, reg, size);
    234     char* stream_start = stream;
    235     stream = (char *)EncoderBase::encode(stream, m, args);
    236 #ifdef PRINT_ENCODER_STREAM
    237     printEncoderInst(m, args);
    238     decodeThenPrint(stream_start);
    239 #endif
    240     return stream;
    241 }
    242 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_reg(Mnemonic m, OpndSize size,
    243                    int disp, int base_reg, bool isBasePhysical,
    244                    int reg, bool isPhysical, LowOpndRegType type, char * stream) {
    245     EncoderBase::Operands args;
    246     add_r(args, reg, size);
    247     add_m(args, base_reg, disp, size);
    248     char* stream_start = stream;
    249     stream = (char *)EncoderBase::encode(stream, m, args);
    250 #ifdef PRINT_ENCODER_STREAM
    251     printEncoderInst(m, args);
    252     decodeThenPrint(stream_start);
    253 #endif
    254     return stream;
    255 }
    256 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_scale_reg(Mnemonic m, OpndSize size,
    257                          int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
    258                          int reg, bool isPhysical, LowOpndRegType type, char * stream) {
    259     EncoderBase::Operands args;
    260     add_r(args, reg, size);
    261     add_m_scale(args, base_reg, index_reg, scale, size);
    262     char* stream_start = stream;
    263     stream = (char *)EncoderBase::encode(stream, m, args);
    264 #ifdef PRINT_ENCODER_STREAM
    265     printEncoderInst(m, args);
    266     decodeThenPrint(stream_start);
    267 #endif
    268     return stream;
    269 }
    270 extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg_mem_scale(Mnemonic m, OpndSize size,
    271                          int reg, bool isPhysical,
    272                          int base_reg, bool isBasePhysical, int index_reg, bool isIndexPhysical, int scale,
    273                          LowOpndRegType type, char * stream) {
    274     EncoderBase::Operands args;
    275     add_m_scale(args, base_reg, index_reg, scale, size);
    276     add_r(args, reg, size);
    277     char* stream_start = stream;
    278     stream = (char *)EncoderBase::encode(stream, m, args);
    279 #ifdef PRINT_ENCODER_STREAM
    280     printEncoderInst(m, args);
    281     decodeThenPrint(stream_start);
    282 #endif
    283     return stream;
    284 }
    285 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_disp_scale_reg(Mnemonic m, OpndSize size,
    286                          int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
    287                          int reg, bool isPhysical, LowOpndRegType type, char * stream) {
    288     EncoderBase::Operands args;
    289     add_r(args, reg, size);
    290     add_m_disp_scale(args, base_reg, disp, index_reg, scale, size);
    291     char* stream_start = stream;
    292     stream = (char *)EncoderBase::encode(stream, m, args);
    293 #ifdef PRINT_ENCODER_STREAM
    294     printEncoderInst(m, args);
    295     decodeThenPrint(stream_start);
    296 #endif
    297     return stream;
    298 }
    299 extern "C" ENCODER_DECLARE_EXPORT char * encoder_movzs_mem_disp_scale_reg(Mnemonic m, OpndSize size,
    300                          int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
    301                          int reg, bool isPhysical, LowOpndRegType type, char * stream) {
    302     EncoderBase::Operands args;
    303     add_r(args, reg, OpndSize_32);
    304     add_m_disp_scale(args, base_reg, disp, index_reg, scale, size);
    305     char* stream_start = stream;
    306     stream = (char *)EncoderBase::encode(stream, m, args);
    307 #ifdef PRINT_ENCODER_STREAM
    308     printEncoderInst(m, args);
    309     decodeThenPrint(stream_start);
    310 #endif
    311     return stream;
    312 }
    313 
    314 extern "C" ENCODER_DECLARE_EXPORT char* encoder_reg_mem_disp_scale(Mnemonic m, OpndSize size,
    315                          int reg, bool isPhysical,
    316                          int base_reg, bool isBasePhysical, int disp, int index_reg, bool isIndexPhysical, int scale,
    317                          LowOpndRegType type, char* stream) {
    318     EncoderBase::Operands args;
    319     add_m_disp_scale(args, base_reg, disp, index_reg, scale, size);
    320     add_r(args, reg, size);
    321     char* stream_start = stream;
    322     stream = (char *)EncoderBase::encode(stream, m, args);
    323 #ifdef PRINT_ENCODER_STREAM
    324     printEncoderInst(m, args);
    325     decodeThenPrint(stream_start);
    326 #endif
    327     return stream;
    328 }
    329 
    330 extern "C" ENCODER_DECLARE_EXPORT char * encoder_reg_mem(Mnemonic m, OpndSize size,
    331                    int reg, bool isPhysical,
    332                    int disp, int base_reg, bool isBasePhysical, LowOpndRegType type, char * stream) {
    333     EncoderBase::Operands args;
    334     add_m(args, base_reg, disp, size);
    335     add_r(args, reg, size);
    336     char* stream_start = stream;
    337     stream = (char *)EncoderBase::encode(stream, m, args);
    338 #ifdef PRINT_ENCODER_STREAM
    339     printEncoderInst(m, args);
    340     decodeThenPrint(stream_start);
    341 #endif
    342     return stream;
    343 }
    344 extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm_reg(Mnemonic m, OpndSize size,
    345                    int imm, int reg, bool isPhysical, LowOpndRegType type, char * stream) {
    346     EncoderBase::Operands args;
    347     add_r(args, reg, size); //dst
    348     if(m == Mnemonic_IMUL) add_r(args, reg, size); //src CHECK
    349     if(m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL
    350        || m == Mnemonic_SAR || m == Mnemonic_ROR)  //fix for shift opcodes
    351       add_imm(args, OpndSize_8, imm, true/*is_signed*/);
    352     else
    353       add_imm(args, size, imm, true/*is_signed*/);
    354     char* stream_start = stream;
    355     stream = (char *)EncoderBase::encode(stream, m, args);
    356 #ifdef PRINT_ENCODER_STREAM
    357     printEncoderInst(m, args);
    358     decodeThenPrint(stream_start);
    359 #endif
    360     return stream;
    361 }
    362 extern "C" ENCODER_DECLARE_EXPORT char * encoder_update_imm_rm(int imm, char * stream) {
    363     Inst decInst;
    364     unsigned numBytes = DecoderBase::decode(stream, &decInst);
    365     EncoderBase::Operands args;
    366     args.add(decInst.operands[0]);
    367     add_imm(args, decInst.operands[1].size(), imm, true/*is_signed*/);
    368     char* stream_next = (char *)EncoderBase::encode(stream, decInst.mn, args);
    369 #ifdef PRINT_ENCODER_STREAM
    370     printEncoderInst(decInst.mn, args);
    371     decodeThenPrint(stream);
    372 #endif
    373     return stream_next;
    374 }
    375 extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm_mem(Mnemonic m, OpndSize size,
    376                    int imm,
    377                    int disp, int base_reg, bool isBasePhysical, char * stream) {
    378     EncoderBase::Operands args;
    379     add_m(args, base_reg, disp, size);
    380     if (m == Mnemonic_SAL || m == Mnemonic_SHR || m == Mnemonic_SHL
    381         || m == Mnemonic_SAR || m == Mnemonic_ROR)
    382         size = OpndSize_8;
    383     add_imm(args, size, imm, true);
    384     char* stream_start = stream;
    385     stream = (char *)EncoderBase::encode(stream, m, args);
    386 #ifdef PRINT_ENCODER_STREAM
    387     printEncoderInst(m, args);
    388     decodeThenPrint(stream_start);
    389 #endif
    390     return stream;
    391 }
    392 extern "C" ENCODER_DECLARE_EXPORT char * encoder_fp_mem(Mnemonic m, OpndSize size, int reg,
    393                   int disp, int base_reg, bool isBasePhysical, char * stream) {
    394     EncoderBase::Operands args;
    395     add_m(args, base_reg, disp, size);
    396     // a fake FP register as operand
    397     add_fp(args, reg, size == OpndSize_64/*is_double*/);
    398     char* stream_start = stream;
    399     stream = (char *)EncoderBase::encode(stream, m, args);
    400 #ifdef PRINT_ENCODER_STREAM
    401     printEncoderInst(m, args);
    402     decodeThenPrint(stream_start);
    403 #endif
    404     return stream;
    405 }
    406 extern "C" ENCODER_DECLARE_EXPORT char * encoder_mem_fp(Mnemonic m, OpndSize size,
    407                   int disp, int base_reg, bool isBasePhysical,
    408                   int reg, char * stream) {
    409     EncoderBase::Operands args;
    410     // a fake FP register as operand
    411     add_fp(args, reg, size == OpndSize_64/*is_double*/);
    412     add_m(args, base_reg, disp, size);
    413     char* stream_start = stream;
    414     stream = (char *)EncoderBase::encode(stream, m, args);
    415 #ifdef PRINT_ENCODER_STREAM
    416     printEncoderInst(m, args);
    417     decodeThenPrint(stream_start);
    418 #endif
    419     return stream;
    420 }
    421 
    422 extern "C" ENCODER_DECLARE_EXPORT char * encoder_return(char * stream) {
    423     EncoderBase::Operands args;
    424     char* stream_start = stream;
    425     stream = (char *)EncoderBase::encode(stream, Mnemonic_RET, args);
    426 #ifdef PRINT_ENCODER_STREAM
    427     printEncoderInst(Mnemonic_RET, args);
    428     decodeThenPrint(stream_start);
    429 #endif
    430     return stream;
    431 }
    432 extern "C" ENCODER_DECLARE_EXPORT char * encoder_compare_fp_stack(bool pop, int reg, bool isDouble, char * stream) {
    433     //Mnemonic m = pop ? Mnemonic_FUCOMP : Mnemonic_FUCOM;
    434     Mnemonic m = pop ? Mnemonic_FUCOMIP : Mnemonic_FUCOMI;
    435     //a single operand or 2 operands?
    436     //FST ST(i) has a single operand in encoder.inl?
    437     EncoderBase::Operands args;
    438     add_fp(args, reg, isDouble);
    439     char* stream_start = stream;
    440     stream = (char *)EncoderBase::encode(stream, m, args);
    441 #ifdef PRINT_ENCODER_STREAM
    442     printEncoderInst(m, args);
    443     decodeThenPrint(stream_start);
    444 #endif
    445     return stream;
    446 }
    447 extern "C" ENCODER_DECLARE_EXPORT char * encoder_movez_mem_to_reg(OpndSize size,
    448                       int disp, int base_reg, bool isBasePhysical,
    449                       int reg, bool isPhysical, char * stream) {
    450     EncoderBase::Operands args;
    451     add_r(args, reg, OpndSize_32);
    452     add_m(args, base_reg, disp, size);
    453     char* stream_start = stream;
    454     stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVZX, args);
    455 #ifdef PRINT_ENCODER_STREAM
    456     printEncoderInst(Mnemonic_MOVZX, args);
    457     decodeThenPrint(stream_start);
    458 #endif
    459     return stream;
    460 }
    461 extern "C" ENCODER_DECLARE_EXPORT char * encoder_moves_mem_to_reg(OpndSize size,
    462                       int disp, int base_reg, bool isBasePhysical,
    463                       int reg, bool isPhysical, char * stream) {
    464     EncoderBase::Operands args;
    465     add_r(args, reg, OpndSize_32);
    466     add_m(args, base_reg, disp, size);
    467     char* stream_start = stream;
    468     stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVSX, args);
    469 #ifdef PRINT_ENCODER_STREAM
    470     printEncoderInst(Mnemonic_MOVSX, args);
    471     decodeThenPrint(stream_start);
    472 #endif
    473     return stream;
    474 }
    475 extern "C" ENCODER_DECLARE_EXPORT char * encoder_movez_reg_to_reg(OpndSize size,
    476                       int reg, bool isPhysical, int reg2,
    477                       bool isPhysical2, LowOpndRegType type, char * stream) {
    478     EncoderBase::Operands args;
    479     add_r(args, reg2, OpndSize_32); //destination
    480     add_r(args, reg, size);
    481     char* stream_start = stream;
    482     stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVZX, args);
    483 #ifdef PRINT_ENCODER_STREAM
    484     printEncoderInst(Mnemonic_MOVZX, args);
    485     decodeThenPrint(stream_start);
    486 #endif
    487     return stream;
    488 }
    489 extern "C" ENCODER_DECLARE_EXPORT char * encoder_moves_reg_to_reg(OpndSize size,
    490                       int reg, bool isPhysical,int reg2,
    491                       bool isPhysical2, LowOpndRegType type, char * stream) {
    492     EncoderBase::Operands args;
    493     add_r(args, reg2, OpndSize_32); //destination
    494     add_r(args, reg, size);
    495     char* stream_start = stream;
    496     stream = (char *)EncoderBase::encode(stream, Mnemonic_MOVSX, args);
    497 #ifdef PRINT_ENCODER_STREAM
    498     printEncoderInst(Mnemonic_MOVSX, args);
    499     decodeThenPrint(stream_start);
    500 #endif
    501     return stream;
    502 }
    503 
    504 // Disassemble the operand "opnd" and put the readable format in "strbuf"
    505 // up to a string length of "len".
    506 unsigned int DisassembleOperandToBuf(const EncoderBase::Operand& opnd, char* strbuf, unsigned int len)
    507 {
    508     unsigned int sz = 0;
    509     if(opnd.size() != OpndSize_32) {
    510         sz += snprintf(&strbuf[sz], len-sz, "%s ",
    511                        getOpndSizeString(opnd.size()));
    512     }
    513     if(opnd.is_mem()) {
    514         if(opnd.scale() != 0) {
    515             sz += snprintf(&strbuf[sz], len-sz, "%d(%s,%s,%d)", opnd.disp(),
    516                            getRegNameString(opnd.base()),
    517                            getRegNameString(opnd.index()), opnd.scale());
    518         } else {
    519             sz += snprintf(&strbuf[sz], len-sz, "%d(%s)",
    520                            opnd.disp(), getRegNameString(opnd.base()));
    521         }
    522     } else if(opnd.is_imm()) {
    523         sz += snprintf(&strbuf[sz], len-sz, "#%x", (int)opnd.imm());
    524     } else if(opnd.is_reg()) {
    525         sz += snprintf(&strbuf[sz], len-sz, "%s",
    526                        getRegNameString(opnd.reg()));
    527     }
    528     return sz;
    529 }
    530 
    531 // Disassemble the instruction "decInst" and put the readable format
    532 // in "strbuf" up to a string length of "len".
    533 void DisassembleInstToBuf(Inst& decInst, char* strbuf, unsigned int len)
    534 {
    535     unsigned int sz = 0;
    536     int k;
    537     sz += snprintf(&strbuf[sz], len-sz, "%s ", EncoderBase::toStr(decInst.mn));
    538     if (decInst.argc > 0) {
    539         sz += DisassembleOperandToBuf(decInst.operands[decInst.argc-1],
    540                                  &strbuf[sz], len-sz);
    541         for(k = decInst.argc-2; k >= 0; k--) {
    542             sz += snprintf(&strbuf[sz], len-sz, ", ");
    543             sz += DisassembleOperandToBuf(decInst.operands[k], &strbuf[sz], len-sz);
    544         }
    545     }
    546 }
    547 
    548 // Disassmble the x86 instruction pointed to by code pointer "stream."
    549 // Put the disassemble text in the "strbuf" up to string length "len".
    550 // Return the code pointer after the disassemble x86 instruction.
    551 extern "C" ENCODER_DECLARE_EXPORT
    552 char* decoder_disassemble_instr(char* stream, char* strbuf, unsigned int len)
    553 {
    554     Inst decInst;
    555     unsigned numBytes = DecoderBase::decode(stream, &decInst);
    556     DisassembleInstToBuf(decInst, strbuf, len);
    557     return (stream + numBytes);
    558 }
    559