123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- /*
- * Value handling
- *
- * Copyright (C) 2006-2007 Peter Johnson
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
- #include "util.h"
- #include "libyasm-stdint.h"
- #include "coretype.h"
- #include "bitvect.h"
- #include "errwarn.h"
- #include "intnum.h"
- #include "floatnum.h"
- #include "expr.h"
- #include "value.h"
- #include "symrec.h"
- #include "bytecode.h"
- #include "section.h"
- #include "arch.h"
- void
- yasm_value_initialize(/*@out@*/ yasm_value *value,
- /*@null@*/ /*@kept@*/ yasm_expr *e, unsigned int size)
- {
- value->abs = e;
- value->rel = NULL;
- value->wrt = NULL;
- value->seg_of = 0;
- value->rshift = 0;
- value->curpos_rel = 0;
- value->ip_rel = 0;
- value->jump_target = 0;
- value->section_rel = 0;
- value->no_warn = 0;
- value->sign = 0;
- value->size = size;
- }
- void
- yasm_value_init_sym(/*@out@*/ yasm_value *value, /*@null@*/ yasm_symrec *sym,
- unsigned int size)
- {
- value->abs = NULL;
- value->rel = sym;
- value->wrt = NULL;
- value->seg_of = 0;
- value->rshift = 0;
- value->curpos_rel = 0;
- value->ip_rel = 0;
- value->jump_target = 0;
- value->section_rel = 0;
- value->no_warn = 0;
- value->sign = 0;
- value->size = size;
- }
- void
- yasm_value_init_copy(yasm_value *value, const yasm_value *orig)
- {
- value->abs = orig->abs ? yasm_expr_copy(orig->abs) : NULL;
- value->rel = orig->rel;
- value->wrt = orig->wrt;
- value->seg_of = orig->seg_of;
- value->rshift = orig->rshift;
- value->curpos_rel = orig->curpos_rel;
- value->ip_rel = orig->ip_rel;
- value->jump_target = orig->jump_target;
- value->section_rel = orig->section_rel;
- value->no_warn = orig->no_warn;
- value->sign = orig->sign;
- value->size = orig->size;
- }
- void
- yasm_value_delete(yasm_value *value)
- {
- if (value->abs)
- yasm_expr_destroy(value->abs);
- value->abs = NULL;
- value->rel = NULL;
- }
- void
- yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc,
- unsigned int ip_rel)
- {
- value->curpos_rel = 1;
- value->ip_rel = ip_rel;
- /* In order for us to correctly output curpos-relative values, we must
- * have a relative portion of the value. If one doesn't exist, point
- * to a custom absolute symbol.
- */
- if (!value->rel) {
- yasm_object *object = yasm_section_get_object(yasm_bc_get_section(bc));
- value->rel = yasm_symtab_abs_sym(object->symtab);
- }
- }
- static int
- value_finalize_scan(yasm_value *value, yasm_expr *e,
- /*@null@*/ yasm_bytecode *expr_precbc, int ssym_not_ok)
- {
- int i;
- /*@dependent@*/ yasm_section *sect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- unsigned long shamt; /* for SHR */
- /* Yes, this has a maximum upper bound on 32 terms, based on an
- * "insane number of terms" (and ease of implementation) WAG.
- * The right way to do this would be a stack-based alloca, but that's
- * not ISO C. We really don't want to malloc here as this function is
- * hit a lot!
- *
- * This is a bitmask to keep things small, as this is a recursive
- * routine and we don't want to eat up stack space.
- */
- unsigned long used; /* for ADD */
- /* Thanks to this running after a simplify, we don't need to iterate
- * down through IDENTs or handle SUB.
- *
- * We scan for a single symrec, gathering info along the way. After
- * we've found the symrec, we keep scanning but error if we find
- * another one. We pull out the single symrec and any legal operations
- * performed on it.
- *
- * Also, if we find a float anywhere, we don't allow mixing of a single
- * symrec with it.
- */
- switch (e->op) {
- case YASM_EXPR_ADD:
- /* Okay for single symrec anywhere in expr.
- * Check for single symrec anywhere.
- * Handle symrec-symrec by checking for (-1*symrec)
- * and symrec term pairs (where both symrecs are in the same
- * segment).
- */
- if (e->numterms > 32)
- yasm__fatal(N_("expression on line %d has too many add terms;"
- " internal limit of 32"), e->line);
- used = 0;
- for (i=0; i<e->numterms; i++) {
- int j;
- yasm_expr *sube;
- yasm_intnum *intn;
- yasm_symrec *sym;
- /*@dependent@*/ yasm_section *sect2;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
- /* First look for an (-1*symrec) term */
- if (e->terms[i].type != YASM_EXPR_EXPR)
- continue;
- sube = e->terms[i].data.expn;
- if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) {
- /* recurse instead */
- if (value_finalize_scan(value, sube, expr_precbc,
- ssym_not_ok))
- return 1;
- continue;
- }
- if (sube->terms[0].type == YASM_EXPR_INT &&
- sube->terms[1].type == YASM_EXPR_SYM) {
- intn = sube->terms[0].data.intn;
- sym = sube->terms[1].data.sym;
- } else if (sube->terms[0].type == YASM_EXPR_SYM &&
- sube->terms[1].type == YASM_EXPR_INT) {
- sym = sube->terms[0].data.sym;
- intn = sube->terms[1].data.intn;
- } else {
- if (value_finalize_scan(value, sube, expr_precbc,
- ssym_not_ok))
- return 1;
- continue;
- }
- if (!yasm_intnum_is_neg1(intn)) {
- if (value_finalize_scan(value, sube, expr_precbc,
- ssym_not_ok))
- return 1;
- continue;
- }
- /* Look for the same symrec term; even if both are external,
- * they should cancel out.
- */
- for (j=0; j<e->numterms; j++) {
- if (e->terms[j].type == YASM_EXPR_SYM
- && e->terms[j].data.sym == sym
- && (used & (1<<j)) == 0) {
- /* Mark as used */
- used |= 1<<j;
- /* Replace both symrec portions with 0 */
- yasm_expr_destroy(sube);
- e->terms[i].type = YASM_EXPR_INT;
- e->terms[i].data.intn = yasm_intnum_create_uint(0);
- e->terms[j].type = YASM_EXPR_INT;
- e->terms[j].data.intn = yasm_intnum_create_uint(0);
- break; /* stop looking */
- }
- }
- if (j != e->numterms)
- continue;
- if (!yasm_symrec_get_label(sym, &precbc)) {
- if (value_finalize_scan(value, sube, expr_precbc,
- ssym_not_ok))
- return 1;
- continue;
- }
- sect2 = yasm_bc_get_section(precbc);
- /* Now look for a unused symrec term in the same segment */
- for (j=0; j<e->numterms; j++) {
- if (e->terms[j].type == YASM_EXPR_SYM
- && yasm_symrec_get_label(e->terms[j].data.sym,
- &precbc2)
- && (sect = yasm_bc_get_section(precbc2))
- && sect == sect2
- && (used & (1<<j)) == 0) {
- /* Mark as used */
- used |= 1<<j;
- break; /* stop looking */
- }
- }
- /* We didn't match in the same segment. If the
- * -1*symrec is actually -1*curpos, we can match
- * unused symrec terms in other segments and generate
- * a curpos-relative reloc.
- *
- * Similarly, handle -1*symrec in other segment via the
- * following transformation:
- * other-this = (other-.)+(.-this)
- * We can only do this transformation if "this" is in
- * this expr's segment.
- *
- * Don't do this if we've already become curpos-relative.
- * The unmatched symrec will be caught below.
- */
- if (j == e->numterms && !value->curpos_rel
- && (yasm_symrec_is_curpos(sym)
- || (expr_precbc
- && sect2 == yasm_bc_get_section(expr_precbc)))) {
- for (j=0; j<e->numterms; j++) {
- if (e->terms[j].type == YASM_EXPR_SYM
- && !yasm_symrec_get_equ(e->terms[j].data.sym)
- && !yasm_symrec_is_special(e->terms[j].data.sym)
- && (used & (1<<j)) == 0) {
- /* Mark as used */
- used |= 1<<j;
- /* Mark value as curpos-relative */
- if (value->rel || ssym_not_ok)
- return 1;
- value->rel = e->terms[j].data.sym;
- value->curpos_rel = 1;
- if (yasm_symrec_is_curpos(sym)) {
- /* Replace both symrec portions with 0 */
- yasm_expr_destroy(sube);
- e->terms[i].type = YASM_EXPR_INT;
- e->terms[i].data.intn =
- yasm_intnum_create_uint(0);
- e->terms[j].type = YASM_EXPR_INT;
- e->terms[j].data.intn =
- yasm_intnum_create_uint(0);
- } else {
- /* Replace positive portion with curpos */
- yasm_object *object =
- yasm_section_get_object(sect2);
- yasm_symtab *symtab = object->symtab;
- e->terms[j].data.sym =
- yasm_symtab_define_curpos
- (symtab, ".", expr_precbc, e->line);
- }
- break; /* stop looking */
- }
- }
- }
- if (j == e->numterms)
- return 1; /* We didn't find a match! */
- }
- /* Look for unmatched symrecs. If we've already found one or
- * we don't WANT to find one, error out.
- */
- for (i=0; i<e->numterms; i++) {
- if (e->terms[i].type == YASM_EXPR_SYM
- && (used & (1<<i)) == 0) {
- if (value->rel || ssym_not_ok)
- return 1;
- value->rel = e->terms[i].data.sym;
- /* and replace with 0 */
- e->terms[i].type = YASM_EXPR_INT;
- e->terms[i].data.intn = yasm_intnum_create_uint(0);
- }
- }
- break;
- case YASM_EXPR_SHR:
- /* Okay for single symrec in LHS and constant on RHS.
- * Single symrecs are not okay on RHS.
- * If RHS is non-constant, don't allow single symrec on LHS.
- * XXX: should rshift be an expr instead??
- */
- /* Check for single sym on LHS */
- if (e->terms[0].type != YASM_EXPR_SYM)
- break;
- /* If we already have a sym, we can't take another one */
- if (value->rel || ssym_not_ok)
- return 1;
- /* RHS must be a positive integer */
- if (e->terms[1].type != YASM_EXPR_INT)
- return 1; /* can't shift sym by non-constant integer */
- shamt = yasm_intnum_get_uint(e->terms[1].data.intn);
- if ((shamt + value->rshift) > YASM_VALUE_RSHIFT_MAX)
- return 1; /* total shift would be too large */
- /* Update value */
- value->rshift += shamt;
- value->rel = e->terms[0].data.sym;
- /* Replace symbol with 0 */
- e->terms[0].type = YASM_EXPR_INT;
- e->terms[0].data.intn = yasm_intnum_create_uint(0);
- /* Just leave SHR in place */
- break;
- case YASM_EXPR_SEG:
- /* Okay for single symrec (can only be done once).
- * Not okay for anything BUT a single symrec as an immediate
- * child.
- */
- if (e->terms[0].type != YASM_EXPR_SYM)
- return 1;
- if (value->seg_of)
- return 1; /* multiple SEG not legal */
- value->seg_of = 1;
- if (value->rel || ssym_not_ok)
- return 1; /* got a relative portion somewhere else? */
- value->rel = e->terms[0].data.sym;
- /* replace with ident'ed 0 */
- e->op = YASM_EXPR_IDENT;
- e->terms[0].type = YASM_EXPR_INT;
- e->terms[0].data.intn = yasm_intnum_create_uint(0);
- break;
- case YASM_EXPR_WRT:
- /* Okay for single symrec in LHS and either a register or single
- * symrec (as an immediate child) on RHS.
- * If a single symrec on RHS, can only be done once.
- * WRT reg is left in expr for arch to look at.
- */
- /* Handle RHS */
- switch (e->terms[1].type) {
- case YASM_EXPR_SYM:
- if (value->wrt)
- return 1;
- value->wrt = e->terms[1].data.sym;
- /* and drop the WRT portion */
- e->op = YASM_EXPR_IDENT;
- e->numterms = 1;
- break;
- case YASM_EXPR_REG:
- break; /* ignore */
- default:
- return 1;
- }
- /* Handle LHS */
- switch (e->terms[0].type) {
- case YASM_EXPR_SYM:
- if (value->rel || ssym_not_ok)
- return 1;
- value->rel = e->terms[0].data.sym;
- /* and replace with 0 */
- e->terms[0].type = YASM_EXPR_INT;
- e->terms[0].data.intn = yasm_intnum_create_uint(0);
- break;
- case YASM_EXPR_EXPR:
- /* recurse */
- return value_finalize_scan(value, e->terms[0].data.expn,
- expr_precbc, ssym_not_ok);
- default:
- break; /* ignore */
- }
- break;
- default:
- /* Single symrec not allowed anywhere */
- for (i=0; i<e->numterms; i++) {
- switch (e->terms[i].type) {
- case YASM_EXPR_SYM:
- return 1;
- case YASM_EXPR_EXPR:
- /* recurse */
- return value_finalize_scan(value,
- e->terms[i].data.expn,
- expr_precbc, 1);
- default:
- break;
- }
- }
- break;
- }
- return 0;
- }
- int
- yasm_value_finalize_expr(yasm_value *value, yasm_expr *e,
- yasm_bytecode *precbc, unsigned int size)
- {
- if (!e) {
- yasm_value_initialize(value, NULL, size);
- return 0;
- }
- yasm_value_initialize(value, e, size);
- return yasm_value_finalize(value, precbc);
- }
- int
- yasm_value_finalize(yasm_value *value, yasm_bytecode *precbc)
- {
- if (!value->abs)
- return 0;
- value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);
- /* quit early if there was an issue in simplify() */
- if (yasm_error_occurred())
- return 1;
- /* Strip top-level AND masking to an all-1s mask the same size
- * of the value size. This allows forced avoidance of overflow warnings.
- */
- if (value->abs->op == YASM_EXPR_AND) {
- int term;
- /* Calculate 1<<size - 1 value */
- yasm_intnum *mask = yasm_intnum_create_uint(1);
- yasm_intnum *mask_tmp = yasm_intnum_create_uint(value->size);
- yasm_intnum_calc(mask, YASM_EXPR_SHL, mask_tmp);
- yasm_intnum_set_uint(mask_tmp, 1);
- yasm_intnum_calc(mask, YASM_EXPR_SUB, mask_tmp);
- yasm_intnum_destroy(mask_tmp);
- /* Walk terms and delete matching masks */
- for (term=value->abs->numterms-1; term>=0; term--) {
- if (value->abs->terms[term].type == YASM_EXPR_INT &&
- yasm_intnum_compare(value->abs->terms[term].data.intn,
- mask) == 0) {
- /* Delete the intnum */
- yasm_intnum_destroy(value->abs->terms[term].data.intn);
- /* Slide everything to its right over by 1 */
- if (term != value->abs->numterms-1) /* if it wasn't last.. */
- memmove(&value->abs->terms[term],
- &value->abs->terms[term+1],
- (value->abs->numterms-1-term)*
- sizeof(yasm_expr__item));
- /* Update numterms */
- value->abs->numterms--;
- /* Indicate warnings have been disabled */
- value->no_warn = 1;
- }
- }
- if (value->abs->numterms == 1)
- value->abs->op = YASM_EXPR_IDENT;
- yasm_intnum_destroy(mask);
- }
- /* Handle trivial (IDENT) cases immediately */
- if (value->abs->op == YASM_EXPR_IDENT) {
- switch (value->abs->terms[0].type) {
- case YASM_EXPR_INT:
- if (yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
- yasm_expr_destroy(value->abs);
- value->abs = NULL;
- }
- return 0;
- case YASM_EXPR_REG:
- case YASM_EXPR_FLOAT:
- return 0;
- case YASM_EXPR_SYM:
- value->rel = value->abs->terms[0].data.sym;
- yasm_expr_destroy(value->abs);
- value->abs = NULL;
- return 0;
- case YASM_EXPR_EXPR:
- /* Bring up lower values. */
- while (value->abs->op == YASM_EXPR_IDENT
- && value->abs->terms[0].type == YASM_EXPR_EXPR) {
- yasm_expr *sube = value->abs->terms[0].data.expn;
- yasm_xfree(value->abs);
- value->abs = sube;
- }
- break;
- default:
- yasm_internal_error(N_("unexpected expr term type"));
- }
- }
- if (value_finalize_scan(value, value->abs, precbc, 0))
- return 1;
- value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);
- /* Simplify 0 in abs to NULL */
- if (value->abs->op == YASM_EXPR_IDENT
- && value->abs->terms[0].type == YASM_EXPR_INT
- && yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
- yasm_expr_destroy(value->abs);
- value->abs = NULL;
- }
- return 0;
- }
- yasm_intnum *
- yasm_value_get_intnum(yasm_value *value, yasm_bytecode *bc, int calc_bc_dist)
- {
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
- /*@only@*/ yasm_intnum *outval;
- int sym_local;
- if (value->abs) {
- /* Handle integer expressions, if non-integer or too complex, return
- * NULL.
- */
- intn = yasm_expr_get_intnum(&value->abs, calc_bc_dist);
- if (!intn)
- return NULL;
- }
- if (value->rel) {
- /* If relative portion is not in bc section, return NULL.
- * Otherwise get the relative portion's offset.
- */
- /*@dependent@*/ yasm_bytecode *rel_prevbc;
- unsigned long dist;
- if (!bc)
- return NULL; /* Can't calculate relative value */
- sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
- if (value->wrt || value->seg_of || value->section_rel || !sym_local)
- return NULL; /* we can't handle SEG, WRT, or external symbols */
- if (rel_prevbc->section != bc->section)
- return NULL; /* not in this section */
- if (!value->curpos_rel)
- return NULL; /* not PC-relative */
- /* Calculate value relative to current assembly position */
- dist = yasm_bc_next_offset(rel_prevbc);
- if (dist < bc->offset) {
- outval = yasm_intnum_create_uint(bc->offset - dist);
- yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
- } else {
- dist -= bc->offset;
- outval = yasm_intnum_create_uint(dist);
- }
- if (value->rshift > 0) {
- /*@only@*/ yasm_intnum *shamt =
- yasm_intnum_create_uint((unsigned long)value->rshift);
- yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
- yasm_intnum_destroy(shamt);
- }
- /* Add in absolute portion */
- if (intn)
- yasm_intnum_calc(outval, YASM_EXPR_ADD, intn);
- return outval;
- }
- if (intn)
- return yasm_intnum_copy(intn);
-
- /* No absolute or relative portions: output 0 */
- return yasm_intnum_create_uint(0);
- }
- int
- yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
- size_t destsize, yasm_bytecode *bc, int warn,
- yasm_arch *arch)
- {
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
- /*@only@*/ yasm_intnum *outval;
- int sym_local;
- int retval = 1;
- unsigned int valsize = value->size;
- if (value->no_warn)
- warn = 0;
- if (value->abs) {
- /* Handle floating point expressions */
- if (!value->rel && value->abs->op == YASM_EXPR_IDENT
- && value->abs->terms[0].type == YASM_EXPR_FLOAT) {
- if (yasm_arch_floatnum_tobytes(arch, value->abs->terms[0].data.flt,
- buf, destsize, valsize, 0, warn))
- return -1;
- else
- return 1;
- }
- /* Check for complex float expressions */
- if (yasm_expr__contains(value->abs, YASM_EXPR_FLOAT)) {
- yasm_error_set(YASM_ERROR_FLOATING_POINT,
- N_("floating point expression too complex"));
- return -1;
- }
- /* Handle normal integer expressions */
- intn = yasm_expr_get_intnum(&value->abs, 1);
- if (!intn) {
- /* Second try before erroring: yasm_expr_get_intnum doesn't handle
- * SEG:OFF, so try simplifying out any to just the OFF portion,
- * then getting the intnum again.
- */
- yasm_expr *seg = yasm_expr_extract_deep_segoff(&value->abs);
- if (seg)
- yasm_expr_destroy(seg);
- intn = yasm_expr_get_intnum(&value->abs, 1);
- }
- if (!intn) {
- /* Still don't have an integer! */
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("expression too complex"));
- return -1;
- }
- }
- /* Adjust warn for signed/unsigned integer warnings */
- if (warn != 0)
- warn = value->sign ? -1 : 1;
- if (value->rel) {
- /* If relative portion is not in bc section, don't try to handle it
- * here. Otherwise get the relative portion's offset.
- */
- /*@dependent@*/ yasm_bytecode *rel_prevbc;
- unsigned long dist;
- sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
- if (value->wrt || value->seg_of || value->section_rel || !sym_local)
- return 0; /* we can't handle SEG, WRT, or external symbols */
- if (rel_prevbc->section != bc->section)
- return 0; /* not in this section */
- if (!value->curpos_rel)
- return 0; /* not PC-relative */
- /* Calculate value relative to current assembly position */
- dist = yasm_bc_next_offset(rel_prevbc);
- if (dist < bc->offset) {
- outval = yasm_intnum_create_uint(bc->offset - dist);
- yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
- } else {
- dist -= bc->offset;
- outval = yasm_intnum_create_uint(dist);
- }
- if (value->rshift > 0) {
- /*@only@*/ yasm_intnum *shamt =
- yasm_intnum_create_uint((unsigned long)value->rshift);
- yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
- yasm_intnum_destroy(shamt);
- }
- /* Add in absolute portion */
- if (intn)
- yasm_intnum_calc(outval, YASM_EXPR_ADD, intn);
- /* Output! */
- if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
- bc, warn))
- retval = -1;
- yasm_intnum_destroy(outval);
- return retval;
- }
- if (value->seg_of || value->rshift || value->curpos_rel || value->ip_rel
- || value->section_rel)
- return 0; /* We can't handle this with just an absolute */
- if (intn) {
- /* Output just absolute portion */
- if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, 0, bc,
- warn))
- retval = -1;
- } else {
- /* No absolute or relative portions: output 0 */
- outval = yasm_intnum_create_uint(0);
- if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
- bc, warn))
- retval = -1;
- yasm_intnum_destroy(outval);
- }
- return retval;
- }
- void
- yasm_value_print(const yasm_value *value, FILE *f, int indent_level)
- {
- fprintf(f, "%*s%u-bit, %ssigned", indent_level, "", value->size,
- value->sign ? "" : "un");
- fprintf(f, "%*sAbsolute portion=", indent_level, "");
- yasm_expr_print(value->abs, f);
- fprintf(f, "\n");
- if (value->rel) {
- fprintf(f, "%*sRelative to=%s%s\n", indent_level, "",
- value->seg_of ? "SEG " : "",
- yasm_symrec_get_name(value->rel));
- if (value->wrt)
- fprintf(f, "%*s(With respect to=%s)\n", indent_level, "",
- yasm_symrec_get_name(value->wrt));
- if (value->rshift > 0)
- fprintf(f, "%*s(Right shifted by=%u)\n", indent_level, "",
- value->rshift);
- if (value->curpos_rel)
- fprintf(f, "%*s(Relative to current position)\n", indent_level,
- "");
- if (value->ip_rel)
- fprintf(f, "%*s(IP-relative)\n", indent_level, "");
- if (value->jump_target)
- fprintf(f, "%*s(Jump target)\n", indent_level, "");
- if (value->section_rel)
- fprintf(f, "%*s(Section-relative)\n", indent_level, "");
- if (value->no_warn)
- fprintf(f, "%*s(Overflow warnings disabled)\n", indent_level, "");
- }
- }
|