summaryrefslogtreecommitdiff
path: root/modules/arch/x86/x86arch.h
blob: b5c0f0910ece8befe56cf89e132b01bb5582369c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/* $Id$
 * x86 Architecture header file
 *
 *  Copyright (C) 2001-2007  Peter Johnson
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef YASM_X86ARCH_H
#define YASM_X86ARCH_H

#include <libyasm/bitvect.h>

/* Available CPU feature flags */
#define CPU_Any     0       /* Any old cpu will do */
#define CPU_086     CPU_Any
#define CPU_186     1       /* i186 or better required */
#define CPU_286     2       /* i286 or better required */
#define CPU_386     3       /* i386 or better required */
#define CPU_486     4       /* i486 or better required */
#define CPU_586     5       /* i585 or better required */
#define CPU_686     6       /* i686 or better required */
#define CPU_P3      7       /* Pentium3 or better required */
#define CPU_P4      8       /* Pentium4 or better required */
#define CPU_IA64    9       /* IA-64 or better required */
#define CPU_K6      10      /* AMD K6 or better required */
#define CPU_Athlon  11      /* AMD Athlon or better required */
#define CPU_Hammer  12      /* AMD Sledgehammer or better required */
#define CPU_FPU     13      /* FPU support required */
#define CPU_MMX     14      /* MMX support required */
#define CPU_SSE     15      /* Streaming SIMD extensions required */
#define CPU_SSE2    16      /* Streaming SIMD extensions 2 required */
#define CPU_SSE3    17      /* Streaming SIMD extensions 3 required */
#define CPU_3DNow   18      /* 3DNow! support required */
#define CPU_Cyrix   19      /* Cyrix-specific instruction */
#define CPU_AMD     20      /* AMD-specific inst. (older than K6) */
#define CPU_SMM     21      /* System Management Mode instruction */
#define CPU_Prot    22      /* Protected mode only instruction */
#define CPU_Undoc   23      /* Undocumented instruction */
#define CPU_Obs     24      /* Obsolete instruction */
#define CPU_Priv    25      /* Priveleged instruction */
#define CPU_SVM     26      /* Secure Virtual Machine instruction */
#define CPU_PadLock 27      /* VIA PadLock instruction */
#define CPU_EM64T   28      /* Intel EM64T or better */
#define CPU_SSSE3   29      /* Streaming SIMD extensions 3 required */
#define CPU_SSE41   30      /* Streaming SIMD extensions 4.1 required */
#define CPU_SSE42   31      /* Streaming SIMD extensions 4.2 required */
#define CPU_SSE4a   32      /* AMD Streaming SIMD extensions 4a required */
#define CPU_SSE5    33      /* AMD Streaming SIMD extensions 5 required */

/* Technically not CPU capabilities, they do affect what instructions are
 * available.  These are tested against BITS==64.
 */
#define CPU_64      120     /* Only available in 64-bit mode */
#define CPU_Not64   121     /* Not available (invalid) in 64-bit mode */

typedef struct yasm_arch_x86 {
    yasm_arch_base arch;        /* base structure */

    /* What instructions/features are enabled? */
    unsigned int active_cpu;        /* active index into cpu_enables table */
    unsigned int cpu_enables_size;  /* size of cpu_enables table */
    wordptr *cpu_enables;

    unsigned int amd64_machine;
    enum {
        X86_PARSER_NASM = 0,
        X86_PARSER_GAS = 1
    } parser;
    unsigned int mode_bits;
    unsigned int force_strict;
    unsigned int default_rel;
} yasm_arch_x86;

/* 0-15 (low 4 bits) used for register number, stored in same data area.
 * Note 8-15 are only valid for some registers, and only in 64-bit mode.
 */
typedef enum {
    X86_REG8 = 0x1<<4,
    X86_REG8X = 0x2<<4,     /* 64-bit mode only, REX prefix version of REG8 */
    X86_REG16 = 0x3<<4,
    X86_REG32 = 0x4<<4,
    X86_REG64 = 0x5<<4,     /* 64-bit mode only */
    X86_FPUREG = 0x6<<4,
    X86_MMXREG = 0x7<<4,
    X86_XMMREG = 0x8<<4,
    X86_CRREG = 0x9<<4,
    X86_DRREG = 0xA<<4,
    X86_TRREG = 0xB<<4,
    X86_RIP = 0xC<<4        /* 64-bit mode only, always RIP (regnum ignored) */
} x86_expritem_reg_size;

/* Low 8 bits are used for the prefix value, stored in same data area. */
typedef enum {
    X86_LOCKREP = 1<<8,
    X86_ADDRSIZE = 2<<8,
    X86_OPERSIZE = 3<<8,
    X86_SEGREG = 4<<8,
    X86_REX = 5<<8
} x86_parse_insn_prefix;

typedef enum {
    X86_NEAR = 1,
    X86_SHORT,
    X86_FAR,
    X86_TO
} x86_parse_targetmod;

typedef enum {
    JMP_NONE,
    JMP_SHORT,
    JMP_NEAR,
    JMP_SHORT_FORCED,
    JMP_NEAR_FORCED
} x86_jmp_opcode_sel;

typedef enum {
    X86_REX_W = 3,
    X86_REX_R = 2,
    X86_REX_X = 1,
    X86_REX_B = 0
} x86_rex_bit_pos;

/* Sets REX (4th bit) and 3 LS bits from register size/number.  Returns 1 if
 * impossible to fit reg into REX, otherwise returns 0.  Input parameter rexbit
 * indicates bit of REX to use if REX is needed.  Will not modify REX if not
 * in 64-bit mode or if it wasn't needed to express reg.
 */
int yasm_x86__set_rex_from_reg(unsigned char *rex, unsigned char *drex,
                               unsigned char *low3, uintptr_t reg,
                               unsigned int bits, x86_rex_bit_pos rexbit);

/* Effective address type */
typedef struct x86_effaddr {
    yasm_effaddr ea;            /* base structure */

    /* How the spare (register) bits in Mod/RM are handled:
     * Even if valid_modrm=0, the spare bits are still valid (don't overwrite!)
     * They're set in bytecode_create_insn().
     */
    unsigned char modrm;
    unsigned char valid_modrm;  /* 1 if Mod/RM byte currently valid, 0 if not */
    unsigned char need_modrm;   /* 1 if Mod/RM byte needed, 0 if not */

    unsigned char sib;
    unsigned char valid_sib;    /* 1 if SIB byte currently valid, 0 if not */
    unsigned char need_sib;     /* 1 if SIB byte needed, 0 if not,
                                   0xff if unknown */

    unsigned char drex;         /* DREX SSE5 extension byte */
    unsigned char need_drex;    /* 1 if DREX byte needed, 0 if not */
} x86_effaddr;

void yasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare,
                       unsigned int drex, unsigned int need_drex,
                       yasm_bytecode *precbc);

void yasm_x86__ea_set_disponly(x86_effaddr *x86_ea);
x86_effaddr *yasm_x86__ea_create_reg(x86_effaddr *x86_ea, unsigned long reg,
                                     unsigned char *rex, unsigned char *drex,
                                     unsigned int bits);
x86_effaddr *yasm_x86__ea_create_imm
    (x86_effaddr *x86_ea, /*@keep@*/ yasm_expr *imm, unsigned int im_len);
yasm_effaddr *yasm_x86__ea_create_expr(yasm_arch *arch,
                                       /*@keep@*/ yasm_expr *e);
void yasm_x86__ea_destroy(yasm_effaddr *ea);
void yasm_x86__ea_print(const yasm_effaddr *ea, FILE *f, int indent_level);

void yasm_x86__bc_insn_opersize_override(yasm_bytecode *bc,
                                         unsigned int opersize);
void yasm_x86__bc_insn_addrsize_override(yasm_bytecode *bc,
                                         unsigned int addrsize);
void yasm_x86__bc_insn_set_lockrep_prefix(yasm_bytecode *bc,
                                          unsigned int prefix);

/* Bytecode types */
typedef struct x86_common {
    unsigned char addrsize;         /* 0 or =mode_bits => no override */
    unsigned char opersize;         /* 0 or =mode_bits => no override */
    unsigned char lockrep_pre;      /* 0 indicates no prefix */

    unsigned char mode_bits;
} x86_common;

typedef struct x86_opcode {
    unsigned char opcode[3];        /* opcode */
    unsigned char len;
} x86_opcode;

typedef struct x86_insn {
    x86_common common;              /* common x86 information */
    x86_opcode opcode;

    /*@null@*/ x86_effaddr *x86_ea; /* effective address */

    /*@null@*/ yasm_value *imm;     /* immediate or relative value */

    unsigned char def_opersize_64;  /* default operand size in 64-bit mode */
    unsigned char special_prefix;   /* "special" prefix (0=none) */

    unsigned char rex;          /* REX AMD64 extension, 0 if none,
                                   0xff if not allowed (high 8 bit reg used) */

    /* Postponed (from parsing to later binding) action options. */
    enum {
        /* None */
        X86_POSTOP_NONE = 0,

        /* Instructions that take a sign-extended imm8 as well as imm values
         * (eg, the arith instructions and a subset of the imul instructions)
         * should set this and put the imm8 form as the "normal" opcode (in
         * the first one or two bytes) and non-imm8 form in the second or
         * third byte of the opcode.
         */
        X86_POSTOP_SIGNEXT_IMM8,

        /* Override any attempt at address-size override to 16 bits, and never
         * generate a prefix.  This is used for the ENTER opcode.
         */
        X86_POSTOP_ADDRESS16
    } postop;
} x86_insn;

typedef struct x86_jmp {
    x86_common common;          /* common x86 information */
    x86_opcode shortop, nearop;

    yasm_value target;          /* jump target */

    /* which opcode are we using? */
    /* The *FORCED forms are specified in the source as such */
    x86_jmp_opcode_sel op_sel;
} x86_jmp;

/* Direct (immediate) FAR jumps ONLY; indirect FAR jumps get turned into
 * x86_insn bytecodes; relative jumps turn into x86_jmp bytecodes.
 * This bytecode is not legal in 64-bit mode.
 */
typedef struct x86_jmpfar {
    x86_common common;          /* common x86 information */
    x86_opcode opcode;

    yasm_value segment;         /* target segment */
    yasm_value offset;          /* target offset */
} x86_jmpfar;

void yasm_x86__bc_transform_insn(yasm_bytecode *bc, x86_insn *insn);
void yasm_x86__bc_transform_jmp(yasm_bytecode *bc, x86_jmp *jmp);
void yasm_x86__bc_transform_jmpfar(yasm_bytecode *bc, x86_jmpfar *jmpfar);

void yasm_x86__bc_apply_prefixes
    (x86_common *common, unsigned char *rex, unsigned int def_opersize_64,
     unsigned int num_prefixes, uintptr_t *prefixes);

/* Check an effective address.  Returns 0 if EA was successfully determined,
 * 1 if invalid EA, or 2 if indeterminate EA.
 */
int yasm_x86__expr_checkea
    (x86_effaddr *x86_ea, unsigned char *addrsize, unsigned int bits,
     int address16_op, unsigned char *rex, yasm_bytecode *bc);

void yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid,
                         size_t cpuid_len);

yasm_arch_insnprefix yasm_x86__parse_check_insnprefix
    (yasm_arch *arch, const char *id, size_t id_len, unsigned long line,
     /*@out@*/ yasm_bytecode **bc, /*@out@*/ uintptr_t *prefix);
yasm_arch_regtmod yasm_x86__parse_check_regtmod
    (yasm_arch *arch, const char *id, size_t id_len,
     /*@out@*/ uintptr_t *data);

int yasm_x86__floatnum_tobytes
    (yasm_arch *arch, const yasm_floatnum *flt, unsigned char *buf,
     size_t destsize, size_t valsize, size_t shift, int warn);
int yasm_x86__intnum_tobytes
    (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf,
     size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc,
     int warn);

unsigned int yasm_x86__get_reg_size(uintptr_t reg);

/*@only@*/ yasm_bytecode *yasm_x86__create_empty_insn(yasm_arch *arch,
                                                      unsigned long line);
#endif