• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Bytecode utility functions
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 "errwarn.h"
33 #include "intnum.h"
34 #include "expr.h"
35 #include "value.h"
36 #include "symrec.h"
37 
38 #include "bytecode.h"
39 
40 
41 void
yasm_bc_set_multiple(yasm_bytecode * bc,yasm_expr * e)42 yasm_bc_set_multiple(yasm_bytecode *bc, yasm_expr *e)
43 {
44     if (bc->multiple)
45         bc->multiple = yasm_expr_create_tree(bc->multiple, YASM_EXPR_MUL, e,
46                                              e->line);
47     else
48         bc->multiple = e;
49 }
50 
51 void
yasm_bc_finalize_common(yasm_bytecode * bc,yasm_bytecode * prev_bc)52 yasm_bc_finalize_common(yasm_bytecode *bc, yasm_bytecode *prev_bc)
53 {
54 }
55 
56 int
yasm_bc_calc_len_common(yasm_bytecode * bc,yasm_bc_add_span_func add_span,void * add_span_data)57 yasm_bc_calc_len_common(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
58                         void *add_span_data)
59 {
60     yasm_internal_error(N_("bytecode length cannot be calculated"));
61     /*@unreached@*/
62     return 0;
63 }
64 
65 int
yasm_bc_expand_common(yasm_bytecode * bc,int span,long old_val,long new_val,long * neg_thres,long * pos_thres)66 yasm_bc_expand_common(yasm_bytecode *bc, int span, long old_val, long new_val,
67                       /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
68 {
69     yasm_internal_error(N_("bytecode does not have any dependent spans"));
70     /*@unreached@*/
71     return 0;
72 }
73 
74 int
yasm_bc_tobytes_common(yasm_bytecode * bc,unsigned char ** buf,unsigned char * bufstart,void * d,yasm_output_value_func output_value,yasm_output_reloc_func output_reloc)75 yasm_bc_tobytes_common(yasm_bytecode *bc, unsigned char **buf,
76                        unsigned char *bufstart, void *d,
77                        yasm_output_value_func output_value,
78                        /*@null@*/ yasm_output_reloc_func output_reloc)
79 {
80     yasm_internal_error(N_("bytecode cannot be converted to bytes"));
81     /*@unreached@*/
82     return 0;
83 }
84 
85 void
yasm_bc_transform(yasm_bytecode * bc,const yasm_bytecode_callback * callback,void * contents)86 yasm_bc_transform(yasm_bytecode *bc, const yasm_bytecode_callback *callback,
87                   void *contents)
88 {
89     if (bc->callback)
90         bc->callback->destroy(bc->contents);
91     bc->callback = callback;
92     bc->contents = contents;
93 }
94 
95 yasm_bytecode *
yasm_bc_create_common(const yasm_bytecode_callback * callback,void * contents,unsigned long line)96 yasm_bc_create_common(const yasm_bytecode_callback *callback, void *contents,
97                       unsigned long line)
98 {
99     yasm_bytecode *bc = yasm_xmalloc(sizeof(yasm_bytecode));
100 
101     bc->callback = callback;
102     bc->section = NULL;
103     bc->multiple = (yasm_expr *)NULL;
104     bc->len = 0;
105     bc->mult_int = 1;
106     bc->line = line;
107     bc->offset = ~0UL;  /* obviously incorrect / uninitialized value */
108     bc->symrecs = NULL;
109     bc->contents = contents;
110 
111     return bc;
112 }
113 
114 yasm_section *
yasm_bc_get_section(yasm_bytecode * bc)115 yasm_bc_get_section(yasm_bytecode *bc)
116 {
117     return bc->section;
118 }
119 
120 void
yasm_bc__add_symrec(yasm_bytecode * bc,yasm_symrec * sym)121 yasm_bc__add_symrec(yasm_bytecode *bc, yasm_symrec *sym)
122 {
123     if (!bc->symrecs) {
124         bc->symrecs = yasm_xmalloc(2*sizeof(yasm_symrec *));
125         bc->symrecs[0] = sym;
126         bc->symrecs[1] = NULL;
127     } else {
128         /* Very inefficient implementation for large numbers of symbols.  But
129          * that would be very unusual, so use the simple algorithm instead.
130          */
131         size_t count = 1;
132         while (bc->symrecs[count])
133             count++;
134         bc->symrecs = yasm_xrealloc(bc->symrecs,
135                                     (count+2)*sizeof(yasm_symrec *));
136         bc->symrecs[count] = sym;
137         bc->symrecs[count+1] = NULL;
138     }
139 }
140 
141 void
yasm_bc_destroy(yasm_bytecode * bc)142 yasm_bc_destroy(yasm_bytecode *bc)
143 {
144     if (!bc)
145         return;
146 
147     if (bc->callback)
148         bc->callback->destroy(bc->contents);
149     yasm_expr_destroy(bc->multiple);
150     if (bc->symrecs)
151         yasm_xfree(bc->symrecs);
152     yasm_xfree(bc);
153 }
154 
155 void
yasm_bc_print(const yasm_bytecode * bc,FILE * f,int indent_level)156 yasm_bc_print(const yasm_bytecode *bc, FILE *f, int indent_level)
157 {
158     if (!bc->callback)
159         fprintf(f, "%*s_Empty_\n", indent_level, "");
160     else
161         bc->callback->print(bc->contents, f, indent_level);
162     fprintf(f, "%*sMultiple=", indent_level, "");
163     if (!bc->multiple)
164         fprintf(f, "nil (1)");
165     else
166         yasm_expr_print(bc->multiple, f);
167     fprintf(f, "\n%*sLength=%lu\n", indent_level, "", bc->len);
168     fprintf(f, "%*sLine Index=%lu\n", indent_level, "", bc->line);
169     fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset);
170 }
171 
172 void
yasm_bc_finalize(yasm_bytecode * bc,yasm_bytecode * prev_bc)173 yasm_bc_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
174 {
175     if (bc->callback)
176         bc->callback->finalize(bc, prev_bc);
177     if (bc->multiple) {
178         yasm_value val;
179 
180         if (yasm_value_finalize_expr(&val, bc->multiple, prev_bc, 0))
181             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
182                            N_("multiple expression too complex"));
183         else if (val.rel)
184             yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
185                            N_("multiple expression not absolute"));
186         /* Finalize creates NULL output if value=0, but bc->multiple is NULL
187          * if value=1 (this difference is to make the common case small).
188          * However, this means we need to set bc->multiple explicitly to 0
189          * here if val.abs is NULL.
190          */
191         if (val.abs)
192             bc->multiple = val.abs;
193         else
194             bc->multiple = yasm_expr_create_ident(
195                 yasm_expr_int(yasm_intnum_create_uint(0)), bc->line);
196     }
197 }
198 
199 /*@null@*/ yasm_intnum *
yasm_calc_bc_dist(yasm_bytecode * precbc1,yasm_bytecode * precbc2)200 yasm_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2)
201 {
202     unsigned long dist2, dist1;
203     yasm_intnum *intn;
204 
205     if (precbc1->section != precbc2->section)
206         return NULL;
207 
208     dist1 = yasm_bc_next_offset(precbc1);
209     dist2 = yasm_bc_next_offset(precbc2);
210     if (dist2 < dist1) {
211         intn = yasm_intnum_create_uint(dist1 - dist2);
212         yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
213         return intn;
214     }
215     dist2 -= dist1;
216     return yasm_intnum_create_uint(dist2);
217 }
218 
219 unsigned long
yasm_bc_next_offset(yasm_bytecode * precbc)220 yasm_bc_next_offset(yasm_bytecode *precbc)
221 {
222     return precbc->offset + precbc->len*precbc->mult_int;
223 }
224 
225 int
yasm_bc_elem_size(yasm_bytecode * bc)226 yasm_bc_elem_size(yasm_bytecode *bc)
227 {
228     if (!bc->callback) {
229         yasm_internal_error(N_("got empty bytecode in yasm_bc_elem_size"));
230         return 0;
231     } else if (!bc->callback->elem_size)
232         return 0;
233     else
234         return bc->callback->elem_size(bc);
235 }
236 
237 int
yasm_bc_calc_len(yasm_bytecode * bc,yasm_bc_add_span_func add_span,void * add_span_data)238 yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
239                  void *add_span_data)
240 {
241     int retval = 0;
242 
243     bc->len = 0;
244 
245     if (!bc->callback)
246         yasm_internal_error(N_("got empty bytecode in yasm_bc_calc_len"));
247     else
248         retval = bc->callback->calc_len(bc, add_span, add_span_data);
249 
250     /* Check for multiples */
251     bc->mult_int = 1;
252     if (bc->multiple) {
253         /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
254 
255         num = yasm_expr_get_intnum(&bc->multiple, 0);
256         if (num) {
257             if (yasm_intnum_sign(num) < 0) {
258                 yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative"));
259                 retval = -1;
260             } else
261                 bc->mult_int = yasm_intnum_get_int(num);
262         } else {
263             if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) {
264                 yasm_error_set(YASM_ERROR_VALUE,
265                     N_("expression must not contain floating point value"));
266                 retval = -1;
267             } else {
268                 yasm_value value;
269                 yasm_value_initialize(&value, bc->multiple, 0);
270                 add_span(add_span_data, bc, 0, &value, 0, 0);
271                 bc->mult_int = 0;   /* assume 0 to start */
272             }
273         }
274     }
275 
276     /* If we got an error somewhere along the line, clear out any calc len */
277     if (retval < 0)
278         bc->len = 0;
279 
280     return retval;
281 }
282 
283 int
yasm_bc_expand(yasm_bytecode * bc,int span,long old_val,long new_val,long * neg_thres,long * pos_thres)284 yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
285                /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
286 {
287     if (span == 0) {
288         bc->mult_int = new_val;
289         return 1;
290     }
291     if (!bc->callback) {
292         yasm_internal_error(N_("got empty bytecode in yasm_bc_expand"));
293         /*@unreached@*/
294         return -1;
295     } else
296         return bc->callback->expand(bc, span, old_val, new_val, neg_thres,
297                                     pos_thres);
298 }
299 
300 /*@null@*/ /*@only@*/ unsigned char *
yasm_bc_tobytes(yasm_bytecode * bc,unsigned char * buf,unsigned long * bufsize,int * gap,void * d,yasm_output_value_func output_value,yasm_output_reloc_func output_reloc)301 yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
302                 /*@out@*/ int *gap, void *d,
303                 yasm_output_value_func output_value,
304                 /*@null@*/ yasm_output_reloc_func output_reloc)
305     /*@sets *buf@*/
306 {
307     /*@only@*/ /*@null@*/ unsigned char *mybuf = NULL;
308     unsigned char *bufstart;
309     unsigned char *origbuf, *destbuf;
310     long i;
311     int error = 0;
312 
313     long mult;
314     if (yasm_bc_get_multiple(bc, &mult, 1) || mult == 0) {
315         *bufsize = 0;
316         return NULL;
317     }
318     bc->mult_int = mult;
319 
320     /* special case for reserve bytecodes */
321     if (bc->callback->special == YASM_BC_SPECIAL_RESERVE) {
322         *bufsize = bc->len*bc->mult_int;
323         *gap = 1;
324         return NULL;    /* we didn't allocate a buffer */
325     }
326     *gap = 0;
327 
328     if (*bufsize < bc->len*bc->mult_int) {
329         mybuf = yasm_xmalloc(bc->len*bc->mult_int);
330         destbuf = mybuf;
331     } else
332         destbuf = buf;
333     bufstart = destbuf;
334 
335     *bufsize = bc->len*bc->mult_int;
336 
337     if (!bc->callback)
338         yasm_internal_error(N_("got empty bytecode in bc_tobytes"));
339     else for (i=0; i<bc->mult_int; i++) {
340         origbuf = destbuf;
341         error = bc->callback->tobytes(bc, &destbuf, bufstart, d, output_value,
342                                       output_reloc);
343 
344         if (!error && ((unsigned long)(destbuf - origbuf) != bc->len))
345             yasm_internal_error(
346                 N_("written length does not match optimized length"));
347     }
348 
349     return mybuf;
350 }
351 
352 int
yasm_bc_get_multiple(yasm_bytecode * bc,long * multiple,int calc_bc_dist)353 yasm_bc_get_multiple(yasm_bytecode *bc, long *multiple, int calc_bc_dist)
354 {
355     /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
356 
357     *multiple = 1;
358     if (bc->multiple) {
359         num = yasm_expr_get_intnum(&bc->multiple, calc_bc_dist);
360         if (!num) {
361             yasm_error_set(YASM_ERROR_VALUE,
362                            N_("could not determine multiple"));
363             return 1;
364         }
365         if (yasm_intnum_sign(num) < 0) {
366             yasm_error_set(YASM_ERROR_VALUE, N_("multiple is negative"));
367             return 1;
368         }
369         *multiple = yasm_intnum_get_int(num);
370     }
371     return 0;
372 }
373 
374 const yasm_expr *
yasm_bc_get_multiple_expr(const yasm_bytecode * bc)375 yasm_bc_get_multiple_expr(const yasm_bytecode *bc)
376 {
377     return bc->multiple;
378 }
379 
380 yasm_insn *
yasm_bc_get_insn(yasm_bytecode * bc)381 yasm_bc_get_insn(yasm_bytecode *bc)
382 {
383     if (bc->callback->special != YASM_BC_SPECIAL_INSN)
384         return NULL;
385     return (yasm_insn *)bc->contents;
386 }
387