1/*
2 * Mnemonic instruction bytecode
3 *
4 *  Copyright (C) 2005-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-stdint.h"
30#include "coretype.h"
31
32#include "errwarn.h"
33#include "expr.h"
34#include "value.h"
35
36#include "bytecode.h"
37#include "insn.h"
38#include "arch.h"
39
40
41void
42yasm_ea_set_segreg(yasm_effaddr *ea, uintptr_t segreg)
43{
44    if (!ea)
45        return;
46
47    if (segreg != 0 && ea->segreg != 0)
48        yasm_warn_set(YASM_WARN_GENERAL,
49                      N_("multiple segment overrides, using leftmost"));
50
51    ea->segreg = segreg;
52}
53
54yasm_insn_operand *
55yasm_operand_create_reg(uintptr_t reg)
56{
57    yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand));
58
59    retval->type = YASM_INSN__OPERAND_REG;
60    retval->data.reg = reg;
61    retval->seg = 0;
62    retval->targetmod = 0;
63    retval->size = 0;
64    retval->deref = 0;
65    retval->strict = 0;
66
67    return retval;
68}
69
70yasm_insn_operand *
71yasm_operand_create_segreg(uintptr_t segreg)
72{
73    yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand));
74
75    retval->type = YASM_INSN__OPERAND_SEGREG;
76    retval->data.reg = segreg;
77    retval->seg = 0;
78    retval->targetmod = 0;
79    retval->size = 0;
80    retval->deref = 0;
81    retval->strict = 0;
82
83    return retval;
84}
85
86yasm_insn_operand *
87yasm_operand_create_mem(/*@only@*/ yasm_effaddr *ea)
88{
89    yasm_insn_operand *retval = yasm_xmalloc(sizeof(yasm_insn_operand));
90
91    retval->type = YASM_INSN__OPERAND_MEMORY;
92    retval->data.ea = ea;
93    retval->seg = 0;
94    retval->targetmod = 0;
95    retval->size = 0;
96    retval->deref = 0;
97    retval->strict = 0;
98    retval->size = ea->data_len * 8;
99
100    return retval;
101}
102
103yasm_insn_operand *
104yasm_operand_create_imm(/*@only@*/ yasm_expr *val)
105{
106    yasm_insn_operand *retval;
107    const uintptr_t *reg;
108
109    reg = yasm_expr_get_reg(&val, 0);
110    if (reg) {
111        retval = yasm_operand_create_reg(*reg);
112        yasm_expr_destroy(val);
113    } else {
114        retval = yasm_xmalloc(sizeof(yasm_insn_operand));
115        retval->type = YASM_INSN__OPERAND_IMM;
116        retval->data.val = val;
117        retval->seg = 0;
118        retval->targetmod = 0;
119        retval->size = 0;
120        retval->deref = 0;
121        retval->strict = 0;
122    }
123
124    return retval;
125}
126
127yasm_insn_operand *
128yasm_insn_ops_append(yasm_insn *insn, yasm_insn_operand *op)
129{
130    if (op) {
131        insn->num_operands++;
132        STAILQ_INSERT_TAIL(&insn->operands, op, link);
133        return op;
134    }
135    return (yasm_insn_operand *)NULL;
136}
137
138void
139yasm_insn_add_prefix(yasm_insn *insn, uintptr_t prefix)
140{
141    insn->prefixes =
142        yasm_xrealloc(insn->prefixes,
143                      (insn->num_prefixes+1)*sizeof(uintptr_t));
144    insn->prefixes[insn->num_prefixes] = prefix;
145    insn->num_prefixes++;
146}
147
148void
149yasm_insn_add_seg_prefix(yasm_insn *insn, uintptr_t segreg)
150{
151    insn->segregs =
152        yasm_xrealloc(insn->segregs, (insn->num_segregs+1)*sizeof(uintptr_t));
153    insn->segregs[insn->num_segregs] = segreg;
154    insn->num_segregs++;
155}
156
157void
158yasm_insn_initialize(yasm_insn *insn)
159{
160    STAILQ_INIT(&insn->operands);
161
162    insn->prefixes = NULL;
163    insn->segregs = NULL;
164
165    insn->num_operands = 0;
166    insn->num_prefixes = 0;
167    insn->num_segregs = 0;
168}
169
170void
171yasm_insn_delete(yasm_insn *insn,
172                 void (*ea_destroy) (/*@only@*/ yasm_effaddr *))
173{
174    if (insn->num_operands > 0) {
175        yasm_insn_operand *cur, *next;
176
177        cur = STAILQ_FIRST(&insn->operands);
178        while (cur) {
179            next = STAILQ_NEXT(cur, link);
180            switch (cur->type) {
181                case YASM_INSN__OPERAND_MEMORY:
182                    ea_destroy(cur->data.ea);
183                    break;
184                case YASM_INSN__OPERAND_IMM:
185                    yasm_expr_destroy(cur->data.val);
186                    break;
187                default:
188                    break;
189            }
190            yasm_xfree(cur);
191            cur = next;
192        }
193    }
194    if (insn->num_prefixes > 0)
195        yasm_xfree(insn->prefixes);
196    if (insn->num_segregs > 0)
197        yasm_xfree(insn->segregs);
198}
199
200void
201yasm_insn_print(const yasm_insn *insn, FILE *f, int indent_level)
202{
203    const yasm_insn_operand *op;
204
205    STAILQ_FOREACH (op, &insn->operands, link) {
206        switch (op->type) {
207            case YASM_INSN__OPERAND_REG:
208                fprintf(f, "%*sReg=", indent_level, "");
209                /*yasm_arch_reg_print(arch, op->data.reg, f);*/
210                fprintf(f, "\n");
211                break;
212            case YASM_INSN__OPERAND_SEGREG:
213                fprintf(f, "%*sSegReg=", indent_level, "");
214                /*yasm_arch_segreg_print(arch, op->data.reg, f);*/
215                fprintf(f, "\n");
216                break;
217            case YASM_INSN__OPERAND_MEMORY:
218                fprintf(f, "%*sMemory=\n", indent_level, "");
219                /*yasm_arch_ea_print(arch, op->data.ea, f, indent_level);*/
220                break;
221            case YASM_INSN__OPERAND_IMM:
222                fprintf(f, "%*sImm=", indent_level, "");
223                yasm_expr_print(op->data.val, f);
224                fprintf(f, "\n");
225                break;
226        }
227        fprintf(f, "%*sTargetMod=%lx\n", indent_level+1, "",
228                (unsigned long)op->targetmod);
229        fprintf(f, "%*sSize=%u\n", indent_level+1, "", op->size);
230        fprintf(f, "%*sDeref=%d, Strict=%d\n", indent_level+1, "",
231                (int)op->deref, (int)op->strict);
232    }
233}
234
235void
236yasm_insn_finalize(yasm_insn *insn)
237{
238    unsigned int i;
239    yasm_insn_operand *op;
240    yasm_error_class eclass;
241    char *str, *xrefstr;
242    unsigned long xrefline;
243
244    /* Simplify the operands' expressions first. */
245    for (i = 0, op = yasm_insn_ops_first(insn);
246         op && i<insn->num_operands; op = yasm_insn_op_next(op), i++) {
247        /* Check operand type */
248        switch (op->type) {
249            case YASM_INSN__OPERAND_MEMORY:
250                /* Don't get over-ambitious here; some archs' memory expr
251                 * parser are sensitive to the presence of *1, etc, so don't
252                 * simplify reg*1 identities.
253                 */
254                if (op->data.ea)
255                    op->data.ea->disp.abs =
256                        yasm_expr__level_tree(op->data.ea->disp.abs, 1, 1, 0,
257                                              0, NULL, NULL);
258                if (yasm_error_occurred()) {
259                    /* Add a pointer to where it was used to the error */
260                    yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr);
261                    if (xrefstr) {
262                        yasm_error_set_xref(xrefline, "%s", xrefstr);
263                        yasm_xfree(xrefstr);
264                    }
265                    if (str) {
266                        yasm_error_set(eclass, "%s in memory expression", str);
267                        yasm_xfree(str);
268                    }
269                    return;
270                }
271                break;
272            case YASM_INSN__OPERAND_IMM:
273                op->data.val =
274                    yasm_expr__level_tree(op->data.val, 1, 1, 1, 0, NULL,
275                                          NULL);
276                if (yasm_error_occurred()) {
277                    /* Add a pointer to where it was used to the error */
278                    yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr);
279                    if (xrefstr) {
280                        yasm_error_set_xref(xrefline, "%s", xrefstr);
281                        yasm_xfree(xrefstr);
282                    }
283                    if (str) {
284                        yasm_error_set(eclass, "%s in immediate expression",
285                                       str);
286                        yasm_xfree(str);
287                    }
288                    return;
289                }
290                break;
291            default:
292                break;
293        }
294    }
295}
296