2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "enc_wrapper.h"
23 #include "utils/Log.h"
25 //#define PRINT_ENCODER_STREAM
26 bool dump_x86_inst = false;
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,
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
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);
50 args.add(EncoderBase::Operand(reg, ext));
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],
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,
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,
73 inline void add_fp(EncoderBase::Operands & args, unsigned i, bool dbl) {
74 return args.add((RegName)( (dbl ? RegName_FP0D : RegName_FP0S) + i));
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));
82 #define MAX_DECODED_STRING_LEN 1024
83 char tmpBuffer[MAX_DECODED_STRING_LEN];
85 void printOperand(const EncoderBase::Operand & opnd) {
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()));
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());
100 sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%d(%s)",
101 opnd.disp(), getRegNameString(opnd.base()));
105 sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "#%x",
109 sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, "%s",
110 getRegNameString(opnd.reg()));
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) {
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++) {
124 sz = strlen(tmpBuffer);
125 sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, ", ");
127 printOperand(decInst.operands[decInst.argc-1-k]);
129 ALOGE("%s", tmpBuffer);
131 void printOperands(EncoderBase::Operands& opnds) {
133 if(!dump_x86_inst) return;
134 for(unsigned int k = 0; k < opnds.count(); k++) {
136 sz = strlen(tmpBuffer);
137 sz += snprintf(&tmpBuffer[sz], MAX_DECODED_STRING_LEN-sz, ", ");
139 printOperand(opnds[opnds.count()-1-k]);
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);
149 int decodeThenPrint(char* stream_start) {
150 if(!dump_x86_inst) return 0;
151 snprintf(tmpBuffer, MAX_DECODED_STRING_LEN, "--- INST @ %p: ",
154 unsigned numBytes = DecoderBase::decode(stream_start, &decInst);
155 printDecoderInst(decInst);
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);
171 extern "C" ENCODER_DECLARE_EXPORT unsigned encoder_get_inst_size(char * stream) {
173 unsigned numBytes = DecoderBase::decode(stream, &decInst);
177 extern "C" ENCODER_DECLARE_EXPORT unsigned encoder_get_cur_operand_offset(int opnd_id)
179 return (unsigned)EncoderBase::getOpndLocation(opnd_id);
182 extern "C" ENCODER_DECLARE_EXPORT char * encoder_update_imm(int imm, char * stream) {
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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*/);
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);
362 extern "C" ENCODER_DECLARE_EXPORT char * encoder_update_imm_rm(int imm, char * stream) {
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);
375 extern "C" ENCODER_DECLARE_EXPORT char * encoder_imm_mem(Mnemonic m, OpndSize size,
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)
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);
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);
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);
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);
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);
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);
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);
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);
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);
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)
509 if(opnd.size() != OpndSize_32) {
510 sz += snprintf(&strbuf[sz], len-sz, "%s ",
511 getOpndSizeString(opnd.size()));
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());
519 sz += snprintf(&strbuf[sz], len-sz, "%d(%s)",
520 opnd.disp(), getRegNameString(opnd.base()));
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()));
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)
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);
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)
555 unsigned numBytes = DecoderBase::decode(stream, &decInst);
556 DisassembleInstToBuf(decInst, strbuf, len);
557 return (stream + numBytes);