1/*
2 * x86 architecture description
3 *
4 *  Copyright (C) 2002-2007  Peter Johnson
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27#include <util.h>
28
29#include <libyasm.h>
30
31#include "x86arch.h"
32
33
34yasm_arch_module yasm_x86_LTX_arch;
35
36
37static /*@only@*/ yasm_arch *
38x86_create(const char *machine, const char *parser,
39           /*@out@*/ yasm_arch_create_error *error)
40{
41    yasm_arch_x86 *arch_x86;
42    unsigned int amd64_machine;
43
44    *error = YASM_ARCH_CREATE_OK;
45
46    if (yasm__strcasecmp(machine, "x86") == 0)
47        amd64_machine = 0;
48    else if (yasm__strcasecmp(machine, "amd64") == 0)
49        amd64_machine = 1;
50    else {
51        *error = YASM_ARCH_CREATE_BAD_MACHINE;
52        return NULL;
53    }
54
55    arch_x86 = yasm_xmalloc(sizeof(yasm_arch_x86));
56
57    arch_x86->arch.module = &yasm_x86_LTX_arch;
58
59    /* default to all instructions/features enabled */
60    arch_x86->active_cpu = 0;
61    arch_x86->cpu_enables_size = 1;
62    arch_x86->cpu_enables = yasm_xmalloc(sizeof(wordptr));
63    arch_x86->cpu_enables[0] = BitVector_Create(64, FALSE);
64    BitVector_Fill(arch_x86->cpu_enables[0]);
65
66    arch_x86->amd64_machine = amd64_machine;
67    arch_x86->mode_bits = 0;
68    arch_x86->force_strict = 0;
69    arch_x86->default_rel = 0;
70    arch_x86->gas_intel_mode = 0;
71    arch_x86->nop = X86_NOP_BASIC;
72
73    if (yasm__strcasecmp(parser, "nasm") == 0)
74        arch_x86->parser = X86_PARSER_NASM;
75    else if (yasm__strcasecmp(parser, "tasm") == 0)
76        arch_x86->parser = X86_PARSER_TASM;
77    else if (yasm__strcasecmp(parser, "gas") == 0
78             || yasm__strcasecmp(parser, "gnu") == 0)
79        arch_x86->parser = X86_PARSER_GAS;
80    else {
81        yasm_xfree(arch_x86);
82        *error = YASM_ARCH_CREATE_BAD_PARSER;
83        return NULL;
84    }
85
86    return (yasm_arch *)arch_x86;
87}
88
89static void
90x86_destroy(/*@only@*/ yasm_arch *arch)
91{
92    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
93    unsigned int i;
94    for (i=0; i<arch_x86->cpu_enables_size; i++)
95        BitVector_Destroy(arch_x86->cpu_enables[i]);
96    yasm_xfree(arch_x86->cpu_enables);
97    yasm_xfree(arch);
98}
99
100static const char *
101x86_get_machine(const yasm_arch *arch)
102{
103    const yasm_arch_x86 *arch_x86 = (const yasm_arch_x86 *)arch;
104    if (arch_x86->amd64_machine)
105        return "amd64";
106    else
107        return "x86";
108}
109
110static unsigned int
111x86_get_address_size(const yasm_arch *arch)
112{
113    const yasm_arch_x86 *arch_x86 = (const yasm_arch_x86 *)arch;
114    if (arch_x86->mode_bits != 0)
115        return arch_x86->mode_bits;
116    if (arch_x86->amd64_machine)
117        return 64;
118    else
119        return 32;
120}
121
122static int
123x86_set_var(yasm_arch *arch, const char *var, unsigned long val)
124{
125    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
126    if (yasm__strcasecmp(var, "mode_bits") == 0)
127        arch_x86->mode_bits = (unsigned int)val;
128    else if (yasm__strcasecmp(var, "force_strict") == 0)
129        arch_x86->force_strict = (unsigned int)val;
130    else if (yasm__strcasecmp(var, "default_rel") == 0) {
131        if (arch_x86->mode_bits != 64)
132            yasm_warn_set(YASM_WARN_GENERAL,
133                          N_("ignoring default rel in non-64-bit mode"));
134        else
135            arch_x86->default_rel = (unsigned int)val;
136    } else if (yasm__strcasecmp(var, "gas_intel_mode") == 0) {
137        arch_x86->gas_intel_mode = (unsigned int)val;
138    } else
139        return 1;
140    return 0;
141}
142
143static void
144x86_dir_cpu(yasm_object *object, yasm_valparamhead *valparams,
145            yasm_valparamhead *objext_valparams, unsigned long line)
146{
147    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch;
148
149    yasm_valparam *vp;
150    yasm_vps_foreach(vp, valparams) {
151        /*@null@*/ /*@dependent@*/ const char *s = yasm_vp_string(vp);
152        if (s)
153            yasm_x86__parse_cpu(arch_x86, s, strlen(s));
154        else if (vp->type == YASM_PARAM_EXPR) {
155            const yasm_intnum *intcpu;
156            intcpu = yasm_expr_get_intnum(&vp->param.e, 0);
157            if (!intcpu)
158                yasm_error_set(YASM_ERROR_SYNTAX,
159                               N_("invalid argument to [%s]"), "CPU");
160            else {
161                char strcpu[16];
162                sprintf(strcpu, "%lu", yasm_intnum_get_uint(intcpu));
163                yasm_x86__parse_cpu(arch_x86, strcpu, strlen(strcpu));
164            }
165        } else
166            yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid argument to [%s]"),
167                           "CPU");
168    }
169}
170
171static void
172x86_dir_bits(yasm_object *object, yasm_valparamhead *valparams,
173             yasm_valparamhead *objext_valparams, unsigned long line)
174{
175    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch;
176    yasm_valparam *vp;
177    /*@only@*/ /*@null@*/ yasm_expr *e = NULL;
178    const yasm_intnum *intn;
179    long lval;
180
181    if ((vp = yasm_vps_first(valparams)) && !vp->val &&
182        (e = yasm_vp_expr(vp, object->symtab, line)) != NULL &&
183        (intn = yasm_expr_get_intnum(&e, 0)) != NULL &&
184        (lval = yasm_intnum_get_int(intn)) &&
185        (lval == 16 || lval == 32 || lval == 64))
186        arch_x86->mode_bits = (unsigned char)lval;
187    else
188        yasm_error_set(YASM_ERROR_VALUE, N_("invalid argument to [%s]"),
189                       "BITS");
190    if (e)
191        yasm_expr_destroy(e);
192}
193
194static void
195x86_dir_code16(yasm_object *object, yasm_valparamhead *valparams,
196               yasm_valparamhead *objext_valparams, unsigned long line)
197{
198    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch;
199    arch_x86->mode_bits = 16;
200}
201
202static void
203x86_dir_code32(yasm_object *object, yasm_valparamhead *valparams,
204               yasm_valparamhead *objext_valparams, unsigned long line)
205{
206    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch;
207    arch_x86->mode_bits = 32;
208}
209
210static void
211x86_dir_code64(yasm_object *object, yasm_valparamhead *valparams,
212               yasm_valparamhead *objext_valparams, unsigned long line)
213{
214    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)object->arch;
215    arch_x86->mode_bits = 64;
216}
217
218static const unsigned char **
219x86_get_fill(const yasm_arch *arch)
220{
221    const yasm_arch_x86 *arch_x86 = (const yasm_arch_x86 *)arch;
222
223    /* Fill patterns that GAS uses. */
224    static const unsigned char fill16_1[1] =
225        {0x90};                                 /* 1 - nop */
226    static const unsigned char fill16_2[2] =
227        {0x89, 0xf6};                           /* 2 - mov si, si */
228    static const unsigned char fill16_3[3] =
229        {0x8d, 0x74, 0x00};                     /* 3 - lea si, [si+byte 0] */
230    static const unsigned char fill16_4[4] =
231        {0x8d, 0xb4, 0x00, 0x00};               /* 4 - lea si, [si+word 0] */
232    static const unsigned char fill16_5[5] =
233        {0x90,                                  /* 5 - nop */
234         0x8d, 0xb4, 0x00, 0x00};               /*     lea si, [si+word 0] */
235    static const unsigned char fill16_6[6] =
236        {0x89, 0xf6,                            /* 6 - mov si, si */
237         0x8d, 0xbd, 0x00, 0x00};               /*     lea di, [di+word 0] */
238    static const unsigned char fill16_7[7] =
239        {0x8d, 0x74, 0x00,                      /* 7 - lea si, [si+byte 0] */
240         0x8d, 0xbd, 0x00, 0x00};               /*     lea di, [di+word 0] */
241    static const unsigned char fill16_8[8] =
242        {0x8d, 0xb4, 0x00, 0x00,                /* 8 - lea si, [si+word 0] */
243         0x8d, 0xbd, 0x00, 0x00};               /*     lea di, [di+word 0] */
244    static const unsigned char fill16_9[9] =
245        {0xeb, 0x07, 0x90, 0x90, 0x90, 0x90,    /* 9 - jmp $+9; nop fill */
246         0x90, 0x90, 0x90};
247    static const unsigned char fill16_10[10] =
248        {0xeb, 0x08, 0x90, 0x90, 0x90, 0x90,    /* 10 - jmp $+10; nop fill */
249         0x90, 0x90, 0x90, 0x90};
250    static const unsigned char fill16_11[11] =
251        {0xeb, 0x09, 0x90, 0x90, 0x90, 0x90,    /* 11 - jmp $+11; nop fill */
252         0x90, 0x90, 0x90, 0x90, 0x90};
253    static const unsigned char fill16_12[12] =
254        {0xeb, 0x0a, 0x90, 0x90, 0x90, 0x90,    /* 12 - jmp $+12; nop fill */
255         0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
256    static const unsigned char fill16_13[13] =
257        {0xeb, 0x0b, 0x90, 0x90, 0x90, 0x90,    /* 13 - jmp $+13; nop fill */
258         0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
259    static const unsigned char fill16_14[14] =
260        {0xeb, 0x0c, 0x90, 0x90, 0x90, 0x90,    /* 14 - jmp $+14; nop fill */
261         0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
262    static const unsigned char fill16_15[15] =
263        {0xeb, 0x0d, 0x90, 0x90, 0x90, 0x90,    /* 15 - jmp $+15; nop fill */
264         0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
265    static const unsigned char *fill16[16] =
266    {
267        NULL,      fill16_1,  fill16_2,  fill16_3,
268        fill16_4,  fill16_5,  fill16_6,  fill16_7,
269        fill16_8,  fill16_9,  fill16_10, fill16_11,
270        fill16_12, fill16_13, fill16_14, fill16_15
271    };
272
273    static const unsigned char fill32_1[1] =
274        {0x90};                              /* 1 - nop */
275    static const unsigned char fill32_2[2] =
276        {0x66, 0x90};                        /* 2 - xchg ax, ax (o16 nop) */
277    static const unsigned char fill32_3[3] =
278        {0x8d, 0x76, 0x00};                  /* 3 - lea esi, [esi+byte 0] */
279    static const unsigned char fill32_4[4] =
280        {0x8d, 0x74, 0x26, 0x00};            /* 4 - lea esi, [esi*1+byte 0] */
281    static const unsigned char fill32_5[5] =
282        {0x90,                               /* 5 - nop */
283         0x8d, 0x74, 0x26, 0x00};            /*     lea esi, [esi*1+byte 0] */
284    static const unsigned char fill32_6[6] =
285        {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00};/* 6 - lea esi, [esi+dword 0] */
286    static const unsigned char fill32_7[7] =
287        {0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, /* 7 - lea esi, [esi*1+dword 0] */
288         0x00};
289    static const unsigned char fill32_8[8] =
290        {0x90,                               /* 8 - nop */
291         0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, /*     lea esi, [esi*1+dword 0] */
292         0x00};
293#if 0
294    /* GAS uses these */
295    static const unsigned char fill32_9[9] =
296        {0x89, 0xf6,                         /* 9 - mov esi, esi */
297         0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /*     lea edi, [edi*1+dword 0] */
298         0x00};
299    static const unsigned char fill32_10[10] =
300        {0x8d, 0x76, 0x00,                   /* 10 - lea esi, [esi+byte 0] */
301         0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /*      lea edi, [edi+dword 0] */
302         0x00};
303    static const unsigned char fill32_11[11] =
304        {0x8d, 0x74, 0x26, 0x00,             /* 11 - lea esi, [esi*1+byte 0] */
305         0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /*      lea edi, [edi*1+dword 0] */
306         0x00};
307    static const unsigned char fill32_12[12] =
308        {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, /* 12 - lea esi, [esi+dword 0] */
309         0x8d, 0xbf, 0x00, 0x00, 0x00, 0x00};/*      lea edi, [edi+dword 0] */
310    static const unsigned char fill32_13[13] =
311        {0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00, /* 13 - lea esi, [esi+dword 0] */
312         0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /*      lea edi, [edi*1+dword 0] */
313         0x00};
314    static const unsigned char fill32_14[14] =
315        {0x8d, 0xb4, 0x26, 0x00, 0x00, 0x00, /* 14 - lea esi, [esi*1+dword 0] */
316         0x00,
317         0x8d, 0xbc, 0x27, 0x00, 0x00, 0x00, /*      lea edi, [edi*1+dword 0] */
318         0x00};
319#else
320    /* But on newer processors, these are recommended */
321    static const unsigned char fill32_9[9] =
322        {0xeb, 0x07, 0x90, 0x90, 0x90, 0x90, /* 9 - jmp $+9; nop fill */
323         0x90, 0x90, 0x90};
324    static const unsigned char fill32_10[10] =
325        {0xeb, 0x08, 0x90, 0x90, 0x90, 0x90, /* 10 - jmp $+10; nop fill */
326         0x90, 0x90, 0x90, 0x90};
327    static const unsigned char fill32_11[11] =
328        {0xeb, 0x09, 0x90, 0x90, 0x90, 0x90, /* 11 - jmp $+11; nop fill */
329         0x90, 0x90, 0x90, 0x90, 0x90};
330    static const unsigned char fill32_12[12] =
331        {0xeb, 0x0a, 0x90, 0x90, 0x90, 0x90, /* 12 - jmp $+12; nop fill */
332         0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
333    static const unsigned char fill32_13[13] =
334        {0xeb, 0x0b, 0x90, 0x90, 0x90, 0x90, /* 13 - jmp $+13; nop fill */
335         0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
336    static const unsigned char fill32_14[14] =
337        {0xeb, 0x0c, 0x90, 0x90, 0x90, 0x90, /* 14 - jmp $+14; nop fill */
338         0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
339#endif
340    static const unsigned char fill32_15[15] =
341        {0xeb, 0x0d, 0x90, 0x90, 0x90, 0x90, /* 15 - jmp $+15; nop fill */
342         0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
343    static const unsigned char *fill32[16] =
344    {
345        NULL,      fill32_1,  fill32_2,  fill32_3,
346        fill32_4,  fill32_5,  fill32_6,  fill32_7,
347        fill32_8,  fill32_9,  fill32_10, fill32_11,
348        fill32_12, fill32_13, fill32_14, fill32_15
349    };
350
351    /* Long form nops available on more recent Intel and AMD processors */
352    static const unsigned char fill32new_3[3] =
353        {0x0f, 0x1f, 0x00};                         /* 3 - nop(3) */
354    static const unsigned char fill32new_4[4] =
355        {0x0f, 0x1f, 0x40, 0x00};                   /* 4 - nop(4) */
356    static const unsigned char fill32new_5[5] =
357        {0x0f, 0x1f, 0x44, 0x00, 0x00};             /* 5 - nop(5) */
358    static const unsigned char fill32new_6[6] =
359        {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00};       /* 6 - nop(6) */
360    static const unsigned char fill32new_7[7] =
361        {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}; /* 7 - nop(7) */
362    static const unsigned char fill32new_8[8] =
363        {0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00,  /* 8 - nop(8) */
364         0x00};
365    static const unsigned char fill32new_9[9] =
366        {0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00,  /* 9 - nop(9) */
367         0x00, 0x00};
368
369    /* Longer forms preferred by Intel use repeated o16 prefixes */
370    static const unsigned char fill32intel_10[10] =
371        {0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00,  /* 10 - o16; cs; nop */
372         0x00, 0x00, 0x00};
373    static const unsigned char fill32intel_11[11] =
374        {0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00,  /* 11 - 2x o16; cs; nop */
375         0x00, 0x00, 0x00, 0x00};
376    static const unsigned char fill32intel_12[12] =
377        {0x66, 0x66, 0x66, 0x2e, 0x0f, 0x1f, 0x84,  /* 12 - 3x o16; cs; nop */
378         0x00, 0x00, 0x00, 0x00, 0x00};
379    static const unsigned char fill32intel_13[13] =
380        {0x66, 0x66, 0x66, 0x66, 0x2e, 0x0f, 0x1f,  /* 13 - 4x o16; cs; nop */
381         0x84, 0x00, 0x00, 0x00, 0x00, 0x00};
382    static const unsigned char fill32intel_14[14] =
383        {0x66, 0x66, 0x66, 0x66, 0x66, 0x2e, 0x0f,  /* 14 - 5x o16; cs; nop */
384         0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00};
385    static const unsigned char fill32intel_15[15] =
386        {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x2e,  /* 15 - 6x o16; cs; nop */
387         0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00};
388
389    /* Longer forms preferred by AMD use fewer o16 prefixes and no CS prefix;
390     * Source: Software Optimisation Guide for AMD Family 10h
391     * Processors 40546 revision 3.10 February 2009
392     */
393    static const unsigned char fill32amd_10[10] =
394        {0x66, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00,  /* 10 - nop(10) */
395         0x00, 0x00, 0x00};
396    static const unsigned char fill32amd_11[11] =
397        {0x0f, 0x1f, 0x44, 0x00, 0x00,              /* 11 - nop(5) */
398         0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00};       /*      nop(6) */
399    static const unsigned char fill32amd_12[12] =
400        {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00,        /* 12 - nop(6) */
401         0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00};       /*      nop(6) */
402    static const unsigned char fill32amd_13[13] =
403        {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00,        /* 13 - nop(6) */
404         0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}; /*      nop(7) */
405    static const unsigned char fill32amd_14[14] =
406        {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00,  /* 14 - nop(7) */
407         0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}; /*      nop(7) */
408    static const unsigned char fill32amd_15[15] =
409        {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00,        /* 15 - nop(7) */
410         0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}; /*      nop(8) */
411
412    static const unsigned char *fill32_intel[16] =
413    {
414        NULL,           fill32_1,       fill32_2,       fill32new_3,
415        fill32new_4,    fill32new_5,    fill32new_6,    fill32new_7,
416        fill32new_8,    fill32new_9,    fill32intel_10, fill32intel_11,
417        fill32intel_12, fill32intel_13, fill32intel_14, fill32intel_15
418    };
419    static const unsigned char *fill32_amd[16] =
420    {
421        NULL,           fill32_1,       fill32_2,       fill32new_3,
422        fill32new_4,    fill32new_5,    fill32new_6,    fill32new_7,
423        fill32new_8,    fill32new_9,    fill32amd_10,   fill32amd_11,
424        fill32amd_12,   fill32amd_13,   fill32amd_14,   fill32amd_15
425    };
426
427    switch (arch_x86->mode_bits) {
428        case 16:
429            return fill16;
430        case 32:
431            if (arch_x86->nop == X86_NOP_INTEL)
432                return fill32_intel;
433            else if (arch_x86->nop == X86_NOP_AMD)
434                return fill32_amd;
435            else
436                return fill32;
437        case 64:
438            /* We know long nops are available in 64-bit mode; default to Intel
439             * ones if unspecified (to match GAS behavior).
440             */
441            if (arch_x86->nop == X86_NOP_AMD)
442                return fill32_amd;
443            else
444                return fill32_intel;
445        default:
446            yasm_error_set(YASM_ERROR_VALUE,
447                           N_("Invalid mode_bits in x86_get_fill"));
448            return NULL;
449    }
450}
451
452unsigned int
453yasm_x86__get_reg_size(uintptr_t reg)
454{
455    switch ((x86_expritem_reg_size)(reg & ~0xFUL)) {
456        case X86_REG8:
457        case X86_REG8X:
458            return 8;
459        case X86_REG16:
460            return 16;
461        case X86_REG32:
462        case X86_CRREG:
463        case X86_DRREG:
464        case X86_TRREG:
465            return 32;
466        case X86_REG64:
467        case X86_MMXREG:
468            return 64;
469        case X86_XMMREG:
470            return 128;
471        case X86_YMMREG:
472            return 256;
473        case X86_FPUREG:
474            return 80;
475        default:
476            yasm_error_set(YASM_ERROR_VALUE, N_("unknown register size"));
477    }
478    return 0;
479}
480
481static unsigned int
482x86_get_reg_size(yasm_arch *arch, uintptr_t reg)
483{
484    return yasm_x86__get_reg_size(reg);
485}
486
487static uintptr_t
488x86_reggroup_get_reg(yasm_arch *arch, uintptr_t reggroup,
489                     unsigned long regindex)
490{
491    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
492    switch ((x86_expritem_reg_size)(reggroup & ~0xFUL)) {
493        case X86_XMMREG:
494        case X86_YMMREG:
495            if (arch_x86->mode_bits == 64) {
496                if (regindex > 15)
497                    return 0;
498                return reggroup | (regindex & 15);
499            }
500            /*@fallthrough@*/
501        case X86_MMXREG:
502        case X86_FPUREG:
503            if (regindex > 7)
504                return 0;
505            return reggroup | (regindex & 7);
506        default:
507            yasm_error_set(YASM_ERROR_VALUE, N_("bad register group"));
508    }
509    return 0;
510}
511
512static void
513x86_reg_print(yasm_arch *arch, uintptr_t reg, FILE *f)
514{
515    static const char *name8[] = {"al","cl","dl","bl","ah","ch","dh","bh"};
516    static const char *name8x[] = {
517        "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
518        "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"
519    };
520    static const char *name16[] = {
521        "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
522        "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
523    };
524    static const char *name32[] = {
525        "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
526        "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
527    };
528    static const char *name64[] = {
529        "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
530        "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
531    };
532
533    switch ((x86_expritem_reg_size)(reg & ~0xFUL)) {
534        case X86_REG8:
535            fprintf(f, "%s", name8[reg&0xF]);
536            break;
537        case X86_REG8X:
538            fprintf(f, "%s", name8x[reg&0xF]);
539            break;
540        case X86_REG16:
541            fprintf(f, "%s", name16[reg&0xF]);
542            break;
543        case X86_REG32:
544            fprintf(f, "%s", name32[reg&0xF]);
545            break;
546        case X86_REG64:
547            fprintf(f, "%s", name64[reg&0xF]);
548            break;
549        case X86_MMXREG:
550            fprintf(f, "mm%d", (int)(reg&0xF));
551            break;
552        case X86_XMMREG:
553            fprintf(f, "xmm%d", (int)(reg&0xF));
554            break;
555        case X86_YMMREG:
556            fprintf(f, "ymm%d", (int)(reg&0xF));
557            break;
558        case X86_CRREG:
559            fprintf(f, "cr%d", (int)(reg&0xF));
560            break;
561        case X86_DRREG:
562            fprintf(f, "dr%d", (int)(reg&0xF));
563            break;
564        case X86_TRREG:
565            fprintf(f, "tr%d", (int)(reg&0xF));
566            break;
567        case X86_FPUREG:
568            fprintf(f, "st%d", (int)(reg&0xF));
569            break;
570        default:
571            yasm_error_set(YASM_ERROR_VALUE, N_("unknown register size"));
572    }
573}
574
575static void
576x86_segreg_print(yasm_arch *arch, uintptr_t segreg, FILE *f)
577{
578    static const char *name[] = {"es","cs","ss","ds","fs","gs"};
579    fprintf(f, "%s", name[segreg&7]);
580}
581
582/* Define x86 machines -- see arch.h for details */
583static const yasm_arch_machine x86_machines[] = {
584    { "IA-32 and derivatives", "x86" },
585    { "AMD64", "amd64" },
586    { NULL, NULL }
587};
588
589static const yasm_directive x86_directives[] = {
590    { "cpu",            "nasm", x86_dir_cpu,    YASM_DIR_ARG_REQUIRED },
591    { "bits",           "nasm", x86_dir_bits,   YASM_DIR_ARG_REQUIRED },
592    { ".code16",        "gas",  x86_dir_code16, YASM_DIR_ANY },
593    { ".code32",        "gas",  x86_dir_code32, YASM_DIR_ANY },
594    { ".code64",        "gas",  x86_dir_code64, YASM_DIR_ANY },
595    { NULL, NULL, NULL, 0 }
596};
597
598/* Define arch structure -- see arch.h for details */
599yasm_arch_module yasm_x86_LTX_arch = {
600    "x86 (IA-32 and derivatives), AMD64",
601    "x86",
602    x86_directives,
603    x86_create,
604    x86_destroy,
605    x86_get_machine,
606    x86_get_address_size,
607    x86_set_var,
608    yasm_x86__parse_check_insnprefix,
609    yasm_x86__parse_check_regtmod,
610    x86_get_fill,
611    yasm_x86__floatnum_tobytes,
612    yasm_x86__intnum_tobytes,
613    x86_get_reg_size,
614    x86_reggroup_get_reg,
615    x86_reg_print,
616    x86_segreg_print,
617    yasm_x86__ea_create_expr,
618    yasm_x86__ea_destroy,
619    yasm_x86__ea_print,
620    yasm_x86__create_empty_insn,
621    x86_machines,
622    "x86",
623    16,
624    1
625};
626