145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*
245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Value handling
345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *  Copyright (C) 2006-2007  Peter Johnson
545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Redistribution and use in source and binary forms, with or without
745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * modification, are permitted provided that the following conditions
845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * are met:
945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * 1. Redistributions of source code must retain the above copyright
1045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    notice, this list of conditions and the following disclaimer.
1145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * 2. Redistributions in binary form must reproduce the above copyright
1245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    notice, this list of conditions and the following disclaimer in the
1345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    documentation and/or other materials provided with the distribution.
1445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
1545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
1645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
1945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * POSSIBILITY OF SUCH DAMAGE.
2645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
2745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "util.h"
2845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
2945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "libyasm-stdint.h"
3045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "coretype.h"
3145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "bitvect.h"
3245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
3345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "errwarn.h"
3445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "intnum.h"
3545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "floatnum.h"
3645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "expr.h"
3745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "value.h"
3845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "symrec.h"
3945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "bytecode.h"
4145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "section.h"
4245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "arch.h"
4445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
4745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_value_initialize(/*@out@*/ yasm_value *value,
4845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      /*@null@*/ /*@kept@*/ yasm_expr *e, unsigned int size)
4945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
5045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->abs = e;
5145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->rel = NULL;
5245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->wrt = NULL;
5345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->seg_of = 0;
5445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->rshift = 0;
5545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->curpos_rel = 0;
5645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->ip_rel = 0;
5745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->jump_target = 0;
5845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->section_rel = 0;
5945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->no_warn = 0;
6045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->sign = 0;
6145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->size = size;
6245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
6345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
6445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
6545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_value_init_sym(/*@out@*/ yasm_value *value, /*@null@*/ yasm_symrec *sym,
6645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    unsigned int size)
6745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
6845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->abs = NULL;
6945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->rel = sym;
7045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->wrt = NULL;
7145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->seg_of = 0;
7245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->rshift = 0;
7345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->curpos_rel = 0;
7445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->ip_rel = 0;
7545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->jump_target = 0;
7645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->section_rel = 0;
7745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->no_warn = 0;
7845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->sign = 0;
7945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->size = size;
8045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
8145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
8345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_value_init_copy(yasm_value *value, const yasm_value *orig)
8445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
8545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->abs = orig->abs ? yasm_expr_copy(orig->abs) : NULL;
8645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->rel = orig->rel;
8745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->wrt = orig->wrt;
8845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->seg_of = orig->seg_of;
8945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->rshift = orig->rshift;
9045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->curpos_rel = orig->curpos_rel;
9145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->ip_rel = orig->ip_rel;
9245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->jump_target = orig->jump_target;
9345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->section_rel = orig->section_rel;
9445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->no_warn = orig->no_warn;
9545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->sign = orig->sign;
9645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->size = orig->size;
9745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
9845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
9945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
10045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_value_delete(yasm_value *value)
10145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
10245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->abs)
10345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_expr_destroy(value->abs);
10445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->abs = NULL;
10545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->rel = NULL;
10645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
10745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
10845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
10945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc,
11045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                          unsigned int ip_rel)
11145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
11245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->curpos_rel = 1;
11345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->ip_rel = ip_rel;
11445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* In order for us to correctly output curpos-relative values, we must
11545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * have a relative portion of the value.  If one doesn't exist, point
11645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * to a custom absolute symbol.
11745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
11845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!value->rel) {
11945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_object *object = yasm_section_get_object(yasm_bc_get_section(bc));
12045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        value->rel = yasm_symtab_abs_sym(object->symtab);
12145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
12245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
12345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
12445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
12545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvalue_finalize_scan(yasm_value *value, yasm_expr *e,
12645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /*@null@*/ yasm_bytecode *expr_precbc, int ssym_not_ok)
12745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
12845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int i;
12945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@dependent@*/ yasm_section *sect;
13045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
13145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
13245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned long shamt;    /* for SHR */
13345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
13445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Yes, this has a maximum upper bound on 32 terms, based on an
13545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * "insane number of terms" (and ease of implementation) WAG.
13645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * The right way to do this would be a stack-based alloca, but that's
13745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * not ISO C.  We really don't want to malloc here as this function is
13845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * hit a lot!
13945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     *
14045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * This is a bitmask to keep things small, as this is a recursive
14145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * routine and we don't want to eat up stack space.
14245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
14345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned long used;     /* for ADD */
14445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
14545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Thanks to this running after a simplify, we don't need to iterate
14645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * down through IDENTs or handle SUB.
14745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     *
14845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * We scan for a single symrec, gathering info along the way.  After
14945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * we've found the symrec, we keep scanning but error if we find
15045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * another one.  We pull out the single symrec and any legal operations
15145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * performed on it.
15245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     *
15345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * Also, if we find a float anywhere, we don't allow mixing of a single
15445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * symrec with it.
15545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
15645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    switch (e->op) {
15745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_ADD:
15845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Okay for single symrec anywhere in expr.
15945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * Check for single symrec anywhere.
16045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * Handle symrec-symrec by checking for (-1*symrec)
16145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * and symrec term pairs (where both symrecs are in the same
16245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * segment).
16345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
16445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (e->numterms > 32)
16545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm__fatal(N_("expression on line %d has too many add terms;"
16645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                               " internal limit of 32"), e->line);
16745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
16845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            used = 0;
16945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
17045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            for (i=0; i<e->numterms; i++) {
17145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                int j;
17245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_expr *sube;
17345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum *intn;
17445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_symrec *sym;
17545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /*@dependent@*/ yasm_section *sect2;
17645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
17745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
17845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* First look for an (-1*symrec) term */
17945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (e->terms[i].type != YASM_EXPR_EXPR)
18045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    continue;
18145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                sube = e->terms[i].data.expn;
18245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
18345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (sube->op != YASM_EXPR_MUL || sube->numterms != 2) {
18445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* recurse instead */
18545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (value_finalize_scan(value, sube, expr_precbc,
18645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                            ssym_not_ok))
18745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        return 1;
18845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    continue;
18945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
19045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
19145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (sube->terms[0].type == YASM_EXPR_INT &&
19245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    sube->terms[1].type == YASM_EXPR_SYM) {
19345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    intn = sube->terms[0].data.intn;
19445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    sym = sube->terms[1].data.sym;
19545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                } else if (sube->terms[0].type == YASM_EXPR_SYM &&
19645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                           sube->terms[1].type == YASM_EXPR_INT) {
19745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    sym = sube->terms[0].data.sym;
19845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    intn = sube->terms[1].data.intn;
19945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                } else {
20045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (value_finalize_scan(value, sube, expr_precbc,
20145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                            ssym_not_ok))
20245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        return 1;
20345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    continue;
20445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
20545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
20645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (!yasm_intnum_is_neg1(intn)) {
20745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (value_finalize_scan(value, sube, expr_precbc,
20845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                            ssym_not_ok))
20945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        return 1;
21045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    continue;
21145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
21245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
21345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Look for the same symrec term; even if both are external,
21445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * they should cancel out.
21545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 */
21645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                for (j=0; j<e->numterms; j++) {
21745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (e->terms[j].type == YASM_EXPR_SYM
21845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        && e->terms[j].data.sym == sym
21945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        && (used & (1<<j)) == 0) {
22045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        /* Mark as used */
22145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        used |= 1<<j;
22245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
22345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        /* Replace both symrec portions with 0 */
22445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        yasm_expr_destroy(sube);
22545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        e->terms[i].type = YASM_EXPR_INT;
22645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        e->terms[i].data.intn = yasm_intnum_create_uint(0);
22745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        e->terms[j].type = YASM_EXPR_INT;
22845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        e->terms[j].data.intn = yasm_intnum_create_uint(0);
22945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
23045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        break;  /* stop looking */
23145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    }
23245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
23345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (j != e->numterms)
23445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    continue;
23545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
23645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (!yasm_symrec_get_label(sym, &precbc)) {
23745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (value_finalize_scan(value, sube, expr_precbc,
23845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                            ssym_not_ok))
23945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        return 1;
24045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    continue;
24145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
24245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                sect2 = yasm_bc_get_section(precbc);
24345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
24445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Now look for a unused symrec term in the same segment */
24545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                for (j=0; j<e->numterms; j++) {
24645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (e->terms[j].type == YASM_EXPR_SYM
24745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        && yasm_symrec_get_label(e->terms[j].data.sym,
24845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                                 &precbc2)
24945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        && (sect = yasm_bc_get_section(precbc2))
25045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        && sect == sect2
25145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        && (used & (1<<j)) == 0) {
25245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        /* Mark as used */
25345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        used |= 1<<j;
25445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        break;  /* stop looking */
25545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    }
25645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
25745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
25845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* We didn't match in the same segment.  If the
25945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * -1*symrec is actually -1*curpos, we can match
26045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * unused symrec terms in other segments and generate
26145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * a curpos-relative reloc.
26245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 *
26345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * Similarly, handle -1*symrec in other segment via the
26445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * following transformation:
26545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * other-this = (other-.)+(.-this)
26645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * We can only do this transformation if "this" is in
26745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * this expr's segment.
26845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 *
26945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * Don't do this if we've already become curpos-relative.
27045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * The unmatched symrec will be caught below.
27145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 */
27245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (j == e->numterms && !value->curpos_rel
27345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    && (yasm_symrec_is_curpos(sym)
27445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        || (expr_precbc
27545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            && sect2 == yasm_bc_get_section(expr_precbc)))) {
27645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    for (j=0; j<e->numterms; j++) {
27745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        if (e->terms[j].type == YASM_EXPR_SYM
27845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            && !yasm_symrec_get_equ(e->terms[j].data.sym)
27945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            && !yasm_symrec_is_special(e->terms[j].data.sym)
28045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            && (used & (1<<j)) == 0) {
28145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            /* Mark as used */
28245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            used |= 1<<j;
28345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            /* Mark value as curpos-relative */
28445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            if (value->rel || ssym_not_ok)
28545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                return 1;
28645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            value->rel = e->terms[j].data.sym;
28745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            value->curpos_rel = 1;
28845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            if (yasm_symrec_is_curpos(sym)) {
28945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                /* Replace both symrec portions with 0 */
29045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                yasm_expr_destroy(sube);
29145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                e->terms[i].type = YASM_EXPR_INT;
29245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                e->terms[i].data.intn =
29345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                    yasm_intnum_create_uint(0);
29445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                e->terms[j].type = YASM_EXPR_INT;
29545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                e->terms[j].data.intn =
29645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                    yasm_intnum_create_uint(0);
29745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            } else {
29845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                /* Replace positive portion with curpos */
29945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                yasm_object *object =
30045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                    yasm_section_get_object(sect2);
30145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                yasm_symtab *symtab = object->symtab;
30245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                e->terms[j].data.sym =
30345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                    yasm_symtab_define_curpos
30445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                    (symtab, ".", expr_precbc, e->line);
30545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            }
30645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            break;      /* stop looking */
30745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        }
30845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    }
30945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
31045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
31145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
31245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (j == e->numterms)
31345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    return 1;   /* We didn't find a match! */
31445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
31545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
31645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Look for unmatched symrecs.  If we've already found one or
31745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * we don't WANT to find one, error out.
31845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
31945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            for (i=0; i<e->numterms; i++) {
32045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (e->terms[i].type == YASM_EXPR_SYM
32145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    && (used & (1<<i)) == 0) {
32245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (value->rel || ssym_not_ok)
32345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        return 1;
32445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    value->rel = e->terms[i].data.sym;
32545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* and replace with 0 */
32645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    e->terms[i].type = YASM_EXPR_INT;
32745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    e->terms[i].data.intn = yasm_intnum_create_uint(0);
32845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
32945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
33045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
33145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SHR:
33245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Okay for single symrec in LHS and constant on RHS.
33345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * Single symrecs are not okay on RHS.
33445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * If RHS is non-constant, don't allow single symrec on LHS.
33545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * XXX: should rshift be an expr instead??
33645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
33745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
338a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            /* Check for single sym on LHS */
339a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            if (e->terms[0].type != YASM_EXPR_SYM)
340a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                break;
34145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
342a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            /* If we already have a sym, we can't take another one */
343a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            if (value->rel || ssym_not_ok)
344a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                return 1;
34545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
346a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            /* RHS must be a positive integer */
34745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (e->terms[1].type != YASM_EXPR_INT)
34845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;       /* can't shift sym by non-constant integer */
34945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            shamt = yasm_intnum_get_uint(e->terms[1].data.intn);
35045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if ((shamt + value->rshift) > YASM_VALUE_RSHIFT_MAX)
35145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;       /* total shift would be too large */
352a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
353a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            /* Update value */
35445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            value->rshift += shamt;
355a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            value->rel = e->terms[0].data.sym;
356a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
357a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            /* Replace symbol with 0 */
358a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            e->terms[0].type = YASM_EXPR_INT;
359a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            e->terms[0].data.intn = yasm_intnum_create_uint(0);
36045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
36145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Just leave SHR in place */
36245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
36345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_SEG:
36445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Okay for single symrec (can only be done once).
36545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * Not okay for anything BUT a single symrec as an immediate
36645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * child.
36745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
36845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (e->terms[0].type != YASM_EXPR_SYM)
36945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
37045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
37145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (value->seg_of)
37245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;       /* multiple SEG not legal */
37345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            value->seg_of = 1;
37445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
37545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (value->rel || ssym_not_ok)
37645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;       /* got a relative portion somewhere else? */
37745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            value->rel = e->terms[0].data.sym;
37845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
37945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* replace with ident'ed 0 */
38045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->op = YASM_EXPR_IDENT;
38145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[0].type = YASM_EXPR_INT;
38245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[0].data.intn = yasm_intnum_create_uint(0);
38345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
38445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case YASM_EXPR_WRT:
38545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Okay for single symrec in LHS and either a register or single
38645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * symrec (as an immediate child) on RHS.
38745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * If a single symrec on RHS, can only be done once.
38845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * WRT reg is left in expr for arch to look at.
38945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
39045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
39145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Handle RHS */
39245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            switch (e->terms[1].type) {
39345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case YASM_EXPR_SYM:
39445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (value->wrt)
39545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        return 1;
39645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    value->wrt = e->terms[1].data.sym;
39745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* and drop the WRT portion */
39845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    e->op = YASM_EXPR_IDENT;
39945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    e->numterms = 1;
40045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    break;
40145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case YASM_EXPR_REG:
40245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    break;  /* ignore */
40345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                default:
40445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    return 1;
40545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
40645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
40745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Handle LHS */
40845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            switch (e->terms[0].type) {
40945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case YASM_EXPR_SYM:
41045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (value->rel || ssym_not_ok)
41145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        return 1;
41245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    value->rel = e->terms[0].data.sym;
41345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* and replace with 0 */
41445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    e->terms[0].type = YASM_EXPR_INT;
41545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    e->terms[0].data.intn = yasm_intnum_create_uint(0);
41645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    break;
41745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case YASM_EXPR_EXPR:
41845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* recurse */
41945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    return value_finalize_scan(value, e->terms[0].data.expn,
42045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                               expr_precbc, ssym_not_ok);
42145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                default:
42245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    break;  /* ignore */
42345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
42445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
42545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
42645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
42745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Single symrec not allowed anywhere */
42845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            for (i=0; i<e->numterms; i++) {
42945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                switch (e->terms[i].type) {
43045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    case YASM_EXPR_SYM:
43145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        return 1;
43245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    case YASM_EXPR_EXPR:
43345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        /* recurse */
43445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        return value_finalize_scan(value,
43545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                                   e->terms[i].data.expn,
43645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                                   expr_precbc, 1);
43745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    default:
43845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        break;
43945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
44045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
44145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
44245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
44345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
44445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
44545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
44645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
44745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
44845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_value_finalize_expr(yasm_value *value, yasm_expr *e,
44945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                         yasm_bytecode *precbc, unsigned int size)
45045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
45145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!e) {
45245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_value_initialize(value, NULL, size);
45345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
45445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
455d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    yasm_value_initialize(value, e, size);
456d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    return yasm_value_finalize(value, precbc);
457d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org}
458d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org
459d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.orgint
460d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.orgyasm_value_finalize(yasm_value *value, yasm_bytecode *precbc)
461d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org{
462d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    if (!value->abs)
463d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org        return 0;
46445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
465d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);
46645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
46745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* quit early if there was an issue in simplify() */
46845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (yasm_error_occurred())
46945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 1;
47045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
47145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Strip top-level AND masking to an all-1s mask the same size
47245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * of the value size.  This allows forced avoidance of overflow warnings.
47345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
47445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->abs->op == YASM_EXPR_AND) {
47545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        int term;
47645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
47745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Calculate 1<<size - 1 value */
47845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum *mask = yasm_intnum_create_uint(1);
47945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum *mask_tmp = yasm_intnum_create_uint(value->size);
48045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum_calc(mask, YASM_EXPR_SHL, mask_tmp);
48145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum_set_uint(mask_tmp, 1);
48245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum_calc(mask, YASM_EXPR_SUB, mask_tmp);
48345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum_destroy(mask_tmp);
48445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
48545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Walk terms and delete matching masks */
48645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for (term=value->abs->numterms-1; term>=0; term--) {
48745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (value->abs->terms[term].type == YASM_EXPR_INT &&
48845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum_compare(value->abs->terms[term].data.intn,
48945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                    mask) == 0) {
49045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Delete the intnum */
49145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum_destroy(value->abs->terms[term].data.intn);
49245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
49345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Slide everything to its right over by 1 */
49445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (term != value->abs->numterms-1) /* if it wasn't last.. */
49545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    memmove(&value->abs->terms[term],
49645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            &value->abs->terms[term+1],
49745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            (value->abs->numterms-1-term)*
49845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                sizeof(yasm_expr__item));
49945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
50045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Update numterms */
50145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                value->abs->numterms--;
50245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
50345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Indicate warnings have been disabled */
50445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                value->no_warn = 1;
50545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
50645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
50745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->abs->numterms == 1)
50845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            value->abs->op = YASM_EXPR_IDENT;
50945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum_destroy(mask);
51045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
51145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
51245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Handle trivial (IDENT) cases immediately */
51345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->abs->op == YASM_EXPR_IDENT) {
51445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        switch (value->abs->terms[0].type) {
51545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_INT:
51645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
51745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_expr_destroy(value->abs);
51845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    value->abs = NULL;
51945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
52045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 0;
52145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_REG:
52245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_FLOAT:
52345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 0;
52445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_SYM:
52545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                value->rel = value->abs->terms[0].data.sym;
52645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_expr_destroy(value->abs);
52745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                value->abs = NULL;
52845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 0;
52945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case YASM_EXPR_EXPR:
53045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Bring up lower values. */
53145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                while (value->abs->op == YASM_EXPR_IDENT
53245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                       && value->abs->terms[0].type == YASM_EXPR_EXPR) {
53345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_expr *sube = value->abs->terms[0].data.expn;
53445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_xfree(value->abs);
53545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    value->abs = sube;
53645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
53745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
53845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            default:
53945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_internal_error(N_("unexpected expr term type"));
54045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
54145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
54245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
54345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value_finalize_scan(value, value->abs, precbc, 0))
54445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 1;
54545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
54645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, 0, NULL, NULL);
54745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
54845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Simplify 0 in abs to NULL */
54945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->abs->op == YASM_EXPR_IDENT
55045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        && value->abs->terms[0].type == YASM_EXPR_INT
55145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        && yasm_intnum_is_zero(value->abs->terms[0].data.intn)) {
55245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_expr_destroy(value->abs);
55345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        value->abs = NULL;
55445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
55545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
55645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
55745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
55845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_intnum *
55945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_value_get_intnum(yasm_value *value, yasm_bytecode *bc, int calc_bc_dist)
56045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
56145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
56245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@only@*/ yasm_intnum *outval;
56345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int sym_local;
56445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
56545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->abs) {
56645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Handle integer expressions, if non-integer or too complex, return
56745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * NULL.
56845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
56945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        intn = yasm_expr_get_intnum(&value->abs, calc_bc_dist);
57045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (!intn)
57145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return NULL;
57245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
57345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
57445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->rel) {
57545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* If relative portion is not in bc section, return NULL.
57645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * Otherwise get the relative portion's offset.
57745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
57845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /*@dependent@*/ yasm_bytecode *rel_prevbc;
57945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        unsigned long dist;
58045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
58145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (!bc)
58245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return NULL;    /* Can't calculate relative value */
58345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
58445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
58545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->wrt || value->seg_of || value->section_rel || !sym_local)
58645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return NULL;    /* we can't handle SEG, WRT, or external symbols */
58745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (rel_prevbc->section != bc->section)
58845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return NULL;    /* not in this section */
58945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (!value->curpos_rel)
59045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return NULL;    /* not PC-relative */
59145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
59245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Calculate value relative to current assembly position */
59345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        dist = yasm_bc_next_offset(rel_prevbc);
59445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (dist < bc->offset) {
59545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            outval = yasm_intnum_create_uint(bc->offset - dist);
59645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
59745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else {
59845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            dist -= bc->offset;
59945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            outval = yasm_intnum_create_uint(dist);
60045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
60145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
60245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->rshift > 0) {
60345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /*@only@*/ yasm_intnum *shamt =
60445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum_create_uint((unsigned long)value->rshift);
60545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
60645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_intnum_destroy(shamt);
60745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
60845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Add in absolute portion */
60945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (intn)
61045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_intnum_calc(outval, YASM_EXPR_ADD, intn);
61145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return outval;
61245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
61345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
61445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (intn)
61545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return yasm_intnum_copy(intn);
61645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
61745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* No absolute or relative portions: output 0 */
61845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return yasm_intnum_create_uint(0);
61945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
62045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
62145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
62245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
62345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        size_t destsize, yasm_bytecode *bc, int warn,
62445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        yasm_arch *arch)
62545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
62645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
62745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@only@*/ yasm_intnum *outval;
62845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int sym_local;
62945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int retval = 1;
63045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned int valsize = value->size;
63145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
63245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->no_warn)
63345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        warn = 0;
63445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
63545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->abs) {
63645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Handle floating point expressions */
63745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (!value->rel && value->abs->op == YASM_EXPR_IDENT
63845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            && value->abs->terms[0].type == YASM_EXPR_FLOAT) {
63945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (yasm_arch_floatnum_tobytes(arch, value->abs->terms[0].data.flt,
64045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                           buf, destsize, valsize, 0, warn))
64145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return -1;
64245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
64345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
64445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
64545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
64645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Check for complex float expressions */
64745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (yasm_expr__contains(value->abs, YASM_EXPR_FLOAT)) {
64845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_error_set(YASM_ERROR_FLOATING_POINT,
64945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                           N_("floating point expression too complex"));
65045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return -1;
65145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
65245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
65345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Handle normal integer expressions */
65445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        intn = yasm_expr_get_intnum(&value->abs, 1);
65545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
65645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (!intn) {
65745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Second try before erroring: yasm_expr_get_intnum doesn't handle
65845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * SEG:OFF, so try simplifying out any to just the OFF portion,
65945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * then getting the intnum again.
66045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
66145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_expr *seg = yasm_expr_extract_deep_segoff(&value->abs);
66245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (seg)
66345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_expr_destroy(seg);
66445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            intn = yasm_expr_get_intnum(&value->abs, 1);
66545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
66645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
66745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (!intn) {
66845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Still don't have an integer! */
66945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_error_set(YASM_ERROR_TOO_COMPLEX,
67045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                           N_("expression too complex"));
67145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return -1;
67245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
67345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
67445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
67545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Adjust warn for signed/unsigned integer warnings */
67645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (warn != 0)
67745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        warn = value->sign ? -1 : 1;
67845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
67945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->rel) {
68045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* If relative portion is not in bc section, don't try to handle it
68145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * here.  Otherwise get the relative portion's offset.
68245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
68345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /*@dependent@*/ yasm_bytecode *rel_prevbc;
68445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        unsigned long dist;
68545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
68645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
68745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->wrt || value->seg_of || value->section_rel || !sym_local)
68845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return 0;       /* we can't handle SEG, WRT, or external symbols */
68945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (rel_prevbc->section != bc->section)
69045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return 0;       /* not in this section */
69145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (!value->curpos_rel)
69245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return 0;       /* not PC-relative */
69345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
69445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Calculate value relative to current assembly position */
69545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        dist = yasm_bc_next_offset(rel_prevbc);
69645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (dist < bc->offset) {
69745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            outval = yasm_intnum_create_uint(bc->offset - dist);
69845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
69945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else {
70045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            dist -= bc->offset;
70145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            outval = yasm_intnum_create_uint(dist);
70245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
70345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
70445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->rshift > 0) {
70545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /*@only@*/ yasm_intnum *shamt =
70645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum_create_uint((unsigned long)value->rshift);
70745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
70845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_intnum_destroy(shamt);
70945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
71045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Add in absolute portion */
71145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (intn)
71245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_intnum_calc(outval, YASM_EXPR_ADD, intn);
71345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Output! */
71445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
71545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                     bc, warn))
71645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            retval = -1;
71745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum_destroy(outval);
71845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return retval;
71945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
72045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
72145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->seg_of || value->rshift || value->curpos_rel || value->ip_rel
72245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        || value->section_rel)
72345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;   /* We can't handle this with just an absolute */
72445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
72545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (intn) {
72645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Output just absolute portion */
72745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, 0, bc,
72845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                     warn))
72945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            retval = -1;
73045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    } else {
73145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* No absolute or relative portions: output 0 */
73245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        outval = yasm_intnum_create_uint(0);
73345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize, 0,
73445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                     bc, warn))
73545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            retval = -1;
73645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_intnum_destroy(outval);
73745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
73845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return retval;
73945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
74045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
74145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
74245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_value_print(const yasm_value *value, FILE *f, int indent_level)
74345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
74445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*s%u-bit, %ssigned", indent_level, "", value->size,
74545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            value->sign ? "" : "un");
74645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sAbsolute portion=", indent_level, "");
74745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_expr_print(value->abs, f);
74845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "\n");
74945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (value->rel) {
75045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        fprintf(f, "%*sRelative to=%s%s\n", indent_level, "",
75145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                value->seg_of ? "SEG " : "",
75245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_symrec_get_name(value->rel));
75345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->wrt)
75445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "%*s(With respect to=%s)\n", indent_level, "",
75545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_symrec_get_name(value->wrt));
75645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->rshift > 0)
75745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "%*s(Right shifted by=%u)\n", indent_level, "",
75845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    value->rshift);
75945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->curpos_rel)
76045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "%*s(Relative to current position)\n", indent_level,
76145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    "");
76245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->ip_rel)
76345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "%*s(IP-relative)\n", indent_level, "");
76445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->jump_target)
76545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "%*s(Jump target)\n", indent_level, "");
76645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->section_rel)
76745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "%*s(Section-relative)\n", indent_level, "");
76845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (value->no_warn)
76945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "%*s(Overflow warnings disabled)\n", indent_level, "");
77045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
77145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
772