/* Check for undefined symbols */
yasm_symtab_parser_finalize(yasm_object_get_symtab(object),
strcmp(cur_parser_module->keyword, "gas")==0,
- cur_objfmt);
-
- if (yasm_get_num_errors(warning_error) > 0) {
- yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error,
- print_yasm_error, print_yasm_warning);
- cleanup(object);
- return EXIT_FAILURE;
- }
+ cur_objfmt, errwarns);
+ check_errors(errwarns, object);
/* Finalize parse */
- yasm_object_finalize(object);
-
- if (yasm_get_num_errors(warning_error) > 0) {
- yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error,
- print_yasm_error, print_yasm_warning);
- cleanup(object);
- return EXIT_FAILURE;
- }
+ yasm_object_finalize(object, errwarns);
+ check_errors(errwarns, object);
/* Optimize */
- cur_optimizer_module->optimize(object, errwarns);
+ yasm_object_optimize(object, cur_arch);
-
- if (yasm_get_num_errors(warning_error) > 0) {
- yasm_errwarn_output_all(yasm_object_get_linemap(object), warning_error,
- print_yasm_error, print_yasm_warning);
- cleanup(object);
- return EXIT_FAILURE;
- }
+ check_errors(errwarns, object);
/* generate any debugging information */
- yasm_dbgfmt_generate(cur_dbgfmt);
+ yasm_dbgfmt_generate(cur_dbgfmt, errwarns);
+ check_errors(errwarns, object);
/* open the object file for output (if not already opened by dbg objfmt) */
if (!obj && strcmp(cur_objfmt_module->keyword, "dbg") != 0) {
# $Id$
+ libyasm_a_SOURCES += libyasm/arch.c
+ libyasm_a_SOURCES += libyasm/assocdat.c
+ libyasm_a_SOURCES += libyasm/bitvect.c
+ libyasm_a_SOURCES += libyasm/bc-align.c
+ libyasm_a_SOURCES += libyasm/bc-data.c
+ libyasm_a_SOURCES += libyasm/bc-incbin.c
+ libyasm_a_SOURCES += libyasm/bc-insn.c
+ libyasm_a_SOURCES += libyasm/bc-org.c
+ libyasm_a_SOURCES += libyasm/bc-reserve.c
libyasm_a_SOURCES += libyasm/bytecode.c
+ libyasm_a_SOURCES += libyasm/errwarn.c
libyasm_a_SOURCES += libyasm/expr.c
- libyasm_a_SOURCES += libyasm/symrec.c
libyasm_a_SOURCES += libyasm/file.c
- libyasm_a_SOURCES += libyasm/section.c
- libyasm_a_SOURCES += libyasm/arch.c
- libyasm_a_SOURCES += libyasm/objfmt.c
- libyasm_a_SOURCES += libyasm/intnum.c
libyasm_a_SOURCES += libyasm/floatnum.c
libyasm_a_SOURCES += libyasm/hamt.c
- libyasm_a_SOURCES += libyasm/bitvect.c
- libyasm_a_SOURCES += libyasm/valparam.c
- libyasm_a_SOURCES += libyasm/errwarn.c
+ libyasm_a_SOURCES += libyasm/intnum.c
libyasm_a_SOURCES += libyasm/linemgr.c
- libyasm_a_SOURCES += libyasm/assocdat.c
- libyasm_a_SOURCES += libyasm/xmalloc.c
- libyasm_a_SOURCES += libyasm/xstrdup.c
- libyasm_a_SOURCES += libyasm/strcasecmp.c
+ libyasm_a_SOURCES += libyasm/md5.c
libyasm_a_SOURCES += libyasm/mergesort.c
+ libyasm_a_SOURCES += libyasm/phash.c
+ libyasm_a_SOURCES += libyasm/section.c
+ libyasm_a_SOURCES += libyasm/strcasecmp.c
libyasm_a_SOURCES += libyasm/strsep.c
+ libyasm_a_SOURCES += libyasm/symrec.c
+ libyasm_a_SOURCES += libyasm/valparam.c
+ libyasm_a_SOURCES += libyasm/value.c
+ libyasm_a_SOURCES += libyasm/xmalloc.c
+ libyasm_a_SOURCES += libyasm/xstrdup.c
+libyasm_a_SOURCES += libyasm/qq.c
+libyasm_a_SOURCES += libyasm/stack.c
+libyasm_a_SOURCES += libyasm/interval_tree.c
libyasm_a_SOURCES += module.c
module.c: $(top_srcdir)/libyasm/module.in genmodule$(EXEEXT) Makefile
modinclude_HEADERS += libyasm/errwarn.h
modinclude_HEADERS += libyasm/expr.h
modinclude_HEADERS += libyasm/expr-int.h
- modinclude_HEADERS += libyasm/symrec.h
- modinclude_HEADERS += libyasm/linemgr.h
- modinclude_HEADERS += libyasm/coretype.h
modinclude_HEADERS += libyasm/file.h
- modinclude_HEADERS += libyasm/section.h
- modinclude_HEADERS += libyasm/arch.h
- modinclude_HEADERS += libyasm/dbgfmt.h
- modinclude_HEADERS += libyasm/objfmt.h
+ modinclude_HEADERS += libyasm/floatnum.h
+ modinclude_HEADERS += libyasm/hamt.h
+ modinclude_HEADERS += libyasm/intnum.h
+ modinclude_HEADERS += libyasm/linemgr.h
modinclude_HEADERS += libyasm/listfmt.h
-modinclude_HEADERS += libyasm/optimizer.h
+ modinclude_HEADERS += libyasm/md5.h
+ modinclude_HEADERS += libyasm/module.h
+ modinclude_HEADERS += libyasm/objfmt.h
modinclude_HEADERS += libyasm/parser.h
+ modinclude_HEADERS += libyasm/phash.h
modinclude_HEADERS += libyasm/preproc.h
- modinclude_HEADERS += libyasm/intnum.h
- modinclude_HEADERS += libyasm/floatnum.h
- modinclude_HEADERS += libyasm/hamt.h
- modinclude_HEADERS += libyasm/bitvect.h
+ modinclude_HEADERS += libyasm/section.h
+ modinclude_HEADERS += libyasm/symrec.h
modinclude_HEADERS += libyasm/valparam.h
- modinclude_HEADERS += libyasm/compat-queue.h
- modinclude_HEADERS += libyasm/assocdat.h
- modinclude_HEADERS += libyasm/module.h
+ modinclude_HEADERS += libyasm/value.h
+modinclude_HEADERS += libyasm/qq.h
+modinclude_HEADERS += libyasm/stack.h
+modinclude_HEADERS += libyasm/interval_tree.h
EXTRA_DIST += libyasm/tests/Makefile.inc
*/
unsigned int wordsize;
+ /** Long/short jump size descriminator. Number of bytes (+/-) a short
+ * jump can range over. Used to size optimization FIFOs, so don't
+ * make this extremely large (e.g. >1000).
+ */
+ const unsigned long jmpsize_threshold;
++
+ /** Worst case minimum instruction length in bytes.
+ * Call yasm_arch_min_insn_len() to get the minimum instruction length of
+ * a particular #yasm_arch.
+ */
+ unsigned int min_insn_len;
} yasm_arch_module;
#ifdef YASM_LIB_INTERNAL
(((yasm_arch_base *)arch)->module->keyword)
#define yasm_arch_wordsize(arch) \
(((yasm_arch_base *)arch)->module->wordsize)
+#define yasm_arch_jmpsize_threshold(arch) \
+ (((yasm_arch_base *)arch)->module->jmpsize_threshold)
+ #define yasm_arch_min_insn_len(arch) \
+ (((yasm_arch_base *)arch)->module->min_insn_len)
#define yasm_arch_create(module, machine, parser, error) \
module->create(machine, parser, error)
--- /dev/null
-static yasm_bc_resolve_flags bc_align_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * Align bytecode
+ *
+ * Copyright (C) 2005-2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+
+ #include "coretype.h"
+
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+
+ #include "bytecode.h"
+
+ #include "bc-int.h"
+
+
+ typedef struct bytecode_align {
+ /*@only@*/ yasm_expr *boundary; /* alignment boundary */
+
+ /* What to fill intervening locations with, NULL if using code_fill */
+ /*@only@*/ /*@null@*/ yasm_expr *fill;
+
+ /* Maximum number of bytes to skip, NULL if no maximum. */
+ /*@only@*/ /*@null@*/ yasm_expr *maxskip;
+
+ /* Code fill, NULL if using 0 fill */
+ /*@null@*/ const unsigned char **code_fill;
+ } bytecode_align;
+
+ static void bc_align_destroy(void *contents);
+ static void bc_align_print(const void *contents, FILE *f, int indent_level);
+ static void bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
- bc_align_resolve,
++static int bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data);
++static int bc_align_expand(yasm_bytecode *bc, int span, long old_val,
++ long new_val, /*@out@*/ long *neg_thres,
++ /*@out@*/ long *pos_thres);
+ static int bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static const yasm_bytecode_callback bc_align_callback = {
+ bc_align_destroy,
+ bc_align_print,
+ bc_align_finalize,
-static yasm_bc_resolve_flags
-bc_align_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ bc_align_calc_len,
++ bc_align_expand,
+ bc_align_tobytes,
+ 0
+ };
+
+
+ static void
+ bc_align_destroy(void *contents)
+ {
+ bytecode_align *align = (bytecode_align *)contents;
+ if (align->boundary)
+ yasm_expr_destroy(align->boundary);
+ if (align->fill)
+ yasm_expr_destroy(align->fill);
+ if (align->maxskip)
+ yasm_expr_destroy(align->maxskip);
+ yasm_xfree(contents);
+ }
+
+ static void
+ bc_align_print(const void *contents, FILE *f, int indent_level)
+ {
+ const bytecode_align *align = (const bytecode_align *)contents;
+ fprintf(f, "%*s_Align_\n", indent_level, "");
+ fprintf(f, "%*sBoundary=", indent_level, "");
+ yasm_expr_print(align->boundary, f);
+ fprintf(f, "\n%*sFill=", indent_level, "");
+ yasm_expr_print(align->fill, f);
+ fprintf(f, "\n%*sMax Skip=", indent_level, "");
+ yasm_expr_print(align->maxskip, f);
+ fprintf(f, "\n");
+ }
+
+ static void
+ bc_align_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+ bytecode_align *align = (bytecode_align *)bc->contents;
+ if (!yasm_expr_get_intnum(&align->boundary, NULL))
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("align boundary must be a constant"));
+ if (align->fill && !yasm_expr_get_intnum(&align->fill, NULL))
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("align fill must be a constant"));
+ if (align->maxskip && !yasm_expr_get_intnum(&align->maxskip, NULL))
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("align maximum skip must be a constant"));
+ }
+
- return YASM_BC_RESOLVE_MIN_LEN;
++static int
++bc_align_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
++ yasm_internal_error(N_("align not yet implemented"));
++#if 0
+ bytecode_align *align = (bytecode_align *)bc->contents;
+ unsigned long end;
+ unsigned long boundary =
+ yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, NULL));
+
+ if (boundary == 0) {
+ bc->len = 0;
+ return YASM_BC_RESOLVE_MIN_LEN;
+ }
+
+ end = bc->offset;
+ if (bc->offset & (boundary-1))
+ end = (bc->offset & ~(boundary-1)) + boundary;
+
+ bc->len = end - bc->offset;
+
+ if (align->maxskip) {
+ unsigned long maxskip =
+ yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip, NULL));
+ if ((end - bc->offset) > maxskip)
+ bc->len = 0;
+ }
++#endif
++ return 0;
++}
++
++static int
++bc_align_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
++ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
++{
++ yasm_internal_error(N_("align not yet implemented"));
++ return 0;
+ }
+
+ static int
+ bc_align_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+ bytecode_align *align = (bytecode_align *)bc->contents;
+ unsigned long len;
+ unsigned long boundary =
+ yasm_intnum_get_uint(yasm_expr_get_intnum(&align->boundary, NULL));
+
+ if (boundary == 0)
+ return 0;
+ else {
+ unsigned long end = bc->offset;
+ if (bc->offset & (boundary-1))
+ end = (bc->offset & ~(boundary-1)) + boundary;
+ len = end - bc->offset;
+ if (len == 0)
+ return 0;
+ if (align->maxskip) {
+ unsigned long maxskip =
+ yasm_intnum_get_uint(yasm_expr_get_intnum(&align->maxskip,
+ NULL));
+ if (len > maxskip)
+ return 0;
+ }
+ }
+
+ if (align->fill) {
+ unsigned long v;
+ v = yasm_intnum_get_uint(yasm_expr_get_intnum(&align->fill, NULL));
+ memset(*bufp, (int)v, len);
+ *bufp += len;
+ } else if (align->code_fill) {
+ unsigned long maxlen = 15;
+ while (!align->code_fill[maxlen] && maxlen>0)
+ maxlen--;
+ if (maxlen == 0) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("could not find any code alignment size"));
+ return 1;
+ }
+
+ /* Fill with maximum code fill as much as possible */
+ while (len > maxlen) {
+ memcpy(*bufp, align->code_fill[maxlen], maxlen);
+ *bufp += maxlen;
+ len -= maxlen;
+ }
+
+ if (!align->code_fill[len]) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("invalid alignment size %d"), len);
+ return 1;
+ }
+ /* Handle rest of code fill */
+ memcpy(*bufp, align->code_fill[len], len);
+ *bufp += len;
+ } else {
+ /* Just fill with 0 */
+ memset(*bufp, 0, len);
+ *bufp += len;
+ }
+ return 0;
+ }
+
+ yasm_bytecode *
+ yasm_bc_create_align(yasm_expr *boundary, yasm_expr *fill,
+ yasm_expr *maxskip, const unsigned char **code_fill,
+ unsigned long line)
+ {
+ bytecode_align *align = yasm_xmalloc(sizeof(bytecode_align));
+
+ align->boundary = boundary;
+ align->fill = fill;
+ align->maxskip = maxskip;
+ align->code_fill = code_fill;
+
+ return yasm_bc_create_common(&bc_align_callback, align, line);
+ }
--- /dev/null
-static yasm_bc_resolve_flags bc_data_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * Data (and LEB128) bytecode
+ *
+ * Copyright (C) 2001-2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+
+ #include "coretype.h"
+
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+ #include "value.h"
+
+ #include "bytecode.h"
+ #include "arch.h"
+
+ #include "bc-int.h"
+
+
+ struct yasm_dataval {
+ /*@reldef@*/ STAILQ_ENTRY(yasm_dataval) link;
+
+ enum { DV_EMPTY, DV_VALUE, DV_RAW, DV_ULEB128, DV_SLEB128 } type;
+
+ union {
+ yasm_value val;
+ struct {
+ /*@only@*/ unsigned char *contents;
+ unsigned long len;
+ } raw;
+ } data;
+ };
+
+ typedef struct bytecode_data {
+ /* converted data (linked list) */
+ yasm_datavalhead datahead;
+ } bytecode_data;
+
+ static void bc_data_destroy(void *contents);
+ static void bc_data_print(const void *contents, FILE *f, int indent_level);
+ static void bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
- bc_data_resolve,
++static int bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data);
+ static int bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static const yasm_bytecode_callback bc_data_callback = {
+ bc_data_destroy,
+ bc_data_print,
+ bc_data_finalize,
-static yasm_bc_resolve_flags
-bc_data_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ bc_data_calc_len,
++ yasm_bc_expand_common,
+ bc_data_tobytes,
+ 0
+ };
+
+
+ static void
+ bc_data_destroy(void *contents)
+ {
+ bytecode_data *bc_data = (bytecode_data *)contents;
+ yasm_dvs_destroy(&bc_data->datahead);
+ yasm_xfree(contents);
+ }
+
+ static void
+ bc_data_print(const void *contents, FILE *f, int indent_level)
+ {
+ const bytecode_data *bc_data = (const bytecode_data *)contents;
+ fprintf(f, "%*s_Data_\n", indent_level, "");
+ fprintf(f, "%*sElements:\n", indent_level+1, "");
+ yasm_dvs_print(&bc_data->datahead, f, indent_level+2);
+ }
+
+ static void
+ bc_data_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+ bytecode_data *bc_data = (bytecode_data *)bc->contents;
+ yasm_dataval *dv;
+ yasm_intnum *intn;
+
+ /* Convert values from simple expr to value. */
+ STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+ switch (dv->type) {
+ case DV_VALUE:
+ if (yasm_value_finalize(&dv->data.val)) {
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("data expression too complex"));
+ return;
+ }
+ break;
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("LEB128 requires constant values"));
+ return;
+ }
+ /* Warn for negative values in unsigned environment.
+ * This could be an error instead: the likelihood this is
+ * desired is very low!
+ */
+ if (yasm_intnum_sign(intn) == -1 && dv->type == DV_ULEB128)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("negative value in unsigned LEB128"));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
- return YASM_BC_RESOLVE_MIN_LEN;
++static int
++bc_data_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
+ bytecode_data *bc_data = (bytecode_data *)bc->contents;
+ yasm_dataval *dv;
+ yasm_intnum *intn;
+
+ /* Count up element sizes, rounding up string length. */
+ STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+ switch (dv->type) {
+ case DV_EMPTY:
+ break;
+ case DV_VALUE:
+ bc->len += dv->data.val.size/8;
+ break;
+ case DV_RAW:
+ bc->len += dv->data.raw.len;
+ break;
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+ if (!intn)
+ yasm_internal_error(N_("non-constant in data_tobytes"));
+ bc->len +=
+ yasm_intnum_size_leb128(intn, dv->type == DV_SLEB128);
+ break;
+ }
+ }
+
++ return 0;
+ }
+
+ static int
+ bc_data_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+ bytecode_data *bc_data = (bytecode_data *)bc->contents;
+ yasm_dataval *dv;
+ unsigned char *bufp_orig = *bufp;
+ yasm_intnum *intn;
+ unsigned int val_len;
+
+ STAILQ_FOREACH(dv, &bc_data->datahead, link) {
+ switch (dv->type) {
+ case DV_EMPTY:
+ break;
+ case DV_VALUE:
+ val_len = dv->data.val.size/8;
+ if (output_value(&dv->data.val, *bufp, val_len,
+ (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+ return 1;
+ *bufp += val_len;
+ break;
+ case DV_RAW:
+ memcpy(*bufp, dv->data.raw.contents, dv->data.raw.len);
+ *bufp += dv->data.raw.len;
+ break;
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+ if (!intn)
+ yasm_internal_error(N_("non-constant in data_tobytes"));
+ *bufp +=
+ yasm_intnum_get_leb128(intn, *bufp, dv->type == DV_SLEB128);
+ }
+ }
+
+ return 0;
+ }
+
+ yasm_bytecode *
+ yasm_bc_create_data(yasm_datavalhead *datahead, unsigned int size,
+ int append_zero, yasm_arch *arch, unsigned long line)
+ {
+ bytecode_data *data = yasm_xmalloc(sizeof(bytecode_data));
+ yasm_bytecode *bc = yasm_bc_create_common(&bc_data_callback, data, line);
+ yasm_dataval *dv, *dv2, *dvo;
+ yasm_intnum *intn;
+ unsigned long len = 0, rlen, i;
+
+
+ yasm_dvs_initialize(&data->datahead);
+
+ /* Prescan input data for length, etc. Careful: this needs to be
+ * precisely paired with the second loop.
+ */
+ STAILQ_FOREACH(dv, datahead, link) {
+ switch (dv->type) {
+ case DV_EMPTY:
+ break;
+ case DV_VALUE:
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+ if (intn && dv->type == DV_VALUE && (arch || size == 1))
+ len += size;
+ else if (intn && dv->type == DV_ULEB128)
+ len += yasm_intnum_size_leb128(intn, 0);
+ else if (intn && dv->type == DV_SLEB128)
+ len += yasm_intnum_size_leb128(intn, 1);
+ else {
+ if (len > 0) {
+ /* Create bytecode for all previous len */
+ dvo = yasm_dv_create_raw(yasm_xmalloc(len), len);
+ STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+ len = 0;
+ }
+
+ /* Create bytecode for this value */
+ dvo = yasm_xmalloc(sizeof(yasm_dataval));
+ STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+ }
+ break;
+ case DV_RAW:
+ rlen = dv->data.raw.len;
+ /* find count, rounding up to nearest multiple of size */
+ rlen = (rlen + size - 1) / size;
+ len += rlen*size;
+ break;
+ }
+ if (append_zero)
+ len++;
+ }
+
+ /* Create final dataval for any trailing length */
+ if (len > 0) {
+ dvo = yasm_dv_create_raw(yasm_xmalloc(len), len);
+ STAILQ_INSERT_TAIL(&data->datahead, dvo, link);
+ }
+
+ /* Second iteration: copy data and delete input datavals. */
+ dv = STAILQ_FIRST(datahead);
+ dvo = STAILQ_FIRST(&data->datahead);
+ len = 0;
+ while (dv) {
+ switch (dv->type) {
+ case DV_EMPTY:
+ break;
+ case DV_VALUE:
+ case DV_ULEB128:
+ case DV_SLEB128:
+ intn = yasm_expr_get_intnum(&dv->data.val.abs, NULL);
+ if (intn && dv->type == DV_VALUE && (arch || size == 1)) {
+ if (size == 1)
+ yasm_intnum_get_sized(intn,
+ &dvo->data.raw.contents[len],
+ 1, 8, 0, 0, 1);
+ else
+ yasm_arch_intnum_tobytes(arch, intn,
+ &dvo->data.raw.contents[len],
+ size, size*8, 0, bc, 1);
+ yasm_value_delete(&dv->data.val);
+ len += size;
+ } else if (intn && dv->type == DV_ULEB128) {
+ len += yasm_intnum_get_leb128(intn,
+ &dvo->data.raw.contents[len],
+ 0);
+ } else if (intn && dv->type == DV_SLEB128) {
+ len += yasm_intnum_get_leb128(intn,
+ &dvo->data.raw.contents[len],
+ 1);
+ } else {
+ dvo->type = dv->type;
+ dvo->data.val = dv->data.val; /* structure copy */
+ dvo->data.val.size = size*8; /* remember size */
+ dvo = STAILQ_NEXT(dvo, link);
+ len = 0;
+ }
+ break;
+ case DV_RAW:
+ rlen = dv->data.raw.len;
+ memcpy(&dvo->data.raw.contents[len], dv->data.raw.contents,
+ rlen);
+ yasm_xfree(dv->data.raw.contents);
+ len += rlen;
+ /* pad with 0's to nearest multiple of size */
+ rlen %= size;
+ if (rlen > 0) {
+ rlen = size-rlen;
+ for (i=0; i<rlen; i++)
+ dvo->data.raw.contents[len++] = 0;
+ }
+ break;
+ }
+ if (append_zero)
+ dvo->data.raw.contents[len++] = 0;
+ dv2 = STAILQ_NEXT(dv, link);
+ yasm_xfree(dv);
+ dv = dv2;
+ }
+
+ return bc;
+ }
+
+ yasm_bytecode *
+ yasm_bc_create_leb128(yasm_datavalhead *datahead, int sign, unsigned long line)
+ {
+ yasm_dataval *dv;
+
+ /* Convert all values into LEB type, error on strings/raws */
+ STAILQ_FOREACH(dv, datahead, link) {
+ switch (dv->type) {
+ case DV_VALUE:
+ dv->type = sign ? DV_SLEB128 : DV_ULEB128;
+ break;
+ case DV_RAW:
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("LEB128 does not allow string constants"));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return yasm_bc_create_data(datahead, 0, 0, 0, line);
+ }
+
+ yasm_dataval *
+ yasm_dv_create_expr(yasm_expr *e)
+ {
+ yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
+
+ retval->type = DV_VALUE;
+ yasm_value_initialize(&retval->data.val, e, 0);
+
+ return retval;
+ }
+
+ yasm_dataval *
+ yasm_dv_create_raw(unsigned char *contents, unsigned long len)
+ {
+ yasm_dataval *retval = yasm_xmalloc(sizeof(yasm_dataval));
+
+ retval->type = DV_RAW;
+ retval->data.raw.contents = contents;
+ retval->data.raw.len = len;
+
+ return retval;
+ }
+
+ void
+ yasm_dvs_destroy(yasm_datavalhead *headp)
+ {
+ yasm_dataval *cur, *next;
+
+ cur = STAILQ_FIRST(headp);
+ while (cur) {
+ next = STAILQ_NEXT(cur, link);
+ switch (cur->type) {
+ case DV_VALUE:
+ yasm_value_delete(&cur->data.val);
+ break;
+ case DV_RAW:
+ yasm_xfree(cur->data.raw.contents);
+ break;
+ default:
+ break;
+ }
+ yasm_xfree(cur);
+ cur = next;
+ }
+ STAILQ_INIT(headp);
+ }
+
+ yasm_dataval *
+ yasm_dvs_append(yasm_datavalhead *headp, yasm_dataval *dv)
+ {
+ if (dv) {
+ STAILQ_INSERT_TAIL(headp, dv, link);
+ return dv;
+ }
+ return (yasm_dataval *)NULL;
+ }
+
+ void
+ yasm_dvs_print(const yasm_datavalhead *head, FILE *f, int indent_level)
+ {
+ yasm_dataval *cur;
+ unsigned long i;
+
+ STAILQ_FOREACH(cur, head, link) {
+ switch (cur->type) {
+ case DV_EMPTY:
+ fprintf(f, "%*sEmpty\n", indent_level, "");
+ break;
+ case DV_VALUE:
+ fprintf(f, "%*sValue:\n", indent_level, "");
+ yasm_value_print(&cur->data.val, f, indent_level+1);
+ break;
+ case DV_RAW:
+ fprintf(f, "%*sLength=%lu\n", indent_level, "",
+ cur->data.raw.len);
+ fprintf(f, "%*sBytes=[", indent_level, "");
+ for (i=0; i<cur->data.raw.len; i++)
+ fprintf(f, "0x%02x, ", cur->data.raw.contents[i]);
+ fprintf(f, "]\n");
+ break;
+ case DV_ULEB128:
+ fprintf(f, "%*sULEB128 value:\n", indent_level, "");
+ yasm_value_print(&cur->data.val, f, indent_level+1);
+ break;
+ case DV_SLEB128:
+ fprintf(f, "%*sSLEB128 value:\n", indent_level, "");
+ yasm_value_print(&cur->data.val, f, indent_level+1);
+ break;
+ }
+ }
+ }
+
+ /* Non-macro yasm_dvs_initialize() for non-YASM_LIB_INTERNAL users. */
+ #undef yasm_dvs_initialize
+ void
+ yasm_dvs_initialize(yasm_datavalhead *headp)
+ {
+ STAILQ_INIT(headp);
+ }
--- /dev/null
-static yasm_bc_resolve_flags bc_incbin_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * Incbin bytecode
+ *
+ * Copyright (C) 2001-2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+
+ #include "coretype.h"
+
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+ #include "value.h"
+
+ #include "bytecode.h"
+
+ #include "bc-int.h"
+
+
+ typedef struct bytecode_incbin {
+ /*@only@*/ char *filename; /* file to include data from */
+
+ /* starting offset to read from (NULL=0) */
+ /*@only@*/ /*@null@*/ yasm_expr *start;
+
+ /* maximum number of bytes to read (NULL=no limit) */
+ /*@only@*/ /*@null@*/ yasm_expr *maxlen;
+ } bytecode_incbin;
+
+ static void bc_incbin_destroy(void *contents);
+ static void bc_incbin_print(const void *contents, FILE *f, int indent_level);
+ static void bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
- bc_incbin_resolve,
++static int bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data);
+ static int bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static const yasm_bytecode_callback bc_incbin_callback = {
+ bc_incbin_destroy,
+ bc_incbin_print,
+ bc_incbin_finalize,
-static yasm_bc_resolve_flags
-bc_incbin_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ bc_incbin_calc_len,
++ yasm_bc_expand_common,
+ bc_incbin_tobytes,
+ 0
+ };
+
+
+ static void
+ bc_incbin_destroy(void *contents)
+ {
+ bytecode_incbin *incbin = (bytecode_incbin *)contents;
+ yasm_xfree(incbin->filename);
+ yasm_expr_destroy(incbin->start);
+ yasm_expr_destroy(incbin->maxlen);
+ yasm_xfree(contents);
+ }
+
+ static void
+ bc_incbin_print(const void *contents, FILE *f, int indent_level)
+ {
+ const bytecode_incbin *incbin = (const bytecode_incbin *)contents;
+ fprintf(f, "%*s_IncBin_\n", indent_level, "");
+ fprintf(f, "%*sFilename=`%s'\n", indent_level, "",
+ incbin->filename);
+ fprintf(f, "%*sStart=", indent_level, "");
+ if (!incbin->start)
+ fprintf(f, "nil (0)");
+ else
+ yasm_expr_print(incbin->start, f);
+ fprintf(f, "%*sMax Len=", indent_level, "");
+ if (!incbin->maxlen)
+ fprintf(f, "nil (unlimited)");
+ else
+ yasm_expr_print(incbin->maxlen, f);
+ fprintf(f, "\n");
+ }
+
+ static void
+ bc_incbin_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+ bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+ yasm_value val;
+
+ if (yasm_value_finalize_expr(&val, incbin->start, 0))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("start expression too complex"));
+ else if (val.rel)
+ yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+ N_("start expression not absolute"));
+ incbin->start = val.abs;
+
+ if (yasm_value_finalize_expr(&val, incbin->maxlen, 0))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("maximum length expression too complex"));
+ else if (val.rel)
+ yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+ N_("maximum length expression not absolute"));
+ incbin->maxlen = val.abs;
+ }
+
- /*@null@*/ yasm_expr *temp;
- yasm_expr **tempp;
++static int
++bc_incbin_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
+ bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+ FILE *f;
- if (save) {
- temp = NULL;
- tempp = &incbin->start;
- } else {
- temp = yasm_expr_copy(incbin->start);
- assert(temp != NULL);
- tempp = &temp;
- }
- num = yasm_expr_get_intnum(tempp, calc_bc_dist);
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+ unsigned long start = 0, maxlen = 0xFFFFFFFFUL, flen;
+
+ /* Try to convert start to integer value */
+ if (incbin->start) {
- yasm_expr_destroy(temp);
- if (!num)
- return YASM_BC_RESOLVE_UNKNOWN_LEN;
++ num = yasm_expr_get_intnum(&incbin->start, NULL);
+ if (num)
+ start = yasm_intnum_get_uint(num);
- if (save) {
- temp = NULL;
- tempp = &incbin->maxlen;
- } else {
- temp = yasm_expr_copy(incbin->maxlen);
- assert(temp != NULL);
- tempp = &temp;
- }
- num = yasm_expr_get_intnum(tempp, calc_bc_dist);
++ if (!num) {
++ /* FIXME */
++ yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED,
++ N_("incbin does not yet understand non-constant"));
++ return -1;
++ }
+ }
+
+ /* Try to convert maxlen to integer value */
+ if (incbin->maxlen) {
- yasm_expr_destroy(temp);
- if (!num)
- return YASM_BC_RESOLVE_UNKNOWN_LEN;
++ num = yasm_expr_get_intnum(&incbin->maxlen, NULL);
+ if (num)
+ maxlen = yasm_intnum_get_uint(num);
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
++ if (!num) {
++ /* FIXME */
++ yasm_error_set(YASM_ERROR_NOT_IMPLEMENTED,
++ N_("incbin does not yet understand non-constant"));
++ return -1;
++ }
+ }
+
+ /* FIXME: Search include path for filename. Save full path back into
+ * filename if save is true.
+ */
+
+ /* Open file and determine its length */
+ f = fopen(incbin->filename, "rb");
+ if (!f) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("`incbin': unable to open file `%s'"),
+ incbin->filename);
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
++ return -1;
+ }
+ if (fseek(f, 0L, SEEK_END) < 0) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("`incbin': unable to seek on file `%s'"),
+ incbin->filename);
- return YASM_BC_RESOLVE_MIN_LEN;
++ return -1;
+ }
+ flen = (unsigned long)ftell(f);
+ fclose(f);
+
+ /* Compute length of incbin from start, maxlen, and len */
+ if (start > flen) {
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("`incbin': start past end of file `%s'"),
+ incbin->filename);
+ start = flen;
+ }
+ flen -= start;
+ if (incbin->maxlen)
+ if (maxlen < flen)
+ flen = maxlen;
+ bc->len += flen;
++ return 0;
+ }
+
+ static int
+ bc_incbin_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+ bytecode_incbin *incbin = (bytecode_incbin *)bc->contents;
+ FILE *f;
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+ unsigned long start = 0;
+
+ /* Convert start to integer value */
+ if (incbin->start) {
+ num = yasm_expr_get_intnum(&incbin->start, NULL);
+ if (!num)
+ yasm_internal_error(
+ N_("could not determine start in bc_tobytes_incbin"));
+ start = yasm_intnum_get_uint(num);
+ }
+
+ /* Open file */
+ f = fopen(incbin->filename, "rb");
+ if (!f) {
+ yasm_error_set(YASM_ERROR_IO, N_("`incbin': unable to open file `%s'"),
+ incbin->filename);
+ return 1;
+ }
+
+ /* Seek to start of data */
+ if (fseek(f, (long)start, SEEK_SET) < 0) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("`incbin': unable to seek on file `%s'"),
+ incbin->filename);
+ fclose(f);
+ return 1;
+ }
+
+ /* Read len bytes */
+ if (fread(*bufp, 1, (size_t)bc->len, f) < (size_t)bc->len) {
+ yasm_error_set(YASM_ERROR_IO,
+ N_("`incbin': unable to read %lu bytes from file `%s'"),
+ bc->len, incbin->filename);
+ fclose(f);
+ return 1;
+ }
+
+ *bufp += bc->len;
+ fclose(f);
+ return 0;
+ }
+
+ yasm_bytecode *
+ yasm_bc_create_incbin(char *filename, yasm_expr *start, yasm_expr *maxlen,
+ unsigned long line)
+ {
+ bytecode_incbin *incbin = yasm_xmalloc(sizeof(bytecode_incbin));
+
+ /*@-mustfree@*/
+ incbin->filename = filename;
+ incbin->start = start;
+ incbin->maxlen = maxlen;
+ /*@=mustfree@*/
+
+ return yasm_bc_create_common(&bc_incbin_callback, incbin, line);
+ }
--- /dev/null
-static yasm_bc_resolve_flags bc_insn_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * Insn bytecode
+ *
+ * Copyright (C) 2005-2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+
+ #include "coretype.h"
+
+ #include "errwarn.h"
+ #include "expr.h"
+ #include "value.h"
+
+ #include "bytecode.h"
+ #include "arch.h"
+
+ #include "bc-int.h"
+
+
+ typedef struct bytecode_insn {
+ /*@dependent@*/ yasm_arch *arch;
+ unsigned long insn_data[4];
+
+ int num_operands;
+ /*@null@*/ yasm_insn_operands operands;
+
+ /* array of 4-element prefix_data arrays */
+ int num_prefixes;
+ /*@null@*/ unsigned long **prefixes;
+
+ /* array of segment prefixes */
+ int num_segregs;
+ /*@null@*/ unsigned long *segregs;
+ } bytecode_insn;
+
+ static void bc_insn_destroy(void *contents);
+ static void bc_insn_print(const void *contents, FILE *f, int indent_level);
+ static void bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
- bc_insn_resolve,
++static int bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data);
+ static int bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static const yasm_bytecode_callback bc_insn_callback = {
+ bc_insn_destroy,
+ bc_insn_print,
+ bc_insn_finalize,
-static yasm_bc_resolve_flags
-bc_insn_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ bc_insn_calc_len,
++ yasm_bc_expand_common,
+ bc_insn_tobytes,
+ 0
+ };
+
+
+ yasm_immval *
+ yasm_imm_create_expr(yasm_expr *e)
+ {
+ yasm_immval *im = yasm_xmalloc(sizeof(yasm_immval));
+
+ if (yasm_value_finalize_expr(&im->val, e, 0))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("immediate expression too complex"));
+ im->sign = 0;
+
+ return im;
+ }
+
+ const yasm_expr *
+ yasm_ea_get_disp(const yasm_effaddr *ea)
+ {
+ return ea->disp.abs;
+ }
+
+ void
+ yasm_ea_set_len(yasm_effaddr *ptr, unsigned int len)
+ {
+ if (!ptr)
+ return;
+
+ /* Currently don't warn if length truncated, as this is called only from
+ * an explicit override, where we expect the user knows what they're doing.
+ */
+
+ ptr->disp.size = (unsigned char)len;
+ }
+
+ void
+ yasm_ea_set_nosplit(yasm_effaddr *ptr, unsigned int nosplit)
+ {
+ if (!ptr)
+ return;
+
+ ptr->nosplit = (unsigned char)nosplit;
+ }
+
+ void
+ yasm_ea_set_strong(yasm_effaddr *ptr, unsigned int strong)
+ {
+ if (!ptr)
+ return;
+
+ ptr->strong = (unsigned char)strong;
+ }
+
+ void
+ yasm_ea_set_segreg(yasm_effaddr *ea, unsigned long segreg)
+ {
+ if (!ea)
+ return;
+
+ if (segreg != 0 && ea->segreg != 0)
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("multiple segment overrides, using leftmost"));
+
+ ea->segreg = segreg;
+ }
+
+ /*@-nullstate@*/
+ void
+ yasm_ea_destroy(yasm_effaddr *ea)
+ {
+ ea->callback->destroy(ea);
+ yasm_value_delete(&ea->disp);
+ yasm_xfree(ea);
+ }
+ /*@=nullstate@*/
+
+ /*@-nullstate@*/
+ void
+ yasm_ea_print(const yasm_effaddr *ea, FILE *f, int indent_level)
+ {
+ fprintf(f, "%*sDisp:\n", indent_level, "");
+ yasm_value_print(&ea->disp, f, indent_level+1);
+ fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit);
+ ea->callback->print(ea, f, indent_level);
+ }
+ /*@=nullstate@*/
+
+ static void
+ bc_insn_destroy(void *contents)
+ {
+ bytecode_insn *insn = (bytecode_insn *)contents;
+ if (insn->num_operands > 0)
+ yasm_ops_delete(&insn->operands, 0);
+ if (insn->num_prefixes > 0) {
+ int i;
+ for (i=0; i<insn->num_prefixes; i++)
+ yasm_xfree(insn->prefixes[i]);
+ yasm_xfree(insn->prefixes);
+ }
+ if (insn->num_segregs > 0)
+ yasm_xfree(insn->segregs);
+ yasm_xfree(contents);
+ }
+
+ static void
+ bc_insn_print(const void *contents, FILE *f, int indent_level)
+ {
+ }
+
+ static void
+ bc_insn_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+ bytecode_insn *insn = (bytecode_insn *)bc->contents;
+ int i;
+ yasm_insn_operand *op;
+ yasm_error_class eclass;
+ char *str, *xrefstr;
+ unsigned long xrefline;
+
+ /* Simplify the operands' expressions first. */
+ for (i = 0, op = yasm_ops_first(&insn->operands);
+ op && i<insn->num_operands; op = yasm_operand_next(op), i++) {
+ /* Check operand type */
+ switch (op->type) {
+ case YASM_INSN__OPERAND_MEMORY:
+ /* Don't get over-ambitious here; some archs' memory expr
+ * parser are sensitive to the presence of *1, etc, so don't
+ * simplify reg*1 identities.
+ */
+ if (op->data.ea)
+ op->data.ea->disp.abs =
+ yasm_expr__level_tree(op->data.ea->disp.abs, 1, 1, 0,
+ NULL, NULL, NULL, NULL);
+ if (yasm_error_occurred()) {
+ /* Add a pointer to where it was used to the error */
+ yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr);
+ if (xrefstr) {
+ yasm_error_set_xref(xrefline, "%s", xrefstr);
+ yasm_xfree(xrefstr);
+ }
+ if (str) {
+ yasm_error_set(eclass, "%s in memory expression", str);
+ yasm_xfree(str);
+ }
+ return;
+ }
+ break;
+ case YASM_INSN__OPERAND_IMM:
+ op->data.val =
+ yasm_expr__level_tree(op->data.val, 1, 1, 1, NULL, NULL,
+ NULL, NULL);
+ if (yasm_error_occurred()) {
+ /* Add a pointer to where it was used to the error */
+ yasm_error_fetch(&eclass, &str, &xrefline, &xrefstr);
+ if (xrefstr) {
+ yasm_error_set_xref(xrefline, "%s", xrefstr);
+ yasm_xfree(xrefstr);
+ }
+ if (str) {
+ yasm_error_set(eclass, "%s in immediate expression",
+ str);
+ yasm_xfree(str);
+ }
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ yasm_arch_finalize_insn(insn->arch, bc, prev_bc, insn->insn_data,
+ insn->num_operands, &insn->operands,
+ insn->num_prefixes, insn->prefixes,
+ insn->num_segregs, insn->segregs);
+ }
+
- yasm_internal_error(N_("bc_insn_resolve() is not implemented"));
++static int
++bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
- return YASM_BC_RESOLVE_ERROR;
++ yasm_internal_error(N_("bc_insn_calc_len() is not implemented"));
+ /*@notreached@*/
++ return 0;
+ }
+
+ static int
+ bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+ yasm_internal_error(N_("bc_insn_tobytes() is not implemented"));
+ /*@notreached@*/
+ return 1;
+ }
+
+ yasm_bytecode *
+ yasm_bc_create_insn(yasm_arch *arch, const unsigned long insn_data[4],
+ int num_operands, /*@null@*/ yasm_insn_operands *operands,
+ unsigned long line)
+ {
+ bytecode_insn *insn = yasm_xmalloc(sizeof(bytecode_insn));
+
+ insn->arch = arch;
+ insn->insn_data[0] = insn_data[0];
+ insn->insn_data[1] = insn_data[1];
+ insn->insn_data[2] = insn_data[2];
+ insn->insn_data[3] = insn_data[3];
+ insn->num_operands = num_operands;
+ if (operands)
+ insn->operands = *operands; /* structure copy */
+ else
+ yasm_ops_initialize(&insn->operands);
+ insn->num_prefixes = 0;
+ insn->prefixes = NULL;
+ insn->num_segregs = 0;
+ insn->segregs = NULL;
+
+ return yasm_bc_create_common(&bc_insn_callback, insn, line);
+ }
+
+ yasm_bytecode *
+ yasm_bc_create_empty_insn(yasm_arch *arch, unsigned long line)
+ {
+ bytecode_insn *insn = yasm_xmalloc(sizeof(bytecode_insn));
+
+ insn->arch = arch;
+ insn->insn_data[0] = 0;
+ insn->insn_data[1] = 0;
+ insn->insn_data[2] = 0;
+ insn->insn_data[3] = 0;
+ insn->num_operands = 0;
+ yasm_ops_initialize(&insn->operands);
+ insn->num_prefixes = 0;
+ insn->prefixes = NULL;
+ insn->num_segregs = 0;
+ insn->segregs = NULL;
+
+ return yasm_bc_create_common(&bc_insn_callback, insn, line);
+ }
+
+ void
+ yasm_bc_insn_add_prefix(yasm_bytecode *bc, const unsigned long prefix_data[4])
+ {
+ bytecode_insn *insn = (bytecode_insn *)bc->contents;
+
+ assert(bc->callback == bc_insn_callback);
+
+ insn->prefixes =
+ yasm_xrealloc(insn->prefixes,
+ (insn->num_prefixes+1)*sizeof(unsigned long *));
+ insn->prefixes[insn->num_prefixes] =
+ yasm_xmalloc(4*sizeof(unsigned long));
+ insn->prefixes[insn->num_prefixes][0] = prefix_data[0];
+ insn->prefixes[insn->num_prefixes][1] = prefix_data[1];
+ insn->prefixes[insn->num_prefixes][2] = prefix_data[2];
+ insn->prefixes[insn->num_prefixes][3] = prefix_data[3];
+ insn->num_prefixes++;
+ }
+
+ void
+ yasm_bc_insn_add_seg_prefix(yasm_bytecode *bc, unsigned long segreg)
+ {
+ bytecode_insn *insn = (bytecode_insn *)bc->contents;
+
+ assert(bc->callback == bc_insn_callback);
+
+ insn->segregs =
+ yasm_xrealloc(insn->segregs,
+ (insn->num_segregs+1)*sizeof(unsigned long));
+ insn->segregs[insn->num_segregs] = segreg;
+ insn->num_segregs++;
+ }
void (*destroy) (/*@only@*/ void *contents);
void (*print) (const void *contents, FILE *f, int indent_level);
void (*finalize) (yasm_bytecode *bc, yasm_bytecode *prev_bc);
- yasm_bc_resolve_flags (*resolve)
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ int (*calc_len) (yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data);
+ int (*expand) (yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
int (*tobytes) (yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
+ int reserve; /* Reserve space instead of outputting data */
} yasm_bytecode_callback;
struct yasm_bytecode {
--- /dev/null
-static yasm_bc_resolve_flags bc_org_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * ORG bytecode
+ *
+ * Copyright (C) 2005-2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+
+ #include "coretype.h"
+ #include "file.h"
+
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+ #include "value.h"
+
+ #include "bytecode.h"
+
+ #include "bc-int.h"
+
+
+ typedef struct bytecode_org {
+ unsigned long start; /* target starting offset within section */
+ } bytecode_org;
+
+ static void bc_org_destroy(void *contents);
+ static void bc_org_print(const void *contents, FILE *f, int indent_level);
+ static void bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
- bc_org_resolve,
++static int bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data);
++static int bc_org_expand(yasm_bytecode *bc, int span, long old_val,
++ long new_val, /*@out@*/ long *neg_thres,
++ /*@out@*/ long *pos_thres);
+ static int bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static const yasm_bytecode_callback bc_org_callback = {
+ bc_org_destroy,
+ bc_org_print,
+ bc_org_finalize,
-static yasm_bc_resolve_flags
-bc_org_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ bc_org_calc_len,
++ bc_org_expand,
+ bc_org_tobytes,
+ 0
+ };
+
+
+ static void
+ bc_org_destroy(void *contents)
+ {
+ yasm_xfree(contents);
+ }
+
+ static void
+ bc_org_print(const void *contents, FILE *f, int indent_level)
+ {
+ const bytecode_org *org = (const bytecode_org *)contents;
+ fprintf(f, "%*s_Org_\n", indent_level, "");
+ fprintf(f, "%*sStart=%lu\n", indent_level, "", org->start);
+ }
+
+ static void
+ bc_org_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+ }
+
- return YASM_BC_RESOLVE_MIN_LEN;
++static int
++bc_org_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
++ yasm_internal_error(N_("org not yet implemented"));
++#if 0
+ bytecode_org *org = (bytecode_org *)bc->contents;
+
+ /* Check for overrun */
+ if (bc->offset > org->start) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("ORG overlap with already existing data"));
+ return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
+ }
+
+ /* Generate space to start offset */
+ bc->len = org->start - bc->offset;
++#endif
++ return 0;
++}
++
++static int
++bc_org_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
++ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
++{
++ yasm_internal_error(N_("org not yet implemented"));
++ return 0;
+ }
+
+ static int
+ bc_org_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+ bytecode_org *org = (bytecode_org *)bc->contents;
+ unsigned long len, i;
+
+ /* Sanity check for overrun */
+ if (bc->offset > org->start) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("ORG overlap with already existing data"));
+ return 1;
+ }
+ len = org->start - bc->offset;
+ for (i=0; i<len; i++)
+ YASM_WRITE_8(*bufp, 0);
+ return 0;
+ }
+
+ yasm_bytecode *
+ yasm_bc_create_org(unsigned long start, unsigned long line)
+ {
+ bytecode_org *org = yasm_xmalloc(sizeof(bytecode_org));
+
+ org->start = start;
+
+ return yasm_bc_create_common(&bc_org_callback, org, line);
+ }
--- /dev/null
-static yasm_bc_resolve_flags bc_reserve_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * Bytecode utility functions
+ *
+ * Copyright (C) 2001 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #define YASM_LIB_INTERNAL
+ #include "util.h"
+ /*@unused@*/ RCSID("$Id$");
+
+ #include "coretype.h"
+
+ #include "errwarn.h"
+ #include "intnum.h"
+ #include "expr.h"
+ #include "value.h"
+
+ #include "bytecode.h"
+
+ #include "bc-int.h"
+ #include "expr-int.h"
+
+
+ typedef struct bytecode_reserve {
+ /*@only@*/ /*@null@*/ yasm_expr *numitems; /* number of items to reserve */
+ unsigned char itemsize; /* size of each item (in bytes) */
+ } bytecode_reserve;
+
+ static void bc_reserve_destroy(void *contents);
+ static void bc_reserve_print(const void *contents, FILE *f, int indent_level);
+ static void bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc);
- bc_reserve_resolve,
++static int bc_reserve_calc_len(yasm_bytecode *bc,
++ yasm_bc_add_span_func add_span,
++ void *add_span_data);
+ static int bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static const yasm_bytecode_callback bc_reserve_callback = {
+ bc_reserve_destroy,
+ bc_reserve_print,
+ bc_reserve_finalize,
-static yasm_bc_resolve_flags
-bc_reserve_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ bc_reserve_calc_len,
++ yasm_bc_expand_common,
+ bc_reserve_tobytes,
+ 1
+ };
+
+
+ static void
+ bc_reserve_destroy(void *contents)
+ {
+ bytecode_reserve *reserve = (bytecode_reserve *)contents;
+ yasm_expr_destroy(reserve->numitems);
+ yasm_xfree(contents);
+ }
+
+ static void
+ bc_reserve_print(const void *contents, FILE *f, int indent_level)
+ {
+ const bytecode_reserve *reserve = (const bytecode_reserve *)contents;
+ fprintf(f, "%*s_Reserve_\n", indent_level, "");
+ fprintf(f, "%*sNum Items=", indent_level, "");
+ yasm_expr_print(reserve->numitems, f);
+ fprintf(f, "\n%*sItem Size=%u\n", indent_level, "",
+ (unsigned int)reserve->itemsize);
+ }
+
+ static void
+ bc_reserve_finalize(yasm_bytecode *bc, yasm_bytecode *prev_bc)
+ {
+ bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
+ yasm_value val;
+
+ if (yasm_value_finalize_expr(&val, reserve->numitems, 0))
+ yasm_error_set(YASM_ERROR_TOO_COMPLEX,
+ N_("reserve expression too complex"));
+ else if (val.rel)
+ yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
+ N_("reserve expression not absolute"));
+ else if (val.abs && yasm_expr__contains(val.abs, YASM_EXPR_FLOAT))
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("expression must not contain floating point value"));
+ reserve->numitems = val.abs;
+ }
+
- yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
- /*@null@*/ yasm_expr *temp;
- yasm_expr **tempp;
++static int
++bc_reserve_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
+ bytecode_reserve *reserve = (bytecode_reserve *)bc->contents;
- return YASM_BC_RESOLVE_MIN_LEN;
-
- if (save) {
- temp = NULL;
- tempp = &reserve->numitems;
- } else {
- temp = yasm_expr_copy(reserve->numitems);
- assert(temp != NULL);
- tempp = &temp;
- }
- num = yasm_expr_get_intnum(tempp, calc_bc_dist);
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+
+ if (!reserve->numitems)
- /* For reserve, just say non-constant quantity instead of allowing
- * the circular reference error to filter through.
- */
++ return 0;
++
++ num = yasm_expr_get_intnum(&reserve->numitems, NULL);
+ if (!num) {
- retval = YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
- } else
- bc->len += yasm_intnum_get_uint(num)*reserve->itemsize;
- yasm_expr_destroy(temp);
- return retval;
++ /* Check for use of floats first. */
++ if (reserve->numitems &&
++ yasm_expr__contains(reserve->numitems, YASM_EXPR_FLOAT)) {
++ yasm_error_set(YASM_ERROR_VALUE,
++ N_("expression must not contain floating point value"));
++ return -1;
++ }
++ /* FIXME: Non-constant currently not allowed. */
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("attempt to reserve non-constant quantity of space"));
++ return -1;
++ }
++
++ bc->len += yasm_intnum_get_uint(num)*reserve->itemsize;
++ return 0;
+ }
+
+ static int
+ bc_reserve_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@unused@*/ yasm_output_reloc_func output_reloc)
+ {
+ yasm_internal_error(N_("bc_reserve_tobytes called"));
+ /*@notreached@*/
+ return 1;
+ }
+
+ yasm_bytecode *
+ yasm_bc_create_reserve(yasm_expr *numitems, unsigned int itemsize,
+ unsigned long line)
+ {
+ bytecode_reserve *reserve = yasm_xmalloc(sizeof(bytecode_reserve));
+
+ /*@-mustfree@*/
+ reserve->numitems = numitems;
+ /*@=mustfree@*/
+ reserve->itemsize = (unsigned char)itemsize;
+
+ return yasm_bc_create_common(&bc_reserve_callback, reserve, line);
+ }
}
/*@null@*/ yasm_intnum *
- yasm_common_calc_bc_dist(/*@null@*/ yasm_bytecode *precbc1,
- /*@null@*/ yasm_bytecode *precbc2)
+ yasm_common_calc_bc_dist(yasm_bytecode *precbc1, yasm_bytecode *precbc2)
{
- unsigned int dist;
+ unsigned long dist;
yasm_intnum *intn;
- if (precbc2) {
- dist = precbc2->offset + precbc2->len;
- if (precbc1) {
- if (dist < precbc1->offset + precbc1->len) {
- intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len
- - dist);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
- return intn;
- }
- dist -= precbc1->offset + precbc1->len;
- }
- return yasm_intnum_create_uint(dist);
- } else {
- if (precbc1) {
- intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len);
- yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL, precbc1->line);
- return intn;
- } else {
- return yasm_intnum_create_uint(0);
- }
+ if (precbc1->section != precbc2->section)
+ return NULL;
+
+ dist = precbc2->offset + precbc2->len;
+ if (dist < precbc1->offset + precbc1->len) {
+ intn = yasm_intnum_create_uint(precbc1->offset + precbc1->len - dist);
+ yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
+ return intn;
}
+ dist -= precbc1->offset + precbc1->len;
+ return yasm_intnum_create_uint(dist);
}
-yasm_bc_resolve_flags
-yasm_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
+int
+yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
{
- yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
- /*@null@*/ yasm_expr *temp;
- yasm_expr **tempp;
- /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+ int retval = 0;
- bc->len = 0; /* start at 0 */
+ bc->len = 0;
if (!bc->callback)
yasm_internal_error(N_("got empty bytecode in bc_resolve"));
else
- retval = bc->callback->resolve(bc, save, calc_bc_dist);
-
- /* Multiply len by number of multiples */
+ retval = bc->callback->calc_len(bc, add_span, add_span_data);
+#if 0
+ /* Check for multiples */
if (bc->multiple) {
- if (save) {
- temp = NULL;
- tempp = &bc->multiple;
- } else {
- temp = yasm_expr_copy(bc->multiple);
- assert(temp != NULL);
- tempp = &temp;
- }
- num = yasm_expr_get_intnum(tempp, calc_bc_dist);
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *num;
+
+ num = yasm_expr_get_intnum(&bc->multiple, NULL);
if (!num) {
- retval = YASM_BC_RESOLVE_UNKNOWN_LEN;
- if (temp && yasm_expr__contains(temp, YASM_EXPR_FLOAT)) {
+ if (yasm_expr__contains(bc->multiple, YASM_EXPR_FLOAT)) {
- yasm__error(bc->line,
+ yasm_error_set(YASM_ERROR_VALUE,
N_("expression must not contain floating point value"));
- retval |= YASM_BC_RESOLVE_ERROR;
+ retval = -1;
+ } else {
+ /* FIXME: Non-constant currently not allowed. */
+ yasm__error(bc->line,
+ N_("attempt to use non-constant multiple"));
+ retval = -1;
}
- } else {
- if (yasm_intnum_sign(num) >= 0)
- bc->len *= yasm_intnum_get_uint(num);
- else
- retval |= YASM_BC_RESOLVE_ERROR;
}
- yasm_expr_destroy(temp);
}
-
+#endif
/* If we got an error somewhere along the line, clear out any calc len */
- if (retval & YASM_BC_RESOLVE_UNKNOWN_LEN)
+ if (retval < 0)
bc->len = 0;
return retval;
}
+int
+yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ if (!bc->callback) {
+ yasm_internal_error(N_("got empty bytecode in bc_set_long"));
+ /*@unreached@*/
+ return 0;
+ } else
+ return bc->callback->expand(bc, span, old_val, new_val, neg_thres,
+ pos_thres);
+}
+
/*@null@*/ /*@only@*/ unsigned char *
yasm_bc_tobytes(yasm_bytecode *bc, unsigned char *buf, unsigned long *bufsize,
- /*@out@*/ unsigned long *multiple, /*@out@*/ int *gap,
- void *d, yasm_output_expr_func output_expr,
+ /*@out@*/ int *gap, void *d,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc)
/*@sets *buf@*/
{
/*@reldef@*/ STAILQ_HEAD(yasm_datavalhead, yasm_dataval);
#endif
- /** Create an immediate value from an unsigned integer.
- * \param int_val unsigned integer
- * \param line virtual line (from yasm_linemap)
- * \return Newly allocated immediate value.
- */
- /*@only@*/ yasm_immval *yasm_imm_create_int(unsigned long int_val,
- unsigned long line);
-/** Return value flags for yasm_bc_resolve(). */
-typedef enum {
- YASM_BC_RESOLVE_NONE = 0, /**< Ok, but length is not minimum. */
- YASM_BC_RESOLVE_ERROR = 1<<0, /**< Error found, output. */
- YASM_BC_RESOLVE_MIN_LEN = 1<<1, /**< Length is minimum possible. */
- YASM_BC_RESOLVE_UNKNOWN_LEN = 1<<2 /**< Length indeterminate. */
-} yasm_bc_resolve_flags;
--
/** Create an immediate value from an expression.
* \param e expression (kept, do not free).
* \return Newly allocated immediate value.
* yasm_expr output functions.
* \see yasm_calc_bc_dist_func for parameter descriptions.
*/
- /*@null@*/ yasm_intnum *yasm_common_calc_bc_dist
- (/*@null@*/ yasm_bytecode *precbc1, /*@null@*/ yasm_bytecode *precbc2);
+ /*@null@*/ /*@only@*/ yasm_intnum *yasm_common_calc_bc_dist
+ (yasm_bytecode *precbc1, yasm_bytecode *precbc2);
-/** Resolve labels in a bytecode, and calculate its length.
- * Tries to minimize the length as much as possible.
- * \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.
+/**
- * \param critical dependent expression for bytecode expansion
++ * \param value dependent value for bytecode expansion
++ * \param origin_prevbc origin for distance computation to relative portion of
++ * value; value.rel and origin must be within the same
++ * section.
+ * \param neg_thres negative threshold for long/short decision
+ * \param pos_thres positive threshold for long/short decision
+ */
+typedef void (*yasm_bc_add_span_func)
- (void *add_span_data, yasm_bytecode *bc, int id,
- /*@only@*/ yasm_expr *dependent, long neg_thres, long pos_thres);
++ (void *add_span_data, yasm_bytecode *bc, int id, yasm_value *value,
++ /*@null@*/ yasm_bytecode *origin_prevbc, long neg_thres, long pos_thres);
+
+/** Resolve EQUs in a bytecode and calculate its minimum size.
- * Returns dependent bytecode spans for cases where, if the length spanned
++ * Generates dependent bytecode spans for cases where, if the length spanned
+ * increases, it could cause the bytecode size to increase.
+ * Any bytecode multiple is NOT included in the length or spans generation;
+ * this must be handled at a higher level.
+ * \param bc bytecode
+ * \return 0 if no error occurred, nonzero if there was an error recognized
+ * (and output) during execution.
+ * \note May store to bytecode updated expressions and the short length.
+ */
+int yasm_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data);
+
+/** Recalculate a bytecode's length based on an expanded span length.
* \param bc bytecode
- * \param save when zero, this function does \em not modify bc other
- * than the length/size values (i.e. it doesn't keep the
- * values returned by calc_bc_dist except temporarily to
- * try to minimize the length); when nonzero, all fields
- * in bc may be modified by this function
- * \param calc_bc_dist function used to determine bytecode distance
- * \return Flags indicating whether the length is the minimum possible,
- * indeterminate, and if there was an error recognized (and output)
- * during execution.
+ * \param span span ID (as given to yasm_bc_add_span_func in
+ * yasm_bc_calc_len)
+ * \param old_val previous span value
+ * \param new_val new span value
+ * \param neg_thres negative threshold for long/short decision (returned)
+ * \param pos_thres postivie threshold for long/short decision (returned)
+ * \return 0 if bc no longer dependent on this span's length, negative if
+ * there was an error recognized (and output) during execution, and
+ * positive if bc size may increase for this span further based on the
+ * new negative and positive thresholds returned.
+ * \note May store to bytecode updated expressions and the updated length.
*/
-yasm_bc_resolve_flags yasm_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist);
+int yasm_bc_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres);
/** Convert a bytecode into its byte representation.
* \param bc bytecode
return (Set_Max(val) < (long)size);
}
- unsigned long
- yasm_intnum_get_leb128(const yasm_intnum *intn, unsigned char *ptr, int sign)
+int
+yasm_intnum_in_range(const yasm_intnum *intn, long low, long high)
+{
+ wordptr val = result;
+ wordptr lval = op1static;
+ wordptr hval = op2static;
+
+ /* If not already a bitvect, convert value to be written to a bitvect */
+ if (intn->type == INTNUM_BV)
+ val = intn->val.bv;
+ else {
+ BitVector_Empty(val);
+ BitVector_Chunk_Store(val, 32, 0, intn->val.ul);
+ }
+
+ /* Convert high and low to bitvects */
+ BitVector_Empty(lval);
+ if (low >= 0)
+ BitVector_Chunk_Store(lval, 32, 0, (unsigned long)low);
+ else {
+ BitVector_Chunk_Store(lval, 32, 0, (unsigned long)(-low));
+ BitVector_Negate(lval, lval);
+ }
+
+ BitVector_Empty(hval);
+ if (high >= 0)
+ BitVector_Chunk_Store(hval, 32, 0, (unsigned long)high);
+ else {
+ BitVector_Chunk_Store(hval, 32, 0, (unsigned long)(-high));
+ BitVector_Negate(hval, hval);
+ }
+
+ /* Compare! */
+ return (BitVector_Compare(val, lval) >= 0
+ && BitVector_Compare(val, hval) <= 0);
+}
+
+ static unsigned long
+ get_leb128(wordptr val, unsigned char *ptr, int sign)
{
- wordptr val = op1static;
unsigned long i, size;
unsigned char *ptr_orig = ptr;
}
}
}
- /*@owned@*/ yasm_expr *dependent;
+
+/*
+ * Robertson (1977) optimizer
+ * Based (somewhat loosely) on the algorithm given in:
+ * MRC Technical Summary Report # 1779
+ * CODE GENERATION FOR SHORT/LONG ADDRESS MACHINES
+ * Edward L. Robertson
+ * Mathematics Research Center
+ * University of Wisconsin-Madison
+ * 610 Walnut Street
+ * Madison, Wisconsin 53706
+ * August 1977
+ *
+ * Key components of algorithm:
+ * - start assuming all short forms
+ * - build spans for short->long transition dependencies
+ * - if a long form is needed, walk the dependencies and update
+ * Major differences from Robertson's algorithm:
+ * - detection of cycles
+ * - any difference of two locations is allowed
+ * - handling of alignment gaps
+ * - handling of multiples
+ *
+ * Data structures:
+ * - Interval tree to store spans and associated data
+ * - Queue Q
+ *
+ * Each span keeps track of:
+ * - Associated bytecode (bytecode that depends on the span length)
+ * - Active/inactive state (starts out active)
+ * - Sign (negative/positive; negative being "backwards" in address)
+ * - Current length in bytes
+ * - New length in bytes
+ * - Negative/Positive thresholds
+ * - Span ID (unique within each bytecode)
+ *
+ * How org and align are handled:
+ * Some portions are critical values that must not depend on any bytecode
+ * offset (either relative or absolute).
+ *
+ * ALIGN: 0 length (always). Bump offset to alignment. Span from 0 to
+ * align bytecode, update on any change. If span length
+ * increases past alignment, increase offset by alignment and update
+ * dependent spans. Alignment is critical value.
+ * ORG: Same as align, but if span's length exceeds org value, error.
+ * ORG value is critical value.
+ *
+ * How times is handled:
+ *
+ * TIMES: Handled separately from bytecode "raw" size. If not span-dependent,
+ * trivial (just multiplied in at any bytecode size increase). Span
+ * dependent times update on any change (span ID 0). If the resultant
+ * next bytecode offset would be less than the old next bytecode offset,
+ * error. Otherwise increase offset and update dependent spans.
+ *
+ * To reduce interval tree size, a first expansion pass is performed
+ * before the spans are added to the tree.
+ *
+ * Basic algorithm outline:
+ *
+ * 1. Initialization:
+ * a. Number bytecodes sequentially (via bc_index) and calculate offsets
+ * of all bytecodes assuming minimum length, building a list of all
+ * dependent spans as we go.
+ * "minimum" here means absolute minimum:
+ * - align 0 length
+ * - times values (with span-dependent values) assumed to be 0
+ * - org bumps offset
+ * b. Iterate over spans. Set span length based on bytecode offsets
+ * determined in 1a. If span is "certainly" long because the span
+ * is an absolute reference to another section (or external) or the
+ * distance calculated based on the minimum length is greater than the
+ * span's threshold, expand the span's bytecode, and if no further
+ * expansion can result, delete the span. Otherwise (or if the
+ * expansion results in another threshold of expansion), add span to
+ * interval tree.
+ * c. Iterate over bytecodes to update all bytecode offsets based on new
+ * (expanded) lengths calculated in 1b.
+ * d. Iterate over spans. Update span's length based on new bytecode offsets
+ * determined in 1c. If span's length exceeds long threshold, add that
+ * span to Q.
+ * 2. Main loop:
+ * While Q not empty:
+ * Expand BC dependent on span at head of Q (and remove span from Q).
+ * Update span:
+ * If BC no longer dependent on span, mark span as inactive.
+ * If BC has new thresholds for span, update span.
+ * If BC increased in size, for each active span that contains BC:
+ * Increase span length by difference between short and long BC length.
+ * If span exceeds long threshold (or is flagged to recalculate on any
+ * change), add it to tail of Q.
+ * 3. Final pass over bytecodes to generate final offsets.
+ */
+
+typedef struct yasm_span {
+ /*@reldef@*/ STAILQ_ENTRY(yasm_span) link;
+
+ /*@dependent@*/ yasm_bytecode *bc;
+
- /*@only@*/ yasm_expr *dependent, long neg_thres,
- long pos_thres)
++ yasm_value *depval;
++ yasm_bytecode *origin_prevbc;
+
+ /* Special handling: see descriptions above */
+ enum {
+ NOT_SPECIAL = 0,
+ SPECIAL_ALIGN,
+ SPECIAL_ORG,
+ SPECIAL_TIMES
+ } special;
+
+ long cur_val;
+ long new_val;
+
+ long neg_thres;
+ long pos_thres;
+
+ int id;
+
+ int active;
+} yasm_span;
+
+typedef struct optimize_data {
+ /*@reldef@*/ STAILQ_HEAD(yasm_spanhead, yasm_span) spans;
+} optimize_data;
+
+static void
+optimize_add_span(void *add_span_data, yasm_bytecode *bc, int id,
- span->dependent = dependent;
++ yasm_value *value, /*@null@*/ yasm_bytecode *origin_prevbc,
++ long neg_thres, long pos_thres)
+{
+ optimize_data *optd = (optimize_data *)add_span_data;
+ yasm_span *span = yasm_xmalloc(sizeof(yasm_span));
+
+ span->bc = bc;
-
++ span->depval = value;
++ span->origin_prevbc = origin_prevbc;
+ span->special = NOT_SPECIAL;
+ span->cur_val = 0;
+ span->new_val = 0;
+ span->neg_thres = neg_thres;
+ span->pos_thres = pos_thres;
+ span->id = id;
+ span->active = 1;
+
+ STAILQ_INSERT_TAIL(&optd->spans, span, link);
+}
+
+static void
+update_all_bc_offsets(yasm_object *object)
+{
+ yasm_section *sect;
+
+ STAILQ_FOREACH(sect, &object->sections, link) {
+ unsigned long offset = 0;
+
+ yasm_bytecode *cur = STAILQ_FIRST(§->bcs);
+ yasm_bytecode *prev;
+
+ /* Skip our locally created empty bytecode first. */
+ prev = cur;
+ cur = STAILQ_NEXT(cur, link);
+
+ /* Iterate through the remainder, if any. */
+ while (cur) {
+ cur->offset = offset;
+ offset += cur->len;
+ prev = cur;
+ cur = STAILQ_NEXT(cur, link);
+ }
+ }
+}
+
+void
+yasm_object_optimize(yasm_object *object, yasm_arch *arch)
+{
+ yasm_section *sect;
+ unsigned long bc_index = 0;
+ int saw_error = 0;
+ optimize_data optd;
+ yasm_span *span;
+ long neg_thres, pos_thres;
+
+ STAILQ_INIT(&optd.spans);
+
+ /* Step 1a */
+ STAILQ_FOREACH(sect, &object->sections, link) {
+ unsigned long offset = 0;
+
+ yasm_bytecode *cur = STAILQ_FIRST(§->bcs);
+ yasm_bytecode *prev;
+
+ cur->bc_index = bc_index++;
+
+ /* Skip our locally created empty bytecode first. */
+ prev = cur;
+ cur = STAILQ_NEXT(cur, link);
+
+ /* Iterate through the remainder, if any. */
+ while (cur) {
+ cur->bc_index = bc_index++;
+
+ if (yasm_bc_calc_len(cur, optimize_add_span, &optd))
+ saw_error = 1;
+
+ /* TODO: times */
+ if (cur->multiple)
+ yasm_internal_error("multiple not yet supported");
+
+ cur->offset = offset;
+ offset += cur->len;
+ prev = cur;
+ cur = STAILQ_NEXT(cur, link);
+ }
+ }
+
+ if (saw_error)
+ return;
- yasm_expr *depcopy = yasm_expr_copy(span->dependent);
- yasm_intnum *intn =
- yasm_expr_get_intnum(&depcopy, yasm_common_calc_bc_dist);
- if (intn)
- span->new_val = yasm_intnum_get_int(intn);
- else {
- /* absolute, external, or too complex; force to longer form */
- span->new_val = LONG_MAX;
- span->active = 0;
++#if 0
+ /* Step 1b */
+ STAILQ_FOREACH(span, &optd.spans, link) {
- yasm_expr_destroy(depcopy);
++ /* Handle absolute portion */
++ if (span->depval->abs) {
++ yasm_expr *depcopy = yasm_expr_copy(span->depval->abs);
++ yasm_intnum *intn =
++ yasm_expr_get_intnum(&depcopy, yasm_common_calc_bc_dist);
++ if (intn)
++ span->new_val = yasm_intnum_get_int(intn);
++ else {
++ /* absolute, external, or too complex; force to longer form */
++ span->new_val = LONG_MAX;
++ span->active = 0;
++ }
++ yasm_expr_destroy(depcopy);
++ } else
++ span->new_val = 0;
++
++ /* Handle relative portion */
++ if (span->depval->rel && span->new_val != LONG_MAX) {
++ span->new_val +=
+ }
+
+ if (span->new_val < span->neg_thres
+ || span->new_val > span->pos_thres) {
+ int retval = yasm_bc_expand(span->bc, span->id, span->cur_val,
+ span->new_val, &neg_thres, &pos_thres);
+ if (retval < 0)
+ saw_error = 1;
+ else if (retval > 0) {
+ span->neg_thres = neg_thres;
+ span->pos_thres = pos_thres;
+ } else
+ span->active = 0;
+ }
+ span->cur_val = span->new_val;
-
+ }
++#endif
+ if (saw_error)
+ return;
+
+ /* Step 1c */
+ update_all_bc_offsets(object);
+
+ /* Step 1d */
+ STAILQ_FOREACH(span, &optd.spans, link) {
+ if (!span->active)
+ continue;
+ }
+
+ /* Step 2 */
+
+ /* Step 3 */
+ update_all_bc_offsets(object);
+}
lc3b_ea_create_expr,
lc3b_machines,
"lc3b",
- 2,
- 512
+ 16,
++ 512,
+ 2
};
yasm_x86__ea_create_expr,
x86_machines,
"x86",
- 2,
- 128
+ 16,
++ 128,
+ 1
};
/* None */
X86_POSTOP_NONE = 0,
-- /* Shift opcodes have an immediate form and a ,1 form (with no
-- * immediate). In the parser, we set this and opcode_len=1, but store
- * the non-,1 version in the second byte of the opcode array. We then
- * the ,1 version in the second byte of the opcode array. We then
-- * choose between the two versions once we know the actual value of
-- * imm (because we don't know it in the parser module).
-- *
-- * A override to force the imm version should just leave this at
-- * 0. Then later code won't know the ,1 version even exists.
-- * TODO: Figure out how this affects CPU flags processing.
-- */
-- X86_POSTOP_SHIFT,
--
/* Instructions that take a sign-extended imm8 as well as imm values
* (eg, the arith instructions and a subset of the imul instructions)
- * should set this and put the non-imm8 form in the second byte of the
- * should set this and put the imm8 form in the second byte of the
-- * opcode.
++ * should set this and put the imm8 form in the second (and possibly
++ * third) byte of the opcode.
*/
X86_POSTOP_SIGNEXT_IMM8,
-- /* Long (modrm+sib) mov instructions in amd64 can be optimized into
-- * short mov instructions if a 32-bit address override is applied in
-- * 64-bit mode to an EA of just an offset (no registers) and the
-- * target register is al/ax/eax/rax.
-- */
-- X86_POSTOP_SHORTMOV,
--
/* Override any attempt at address-size override to 16 bits, and never
* generate a prefix. This is used for the ENTER opcode.
*/
-- X86_POSTOP_ADDRESS16,
--
-- /* Used for 64-bit mov immediate, which can take a sign-extended
-- * imm32 as well as imm64 values. The imm32 form is put in the
-- * second byte of the opcode and its ModRM byte is put in the third
-- * byte of the opcode.
- * FIXME: Update for new optimizer.
-- */
-- X86_POSTOP_SIGNEXT_IMM32
++ X86_POSTOP_ADDRESS16
} postop;
} x86_insn;
* 1 if invalid EA, or 2 if indeterminate EA.
*/
int yasm_x86__expr_checkea
- (yasm_expr **ep, unsigned char *addrsize, unsigned int bits,
- unsigned int nosplit, int address16_op, unsigned char *displen,
- unsigned char *modrm, unsigned char *v_modrm, unsigned char *n_modrm,
- unsigned char *sib, unsigned char *v_sib, unsigned char *n_sib,
- unsigned char *pcrel, unsigned char *rex);
-
- void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid,
- unsigned long line);
-
- int yasm_x86__parse_check_reg
- (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
- unsigned long line);
- int yasm_x86__parse_check_reggroup
- (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
- unsigned long line);
- int yasm_x86__parse_check_segreg
- (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
- unsigned long line);
- int yasm_x86__parse_check_insn
- (yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
- unsigned long line);
- int yasm_x86__parse_check_prefix
+ (x86_effaddr *x86_ea, unsigned char *addrsize, unsigned int bits,
- int address16_op, unsigned char *rex,
- yasm_calc_bc_dist_func calc_bc_dist);
++ int address16_op, unsigned char *rex);
+
+ void yasm_x86__parse_cpu(yasm_arch *arch, const char *cpuid, size_t cpuid_len);
+
+ yasm_arch_insnprefix yasm_x86__parse_check_insnprefix
(yasm_arch *arch, /*@out@*/ unsigned long data[4], const char *id,
- unsigned long line);
- int yasm_x86__parse_check_targetmod
- (yasm_arch *arch, /*@out@*/ unsigned long data[1], const char *id,
- unsigned long line);
+ size_t id_len);
+ yasm_arch_regtmod yasm_x86__parse_check_regtmod
+ (yasm_arch *arch, /*@out@*/ unsigned long *data, const char *id,
+ size_t id_len);
void yasm_x86__finalize_insn
(yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc,
static void x86_bc_insn_destroy(void *contents);
static void x86_bc_insn_print(const void *contents, FILE *f,
int indent_level);
-static yasm_bc_resolve_flags x86_bc_insn_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int x86_bc_insn_calc_len(yasm_bytecode *bc,
+ yasm_bc_add_span_func add_span,
+ void *add_span_data);
+static int x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val,
+ long new_val, /*@out@*/ long *neg_thres,
+ /*@out@*/ long *pos_thres);
static int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- void *d, yasm_output_expr_func output_expr,
+ void *d, yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void x86_bc_jmp_destroy(void *contents);
static void x86_bc_jmp_print(const void *contents, FILE *f, int indent_level);
-static yasm_bc_resolve_flags x86_bc_jmp_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int x86_bc_jmp_calc_len(yasm_bytecode *bc,
+ yasm_bc_add_span_func add_span,
+ void *add_span_data);
+static int x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val,
+ long new_val, /*@out@*/ long *neg_thres,
+ /*@out@*/ long *pos_thres);
static int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
- void *d, yasm_output_expr_func output_expr,
+ void *d, yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
static void x86_bc_jmpfar_destroy(void *contents);
static void x86_bc_jmpfar_print(const void *contents, FILE *f,
int indent_level);
-static yasm_bc_resolve_flags x86_bc_jmpfar_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int x86_bc_jmpfar_calc_len(yasm_bytecode *bc,
+ yasm_bc_add_span_func add_span,
+ void *add_span_data);
static int x86_bc_jmpfar_tobytes
(yasm_bytecode *bc, unsigned char **bufp, void *d,
- yasm_output_expr_func output_expr,
+ yasm_output_value_func output_value,
/*@null@*/ yasm_output_reloc_func output_reloc);
/* Effective address callback structures */
x86_bc_insn_destroy,
x86_bc_insn_print,
yasm_bc_finalize_common,
- x86_bc_insn_resolve,
+ x86_bc_insn_calc_len,
+ x86_bc_insn_expand,
- x86_bc_insn_tobytes
+ x86_bc_insn_tobytes,
+ 0
};
static const yasm_bytecode_callback x86_bc_callback_jmp = {
x86_bc_jmp_destroy,
x86_bc_jmp_print,
yasm_bc_finalize_common,
- x86_bc_jmp_resolve,
+ x86_bc_jmp_calc_len,
+ x86_bc_jmp_expand,
- x86_bc_jmp_tobytes
+ x86_bc_jmp_tobytes,
+ 0
};
static const yasm_bytecode_callback x86_bc_callback_jmpfar = {
x86_bc_jmpfar_destroy,
x86_bc_jmpfar_print,
yasm_bc_finalize_common,
- x86_bc_jmpfar_resolve,
+ x86_bc_jmpfar_calc_len,
+ yasm_bc_expand_common,
- x86_bc_jmpfar_tobytes
+ x86_bc_jmpfar_tobytes,
+ 0
};
int
return len;
}
-static yasm_bc_resolve_flags
-x86_bc_insn_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
+static int
+x86_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
{
x86_insn *insn = (x86_insn *)bc->contents;
- /*@null@*/ yasm_expr *temp;
- x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
- yasm_effaddr *ea = &x86_ea->ea;
+ x86_effaddr *x86_ea = insn->x86_ea;
yasm_immval *imm = insn->imm;
- yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
- if (ea) {
- if (ea->disp) {
- /* Handle shortmov special-casing */
- if (insn->postop == X86_POSTOP_SHORTMOV &&
- insn->common.mode_bits == 64 && insn->common.addrsize == 32 &&
- !yasm_expr__contains(ea->disp, YASM_EXPR_REG)) {
- yasm_x86__ea_set_disponly((yasm_effaddr *)x86_ea);
- /* Make the short form permanent. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- }
+ if (x86_ea) {
- /* Create temp copy of disp, etc. */
- x86_effaddr eat = *x86_ea; /* structure copy */
-
- /* Don't overwrite original expression portion */
- if (x86_ea->ea.disp.abs)
- eat.ea.disp.abs = yasm_expr_copy(x86_ea->ea.disp.abs);
-
- /* Handle shortmov special-casing */
- if (insn->postop == X86_POSTOP_SHORTMOV &&
- insn->common.mode_bits == 64 && insn->common.addrsize == 32 &&
- (!eat.ea.disp.abs ||
- !yasm_expr__contains(eat.ea.disp.abs, YASM_EXPR_REG))) {
- yasm_x86__ea_set_disponly(&eat);
-
- if (save) {
- /* Make the short form permanent. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- }
- }
-
+ /* Check validity of effective address and calc R/M bits of
+ * Mod/RM byte and SIB byte. We won't know the Mod field
+ * of the Mod/RM byte until we know more about the
+ * displacement.
+ */
- switch (yasm_x86__expr_checkea(&eat, &insn->common.addrsize,
++ if (yasm_x86__expr_checkea(x86_ea, &insn->common.addrsize,
+ insn->common.mode_bits, insn->postop == X86_POSTOP_ADDRESS16,
- &insn->rex, calc_bc_dist)) {
- case 1:
- yasm_expr_destroy(eat.ea.disp.abs);
- /* failed, don't bother checking rest of insn */
- return YASM_BC_RESOLVE_UNKNOWN_LEN|YASM_BC_RESOLVE_ERROR;
- case 2:
- yasm_expr_destroy(eat.ea.disp.abs);
- /* failed, don't bother checking rest of insn */
- return YASM_BC_RESOLVE_UNKNOWN_LEN;
- default:
- yasm_expr_destroy(eat.ea.disp.abs);
- /* okay */
- break;
- }
-
- if (eat.ea.disp.size != 8) {
- /* Fits into a word/dword, or unknown. */
- retval = YASM_BC_RESOLVE_NONE; /* may not be smallest size */
++ &insn->rex))
++ /* failed, don't bother checking rest of insn */
++ return -1;
- /* Check validity of effective address and calc R/M bits of
- * Mod/RM byte and SIB byte. We won't know the Mod field
- * of the Mod/RM byte until we know more about the
- * displacement.
- /* Handle unknown case, make displen word-sized */
- if (eat.ea.need_nonzero_len)
- eat.ea.disp.size = (insn->common.addrsize == 16) ? 16 : 32;
- }
++ if (x86_ea->ea.disp.size == 0) {
++ /* Handle unknown case, default to byte-sized and set as
++ * critical expression.
+ */
- if (yasm_x86__expr_checkea(&ea->disp, &insn->common.addrsize,
- insn->common.mode_bits, ea->nosplit,
- insn->postop == X86_POSTOP_ADDRESS16, &ea->len,
- &x86_ea->modrm, &x86_ea->valid_modrm, &x86_ea->need_modrm,
- &x86_ea->sib, &x86_ea->valid_sib, &x86_ea->need_sib,
- &x86_ea->pcrel, &insn->rex))
- /* failed, don't bother checking rest of insn */
- return -1;
-
- /* Handle address16 postop case */
- if (insn->postop == X86_POSTOP_ADDRESS16)
- insn->common.addrsize = 0;
-
- if (ea->len == 0xff) {
- /* Handle unknown case, default to byte-sized and set as
- * critical expression.
- */
- bc->len += 1;
- add_span(add_span_data, bc, 1, yasm_expr_copy(ea->disp), -128,
- 127);
- } else
- bc->len += ea->len;
- }
++ bc->len += 1;
++ add_span(add_span_data, bc, 1, &x86_ea->ea.disp, NULL, -128, 127);
++ } else
++ bc->len + x86_ea->ea.disp.size/8;
+
+ /* Handle address16 postop case */
+ if (insn->postop == X86_POSTOP_ADDRESS16)
+ insn->common.addrsize = 0;
- /* If we had forced ea->len but had to override, save it now */
- if (x86_ea->ea.disp.size != 0 &&
- x86_ea->ea.disp.size != eat.ea.disp.size)
- x86_ea->ea.disp.size = eat.ea.disp.size;
-
- if (save) {
- eat.ea.disp.abs = x86_ea->ea.disp.abs; /* Copy back original */
- *x86_ea = eat; /* structure copy */
- if (x86_ea->ea.disp.size == 0) {
- yasm_value_delete(&x86_ea->ea.disp);
- x86_ea->ea.need_disp = 0;
- }
- }
-
/* Compute length of ea and add to total */
- bc->len += eat.need_modrm + (eat.need_sib ? 1:0) + eat.ea.disp.size/8;
- bc->len += (eat.ea.segreg != 0) ? 1 : 0;
+ bc->len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0);
+ bc->len += (x86_ea->ea.segreg != 0) ? 1 : 0;
}
if (imm) {
- int immlen = imm->len;
-
- if (imm->val) {
- /* TODO: check imm->len vs. sized len from expr? */
-
- /* Handle signext_imm8 postop special-casing */
- if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
- /*@dependent@*/ /*@null@*/ yasm_intnum *num;
- num = yasm_expr_get_intnum(&imm->val, NULL);
- if (num) {
- int val = yasm_intnum_get_int(num);
- if (val >= -128 && val <= 127) {
- /* We can use the sign-extended byte form: shorten
- * the immediate length to 1.
- */
- imm->len = 1;
- immlen = 1;
- } else {
- /* We can't use the ,1. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- }
- insn->postop = X86_POSTOP_NONE;
- } else {
- /* Unknown; default to byte form and set as critical
- * expression.
- */
- immlen = 1;
- add_span(add_span_data, bc, 2, yasm_expr_copy(imm->val),
- -128, 127);
- }
- }
- /*@null@*/ yasm_expr *temp = NULL;
- const yasm_intnum *num = NULL;
++ yasm_intnum *zero = yasm_intnum_create_uint(0);
++ const yasm_intnum *num = zero;
+ unsigned int immlen = imm->val.size;
+ long val;
- /* Handle shift postop special-casing */
- if (insn->postop == X86_POSTOP_SHIFT) {
- /*@dependent@*/ /*@null@*/ yasm_intnum *num;
- num = yasm_expr_get_intnum(&imm->val, NULL);
- if (num) {
- if (yasm_intnum_get_uint(num) == 1) {
- /* We can use the ,1. */
- yasm_expr_destroy(imm->val);
- yasm_xfree(imm);
- insn->imm = NULL;
- immlen = 0;
- } else {
- /* We can't use the ,1. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- }
- insn->postop = X86_POSTOP_NONE;
- } else {
- /* Just assume we can't use the ,1 form: allowing this
- * is more work than it's worth.
- if (imm->val.abs) {
- temp = yasm_expr_copy(imm->val.abs);
- assert(temp != NULL);
- num = yasm_expr_get_intnum(&temp, calc_bc_dist);
- }
++ if (imm->val.abs)
++ num = yasm_expr_get_intnum(&imm->val.abs, NULL);
+
+ /* TODO: check imm->len vs. sized len from expr? */
+
- switch (insn->postop) {
- case X86_POSTOP_SIGNEXT_IMM8:
- /* Handle signext_imm8 postop special-casing */
++ /* Handle signext_imm8 postop special-casing */
++ if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
++ if (imm->val.rel || num) {
+ if (imm->val.rel)
- val = 1000; /* has relative portion, don't collapse */
- else if (num)
- val = yasm_intnum_get_int(num);
++ val = 1000; /* has relative portion, don't collapse */
+ else
- val = 0;
++ val = yasm_intnum_get_int(num);
+ if (val >= -128 && val <= 127) {
+ /* We can use the sign-extended byte form: shorten
- * the immediate length to 1.
++ * the immediate length to 1 and make the byte form
++ * permanent.
*/
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- insn->postop = X86_POSTOP_NONE;
++ imm->val.size = 8;
+ immlen = 8;
- if (save) {
- /* Make the byte form permanent. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- imm->val.size = 8;
- if (insn->opcode.opcode[2] != 0) {
- insn->opcode.opcode[1] = insn->opcode.opcode[2];
- insn->opcode.len++;
- }
- } else if (insn->opcode.opcode[2] != 0)
- bc->len++;
- }
- /* Not really necessary, but saves confusion over it. */
- if (save)
- insn->postop = X86_POSTOP_NONE;
- break;
-
- case X86_POSTOP_SIGNEXT_IMM32:
- /* Handle signext_imm32 postop special-casing */
- if (!num || yasm_intnum_check_size(num, 32, 0, 1)) {
- bc->len++; /* Due to ModRM byte */
- immlen = 32;
- if (save) {
- /* Throwaway REX byte */
- unsigned char rex_temp = 0;
-
- /* Build ModRM EA - CAUTION: this depends on
- * opcode 0 being a mov instruction!
- */
- insn->x86_ea = yasm_x86__ea_create_reg(
- (unsigned long)insn->opcode.opcode[0]-0xB8,
- &rex_temp, 64);
-
- /* Make the imm32s form permanent. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- imm->val.size = 32;
++ if (insn->opcode.opcode[2] != 0) {
++ insn->opcode.opcode[1] = insn->opcode.opcode[2];
++ insn->opcode.len++;
+ }
}
- /* Not really necessary, but saves confusion over it. */
- if (save)
- insn->postop = X86_POSTOP_NONE;
- break;
-
- case X86_POSTOP_SHIFT:
- /* Handle shift postop special-casing */
- if (num && yasm_intnum_get_uint(num) == 1) {
- /* We can use the ,1 form: no imm (set to 0 len) */
- immlen = 0;
-
- if (save) {
- /* Make the ,1 form permanent. */
- insn->opcode.opcode[0] = insn->opcode.opcode[1];
- /* Delete imm, as it's not needed. */
- yasm_value_delete(&imm->val);
- yasm_xfree(imm);
- insn->imm = (yasm_immval *)NULL;
- }
- } else
- retval = YASM_BC_RESOLVE_NONE; /* could still get ,1 */
-
- /* Not really necessary, but saves confusion over it. */
- if (save)
- insn->postop = X86_POSTOP_NONE;
- break;
-
- default:
- break;
++ insn->postop = X86_POSTOP_NONE;
++ } else {
++ /* Unknown; default to byte form and set as critical
++ * expression.
++ */
++ immlen = 8;
++ add_span(add_span_data, bc, 2, &imm->val, NULL, -128, 127);
+ }
}
- bc->len += immlen;
- yasm_expr_destroy(temp);
++ yasm_intnum_destroy(zero);
+
+ bc->len += immlen/8;
}
bc->len += insn->opcode.len;
(insn->common.mode_bits == 64 && insn->common.opersize == 64 &&
insn->def_opersize_64 != 64)))
bc->len++;
- x86_effaddr *x86_ea = (x86_effaddr *)insn->ea;
+ return 0;
+}
+
+static int
+x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ x86_insn *insn = (x86_insn *)bc->contents;
+ /*@null@*/ yasm_expr *temp;
- if (ea && ea->disp) {
++ x86_effaddr *x86_ea = insn->x86_ea;
+ yasm_effaddr *ea = &x86_ea->ea;
+ yasm_immval *imm = insn->imm;
+
- if (ea->len == 0xff) {
- ea->len = (insn->common.addrsize == 16) ? 2U : 4U;
++ if (ea && ea->disp.abs) {
+ /* Change displacement length into word-sized */
- bc->len += ea->len;
++ if (ea->disp.size == 0) {
++ ea->disp.size = (insn->common.addrsize == 16) ? 16 : 32;
+ x86_ea->modrm &= ~0300;
+ x86_ea->modrm |= 0200;
+ bc->len--;
++ bc->len += ea->disp.size/8;
+ }
+ }
- if (imm && imm->val) {
- return retval;
++ if (imm && imm->val.abs) {
+ if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
+ bc->len--;
- bc->len += imm->len;
++ bc->len += imm->val.size/8;
+ insn->postop = X86_POSTOP_NONE;
+ }
+ }
+
+ return 0;
}
-static yasm_bc_resolve_flags
-x86_bc_jmp_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
+static int
+x86_bc_jmp_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
{
x86_jmp *jmp = (x86_jmp *)bc->contents;
- yasm_bc_resolve_flags retval = YASM_BC_RESOLVE_MIN_LEN;
+ yasm_bytecode *target_prevbc;
+ /*@null@*/ yasm_expr *temp;
+ /*@only@*/ yasm_intnum *num;
+ /*@dependent@*/ /*@null@*/ yasm_intnum *num2;
+ long rel;
unsigned char opersize;
- x86_jmp_opcode_sel jrtype = JMP_NONE;
/* As opersize may be 0, figure out its "real" value. */
opersize = (jmp->common.opersize == 0) ?
jmp->common.mode_bits : jmp->common.opersize;
- /* We only check to see if forced forms are actually legal if we're in
- * save mode. Otherwise we assume that they are legal.
- */
- switch (jmp->op_sel) {
- case JMP_SHORT_FORCED:
- /* 1 byte relative displacement */
- jrtype = JMP_SHORT;
- if (save) {
- /* does a short form exist? */
- if (jmp->shortop.len == 0) {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("short jump does not exist"));
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
-
- if (!jmp->target.rel)
- num = yasm_intnum_create_uint(0);
- else if (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc)
- || target_prevbc->section != jmp->origin_prevbc->section
- || !(num = calc_bc_dist(jmp->origin_prevbc,
- target_prevbc))) {
- /* External or out of segment, so we can't check distance.
- * This depends on the objfmt supporting 8-bit relocs.
- * While most don't, some might, so allow it. The objfmt
- * will error if not supported.
- */
- break;
- }
+ bc->len += x86_common_calc_len(&jmp->common);
- if (jmp->target.abs) {
- temp = yasm_expr_copy(jmp->target.abs);
- num2 = yasm_expr_get_intnum(&temp, calc_bc_dist);
- if (!num2) {
- yasm_expr_destroy(temp);
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("jump target too complex"));
- return YASM_BC_RESOLVE_ERROR |
- YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
- yasm_intnum_calc(num, YASM_EXPR_ADD, num2);
- yasm_expr_destroy(temp);
- }
+ if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) {
+ if (jmp->nearop.len == 0) {
- yasm__error(bc->line, N_("near jump does not exist"));
++ yasm_error_set(YASM_ERROR_TYPE, N_("near jump does not exist"));
+ return -1;
+ }
- rel = yasm_intnum_get_int(num);
- yasm_intnum_destroy(num);
- rel -= jmp->shortop.len+1;
- /* short displacement must fit in -128 <= rel <= +127 */
- if (rel < -128 || rel > 127) {
- yasm_error_set(YASM_ERROR_OVERFLOW,
- N_("short jump out of range"));
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
- }
- break;
- case JMP_NEAR_FORCED:
- /* 2/4 byte relative displacement (depending on operand size) */
- jrtype = JMP_NEAR;
- if (save) {
- if (jmp->nearop.len == 0) {
- yasm_error_set(YASM_ERROR_TYPE,
- N_("near jump does not exist"));
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
- }
- break;
- default:
- /* Due to code in x86_finalize_jmp(), we can only get here if
- * there's BOTH short and near opcodes available, and it wasn't
- * forced by the user.
- */
- if (!jmp->target.rel)
- num = yasm_intnum_create_uint(0);
- else if (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc)
- || target_prevbc->section != jmp->origin_prevbc->section
- || !(num = calc_bc_dist(jmp->origin_prevbc,
- target_prevbc))) {
- /* It's unknown. Thus, assume near displacement. */
- jrtype = JMP_NEAR;
- retval = YASM_BC_RESOLVE_NONE;
- break;
- }
+ /* Near jump, no spans needed */
+ bc->len += jmp->nearop.len;
+ bc->len += (opersize == 16) ? 2 : 4;
+ return 0;
+ }
- /* Try to find shortest displacement based on difference between
- * target expr value and origin offset.
- */
- if (jmp->target.abs) {
- temp = yasm_expr_copy(jmp->target.abs);
- num2 = yasm_expr_get_intnum(&temp, calc_bc_dist);
- if (!num2) {
- yasm_expr_destroy(temp);
- yasm_error_set(YASM_ERROR_TOO_COMPLEX,
- N_("jump target too complex"));
- return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN;
- }
- yasm_intnum_calc(num, YASM_EXPR_ADD, num2);
- yasm_expr_destroy(temp);
- }
+ if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
+ if (jmp->shortop.len == 0) {
- yasm__error(bc->line, N_("short jump does not exist"));
++ yasm_error_set(YASM_ERROR_TYPE, N_("short jump does not exist"));
+ return -1;
+ }
- rel = yasm_intnum_get_int(num);
- yasm_intnum_destroy(num);
- rel -= jmp->shortop.len+1;
- /* short displacement must fit within -128 <= rel <= +127 */
- if (rel >= -128 && rel <= 127) {
- /* It fits into a short displacement. */
- jrtype = JMP_SHORT;
- } else {
- /* Near for now, but could get shorter in the future as
- * there's a short form available.
- */
- jrtype = JMP_NEAR;
- retval = YASM_BC_RESOLVE_NONE;
- }
- break;
+ /* We want to be sure to error if we exceed short length, so
+ * put it in as a dependent expression (falling through).
+ */
}
- /* Short jump, generate span */
- switch (jrtype) {
- case JMP_SHORT:
- if (save)
- jmp->op_sel = JMP_SHORT;
- if (jmp->shortop.len == 0)
- return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */
-
++ if (jmp->target.rel
++ && (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc)
++ || target_prevbc->section != jmp->origin_prevbc->section)) {
++ /* External or out of segment, so we can't check distance.
++ * Allowing forced short jumps depends on the objfmt supporting
++ * 8-bit relocs. While most don't, some might, so allow it here.
++ * Otherwise default to word-sized.
++ * The objfmt will error if not supported.
++ */
++ if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
+ bc->len += jmp->shortop.len + 1;
- break;
- case JMP_NEAR:
- if (save)
- jmp->op_sel = JMP_NEAR;
- if (jmp->nearop.len == 0)
- return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */
-
++ } else {
+ bc->len += jmp->nearop.len;
+ bc->len += (opersize == 16) ? 2 : 4;
- break;
- default:
- yasm_internal_error(N_("unknown jump type"));
++ }
++ return 0;
++ }
++
++ /* Default to short jump and generate span */
+ bc->len += jmp->shortop.len + 1;
- add_span(add_span_data, bc, 1,
- yasm_expr_create(YASM_EXPR_SUB,
- yasm_expr_expr(yasm_expr_copy(jmp->target)),
- yasm_expr_sym(jmp->origin), bc->line),
- -128, 127);
++ add_span(add_span_data, bc, 1, &jmp->target, jmp->origin_prevbc, -128, 127);
+ return 0;
+}
+
+static int
+x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
+ /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
+{
+ x86_jmp *jmp = (x86_jmp *)bc->contents;
+ unsigned char opersize;
+
+ if (span != 1)
+ yasm_internal_error(N_("unrecognized span id"));
+
+ /* As opersize may be 0, figure out its "real" value. */
+ opersize = (jmp->common.opersize == 0) ?
+ jmp->common.mode_bits : jmp->common.opersize;
+
+ if (jmp->nearop.len == 0) {
- yasm__error(bc->line, N_("short jump out of range"));
++ yasm_error_set(YASM_ERROR_VALUE, N_("short jump out of range"));
+ return -1;
}
- bc->len += x86_common_resolve(&jmp->common);
- return retval;
+ /* Upgrade to a near jump */
+ jmp->op_sel = JMP_NEAR;
+ bc->len -= jmp->shortop.len + 1;
+ bc->len += jmp->nearop.len;
+ bc->len += (opersize == 16) ? 2 : 4;
+
+ return 0;
}
-static yasm_bc_resolve_flags
-x86_bc_jmpfar_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
+static int
+x86_bc_jmpfar_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
+ void *add_span_data)
{
x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
unsigned char opersize;
YASM_WRITE_8(*bufp, x86_ea->sib);
}
- if (ea->disp) {
- /* Simplify expression */
- ea->disp = yasm_expr_simplify(ea->disp, yasm_common_calc_bc_dist);
- if (x86_ea->pcrel) {
- /*@null@*/ yasm_expr *wrt = yasm_expr_extract_wrt(&ea->disp);
- ea->disp =
- yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(ea->disp),
- yasm_expr_sym(x86_ea->origin), bc->line);
- if (wrt) {
- ea->disp =
- yasm_expr_create(YASM_EXPR_WRT,
- yasm_expr_expr(ea->disp),
- yasm_expr_expr(wrt), bc->line);
- }
- if (output_expr(&ea->disp, *bufp, ea->len,
- (size_t)(ea->len*8), 0,
- (unsigned long)(*bufp-bufp_orig), bc, 1, 1,
- d))
- return 1;
- } else {
- if (output_expr(&ea->disp, *bufp, ea->len,
- (size_t)(ea->len*8), 0,
- (unsigned long)(*bufp-bufp_orig), bc, 0, 1,
- d))
- return 1;
+ if (x86_ea->ea.need_disp) {
+ x86_effaddr eat = *x86_ea; /* structure copy */
+ unsigned char addrsize = insn->common.addrsize;
+ unsigned int disp_len = x86_ea->ea.disp.size/8;
+
+ eat.valid_modrm = 0; /* force checkea to actually run */
+
+ if (x86_ea->ea.disp.abs) {
+ /* Call checkea() to simplify the registers out of the
+ * displacement. Throw away all of the return values except
+ * for the modified expr.
+ */
+ if (yasm_x86__expr_checkea
+ (&eat, &addrsize, insn->common.mode_bits,
- insn->postop == X86_POSTOP_ADDRESS16, &insn->rex,
- yasm_common_calc_bc_dist))
++ insn->postop == X86_POSTOP_ADDRESS16, &insn->rex))
+ yasm_internal_error(N_("checkea failed"));
+ x86_ea->ea.disp.abs = eat.ea.disp.abs;
}
- *bufp += ea->len;
- } else {
- /* 0 displacement, but we didn't know it before, so we have to
- * write out 0 value.
- * FIXME: Is this still needed?
- */
- for (i=0; i<ea->len; i++)
- YASM_WRITE_8(*bufp, 0);
+
+ if (x86_ea->ea.disp.ip_rel) {
+ /* Adjust relative displacement to end of bytecode */
+ /*@only@*/ yasm_intnum *delta;
+ delta = yasm_intnum_create_int(-(long)bc->len);
+ if (!x86_ea->ea.disp.abs)
+ x86_ea->ea.disp.abs =
+ yasm_expr_create_ident(yasm_expr_int(delta), bc->line);
+ else
+ x86_ea->ea.disp.abs =
+ yasm_expr_create(YASM_EXPR_ADD,
+ yasm_expr_expr(x86_ea->ea.disp.abs),
+ yasm_expr_int(delta), bc->line);
+ }
+ if (output_value(&x86_ea->ea.disp, *bufp, disp_len,
+ (unsigned long)(*bufp-bufp_orig), bc, 1, d))
+ return 1;
+ *bufp += disp_len;
}
}
* and 0 if all values successfully determined and saved in data.
*/
static int
- x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
- /*@null@*/ int *indexreg, unsigned char *pcrel, unsigned int bits,
- void *data, int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d))
+ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg,
+ int *pcrel, unsigned int bits, void *data,
- int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d),
- yasm_calc_bc_dist_func calc_bc_dist)
++ int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d))
{
int i;
int *reg;
int regnum;
int indexval = 0;
int indexmult = 0;
- yasm_expr *e;
+ yasm_expr *e, *wrt;
/*@-unqualifiedtrans@*/
- *ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, NULL, NULL, NULL, NULL);
- if (*wrt)
- *wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, NULL, NULL, NULL,
- NULL);
- *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, calc_bc_dist, NULL,
- NULL, NULL);
++ *ep = yasm_expr__level_tree(*ep, 1, 1, indexreg == 0, NULL, NULL, NULL,
++ NULL);
+
+ /* Check for WRT rip first */
+ wrt = yasm_expr_extract_wrt(ep);
+ if (wrt && wrt->op == YASM_EXPR_IDENT &&
+ wrt->terms[0].type == YASM_EXPR_REG) {
+ if (bits != 64) { /* only valid in 64-bit mode */
+ yasm_expr_destroy(wrt);
+ return 1;
+ }
+ reg = get_reg(&wrt->terms[0], ®num, data);
+ if (!reg || regnum != 16) { /* only accept rip */
+ yasm_expr_destroy(wrt);
+ return 1;
+ }
+ (*reg)++;
+
+ /* Delete WRT. Set pcrel to 1 to indicate to x86
+ * bytecode code to do PC-relative displacement transform.
+ */
+ *pcrel = 1;
+ yasm_expr_destroy(wrt);
+ } else if (wrt) {
+ yasm_expr_destroy(wrt);
+ return 1;
+ }
+
/*@=unqualifiedtrans@*/
assert(*ep != NULL);
e = *ep;
} else if (dispreq) {
/* for BP/EBP, there *must* be a displacement value, but we
* may not know the size (8 or 16/32) for sure right now.
- * We can't leave displen at 0, because that just means
- * unknown displacement, including none.
*/
- *displen = 0xff;
- *modrm |= 0100;
- *v_modrm = 1;
+ x86_ea->ea.need_nonzero_len = 1;
++ x86_ea->modrm |= 0100;
++ x86_ea->valid_modrm = 1;
++ return 0;
+ }
+
- if (x86_ea->ea.disp.rel ||
- (x86_ea->ea.disp.abs &&
- !(intn = yasm_expr_get_intnum(&x86_ea->ea.disp.abs, NULL)))) {
- /* expr still has unknown values or is relative:
- * assume 16/32-bit disp
- */
++ /* Relative displacement; basically all object formats need non-byte
++ * for relocation here, so just do that.
++ */
++ if (x86_ea->ea.disp.rel)
+ x86_ea->ea.disp.size = wordsize;
- x86_ea->modrm |= 0200;
- x86_ea->valid_modrm = 1;
- return 0;
- }
+
+ /* don't try to find out what size displacement we have if
+ * displen is known.
+ */
+ if (x86_ea->ea.disp.size != 0) {
+ if (x86_ea->ea.disp.size == 8)
+ x86_ea->modrm |= 0100;
+ else
+ x86_ea->modrm |= 0200;
+ x86_ea->valid_modrm = 1;
return 0;
}
-
- intn = yasm_expr_get_intnum(ep, NULL);
- if (!intn) {
+ /* At this point there's 3 possibilities for the displacement:
+ * - None (if =0)
+ * - signed 8 bit (if in -128 to 127 range)
+ * - 16/32 bit (word size)
+ * For now, check intnum value right now; if it's not 0,
+ * assume 8 bit and set up for allowing 16 bit later.
+ * FIXME: this should really set up two thresholds, one for 8-bit
+ * expansion and one for 16-bit expansion. The complex expression
+ * equaling zero is probably a rare case, so we ignore it for now.
+ */
- *displen = 0xff;
- *modrm |= 0100;
- *v_modrm = 1;
++ if (x86_ea->ea.disp.abs &&
++ !(intn = yasm_expr_get_intnum(&x86_ea->ea.disp.abs, NULL))) {
+ /* expr still has unknown values: treat like BP/EBP above */
- }
++ x86_ea->ea.need_nonzero_len = 1;
++ x86_ea->modrm |= 0100;
++ x86_ea->valid_modrm = 1;
+ return 0;
- dispval = yasm_intnum_get_int(intn);
++ }
+
+ if (intn)
+ dispval = yasm_intnum_get_int(intn);
+ else
+ dispval = 0;
/* Figure out what size displacement we will have. */
- if (dispval == 0) {
+ if (!x86_ea->ea.need_nonzero_len && dispval == 0) {
/* if we know that the displacement is 0 right now,
- * go ahead and delete the expr (making it so no
- * displacement value is included in the output).
+ * go ahead and delete the expr and make it so no
+ * displacement value is included in the output.
* The Mod bits of ModRM are set to 0 above, and
* we're done with the ModRM byte!
- *
- * Don't do this if we came from dispreq check above, so
- * check *displen.
*/
- yasm_expr_destroy(e);
- *ep = (yasm_expr *)NULL;
+ yasm_expr_destroy(x86_ea->ea.disp.abs);
+ x86_ea->ea.disp.abs = NULL;
+ x86_ea->ea.need_disp = 0;
} else if (dispval >= -128 && dispval <= 127) {
/* It fits into a signed byte */
- *displen = 1;
- *modrm |= 0100;
+ x86_ea->ea.disp.size = 8;
+ x86_ea->modrm |= 0100;
} else {
/* It's a 16/32-bit displacement */
- *displen = wordsize;
- *modrm |= 0200;
+ x86_ea->ea.disp.size = wordsize;
+ x86_ea->modrm |= 0200;
}
- *v_modrm = 1; /* We're done with ModRM */
+ x86_ea->valid_modrm = 1; /* We're done with ModRM */
}
return 0;
}
int
- yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
- unsigned int bits, unsigned int nosplit,
- int address16_op, unsigned char *displen,
- unsigned char *modrm, unsigned char *v_modrm,
- unsigned char *n_modrm, unsigned char *sib,
- unsigned char *v_sib, unsigned char *n_sib,
- unsigned char *pcrel, unsigned char *rex)
+ yasm_x86__expr_checkea(x86_effaddr *x86_ea, unsigned char *addrsize,
- unsigned int bits, int address16_op, unsigned char *rex,
- yasm_calc_bc_dist_func calc_bc_dist)
++ unsigned int bits, int address16_op, unsigned char *rex)
{
- yasm_expr *e, *wrt;
int retval;
- /* First split off any top-level WRT. We'll add it back in at the end */
- wrt = yasm_expr_extract_wrt(ep);
- e = *ep;
-
if (*addrsize == 0) {
/* we need to figure out the address size from what we know about:
* - the displacement length
reg3264_data.regs = reg3264mult;
reg3264_data.bits = bits;
reg3264_data.addrsize = *addrsize;
- if (x86_expr_checkea_getregusage(ep, &wrt, &indexreg, pcrel, bits,
- ®3264_data,
- x86_expr_checkea_get_reg3264)) {
- yasm__error((*ep)->line, N_("invalid effective address"));
- return 1;
+ if (x86_ea->ea.disp.abs) {
+ int pcrel = 0;
+ switch (x86_expr_checkea_getregusage
+ (&x86_ea->ea.disp.abs, &indexreg, &pcrel, bits,
- ®3264_data, x86_expr_checkea_get_reg3264,
- calc_bc_dist)) {
++ ®3264_data, x86_expr_checkea_get_reg3264)) {
+ case 1:
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("invalid effective address"));
+ return 1;
+ case 2:
+ if (pcrel) {
+ x86_ea->ea.disp.curpos_rel = 1;
+ x86_ea->ea.disp.ip_rel = 1;
+ }
+ return 2;
+ default:
+ if (pcrel) {
+ x86_ea->ea.disp.curpos_rel = 1;
+ x86_ea->ea.disp.ip_rel = 1;
+ }
+ break;
+ }
}
- e = *ep;
/* If indexreg mult is 0, discard it.
* This is possible because of the way indexreg is found in
}
/* 16-bit cannot have SIB */
- *sib = 0;
- *v_sib = 0;
- *n_sib = 0;
-
- if (x86_expr_checkea_getregusage(ep, &wrt, NULL, pcrel, bits,
- ®16mult,
- x86_expr_checkea_get_reg16)) {
- yasm__error((*ep)->line, N_("invalid effective address"));
- return 1;
+ x86_ea->sib = 0;
+ x86_ea->valid_sib = 0;
+ x86_ea->need_sib = 0;
+
+ if (x86_ea->ea.disp.abs) {
+ int pcrel = 0;
+ switch (x86_expr_checkea_getregusage
+ (&x86_ea->ea.disp.abs, (int *)NULL, &pcrel, bits,
- ®16mult, x86_expr_checkea_get_reg16, calc_bc_dist)) {
++ ®16mult, x86_expr_checkea_get_reg16)) {
+ case 1:
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("invalid effective address"));
+ return 1;
+ case 2:
+ if (pcrel) {
+ x86_ea->ea.disp.curpos_rel = 1;
+ x86_ea->ea.disp.ip_rel = 1;
+ }
+ return 2;
+ default:
+ if (pcrel) {
+ x86_ea->ea.disp.curpos_rel = 1;
+ x86_ea->ea.disp.ip_rel = 1;
+ }
+ break;
+ }
}
- e = *ep;
/* reg multipliers not 0 or 1 are illegal. */
if (reg16mult.bx & ~1 || reg16mult.si & ~1 || reg16mult.di & ~1 ||
* 14 = CR4
* 15 = memory offset (an EA, but with no registers allowed)
* [special case for MOV opcode]
++ * 16 = immediate, value=1 (for special-case shift)
* - 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)
* 9 = operand size goes into address size (jmp only)
* A = far jump (outputs a farjmp instead of normal insn)
* The below describes postponed actions: actions which can't be completed at
-- * parse-time due to things like EQU and complex expressions. For these, some
++ * parse-time due to possibly dependent expressions. For these, some
* additional data (stored in the second byte of the opcode with a one-byte
* opcode) is passed to later stages of the assembler with flags set to
* indicate postponed actions.
* - 3 bits = postponed action:
* 0 = none
-- * 1 = shift operation with a ,1 short form (instead of imm8).
-- * 2 = large imm16/32 that can become a sign-extended imm8.
-- * 3 = could become a short opcode mov with bits=64 and a32 prefix
-- * 4 = forced 16-bit address size (override ignored, no prefix)
-- * 5 = large imm64 that can become a sign-extended imm32.
++ * 1 = large imm16/32 that can become a sign-extended imm8.
++ * 2 = could become a short opcode mov with bits=64 and a32 prefix
++ * 3 = forced 16-bit address size (override ignored, no prefix)
++ * 4 = large imm64 that can become a sign-extended imm32.
*/
#define OPT_Imm 0x0
#define OPT_Reg 0x1
#define OPT_SS 0x13
#define OPT_CR4 0x14
#define OPT_MemOffs 0x15
++#define OPT_Imm1 0x16
#define OPT_MASK 0x1F
#define OPS_Any (0UL<<5)
#define OPA_MASK (0xFUL<<13)
#define OPAP_None (0UL<<17)
--#define OPAP_ShiftOp (1UL<<17)
--#define OPAP_SImm8Avail (2UL<<17)
--#define OPAP_ShortMov (3UL<<17)
--#define OPAP_A16 (4UL<<17)
--#define OPAP_SImm32Avail (5UL<<17)
++#define OPAP_SImm8Avail (1UL<<17)
++#define OPAP_ShortMov (2UL<<17)
++#define OPAP_A16 (3UL<<17)
++#define OPAP_SImm32Avail (4UL<<17)
#define OPAP_MASK (7UL<<17)
typedef struct x86_insn_info {
static const x86_insn_info shift_insn[] = {
{ CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD2, 0, 0}, 0, 2,
{OPT_RM|OPS_8|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
-- /* FIXME: imm8 is only avail on 186+, but we use imm8 to get to postponed
-- * ,1 form, so it has to be marked as Any. We need to store the active
-- * CPU flags somewhere to pass that parse-time info down the line.
-- */
- { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0xC0, 0}, 0, 2,
- { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xC0, 0xD0, 0}, 0, 2,
-- {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
-- 0} },
++ { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0, 0}, 0, 2,
++ {OPT_RM|OPS_8|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} },
++ { CPU_186, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xC0, 0, 0}, 0, 2,
++ {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} },
{ CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD3, 0, 0}, 0, 2,
{OPT_RM|OPS_16|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
- { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2,
- { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xC1, 0xD1, 0}, 0, 2,
-- {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
-- 0} },
++ { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD1, 0, 0}, 0, 2,
++ {OPT_RM|OPS_16|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} },
++ { CPU_186, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xC1, 0, 0}, 0, 2,
++ {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} },
{ CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD3, 0, 0}, 0, 2,
{OPT_RM|OPS_32|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
- { CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2,
- { CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xC1, 0xD1, 0}, 0, 2,
-- {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
- 0} },
- { CPU_Hammer|CPU_64, MOD_SpAdd, 64, 0, 0, 1, {0xD3, 0, 0}, 0, 2,
- {OPT_RM|OPS_64|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
- { CPU_Hammer|CPU_64, MOD_SpAdd, 64, 0, 0, 1, {0xD1, 0xC1, 0}, 0, 2,
- {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp,
-- 0} },
++ { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD1, 0, 0}, 0, 2,
++ {OPT_RM|OPS_32|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} },
++ { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xC1, 0, 0}, 0, 2,
++ {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} },
{ CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD3, 0, 0}, 0,
2, {OPT_RM|OPS_64|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} },
- { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD1, 0xC1, 0},
- { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xC1, 0xD1, 0},
-- 0, 2, {OPT_RM|OPS_64|OPA_EA,
-- OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm|OPAP_ShiftOp, 0} },
++ { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD1, 0, 0},
++ 0, 2, {OPT_RM|OPS_64|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} },
++ { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xC1, 0, 0},
++ 0, 2, {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} },
/* In GAS mode, single operands are equivalent to shifting by 1 forms */
{ CPU_Any, MOD_SpAdd|MOD_GasOnly|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0, 0},
0, 1, {OPT_RM|OPS_8|OPA_EA, 0, 0} },
unsigned char im_sign;
unsigned char spare;
int i;
- static const unsigned int size_lookup[] = {0, 1, 2, 4, 8, 10, 16, 0};
+ unsigned int size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 0};
++ unsigned long do_postop = 0;
+
+ size_lookup[7] = mode_bits;
if (!info) {
num_info = 1;
YASM_EXPR_REG))
mismatch = 1;
break;
++ case OPT_Imm1:
++ if (op->type == YASM_INSN__OPERAND_IMM) {
++ const yasm_intnum *num;
++ num = yasm_expr_get_intnum(&op->data.val, NULL);
++ if (!num || !yasm_intnum_is_pos1(num))
++ mismatch = 1;
++ } else
++ mismatch = 1;
++ break;
default:
yasm_internal_error(N_("invalid operand type"));
}
switch ((int)(info->operands[i] & OPAP_MASK)) {
case OPAP_None:
break;
-- case OPAP_ShiftOp:
-- insn->postop = X86_POSTOP_SHIFT;
-- break;
case OPAP_SImm8Avail:
insn->postop = X86_POSTOP_SIGNEXT_IMM8;
break;
case OPAP_ShortMov:
-- insn->postop = X86_POSTOP_SHORTMOV;
++ do_postop = OPAP_ShortMov;
break;
case OPAP_A16:
insn->postop = X86_POSTOP_ADDRESS16;
break;
case OPAP_SImm32Avail:
-- insn->postop = X86_POSTOP_SIGNEXT_IMM32;
++ do_postop = OPAP_SImm32Avail;
break;
default:
yasm_internal_error(
insn->common.addrsize = 0;
}
++ /* Handle non-span-dependent post-ops here */
++ switch (do_postop) {
++ case OPAP_ShortMov:
++ /* Long (modrm+sib) mov instructions in amd64 can be optimized into
++ * short mov instructions if a 32-bit address override is applied in
++ * 64-bit mode to an EA of just an offset (no registers) and the
++ * target register is al/ax/eax/rax.
++ */
++ if (insn->common.mode_bits == 64 && insn->common.addrsize == 32 &&
++ (!insn->x86_ea->ea.disp.abs ||
++ !yasm_expr__contains(insn->x86_ea->ea.disp.abs,
++ YASM_EXPR_REG))) {
++ yasm_x86__ea_set_disponly(insn->x86_ea);
++ /* Make the short form permanent. */
++ insn->opcode.opcode[0] = insn->opcode.opcode[1];
++ }
++ insn->opcode.opcode[1] = 0; /* avoid possible confusion */
++ break;
++ case OPAP_SImm32Avail:
++ /* Used for 64-bit mov immediate, which can take a sign-extended
++ * imm32 as well as imm64 values. The imm32 form is put in the
++ * second byte of the opcode and its ModRM byte is put in the third
++ * byte of the opcode.
++ */
++ if (!insn->imm->val.abs ||
++ yasm_intnum_check_size(
++ yasm_expr_get_intnum(&insn->imm->val.abs, NULL),
++ 32, 0, 1)) {
++ /* Throwaway REX byte */
++ unsigned char rex_temp = 0;
++
++ /* Build ModRM EA - CAUTION: this depends on
++ * opcode 0 being a mov instruction!
++ */
++ insn->x86_ea = yasm_x86__ea_create_reg(
++ (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp, 64);
++
++ /* Make the imm32s form permanent. */
++ insn->opcode.opcode[0] = insn->opcode.opcode[1];
++ insn->imm->val.size = 32;
++ }
++ insn->opcode.opcode[1] = 0; /* avoid possible confusion */
++ break;
++ default:
++ break;
++ }
++
/* Transform the bytecode */
yasm_x86__bc_transform_insn(bc, insn);
}
EXTRA_DIST += modules/dbgfmts/null/Makefile.inc
EXTRA_DIST += modules/dbgfmts/stabs/Makefile.inc
+ include modules/dbgfmts/codeview/Makefile.inc
+ include modules/dbgfmts/dwarf2/Makefile.inc
include modules/dbgfmts/null/Makefile.inc
-include modules/dbgfmts/stabs/Makefile.inc
+#include modules/dbgfmts/stabs/Makefile.inc
--- /dev/null
-static yasm_bc_resolve_flags cv8_symhead_bc_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * CodeView debugging format - symbol and line information
+ *
+ * Copyright (C) 2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #include <util.h>
+ /*@unused@*/ RCSID("$Id$");
+
+ #define YASM_LIB_INTERNAL
+ #define YASM_BC_INTERNAL
+ #include <libyasm.h>
+
+ #include "cv-dbgfmt.h"
+
+ enum cv8_symheadtype {
+ CV8_DEBUG_SYMS = 0xF1, /* CV5 symbol information */
+ CV8_LINE_NUMS = 0xF2, /* line numbers for a section */
+ CV8_FILE_STRTAB = 0xF3, /* filename string table */
+ CV8_FILE_INFO = 0xF4 /* source file info */
+ };
+
+ enum cv_symtype {
+ /* Non-modal Symbols */
+ CV_S_COMPILE = 0x0001, /* Compile Flag */
+ CV_S_REGISTER = 0x0002, /* Register */
+ CV_S_CONSTANT = 0x0003, /* Constant */
+ CV_S_UDT = 0x0004, /* User-defined Type */
+ CV_S_SSEARCH = 0x0005, /* Start Search */
+ CV_S_END = 0x0006, /* End of Block */
+ CV_S_SKIP = 0x0007, /* Skip Record */
+ CV_S_OBJNAME = 0x0009, /* Object File Name */
+ CV_S_ENDARG = 0x000a, /* End of Arguments */
+ CV_S_COBOLUDT = 0x000b, /* COBOL User-defined Type */
+ CV_S_MANYREG = 0x000c, /* Many Registers */
+ CV_S_RETURN = 0x000d, /* Function Return */
+ CV_S_ENTRYTHIS = 0x000e, /* "this" at Method Entry */
+
+ /* Symbols for 16:16 Segmented Architectures */
+ CV_S_BPREL16 = 0x0100, /* BP Relative 16:16 */
+ CV_S_LDATA16 = 0x0101, /* Local Data 16:16 */
+ CV_S_GDATA16 = 0x0102, /* Global Data Symbol 16:16 */
+ CV_S_PUB16 = 0x0103, /* Public Symbol 16:16 */
+ CV_S_LPROC16 = 0x0104, /* Local Start 16:16 */
+ CV_S_GPROC16 = 0x0105, /* Global Start 16:16 */
+ CV_S_THUNK16 = 0x0106, /* Thunk Start 16:16 */
+ CV_S_BLOCK16 = 0x0107, /* Block Start 16:16 */
+ CV_S_WITH16 = 0x0108, /* With Start 16:16 */
+ CV_S_LABEL16 = 0x0109, /* Code Label 16:16 */
+ CV_S_CEXMODEL16 = 0x0110, /* Change Execution Model 16:16 */
+ CV_S_VFTPATH16 = 0x010b, /* Virtual Function Table Path 16:16 */
+ CV_S_REGREL16 = 0x010c, /* Register Relative 16:16 */
+
+ /* Symbols for 16:32 Segmented Architectures */
+ CV_S_BPREL32 = 0x0200, /* BP Relative 16:32 */
+ CV_S_LDATA32 = 0x0201, /* Local Data 16:32 */
+ CV_S_GDATA32 = 0x0202, /* Global Data Symbol 16:32 */
+ CV_S_PUB32 = 0x0203, /* Public Symbol 16:32 */
+ CV_S_LPROC32 = 0x0204, /* Local Start 16:32 */
+ CV_S_GPROC32 = 0x0205, /* Global Start 16:32 */
+ CV_S_THUNK32 = 0x0206, /* Thunk Start 16:32 */
+ CV_S_BLOCK32 = 0x0207, /* Block Start 16:32 */
+ CV_S_WITH32 = 0x0208, /* With Start 16:32 */
+ CV_S_LABEL32 = 0x0209, /* Code Label 16:32 */
+ CV_S_CEXMODEL32 = 0x0210, /* Change Execution Model 16:32 */
+ CV_S_VFTPATH32 = 0x020b, /* Virtual Function Table Path 16:32 */
+ CV_S_REGREL32 = 0x020c, /* Register Relative 16:32 */
+ CV_S_LTHREAD32 = 0x020d, /* Local Thread Storage 16:32 */
+ CV_S_GTHREAD32 = 0x020e, /* Global Thread Storage 16:32 */
+
+ /* Symbols for MIPS */
+ CV_S_LPROCMIPS = 0x0300, /* Local procedure start MIPS */
+ CV_S_GPROCMIPS = 0x0301, /* Global procedure start MIPS */
+
+ /* Symbols for CV8 - strings are 0 terminated rather than length-prefix.
+ * Incomplete and unofficial.
+ */
+ CV8_S_OBJNAME = 0x1101, /* Object File Name */
+ CV8_S_LABEL32 = 0x1105, /* Code Label 16:32 */
+ CV8_S_LDATA32 = 0x110c, /* Local Data 16:32 */
+ CV8_S_GDATA32 = 0x110d, /* Global Data 16:32 */
+ CV8_S_LPROC32 = 0x1110, /* Local Start 16:32 */
+ CV8_S_COMPILE = 0x1116 /* Compile Flag */
+ };
+
+ typedef struct cv8_symhead {
+ yasm_dbgfmt_cv *dbgfmt_cv;
+ enum cv8_symheadtype type;
+ yasm_bytecode *start_prevbc;
+ yasm_bytecode *end_prevbc;
+ int first; /* nonzero if first symhead in section */
+ } cv8_symhead;
+
+ typedef struct cv8_fileinfo {
+ yasm_dbgfmt_cv *dbgfmt_cv;
+ const cv_filename *fn;
+ } cv8_fileinfo;
+
+ /* Note: each line number group is associated with a file AND a section */
+ typedef struct cv8_linepair {
+ unsigned long offset;
+ unsigned long line;
+ } cv8_linepair;
+
+ /* Decrease linked list overhead a bit doing it this way */
+ typedef struct cv8_lineset {
+ STAILQ_ENTRY(cv8_lineset) link;
+ cv8_linepair pairs[126];
+ size_t num_pairs;
+ } cv8_lineset;
+
+ typedef struct cv8_lineinfo {
+ STAILQ_ENTRY(cv8_lineinfo) link;
+ yasm_dbgfmt_cv *dbgfmt_cv;
+ const cv_filename *fn; /* filename associated with line numbers */
+ yasm_section *sect; /* section line numbers are for */
+ yasm_symrec *sectsym; /* symbol for beginning of sect */
+ unsigned long num_linenums;
+ STAILQ_HEAD(, cv8_lineset) linesets;
+ } cv8_lineinfo;
+
+ /* Symbols use a bit of meta-programming to encode formats: each character
+ * of format represents the output generated, as follows:
+ * 'b' : 1 byte value (integer)
+ * 'h' : 2 byte value (integer)
+ * 'w' : 4 byte value (integer)
+ * 'Y' : symrec SECREL+SECTION (pointer)
+ * 'T' : type index (integer)
+ * 'S' : length-prefixed string (pointer)
+ * 'Z' : 0-terminated string (pointer)
+ */
+ typedef struct cv_sym {
+ yasm_dbgfmt_cv *dbgfmt_cv;
+ enum cv_symtype type;
+ const char *format;
+ union {
+ unsigned long i;
+ void *p;
+ } args[10];
+ } cv_sym;
+
+ /* Bytecode callback function prototypes */
+ static void cv8_symhead_bc_destroy(void *contents);
+ static void cv8_symhead_bc_print(const void *contents, FILE *f,
+ int indent_level);
-static yasm_bc_resolve_flags cv8_fileinfo_bc_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
++static int cv8_symhead_bc_calc_len
++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv8_symhead_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static void cv8_fileinfo_bc_destroy(void *contents);
+ static void cv8_fileinfo_bc_print(const void *contents, FILE *f,
+ int indent_level);
-static yasm_bc_resolve_flags cv8_lineinfo_bc_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
++static int cv8_fileinfo_bc_calc_len
++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv8_fileinfo_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static void cv8_lineinfo_bc_destroy(void *contents);
+ static void cv8_lineinfo_bc_print(const void *contents, FILE *f,
+ int indent_level);
-static yasm_bc_resolve_flags cv_sym_bc_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
++static int cv8_lineinfo_bc_calc_len
++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv8_lineinfo_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static void cv_sym_bc_destroy(void *contents);
+ static void cv_sym_bc_print(const void *contents, FILE *f, int indent_level);
- cv8_symhead_bc_resolve,
++static int cv_sym_bc_calc_len
++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv_sym_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ /* Bytecode callback structures */
+ static const yasm_bytecode_callback cv8_symhead_bc_callback = {
+ cv8_symhead_bc_destroy,
+ cv8_symhead_bc_print,
+ yasm_bc_finalize_common,
- cv8_fileinfo_bc_resolve,
++ cv8_symhead_bc_calc_len,
++ yasm_bc_expand_common,
+ cv8_symhead_bc_tobytes,
+ 0
+ };
+
+ static const yasm_bytecode_callback cv8_fileinfo_bc_callback = {
+ cv8_fileinfo_bc_destroy,
+ cv8_fileinfo_bc_print,
+ yasm_bc_finalize_common,
- cv8_lineinfo_bc_resolve,
++ cv8_fileinfo_bc_calc_len,
++ yasm_bc_expand_common,
+ cv8_fileinfo_bc_tobytes,
+ 0
+ };
+
+ static const yasm_bytecode_callback cv8_lineinfo_bc_callback = {
+ cv8_lineinfo_bc_destroy,
+ cv8_lineinfo_bc_print,
+ yasm_bc_finalize_common,
- cv_sym_bc_resolve,
++ cv8_lineinfo_bc_calc_len,
++ yasm_bc_expand_common,
+ cv8_lineinfo_bc_tobytes,
+ 0
+ };
+
+ static const yasm_bytecode_callback cv_sym_bc_callback = {
+ cv_sym_bc_destroy,
+ cv_sym_bc_print,
+ yasm_bc_finalize_common,
- yasm_bc_resolve(bc, 0, NULL);
++ cv_sym_bc_calc_len,
++ yasm_bc_expand_common,
+ cv_sym_bc_tobytes,
+ 0
+ };
+
+ static cv8_symhead *cv8_add_symhead(yasm_dbgfmt_cv *dbgfmt_cv,
+ yasm_section *sect, unsigned long type,
+ int first);
+ static void cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc);
+
+ static yasm_bytecode *cv8_add_fileinfo
+ (yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, const cv_filename *fn);
+
+ static unsigned long cv_sym_size(const cv_sym *cvs);
+
+
+ static cv_sym *
+ cv8_add_sym_objname(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+ /*@keep@*/ char *objname)
+ {
+ yasm_bytecode *bc;
+ cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+ cvs->dbgfmt_cv = dbgfmt_cv;
+ cvs->type = CV8_S_OBJNAME;
+ cvs->format = "wZ";
+ cvs->args[0].i = 0; /* signature (0=asm) */
+ cvs->args[1].p = objname; /* object filename */
+
+ bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+ bc->len = cv_sym_size(cvs);
+ yasm_cv__append_bc(sect, bc);
+ return cvs;
+ }
+
+ static cv_sym *
+ cv8_add_sym_compile(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+ /*@keep@*/ char *creator)
+ {
+ yasm_bytecode *bc;
+ cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+ cvs->dbgfmt_cv = dbgfmt_cv;
+ cvs->type = CV8_S_COMPILE;
+ cvs->format = "wwwwZh";
+ cvs->args[0].i = 3; /* language (3=Masm) */
+
+ /* target processor; 0xD0 = AMD64 */
+ if (strcmp(yasm_arch_keyword(dbgfmt_cv->arch), "x86") == 0) {
+ if (strcmp(yasm_arch_get_machine(dbgfmt_cv->arch), "amd64") == 0)
+ cvs->args[1].i = 0xD0;
+ else
+ cvs->args[1].i = 0x6; /* 686, FIXME */
+ } else
+ cvs->args[1].i = 0; /* XXX: unknown */
+
+ cvs->args[2].i = 0; /* flags (assume 0 for now) */
+ cvs->args[3].i = 0; /* creator version number (assume 0 for now) */
+ cvs->args[4].p = creator; /* creator string */
+ cvs->args[5].i = 0; /* no pairs of key/value */
+
+ bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+ bc->len = cv_sym_size(cvs);
+ yasm_cv__append_bc(sect, bc);
+ return cvs;
+ }
+
+ static cv_sym *
+ cv8_add_sym_label(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+ yasm_symrec *sym)
+ {
+ yasm_bytecode *bc;
+ cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+ cvs->dbgfmt_cv = dbgfmt_cv;
+ cvs->type = CV8_S_LABEL32;
+ cvs->format = "YbZ";
+ cvs->args[0].p = sym; /* symrec for label */
+ cvs->args[1].i = 0; /* flags (assume 0 for now) */
+ cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym));
+
+ bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+ bc->len = cv_sym_size(cvs);
+ yasm_cv__append_bc(sect, bc);
+ return cvs;
+ }
+
+ static cv_sym *
+ cv8_add_sym_data(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+ unsigned long type, yasm_symrec *sym, int is_global)
+ {
+ yasm_bytecode *bc;
+ cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+ cvs->dbgfmt_cv = dbgfmt_cv;
+ cvs->type = is_global ? CV8_S_GDATA32 : CV8_S_LDATA32;
+ cvs->format = "wYZ";
+ cvs->args[0].i = type; /* type index */
+ cvs->args[1].p = sym; /* symrec for label */
+ cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym));
+
+ bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+ bc->len = cv_sym_size(cvs);
+ yasm_cv__append_bc(sect, bc);
+ return cvs;
+ }
+
+ static size_t
+ cv_dbgfmt_add_file(yasm_dbgfmt_cv *dbgfmt_cv, size_t filenum,
+ const char *filename)
+ {
+ char *pathname;
+ size_t i;
+ yasm_md5_context context;
+ FILE *f;
+ unsigned char *buf;
+ size_t len;
+
+ /* Put the filename into the filename table */
+ if (filenum == 0) {
+ /* Look to see if we already have that filename in the table */
+ for (; filenum<dbgfmt_cv->filenames_size; filenum++) {
+ if (!dbgfmt_cv->filenames[filenum].filename ||
+ strcmp(dbgfmt_cv->filenames[filenum].filename, filename) == 0)
+ break;
+ }
+ } else
+ filenum--; /* array index is 0-based */
+
+ /* Realloc table if necessary */
+ if (filenum >= dbgfmt_cv->filenames_allocated) {
+ size_t old_allocated = dbgfmt_cv->filenames_allocated;
+ dbgfmt_cv->filenames_allocated = filenum+32;
+ dbgfmt_cv->filenames = yasm_xrealloc(dbgfmt_cv->filenames,
+ sizeof(cv_filename)*dbgfmt_cv->filenames_allocated);
+ for (i=old_allocated; i<dbgfmt_cv->filenames_allocated; i++) {
+ dbgfmt_cv->filenames[i].pathname = NULL;
+ dbgfmt_cv->filenames[i].filename = NULL;
+ dbgfmt_cv->filenames[i].str_off = 0;
+ dbgfmt_cv->filenames[i].info_off = 0;
+ }
+ }
+
+ /* Calculate MD5 checksum of file */
+ buf = yasm_xmalloc(1024);
+ yasm_md5_init(&context);
+ f = fopen(filename, "rb");
+ if (!f)
+ yasm__fatal(N_("codeview: could not open source file"));
+ while ((len = fread(buf, 1, 1024, f)) > 0)
+ yasm_md5_update(&context, buf, len);
+ yasm_md5_final(dbgfmt_cv->filenames[filenum].digest, &context);
+ fclose(f);
+ yasm_xfree(buf);
+
+ /* Actually save in table */
+ if (dbgfmt_cv->filenames[filenum].pathname)
+ yasm_xfree(dbgfmt_cv->filenames[filenum].pathname);
+ if (dbgfmt_cv->filenames[filenum].filename)
+ yasm_xfree(dbgfmt_cv->filenames[filenum].filename);
+
+ pathname = yasm__abspath(filename);
+ dbgfmt_cv->filenames[filenum].pathname = pathname;
+ dbgfmt_cv->filenames[filenum].filename = yasm__xstrdup(filename);
+
+ /* Update table size */
+ if (filenum >= dbgfmt_cv->filenames_size)
+ dbgfmt_cv->filenames_size = filenum + 1;
+
+ return filenum;
+ }
+
+ static yasm_bytecode *
+ cv_append_str(yasm_section *sect, const char *str)
+ {
+ yasm_datavalhead dvs;
+ yasm_bytecode *bc;
+
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(str),
+ strlen(str)));
+ bc = yasm_bc_create_data(&dvs, 1, 1, NULL, 0);
+ yasm_bc_finalize(bc, yasm_cv__append_bc(sect, bc));
- yasm_bc_resolve(bc, 0, NULL);
++ yasm_bc_calc_len(bc, NULL, NULL);
+ return bc;
+ }
+
+ typedef struct cv_line_info {
+ yasm_section *debug_symline;
+ yasm_dbgfmt_cv *dbgfmt_cv;
+ yasm_errwarns *errwarns;
+ unsigned int num_lineinfos;
+ STAILQ_HEAD(, cv8_lineinfo) cv8_lineinfos;
+ /*@null@*/ cv8_lineinfo *cv8_cur_li;
+ /*@null@*/ cv8_lineset *cv8_cur_ls;
+ } cv_line_info;
+
+ static int
+ cv_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d)
+ {
+ cv_line_info *info = (cv_line_info *)d;
+ yasm_dbgfmt_cv *dbgfmt_cv = info->dbgfmt_cv;
+ size_t i;
+ const char *filename;
+ unsigned long line;
+ /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc);
+ yasm_section *sect = yasm_bc_get_section(bc);
+
+ if (nextbc && bc->offset == nextbc->offset)
+ return 0;
+
+ yasm_linemap_lookup(dbgfmt_cv->linemap, bc->line, &filename, &line);
+
+ if (!info->cv8_cur_li
+ || strcmp(filename, info->cv8_cur_li->fn->filename) != 0) {
+ yasm_bytecode *sectbc;
+ char symname[8];
+
+ /* first see if we already have a lineinfo that is for this section and
+ * filename
+ */
+ STAILQ_FOREACH(info->cv8_cur_li, &info->cv8_lineinfos, link) {
+ if (sect == info->cv8_cur_li->sect
+ && strcmp(filename, info->cv8_cur_li->fn->filename) == 0)
+ break;
+ }
+
+ if (info->cv8_cur_li) {
+ info->cv8_cur_ls = STAILQ_LAST(&info->cv8_cur_li->linesets,
+ cv8_lineset, link);
+ goto done; /* found one */
+ }
+
+ /* Nope; find file */
+ for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+ if (strcmp(filename, dbgfmt_cv->filenames[i].filename) == 0)
+ break;
+ }
+ if (i >= dbgfmt_cv->filenames_size)
+ yasm_internal_error(N_("could not find filename in table"));
+
+ /* and create new lineinfo structure */
+ info->cv8_cur_li = yasm_xmalloc(sizeof(cv8_lineinfo));
+ info->cv8_cur_li->dbgfmt_cv = dbgfmt_cv;
+ info->cv8_cur_li->fn = &dbgfmt_cv->filenames[i];
+ info->cv8_cur_li->sect = sect;
+ sectbc = yasm_section_bcs_first(sect);
+ if (sectbc->symrecs && sectbc->symrecs[0])
+ info->cv8_cur_li->sectsym = sectbc->symrecs[0];
+ else {
+ sprintf(symname, ".%06u", info->num_lineinfos++);
+ info->cv8_cur_li->sectsym =
+ yasm_symtab_define_label(dbgfmt_cv->symtab, symname, sectbc,
+ 1, 0);
+ }
+ info->cv8_cur_li->num_linenums = 0;
+ STAILQ_INIT(&info->cv8_cur_li->linesets);
+ STAILQ_INSERT_TAIL(&info->cv8_lineinfos, info->cv8_cur_li, link);
+ info->cv8_cur_ls = NULL;
+ }
+ done:
+
+ /* build new lineset if necessary */
+ if (!info->cv8_cur_ls || info->cv8_cur_ls->num_pairs >= 126) {
+ info->cv8_cur_ls = yasm_xmalloc(sizeof(cv8_lineset));
+ info->cv8_cur_ls->num_pairs = 0;
+ STAILQ_INSERT_TAIL(&info->cv8_cur_li->linesets, info->cv8_cur_ls, link);
+ }
+
+ /* add linepair for this bytecode */
+ info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].offset = bc->offset;
+ info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].line =
+ 0x80000000 | line;
+ info->cv8_cur_ls->num_pairs++;
+ info->cv8_cur_li->num_linenums++;
+
+ return 0;
+ }
+
+ static int
+ cv_generate_line_section(yasm_section *sect, /*@null@*/ void *d)
+ {
+ cv_line_info *info = (cv_line_info *)d;
+
+ if (!yasm_section_is_code(sect))
+ return 0; /* not code, so no line data for this section */
+
+ info->cv8_cur_li = NULL;
+ info->cv8_cur_ls = NULL;
+
+ yasm_section_bcs_traverse(sect, info->errwarns, info, cv_generate_line_bc);
+
+ return 0;
+ }
+
+ static int
+ cv_generate_filename(const char *filename, void *d)
+ {
+ yasm_dbgfmt_cv *dbgfmt_cv = (yasm_dbgfmt_cv *)d;
+ cv_dbgfmt_add_file(dbgfmt_cv, 0, filename);
+ return 0;
+ }
+
+ static int
+ cv_generate_sym(yasm_symrec *sym, void *d)
+ {
+ cv_line_info *info = (cv_line_info *)d;
+ yasm_bytecode *precbc;
+
+ /* only care about labels (for now) */
+ if (!yasm_symrec_get_label(sym, &precbc))
+ return 0;
+
+ /* TODO: add data types; until then, just mark everything as UBYTE */
+ if (yasm_section_is_code(yasm_bc_get_section(precbc)))
+ cv8_add_sym_label(info->dbgfmt_cv, info->debug_symline, sym);
+ else
+ cv8_add_sym_data(info->dbgfmt_cv, info->debug_symline, 0x20, sym,
+ yasm_symrec_get_visibility(sym) & YASM_SYM_GLOBAL?1:0);
+ return 0;
+ }
+
+ yasm_section *
+ yasm_cv__generate_symline(yasm_dbgfmt_cv *dbgfmt_cv, yasm_errwarns *errwarns)
+ {
+ cv_line_info info;
+ int new;
+ size_t i;
+ cv8_symhead *head;
+ cv8_lineinfo *li;
+ yasm_bytecode *bc;
+ unsigned long off;
+
+ /* Generate filenames based on linemap */
+ yasm_linemap_traverse_filenames(dbgfmt_cv->linemap, dbgfmt_cv,
+ cv_generate_filename);
+
+ info.dbgfmt_cv = dbgfmt_cv;
+ info.errwarns = errwarns;
+ info.debug_symline = yasm_object_get_general(dbgfmt_cv->object,
+ ".debug$S", 0, 1, 0, 0, &new,
+ 0);
+ info.num_lineinfos = 0;
+ STAILQ_INIT(&info.cv8_lineinfos);
+ info.cv8_cur_li = NULL;
+ info.cv8_cur_ls = NULL;
+
+ /* source filenames string table */
+ head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_FILE_STRTAB, 1);
+ cv_append_str(info.debug_symline, "");
+ off = 1;
+ for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+ if (!dbgfmt_cv->filenames[i].pathname) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("codeview file number %d unassigned"), i+1);
+ yasm_errwarn_propagate(errwarns, 0);
+ continue;
+ }
+ bc = cv_append_str(info.debug_symline,
+ dbgfmt_cv->filenames[i].pathname);
+ dbgfmt_cv->filenames[i].str_off = off;
+ off += bc->len;
+ }
+ cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+
+ /* Align 4 */
+ bc = yasm_bc_create_align
+ (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0),
+ NULL, NULL, NULL, 0);
+ yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc));
- yasm_bc_resolve(bc, 0, NULL);
++ yasm_bc_calc_len(bc, NULL, NULL);
+
+ /* source file info table */
+ head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_FILE_INFO, 0);
+ off = 0;
+ for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+ if (!dbgfmt_cv->filenames[i].pathname)
+ continue;
+ bc = cv8_add_fileinfo(dbgfmt_cv, info.debug_symline,
+ &dbgfmt_cv->filenames[i]);
+ dbgfmt_cv->filenames[i].info_off = off;
+ off += bc->len;
+ }
+ cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+
+ /* Already aligned 4 */
+
+ /* Generate line numbers for sections */
+ yasm_object_sections_traverse(dbgfmt_cv->object, (void *)&info,
+ cv_generate_line_section);
+
+ /* Output line numbers for sections */
+ STAILQ_FOREACH(li, &info.cv8_lineinfos, link) {
+ head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_LINE_NUMS,
+ 0);
+ bc = yasm_bc_create_common(&cv8_lineinfo_bc_callback, li, 0);
+ bc->len = 24+li->num_linenums*8;
+ yasm_cv__append_bc(info.debug_symline, bc);
+ cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+ }
+
+ /* Already aligned 4 */
+
+ /* Output debugging symbols */
+ head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_DEBUG_SYMS, 0);
+ /* add object and compile flag first */
+ cv8_add_sym_objname(dbgfmt_cv, info.debug_symline,
+ yasm__abspath(yasm_object_get_object_fn(dbgfmt_cv->object)));
+ cv8_add_sym_compile(dbgfmt_cv, info.debug_symline,
+ yasm__xstrdup(PACKAGE_NAME " " PACKAGE_INTVER "."
+ PACKAGE_BUILD));
+ /* then iterate through symbol table */
+ yasm_symtab_traverse(dbgfmt_cv->symtab, &info, cv_generate_sym);
+ cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+
+ /* Align 4 at end */
+ bc = yasm_bc_create_align
+ (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0),
+ NULL, NULL, NULL, 0);
+ yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc));
-static yasm_bc_resolve_flags
-cv8_symhead_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ yasm_bc_calc_len(bc, NULL, NULL);
+
+ return info.debug_symline;
+ }
+
+ static void
+ cv_out_sym(yasm_symrec *sym, unsigned long off, yasm_bytecode *bc,
+ unsigned char **bufp, void *d, yasm_output_value_func output_value)
+ {
+ yasm_value val;
+
+ /* sym in its section */
+ yasm_value_init_sym(&val, sym, 32);
+ val.section_rel = 1;
+ output_value(&val, *bufp, 4, off, bc, 0, d);
+ *bufp += 4;
+
+ /* section index */
+ yasm_value_init_sym(&val, sym, 16);
+ val.seg_of = 1;
+ output_value(&val, *bufp, 2, off+4, bc, 0, d);
+ *bufp += 2;
+ }
+
+ static cv8_symhead *
+ cv8_add_symhead(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+ unsigned long type, int first)
+ {
+ cv8_symhead *head;
+ yasm_bytecode *bc;
+
+ head = yasm_xmalloc(sizeof(cv8_symhead));
+ head->dbgfmt_cv = dbgfmt_cv;
+ head->type = type;
+ head->first = first;
+ head->start_prevbc = yasm_section_bcs_last(sect);
+
+ bc = yasm_bc_create_common(&cv8_symhead_bc_callback, head, 0);
+ if (first)
+ bc->len = 12;
+ else
+ bc->len = 8;
+
+ head->end_prevbc = bc;
+ yasm_cv__append_bc(sect, bc);
+ return head;
+ }
+
+ static void
+ cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc)
+ {
+ head->end_prevbc = end_prevbc;
+ }
+
+ static void
+ cv8_symhead_bc_destroy(void *contents)
+ {
+ yasm_xfree(contents);
+ }
+
+ static void
+ cv8_symhead_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
- yasm_internal_error(N_("tried to resolve a codeview symhead bytecode"));
++static int
++cv8_symhead_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
- return YASM_BC_RESOLVE_MIN_LEN;
++ yasm_internal_error(N_("tried to calc_len a codeview symhead bytecode"));
+ /*@notreached@*/
-static yasm_bc_resolve_flags
-cv8_fileinfo_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ return 0;
+ }
+
+ static int
+ cv8_symhead_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+ {
+ cv8_symhead *head = (cv8_symhead *)bc->contents;
+ yasm_dbgfmt_cv *dbgfmt_cv = head->dbgfmt_cv;
+ unsigned char *buf = *bufp;
+ yasm_intnum *intn, *cval;
+
+ cval = yasm_intnum_create_uint(4);
+ /* Output "version" if first */
+ if (head->first) {
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+ buf += 4;
+ }
+
+ /* Type contained - 4 bytes */
+ yasm_intnum_set_uint(cval, head->type);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+ buf += 4;
+
+ /* Total length of info (following this field) - 4 bytes */
+ yasm_intnum_set_uint(cval, bc->len);
+ intn = yasm_common_calc_bc_dist(head->start_prevbc, head->end_prevbc);
+ yasm_intnum_calc(intn, YASM_EXPR_SUB, cval);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, intn, buf, 4, 32, 0, bc, 0);
+ buf += 4;
+ yasm_intnum_destroy(intn);
+
+ *bufp = buf;
+
+ yasm_intnum_destroy(cval);
+ return 0;
+ }
+
+ static yasm_bytecode *
+ cv8_add_fileinfo(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+ const cv_filename *fn)
+ {
+ cv8_fileinfo *fi;
+ yasm_bytecode *bc;
+
+ fi = yasm_xmalloc(sizeof(cv8_fileinfo));
+ fi->dbgfmt_cv = dbgfmt_cv;
+ fi->fn = fn;
+
+ bc = yasm_bc_create_common(&cv8_fileinfo_bc_callback, fi, 0);
+ bc->len = 24;
+
+ yasm_cv__append_bc(sect, bc);
+ return bc;
+ }
+
+ static void
+ cv8_fileinfo_bc_destroy(void *contents)
+ {
+ yasm_xfree(contents);
+ }
+
+ static void
+ cv8_fileinfo_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
- yasm_internal_error(N_("tried to resolve a codeview fileinfo bytecode"));
++static int
++cv8_fileinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
- return YASM_BC_RESOLVE_MIN_LEN;
++ yasm_internal_error(N_("tried to calc_len a codeview fileinfo bytecode"));
+ /*@notreached@*/
-static yasm_bc_resolve_flags
-cv8_lineinfo_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ return 0;
+ }
+
+ static int
+ cv8_fileinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+ {
+ cv8_fileinfo *fi = (cv8_fileinfo *)bc->contents;
+ yasm_dbgfmt_cv *dbgfmt_cv = fi->dbgfmt_cv;
+ unsigned char *buf = *bufp;
+ yasm_intnum *cval;
+ int i;
+
+ /* Offset in filename string table */
+ cval = yasm_intnum_create_uint(fi->fn->str_off);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+ buf += 4;
+
+ /* Checksum type/length */
+ yasm_intnum_set_uint(cval, 0x0110);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 0);
+ buf += 2;
+
+ /* Checksum */
+ for (i=0; i<16; i++)
+ YASM_WRITE_8(buf, fi->fn->digest[i]);
+
+ /* Pad */
+ YASM_WRITE_8(buf, 0);
+ YASM_WRITE_8(buf, 0);
+
+ *bufp = buf;
+
+ yasm_intnum_destroy(cval);
+ return 0;
+ }
+
+ static void
+ cv8_lineinfo_bc_destroy(void *contents)
+ {
+ cv8_lineinfo *li = (cv8_lineinfo *)contents;
+ cv8_lineset *ls1, *ls2;
+
+ /* delete line sets */
+ ls1 = STAILQ_FIRST(&li->linesets);
+ while (ls1) {
+ ls2 = STAILQ_NEXT(ls1, link);
+ yasm_xfree(ls1);
+ ls1 = ls2;
+ }
+
+ yasm_xfree(contents);
+ }
+
+ static void
+ cv8_lineinfo_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
- yasm_internal_error(N_("tried to resolve a codeview linehead bytecode"));
++static int
++cv8_lineinfo_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
- return YASM_BC_RESOLVE_MIN_LEN;
++ yasm_internal_error(N_("tried to calc_len a codeview linehead bytecode"));
+ /*@notreached@*/
-static yasm_bc_resolve_flags
-cv_sym_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ return 0;
+ }
+
+ static int
+ cv8_lineinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+ {
+ cv8_lineinfo *li = (cv8_lineinfo *)bc->contents;
+ yasm_dbgfmt_cv *dbgfmt_cv = li->dbgfmt_cv;
+ unsigned char *buf = *bufp;
+ yasm_intnum *cval;
+ unsigned long i;
+ cv8_lineset *ls;
+
+ /* start offset and section */
+ cv_out_sym(li->sectsym, 0, bc, &buf, d, output_value);
+
+ /* Two bytes of pad/alignment */
+ YASM_WRITE_8(buf, 0);
+ YASM_WRITE_8(buf, 0);
+
+ /* Section length covered by line number info */
+ cval = yasm_common_calc_bc_dist(yasm_section_bcs_first(li->sect),
+ yasm_section_bcs_last(li->sect));
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+ buf += 4;
+
+ /* Offset of source file in info table */
+ yasm_intnum_set_uint(cval, li->fn->info_off);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+ buf += 4;
+
+ /* Number of line number pairs */
+ yasm_intnum_set_uint(cval, li->num_linenums);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+ buf += 4;
+
+ /* Number of bytes of line number pairs + 12 (no, I don't know why) */
+ yasm_intnum_set_uint(cval, li->num_linenums*8+12);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0);
+ buf += 4;
+
+ /* Offset / line number pairs */
+ i = 0;
+ STAILQ_FOREACH(ls, &li->linesets, link) {
+ unsigned long j;
+ for (j=0; i<li->num_linenums && j<126; i++, j++) {
+ /* offset in section */
+ yasm_intnum_set_uint(cval, ls->pairs[j].offset);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc,
+ 0);
+ buf += 4;
+
+ /* line number in file */
+ yasm_intnum_set_uint(cval, ls->pairs[j].line);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc,
+ 0);
+ buf += 4;
+ }
+ }
+
+ *bufp = buf;
+
+ yasm_intnum_destroy(cval);
+ return 0;
+ }
+
+ static unsigned long
+ cv_sym_size(const cv_sym *cvs)
+ {
+ const char *ch = cvs->format;
+ unsigned long len = 4; /* sym length and type */
+ unsigned long slen;
+ int arg = 0;
+
+ while (*ch) {
+ switch (*ch) {
+ case 'b':
+ len++;
+ arg++;
+ break;
+ case 'h':
+ len += 2;
+ arg++;
+ break;
+ case 'w':
+ len += 4;
+ arg++;
+ break;
+ case 'Y':
+ len += 6; /* XXX: will be 4 in 16-bit version */
+ arg++;
+ break;
+ case 'T':
+ len += 4; /* XXX: will be 2 in CV4 */
+ arg++;
+ break;
+ case 'S':
+ len += 1; /* XXX: is this 1 or 2? */
+ slen = strlen((const char *)cvs->args[arg++].p);
+ len += slen <= 0xff ? slen : 0xff;
+ break;
+ case 'Z':
+ len += strlen((const char *)cvs->args[arg++].p) + 1;
+ break;
+ default:
+ yasm_internal_error(N_("unknown sym format character"));
+ }
+ ch++;
+ }
+
+ return len;
+ }
+
+ static void
+ cv_sym_bc_destroy(void *contents)
+ {
+ cv_sym *cvs = (cv_sym *)contents;
+ const char *ch = cvs->format;
+ int arg = 0;
+
+ while (*ch) {
+ switch (*ch) {
+ case 'b':
+ case 'h':
+ case 'w':
+ case 'Y':
+ case 'T':
+ arg++;
+ break; /* nothing to destroy */
+ case 'S':
+ case 'Z':
+ yasm_xfree(cvs->args[arg++].p);
+ break;
+ default:
+ yasm_internal_error(N_("unknown sym format character"));
+ }
+ ch++;
+ }
+
+ yasm_xfree(contents);
+ }
+
+ static void
+ cv_sym_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
- yasm_internal_error(N_("tried to resolve a codeview sym bytecode"));
++static int
++cv_sym_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
- return YASM_BC_RESOLVE_MIN_LEN;
++ yasm_internal_error(N_("tried to calc_len a codeview sym bytecode"));
+ /*@notreached@*/
++ return 0;
+ }
+
+ static int
+ cv_sym_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+ {
+ cv_sym *cvs = (cv_sym *)bc->contents;
+ yasm_dbgfmt_cv *dbgfmt_cv = cvs->dbgfmt_cv;
+ unsigned char *buf = *bufp;
+ yasm_intnum *cval;
+ const char *ch = cvs->format;
+ size_t len;
+ int arg = 0;
+
+ /* Total length of record (following this field) - 2 bytes */
+ cval = yasm_intnum_create_uint(bc->len-2);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 1);
+ buf += 2;
+
+ /* Type contained - 2 bytes */
+ yasm_intnum_set_uint(cval, cvs->type);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 0);
+ buf += 2;
+
+ while (*ch) {
+ switch (*ch) {
+ case 'b':
+ YASM_WRITE_8(buf, cvs->args[arg].i);
+ arg++;
+ break;
+ case 'h':
+ yasm_intnum_set_uint(cval, cvs->args[arg++].i);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0,
+ bc, 0);
+ buf += 2;
+ break;
+ case 'w':
+ yasm_intnum_set_uint(cval, cvs->args[arg++].i);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0,
+ bc, 0);
+ buf += 4;
+ break;
+ case 'Y':
+ cv_out_sym((yasm_symrec *)cvs->args[arg++].p,
+ (unsigned long)(buf-(*bufp)), bc, &buf, d,
+ output_value);
+ break;
+ case 'T':
+ yasm_intnum_set_uint(cval, cvs->args[arg++].i);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0,
+ bc, 0);
+ buf += 4; /* XXX: will be 2 in CV4 */
+ break;
+ case 'S':
+ len = strlen((char *)cvs->args[arg].p);
+ len = len <= 0xff ? len : 0xff;
+ YASM_WRITE_8(buf, len);
+ memcpy(buf, (char *)cvs->args[arg].p, len);
+ buf += len;
+ arg++;
+ break;
+ case 'Z':
+ len = strlen((char *)cvs->args[arg].p)+1;
+ memcpy(buf, (char *)cvs->args[arg].p, len);
+ buf += len;
+ arg++;
+ break;
+ default:
+ yasm_internal_error(N_("unknown leaf format character"));
+ }
+ ch++;
+ }
+
+ *bufp = buf;
+
+ yasm_intnum_destroy(cval);
+ return 0;
+ }
--- /dev/null
-static yasm_bc_resolve_flags cv_type_bc_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * CodeView debugging format - type information
+ *
+ * Copyright (C) 2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #include <util.h>
+ /*@unused@*/ RCSID("$Id$");
+
+ #define YASM_LIB_INTERNAL
+ #define YASM_BC_INTERNAL
+ #include <libyasm.h>
+
+ #include "cv-dbgfmt.h"
+
+ enum cv_reservedtype {
+ /* Bitfields representation - type */
+ CV_TYPE_SPECIAL = 0x00<<4, /* Special */
+ CV_TYPE_SIGNED = 0x01<<4, /* Signed integral value */
+ CV_TYPE_UNSIGNED = 0x02<<4, /* Unsigned integral value */
+ CV_TYPE_BOOLEAN = 0x03<<4, /* Boolean */
+ CV_TYPE_REAL = 0x04<<4, /* Real */
+ CV_TYPE_COMPLEX = 0x05<<4, /* Complex */
+ CV_TYPE_SPECIAL2 = 0x06<<4, /* Special2 */
+ CV_TYPE_REALINT = 0x07<<4, /* Really int value */
+
+ /* "size" of CV_TYPE_SPECIAL */
+ CV_SPECIAL_NOTYPE = 0x00<<0, /* No type */
+ CV_SPECIAL_ABS = 0x01<<0, /* Absolute symbol */
+ CV_SPECIAL_SEG = 0x02<<0, /* Segment */
+ CV_SPECIAL_VOID = 0x03<<0, /* Void */
+ CV_SPECIAL_CURRENCY = 0x04<<0, /* Basic 8-byte currency value */
+ CV_SPECIAL_NEARBSTR = 0x05<<0, /* Near Basic string */
+ CV_SPECIAL_FARBSTR = 0x06<<0, /* Far Basic string */
+
+ /* Size of CV_TYPE_SIGNED, CV_TYPE_UNSIGNED, and CV_TYPE_BOOLEAN */
+ CV_INTEGER_1BYTE = 0x00<<0, /* 1 byte */
+ CV_INTEGER_2BYTE = 0x01<<0, /* 2 byte */
+ CV_INTEGER_4BYTE = 0x02<<0, /* 4 byte */
+ CV_INTEGER_8BYTE = 0x03<<0, /* 8 byte */
+
+ /* Size of CV_TYPE_REAL and CV_TYPE_COMPLEX */
+ CV_REAL_32BIT = 0x00<<0, /* 32 bit */
+ CV_REAL_64BIT = 0x01<<0, /* 64 bit */
+ CV_REAL_80BIT = 0x02<<0, /* 80 bit */
+ CV_REAL_128BIT = 0x03<<0, /* 128 bit */
+ CV_REAL_48BIT = 0x04<<0, /* 48 bit */
+
+ /* "size" of CV_TYPE_SPECIAL2 */
+ CV_SPECIAL2_BIT = 0x00<<0, /* Bit */
+ CV_SPECIAL2_PASCHAR = 0x01<<0, /* Pascal CHAR */
+
+ /* Size of CV_TYPE_REALINT */
+ CV_REALINT_CHAR = 0x00<<0, /* Char */
+ CV_REALINT_WCHAR = 0x01<<0, /* Wide character */
+ CV_REALINT_S2BYTE = 0x02<<0, /* 2-byte signed integer */
+ CV_REALINT_U2BYTE = 0x03<<0, /* 2-byte unsigned integer */
+ CV_REALINT_S4BYTE = 0x04<<0, /* 4-byte signed integer */
+ CV_REALINT_U4BYTE = 0x05<<0, /* 4-byte unsigned integer */
+ CV_REALINT_S8BYTE = 0x06<<0, /* 8-byte signed integer */
+ CV_REALINT_U8BYTE = 0x07<<0, /* 8-byte unsigned integer */
+
+ /* Mode */
+ CV_MODE_DIRECT = 0x00<<8, /* Direct; not a pointer */
+ CV_MODE_NEAR = 0x01<<8, /* Near pointer */
+ CV_MODE_FAR = 0x02<<8, /* Far pointer */
+ CV_MODE_HUGE = 0x03<<8, /* Huge pointer */
+ CV_MODE_NEAR32 = 0x04<<8, /* 32-bit near pointer */
+ CV_MODE_FAR32 = 0x05<<8, /* 32-bit far pointer */
+ CV_MODE_NEAR64 = 0x06<<8, /* 64-bit near pointer */
+
+ /* Pure primitive type listing - based on above bitfields */
+
+ /* Special Types */
+ CV_T_NOTYPE = 0x0000, /* Uncharacterized type (no type) */
+ CV_T_ABS = 0x0001, /* Absolute symbol */
+ CV_T_SEGMENT = 0x0002, /* Segment type */
+ CV_T_VOID = 0x0003, /* Void */
+ CV_T_PVOID = 0x0103, /* Near pointer to void */
+ CV_T_PFVOID = 0x0203, /* Far pointer to void */
+ CV_T_PHVOID = 0x0303, /* Huge pointer to void */
+ CV_T_32PVOID = 0x0403, /* 32-bit near pointer to void */
+ CV_T_32PFVOID = 0x0503, /* 32-bit far pointer to void */
+ CV_T_CURRENCY = 0x0004, /* Basic 8-byte currency value */
+ CV_T_NBASICSTR = 0x0005, /* Near Basic string */
+ CV_T_FBASICSTR = 0x0006, /* Far Basic string */
+ CV_T_BIT = 0x0060, /* Bit */
+ CV_T_PASCHAR = 0x0061, /* Pascal CHAR */
+ /* Character Types */
+ CV_T_CHAR = 0x0010, /* 8-bit signed */
+ CV_T_UCHAR = 0x0020, /* 8-bit unsigned */
+ CV_T_PCHAR = 0x0110, /* Near pointer to 8-bit signed */
+ CV_T_PUCHAR = 0x0120, /* Near pointer to 8-bit unsigned */
+ CV_T_PFCHAR = 0x0210, /* Far pointer to 8-bit signed */
+ CV_T_PFUCHAR = 0x0220, /* Far pointer to 8-bit unsigned */
+ CV_T_PHCHAR = 0x0310, /* Huge pointer to 8-bit signed */
+ CV_T_PHUCHAR = 0x0320, /* Huge pointer to 8-bit unsigned */
+ CV_T_32PCHAR = 0x0410, /* 16:32 near pointer to 8-bit signed */
+ CV_T_32PUCHAR = 0x0420, /* 16:32 near pointer to 8-bit unsigned */
+ CV_T_32PFCHAR = 0x0510, /* 16:32 far pointer to 8-bit signed */
+ CV_T_32PFUCHAR = 0x0520, /* 16:32 far pointer to 8-bit unsigned */
+ /* Real Character Types */
+ CV_T_RCHAR = 0x0070, /* Real char */
+ CV_T_PRCHAR = 0x0170, /* Near pointer to a real char */
+ CV_T_PFRCHAR = 0x0270, /* Far pointer to a real char */
+ CV_T_PHRCHAR = 0x0370, /* Huge pointer to a real char */
+ CV_T_32PRCHAR = 0x0470, /* 16:32 near pointer to a real char */
+ CV_T_32PFRCHAR = 0x0570, /* 16:32 far pointer to a real char */
+ /* Wide Character Types */
+ CV_T_WCHAR = 0x0071, /* Wide char */
+ CV_T_PWCHAR = 0x0171, /* Near pointer to a wide char */
+ CV_T_PFWCHAR = 0x0271, /* Far pointer to a wide char */
+ CV_T_PHWCHAR = 0x0371, /* Huge pointer to a wide char */
+ CV_T_32PWCHAR = 0x0471, /* 16:32 near pointer to a wide char */
+ CV_T_32PFWCHAR = 0x0571, /* 16:32 far pointer to a wide char */
+ /* Real 16-bit Integer Types */
+ CV_T_INT2 = 0x0072, /* Real 16-bit signed int */
+ CV_T_UINT2 = 0x0073, /* Real 16-bit unsigned int */
+ CV_T_PINT2 = 0x0172, /* Near pointer to 16-bit signed int */
+ CV_T_PUINT2 = 0x0173, /* Near pointer to 16-bit unsigned int */
+ CV_T_PFINT2 = 0x0272, /* Far pointer to 16-bit signed int */
+ CV_T_PFUINT2 = 0x0273, /* Far pointer to 16-bit unsigned int */
+ CV_T_PHINT2 = 0x0372, /* Huge pointer to 16-bit signed int */
+ CV_T_PHUINT2 = 0x0373, /* Huge pointer to 16-bit unsigned int */
+ CV_T_32PINT2 = 0x0472, /* 16:32 near pointer to 16-bit signed int */
+ CV_T_32PUINT2 = 0x0473, /* 16:32 near pointer to 16-bit unsigned int */
+ CV_T_32PFINT2 = 0x0572, /* 16:32 far pointer to 16-bit signed int */
+ CV_T_32PFUINT2 = 0x0573, /* 16:32 far pointer to 16-bit unsigned int */
+ /* 16-bit Short Types */
+ CV_T_SHORT = 0x0011, /* 16-bit signed */
+ CV_T_USHORT = 0x0021, /* 16-bit unsigned */
+ CV_T_PSHORT = 0x0111, /* Near pointer to 16-bit signed */
+ CV_T_PUSHORT = 0x0121, /* Near pointer to 16-bit unsigned */
+ CV_T_PFSHORT = 0x0211, /* Far pointer to 16-bit signed */
+ CV_T_PFUSHORT = 0x0221, /* Far pointer to 16-bit unsigned */
+ CV_T_PHSHORT = 0x0311, /* Huge pointer to 16-bit signed */
+ CV_T_PHUSHORT = 0x0321, /* Huge pointer to 16-bit unsigned */
+ CV_T_32PSHORT = 0x0411, /* 16:32 near pointer to 16-bit signed */
+ CV_T_32PUSHORT = 0x0421, /* 16:32 near pointer to 16-bit unsigned */
+ CV_T_32PFSHORT = 0x0511, /* 16:32 far pointer to 16-bit signed */
+ CV_T_32PFUSHORT = 0x0521, /* 16:32 far pointer to 16-bit unsigned */
+ /* Real 32-bit Integer Types */
+ CV_T_INT4 = 0x0074, /* Real 32-bit signed int */
+ CV_T_UINT4 = 0x0075, /* Real 32-bit unsigned int */
+ CV_T_PINT4 = 0x0174, /* Near pointer to 32-bit signed int */
+ CV_T_PUINT4 = 0x0175, /* Near pointer to 32-bit unsigned int */
+ CV_T_PFINT4 = 0x0274, /* Far pointer to 32-bit signed int */
+ CV_T_PFUINT4 = 0x0275, /* Far pointer to 32-bit unsigned int */
+ CV_T_PHINT4 = 0x0374, /* Huge pointer to 32-bit signed int */
+ CV_T_PHUINT4 = 0x0375, /* Huge pointer to 32-bit unsigned int */
+ CV_T_32PINT4 = 0x0474, /* 16:32 near pointer to 32-bit signed int */
+ CV_T_32PUINT4 = 0x0475, /* 16:32 near pointer to 32-bit unsigned int */
+ CV_T_32PFINT4 = 0x0574, /* 16:32 far pointer to 32-bit signed int */
+ CV_T_32PFUINT4 = 0x0575, /* 16:32 far pointer to 32-bit unsigned int */
+ /* 32-bit Long Types */
+ CV_T_LONG = 0x0012, /* 32-bit signed */
+ CV_T_ULONG = 0x0022, /* 32-bit unsigned */
+ CV_T_PLONG = 0x0112, /* Near pointer to 32-bit signed */
+ CV_T_PULONG = 0x0122, /* Near pointer to 32-bit unsigned */
+ CV_T_PFLONG = 0x0212, /* Far pointer to 32-bit signed */
+ CV_T_PFULONG = 0x0222, /* Far pointer to 32-bit unsigned */
+ CV_T_PHLONG = 0x0312, /* Huge pointer to 32-bit signed */
+ CV_T_PHULONG = 0x0322, /* Huge pointer to 32-bit unsigned */
+ CV_T_32PLONG = 0x0412, /* 16:32 near pointer to 32-bit signed */
+ CV_T_32PULONG = 0x0422, /* 16:32 near pointer to 32-bit unsigned */
+ CV_T_32PFLONG = 0x0512, /* 16:32 far pointer to 32-bit signed */
+ CV_T_32PFULONG = 0x0522, /* 16:32 far pointer to 32-bit unsigned */
+ /* Real 64-bit int Types */
+ CV_T_INT8 = 0x0076, /* 64-bit signed int */
+ CV_T_UINT8 = 0x0077, /* 64-bit unsigned int */
+ CV_T_PINT8 = 0x0176, /* Near pointer to 64-bit signed int */
+ CV_T_PUINT8 = 0x0177, /* Near pointer to 64-bit unsigned int */
+ CV_T_PFINT8 = 0x0276, /* Far pointer to 64-bit signed int */
+ CV_T_PFUINT8 = 0x0277, /* Far pointer to 64-bit unsigned int */
+ CV_T_PHINT8 = 0x0376, /* Huge pointer to 64-bit signed int */
+ CV_T_PHUINT8 = 0x0377, /* Huge pointer to 64-bit unsigned int */
+ CV_T_32PINT8 = 0x0476, /* 16:32 near pointer to 64-bit signed int */
+ CV_T_32PUINT8 = 0x0477, /* 16:32 near pointer to 64-bit unsigned int */
+ CV_T_32PFINT8 = 0x0576, /* 16:32 far pointer to 64-bit signed int */
+ CV_T_32PFUINT8 = 0x0577, /* 16:32 far pointer to 64-bit unsigned int */
+ /* 64-bit Integral Types */
+ CV_T_QUAD = 0x0013, /* 64-bit signed */
+ CV_T_UQUAD = 0x0023, /* 64-bit unsigned */
+ CV_T_PQUAD = 0x0113, /* Near pointer to 64-bit signed */
+ CV_T_PUQUAD = 0x0123, /* Near pointer to 64-bit unsigned */
+ CV_T_PFQUAD = 0x0213, /* Far pointer to 64-bit signed */
+ CV_T_PFUQUAD = 0x0223, /* Far pointer to 64-bit unsigned */
+ CV_T_PHQUAD = 0x0313, /* Huge pointer to 64-bit signed */
+ CV_T_PHUQUAD = 0x0323, /* Huge pointer to 64-bit unsigned */
+ CV_T_32PQUAD = 0x0413, /* 16:32 near pointer to 64-bit signed */
+ CV_T_32PUQUAD = 0x0423, /* 16:32 near pointer to 64-bit unsigned */
+ CV_T_32PFQUAD = 0x0513, /* 16:32 far pointer to 64-bit signed */
+ CV_T_32PFUQUAD = 0x0523, /* 16:32 far pointer to 64-bit unsigned */
+ /* 32-bit Real Types */
+ CV_T_REAL32 = 0x0040, /* 32-bit real */
+ CV_T_PREAL32 = 0x0140, /* Near pointer to 32-bit real */
+ CV_T_PFREAL32 = 0x0240, /* Far pointer to 32-bit real */
+ CV_T_PHREAL32 = 0x0340, /* Huge pointer to 32-bit real */
+ CV_T_32PREAL32 = 0x0440, /* 16:32 near pointer to 32-bit real */
+ CV_T_32PFREAL32 = 0x0540, /* 16:32 far pointer to 32-bit real */
+ /* 48-bit Real Types */
+ CV_T_REAL48 = 0x0044, /* 48-bit real */
+ CV_T_PREAL48 = 0x0144, /* Near pointer to 48-bit real */
+ CV_T_PFREAL48 = 0x0244, /* Far pointer to 48-bit real */
+ CV_T_PHREAL48 = 0x0344, /* Huge pointer to 48-bit real */
+ CV_T_32PREAL48 = 0x0444, /* 16:32 near pointer to 48-bit real */
+ CV_T_32PFREAL48 = 0x0544, /* 16:32 far pointer to 48-bit real */
+ /* 64-bit Real Types */
+ CV_T_REAL64 = 0x0041, /* 64-bit real */
+ CV_T_PREAL64 = 0x0141, /* Near pointer to 64-bit real */
+ CV_T_PFREAL64 = 0x0241, /* Far pointer to 64-bit real */
+ CV_T_PHREAL64 = 0x0341, /* Huge pointer to 64-bit real */
+ CV_T_32PREAL64 = 0x0441, /* 16:32 near pointer to 64-bit real */
+ CV_T_32PFREAL64 = 0x0541, /* 16:32 far pointer to 64-bit real */
+ /* 80-bit Real Types */
+ CV_T_REAL80 = 0x0042, /* 80-bit real */
+ CV_T_PREAL80 = 0x0142, /* Near pointer to 80-bit real */
+ CV_T_PFREAL80 = 0x0242, /* Far pointer to 80-bit real */
+ CV_T_PHREAL80 = 0x0342, /* Huge pointer to 80-bit real */
+ CV_T_32PREAL80 = 0x0442, /* 16:32 near pointer to 80-bit real */
+ CV_T_32PFREAL80 = 0x0542, /* 16:32 far pointer to 80-bit real */
+ /* 128-bit Real Types */
+ CV_T_REAL128 = 0x0043, /* 128-bit real */
+ CV_T_PREAL128 = 0x0143, /* Near pointer to 128-bit real */
+ CV_T_PFREAL128 = 0x0243, /* Far pointer to 128-bit real */
+ CV_T_PHREAL128 = 0x0343, /* Huge pointer to 128-bit real */
+ CV_T_32PREAL128 = 0x0443, /* 16:32 near pointer to 128-bit real */
+ CV_T_32PFREAL128 = 0x0543, /* 16:32 far pointer to 128-bit real */
+ /* 32-bit Complex Types */
+ CV_T_CPLX32 = 0x0050, /* 32-bit complex */
+ CV_T_PCPLX32 = 0x0150, /* Near pointer to 32-bit complex */
+ CV_T_PFCPLX32 = 0x0250, /* Far pointer to 32-bit complex */
+ CV_T_PHCPLX32 = 0x0350, /* Huge pointer to 32-bit complex */
+ CV_T_32PCPLX32 = 0x0450, /* 16:32 near pointer to 32-bit complex */
+ CV_T_32PFCPLX32 = 0x0550, /* 16:32 far pointer to 32-bit complex */
+ /* 64-bit Complex Types */
+ CV_T_CPLX64 = 0x0051, /* 64-bit complex */
+ CV_T_PCPLX64 = 0x0151, /* Near pointer to 64-bit complex */
+ CV_T_PFCPLX64 = 0x0251, /* Far pointer to 64-bit complex */
+ CV_T_PHCPLX64 = 0x0351, /* Huge pointer to 64-bit complex */
+ CV_T_32PCPLX64 = 0x0451, /* 16:32 near pointer to 64-bit complex */
+ CV_T_32PFCPLX64 = 0x0551, /* 16:32 far pointer to 64-bit complex */
+ /* 80-bit Complex Types */
+ CV_T_CPLX80 = 0x0052, /* 80-bit complex */
+ CV_T_PCPLX80 = 0x0152, /* Near pointer to 80-bit complex */
+ CV_T_PFCPLX80 = 0x0252, /* Far pointer to 80-bit complex */
+ CV_T_PHCPLX80 = 0x0352, /* Huge pointer to 80-bit complex */
+ CV_T_32PCPLX80 = 0x0452, /* 16:32 near pointer to 80-bit complex */
+ CV_T_32PFCPLX80 = 0x0552, /* 16:32 far pointer to 80-bit complex */
+ /* 128-bit Complex Types */
+ CV_T_CPLX128 = 0x0053, /* 128-bit complex */
+ CV_T_PCPLX128 = 0x0153, /* Near pointer to 128-bit complex */
+ CV_T_PFCPLX128 = 0x0253, /* Far pointer to 128-bit complex */
+ CV_T_PHCPLX128 = 0x0353, /* Huge pointer to 128-bit real */
+ CV_T_32PCPLX128 = 0x0453, /* 16:32 near pointer to 128-bit complex */
+ CV_T_32PFCPLX128 = 0x0553, /* 16:32 far pointer to 128-bit complex */
+ /* Boolean Types */
+ CV_T_BOOL08 = 0x0030, /* 8-bit Boolean */
+ CV_T_BOOL16 = 0x0031, /* 16-bit Boolean */
+ CV_T_BOOL32 = 0x0032, /* 32-bit Boolean */
+ CV_T_BOOL64 = 0x0033, /* 64-bit Boolean */
+ CV_T_PBOOL08 = 0x0130, /* Near pointer to 8-bit Boolean */
+ CV_T_PBOOL16 = 0x0131, /* Near pointer to 16-bit Boolean */
+ CV_T_PBOOL32 = 0x0132, /* Near pointer to 32-bit Boolean */
+ CV_T_PBOOL64 = 0x0133, /* Near pointer to 64-bit Boolean */
+ CV_T_PFBOOL08 = 0x0230, /* Far pointer to 8-bit Boolean */
+ CV_T_PFBOOL16 = 0x0231, /* Far pointer to 16-bit Boolean */
+ CV_T_PFBOOL32 = 0x0232, /* Far pointer to 32-bit Boolean */
+ CV_T_PFBOOL64 = 0x0233, /* Far pointer to 64-bit Boolean */
+ CV_T_PHBOOL08 = 0x0330, /* Huge pointer to 8-bit Boolean */
+ CV_T_PHBOOL16 = 0x0331, /* Huge pointer to 16-bit Boolean */
+ CV_T_PHBOOL32 = 0x0332, /* Huge pointer to 32-bit Boolean */
+ CV_T_PHBOOL64 = 0x0333, /* Huge pointer to 64-bit Boolean */
+ CV_T_32PBOOL08 = 0x0430, /* 16:32 near pointer to 8-bit Boolean */
+ CV_T_32PBOOL16 = 0x0431, /* 16:32 near pointer to 16-bit Boolean */
+ CV_T_32PBOOL32 = 0x0432, /* 16:32 near pointer to 32-bit Boolean */
+ CV_T_32PBOOL64 = 0x0433, /* 16:32 near pointer to 64-bit Boolean */
+ CV_T_32PFBOOL08 = 0x0530, /* 16:32 far pointer to 8-bit Boolean */
+ CV_T_32PFBOOL16 = 0x0531, /* 16:32 far pointer to 16-bit Boolean */
+ CV_T_32PFBOOL32 = 0x0532, /* 16:32 far pointer to 32-bit Boolean */
+ CV_T_32PFBOOL64 = 0x0533, /* 16:32 far pointer to 64-bit Boolean */
+
+ /* Non-primitive types are stored in the TYPES section (generated in
+ * cv-type.c) and start at this index (e.g. 0x1000 is the first type
+ * in TYPES, 0x1001 the second, etc.
+ */
+ CV_FIRST_NONPRIM = 0x1000
+ };
+
+ enum cv_leaftype {
+ /* Leaf indices for type records that can be referenced from symbols */
+ CV4_LF_MODIFIER = 0x0001, /* Type Modifier */
+ CV4_LF_POINTER = 0x0002, /* Pointer */
+ CV4_LF_ARRAY = 0x0003, /* Simple Array */
+ CV4_LF_CLASS = 0x0004, /* Classes */
+ CV4_LF_STRUCTURE = 0x0005, /* Structures */
+ CV4_LF_UNION = 0x0006, /* Unions */
+ CV4_LF_ENUM = 0x0007, /* Enumeration */
+ CV4_LF_PROCEDURE = 0x0008, /* Procedure */
+ CV4_LF_MFUNCTION = 0x0009, /* Member Function */
+ CV4_LF_VTSHAPE = 0x000a, /* Virtual Function Table Shape */
+ CV4_LF_BARRAY = 0x000d, /* Basic Array */
+ CV4_LF_LABEL = 0x000e, /* Label */
+ CV4_LF_NULL = 0x000f, /* Null */
+ CV4_LF_DIMARRAY = 0x0011, /* Multiply Dimensioned Array */
+ CV4_LF_VFTPATH = 0x0012, /* Path to Virtual Function Table */
+ CV4_LF_PRECOMP = 0x0013, /* Reference Precompiled Types */
+ CV4_LF_ENDPRECOMP = 0x0014, /* End of Precompiled Types */
+
+ /* CodeView 5.0 version */
+ CV5_LF_MODIFIER = 0x1001, /* Type Modifier */
+ CV5_LF_POINTER = 0x1002, /* Pointer */
+ CV5_LF_ARRAY = 0x1003, /* Simple Array */
+ CV5_LF_CLASS = 0x1004, /* Classes */
+ CV5_LF_STRUCTURE = 0x1005, /* Structures */
+ CV5_LF_UNION = 0x1006, /* Unions */
+ CV5_LF_ENUM = 0x1007, /* Enumeration */
+ CV5_LF_PROCEDURE = 0x1008, /* Procedure */
+ CV5_LF_MFUNCTION = 0x1009, /* Member Function */
+ CV5_LF_VTSHAPE = 0x000a, /* Virtual Function Table Shape */
+ CV5_LF_BARRAY = 0x100d, /* Basic Array */
+ CV5_LF_LABEL = 0x000e, /* Label */
+ CV5_LF_NULL = 0x000f, /* Null */
+ CV5_LF_DIMARRAY = 0x100c, /* Multiply Dimensioned Array */
+ CV5_LF_VFTPATH = 0x100d, /* Path to Virtual Function Table */
+ CV5_LF_PRECOMP = 0x100e, /* Reference Precompiled Types */
+ CV5_LF_ENDPRECOMP = 0x0014, /* End of Precompiled Types */
+ CV5_LF_TYPESERVER = 0x0016, /* Reference Typeserver */
+
+ /* Leaf indices for type records that can be referenced from other type
+ * records
+ */
+ CV4_LF_SKIP = 0x0200, /* Skip */
+ CV4_LF_ARGLIST = 0x0201, /* Argument List */
+ CV4_LF_DEFARG = 0x0202, /* Default Argument */
+ CV4_LF_LIST = 0x0203, /* Arbitrary List */
+ CV4_LF_FIELDLIST = 0x0204, /* Field List */
+ CV4_LF_DERIVED = 0x0205, /* Derived Classes */
+ CV4_LF_BITFIELD = 0x0206, /* Bit Fields */
+ CV4_LF_METHODLIST = 0x0207, /* Method List */
+ CV4_LF_DIMCONU = 0x0208, /* Dimensioned Array with Constant Upper Bound */
+ CV4_LF_DIMCONLU = 0x0209, /* Dimensioned Array with Constant Lower and Upper Bounds */
+ CV4_LF_DIMVARU = 0x020a, /* Dimensioned Array with Variable Upper Bound */
+ CV4_LF_DIMVARLU = 0x020b, /* Dimensioned Array with Variable Lower and Upper Bounds */
+ CV4_LF_REFSYM = 0x020c, /* Referenced Symbol */
+
+ /* CodeView 5.0 version */
+ CV5_LF_SKIP = 0x1200, /* Skip */
+ CV5_LF_ARGLIST = 0x1201, /* Argument List */
+ CV5_LF_DEFARG = 0x1202, /* Default Argument */
+ CV5_LF_FIELDLIST = 0x1203, /* Field List */
+ CV5_LF_DERIVED = 0x1204, /* Derived Classes */
+ CV5_LF_BITFIELD = 0x1205, /* Bit Fields */
+ CV5_LF_METHODLIST = 0x1206, /* Method List */
+ CV5_LF_DIMCONU = 0x1207, /* Dimensioned Array with Constant Upper Bound */
+ CV5_LF_DIMCONLU = 0x1208, /* Dimensioned Array with Constant Lower and Upper Bounds */
+ CV5_LF_DIMVARU = 0x1209, /* Dimensioned Array with Variable Upper Bound */
+ CV5_LF_DIMVARLU = 0x120a, /* Dimensioned Array with Variable Lower and Upper Bounds */
+ CV5_LF_REFSYM = 0x020c, /* Referenced Symbol */
+
+ /* Leaf indices for fields of complex lists */
+ CV4_LF_BCLASS = 0x0400, /* Real Base Class */
+ CV4_LF_VBCLASS = 0x0401, /* Direct Virtual Base Class */
+ CV4_LF_IVBCLASS = 0x0402, /* Indirect Virtual Base Class */
+ CV4_LF_ENUMERATE = 0x0403, /* Enumeration Name and Value */
+ CV4_LF_FRIENDFCN = 0x0404, /* Friend Function */
+ CV4_LF_INDEX = 0x0405, /* Index To Another Type Record */
+ CV4_LF_MEMBER = 0x0406, /* Data Member */
+ CV4_LF_STMEMBER = 0x0407, /* Static Data Member */
+ CV4_LF_METHOD = 0x0408, /* Method */
+ CV4_LF_NESTTYPE = 0x0409, /* Nested Type Definition */
+ CV4_LF_VFUNCTAB = 0x040a, /* Virtual Function Table Pointer */
+ CV4_LF_FRIENDCLS = 0x040b, /* Friend Class */
+ CV4_LF_ONEMETHOD = 0x040c, /* One Method */
+ CV4_LF_VFUNCOFF = 0x040d, /* Virtual Function Offset */
+
+ /* CodeView 5.0 version */
+ CV5_LF_BCLASS = 0x1400, /* Real Base Class */
+ CV5_LF_VBCLASS = 0x1401, /* Direct Virtual Base Class */
+ CV5_LF_IVBCLASS = 0x1402, /* Indirect Virtual Base Class */
+ CV5_LF_ENUMERATE = 0x0403, /* Enumeration Name and Value */
+ CV5_LF_FRIENDFCN = 0x1403, /* Friend Function */
+ CV5_LF_INDEX = 0x1404, /* Index To Another Type Record */
+ CV5_LF_MEMBER = 0x1405, /* Data Member */
+ CV5_LF_STMEMBER = 0x1406, /* Static Data Member */
+ CV5_LF_METHOD = 0x1407, /* Method */
+ CV5_LF_NESTTYPE = 0x1408, /* Nested Type Definition */
+ CV5_LF_VFUNCTAB = 0x1409, /* Virtual Function Table Pointer */
+ CV5_LF_FRIENDCLS = 0x140a, /* Friend Class */
+ CV5_LF_ONEMETHOD = 0x140b, /* One Method */
+ CV5_LF_VFUNCOFF = 0x140c, /* Virtual Function Offset */
+ CV5_LF_NESTTYPEEX = 0x140d, /* Nested Type Extended Definition */
+ CV5_LF_MEMBERMODIFY = 0x140e, /* Member Modification */
+ /* XXX: CodeView 5.0 spec also lists 0x040f as LF_MEMBERMODIFY? */
+
+ /* Leaf indices for numeric fields of symbols and type records */
+ CV_LF_NUMERIC = 0x8000,
+ CV_LF_CHAR = 0x8000, /* Signed Char (8-bit) */
+ CV_LF_SHORT = 0x8001, /* Signed Short (16-bit) */
+ CV_LF_USHORT = 0x8002, /* Unsigned Short (16-bit) */
+ CV_LF_LONG = 0x8003, /* Signed Long (32-bit) */
+ CV_LF_ULONG = 0x8004, /* Unsigned Long (32-bit) */
+ CV_LF_REAL32 = 0x8005, /* 32-bit Float */
+ CV_LF_REAL64 = 0x8006, /* 64-bit Float */
+ CV_LF_REAL80 = 0x8007, /* 80-bit Float */
+ CV_LF_REAL128 = 0x8008, /* 128-bit Float */
+ CV_LF_QUADWORD = 0x8009, /* Signed Quad Word (64-bit) */
+ CV_LF_UQUADWORD = 0x800a, /* Unsigned Quad Word (64-bit) */
+ CV_LF_REAL48 = 0x800b, /* 48-bit Float */
+ CV_LF_COMPLEX32 = 0x800c, /* 32-bit Complex */
+ CV_LF_COMPLEX64 = 0x800d, /* 64-bit Complex */
+ CV_LF_COMPLEX80 = 0x800e, /* 80-bit Complex */
+ CV_LF_COMPLEX128 = 0x800f, /* 128-bit Complex */
+ CV_LF_VARSTRING = 0x8010, /* Variable-length String */
+
+ /* Leaf padding bytes */
+ CV_LF_PAD0 = 0xf0,
+ CV_LF_PAD1 = 0xf1,
+ CV_LF_PAD2 = 0xf2,
+ CV_LF_PAD3 = 0xf3,
+ CV_LF_PAD4 = 0xf4,
+ CV_LF_PAD5 = 0xf5,
+ CV_LF_PAD6 = 0xf6,
+ CV_LF_PAD7 = 0xf7,
+ CV_LF_PAD8 = 0xf8,
+ CV_LF_PAD9 = 0xf9,
+ CV_LF_PAD10 = 0xfa,
+ CV_LF_PAD11 = 0xfb,
+ CV_LF_PAD12 = 0xfc,
+ CV_LF_PAD13 = 0xfc,
+ CV_LF_PAD14 = 0xfe,
+ CV_LF_PAD15 = 0xff
+ };
+
+ /* Leaves use a bit of meta-programming to encode formats: each character
+ * of format represents the output generated, as follows:
+ * 'b' : 1 byte value (integer)
+ * 'h' : 2 byte value (integer)
+ * 'w' : 4 byte value (integer)
+ * 'L' : subleaf, recurses into cv_leaf (pointer)
+ * 'T' : 4 byte type index, pulls cv_type.index from cv_type (pointer)
+ * 'S' : length-prefixed string (pointer)
+ */
+ typedef struct cv_leaf {
+ enum cv_leaftype type;
+ const char *format; /* format of args */
+ union {
+ unsigned long i;
+ void *p;
+ } args[6];
+ } cv_leaf;
+
+ typedef struct cv_type {
+ yasm_dbgfmt_cv *dbgfmt_cv;
+ unsigned long indx; /* type # (must be same as output order) */
+ size_t num_leaves;
+ /*@null@*/ /*@only@*/ cv_leaf **leaves;
+ } cv_type;
+
+ /* Bytecode callback function prototypes */
+ static void cv_type_bc_destroy(void *contents);
+ static void cv_type_bc_print(const void *contents, FILE *f, int indent_level);
- cv_type_bc_resolve,
++static int cv_type_bc_calc_len
++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int cv_type_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ /* Bytecode callback structures */
+ static const yasm_bytecode_callback cv_type_bc_callback = {
+ cv_type_bc_destroy,
+ cv_type_bc_print,
+ yasm_bc_finalize_common,
- yasm_bc_resolve(bc, 0, NULL);
++ cv_type_bc_calc_len,
++ yasm_bc_expand_common,
+ cv_type_bc_tobytes,
+ 0
+ };
+
+ static cv_type *cv_type_create(yasm_dbgfmt_cv *dbgfmt_cv, unsigned long indx);
+ static void cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf);
+
+
+ static cv_leaf *
+ cv_leaf_create_label(int is_far)
+ {
+ cv_leaf *leaf = yasm_xmalloc(sizeof(cv_leaf));
+ leaf->type = CV5_LF_LABEL;
+ leaf->format = "h";
+ leaf->args[0].i = is_far ? 4 : 0;
+ return leaf;
+ }
+
+ yasm_section *
+ yasm_cv__generate_type(yasm_dbgfmt_cv *dbgfmt_cv)
+ {
+ int new;
+ unsigned long indx = CV_FIRST_NONPRIM;
+ yasm_section *debug_type;
+ yasm_bytecode *bc;
+ cv_type *type;
+
+ debug_type = yasm_object_get_general(dbgfmt_cv->object, ".debug$T", 0, 1,
+ 0, 0, &new, 0);
+
+ /* Add label type */
+ type = cv_type_create(dbgfmt_cv, indx++);
+ cv_type_append_leaf(type, cv_leaf_create_label(0));
+ bc = yasm_bc_create_common(&cv_type_bc_callback, type, 0);
+ yasm_bc_finalize(bc, yasm_cv__append_bc(debug_type, bc));
-static yasm_bc_resolve_flags
-cv_type_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ yasm_bc_calc_len(bc, NULL, NULL);
+
+ return debug_type;
+ }
+
+ static void
+ cv_leaf_destroy(cv_leaf *leaf)
+ {
+ const char *ch = leaf->format;
+ int arg = 0;
+
+ while (*ch) {
+ switch (*ch) {
+ case 'b':
+ case 'h':
+ case 'w':
+ arg++;
+ break; /* nothing to destroy */
+ case 'L':
+ cv_leaf_destroy((cv_leaf *)leaf->args[arg++].p);
+ break;
+ case 'T':
+ arg++; /* nothing to destroy */
+ break;
+ case 'S':
+ yasm_xfree(leaf->args[arg++].p);
+ break;
+ default:
+ yasm_internal_error(N_("unknown leaf format character"));
+ }
+ ch++;
+ }
+ }
+
+ static unsigned long
+ cv_leaf_size(const cv_leaf *leaf)
+ {
+ const char *ch = leaf->format;
+ unsigned long len = 2; /* leaf type */
+ unsigned long slen;
+ int arg = 0;
+
+ while (*ch) {
+ switch (*ch) {
+ case 'b':
+ len++;
+ arg++;
+ break;
+ case 'h':
+ len += 2;
+ arg++;
+ break;
+ case 'w':
+ len += 4;
+ arg++;
+ break;
+ case 'L':
+ len += cv_leaf_size((const cv_leaf *)leaf->args[arg++].p);
+ break;
+ case 'T':
+ len += 4; /* XXX: will be 2 in CV4 */
+ arg++;
+ break;
+ case 'S':
+ len += 1; /* XXX: is this 1 or 2? */
+ slen = strlen((const char *)leaf->args[arg++].p);
+ len += slen <= 0xff ? slen : 0xff;
+ break;
+ default:
+ yasm_internal_error(N_("unknown leaf format character"));
+ }
+ ch++;
+ }
+
+ return len;
+ }
+
+ static void
+ cv_leaf_tobytes(const cv_leaf *leaf, yasm_bytecode *bc, yasm_arch *arch,
+ unsigned char **bufp, yasm_intnum *cval)
+ {
+ unsigned char *buf = *bufp;
+ const char *ch = leaf->format;
+ size_t len;
+ int arg = 0;
+
+ /* leaf type */
+ yasm_intnum_set_uint(cval, leaf->type);
+ yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0);
+ buf += 2;
+
+ while (*ch) {
+ switch (*ch) {
+ case 'b':
+ YASM_WRITE_8(buf, leaf->args[arg].i);
+ arg++;
+ break;
+ case 'h':
+ yasm_intnum_set_uint(cval, leaf->args[arg++].i);
+ yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0);
+ buf += 2;
+ break;
+ case 'w':
+ yasm_intnum_set_uint(cval, leaf->args[arg++].i);
+ yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0);
+ buf += 4;
+ break;
+ case 'L':
+ cv_leaf_tobytes((const cv_leaf *)leaf->args[arg++].p, bc, arch,
+ &buf, cval);
+ break;
+ case 'T':
+ yasm_intnum_set_uint(cval,
+ ((const cv_type *)leaf->args[arg++].p)->indx);
+ yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0);
+ buf += 4; /* XXX: will be 2 in CV4 */
+ break;
+ case 'S':
+ len = strlen((const char *)leaf->args[arg].p);
+ len = len <= 0xff ? len : 0xff;
+ YASM_WRITE_8(buf, len);
+ memcpy(buf, (const char *)leaf->args[arg].p, len);
+ buf += len;
+ arg++;
+ break;
+ default:
+ yasm_internal_error(N_("unknown leaf format character"));
+ }
+ ch++;
+ }
+
+ *bufp = buf;
+ }
+
+ static cv_type *
+ cv_type_create(yasm_dbgfmt_cv *dbgfmt_cv, unsigned long indx)
+ {
+ cv_type *type = yasm_xmalloc(sizeof(cv_type));
+
+ type->dbgfmt_cv = dbgfmt_cv;
+ type->indx = indx;
+ type->num_leaves = 0;
+ type->leaves = NULL;
+
+ return type;
+ }
+
+ static void
+ cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf)
+ {
+ type->num_leaves++;
+
+ /* This is inefficient for large numbers of leaves, but that won't happen
+ * until we add structure support.
+ */
+ type->leaves = yasm_xrealloc(type->leaves,
+ type->num_leaves*sizeof(cv_leaf *));
+
+ type->leaves[type->num_leaves-1] = leaf;
+ }
+
+ static void
+ cv_type_bc_destroy(void *contents)
+ {
+ cv_type *type = (cv_type *)contents;
+ size_t i;
+
+ for (i=0; i<type->num_leaves; i++)
+ cv_leaf_destroy(type->leaves[i]);
+ if (type->leaves)
+ yasm_xfree(type->leaves);
+ yasm_xfree(contents);
+ }
+
+ static void
+ cv_type_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
- return YASM_BC_RESOLVE_MIN_LEN;
++static int
++cv_type_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
+ cv_type *type = (cv_type *)bc->contents;
+ size_t i;
+
+ if (type->indx == CV_FIRST_NONPRIM)
+ bc->len = 4+2;
+ else
+ bc->len = 2;
+
+ for (i=0; i<type->num_leaves; i++)
+ bc->len += cv_leaf_size(type->leaves[i]);
+
+ /* Pad to multiple of 4 */
+ if (bc->len & 0x3)
+ bc->len += 4-(bc->len & 0x3);
+
++ return 0;
+ }
+
+ static int
+ cv_type_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+ {
+ cv_type *type = (cv_type *)bc->contents;
+ yasm_dbgfmt_cv *dbgfmt_cv = type->dbgfmt_cv;
+ unsigned char *buf = *bufp;
+ yasm_intnum *cval;
+ size_t i;
+ unsigned long reclen = bc->len - 2;
+
+ cval = yasm_intnum_create_uint(4); /* version */
+ if (type->indx == CV_FIRST_NONPRIM) {
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 1);
+ buf += 4;
+ reclen -= 4;
+ }
+
+ /* Total length of record (following this field) - 2 bytes */
+ yasm_intnum_set_uint(cval, reclen);
+ yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 1);
+ buf += 2;
+
+ /* Leaves */
+ for (i=0; i<type->num_leaves; i++)
+ cv_leaf_tobytes(type->leaves[i], bc, dbgfmt_cv->arch, &buf, cval);
+
+ /* Pad to multiple of 4 */
+ switch ((buf-(*bufp)) & 0x3) {
+ case 3:
+ YASM_WRITE_8(buf, CV_LF_PAD3);
+ case 2:
+ YASM_WRITE_8(buf, CV_LF_PAD2);
+ case 1:
+ YASM_WRITE_8(buf, CV_LF_PAD1);
+ case 0:
+ break;
+ }
+
+ *bufp = buf;
+
+ yasm_intnum_destroy(cval);
+ return 0;
+ }
--- /dev/null
- yasm_bc_resolve(bc, 0, NULL);
+ /*
+ * DWARF2 debugging format - address range table
+ *
+ * Copyright (C) 2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #include <util.h>
+ /*@unused@*/ RCSID("$Id$");
+
+ #define YASM_LIB_INTERNAL
+ #define YASM_BC_INTERNAL
+ #include <libyasm.h>
+
+ #include "dwarf2-dbgfmt.h"
+
+
+ static void
+ dwarf2_append_arange(yasm_section *debug_aranges, /*@only@*/ yasm_expr *start,
+ /*@only@*/ yasm_expr *length, size_t sizeof_address)
+ {
+ yasm_datavalhead dvs;
+ yasm_bytecode *bc;
+
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(start));
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(length));
+ bc = yasm_bc_create_data(&dvs, sizeof_address, 0, NULL, 0);
+ yasm_bc_finalize(bc, yasm_dwarf2__append_bc(debug_aranges, bc));
- yasm_bc_resolve(bc, 0, NULL);
++ yasm_bc_calc_len(bc, NULL, NULL);
+ }
+
+ typedef struct dwarf2_aranges_info {
+ yasm_section *debug_aranges; /* section to which address ranges go */
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+ } dwarf2_aranges_info;
+
+ static int
+ dwarf2_generate_aranges_section(yasm_section *sect, /*@null@*/ void *d)
+ {
+ dwarf2_aranges_info *info = (dwarf2_aranges_info *)d;
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2;
+ /*@null@*/ dwarf2_section_data *dsd;
+ /*@only@*/ yasm_expr *start, *length;
+
+ dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb);
+ if (!dsd)
+ return 0; /* no line data for this section */
+
+ /* Create address range descriptor */
+ start = yasm_expr_create_ident(
+ yasm_expr_sym(yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+ yasm_section_bcs_first(sect))), 0);
+ length = yasm_expr_create_ident(
+ yasm_expr_int(yasm_common_calc_bc_dist(
+ yasm_section_bcs_first(sect), yasm_section_bcs_last(sect))), 0);
+ dwarf2_append_arange(info->debug_aranges, start, length,
+ dbgfmt_dwarf2->sizeof_address);
+
+ return 0;
+ }
+
+ yasm_section *
+ yasm_dwarf2__generate_aranges(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2,
+ yasm_section *debug_info)
+ {
+ int new;
+ yasm_section *debug_aranges;
+ yasm_bytecode *bc;
+ dwarf2_head *head;
+ dwarf2_aranges_info info;
+
+ debug_aranges =
+ yasm_object_get_general(dbgfmt_dwarf2->object, ".debug_aranges", 0,
+ 2*dbgfmt_dwarf2->sizeof_address, 0, 0, &new,
+ 0);
+
+ /* header */
+ head = yasm_dwarf2__add_head(dbgfmt_dwarf2, debug_aranges, debug_info, 1,
+ 1);
+
+ /* align ranges to 2x address size (range size) */
+ bc = yasm_bc_create_align(
+ yasm_expr_create_ident(yasm_expr_int(
+ yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_address*2)), 0),
+ NULL, NULL, NULL, 0);
+ yasm_bc_finalize(bc, yasm_dwarf2__append_bc(debug_aranges, bc));
++ yasm_bc_calc_len(bc, NULL, NULL);
+
+ info.debug_aranges = debug_aranges;
+ info.dbgfmt_dwarf2 = dbgfmt_dwarf2;
+
+ yasm_object_sections_traverse(dbgfmt_dwarf2->object, (void *)&info,
+ dwarf2_generate_aranges_section);
+
+ /* Terminate with empty address range descriptor */
+ dwarf2_append_arange(debug_aranges,
+ yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0),
+ yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(0)), 0),
+ dbgfmt_dwarf2->sizeof_address);
+
+ /* mark end of aranges information */
+ yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(debug_aranges));
+
+ return debug_aranges;
+ }
+
--- /dev/null
-static yasm_bc_resolve_flags dwarf2_head_bc_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * DWARF2 debugging format
+ *
+ * Copyright (C) 2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #include <util.h>
+ /*@unused@*/ RCSID("$Id$");
+
+ #define YASM_LIB_INTERNAL
+ #define YASM_BC_INTERNAL
+ #include <libyasm.h>
+
+ #include "dwarf2-dbgfmt.h"
+
+ struct dwarf2_head {
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+ yasm_bytecode *start_prevbc;
+ yasm_bytecode *end_prevbc;
+ /*@null@*/ yasm_section *debug_ptr;
+ int with_address;
+ int with_segment;
+ };
+
+ /* Bytecode callback function prototypes */
+ static void dwarf2_head_bc_destroy(void *contents);
+ static void dwarf2_head_bc_print(const void *contents, FILE *f,
+ int indent_level);
- dwarf2_head_bc_resolve,
++static int dwarf2_head_bc_calc_len
++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int dwarf2_head_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ /* Bytecode callback structures */
+ static const yasm_bytecode_callback dwarf2_head_bc_callback = {
+ dwarf2_head_bc_destroy,
+ dwarf2_head_bc_print,
+ yasm_bc_finalize_common,
-static yasm_bc_resolve_flags
-dwarf2_head_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ dwarf2_head_bc_calc_len,
++ yasm_bc_expand_common,
+ dwarf2_head_bc_tobytes,
+ 0
+ };
+
+ /* Section data callback function prototypes */
+ static void dwarf2_section_data_destroy(void *data);
+ static void dwarf2_section_data_print(void *data, FILE *f, int indent_level);
+
+ /* Section data callback */
+ const yasm_assoc_data_callback yasm_dwarf2__section_data_cb = {
+ dwarf2_section_data_destroy,
+ dwarf2_section_data_print
+ };
+
+ yasm_dbgfmt_module yasm_dwarf2_LTX_dbgfmt;
+
+
+ static /*@null@*/ /*@only@*/ yasm_dbgfmt *
+ dwarf2_dbgfmt_create(yasm_object *object, yasm_objfmt *of, yasm_arch *a)
+ {
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 =
+ yasm_xmalloc(sizeof(yasm_dbgfmt_dwarf2));
+ size_t i;
+
+ dbgfmt_dwarf2->dbgfmt.module = &yasm_dwarf2_LTX_dbgfmt;
+
+ dbgfmt_dwarf2->object = object;
+ dbgfmt_dwarf2->symtab = yasm_object_get_symtab(object);
+ dbgfmt_dwarf2->linemap = yasm_object_get_linemap(object);
+ dbgfmt_dwarf2->arch = a;
+
+ dbgfmt_dwarf2->dirs_allocated = 32;
+ dbgfmt_dwarf2->dirs_size = 0;
+ dbgfmt_dwarf2->dirs =
+ yasm_xmalloc(sizeof(char *)*dbgfmt_dwarf2->dirs_allocated);
+
+ dbgfmt_dwarf2->filenames_allocated = 32;
+ dbgfmt_dwarf2->filenames_size = 0;
+ dbgfmt_dwarf2->filenames =
+ yasm_xmalloc(sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated);
+ for (i=0; i<dbgfmt_dwarf2->filenames_allocated; i++) {
+ dbgfmt_dwarf2->filenames[i].pathname = NULL;
+ dbgfmt_dwarf2->filenames[i].filename = NULL;
+ dbgfmt_dwarf2->filenames[i].dir = 0;
+ }
+
+ dbgfmt_dwarf2->format = DWARF2_FORMAT_32BIT; /* TODO: flexible? */
+
+ dbgfmt_dwarf2->sizeof_address = yasm_arch_get_address_size(a)/8;
+ switch (dbgfmt_dwarf2->format) {
+ case DWARF2_FORMAT_32BIT:
+ dbgfmt_dwarf2->sizeof_offset = 4;
+ break;
+ case DWARF2_FORMAT_64BIT:
+ dbgfmt_dwarf2->sizeof_offset = 8;
+ break;
+ }
+ dbgfmt_dwarf2->min_insn_len = yasm_arch_min_insn_len(a);
+
+ return (yasm_dbgfmt *)dbgfmt_dwarf2;
+ }
+
+ static void
+ dwarf2_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt)
+ {
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt;
+ size_t i;
+ for (i=0; i<dbgfmt_dwarf2->dirs_size; i++)
+ if (dbgfmt_dwarf2->dirs[i])
+ yasm_xfree(dbgfmt_dwarf2->dirs[i]);
+ yasm_xfree(dbgfmt_dwarf2->dirs);
+ for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
+ if (dbgfmt_dwarf2->filenames[i].pathname)
+ yasm_xfree(dbgfmt_dwarf2->filenames[i].pathname);
+ if (dbgfmt_dwarf2->filenames[i].filename)
+ yasm_xfree(dbgfmt_dwarf2->filenames[i].filename);
+ }
+ yasm_xfree(dbgfmt_dwarf2->filenames);
+ yasm_xfree(dbgfmt);
+ }
+
+ /* Add a bytecode to a section, updating offset on insertion;
+ * no optimization necessary.
+ */
+ yasm_bytecode *
+ yasm_dwarf2__append_bc(yasm_section *sect, yasm_bytecode *bc)
+ {
+ yasm_bytecode *precbc = yasm_section_bcs_last(sect);
+ bc->offset = precbc ? precbc->offset + precbc->len : 0;
+ yasm_section_bcs_append(sect, bc);
+ return precbc;
+ }
+
+ static void
+ dwarf2_dbgfmt_generate(yasm_dbgfmt *dbgfmt, yasm_errwarns *errwarns)
+ {
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt;
+ size_t num_line_sections;
+ /*@null@*/ yasm_section *debug_info, *debug_line, *main_code;
+
+ /* If we don't have any .file directives, generate line information
+ * based on the asm source.
+ */
+ debug_line = yasm_dwarf2__generate_line(dbgfmt_dwarf2, errwarns,
+ dbgfmt_dwarf2->filenames_size == 0,
+ &main_code, &num_line_sections);
+
+ /* If we don't have a .debug_info (or it's empty), generate the minimal
+ * set of .debug_info, .debug_aranges, and .debug_abbrev so that the
+ * .debug_line we're generating is actually useful.
+ */
+ debug_info = yasm_object_find_general(dbgfmt_dwarf2->object, ".debug_info");
+ if (num_line_sections > 0 &&
+ (!debug_info || yasm_section_bcs_first(debug_info)
+ == yasm_section_bcs_last(debug_info))) {
+ debug_info = yasm_dwarf2__generate_info(dbgfmt_dwarf2, debug_line,
+ main_code);
+ yasm_dwarf2__generate_aranges(dbgfmt_dwarf2, debug_info);
+ /*yasm_dwarf2__generate_pubnames(dbgfmt_dwarf2, debug_info);*/
+ }
+ }
+
+ yasm_symrec *
+ yasm_dwarf2__bc_sym(yasm_symtab *symtab, yasm_bytecode *bc)
+ {
+ /*@dependent@*/ yasm_symrec *sym;
+ if (bc->symrecs && bc->symrecs[0])
+ sym = bc->symrecs[0];
+ else
+ sym = yasm_symtab_define_label(symtab, ".bcsym", bc, 0, 0);
+ return sym;
+ }
+
+ dwarf2_head *
+ yasm_dwarf2__add_head
+ (yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, yasm_section *sect,
+ /*@null@*/ yasm_section *debug_ptr, int with_address, int with_segment)
+ {
+ dwarf2_head *head;
+ yasm_bytecode *bc;
+
+ head = yasm_xmalloc(sizeof(dwarf2_head));
+ head->dbgfmt_dwarf2 = dbgfmt_dwarf2;
+ head->start_prevbc = yasm_section_bcs_last(sect);
+
+ bc = yasm_bc_create_common(&dwarf2_head_bc_callback, head, 0);
+ bc->len = dbgfmt_dwarf2->sizeof_offset + 2;
+ if (dbgfmt_dwarf2->format == DWARF2_FORMAT_64BIT)
+ bc->len += 4;
+
+ if (debug_ptr) {
+ head->debug_ptr = debug_ptr;
+ bc->len += dbgfmt_dwarf2->sizeof_offset;
+ } else
+ head->debug_ptr = NULL;
+
+ head->with_address = with_address;
+ head->with_segment = with_segment;
+ if (with_address)
+ bc->len++;
+ if (with_segment)
+ bc->len++;
+
+ head->end_prevbc = bc;
+ yasm_dwarf2__append_bc(sect, bc);
+ return head;
+ }
+
+ void
+ yasm_dwarf2__set_head_end(dwarf2_head *head, yasm_bytecode *end_prevbc)
+ {
+ head->end_prevbc = end_prevbc;
+ }
+
+ static void
+ dwarf2_head_bc_destroy(void *contents)
+ {
+ yasm_xfree(contents);
+ }
+
+ static void
+ dwarf2_head_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
- yasm_internal_error(N_("tried to resolve a dwarf2 head bytecode"));
++static int
++dwarf2_head_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
- return YASM_BC_RESOLVE_MIN_LEN;
++ yasm_internal_error(N_("tried to calc_len a dwarf2 head bytecode"));
+ /*@notreached@*/
++ return 0;
+ }
+
+ static int
+ dwarf2_head_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+ {
+ dwarf2_head *head = (dwarf2_head *)bc->contents;
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = head->dbgfmt_dwarf2;
+ unsigned char *buf = *bufp;
+ yasm_intnum *intn, *cval;
+
+ if (dbgfmt_dwarf2->format == DWARF2_FORMAT_64BIT) {
+ YASM_WRITE_8(buf, 0xff);
+ YASM_WRITE_8(buf, 0xff);
+ YASM_WRITE_8(buf, 0xff);
+ YASM_WRITE_8(buf, 0xff);
+ }
+
+ /* Total length of aranges info (following this field) */
+ cval = yasm_intnum_create_uint(dbgfmt_dwarf2->sizeof_offset);
+ intn = yasm_common_calc_bc_dist(head->start_prevbc, head->end_prevbc);
+ yasm_intnum_calc(intn, YASM_EXPR_SUB, cval);
+ yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, intn, buf,
+ dbgfmt_dwarf2->sizeof_offset,
+ dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 0);
+ buf += dbgfmt_dwarf2->sizeof_offset;
+ yasm_intnum_destroy(intn);
+
+ /* DWARF version */
+ yasm_intnum_set_uint(cval, 2);
+ yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, cval, buf, 2, 16, 0, bc, 0);
+ buf += 2;
+
+ /* Pointer to another debug section */
+ if (head->debug_ptr) {
+ yasm_value value;
+ yasm_value_init_sym(&value,
+ yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+ yasm_section_bcs_first(head->debug_ptr)),
+ dbgfmt_dwarf2->sizeof_offset*8);
+ output_value(&value, buf, dbgfmt_dwarf2->sizeof_offset,
+ (unsigned long)(buf-*bufp), bc, 0, d);
+ buf += dbgfmt_dwarf2->sizeof_offset;
+ }
+
+ /* Size of the offset portion of the address */
+ if (head->with_address)
+ YASM_WRITE_8(buf, dbgfmt_dwarf2->sizeof_address);
+
+ /* Size of a segment descriptor. 0 = flat address space */
+ if (head->with_segment)
+ YASM_WRITE_8(buf, 0);
+
+ *bufp = buf;
+
+ yasm_intnum_destroy(cval);
+ return 0;
+ }
+
+ static void
+ dwarf2_section_data_destroy(void *data)
+ {
+ dwarf2_section_data *dsd = data;
+ dwarf2_loc *n1, *n2;
+
+ /* Delete locations */
+ n1 = STAILQ_FIRST(&dsd->locs);
+ while (n1) {
+ n2 = STAILQ_NEXT(n1, link);
+ yasm_xfree(n1);
+ n1 = n2;
+ }
+
+ yasm_xfree(data);
+ }
+
+ static void
+ dwarf2_section_data_print(void *data, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
+ static int
+ dwarf2_dbgfmt_directive(yasm_dbgfmt *dbgfmt, const char *name,
+ yasm_section *sect, yasm_valparamhead *valparams,
+ unsigned long line)
+ {
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)dbgfmt;
+ return yasm_dwarf2__line_directive(dbgfmt_dwarf2, name, sect, valparams,
+ line);
+ }
+
+ /* Define dbgfmt structure -- see dbgfmt.h for details */
+ yasm_dbgfmt_module yasm_dwarf2_LTX_dbgfmt = {
+ "DWARF2 debugging format",
+ "dwarf2",
+ dwarf2_dbgfmt_create,
+ dwarf2_dbgfmt_destroy,
+ dwarf2_dbgfmt_directive,
+ dwarf2_dbgfmt_generate
+ };
--- /dev/null
-static yasm_bc_resolve_flags dwarf2_abbrev_bc_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * DWARF2 debugging format - info and abbreviation tables
+ *
+ * Copyright (C) 2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #undef HAVE_CONFIG_H
+ #endif
+
+ /* Need either unistd.h or direct.h (on Windows) to prototype getcwd() */
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #elif defined(WIN32) || defined(_WIN32)
+ #include <direct.h>
+ #endif
+
+ #include <util.h>
+ /*@unused@*/ RCSID("$Id$");
+
+ #define YASM_LIB_INTERNAL
+ #define YASM_BC_INTERNAL
+ #include <libyasm.h>
+
+ #include "dwarf2-dbgfmt.h"
+
+ #define DW_LANG_Mips_Assembler 0x8001
+
+ /* Tag encodings */
+ typedef enum {
+ DW_TAG_padding = 0x00,
+ DW_TAG_array_type = 0x01,
+ DW_TAG_class_type = 0x02,
+ DW_TAG_entry_point = 0x03,
+ DW_TAG_enumeration_type = 0x04,
+ DW_TAG_formal_parameter = 0x05,
+ DW_TAG_imported_declaration = 0x08,
+ DW_TAG_label = 0x0a,
+ DW_TAG_lexical_block = 0x0b,
+ DW_TAG_member = 0x0d,
+ DW_TAG_pointer_type = 0x0f,
+ DW_TAG_reference_type = 0x10,
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_string_type = 0x12,
+ DW_TAG_structure_type = 0x13,
+ DW_TAG_subroutine_type = 0x15,
+ DW_TAG_typedef = 0x16,
+ DW_TAG_union_type = 0x17,
+ DW_TAG_unspecified_parameters = 0x18,
+ DW_TAG_variant = 0x19,
+ DW_TAG_common_block = 0x1a,
+ DW_TAG_common_inclusion = 0x1b,
+ DW_TAG_inheritance = 0x1c,
+ DW_TAG_inlined_subroutine = 0x1d,
+ DW_TAG_module = 0x1e,
+ DW_TAG_ptr_to_member_type = 0x1f,
+ DW_TAG_set_type = 0x20,
+ DW_TAG_subrange_type = 0x21,
+ DW_TAG_with_stmt = 0x22,
+ DW_TAG_access_declaration = 0x23,
+ DW_TAG_base_type = 0x24,
+ DW_TAG_catch_block = 0x25,
+ DW_TAG_const_type = 0x26,
+ DW_TAG_constant = 0x27,
+ DW_TAG_enumerator = 0x28,
+ DW_TAG_file_type = 0x29,
+ DW_TAG_friend = 0x2a,
+ DW_TAG_namelist = 0x2b,
+ DW_TAG_namelist_item = 0x2c,
+ DW_TAG_packed_type = 0x2d,
+ DW_TAG_subprogram = 0x2e,
+ DW_TAG_template_type_param = 0x2f,
+ DW_TAG_template_value_param = 0x30,
+ DW_TAG_thrown_type = 0x31,
+ DW_TAG_try_block = 0x32,
+ DW_TAG_variant_part = 0x33,
+ DW_TAG_variable = 0x34,
+ DW_TAG_volatile_type = 0x35
+ } dwarf_tag;
+
+ /* Attribute form encodings */
+ typedef enum {
+ DW_FORM_addr = 0x01,
+ DW_FORM_block2 = 0x03,
+ DW_FORM_block4 = 0x04,
+ DW_FORM_data2 = 0x05,
+ DW_FORM_data4 = 0x06,
+ DW_FORM_data8 = 0x07,
+ DW_FORM_string = 0x08,
+ DW_FORM_block = 0x09,
+ DW_FORM_block1 = 0x0a,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_flag = 0x0c,
+ DW_FORM_sdata = 0x0d,
+ DW_FORM_strp = 0x0e,
+ DW_FORM_udata = 0x0f,
+ DW_FORM_ref_addr = 0x10,
+ DW_FORM_ref1 = 0x11,
+ DW_FORM_ref2 = 0x12,
+ DW_FORM_ref4 = 0x13,
+ DW_FORM_ref8 = 0x14,
+ DW_FORM_ref_udata = 0x15,
+ DW_FORM_indirect = 0x16
+ } dwarf_form;
+
+ /* Attribute encodings */
+ typedef enum {
+ DW_AT_sibling = 0x01,
+ DW_AT_location = 0x02,
+ DW_AT_name = 0x03,
+ DW_AT_ordering = 0x09,
+ DW_AT_subscr_data = 0x0a,
+ DW_AT_byte_size = 0x0b,
+ DW_AT_bit_offset = 0x0c,
+ DW_AT_bit_size = 0x0d,
+ DW_AT_element_list = 0x0f,
+ DW_AT_stmt_list = 0x10,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+ DW_AT_member = 0x14,
+ DW_AT_discr = 0x15,
+ DW_AT_discr_value = 0x16,
+ DW_AT_visibility = 0x17,
+ DW_AT_import = 0x18,
+ DW_AT_string_length = 0x19,
+ DW_AT_common_reference = 0x1a,
+ DW_AT_comp_dir = 0x1b,
+ DW_AT_const_value = 0x1c,
+ DW_AT_containing_type = 0x1d,
+ DW_AT_default_value = 0x1e,
+ DW_AT_inline = 0x20,
+ DW_AT_is_optional = 0x21,
+ DW_AT_lower_bound = 0x22,
+ DW_AT_producer = 0x25,
+ DW_AT_prototyped = 0x27,
+ DW_AT_return_addr = 0x2a,
+ DW_AT_start_scope = 0x2c,
+ DW_AT_stride_size = 0x2e,
+ DW_AT_upper_bound = 0x2f,
+ DW_AT_abstract_origin = 0x31,
+ DW_AT_accessibility = 0x32,
+ DW_AT_address_class = 0x33,
+ DW_AT_artificial = 0x34,
+ DW_AT_base_types = 0x35,
+ DW_AT_calling_convention = 0x36,
+ DW_AT_count = 0x37,
+ DW_AT_data_member_location = 0x38,
+ DW_AT_decl_column = 0x39,
+ DW_AT_decl_file = 0x3a,
+ DW_AT_decl_line = 0x3b,
+ DW_AT_declaration = 0x3c,
+ DW_AT_discr_list = 0x3d,
+ DW_AT_encoding = 0x3e,
+ DW_AT_external = 0x3f,
+ DW_AT_frame_base = 0x40,
+ DW_AT_friend = 0x41,
+ DW_AT_identifier_case = 0x42,
+ DW_AT_macro_info = 0x43,
+ DW_AT_namelist_items = 0x44,
+ DW_AT_priority = 0x45,
+ DW_AT_segment = 0x46,
+ DW_AT_specification = 0x47,
+ DW_AT_static_link = 0x48,
+ DW_AT_type = 0x49,
+ DW_AT_use_location = 0x4a,
+ DW_AT_variable_parameter = 0x4b,
+ DW_AT_virtuality = 0x4c,
+ DW_AT_vtable_elem_location = 0x4d
+ } dwarf_attribute;
+
+ typedef struct dwarf2_abbrev_attr {
+ STAILQ_ENTRY(dwarf2_abbrev_attr) link;
+ dwarf_attribute name;
+ dwarf_form form;
+ } dwarf2_abbrev_attr;
+
+ typedef struct dwarf2_abbrev {
+ unsigned long id;
+ dwarf_tag tag;
+ int has_children;
+ STAILQ_HEAD(dwarf2_abbrev_attrhead, dwarf2_abbrev_attr) attrs;
+ } dwarf2_abbrev;
+
+ /* Bytecode callback function prototypes */
+
+ static void dwarf2_abbrev_bc_destroy(void *contents);
+ static void dwarf2_abbrev_bc_print(const void *contents, FILE *f,
+ int indent_level);
- dwarf2_abbrev_bc_resolve,
++static int dwarf2_abbrev_bc_calc_len
++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int dwarf2_abbrev_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ /* Bytecode callback structures */
+
+ static const yasm_bytecode_callback dwarf2_abbrev_bc_callback = {
+ dwarf2_abbrev_bc_destroy,
+ dwarf2_abbrev_bc_print,
+ yasm_bc_finalize_common,
- yasm_bc_resolve(bc, 0, NULL);
++ dwarf2_abbrev_bc_calc_len,
++ yasm_bc_expand_common,
+ dwarf2_abbrev_bc_tobytes,
+ 0
+ };
+
+
+ static unsigned long
+ dwarf2_add_abbrev_attr(dwarf2_abbrev *abbrev, dwarf_attribute name,
+ dwarf_form form)
+ {
+ dwarf2_abbrev_attr *attr = yasm_xmalloc(sizeof(dwarf2_abbrev_attr));
+ attr->name = name;
+ attr->form = form;
+ STAILQ_INSERT_TAIL(&abbrev->attrs, attr, link);
+ return yasm_size_uleb128(name) + yasm_size_uleb128(form);
+ }
+
+ static void
+ dwarf2_append_expr(yasm_section *sect, /*@only@*/ yasm_expr *expr, size_t size,
+ int leb)
+ {
+ yasm_datavalhead dvs;
+ yasm_bytecode *bc;
+
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_expr(expr));
+ if (leb == 0)
+ bc = yasm_bc_create_data(&dvs, size, 0, NULL, 0);
+ else
+ bc = yasm_bc_create_leb128(&dvs, leb<0, 0);
+ yasm_bc_finalize(bc, yasm_dwarf2__append_bc(sect, bc));
- yasm_bc_resolve(bc, 0, NULL);
++ yasm_bc_calc_len(bc, NULL, NULL);
+ }
+
+ static void
+ dwarf2_append_str(yasm_section *sect, const char *str)
+ {
+ yasm_datavalhead dvs;
+ yasm_bytecode *bc;
+
+ yasm_dvs_initialize(&dvs);
+ yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(str),
+ strlen(str)));
+ bc = yasm_bc_create_data(&dvs, 1, 1, NULL, 0);
+ yasm_bc_finalize(bc, yasm_dwarf2__append_bc(sect, bc));
-static yasm_bc_resolve_flags
-dwarf2_abbrev_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ yasm_bc_calc_len(bc, NULL, NULL);
+ }
+
+ yasm_section *
+ yasm_dwarf2__generate_info(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2,
+ yasm_section *debug_line, yasm_section *main_code)
+ {
+ int new;
+ yasm_bytecode *abc;
+ dwarf2_abbrev *abbrev;
+ dwarf2_head *head;
+ char *buf;
+ yasm_section *debug_abbrev =
+ yasm_object_get_general(dbgfmt_dwarf2->object, ".debug_abbrev", 0,
+ 4, 0, 0, &new, 0);
+ yasm_section *debug_info =
+ yasm_object_get_general(dbgfmt_dwarf2->object, ".debug_info", 0, 4, 0,
+ 0, &new, 0);
+
+ yasm_section_set_align(debug_abbrev, 0, 0);
+ yasm_section_set_align(debug_info, 0, 0);
+
+ /* Create abbreviation table entry for compilation unit */
+ abbrev = yasm_xmalloc(sizeof(dwarf2_abbrev));
+ abc = yasm_bc_create_common(&dwarf2_abbrev_bc_callback, abbrev, 0);
+ abbrev->id = 1;
+ abbrev->tag = DW_TAG_compile_unit;
+ abbrev->has_children = 0;
+ abc->len = yasm_size_uleb128(abbrev->id) + yasm_size_uleb128(abbrev->tag)
+ + 3;
+ STAILQ_INIT(&abbrev->attrs);
+ yasm_dwarf2__append_bc(debug_abbrev, abc);
+
+ /* info header */
+ head = yasm_dwarf2__add_head(dbgfmt_dwarf2, debug_info, debug_abbrev, 1, 0);
+
+ /* Generate abbreviations at the same time as info (since they're linked
+ * and we're only generating one piece of info).
+ */
+
+ /* generating info using abbrev 1 */
+ dwarf2_append_expr(debug_info,
+ yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(1)), 0),
+ 0, 1);
+
+ /* statement list (line numbers) */
+ abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_stmt_list, DW_FORM_data4);
+ dwarf2_append_expr(debug_info,
+ yasm_expr_create_ident(yasm_expr_sym(
+ yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+ yasm_section_bcs_first(debug_line))), 0),
+ dbgfmt_dwarf2->sizeof_offset, 0);
+
+ if (main_code) {
+ yasm_symrec *first;
+ first = yasm_dwarf2__bc_sym(dbgfmt_dwarf2->symtab,
+ yasm_section_bcs_first(main_code));
+ /* All code is contiguous in one section */
+ abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_low_pc, DW_FORM_addr);
+ dwarf2_append_expr(debug_info,
+ yasm_expr_create_ident(yasm_expr_sym(first), 0),
+ dbgfmt_dwarf2->sizeof_address, 0);
+
+ abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_high_pc, DW_FORM_addr);
+ dwarf2_append_expr(debug_info,
+ yasm_expr_create(YASM_EXPR_ADD, yasm_expr_sym(first),
+ yasm_expr_int(yasm_common_calc_bc_dist(
+ yasm_section_bcs_first(main_code),
+ yasm_section_bcs_last(main_code))), 0),
+ dbgfmt_dwarf2->sizeof_address, 0);
+ }
+
+ /* input filename */
+ abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_name, DW_FORM_string);
+ dwarf2_append_str(debug_info,
+ yasm_object_get_source_fn(dbgfmt_dwarf2->object));
+
+ /* compile directory (current working directory) */
+ abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_comp_dir, DW_FORM_string);
+ buf = getcwd(NULL, 0);
+ dwarf2_append_str(debug_info, buf);
+ free(buf);
+
+ /* producer - assembler name */
+ abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_producer, DW_FORM_string);
+ dwarf2_append_str(debug_info, PACKAGE " " VERSION);
+
+ /* language - no standard code for assembler, use MIPS as a substitute */
+ abc->len += dwarf2_add_abbrev_attr(abbrev, DW_AT_language, DW_FORM_data2);
+ dwarf2_append_expr(debug_info,
+ yasm_expr_create_ident(yasm_expr_int(
+ yasm_intnum_create_uint(DW_LANG_Mips_Assembler)), 0), 2, 0);
+
+ /* Terminate list of abbreviations */
+ abbrev = yasm_xmalloc(sizeof(dwarf2_abbrev));
+ abc = yasm_bc_create_common(&dwarf2_abbrev_bc_callback, abbrev, 0);
+ abbrev->id = 0;
+ abbrev->tag = 0;
+ abbrev->has_children = 0;
+ STAILQ_INIT(&abbrev->attrs);
+ abc->len = 1;
+ yasm_dwarf2__append_bc(debug_abbrev, abc);
+
+ /* mark end of info */
+ yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(debug_info));
+
+ return debug_info;
+ }
+
+ static void
+ dwarf2_abbrev_bc_destroy(void *contents)
+ {
+ dwarf2_abbrev *abbrev = (dwarf2_abbrev *)contents;
+ dwarf2_abbrev_attr *n1, *n2;
+
+ /* Delete attributes */
+ n1 = STAILQ_FIRST(&abbrev->attrs);
+ while (n1) {
+ n2 = STAILQ_NEXT(n1, link);
+ yasm_xfree(n1);
+ n1 = n2;
+ }
+
+ yasm_xfree(contents);
+ }
+
+ static void
+ dwarf2_abbrev_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
- yasm_internal_error(N_("tried to resolve a dwarf2 aranges head bytecode"));
++static int
++dwarf2_abbrev_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
- return YASM_BC_RESOLVE_MIN_LEN;
++ yasm_internal_error(N_("tried to calc_len a dwarf2 aranges head bytecode"));
+ /*@notreached@*/
++ return 0;
+ }
+
+ static int
+ dwarf2_abbrev_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+ {
+ dwarf2_abbrev *abbrev = (dwarf2_abbrev *)bc->contents;
+ unsigned char *buf = *bufp;
+ dwarf2_abbrev_attr *attr;
+
+ if (abbrev->id == 0) {
+ YASM_WRITE_8(buf, 0);
+ *bufp = buf;
+ return 0;
+ }
+
+ buf += yasm_get_uleb128(abbrev->id, buf);
+ buf += yasm_get_uleb128(abbrev->tag, buf);
+ YASM_WRITE_8(buf, abbrev->has_children);
+
+ STAILQ_FOREACH(attr, &abbrev->attrs, link) {
+ buf += yasm_get_uleb128(attr->name, buf);
+ buf += yasm_get_uleb128(attr->form, buf);
+ }
+
+ YASM_WRITE_8(buf, 0);
+ YASM_WRITE_8(buf, 0);
+
+ *bufp = buf;
+ return 0;
+ }
+
--- /dev/null
-static yasm_bc_resolve_flags dwarf2_spp_bc_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+ /*
+ * DWARF2 debugging format - line information
+ *
+ * Copyright (C) 2006 Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ #include <util.h>
+ /*@unused@*/ RCSID("$Id$");
+
+ #define YASM_LIB_INTERNAL
+ #define YASM_BC_INTERNAL
+ #include <libyasm.h>
+
+ #include "dwarf2-dbgfmt.h"
+
+ /* DWARF line number opcodes */
+ typedef enum {
+ DW_LNS_extended_op = 0,
+ DW_LNS_copy,
+ DW_LNS_advance_pc,
+ DW_LNS_advance_line,
+ DW_LNS_set_file,
+ DW_LNS_set_column,
+ DW_LNS_negate_stmt,
+ DW_LNS_set_basic_block,
+ DW_LNS_const_add_pc,
+ DW_LNS_fixed_advance_pc,
+ #ifdef WITH_DWARF3
+ /* DWARF 3 extensions */
+ DW_LNS_set_prologue_end,
+ DW_LNS_set_epilogue_begin,
+ DW_LNS_set_isa,
+ #endif
+ DWARF2_LINE_OPCODE_BASE
+ } dwarf_line_number_op;
+
+ /* # of LEB128 operands needed for each of the above opcodes */
+ static unsigned char line_opcode_num_operands[DWARF2_LINE_OPCODE_BASE-1] = {
+ 0, /* DW_LNS_copy */
+ 1, /* DW_LNS_advance_pc */
+ 1, /* DW_LNS_advance_line */
+ 1, /* DW_LNS_set_file */
+ 1, /* DW_LNS_set_column */
+ 0, /* DW_LNS_negate_stmt */
+ 0, /* DW_LNS_set_basic_block */
+ 0, /* DW_LNS_const_add_pc */
+ 1, /* DW_LNS_fixed_advance_pc */
+ #ifdef WITH_DWARF3
+ 0, /* DW_LNS_set_prologue_end */
+ 0, /* DW_LNS_set_epilogue_begin */
+ 1 /* DW_LNS_set_isa */
+ #endif
+ };
+
+ /* Line number extended opcodes */
+ typedef enum {
+ DW_LNE_end_sequence = 1,
+ DW_LNE_set_address,
+ DW_LNE_define_file
+ } dwarf_line_number_ext_op;
+
+ /* Base and range for line offsets in special opcodes */
+ #define DWARF2_LINE_BASE -5
+ #define DWARF2_LINE_RANGE 14
+
+ #define DWARF2_MAX_SPECIAL_ADDR_DELTA \
+ (((255-DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)*\
+ dbgfmt_dwarf2->min_insn_len)
+
+ /* Initial value of is_stmt register */
+ #define DWARF2_LINE_DEFAULT_IS_STMT 1
+
+ /* Line number state machine register state */
+ typedef struct dwarf2_line_state {
+ /* static configuration */
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+
+ /* DWARF2 state machine registers */
+ unsigned long address;
+ unsigned long file;
+ unsigned long line;
+ unsigned long column;
+ unsigned long isa;
+ int is_stmt;
+
+ /* other state information */
+ /*@null@*/ yasm_bytecode *precbc;
+ } dwarf2_line_state;
+
+ typedef struct dwarf2_spp {
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+ yasm_bytecode *line_start_prevbc;
+ yasm_bytecode *line_end_prevbc;
+ } dwarf2_spp;
+
+ typedef struct dwarf2_line_op {
+ dwarf_line_number_op opcode;
+ /*@owned@*/ /*@null@*/ yasm_intnum *operand;
+
+ /* extended opcode */
+ dwarf_line_number_ext_op ext_opcode;
+ /*@null@*/ /*@dependent@*/ yasm_symrec *ext_operand; /* unsigned */
+ unsigned long ext_operandsize;
+ } dwarf2_line_op;
+
+ /* Bytecode callback function prototypes */
+ static void dwarf2_spp_bc_destroy(void *contents);
+ static void dwarf2_spp_bc_print(const void *contents, FILE *f,
+ int indent_level);
-static yasm_bc_resolve_flags dwarf2_line_op_bc_resolve
- (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
++static int dwarf2_spp_bc_calc_len
++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int dwarf2_spp_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ static void dwarf2_line_op_bc_destroy(void *contents);
+ static void dwarf2_line_op_bc_print(const void *contents, FILE *f,
+ int indent_level);
- dwarf2_spp_bc_resolve,
++static int dwarf2_line_op_bc_calc_len
++ (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data);
+ static int dwarf2_line_op_bc_tobytes
+ (yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ /*@null@*/ yasm_output_reloc_func output_reloc);
+
+ /* Bytecode callback structures */
+ static const yasm_bytecode_callback dwarf2_spp_bc_callback = {
+ dwarf2_spp_bc_destroy,
+ dwarf2_spp_bc_print,
+ yasm_bc_finalize_common,
- dwarf2_line_op_bc_resolve,
++ dwarf2_spp_bc_calc_len,
++ yasm_bc_expand_common,
+ dwarf2_spp_bc_tobytes,
+ 0
+ };
+
+ static const yasm_bytecode_callback dwarf2_line_op_bc_callback = {
+ dwarf2_line_op_bc_destroy,
+ dwarf2_line_op_bc_print,
+ yasm_bc_finalize_common,
-static yasm_bc_resolve_flags
-dwarf2_spp_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ dwarf2_line_op_bc_calc_len,
++ yasm_bc_expand_common,
+ dwarf2_line_op_bc_tobytes,
+ 0
+ };
+
+
+ static size_t
+ dwarf2_dbgfmt_add_file(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2, size_t filenum,
+ const char *pathname)
+ {
+ size_t dirlen;
+ const char *filename;
+ size_t i, dir;
+
+ /* Put the directory into the directory table */
+ dir = 0;
+ dirlen = yasm__splitpath(pathname, &filename);
+ if (dirlen > 0) {
+ /* Look to see if we already have that dir in the table */
+ for (dir=1; dir<dbgfmt_dwarf2->dirs_size+1; dir++) {
+ if (strncmp(dbgfmt_dwarf2->dirs[dir-1], pathname, dirlen) == 0
+ && dbgfmt_dwarf2->dirs[dir-1][dirlen] == '\0')
+ break;
+ }
+ if (dir >= dbgfmt_dwarf2->dirs_size+1) {
+ /* Not found in table, add to end, reallocing if necessary */
+ if (dir >= dbgfmt_dwarf2->dirs_allocated+1) {
+ dbgfmt_dwarf2->dirs_allocated = dir+32;
+ dbgfmt_dwarf2->dirs = yasm_xrealloc(dbgfmt_dwarf2->dirs,
+ sizeof(char *)*dbgfmt_dwarf2->dirs_allocated);
+ }
+ dbgfmt_dwarf2->dirs[dir-1] = yasm__xstrndup(pathname, dirlen);
+ dbgfmt_dwarf2->dirs_size = dir;
+ }
+ }
+
+ /* Put the filename into the filename table */
+ if (filenum == 0) {
+ /* Look to see if we already have that filename in the table */
+ for (; filenum<dbgfmt_dwarf2->filenames_size; filenum++) {
+ if (!dbgfmt_dwarf2->filenames[filenum].filename ||
+ (dbgfmt_dwarf2->filenames[filenum].dir == dir
+ && strcmp(dbgfmt_dwarf2->filenames[filenum].filename,
+ filename) == 0))
+ break;
+ }
+ } else
+ filenum--; /* array index is 0-based */
+
+ /* Realloc table if necessary */
+ if (filenum >= dbgfmt_dwarf2->filenames_allocated) {
+ size_t old_allocated = dbgfmt_dwarf2->filenames_allocated;
+ dbgfmt_dwarf2->filenames_allocated = filenum+32;
+ dbgfmt_dwarf2->filenames = yasm_xrealloc(dbgfmt_dwarf2->filenames,
+ sizeof(dwarf2_filename)*dbgfmt_dwarf2->filenames_allocated);
+ for (i=old_allocated; i<dbgfmt_dwarf2->filenames_allocated; i++) {
+ dbgfmt_dwarf2->filenames[i].pathname = NULL;
+ dbgfmt_dwarf2->filenames[i].filename = NULL;
+ dbgfmt_dwarf2->filenames[i].dir = 0;
+ }
+ }
+
+ /* Actually save in table */
+ if (dbgfmt_dwarf2->filenames[filenum].pathname)
+ yasm_xfree(dbgfmt_dwarf2->filenames[filenum].pathname);
+ if (dbgfmt_dwarf2->filenames[filenum].filename)
+ yasm_xfree(dbgfmt_dwarf2->filenames[filenum].filename);
+ dbgfmt_dwarf2->filenames[filenum].pathname = yasm__xstrdup(pathname);
+ dbgfmt_dwarf2->filenames[filenum].filename = yasm__xstrdup(filename);
+ dbgfmt_dwarf2->filenames[filenum].dir = dir;
+
+ /* Update table size */
+ if (filenum >= dbgfmt_dwarf2->filenames_size)
+ dbgfmt_dwarf2->filenames_size = filenum + 1;
+
+ return filenum;
+ }
+
+ /* Create and add a new line opcode to a section, updating offset on insertion;
+ * no optimization necessary.
+ */
+ static yasm_bytecode *
+ dwarf2_dbgfmt_append_line_op(yasm_section *sect, dwarf_line_number_op opcode,
+ /*@only@*/ /*@null@*/ yasm_intnum *operand)
+ {
+ dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op));
+ yasm_bytecode *bc;
+
+ line_op->opcode = opcode;
+ line_op->operand = operand;
+ line_op->ext_opcode = 0;
+ line_op->ext_operand = NULL;
+ line_op->ext_operandsize = 0;
+
+ bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0);
+ bc->len = 1;
+ if (operand)
+ bc->len += yasm_intnum_size_leb128(operand,
+ opcode == DW_LNS_advance_line);
+
+ yasm_dwarf2__append_bc(sect, bc);
+ return bc;
+ }
+
+ /* Create and add a new extended line opcode to a section, updating offset on
+ * insertion; no optimization necessary.
+ */
+ static yasm_bytecode *
+ dwarf2_dbgfmt_append_line_ext_op(yasm_section *sect,
+ dwarf_line_number_ext_op ext_opcode,
+ unsigned long ext_operandsize,
+ /*@null@*/ yasm_symrec *ext_operand)
+ {
+ dwarf2_line_op *line_op = yasm_xmalloc(sizeof(dwarf2_line_op));
+ yasm_bytecode *bc;
+
+ line_op->opcode = DW_LNS_extended_op;
+ line_op->operand = yasm_intnum_create_uint(ext_operandsize+1);
+ line_op->ext_opcode = ext_opcode;
+ line_op->ext_operand = ext_operand;
+ line_op->ext_operandsize = ext_operandsize;
+
+ bc = yasm_bc_create_common(&dwarf2_line_op_bc_callback, line_op, 0);
+ bc->len = 2 + yasm_intnum_size_leb128(line_op->operand, 0) +
+ ext_operandsize;
+
+ yasm_dwarf2__append_bc(sect, bc);
+ return bc;
+ }
+
+ static void
+ dwarf2_dbgfmt_finalize_locs(yasm_section *sect, dwarf2_section_data *dsd)
+ {
+ /*@dependent@*/ yasm_symrec *lastsym = NULL;
+ /*@null@*/ yasm_bytecode *bc;
+ /*@null@*/ dwarf2_loc *loc;
+
+ bc = yasm_section_bcs_first(sect);
+ STAILQ_FOREACH(loc, &dsd->locs, link) {
+ /* Find the first bytecode following this loc by looking at
+ * the virtual line numbers. XXX: this assumes the source file
+ * order will be the same as the actual section order. If we ever
+ * implement subsegs this will NOT necessarily be true and this logic
+ * will need to be fixed to handle it!
+ *
+ * Keep track of last symbol seen prior to the loc.
+ */
+ while (bc && bc->line <= loc->vline) {
+ if (bc->symrecs) {
+ int i = 0;
+ while (bc->symrecs[i]) {
+ lastsym = bc->symrecs[i];
+ i++;
+ }
+ }
+ bc = yasm_bc__next(bc);
+ }
+ loc->sym = lastsym;
+ loc->bc = bc;
+ }
+ }
+
+ static int
+ dwarf2_dbgfmt_gen_line_op(yasm_section *debug_line, dwarf2_line_state *state,
+ const dwarf2_loc *loc,
+ /*@null@*/ const dwarf2_loc *nextloc)
+ {
+ unsigned long addr_delta;
+ long line_delta;
+ int opcode1, opcode2;
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = state->dbgfmt_dwarf2;
+
+ if (state->file != loc->file) {
+ state->file = loc->file;
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_file,
+ yasm_intnum_create_uint(state->file));
+ }
+ if (state->column != loc->column) {
+ state->column = loc->column;
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_column,
+ yasm_intnum_create_uint(state->column));
+ }
+ #ifdef WITH_DWARF3
+ if (loc->isa_change) {
+ state->isa = loc->isa;
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_isa,
+ yasm_intnum_create_uint(state->isa));
+ }
+ #endif
+ if (state->is_stmt == 0 && loc->is_stmt == IS_STMT_SET) {
+ state->is_stmt = 1;
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL);
+ } else if (state->is_stmt == 1 && loc->is_stmt == IS_STMT_CLEAR) {
+ state->is_stmt = 0;
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_negate_stmt, NULL);
+ }
+ if (loc->basic_block) {
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_basic_block, NULL);
+ }
+ #ifdef WITH_DWARF3
+ if (loc->prologue_end) {
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_prologue_end, NULL);
+ }
+ if (loc->epilogue_begin) {
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_set_epilogue_begin,
+ NULL);
+ }
+ #endif
+
+ /* If multiple loc for the same location, use last */
+ if (nextloc && nextloc->bc->offset == loc->bc->offset)
+ return 0;
+
+ if (!state->precbc) {
+ /* Set the starting address for the section */
+ if (!loc->sym) {
+ /* shouldn't happen! */
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("could not find label prior to loc"));
+ return 1;
+ }
+ dwarf2_dbgfmt_append_line_ext_op(debug_line, DW_LNE_set_address,
+ dbgfmt_dwarf2->sizeof_address, loc->sym);
+ addr_delta = 0;
+ } else if (loc->bc) {
+ if (state->precbc->offset > loc->bc->offset)
+ yasm_internal_error(N_("dwarf2 address went backwards?"));
+ addr_delta = loc->bc->offset - state->precbc->offset;
+ } else
+ return 0; /* ran out of bytecodes! XXX: do something? */
+
+ /* Generate appropriate opcode(s). Address can only increment,
+ * whereas line number can go backwards.
+ */
+ line_delta = loc->line - state->line;
+ state->line = loc->line;
+
+ /* First handle the line delta */
+ if (line_delta < DWARF2_LINE_BASE
+ || line_delta >= DWARF2_LINE_BASE+DWARF2_LINE_RANGE) {
+ /* Won't fit in special opcode, use (signed) line advance */
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_line,
+ yasm_intnum_create_int(line_delta));
+ line_delta = 0;
+ }
+
+ /* Next handle the address delta */
+ opcode1 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE +
+ DWARF2_LINE_RANGE * (addr_delta / dbgfmt_dwarf2->min_insn_len);
+ opcode2 = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE +
+ DWARF2_LINE_RANGE * ((addr_delta - DWARF2_MAX_SPECIAL_ADDR_DELTA) /
+ dbgfmt_dwarf2->min_insn_len);
+ if (line_delta == 0 && addr_delta == 0) {
+ /* Both line and addr deltas are 0: do DW_LNS_copy */
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL);
+ } else if (addr_delta <= DWARF2_MAX_SPECIAL_ADDR_DELTA && opcode1 <= 255) {
+ /* Addr delta in range of special opcode */
+ dwarf2_dbgfmt_append_line_op(debug_line, opcode1, NULL);
+ } else if (addr_delta <= 2*DWARF2_MAX_SPECIAL_ADDR_DELTA
+ && opcode2 <= 255) {
+ /* Addr delta in range of const_add_pc + special */
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_const_add_pc, NULL);
+ dwarf2_dbgfmt_append_line_op(debug_line, opcode2, NULL);
+ } else {
+ /* Need advance_pc */
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_advance_pc,
+ yasm_intnum_create_uint(addr_delta));
+ /* Take care of any remaining line_delta and add entry to matrix */
+ if (line_delta == 0)
+ dwarf2_dbgfmt_append_line_op(debug_line, DW_LNS_copy, NULL);
+ else {
+ unsigned int opcode;
+ opcode = DWARF2_LINE_OPCODE_BASE + line_delta - DWARF2_LINE_BASE;
+ dwarf2_dbgfmt_append_line_op(debug_line, opcode, NULL);
+ }
+ }
+ state->precbc = loc->bc;
+ return 0;
+ }
+
+ typedef struct dwarf2_line_bc_info {
+ yasm_section *debug_line;
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+ dwarf2_line_state *state;
+ dwarf2_loc loc;
+ size_t lastfile;
+ } dwarf2_line_bc_info;
+
+ static int
+ dwarf2_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d)
+ {
+ dwarf2_line_bc_info *info = (dwarf2_line_bc_info *)d;
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2;
+ size_t i;
+ const char *filename;
+ /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc);
+
+ if (nextbc && bc->offset == nextbc->offset)
+ return 0;
+
+ info->loc.vline = bc->line;
+ info->loc.bc = bc;
+
+ /* Keep track of last symbol seen */
+ if (bc->symrecs) {
+ i = 0;
+ while (bc->symrecs[i]) {
+ info->loc.sym = bc->symrecs[i];
+ i++;
+ }
+ }
+
+ yasm_linemap_lookup(dbgfmt_dwarf2->linemap, bc->line, &filename,
+ &info->loc.line);
+ /* Find file index; just linear search it unless it was the last used */
+ if (info->lastfile > 0
+ && strcmp(filename, dbgfmt_dwarf2->filenames[info->lastfile-1].pathname)
+ == 0)
+ info->loc.file = info->lastfile;
+ else {
+ for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
+ if (strcmp(filename, dbgfmt_dwarf2->filenames[i].pathname) == 0)
+ break;
+ }
+ if (i >= dbgfmt_dwarf2->filenames_size)
+ yasm_internal_error(N_("could not find filename in table"));
+ info->loc.file = i+1;
+ info->lastfile = i+1;
+ }
+ if (dwarf2_dbgfmt_gen_line_op(info->debug_line, info->state, &info->loc,
+ NULL))
+ return 1;
+ return 0;
+ }
+
+ typedef struct dwarf2_line_info {
+ yasm_section *debug_line; /* section to which line number info goes */
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2;
+ yasm_errwarns *errwarns;
+
+ /* Generate based on bytecodes (1) or locs (0)? Use bytecodes if we're
+ * generating line numbers for the actual assembly source file.
+ */
+ int asm_source;
+
+ /* number of sections line number info generated for */
+ size_t num_sections;
+ /* last section line number info generated for */
+ /*@null@*/ yasm_section *last_code;
+ } dwarf2_line_info;
+
+ static int
+ dwarf2_generate_line_section(yasm_section *sect, /*@null@*/ void *d)
+ {
+ dwarf2_line_info *info = (dwarf2_line_info *)d;
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = info->dbgfmt_dwarf2;
+ /*@null@*/ dwarf2_section_data *dsd;
+ /*@null@*/ yasm_bytecode *bc;
+ dwarf2_line_state state;
+ unsigned long addr_delta;
+
+ dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb);
+ if (!dsd) {
+ if (info->asm_source && yasm_section_is_code(sect)) {
+ /* Create line data for asm code sections */
+ dsd = yasm_xmalloc(sizeof(dwarf2_section_data));
+ STAILQ_INIT(&dsd->locs);
+ yasm_section_add_data(sect, &yasm_dwarf2__section_data_cb, dsd);
+ } else
+ return 0; /* no line data for this section */
+ }
+
+ info->num_sections++;
+ info->last_code = sect;
+
+ /* initialize state machine registers for each sequence */
+ state.dbgfmt_dwarf2 = dbgfmt_dwarf2;
+ state.address = 0;
+ state.file = 1;
+ state.line = 1;
+ state.column = 0;
+ state.isa = 0;
+ state.is_stmt = DWARF2_LINE_DEFAULT_IS_STMT;
+ state.precbc = NULL;
+
+ if (info->asm_source) {
+ dwarf2_line_bc_info bcinfo;
+
+ bcinfo.debug_line = info->debug_line;
+ bcinfo.dbgfmt_dwarf2 = dbgfmt_dwarf2;
+ bcinfo.state = &state;
+ bcinfo.lastfile = 0;
+ bcinfo.loc.isa_change = 0;
+ bcinfo.loc.column = 0;
+ bcinfo.loc.is_stmt = IS_STMT_NOCHANGE;
+ bcinfo.loc.basic_block = 0;
+ bcinfo.loc.prologue_end = 0;
+ bcinfo.loc.epilogue_begin = 0;
+ bcinfo.loc.sym = NULL;
+
+ /* bcs_traverse() skips first "dummy" bytecode, so look at it
+ * separately to determine the initial symrec.
+ */
+ bc = yasm_section_bcs_first(sect);
+ if (bc->symrecs) {
+ size_t i = 0;
+ while (bc->symrecs[i]) {
+ bcinfo.loc.sym = bc->symrecs[i];
+ i++;
+ }
+ }
+
+ yasm_section_bcs_traverse(sect, info->errwarns, &bcinfo,
+ dwarf2_generate_line_bc);
+ } else {
+ /*@null@*/ dwarf2_loc *loc;
+
+ dwarf2_dbgfmt_finalize_locs(sect, dsd);
+
+ STAILQ_FOREACH(loc, &dsd->locs, link) {
+ if (dwarf2_dbgfmt_gen_line_op(info->debug_line, &state, loc,
+ STAILQ_NEXT(loc, link)))
+ return 1;
+ }
+ }
+
+ /* End sequence: bring address to end of section, then output end
+ * sequence opcode. Don't use a special opcode to do this as we don't
+ * want an extra entry in the line matrix.
+ */
+ if (!state.precbc)
+ state.precbc = yasm_section_bcs_first(sect);
+ bc = yasm_section_bcs_last(sect);
+ addr_delta = bc->offset + bc->len - state.precbc->offset;
+ if (addr_delta == DWARF2_MAX_SPECIAL_ADDR_DELTA)
+ dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_const_add_pc,
+ NULL);
+ else if (addr_delta > 0)
+ dwarf2_dbgfmt_append_line_op(info->debug_line, DW_LNS_advance_pc,
+ yasm_intnum_create_uint(addr_delta));
+ dwarf2_dbgfmt_append_line_ext_op(info->debug_line, DW_LNE_end_sequence, 0,
+ NULL);
+
+ return 0;
+ }
+
+ static int
+ dwarf2_generate_filename(const char *filename, void *d)
+ {
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = (yasm_dbgfmt_dwarf2 *)d;
+ dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, 0, filename);
+ return 0;
+ }
+
+ yasm_section *
+ yasm_dwarf2__generate_line(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2,
+ yasm_errwarns *errwarns, int asm_source,
+ /*@out@*/ yasm_section **main_code,
+ /*@out@*/ size_t *num_line_sections)
+ {
+ dwarf2_line_info info;
+ int new;
+ size_t i;
+ yasm_bytecode *last, *sppbc;
+ dwarf2_spp *spp;
+ dwarf2_head *head;
+
+ if (asm_source) {
+ /* Generate dirs and filenames based on linemap */
+ yasm_linemap_traverse_filenames(dbgfmt_dwarf2->linemap, dbgfmt_dwarf2,
+ dwarf2_generate_filename);
+ }
+
+ info.num_sections = 0;
+ info.last_code = NULL;
+ info.asm_source = asm_source;
+ info.dbgfmt_dwarf2 = dbgfmt_dwarf2;
+ info.debug_line = yasm_object_get_general(dbgfmt_dwarf2->object,
+ ".debug_line", 0, 1, 0, 0, &new,
+ 0);
+ last = yasm_section_bcs_last(info.debug_line);
+
+ /* header */
+ head = yasm_dwarf2__add_head(dbgfmt_dwarf2, info.debug_line, NULL, 0, 0);
+
+ /* statement program prologue */
+ spp = yasm_xmalloc(sizeof(dwarf2_spp));
+ spp->dbgfmt_dwarf2 = dbgfmt_dwarf2;
+ sppbc = yasm_bc_create_common(&dwarf2_spp_bc_callback, spp, 0);
+ sppbc->len = dbgfmt_dwarf2->sizeof_offset + 5 +
+ NELEMS(line_opcode_num_operands);
+
+ /* directory list */
+ for (i=0; i<dbgfmt_dwarf2->dirs_size; i++)
+ sppbc->len += strlen(dbgfmt_dwarf2->dirs[i])+1;
+ sppbc->len++;
+
+ /* filename list */
+ for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
+ if (!dbgfmt_dwarf2->filenames[i].filename) {
+ yasm_error_set(YASM_ERROR_GENERAL,
+ N_("dwarf2 file number %d unassigned"), i+1);
+ yasm_errwarn_propagate(errwarns, 0);
+ continue;
+ }
+ sppbc->len += strlen(dbgfmt_dwarf2->filenames[i].filename) + 1 +
+ yasm_size_uleb128(dbgfmt_dwarf2->filenames[i].dir) + 2;
+ }
+ sppbc->len++;
+ yasm_dwarf2__append_bc(info.debug_line, sppbc);
+
+ /* statement program */
+ yasm_object_sections_traverse(dbgfmt_dwarf2->object, (void *)&info,
+ dwarf2_generate_line_section);
+
+ /* mark end of line information */
+ yasm_dwarf2__set_head_end(head, yasm_section_bcs_last(info.debug_line));
+
+ *num_line_sections = info.num_sections;
+ if (info.num_sections == 1)
+ *main_code = info.last_code;
+ else
+ *main_code = NULL;
+ return info.debug_line;
+ }
+
+ static void
+ dwarf2_spp_bc_destroy(void *contents)
+ {
+ yasm_xfree(contents);
+ }
+
+ static void
+ dwarf2_spp_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
- yasm_internal_error(N_("tried to resolve a dwarf2 spp bytecode"));
++static int
++dwarf2_spp_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
- return YASM_BC_RESOLVE_MIN_LEN;
++ yasm_internal_error(N_("tried to calc_len a dwarf2 spp bytecode"));
+ /*@notreached@*/
-static yasm_bc_resolve_flags
-dwarf2_line_op_bc_resolve(yasm_bytecode *bc, int save,
- yasm_calc_bc_dist_func calc_bc_dist)
++ return 0;
+ }
+
+ static int
+ dwarf2_spp_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+ {
+ dwarf2_spp *spp = (dwarf2_spp *)bc->contents;
+ yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2 = spp->dbgfmt_dwarf2;
+ unsigned char *buf = *bufp;
+ yasm_intnum *cval;
+ size_t i, len;
+
+ /* Prologue length (following this field) */
+ cval = yasm_intnum_create_uint(bc->len - (buf-*bufp) -
+ dbgfmt_dwarf2->sizeof_offset);
+ yasm_arch_intnum_tobytes(dbgfmt_dwarf2->arch, cval, buf,
+ dbgfmt_dwarf2->sizeof_offset,
+ dbgfmt_dwarf2->sizeof_offset*8, 0, bc, 0);
+ buf += dbgfmt_dwarf2->sizeof_offset;
+
+ YASM_WRITE_8(buf, dbgfmt_dwarf2->min_insn_len); /* minimum_instr_len */
+ YASM_WRITE_8(buf, DWARF2_LINE_DEFAULT_IS_STMT); /* default_is_stmt */
+ YASM_WRITE_8(buf, DWARF2_LINE_BASE); /* line_base */
+ YASM_WRITE_8(buf, DWARF2_LINE_RANGE); /* line_range */
+ YASM_WRITE_8(buf, DWARF2_LINE_OPCODE_BASE); /* opcode_base */
+
+ /* Standard opcode # operands array */
+ for (i=0; i<NELEMS(line_opcode_num_operands); i++)
+ YASM_WRITE_8(buf, line_opcode_num_operands[i]);
+
+ /* directory list */
+ for (i=0; i<dbgfmt_dwarf2->dirs_size; i++) {
+ len = strlen(dbgfmt_dwarf2->dirs[i])+1;
+ memcpy(buf, dbgfmt_dwarf2->dirs[i], len);
+ buf += len;
+ }
+ /* finish with single 0 byte */
+ YASM_WRITE_8(buf, 0);
+
+ /* filename list */
+ for (i=0; i<dbgfmt_dwarf2->filenames_size; i++) {
+ len = strlen(dbgfmt_dwarf2->filenames[i].filename)+1;
+ memcpy(buf, dbgfmt_dwarf2->filenames[i].filename, len);
+ buf += len;
+
+ /* dir */
+ buf += yasm_get_uleb128(dbgfmt_dwarf2->filenames[i].dir, buf);
+ YASM_WRITE_8(buf, 0); /* time */
+ YASM_WRITE_8(buf, 0); /* length */
+ }
+ /* finish with single 0 byte */
+ YASM_WRITE_8(buf, 0);
+
+ *bufp = buf;
+
+ yasm_intnum_destroy(cval);
+ return 0;
+ }
+
+ static void
+ dwarf2_line_op_bc_destroy(void *contents)
+ {
+ dwarf2_line_op *line_op = (dwarf2_line_op *)contents;
+ if (line_op->operand)
+ yasm_intnum_destroy(line_op->operand);
+ yasm_xfree(contents);
+ }
+
+ static void
+ dwarf2_line_op_bc_print(const void *contents, FILE *f, int indent_level)
+ {
+ /* TODO */
+ }
+
- yasm_internal_error(N_("tried to resolve a dwarf2 line_op bytecode"));
++static int
++dwarf2_line_op_bc_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
++ void *add_span_data)
+ {
- return YASM_BC_RESOLVE_MIN_LEN;
++ yasm_internal_error(N_("tried to calc_len a dwarf2 line_op bytecode"));
+ /*@notreached@*/
++ return 0;
+ }
+
+ static int
+ dwarf2_line_op_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+ yasm_output_value_func output_value,
+ yasm_output_reloc_func output_reloc)
+ {
+ dwarf2_line_op *line_op = (dwarf2_line_op *)bc->contents;
+ unsigned char *buf = *bufp;
+
+ YASM_WRITE_8(buf, line_op->opcode);
+ if (line_op->operand)
+ buf += yasm_intnum_get_leb128(line_op->operand, buf,
+ line_op->opcode == DW_LNS_advance_line);
+ if (line_op->ext_opcode > 0) {
+ YASM_WRITE_8(buf, line_op->ext_opcode);
+ if (line_op->ext_operand) {
+ yasm_value value;
+ yasm_value_init_sym(&value, line_op->ext_operand,
+ line_op->ext_operandsize*8);
+ output_value(&value, buf, line_op->ext_operandsize,
+ (unsigned long)(buf-*bufp), bc, 0, d);
+ buf += line_op->ext_operandsize;
+ }
+ }
+
+ *bufp = buf;
+ return 0;
+ }
+
+ int
+ yasm_dwarf2__line_directive(yasm_dbgfmt_dwarf2 *dbgfmt_dwarf2,
+ const char *name, yasm_section *sect,
+ yasm_valparamhead *valparams, unsigned long line)
+ {
+ if (yasm__strcasecmp(name, "loc") == 0) {
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
+ dwarf2_section_data *dsd;
+ dwarf2_loc *loc = yasm_xmalloc(sizeof(dwarf2_loc));
+
+ /* File number (required) */
+ yasm_valparam *vp = yasm_vps_first(valparams);
+ if (!vp || !vp->param) {
+ yasm_error_set(YASM_ERROR_SYNTAX, N_("file number required"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ intn = yasm_expr_get_intnum(&vp->param, NULL);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("file number is not a constant"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ if (yasm_intnum_sign(intn) != 1) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("file number less than one"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ loc->file = yasm_intnum_get_uint(intn);
+
+ /* Line number (required) */
+ vp = yasm_vps_next(vp);
+ if (!vp || !vp->param) {
+ yasm_error_set(YASM_ERROR_SYNTAX, N_("line number required"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ intn = yasm_expr_get_intnum(&vp->param, NULL);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("file number is not a constant"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ loc->line = yasm_intnum_get_uint(intn);
+
+ /* Generate new section data if it doesn't already exist */
+ dsd = yasm_section_get_data(sect, &yasm_dwarf2__section_data_cb);
+ if (!dsd) {
+ dsd = yasm_xmalloc(sizeof(dwarf2_section_data));
+ STAILQ_INIT(&dsd->locs);
+ yasm_section_add_data(sect, &yasm_dwarf2__section_data_cb, dsd);
+ }
+
+ /* Defaults for optional settings */
+ loc->column = 0;
+ loc->isa_change = 0;
+ loc->isa = 0;
+ loc->is_stmt = IS_STMT_NOCHANGE;
+ loc->basic_block = 0;
+ loc->prologue_end = 0;
+ loc->epilogue_begin = 0;
+
+ /* Optional column number */
+ vp = yasm_vps_next(vp);
+ if (vp && vp->param) {
+ intn = yasm_expr_get_intnum(&vp->param, NULL);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("column number is not a constant"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ loc->column = yasm_intnum_get_uint(intn);
+ vp = yasm_vps_next(vp);
+ }
+
+ /* Other options */
+ while (vp && vp->val) {
+ if (yasm__strcasecmp(vp->val, "basic_block") == 0)
+ loc->basic_block = 1;
+ else if (yasm__strcasecmp(vp->val, "prologue_end") == 0)
+ loc->prologue_end = 1;
+ else if (yasm__strcasecmp(vp->val, "epilogue_begin") == 0)
+ loc->epilogue_begin = 1;
+ else if (yasm__strcasecmp(vp->val, "is_stmt") == 0) {
+ if (!vp->param) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("is_stmt requires value"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ intn = yasm_expr_get_intnum(&vp->param, NULL);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("is_stmt value is not a constant"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ if (yasm_intnum_is_zero(intn))
+ loc->is_stmt = IS_STMT_SET;
+ else if (yasm_intnum_is_pos1(intn))
+ loc->is_stmt = IS_STMT_CLEAR;
+ else {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("is_stmt value not 0 or 1"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ } else if (yasm__strcasecmp(vp->val, "isa") == 0) {
+ if (!vp->param) {
+ yasm_error_set(YASM_ERROR_SYNTAX, N_("isa requires value"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ intn = yasm_expr_get_intnum(&vp->param, NULL);
+ if (!intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("isa value is not a constant"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ if (yasm_intnum_sign(intn) < 0) {
+ yasm_error_set(YASM_ERROR_VALUE,
+ N_("isa value less than zero"));
+ yasm_xfree(loc);
+ return 0;
+ }
+ loc->isa_change = 1;
+ loc->isa = yasm_intnum_get_uint(intn);
+ } else
+ yasm_warn_set(YASM_WARN_GENERAL,
+ N_("unrecognized loc option `%s'"), vp->val);
+ }
+
+ /* Append new location */
+ loc->vline = line;
+ loc->bc = NULL;
+ loc->sym = NULL;
+ STAILQ_INSERT_TAIL(&dsd->locs, loc, link);
+
+ return 0;
+ } else if (yasm__strcasecmp(name, "file") == 0) {
+ /*@dependent@*/ /*@null@*/ const yasm_intnum *file_intn;
+ size_t filenum;
+
+ yasm_valparam *vp = yasm_vps_first(valparams);
+
+ if (vp->val) {
+ /* Just a bare filename */
+ yasm_object_set_source_fn(dbgfmt_dwarf2->object, vp->val);
+ return 0;
+ }
+
+ /* Otherwise.. first vp is the file number */
+ file_intn = yasm_expr_get_intnum(&vp->param, NULL);
+ if (!file_intn) {
+ yasm_error_set(YASM_ERROR_NOT_CONSTANT,
+ N_("file number is not a constant"));
+ return 0;
+ }
+ filenum = (size_t)yasm_intnum_get_uint(file_intn);
+
+ vp = yasm_vps_next(vp);
+ if (!vp || !vp->val) {
+ yasm_error_set(YASM_ERROR_SYNTAX,
+ N_("file number given but no filename"));
+ return 0;
+ }
+
+ dwarf2_dbgfmt_add_file(dbgfmt_dwarf2, filenum, vp->val);
+ return 0;
+ }
+ return 1;
+ }
+