groundwork for further features and possible cleanups.
Note: this commit changes the way in which relocations in the
COFF/Win32/Win64 target can be forced to reference a different symbol than
is being pointed to; instead of the ambiguous "trap+(trap.end-trap)" to get
the reloc to point at trap.end but reference the trap symbol, after this
commit "trap.end wrt trap" is the way to say this. This also reads a lot
more clearly and is not ambiguous. This should really only affect people
who write .pdata sections for Win64. See the
objfmts/win64/tests/win64-dataref.asm testcase for an example of usage.
This cleanup adds a new data structure, yasm_value, which is used for all
expressions that can be potentially relocatable. This data structure
splits the absolute portion of the expression away from the relative
portion and any modifications to the relative portion (SEG, WRT,
PC-relative, etc). A large amount of code in the new value module breaks
a general expression into its absolute and relative parts
(yasm_value_finalize_expr) and provides a common set of code for writing
out non-relocated values (yasm_value_output_basic).
All bytecode handling in both libyasm and the architecture modules was
rewritten to use yasm_values when appropriate (e.g. data values,
immediates, and effective addresses). The yasm_output_expr_func is now
yasm_output_value_func and all users and implementors (mainly in object
formats) have been updated to handle yasm_values.
Simultaneously with this change, yasm_effaddr and yasm_immval full
structure definitions have been moved from bc-int.h to bytecode.h.
The data hiding provided by bc-int.h was relatively minimal and probably
overkill. Also, great simplifications have been made to x86 effective
address expression handling.
svn path=/trunk/yasm/; revision=1419
libyasm/bytecode.o \
libyasm/errwarn.o \
libyasm/expr.o \
+ libyasm/value.o \
libyasm/file.o \
libyasm/floatnum.o \
libyasm/hamt.o \
libyasm/bytecode.o \
libyasm/errwarn.o \
libyasm/expr.o \
+ libyasm/value.o \
libyasm/file.o \
libyasm/floatnum.o \
libyasm/hamt.o \
BasicRuntimeChecks="3"/>\r
</FileConfiguration>\r
</File>\r
+ <File\r
+ RelativePath="..\..\..\libyasm\value.c">\r
+ </File>\r
<File\r
RelativePath="..\..\..\libyasm\xmalloc.c">\r
<FileConfiguration\r
<File\r
RelativePath="..\..\..\libyasm\valparam.h">\r
</File>\r
+ <File\r
+ RelativePath="..\..\..\libyasm\value.h">\r
+ </File>\r
</Filter>\r
</Files>\r
<Globals>\r
/>\r
</FileConfiguration>\r
</File>\r
+ <File\r
+ RelativePath="..\..\..\libyasm\value.c"\r
+ >\r
+ </File>\r
<File\r
RelativePath="..\..\..\libyasm\xmalloc.c"\r
>\r
RelativePath="..\..\..\libyasm\valparam.h"\r
>\r
</File>\r
+ <File\r
+ RelativePath="..\..\..\libyasm\value.h"\r
+ >\r
+ </File>\r
</Filter>\r
</Files>\r
<Globals>\r
#include <libyasm/intnum.h>
#include <libyasm/floatnum.h>
#include <libyasm/expr.h>
+#include <libyasm/value.h>
#include <libyasm/symrec.h>
#include <libyasm/bytecode.h>
libyasm_a_SOURCES += libyasm/bytecode.c
libyasm_a_SOURCES += libyasm/expr.c
+libyasm_a_SOURCES += libyasm/value.c
libyasm_a_SOURCES += libyasm/symrec.c
libyasm_a_SOURCES += libyasm/file.c
libyasm_a_SOURCES += libyasm/section.c
modinclude_HEADERS += libyasm/errwarn.h
modinclude_HEADERS += libyasm/expr.h
modinclude_HEADERS += libyasm/expr-int.h
+modinclude_HEADERS += libyasm/value.h
modinclude_HEADERS += libyasm/symrec.h
modinclude_HEADERS += libyasm/linemgr.h
modinclude_HEADERS += libyasm/coretype.h
size_t valsize, size_t shift, int warn,
unsigned long line);
- /** Module-level implementation of yasm_arch_intnum_fixup_rel().
- * Call yasm_arch_intnum_fixup_rel() instead of calling this function.
- */
- int (*intnum_fixup_rel) (yasm_arch *arch, yasm_intnum *intn,
- size_t valsize, const yasm_bytecode *bc,
- unsigned long line);
-
/** Module-level implementation of yasm_arch_intnum_tobytes().
* Call yasm_arch_intnum_tobytes() instead of calling this function.
*/
size_t valsize, size_t shift, int warn,
unsigned long line);
-/** Adjust #yasm_intnum for relative displacement from bc. Displacement
- * is modified in-place.
- * \param arch architecture
- * \param intn integer value
- * \param valsize size (in bits)
- * \param bc bytecode being output ("parent" of value)
- * \param line virtual line; may be 0 if warn is 0
- * \return Nonzero on error.
- */
-int yasm_arch_intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn,
- size_t valsize, const yasm_bytecode *bc,
- unsigned long line);
-
/** Output #yasm_intnum to buffer. Puts the value into the least
* significant bits of the destination, or may be shifted into more
* significant bits by the shift parameter. The destination bits are
warn, line) \
((yasm_arch_base *)arch)->module->floatnum_tobytes \
(arch, flt, buf, destsize, valsize, shift, warn, line)
-#define yasm_arch_intnum_fixup_rel(arch, intn, valsize, bc, line) \
- ((yasm_arch_base *)arch)->module->intnum_fixup_rel \
- (arch, intn, valsize, bc, line)
#define yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, shift, \
bc, warn, line) \
((yasm_arch_base *)arch)->module->intnum_tobytes \
#ifndef YASM_BC_INT_H
#define YASM_BC_INT_H
-typedef struct yasm_effaddr_callback {
- void (*destroy) (yasm_effaddr *ea);
- void (*print) (const yasm_effaddr *ea, FILE *f, int indent_level);
-} yasm_effaddr_callback;
-
-struct yasm_effaddr {
- const yasm_effaddr_callback *callback; /* callback functions */
-
- /*@only@*/ /*@null@*/ yasm_expr *disp; /* address displacement */
- unsigned long segreg; /* segment register override (0 if none) */
- unsigned char len; /* length of disp (in bytes), 0 if unknown,
- * 0xff if unknown and required to be >0.
- */
- unsigned char nosplit; /* 1 if reg*2 should not be split into
- reg+reg. (0 if not) */
- unsigned char strong; /* 1 if effective address is *definitely*
- * an effective address, e.g. in GAS if
- * expr(,1) form is used vs. just expr.
- */
-};
-
-struct yasm_immval {
- /*@only@*/ /*@null@*/ yasm_expr *val;
-
- unsigned char len; /* final length (in bytes), 0 if unknown */
- unsigned char sign; /* 1 if final imm is treated as signed */
-};
-
typedef struct yasm_bytecode_callback {
void (*destroy) (/*@only@*/ void *contents);
void (*print) (const void *contents, FILE *f, int indent_level);
yasm_bc_resolve_flags (*resolve)
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
} yasm_bytecode_callback;
#include "errwarn.h"
#include "intnum.h"
#include "expr.h"
+#include "value.h"
+#include "symrec.h"
#include "bytecode.h"
#include "arch.h"
struct yasm_dataval {
/*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link;
- enum { DV_EMPTY, DV_EXPR, DV_STRING } type;
+ enum { DV_EMPTY, DV_VALUE, DV_STRING } type;
union {
- /*@only@*/ yasm_expr *expn;
+ yasm_value val;
struct {
/*@only@*/ char *contents;
size_t len;
} bytecode_leb128;
typedef struct bytecode_reserve {
- /*@only@*/ yasm_expr *numitems; /* number of items to reserve */
+ /*@only@*/ /*@null@*/ yasm_expr *numitems; /* number of items to reserve */
unsigned char itemsize; /* size of each item (in bytes) */
} bytecode_reserve;
static void bc_data_destroy(void *contents);
static void bc_data_print(const void *contents, FILE *f, int indent_level);
+static void bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
static yasm_bc_resolve_flags bc_data_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_leb128_destroy(void *contents);
static yasm_bc_resolve_flags bc_leb128_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_leb128_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_reserve_destroy(void *contents);
static void bc_reserve_print(const void *contents, FILE *f, int indent_level);
+static void bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
static yasm_bc_resolve_flags bc_reserve_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_incbin_destroy(void *contents);
static void bc_incbin_print(const void *contents, FILE *f, int indent_level);
+static void bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
static yasm_bc_resolve_flags bc_incbin_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_align_destroy(void *contents);
static yasm_bc_resolve_flags bc_align_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_org_destroy(void *contents);
static void bc_org_print(const void *contents, FILE *f, int indent_level);
+static void bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
static yasm_bc_resolve_flags bc_org_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void bc_insn_destroy(void *contents);
static yasm_bc_resolve_flags bc_insn_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
/* Standard bytecode callback structures */
static const yasm_bytecode_callback bc_data_callback = {
bc_data_destroy,
bc_data_print,
- yasm_bc_finalize_common,
+ bc_data_finalize,
bc_data_resolve,
bc_data_tobytes
};
static const yasm_bytecode_callback bc_reserve_callback = {
bc_reserve_destroy,
bc_reserve_print,
- yasm_bc_finalize_common,
+ bc_reserve_finalize,
bc_reserve_resolve,
bc_reserve_tobytes
};
static const yasm_bytecode_callback bc_incbin_callback = {
bc_incbin_destroy,
bc_incbin_print,
- yasm_bc_finalize_common,
+ bc_incbin_finalize,
bc_incbin_resolve,
bc_incbin_tobytes
};
static const yasm_bytecode_callback bc_org_callback = {
bc_org_destroy,
bc_org_print,
- yasm_bc_finalize_common,
+ bc_org_finalize,
bc_org_resolve,
bc_org_tobytes
};
yasm_immval *
-yasm_imm_create_int(unsigned long int_val, unsigned long line)
-{
- return yasm_imm_create_expr(
- yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(int_val)),
- line));
-}
-
-yasm_immval *
-yasm_imm_create_expr(yasm_expr *expr_ptr)
+yasm_imm_create_expr(yasm_expr *e)
{
yasm_immval *im = yasm_xmalloc(sizeof(yasm_immval));
- im->val = expr_ptr;
+ if (yasm_value_finalize_expr(&im->val, e))
+ yasm__error(e->line, N_("immediate expression too complex"));
im->len = 0;
im->sign = 0;
}
const yasm_expr *
-yasm_ea_get_disp(const yasm_effaddr *ptr)
+yasm_ea_get_disp(const yasm_effaddr *ea)
{
- return ptr->disp;
+ return ea->disp.abs;
}
void
* an explicit override, where we expect the user knows what they're doing.
*/
- ptr->len = (unsigned char)len;
+ ptr->disp_len = (unsigned char)len;
}
void
yasm_ea_destroy(yasm_effaddr *ea)
{
ea->callback->destroy(ea);
- yasm_expr_destroy(ea->disp);
+ yasm_value_delete(&ea->disp);
yasm_xfree(ea);
}
/*@=nullstate@*/
void
yasm_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level)
{
- fprintf(f, "%*sDisp=", indent_level, "");
- yasm_expr_print(ea->disp, f);
- fprintf(f, "\n%*sLen=%u\n", indent_level, "", (unsigned int)ea->len);
+ fprintf(f, "%*sDisp:\n", indent_level, "");
+ yasm_value_print(&ea->disp, f, indent_level+1);
+ fprintf(f, "%*sLen=%u\n", indent_level, "", (unsigned int)ea->disp_len);
fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit);
ea->callback->print(ea, f, indent_level);
}
yasm_dvs_print(&bc_data->datahead, f, indent_level+2);
}
+static void
+bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ bytecode_data *bc_data = (bytecode_data *)bc->contents;
+ yasm_dataval *dv;
+
+ /* Convert values from simple expr to value. */
+ STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+ if (dv->type == DV_VALUE) {
+ if (yasm_value_finalize(&dv->data.val))
+ yasm__error(bc->line, N_("expression too complex"));
+ }
+ }
+}
+
static yasm_bc_resolve_flags
bc_data_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
switch (dv->type) {
case DV_EMPTY:
break;
- case DV_EXPR:
+ case DV_VALUE:
bc->len += bc_data->size;
break;
case DV_STRING:
static int
bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
bytecode_data *bc_data = (bytecode_data *)bc->contents;
switch (dv->type) {
case DV_EMPTY:
break;
- case DV_EXPR:
- if (output_expr(&dv->data.expn, *bufp, bc_data->size,
- (size_t)(bc_data->size*8), 0,
- (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d))
+ case DV_VALUE:
+ if (output_value(&dv->data.val, *bufp, bc_data->size,
+ (size_t)(bc_data->size*8), 0,
+ (unsigned long)(*bufp-bufp_orig), bc, 1, d))
return 1;
*bufp += bc_data->size;
break;
switch (dv->type) {
case DV_EMPTY:
break;
- case DV_EXPR:
- intn = yasm_expr_get_intnum(&dv->data.expn, NULL);
+ case DV_VALUE:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
if (!intn) {
yasm__error(bc->line,
N_("LEB128 requires constant values"));
static int
bc_leb128_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
bytecode_leb128 *bc_leb128 = (bytecode_leb128 *)bc->contents;
switch (dv->type) {
case DV_EMPTY:
break;
- case DV_EXPR:
- intn = yasm_expr_get_intnum(&dv->data.expn, NULL);
+ case DV_VALUE:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
if (!intn)
yasm_internal_error(N_("non-constant in leb128_tobytes"));
*bufp += yasm_intnum_get_leb128(intn, *bufp, bc_leb128->sign);
(unsigned int)reserve->itemsize);
}
+static void
+bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
+ yasm_value val;
+
+ if (yasm_value_finalize_expr(&val, reserve->numitems))
+ yasm__error(bc->line, N_("expression too complex"));
+ else if (val.rel)
+ yasm__error(bc->line, N_("reserve expression not absolute"));
+ else if (val.abs && yasm_expr__contains(val.abs, YASM_EXPR_FLOAT))
+ yasm__error(bc->line,
+ N_("expression must not contain floating point value"));
+ reserve->numitems = val.abs;
+}
+
static yasm_bc_resolve_flags
bc_reserve_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
yasm_expr **tempp;
/*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+ if (!reserve->numitems)
+ return YASM_BC_RESOLVE_MIN_LEN;
+
if (save) {
temp = NULL;
tempp = &reserve->numitems;
/* For reserve, just say non-constant quantity instead of allowing
* the circular reference error to filter through.
*/
- if (temp && yasm_expr__contains(temp, YASM_EXPR_FLOAT))
- yasm__error(bc->line,
- N_("expression must not contain floating point value"));
- else
- yasm__error(bc->line,
- N_("attempt to reserve non-constant quantity of space"));
+ yasm__error(bc->line,
+ N_("attempt to reserve non-constant quantity of space"));
retval = YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
} else
bc->len += yasm_intnum_get_uint(num)*reserve->itemsize;
static int
bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
yasm_internal_error(N_("bc_reserve_tobytes called"));
fprintf(f, "\n");
}
+static void
+bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+ bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+ yasm_value val;
+
+ if (yasm_value_finalize_expr(&val, incbin->start))
+ yasm__error(bc->line, N_("start expression too complex"));
+ else if (val.rel)
+ yasm__error(bc->line, N_("start expression not absolute"));
+ incbin->start = val.abs;
+
+ if (yasm_value_finalize_expr(&val, incbin->maxlen))
+ yasm__error(bc->line, N_("maximum length expression too complex"));
+ else if (val.rel)
+ yasm__error(bc->line, N_("maximum length expression not absolute"));
+ incbin->maxlen = val.abs;
+}
+
static yasm_bc_resolve_flags
bc_incbin_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
static int
bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
bytecode_align *align = (bytecode_align *)bc->contents;
fprintf(f, "%*sStart=%lu\n", indent_level, "", org->start);
}
+static void
+bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+{
+}
+
static yasm_bc_resolve_flags
bc_org_resolve(yasm_bytecode *bc, int save,
yasm_calc_bc_dist_func calc_bc_dist)
static int
bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
bytecode_org *org = (bytecode_org *)bc->contents;
{
bytecode_insn *insn = (bytecode_insn *)bc->contents;
int i;
+ int error = 0;
yasm_insn_operand *op;
/* Simplify the operands' expressions first. */
case YASM_INSN__OPERAND_MEMORY:
/* Don't get over-ambitious here; some archs' memory expr
* parser are sensitive to the presence of *1, etc, so don't
- * simplify identities.
+ * simplify reg*1 identities.
*/
if (op->data.ea)
- op->data.ea->disp =
- yasm_expr__level_tree(op->data.ea->disp, 1, 0, NULL,
- NULL, NULL, NULL);
+ op->data.ea->disp.abs =
+ yasm_expr__level_tree(op->data.ea->disp.abs, 1, 1, 0,
+ NULL, NULL, NULL, NULL, &error);
+ if (error) {
+ /* Follow up error with a pointer to where it was used */
+ yasm__error(bc->line, N_("(used in memory expression)"));
+ return;
+ }
break;
case YASM_INSN__OPERAND_IMM:
- op->data.val = yasm_expr_simplify(op->data.val, NULL);
+ op->data.val =
+ yasm_expr__level_tree(op->data.val, 1, 1, 1, NULL, NULL,
+ NULL, NULL, &error);
+ if (error) {
+ /* Follow up error with a pointer to where it was used */
+ yasm__error(bc->line,
+ N_("(used in immediate expression)"));
+ return;
+ }
break;
default:
break;
static int
bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
yasm_internal_error(N_("bc_insn_tobytes() is not implemented"));
{
if (bc->callback)
bc->callback->finalize(bc, prev_bc);
+ if (bc->multiple) {
+ yasm_value val;
+
+ if (yasm_value_finalize_expr(&val, bc->multiple))
+ yasm__error(bc->line, N_("multiple expression too complex"));
+ else if (val.rel)
+ yasm__error(bc->line, N_("multiple expression not absolute"));
+ bc->multiple = val.abs;
+ }
}
/*@null@*/ yasm_intnum *
-yasm_common_calc_bc_dist(/*@null@*/ yasm_bytecode *precbc1,
- /*@null@*/ yasm_bytecode *precbc2)
+yasm_common_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2)
{
- unsigned int dist;
+ unsigned long dist;
yasm_intnum *intn;
- if (precbc2) {
- dist = precbc2->offset + precbc2->len;
- if (precbc1) {
- if (dist < precbc1->offset + precbc1->len) {
- intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len
- - dist);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
- return intn;
- }
- dist -= precbc1->offset + precbc1->len;
- }
- return yasm_intnum_create_uint(dist);
- } else {
- if (precbc1) {
- intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
- return intn;
- } else {
- return yasm_intnum_create_uint(0);
- }
+ if (precbc1->section != precbc2->section)
+ return NULL;
+
+ dist = precbc2->offset + precbc2->len;
+ if (dist < precbc1->offset + precbc1->len) {
+ intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len - dist);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
+ return intn;
}
+ dist -= precbc1->offset + precbc1->len;
+ return yasm_intnum_create_uint(dist);
}
yasm_bc_resolve_flags
/*@null@*/ /*@only@*/ unsigned char *
yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
/*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,
- void *d, yasm_output_expr_func output_expr,
+ void *d, yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc)
/*@sets *buf@*/
{
if (!bc->callback)
yasm_internal_error(N_("got empty bytecode in bc_tobytes"));
else
- error = bc->callback->tobytes(bc, &destbuf, d, output_expr,
+ error = bc->callback->tobytes(bc, &destbuf, d, output_value,
output_reloc);
if (!error && ((unsigned long)(destbuf - origbuf) != datasize))
}
yasm_dataval *
-yasm_dv_create_expr(yasm_expr *expn)
+yasm_dv_create_expr(yasm_expr *e)
{
yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
- retval->type = DV_EXPR;
- retval->data.expn = expn;
+ retval->type = DV_VALUE;
+ yasm_value_initialize(&retval->data.val, e);
return retval;
}
while (cur) {
next = STAILQ_NEXT(cur, link);
switch (cur->type) {
- case DV_EXPR:
- yasm_expr_destroy(cur->data.expn);
+ case DV_VALUE:
+ yasm_value_delete(&cur->data.val);
break;
case DV_STRING:
yasm_xfree(cur->data.str.contents);
case DV_EMPTY:
fprintf(f, "%*sEmpty\n", indent_level, "");
break;
- case DV_EXPR:
- fprintf(f, "%*sExpr=", indent_level, "");
- yasm_expr_print(cur->data.expn, f);
- fprintf(f, "\n");
+ case DV_VALUE:
+ fprintf(f, "%*sValue:\n", indent_level, "");
+ yasm_value_print(&cur->data.val, f, indent_level+1);
break;
case DV_STRING:
fprintf(f, "%*sLength=%lu\n", indent_level, "",
#ifndef YASM_BYTECODE_H
#define YASM_BYTECODE_H
-/** An effective address (opaque type). */
+/** An effective address. */
typedef struct yasm_effaddr yasm_effaddr;
-/** An immediate value (opaque type). */
-typedef struct yasm_immval yasm_immval;
+
+/** Callbacks for effective address implementations. */
+typedef struct yasm_effaddr_callback {
+ /** Destroy the effective address (freeing it).
+ * \param ea effective address
+ */
+ void (*destroy) (/*@only@*/ yasm_effaddr *ea);
+
+ /** Print the effective address.
+ * \param ea effective address
+ * \param f file to output to
+ * \param indent_level indentation level
+ */
+ void (*print) (const yasm_effaddr *ea, FILE *f, int indent_level);
+} yasm_effaddr_callback;
+
+/** An effective address. */
+struct yasm_effaddr {
+ const yasm_effaddr_callback *callback; /**< callback functions */
+
+ yasm_value disp; /**< address displacement */
+
+ unsigned long segreg; /**< segment register override (0 if none) */
+
+ unsigned char disp_len; /**< length of disp (in bytes), 0 if unknown,
+ * 0xff if unknown and required to be >0.
+ */
+ unsigned char need_disp; /**< 1 if a displacement should be present
+ * in the output.
+ */
+ unsigned char nosplit; /**< 1 if reg*2 should not be split into
+ * reg+reg. (0 if not)
+ */
+ unsigned char strong; /**< 1 if effective address is *definitely*
+ * an effective address, e.g. in GAS if
+ * expr(,1) form is used vs. just expr.
+ */
+};
+
+/** An immediate value. */
+typedef struct yasm_immval {
+ yasm_value val; /**< the immediate value itself */
+
+ unsigned char len; /**< final length (in bytes), 0 if unknown */
+ unsigned char sign; /**< 1 if final imm is treated as signed */
+} yasm_immval;
+
/** A data value (opaque type). */
typedef struct yasm_dataval yasm_dataval;
/** A list of data values (opaque type). */
YASM_BC_RESOLVE_UNKNOWN_LEN = 1<<2 /**< Length indeterminate. */
} yasm_bc_resolve_flags;
-/** Create an immediate value from an unsigned integer.
- * \param int_val unsigned integer
- * \param line virtual line (from yasm_linemap)
- * \return Newly allocated immediate value.
- */
-/*@only@*/ yasm_immval *yasm_imm_create_int(unsigned long int_val,
- unsigned long line);
-
/** Create an immediate value from an expression.
* \param e expression (kept, do not free).
* \return Newly allocated immediate value.
* yasm_expr output functions.
* \see yasm_calc_bc_dist_func for parameter descriptions.
*/
-/*@null@*/ yasm_intnum *yasm_common_calc_bc_dist
- (/*@null@*/ yasm_bytecode *precbc1, /*@null@*/ yasm_bytecode *precbc2);
+/*@null@*/ /*@only@*/ yasm_intnum *yasm_common_calc_bc_dist
+ (yasm_bytecode *precbc1, yasm_bytecode *precbc2);
/** Resolve labels in a bytecode, and calculate its length.
* Tries to minimize the length as much as possible.
* \param gap if nonzero, indicates the data does not really need to
* exist in the object file; if nonzero, contents of buf
* are undefined [output]
- * \param d data to pass to each call to output_expr/output_reloc
- * \param output_expr function to call to convert expressions into their byte
+ * \param d data to pass to each call to output_value/output_reloc
+ * \param output_value function to call to convert values into their byte
* representation
* \param output_reloc function to call to output relocation entries
* for a single sym
/*@null@*/ /*@only@*/ unsigned char *yasm_bc_tobytes
(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
/*@out@*/ unsigned long *multiple, /*@out@*/ int *gap, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc)
/*@sets *buf@*/;
*/
typedef struct yasm_floatnum yasm_floatnum;
+/** A value. May be absolute or relative. Outside the parser, yasm_expr
+ * should only be used for absolute exprs. Anything that could contain
+ * a relocatable value should use this structure instead.
+ * \see value.h for related functions.
+ */
+typedef struct yasm_value {
+ /** The absolute portion of the value. May contain *differences* between
+ * symrecs but not standalone symrecs. May be NULL if there is no
+ * absolute portion (e.g. the absolute portion is 0).
+ */
+ /*@null@*/ /*@only@*/ yasm_expr *abs;
+
+ /** The relative portion of the value. This is the portion that may
+ * need to generate a relocation. May be NULL if no relative portion.
+ */
+ /*@null@*/ /*@dependent@*/ yasm_symrec *rel;
+
+ /** What the relative portion is in reference to. NULL if the default. */
+ /*@null@*/ /*@dependent@*/ yasm_symrec *wrt;
+
+ /** If the segment of the relative portion should be used, not the
+ * relative portion itself. Boolean.
+ */
+ unsigned int seg_of : 1;
+
+ /** If the relative portion of the value should be shifted right
+ * (supported only by a few object formats). If just the absolute portion
+ * should be shifted, that must be in the abs expr, not here!
+ */
+ unsigned int rshift : 7;
+
+ /** Indicates the relative portion of the value should be relocated
+ * relative to the current assembly position rather than relative to the
+ * section start. "Current assembly position" here refers to the starting
+ * address of the bytecode containing this value. Boolean.
+ */
+ unsigned int curpos_rel : 1;
+} yasm_value;
+
+/** Maximum value of #yasm_value.rshift */
+#define YASM_VALUE_RSHIFT_MAX 127
+
/** Line number mapping repository (opaque type). \see linemgr.h for related
* functions.
*/
* \return Distance in bytes between the two bytecodes (bc2-bc1), or NULL if
* the distance was indeterminate.
*/
-typedef /*@null@*/ yasm_intnum * (*yasm_calc_bc_dist_func)
+typedef /*@null@*/ /*@only@*/ yasm_intnum * (*yasm_calc_bc_dist_func)
(yasm_bytecode *precbc1, yasm_bytecode *precbc2);
-/** Convert yasm_expr to its byte representation. Usually implemented by
+/** Convert yasm_value to its byte representation. Usually implemented by
* object formats to keep track of relocations and verify legal expressions.
* Must put the value into the least significant bits of the destination,
* unless shifted into more significant bits by the shift parameter. The
* destination bits must be cleared before being set.
- * \param ep (double) pointer to expression
+ * \param value value
* \param buf buffer for byte representation
* \param destsize destination size (in bytes)
* \param valsize size (in bits)
* \param shift left shift (in bits); may be negative to specify right
* shift (standard warnings include truncation to boundary)
* \param offset offset (in bytes) of the expr contents from the start
- * of the bytecode (sometimes needed for conditional jumps)
+ * of the bytecode (needed for relative)
* \param bc current bytecode (usually passed into higher-level
* calling function)
- * \param rel if nonzero, expr should be treated as PC/IP-relative
* \param warn enables standard warnings: zero for none;
* nonzero for overflow/underflow floating point warnings;
* negative for signed integer warnings,
* function)
* \return Nonzero if an error occurred, 0 otherwise.
*/
-typedef int (*yasm_output_expr_func)
- (yasm_expr **ep, /*@out@*/ unsigned char *buf, size_t destsize,
+typedef int (*yasm_output_value_func)
+ (yasm_value *value, /*@out@*/ unsigned char *buf, size_t destsize,
size_t valsize, int shift, unsigned long offset, yasm_bytecode *bc,
- int rel, int warn, /*@null@*/ void *d) /*@uses *ep@*/;
+ int warn, /*@null@*/ void *d) /*@uses *ep@*/;
/** Convert a symbol reference to its byte representation. Usually implemented
* by object formats and debug formats to keep track of relocations generated
* NOTE: Really designed to only be used by expr_level_op().
*/
static int
-expr_simplify_identity(yasm_expr *e, int numterms, int int_term)
+expr_simplify_identity(yasm_expr *e, int numterms, int int_term,
+ int simplify_reg_mul)
{
int i;
+ int save_numterms;
- /* Check for simple identities that delete the intnum.
- * Don't delete if the intnum is the only thing in the expn.
+ /* Don't do this step if it's 1*REG. Save and restore numterms so
+ * yasm_expr__contains() works correctly.
*/
- if ((int_term == 0 && numterms > 1 &&
- expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) ||
- (int_term > 0 &&
- expr_can_destroy_int_right(e->op, e->terms[int_term].data.intn))) {
- /* Delete the intnum */
- yasm_intnum_destroy(e->terms[int_term].data.intn);
-
- /* Slide everything to its right over by 1 */
- if (int_term != numterms-1) /* if it wasn't last.. */
- memmove(&e->terms[int_term], &e->terms[int_term+1],
- (numterms-1-int_term)*sizeof(yasm_expr__item));
-
- /* Update numterms */
- numterms--;
+ save_numterms = e->numterms;
+ e->numterms = numterms;
+ if (simplify_reg_mul || e->op != YASM_EXPR_MUL
+ || !yasm_intnum_is_pos1(e->terms[int_term].data.intn)
+ || !yasm_expr__contains(e, YASM_EXPR_REG)) {
+ /* Check for simple identities that delete the intnum.
+ * Don't delete if the intnum is the only thing in the expn.
+ */
+ if ((int_term == 0 && numterms > 1 &&
+ expr_can_destroy_int_left(e->op, e->terms[0].data.intn)) ||
+ (int_term > 0 &&
+ expr_can_destroy_int_right(e->op, e->terms[int_term].data.intn))) {
+ /* Delete the intnum */
+ yasm_intnum_destroy(e->terms[int_term].data.intn);
+
+ /* Slide everything to its right over by 1 */
+ if (int_term != numterms-1) /* if it wasn't last.. */
+ memmove(&e->terms[int_term], &e->terms[int_term+1],
+ (numterms-1-int_term)*sizeof(yasm_expr__item));
+
+ /* Update numterms */
+ numterms--;
+ }
}
+ e->numterms = save_numterms;
/* Check for simple identites that delete everything BUT the intnum.
* Don't bother if the intnum is the only thing in the expn.
/*@-mustfree@*/
static /*@only@*/ yasm_expr *
expr_level_op(/*@returned@*/ /*@only@*/ yasm_expr *e, int fold_const,
- int simplify_ident)
+ int simplify_ident, int simplify_reg_mul)
{
int i, j, o, fold_numterms, level_numterms, level_fold_numterms;
int first_int_term = -1;
if (simplify_ident) {
int new_fold_numterms;
/* Simplify identities and make IDENT if possible. */
- new_fold_numterms = expr_simplify_identity(e, fold_numterms,
- first_int_term);
+ new_fold_numterms =
+ expr_simplify_identity(e, fold_numterms, first_int_term,
+ simplify_reg_mul);
level_numterms -= fold_numterms-new_fold_numterms;
fold_numterms = new_fold_numterms;
}
/* Simplify identities, make IDENT if possible, and save to e->numterms. */
if (simplify_ident && first_int_term != -1) {
e->numterms = expr_simplify_identity(e, level_numterms,
- first_int_term);
+ first_int_term, simplify_reg_mul);
} else {
e->numterms = level_numterms;
if (level_numterms == 1)
/* Level an entire expn tree, expanding equ's as we go */
yasm_expr *
yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
- yasm_calc_bc_dist_func calc_bc_dist,
+ int simplify_reg_mul, yasm_calc_bc_dist_func calc_bc_dist,
yasm_expr_xform_func expr_xform_extra,
- void *expr_xform_extra_data, yasm__exprhead *eh)
+ void *expr_xform_extra_data, yasm__exprhead *eh,
+ int *error)
{
int i;
yasm__exprhead eh_local;
SLIST_FOREACH(np, eh, next) {
if (np->e == equ_expr) {
yasm__error(e->line,
- N_("circular reference detected."));
+ N_("circular reference detected"));
+ if (error)
+ *error = 1;
return e;
}
}
SLIST_FOREACH(np, eh, next) {
if (np->e == start) {
yasm__error(e->line,
- N_("circular reference detected."));
+ N_("circular reference detected"));
+ if (error)
+ *error = 1;
return e;
}
}
if (e->terms[i].type == YASM_EXPR_EXPR)
e->terms[i].data.expn =
yasm_expr__level_tree(e->terms[i].data.expn, fold_const,
- simplify_ident, calc_bc_dist,
- expr_xform_extra, expr_xform_extra_data,
- eh);
+ simplify_ident, simplify_reg_mul,
+ calc_bc_dist, expr_xform_extra,
+ expr_xform_extra_data, eh, error);
if (ee.e) {
SLIST_REMOVE_HEAD(eh, next);
}
/* do callback */
- e = expr_level_op(e, fold_const, simplify_ident);
+ e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul);
if (calc_bc_dist || expr_xform_extra) {
if (calc_bc_dist)
e = expr_xform_bc_dist(e, calc_bc_dist);
if (expr_xform_extra)
e = expr_xform_extra(e, expr_xform_extra_data);
- e = yasm_expr__level_tree(e, fold_const, simplify_ident, NULL, NULL,
- NULL, NULL);
+ e = yasm_expr__level_tree(e, fold_const, simplify_ident,
+ simplify_reg_mul, NULL, NULL, NULL, NULL,
+ error);
}
return e;
}
return 0;
}
-yasm_symrec *
-yasm_expr_extract_symrec(yasm_expr **ep,
- yasm_symrec_relocate_action relocate_action,
- yasm_calc_bc_dist_func calc_bc_dist)
-{
- yasm_symrec *sym = NULL;
- int i, symterm = -1;
-
- switch ((*ep)->op) {
- case YASM_EXPR_IDENT:
- /* Be kind, recurse */
- if ((*ep)->terms[0].type == YASM_EXPR_EXPR)
- return yasm_expr_extract_symrec(&((*ep)->terms[0].data.expn),
- relocate_action, calc_bc_dist);
- /* Replace sym with 0 value, return sym */
- if ((*ep)->terms[0].type == YASM_EXPR_SYM ||
- (*ep)->terms[0].type == YASM_EXPR_SYMEXP) {
- sym = (*ep)->terms[0].data.sym;
- symterm = 0;
- }
- break;
- case YASM_EXPR_ADD:
- /* Search for sym, if found, delete it from expr and return it */
- for (i=0; i<(*ep)->numterms; i++) {
- if ((*ep)->terms[i].type == YASM_EXPR_SYM ||
- (*ep)->terms[i].type == YASM_EXPR_SYMEXP) {
- sym = (*ep)->terms[i].data.sym;
- symterm = i;
- break;
- }
- }
- break;
- default:
- break;
- }
- if (sym) {
- /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
- /*@null@*/ yasm_intnum *intn;
-
- if (yasm_symrec_get_label(sym, &precbc)
- && (relocate_action == YASM_SYMREC_REPLACE_VALUE ||
- (relocate_action == YASM_SYMREC_REPLACE_VALUE_IF_LOCAL
- && yasm_symrec_get_visibility(sym) == YASM_SYM_LOCAL))) {
- intn = calc_bc_dist(yasm_section_bcs_first(
- yasm_bc_get_section(precbc)), precbc);
- if (!intn)
- return NULL;
- } else
- intn = yasm_intnum_create_uint(0);
- (*ep)->terms[symterm].type = YASM_EXPR_INT;
- (*ep)->terms[symterm].data.intn = intn;
- }
- return sym;
-}
-
-yasm_expr *
-yasm_expr_extract_seg(yasm_expr **ep)
-{
- yasm_expr *e = *ep;
-
- /* If not SEG, we can't do this transformation */
- if (e->op != YASM_EXPR_SEG)
- return NULL;
-
- /* Remove the SEG by changing the expression into an IDENT */
- e->op = YASM_EXPR_IDENT;
-
- return e;
-}
-
yasm_expr *
yasm_expr_extract_segoff(yasm_expr **ep)
{
return retval;
}
-yasm_expr *
-yasm_expr_extract_shr(yasm_expr **ep)
-{
- yasm_expr *retval;
- yasm_expr *e = *ep;
-
- /* If not SHR, we can't do this transformation */
- if (e->op != YASM_EXPR_SHR)
- return NULL;
-
- /* Extract the right side portion out to its own expression */
- if (e->terms[1].type == YASM_EXPR_EXPR)
- retval = e->terms[1].data.expn;
- else {
- /* Need to build IDENT expression to hold non-expression contents */
- retval = yasm_xmalloc(sizeof(yasm_expr));
- retval->op = YASM_EXPR_IDENT;
- retval->numterms = 1;
- retval->terms[0] = e->terms[1]; /* structure copy */
- }
-
- /* Delete the right side portion by changing the expr into an IDENT */
- e->op = YASM_EXPR_IDENT;
- e->numterms = 1;
-
- return retval;
-}
-
/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
yasm_intnum *
yasm_expr_get_intnum(yasm_expr **ep, yasm_calc_bc_dist_func calc_bc_dist)
}
/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
-/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
-const yasm_floatnum *
-yasm_expr_get_floatnum(yasm_expr **ep)
-{
- *ep = yasm_expr_simplify(*ep, NULL);
-
- if ((*ep)->op == YASM_EXPR_IDENT &&
- (*ep)->terms[0].type == YASM_EXPR_FLOAT)
- return (*ep)->terms[0].data.flt;
- else
- return (yasm_floatnum *)NULL;
-}
-/*@=unqualifiedtrans =nullderef -nullstate -onlytrans@*/
-
/*@-unqualifiedtrans -nullderef -nullstate -onlytrans@*/
const yasm_symrec *
yasm_expr_get_symrec(yasm_expr **ep, int simplify)
* \param e expression
* \param fold_const enable constant folding if nonzero
* \param simplify_ident simplify identities
+ * \param simplify_reg_mul simplify REG*1 identities
* \param calc_bc_dist bytecode distance-calculation function
* \param expr_xform_extra extra transformation function
* \param expr_xform_extra_data data to pass to expr_xform_extra
* \param eh call with NULL (for internal use in recursion)
+ * \param error if non-NULL, set to 1 if an error is encountered
+ * (e.g. circular reference errors)
* \return Leveled expression.
*/
/*@only@*/ /*@null@*/ yasm_expr *yasm_expr__level_tree
(/*@returned@*/ /*@only@*/ /*@null@*/ yasm_expr *e, int fold_const,
- int simplify_ident, /*@null@*/ yasm_calc_bc_dist_func calc_bc_dist,
+ int simplify_ident, int simplify_reg_mul,
+ /*@null@*/ yasm_calc_bc_dist_func calc_bc_dist,
/*@null@*/ yasm_expr_xform_func expr_xform_extra,
- /*@null@*/ void *expr_xform_extra_data, /*@null@*/ yasm__exprhead *eh);
+ /*@null@*/ void *expr_xform_extra_data, /*@null@*/ yasm__exprhead *eh,
+ /*@null@*/ int *error);
/** Simplify an expression as much as possible. Eliminates extraneous
* branches and simplifies integer-only subexpressions. Simplified version
* \return Simplified expression.
*/
#define yasm_expr_simplify(e, cbd) \
- yasm_expr__level_tree(e, 1, 1, cbd, NULL, NULL, NULL)
-
-/** Relocation actions for yasm_expr_extract_symrec(). */
-typedef enum yasm_symrec_relocate_action {
- YASM_SYMREC_REPLACE_ZERO = 0, /**< Replace the symbol with 0 */
- YASM_SYMREC_REPLACE_VALUE, /**< Replace with symbol's value (offset)
- * if symbol is a label.
- */
- YASM_SYMREC_REPLACE_VALUE_IF_LOCAL /**< Replace with symbol's value only
- * if symbol is label and declared
- * local.
- */
-} yasm_symrec_relocate_action;
-
-/** Extract a single symbol out of an expression. Replaces it with 0, or
- * optionally the symbol's value (if it's a label).
- * \param ep expression (pointer to)
- * \param relocate_action replacement action to take on symbol in expr
- * \param calc_bc_dist bytecode distance-calculation function
- * \return NULL if unable to extract a symbol (too complex of expr, none
- * present, etc); otherwise returns the extracted symbol.
- */
-/*@dependent@*/ /*@null@*/ yasm_symrec *yasm_expr_extract_symrec
- (yasm_expr **ep, yasm_symrec_relocate_action relocate_action,
- yasm_calc_bc_dist_func calc_bc_dist);
-
-/** Remove the SEG unary operator if present, leaving the lower level
- * expression.
- * \param ep expression (pointer to)
- * \return NULL if the expression does not have a top-level operator of SEG;
- * otherwise the modified input expression (without the SEG).
- */
-/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_seg(yasm_expr **ep);
+ yasm_expr__level_tree(e, 1, 1, 1, cbd, NULL, NULL, NULL, NULL)
/** Extract the segment portion of a SEG:OFF expression, leaving the offset.
* \param ep expression (pointer to)
*/
/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_wrt(yasm_expr **ep);
-/** Extract the right portion (y) of a x SHR y expression, leaving the left
- * portion (x).
- * \param ep expression (pointer to)
- * \return NULL if unable to extract (YASM_EXPR_SHR not the top-level
- * operator), otherwise the right side of the SHR expression. The
- * input expression is modified such that on return, it's the left side
- * of the SHR expression.
- */
-/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_shr(yasm_expr **ep);
-
/** Get the integer value of an expression if it's just an integer.
* \param ep expression (pointer to)
* \param calc_bc_dist bytecode distance-calculation function
/*@dependent@*/ /*@null@*/ yasm_intnum *yasm_expr_get_intnum
(yasm_expr **ep, /*@null@*/ yasm_calc_bc_dist_func calc_bc_dist);
-/** Get the floating point value of an expression if it's just an floatnum.
- * \param ep expression (pointer to)
- * \return NULL if the expression is too complex (contains anything other than
- * floats, ie integers, non-valued labels, registers); otherwise the
- * floatnum value of the expression.
- */
-/*@dependent@*/ /*@null@*/ const yasm_floatnum *yasm_expr_get_floatnum
- (yasm_expr **ep);
-
/** Get the symbol value of an expression if it's just a symbol.
* \param ep expression (pointer to)
* \param simplify if nonzero, simplify the expression first
EXTRA_DIST += libyasm/tests/unary.asm
EXTRA_DIST += libyasm/tests/unary.errwarn
EXTRA_DIST += libyasm/tests/unary.hex
+EXTRA_DIST += libyasm/tests/value-err.asm
+EXTRA_DIST += libyasm/tests/value-err.errwarn
check_PROGRAMS += bitvect_test
check_PROGRAMS += floatnum_test
--:1: circular reference detected.
+-:1: circular reference detected
+-:6: (used in memory expression)
--- /dev/null
+label:
+mov [label/2+1], ax
+mov ax, label*2
+mov [label+5], ax
+mov ax, label wrt foo
+foo:
+dd label
+dd label<<5
+dd label>>2
--- /dev/null
+-:2: effective address too complex
+-:3: immediate expression too complex
+-:8: expression too complex
--- /dev/null
+/*
+ * Value handling
+ *
+ * Copyright (C) 2006 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.
+ */
+#define YASM_LIB_INTERNAL
+#include "util.h"
+/*@unused@*/ RCSID("$Id$");
+
+#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"
+
+#include "expr-int.h"
+#include "bc-int.h"
+
+static int
+value_finalize_scan(yasm_value *value, yasm_expr *e, 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, ssym_not_ok))
+ return 1;
+ continue;
+ }
+
+ if (sube->terms[0].type == YASM_EXPR_INT &&
+ (sube->terms[1].type == YASM_EXPR_SYM ||
+ sube->terms[1].type == YASM_EXPR_SYMEXP)) {
+ intn = sube->terms[0].data.intn;
+ sym = sube->terms[1].data.sym;
+ } else if ((sube->terms[0].type == YASM_EXPR_SYM ||
+ sube->terms[0].type == YASM_EXPR_SYMEXP) &&
+ 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, ssym_not_ok))
+ return 1;
+ continue;
+ }
+
+ if (!yasm_intnum_is_neg1(intn)) {
+ if (value_finalize_scan(value, sube, ssym_not_ok))
+ return 1;
+ continue;
+ }
+
+ if (!yasm_symrec_get_label(sym, &precbc)) {
+ if (value_finalize_scan(value, sube, 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
+ || e->terms[j].type == YASM_EXPR_SYMEXP)
+ && 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 */
+ }
+ }
+ }
+
+ /* 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
+ || e->terms[i].type == YASM_EXPR_SYMEXP)
+ && (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 not allowed cases on RHS */
+ switch (e->terms[1].type) {
+ case YASM_EXPR_REG:
+ case YASM_EXPR_FLOAT:
+ return 1; /* not legal */
+ case YASM_EXPR_SYM:
+ case YASM_EXPR_SYMEXP:
+ return 1;
+ case YASM_EXPR_EXPR:
+ if (value_finalize_scan(value, e->terms[1].data.expn, 1))
+ return 1;
+ break;
+ default:
+ break;
+ }
+
+ /* Check for single sym and allowed cases on LHS */
+ switch (e->terms[0].type) {
+ /*case YASM_EXPR_REG: ????? should this be illegal ????? */
+ case YASM_EXPR_FLOAT:
+ return 1; /* not legal */
+ case YASM_EXPR_SYM:
+ case YASM_EXPR_SYMEXP:
+ 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 */
+ if (value_finalize_scan(value, e->terms[0].data.expn,
+ ssym_not_ok))
+ return 1;
+ break;
+ default:
+ break; /* ignore */
+ }
+
+ /* Handle RHS */
+ if (!value->rel)
+ break; /* no handling needed */
+ 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 */
+ value->rshift += shamt;
+
+ /* 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
+ && e->terms[0].type != YASM_EXPR_SYMEXP)
+ 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:
+ case YASM_EXPR_SYMEXP:
+ 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:
+ case YASM_EXPR_SYMEXP:
+ 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,
+ 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:
+ case YASM_EXPR_SYMEXP:
+ return 1;
+ case YASM_EXPR_EXPR:
+ /* recurse */
+ return value_finalize_scan(value,
+ e->terms[i].data.expn, 1);
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int
+yasm_value_finalize_expr(yasm_value *value, yasm_expr *e)
+{
+ int error = 0;
+
+ if (!e) {
+ yasm_value_initialize(value, NULL);
+ return 0;
+ }
+
+ yasm_value_initialize(value, yasm_expr__level_tree
+ (e, 1, 1, 0, NULL, NULL, NULL, NULL, &error));
+
+ /* quit early if there was an issue in simplify() */
+ if (error)
+ return 1;
+
+ /* 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:
+ case YASM_EXPR_SYMEXP:
+ 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, 0))
+ return 1;
+
+ value->abs = yasm_expr__level_tree(value->abs, 1, 1, 0, NULL, NULL, NULL,
+ 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;
+}
+
+int
+yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
+ size_t destsize, size_t valsize, int shift,
+ yasm_bytecode *bc, int warn, yasm_arch *arch,
+ yasm_calc_bc_dist_func calc_bc_dist)
+{
+ /*@dependent@*/ /*@null@*/ yasm_intnum *intn = NULL;
+ /*@only@*/ yasm_intnum *outval;
+ int sym_local;
+ int retval = 1;
+
+ 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 (shift < 0)
+ yasm_internal_error(N_("attempting to negative shift a float"));
+ if (yasm_arch_floatnum_tobytes(arch, value->abs->terms[0].data.flt,
+ buf, destsize, valsize,
+ (unsigned int)shift, warn,
+ bc->line))
+ return -1;
+ else
+ return 1;
+ }
+
+ /* Check for complex float expressions */
+ if (yasm_expr__contains(value->abs, YASM_EXPR_FLOAT)) {
+ yasm__error(bc->line, N_("floating point expression too complex"));
+ return -1;
+ }
+
+ /* Handle integer expressions */
+ intn = yasm_expr_get_intnum(&value->abs, calc_bc_dist);
+ if (!intn) {
+ yasm__error(bc->line, N_("expression too complex"));
+ return -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 || !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 = rel_prevbc->offset + rel_prevbc->len;
+ if (dist < bc->offset) {
+ outval = yasm_intnum_create_uint(bc->offset - dist);
+ yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL, bc->line);
+ } 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, bc->line);
+ yasm_intnum_destroy(shamt);
+ }
+ /* Add in absolute portion */
+ if (intn)
+ yasm_intnum_calc(outval, YASM_EXPR_ADD, intn, bc->line);
+ /* Output! */
+ if (yasm_arch_intnum_tobytes(arch, outval, buf, destsize, valsize,
+ shift, bc, warn, bc->line))
+ retval = -1;
+ yasm_intnum_destroy(outval);
+ } else if (intn) {
+ /* Output just absolute portion */
+ if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize,
+ shift, bc, warn, bc->line))
+ 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,
+ shift, bc, warn, bc->line))
+ retval = -1;
+ yasm_intnum_destroy(outval);
+ }
+ return retval;
+}
+
+void
+yasm_value_print(const yasm_value *value, FILE *f, int indent_level)
+{
+ 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,
+ "");
+ }
+}
--- /dev/null
+/**
+ * \file libyasm/value.h
+ * \brief YASM value interface.
+ *
+ * \rcs
+ * $Id$
+ * \endrcs
+ *
+ * \license
+ * Copyright (C) 2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - 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.
+ * \endlicense
+ */
+#ifndef YASM_VALUE_H
+#define YASM_VALUE_H
+
+/** Initialize a #yasm_value with just an expression. No processing is
+ * performed, the expression is simply stuck into value.abs and the other
+ * fields are initialized. Use yasm_expr_extract_value() to perform "smart"
+ * processing into a #yasm_value. This function is intended for use during
+ * parsing simply to ensure all fields of the value are initialized; after
+ * the parse is complete, yasm_value_extract() should be called to finalize
+ * the value.
+ * \param value value to be initialized
+ * \param e expression (kept)
+ */
+void yasm_value_initialize(/*@out@*/ yasm_value *value,
+ /*@null@*/ /*@kept@*/ yasm_expr *e);
+
+/** Initialize a #yasm_value with just a symrec. No processing is performed,
+ * the symrec is simply stuck into value.rel and the other fields are
+ * initialized.
+ * \param value value to be initialized
+ * \param sym symrec
+ */
+void yasm_value_init_sym(/*@out@*/ yasm_value *value,
+ /*@null@*/ yasm_symrec *sym);
+
+/** Frees any memory inside value; does not free value itself.
+ * \param value value
+ */
+void yasm_value_delete(yasm_value *value);
+
+/** Perform yasm_value_finalize_expr() on a value that already exists from
+ * being initialized with yasm_value_initialize().
+ * \param value value
+ * \return Nonzero if value could not be split.
+ */
+int yasm_value_finalize(yasm_value *value);
+
+/** Break a #yasm_expr into a #yasm_value constituent parts. Extracts
+ * the relative portion of the value, SEG and WRT portions, and top-level
+ * right shift, if any. Places the remaining expr into the absolute
+ * portion of the value. Essentially a combination of yasm_value_initialize()
+ * and yasm_value_finalize(). First expands references to symrecs in
+ * absolute sections by expanding with the absolute section start plus the
+ * symrec offset within the absolute section.
+ * \param value value to store split portions into
+ * \param e expression input
+ * \return Nonzero if the expr could not be split into a value for some
+ * reason (e.g. the relative portion was not added, but multiplied,
+ * etc).
+ * \caution Do not use e after this call. Even if an error is returned, e
+ * is stored into value.
+ * \note This should only be called after the parse is complete. Calling
+ * before the parse is complete will usually result in an error return.
+ */
+int yasm_value_finalize_expr(/*@out@*/ yasm_value *value,
+ /*@null@*/ /*@kept@*/ yasm_expr *e);
+
+/** Output value if constant or PC-relative section-local. This should be
+ * used from objfmt yasm_output_value_func() functions.
+ * functions.
+ * \param value value
+ * \param buf buffer for byte representation
+ * \param destsize destination size (in bytes)
+ * \param valsize size (in bits)
+ * \param shift left shift (in bits); may be negative to specify right
+ * shift (standard warnings include truncation to boundary)
+ * \param bc current bytecode (usually passed into higher-level
+ * calling function)
+ * \param warn enables standard warnings: zero for none;
+ * nonzero for overflow/underflow floating point warnings;
+ * negative for signed integer warnings,
+ * positive for unsigned integer warnings
+ * \param arch architecture
+ * \param calc_bc_dist function used to determine bytecode distance
+ * \note Adds in value.rel (correctly) if PC-relative and in the same section
+ * as bc (and there is no WRT or SEG); if this is not the desired
+ * behavior, e.g. a reloc is needed in this case, don't use this
+ * function!
+ * \return 0 if no value output due to value needing relocation;
+ * 1 if value output; -1 if error.
+ */
+int yasm_value_output_basic
+ (yasm_value *value, /*@out@*/ unsigned char *buf, size_t destsize,
+ size_t valsize, int shift, yasm_bytecode *bc, int warn, yasm_arch *arch,
+ yasm_calc_bc_dist_func calc_bc_dist);
+
+/** Print a value. For debugging purposes.
+ * \param value value
+ * \param indent_level indentation level
+ * \param f file
+ */
+void yasm_value_print(const yasm_value *value, FILE *f, int indent_level);
+
+
+#ifndef YASM_DOXYGEN
+#define yasm_value_initialize(value, e) \
+ do { \
+ (value)->abs = e; \
+ (value)->rel = NULL; \
+ (value)->wrt = NULL; \
+ (value)->seg_of = 0; \
+ (value)->rshift = 0; \
+ (value)->curpos_rel = 0; \
+ } while(0)
+
+#define yasm_value_init_sym(value, sym) \
+ do { \
+ (value)->abs = NULL; \
+ (value)->rel = sym; \
+ (value)->wrt = NULL; \
+ (value)->seg_of = 0; \
+ (value)->rshift = 0; \
+ (value)->curpos_rel = 0; \
+ } while(0)
+
+#define yasm_value_delete(value) \
+ do { \
+ yasm_expr_destroy((value)->abs); \
+ (value)->abs = NULL; \
+ (value)->rel = NULL; \
+ } while(0)
+
+#define yasm_value_finalize(value) \
+ yasm_value_finalize_expr(value, (value)->abs)
+#endif
+
+#endif
lc3b_get_fill,
yasm_lc3b__finalize_insn,
lc3b_floatnum_tobytes,
- yasm_lc3b__intnum_fixup_rel,
yasm_lc3b__intnum_tobytes,
lc3b_get_reg_size,
lc3b_reggroup_get_reg,
/* Bytecode types */
typedef struct lc3b_insn {
- /*@null@*/ yasm_expr *imm; /* immediate or relative value */
+ yasm_value imm; /* immediate or relative value */
lc3b_imm_type imm_type; /* size of the immediate */
- /*@null@*/ /*@dependent@*/ yasm_symrec *origin; /* PC origin if needed */
+ /* PC origin if needed */
+ /*@null@*/ /*@dependent@*/ yasm_bytecode *origin_prevbc;
unsigned int opcode; /* opcode */
} lc3b_insn;
/*@null@*/ yasm_insn_operands *operands, int num_prefixes,
unsigned long **prefixes, int num_segregs, const unsigned long *segregs);
-int yasm_lc3b__intnum_fixup_rel
- (yasm_arch *arch, yasm_intnum *intn, size_t valsize,
- const yasm_bytecode *bc, unsigned long line);
-
int yasm_lc3b__intnum_tobytes
(yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf,
size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc,
static yasm_bc_resolve_flags lc3b_bc_insn_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- void *d, yasm_output_expr_func output_expr,
+ void *d, yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
/* Bytecode callback structures */
lc3b_bc_insn_destroy(void *contents)
{
lc3b_insn *insn = (lc3b_insn *)contents;
- if (insn->imm)
- yasm_expr_destroy(insn->imm);
+ yasm_value_delete(&insn->imm);
yasm_xfree(contents);
}
fprintf(f, "%*s_Instruction_\n", indent_level, "");
fprintf(f, "%*sImmediate Value:", indent_level, "");
- if (!insn->imm)
+ if (!insn->imm.abs)
fprintf(f, " (nil)\n");
else {
indent_level++;
- fprintf(f, "\n%*sVal=", indent_level, "");
- yasm_expr_print(insn->imm, f);
- fprintf(f, "\n%*sType=", indent_level, "");
+ fprintf(f, "\n");
+ yasm_value_print(&insn->imm, f, indent_level);
+ fprintf(f, "%*sType=", indent_level, "");
switch (insn->imm_type) {
case LC3B_IMM_NONE:
fprintf(f, "NONE-SHOULDN'T HAPPEN");
}
indent_level--;
}
+ /* FIXME
fprintf(f, "\n%*sOrigin=", indent_level, "");
if (insn->origin) {
fprintf(f, "\n");
yasm_symrec_print(insn->origin, f, indent_level+1);
} else
fprintf(f, "(nil)\n");
+ */
fprintf(f, "%*sOpcode: %04x\n", indent_level, "",
(unsigned int)insn->opcode);
}
yasm_calc_bc_dist_func calc_bc_dist)
{
lc3b_insn *insn = (lc3b_insn *)bc->contents;
- /*@null@*/ yasm_expr *temp;
- /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+ yasm_bytecode *target_prevbc;
+ /*@only@*/ yasm_intnum *num;
long rel;
/* Fixed size instruction length */
if (insn->imm_type != LC3B_IMM_9_PC || !save)
return YASM_BC_RESOLVE_MIN_LEN;
- temp = yasm_expr_copy(insn->imm);
- temp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(temp),
- yasm_expr_sym(insn->origin), bc->line);
- num = yasm_expr_get_intnum(&temp, calc_bc_dist);
- if (!num) {
- yasm__error(bc->line, N_("target external or out of segment"));
+ if (!insn->imm.rel)
+ num = yasm_intnum_create_uint(0);
+ else if (!yasm_symrec_get_label(insn->imm.rel, &target_prevbc)
+ || target_prevbc->section != insn->origin_prevbc->section
+ || !(num = calc_bc_dist(insn->origin_prevbc, target_prevbc))) {
+ /* External or out of segment, so we can't check distance. */
+ return YASM_BC_RESOLVE_MIN_LEN;
+ }
+
+ if (insn->imm.abs) {
+ /*@only@*/ yasm_expr *temp = yasm_expr_copy(insn->imm.abs);
+ /*@dependent@*/ /*@null@*/ yasm_intnum *num2;
+ num2 = yasm_expr_get_intnum(&temp, calc_bc_dist);
+ if (!num2) {
+ yasm__error(bc->line, N_("jump target too complex"));
+ yasm_expr_destroy(temp);
+ return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
+ }
+ yasm_intnum_calc(num, YASM_EXPR_ADD, num2, bc->line);
yasm_expr_destroy(temp);
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
}
+
rel = yasm_intnum_get_int(num);
+ yasm_intnum_destroy(num);
rel -= 2;
- yasm_expr_destroy(temp);
/* 9-bit signed, word-multiple displacement */
if (rel < -512 || rel > 511) {
yasm__error(bc->line, N_("target out of range"));
static int
lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
lc3b_insn *insn = (lc3b_insn *)bc->contents;
+ /*@only@*/ yasm_intnum *delta;
/* Output opcode */
YASM_SAVE_16_L(*bufp, insn->opcode);
case LC3B_IMM_NONE:
break;
case LC3B_IMM_4:
- if (output_expr(&insn->imm, *bufp, 2, 4, 0, 0, bc, 0, 1, d))
+ if (output_value(&insn->imm, *bufp, 2, 4, 0, 0, bc, 1, d))
return 1;
break;
case LC3B_IMM_5:
- if (output_expr(&insn->imm, *bufp, 2, 5, 0, 0, bc, 0, 1, d))
+ if (output_value(&insn->imm, *bufp, 2, 5, 0, 0, bc, 1, d))
return 1;
break;
case LC3B_IMM_6_WORD:
- if (output_expr(&insn->imm, *bufp, 2, 6, -1, 0, bc, 0, 1, d))
+ if (output_value(&insn->imm, *bufp, 2, 6, -1, 0, bc, 1, d))
return 1;
break;
case LC3B_IMM_6_BYTE:
- if (output_expr(&insn->imm, *bufp, 2, 6, 0, 0, bc, 0, 1, d))
+ if (output_value(&insn->imm, *bufp, 2, 6, 0, 0, bc, 1, d))
return 1;
break;
case LC3B_IMM_8:
- if (output_expr(&insn->imm, *bufp, 2, 8, -1, 0, bc, 0, 1, d))
+ if (output_value(&insn->imm, *bufp, 2, 8, -1, 0, bc, 1, d))
return 1;
break;
case LC3B_IMM_9_PC:
- insn->imm = yasm_expr_create(YASM_EXPR_SUB,
- yasm_expr_expr(insn->imm), yasm_expr_sym(insn->origin),
- bc->line);
- if (output_expr(&insn->imm, *bufp, 2, 9, -1, 0, bc, 1, 1, d))
+ /* Adjust relative displacement to end of bytecode */
+ delta = yasm_intnum_create_int(-(long)bc->len);
+ if (!insn->imm.abs)
+ insn->imm.abs = yasm_expr_create_ident(yasm_expr_int(delta),
+ bc->line);
+ else
+ insn->imm.abs =
+ yasm_expr_create(YASM_EXPR_ADD,
+ yasm_expr_expr(insn->imm.abs),
+ yasm_expr_int(delta), bc->line);
+
+ if (output_value(&insn->imm, *bufp, 2, 9, -1, 0, bc, 1, d))
return 1;
break;
case LC3B_IMM_9:
- if (output_expr(&insn->imm, *bufp, 2, 9, -1, 0, bc, 0, 1, d))
+ if (output_value(&insn->imm, *bufp, 2, 9, -1, 0, bc, 1, d))
return 1;
break;
default:
return 0;
}
-int
-yasm_lc3b__intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn,
- size_t valsize, const yasm_bytecode *bc,
- unsigned long line)
-{
- yasm_intnum *delta;
- if (valsize != 9)
- yasm_internal_error(
- N_("tried to do PC-relative offset from invalid sized value"));
- delta = yasm_intnum_create_uint(bc->len);
- yasm_intnum_calc(intn, YASM_EXPR_SUB, delta, line);
- yasm_intnum_destroy(delta);
- return 0;
-}
-
int
yasm_lc3b__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
unsigned char *buf, size_t destsize, size_t valsize,
/* Copy what we can from info */
insn = yasm_xmalloc(sizeof(lc3b_insn));
- insn->imm = NULL;
+ yasm_value_initialize(&insn->imm, NULL);
insn->imm_type = LC3B_IMM_NONE;
- insn->origin = NULL;
+ insn->origin_prevbc = NULL;
insn->opcode = info->opcode;
/* Apply modifiers */
case OPA_Imm:
switch (op->type) {
case YASM_INSN__OPERAND_IMM:
- insn->imm = op->data.val;
+ if (yasm_value_finalize_expr(&insn->imm,
+ op->data.val))
+ yasm__error(bc->line,
+ N_("immediate expression too complex"));
break;
case YASM_INSN__OPERAND_REG:
- insn->imm = yasm_expr_create_ident(yasm_expr_int(
- yasm_intnum_create_uint(op->data.reg & 0x7)),
- bc->line);
+ if (yasm_value_finalize_expr(&insn->imm,
+ yasm_expr_create_ident(yasm_expr_int(
+ yasm_intnum_create_uint(op->data.reg & 0x7)),
+ bc->line)))
+ yasm_internal_error(N_("reg expr too complex?"));
break;
default:
yasm_internal_error(N_("invalid operand conversion"));
}
insn->imm_type = (info->operands[i] & OPI_MASK)>>3;
- if (insn->imm_type == LC3B_IMM_9_PC)
- insn->origin = yasm_symtab_define_label2("$", prev_bc, 0,
- bc->line);
+ if (insn->imm_type == LC3B_IMM_9_PC) {
+ insn->origin_prevbc = prev_bc;
+ if (insn->imm.seg_of || insn->imm.rshift
+ || insn->imm.curpos_rel)
+ yasm__error(bc->line, N_("invalid jump target"));
+ insn->imm.curpos_rel = 1;
+ }
}
}
- if (!insn->imm)
- insn->imm_type = LC3B_IMM_NONE;
-
/* Transform the bytecode */
yasm_lc3b__bc_transform_insn(bc, insn);
}
x86_get_fill,
yasm_x86__finalize_insn,
yasm_x86__floatnum_tobytes,
- yasm_x86__intnum_fixup_rel,
yasm_x86__intnum_tobytes,
yasm_x86__get_reg_size,
x86_reggroup_get_reg,
unsigned long reg, unsigned int bits,
x86_rex_bit_pos rexbit);
-void yasm_x86__ea_set_disponly(yasm_effaddr *ea);
-yasm_effaddr *yasm_x86__ea_create_reg(unsigned long reg, unsigned char *rex,
- unsigned int bits);
-yasm_effaddr *yasm_x86__ea_create_imm
+/* Effective address type */
+typedef struct x86_effaddr {
+ yasm_effaddr ea; /* base structure */
+
+ /* How the spare (register) bits in Mod/RM are handled:
+ * Even if valid_modrm=0, the spare bits are still valid (don't overwrite!)
+ * They're set in bytecode_create_insn().
+ */
+ unsigned char modrm;
+ unsigned char valid_modrm; /* 1 if Mod/RM byte currently valid, 0 if not */
+ unsigned char need_modrm; /* 1 if Mod/RM byte needed, 0 if not */
+
+ unsigned char sib;
+ unsigned char valid_sib; /* 1 if SIB byte currently valid, 0 if not */
+ unsigned char need_sib; /* 1 if SIB byte needed, 0 if not,
+ 0xff if unknown */
+} x86_effaddr;
+
+void yasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare,
+ unsigned long line);
+
+void yasm_x86__ea_set_disponly(x86_effaddr *x86_ea);
+x86_effaddr *yasm_x86__ea_create_reg(unsigned long reg, unsigned char *rex,
+ unsigned int bits);
+x86_effaddr *yasm_x86__ea_create_imm
(/*@keep@*/ yasm_expr *imm, unsigned int im_len);
yasm_effaddr *yasm_x86__ea_create_expr(yasm_arch *arch,
/*@keep@*/ yasm_expr *e);
-/*@observer@*/ /*@null@*/ yasm_effaddr *yasm_x86__bc_insn_get_ea
- (/*@null@*/ yasm_bytecode *bc);
-
void yasm_x86__bc_insn_opersize_override(yasm_bytecode *bc,
unsigned int opersize);
void yasm_x86__bc_insn_addrsize_override(yasm_bytecode *bc,
x86_common common; /* common x86 information */
x86_opcode opcode;
- /*@null@*/ yasm_effaddr *ea; /* effective address */
+ /*@null@*/ x86_effaddr *x86_ea; /* effective address */
/*@null@*/ yasm_immval *imm; /* immediate or relative value */
x86_common common; /* common x86 information */
x86_opcode shortop, nearop;
- yasm_expr *target; /* target location */
- /*@dependent@*/ yasm_symrec *origin; /* jump origin */
+ yasm_value target; /* jump target */
+ /*@dependent@*/ yasm_bytecode *origin_prevbc; /* jump origin */
/* which opcode are we using? */
/* The *FORCED forms are specified in the source as such */
x86_common common; /* common x86 information */
x86_opcode opcode;
- yasm_expr *segment; /* target segment */
- yasm_expr *offset; /* target offset */
+ yasm_value segment; /* target segment */
+ yasm_value offset; /* target offset */
} x86_jmpfar;
void yasm_x86__bc_transform_insn(yasm_bytecode *bc, x86_insn *insn);
(x86_common *common, unsigned char *rex, int num_prefixes,
unsigned long **prefixes, unsigned long line);
-void yasm_x86__ea_init(yasm_effaddr *ea, unsigned int spare,
- /*@null@*/ yasm_symrec *origin);
-
/* Check an effective address. Returns 0 if EA was successfully determined,
* 1 if invalid EA, or 2 if indeterminate EA.
*/
int yasm_x86__expr_checkea
- (yasm_expr **ep, unsigned char *addrsize, unsigned int bits,
- unsigned int nosplit, int address16_op, unsigned char *displen,
- unsigned char *modrm, unsigned char *v_modrm, unsigned char *n_modrm,
- unsigned char *sib, unsigned char *v_sib, unsigned char *n_sib,
- unsigned char *pcrel, unsigned char *rex,
- yasm_calc_bc_dist_func calc_bc_dist);
+ (x86_effaddr *x86_ea, unsigned char *addrsize, unsigned int bits,
+ int address16_op, unsigned char *rex,
+ yasm_calc_bc_dist_func calc_bc_dist, unsigned long line);
void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len,
unsigned long line);
(yasm_arch *arch, const yasm_floatnum *flt, unsigned char *buf,
size_t destsize, size_t valsize, size_t shift, int warn,
unsigned long line);
-int yasm_x86__intnum_fixup_rel
- (yasm_arch *arch, yasm_intnum *intn, size_t valsize,
- const yasm_bytecode *bc, unsigned long line);
int yasm_x86__intnum_tobytes
(yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf,
size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc,
#include "x86arch.h"
-/* Effective address type */
-
-typedef struct x86_effaddr {
- yasm_effaddr ea; /* base structure */
-
- /* PC-relative portions are for AMD64 only (RIP addressing) */
- /*@null@*/ /*@dependent@*/ yasm_symrec *origin; /* pcrel origin */
-
- /* How the spare (register) bits in Mod/RM are handled:
- * Even if valid_modrm=0, the spare bits are still valid (don't overwrite!)
- * They're set in bytecode_create_insn().
- */
- unsigned char modrm;
- unsigned char valid_modrm; /* 1 if Mod/RM byte currently valid, 0 if not */
- unsigned char need_modrm; /* 1 if Mod/RM byte needed, 0 if not */
-
- unsigned char sib;
- unsigned char valid_sib; /* 1 if SIB byte currently valid, 0 if not */
- unsigned char need_sib; /* 1 if SIB byte needed, 0 if not,
- 0xff if unknown */
-
- unsigned char pcrel; /* 1 if PC-relative transformation needed */
-} x86_effaddr;
-
/* Effective address callback function prototypes */
static void x86_ea_destroy(yasm_effaddr *ea);
static yasm_bc_resolve_flags x86_bc_insn_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- void *d, yasm_output_expr_func output_expr,
+ void *d, yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void x86_bc_jmp_destroy(void *contents);
static yasm_bc_resolve_flags x86_bc_jmp_resolve
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- void *d, yasm_output_expr_func output_expr,
+ void *d, yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void x86_bc_jmpfar_destroy(void *contents);
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int x86_bc_jmpfar_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
/* Effective address callback structures */
}
void
-yasm_x86__ea_init(yasm_effaddr *ea, unsigned int spare, yasm_symrec *origin)
+yasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare, unsigned long line)
{
- x86_effaddr *x86_ea = (x86_effaddr *)ea;
- x86_ea->origin = origin;
+ if (yasm_value_finalize(&x86_ea->ea.disp))
+ yasm__error(line, N_("effective address too complex"));
x86_ea->modrm &= 0xC7; /* zero spare/reg bits */
x86_ea->modrm |= (spare << 3) & 0x38; /* plug in provided bits */
}
void
-yasm_x86__ea_set_disponly(yasm_effaddr *ea)
+yasm_x86__ea_set_disponly(x86_effaddr *x86_ea)
{
- x86_effaddr *x86_ea = (x86_effaddr *)ea;
-
x86_ea->valid_modrm = 0;
x86_ea->need_modrm = 0;
x86_ea->valid_sib = 0;
x86_ea->need_sib = 0;
- x86_ea->pcrel = 0;
}
-yasm_effaddr *
+x86_effaddr *
yasm_x86__ea_create_reg(unsigned long reg, unsigned char *rex,
unsigned int bits)
{
x86_ea = yasm_xmalloc(sizeof(x86_effaddr));
x86_ea->ea.callback = &x86_ea_callback;
- x86_ea->ea.disp = (yasm_expr *)NULL;
- x86_ea->ea.len = 0;
+ yasm_value_initialize(&x86_ea->ea.disp, NULL);
+ x86_ea->ea.disp_len = 0;
+ x86_ea->ea.need_disp = 0;
x86_ea->ea.nosplit = 0;
x86_ea->ea.strong = 0;
x86_ea->ea.segreg = 0;
x86_ea->sib = 0;
x86_ea->valid_sib = 0;
x86_ea->need_sib = 0;
- x86_ea->pcrel = 0;
- return (yasm_effaddr *)x86_ea;
+ return x86_ea;
}
yasm_effaddr *
yasm_expr_reg(X86_RIP), e->line);
}
}
- x86_ea->ea.disp = e;
- x86_ea->ea.len = 0;
+ yasm_value_initialize(&x86_ea->ea.disp, e);
+ x86_ea->ea.disp_len = 0;
+ x86_ea->ea.need_disp = 1;
x86_ea->ea.nosplit = 0;
x86_ea->ea.strong = 0;
x86_ea->ea.segreg = 0;
* the BITS/address override setting.
*/
x86_ea->need_sib = 0xff;
- x86_ea->pcrel = 0;
return (yasm_effaddr *)x86_ea;
}
/*@-compmempass@*/
-yasm_effaddr *
+x86_effaddr *
yasm_x86__ea_create_imm(yasm_expr *imm, unsigned int im_len)
{
x86_effaddr *x86_ea;
x86_ea = yasm_xmalloc(sizeof(x86_effaddr));
x86_ea->ea.callback = &x86_ea_callback;
- x86_ea->ea.disp = imm;
- x86_ea->ea.len = (unsigned char)im_len;
+ yasm_value_initialize(&x86_ea->ea.disp, imm);
+ x86_ea->ea.disp_len = (unsigned char)im_len;
+ x86_ea->ea.need_disp = 1;
x86_ea->ea.nosplit = 0;
x86_ea->ea.strong = 0;
x86_ea->ea.segreg = 0;
x86_ea->sib = 0;
x86_ea->valid_sib = 0;
x86_ea->need_sib = 0;
- x86_ea->pcrel = 0;
- return (yasm_effaddr *)x86_ea;
+ return x86_ea;
}
/*@=compmempass@*/
x86_bc_insn_destroy(void *contents)
{
x86_insn *insn = (x86_insn *)contents;
- if (insn->ea)
- yasm_ea_destroy((yasm_effaddr *)insn->ea);
+ if (insn->x86_ea)
+ yasm_ea_destroy((yasm_effaddr *)insn->x86_ea);
if (insn->imm) {
- yasm_expr_destroy(insn->imm->val);
+ yasm_value_delete(&insn->imm->val);
yasm_xfree(insn->imm);
}
yasm_xfree(contents);
x86_bc_jmp_destroy(void *contents)
{
x86_jmp *jmp = (x86_jmp *)contents;
- yasm_expr_destroy(jmp->target);
+ yasm_value_delete(&jmp->target);
yasm_xfree(contents);
}
x86_bc_jmpfar_destroy(void *contents)
{
x86_jmpfar *jmpfar = (x86_jmpfar *)contents;
- yasm_expr_destroy(jmpfar->segment);
- yasm_expr_destroy(jmpfar->offset);
+ yasm_value_delete(&jmpfar->segment);
+ yasm_value_delete(&jmpfar->offset);
yasm_xfree(contents);
}
x86_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level)
{
const x86_effaddr *x86_ea = (const x86_effaddr *)ea;
- fprintf(f, "%*sSegmentOv=%02x PCRel=%u\n", indent_level, "",
- (unsigned int)x86_ea->ea.segreg, (unsigned int)x86_ea->pcrel);
+ fprintf(f, "%*sSegmentOv=%02x\n", indent_level, "",
+ (unsigned int)x86_ea->ea.segreg);
fprintf(f, "%*sModRM=%03o ValidRM=%u NeedRM=%u\n", indent_level, "",
(unsigned int)x86_ea->modrm, (unsigned int)x86_ea->valid_modrm,
(unsigned int)x86_ea->need_modrm);
fprintf(f, "%*s_Instruction_\n", indent_level, "");
fprintf(f, "%*sEffective Address:", indent_level, "");
- if (insn->ea) {
+ if (insn->x86_ea) {
fprintf(f, "\n");
- yasm_ea_print((yasm_effaddr *)insn->ea, f, indent_level+1);
+ yasm_ea_print((yasm_effaddr *)insn->x86_ea, f, indent_level+1);
} else
fprintf(f, " (nil)\n");
fprintf(f, "%*sImmediate Value:", indent_level, "");
fprintf(f, " (nil)\n");
else {
indent_level++;
- fprintf(f, "\n%*sVal=", indent_level, "");
- if (insn->imm->val)
- yasm_expr_print(insn->imm->val, f);
- else
- fprintf(f, "(nil-SHOULDN'T HAPPEN)");
fprintf(f, "\n");
+ yasm_value_print(&insn->imm->val, f, indent_level);
fprintf(f, "%*sLen=%u, Sign=%u\n", indent_level, "",
(unsigned int)insn->imm->len,
(unsigned int)insn->imm->sign);
const x86_jmp *jmp = (const x86_jmp *)contents;
fprintf(f, "%*s_Jump_\n", indent_level, "");
- fprintf(f, "%*sTarget=", indent_level, "");
- yasm_expr_print(jmp->target, f);
+ fprintf(f, "%*sTarget:\n", indent_level, "");
+ yasm_value_print(&jmp->target, f, indent_level+1);
+ /* FIXME
fprintf(f, "%*sOrigin=\n", indent_level, "");
yasm_symrec_print(jmp->origin, f, indent_level+1);
+ */
fprintf(f, "\n%*sShort Form:\n", indent_level, "");
if (jmp->shortop.len == 0)
fprintf(f, "%*sNone\n", indent_level+1, "");
const x86_jmpfar *jmpfar = (const x86_jmpfar *)contents;
fprintf(f, "%*s_Far_Jump_\n", indent_level, "");
- fprintf(f, "%*sSegment=", indent_level, "");
- yasm_expr_print(jmpfar->segment, f);
- fprintf(f, "\n%*sOffset=", indent_level, "");
- yasm_expr_print(jmpfar->offset, f);
+ fprintf(f, "%*sSegment:\n", indent_level, "");
+ yasm_value_print(&jmpfar->segment, f, indent_level+1);
+ fprintf(f, "%*sOffset:\n", indent_level, "");
+ yasm_value_print(&jmpfar->offset, f, indent_level+1);
x86_opcode_print(&jmpfar->opcode, f, indent_level);
x86_common_print(&jmpfar->common, f, indent_level);
}
yasm_calc_bc_dist_func calc_bc_dist)
{
x86_insn *insn = (x86_insn *)bc->contents;
- /*@null@*/ yasm_expr *temp;
- x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
- yasm_effaddr *ea = &x86_ea->ea;
+ x86_effaddr *x86_ea = insn->x86_ea;
yasm_immval *imm = insn->imm;
yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
- if (ea) {
+ if (x86_ea) {
/* Create temp copy of disp, etc. */
- x86_effaddr eat = *x86_ea; /* structure copy */
- unsigned char displen = ea->len;
+ x86_effaddr eat = *x86_ea; /* structure copy */
- if (ea->disp) {
- temp = yasm_expr_copy(ea->disp);
- assert(temp != NULL);
+ /* Don't overwrite original expression portion */
+ if (x86_ea->ea.disp.abs)
+ eat.ea.disp.abs = yasm_expr_copy(x86_ea->ea.disp.abs);
- /* Handle shortmov special-casing */
- if (insn->postop == X86_POSTOP_SHORTMOV &&
- insn->common.mode_bits == 64 && insn->common.addrsize == 32 &&
- !yasm_expr__contains(temp, YASM_EXPR_REG)) {
- yasm_x86__ea_set_disponly((yasm_effaddr *)&eat);
+ /* Handle shortmov special-casing */
+ if (insn->postop == X86_POSTOP_SHORTMOV &&
+ insn->common.mode_bits == 64 && insn->common.addrsize == 32 &&
+ (!eat.ea.disp.abs ||
+ !yasm_expr__contains(eat.ea.disp.abs, YASM_EXPR_REG))) {
+ yasm_x86__ea_set_disponly(&eat);
- if (save) {
- /* Make the short form permanent. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- }
+ if (save) {
+ /* Make the short form permanent. */
+ insn->opcode.opcode[0] = insn->opcode.opcode[1];
}
+ }
- /* Check validity of effective address and calc R/M bits of
- * Mod/RM byte and SIB byte. We won't know the Mod field
- * of the Mod/RM byte until we know more about the
- * displacement.
- */
- switch (yasm_x86__expr_checkea(&temp, &insn->common.addrsize,
- insn->common.mode_bits, ea->nosplit,
- insn->postop == X86_POSTOP_ADDRESS16, &displen, &eat.modrm,
- &eat.valid_modrm, &eat.need_modrm, &eat.sib,
- &eat.valid_sib, &eat.need_sib, &eat.pcrel, &insn->rex,
- calc_bc_dist)) {
- case 1:
- yasm_expr_destroy(temp);
- /* failed, don't bother checking rest of insn */
- return YASM_BC_RESOLVE_UNKNOWN_LEN|YASM_BC_RESOLVE_ERROR;
- case 2:
- yasm_expr_destroy(temp);
- /* failed, don't bother checking rest of insn */
- return YASM_BC_RESOLVE_UNKNOWN_LEN;
- default:
- yasm_expr_destroy(temp);
- /* okay */
- break;
- }
+ /* Check validity of effective address and calc R/M bits of
+ * Mod/RM byte and SIB byte. We won't know the Mod field
+ * of the Mod/RM byte until we know more about the
+ * displacement.
+ */
+ switch (yasm_x86__expr_checkea(&eat, &insn->common.addrsize,
+ insn->common.mode_bits, insn->postop == X86_POSTOP_ADDRESS16,
+ &insn->rex, calc_bc_dist, bc->line)) {
+ case 1:
+ yasm_expr_destroy(eat.ea.disp.abs);
+ /* failed, don't bother checking rest of insn */
+ return YASM_BC_RESOLVE_UNKNOWN_LEN|YASM_BC_RESOLVE_ERROR;
+ case 2:
+ yasm_expr_destroy(eat.ea.disp.abs);
+ /* failed, don't bother checking rest of insn */
+ return YASM_BC_RESOLVE_UNKNOWN_LEN;
+ default:
+ yasm_expr_destroy(eat.ea.disp.abs);
+ /* okay */
+ break;
+ }
- if (displen != 1) {
- /* Fits into a word/dword, or unknown. */
- retval = YASM_BC_RESOLVE_NONE; /* may not be smallest size */
+ if (eat.ea.disp_len != 1) {
+ /* Fits into a word/dword, or unknown. */
+ retval = YASM_BC_RESOLVE_NONE; /* may not be smallest size */
- /* Handle unknown case, make displen word-sized */
- if (displen == 0xff)
- displen = (insn->common.addrsize == 16) ? 2U : 4U;
- }
+ /* Handle unknown case, make displen word-sized */
+ if (eat.ea.disp_len == 0xff)
+ eat.ea.disp_len = (insn->common.addrsize == 16) ? 2U : 4U;
+ }
- /* Handle address16 postop case */
- if (insn->postop == X86_POSTOP_ADDRESS16)
- insn->common.addrsize = 0;
+ /* Handle address16 postop case */
+ if (insn->postop == X86_POSTOP_ADDRESS16)
+ insn->common.addrsize = 0;
- /* If we had forced ea->len but had to override, save it now */
- if (ea->len != 0 && ea->len != displen)
- ea->len = displen;
+ /* If we had forced ea->len but had to override, save it now */
+ if (x86_ea->ea.disp_len != 0 && x86_ea->ea.disp_len != eat.ea.disp_len)
+ x86_ea->ea.disp_len = eat.ea.disp_len;
- if (save) {
- *x86_ea = eat; /* structure copy */
- ea->len = displen;
- if (displen == 0 && ea->disp) {
- yasm_expr_destroy(ea->disp);
- ea->disp = NULL;
- }
+ if (save) {
+ eat.ea.disp.abs = x86_ea->ea.disp.abs; /* Copy back original */
+ *x86_ea = eat; /* structure copy */
+ if (x86_ea->ea.disp_len == 0) {
+ yasm_value_delete(&x86_ea->ea.disp);
+ x86_ea->ea.need_disp = 0;
}
}
/* Compute length of ea and add to total */
- bc->len += eat.need_modrm + (eat.need_sib ? 1:0) + displen;
+ bc->len += eat.need_modrm + (eat.need_sib ? 1:0) + eat.ea.disp_len;
bc->len += (eat.ea.segreg != 0) ? 1 : 0;
}
if (imm) {
- const yasm_intnum *num;
+ /*@null@*/ yasm_expr *temp = NULL;
+ const yasm_intnum *num = NULL;
unsigned int immlen = imm->len;
+ long val;
- if (imm->val) {
- temp = yasm_expr_copy(imm->val);
+ if (imm->val.abs) {
+ temp = yasm_expr_copy(imm->val.abs);
assert(temp != NULL);
-
- /* TODO: check imm->len vs. sized len from expr? */
-
num = yasm_expr_get_intnum(&temp, calc_bc_dist);
+ }
- switch (insn->postop) {
- case X86_POSTOP_SIGNEXT_IMM8:
- /* Handle signext_imm8 postop special-casing */
- if (num) {
- long val = yasm_intnum_get_int(num);
- if (val >= -128 && val <= 127) {
- /* We can use the sign-extended byte form: shorten
- * the immediate length to 1.
- */
- immlen = 1;
- if (save) {
- /* Make the byte form permanent. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- imm->len = 1;
- if (insn->opcode.opcode[2] != 0) {
- insn->opcode.opcode[1] = insn->opcode.opcode[2];
- insn->opcode.len++;
- }
- } else if (insn->opcode.opcode[2] != 0)
- bc->len++;
+ /* TODO: check imm->len vs. sized len from expr? */
+
+ switch (insn->postop) {
+ case X86_POSTOP_SIGNEXT_IMM8:
+ /* Handle signext_imm8 postop special-casing */
+ if (imm->val.rel)
+ val = 1000; /* has relative portion, don't collapse */
+ else if (num)
+ val = yasm_intnum_get_int(num);
+ else
+ val = 0;
+ if (val >= -128 && val <= 127) {
+ /* We can use the sign-extended byte form: shorten
+ * the immediate length to 1.
+ */
+ immlen = 1;
+ if (save) {
+ /* Make the byte form permanent. */
+ insn->opcode.opcode[0] = insn->opcode.opcode[1];
+ imm->len = 1;
+ if (insn->opcode.opcode[2] != 0) {
+ insn->opcode.opcode[1] = insn->opcode.opcode[2];
+ insn->opcode.len++;
}
- }
- /* Not really necessary, but saves confusion over it. */
- if (save)
- insn->postop = X86_POSTOP_NONE;
- break;
+ } else if (insn->opcode.opcode[2] != 0)
+ bc->len++;
+ }
+ /* Not really necessary, but saves confusion over it. */
+ if (save)
+ insn->postop = X86_POSTOP_NONE;
+ break;
- case X86_POSTOP_SIGNEXT_IMM32:
- /* Handle signext_imm32 postop special-casing */
- if (!num || yasm_intnum_check_size(num, 32, 0, 1)) {
- bc->len++; /* Due to ModRM byte */
- immlen = 4;
- if (save) {
- /* Throwaway REX byte */
- unsigned char rex_temp = 0;
-
- /* Build ModRM EA - CAUTION: this depends on
- * opcode 0 being a mov instruction!
- */
- insn->ea = yasm_x86__ea_create_reg(
- (unsigned long)insn->opcode.opcode[0]-0xB8,
- &rex_temp, 64);
-
- /* Make the imm32s form permanent. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- imm->len = 4;
- }
+ case X86_POSTOP_SIGNEXT_IMM32:
+ /* Handle signext_imm32 postop special-casing */
+ if (!num || yasm_intnum_check_size(num, 32, 0, 1)) {
+ bc->len++; /* Due to ModRM byte */
+ immlen = 4;
+ if (save) {
+ /* Throwaway REX byte */
+ unsigned char rex_temp = 0;
+
+ /* Build ModRM EA - CAUTION: this depends on
+ * opcode 0 being a mov instruction!
+ */
+ insn->x86_ea = yasm_x86__ea_create_reg(
+ (unsigned long)insn->opcode.opcode[0]-0xB8,
+ &rex_temp, 64);
+
+ /* Make the imm32s form permanent. */
+ insn->opcode.opcode[0] = insn->opcode.opcode[1];
+ imm->len = 4;
}
- /* Not really necessary, but saves confusion over it. */
- if (save)
- insn->postop = X86_POSTOP_NONE;
- break;
+ }
+ /* Not really necessary, but saves confusion over it. */
+ if (save)
+ insn->postop = X86_POSTOP_NONE;
+ break;
- case X86_POSTOP_SHIFT:
- /* Handle shift postop special-casing */
- if (num && yasm_intnum_get_uint(num) == 1) {
- /* We can use the ,1 form: no imm (set to 0 len) */
- immlen = 0;
-
- if (save) {
- /* Make the ,1 form permanent. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- /* Delete imm, as it's not needed. */
- yasm_expr_destroy(imm->val);
- yasm_xfree(imm);
- insn->imm = (yasm_immval *)NULL;
- }
- } else
- retval = YASM_BC_RESOLVE_NONE; /* could still get ,1 */
+ case X86_POSTOP_SHIFT:
+ /* Handle shift postop special-casing */
+ if (num && yasm_intnum_get_uint(num) == 1) {
+ /* We can use the ,1 form: no imm (set to 0 len) */
+ immlen = 0;
- /* Not really necessary, but saves confusion over it. */
- if (save)
- insn->postop = X86_POSTOP_NONE;
- break;
+ if (save) {
+ /* Make the ,1 form permanent. */
+ insn->opcode.opcode[0] = insn->opcode.opcode[1];
+ /* Delete imm, as it's not needed. */
+ yasm_value_delete(&imm->val);
+ yasm_xfree(imm);
+ insn->imm = (yasm_immval *)NULL;
+ }
+ } else
+ retval = YASM_BC_RESOLVE_NONE; /* could still get ,1 */
- default:
- break;
- }
+ /* Not really necessary, but saves confusion over it. */
+ if (save)
+ insn->postop = X86_POSTOP_NONE;
+ break;
- yasm_expr_destroy(temp);
+ default:
+ break;
}
+ yasm_expr_destroy(temp);
+
bc->len += immlen;
}
{
x86_jmp *jmp = (x86_jmp *)bc->contents;
yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
+ yasm_bytecode *target_prevbc;
/*@null@*/ yasm_expr *temp;
- /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+ /*@only@*/ yasm_intnum *num;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *num2;
long rel;
unsigned char opersize;
x86_jmp_opcode_sel jrtype = JMP_NONE;
/* 1 byte relative displacement */
jrtype = JMP_SHORT;
if (save) {
- temp = yasm_expr_copy(jmp->target);
- temp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(temp),
- yasm_expr_sym(jmp->origin), bc->line);
- num = yasm_expr_get_intnum(&temp, calc_bc_dist);
- if (!num) {
- yasm__error(bc->line,
- N_("short jump target external or out of segment"));
- yasm_expr_destroy(temp);
+ /* does a short form exist? */
+ if (jmp->shortop.len == 0) {
+ yasm__error(bc->line, N_("short jump does not exist"));
return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
- } else {
- rel = yasm_intnum_get_int(num);
- rel -= jmp->shortop.len+1;
- yasm_expr_destroy(temp);
- /* does a short form exist? */
- if (jmp->shortop.len == 0) {
- yasm__error(bc->line, N_("short jump does not exist"));
- return YASM_BC_RESOLVE_ERROR |
- YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
- /* short displacement must fit in -128 <= rel <= +127 */
- if (rel < -128 || rel > 127) {
- yasm__error(bc->line, N_("short jump out of range"));
+ }
+
+ if (!jmp->target.rel)
+ num = yasm_intnum_create_uint(0);
+ else if (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc)
+ || target_prevbc->section != jmp->origin_prevbc->section
+ || !(num = calc_bc_dist(jmp->origin_prevbc,
+ target_prevbc))) {
+ /* External or out of segment, so we can't check distance.
+ * This depends on the objfmt supporting 8-bit relocs.
+ * While most don't, some might, so allow it. The objfmt
+ * will error if not supported.
+ */
+ break;
+ }
+
+ if (jmp->target.abs) {
+ temp = yasm_expr_copy(jmp->target.abs);
+ num2 = yasm_expr_get_intnum(&temp, calc_bc_dist);
+ if (!num2) {
+ yasm_expr_destroy(temp);
+ yasm__error(bc->line, N_("jump target too complex"));
return YASM_BC_RESOLVE_ERROR |
YASM_BC_RESOLVE_UNKNOWN_LEN;
}
+ yasm_intnum_calc(num, YASM_EXPR_ADD, num2, bc->line);
+ yasm_expr_destroy(temp);
+ }
+
+ rel = yasm_intnum_get_int(num);
+ yasm_intnum_destroy(num);
+ rel -= jmp->shortop.len+1;
+ /* short displacement must fit in -128 <= rel <= +127 */
+ if (rel < -128 || rel > 127) {
+ yasm__error(bc->line, N_("short jump out of range"));
+ return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
}
}
break;
}
break;
default:
- temp = yasm_expr_copy(jmp->target);
+ /* Due to code in x86_finalize_jmp(), we can only get here if
+ * there's BOTH short and near opcodes available, and it wasn't
+ * forced by the user.
+ */
+ if (!jmp->target.rel)
+ num = yasm_intnum_create_uint(0);
+ else if (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc)
+ || target_prevbc->section != jmp->origin_prevbc->section
+ || !(num = calc_bc_dist(jmp->origin_prevbc,
+ target_prevbc))) {
+ /* It's unknown. Thus, assume near displacement. */
+ jrtype = JMP_NEAR;
+ retval = YASM_BC_RESOLVE_NONE;
+ break;
+ }
/* Try to find shortest displacement based on difference between
- * target expr value and our (this bytecode's) offset. Note this
- * requires offset to be set BEFORE calling calc_len in order for
- * this test to be valid.
+ * target expr value and origin offset.
*/
- temp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(temp),
- yasm_expr_sym(jmp->origin), bc->line);
- num = yasm_expr_get_intnum(&temp, calc_bc_dist);
- if (num) {
- rel = yasm_intnum_get_int(num);
- rel -= jmp->shortop.len+1;
- /* short displacement must fit within -128 <= rel <= +127 */
- if (jmp->shortop.len != 0 && rel >= -128 && rel <= 127) {
- /* It fits into a short displacement. */
- jrtype = JMP_SHORT;
- } else if (jmp->nearop.len != 0) {
- /* Near for now, but could get shorter in the future if
- * there's a short form available.
- */
- jrtype = JMP_NEAR;
- if (jmp->shortop.len != 0)
- retval = YASM_BC_RESOLVE_NONE;
- } else {
- /* Doesn't fit into short, and there's no near opcode.
- * Error out if saving, otherwise just make it a short
- * (in the hopes that a short might make it possible for
- * it to actually be within short range).
- */
- if (save) {
- yasm__error(bc->line,
- N_("short jump out of range (near jump does not exist)"));
- return YASM_BC_RESOLVE_ERROR |
- YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
- jrtype = JMP_SHORT;
+ if (jmp->target.abs) {
+ temp = yasm_expr_copy(jmp->target.abs);
+ num2 = yasm_expr_get_intnum(&temp, calc_bc_dist);
+ if (!num2) {
+ yasm_expr_destroy(temp);
+ yasm__error(bc->line, N_("jump target too complex"));
+ return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
}
+ yasm_intnum_calc(num, YASM_EXPR_ADD, num2, bc->line);
+ yasm_expr_destroy(temp);
+ }
+
+ rel = yasm_intnum_get_int(num);
+ yasm_intnum_destroy(num);
+ rel -= jmp->shortop.len+1;
+ /* short displacement must fit within -128 <= rel <= +127 */
+ if (rel >= -128 && rel <= 127) {
+ /* It fits into a short displacement. */
+ jrtype = JMP_SHORT;
} else {
- /* It's unknown. Thus, assume near displacement. If a near
- * opcode is not available, use a short opcode instead.
- * If we're saving, error if a near opcode is not available.
+ /* Near for now, but could get shorter in the future as
+ * there's a short form available.
*/
- if (jmp->nearop.len != 0) {
- if (jmp->shortop.len != 0)
- retval = YASM_BC_RESOLVE_NONE;
- jrtype = JMP_NEAR;
- } else {
- if (save) {
- yasm__error(bc->line,
- N_("short jump out of range (near jump does not exist)"));
- return YASM_BC_RESOLVE_ERROR |
- YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
- jrtype = JMP_SHORT;
- }
+ jrtype = JMP_NEAR;
+ retval = YASM_BC_RESOLVE_NONE;
}
- yasm_expr_destroy(temp);
break;
}
static int
x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
x86_insn *insn = (x86_insn *)bc->contents;
- /*@null@*/ x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
- /*@null@*/ yasm_effaddr *ea = &x86_ea->ea;
+ /*@null@*/ x86_effaddr *x86_ea = (x86_effaddr *)insn->x86_ea;
yasm_immval *imm = insn->imm;
- unsigned int i;
unsigned char *bufp_orig = *bufp;
/* Prefixes */
if (insn->special_prefix != 0)
YASM_WRITE_8(*bufp, insn->special_prefix);
- x86_common_tobytes(&insn->common, bufp, ea ? (ea->segreg>>8) : 0);
+ x86_common_tobytes(&insn->common, bufp,
+ x86_ea ? (x86_ea->ea.segreg>>8) : 0);
if (insn->rex != 0xff) {
if (insn->common.mode_bits == 64 && insn->common.opersize == 64 &&
insn->def_opersize_64 != 64)
/* Effective address: ModR/M (if required), SIB (if required), and
* displacement (if required).
*/
- if (ea) {
+ if (x86_ea) {
if (x86_ea->need_modrm) {
if (!x86_ea->valid_modrm)
yasm_internal_error(N_("invalid Mod/RM in x86 tobytes_insn"));
YASM_WRITE_8(*bufp, x86_ea->sib);
}
- if (ea->disp) {
+ if (x86_ea->ea.need_disp) {
x86_effaddr eat = *x86_ea; /* structure copy */
- unsigned char displen = ea->len;
unsigned char addrsize = insn->common.addrsize;
eat.valid_modrm = 0; /* force checkea to actually run */
- /* Call checkea() to simplify the registers out of the
- * displacement. Throw away all of the return values except for
- * the modified expr.
- */
- if (yasm_x86__expr_checkea(&ea->disp, &addrsize,
- insn->common.mode_bits, ea->nosplit,
- insn->postop == X86_POSTOP_ADDRESS16,
- &displen, &eat.modrm, &eat.valid_modrm,
- &eat.need_modrm, &eat.sib,
- &eat.valid_sib, &eat.need_sib,
- &eat.pcrel, &insn->rex,
- yasm_common_calc_bc_dist))
- yasm_internal_error(N_("checkea failed"));
-
- if (ea->disp) {
- if (eat.pcrel) {
- /*@null@*/ yasm_expr *wrt = yasm_expr_extract_wrt(&ea->disp);
- ea->disp =
- yasm_expr_create(YASM_EXPR_SUB,
- yasm_expr_expr(ea->disp),
- yasm_expr_sym(eat.origin), bc->line);
- if (wrt) {
- ea->disp =
- yasm_expr_create(YASM_EXPR_WRT,
- yasm_expr_expr(ea->disp),
- yasm_expr_expr(wrt), bc->line);
- }
- if (output_expr(&ea->disp, *bufp, ea->len,
- (size_t)(ea->len*8), 0,
- (unsigned long)(*bufp-bufp_orig), bc, 1, 1,
- d))
- return 1;
- } else {
- if (output_expr(&ea->disp, *bufp, ea->len,
- (size_t)(ea->len*8), 0,
- (unsigned long)(*bufp-bufp_orig), bc, 0, 1,
- d))
- return 1;
- }
- *bufp += ea->len;
- } else {
- /* 0 displacement, but we didn't know it before, so we have to
- * write out 0 value.
+ if (x86_ea->ea.disp.abs) {
+ /* Call checkea() to simplify the registers out of the
+ * displacement. Throw away all of the return values except
+ * for the modified expr.
*/
- for (i=0; i<ea->len; i++)
- YASM_WRITE_8(*bufp, 0);
+ if (yasm_x86__expr_checkea
+ (&eat, &addrsize, insn->common.mode_bits,
+ insn->postop == X86_POSTOP_ADDRESS16, &insn->rex,
+ yasm_common_calc_bc_dist, bc->line))
+ yasm_internal_error(N_("checkea failed"));
+ x86_ea->ea.disp.abs = eat.ea.disp.abs;
}
+
+ if (x86_ea->ea.disp.curpos_rel) {
+ /* Adjust relative displacement to end of bytecode */
+ /*@only@*/ yasm_intnum *delta;
+ delta = yasm_intnum_create_int(-(long)bc->len);
+ if (!x86_ea->ea.disp.abs)
+ x86_ea->ea.disp.abs =
+ yasm_expr_create_ident(yasm_expr_int(delta), bc->line);
+ else
+ x86_ea->ea.disp.abs =
+ yasm_expr_create(YASM_EXPR_ADD,
+ yasm_expr_expr(x86_ea->ea.disp.abs),
+ yasm_expr_int(delta), bc->line);
+ }
+ if (output_value(&x86_ea->ea.disp, *bufp, x86_ea->ea.disp_len,
+ (size_t)(x86_ea->ea.disp_len*8), 0,
+ (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+ return 1;
+ *bufp += x86_ea->ea.disp_len;
}
}
/* Immediate (if required) */
- if (imm && imm->val) {
- if (output_expr(&imm->val, *bufp, imm->len, (size_t)(imm->len*8), 0,
- (unsigned long)(*bufp-bufp_orig), bc, 0,
- imm->sign?-1:1, d))
+ if (imm) {
+ if (output_value(&imm->val, *bufp, imm->len, (size_t)(imm->len*8), 0,
+ (unsigned long)(*bufp-bufp_orig), bc, imm->sign?-1:1,
+ d))
return 1;
*bufp += imm->len;
}
static int
x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
x86_jmp *jmp = (x86_jmp *)bc->contents;
unsigned char opersize;
unsigned int i;
unsigned char *bufp_orig = *bufp;
- /*@null@*/ yasm_expr *wrt;
+ /*@only@*/ yasm_intnum *delta;
/* Prefixes */
x86_common_tobytes(&jmp->common, bufp, 0);
/* Opcode */
x86_opcode_tobytes(&jmp->shortop, bufp);
- /* Relative displacement */
- wrt = yasm_expr_extract_wrt(&jmp->target);
- jmp->target =
- yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target),
- yasm_expr_sym(jmp->origin), bc->line);
- if (wrt)
- jmp->target = yasm_expr_create_tree(jmp->target,
- YASM_EXPR_WRT, wrt,
- bc->line);
- if (output_expr(&jmp->target, *bufp, 1, 8, 0,
- (unsigned long)(*bufp-bufp_orig), bc, 1, -1, d))
+ /* Adjust relative displacement to end of bytecode */
+ delta = yasm_intnum_create_int(-(long)bc->len);
+ if (!jmp->target.abs)
+ jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta),
+ bc->line);
+ else
+ jmp->target.abs =
+ yasm_expr_create(YASM_EXPR_ADD,
+ yasm_expr_expr(jmp->target.abs),
+ yasm_expr_int(delta), bc->line);
+
+ if (output_value(&jmp->target, *bufp, 1, 8, 0,
+ (unsigned long)(*bufp-bufp_orig), bc, -1, d))
return 1;
*bufp += 1;
break;
/* Opcode */
x86_opcode_tobytes(&jmp->nearop, bufp);
- /* Relative displacement */
- wrt = yasm_expr_extract_wrt(&jmp->target);
- jmp->target =
- yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target),
- yasm_expr_sym(jmp->origin), bc->line);
- if (wrt)
- jmp->target = yasm_expr_create_tree(jmp->target,
- YASM_EXPR_WRT, wrt,
- bc->line);
i = (opersize == 16) ? 2 : 4;
- if (output_expr(&jmp->target, *bufp, i, i*8, 0,
- (unsigned long)(*bufp-bufp_orig), bc, 1, -1, d))
+
+ /* Adjust relative displacement to end of bytecode */
+ delta = yasm_intnum_create_int(-(long)bc->len);
+ if (!jmp->target.abs)
+ jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta),
+ bc->line);
+ else
+ jmp->target.abs =
+ yasm_expr_create(YASM_EXPR_ADD,
+ yasm_expr_expr(jmp->target.abs),
+ yasm_expr_int(delta), bc->line);
+
+ if (output_value(&jmp->target, *bufp, i, i*8, 0,
+ (unsigned long)(*bufp-bufp_orig), bc, -1, d))
return 1;
*bufp += i;
break;
static int
x86_bc_jmpfar_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@unused@*/ yasm_output_reloc_func output_reloc)
{
x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
/* Absolute displacement: segment and offset */
i = (opersize == 16) ? 2 : 4;
- if (output_expr(&jmpfar->offset, *bufp, i, i*8, 0,
- (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d))
+ if (output_value(&jmpfar->offset, *bufp, i, i*8, 0,
+ (unsigned long)(*bufp-bufp_orig), bc, 1, d))
return 1;
*bufp += i;
- if (output_expr(&jmpfar->segment, *bufp, 2, 2*8, 0,
- (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d))
+ if (output_value(&jmpfar->segment, *bufp, 2, 2*8, 0,
+ (unsigned long)(*bufp-bufp_orig), bc, 1, d))
return 1;
*bufp += 2;
return 0;
}
-int
-yasm_x86__intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn, size_t valsize,
- const yasm_bytecode *bc, unsigned long line)
-{
- yasm_intnum *delta;
- if (valsize != 8 && valsize != 16 && valsize != 32)
- yasm_internal_error(
- N_("tried to do PC-relative offset from invalid sized value"));
- delta = yasm_intnum_create_uint(bc->len);
- yasm_intnum_calc(intn, YASM_EXPR_SUB, delta, line);
- yasm_intnum_destroy(delta);
- return 0;
-}
-
int
yasm_x86__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
unsigned char *buf, size_t destsize, size_t valsize,
* and 0 if all values successfully determined and saved in data.
*/
static int
-x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
- /*@null@*/ int *indexreg, unsigned char *pcrel, unsigned int bits,
- void *data, int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d),
+x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg,
+ int *pcrel, unsigned int bits, void *data,
+ int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d),
yasm_calc_bc_dist_func calc_bc_dist)
{
int i;
int regnum;
int indexval = 0;
int indexmult = 0;
- yasm_expr *e;
+ yasm_expr *e, *wrt;
/*@-unqualifiedtrans@*/
- *ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, calc_bc_dist, NULL,
- NULL, NULL);
- if (*wrt)
- *wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, calc_bc_dist,
- NULL, NULL, NULL);
+ *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, calc_bc_dist, NULL,
+ NULL, NULL, NULL);
+
+ /* Check for WRT rip first */
+ wrt = yasm_expr_extract_wrt(ep);
+ if (wrt && wrt->op == YASM_EXPR_IDENT &&
+ wrt->terms[0].type == YASM_EXPR_REG) {
+ if (bits != 64) { /* only valid in 64-bit mode */
+ yasm_expr_destroy(wrt);
+ return 1;
+ }
+ reg = get_reg(&wrt->terms[0], ®num, data);
+ if (!reg || regnum != 16) { /* only accept rip */
+ yasm_expr_destroy(wrt);
+ return 1;
+ }
+ (*reg)++;
+
+ /* Delete WRT. Set pcrel to 1 to indicate to x86
+ * bytecode code to do PC-relative displacement transform.
+ */
+ *pcrel = 1;
+ yasm_expr_destroy(wrt);
+ } else if (wrt) {
+ yasm_expr_destroy(wrt);
+ return 1;
+ }
+
/*@=unqualifiedtrans@*/
assert(*ep != NULL);
e = *ep;
return 1;
case 2:
/* Need to simplify again */
- *ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, NULL, NULL,
- NULL, NULL);
+ *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, NULL, NULL,
+ NULL, NULL, NULL);
e = *ep;
break;
default:
break;
}
- if (*wrt && (*wrt)->op == YASM_EXPR_IDENT &&
- (*wrt)->terms[0].type == YASM_EXPR_REG) {
- /* Handle xx WRT rip. */
- if (bits != 64) /* only valid in 64-bit mode */
- return 1;
- reg = get_reg(&(*wrt)->terms[0], ®num, data);
- if (!reg || regnum != 16) /* only accept rip */
- return 1;
- (*reg)++;
-
- /* Delete WRT. Set pcrel to 1 to indicate to x86
- * bytecode code to do PC-relative displacement transform.
- */
- *pcrel = 1;
- yasm_expr_destroy(*wrt);
-
- /* Drill down to next WRT and recurse if there was one. */
- *wrt = yasm_expr_extract_wrt(ep);
- if (*wrt)
- return x86_expr_checkea_getregusage(ep, wrt, indexreg, pcrel,
- bits, data, get_reg,
- calc_bc_dist);
- }
-
switch (e->op) {
case YASM_EXPR_ADD:
/* Prescan for non-int multipliers against a reg.
*/
/*@-nullstate@*/
static int
-x86_checkea_calc_displen(yasm_expr **ep, unsigned int wordsize, int noreg,
- int dispreq, unsigned char *displen,
- unsigned char *modrm, unsigned char *v_modrm)
+x86_checkea_calc_displen(x86_effaddr *x86_ea, unsigned int wordsize, int noreg,
+ int dispreq, unsigned long line)
{
- yasm_expr *e = *ep;
- const yasm_intnum *intn;
+ /*@null@*/ const yasm_intnum *intn = NULL;
long dispval;
- *v_modrm = 0; /* default to not yet valid */
+ x86_ea->valid_modrm = 0; /* default to not yet valid */
- switch (*displen) {
+ switch (x86_ea->ea.disp_len) {
case 0:
break;
/* If not 0, the displacement length was forced; set the Mod bits
case 1:
/* Byte is not valid override in noreg case; fix it. */
if (noreg) {
- *displen = 0;
- yasm__warning(YASM_WARN_GENERAL, e->line,
+ x86_ea->ea.disp_len = 0;
+ yasm__warning(YASM_WARN_GENERAL, line,
N_("invalid displacement size; fixed"));
} else
- *modrm |= 0100;
- *v_modrm = 1;
+ x86_ea->modrm |= 0100;
+ x86_ea->valid_modrm = 1;
break;
case 2:
case 4:
- if (wordsize != *displen) {
- yasm__error(e->line,
+ if (wordsize != x86_ea->ea.disp_len) {
+ yasm__error(line,
N_("invalid effective address (displacement size)"));
return 1;
}
/* 2/4 is not valid override in noreg case; fix it. */
if (noreg) {
- if (wordsize != *displen)
- yasm__warning(YASM_WARN_GENERAL, e->line,
+ if (wordsize != x86_ea->ea.disp_len)
+ yasm__warning(YASM_WARN_GENERAL, line,
N_("invalid displacement size; fixed"));
- *displen = 0;
+ x86_ea->ea.disp_len = 0;
} else
- *modrm |= 0200;
- *v_modrm = 1;
+ x86_ea->modrm |= 0200;
+ x86_ea->valid_modrm = 1;
break;
default:
/* we shouldn't ever get any other size! */
yasm_internal_error(N_("strange EA displacement size"));
}
- if (*displen == 0) {
+ if (x86_ea->ea.disp_len == 0) {
/* the displacement length hasn't been forced (or the forcing wasn't
* valid), try to determine what it is.
*/
* and as the Mod bits are set to 0 by the caller, we're done
* with the ModRM byte.
*/
- *displen = wordsize;
- *v_modrm = 1;
+ x86_ea->ea.disp_len = wordsize;
+ x86_ea->valid_modrm = 1;
return 0;
} else if (dispreq) {
/* for BP/EBP, there *must* be a displacement value, but we
* We can't leave displen at 0, because that just means
* unknown displacement, including none.
*/
- *displen = 0xff;
+ x86_ea->ea.disp_len = 0xff;
}
- intn = yasm_expr_get_intnum(ep, NULL);
- if (!intn) {
- /* expr still has unknown values: assume 16/32-bit disp */
- *displen = wordsize;
- *modrm |= 0200;
- *v_modrm = 1;
+ if (x86_ea->ea.disp.rel ||
+ (x86_ea->ea.disp.abs &&
+ !(intn = yasm_expr_get_intnum(&x86_ea->ea.disp.abs, NULL)))) {
+ /* expr still has unknown values or is relative:
+ * assume 16/32-bit disp
+ */
+ x86_ea->ea.disp_len = wordsize;
+ x86_ea->modrm |= 0200;
+ x86_ea->valid_modrm = 1;
return 0;
}
/* don't try to find out what size displacement we have if
* displen is known.
*/
- if (*displen != 0 && *displen != 0xff) {
- if (*displen == 1)
- *modrm |= 0100;
+ if (x86_ea->ea.disp_len != 0 && x86_ea->ea.disp_len != 0xff) {
+ if (x86_ea->ea.disp_len == 1)
+ x86_ea->modrm |= 0100;
else
- *modrm |= 0200;
- *v_modrm = 1;
+ x86_ea->modrm |= 0200;
+ x86_ea->valid_modrm = 1;
return 0;
}
- dispval = yasm_intnum_get_int(intn);
+ if (intn)
+ dispval = yasm_intnum_get_int(intn);
+ else
+ dispval = 0;
/* Figure out what size displacement we will have. */
- if (*displen != 0xff && dispval == 0) {
+ if (x86_ea->ea.disp_len != 0xff && dispval == 0) {
/* if we know that the displacement is 0 right now,
- * go ahead and delete the expr (making it so no
- * displacement value is included in the output).
+ * go ahead and delete the expr and make it so no
+ * displacement value is included in the output.
* The Mod bits of ModRM are set to 0 above, and
* we're done with the ModRM byte!
*
* Don't do this if we came from dispreq check above, so
* check *displen.
*/
- yasm_expr_destroy(e);
- *ep = (yasm_expr *)NULL;
+ yasm_expr_destroy(x86_ea->ea.disp.abs);
+ x86_ea->ea.disp.abs = NULL;
+ x86_ea->ea.need_disp = 0;
} else if (dispval >= -128 && dispval <= 127) {
/* It fits into a signed byte */
- *displen = 1;
- *modrm |= 0100;
+ x86_ea->ea.disp_len = 1;
+ x86_ea->modrm |= 0100;
} else {
/* It's a 16/32-bit displacement */
- *displen = wordsize;
- *modrm |= 0200;
+ x86_ea->ea.disp_len = wordsize;
+ x86_ea->modrm |= 0200;
}
- *v_modrm = 1; /* We're done with ModRM */
+ x86_ea->valid_modrm = 1; /* We're done with ModRM */
}
return 0;
}
int
-yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
- unsigned int bits, unsigned int nosplit,
- int address16_op, unsigned char *displen,
- unsigned char *modrm, unsigned char *v_modrm,
- unsigned char *n_modrm, unsigned char *sib,
- unsigned char *v_sib, unsigned char *n_sib,
- unsigned char *pcrel, unsigned char *rex,
- yasm_calc_bc_dist_func calc_bc_dist)
+yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize,
+ unsigned int bits, int address16_op, unsigned char *rex,
+ yasm_calc_bc_dist_func calc_bc_dist, unsigned long line)
{
- yasm_expr *e, *wrt;
int retval;
- /* First split off any top-level WRT. We'll add it back in at the end */
- wrt = yasm_expr_extract_wrt(ep);
- e = *ep;
-
if (*addrsize == 0) {
/* we need to figure out the address size from what we know about:
* - the displacement length
* - what registers are used in the expression
* - the bits setting
*/
- switch (*displen) {
+ switch (x86_ea->ea.disp_len) {
case 2:
/* must be 16-bit */
*addrsize = 16;
/* We have to support this for the MemOffs case, but it's
* otherwise illegal. It's also illegal in non-64-bit mode.
*/
- if (*n_modrm || *n_sib) {
- yasm__error(e->line,
+ if (x86_ea->need_modrm || x86_ea->need_sib) {
+ yasm__error(line,
N_("invalid effective address (displacement size)"));
return 1;
}
* we don't know unless we look at the registers, except in the
* MemOffs case (see the end of this function).
*/
- if (bits != 64 || (!*n_modrm && !*n_sib)) {
+ if (bits != 64 || (!x86_ea->need_modrm && !x86_ea->need_sib)) {
*addrsize = 32;
break;
}
/* check for use of 16 or 32-bit registers; if none are used
* default to bits setting.
*/
- if (!yasm_expr__traverse_leaves_in(e, addrsize,
- x86_expr_checkea_getregsize_callback))
+ if (!x86_ea->ea.disp.abs ||
+ !yasm_expr__traverse_leaves_in(x86_ea->ea.disp.abs,
+ addrsize, x86_expr_checkea_getregsize_callback))
*addrsize = bits;
/* TODO: Add optional warning here if switched address size
* from bits setting just by register use.. eg [ax] in
}
if ((*addrsize == 32 || *addrsize == 64) &&
- ((*n_modrm && !*v_modrm) || (*n_sib && !*v_sib))) {
+ ((x86_ea->need_modrm && !x86_ea->valid_modrm) ||
+ (x86_ea->need_sib && !x86_ea->valid_sib))) {
int i;
unsigned char low3;
typedef enum {
/* We can only do 64-bit addresses in 64-bit mode. */
if (*addrsize == 64 && bits != 64) {
- yasm__error(e->line,
+ yasm__error(line,
N_("invalid effective address (64-bit in non-64-bit mode)"));
return 1;
}
reg3264_data.regs = reg3264mult;
reg3264_data.bits = bits;
reg3264_data.addrsize = *addrsize;
- switch (x86_expr_checkea_getregusage(ep, &wrt, &indexreg, pcrel, bits,
- ®3264_data,
- x86_expr_checkea_get_reg3264,
- calc_bc_dist)) {
- case 1:
- e = *ep;
- yasm__error(e->line, N_("invalid effective address"));
- return 1;
- case 2:
- if (wrt)
- *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
- (*ep)->line);
- return 2;
- default:
- e = *ep;
- break;
+ if (x86_ea->ea.disp.abs) {
+ int pcrel = 0;
+ switch (x86_expr_checkea_getregusage
+ (&x86_ea->ea.disp.abs, &indexreg, &pcrel, bits,
+ ®3264_data, x86_expr_checkea_get_reg3264,
+ calc_bc_dist)) {
+ case 1:
+ yasm__error(line, N_("invalid effective address"));
+ return 1;
+ case 2:
+ if (pcrel)
+ x86_ea->ea.disp.curpos_rel = 1;
+ return 2;
+ default:
+ if (pcrel)
+ x86_ea->ea.disp.curpos_rel = 1;
+ break;
+ }
}
/* If indexreg mult is 0, discard it.
*/
for (i=0; i<17; i++) {
if (reg3264mult[i] < 0) {
- yasm__error(e->line, N_("invalid effective address"));
+ yasm__error(line, N_("invalid effective address"));
return 1;
}
if (i != indexreg && reg3264mult[i] == 1 &&
switch (reg3264mult[indexreg]) {
case 1:
/* Only optimize this way if nosplit wasn't specified */
- if (!nosplit) {
+ if (!x86_ea->ea.nosplit) {
basereg = indexreg;
indexreg = -1;
}
break;
case 2:
/* Only split if nosplit wasn't specified */
- if (!nosplit) {
+ if (!x86_ea->ea.nosplit) {
basereg = indexreg;
reg3264mult[indexreg] = 1;
}
*/
for (i=0; i<17; i++)
if (i != basereg && i != indexreg && reg3264mult[i] != 0) {
- yasm__error(e->line, N_("invalid effective address"));
+ yasm__error(line, N_("invalid effective address"));
return 1;
}
if (indexreg != REG3264_NONE && reg3264mult[indexreg] != 1 &&
reg3264mult[indexreg] != 2 && reg3264mult[indexreg] != 4 &&
reg3264mult[indexreg] != 8) {
- yasm__error(e->line, N_("invalid effective address"));
+ yasm__error(line, N_("invalid effective address"));
return 1;
}
* legal.
*/
if (reg3264mult[REG3264_ESP] > 1 || basereg == REG3264_ESP) {
- yasm__error(e->line, N_("invalid effective address"));
+ yasm__error(line, N_("invalid effective address"));
return 1;
}
/* If mult==1 and basereg is not ESP, swap indexreg w/basereg. */
/* RIP is only legal if it's the ONLY register used. */
if (indexreg == REG64_RIP ||
(basereg == REG64_RIP && indexreg != REG3264_NONE)) {
- yasm__error(e->line, N_("invalid effective address"));
+ yasm__error(line, N_("invalid effective address"));
return 1;
}
*/
/* First determine R/M (Mod is later determined from disp size) */
- *n_modrm = 1; /* we always need ModRM */
+ x86_ea->need_modrm = 1; /* we always need ModRM */
if (basereg == REG3264_NONE && indexreg == REG3264_NONE) {
/* Just a disp32: in 64-bit mode the RM encoding is used for RIP
* offset addressing, so we need to use the SIB form instead.
*/
if (bits == 64) {
- *modrm |= 4;
- *n_sib = 1;
+ x86_ea->modrm |= 4;
+ x86_ea->need_sib = 1;
} else {
- *modrm |= 5;
- *sib = 0;
- *v_sib = 0;
- *n_sib = 0;
+ x86_ea->modrm |= 5;
+ x86_ea->sib = 0;
+ x86_ea->valid_sib = 0;
+ x86_ea->need_sib = 0;
}
} else if (basereg == REG64_RIP) {
- *modrm |= 5;
- *sib = 0;
- *v_sib = 0;
- *n_sib = 0;
+ x86_ea->modrm |= 5;
+ x86_ea->sib = 0;
+ x86_ea->valid_sib = 0;
+ x86_ea->need_sib = 0;
/* RIP always requires a 32-bit displacement */
- *v_modrm = 1;
- *displen = 4;
- if (wrt)
- *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
- (*ep)->line);
+ x86_ea->valid_modrm = 1;
+ x86_ea->ea.disp_len = 4;
return 0;
} else if (indexreg == REG3264_NONE) {
/* basereg only */
if (yasm_x86__set_rex_from_reg(rex, &low3,
(unsigned int)(X86_REG64 | basereg),
bits, X86_REX_B)) {
- yasm__error(e->line,
+ yasm__error(line,
N_("invalid combination of operands and effective address"));
return 1;
}
- *modrm |= low3;
+ x86_ea->modrm |= low3;
/* we don't need an SIB *unless* basereg is ESP or R12 */
if (basereg == REG3264_ESP || basereg == REG64_R12)
- *n_sib = 1;
+ x86_ea->need_sib = 1;
else {
- *sib = 0;
- *v_sib = 0;
- *n_sib = 0;
+ x86_ea->sib = 0;
+ x86_ea->valid_sib = 0;
+ x86_ea->need_sib = 0;
}
} else {
/* index or both base and index */
- *modrm |= 4;
- *n_sib = 1;
+ x86_ea->modrm |= 4;
+ x86_ea->need_sib = 1;
}
/* Determine SIB if needed */
- if (*n_sib == 1) {
- *sib = 0; /* start with 0 */
+ if (x86_ea->need_sib == 1) {
+ x86_ea->sib = 0; /* start with 0 */
/* Special case: no basereg */
if (basereg == REG3264_NONE)
- *sib |= 5;
+ x86_ea->sib |= 5;
else {
if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int)
(X86_REG64 | basereg), bits,
X86_REX_B)) {
- yasm__error(e->line,
+ yasm__error(line,
N_("invalid combination of operands and effective address"));
return 1;
}
- *sib |= low3;
+ x86_ea->sib |= low3;
}
/* Put in indexreg, checking for none case */
if (indexreg == REG3264_NONE)
- *sib |= 040;
+ x86_ea->sib |= 040;
/* Any scale field is valid, just leave at 0. */
else {
if (yasm_x86__set_rex_from_reg(rex, &low3, (unsigned int)
(X86_REG64 | indexreg), bits,
X86_REX_X)) {
- yasm__error(e->line,
+ yasm__error(line,
N_("invalid combination of operands and effective address"));
return 1;
}
- *sib |= low3 << 3;
+ x86_ea->sib |= low3 << 3;
/* Set scale field, 1 case -> 0, so don't bother. */
switch (reg3264mult[indexreg]) {
case 2:
- *sib |= 0100;
+ x86_ea->sib |= 0100;
break;
case 4:
- *sib |= 0200;
+ x86_ea->sib |= 0200;
break;
case 8:
- *sib |= 0300;
+ x86_ea->sib |= 0300;
break;
}
}
- *v_sib = 1; /* Done with SIB */
+ x86_ea->valid_sib = 1; /* Done with SIB */
}
/* Calculate displacement length (if possible) */
- retval = x86_checkea_calc_displen(ep, 4, basereg == REG3264_NONE,
- basereg == REG3264_EBP || basereg == REG64_R13, displen, modrm,
- v_modrm);
- if (wrt)
- *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line);
+ retval = x86_checkea_calc_displen
+ (x86_ea, 4, basereg == REG3264_NONE,
+ basereg == REG3264_EBP || basereg == REG64_R13, line);
return retval;
- } else if (*addrsize == 16 && *n_modrm && !*v_modrm) {
+ } else if (*addrsize == 16 && x86_ea->need_modrm && !x86_ea->valid_modrm) {
static const unsigned char modrm16[16] = {
0006 /* disp16 */, 0007 /* [BX] */, 0004 /* [SI] */,
0000 /* [BX+SI] */, 0005 /* [DI] */, 0001 /* [BX+DI] */,
/* 64-bit mode does not allow 16-bit addresses */
if (bits == 64 && !address16_op) {
- yasm__error(e->line,
+ yasm__error(line,
N_("16-bit addresses not supported in 64-bit mode"));
return 1;
}
/* 16-bit cannot have SIB */
- *sib = 0;
- *v_sib = 0;
- *n_sib = 0;
-
- switch (x86_expr_checkea_getregusage(ep, &wrt, (int *)NULL, pcrel,
- bits, ®16mult,
- x86_expr_checkea_get_reg16,
- calc_bc_dist)) {
- case 1:
- e = *ep;
- yasm__error(e->line, N_("invalid effective address"));
- return 1;
- case 2:
- if (wrt)
- *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
- (*ep)->line);
- return 2;
- default:
- e = *ep;
- break;
+ x86_ea->sib = 0;
+ x86_ea->valid_sib = 0;
+ x86_ea->need_sib = 0;
+
+ if (x86_ea->ea.disp.abs) {
+ int pcrel = 0;
+ switch (x86_expr_checkea_getregusage
+ (&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits,
+ ®16mult, x86_expr_checkea_get_reg16, calc_bc_dist)) {
+ case 1:
+ yasm__error(line, N_("invalid effective address"));
+ return 1;
+ case 2:
+ if (pcrel)
+ x86_ea->ea.disp.curpos_rel = 1;
+ return 2;
+ default:
+ if (pcrel)
+ x86_ea->ea.disp.curpos_rel = 1;
+ break;
+ }
}
/* reg multipliers not 0 or 1 are illegal. */
if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 ||
reg16mult.bp & ~1) {
- yasm__error(e->line, N_("invalid effective address"));
+ yasm__error(line, N_("invalid effective address"));
return 1;
}
/* Check the modrm value for invalid combinations. */
if (modrm16[havereg] & 0070) {
- yasm__error(e->line, N_("invalid effective address"));
+ yasm__error(line, N_("invalid effective address"));
return 1;
}
/* Set ModRM byte for registers */
- *modrm |= modrm16[havereg];
+ x86_ea->modrm |= modrm16[havereg];
/* Calculate displacement length (if possible) */
- retval = x86_checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
- havereg == HAVE_BP, displen, modrm,
- v_modrm);
- if (wrt)
- *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line);
+ retval = x86_checkea_calc_displen
+ (x86_ea, 2, havereg == HAVE_NONE, havereg == HAVE_BP, line);
return retval;
- } else if (!*n_modrm && !*n_sib) {
+ } else if (!x86_ea->need_modrm && !x86_ea->need_sib) {
/* Special case for MOV MemOffs opcode: displacement but no modrm. */
switch (*addrsize) {
case 64:
if (bits != 64) {
- yasm__error(e->line,
+ yasm__error(line,
N_("invalid effective address (64-bit in non-64-bit mode)"));
return 1;
}
- *displen = 8;
+ x86_ea->ea.disp_len = 8;
break;
case 32:
- *displen = 4;
+ x86_ea->ea.disp_len = 4;
break;
case 16:
/* 64-bit mode does not allow 16-bit addresses */
if (bits == 64 && !address16_op) {
- yasm__error(e->line,
+ yasm__error(line,
N_("16-bit addresses not supported in 64-bit mode"));
return 1;
}
- *displen = 2;
+ x86_ea->ea.disp_len = 2;
break;
}
}
- if (wrt)
- *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line);
return 0;
}
{
x86_jmpfar *jmpfar;
yasm_insn_operand *op;
+ /*@only@*/ yasm_expr *segment;
jmpfar = yasm_xmalloc(sizeof(x86_jmpfar));
x86_finalize_common(&jmpfar->common, info, data[3]);
switch (op->targetmod) {
case X86_FAR:
/* "FAR imm" target needs to become "seg imm:imm". */
- jmpfar->offset = yasm_expr_copy(op->data.val);
- jmpfar->segment = yasm_expr_create_branch(YASM_EXPR_SEG,
- op->data.val, bc->line);
+ if (yasm_value_finalize_expr(&jmpfar->offset,
+ yasm_expr_copy(op->data.val))
+ || yasm_value_finalize_expr(&jmpfar->segment, op->data.val))
+ yasm__error(bc->line, N_("jump target expression too complex"));
+ jmpfar->segment.seg_of = 1;
break;
case X86_FAR_SEGOFF:
/* SEG:OFF expression; split it. */
- jmpfar->offset = op->data.val;
- jmpfar->segment = yasm_expr_extract_segoff(&jmpfar->offset);
- if (!jmpfar->segment)
+ segment = yasm_expr_extract_segoff(&op->data.val);
+ if (!segment)
yasm_internal_error(N_("didn't get SEG:OFF expression in jmpfar"));
+ if (yasm_value_finalize_expr(&jmpfar->segment, segment))
+ yasm__error(bc->line, N_("jump target segment too complex"));
+ if (yasm_value_finalize_expr(&jmpfar->offset, op->data.val))
+ yasm__error(bc->line, N_("jump target offset too complex"));
break;
default:
yasm_internal_error(N_("didn't get FAR expression in jmpfar"));
jmp = yasm_xmalloc(sizeof(x86_jmp));
x86_finalize_common(&jmp->common, jinfo, mode_bits);
- jmp->target = op->data.val;
+ if (yasm_value_finalize_expr(&jmp->target, op->data.val))
+ yasm__error(bc->line, N_("jump target expression too complex"));
+ if (jmp->target.seg_of || jmp->target.rshift || jmp->target.curpos_rel)
+ yasm__error(bc->line, N_("invalid jump target"));
+ jmp->target.curpos_rel = 1;
/* Need to save jump origin for relative jumps. */
- jmp->origin = yasm_symtab_define_label2("$", prev_bc, 0, bc->line);
+ jmp->origin_prevbc = prev_bc;
/* See if the user explicitly specified short/near/far. */
switch ((int)(jinfo->operands[0] & OPTM_MASK)) {
yasm__error(bc->line,
N_("no NEAR form of that jump instruction exists"));
+ if (jmp->op_sel == JMP_NONE) {
+ if (jmp->nearop.len == 0)
+ jmp->op_sel = JMP_SHORT_FORCED;
+ if (jmp->shortop.len == 0)
+ jmp->op_sel = JMP_NEAR_FORCED;
+ }
+
yasm_x86__bc_apply_prefixes((x86_common *)jmp, NULL, num_prefixes,
prefixes, bc->line);
unsigned long suffix = (data[3]>>8) & 0xFF;
int found = 0;
yasm_insn_operand *op, *ops[4], *rev_ops[4], **use_ops;
- /*@null@*/ yasm_symrec *origin;
/*@null@*/ yasm_expr *imm;
unsigned char im_len;
unsigned char im_sign;
if (op->data.ea->segreg != 0)
yasm__warning(YASM_WARN_GENERAL, bc->line,
N_("skipping prefixes on this instruction"));
- imm = yasm_expr_copy(op->data.ea->disp);
+ imm = op->data.ea->disp.abs;
+ op->data.ea->disp.abs = NULL;
yasm_ea_destroy(op->data.ea);
op->type = YASM_INSN__OPERAND_IMM;
op->data.val = imm;
/* Check for 64-bit effective address size */
if (op->type == YASM_INSN__OPERAND_MEMORY) {
if ((info->operands[i] & OPEAS_MASK) == OPEAS_64) {
- if (op->data.ea->len != 8)
+ if (op->data.ea->disp_len != 8)
mismatch = 1;
- } else if (op->data.ea->len == 8)
+ } else if (op->data.ea->disp_len == 8)
mismatch = 1;
}
insn = yasm_xmalloc(sizeof(x86_insn));
x86_finalize_common(&insn->common, info, mode_bits);
x86_finalize_opcode(&insn->opcode, info);
- insn->ea = NULL;
- origin = NULL;
+ insn->x86_ea = NULL;
imm = NULL;
insn->def_opersize_64 = info->def_opersize_64;
insn->special_prefix = info->special_prefix;
case OPA_EA:
switch (op->type) {
case YASM_INSN__OPERAND_REG:
- insn->ea =
+ insn->x86_ea =
yasm_x86__ea_create_reg(op->data.reg,
&insn->rex,
mode_bits);
yasm_internal_error(
N_("invalid operand conversion"));
case YASM_INSN__OPERAND_MEMORY:
- insn->ea = op->data.ea;
+ insn->x86_ea = (x86_effaddr *)op->data.ea;
if ((info->operands[i] & OPT_MASK) == OPT_MemOffs)
/* Special-case for MOV MemOffs instruction */
- yasm_x86__ea_set_disponly(insn->ea);
- else if (mode_bits == 64)
- /* Save origin for possible RIP-relative */
- origin =
- yasm_symtab_define_label2("$", prev_bc, 0,
- bc->line);
+ yasm_x86__ea_set_disponly(insn->x86_ea);
break;
case YASM_INSN__OPERAND_IMM:
- insn->ea = yasm_x86__ea_create_imm(op->data.val,
- size_lookup[(info->operands[i] &
- OPS_MASK)>>OPS_SHIFT]);
+ insn->x86_ea =
+ yasm_x86__ea_create_imm(op->data.val,
+ size_lookup[(info->operands[i] &
+ OPS_MASK)>>OPS_SHIFT]);
break;
}
break;
break;
case OPA_SpareEA:
if (op->type == YASM_INSN__OPERAND_REG) {
- insn->ea = yasm_x86__ea_create_reg(op->data.reg,
- &insn->rex,
- mode_bits);
- if (!insn->ea ||
+ insn->x86_ea = yasm_x86__ea_create_reg(op->data.reg,
+ &insn->rex,
+ mode_bits);
+ if (!insn->x86_ea ||
yasm_x86__set_rex_from_reg(&insn->rex, &spare,
op->data.reg, mode_bits, X86_REX_R)) {
yasm__error(bc->line,
N_("invalid combination of opcode and operands"));
- if (insn->ea)
- yasm_xfree(insn->ea);
+ if (insn->x86_ea)
+ yasm_xfree(insn->x86_ea);
yasm_xfree(insn);
return;
}
}
}
- if (insn->ea) {
- yasm_x86__ea_init(insn->ea, spare, origin);
+ if (insn->x86_ea) {
+ yasm_x86__ea_init(insn->x86_ea, spare, bc->line);
for (i=0; i<num_segregs; i++)
- yasm_ea_set_segreg(insn->ea, segregs[i], bc->line);
+ yasm_ea_set_segreg(&insn->x86_ea->ea, segregs[i], bc->line);
} else if (num_segregs > 0 && insn->special_prefix == 0) {
if (num_segregs > 1)
yasm__warning(YASM_WARN_GENERAL, bc->line,
yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
yasm_bytecode *start_prevbc;
yasm_bytecode *end_prevbc;
- /*@null@*/ yasm_expr *debug_ptr;
+ /*@null@*/ yasm_symrec *debug_ptr;
int with_address;
int with_segment;
};
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int dwarf2_head_bc_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
/* Bytecode callback structures */
}
}
-yasm_expr *
+yasm_symrec *
yasm_dwarf2__bc_sym(yasm_symtab *symtab, yasm_bytecode *bc)
{
/*@dependent@*/ yasm_symrec *sym;
sym = bc->symrecs[0];
else
sym = yasm_symtab_define_label(symtab, ".bcsym", bc, 0, 0);
- return yasm_expr_create_ident(yasm_expr_sym(sym), 0);
+ return sym;
}
dwarf2_head *
dwarf2_head_bc_destroy(void *contents)
{
dwarf2_head *head = (dwarf2_head *)contents;
- if (head->debug_ptr)
- yasm_expr_destroy(head->debug_ptr);
yasm_xfree(contents);
}
static int
dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
yasm_output_reloc_func output_reloc)
{
dwarf2_head *head = (dwarf2_head *)bc->contents;
/* Pointer to another debug section */
if (head->debug_ptr) {
- output_expr(&head->debug_ptr, buf, dbgfmt_dwarf2->sizeof_offset,
- dbgfmt_dwarf2->sizeof_offset*8, 0,
- (unsigned long)(buf-*bufp), bc, 0, 0, d);
+ yasm_value value;
+ yasm_value_init_sym(&value, head->debug_ptr);
+ output_value(&value, buf, dbgfmt_dwarf2->sizeof_offset,
+ dbgfmt_dwarf2->sizeof_offset*8, 0,
+ (unsigned long)(buf-*bufp), bc, 0, d);
buf += dbgfmt_dwarf2->sizeof_offset;
}
yasm_bytecode *yasm_dwarf2__append_bc(yasm_section *sect, yasm_bytecode *bc);
-/*@only@*/ yasm_expr *yasm_dwarf2__bc_sym(yasm_symtab *symtab,
- yasm_bytecode *bc);
+/*@dependent@*/ yasm_symrec *yasm_dwarf2__bc_sym(yasm_symtab *symtab,
+ yasm_bytecode *bc);
typedef struct dwarf2_head dwarf2_head;
dwarf2_head *yasm_dwarf2__add_head
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int dwarf2_abbrev_bc_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
/* Bytecode callback structures */
/* statement list (line numbers) */
abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_stmt_list, DW_FORM_data4);
dwarf2_append_expr(debug_info,
- yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
- yasm_section_bcs_first(debug_line)),
+ yasm_expr_create_ident(yasm_expr_sym(
+ yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+ yasm_section_bcs_first(debug_line))), 0),
dbgfmt_dwarf2->sizeof_offset, 0);
if (main_code) {
/* All code is contiguous in one section */
abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_low_pc, DW_FORM_addr);
dwarf2_append_expr(debug_info,
- yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
- yasm_section_bcs_first(main_code)),
+ yasm_expr_create_ident(yasm_expr_sym(
+ yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+ yasm_section_bcs_first(main_code))), 0),
dbgfmt_dwarf2->sizeof_address, 0);
abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_high_pc, DW_FORM_addr);
dwarf2_append_expr(debug_info,
- yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
- yasm_section_bcs_last(main_code)),
+ yasm_expr_create_ident(yasm_expr_sym(
+ yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+ yasm_section_bcs_last(main_code))), 0),
dbgfmt_dwarf2->sizeof_address, 0);
}
static int
dwarf2_abbrev_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
yasm_output_reloc_func output_reloc)
{
dwarf2_abbrev *abbrev = (dwarf2_abbrev *)bc->contents;
/* extended opcode */
dwarf_line_number_ext_op ext_opcode;
- /*@owned@*/ /*@null@*/ yasm_expr *ext_operand; /* unsigned */
+ /*@null@*/ /*@dependent@*/ yasm_symrec *ext_operand; /* unsigned */
unsigned long ext_operandsize;
} dwarf2_line_op;
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int dwarf2_spp_bc_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void dwarf2_line_op_bc_destroy(void *contents);
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int dwarf2_line_op_bc_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
/* Bytecode callback structures */
dwarf2_dbgfmt_append_line_ext_op(yasm_section *sect,
dwarf_line_number_ext_op ext_opcode,
unsigned long ext_operandsize,
- /*@only@*/ /*@null@*/ yasm_expr *ext_operand)
+ /*@null@*/ yasm_symrec *ext_operand)
{
dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op));
yasm_bytecode *bc;
return 1;
}
dwarf2_dbgfmt_append_line_ext_op(debug_line, DW_LNE_set_address,
- dbgfmt_dwarf2->sizeof_address,
- yasm_expr_create_ident(yasm_expr_sym(loc->sym), loc->line));
+ dbgfmt_dwarf2->sizeof_address, loc->sym);
addr_delta = 0;
} else if (loc->bc) {
if (state->precbc->offset > loc->bc->offset)
static int
dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
yasm_output_reloc_func output_reloc)
{
dwarf2_spp *spp = (dwarf2_spp *)bc->contents;
dwarf2_line_op *line_op = (dwarf2_line_op *)contents;
if (line_op->operand)
yasm_intnum_destroy(line_op->operand);
- if (line_op->ext_operand)
- yasm_expr_destroy(line_op->ext_operand);
yasm_xfree(contents);
}
static int
dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
yasm_output_reloc_func output_reloc)
{
dwarf2_line_op *line_op = (dwarf2_line_op *)bc->contents;
if (line_op->ext_opcode > 0) {
YASM_WRITE_8(buf, line_op->ext_opcode);
if (line_op->ext_operand) {
- output_expr(&line_op->ext_operand, buf, line_op->ext_operandsize,
- line_op->ext_operandsize*8, 0,
- (unsigned long)(buf-*bufp), bc, 0, 0, d);
+ yasm_value value;
+ yasm_value_init_sym(&value, line_op->ext_operand);
+ output_value(&value, buf, line_op->ext_operandsize,
+ line_op->ext_operandsize*8, 0,
+ (unsigned long)(buf-*bufp), bc, 0, d);
buf += line_op->ext_operandsize;
}
}
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int stabs_bc_str_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void stabs_bc_stab_destroy(void *contents);
(yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
static int stabs_bc_stab_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
/* Bytecode callback structures */
static int
stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
yasm_output_reloc_func output_reloc)
{
/* This entire function, essentially the core of rendering stabs to a file,
static int
stabs_bc_str_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
yasm_output_reloc_func output_reloc)
{
const char *str = (const char *)bc->contents;
}
static int
-nasm_listfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
- size_t valsize, int shift, unsigned long offset,
- yasm_bytecode *bc, int rel, int warn,
- /*@null@*/ void *d)
+nasm_listfmt_output_value(yasm_value *value, unsigned char *buf,
+ size_t destsize, size_t valsize, int shift,
+ unsigned long offset, yasm_bytecode *bc, int warn,
+ /*@null@*/ void *d)
{
/*@null@*/ nasm_listfmt_output_info *info = (nasm_listfmt_output_info *)d;
/*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
assert(info != NULL);
+ /* Output */
+ switch (yasm_value_output_basic(value, buf, destsize, valsize, shift, bc,
+ warn, info->arch, NULL)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
+ }
+
/* Generate reloc if needed */
if (info->next_reloc && info->next_reloc_addr == bc->offset+offset) {
bcreloc *reloc = yasm_xmalloc(sizeof(bcreloc));
reloc->offset = offset;
reloc->size = destsize;
- reloc->rel = rel;
+ reloc->rel = value->curpos_rel;
STAILQ_INSERT_TAIL(&info->bcrelocs, reloc, link);
/* Get next reloc's info */
}
}
- flt = yasm_expr_get_floatnum(ep);
- if (flt) {
- if (shift < 0)
- yasm_internal_error(N_("attempting to negative shift a float"));
- return yasm_arch_floatnum_tobytes(info->arch, flt, buf, destsize,
- valsize, (unsigned int)shift, 0,
- bc->line);
- }
-
- intn = yasm_expr_get_intnum(ep, NULL);
- if (intn)
- return yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize,
- valsize, shift, bc, 0, bc->line);
- else {
+ if (value->abs) {
+ intn = yasm_expr_get_intnum(&value->abs, NULL);
+ if (intn)
+ return yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize,
+ valsize, shift, bc, 0, bc->line);
+ else {
+ yasm__error(bc->line, N_("relocation too complex"));
+ return 1;
+ }
+ } else {
int retval;
intn = yasm_intnum_create_uint(0);
retval = yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize,
* way
*/
bigbuf = yasm_bc_tobytes(bc, buf, &size, &multiple, &gap,
- &info, nasm_listfmt_output_expr,
+ &info, nasm_listfmt_output_value,
NULL);
/* output bytes with reloc information */
}
static int
-bin_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
- size_t valsize, int shift,
- /*@unused@*/ unsigned long offset, yasm_bytecode *bc,
- int rel, int warn, /*@null@*/ void *d)
+bin_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
+ size_t valsize, int shift,
+ /*@unused@*/ unsigned long offset, yasm_bytecode *bc,
+ int warn, /*@null@*/ void *d)
{
/*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
- /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
+ /*@dependent@*/ yasm_section *sect;
assert(info != NULL);
- /* For binary output, this is trivial: any expression that doesn't simplify
- * to an integer is an error (references something external).
- * Other object formats need to generate their relocation list from here!
- */
-
- *ep = yasm_expr__level_tree(*ep, 1, 1, NULL, bin_objfmt_expr_xform, NULL,
- NULL);
-
- /* Handle floating point expressions */
- flt = yasm_expr_get_floatnum(ep);
- if (flt) {
- if (shift < 0)
- yasm_internal_error(N_("attempting to negative shift a float"));
- return yasm_arch_floatnum_tobytes(info->objfmt_bin->arch, flt, buf,
- destsize, valsize,
- (unsigned int)shift, warn, bc->line);
+ /* Binary objects we need to resolve against object, not against section. */
+ if (value->rel && !value->curpos_rel
+ && yasm_symrec_get_label(value->rel, &precbc)
+ && (sect = yasm_bc_get_section(precbc))) {
+ if (!value->abs)
+ value->abs = yasm_expr_create_ident(yasm_expr_sym(value->rel),
+ bc->line);
+ else
+ value->abs =
+ yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(value->abs),
+ yasm_expr_sym(value->rel), bc->line);
+ value->rel = NULL;
}
- /* Handle integer expressions */
- intn = yasm_expr_get_intnum(ep, NULL);
- if (intn) {
- if (rel) {
- int retval = yasm_arch_intnum_fixup_rel(info->objfmt_bin->arch,
- intn, valsize, bc,
- bc->line);
- if (retval)
- return retval;
- }
- return yasm_arch_intnum_tobytes(info->objfmt_bin->arch, intn, buf,
- destsize, valsize, shift, bc, warn,
- bc->line);
- }
-
- /* Check for complex float expressions */
- if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
- yasm__error(bc->line, N_("floating point expression too complex"));
- return 1;
+ /* Simplify absolute portion of value, transforming symrecs */
+ if (value->abs)
+ value->abs = yasm_expr__level_tree
+ (value->abs, 1, 1, 1, NULL, bin_objfmt_expr_xform, NULL, NULL,
+ NULL);
+
+ /* Output */
+ switch (yasm_value_output_basic(value, buf, destsize, valsize, shift,
+ bc, warn, info->objfmt_bin->arch, NULL)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
}
/* Couldn't output, assume it contains an external reference. */
assert(info != NULL);
bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info,
- bin_objfmt_output_expr, NULL);
+ bin_objfmt_output_value, NULL);
/* Don't bother doing anything else if size ended up being 0. */
if (size == 0) {
-:4: expression must not contain floating point value
-:5: expression must not contain floating point value
--:7: attempt to reserve non-constant quantity of space
+-:7: reserve expression not absolute
-:11: expression must not contain floating point value
-:12: expression must not contain floating point value
--:14: attempt to reserve non-constant quantity of space
+-:14: reserve expression not absolute
}
static int
-coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
- size_t valsize, int shift, unsigned long offset,
- yasm_bytecode *bc, int rel, int warn,
- /*@null@*/ void *d)
+coff_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
+ size_t valsize, int shift, unsigned long offset,
+ yasm_bytecode *bc, int warn, /*@null@*/ void *d)
{
/*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
yasm_objfmt_coff *objfmt_coff;
+ /*@only@*/ /*@null@*/ yasm_intnum *dist = NULL;
/*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
- /*@dependent@*/ /*@null@*/ yasm_symrec *sym;
- /*@dependent@*/ yasm_section *label_sect;
- /*@dependent@*/ /*@null@*/ yasm_bytecode *label_precbc;
+ unsigned long intn_val, intn_minus;
+ int retval;
assert(info != NULL);
objfmt_coff = info->objfmt_coff;
- *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+ if (value->abs)
+ value->abs = yasm_expr_simplify(value->abs, yasm_common_calc_bc_dist);
- /* Handle floating point expressions */
- flt = yasm_expr_get_floatnum(ep);
- if (flt) {
- if (shift < 0)
- yasm_internal_error(N_("attempting to negative shift a float"));
- return yasm_arch_floatnum_tobytes(objfmt_coff->arch, flt, buf,
- destsize, valsize,
- (unsigned int)shift, warn, bc->line);
+ /* Try to output constant and PC-relative section-local first.
+ * Note this does NOT output any value with a SEG, WRT, external,
+ * cross-section, or non-PC-relative reference (those are handled below).
+ */
+ switch (yasm_value_output_basic(value, buf, destsize, valsize, shift, bc,
+ warn, info->objfmt_coff->arch,
+ yasm_common_calc_bc_dist)) {
+ case -1:
+ return 1;
+ case 0:
+ break;
+ default:
+ return 0;
}
- /* Handle integer expressions, with relocation if necessary */
- if (objfmt_coff->win64)
- sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_ZERO,
- yasm_common_calc_bc_dist);
- else
- sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_VALUE,
- yasm_common_calc_bc_dist);
+ /* Handle other expressions, with relocation if necessary */
+ if (value->seg_of || value->rshift > 0) {
+ yasm__error(bc->line, N_("coff: relocation too complex"));
+ return 1;
+ }
- if (sym) {
+ intn_val = 0;
+ intn_minus = 0;
+ if (value->rel) {
+ yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
+ /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
unsigned long addr;
coff_reloc *reloc;
- yasm_sym_vis vis;
- reloc = yasm_xmalloc(sizeof(coff_reloc));
- addr = bc->offset + offset;
- if (COFF_SET_VMA)
- addr += info->addr;
- reloc->reloc.addr = yasm_intnum_create_uint(addr);
- reloc->reloc.sym = sym;
- vis = yasm_symrec_get_visibility(sym);
+ /* Sometimes we want the relocation to be generated against one
+ * symbol but the value generated correspond to a different symbol.
+ * This is done through (sym being referenced) WRT (sym used for reloc).
+ * Note both syms need to be in the same section!
+ */
+ if (value->wrt) {
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *rel_precbc, *wrt_precbc;
+ if (!yasm_symrec_get_label(sym, &rel_precbc)
+ || !yasm_symrec_get_label(value->wrt, &wrt_precbc)) {
+ yasm__error(bc->line, N_("coff: wrt expression too complex"));
+ return 1;
+ }
+ dist = yasm_common_calc_bc_dist(wrt_precbc, rel_precbc);
+ if (!dist) {
+ yasm__error(bc->line, N_("coff: cannot wrt across sections"));
+ return 1;
+ }
+ sym = value->wrt;
+ }
+
if (vis & YASM_SYM_COMMON) {
/* In standard COFF, COMMON symbols have their length added in */
if (!objfmt_coff->win32) {
/*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *common_size;
csymd = yasm_symrec_get_data(sym, &coff_symrec_data_cb);
assert(csymd != NULL);
- *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
- yasm_expr_expr(yasm_expr_copy(csymd->size)),
- csymd->size->line);
- *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+ common_size = yasm_expr_get_intnum(&csymd->size,
+ yasm_common_calc_bc_dist);
+ if (!common_size) {
+ yasm__error(bc->line, N_("coff: common size too complex"));
+ return 1;
+ }
+
+ if (yasm_intnum_sign(common_size) < 0) {
+ yasm__error(bc->line, N_("coff: common size is negative"));
+ return 1;
+ }
+
+ intn_val += yasm_intnum_get_uint(common_size);
}
} else if (!(vis & YASM_SYM_EXTERN) && !objfmt_coff->win64) {
+ /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
+
/* Local symbols need relocation to their section's start */
- if (yasm_symrec_get_label(sym, &label_precbc)) {
- /*@null@*/ coff_section_data *label_csd;
- label_sect = yasm_bc_get_section(label_precbc);
- label_csd = yasm_section_get_data(label_sect,
- &coff_section_data_cb);
- assert(label_csd != NULL);
- reloc->reloc.sym = label_csd->sym;
+ if (yasm_symrec_get_label(sym, &sym_precbc)) {
+ yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
+ /*@null@*/ coff_section_data *sym_csd;
+ sym_csd = yasm_section_get_data(sym_sect,
+ &coff_section_data_cb);
+ assert(sym_csd != NULL);
+ sym = sym_csd->sym;
+ intn_val = sym_precbc->offset + sym_precbc->len;
if (COFF_SET_VMA)
- *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
- yasm_expr_int(yasm_intnum_create_uint(label_csd->addr)),
- (*ep)->line);
+ intn_val += sym_csd->addr;
}
}
- if (rel) {
+ if (value->curpos_rel) {
+ /* For standard COFF, need to adjust to start of section, e.g.
+ * subtract out the bytecode offset.
+ * For Win32 COFF, need to reference to next bytecode.
+ */
+ if (objfmt_coff->win32)
+ intn_val += bc->len;
+ else
+ intn_minus = bc->offset;
+ }
+
+ /* Generate reloc */
+ reloc = yasm_xmalloc(sizeof(coff_reloc));
+ addr = bc->offset + offset;
+ if (COFF_SET_VMA)
+ addr += info->addr;
+ reloc->reloc.addr = yasm_intnum_create_uint(addr);
+ reloc->reloc.sym = sym;
+
+ if (value->curpos_rel) {
if (objfmt_coff->machine == COFF_MACHINE_I386) {
if (valsize == 32)
reloc->type = COFF_RELOC_I386_REL32;
}
} else
yasm_internal_error(N_("coff objfmt: unrecognized machine"));
- /* For standard COFF, need to reference to start of section, so add
- * $$ in.
- * For Win32 COFF, need to reference to next bytecode, so add '$'
- * (really $+$.len) in.
- */
- if (objfmt_coff->win32)
- *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
- yasm_expr_sym(yasm_symtab_define_label2("$", bc,
- 0, (*ep)->line)),
- (*ep)->line);
- else
- *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
- yasm_expr_sym(yasm_symtab_define_label2("$$",
- yasm_section_bcs_first(info->sect), 0, (*ep)->line)),
- (*ep)->line);
- *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
} else {
if (objfmt_coff->machine == COFF_MACHINE_I386) {
if (info->csd->flags2 & COFF_FLAG_NOBASE)
info->csd->nreloc++;
yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
}
- intn = yasm_expr_get_intnum(ep, NULL);
- if (intn) {
- if (rel) {
- int retval = yasm_arch_intnum_fixup_rel(objfmt_coff->arch, intn,
- valsize, bc, bc->line);
- if (retval)
- return retval;
+
+ /* Build up final integer output from intn_val, intn_minus, value->abs,
+ * and dist. We do all this at the end to avoid creating temporary
+ * intnums above (except for dist).
+ */
+ if (intn_minus <= intn_val)
+ intn = yasm_intnum_create_uint(intn_val-intn_minus);
+ else {
+ intn = yasm_intnum_create_uint(intn_minus-intn_val);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, bc->line);
+ }
+
+ if (value->abs) {
+ yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, NULL);
+ if (!intn2) {
+ yasm__error(bc->line, N_("coff: relocation too complex"));
+ yasm_intnum_destroy(intn);
+ if (dist)
+ yasm_intnum_destroy(dist);
+ return 1;
}
- return yasm_arch_intnum_tobytes(objfmt_coff->arch, intn, buf, destsize,
- valsize, shift, bc, warn, bc->line);
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2, bc->line);
}
- /* Check for complex float expressions */
- if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
- yasm__error(bc->line, N_("floating point expression too complex"));
- return 1;
+ if (dist) {
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, dist, bc->line);
+ yasm_intnum_destroy(dist);
}
- yasm__error(bc->line, N_("coff: relocation too complex"));
- return 1;
+ retval = yasm_arch_intnum_tobytes(objfmt_coff->arch, intn, buf, destsize,
+ valsize, shift, bc, warn, bc->line);
+ yasm_intnum_destroy(intn);
+ return retval;
}
static int
assert(info != NULL);
bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info,
- coff_objfmt_output_expr, NULL);
+ coff_objfmt_output_value, NULL);
/* Don't bother doing anything else if size ended up being 0. */
if (size == 0) {
}
static int
-elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
+elf_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
size_t valsize, int shift, unsigned long offset,
- yasm_bytecode *bc, int rel, int warn,
- /*@null@*/ void *d)
+ yasm_bytecode *bc, int warn, /*@null@*/ void *d)
{
/*@null@*/ elf_objfmt_output_info *info = (elf_objfmt_output_info *)d;
/*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
- /*@dependent@*/ /*@null@*/ yasm_symrec *sym;
+ unsigned long intn_val;
/*@null@*/ elf_reloc_entry *reloc = NULL;
- /*@null@*/ yasm_expr *wrt_expr;
- /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = NULL;
+ int retval;
if (info == NULL)
yasm_internal_error("null info struct");
- *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
-
- /* Handle floating point expressions */
- flt = yasm_expr_get_floatnum(ep);
- if (flt) {
- if (shift < 0)
- yasm_internal_error(N_("attempting to negative shift a float"));
- return yasm_arch_floatnum_tobytes(info->objfmt_elf->arch, flt, buf,
- destsize, valsize,
- (unsigned int)shift, warn, bc->line);
- }
-
- /* Check for a WRT relocation */
- wrt_expr = yasm_expr_extract_wrt(ep);
- if (wrt_expr) {
- wrt = yasm_expr_extract_symrec(&wrt_expr, YASM_SYMREC_REPLACE_ZERO,
- yasm_common_calc_bc_dist);
- yasm_expr_destroy(wrt_expr);
- if (!wrt) {
- yasm__error(bc->line, N_("WRT expression too complex"));
+ if (value->abs)
+ value->abs = yasm_expr_simplify(value->abs, yasm_common_calc_bc_dist);
+
+ /* Try to output constant and PC-relative section-local first.
+ * Note this does NOT output any value with a SEG, WRT, external,
+ * cross-section, or non-PC-relative reference (those are handled below).
+ */
+ switch (yasm_value_output_basic(value, buf, destsize, valsize, shift, bc,
+ warn, info->objfmt_elf->arch,
+ yasm_common_calc_bc_dist)) {
+ case -1:
return 1;
- }
+ case 0:
+ break;
+ default:
+ return 0;
}
- /* Handle integer expressions, with relocation if necessary */
- if (wrt == info->objfmt_elf->dotdotsym
- || (wrt && elf_is_wrt_sym_relative(wrt)))
- sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_ZERO,
- yasm_common_calc_bc_dist);
- else
- sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_VALUE_IF_LOCAL,
- yasm_common_calc_bc_dist);
+ /* Handle other expressions, with relocation if necessary */
+ if (value->seg_of || value->rshift > 0) {
+ yasm__error(bc->line, N_("elf: relocation too complex"));
+ return 1;
+ }
- if (sym) {
- yasm_sym_vis vis;
+ intn_val = 0;
+ if (value->rel) {
+ yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
+ /*@dependent@*/ /*@null@*/ yasm_symrec *sym = value->rel;
+ /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = value->wrt;
- vis = yasm_symrec_get_visibility(sym);
if (wrt == info->objfmt_elf->dotdotsym)
wrt = NULL;
else if (wrt && elf_is_wrt_sym_relative(wrt))
;
else if (vis == YASM_SYM_LOCAL) {
- yasm_bytecode *label_precbc;
- /* Local symbols need relocation to their section's start */
- if (yasm_symrec_get_label(sym, &label_precbc)) {
- yasm_section *label_sect = yasm_bc_get_section(label_precbc);
+ yasm_bytecode *sym_precbc;
+ /* Local symbols need relocation to their section's start, and
+ * add in the offset of the bytecode (within the target section)
+ * into the abs portion.
+ *
+ * This is only done if the symbol is relocated against the
+ * section instead of the symbol itself.
+ */
+ if (yasm_symrec_get_label(sym, &sym_precbc)) {
+ /* Relocate to section start */
+ yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
/*@null@*/ elf_secthead *sym_shead;
- sym_shead =
- yasm_section_get_data(label_sect, &elf_section_data);
+ sym_shead = yasm_section_get_data(sym_sect, &elf_section_data);
assert(sym_shead != NULL);
sym = elf_secthead_get_sym(sym_shead);
- }
- }
- if (rel) {
- /* Need to reference to start of section, so add $$ in. */
- *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
- yasm_expr_sym(yasm_symtab_define_label2("$$",
- yasm_section_bcs_first(info->sect), 0, (*ep)->line)),
- (*ep)->line);
- /* HELP: and this seems to have the desired effect. */
- *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
- yasm_expr_int(yasm_intnum_create_uint(bc->offset + offset)),
- (*ep)->line);
- *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+ intn_val = sym_precbc->offset + sym_precbc->len;
+ }
}
+
+ /* For PC-relative, need to add offset of expression within bc. */
+ if (value->curpos_rel)
+ intn_val += offset;
reloc = elf_reloc_entry_create(sym, wrt,
- yasm_intnum_create_uint(bc->offset + offset), rel, valsize);
+ yasm_intnum_create_uint(bc->offset + offset), value->curpos_rel,
+ valsize);
if (reloc == NULL) {
yasm__error(bc->line, N_("elf: invalid relocation (WRT or size)"));
return 1;
elf_secthead_append_reloc(info->sect, info->shead, reloc);
}
- intn = yasm_expr_get_intnum(ep, NULL);
- if (intn) {
- if (rel) {
- int retval = yasm_arch_intnum_fixup_rel(info->objfmt_elf->arch,
- intn, valsize, bc,
- bc->line);
- if (retval)
- return retval;
- }
- if (reloc)
- elf_handle_reloc_addend(intn, reloc);
- return yasm_arch_intnum_tobytes(info->objfmt_elf->arch, intn, buf,
- destsize, valsize, shift, bc, warn,
- bc->line);
- }
+ intn = yasm_intnum_create_uint(intn_val);
- /* Check for complex float expressions */
- if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
- yasm__error(bc->line, N_("floating point expression too complex"));
- return 1;
+ if (value->abs) {
+ yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, NULL);
+ if (!intn2) {
+ yasm__error(bc->line, N_("elf: relocation too complex"));
+ yasm_intnum_destroy(intn);
+ return 1;
+ }
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2, bc->line);
}
- yasm__error(bc->line, N_("elf: relocation too complex"));
- return 1;
+ if (reloc)
+ elf_handle_reloc_addend(intn, reloc);
+ retval = yasm_arch_intnum_tobytes(info->objfmt_elf->arch, intn, buf,
+ destsize, valsize, shift, bc, warn,
+ bc->line);
+ yasm_intnum_destroy(intn);
+ return retval;
}
static int
yasm_internal_error("null info struct");
bigbuf = yasm_bc_tobytes(bc, buf, &size, &multiple, &gap, info,
- elf_objfmt_output_expr, elf_objfmt_output_reloc);
+ elf_objfmt_output_value, elf_objfmt_output_reloc);
/* Don't bother doing anything else if size ended up being 0. */
if (size == 0) {
[SECTION .pdata]
dd trap
-dd trap+(trap.end-trap)
+dd trap.end wrt trap
dd $xdatasym
[SECTION .xdata]
}
static int
-xdf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
+xdf_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
size_t valsize, int shift, unsigned long offset,
- yasm_bytecode *bc, int rel, int warn,
- /*@null@*/ void *d)
+ yasm_bytecode *bc, int warn, /*@null@*/ void *d)
{
/*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
yasm_objfmt_xdf *objfmt_xdf;
/*@dependent@*/ /*@null@*/ yasm_intnum *intn;
- /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
- /*@dependent@*/ /*@null@*/ yasm_symrec *sym;
- yasm_expr *shr_expr;
- yasm_expr *wrt_expr;
- unsigned int shr = 0;
- unsigned int seg = 0;
+ unsigned long intn_minus;
+ int retval;
assert(info != NULL);
objfmt_xdf = info->objfmt_xdf;
- *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
-
- /* Handle floating point expressions */
- flt = yasm_expr_get_floatnum(ep);
- if (flt) {
- if (shift < 0)
- yasm_internal_error(N_("attempting to negative shift a float"));
- return yasm_arch_floatnum_tobytes(objfmt_xdf->arch, flt, buf,
- destsize, valsize,
- (unsigned int)shift, warn, bc->line);
- }
-
- /* Check for a right shift value */
- shr_expr = yasm_expr_extract_shr(ep);
- if (shr_expr) {
- /*@dependent@*/ /*@null@*/ const yasm_intnum *shr_intn;
- shr_intn = yasm_expr_get_intnum(&shr_expr, NULL);
- if (!shr_intn) {
- yasm__error(bc->line, N_("shift expression too complex"));
+ if (value->abs)
+ value->abs = yasm_expr_simplify(value->abs, yasm_common_calc_bc_dist);
+
+ /* Try to output constant and PC-relative section-local first.
+ * Note this does NOT output any value with a SEG, WRT, external,
+ * cross-section, or non-PC-relative reference (those are handled below).
+ */
+ switch (yasm_value_output_basic(value, buf, destsize, valsize, shift, bc,
+ warn, info->objfmt_xdf->arch,
+ yasm_common_calc_bc_dist)) {
+ case -1:
return 1;
- }
- shr = yasm_intnum_get_uint(shr_intn);
+ case 0:
+ break;
+ default:
+ return 0;
}
- /* Check for a segment relocation */
- if (yasm_expr_extract_seg(ep))
- seg = 1;
-
- /* Check for a WRT relocation */
- wrt_expr = yasm_expr_extract_wrt(ep);
-
- /* Handle integer expressions, with relocation if necessary */
- sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_ZERO,
- yasm_common_calc_bc_dist);
- if (sym) {
+ intn_minus = 0;
+ if (value->rel) {
xdf_reloc *reloc;
reloc = yasm_xmalloc(sizeof(xdf_reloc));
reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
- reloc->reloc.sym = sym;
+ reloc->reloc.sym = value->rel;
reloc->base = NULL;
reloc->size = valsize/8;
- reloc->shift = shr;
+ reloc->shift = value->rshift;
- if (seg)
+ if (value->seg_of)
reloc->type = XDF_RELOC_SEG;
- else if (wrt_expr) {
- reloc->base = yasm_expr_extract_symrec(&wrt_expr,
- YASM_SYMREC_REPLACE_ZERO,
- yasm_common_calc_bc_dist);
- if (!reloc->base) {
- yasm__error(bc->line, N_("WRT expression too complex"));
- return 1;
- }
+ else if (value->wrt) {
+ reloc->base = value->wrt;
reloc->type = XDF_RELOC_WRT;
- } else if (rel) {
+ } else if (value->curpos_rel) {
reloc->type = XDF_RELOC_RIP;
- /* Need to reference to start of section, so add $$ in. */
- *ep = yasm_expr_create(YASM_EXPR_ADD, yasm_expr_expr(*ep),
- yasm_expr_sym(yasm_symtab_define_label2("$$",
- yasm_section_bcs_first(info->sect), 0, (*ep)->line)),
- (*ep)->line);
- *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
+ /* Adjust to start of section, so subtract out the bytecode
+ * offset.
+ */
+ intn_minus = bc->offset;
} else
reloc->type = XDF_RELOC_REL;
info->xsd->nreloc++;
yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
}
- intn = yasm_expr_get_intnum(ep, NULL);
- if (intn) {
- if (rel) {
- int retval = yasm_arch_intnum_fixup_rel(objfmt_xdf->arch, intn,
- valsize, bc, bc->line);
- if (retval)
- return retval;
- }
- return yasm_arch_intnum_tobytes(objfmt_xdf->arch, intn, buf, destsize,
- valsize, shift, bc, warn, bc->line);
- }
- /* Check for complex float expressions */
- if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {
- yasm__error(bc->line, N_("floating point expression too complex"));
- return 1;
+ if (intn_minus > 0) {
+ intn = yasm_intnum_create_uint(intn_minus);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, bc->line);
+ } else
+ intn = yasm_intnum_create_uint(0);
+
+ if (value->abs) {
+ yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, NULL);
+ if (!intn2) {
+ yasm__error(bc->line, N_("xdf: relocation too complex"));
+ yasm_intnum_destroy(intn);
+ return 1;
+ }
+ yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2, bc->line);
}
- yasm__error(bc->line, N_("xdf: relocation too complex"));
- return 1;
+ retval = yasm_arch_intnum_tobytes(objfmt_xdf->arch, intn, buf, destsize,
+ valsize, shift, bc, warn, bc->line);
+ yasm_intnum_destroy(intn);
+ return retval;
}
static int
assert(info != NULL);
bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &multiple, &gap, info,
- xdf_objfmt_output_expr, NULL);
+ xdf_objfmt_output_value, NULL);
/* Don't bother doing anything else if size ended up being 0. */
if (size == 0) {