From: Peter Johnson Date: Fri, 29 Sep 2006 07:18:45 +0000 (-0000) Subject: - Fix much brokenness in absolute value handling, particularly in regards to X-Git-Tag: v0.6.0~145 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3e8d2c2e7a162cc7a8d20f07e60f6f009914e795;p=yasm - 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 --- diff --git a/libyasm/expr-int.h b/libyasm/expr-int.h index 0a1bc5a9..8f5842df 100644 --- a/libyasm/expr-int.h +++ b/libyasm/expr-int.h @@ -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; diff --git a/libyasm/expr.c b/libyasm/expr.c index 60f2409a..531ad604 100644 --- a/libyasm/expr.c +++ b/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; jnumterms; 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; inumterms; 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; inumterms; 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; inumterms; 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; inumterms; 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; inumterms; 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; inumterms; 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)); diff --git a/libyasm/expr.h b/libyasm/expr.h index 801594eb..9c7574fb 100644 --- a/libyasm/expr.h +++ b/libyasm/expr.h @@ -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 diff --git a/libyasm/symrec.c b/libyasm/symrec.c index 08e90f85..6028c4bc 100644 --- a/libyasm/symrec.c +++ b/libyasm/symrec.c @@ -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) { diff --git a/libyasm/symrec.h b/libyasm/symrec.h index a4d97391..04ec321b 100644 --- a/libyasm/symrec.h +++ b/libyasm/symrec.h @@ -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. diff --git a/libyasm/value.c b/libyasm/value.c index 50b5482c..6ef16855 100644 --- a/libyasm/value.c +++ b/libyasm/value.c @@ -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)) diff --git a/libyasm/value.h b/libyasm/value.h index 89a93aa8..4c871073 100644 --- a/libyasm/value.h +++ b/libyasm/value.h @@ -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 diff --git a/modules/arch/x86/x86arch.h b/modules/arch/x86/x86arch.h index 328e270a..a2639c47 100644 --- a/modules/arch/x86/x86arch.h +++ b/modules/arch/x86/x86arch.h @@ -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); diff --git a/modules/arch/x86/x86bc.c b/modules/arch/x86/x86bc.c index e587d36d..6897261b 100644 --- a/modules/arch/x86/x86bc.c +++ b/modules/arch/x86/x86bc.c @@ -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; diff --git a/modules/arch/x86/x86expr.c b/modules/arch/x86/x86expr.c index 21ae3deb..c114547c 100644 --- a/modules/arch/x86/x86expr.c +++ b/modules/arch/x86/x86expr.c @@ -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; } } diff --git a/modules/arch/x86/x86id.c b/modules/arch/x86/x86id.c index a0275a2c..def4549b 100644 --- a/modules/arch/x86/x86id.c +++ b/modules/arch/x86/x86id.c @@ -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: diff --git a/modules/objfmts/bin/bin-objfmt.c b/modules/objfmts/bin/bin-objfmt.c index 9d9114ee..17bdfab2 100644 --- a/modules/objfmts/bin/bin-objfmt.c +++ b/modules/objfmts/bin/bin-objfmt.c @@ -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. */ diff --git a/modules/objfmts/bin/tests/Makefile.inc b/modules/objfmts/bin/tests/Makefile.inc index a2620ee5..1251308c 100644 --- a/modules/objfmts/bin/tests/Makefile.inc +++ b/modules/objfmts/bin/tests/Makefile.inc @@ -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 diff --git a/modules/objfmts/bin/tests/bin-farabs.asm b/modules/objfmts/bin/tests/bin-farabs.asm new file mode 100644 index 00000000..e26bcbc6 --- /dev/null +++ b/modules/objfmts/bin/tests/bin-farabs.asm @@ -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 + diff --git a/modules/objfmts/bin/tests/bin-farabs.hex b/modules/objfmts/bin/tests/bin-farabs.hex new file mode 100644 index 00000000..6f626b56 --- /dev/null +++ b/modules/objfmts/bin/tests/bin-farabs.hex @@ -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 diff --git a/modules/objfmts/elf/elf-objfmt.c b/modules/objfmts/elf/elf-objfmt.c index e82b574d..c5947c5a 100644 --- a/modules/objfmts/elf/elf-objfmt.c +++ b/modules/objfmts/elf/elf-objfmt.c @@ -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; diff --git a/modules/objfmts/elf/elf.c b/modules/objfmts/elf/elf.c index ce1e9dcb..5961c6a1 100644 --- a/modules/objfmts/elf/elf.c +++ b/modules/objfmts/elf/elf.c @@ -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); } diff --git a/modules/objfmts/elf/tests/Makefile.inc b/modules/objfmts/elf/tests/Makefile.inc index 716c99c1..e6d485f3 100644 --- a/modules/objfmts/elf/tests/Makefile.inc +++ b/modules/objfmts/elf/tests/Makefile.inc @@ -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 diff --git a/modules/objfmts/elf/tests/elfabssect.asm b/modules/objfmts/elf/tests/elfabssect.asm index cf0cb3ba..0c9c4348 100644 --- a/modules/objfmts/elf/tests/elfabssect.asm +++ b/modules/objfmts/elf/tests/elfabssect.asm @@ -7,3 +7,6 @@ teststruc: teststruc_size: %line 3+0 elfabssect.asm [section .text] +;global teststruc +global teststruc.testlabel +global teststruc_size diff --git a/modules/objfmts/elf/tests/elfabssect.hex b/modules/objfmts/elf/tests/elfabssect.hex index 7b34fd08..65d3974a 100644 --- a/modules/objfmts/elf/tests/elfabssect.hex +++ b/modules/objfmts/elf/tests/elfabssect.hex @@ -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,8 +174,6 @@ ff 00 00 00 -02 -00 00 00 00 @@ -148,10 +182,11 @@ ff 00 00 00 -f1 -ff +03 00 +04 00 +03 00 00 00 @@ -163,12 +198,15 @@ ff 00 00 00 +10 00 f1 ff +17 00 00 00 +02 00 00 00 @@ -176,9 +214,7 @@ ff 00 00 00 -00 -00 -00 +10 00 f1 ff @@ -194,26 +230,6 @@ ff 00 00 00 -03 -00 -04 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -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 diff --git a/modules/objfmts/elf/tests/elfequabs.asm b/modules/objfmts/elf/tests/elfequabs.asm new file mode 100644 index 00000000..39f62a28 --- /dev/null +++ b/modules/objfmts/elf/tests/elfequabs.asm @@ -0,0 +1,10 @@ +global label +absolute 5000h +label: + +section .text +global absval +absval equ 1000h + +jmp absval +jmp label diff --git a/modules/objfmts/elf/tests/elfequabs.hex b/modules/objfmts/elf/tests/elfequabs.hex new file mode 100644 index 00000000..514f7d29 --- /dev/null +++ b/modules/objfmts/elf/tests/elfequabs.hex @@ -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 diff --git a/modules/objfmts/elf/tests/elfmanysym.hex b/modules/objfmts/elf/tests/elfmanysym.hex index c4971e1f..a5f6e1ad 100644 --- a/modules/objfmts/elf/tests/elfmanysym.hex +++ b/modules/objfmts/elf/tests/elfmanysym.hex @@ -30,8 +30,8 @@ 00 00 00 -20 -16 +b0 +10 00 00 00 @@ -75,8 +75,8 @@ bf 00 00 01 -01 -01 +aa +00 00 00 2e @@ -3678,16 +3678,11 @@ ff 00 00 00 +03 00 +04 00 -f1 -ff -00 -00 -00 -00 -00 -00 +03 00 00 00 @@ -3696,14 +3691,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +08 00 00 00 @@ -3712,14 +3707,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +0e 00 00 00 @@ -3728,14 +3723,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +16 00 00 00 @@ -3744,14 +3739,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +22 00 00 00 @@ -3760,14 +3755,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +2d 00 00 00 @@ -3776,14 +3771,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +43 00 00 00 @@ -3792,14 +3787,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +59 00 00 00 @@ -3808,14 +3803,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +76 00 00 00 @@ -3824,14 +3819,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +87 00 00 00 @@ -3840,14 +3835,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +99 00 00 00 @@ -3856,14 +3851,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +ac 00 00 00 @@ -3872,14 +3867,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +c0 00 00 00 @@ -3888,14 +3883,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +d4 00 00 00 @@ -3904,14 +3899,14 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +e9 00 00 00 @@ -3920,14 +3915,15 @@ ff 00 00 00 -f1 -ff 00 00 00 +10 00 00 00 +04 +01 00 00 00 @@ -3936,15 +3932,17 @@ ff 00 00 00 -f1 -ff 00 00 +10 00 00 00 +20 +01 00 00 +05 00 00 00 @@ -3952,10 +3950,12 @@ ff 00 00 00 -f1 -ff +10 00 +04 00 +3f +01 00 00 00 @@ -3966,13 +3966,15 @@ ff 00 00 00 +10 00 00 -f1 -ff 00 +5e +01 00 00 +05 00 00 00 @@ -3980,12 +3982,15 @@ ff 00 00 00 +10 00 +04 00 +7b +01 00 00 -f1 -ff +05 00 00 00 @@ -3993,36 +3998,47 @@ ff 00 00 00 +10 00 +04 00 +98 +01 00 00 +05 00 00 00 -f1 -ff 00 00 00 00 +10 00 +04 00 +b5 +01 00 00 +05 00 00 00 00 00 00 -f1 -ff 00 +10 00 +04 00 +d3 +01 00 00 +05 00 00 00 @@ -4030,26 +4046,15 @@ ff 00 00 00 +10 00 +04 00 f1 -ff -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 +01 00 00 -f1 -ff +05 00 00 00 @@ -4057,36 +4062,47 @@ ff 00 00 00 +10 00 +04 00 +13 +02 00 00 +05 00 00 00 -f1 -ff 00 00 00 00 +10 00 +04 00 +2f +02 00 00 +05 00 00 00 00 00 00 -f1 -ff 00 +10 00 +04 00 +4d +02 00 00 +05 00 00 00 @@ -4094,12 +4110,15 @@ ff 00 00 00 +10 00 +04 00 -f1 -ff +6b +02 00 00 +05 00 00 00 @@ -4107,36 +4126,47 @@ ff 00 00 00 +10 00 +04 00 +87 +02 00 00 +05 00 -f1 -ff 00 00 00 00 00 00 +10 00 +04 00 +a4 +02 00 00 +05 00 00 00 00 -f1 -ff 00 00 00 +10 00 +04 00 +c1 +02 00 00 +05 00 00 00 @@ -4144,10 +4174,12 @@ ff 00 00 00 -f1 -ff +10 00 +04 00 +e2 +02 00 00 00 @@ -4158,12 +4190,15 @@ ff 00 00 00 +10 00 +04 00 -f1 -ff +01 +03 00 00 +05 00 00 00 @@ -4171,36 +4206,47 @@ ff 00 00 00 +10 00 +04 00 +22 +03 00 00 +05 00 -f1 -ff 00 00 00 00 00 00 +10 00 +04 00 +33 +03 00 00 +05 00 00 00 00 -f1 -ff 00 00 00 +10 00 +04 00 +45 +03 00 00 +05 00 00 00 @@ -4208,9 +4254,9 @@ ff 00 00 00 -f1 -ff +10 00 +04 00 00 00 @@ -4224,8 +4270,6 @@ ff 00 00 00 -f1 -ff 00 00 00 @@ -4240,8 +4284,6 @@ ff 00 00 00 -f1 -ff 00 00 00 @@ -4256,8 +4298,6 @@ ff 00 00 00 -f1 -ff 00 00 00 @@ -4270,11 +4310,11 @@ ff 00 00 00 +21 00 00 -f1 -ff 00 +03 00 00 00 @@ -4286,11 +4326,11 @@ ff 00 00 00 +50 00 00 -f1 -ff 00 +2b 00 00 00 @@ -4304,40 +4344,39 @@ ff 00 00 00 -f1 -ff 00 00 00 00 00 00 +11 00 00 00 +03 00 00 00 00 00 -f1 -ff 00 00 00 00 00 00 +7c 00 00 00 +56 +03 00 00 00 00 00 -f1 -ff 00 00 00 @@ -4351,11 +4390,11 @@ ff 00 00 00 +19 00 -f1 -ff 00 00 +02 00 00 00 @@ -4367,1453 +4406,22 @@ ff 00 00 00 +d4 +03 00 -f1 -ff 00 +d0 +0c 00 00 +02 00 00 00 +a9 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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -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 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -08 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -0e -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -16 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -22 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -2d -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -43 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -59 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -76 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -87 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -99 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -ac -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -c0 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -d4 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -e9 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -04 -01 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -20 -01 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -3f -01 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -00 -00 -5e -01 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -7b -01 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -98 -01 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -b5 -01 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -d3 -01 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -f1 -01 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -13 -02 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -2f -02 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -4d -02 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -6b -02 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -87 -02 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -a4 -02 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -c1 -02 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -e2 -02 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -01 -03 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -22 -03 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -33 -03 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -00 -45 -03 -00 -00 -05 -00 -00 -00 -00 -00 -00 -00 -10 -00 -04 -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 -00 -00 -00 -00 -00 -21 -00 -00 -00 -03 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -50 -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 -7c -00 -00 -00 -56 -03 -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 -d4 -03 -00 -00 -40 -12 -00 -00 -02 -00 -00 -00 -00 -01 -00 -00 04 00 00