123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /*
- * Align bytecode
- *
- * Copyright (C) 2005-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 "bytecode.h"
- typedef struct bytecode_align {
- /*@only@*/ yasm_expr *boundary; /* alignment boundary */
- /* What to fill intervening locations with, NULL if using code_fill */
- /*@only@*/ /*@null@*/ yasm_expr *fill;
- /* Maximum number of bytes to skip, NULL if no maximum. */
- /*@only@*/ /*@null@*/ yasm_expr *maxskip;
- /* Code fill, NULL if using 0 fill */
- /*@null@*/ const unsigned char **code_fill;
- } bytecode_align;
- static void bc_align_destroy(void *contents);
- static void bc_align_print(const void *contents, FILE *f, int indent_level);
- static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
- static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
- void *add_span_data);
- static int bc_align_expand(yasm_bytecode *bc, int span, long old_val,
- long new_val, /*@out@*/ long *neg_thres,
- /*@out@*/ long *pos_thres);
- static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- /*@null@*/ yasm_output_reloc_func output_reloc);
- static const yasm_bytecode_callback bc_align_callback = {
- bc_align_destroy,
- bc_align_print,
- bc_align_finalize,
- NULL,
- bc_align_calc_len,
- bc_align_expand,
- bc_align_tobytes,
- YASM_BC_SPECIAL_OFFSET
- };
- static void
- bc_align_destroy(void *contents)
- {
- bytecode_align *align = (bytecode_align *)contents;
- if (align->boundary)
- yasm_expr_destroy(align->boundary);
- if (align->fill)
- yasm_expr_destroy(align->fill);
- if (align->maxskip)
- yasm_expr_destroy(align->maxskip);
- yasm_xfree(contents);
- }
- static void
- bc_align_print(const void *contents, FILE *f, int indent_level)
- {
- const bytecode_align *align = (const bytecode_align *)contents;
- fprintf(f, "%*s_Align_\n", indent_level, "");
- fprintf(f, "%*sBoundary=", indent_level, "");
- yasm_expr_print(align->boundary, f);
- fprintf(f, "\n%*sFill=", indent_level, "");
- yasm_expr_print(align->fill, f);
- fprintf(f, "\n%*sMax Skip=", indent_level, "");
- yasm_expr_print(align->maxskip, f);
- fprintf(f, "\n");
- }
- static void
- bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
- {
- bytecode_align *align = (bytecode_align *)bc->contents;
- if (!yasm_expr_get_intnum(&align->boundary, 0))
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("align boundary must be a constant"));
- if (align->fill && !yasm_expr_get_intnum(&align->fill, 0))
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("align fill must be a constant"));
- if (align->maxskip && !yasm_expr_get_intnum(&align->maxskip, 0))
- yasm_error_set(YASM_ERROR_NOT_CONSTANT,
- N_("align maximum skip must be a constant"));
- }
- static int
- bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
- void *add_span_data)
- {
- long neg_thres = 0;
- long pos_thres = 0;
- if (bc_align_expand(bc, 0, 0, (long)bc->offset, &neg_thres,
- &pos_thres) < 0)
- return -1;
- return 0;
- }
- static int
- bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
- /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
- {
- bytecode_align *align = (bytecode_align *)bc->contents;
- unsigned long end;
- unsigned long boundary =
- yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0));
- if (boundary == 0) {
- bc->len = 0;
- *pos_thres = new_val;
- return 0;
- }
- end = (unsigned long)new_val;
- if ((unsigned long)new_val & (boundary-1))
- end = ((unsigned long)new_val & ~(boundary-1)) + boundary;
- *pos_thres = (long)end;
- bc->len = end - (unsigned long)new_val;
- if (align->maxskip) {
- unsigned long maxskip =
- yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0));
- if (bc->len > maxskip) {
- *pos_thres = (long)end-maxskip-1;
- bc->len = 0;
- }
- }
- return 1;
- }
- static int
- bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- unsigned char *bufstart, void *d,
- yasm_output_value_func output_value,
- /*@unused@*/ yasm_output_reloc_func output_reloc)
- {
- bytecode_align *align = (bytecode_align *)bc->contents;
- unsigned long len;
- unsigned long boundary =
- yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0));
- if (boundary == 0)
- return 0;
- else {
- unsigned long end = bc->offset;
- if (bc->offset & (boundary-1))
- end = (bc->offset & ~(boundary-1)) + boundary;
- len = end - bc->offset;
- if (len == 0)
- return 0;
- if (align->maxskip) {
- unsigned long maxskip =
- yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0));
- if (len > maxskip)
- return 0;
- }
- }
- if (align->fill) {
- unsigned long v;
- v = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->fill, 0));
- memset(*bufp, (int)v, len);
- *bufp += len;
- } else if (align->code_fill) {
- unsigned long maxlen = 15;
- while (!align->code_fill[maxlen] && maxlen>0)
- maxlen--;
- if (maxlen == 0) {
- yasm_error_set(YASM_ERROR_GENERAL,
- N_("could not find any code alignment size"));
- return 1;
- }
- /* Fill with maximum code fill as much as possible */
- while (len > maxlen) {
- memcpy(*bufp, align->code_fill[maxlen], maxlen);
- *bufp += maxlen;
- len -= maxlen;
- }
- if (!align->code_fill[len]) {
- yasm_error_set(YASM_ERROR_VALUE,
- N_("invalid alignment size %d"), len);
- return 1;
- }
- /* Handle rest of code fill */
- memcpy(*bufp, align->code_fill[len], len);
- *bufp += len;
- } else {
- /* Just fill with 0 */
- memset(*bufp, 0, len);
- *bufp += len;
- }
- return 0;
- }
- yasm_bytecode *
- yasm_bc_create_align(yasm_expr *boundary, yasm_expr *fill,
- yasm_expr *maxskip, const unsigned char **code_fill,
- unsigned long line)
- {
- bytecode_align *align = yasm_xmalloc(sizeof(bytecode_align));
- align->boundary = boundary;
- align->fill = fill;
- align->maxskip = maxskip;
- align->code_fill = code_fill;
- return yasm_bc_create_common(&bc_align_callback, align, line);
- }
|