1 /* 2 * Align 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 "intnum.h" 34 #include "expr.h" 35 36 #include "bytecode.h" 37 38 39 typedef struct bytecode_align { 40 /*@only@*/ yasm_expr *boundary; /* alignment boundary */ 41 42 /* What to fill intervening locations with, NULL if using code_fill */ 43 /*@only@*/ /*@null@*/ yasm_expr *fill; 44 45 /* Maximum number of bytes to skip, NULL if no maximum. */ 46 /*@only@*/ /*@null@*/ yasm_expr *maxskip; 47 48 /* Code fill, NULL if using 0 fill */ 49 /*@null@*/ const unsigned char **code_fill; 50 } bytecode_align; 51 52 static void bc_align_destroy(void *contents); 53 static void bc_align_print(const void *contents, FILE *f, int indent_level); 54 static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); 55 static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, 56 void *add_span_data); 57 static int bc_align_expand(yasm_bytecode *bc, int span, long old_val, 58 long new_val, /*@out@*/ long *neg_thres, 59 /*@out@*/ long *pos_thres); 60 static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, 61 unsigned char *bufstart, void *d, 62 yasm_output_value_func output_value, 63 /*@null@*/ yasm_output_reloc_func output_reloc); 64 65 static const yasm_bytecode_callback bc_align_callback = { 66 bc_align_destroy, 67 bc_align_print, 68 bc_align_finalize, 69 NULL, 70 bc_align_calc_len, 71 bc_align_expand, 72 bc_align_tobytes, 73 YASM_BC_SPECIAL_OFFSET 74 }; 75 76 77 static void 78 bc_align_destroy(void *contents) 79 { 80 bytecode_align *align = (bytecode_align *)contents; 81 if (align->boundary) 82 yasm_expr_destroy(align->boundary); 83 if (align->fill) 84 yasm_expr_destroy(align->fill); 85 if (align->maxskip) 86 yasm_expr_destroy(align->maxskip); 87 yasm_xfree(contents); 88 } 89 90 static void 91 bc_align_print(const void *contents, FILE *f, int indent_level) 92 { 93 const bytecode_align *align = (const bytecode_align *)contents; 94 fprintf(f, "%*s_Align_\n", indent_level, ""); 95 fprintf(f, "%*sBoundary=", indent_level, ""); 96 yasm_expr_print(align->boundary, f); 97 fprintf(f, "\n%*sFill=", indent_level, ""); 98 yasm_expr_print(align->fill, f); 99 fprintf(f, "\n%*sMax Skip=", indent_level, ""); 100 yasm_expr_print(align->maxskip, f); 101 fprintf(f, "\n"); 102 } 103 104 static void 105 bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) 106 { 107 bytecode_align *align = (bytecode_align *)bc->contents; 108 if (!yasm_expr_get_intnum(&align->boundary, 0)) 109 yasm_error_set(YASM_ERROR_NOT_CONSTANT, 110 N_("align boundary must be a constant")); 111 if (align->fill && !yasm_expr_get_intnum(&align->fill, 0)) 112 yasm_error_set(YASM_ERROR_NOT_CONSTANT, 113 N_("align fill must be a constant")); 114 if (align->maxskip && !yasm_expr_get_intnum(&align->maxskip, 0)) 115 yasm_error_set(YASM_ERROR_NOT_CONSTANT, 116 N_("align maximum skip must be a constant")); 117 } 118 119 static int 120 bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, 121 void *add_span_data) 122 { 123 long neg_thres = 0; 124 long pos_thres = 0; 125 126 if (bc_align_expand(bc, 0, 0, (long)bc->offset, &neg_thres, 127 &pos_thres) < 0) 128 return -1; 129 130 return 0; 131 } 132 133 static int 134 bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val, 135 /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres) 136 { 137 bytecode_align *align = (bytecode_align *)bc->contents; 138 unsigned long end; 139 unsigned long boundary = 140 yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0)); 141 142 if (boundary == 0) { 143 bc->len = 0; 144 *pos_thres = new_val; 145 return 0; 146 } 147 148 end = (unsigned long)new_val; 149 if ((unsigned long)new_val & (boundary-1)) 150 end = ((unsigned long)new_val & ~(boundary-1)) + boundary; 151 152 *pos_thres = (long)end; 153 bc->len = end - (unsigned long)new_val; 154 155 if (align->maxskip) { 156 unsigned long maxskip = 157 yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0)); 158 if (bc->len > maxskip) { 159 *pos_thres = (long)end-maxskip-1; 160 bc->len = 0; 161 } 162 } 163 return 1; 164 } 165 166 static int 167 bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, 168 unsigned char *bufstart, void *d, 169 yasm_output_value_func output_value, 170 /*@unused@*/ yasm_output_reloc_func output_reloc) 171 { 172 bytecode_align *align = (bytecode_align *)bc->contents; 173 unsigned long len; 174 unsigned long boundary = 175 yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, 0)); 176 177 if (boundary == 0) 178 return 0; 179 else { 180 unsigned long end = bc->offset; 181 if (bc->offset & (boundary-1)) 182 end = (bc->offset & ~(boundary-1)) + boundary; 183 len = end - bc->offset; 184 if (len == 0) 185 return 0; 186 if (align->maxskip) { 187 unsigned long maxskip = 188 yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, 0)); 189 if (len > maxskip) 190 return 0; 191 } 192 } 193 194 if (align->fill) { 195 unsigned long v; 196 v = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->fill, 0)); 197 memset(*bufp, (int)v, len); 198 *bufp += len; 199 } else if (align->code_fill) { 200 unsigned long maxlen = 15; 201 while (!align->code_fill[maxlen] && maxlen>0) 202 maxlen--; 203 if (maxlen == 0) { 204 yasm_error_set(YASM_ERROR_GENERAL, 205 N_("could not find any code alignment size")); 206 return 1; 207 } 208 209 /* Fill with maximum code fill as much as possible */ 210 while (len > maxlen) { 211 memcpy(*bufp, align->code_fill[maxlen], maxlen); 212 *bufp += maxlen; 213 len -= maxlen; 214 } 215 216 if (!align->code_fill[len]) { 217 yasm_error_set(YASM_ERROR_VALUE, 218 N_("invalid alignment size %d"), len); 219 return 1; 220 } 221 /* Handle rest of code fill */ 222 memcpy(*bufp, align->code_fill[len], len); 223 *bufp += len; 224 } else { 225 /* Just fill with 0 */ 226 memset(*bufp, 0, len); 227 *bufp += len; 228 } 229 return 0; 230 } 231 232 yasm_bytecode * 233 yasm_bc_create_align(yasm_expr *boundary, yasm_expr *fill, 234 yasm_expr *maxskip, const unsigned char **code_fill, 235 unsigned long line) 236 { 237 bytecode_align *align = yasm_xmalloc(sizeof(bytecode_align)); 238 239 align->boundary = boundary; 240 align->fill = fill; 241 align->maxskip = maxskip; 242 align->code_fill = code_fill; 243 244 return yasm_bc_create_common(&bc_align_callback, align, line); 245 } 246