diff options
Diffstat (limited to 'libyasm/bytecode.c')
-rw-r--r-- | libyasm/bytecode.c | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/libyasm/bytecode.c b/libyasm/bytecode.c new file mode 100644 index 0000000..f864bae --- /dev/null +++ b/libyasm/bytecode.c @@ -0,0 +1,386 @@ +/* + * Bytecode utility functions + * + * 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. + */ +#include "util.h" + +#include "libyasm-stdint.h" +#include "coretype.h" + +#include "errwarn.h" +#include "intnum.h" +#include "expr.h" +#include "value.h" +#include "symrec.h" + +#include "bytecode.h" + + +void +yasm_bc_set_multiple(yasm_bytecode *bc, yasm_expr *e) +{ + if (bc->multiple) + bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL, e, + e->line); + else + bc->multiple = e; +} + +void +yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ +} + +int +yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + yasm_internal_error(N_("bytecode length cannot be calculated")); + /*@unreached@*/ + return 0; +} + +int +yasm_bc_expand_common(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + yasm_internal_error(N_("bytecode does not have any dependent spans")); + /*@unreached@*/ + return 0; +} + +int +yasm_bc_tobytes_common(yasm_bytecode *bc, unsigned char **buf, + unsigned char *bufstart, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc) +{ + yasm_internal_error(N_("bytecode cannot be converted to bytes")); + /*@unreached@*/ + return 0; +} + +void +yasm_bc_transform(yasm_bytecode *bc, const yasm_bytecode_callback *callback, + void *contents) +{ + if (bc->callback) + bc->callback->destroy(bc->contents); + bc->callback = callback; + bc->contents = contents; +} + +yasm_bytecode * +yasm_bc_create_common(const yasm_bytecode_callback *callback, void *contents, + unsigned long line) +{ + yasm_bytecode *bc = yasm_xmalloc(sizeof(yasm_bytecode)); + + bc->callback = callback; + bc->section = NULL; + bc->multiple = (yasm_expr *)NULL; + bc->len = 0; + bc->mult_int = 1; + bc->line = line; + bc->offset = ~0UL; /* obviously incorrect / uninitialized value */ + bc->symrecs = NULL; + bc->contents = contents; + + return bc; +} + +yasm_section * +yasm_bc_get_section(yasm_bytecode *bc) +{ + return bc->section; +} + +void +yasm_bc__add_symrec(yasm_bytecode *bc, yasm_symrec *sym) +{ + if (!bc->symrecs) { + bc->symrecs = yasm_xmalloc(2*sizeof(yasm_symrec *)); + bc->symrecs[0] = sym; + bc->symrecs[1] = NULL; + } else { + /* Very inefficient implementation for large numbers of symbols. But + * that would be very unusual, so use the simple algorithm instead. + */ + size_t count = 1; + while (bc->symrecs[count]) + count++; + bc->symrecs = yasm_xrealloc(bc->symrecs, + (count+2)*sizeof(yasm_symrec *)); + bc->symrecs[count] = sym; + bc->symrecs[count+1] = NULL; + } +} + +void +yasm_bc_destroy(yasm_bytecode *bc) +{ + if (!bc) + return; + + if (bc->callback) + bc->callback->destroy(bc->contents); + yasm_expr_destroy(bc->multiple); + if (bc->symrecs) + yasm_xfree(bc->symrecs); + yasm_xfree(bc); +} + +void +yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level) +{ + if (!bc->callback) + fprintf(f, "%*s_Empty_\n", indent_level, ""); + else + bc->callback->print(bc->contents, f, indent_level); + fprintf(f, "%*sMultiple=", indent_level, ""); + if (!bc->multiple) + fprintf(f, "nil (1)"); + else + yasm_expr_print(bc->multiple, f); + fprintf(f, "\n%*sLength=%lu\n", indent_level, "", bc->len); + fprintf(f, "%*sLine Index=%lu\n", indent_level, "", bc->line); + fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset); +} + +void +yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) +{ + if (bc->callback) + bc->callback->finalize(bc, prev_bc); + if (bc->multiple) { + yasm_value val; + + if (yasm_value_finalize_expr(&val, bc->multiple, prev_bc, 0)) + yasm_error_set(YASM_ERROR_TOO_COMPLEX, + N_("multiple expression too complex")); + else if (val.rel) + yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, + N_("multiple expression not absolute")); + /* Finalize creates NULL output if value=0, but bc->multiple is NULL + * if value=1 (this difference is to make the common case small). + * However, this means we need to set bc->multiple explicitly to 0 + * here if val.abs is NULL. + */ + if (val.abs) + bc->multiple = val.abs; + else + bc->multiple = yasm_expr_create_ident( + yasm_expr_int(yasm_intnum_create_uint(0)), bc->line); + } +} + +/*@null@*/ yasm_intnum * +yasm_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2) +{ + unsigned long dist2, dist1; + yasm_intnum *intn; + + if (precbc1->section != precbc2->section) + return NULL; + + dist1 = yasm_bc_next_offset(precbc1); + dist2 = yasm_bc_next_offset(precbc2); + if (dist2 < dist1) { + intn = yasm_intnum_create_uint(dist1 - dist2); + yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL); + return intn; + } + dist2 -= dist1; + return yasm_intnum_create_uint(dist2); +} + +unsigned long +yasm_bc_next_offset(yasm_bytecode *precbc) +{ + return precbc->offset + precbc->len*precbc->mult_int; +} + +int +yasm_bc_elem_size(yasm_bytecode *bc) +{ + if (!bc->callback) { + yasm_internal_error(N_("got empty bytecode in yasm_bc_elem_size")); + return 0; + } else if (!bc->callback->elem_size) + return 0; + else + return bc->callback->elem_size(bc); +} + +int +yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, + void *add_span_data) +{ + int retval = 0; + + bc->len = 0; + + if (!bc->callback) + yasm_internal_error(N_("got empty bytecode in yasm_bc_calc_len")); + else + retval = bc->callback->calc_len(bc, add_span, add_span_data); + + /* Check for multiples */ + bc->mult_int = 1; + if (bc->multiple) { + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + num = yasm_expr_get_intnum(&bc->multiple, 0); + if (num) { + if (yasm_intnum_sign(num) < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative")); + retval = -1; + } else + bc->mult_int = yasm_intnum_get_int(num); + } else { + if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) { + yasm_error_set(YASM_ERROR_VALUE, + N_("expression must not contain floating point value")); + retval = -1; + } else { + yasm_value value; + yasm_value_initialize(&value, bc->multiple, 0); + add_span(add_span_data, bc, 0, &value, 0, 0); + bc->mult_int = 0; /* assume 0 to start */ + } + } + } + + /* If we got an error somewhere along the line, clear out any calc len */ + if (retval < 0) + bc->len = 0; + + return retval; +} + +int +yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val, + /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) +{ + if (span == 0) { + bc->mult_int = new_val; + return 1; + } + if (!bc->callback) { + yasm_internal_error(N_("got empty bytecode in yasm_bc_expand")); + /*@unreached@*/ + return -1; + } else + return bc->callback->expand(bc, span, old_val, new_val, neg_thres, + pos_thres); +} + +/*@null@*/ /*@only@*/ unsigned char * +yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize, + /*@out@*/ int *gap, void *d, + yasm_output_value_func output_value, + /*@null@*/ yasm_output_reloc_func output_reloc) + /*@sets *buf@*/ +{ + /*@only@*/ /*@null@*/ unsigned char *mybuf = NULL; + unsigned char *bufstart; + unsigned char *origbuf, *destbuf; + long i; + int error = 0; + + long mult; + if (yasm_bc_get_multiple(bc, &mult, 1) || mult == 0) { + *bufsize = 0; + return NULL; + } + bc->mult_int = mult; + + /* special case for reserve bytecodes */ + if (bc->callback->special == YASM_BC_SPECIAL_RESERVE) { + *bufsize = bc->len*bc->mult_int; + *gap = 1; + return NULL; /* we didn't allocate a buffer */ + } + *gap = 0; + + if (*bufsize < bc->len*bc->mult_int) { + mybuf = yasm_xmalloc(bc->len*bc->mult_int); + destbuf = mybuf; + } else + destbuf = buf; + bufstart = destbuf; + + *bufsize = bc->len*bc->mult_int; + + if (!bc->callback) + yasm_internal_error(N_("got empty bytecode in bc_tobytes")); + else for (i=0; i<bc->mult_int; i++) { + origbuf = destbuf; + error = bc->callback->tobytes(bc, &destbuf, bufstart, d, output_value, + output_reloc); + + if (!error && ((unsigned long)(destbuf - origbuf) != bc->len)) + yasm_internal_error( + N_("written length does not match optimized length")); + } + + return mybuf; +} + +int +yasm_bc_get_multiple(yasm_bytecode *bc, long *multiple, int calc_bc_dist) +{ + /*@dependent@*/ /*@null@*/ const yasm_intnum *num; + + *multiple = 1; + if (bc->multiple) { + num = yasm_expr_get_intnum(&bc->multiple, calc_bc_dist); + if (!num) { + yasm_error_set(YASM_ERROR_VALUE, + N_("could not determine multiple")); + return 1; + } + if (yasm_intnum_sign(num) < 0) { + yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative")); + return 1; + } + *multiple = yasm_intnum_get_int(num); + } + return 0; +} + +const yasm_expr * +yasm_bc_get_multiple_expr(const yasm_bytecode *bc) +{ + return bc->multiple; +} + +yasm_insn * +yasm_bc_get_insn(yasm_bytecode *bc) +{ + if (bc->callback->special != YASM_BC_SPECIAL_INSN) + return NULL; + return (yasm_insn *)bc->contents; +} |