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