- 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:
Peter Johnson 2006-09-29 07:18:45 +00:00
parent 096e2eb79a
commit 3e8d2c2e7a
23 changed files with 1066 additions and 1624 deletions

View file

@ -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;

View file

@ -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));

View file

@ -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

View file

@ -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)
{

View file

@ -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.

View file

@ -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))

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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:

View file

@ -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. */

View file

@ -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

View 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

View 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

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

@ -7,3 +7,6 @@ teststruc:
teststruc_size:
%line 3+0 elfabssect.asm
[section .text]
;global teststruc
global teststruc.testlabel
global teststruc_size

View file

@ -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

View file

@ -0,0 +1,10 @@
global label
absolute 5000h
label:
section .text
global absval
absval equ 1000h
jmp absval
jmp label

View 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