1 /* Helper routines for disassembler for x86/x86-64. 2 Copyright (C) 2007, 2008 Red Hat, Inc. 3 This file is part of elfutils. 4 Written by Ulrich Drepper <drepper (at) redhat.com>, 2007. 5 6 This file is free software; you can redistribute it and/or modify 7 it under the terms of either 8 9 * the GNU Lesser General Public License as published by the Free 10 Software Foundation; either version 3 of the License, or (at 11 your option) any later version 12 13 or 14 15 * the GNU General Public License as published by the Free 16 Software Foundation; either version 2 of the License, or (at 17 your option) any later version 18 19 or both in parallel, as here. 20 21 elfutils is distributed in the hope that it will be useful, but 22 WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 General Public License for more details. 25 26 You should have received copies of the GNU General Public License and 27 the GNU Lesser General Public License along with this program. If 28 not, see <http://www.gnu.org/licenses/>. */ 29 30 #include <inttypes.h> 31 #include <stddef.h> 32 #include <stdio.h> 33 #include <stdint.h> 34 #include <libasm.h> 35 36 struct instr_enc 37 { 38 /* The mnemonic. Especially encoded for the optimized table. */ 39 unsigned int mnemonic : MNEMONIC_BITS; 40 41 /* The rep/repe prefixes. */ 42 unsigned int rep : 1; 43 unsigned int repe : 1; 44 45 /* Mnemonic suffix. */ 46 unsigned int suffix : SUFFIX_BITS; 47 48 /* Nonzero if the instruction uses modr/m. */ 49 unsigned int modrm : 1; 50 51 /* 1st parameter. */ 52 unsigned int fct1 : FCT1_BITS; 53 #ifdef STR1_BITS 54 unsigned int str1 : STR1_BITS; 55 #endif 56 unsigned int off1_1 : OFF1_1_BITS; 57 unsigned int off1_2 : OFF1_2_BITS; 58 unsigned int off1_3 : OFF1_3_BITS; 59 60 /* 2nd parameter. */ 61 unsigned int fct2 : FCT2_BITS; 62 #ifdef STR2_BITS 63 unsigned int str2 : STR2_BITS; 64 #endif 65 unsigned int off2_1 : OFF2_1_BITS; 66 unsigned int off2_2 : OFF2_2_BITS; 67 unsigned int off2_3 : OFF2_3_BITS; 68 69 /* 3rd parameter. */ 70 unsigned int fct3 : FCT3_BITS; 71 #ifdef STR3_BITS 72 unsigned int str3 : STR3_BITS; 73 #endif 74 unsigned int off3_1 : OFF3_1_BITS; 75 #ifdef OFF3_2_BITS 76 unsigned int off3_2 : OFF3_2_BITS; 77 #endif 78 #ifdef OFF3_3_BITS 79 unsigned int off3_3 : OFF3_3_BITS; 80 #endif 81 }; 82 83 84 typedef int (*opfct_t) (struct output_data *); 85 86 87 static int 88 data_prefix (struct output_data *d) 89 { 90 char ch = '\0'; 91 if (*d->prefixes & has_cs) 92 { 93 ch = 'c'; 94 *d->prefixes &= ~has_cs; 95 } 96 else if (*d->prefixes & has_ds) 97 { 98 ch = 'd'; 99 *d->prefixes &= ~has_ds; 100 } 101 else if (*d->prefixes & has_es) 102 { 103 ch = 'e'; 104 *d->prefixes &= ~has_es; 105 } 106 else if (*d->prefixes & has_fs) 107 { 108 ch = 'f'; 109 *d->prefixes &= ~has_fs; 110 } 111 else if (*d->prefixes & has_gs) 112 { 113 ch = 'g'; 114 *d->prefixes &= ~has_gs; 115 } 116 else if (*d->prefixes & has_ss) 117 { 118 ch = 's'; 119 *d->prefixes &= ~has_ss; 120 } 121 else 122 return 0; 123 124 if (*d->bufcntp + 4 > d->bufsize) 125 return *d->bufcntp + 4 - d->bufsize; 126 127 d->bufp[(*d->bufcntp)++] = '%'; 128 d->bufp[(*d->bufcntp)++] = ch; 129 d->bufp[(*d->bufcntp)++] = 's'; 130 d->bufp[(*d->bufcntp)++] = ':'; 131 132 return 0; 133 } 134 135 #ifdef X86_64 136 static const char hiregs[8][4] = 137 { 138 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" 139 }; 140 static const char aregs[8][4] = 141 { 142 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi" 143 }; 144 static const char dregs[8][4] = 145 { 146 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" 147 }; 148 #else 149 static const char aregs[8][4] = 150 { 151 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" 152 }; 153 # define dregs aregs 154 #endif 155 156 static int 157 general_mod$r_m (struct output_data *d) 158 { 159 int r = data_prefix (d); 160 if (r != 0) 161 return r; 162 163 int prefixes = *d->prefixes; 164 const uint8_t *data = &d->data[d->opoff1 / 8]; 165 char *bufp = d->bufp; 166 size_t *bufcntp = d->bufcntp; 167 size_t bufsize = d->bufsize; 168 169 uint_fast8_t modrm = data[0]; 170 #ifndef X86_64 171 if (unlikely ((prefixes & has_addr16) != 0)) 172 { 173 int16_t disp = 0; 174 bool nodisp = false; 175 176 if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80) 177 /* 16 bit displacement. */ 178 disp = read_2sbyte_unaligned (&data[1]); 179 else if ((modrm & 0xc0) == 0x40) 180 /* 8 bit displacement. */ 181 disp = *(const int8_t *) &data[1]; 182 else if ((modrm & 0xc0) == 0) 183 nodisp = true; 184 185 char tmpbuf[sizeof ("-0x1234(%rr,%rr)")]; 186 int n; 187 if ((modrm & 0xc7) == 6) 188 n = snprintf (tmpbuf, sizeof (tmpbuf), "0x%" PRIx16, disp); 189 else 190 { 191 n = 0; 192 if (!nodisp) 193 n = snprintf (tmpbuf, sizeof (tmpbuf), "%s0x%" PRIx16, 194 disp < 0 ? "-" : "", disp < 0 ? -disp : disp); 195 196 if ((modrm & 0x4) == 0) 197 n += snprintf (tmpbuf + n, sizeof (tmpbuf) - n, "(%%b%c,%%%ci)", 198 "xp"[(modrm >> 1) & 1], "sd"[modrm & 1]); 199 else 200 n += snprintf (tmpbuf + n, sizeof (tmpbuf) - n, "(%%%s)", 201 ((const char [4][3]) { "si", "di", "bp", "bx" })[modrm & 3]); 202 } 203 204 if (*bufcntp + n + 1 > bufsize) 205 return *bufcntp + n + 1 - bufsize; 206 207 memcpy (&bufp[*bufcntp], tmpbuf, n + 1); 208 *bufcntp += n; 209 } 210 else 211 #endif 212 { 213 if ((modrm & 7) != 4) 214 { 215 int32_t disp = 0; 216 bool nodisp = false; 217 218 if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80) 219 /* 32 bit displacement. */ 220 disp = read_4sbyte_unaligned (&data[1]); 221 else if ((modrm & 0xc0) == 0x40) 222 /* 8 bit displacement. */ 223 disp = *(const int8_t *) &data[1]; 224 else if ((modrm & 0xc0) == 0) 225 nodisp = true; 226 227 char tmpbuf[sizeof ("-0x12345678(%rrrr)")]; 228 int n; 229 if (nodisp) 230 { 231 n = snprintf (tmpbuf, sizeof (tmpbuf), "(%%%s)", 232 #ifdef X86_64 233 (prefixes & has_rex_b) ? hiregs[modrm & 7] : 234 #endif 235 aregs[modrm & 7]); 236 #ifdef X86_64 237 if (prefixes & has_addr16) 238 { 239 if (prefixes & has_rex_b) 240 tmpbuf[n++] = 'd'; 241 else 242 tmpbuf[2] = 'e'; 243 } 244 #endif 245 } 246 else if ((modrm & 0xc7) != 5) 247 { 248 int p; 249 n = snprintf (tmpbuf, sizeof (tmpbuf), "%s0x%" PRIx32 "(%%%n%s)", 250 disp < 0 ? "-" : "", disp < 0 ? -disp : disp, &p, 251 #ifdef X86_64 252 (prefixes & has_rex_b) ? hiregs[modrm & 7] : 253 #endif 254 aregs[modrm & 7]); 255 #ifdef X86_64 256 if (prefixes & has_addr16) 257 { 258 if (prefixes & has_rex_b) 259 tmpbuf[n++] = 'd'; 260 else 261 tmpbuf[p] = 'e'; 262 } 263 #endif 264 } 265 else 266 { 267 #ifdef X86_64 268 n = snprintf (tmpbuf, sizeof (tmpbuf), "%s0x%" PRIx32 "(%%rip)", 269 disp < 0 ? "-" : "", disp < 0 ? -disp : disp); 270 271 d->symaddr_use = addr_rel_always; 272 d->symaddr = disp; 273 #else 274 n = snprintf (tmpbuf, sizeof (tmpbuf), "0x%" PRIx32, disp); 275 #endif 276 } 277 278 if (*bufcntp + n + 1 > bufsize) 279 return *bufcntp + n + 1 - bufsize; 280 281 memcpy (&bufp[*bufcntp], tmpbuf, n + 1); 282 *bufcntp += n; 283 } 284 else 285 { 286 /* SIB */ 287 uint_fast8_t sib = data[1]; 288 int32_t disp = 0; 289 bool nodisp = false; 290 291 if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80 292 || ((modrm & 0xc7) == 0x4 && (sib & 0x7) == 0x5)) 293 /* 32 bit displacement. */ 294 disp = read_4sbyte_unaligned (&data[2]); 295 else if ((modrm & 0xc0) == 0x40) 296 /* 8 bit displacement. */ 297 disp = *(const int8_t *) &data[2]; 298 else 299 nodisp = true; 300 301 char tmpbuf[sizeof ("-0x12345678(%rrrr,%rrrr,N)")]; 302 char *cp = tmpbuf; 303 int n; 304 if ((modrm & 0xc0) != 0 || (sib & 0x3f) != 0x25 305 #ifdef X86_64 306 || (prefixes & has_rex_x) != 0 307 #endif 308 ) 309 { 310 if (!nodisp) 311 { 312 n = snprintf (cp, sizeof (tmpbuf), "%s0x%" PRIx32, 313 disp < 0 ? "-" : "", disp < 0 ? -disp : disp); 314 cp += n; 315 } 316 317 *cp++ = '('; 318 319 if ((modrm & 0xc7) != 0x4 || (sib & 0x7) != 0x5) 320 { 321 *cp++ = '%'; 322 cp = stpcpy (cp, 323 #ifdef X86_64 324 (prefixes & has_rex_b) ? hiregs[sib & 7] : 325 (prefixes & has_addr16) ? dregs[sib & 7] : 326 #endif 327 aregs[sib & 7]); 328 #ifdef X86_64 329 if ((prefixes & (has_rex_b | has_addr16)) 330 == (has_rex_b | has_addr16)) 331 *cp++ = 'd'; 332 #endif 333 } 334 335 if ((sib & 0x38) != 0x20 336 #ifdef X86_64 337 || (prefixes & has_rex_x) != 0 338 #endif 339 ) 340 { 341 *cp++ = ','; 342 *cp++ = '%'; 343 cp = stpcpy (cp, 344 #ifdef X86_64 345 (prefixes & has_rex_x) 346 ? hiregs[(sib >> 3) & 7] : 347 (prefixes & has_addr16) 348 ? dregs[(sib >> 3) & 7] : 349 #endif 350 aregs[(sib >> 3) & 7]); 351 #ifdef X86_64 352 if ((prefixes & (has_rex_b | has_addr16)) 353 == (has_rex_b | has_addr16)) 354 *cp++ = 'd'; 355 #endif 356 357 *cp++ = ','; 358 *cp++ = '0' + (1 << (sib >> 6)); 359 } 360 361 *cp++ = ')'; 362 } 363 else 364 { 365 assert (! nodisp); 366 #ifdef X86_64 367 if ((prefixes & has_addr16) == 0) 368 n = snprintf (cp, sizeof (tmpbuf), "0x%" PRIx64, 369 (int64_t) disp); 370 else 371 #endif 372 n = snprintf (cp, sizeof (tmpbuf), "0x%" PRIx32, disp); 373 cp += n; 374 } 375 376 if (*bufcntp + (cp - tmpbuf) > bufsize) 377 return *bufcntp + (cp - tmpbuf) - bufsize; 378 379 memcpy (&bufp[*bufcntp], tmpbuf, cp - tmpbuf); 380 *bufcntp += cp - tmpbuf; 381 } 382 } 383 return 0; 384 } 385 386 387 static int 388 FCT_MOD$R_M (struct output_data *d) 389 { 390 assert (d->opoff1 % 8 == 0); 391 uint_fast8_t modrm = d->data[d->opoff1 / 8]; 392 if ((modrm & 0xc0) == 0xc0) 393 { 394 assert (d->opoff1 / 8 == d->opoff2 / 8); 395 assert (d->opoff2 % 8 == 5); 396 //uint_fast8_t byte = d->data[d->opoff2 / 8] & 7; 397 uint_fast8_t byte = modrm & 7; 398 399 size_t *bufcntp = d->bufcntp; 400 char *buf = d->bufp + *bufcntp; 401 size_t avail = d->bufsize - *bufcntp; 402 int needed; 403 if (*d->prefixes & (has_rep | has_repne)) 404 needed = snprintf (buf, avail, "%%%s", dregs[byte]); 405 else 406 needed = snprintf (buf, avail, "%%mm%" PRIxFAST8, byte); 407 if ((size_t) needed > avail) 408 return needed - avail; 409 *bufcntp += needed; 410 return 0; 411 } 412 413 return general_mod$r_m (d); 414 } 415 416 417 static int 418 FCT_Mod$R_m (struct output_data *d) 419 { 420 assert (d->opoff1 % 8 == 0); 421 uint_fast8_t modrm = d->data[d->opoff1 / 8]; 422 if ((modrm & 0xc0) == 0xc0) 423 { 424 assert (d->opoff1 / 8 == d->opoff2 / 8); 425 assert (d->opoff2 % 8 == 5); 426 //uint_fast8_t byte = data[opoff2 / 8] & 7; 427 uint_fast8_t byte = modrm & 7; 428 429 size_t *bufcntp = d->bufcntp; 430 size_t avail = d->bufsize - *bufcntp; 431 int needed = snprintf (&d->bufp[*bufcntp], avail, "%%xmm%" PRIxFAST8, 432 byte); 433 if ((size_t) needed > avail) 434 return needed - avail; 435 *d->bufcntp += needed; 436 return 0; 437 } 438 439 return general_mod$r_m (d); 440 } 441 442 static int 443 generic_abs (struct output_data *d, const char *absstring 444 #ifdef X86_64 445 , int abslen 446 #else 447 # define abslen 4 448 #endif 449 ) 450 { 451 int r = data_prefix (d); 452 if (r != 0) 453 return r; 454 455 assert (d->opoff1 % 8 == 0); 456 assert (d->opoff1 / 8 == 1); 457 if (*d->param_start + abslen > d->end) 458 return -1; 459 *d->param_start += abslen; 460 #ifndef X86_64 461 uint32_t absval; 462 # define ABSPRIFMT PRIx32 463 #else 464 uint64_t absval; 465 # define ABSPRIFMT PRIx64 466 if (abslen == 8) 467 absval = read_8ubyte_unaligned (&d->data[1]); 468 else 469 #endif 470 absval = read_4ubyte_unaligned (&d->data[1]); 471 size_t *bufcntp = d->bufcntp; 472 size_t avail = d->bufsize - *bufcntp; 473 int needed = snprintf (&d->bufp[*bufcntp], avail, "%s0x%" ABSPRIFMT, 474 absstring, absval); 475 if ((size_t) needed > avail) 476 return needed - avail; 477 *bufcntp += needed; 478 return 0; 479 } 480 481 482 static int 483 FCT_absval (struct output_data *d) 484 { 485 return generic_abs (d, "$" 486 #ifdef X86_64 487 , 4 488 #endif 489 ); 490 } 491 492 static int 493 FCT_abs (struct output_data *d) 494 { 495 return generic_abs (d, "" 496 #ifdef X86_64 497 , 8 498 #endif 499 ); 500 } 501 502 static int 503 FCT_ax (struct output_data *d) 504 { 505 int is_16bit = (*d->prefixes & has_data16) != 0; 506 507 size_t *bufcntp = d->bufcntp; 508 char *bufp = d->bufp; 509 size_t bufsize = d->bufsize; 510 511 if (*bufcntp + 4 - is_16bit > bufsize) 512 return *bufcntp + 4 - is_16bit - bufsize; 513 514 bufp[(*bufcntp)++] = '%'; 515 if (! is_16bit) 516 bufp[(*bufcntp)++] = ( 517 #ifdef X86_64 518 (*d->prefixes & has_rex_w) ? 'r' : 519 #endif 520 'e'); 521 bufp[(*bufcntp)++] = 'a'; 522 bufp[(*bufcntp)++] = 'x'; 523 524 return 0; 525 } 526 527 528 static int 529 FCT_ax$w (struct output_data *d) 530 { 531 if ((d->data[d->opoff2 / 8] & (1 << (7 - (d->opoff2 & 7)))) != 0) 532 return FCT_ax (d); 533 534 size_t *bufcntp = d->bufcntp; 535 char *bufp = d->bufp; 536 size_t bufsize = d->bufsize; 537 538 if (*bufcntp + 3 > bufsize) 539 return *bufcntp + 3 - bufsize; 540 541 bufp[(*bufcntp)++] = '%'; 542 bufp[(*bufcntp)++] = 'a'; 543 bufp[(*bufcntp)++] = 'l'; 544 545 return 0; 546 } 547 548 549 static int 550 __attribute__ ((noinline)) 551 FCT_crdb (struct output_data *d, const char *regstr) 552 { 553 if (*d->prefixes & has_data16) 554 return -1; 555 556 size_t *bufcntp = d->bufcntp; 557 558 // XXX If this assert is true, use absolute offset below 559 assert (d->opoff1 / 8 == 2); 560 assert (d->opoff1 % 8 == 2); 561 size_t avail = d->bufsize - *bufcntp; 562 int needed = snprintf (&d->bufp[*bufcntp], avail, "%%%s%" PRIx32, 563 regstr, (uint32_t) (d->data[d->opoff1 / 8] >> 3) & 7); 564 if ((size_t) needed > avail) 565 return needed - avail; 566 *bufcntp += needed; 567 return 0; 568 } 569 570 571 static int 572 FCT_ccc (struct output_data *d) 573 { 574 return FCT_crdb (d, "cr"); 575 } 576 577 578 static int 579 FCT_ddd (struct output_data *d) 580 { 581 return FCT_crdb (d, "db"); 582 } 583 584 585 static int 586 FCT_disp8 (struct output_data *d) 587 { 588 assert (d->opoff1 % 8 == 0); 589 if (*d->param_start >= d->end) 590 return -1; 591 int32_t offset = *(const int8_t *) (*d->param_start)++; 592 593 size_t *bufcntp = d->bufcntp; 594 size_t avail = d->bufsize - *bufcntp; 595 int needed = snprintf (&d->bufp[*bufcntp], avail, "0x%" PRIx32, 596 (uint32_t) (d->addr + (*d->param_start - d->data) 597 + offset)); 598 if ((size_t) needed > avail) 599 return needed - avail; 600 *bufcntp += needed; 601 return 0; 602 } 603 604 605 static int 606 __attribute__ ((noinline)) 607 FCT_ds_xx (struct output_data *d, const char *reg) 608 { 609 int prefix = *d->prefixes & SEGMENT_PREFIXES; 610 611 if (prefix == 0) 612 *d->prefixes |= prefix = has_ds; 613 /* Make sure only one bit is set. */ 614 else if ((prefix - 1) & prefix) 615 return -1; 616 617 int r = data_prefix (d); 618 619 assert ((*d->prefixes & prefix) == 0); 620 621 if (r != 0) 622 return r; 623 624 size_t *bufcntp = d->bufcntp; 625 size_t avail = d->bufsize - *bufcntp; 626 int needed = snprintf (&d->bufp[*bufcntp], avail, "(%%%s%s)", 627 #ifdef X86_64 628 *d->prefixes & idx_addr16 ? "e" : "r", 629 #else 630 *d->prefixes & idx_addr16 ? "" : "e", 631 #endif 632 reg); 633 if ((size_t) needed > avail) 634 return (size_t) needed - avail; 635 *bufcntp += needed; 636 637 return 0; 638 } 639 640 641 static int 642 FCT_ds_bx (struct output_data *d) 643 { 644 return FCT_ds_xx (d, "bx"); 645 } 646 647 648 static int 649 FCT_ds_si (struct output_data *d) 650 { 651 return FCT_ds_xx (d, "si"); 652 } 653 654 655 static int 656 FCT_dx (struct output_data *d) 657 { 658 size_t *bufcntp = d->bufcntp; 659 660 if (*bufcntp + 7 > d->bufsize) 661 return *bufcntp + 7 - d->bufsize; 662 663 memcpy (&d->bufp[*bufcntp], "(%dx)", 5); 664 *bufcntp += 5; 665 666 return 0; 667 } 668 669 670 static int 671 FCT_es_di (struct output_data *d) 672 { 673 size_t *bufcntp = d->bufcntp; 674 size_t avail = d->bufsize - *bufcntp; 675 int needed = snprintf (&d->bufp[*bufcntp], avail, "%%es:(%%%sdi)", 676 #ifdef X86_64 677 *d->prefixes & idx_addr16 ? "e" : "r" 678 #else 679 *d->prefixes & idx_addr16 ? "" : "e" 680 #endif 681 ); 682 if ((size_t) needed > avail) 683 return (size_t) needed - avail; 684 *bufcntp += needed; 685 686 return 0; 687 } 688 689 690 static int 691 FCT_imm (struct output_data *d) 692 { 693 size_t *bufcntp = d->bufcntp; 694 size_t avail = d->bufsize - *bufcntp; 695 int needed; 696 if (*d->prefixes & has_data16) 697 { 698 if (*d->param_start + 2 > d->end) 699 return -1; 700 uint16_t word = read_2ubyte_unaligned_inc (*d->param_start); 701 needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx16, word); 702 } 703 else 704 { 705 if (*d->param_start + 4 > d->end) 706 return -1; 707 int32_t word = read_4sbyte_unaligned_inc (*d->param_start); 708 #ifdef X86_64 709 if (*d->prefixes & has_rex_w) 710 needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, 711 (int64_t) word); 712 else 713 #endif 714 needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, word); 715 } 716 if ((size_t) needed > avail) 717 return (size_t) needed - avail; 718 *bufcntp += needed; 719 return 0; 720 } 721 722 723 static int 724 FCT_imm$w (struct output_data *d) 725 { 726 if ((d->data[d->opoff2 / 8] & (1 << (7 - (d->opoff2 & 7)))) != 0) 727 return FCT_imm (d); 728 729 size_t *bufcntp = d->bufcntp; 730 size_t avail = d->bufsize - *bufcntp; 731 if (*d->param_start>= d->end) 732 return -1; 733 uint_fast8_t word = *(*d->param_start)++; 734 int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIxFAST8, word); 735 if ((size_t) needed > avail) 736 return (size_t) needed - avail; 737 *bufcntp += needed; 738 return 0; 739 } 740 741 742 #ifdef X86_64 743 static int 744 FCT_imm64$w (struct output_data *d) 745 { 746 if ((d->data[d->opoff2 / 8] & (1 << (7 - (d->opoff2 & 7)))) == 0 747 || (*d->prefixes & has_data16) != 0) 748 return FCT_imm$w (d); 749 750 size_t *bufcntp = d->bufcntp; 751 size_t avail = d->bufsize - *bufcntp; 752 int needed; 753 if (*d->prefixes & has_rex_w) 754 { 755 if (*d->param_start + 8 > d->end) 756 return -1; 757 uint64_t word = read_8ubyte_unaligned_inc (*d->param_start); 758 needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, word); 759 } 760 else 761 { 762 if (*d->param_start + 4 > d->end) 763 return -1; 764 int32_t word = read_4sbyte_unaligned_inc (*d->param_start); 765 needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, word); 766 } 767 if ((size_t) needed > avail) 768 return (size_t) needed - avail; 769 *bufcntp += needed; 770 return 0; 771 } 772 #endif 773 774 775 static int 776 FCT_imms (struct output_data *d) 777 { 778 size_t *bufcntp = d->bufcntp; 779 size_t avail = d->bufsize - *bufcntp; 780 if (*d->param_start>= d->end) 781 return -1; 782 int8_t byte = *(*d->param_start)++; 783 #ifdef X86_64 784 int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, 785 (int64_t) byte); 786 #else 787 int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, 788 (int32_t) byte); 789 #endif 790 if ((size_t) needed > avail) 791 return (size_t) needed - avail; 792 *bufcntp += needed; 793 return 0; 794 } 795 796 797 static int 798 FCT_imm$s (struct output_data *d) 799 { 800 uint_fast8_t opcode = d->data[d->opoff2 / 8]; 801 size_t *bufcntp = d->bufcntp; 802 size_t avail = d->bufsize - *bufcntp; 803 if ((opcode & 2) != 0) 804 return FCT_imms (d); 805 806 if ((*d->prefixes & has_data16) == 0) 807 { 808 if (*d->param_start + 4 > d->end) 809 return -1; 810 int32_t word = read_4sbyte_unaligned_inc (*d->param_start); 811 #ifdef X86_64 812 int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, 813 (int64_t) word); 814 #else 815 int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, word); 816 #endif 817 if ((size_t) needed > avail) 818 return (size_t) needed - avail; 819 *bufcntp += needed; 820 } 821 else 822 { 823 if (*d->param_start + 2 > d->end) 824 return -1; 825 uint16_t word = read_2ubyte_unaligned_inc (*d->param_start); 826 int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx16, word); 827 if ((size_t) needed > avail) 828 return (size_t) needed - avail; 829 *bufcntp += needed; 830 } 831 return 0; 832 } 833 834 835 static int 836 FCT_imm16 (struct output_data *d) 837 { 838 if (*d->param_start + 2 > d->end) 839 return -1; 840 uint16_t word = read_2ubyte_unaligned_inc (*d->param_start); 841 size_t *bufcntp = d->bufcntp; 842 size_t avail = d->bufsize - *bufcntp; 843 int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx16, word); 844 if ((size_t) needed > avail) 845 return (size_t) needed - avail; 846 *bufcntp += needed; 847 return 0; 848 } 849 850 851 static int 852 FCT_imms8 (struct output_data *d) 853 { 854 size_t *bufcntp = d->bufcntp; 855 size_t avail = d->bufsize - *bufcntp; 856 if (*d->param_start >= d->end) 857 return -1; 858 int_fast8_t byte = *(*d->param_start)++; 859 int needed; 860 #ifdef X86_64 861 if (*d->prefixes & has_rex_w) 862 needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx64, 863 (int64_t) byte); 864 else 865 #endif 866 needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, 867 (int32_t) byte); 868 if ((size_t) needed > avail) 869 return (size_t) needed - avail; 870 *bufcntp += needed; 871 return 0; 872 } 873 874 875 static int 876 FCT_imm8 (struct output_data *d) 877 { 878 size_t *bufcntp = d->bufcntp; 879 size_t avail = d->bufsize - *bufcntp; 880 if (*d->param_start >= d->end) 881 return -1; 882 uint_fast8_t byte = *(*d->param_start)++; 883 int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx32, 884 (uint32_t) byte); 885 if ((size_t) needed > avail) 886 return (size_t) needed - avail; 887 *bufcntp += needed; 888 return 0; 889 } 890 891 892 static int 893 FCT_rel (struct output_data *d) 894 { 895 size_t *bufcntp = d->bufcntp; 896 size_t avail = d->bufsize - *bufcntp; 897 if (*d->param_start + 4 > d->end) 898 return -1; 899 int32_t rel = read_4sbyte_unaligned_inc (*d->param_start); 900 #ifdef X86_64 901 int needed = snprintf (&d->bufp[*bufcntp], avail, "0x%" PRIx64, 902 (uint64_t) (d->addr + rel 903 + (*d->param_start - d->data))); 904 #else 905 int needed = snprintf (&d->bufp[*bufcntp], avail, "0x%" PRIx32, 906 (uint32_t) (d->addr + rel 907 + (*d->param_start - d->data))); 908 #endif 909 if ((size_t) needed > avail) 910 return (size_t) needed - avail; 911 *bufcntp += needed; 912 return 0; 913 } 914 915 916 static int 917 FCT_mmxreg (struct output_data *d) 918 { 919 uint_fast8_t byte = d->data[d->opoff1 / 8]; 920 assert (d->opoff1 % 8 == 2 || d->opoff1 % 8 == 5); 921 byte = (byte >> (5 - d->opoff1 % 8)) & 7; 922 size_t *bufcntp = d->bufcntp; 923 size_t avail = d->bufsize - *bufcntp; 924 int needed = snprintf (&d->bufp[*bufcntp], avail, "%%mm%" PRIxFAST8, byte); 925 if ((size_t) needed > avail) 926 return needed - avail; 927 *bufcntp += needed; 928 return 0; 929 } 930 931 932 static int 933 FCT_mod$r_m (struct output_data *d) 934 { 935 assert (d->opoff1 % 8 == 0); 936 uint_fast8_t modrm = d->data[d->opoff1 / 8]; 937 if ((modrm & 0xc0) == 0xc0) 938 { 939 int prefixes = *d->prefixes; 940 if (prefixes & has_addr16) 941 return -1; 942 943 int is_16bit = (prefixes & has_data16) != 0; 944 945 size_t *bufcntp = d->bufcntp; 946 char *bufp = d->bufp; 947 if (*bufcntp + 5 - is_16bit > d->bufsize) 948 return *bufcntp + 5 - is_16bit - d->bufsize; 949 bufp[(*bufcntp)++] = '%'; 950 951 char *cp; 952 #ifdef X86_64 953 if ((prefixes & has_rex_b) != 0 && !is_16bit) 954 { 955 cp = stpcpy (&bufp[*bufcntp], hiregs[modrm & 7]); 956 if ((prefixes & has_rex_w) == 0) 957 *cp++ = 'd'; 958 } 959 else 960 #endif 961 { 962 cp = stpcpy (&bufp[*bufcntp], dregs[modrm & 7] + is_16bit); 963 #ifdef X86_64 964 if ((prefixes & has_rex_w) != 0) 965 bufp[*bufcntp] = 'r'; 966 #endif 967 } 968 *bufcntp = cp - bufp; 969 return 0; 970 } 971 972 return general_mod$r_m (d); 973 } 974 975 976 #ifndef X86_64 977 static int 978 FCT_moda$r_m (struct output_data *d) 979 { 980 assert (d->opoff1 % 8 == 0); 981 uint_fast8_t modrm = d->data[d->opoff1 / 8]; 982 if ((modrm & 0xc0) == 0xc0) 983 { 984 if (*d->prefixes & has_addr16) 985 return -1; 986 987 size_t *bufcntp = d->bufcntp; 988 if (*bufcntp + 3 > d->bufsize) 989 return *bufcntp + 3 - d->bufsize; 990 991 memcpy (&d->bufp[*bufcntp], "???", 3); 992 *bufcntp += 3; 993 994 return 0; 995 } 996 997 return general_mod$r_m (d); 998 } 999 #endif 1000 1001 1002 #ifdef X86_64 1003 static const char rex_8bit[8][3] = 1004 { 1005 [0] = "a", [1] = "c", [2] = "d", [3] = "b", 1006 [4] = "sp", [5] = "bp", [6] = "si", [7] = "di" 1007 }; 1008 #endif 1009 1010 1011 static int 1012 FCT_mod$r_m$w (struct output_data *d) 1013 { 1014 assert (d->opoff1 % 8 == 0); 1015 const uint8_t *data = d->data; 1016 uint_fast8_t modrm = data[d->opoff1 / 8]; 1017 if ((modrm & 0xc0) == 0xc0) 1018 { 1019 int prefixes = *d->prefixes; 1020 1021 if (prefixes & has_addr16) 1022 return -1; 1023 1024 size_t *bufcntp = d->bufcntp; 1025 char *bufp = d->bufp; 1026 if (*bufcntp + 5 > d->bufsize) 1027 return *bufcntp + 5 - d->bufsize; 1028 1029 if ((data[d->opoff3 / 8] & (1 << (7 - (d->opoff3 & 7)))) == 0) 1030 { 1031 bufp[(*bufcntp)++] = '%'; 1032 1033 #ifdef X86_64 1034 if (prefixes & has_rex) 1035 { 1036 if (prefixes & has_rex_r) 1037 *bufcntp += snprintf (bufp + *bufcntp, d->bufsize - *bufcntp, 1038 "r%db", 8 + (modrm & 7)); 1039 else 1040 { 1041 char *cp = stpcpy (bufp + *bufcntp, hiregs[modrm & 7]); 1042 *cp++ = 'l'; 1043 *bufcntp = cp - bufp; 1044 } 1045 } 1046 else 1047 #endif 1048 { 1049 bufp[(*bufcntp)++] = "acdb"[modrm & 3]; 1050 bufp[(*bufcntp)++] = "lh"[(modrm & 4) >> 2]; 1051 } 1052 } 1053 else 1054 { 1055 int is_16bit = (prefixes & has_data16) != 0; 1056 1057 bufp[(*bufcntp)++] = '%'; 1058 1059 char *cp; 1060 #ifdef X86_64 1061 if ((prefixes & has_rex_b) != 0 && !is_16bit) 1062 { 1063 cp = stpcpy (&bufp[*bufcntp], hiregs[modrm & 7]); 1064 if ((prefixes & has_rex_w) == 0) 1065 *cp++ = 'd'; 1066 } 1067 else 1068 #endif 1069 { 1070 cp = stpcpy (&bufp[*bufcntp], dregs[modrm & 7] + is_16bit); 1071 #ifdef X86_64 1072 if ((prefixes & has_rex_w) != 0) 1073 bufp[*bufcntp] = 'r'; 1074 #endif 1075 } 1076 *bufcntp = cp - bufp; 1077 } 1078 return 0; 1079 } 1080 1081 return general_mod$r_m (d); 1082 } 1083 1084 1085 static int 1086 FCT_mod$8r_m (struct output_data *d) 1087 { 1088 assert (d->opoff1 % 8 == 0); 1089 uint_fast8_t modrm = d->data[d->opoff1 / 8]; 1090 if ((modrm & 0xc0) == 0xc0) 1091 { 1092 size_t *bufcntp = d->bufcntp; 1093 char *bufp = d->bufp; 1094 if (*bufcntp + 3 > d->bufsize) 1095 return *bufcntp + 3 - d->bufsize; 1096 bufp[(*bufcntp)++] = '%'; 1097 bufp[(*bufcntp)++] = "acdb"[modrm & 3]; 1098 bufp[(*bufcntp)++] = "lh"[(modrm & 4) >> 2]; 1099 return 0; 1100 } 1101 1102 return general_mod$r_m (d); 1103 } 1104 1105 1106 static int 1107 FCT_mod$16r_m (struct output_data *d) 1108 { 1109 assert (d->opoff1 % 8 == 0); 1110 uint_fast8_t modrm = d->data[d->opoff1 / 8]; 1111 if ((modrm & 0xc0) == 0xc0) 1112 { 1113 assert (d->opoff1 / 8 == d->opoff2 / 8); 1114 //uint_fast8_t byte = data[opoff2 / 8] & 7; 1115 uint_fast8_t byte = modrm & 7; 1116 1117 size_t *bufcntp = d->bufcntp; 1118 if (*bufcntp + 3 > d->bufsize) 1119 return *bufcntp + 3 - d->bufsize; 1120 d->bufp[(*bufcntp)++] = '%'; 1121 memcpy (&d->bufp[*bufcntp], dregs[byte] + 1, sizeof (dregs[0]) - 1); 1122 *bufcntp += 2; 1123 return 0; 1124 } 1125 1126 return general_mod$r_m (d); 1127 } 1128 1129 1130 #ifdef X86_64 1131 static int 1132 FCT_mod$64r_m (struct output_data *d) 1133 { 1134 assert (d->opoff1 % 8 == 0); 1135 uint_fast8_t modrm = d->data[d->opoff1 / 8]; 1136 if ((modrm & 0xc0) == 0xc0) 1137 { 1138 assert (d->opoff1 / 8 == d->opoff2 / 8); 1139 //uint_fast8_t byte = data[opoff2 / 8] & 7; 1140 uint_fast8_t byte = modrm & 7; 1141 1142 size_t *bufcntp = d->bufcntp; 1143 if (*bufcntp + 4 > d->bufsize) 1144 return *bufcntp + 4 - d->bufsize; 1145 char *cp = &d->bufp[*bufcntp]; 1146 *cp++ = '%'; 1147 cp = stpcpy (cp, 1148 (*d->prefixes & has_rex_b) ? hiregs[byte] : aregs[byte]); 1149 *bufcntp = cp - d->bufp; 1150 return 0; 1151 } 1152 1153 return general_mod$r_m (d); 1154 } 1155 #else 1156 static typeof (FCT_mod$r_m) FCT_mod$64r_m __attribute__ ((alias ("FCT_mod$r_m"))); 1157 #endif 1158 1159 1160 static int 1161 FCT_reg (struct output_data *d) 1162 { 1163 uint_fast8_t byte = d->data[d->opoff1 / 8]; 1164 assert (d->opoff1 % 8 + 3 <= 8); 1165 byte >>= 8 - (d->opoff1 % 8 + 3); 1166 byte &= 7; 1167 int is_16bit = (*d->prefixes & has_data16) != 0; 1168 size_t *bufcntp = d->bufcntp; 1169 if (*bufcntp + 5 > d->bufsize) 1170 return *bufcntp + 5 - d->bufsize; 1171 d->bufp[(*bufcntp)++] = '%'; 1172 #ifdef X86_64 1173 if ((*d->prefixes & has_rex_r) != 0 && !is_16bit) 1174 { 1175 *bufcntp += snprintf (&d->bufp[*bufcntp], d->bufsize - *bufcntp, "r%d", 1176 8 + byte); 1177 if ((*d->prefixes & has_rex_w) == 0) 1178 d->bufp[(*bufcntp)++] = 'd'; 1179 } 1180 else 1181 #endif 1182 { 1183 memcpy (&d->bufp[*bufcntp], dregs[byte] + is_16bit, 3 - is_16bit); 1184 #ifdef X86_64 1185 if ((*d->prefixes & has_rex_w) != 0 && !is_16bit) 1186 d->bufp[*bufcntp] = 'r'; 1187 #endif 1188 *bufcntp += 3 - is_16bit; 1189 } 1190 return 0; 1191 } 1192 1193 1194 #ifdef X86_64 1195 static int 1196 FCT_oreg (struct output_data *d) 1197 { 1198 /* Special form where register comes from opcode. The rex.B bit is used, 1199 rex.R and rex.X are ignored. */ 1200 int save_prefixes = *d->prefixes; 1201 1202 *d->prefixes = ((save_prefixes & ~has_rex_r) 1203 | ((save_prefixes & has_rex_b) << (idx_rex_r - idx_rex_b))); 1204 1205 int r = FCT_reg (d); 1206 1207 *d->prefixes = save_prefixes; 1208 1209 return r; 1210 } 1211 #endif 1212 1213 1214 static int 1215 FCT_reg64 (struct output_data *d) 1216 { 1217 uint_fast8_t byte = d->data[d->opoff1 / 8]; 1218 assert (d->opoff1 % 8 + 3 <= 8); 1219 byte >>= 8 - (d->opoff1 % 8 + 3); 1220 byte &= 7; 1221 if ((*d->prefixes & has_data16) != 0) 1222 return -1; 1223 size_t *bufcntp = d->bufcntp; 1224 if (*bufcntp + 5 > d->bufsize) 1225 return *bufcntp + 5 - d->bufsize; 1226 d->bufp[(*bufcntp)++] = '%'; 1227 #ifdef X86_64 1228 if ((*d->prefixes & has_rex_r) != 0) 1229 { 1230 *bufcntp += snprintf (&d->bufp[*bufcntp], d->bufsize - *bufcntp, "r%d", 1231 8 + byte); 1232 if ((*d->prefixes & has_rex_w) == 0) 1233 d->bufp[(*bufcntp)++] = 'd'; 1234 } 1235 else 1236 #endif 1237 { 1238 memcpy (&d->bufp[*bufcntp], aregs[byte], 3); 1239 *bufcntp += 3; 1240 } 1241 return 0; 1242 } 1243 1244 1245 static int 1246 FCT_reg$w (struct output_data *d) 1247 { 1248 if (d->data[d->opoff2 / 8] & (1 << (7 - (d->opoff2 & 7)))) 1249 return FCT_reg (d); 1250 1251 uint_fast8_t byte = d->data[d->opoff1 / 8]; 1252 assert (d->opoff1 % 8 + 3 <= 8); 1253 byte >>= 8 - (d->opoff1 % 8 + 3); 1254 byte &= 7; 1255 1256 size_t *bufcntp = d->bufcntp; 1257 if (*bufcntp + 4 > d->bufsize) 1258 return *bufcntp + 4 - d->bufsize; 1259 1260 d->bufp[(*bufcntp)++] = '%'; 1261 1262 #ifdef X86_64 1263 if (*d->prefixes & has_rex) 1264 { 1265 if (*d->prefixes & has_rex_r) 1266 *bufcntp += snprintf (d->bufp + *bufcntp, d->bufsize - *bufcntp, 1267 "r%db", 8 + byte); 1268 else 1269 { 1270 char* cp = stpcpy (d->bufp + *bufcntp, rex_8bit[byte]); 1271 *cp++ = 'l'; 1272 *bufcntp = cp - d->bufp; 1273 } 1274 } 1275 else 1276 #endif 1277 { 1278 d->bufp[(*bufcntp)++] = "acdb"[byte & 3]; 1279 d->bufp[(*bufcntp)++] = "lh"[byte >> 2]; 1280 } 1281 return 0; 1282 } 1283 1284 1285 #ifdef X86_64 1286 static int 1287 FCT_oreg$w (struct output_data *d) 1288 { 1289 /* Special form where register comes from opcode. The rex.B bit is used, 1290 rex.R and rex.X are ignored. */ 1291 int save_prefixes = *d->prefixes; 1292 1293 *d->prefixes = ((save_prefixes & ~has_rex_r) 1294 | ((save_prefixes & has_rex_b) << (idx_rex_r - idx_rex_b))); 1295 1296 int r = FCT_reg$w (d); 1297 1298 *d->prefixes = save_prefixes; 1299 1300 return r; 1301 } 1302 #endif 1303 1304 1305 static int 1306 FCT_freg (struct output_data *d) 1307 { 1308 assert (d->opoff1 / 8 == 1); 1309 assert (d->opoff1 % 8 == 5); 1310 size_t *bufcntp = d->bufcntp; 1311 size_t avail = d->bufsize - *bufcntp; 1312 int needed = snprintf (&d->bufp[*bufcntp], avail, "%%st(%" PRIx32 ")", 1313 (uint32_t) (d->data[1] & 7)); 1314 if ((size_t) needed > avail) 1315 return (size_t) needed - avail; 1316 *bufcntp += needed; 1317 return 0; 1318 } 1319 1320 1321 #ifndef X86_64 1322 static int 1323 FCT_reg16 (struct output_data *d) 1324 { 1325 if (*d->prefixes & has_data16) 1326 return -1; 1327 1328 *d->prefixes |= has_data16; 1329 return FCT_reg (d); 1330 } 1331 #endif 1332 1333 1334 static int 1335 FCT_sel (struct output_data *d) 1336 { 1337 assert (d->opoff1 % 8 == 0); 1338 assert (d->opoff1 / 8 == 5); 1339 if (*d->param_start + 2 > d->end) 1340 return -1; 1341 *d->param_start += 2; 1342 uint16_t absval = read_2ubyte_unaligned (&d->data[5]); 1343 1344 size_t *bufcntp = d->bufcntp; 1345 size_t avail = d->bufsize - *bufcntp; 1346 int needed = snprintf (&d->bufp[*bufcntp], avail, "$0x%" PRIx16, absval); 1347 if ((size_t) needed > avail) 1348 return needed - avail; 1349 *bufcntp += needed; 1350 return 0; 1351 } 1352 1353 1354 static int 1355 FCT_sreg2 (struct output_data *d) 1356 { 1357 uint_fast8_t byte = d->data[d->opoff1 / 8]; 1358 assert (d->opoff1 % 8 + 3 <= 8); 1359 byte >>= 8 - (d->opoff1 % 8 + 2); 1360 1361 size_t *bufcntp = d->bufcntp; 1362 char *bufp = d->bufp; 1363 if (*bufcntp + 3 > d->bufsize) 1364 return *bufcntp + 3 - d->bufsize; 1365 1366 bufp[(*bufcntp)++] = '%'; 1367 bufp[(*bufcntp)++] = "ecsd"[byte & 3]; 1368 bufp[(*bufcntp)++] = 's'; 1369 1370 return 0; 1371 } 1372 1373 1374 static int 1375 FCT_sreg3 (struct output_data *d) 1376 { 1377 uint_fast8_t byte = d->data[d->opoff1 / 8]; 1378 assert (d->opoff1 % 8 + 4 <= 8); 1379 byte >>= 8 - (d->opoff1 % 8 + 3); 1380 1381 if ((byte & 7) >= 6) 1382 return -1; 1383 1384 size_t *bufcntp = d->bufcntp; 1385 char *bufp = d->bufp; 1386 if (*bufcntp + 3 > d->bufsize) 1387 return *bufcntp + 3 - d->bufsize; 1388 1389 bufp[(*bufcntp)++] = '%'; 1390 bufp[(*bufcntp)++] = "ecsdfg"[byte & 7]; 1391 bufp[(*bufcntp)++] = 's'; 1392 1393 return 0; 1394 } 1395 1396 1397 static int 1398 FCT_string (struct output_data *d __attribute__ ((unused))) 1399 { 1400 return 0; 1401 } 1402 1403 1404 static int 1405 FCT_xmmreg (struct output_data *d) 1406 { 1407 uint_fast8_t byte = d->data[d->opoff1 / 8]; 1408 assert (d->opoff1 % 8 == 2 || d->opoff1 % 8 == 5); 1409 byte = (byte >> (5 - d->opoff1 % 8)) & 7; 1410 1411 size_t *bufcntp = d->bufcntp; 1412 size_t avail = d->bufsize - *bufcntp; 1413 int needed = snprintf (&d->bufp[*bufcntp], avail, "%%xmm%" PRIxFAST8, byte); 1414 if ((size_t) needed > avail) 1415 return needed - avail; 1416 *bufcntp += needed; 1417 return 0; 1418 } 1419