aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/yasm/libyasm/insn.h
blob: d2d175d039a3d35b49cc011cf5c813ddc485c2cf (plain) (blame)
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
/**
 * \file libyasm/insn.h
 * \brief YASM mnenomic instruction.
 *
 * \license
 *  Copyright (C) 2002-2007  Peter Johnson
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - 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.
 * \endlicense
 */
#ifndef YASM_INSN_H
#define YASM_INSN_H

#ifndef YASM_LIB_DECL
#define YASM_LIB_DECL
#endif

/** Base structure for an effective address.  As with all base
 * structures, must be present as the first element in any
 * #yasm_arch implementation of an effective address.
 */
struct yasm_effaddr {
    yasm_value disp;            /**< address displacement */

    /** Segment register override (0 if none). */
    uintptr_t segreg;

    /** 1 if length of disp must be >0. */
    unsigned int need_nonzero_len:1;

    /** 1 if a displacement should be present in the output. */
    unsigned int need_disp:1;

    /** 1 if reg*2 should not be split into reg+reg. (0 if not).
     * This flag indicates (for architectures that support complex effective
     * addresses such as x86) if various types of complex effective addresses
     * can be split into different forms in order to minimize instruction
     * length.
     */
    unsigned int nosplit:1;

    /** 1 if effective address is /definitely/ an effective address.
     * This is used in e.g. the GAS parser to differentiate
     * between "expr" (which might or might not be an effective address) and
     * "expr(,1)" (which is definitely an effective address).
     */
    unsigned int strong:1;

    /** 1 if effective address is forced PC-relative. */
    unsigned int pc_rel:1;

    /** 1 if effective address is forced non-PC-relative. */
    unsigned int not_pc_rel:1;

    /** length of pointed data (in bytes), 0 if unknown. */
    unsigned int data_len;
};

/** An instruction operand (opaque type). */
typedef struct yasm_insn_operand yasm_insn_operand;

/** The type of an instruction operand. */
typedef enum yasm_insn_operand_type {
    YASM_INSN__OPERAND_REG = 1,     /**< A register. */
    YASM_INSN__OPERAND_SEGREG,      /**< A segment register. */
    YASM_INSN__OPERAND_MEMORY,      /**< An effective address
                                     *   (memory reference). */
    YASM_INSN__OPERAND_IMM          /**< An immediate or jump target. */
} yasm_insn_operand_type;

/** An instruction operand. */
struct yasm_insn_operand {
    /** Link for building linked list of operands.  \internal */
    /*@reldef@*/ STAILQ_ENTRY(yasm_insn_operand) link;

    /** Operand data. */
    union {
        uintptr_t reg;      /**< Arch data for reg/segreg. */
        yasm_effaddr *ea;   /**< Effective address for memory references. */
        yasm_expr *val;     /**< Value of immediate or jump target. */
    } data;

    yasm_expr *seg;         /**< Segment expression */

    uintptr_t targetmod;        /**< Arch target modifier, 0 if none. */

    /** Specified size of the operand, in bits.  0 if not user-specified. */
    unsigned int size:16;

    /** Nonzero if dereference.  Used for "*foo" in GAS.
     * The reason for this is that by default in GAS, an unprefixed value
     * is a memory address, except for jumps/calls, in which case it needs a
     * "*" prefix to become a memory address (otherwise it's an immediate).
     * This isn't knowable in the parser stage, so the parser sets this flag
     * to indicate the "*" prefix has been used, and the arch needs to adjust
     * the operand type appropriately depending on the instruction type.
     */
    unsigned int deref:1;

    /** Nonzero if strict.  Used for "strict foo" in NASM.
     * This is used to inhibit optimization on otherwise "sized" values.
     * For example, the user may just want to be explicit with the size on
     * "push dword 4", but not actually want to force the immediate size to
     * 4 bytes (rather wanting the optimizer to optimize it down to 1 byte as
     * though "dword" was not specified).  To indicate the immediate should
     * actually be forced to 4 bytes, the user needs to write
     * "push strict dword 4", which sets this flag.
     */
    unsigned int strict:1;

    /** Operand type. */
    unsigned int type:4;
};

/** Base structure for "instruction" bytecodes.  These are the mnenomic
 * (rather than raw) representation of instructions.  As with all base
 * structures, must be present as the first element in any
 * #yasm_arch implementation of mnenomic instruction bytecodes.
 */
struct yasm_insn {
    /** Linked list of operands. */
    /*@reldef@*/ STAILQ_HEAD(yasm_insn_operands, yasm_insn_operand) operands;

    /** Array of prefixes. */
    /*@null@*/ uintptr_t *prefixes;

    /** Array of segment prefixes. */
    /*@null@*/ uintptr_t *segregs;

    unsigned int num_operands;       /**< Number of operands. */
    unsigned int num_prefixes;       /**< Number of prefixes. */
    unsigned int num_segregs;        /**< Number of segment prefixes. */
};

/** Set segment override for an effective address.
 * Some architectures (such as x86) support segment overrides on effective
 * addresses.  A override of an override will result in a warning.
 * \param ea            effective address
 * \param segreg        segment register (0 if none)
 */
YASM_LIB_DECL
void yasm_ea_set_segreg(yasm_effaddr *ea, uintptr_t segreg);

/** Create an instruction operand from a register.
 * \param reg   register
 * \return Newly allocated operand.
 */
YASM_LIB_DECL
yasm_insn_operand *yasm_operand_create_reg(uintptr_t reg);

/** Create an instruction operand from a segment register.
 * \param segreg        segment register
 * \return Newly allocated operand.
 */
YASM_LIB_DECL
yasm_insn_operand *yasm_operand_create_segreg(uintptr_t segreg);

/** Create an instruction operand from an effective address.
 * \param ea    effective address
 * \return Newly allocated operand.
 */
YASM_LIB_DECL
yasm_insn_operand *yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea);

/** Create an instruction operand from an immediate expression.
 * Looks for cases of a single register and creates a register variant of
 * #yasm_insn_operand.
 * \param val   immediate expression
 * \return Newly allocated operand.
 */
YASM_LIB_DECL
yasm_insn_operand *yasm_operand_create_imm(/*@only@*/ yasm_expr *val);

/** Get the first operand in an instruction.
 * \param insn          instruction
 * \return First operand (NULL if no operands).
 */
yasm_insn_operand *yasm_insn_ops_first(yasm_insn *insn);
#define yasm_insn_ops_first(insn)   STAILQ_FIRST(&((insn)->operands))

/** Get the next operand in an instruction.
 * \param op            previous operand
 * \return Next operand (NULL if op was the last operand).
 */
yasm_insn_operand *yasm_insn_op_next(yasm_insn_operand *op);
#define yasm_insn_op_next(cur)      STAILQ_NEXT(cur, link)

/** Add operand to the end of an instruction.
 * \note Does not make a copy of the operand; so don't pass this function
 *       static or local variables, and discard the op pointer after calling
 *       this function.
 * \param insn          instruction
 * \param op            operand (may be NULL)
 * \return If operand was actually appended (it wasn't NULL), the operand;
 *         otherwise NULL.
 */
YASM_LIB_DECL
/*@null@*/ yasm_insn_operand *yasm_insn_ops_append
    (yasm_insn *insn,
     /*@returned@*/ /*@null@*/ yasm_insn_operand *op);

/** Associate a prefix with an instruction.
 * \param insn          instruction
 * \param prefix        data that identifies the prefix
 */
YASM_LIB_DECL
void yasm_insn_add_prefix(yasm_insn *insn, uintptr_t prefix);

/** Associate a segment prefix with an instruction.
 * \param insn          instruction
 * \param segreg        data that identifies the segment register
 */
YASM_LIB_DECL
void yasm_insn_add_seg_prefix(yasm_insn *insn, uintptr_t segreg);

/** Initialize the common parts of an instruction.
 * \internal For use by yasm_arch implementations only.
 * \param insn          instruction
 */
YASM_LIB_DECL
void yasm_insn_initialize(/*@out@*/ yasm_insn *insn);

/** Delete the common parts of an instruction.
 * \internal For use by yasm_arch implementations only.
 * \param insn          instruction
 * \param content       if nonzero, deletes content of each operand
 * \param arch          architecture
 */
YASM_LIB_DECL
void yasm_insn_delete(yasm_insn *insn,
                      void (*ea_destroy) (/*@only@*/ yasm_effaddr *));

/** Print a list of instruction operands.  For debugging purposes.
 * \internal For use by yasm_arch implementations only.
 * \param insn          instruction
 * \param f             file
 * \param indent_level  indentation level
 * \param arch          architecture
 */
YASM_LIB_DECL
void yasm_insn_print(const yasm_insn *insn, FILE *f, int indent_level);

/** Finalize the common parts of an instruction.
 * \internal For use by yasm_arch implementations only.
 * \param insn          instruction
 */
YASM_LIB_DECL
void yasm_insn_finalize(yasm_insn *insn);

#endif