From ac2743de635b5a2acea413c20d01b0465de6c227 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Mon, 20 May 2002 01:08:42 +0000 Subject: [PATCH] Prevent spurious "Circular reference detected" errors by refining the return value for bc_resolve() to enum-defined flags. svn path=/trunk/yasm/; revision=623 --- libyasm/arch.h | 5 ++- libyasm/bytecode.c | 30 +++++++------- libyasm/bytecode.h | 17 ++++++-- modules/arch/x86/x86-int.h | 4 +- modules/arch/x86/x86bc.c | 41 ++++++++++--------- modules/objfmts/Makefile.inc | 4 +- modules/objfmts/bin/tests/Makefile.inc | 7 +++- modules/objfmts/bin/tests/reserve-err.asm | 15 +++++++ modules/objfmts/bin/tests/reserve-err.errwarn | 4 ++ modules/optimizers/basic/basic-optimizer.c | 18 +++++--- src/arch.h | 5 ++- src/arch/x86/x86-int.h | 4 +- src/arch/x86/x86bc.c | 41 ++++++++++--------- src/bytecode.c | 30 +++++++------- src/bytecode.h | 17 ++++++-- src/objfmts/Makefile.inc | 4 +- src/objfmts/bin/tests/Makefile.inc | 7 +++- src/objfmts/bin/tests/reserve-err.asm | 15 +++++++ src/objfmts/bin/tests/reserve-err.errwarn | 4 ++ src/optimizers/basic/basic-optimizer.c | 18 +++++--- 20 files changed, 190 insertions(+), 100 deletions(-) create mode 100644 modules/objfmts/bin/tests/reserve-err.asm create mode 100644 modules/objfmts/bin/tests/reserve-err.errwarn create mode 100644 src/objfmts/bin/tests/reserve-err.asm create mode 100644 src/objfmts/bin/tests/reserve-err.errwarn diff --git a/libyasm/arch.h b/libyasm/arch.h index 86779b04..2e53ae30 100644 --- a/libyasm/arch.h +++ b/libyasm/arch.h @@ -40,8 +40,9 @@ struct arch { void (*bc_print) (FILE *f, const bytecode *bc); /* See bytecode.h comments on bc_resolve() */ - int (*bc_resolve) (bytecode *bc, int save, const section *sect, - resolve_label_func resolve_label); + bc_resolve_flags (*bc_resolve) (bytecode *bc, int save, + const section *sect, + resolve_label_func resolve_label); /* See bytecode.h comments on bc_tobytes() */ int (*bc_tobytes) (bytecode *bc, unsigned char **bufp, const section *sect, void *d, diff --git a/libyasm/bytecode.c b/libyasm/bytecode.c index b17448cc..5f3ad3b2 100644 --- a/libyasm/bytecode.c +++ b/libyasm/bytecode.c @@ -293,7 +293,7 @@ bc_print(FILE *f, const bytecode *bc) fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset); } -static int +static bc_resolve_flags bc_resolve_data(bytecode_data *bc_data, unsigned long *len) { dataval *dv; @@ -316,15 +316,15 @@ bc_resolve_data(bytecode_data *bc_data, unsigned long *len) } } - return 1; + return BC_RESOLVE_MIN_LEN; } -static int +static bc_resolve_flags bc_resolve_reserve(bytecode_reserve *reserve, unsigned long *len, int save, unsigned long line, const section *sect, resolve_label_func resolve_label) { - int retval = 1; + bc_resolve_flags retval = BC_RESOLVE_MIN_LEN; /*@null@*/ expr *temp; expr **tempp; /*@dependent@*/ /*@null@*/ const intnum *num; @@ -343,14 +343,14 @@ bc_resolve_reserve(bytecode_reserve *reserve, unsigned long *len, int save, if (expr_contains(temp, EXPR_FLOAT)) ErrorAt(line, _("expression must not contain floating point value")); - retval = -1; + retval = BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } else *len += intnum_get_uint(num)*reserve->itemsize; expr_delete(temp); return retval; } -static int +static bc_resolve_flags bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, unsigned long line, const section *sect, resolve_label_func resolve_label) @@ -377,7 +377,7 @@ bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, start = intnum_get_uint(num); expr_delete(temp); if (!num) - return -1; + return BC_RESOLVE_UNKNOWN_LEN; } /* Try to convert maxlen to integer value */ @@ -396,7 +396,7 @@ bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, maxlen = intnum_get_uint(num); expr_delete(temp); if (!num) - return -1; + return BC_RESOLVE_UNKNOWN_LEN; } /* FIXME: Search include path for filename. Save full path back into @@ -408,12 +408,12 @@ bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, if (!f) { ErrorAt(line, _("`incbin': unable to open file `%s'"), incbin->filename); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } if (fseek(f, 0L, SEEK_END) < 0) { ErrorAt(line, _("`incbin': unable to seek on file `%s'"), incbin->filename); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } flen = (unsigned long)ftell(f); fclose(f); @@ -429,14 +429,14 @@ bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, if (maxlen < flen) flen = maxlen; *len += flen; - return 1; + return BC_RESOLVE_MIN_LEN; } -int +bc_resolve_flags bc_resolve(bytecode *bc, int save, const section *sect, resolve_label_func resolve_label) { - int retval = 1; + bc_resolve_flags retval = BC_RESOLVE_MIN_LEN; bytecode_data *bc_data; bytecode_reserve *reserve; bytecode_incbin *incbin; @@ -487,14 +487,14 @@ bc_resolve(bytecode *bc, int save, const section *sect, if (expr_contains(temp, EXPR_FLOAT)) ErrorAt(bc->line, _("expression must not contain floating point value")); - retval = -1; + retval = BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } else bc->len *= intnum_get_uint(num); expr_delete(temp); } /* If we got an error somewhere along the line, clear out any calc len */ - if (retval < 0) + if (retval & BC_RESOLVE_UNKNOWN_LEN) bc->len = 0; return retval; diff --git a/libyasm/bytecode.h b/libyasm/bytecode.h index 22745634..8704ad4f 100644 --- a/libyasm/bytecode.h +++ b/libyasm/bytecode.h @@ -58,10 +58,19 @@ void bc_delete(/*@only@*/ /*@null@*/ bytecode *bc); void bc_print(FILE *f, const bytecode *bc); +/* Return value flags for bc_resolve() */ +typedef enum { + BC_RESOLVE_NONE = 0, /* Ok, but length is not minimum */ + BC_RESOLVE_ERROR = 1<<0, /* Error found, output */ + BC_RESOLVE_MIN_LEN = 1<<1, /* Length is minimum possible */ + BC_RESOLVE_UNKNOWN_LEN = 1<<2 /* Length indeterminate */ +} bc_resolve_flags; + /* Resolves labels in bytecode, and calculates its length. * Tries to minimize the length as much as possible. - * Returns whether the length is the minimum possible (1=yes, 0=no). - * Returns -1 if the length was indeterminate. + * Returns whether the length is the minimum possible, indeterminate, and + * if there was an error recognized and output during execution (see above + * for return flags). * Note: sometimes it's impossible to determine if a length is the minimum * possible. In this case, this function returns that the length is NOT * the minimum. @@ -72,8 +81,8 @@ void bc_print(FILE *f, const bytecode *bc); * resolve_label except temporarily to try to minimize the length). * When save is nonzero, all fields in bc may be modified by this function. */ -int bc_resolve(bytecode *bc, int save, const section *sect, - resolve_label_func resolve_label); +bc_resolve_flags bc_resolve(bytecode *bc, int save, const section *sect, + resolve_label_func resolve_label); /* Converts the bytecode bc into its byte representation. * Inputs: diff --git a/modules/arch/x86/x86-int.h b/modules/arch/x86/x86-int.h index f027c3a6..86811b62 100644 --- a/modules/arch/x86/x86-int.h +++ b/modules/arch/x86/x86-int.h @@ -96,8 +96,8 @@ typedef struct x86_jmprel { void x86_bc_delete(bytecode *bc); void x86_bc_print(FILE *f, const bytecode *bc); -int x86_bc_resolve(bytecode *bc, int save, const section *sect, - resolve_label_func resolve_label); +bc_resolve_flags x86_bc_resolve(bytecode *bc, int save, const section *sect, + resolve_label_func resolve_label); int x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect, void *d, output_expr_func output_expr); diff --git a/modules/arch/x86/x86bc.c b/modules/arch/x86/x86bc.c index 9f860383..8cc4d4b4 100644 --- a/modules/arch/x86/x86bc.c +++ b/modules/arch/x86/x86bc.c @@ -462,7 +462,7 @@ x86_bc_print(FILE *f, const bytecode *bc) } } -static int +static bc_resolve_flags x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, const section *sect, resolve_label_func resolve_label) { @@ -470,7 +470,7 @@ x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, effaddr *ea = insn->ea; x86_effaddr_data *ead = ea_get_data(ea); immval *imm = insn->imm; - int retval = 1; /* may turn into 0 at some point */ + bc_resolve_flags retval = BC_RESOLVE_MIN_LEN; if (ea) { /* Create temp copy of disp, etc. */ @@ -496,14 +496,15 @@ x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, &ead_t.sib, &ead_t.valid_sib, &ead_t.need_sib)) { expr_delete(temp); - return -1; /* failed, don't bother checking rest of insn */ + /* failed, don't bother checking rest of insn */ + return BC_RESOLVE_UNKNOWN_LEN; } expr_delete(temp); if (displen != 1) { /* Fits into a word/dword, or unknown. */ - retval = 0; /* may not be smallest size */ + retval = BC_RESOLVE_NONE; /* may not be smallest size */ /* Handle unknown case, make displen word-sized */ if (displen == 0xff) @@ -553,7 +554,7 @@ x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, insn->imm = (immval *)NULL; } } else - retval = 0; /* we could still get ,1 */ + retval = BC_RESOLVE_NONE; /* we could still get ,1 */ /* Not really necessary, but saves confusion over it. */ if (save) @@ -574,12 +575,12 @@ x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, return retval; } -static int +static bc_resolve_flags x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, const bytecode *bc, const section *sect, resolve_label_func resolve_label) { - int retval = 1; + bc_resolve_flags retval = BC_RESOLVE_MIN_LEN; /*@null@*/ expr *temp; /*@dependent@*/ /*@null@*/ const intnum *num; unsigned long target; @@ -605,7 +606,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, if (!num) { ErrorAt(bc->line, _("short jump target external or out of segment")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } else { target = intnum_get_uint(num); rel = (long)(target - @@ -613,12 +614,12 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, /* does a short form exist? */ if (jmprel->shortop.opcode_len == 0) { ErrorAt(bc->line, _("short jump does not exist")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } /* short displacement must fit in -128 <= rel <= +127 */ if (rel < -128 || rel > 127) { ErrorAt(bc->line, _("short jump out of range")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } } } @@ -629,7 +630,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, if (save) { if (jmprel->nearop.opcode_len == 0) { ErrorAt(bc->line, _("near jump does not exist")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } } break; @@ -656,7 +657,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, */ jrshort = 0; if (jmprel->shortop.opcode_len != 0) - retval = 0; + retval = BC_RESOLVE_NONE; } else { /* Doesn't fit into short, and there's no near opcode. * Error out if saving, otherwise just make it a short @@ -665,7 +666,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, */ if (save) { ErrorAt(bc->line, _("short jump out of range")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } jrshort = 1; } @@ -676,13 +677,13 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, */ if (jmprel->nearop.opcode_len != 0) { if (jmprel->shortop.opcode_len != 0) - retval = 0; + retval = BC_RESOLVE_NONE; jrshort = 0; } else { if (save) { ErrorAt(bc->line, _("short jump target or out of segment")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } jrshort = 1; } @@ -695,14 +696,14 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, if (save) jmprel->op_sel = JR_SHORT; if (jmprel->shortop.opcode_len == 0) - return -1; /* uh-oh, that size not available */ + return BC_RESOLVE_UNKNOWN_LEN; /* uh-oh, that size not available */ *len += jmprel->shortop.opcode_len + 1; } else { if (save) jmprel->op_sel = JR_NEAR; if (jmprel->nearop.opcode_len == 0) - return -1; /* uh-oh, that size not available */ + return BC_RESOLVE_UNKNOWN_LEN; /* uh-oh, that size not available */ *len += jmprel->nearop.opcode_len; *len += (opersize == 32) ? 4 : 2; @@ -716,7 +717,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, return retval; } -int +bc_resolve_flags x86_bc_resolve(bytecode *bc, int save, const section *sect, resolve_label_func resolve_label) { @@ -735,7 +736,9 @@ x86_bc_resolve(bytecode *bc, int save, const section *sect, default: break; } - return 0; + InternalError(_("Didn't handle bytecode type in x86 arch")); + /*@notreached@*/ + return BC_RESOLVE_UNKNOWN_LEN; } static int diff --git a/modules/objfmts/Makefile.inc b/modules/objfmts/Makefile.inc index 7ebe8be8..b395e5e7 100644 --- a/modules/objfmts/Makefile.inc +++ b/modules/objfmts/Makefile.inc @@ -2,9 +2,11 @@ EXTRA_DIST += \ src/objfmts/dbg/Makefile.inc \ - src/objfmts/bin/Makefile.inc + src/objfmts/bin/Makefile.inc \ + src/objfmts/elf/Makefile.inc YASMOBJFMTFILES = include src/objfmts/dbg/Makefile.inc include src/objfmts/bin/Makefile.inc +include src/objfmts/elf/Makefile.inc yasm_SOURCES += $(YASMOBJFMTFILES) diff --git a/modules/objfmts/bin/tests/Makefile.inc b/modules/objfmts/bin/tests/Makefile.inc index c8d61532..b6926d21 100644 --- a/modules/objfmts/bin/tests/Makefile.inc +++ b/modules/objfmts/bin/tests/Makefile.inc @@ -18,7 +18,9 @@ EXTRA_DIST += \ src/objfmts/bin/tests/integer.errwarn \ src/objfmts/bin/tests/reserve.asm \ src/objfmts/bin/tests/reserve.bin.hx \ - src/objfmts/bin/tests/reserve.errwarn + src/objfmts/bin/tests/reserve.errwarn \ + src/objfmts/bin/tests/reserve-err.asm \ + src/objfmts/bin/tests/reserve-err.errwarn CLEANFILES += \ float-err.ew \ @@ -33,4 +35,5 @@ CLEANFILES += \ integer.ew \ reserve \ reserve.ew \ - reserve.hx + reserve.hx \ + reserve-err.ew diff --git a/modules/objfmts/bin/tests/reserve-err.asm b/modules/objfmts/bin/tests/reserve-err.asm new file mode 100644 index 00000000..ad6e31ae --- /dev/null +++ b/modules/objfmts/bin/tests/reserve-err.asm @@ -0,0 +1,15 @@ +; Test res* family errors +a: +resb -5 +resw 1.2 +resd -1.2 +resq 0xffffffff +rest a + +[section .bss] +resb -5 +resw 1.2 +resd -1.2 +resq 0xffffffff +rest a + diff --git a/modules/objfmts/bin/tests/reserve-err.errwarn b/modules/objfmts/bin/tests/reserve-err.errwarn new file mode 100644 index 00000000..3e755ca4 --- /dev/null +++ b/modules/objfmts/bin/tests/reserve-err.errwarn @@ -0,0 +1,4 @@ +./src/objfmts/bin/tests/reserve-err.asm:4: expression must not contain floating point value +./src/objfmts/bin/tests/reserve-err.asm:5: expression must not contain floating point value +./src/objfmts/bin/tests/reserve-err.asm:11: expression must not contain floating point value +./src/objfmts/bin/tests/reserve-err.asm:12: expression must not contain floating point value diff --git a/modules/optimizers/basic/basic-optimizer.c b/modules/optimizers/basic/basic-optimizer.c index a7bb9a88..2ad60218 100644 --- a/modules/optimizers/basic/basic-optimizer.c +++ b/modules/optimizers/basic/basic-optimizer.c @@ -150,6 +150,7 @@ static int basic_optimize_bytecode_1(/*@observer@*/ bytecode *bc, void *d) { basic_optimize_data *data = (basic_optimize_data *)d; + bc_resolve_flags bcr_retval; /* Don't even bother if we're in-progress or done. */ if (bc->opt_flags == BCFLAG_INPROGRESS) @@ -169,8 +170,10 @@ basic_optimize_bytecode_1(/*@observer@*/ bytecode *bc, void *d) * is minimum or not, and just check for indeterminate length (indicative * of circular reference). */ - if (bc_resolve(bc, 0, data->sect, basic_optimize_resolve_label) < 0) { - ErrorAt(bc->line, _("Circular reference detected.")); + bcr_retval = bc_resolve(bc, 0, data->sect, basic_optimize_resolve_label); + if (bcr_retval & BC_RESOLVE_UNKNOWN_LEN) { + if (!(bcr_retval & BC_RESOLVE_ERROR)) + ErrorAt(bc->line, _("Circular reference detected.")); data->saw_unknown = -1; return 0; } @@ -181,8 +184,9 @@ basic_optimize_bytecode_1(/*@observer@*/ bytecode *bc, void *d) } static int -basic_optimize_section_1(section *sect, /*@unused@*/ /*@null@*/ void *d) +basic_optimize_section_1(section *sect, void *d) { + int *saw_unknown = (int *)d; basic_optimize_data data; unsigned long flags; int retval; @@ -206,7 +210,7 @@ basic_optimize_section_1(section *sect, /*@unused@*/ /*@null@*/ void *d) return retval; if (data.saw_unknown != 0) - return data.saw_unknown; + *saw_unknown = data.saw_unknown; section_set_opt_flags(sect, SECTFLAG_DONE); @@ -252,6 +256,8 @@ basic_optimize_section_2(section *sect, /*@unused@*/ /*@null@*/ void *d) static void basic_optimize(sectionhead *sections) { + int saw_unknown = 0; + /* Optimization process: (essentially NASM's pass 1) * Determine the size of all bytecodes. * Forward references are /not/ resolved (only backward references are @@ -264,7 +270,9 @@ basic_optimize(sectionhead *sections) * - not strictly top->bottom scanning; we scan through a section and * hop to other sections as necessary. */ - if (sections_traverse(sections, NULL, basic_optimize_section_1) < 0) + if (sections_traverse(sections, &saw_unknown, + basic_optimize_section_1) < 0 || + saw_unknown != 0) return; /* Check completion of all sections and save bytecode changes */ diff --git a/src/arch.h b/src/arch.h index 86779b04..2e53ae30 100644 --- a/src/arch.h +++ b/src/arch.h @@ -40,8 +40,9 @@ struct arch { void (*bc_print) (FILE *f, const bytecode *bc); /* See bytecode.h comments on bc_resolve() */ - int (*bc_resolve) (bytecode *bc, int save, const section *sect, - resolve_label_func resolve_label); + bc_resolve_flags (*bc_resolve) (bytecode *bc, int save, + const section *sect, + resolve_label_func resolve_label); /* See bytecode.h comments on bc_tobytes() */ int (*bc_tobytes) (bytecode *bc, unsigned char **bufp, const section *sect, void *d, diff --git a/src/arch/x86/x86-int.h b/src/arch/x86/x86-int.h index f027c3a6..86811b62 100644 --- a/src/arch/x86/x86-int.h +++ b/src/arch/x86/x86-int.h @@ -96,8 +96,8 @@ typedef struct x86_jmprel { void x86_bc_delete(bytecode *bc); void x86_bc_print(FILE *f, const bytecode *bc); -int x86_bc_resolve(bytecode *bc, int save, const section *sect, - resolve_label_func resolve_label); +bc_resolve_flags x86_bc_resolve(bytecode *bc, int save, const section *sect, + resolve_label_func resolve_label); int x86_bc_tobytes(bytecode *bc, unsigned char **bufp, const section *sect, void *d, output_expr_func output_expr); diff --git a/src/arch/x86/x86bc.c b/src/arch/x86/x86bc.c index 9f860383..8cc4d4b4 100644 --- a/src/arch/x86/x86bc.c +++ b/src/arch/x86/x86bc.c @@ -462,7 +462,7 @@ x86_bc_print(FILE *f, const bytecode *bc) } } -static int +static bc_resolve_flags x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, const section *sect, resolve_label_func resolve_label) { @@ -470,7 +470,7 @@ x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, effaddr *ea = insn->ea; x86_effaddr_data *ead = ea_get_data(ea); immval *imm = insn->imm; - int retval = 1; /* may turn into 0 at some point */ + bc_resolve_flags retval = BC_RESOLVE_MIN_LEN; if (ea) { /* Create temp copy of disp, etc. */ @@ -496,14 +496,15 @@ x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, &ead_t.sib, &ead_t.valid_sib, &ead_t.need_sib)) { expr_delete(temp); - return -1; /* failed, don't bother checking rest of insn */ + /* failed, don't bother checking rest of insn */ + return BC_RESOLVE_UNKNOWN_LEN; } expr_delete(temp); if (displen != 1) { /* Fits into a word/dword, or unknown. */ - retval = 0; /* may not be smallest size */ + retval = BC_RESOLVE_NONE; /* may not be smallest size */ /* Handle unknown case, make displen word-sized */ if (displen == 0xff) @@ -553,7 +554,7 @@ x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, insn->imm = (immval *)NULL; } } else - retval = 0; /* we could still get ,1 */ + retval = BC_RESOLVE_NONE; /* we could still get ,1 */ /* Not really necessary, but saves confusion over it. */ if (save) @@ -574,12 +575,12 @@ x86_bc_resolve_insn(x86_insn *insn, unsigned long *len, int save, return retval; } -static int +static bc_resolve_flags x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, const bytecode *bc, const section *sect, resolve_label_func resolve_label) { - int retval = 1; + bc_resolve_flags retval = BC_RESOLVE_MIN_LEN; /*@null@*/ expr *temp; /*@dependent@*/ /*@null@*/ const intnum *num; unsigned long target; @@ -605,7 +606,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, if (!num) { ErrorAt(bc->line, _("short jump target external or out of segment")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } else { target = intnum_get_uint(num); rel = (long)(target - @@ -613,12 +614,12 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, /* does a short form exist? */ if (jmprel->shortop.opcode_len == 0) { ErrorAt(bc->line, _("short jump does not exist")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } /* short displacement must fit in -128 <= rel <= +127 */ if (rel < -128 || rel > 127) { ErrorAt(bc->line, _("short jump out of range")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } } } @@ -629,7 +630,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, if (save) { if (jmprel->nearop.opcode_len == 0) { ErrorAt(bc->line, _("near jump does not exist")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } } break; @@ -656,7 +657,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, */ jrshort = 0; if (jmprel->shortop.opcode_len != 0) - retval = 0; + retval = BC_RESOLVE_NONE; } else { /* Doesn't fit into short, and there's no near opcode. * Error out if saving, otherwise just make it a short @@ -665,7 +666,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, */ if (save) { ErrorAt(bc->line, _("short jump out of range")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } jrshort = 1; } @@ -676,13 +677,13 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, */ if (jmprel->nearop.opcode_len != 0) { if (jmprel->shortop.opcode_len != 0) - retval = 0; + retval = BC_RESOLVE_NONE; jrshort = 0; } else { if (save) { ErrorAt(bc->line, _("short jump target or out of segment")); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } jrshort = 1; } @@ -695,14 +696,14 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, if (save) jmprel->op_sel = JR_SHORT; if (jmprel->shortop.opcode_len == 0) - return -1; /* uh-oh, that size not available */ + return BC_RESOLVE_UNKNOWN_LEN; /* uh-oh, that size not available */ *len += jmprel->shortop.opcode_len + 1; } else { if (save) jmprel->op_sel = JR_NEAR; if (jmprel->nearop.opcode_len == 0) - return -1; /* uh-oh, that size not available */ + return BC_RESOLVE_UNKNOWN_LEN; /* uh-oh, that size not available */ *len += jmprel->nearop.opcode_len; *len += (opersize == 32) ? 4 : 2; @@ -716,7 +717,7 @@ x86_bc_resolve_jmprel(x86_jmprel *jmprel, unsigned long *len, int save, return retval; } -int +bc_resolve_flags x86_bc_resolve(bytecode *bc, int save, const section *sect, resolve_label_func resolve_label) { @@ -735,7 +736,9 @@ x86_bc_resolve(bytecode *bc, int save, const section *sect, default: break; } - return 0; + InternalError(_("Didn't handle bytecode type in x86 arch")); + /*@notreached@*/ + return BC_RESOLVE_UNKNOWN_LEN; } static int diff --git a/src/bytecode.c b/src/bytecode.c index b17448cc..5f3ad3b2 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -293,7 +293,7 @@ bc_print(FILE *f, const bytecode *bc) fprintf(f, "%*sOffset=%lx\n", indent_level, "", bc->offset); } -static int +static bc_resolve_flags bc_resolve_data(bytecode_data *bc_data, unsigned long *len) { dataval *dv; @@ -316,15 +316,15 @@ bc_resolve_data(bytecode_data *bc_data, unsigned long *len) } } - return 1; + return BC_RESOLVE_MIN_LEN; } -static int +static bc_resolve_flags bc_resolve_reserve(bytecode_reserve *reserve, unsigned long *len, int save, unsigned long line, const section *sect, resolve_label_func resolve_label) { - int retval = 1; + bc_resolve_flags retval = BC_RESOLVE_MIN_LEN; /*@null@*/ expr *temp; expr **tempp; /*@dependent@*/ /*@null@*/ const intnum *num; @@ -343,14 +343,14 @@ bc_resolve_reserve(bytecode_reserve *reserve, unsigned long *len, int save, if (expr_contains(temp, EXPR_FLOAT)) ErrorAt(line, _("expression must not contain floating point value")); - retval = -1; + retval = BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } else *len += intnum_get_uint(num)*reserve->itemsize; expr_delete(temp); return retval; } -static int +static bc_resolve_flags bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, unsigned long line, const section *sect, resolve_label_func resolve_label) @@ -377,7 +377,7 @@ bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, start = intnum_get_uint(num); expr_delete(temp); if (!num) - return -1; + return BC_RESOLVE_UNKNOWN_LEN; } /* Try to convert maxlen to integer value */ @@ -396,7 +396,7 @@ bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, maxlen = intnum_get_uint(num); expr_delete(temp); if (!num) - return -1; + return BC_RESOLVE_UNKNOWN_LEN; } /* FIXME: Search include path for filename. Save full path back into @@ -408,12 +408,12 @@ bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, if (!f) { ErrorAt(line, _("`incbin': unable to open file `%s'"), incbin->filename); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } if (fseek(f, 0L, SEEK_END) < 0) { ErrorAt(line, _("`incbin': unable to seek on file `%s'"), incbin->filename); - return -1; + return BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } flen = (unsigned long)ftell(f); fclose(f); @@ -429,14 +429,14 @@ bc_resolve_incbin(bytecode_incbin *incbin, unsigned long *len, int save, if (maxlen < flen) flen = maxlen; *len += flen; - return 1; + return BC_RESOLVE_MIN_LEN; } -int +bc_resolve_flags bc_resolve(bytecode *bc, int save, const section *sect, resolve_label_func resolve_label) { - int retval = 1; + bc_resolve_flags retval = BC_RESOLVE_MIN_LEN; bytecode_data *bc_data; bytecode_reserve *reserve; bytecode_incbin *incbin; @@ -487,14 +487,14 @@ bc_resolve(bytecode *bc, int save, const section *sect, if (expr_contains(temp, EXPR_FLOAT)) ErrorAt(bc->line, _("expression must not contain floating point value")); - retval = -1; + retval = BC_RESOLVE_ERROR | BC_RESOLVE_UNKNOWN_LEN; } else bc->len *= intnum_get_uint(num); expr_delete(temp); } /* If we got an error somewhere along the line, clear out any calc len */ - if (retval < 0) + if (retval & BC_RESOLVE_UNKNOWN_LEN) bc->len = 0; return retval; diff --git a/src/bytecode.h b/src/bytecode.h index 22745634..8704ad4f 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -58,10 +58,19 @@ void bc_delete(/*@only@*/ /*@null@*/ bytecode *bc); void bc_print(FILE *f, const bytecode *bc); +/* Return value flags for bc_resolve() */ +typedef enum { + BC_RESOLVE_NONE = 0, /* Ok, but length is not minimum */ + BC_RESOLVE_ERROR = 1<<0, /* Error found, output */ + BC_RESOLVE_MIN_LEN = 1<<1, /* Length is minimum possible */ + BC_RESOLVE_UNKNOWN_LEN = 1<<2 /* Length indeterminate */ +} bc_resolve_flags; + /* Resolves labels in bytecode, and calculates its length. * Tries to minimize the length as much as possible. - * Returns whether the length is the minimum possible (1=yes, 0=no). - * Returns -1 if the length was indeterminate. + * Returns whether the length is the minimum possible, indeterminate, and + * if there was an error recognized and output during execution (see above + * for return flags). * Note: sometimes it's impossible to determine if a length is the minimum * possible. In this case, this function returns that the length is NOT * the minimum. @@ -72,8 +81,8 @@ void bc_print(FILE *f, const bytecode *bc); * resolve_label except temporarily to try to minimize the length). * When save is nonzero, all fields in bc may be modified by this function. */ -int bc_resolve(bytecode *bc, int save, const section *sect, - resolve_label_func resolve_label); +bc_resolve_flags bc_resolve(bytecode *bc, int save, const section *sect, + resolve_label_func resolve_label); /* Converts the bytecode bc into its byte representation. * Inputs: diff --git a/src/objfmts/Makefile.inc b/src/objfmts/Makefile.inc index 7ebe8be8..b395e5e7 100644 --- a/src/objfmts/Makefile.inc +++ b/src/objfmts/Makefile.inc @@ -2,9 +2,11 @@ EXTRA_DIST += \ src/objfmts/dbg/Makefile.inc \ - src/objfmts/bin/Makefile.inc + src/objfmts/bin/Makefile.inc \ + src/objfmts/elf/Makefile.inc YASMOBJFMTFILES = include src/objfmts/dbg/Makefile.inc include src/objfmts/bin/Makefile.inc +include src/objfmts/elf/Makefile.inc yasm_SOURCES += $(YASMOBJFMTFILES) diff --git a/src/objfmts/bin/tests/Makefile.inc b/src/objfmts/bin/tests/Makefile.inc index c8d61532..b6926d21 100644 --- a/src/objfmts/bin/tests/Makefile.inc +++ b/src/objfmts/bin/tests/Makefile.inc @@ -18,7 +18,9 @@ EXTRA_DIST += \ src/objfmts/bin/tests/integer.errwarn \ src/objfmts/bin/tests/reserve.asm \ src/objfmts/bin/tests/reserve.bin.hx \ - src/objfmts/bin/tests/reserve.errwarn + src/objfmts/bin/tests/reserve.errwarn \ + src/objfmts/bin/tests/reserve-err.asm \ + src/objfmts/bin/tests/reserve-err.errwarn CLEANFILES += \ float-err.ew \ @@ -33,4 +35,5 @@ CLEANFILES += \ integer.ew \ reserve \ reserve.ew \ - reserve.hx + reserve.hx \ + reserve-err.ew diff --git a/src/objfmts/bin/tests/reserve-err.asm b/src/objfmts/bin/tests/reserve-err.asm new file mode 100644 index 00000000..ad6e31ae --- /dev/null +++ b/src/objfmts/bin/tests/reserve-err.asm @@ -0,0 +1,15 @@ +; Test res* family errors +a: +resb -5 +resw 1.2 +resd -1.2 +resq 0xffffffff +rest a + +[section .bss] +resb -5 +resw 1.2 +resd -1.2 +resq 0xffffffff +rest a + diff --git a/src/objfmts/bin/tests/reserve-err.errwarn b/src/objfmts/bin/tests/reserve-err.errwarn new file mode 100644 index 00000000..3e755ca4 --- /dev/null +++ b/src/objfmts/bin/tests/reserve-err.errwarn @@ -0,0 +1,4 @@ +./src/objfmts/bin/tests/reserve-err.asm:4: expression must not contain floating point value +./src/objfmts/bin/tests/reserve-err.asm:5: expression must not contain floating point value +./src/objfmts/bin/tests/reserve-err.asm:11: expression must not contain floating point value +./src/objfmts/bin/tests/reserve-err.asm:12: expression must not contain floating point value diff --git a/src/optimizers/basic/basic-optimizer.c b/src/optimizers/basic/basic-optimizer.c index a7bb9a88..2ad60218 100644 --- a/src/optimizers/basic/basic-optimizer.c +++ b/src/optimizers/basic/basic-optimizer.c @@ -150,6 +150,7 @@ static int basic_optimize_bytecode_1(/*@observer@*/ bytecode *bc, void *d) { basic_optimize_data *data = (basic_optimize_data *)d; + bc_resolve_flags bcr_retval; /* Don't even bother if we're in-progress or done. */ if (bc->opt_flags == BCFLAG_INPROGRESS) @@ -169,8 +170,10 @@ basic_optimize_bytecode_1(/*@observer@*/ bytecode *bc, void *d) * is minimum or not, and just check for indeterminate length (indicative * of circular reference). */ - if (bc_resolve(bc, 0, data->sect, basic_optimize_resolve_label) < 0) { - ErrorAt(bc->line, _("Circular reference detected.")); + bcr_retval = bc_resolve(bc, 0, data->sect, basic_optimize_resolve_label); + if (bcr_retval & BC_RESOLVE_UNKNOWN_LEN) { + if (!(bcr_retval & BC_RESOLVE_ERROR)) + ErrorAt(bc->line, _("Circular reference detected.")); data->saw_unknown = -1; return 0; } @@ -181,8 +184,9 @@ basic_optimize_bytecode_1(/*@observer@*/ bytecode *bc, void *d) } static int -basic_optimize_section_1(section *sect, /*@unused@*/ /*@null@*/ void *d) +basic_optimize_section_1(section *sect, void *d) { + int *saw_unknown = (int *)d; basic_optimize_data data; unsigned long flags; int retval; @@ -206,7 +210,7 @@ basic_optimize_section_1(section *sect, /*@unused@*/ /*@null@*/ void *d) return retval; if (data.saw_unknown != 0) - return data.saw_unknown; + *saw_unknown = data.saw_unknown; section_set_opt_flags(sect, SECTFLAG_DONE); @@ -252,6 +256,8 @@ basic_optimize_section_2(section *sect, /*@unused@*/ /*@null@*/ void *d) static void basic_optimize(sectionhead *sections) { + int saw_unknown = 0; + /* Optimization process: (essentially NASM's pass 1) * Determine the size of all bytecodes. * Forward references are /not/ resolved (only backward references are @@ -264,7 +270,9 @@ basic_optimize(sectionhead *sections) * - not strictly top->bottom scanning; we scan through a section and * hop to other sections as necessary. */ - if (sections_traverse(sections, NULL, basic_optimize_section_1) < 0) + if (sections_traverse(sections, &saw_unknown, + basic_optimize_section_1) < 0 || + saw_unknown != 0) return; /* Check completion of all sections and save bytecode changes */ -- 2.50.0