bc-incbin.c 8.6 KB

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