1 /*
2  * Value handling
3  *
4  *  Copyright (C) 2006-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 #include "bitvect.h"
32 
33 #include "errwarn.h"
34 #include "intnum.h"
35 #include "floatnum.h"
36 #include "expr.h"
37 #include "value.h"
38 #include "symrec.h"
39 
40 #include "bytecode.h"
41 #include "section.h"
42 
43 #include "arch.h"
44 
45 
46 void
yasm_value_initialize(yasm_value * value,yasm_expr * e,unsigned int size)47 yasm_value_initialize(/*@out@*/ yasm_value *value,
48                       /*@null@*/ /*@kept@*/ yasm_expr *e, unsigned int size)
49 {
50     value->abs = e;
51     value->rel = NULL;
52     value->wrt = NULL;
53     value->seg_of = 0;
54     value->rshift = 0;
55     value->curpos_rel = 0;
56     value->ip_rel = 0;
57     value->jump_target = 0;
58     value->section_rel = 0;
59     value->no_warn = 0;
60     value->sign = 0;
61     value->size = size;
62 }
63 
64 void
yasm_value_init_sym(yasm_value * value,yasm_symrec * sym,unsigned int size)65 yasm_value_init_sym(/*@out@*/ yasm_value *value, /*@null@*/ yasm_symrec *sym,
66                     unsigned int size)
67 {
68     value->abs = NULL;
69     value->rel = sym;
70     value->wrt = NULL;
71     value->seg_of = 0;
72     value->rshift = 0;
73     value->curpos_rel = 0;
74     value->ip_rel = 0;
75     value->jump_target = 0;
76     value->section_rel = 0;
77     value->no_warn = 0;
78     value->sign = 0;
79     value->size = size;
80 }
81 
82 void
yasm_value_init_copy(yasm_value * value,const yasm_value * orig)83 yasm_value_init_copy(yasm_value *value, const yasm_value *orig)
84 {
85     value->abs = orig->abs ? yasm_expr_copy(orig->abs) : NULL;
86     value->rel = orig->rel;
87     value->wrt = orig->wrt;
88     value->seg_of = orig->seg_of;
89     value->rshift = orig->rshift;
90     value->curpos_rel = orig->curpos_rel;
91     value->ip_rel = orig->ip_rel;
92     value->jump_target = orig->jump_target;
93     value->section_rel = orig->section_rel;
94     value->no_warn = orig->no_warn;
95     value->sign = orig->sign;
96     value->size = orig->size;
97 }
98 
99 void
yasm_value_delete(yasm_value * value)100 yasm_value_delete(yasm_value *value)
101 {
102     if (value->abs)
103         yasm_expr_destroy(value->abs);
104     value->abs = NULL;
105     value->rel = NULL;
106 }
107 
108 void
yasm_value_set_curpos_rel(yasm_value * value,yasm_bytecode * bc,unsigned int ip_rel)109 yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc,
110                           unsigned int ip_rel)
111 {
112     value->curpos_rel = 1;
113     value->ip_rel = ip_rel;
114     /* In order for us to correctly output curpos-relative values, we must
115      * have a relative portion of the value.  If one doesn't exist, point
116      * to a custom absolute symbol.
117      */
118     if (!value->rel) {
119         yasm_object *object = yasm_section_get_object(yasm_bc_get_section(bc));
120         value->rel = yasm_symtab_abs_sym(object->symtab);
121     }
122 }
123 
124 static int
value_finalize_scan(yasm_value * value,yasm_expr * e,yasm_bytecode * expr_precbc,int ssym_not_ok)125 value_finalize_scan(yasm_value *value, yasm_expr *e,
126                     /*@null@*/ yasm_bytecode *expr_precbc, int ssym_not_ok)
127 {
128     int i;
129     /*@dependent@*/ yasm_section *sect;
130     /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
131 
132     unsigned long shamt;    /* for SHR */
133 
134     /* Yes, this has a maximum upper bound on 32 terms, based on an
135      * "insane number of terms" (and ease of implementation) WAG.
136      * The right way to do this would be a stack-based alloca, but that's
137      * not ISO C.  We really don't want to malloc here as this function is
138      * hit a lot!
139      *
140      * This is a bitmask to keep things small, as this is a recursive
141      * routine and we don't want to eat up stack space.
142      */
143     unsigned long used;     /* for ADD */
144 
145     /* Thanks to this running after a simplify, we don't need to iterate
146      * down through IDENTs or handle SUB.
147      *
148      * We scan for a single symrec, gathering info along the way.  After
149      * we've found the symrec, we keep scanning but error if we find
150      * another one.  We pull out the single symrec and any legal operations
151      * performed on it.
152      *
153      * Also, if we find a float anywhere, we don't allow mixing of a single
154      * symrec with it.
155      */
156     switch (e->op) {
157         case YASM_EXPR_ADD:
158             /* Okay for single symrec anywhere in expr.
159              * Check for single symrec anywhere.
160              * Handle symrec-symrec by checking for (-1*symrec)
161              * and symrec term pairs (where both symrecs are in the same
162              * segment).
163              */
164             if (e->numterms > 32)
165                 yasm__fatal(N_("expression on line %d has too many add terms;"
166                                " internal limit of 32"), e->line);
167 
168             used = 0;
169 
170             for (i=0; i<e->numterms; i++) {
171                 int j;
172                 yasm_expr *sube;
173                 yasm_intnum *intn;
174                 yasm_symrec *sym;
175                 /*@dependent@*/ yasm_section *sect2;
176                 /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
177 
178                 /* First look for an (-1*symrec) term */
179                 if (e->terms[i].type != YASM_EXPR_EXPR)
180                     continue;
181                 sube = e->terms[i].data.expn;
182 
183                 if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) {
184                     /* recurse instead */
185                     if (value_finalize_scan(value, sube, expr_precbc,
186                                             ssym_not_ok))
187                         return 1;
188                     continue;
189                 }
190 
191                 if (sube->terms[0].type == YASM_EXPR_INT &&
192                     sube->terms[1].type == YASM_EXPR_SYM) {
193                     intn = sube->terms[0].data.intn;
194                     sym = sube->terms[1].data.sym;
195                 } else if (sube->terms[0].type == YASM_EXPR_SYM &&
196                            sube->terms[1].type == YASM_EXPR_INT) {
197                     sym = sube->terms[0].data.sym;
198                     intn = sube->terms[1].data.intn;
199                 } else {
200                     if (value_finalize_scan(value, sube, expr_precbc,
201                                             ssym_not_ok))
202                         return 1;
203                     continue;
204                 }
205 
206                 if (!yasm_intnum_is_neg1(intn)) {
207                     if (value_finalize_scan(value, sube, expr_precbc,
208                                             ssym_not_ok))
209                         return 1;
210                     continue;
211                 }
212 
213                 /* Look for the same symrec term; even if both are external,
214                  * they should cancel out.
215                  */
216                 for (j=0; j<e->numterms; j++) {
217                     if (e->terms[j].type == YASM_EXPR_SYM
218                         && e->terms[j].data.sym == sym
219                         && (used & (1<<j)) == 0) {
220                         /* Mark as used */
221                         used |= 1<<j;
222 
223                         /* Replace both symrec portions with 0 */
224                         yasm_expr_destroy(sube);
225                         e->terms[i].type = YASM_EXPR_INT;
226                         e->terms[i].data.intn = yasm_intnum_create_uint(0);
227                         e->terms[j].type = YASM_EXPR_INT;
228                         e->terms[j].data.intn = yasm_intnum_create_uint(0);
229 
230                         break;  /* stop looking */
231                     }
232                 }
233                 if (j != e->numterms)
234                     continue;
235 
236                 if (!yasm_symrec_get_label(sym, &precbc)) {
237                     if (value_finalize_scan(value, sube, expr_precbc,
238                                             ssym_not_ok))
239                         return 1;
240                     continue;
241                 }
242                 sect2 = yasm_bc_get_section(precbc);
243 
244                 /* Now look for a unused symrec term in the same segment */
245                 for (j=0; j<e->numterms; j++) {
246                     if (e->terms[j].type == YASM_EXPR_SYM
247                         && yasm_symrec_get_label(e->terms[j].data.sym,
248                                                  &precbc2)
249                         && (sect = yasm_bc_get_section(precbc2))
250                         && sect == sect2
251                         && (used & (1<<j)) == 0) {
252                         /* Mark as used */
253                         used |= 1<<j;
254                         break;  /* stop looking */
255                     }
256                 }
257 
258                 /* We didn't match in the same segment.  If the
259                  * -1*symrec is actually -1*curpos, we can match
260                  * unused symrec terms in other segments and generate
261                  * a curpos-relative reloc.
262                  *
263                  * Similarly, handle -1*symrec in other segment via the
264                  * following transformation:
265                  * other-this = (other-.)+(.-this)
266                  * We can only do this transformation if "this" is in
267                  * this expr's segment.
268                  *
269                  * Don't do this if we've already become curpos-relative.
270                  * The unmatched symrec will be caught below.
271                  */
272                 if (j == e->numterms && !value->curpos_rel
273                     && (yasm_symrec_is_curpos(sym)
274                         || (expr_precbc
275                             && sect2 == yasm_bc_get_section(expr_precbc)))) {
276                     for (j=0; j<e->numterms; j++) {
277                         if (e->terms[j].type == YASM_EXPR_SYM
278                             && !yasm_symrec_get_equ(e->terms[j].data.sym)
279                             && !yasm_symrec_is_special(e->terms[j].data.sym)
280                             && (used & (1<<j)) == 0) {
281                             /* Mark as used */
282                             used |= 1<<j;
283                             /* Mark value as curpos-relative */
284                             if (value->rel || ssym_not_ok)
285                                 return 1;
286                             value->rel = e->terms[j].data.sym;
287                             value->curpos_rel = 1;
288                             if (yasm_symrec_is_curpos(sym)) {
289                                 /* Replace both symrec portions with 0 */
290                                 yasm_expr_destroy(sube);
291                                 e->terms[i].type = YASM_EXPR_INT;
292                                 e->terms[i].data.intn =
293                                     yasm_intnum_create_uint(0);
294                                 e->terms[j].type = YASM_EXPR_INT;
295                                 e->terms[j].data.intn =
296                                     yasm_intnum_create_uint(0);
297                             } else {
298                                 /* Replace positive portion with curpos */
299                                 yasm_object *object =
300                                     yasm_section_get_object(sect2);
301                                 yasm_symtab *symtab = object->symtab;
302                                 e->terms[j].data.sym =
303                                     yasm_symtab_define_curpos
304                                     (symtab, ".", expr_precbc, e->line);
305                             }
306                             break;      /* stop looking */
307                         }
308                     }
309                 }
310 
311 
312                 if (j == e->numterms)
313                     return 1;   /* We didn't find a match! */
314             }
315 
316             /* Look for unmatched symrecs.  If we've already found one or
317              * we don't WANT to find one, error out.
318              */
319             for (i=0; i<e->numterms; i++) {
320                 if (e->terms[i].type == YASM_EXPR_SYM
321                     && (used & (1<<i)) == 0) {
322                     if (value->rel || ssym_not_ok)
323                         return 1;
324                     value->rel = e->terms[i].data.sym;
325                     /* and replace with 0 */
326                     e->terms[i].type = YASM_EXPR_INT;
327                     e->terms[i].data.intn = yasm_intnum_create_uint(0);
328                 }
329             }
330             break;
331         case YASM_EXPR_SHR:
332             /* Okay for single symrec in LHS and constant on RHS.
333              * Single symrecs are not okay on RHS.
334              * If RHS is non-constant, don't allow single symrec on LHS.
335              * XXX: should rshift be an expr instead??
336              */
337 
338             /* Check for single sym on LHS */
339             if (e->terms[0].type != YASM_EXPR_SYM)
340                 break;
341 
342             /* If we already have a sym, we can't take another one */
343             if (value->rel || ssym_not_ok)
344                 return 1;
345 
346             /* RHS must be a positive integer */
347             if (e->terms[1].type != YASM_EXPR_INT)
348                 return 1;       /* can't shift sym by non-constant integer */
349             shamt = yasm_intnum_get_uint(e->terms[1].data.intn);
350             if ((shamt + value->rshift) > YASM_VALUE_RSHIFT_MAX)
351                 return 1;       /* total shift would be too large */
352 
353             /* Update value */
354             value->rshift += shamt;
355             value->rel = e->terms[0].data.sym;
356 
357             /* Replace symbol with 0 */
358             e->terms[0].type = YASM_EXPR_INT;
359             e->terms[0].data.intn = yasm_intnum_create_uint(0);
360 
361             /* Just leave SHR in place */
362             break;
363         case YASM_EXPR_SEG:
364             /* Okay for single symrec (can only be done once).
365              * Not okay for anything BUT a single symrec as an immediate
366              * child.
367              */
368             if (e->terms[0].type != YASM_EXPR_SYM)
369                 return 1;
370 
371             if (value->seg_of)
372                 return 1;       /* multiple SEG not legal */
373             value->seg_of = 1;
374 
375             if (value->rel || ssym_not_ok)
376                 return 1;       /* got a relative portion somewhere else? */
377             value->rel = e->terms[0].data.sym;
378 
379             /* replace with ident'ed 0 */
380             e->op = YASM_EXPR_IDENT;
381             e->terms[0].type = YASM_EXPR_INT;
382             e->terms[0].data.intn = yasm_intnum_create_uint(0);
383             break;
384         case YASM_EXPR_WRT:
385             /* Okay for single symrec in LHS and either a register or single
386              * symrec (as an immediate child) on RHS.
387              * If a single symrec on RHS, can only be done once.
388              * WRT reg is left in expr for arch to look at.
389              */
390 
391             /* Handle RHS */
392             switch (e->terms[1].type) {
393                 case YASM_EXPR_SYM:
394                     if (value->wrt)
395                         return 1;
396                     value->wrt = e->terms[1].data.sym;
397                     /* and drop the WRT portion */
398                     e->op = YASM_EXPR_IDENT;
399                     e->numterms = 1;
400                     break;
401                 case YASM_EXPR_REG:
402                     break;  /* ignore */
403                 default:
404                     return 1;
405             }
406 
407             /* Handle LHS */
408             switch (e->terms[0].type) {
409                 case YASM_EXPR_SYM:
410                     if (value->rel || ssym_not_ok)
411                         return 1;
412                     value->rel = e->terms[0].data.sym;
413                     /* and replace with 0 */
414                     e->terms[0].type = YASM_EXPR_INT;
415                     e->terms[0].data.intn = yasm_intnum_create_uint(0);
416                     break;
417                 case YASM_EXPR_EXPR:
418                     /* recurse */
419                     return value_finalize_scan(value, e->terms[0].data.expn,
420                                                expr_precbc, ssym_not_ok);
421                 default:
422                     break;  /* ignore */
423             }
424 
425             break;
426         default:
427             /* Single symrec not allowed anywhere */
428             for (i=0; i<e->numterms; i++) {
429                 switch (e->terms[i].type) {
430                     case YASM_EXPR_SYM:
431                         return 1;
432                     case YASM_EXPR_EXPR:
433                         /* recurse */
434                         return value_finalize_scan(value,
435                                                    e->terms[i].data.expn,
436                                                    expr_precbc, 1);
437                     default:
438                         break;
439                 }
440             }
441             break;
442     }
443 
444     return 0;
445 }
446 
447 int
yasm_value_finalize_expr(yasm_value * value,yasm_expr * e,yasm_bytecode * precbc,unsigned int size)448 yasm_value_finalize_expr(yasm_value *value, yasm_expr *e,
449                          yasm_bytecode *precbc, unsigned int size)
450 {
451     if (!e) {
452         yasm_value_initialize(value, NULL, size);
453         return 0;
454     }
455     yasm_value_initialize(value, e, size);
456     return yasm_value_finalize(value, precbc);
457 }
458 
459 int
yasm_value_finalize(yasm_value * value,yasm_bytecode * precbc)460 yasm_value_finalize(yasm_value *value, yasm_bytecode *precbc)
461 {
462     if (!value->abs)
463         return 0;
464 
465     value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);
466 
467     /* quit early if there was an issue in simplify() */
468     if (yasm_error_occurred())
469         return 1;
470 
471     /* Strip top-level AND masking to an all-1s mask the same size
472      * of the value size.  This allows forced avoidance of overflow warnings.
473      */
474     if (value->abs->op == YASM_EXPR_AND) {
475         int term;
476 
477         /* Calculate 1<<size - 1 value */
478         yasm_intnum *mask = yasm_intnum_create_uint(1);
479         yasm_intnum *mask_tmp = yasm_intnum_create_uint(value->size);
480         yasm_intnum_calc(mask, YASM_EXPR_SHL, mask_tmp);
481         yasm_intnum_set_uint(mask_tmp, 1);
482         yasm_intnum_calc(mask, YASM_EXPR_SUB, mask_tmp);
483         yasm_intnum_destroy(mask_tmp);
484 
485         /* Walk terms and delete matching masks */
486         for (term=value->abs->numterms-1; term>=0; term--) {
487             if (value->abs->terms[term].type == YASM_EXPR_INT &&
488                 yasm_intnum_compare(value->abs->terms[term].data.intn,
489                                     mask) == 0) {
490                 /* Delete the intnum */
491                 yasm_intnum_destroy(value->abs->terms[term].data.intn);
492 
493                 /* Slide everything to its right over by 1 */
494                 if (term != value->abs->numterms-1) /* if it wasn't last.. */
495                     memmove(&value->abs->terms[term],
496                             &value->abs->terms[term+1],
497                             (value->abs->numterms-1-term)*
498                                 sizeof(yasm_expr__item));
499 
500                 /* Update numterms */
501                 value->abs->numterms--;
502 
503                 /* Indicate warnings have been disabled */
504                 value->no_warn = 1;
505             }
506         }
507         if (value->abs->numterms == 1)
508             value->abs->op = YASM_EXPR_IDENT;
509         yasm_intnum_destroy(mask);
510     }
511 
512     /* Handle trivial (IDENT) cases immediately */
513     if (value->abs->op == YASM_EXPR_IDENT) {
514         switch (value->abs->terms[0].type) {
515             case YASM_EXPR_INT:
516                 if (yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
517                     yasm_expr_destroy(value->abs);
518                     value->abs = NULL;
519                 }
520                 return 0;
521             case YASM_EXPR_REG:
522             case YASM_EXPR_FLOAT:
523                 return 0;
524             case YASM_EXPR_SYM:
525                 value->rel = value->abs->terms[0].data.sym;
526                 yasm_expr_destroy(value->abs);
527                 value->abs = NULL;
528                 return 0;
529             case YASM_EXPR_EXPR:
530                 /* Bring up lower values. */
531                 while (value->abs->op == YASM_EXPR_IDENT
532                        && value->abs->terms[0].type == YASM_EXPR_EXPR) {
533                     yasm_expr *sube = value->abs->terms[0].data.expn;
534                     yasm_xfree(value->abs);
535                     value->abs = sube;
536                 }
537                 break;
538             default:
539                 yasm_internal_error(N_("unexpected expr term type"));
540         }
541     }
542 
543     if (value_finalize_scan(value, value->abs, precbc, 0))
544         return 1;
545 
546     value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);
547 
548     /* Simplify 0 in abs to NULL */
549     if (value->abs->op == YASM_EXPR_IDENT
550         && value->abs->terms[0].type == YASM_EXPR_INT
551         && yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
552         yasm_expr_destroy(value->abs);
553         value->abs = NULL;
554     }
555     return 0;
556 }
557 
558 yasm_intnum *
yasm_value_get_intnum(yasm_value * value,yasm_bytecode * bc,int calc_bc_dist)559 yasm_value_get_intnum(yasm_value *value, yasm_bytecode *bc, int calc_bc_dist)
560 {
561     /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
562     /*@only@*/ yasm_intnum *outval;
563     int sym_local;
564 
565     if (value->abs) {
566         /* Handle integer expressions, if non-integer or too complex, return
567          * NULL.
568          */
569         intn = yasm_expr_get_intnum(&value->abs, calc_bc_dist);
570         if (!intn)
571             return NULL;
572     }
573 
574     if (value->rel) {
575         /* If relative portion is not in bc section, return NULL.
576          * Otherwise get the relative portion's offset.
577          */
578         /*@dependent@*/ yasm_bytecode *rel_prevbc;
579         unsigned long dist;
580 
581         if (!bc)
582             return NULL;    /* Can't calculate relative value */
583 
584         sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
585         if (value->wrt || value->seg_of || value->section_rel || !sym_local)
586             return NULL;    /* we can't handle SEG, WRT, or external symbols */
587         if (rel_prevbc->section != bc->section)
588             return NULL;    /* not in this section */
589         if (!value->curpos_rel)
590             return NULL;    /* not PC-relative */
591 
592         /* Calculate value relative to current assembly position */
593         dist = yasm_bc_next_offset(rel_prevbc);
594         if (dist < bc->offset) {
595             outval = yasm_intnum_create_uint(bc->offset - dist);
596             yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
597         } else {
598             dist -= bc->offset;
599             outval = yasm_intnum_create_uint(dist);
600         }
601 
602         if (value->rshift > 0) {
603             /*@only@*/ yasm_intnum *shamt =
604                 yasm_intnum_create_uint((unsigned long)value->rshift);
605             yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
606             yasm_intnum_destroy(shamt);
607         }
608         /* Add in absolute portion */
609         if (intn)
610             yasm_intnum_calc(outval, YASM_EXPR_ADD, intn);
611         return outval;
612     }
613 
614     if (intn)
615         return yasm_intnum_copy(intn);
616 
617     /* No absolute or relative portions: output 0 */
618     return yasm_intnum_create_uint(0);
619 }
620 
621 int
yasm_value_output_basic(yasm_value * value,unsigned char * buf,size_t destsize,yasm_bytecode * bc,int warn,yasm_arch * arch)622 yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
623                         size_t destsize, yasm_bytecode *bc, int warn,
624                         yasm_arch *arch)
625 {
626     /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
627     /*@only@*/ yasm_intnum *outval;
628     int sym_local;
629     int retval = 1;
630     unsigned int valsize = value->size;
631 
632     if (value->no_warn)
633         warn = 0;
634 
635     if (value->abs) {
636         /* Handle floating point expressions */
637         if (!value->rel && value->abs->op == YASM_EXPR_IDENT
638             && value->abs->terms[0].type == YASM_EXPR_FLOAT) {
639             if (yasm_arch_floatnum_tobytes(arch, value->abs->terms[0].data.flt,
640                                            buf, destsize, valsize, 0, warn))
641                 return -1;
642             else
643                 return 1;
644         }
645 
646         /* Check for complex float expressions */
647         if (yasm_expr__contains(value->abs, YASM_EXPR_FLOAT)) {
648             yasm_error_set(YASM_ERROR_FLOATING_POINT,
649                            N_("floating point expression too complex"));
650             return -1;
651         }
652 
653         /* Handle normal integer expressions */
654         intn = yasm_expr_get_intnum(&value->abs, 1);
655 
656         if (!intn) {
657             /* Second try before erroring: yasm_expr_get_intnum doesn't handle
658              * SEG:OFF, so try simplifying out any to just the OFF portion,
659              * then getting the intnum again.
660              */
661             yasm_expr *seg = yasm_expr_extract_deep_segoff(&value->abs);
662             if (seg)
663                 yasm_expr_destroy(seg);
664             intn = yasm_expr_get_intnum(&value->abs, 1);
665         }
666 
667         if (!intn) {
668             /* Still don't have an integer! */
669             yasm_error_set(YASM_ERROR_TOO_COMPLEX,
670                            N_("expression too complex"));
671             return -1;
672         }
673     }
674 
675     /* Adjust warn for signed/unsigned integer warnings */
676     if (warn != 0)
677         warn = value->sign ? -1 : 1;
678 
679     if (value->rel) {
680         /* If relative portion is not in bc section, don't try to handle it
681          * here.  Otherwise get the relative portion's offset.
682          */
683         /*@dependent@*/ yasm_bytecode *rel_prevbc;
684         unsigned long dist;
685 
686         sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
687         if (value->wrt || value->seg_of || value->section_rel || !sym_local)
688             return 0;       /* we can't handle SEG, WRT, or external symbols */
689         if (rel_prevbc->section != bc->section)
690             return 0;       /* not in this section */
691         if (!value->curpos_rel)
692             return 0;       /* not PC-relative */
693 
694         /* Calculate value relative to current assembly position */
695         dist = yasm_bc_next_offset(rel_prevbc);
696         if (dist < bc->offset) {
697             outval = yasm_intnum_create_uint(bc->offset - dist);
698             yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
699         } else {
700             dist -= bc->offset;
701             outval = yasm_intnum_create_uint(dist);
702         }
703 
704         if (value->rshift > 0) {
705             /*@only@*/ yasm_intnum *shamt =
706                 yasm_intnum_create_uint((unsigned long)value->rshift);
707             yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
708             yasm_intnum_destroy(shamt);
709         }
710         /* Add in absolute portion */
711         if (intn)
712             yasm_intnum_calc(outval, YASM_EXPR_ADD, intn);
713         /* Output! */
714         if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
715                                      bc, warn))
716             retval = -1;
717         yasm_intnum_destroy(outval);
718         return retval;
719     }
720 
721     if (value->seg_of || value->rshift || value->curpos_rel || value->ip_rel
722         || value->section_rel)
723         return 0;   /* We can't handle this with just an absolute */
724 
725     if (intn) {
726         /* Output just absolute portion */
727         if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, 0, bc,
728                                      warn))
729             retval = -1;
730     } else {
731         /* No absolute or relative portions: output 0 */
732         outval = yasm_intnum_create_uint(0);
733         if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
734                                      bc, warn))
735             retval = -1;
736         yasm_intnum_destroy(outval);
737     }
738     return retval;
739 }
740 
741 void
yasm_value_print(const yasm_value * value,FILE * f,int indent_level)742 yasm_value_print(const yasm_value *value, FILE *f, int indent_level)
743 {
744     fprintf(f, "%*s%u-bit, %ssigned", indent_level, "", value->size,
745             value->sign ? "" : "un");
746     fprintf(f, "%*sAbsolute portion=", indent_level, "");
747     yasm_expr_print(value->abs, f);
748     fprintf(f, "\n");
749     if (value->rel) {
750         fprintf(f, "%*sRelative to=%s%s\n", indent_level, "",
751                 value->seg_of ? "SEG " : "",
752                 yasm_symrec_get_name(value->rel));
753         if (value->wrt)
754             fprintf(f, "%*s(With respect to=%s)\n", indent_level, "",
755                     yasm_symrec_get_name(value->wrt));
756         if (value->rshift > 0)
757             fprintf(f, "%*s(Right shifted by=%u)\n", indent_level, "",
758                     value->rshift);
759         if (value->curpos_rel)
760             fprintf(f, "%*s(Relative to current position)\n", indent_level,
761                     "");
762         if (value->ip_rel)
763             fprintf(f, "%*s(IP-relative)\n", indent_level, "");
764         if (value->jump_target)
765             fprintf(f, "%*s(Jump target)\n", indent_level, "");
766         if (value->section_rel)
767             fprintf(f, "%*s(Section-relative)\n", indent_level, "");
768         if (value->no_warn)
769             fprintf(f, "%*s(Overflow warnings disabled)\n", indent_level, "");
770     }
771 }
772