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@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
36struct 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
84typedef int (*opfct_t) (struct output_data *);
85
86
87static int
88data_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
136static const char hiregs[8][4] =
137  {
138    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
139  };
140static const char aregs[8][4] =
141  {
142    "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"
143  };
144static const char dregs[8][4] =
145  {
146    "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
147  };
148#else
149static const char aregs[8][4] =
150  {
151    "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
152  };
153# define dregs aregs
154#endif
155
156static int
157general_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
387static int
388FCT_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
417static int
418FCT_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
442static int
443generic_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
482static int
483FCT_absval (struct output_data *d)
484{
485  return generic_abs (d, "$"
486#ifdef X86_64
487		      , 4
488#endif
489		      );
490}
491
492static int
493FCT_abs (struct output_data *d)
494{
495  return generic_abs (d, ""
496#ifdef X86_64
497		      , 8
498#endif
499		      );
500}
501
502static int
503FCT_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
528static int
529FCT_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
549static int
550__attribute__ ((noinline))
551FCT_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
571static int
572FCT_ccc (struct output_data *d)
573{
574  return FCT_crdb (d, "cr");
575}
576
577
578static int
579FCT_ddd (struct output_data *d)
580{
581  return FCT_crdb (d, "db");
582}
583
584
585static int
586FCT_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
605static int
606__attribute__ ((noinline))
607FCT_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
641static int
642FCT_ds_bx (struct output_data *d)
643{
644  return FCT_ds_xx (d, "bx");
645}
646
647
648static int
649FCT_ds_si (struct output_data *d)
650{
651  return FCT_ds_xx (d, "si");
652}
653
654
655static int
656FCT_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
670static int
671FCT_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
690static int
691FCT_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
723static int
724FCT_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
743static int
744FCT_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
775static int
776FCT_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
797static int
798FCT_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
835static int
836FCT_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
851static int
852FCT_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
875static int
876FCT_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
892static int
893FCT_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
916static int
917FCT_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
932static int
933FCT_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
977static int
978FCT_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
1003static 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
1011static int
1012FCT_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
1085static int
1086FCT_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
1106static int
1107FCT_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
1131static int
1132FCT_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
1156static typeof (FCT_mod$r_m) FCT_mod$64r_m __attribute__ ((alias ("FCT_mod$r_m")));
1157#endif
1158
1159
1160static int
1161FCT_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
1195static int
1196FCT_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
1214static int
1215FCT_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
1245static int
1246FCT_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
1286static int
1287FCT_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
1305static int
1306FCT_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
1322static int
1323FCT_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
1334static int
1335FCT_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
1354static int
1355FCT_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
1374static int
1375FCT_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
1397static int
1398FCT_string (struct output_data *d __attribute__ ((unused)))
1399{
1400  return 0;
1401}
1402
1403
1404static int
1405FCT_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