mirror of
https://github.com/yasm/yasm
synced 2026-08-26 22:26:05 -04:00
- Fix much brokenness in absolute value handling, particularly in regards to
PC-relative relocations (jumps and calls). - Allow SEG:OFF to be used as just an offset portion (like NASM does). - Labels in absolute sections that are declared global are given the correct absolute value in the symbol table. One difference from NASM: label equ 0040h:001eh jmp label in NASM means the same as: jmp 001eh (a near jump) but yasm will treat this the same as: jmp 0040h:001eh (a far jump) I'm still not completely happy with this implementation, but it's workable and fixes all the bugs I've found so far in absolute handling. svn path=/trunk/yasm/; revision=1634
This commit is contained in:
parent
096e2eb79a
commit
3e8d2c2e7a
23 changed files with 1066 additions and 1624 deletions
|
|
@ -27,7 +27,10 @@
|
|||
#ifndef YASM_EXPR_INT_H
|
||||
#define YASM_EXPR_INT_H
|
||||
|
||||
/* Types listed in canonical sorting order. See expr_order_terms(). */
|
||||
/* Types listed in canonical sorting order. See expr_order_terms().
|
||||
* Note precbc must be used carefully (in a-b pairs), as only symrecs can
|
||||
* become the relative term in a #yasm_value.
|
||||
*/
|
||||
typedef enum {
|
||||
YASM_EXPR_NONE = 0,
|
||||
YASM_EXPR_REG = 1<<0,
|
||||
|
|
@ -35,13 +38,15 @@ typedef enum {
|
|||
YASM_EXPR_SUBST = 1<<2,
|
||||
YASM_EXPR_FLOAT = 1<<3,
|
||||
YASM_EXPR_SYM = 1<<4,
|
||||
YASM_EXPR_SYMEXP = 1<<5, /* post-expanded sym (due to absolute expansion) */
|
||||
YASM_EXPR_EXPR = 1<<6
|
||||
YASM_EXPR_SYMEXP = 1<<5, /* post-expanded sym (due to EQU expansion) */
|
||||
YASM_EXPR_PRECBC = 1<<6, /* direct bytecode ref (rather than via symrec) */
|
||||
YASM_EXPR_EXPR = 1<<7
|
||||
} yasm_expr__type;
|
||||
|
||||
struct yasm_expr__item {
|
||||
yasm_expr__type type;
|
||||
union {
|
||||
yasm_bytecode *precbc;
|
||||
yasm_symrec *sym;
|
||||
yasm_expr *expn;
|
||||
yasm_intnum *intn;
|
||||
|
|
|
|||
174
libyasm/expr.c
174
libyasm/expr.c
|
|
@ -49,6 +49,7 @@ static int expr_traverse_nodes_post(/*@null@*/ yasm_expr *e,
|
|||
/*@null@*/ void *d,
|
||||
int (*func) (/*@null@*/ yasm_expr *e,
|
||||
/*@null@*/ void *d));
|
||||
static void expr_delete_term(yasm_expr__item *term, int recurse);
|
||||
|
||||
/* Bitmap of used items. We should really never need more than 2 at a time,
|
||||
* so 31 is pretty much overkill.
|
||||
|
|
@ -138,6 +139,15 @@ expr_get_item(void)
|
|||
return &itempool[z];
|
||||
}
|
||||
|
||||
yasm_expr__item *
|
||||
yasm_expr_precbc(yasm_bytecode *precbc)
|
||||
{
|
||||
yasm_expr__item *e = expr_get_item();
|
||||
e->type = YASM_EXPR_PRECBC;
|
||||
e->data.precbc = precbc;
|
||||
return e;
|
||||
}
|
||||
|
||||
yasm_expr__item *
|
||||
yasm_expr_sym(yasm_symrec *s)
|
||||
{
|
||||
|
|
@ -185,7 +195,8 @@ yasm_expr_reg(unsigned long reg)
|
|||
|
||||
/* Transforms instances of symrec-symrec [symrec+(-1*symrec)] into single
|
||||
* expritems if possible. Uses a simple n^2 algorithm because n is usually
|
||||
* quite small.
|
||||
* quite small. Also works for precbc-precbc (or symrec-precbc,
|
||||
* precbc-symrec).
|
||||
*/
|
||||
static /*@only@*/ yasm_expr *
|
||||
expr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e,
|
||||
|
|
@ -210,7 +221,7 @@ expr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e,
|
|||
int j;
|
||||
yasm_expr *sube;
|
||||
yasm_intnum *intn;
|
||||
yasm_symrec *sym;
|
||||
yasm_symrec *sym = NULL;
|
||||
/*@dependent@*/ yasm_section *sect2;
|
||||
/*@dependent@*/ /*@null@*/ yasm_bytecode *precbc2;
|
||||
|
||||
|
|
@ -223,13 +234,21 @@ expr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e,
|
|||
|
||||
if (sube->terms[0].type == YASM_EXPR_INT &&
|
||||
(sube->terms[1].type == YASM_EXPR_SYM ||
|
||||
sube->terms[1].type == YASM_EXPR_SYMEXP)) {
|
||||
sube->terms[1].type == YASM_EXPR_SYMEXP ||
|
||||
sube->terms[1].type == YASM_EXPR_PRECBC)) {
|
||||
intn = sube->terms[0].data.intn;
|
||||
sym = sube->terms[1].data.sym;
|
||||
if (sube->terms[1].type == YASM_EXPR_PRECBC)
|
||||
precbc = sube->terms[1].data.precbc;
|
||||
else
|
||||
sym = sube->terms[1].data.sym;
|
||||
} else if ((sube->terms[0].type == YASM_EXPR_SYM ||
|
||||
sube->terms[0].type == YASM_EXPR_SYMEXP) &&
|
||||
sube->terms[0].type == YASM_EXPR_SYMEXP ||
|
||||
sube->terms[0].type == YASM_EXPR_PRECBC) &&
|
||||
sube->terms[1].type == YASM_EXPR_INT) {
|
||||
sym = sube->terms[0].data.sym;
|
||||
if (sube->terms[0].type == YASM_EXPR_PRECBC)
|
||||
precbc = sube->terms[0].data.precbc;
|
||||
else
|
||||
sym = sube->terms[0].data.sym;
|
||||
intn = sube->terms[1].data.intn;
|
||||
} else
|
||||
continue;
|
||||
|
|
@ -237,15 +256,17 @@ expr_xform_bc_dist_base(/*@returned@*/ /*@only@*/ yasm_expr *e,
|
|||
if (!yasm_intnum_is_neg1(intn))
|
||||
continue;
|
||||
|
||||
if (!yasm_symrec_get_label(sym, &precbc))
|
||||
if (sym && !yasm_symrec_get_label(sym, &precbc))
|
||||
continue;
|
||||
sect2 = yasm_bc_get_section(precbc);
|
||||
|
||||
/* Now look for a 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) &&
|
||||
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)) ||
|
||||
(e->terms[j].type == YASM_EXPR_PRECBC &&
|
||||
(precbc2 = e->terms[j].data.precbc))) &&
|
||||
(sect = yasm_bc_get_section(precbc2)) &&
|
||||
sect == sect2 &&
|
||||
callback(&e->terms[j], precbc, precbc2, cbd)) {
|
||||
|
|
@ -551,19 +572,7 @@ expr_simplify_identity(yasm_expr *e, int numterms, int int_term,
|
|||
/* Loop through, deleting everything but the integer term */
|
||||
for (i=0; i<e->numterms; i++)
|
||||
if (i != int_term)
|
||||
switch (e->terms[i].type) {
|
||||
case YASM_EXPR_INT:
|
||||
yasm_intnum_destroy(e->terms[i].data.intn);
|
||||
break;
|
||||
case YASM_EXPR_FLOAT:
|
||||
yasm_floatnum_destroy(e->terms[i].data.flt);
|
||||
break;
|
||||
case YASM_EXPR_EXPR:
|
||||
yasm_expr_destroy(e->terms[i].data.expn);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
expr_delete_term(&e->terms[i], 1);
|
||||
|
||||
/* Move integer term to the first term (if not already there) */
|
||||
if (int_term != 0)
|
||||
|
|
@ -813,10 +822,7 @@ yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
|
|||
|
||||
/* traverse terms */
|
||||
for (i=0; i<e->numterms; i++) {
|
||||
/* Expansion stage first: expand equ's, and expand symrecs that
|
||||
* reference absolute sections into
|
||||
* absolute start expr + (symrec - first bc in abs section).
|
||||
*/
|
||||
/* Expansion stage first: expand equ's. */
|
||||
if (e->terms[i].type == YASM_EXPR_SYM) {
|
||||
yasm__exprentry *np;
|
||||
const yasm_expr *equ_expr =
|
||||
|
|
@ -839,45 +845,6 @@ yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
|
|||
|
||||
ee.e = equ_expr;
|
||||
SLIST_INSERT_HEAD(eh, &ee, next);
|
||||
} else if (yasm_symrec_get_label(e->terms[i].data.sym, &precbc) &&
|
||||
(sect = yasm_bc_get_section(precbc)) &&
|
||||
yasm_section_is_absolute(sect)) {
|
||||
const yasm_expr *start = yasm_section_get_start(sect);
|
||||
yasm_expr *sube, *sube2;
|
||||
|
||||
/* Check for circular reference */
|
||||
SLIST_FOREACH(np, eh, next) {
|
||||
if (np->e == start) {
|
||||
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
||||
N_("circular reference detected"));
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
sube = yasm_xmalloc(sizeof(yasm_expr));
|
||||
sube->op = YASM_EXPR_SUB;
|
||||
sube->line = e->line;
|
||||
sube->numterms = 2;
|
||||
sube->terms[0].type = YASM_EXPR_SYMEXP;
|
||||
sube->terms[0].data.sym = e->terms[i].data.sym;
|
||||
sube->terms[1].type = YASM_EXPR_SYMEXP;
|
||||
sube->terms[1].data.sym = yasm_section_abs_get_sym(sect);
|
||||
assert(sube->terms[1].data.sym != NULL);
|
||||
|
||||
sube2 = yasm_xmalloc(sizeof(yasm_expr));
|
||||
sube2->op = YASM_EXPR_ADD;
|
||||
sube2->line = e->line;
|
||||
sube2->numterms = 2;
|
||||
sube2->terms[0].type = YASM_EXPR_EXPR;
|
||||
sube2->terms[0].data.expn = yasm_expr_copy(start);
|
||||
sube2->terms[1].type = YASM_EXPR_EXPR;
|
||||
sube2->terms[1].data.expn = sube;
|
||||
|
||||
e->terms[i].type = YASM_EXPR_EXPR;
|
||||
e->terms[i].data.expn = sube2;
|
||||
|
||||
ee.e = start;
|
||||
SLIST_INSERT_HEAD(eh, &ee, next);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -894,6 +861,15 @@ yasm_expr__level_tree(yasm_expr *e, int fold_const, int simplify_ident,
|
|||
}
|
||||
}
|
||||
|
||||
/* Check for SEG of SEG:OFF, if we match, simplify to just the segment */
|
||||
if (e->op == YASM_EXPR_SEG && e->terms[0].type == YASM_EXPR_EXPR &&
|
||||
e->terms[0].data.expn->op == YASM_EXPR_SEGOFF) {
|
||||
e->op = YASM_EXPR_IDENT;
|
||||
e->terms[0].data.expn->op = YASM_EXPR_IDENT;
|
||||
/* Destroy the second (offset) term */
|
||||
expr_delete_term(&e->terms[1], 1);
|
||||
}
|
||||
|
||||
/* do callback */
|
||||
e = expr_level_op(e, fold_const, simplify_ident, simplify_reg_mul);
|
||||
if (calc_bc_dist || expr_xform_extra) {
|
||||
|
|
@ -963,6 +939,10 @@ expr_item_copy(yasm_expr__item *dest, const yasm_expr__item *src)
|
|||
/* Symbols don't need to be copied */
|
||||
dest->data.sym = src->data.sym;
|
||||
break;
|
||||
case YASM_EXPR_PRECBC:
|
||||
/* Nor do direct bytecode references */
|
||||
dest->data.precbc = src->data.precbc;
|
||||
break;
|
||||
case YASM_EXPR_EXPR:
|
||||
dest->data.expn = yasm_expr__copy_except(src->data.expn, -1);
|
||||
break;
|
||||
|
|
@ -1010,22 +990,31 @@ yasm_expr_copy(const yasm_expr *e)
|
|||
return yasm_expr__copy_except(e, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
expr_delete_term(yasm_expr__item *term, int recurse)
|
||||
{
|
||||
switch (term->type) {
|
||||
case YASM_EXPR_INT:
|
||||
yasm_intnum_destroy(term->data.intn);
|
||||
break;
|
||||
case YASM_EXPR_FLOAT:
|
||||
yasm_floatnum_destroy(term->data.flt);
|
||||
break;
|
||||
case YASM_EXPR_EXPR:
|
||||
if (recurse)
|
||||
yasm_expr_destroy(term->data.expn);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
expr_destroy_each(/*@only@*/ yasm_expr *e, /*@unused@*/ void *d)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<e->numterms; i++) {
|
||||
switch (e->terms[i].type) {
|
||||
case YASM_EXPR_INT:
|
||||
yasm_intnum_destroy(e->terms[i].data.intn);
|
||||
break;
|
||||
case YASM_EXPR_FLOAT:
|
||||
yasm_floatnum_destroy(e->terms[i].data.flt);
|
||||
break;
|
||||
default:
|
||||
break; /* none of the other types needs to be deleted */
|
||||
}
|
||||
}
|
||||
for (i=0; i<e->numterms; i++)
|
||||
expr_delete_term(&e->terms[i], 0);
|
||||
yasm_xfree(e); /* free ourselves */
|
||||
return 0; /* don't stop recursion */
|
||||
}
|
||||
|
|
@ -1164,6 +1153,31 @@ yasm_expr__traverse_leaves_in(yasm_expr *e, void *d,
|
|||
return 0;
|
||||
}
|
||||
|
||||
yasm_expr *
|
||||
yasm_expr_extract_deep_segoff(yasm_expr **ep)
|
||||
{
|
||||
yasm_expr *retval;
|
||||
yasm_expr *e = *ep;
|
||||
int i;
|
||||
|
||||
/* Try to extract at this level */
|
||||
retval = yasm_expr_extract_segoff(ep);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* Not at this level? Search any expr children. */
|
||||
for (i=0; i<e->numterms; i++) {
|
||||
if (e->terms[i].type == YASM_EXPR_EXPR) {
|
||||
retval = yasm_expr_extract_deep_segoff(&e->terms[i].data.expn);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Didn't find one */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
yasm_expr *
|
||||
yasm_expr_extract_segoff(yasm_expr **ep)
|
||||
{
|
||||
|
|
@ -1381,6 +1395,10 @@ yasm_expr_print(const yasm_expr *e, FILE *f)
|
|||
}
|
||||
for (i=0; i<e->numterms; i++) {
|
||||
switch (e->terms[i].type) {
|
||||
case YASM_EXPR_PRECBC:
|
||||
fprintf(f, "{%lx}",
|
||||
yasm_bc_next_offset(e->terms[i].data.precbc));
|
||||
break;
|
||||
case YASM_EXPR_SYM:
|
||||
case YASM_EXPR_SYMEXP:
|
||||
fprintf(f, "%s", yasm_symrec_get_name(e->terms[i].data.sym));
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@ typedef struct yasm_expr__item yasm_expr__item;
|
|||
(yasm_expr_op op, /*@only@*/ yasm_expr__item *a,
|
||||
/*@only@*/ /*@null@*/ yasm_expr__item *b, unsigned long line);
|
||||
|
||||
/** Create a new preceding-bytecode expression item.
|
||||
* \param precbc preceding bytecode
|
||||
* \return Newly allocated expression item.
|
||||
*/
|
||||
/*@only@*/ yasm_expr__item *yasm_expr_precbc(/*@keep@*/ yasm_bytecode *precbc);
|
||||
|
||||
/** Create a new symbol expression item.
|
||||
* \param sym symbol
|
||||
* \return Newly allocated expression item.
|
||||
|
|
@ -171,6 +177,16 @@ SLIST_HEAD(yasm__exprhead, yasm__exprentry);
|
|||
#define yasm_expr_simplify(e, cbd) \
|
||||
yasm_expr__level_tree(e, 1, 1, 1, cbd, NULL, NULL, NULL)
|
||||
|
||||
/** Extract the segment portion of an expression containing SEG:OFF, leaving
|
||||
* the offset.
|
||||
* \param ep expression (pointer to)
|
||||
* \return NULL if unable to extract a segment (expr does not contain a
|
||||
* YASM_EXPR_SEGOFF operator), otherwise the segment expression.
|
||||
* The input expression is modified such that on return, it's the
|
||||
* offset expression.
|
||||
*/
|
||||
/*@only@*/ /*@null@*/ yasm_expr *yasm_expr_extract_deep_segoff(yasm_expr **ep);
|
||||
|
||||
/** Extract the segment portion of a SEG:OFF expression, leaving the offset.
|
||||
* \param ep expression (pointer to)
|
||||
* \return NULL if unable to extract a segment (YASM_EXPR_SEGOFF not the
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "assocdat.h"
|
||||
|
||||
#include "errwarn.h"
|
||||
#include "intnum.h"
|
||||
#include "floatnum.h"
|
||||
#include "expr.h"
|
||||
#include "symrec.h"
|
||||
|
|
@ -193,6 +194,18 @@ yasm_symtab_iter_value(const yasm_symtab_iter *cur)
|
|||
return (yasm_symrec *)HAMTEntry_get_data((const HAMTEntry *)cur);
|
||||
}
|
||||
|
||||
yasm_symrec *
|
||||
yasm_symtab_abs_sym(yasm_symtab *symtab)
|
||||
{
|
||||
yasm_symrec *rec = symtab_get_or_new(symtab, "", 1);
|
||||
rec->line = 0;
|
||||
rec->type = SYM_EQU;
|
||||
rec->value.expn =
|
||||
yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0);
|
||||
rec->status |= SYM_DEFINED|SYM_VALUED|SYM_USED;
|
||||
return rec;
|
||||
}
|
||||
|
||||
yasm_symrec *
|
||||
yasm_symtab_use(yasm_symtab *symtab, const char *name, unsigned long line)
|
||||
{
|
||||
|
|
@ -321,6 +334,8 @@ static int
|
|||
symtab_parser_finalize_checksym(yasm_symrec *sym, /*@null@*/ void *d)
|
||||
{
|
||||
symtab_finalize_info *info = (symtab_finalize_info *)d;
|
||||
yasm_section *sect;
|
||||
|
||||
/* error if a symbol is used but never defined or extern/common declared */
|
||||
if ((sym->status & SYM_USED) && !(sym->status & SYM_DEFINED) &&
|
||||
!(sym->visibility & (YASM_SYM_EXTERN | YASM_SYM_COMMON))) {
|
||||
|
|
@ -335,6 +350,25 @@ symtab_parser_finalize_checksym(yasm_symrec *sym, /*@null@*/ void *d)
|
|||
}
|
||||
}
|
||||
|
||||
/* Change labels in absolute sections into EQUs with value
|
||||
* absolute start expr + (label bc - first bc in abs section).
|
||||
* Don't worry about possible circular references because that will get
|
||||
* caught in EQU expansion.
|
||||
*/
|
||||
if (sym->type == SYM_LABEL && sym->value.precbc
|
||||
&& (sect = yasm_bc_get_section(sym->value.precbc))
|
||||
&& yasm_section_is_absolute(sect)) {
|
||||
sym->type = SYM_EQU;
|
||||
sym->value.expn = yasm_expr_create_tree(
|
||||
yasm_expr_create(YASM_EXPR_SUB,
|
||||
yasm_expr_precbc(sym->value.precbc),
|
||||
yasm_expr_precbc(yasm_section_bcs_first(sect)),
|
||||
sym->line),
|
||||
YASM_EXPR_ADD,
|
||||
yasm_expr_copy(yasm_section_get_start(sect)),
|
||||
sym->line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -429,6 +463,12 @@ yasm_symrec_get_label(const yasm_symrec *sym,
|
|||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
yasm_symrec_is_abs(const yasm_symrec *sym)
|
||||
{
|
||||
return (sym->line == 0 && sym->type == SYM_EQU && sym->name[0] == '\0');
|
||||
}
|
||||
|
||||
int
|
||||
yasm_symrec_is_special(const yasm_symrec *sym)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,6 +44,15 @@ yasm_symtab *yasm_symtab_create(void);
|
|||
*/
|
||||
void yasm_symtab_destroy(/*@only@*/ yasm_symtab *symtab);
|
||||
|
||||
/** Get a reference to the symbol table's "absolute" symbol. This is
|
||||
* essentially an EQU with no name and value 0, and is used for relocating
|
||||
* absolute current-position-relative values.
|
||||
* \see yasm_value_set_curpos_rel().
|
||||
* \param symtab symbol table
|
||||
* \return Absolute symbol (dependent pointer, do not free).
|
||||
*/
|
||||
/*@dependent@*/ yasm_symrec *yasm_symtab_abs_sym(yasm_symtab *symtab);
|
||||
|
||||
/** Get a reference to (use) a symbol. The symbol does not necessarily need to
|
||||
* be defined before it is used.
|
||||
* \param symtab symbol table
|
||||
|
|
@ -227,6 +236,13 @@ typedef /*@dependent@*/ yasm_bytecode *yasm_symrec_get_label_bytecodep;
|
|||
int yasm_symrec_get_label(const yasm_symrec *sym,
|
||||
/*@out@*/ yasm_symrec_get_label_bytecodep *precbc);
|
||||
|
||||
/** Determine if symbol is the "absolute" symbol created by
|
||||
* yasm_symtab_abs_sym().
|
||||
* \param sym symbol
|
||||
* \return 0 if symbol is not the "absolute" symbol, nonzero otherwise.
|
||||
*/
|
||||
int yasm_symrec_is_abs(const yasm_symrec *sym);
|
||||
|
||||
/** Determine if symbol is a special symbol.
|
||||
* \param sym symbol
|
||||
* \return 0 if symbol is not a special symbol, nonzero otherwise.
|
||||
|
|
|
|||
|
|
@ -98,6 +98,22 @@ yasm_value_delete(yasm_value *value)
|
|||
value->rel = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc,
|
||||
unsigned int ip_rel)
|
||||
{
|
||||
value->curpos_rel = 1;
|
||||
value->ip_rel = ip_rel;
|
||||
/* In order for us to correctly output curpos-relative values, we must
|
||||
* have a relative portion of the value. If one doesn't exist, point
|
||||
* to a custom absolute symbol.
|
||||
*/
|
||||
if (!value->rel) {
|
||||
value->rel = yasm_symtab_abs_sym(yasm_object_get_symtab(
|
||||
yasm_section_get_object(yasm_bc_get_section(bc))));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
value_finalize_scan(yasm_value *value, yasm_expr *e, int ssym_not_ok)
|
||||
{
|
||||
|
|
@ -569,9 +585,22 @@ yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Handle integer expressions */
|
||||
/* Handle normal integer expressions */
|
||||
intn = yasm_expr_get_intnum(&value->abs, 1);
|
||||
|
||||
if (!intn) {
|
||||
/* Second try before erroring: yasm_expr_get_intnum doesn't handle
|
||||
* SEG:OFF, so try simplifying out any to just the OFF portion,
|
||||
* then getting the intnum again.
|
||||
*/
|
||||
yasm_expr *seg = yasm_expr_extract_deep_segoff(&value->abs);
|
||||
if (seg)
|
||||
yasm_expr_destroy(seg);
|
||||
intn = yasm_expr_get_intnum(&value->abs, 1);
|
||||
}
|
||||
|
||||
if (!intn) {
|
||||
/* Still don't have an integer! */
|
||||
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
||||
N_("expression too complex"));
|
||||
return -1;
|
||||
|
|
@ -617,7 +646,14 @@ yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
|
|||
bc, warn))
|
||||
retval = -1;
|
||||
yasm_intnum_destroy(outval);
|
||||
} else if (intn) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (value->seg_of || value->rshift || value->curpos_rel || value->ip_rel
|
||||
|| value->section_rel)
|
||||
return 0; /* We can't handle this with just an absolute */
|
||||
|
||||
if (intn) {
|
||||
/* Output just absolute portion */
|
||||
if (yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, 0, bc,
|
||||
warn))
|
||||
|
|
|
|||
|
|
@ -71,6 +71,18 @@ void yasm_value_init_copy(yasm_value *value, const yasm_value *orig);
|
|||
*/
|
||||
void yasm_value_delete(yasm_value *value);
|
||||
|
||||
/** Set a value to be relative to the current assembly position rather than
|
||||
* relative to the section start.
|
||||
* \param value value
|
||||
* \param bc bytecode containing value
|
||||
* \param ip_rel if nonzero, indicates IP-relative data relocation,
|
||||
* sometimes used to generate special relocations
|
||||
* \note If value is just an absolute value, will get an absolute symrec to
|
||||
* reference to (via bc's symbol table).
|
||||
*/
|
||||
void yasm_value_set_curpos_rel(yasm_value *value, yasm_bytecode *bc,
|
||||
unsigned int ip_rel);
|
||||
|
||||
/** Perform yasm_value_finalize_expr() on a value that already exists from
|
||||
* being initialized with yasm_value_initialize().
|
||||
* \param value value
|
||||
|
|
|
|||
|
|
@ -109,8 +109,7 @@ typedef enum {
|
|||
X86_NEAR = 1,
|
||||
X86_SHORT,
|
||||
X86_FAR,
|
||||
X86_TO,
|
||||
X86_FAR_SEGOFF /* FAR due to SEG:OFF immediate */
|
||||
X86_TO
|
||||
} x86_parse_targetmod;
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -256,7 +255,7 @@ void yasm_x86__bc_apply_prefixes
|
|||
*/
|
||||
int yasm_x86__expr_checkea
|
||||
(x86_effaddr *x86_ea, unsigned char *addrsize, unsigned int bits,
|
||||
int address16_op, unsigned char *rex);
|
||||
int address16_op, unsigned char *rex, yasm_bytecode *bc);
|
||||
|
||||
void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len);
|
||||
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ x86_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
|
|||
*/
|
||||
if (yasm_x86__expr_checkea(x86_ea, &insn->common.addrsize,
|
||||
insn->common.mode_bits, insn->postop == X86_POSTOP_ADDRESS16,
|
||||
&insn->rex))
|
||||
&insn->rex, bc))
|
||||
/* failed, don't bother checking rest of insn */
|
||||
return -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -547,7 +547,8 @@ x86_expr_checkea_getregsize_callback(yasm_expr__item *ei, void *d)
|
|||
|
||||
int
|
||||
yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize,
|
||||
unsigned int bits, int address16_op, unsigned char *rex)
|
||||
unsigned int bits, int address16_op, unsigned char *rex,
|
||||
yasm_bytecode *bc)
|
||||
{
|
||||
int retval;
|
||||
|
||||
|
|
@ -649,16 +650,12 @@ yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize,
|
|||
N_("invalid effective address"));
|
||||
return 1;
|
||||
case 2:
|
||||
if (pcrel) {
|
||||
x86_ea->ea.disp.curpos_rel = 1;
|
||||
x86_ea->ea.disp.ip_rel = 1;
|
||||
}
|
||||
if (pcrel)
|
||||
yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1);
|
||||
return 2;
|
||||
default:
|
||||
if (pcrel) {
|
||||
x86_ea->ea.disp.curpos_rel = 1;
|
||||
x86_ea->ea.disp.ip_rel = 1;
|
||||
}
|
||||
if (pcrel)
|
||||
yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -904,16 +901,12 @@ yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize,
|
|||
N_("invalid effective address"));
|
||||
return 1;
|
||||
case 2:
|
||||
if (pcrel) {
|
||||
x86_ea->ea.disp.curpos_rel = 1;
|
||||
x86_ea->ea.disp.ip_rel = 1;
|
||||
}
|
||||
if (pcrel)
|
||||
yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1);
|
||||
return 2;
|
||||
default:
|
||||
if (pcrel) {
|
||||
x86_ea->ea.disp.curpos_rel = 1;
|
||||
x86_ea->ea.disp.ip_rel = 1;
|
||||
}
|
||||
if (pcrel)
|
||||
yasm_value_set_curpos_rel(&x86_ea->ea.disp, bc, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ RCSID("$Id$");
|
|||
* 15 = memory offset (an EA, but with no registers allowed)
|
||||
* [special case for MOV opcode]
|
||||
* 16 = immediate, value=1 (for special-case shift)
|
||||
* 17 = immediate, does not contain SEG:OFF (for jmp/call)
|
||||
* - 3 bits = size (user-specified, or from register size):
|
||||
* 0 = any size acceptable/no size spec acceptable (dep. on strict)
|
||||
* 1/2/3/4 = 8/16/32/64 bits (from user or reg size)
|
||||
|
|
@ -182,6 +183,7 @@ RCSID("$Id$");
|
|||
#define OPT_CR4 0x14
|
||||
#define OPT_MemOffs 0x15
|
||||
#define OPT_Imm1 0x16
|
||||
#define OPT_ImmNotSegOff 0x17
|
||||
#define OPT_MASK 0x1F
|
||||
|
||||
#define OPS_Any (0UL<<5)
|
||||
|
|
@ -1141,13 +1143,13 @@ static const x86_insn_info shlrd_insn[] = {
|
|||
/* Control transfer instructions (unconditional) */
|
||||
static const x86_insn_info call_insn[] = {
|
||||
{ CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_Any|OPA_JmpRel, 0, 0} },
|
||||
{OPT_ImmNotSegOff|OPS_Any|OPA_JmpRel, 0, 0} },
|
||||
{ CPU_Any, 0, 16, 0, 0, 0, {0, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_16|OPA_JmpRel, 0, 0} },
|
||||
{OPT_ImmNotSegOff|OPS_16|OPA_JmpRel, 0, 0} },
|
||||
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 0, {0, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} },
|
||||
{OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} },
|
||||
{ CPU_Hammer|CPU_64, 0, 64, 0, 0, 0, {0, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} },
|
||||
{OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} },
|
||||
|
||||
{ CPU_Any, 0, 16, 64, 0, 1, {0xE8, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_16|OPTM_Near|OPA_JmpRel, 0, 0} },
|
||||
|
|
@ -1175,13 +1177,7 @@ static const x86_insn_info call_insn[] = {
|
|||
{ CPU_Any, 0, 0, 64, 0, 1, {0xFF, 0, 0}, 2, 1,
|
||||
{OPT_Mem|OPS_Any|OPTM_Near|OPA_EA, 0, 0} },
|
||||
|
||||
{ CPU_Not64, 0, 16, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_Not64, 0, 0, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
|
||||
/* Far indirect (through memory). Needs explicit FAR override. */
|
||||
{ CPU_Any, 0, 16, 0, 0, 1, {0xFF, 0, 0}, 3, 1,
|
||||
{OPT_Mem|OPS_16|OPTM_Far|OPA_EA, 0, 0} },
|
||||
{ CPU_386, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 3, 1,
|
||||
|
|
@ -1189,17 +1185,33 @@ static const x86_insn_info call_insn[] = {
|
|||
{ CPU_EM64T|CPU_64, 0, 64, 0, 0, 1, {0xFF, 0, 0}, 3, 1,
|
||||
{OPT_Mem|OPS_64|OPTM_Far|OPA_EA, 0, 0} },
|
||||
{ CPU_Any, 0, 0, 0, 0, 1, {0xFF, 0, 0}, 3, 1,
|
||||
{OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} }
|
||||
{OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} },
|
||||
|
||||
/* With explicit FAR override */
|
||||
{ CPU_Not64, 0, 16, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_Not64, 0, 0, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
|
||||
/* Since not caught by first ImmNotSegOff group, implicitly FAR. */
|
||||
{ CPU_Not64, 0, 16, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_16|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_32|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_Not64, 0, 0, 0, 0, 1, {0x9A, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_Any|OPA_JmpFar, 0, 0} }
|
||||
};
|
||||
static const x86_insn_info jmp_insn[] = {
|
||||
{ CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_Any|OPA_JmpRel, 0, 0} },
|
||||
{OPT_ImmNotSegOff|OPS_Any|OPA_JmpRel, 0, 0} },
|
||||
{ CPU_Any, 0, 16, 0, 0, 0, {0, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_16|OPA_JmpRel, 0, 0} },
|
||||
{OPT_ImmNotSegOff|OPS_16|OPA_JmpRel, 0, 0} },
|
||||
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} },
|
||||
{OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} },
|
||||
{ CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} },
|
||||
{OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} },
|
||||
|
||||
{ CPU_Any, 0, 0, 64, 0, 1, {0xEB, 0, 0}, 0, 1,
|
||||
{OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, 0, 0} },
|
||||
|
|
@ -1229,13 +1241,7 @@ static const x86_insn_info jmp_insn[] = {
|
|||
{ CPU_Any, 0, 0, 64, 0, 1, {0xFF, 0, 0}, 4, 1,
|
||||
{OPT_Mem|OPS_Any|OPTM_Near|OPA_EA, 0, 0} },
|
||||
|
||||
{ CPU_Not64, 0, 16, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_Not64, 0, 0, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
|
||||
/* Far indirect (through memory). Needs explicit FAR override. */
|
||||
{ CPU_Any, 0, 16, 0, 0, 1, {0xFF, 0, 0}, 5, 1,
|
||||
{OPT_Mem|OPS_16|OPTM_Far|OPA_EA, 0, 0} },
|
||||
{ CPU_386, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 5, 1,
|
||||
|
|
@ -1243,7 +1249,23 @@ static const x86_insn_info jmp_insn[] = {
|
|||
{ CPU_EM64T|CPU_64, 0, 64, 0, 0, 1, {0xFF, 0, 0}, 5, 1,
|
||||
{OPT_Mem|OPS_64|OPTM_Far|OPA_EA, 0, 0} },
|
||||
{ CPU_Any, 0, 0, 0, 0, 1, {0xFF, 0, 0}, 5, 1,
|
||||
{OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} }
|
||||
{OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} },
|
||||
|
||||
/* With explicit FAR override */
|
||||
{ CPU_Not64, 0, 16, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_Not64, 0, 0, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} },
|
||||
|
||||
/* Since not caught by first ImmNotSegOff group, implicitly FAR. */
|
||||
{ CPU_Not64, 0, 16, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_16|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_32|OPA_JmpFar, 0, 0} },
|
||||
{ CPU_Not64, 0, 0, 0, 0, 1, {0xEA, 0, 0}, 3, 1,
|
||||
{OPT_Imm|OPS_Any|OPA_JmpFar, 0, 0} }
|
||||
};
|
||||
static const x86_insn_info retnf_insn[] = {
|
||||
{ CPU_Not64, MOD_Op0Add, 0, 0, 0, 1,
|
||||
|
|
@ -2089,31 +2111,28 @@ x86_finalize_jmpfar(yasm_arch *arch, yasm_bytecode *bc,
|
|||
|
||||
op = yasm_ops_first(operands);
|
||||
|
||||
switch (op->targetmod) {
|
||||
case X86_FAR:
|
||||
/* "FAR imm" target needs to become "seg imm:imm". */
|
||||
if (yasm_value_finalize_expr(&jmpfar->offset,
|
||||
yasm_expr_copy(op->data.val), 0)
|
||||
|| yasm_value_finalize_expr(&jmpfar->segment, op->data.val, 16))
|
||||
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
||||
N_("jump target expression too complex"));
|
||||
jmpfar->segment.seg_of = 1;
|
||||
break;
|
||||
case X86_FAR_SEGOFF:
|
||||
/* SEG:OFF expression; split it. */
|
||||
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, 16))
|
||||
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
||||
N_("jump target segment too complex"));
|
||||
if (yasm_value_finalize_expr(&jmpfar->offset, op->data.val, 0))
|
||||
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
||||
N_("jump target offset too complex"));
|
||||
break;
|
||||
default:
|
||||
yasm_internal_error(N_("didn't get FAR expression in jmpfar"));
|
||||
}
|
||||
if (op->type == YASM_INSN__OPERAND_IMM &&
|
||||
yasm_expr_is_op(op->data.val, YASM_EXPR_SEGOFF)) {
|
||||
/* SEG:OFF expression; split it. */
|
||||
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, 16))
|
||||
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
||||
N_("jump target segment too complex"));
|
||||
if (yasm_value_finalize_expr(&jmpfar->offset, op->data.val, 0))
|
||||
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
||||
N_("jump target offset too complex"));
|
||||
} else if (op->targetmod == X86_FAR) {
|
||||
/* "FAR imm" target needs to become "seg imm:imm". */
|
||||
if (yasm_value_finalize_expr(&jmpfar->offset,
|
||||
yasm_expr_copy(op->data.val), 0)
|
||||
|| yasm_value_finalize_expr(&jmpfar->segment, op->data.val, 16))
|
||||
yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
||||
N_("jump target expression too complex"));
|
||||
jmpfar->segment.seg_of = 1;
|
||||
} else
|
||||
yasm_internal_error(N_("didn't get FAR expression in jmpfar"));
|
||||
|
||||
yasm_x86__bc_apply_prefixes((x86_common *)jmpfar, NULL, num_prefixes,
|
||||
prefixes);
|
||||
|
|
@ -2150,7 +2169,7 @@ x86_finalize_jmp(yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc,
|
|||
N_("jump target expression too complex"));
|
||||
if (jmp->target.seg_of || jmp->target.rshift || jmp->target.curpos_rel)
|
||||
yasm_error_set(YASM_ERROR_VALUE, N_("invalid jump target"));
|
||||
jmp->target.curpos_rel = 1;
|
||||
yasm_value_set_curpos_rel(&jmp->target, bc, 0);
|
||||
|
||||
/* See if the user explicitly specified short/near/far. */
|
||||
switch ((int)(jinfo->operands[0] & OPTM_MASK)) {
|
||||
|
|
@ -2320,13 +2339,6 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
|
|||
}
|
||||
}
|
||||
|
||||
/* Look for SEG:OFF operands and apply X86_FAR_SEGOFF targetmod. */
|
||||
for (i = 0, op = ops[0]; op; op = ops[++i]) {
|
||||
if (op->type == YASM_INSN__OPERAND_IMM && op->targetmod == 0 &&
|
||||
yasm_expr_is_op(op->data.val, YASM_EXPR_SEGOFF))
|
||||
op->targetmod = X86_FAR_SEGOFF;
|
||||
}
|
||||
|
||||
/* Just do a simple linear search through the info array for a match.
|
||||
* First match wins.
|
||||
*/
|
||||
|
|
@ -2543,6 +2555,12 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
|
|||
} else
|
||||
mismatch = 1;
|
||||
break;
|
||||
case OPT_ImmNotSegOff:
|
||||
if (op->type != YASM_INSN__OPERAND_IMM ||
|
||||
op->targetmod != 0 ||
|
||||
yasm_expr_is_op(op->data.val, YASM_EXPR_SEGOFF))
|
||||
mismatch = 1;
|
||||
break;
|
||||
default:
|
||||
yasm_internal_error(N_("invalid operand type"));
|
||||
}
|
||||
|
|
@ -2560,7 +2578,9 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
|
|||
/* Register size must exactly match */
|
||||
if (yasm_x86__get_reg_size(arch, op->data.reg) != size)
|
||||
mismatch = 1;
|
||||
} else if ((info->operands[i] & OPT_MASK) == OPT_Imm
|
||||
} else if (((info->operands[i] & OPT_MASK) == OPT_Imm
|
||||
|| (info->operands[i] & OPT_MASK) == OPT_ImmNotSegOff
|
||||
|| (info->operands[i] & OPT_MASK) == OPT_Imm1)
|
||||
&& (info->operands[i] & OPS_RMASK) != OPS_Relaxed
|
||||
&& (info->operands[i] & OPA_MASK) != OPA_JmpRel)
|
||||
mismatch = 1;
|
||||
|
|
@ -2612,8 +2632,7 @@ yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc,
|
|||
mismatch = 1;
|
||||
break;
|
||||
case OPTM_Far:
|
||||
if (op->targetmod != X86_FAR &&
|
||||
op->targetmod != X86_FAR_SEGOFF)
|
||||
if (op->targetmod != X86_FAR)
|
||||
mismatch = 1;
|
||||
break;
|
||||
case OPTM_To:
|
||||
|
|
|
|||
|
|
@ -95,7 +95,8 @@ typedef struct bin_objfmt_output_info {
|
|||
/*@dependent@*/ FILE *f;
|
||||
/*@only@*/ unsigned char *buf;
|
||||
/*@observer@*/ const yasm_section *sect;
|
||||
unsigned long start;
|
||||
unsigned long start; /* what normal variables go against */
|
||||
unsigned long abs_start; /* what absolutes go against */
|
||||
} bin_objfmt_output_info;
|
||||
|
||||
static /*@only@*/ yasm_expr *
|
||||
|
|
@ -169,6 +170,36 @@ bin_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Absolute value; handle it here as output_basic won't understand it */
|
||||
if (yasm_symrec_is_abs(value->rel)) {
|
||||
if (value->curpos_rel) {
|
||||
/* Calculate value relative to current assembly position */
|
||||
/*@only@*/ yasm_intnum *outval;
|
||||
unsigned int valsize = value->size;
|
||||
int retval = 0;
|
||||
|
||||
outval = yasm_intnum_create_uint(bc->offset + info->abs_start);
|
||||
yasm_intnum_calc(outval, YASM_EXPR_NEG, NULL);
|
||||
|
||||
if (value->rshift > 0) {
|
||||
/*@only@*/ yasm_intnum *shamt =
|
||||
yasm_intnum_create_uint((unsigned long)value->rshift);
|
||||
yasm_intnum_calc(outval, YASM_EXPR_SHR, shamt);
|
||||
yasm_intnum_destroy(shamt);
|
||||
}
|
||||
/* Add in absolute portion */
|
||||
if (value->abs)
|
||||
yasm_intnum_calc(outval, YASM_EXPR_ADD,
|
||||
yasm_expr_get_intnum(&value->abs, 1));
|
||||
/* Output! */
|
||||
if (yasm_arch_intnum_tobytes(info->objfmt_bin->arch, outval, buf,
|
||||
destsize, valsize, 0, bc, warn))
|
||||
retval = 1;
|
||||
yasm_intnum_destroy(outval);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Couldn't output, assume it contains an external reference. */
|
||||
yasm_error_set(YASM_ERROR_GENERAL,
|
||||
N_("binary object format does not support external references"));
|
||||
|
|
@ -264,6 +295,7 @@ bin_objfmt_output(yasm_objfmt *objfmt, FILE *f, /*@unused@*/ int all_syms,
|
|||
}
|
||||
start = yasm_intnum_get_uint(startnum);
|
||||
yasm_expr_destroy(startexpr);
|
||||
info.abs_start = start;
|
||||
textstart = start;
|
||||
|
||||
/* Align .data and .bss (if present) by adjusting their starts. */
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ EXTRA_DIST += modules/objfmts/bin/tests/abs.hex
|
|||
EXTRA_DIST += modules/objfmts/bin/tests/bigorg.asm
|
||||
EXTRA_DIST += modules/objfmts/bin/tests/bigorg.hex
|
||||
EXTRA_DIST += modules/objfmts/bin/tests/bigorg.errwarn
|
||||
EXTRA_DIST += modules/objfmts/bin/tests/bin-farabs.asm
|
||||
EXTRA_DIST += modules/objfmts/bin/tests/bin-farabs.hex
|
||||
EXTRA_DIST += modules/objfmts/bin/tests/bintest.asm
|
||||
EXTRA_DIST += modules/objfmts/bin/tests/bintest.hex
|
||||
EXTRA_DIST += modules/objfmts/bin/tests/float-err.asm
|
||||
|
|
|
|||
51
modules/objfmts/bin/tests/bin-farabs.asm
Normal file
51
modules/objfmts/bin/tests/bin-farabs.asm
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
keybuf equ 0040h:001Eh
|
||||
|
||||
absolute 5000h
|
||||
label:
|
||||
|
||||
section .text
|
||||
absval equ 1000h
|
||||
|
||||
org 0x100
|
||||
; Using seg should yield the segment part.
|
||||
mov ax, seg keybuf
|
||||
mov ax, seg (0040h:001Eh) ; NASM doesn't understand this syntax
|
||||
mov es, ax
|
||||
|
||||
; Use without seg should yield just the offset part.
|
||||
mov bx, keybuf
|
||||
mov bx, 0040h:001Eh ; Illegal in NASM ("invalid combination...")
|
||||
|
||||
; Each of the below pairs should be equivalent (and legal) in Yasm.
|
||||
; There are some differences from NASM here!
|
||||
|
||||
; Direct far jump.
|
||||
jmp keybuf ; Results in a near jump in NASM
|
||||
jmp 0040h:001Eh ; But Yasm sees the equ value as equivalent to this
|
||||
|
||||
; Force near (non-far) jump (just offset, no segment).
|
||||
jmp near keybuf
|
||||
jmp near 0040h:001Eh ; Illegal in NASM ("mismatch in operand sizes")
|
||||
|
||||
; A couple of jumps to "normal" absolute addresses.
|
||||
jmp 0x1e
|
||||
jmp 0
|
||||
jmp absval
|
||||
jmp label
|
||||
|
||||
; Non-absolute jump
|
||||
label2:
|
||||
jmp label2
|
||||
|
||||
; Non-relative access
|
||||
mov ax, [0]
|
||||
mov ax, [label]
|
||||
|
||||
; Direct far, explicitly.
|
||||
jmp far keybuf ; Illegal in NASM ("value referenced by FAR is not relocatable")
|
||||
jmp far 0040h:001Eh ; Illegal in NASM ("mismatch in operand sizes")
|
||||
|
||||
keybufptr:
|
||||
dw keybuf ; offset part
|
||||
dw seg keybuf ; segment part
|
||||
|
||||
64
modules/objfmts/bin/tests/bin-farabs.hex
Normal file
64
modules/objfmts/bin/tests/bin-farabs.hex
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
b8
|
||||
40
|
||||
00
|
||||
b8
|
||||
40
|
||||
00
|
||||
8e
|
||||
c0
|
||||
bb
|
||||
1e
|
||||
00
|
||||
bb
|
||||
1e
|
||||
00
|
||||
ea
|
||||
1e
|
||||
00
|
||||
40
|
||||
00
|
||||
ea
|
||||
1e
|
||||
00
|
||||
40
|
||||
00
|
||||
e9
|
||||
03
|
||||
ff
|
||||
e9
|
||||
00
|
||||
ff
|
||||
e9
|
||||
fd
|
||||
fe
|
||||
e9
|
||||
dc
|
||||
fe
|
||||
e9
|
||||
d9
|
||||
0e
|
||||
e9
|
||||
d6
|
||||
4e
|
||||
eb
|
||||
fe
|
||||
a1
|
||||
00
|
||||
00
|
||||
a1
|
||||
00
|
||||
50
|
||||
ea
|
||||
1e
|
||||
00
|
||||
40
|
||||
00
|
||||
ea
|
||||
1e
|
||||
00
|
||||
40
|
||||
00
|
||||
1e
|
||||
00
|
||||
40
|
||||
00
|
||||
|
|
@ -123,14 +123,19 @@ elf_objfmt_append_local_sym(yasm_symrec *sym, /*@null@*/ void *d)
|
|||
|
||||
assert(info != NULL);
|
||||
|
||||
if (!yasm_symrec_get_label(sym, &precbc))
|
||||
return 0;
|
||||
sect = yasm_bc_get_section(precbc);
|
||||
if (!yasm_symrec_get_label(sym, &precbc)) {
|
||||
if (!yasm_symrec_is_abs(sym)) /* let absolute symbol into output */
|
||||
return 0;
|
||||
precbc = NULL;
|
||||
}
|
||||
|
||||
if (precbc)
|
||||
sect = yasm_bc_get_section(precbc);
|
||||
|
||||
entry = yasm_symrec_get_data(sym, &elf_symrec_data);
|
||||
if (!entry || !elf_sym_in_table(entry)) {
|
||||
int is_sect = 0;
|
||||
if (!yasm_section_is_absolute(sect) &&
|
||||
if (sect && !yasm_section_is_absolute(sect) &&
|
||||
strcmp(yasm_symrec_get_name(sym), yasm_section_get_name(sect))==0)
|
||||
is_sect = 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -465,9 +465,8 @@ elf_symtab_write_to_file(FILE *f, elf_symtab_head *symtab,
|
|||
yasm_error_set(YASM_ERROR_VALUE,
|
||||
N_("EQU value not an integer expression"));
|
||||
yasm_errwarn_propagate(errwarns, equ_expr->line);
|
||||
}
|
||||
|
||||
value_intn = yasm_intnum_copy(equ_intn);
|
||||
} else
|
||||
value_intn = yasm_intnum_copy(equ_intn);
|
||||
entry->index = SHN_ABS;
|
||||
yasm_expr_destroy(equ_expr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ EXTRA_DIST += modules/objfmts/elf/tests/elfabssect.asm
|
|||
EXTRA_DIST += modules/objfmts/elf/tests/elfabssect.hex
|
||||
EXTRA_DIST += modules/objfmts/elf/tests/elfcond.asm
|
||||
EXTRA_DIST += modules/objfmts/elf/tests/elfcond.hex
|
||||
EXTRA_DIST += modules/objfmts/elf/tests/elfequabs.asm
|
||||
EXTRA_DIST += modules/objfmts/elf/tests/elfequabs.hex
|
||||
EXTRA_DIST += modules/objfmts/elf/tests/elfglobal.asm
|
||||
EXTRA_DIST += modules/objfmts/elf/tests/elfglobal.hex
|
||||
EXTRA_DIST += modules/objfmts/elf/tests/elfglobext.asm
|
||||
|
|
|
|||
|
|
@ -7,3 +7,6 @@ teststruc:
|
|||
teststruc_size:
|
||||
%line 3+0 elfabssect.asm
|
||||
[section .text]
|
||||
;global teststruc
|
||||
global teststruc.testlabel
|
||||
global teststruc_size
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
00
|
||||
00
|
||||
00
|
||||
d0
|
||||
e0
|
||||
00
|
||||
00
|
||||
00
|
||||
|
|
@ -101,6 +101,42 @@ d0
|
|||
00
|
||||
2d
|
||||
00
|
||||
74
|
||||
65
|
||||
73
|
||||
74
|
||||
73
|
||||
74
|
||||
72
|
||||
75
|
||||
63
|
||||
2e
|
||||
74
|
||||
65
|
||||
73
|
||||
74
|
||||
6c
|
||||
61
|
||||
62
|
||||
65
|
||||
6c
|
||||
00
|
||||
74
|
||||
65
|
||||
73
|
||||
74
|
||||
73
|
||||
74
|
||||
72
|
||||
75
|
||||
63
|
||||
5f
|
||||
73
|
||||
69
|
||||
7a
|
||||
65
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
|
|
@ -138,54 +174,6 @@ ff
|
|||
00
|
||||
00
|
||||
00
|
||||
02
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
f1
|
||||
ff
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
f1
|
||||
ff
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
f1
|
||||
ff
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
|
|
@ -198,6 +186,7 @@ ff
|
|||
00
|
||||
04
|
||||
00
|
||||
03
|
||||
00
|
||||
00
|
||||
00
|
||||
|
|
@ -209,6 +198,33 @@ ff
|
|||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
f1
|
||||
ff
|
||||
17
|
||||
00
|
||||
00
|
||||
00
|
||||
02
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
f1
|
||||
ff
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
|
|
@ -306,7 +322,7 @@ ff
|
|||
00
|
||||
00
|
||||
00
|
||||
03
|
||||
26
|
||||
00
|
||||
00
|
||||
00
|
||||
|
|
@ -342,11 +358,11 @@ ff
|
|||
00
|
||||
00
|
||||
00
|
||||
68
|
||||
8c
|
||||
00
|
||||
00
|
||||
00
|
||||
60
|
||||
50
|
||||
00
|
||||
00
|
||||
00
|
||||
|
|
@ -354,7 +370,7 @@ ff
|
|||
00
|
||||
00
|
||||
00
|
||||
06
|
||||
03
|
||||
00
|
||||
00
|
||||
00
|
||||
|
|
|
|||
10
modules/objfmts/elf/tests/elfequabs.asm
Normal file
10
modules/objfmts/elf/tests/elfequabs.asm
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
global label
|
||||
absolute 5000h
|
||||
label:
|
||||
|
||||
section .text
|
||||
global absval
|
||||
absval equ 1000h
|
||||
|
||||
jmp absval
|
||||
jmp label
|
||||
496
modules/objfmts/elf/tests/elfequabs.hex
Normal file
496
modules/objfmts/elf/tests/elfequabs.hex
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
7f
|
||||
45
|
||||
4c
|
||||
46
|
||||
01
|
||||
01
|
||||
01
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
01
|
||||
00
|
||||
03
|
||||
00
|
||||
01
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
01
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
34
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
28
|
||||
00
|
||||
06
|
||||
00
|
||||
01
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
e9
|
||||
fc
|
||||
0f
|
||||
00
|
||||
00
|
||||
e9
|
||||
fc
|
||||
4f
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
01
|
||||
00
|
||||
00
|
||||
00
|
||||
02
|
||||
02
|
||||
00
|
||||
00
|
||||
06
|
||||
00
|
||||
00
|
||||
00
|
||||
02
|
||||
02
|
||||
00
|
||||
00
|
||||
00
|
||||
2e
|
||||
74
|
||||
65
|
||||
78
|
||||
74
|
||||
00
|
||||
2e
|
||||
72
|
||||
65
|
||||
6c
|
||||
2e
|
||||
74
|
||||
65
|
||||
78
|
||||
74
|
||||
00
|
||||
2e
|
||||
73
|
||||
74
|
||||
72
|
||||
74
|
||||
61
|
||||
62
|
||||
00
|
||||
2e
|
||||
73
|
||||
79
|
||||
6d
|
||||
74
|
||||
61
|
||||
62
|
||||
00
|
||||
2e
|
||||
73
|
||||
68
|
||||
73
|
||||
74
|
||||
72
|
||||
74
|
||||
61
|
||||
62
|
||||
00
|
||||
00
|
||||
00
|
||||
2d
|
||||
00
|
||||
6c
|
||||
61
|
||||
62
|
||||
65
|
||||
6c
|
||||
00
|
||||
61
|
||||
62
|
||||
73
|
||||
76
|
||||
61
|
||||
6c
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
01
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
04
|
||||
00
|
||||
f1
|
||||
ff
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
f1
|
||||
ff
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
03
|
||||
00
|
||||
04
|
||||
00
|
||||
03
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
50
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
f1
|
||||
ff
|
||||
09
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
f1
|
||||
ff
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
21
|
||||
00
|
||||
00
|
||||
00
|
||||
03
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
5c
|
||||
00
|
||||
00
|
||||
00
|
||||
2b
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
11
|
||||
00
|
||||
00
|
||||
00
|
||||
03
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
88
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
19
|
||||
00
|
||||
00
|
||||
00
|
||||
02
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
98
|
||||
00
|
||||
00
|
||||
00
|
||||
60
|
||||
00
|
||||
00
|
||||
00
|
||||
02
|
||||
00
|
||||
00
|
||||
00
|
||||
04
|
||||
00
|
||||
00
|
||||
00
|
||||
04
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
01
|
||||
00
|
||||
00
|
||||
00
|
||||
01
|
||||
00
|
||||
00
|
||||
00
|
||||
06
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
40
|
||||
00
|
||||
00
|
||||
00
|
||||
0a
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
07
|
||||
00
|
||||
00
|
||||
00
|
||||
09
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
00
|
||||
4c
|
||||
00
|
||||
00
|
||||
00
|
||||
10
|
||||
00
|
||||
00
|
||||
00
|
||||
03
|
||||
00
|
||||
00
|
||||
00
|
||||
04
|
||||
00
|
||||
00
|
||||
00
|
||||
04
|
||||
00
|
||||
00
|
||||
00
|
||||
08
|
||||
00
|
||||
00
|
||||
00
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue