Home | History | Annotate | Download | only in libyasm
      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 
     41 void
     42 yasm_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 
     51 void
     52 yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc)
     53 {
     54 }
     55 
     56 int
     57 yasm_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 
     65 int
     66 yasm_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 
     74 int
     75 yasm_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 
     85 void
     86 yasm_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 
     95 yasm_bytecode *
     96 yasm_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 
    114 yasm_section *
    115 yasm_bc_get_section(yasm_bytecode *bc)
    116 {
    117     return bc->section;
    118 }
    119 
    120 void
    121 yasm_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 
    141 void
    142 yasm_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 
    155 void
    156 yasm_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 
    172 void
    173 yasm_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 *
    200 yasm_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 
    219 unsigned long
    220 yasm_bc_next_offset(yasm_bytecode *precbc)
    221 {
    222     return precbc->offset + precbc->len*precbc->mult_int;
    223 }
    224 
    225 int
    226 yasm_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 
    237 int
    238 yasm_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 
    283 int
    284 yasm_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 *
    301 yasm_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 
    352 int
    353 yasm_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 
    374 const yasm_expr *
    375 yasm_bc_get_multiple_expr(const yasm_bytecode *bc)
    376 {
    377     return bc->multiple;
    378 }
    379 
    380 yasm_insn *
    381 yasm_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