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