1 /* 2 * Incbin bytecode 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 "linemap.h" 33 34 #include "errwarn.h" 35 #include "intnum.h" 36 #include "expr.h" 37 #include "value.h" 38 39 #include "bytecode.h" 40 41 #include "file.h" 42 43 44 typedef struct bytecode_incbin { 45 /*@only@*/ char *filename; /* file to include data from */ 46 const char *from; /* filename of what contained incbin */ 47 48 /* starting offset to read from (NULL=0) */ 49 /*@only@*/ /*@null@*/ yasm_expr *start; 50 51 /* maximum number of bytes to read (NULL=no limit) */ 52 /*@only@*/ /*@null@*/ yasm_expr *maxlen; 53 } bytecode_incbin; 54 55 static void bc_incbin_destroy(void *contents); 56 static void bc_incbin_print(const void *contents, FILE *f, int indent_level); 57 static void bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc); 58 static int bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, 59 void *add_span_data); 60 static int bc_incbin_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_incbin_callback = { 66 bc_incbin_destroy, 67 bc_incbin_print, 68 bc_incbin_finalize, 69 NULL, 70 bc_incbin_calc_len, 71 yasm_bc_expand_common, 72 bc_incbin_tobytes, 73 0 74 }; 75 76 77 static void 78 bc_incbin_destroy(void *contents) 79 { 80 bytecode_incbin *incbin = (bytecode_incbin *)contents; 81 yasm_xfree(incbin->filename); 82 yasm_expr_destroy(incbin->start); 83 yasm_expr_destroy(incbin->maxlen); 84 yasm_xfree(contents); 85 } 86 87 static void 88 bc_incbin_print(const void *contents, FILE *f, int indent_level) 89 { 90 const bytecode_incbin *incbin = (const bytecode_incbin *)contents; 91 fprintf(f, "%*s_IncBin_\n", indent_level, ""); 92 fprintf(f, "%*sFilename=`%s'\n", indent_level, "", 93 incbin->filename); 94 fprintf(f, "%*sStart=", indent_level, ""); 95 if (!incbin->start) 96 fprintf(f, "nil (0)"); 97 else 98 yasm_expr_print(incbin->start, f); 99 fprintf(f, "%*sMax Len=", indent_level, ""); 100 if (!incbin->maxlen) 101 fprintf(f, "nil (unlimited)"); 102 else 103 yasm_expr_print(incbin->maxlen, f); 104 fprintf(f, "\n"); 105 } 106 107 static void 108 bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc) 109 { 110 bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; 111 yasm_value val; 112 113 if (yasm_value_finalize_expr(&val, incbin->start, prev_bc, 0)) 114 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 115 N_("start expression too complex")); 116 else if (val.rel) 117 yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, 118 N_("start expression not absolute")); 119 incbin->start = val.abs; 120 121 if (yasm_value_finalize_expr(&val, incbin->maxlen, prev_bc, 0)) 122 yasm_error_set(YASM_ERROR_TOO_COMPLEX, 123 N_("maximum length expression too complex")); 124 else if (val.rel) 125 yasm_error_set(YASM_ERROR_NOT_ABSOLUTE, 126 N_("maximum length expression not absolute")); 127 incbin->maxlen = val.abs; 128 } 129 130 static int 131 bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, 132 void *add_span_data) 133 { 134 bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; 135 FILE *f; 136 /*@dependent@*/ /*@null@*/ const yasm_intnum *num; 137 unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen; 138 139 /* Try to convert start to integer value */ 140 if (incbin->start) { 141 num = yasm_expr_get_intnum(&incbin->start, 0); 142 if (num) 143 start = yasm_intnum_get_uint(num); 144 if (!num) { 145 /* FIXME */ 146 yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, 147 N_("incbin does not yet understand non-constant")); 148 return -1; 149 } 150 } 151 152 /* Try to convert maxlen to integer value */ 153 if (incbin->maxlen) { 154 num = yasm_expr_get_intnum(&incbin->maxlen, 0); 155 if (num) 156 maxlen = yasm_intnum_get_uint(num); 157 if (!num) { 158 /* FIXME */ 159 yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED, 160 N_("incbin does not yet understand non-constant")); 161 return -1; 162 } 163 } 164 165 /* Open file and determine its length */ 166 f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL); 167 if (!f) { 168 yasm_error_set(YASM_ERROR_IO, 169 N_("`incbin': unable to open file `%s'"), 170 incbin->filename); 171 return -1; 172 } 173 if (fseek(f, 0L, SEEK_END) < 0) { 174 yasm_error_set(YASM_ERROR_IO, 175 N_("`incbin': unable to seek on file `%s'"), 176 incbin->filename); 177 return -1; 178 } 179 flen = (unsigned long)ftell(f); 180 fclose(f); 181 182 /* Compute length of incbin from start, maxlen, and len */ 183 if (start > flen) { 184 yasm_warn_set(YASM_WARN_GENERAL, 185 N_("`incbin': start past end of file `%s'"), 186 incbin->filename); 187 start = flen; 188 } 189 flen -= start; 190 if (incbin->maxlen) 191 if (maxlen < flen) 192 flen = maxlen; 193 bc->len += flen; 194 return 0; 195 } 196 197 static int 198 bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, 199 unsigned char *bufstart, void *d, 200 yasm_output_value_func output_value, 201 /*@unused@*/ yasm_output_reloc_func output_reloc) 202 { 203 bytecode_incbin *incbin = (bytecode_incbin *)bc->contents; 204 FILE *f; 205 /*@dependent@*/ /*@null@*/ const yasm_intnum *num; 206 unsigned long start = 0; 207 208 /* Convert start to integer value */ 209 if (incbin->start) { 210 num = yasm_expr_get_intnum(&incbin->start, 0); 211 if (!num) 212 yasm_internal_error( 213 N_("could not determine start in bc_tobytes_incbin")); 214 start = yasm_intnum_get_uint(num); 215 } 216 217 /* Open file */ 218 f = yasm_fopen_include(incbin->filename, incbin->from, "rb", NULL); 219 if (!f) { 220 yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to open file `%s'"), 221 incbin->filename); 222 return 1; 223 } 224 225 /* Seek to start of data */ 226 if (fseek(f, (long)start, SEEK_SET) < 0) { 227 yasm_error_set(YASM_ERROR_IO, 228 N_("`incbin': unable to seek on file `%s'"), 229 incbin->filename); 230 fclose(f); 231 return 1; 232 } 233 234 /* Read len bytes */ 235 if (fread(*bufp, 1, (size_t)bc->len, f) < (size_t)bc->len) { 236 yasm_error_set(YASM_ERROR_IO, 237 N_("`incbin': unable to read %lu bytes from file `%s'"), 238 bc->len, incbin->filename); 239 fclose(f); 240 return 1; 241 } 242 243 *bufp += bc->len; 244 fclose(f); 245 return 0; 246 } 247 248 yasm_bytecode * 249 yasm_bc_create_incbin(char *filename, yasm_expr *start, yasm_expr *maxlen, 250 yasm_linemap *linemap, unsigned long line) 251 { 252 bytecode_incbin *incbin = yasm_xmalloc(sizeof(bytecode_incbin)); 253 unsigned long xline; 254 255 /* Find from filename based on line number */ 256 yasm_linemap_lookup(linemap, line, &incbin->from, &xline); 257 258 /*@-mustfree@*/ 259 incbin->filename = filename; 260 incbin->start = start; 261 incbin->maxlen = maxlen; 262 /*@=mustfree@*/ 263 264 return yasm_bc_create_common(&bc_incbin_callback, incbin, line); 265 } 266