1/*
2 * Bytecode utility functions
3 *
4 *  Copyright (C) 2001-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 "intnum.h"
34#include "expr.h"
35#include "value.h"
36#include "symrec.h"
37
38#include "bytecode.h"
39
40
41void
42yasm_bc_set_multiple(yasm_bytecode *bc, yasm_expr *e)
43{
44    if (bc->multiple)
45        bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL, e,
46                                             e->line);
47    else
48        bc->multiple = e;
49}
50
51void
52yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc)
53{
54}
55
56int
57yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
58                        void *add_span_data)
59{
60    yasm_internal_error(N_("bytecode length cannot be calculated"));
61    /*@unreached@*/
62    return 0;
63}
64
65int
66yasm_bc_expand_common(yasm_bytecode *bc, int span, long old_val, long new_val,
67                      /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
68{
69    yasm_internal_error(N_("bytecode does not have any dependent spans"));
70    /*@unreached@*/
71    return 0;
72}
73
74int
75yasm_bc_tobytes_common(yasm_bytecode *bc, unsigned char **buf,
76                       unsigned char *bufstart, void *d,
77                       yasm_output_value_func output_value,
78                       /*@null@*/ yasm_output_reloc_func output_reloc)
79{
80    yasm_internal_error(N_("bytecode cannot be converted to bytes"));
81    /*@unreached@*/
82    return 0;
83}
84
85void
86yasm_bc_transform(yasm_bytecode *bc, const yasm_bytecode_callback *callback,
87                  void *contents)
88{
89    if (bc->callback)
90        bc->callback->destroy(bc->contents);
91    bc->callback = callback;
92    bc->contents = contents;
93}
94
95yasm_bytecode *
96yasm_bc_create_common(const yasm_bytecode_callback *callback, void *contents,
97                      unsigned long line)
98{
99    yasm_bytecode *bc = yasm_xmalloc(sizeof(yasm_bytecode));
100
101    bc->callback = callback;
102    bc->section = NULL;
103    bc->multiple = (yasm_expr *)NULL;
104    bc->len = 0;
105    bc->mult_int = 1;
106    bc->line = line;
107    bc->offset = ~0UL;  /* obviously incorrect / uninitialized value */
108    bc->symrecs = NULL;
109    bc->contents = contents;
110
111    return bc;
112}
113
114yasm_section *
115yasm_bc_get_section(yasm_bytecode *bc)
116{
117    return bc->section;
118}
119
120void
121yasm_bc__add_symrec(yasm_bytecode *bc, yasm_symrec *sym)
122{
123    if (!bc->symrecs) {
124        bc->symrecs = yasm_xmalloc(2*sizeof(yasm_symrec *));
125        bc->symrecs[0] = sym;
126        bc->symrecs[1] = NULL;
127    } else {
128        /* Very inefficient implementation for large numbers of symbols.  But
129         * that would be very unusual, so use the simple algorithm instead.
130         */
131        size_t count = 1;
132        while (bc->symrecs[count])
133            count++;
134        bc->symrecs = yasm_xrealloc(bc->symrecs,
135                                    (count+2)*sizeof(yasm_symrec *));
136        bc->symrecs[count] = sym;
137        bc->symrecs[count+1] = NULL;
138    }
139}
140
141void
142yasm_bc_destroy(yasm_bytecode *bc)
143{
144    if (!bc)
145        return;
146
147    if (bc->callback)
148        bc->callback->destroy(bc->contents);
149    yasm_expr_destroy(bc->multiple);
150    if (bc->symrecs)
151        yasm_xfree(bc->symrecs);
152    yasm_xfree(bc);
153}
154
155void
156yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level)
157{
158    if (!bc->callback)
159        fprintf(f, "%*s_Empty_\n", indent_level, "");
160    else
161        bc->callback->print(bc->contents, f, indent_level);
162    fprintf(f, "%*sMultiple=", indent_level, "");
163    if (!bc->multiple)
164        fprintf(f, "nil (1)");
165    else
166        yasm_expr_print(bc->multiple, f);
167    fprintf(f, "\n%*sLength=%lu\n", indent_level, "", bc->len);
168    fprintf(f, "%*sLine Index=%lu\n", indent_level, "", bc->line);
169    fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset);
170}
171
172void
173yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
174{
175    if (bc->callback)
176        bc->callback->finalize(bc, prev_bc);
177    if (bc->multiple) {
178        yasm_value val;
179
180        if (yasm_value_finalize_expr(&val, bc->multiple, prev_bc, 0))
181            yasm_error_set(YASM_ERROR_TOO_COMPLEX,
182                           N_("multiple expression too complex"));
183        else if (val.rel)
184            yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
185                           N_("multiple expression not absolute"));
186        /* Finalize creates NULL output if value=0, but bc->multiple is NULL
187         * if value=1 (this difference is to make the common case small).
188         * However, this means we need to set bc->multiple explicitly to 0
189         * here if val.abs is NULL.
190         */
191        if (val.abs)
192            bc->multiple = val.abs;
193        else
194            bc->multiple = yasm_expr_create_ident(
195                yasm_expr_int(yasm_intnum_create_uint(0)), bc->line);
196    }
197}
198
199/*@null@*/ yasm_intnum *
200yasm_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2)
201{
202    unsigned long dist2, dist1;
203    yasm_intnum *intn;
204
205    if (precbc1->section != precbc2->section)
206        return NULL;
207
208    dist1 = yasm_bc_next_offset(precbc1);
209    dist2 = yasm_bc_next_offset(precbc2);
210    if (dist2 < dist1) {
211        intn = yasm_intnum_create_uint(dist1 - dist2);
212        yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
213        return intn;
214    }
215    dist2 -= dist1;
216    return yasm_intnum_create_uint(dist2);
217}
218
219unsigned long
220yasm_bc_next_offset(yasm_bytecode *precbc)
221{
222    return precbc->offset + precbc->len*precbc->mult_int;
223}
224
225int
226yasm_bc_elem_size(yasm_bytecode *bc)
227{
228    if (!bc->callback) {
229        yasm_internal_error(N_("got empty bytecode in yasm_bc_elem_size"));
230        return 0;
231    } else if (!bc->callback->elem_size)
232        return 0;
233    else
234        return bc->callback->elem_size(bc);
235}
236
237int
238yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
239                 void *add_span_data)
240{
241    int retval = 0;
242
243    bc->len = 0;
244
245    if (!bc->callback)
246        yasm_internal_error(N_("got empty bytecode in yasm_bc_calc_len"));
247    else
248        retval = bc->callback->calc_len(bc, add_span, add_span_data);
249
250    /* Check for multiples */
251    bc->mult_int = 1;
252    if (bc->multiple) {
253        /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
254
255        num = yasm_expr_get_intnum(&bc->multiple, 0);
256        if (num) {
257            if (yasm_intnum_sign(num) < 0) {
258                yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative"));
259                retval = -1;
260            } else
261                bc->mult_int = yasm_intnum_get_int(num);
262        } else {
263            if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) {
264                yasm_error_set(YASM_ERROR_VALUE,
265                    N_("expression must not contain floating point value"));
266                retval = -1;
267            } else {
268                yasm_value value;
269                yasm_value_initialize(&value, bc->multiple, 0);
270                add_span(add_span_data, bc, 0, &value, 0, 0);
271                bc->mult_int = 0;   /* assume 0 to start */
272            }
273        }
274    }
275
276    /* If we got an error somewhere along the line, clear out any calc len */
277    if (retval < 0)
278        bc->len = 0;
279
280    return retval;
281}
282
283int
284yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
285               /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
286{
287    if (span == 0) {
288        bc->mult_int = new_val;
289        return 1;
290    }
291    if (!bc->callback) {
292        yasm_internal_error(N_("got empty bytecode in yasm_bc_expand"));
293        /*@unreached@*/
294        return -1;
295    } else
296        return bc->callback->expand(bc, span, old_val, new_val, neg_thres,
297                                    pos_thres);
298}
299
300/*@null@*/ /*@only@*/ unsigned char *
301yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
302                /*@out@*/ int *gap, void *d,
303                yasm_output_value_func output_value,
304                /*@null@*/ yasm_output_reloc_func output_reloc)
305    /*@sets *buf@*/
306{
307    /*@only@*/ /*@null@*/ unsigned char *mybuf = NULL;
308    unsigned char *bufstart;
309    unsigned char *origbuf, *destbuf;
310    long i;
311    int error = 0;
312
313    long mult;
314    if (yasm_bc_get_multiple(bc, &mult, 1) || mult == 0) {
315        *bufsize = 0;
316        return NULL;
317    }
318    bc->mult_int = mult;
319
320    /* special case for reserve bytecodes */
321    if (bc->callback->special == YASM_BC_SPECIAL_RESERVE) {
322        *bufsize = bc->len*bc->mult_int;
323        *gap = 1;
324        return NULL;    /* we didn't allocate a buffer */
325    }
326    *gap = 0;
327
328    if (*bufsize < bc->len*bc->mult_int) {
329        mybuf = yasm_xmalloc(bc->len*bc->mult_int);
330        destbuf = mybuf;
331    } else
332        destbuf = buf;
333    bufstart = destbuf;
334
335    *bufsize = bc->len*bc->mult_int;
336
337    if (!bc->callback)
338        yasm_internal_error(N_("got empty bytecode in bc_tobytes"));
339    else for (i=0; i<bc->mult_int; i++) {
340        origbuf = destbuf;
341        error = bc->callback->tobytes(bc, &destbuf, bufstart, d, output_value,
342                                      output_reloc);
343
344        if (!error && ((unsigned long)(destbuf - origbuf) != bc->len))
345            yasm_internal_error(
346                N_("written length does not match optimized length"));
347    }
348
349    return mybuf;
350}
351
352int
353yasm_bc_get_multiple(yasm_bytecode *bc, long *multiple, int calc_bc_dist)
354{
355    /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
356
357    *multiple = 1;
358    if (bc->multiple) {
359        num = yasm_expr_get_intnum(&bc->multiple, calc_bc_dist);
360        if (!num) {
361            yasm_error_set(YASM_ERROR_VALUE,
362                           N_("could not determine multiple"));
363            return 1;
364        }
365        if (yasm_intnum_sign(num) < 0) {
366            yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative"));
367            return 1;
368        }
369        *multiple = yasm_intnum_get_int(num);
370    }
371    return 0;
372}
373
374const yasm_expr *
375yasm_bc_get_multiple_expr(const yasm_bytecode *bc)
376{
377    return bc->multiple;
378}
379
380yasm_insn *
381yasm_bc_get_insn(yasm_bytecode *bc)
382{
383    if (bc->callback->special != YASM_BC_SPECIAL_INSN)
384        return NULL;
385    return (yasm_insn *)bc->contents;
386}
387