From a7b6bfca683d7679423d5723aa799c1ac889ee00 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 3 May 2017 17:32:02 -0700 Subject: [PATCH] Sanitize the handling of segments a bit Make the internal handling of segment numbers just a little more sane. The whole use of when we have done ofmt->segbase or not is crazy, though... In the meantime, add a few more hacks to the dbg output format to make it more useful. Signed-off-by: H. Peter Anvin --- asm/assemble.c | 123 ++++++++++++++++++++++++++++------------------ asm/directiv.dat | 1 + asm/listing.c | 18 +++++-- include/nasm.h | 1 + output/legacy.c | 16 +++++- output/outdbg.c | 83 ++++++++++++++++++++++--------- output/outdbg.mac | 53 ++++++++++++++++++++ test/objtest.asm | 6 ++- 8 files changed, 222 insertions(+), 79 deletions(-) create mode 100644 output/outdbg.mac diff --git a/asm/assemble.c b/asm/assemble.c index 73d2e171c..4f9cead2f 100644 --- a/asm/assemble.c +++ b/asm/assemble.c @@ -342,13 +342,12 @@ static void out(struct out_data *data) { static int32_t lineno = 0; /* static!!! */ static const char *lnfname = NULL; - int asize; - const int amax = ofmt->maxbits >> 3; /* Maximum address size in bytes */ union { uint8_t b[8]; uint64_t q; } xdata; - uint64_t size = data->size; + size_t asize, amax; + uint64_t zeropad = 0; int64_t addrval; int32_t fixseg; /* Segment for which to produce fixed data */ @@ -371,27 +370,29 @@ static void out(struct out_data *data) goto address; address: + nasm_assert(data->size <= 8); asize = data->size; - nasm_assert(asize <= 8); + amax = ofmt->maxbits >> 3; /* Maximum address size in bytes */ if (data->tsegment == fixseg && data->twrt == NO_SEG) { - uint8_t *q = xdata.b; - warn_overflow_out(addrval, asize, data->sign); - - WRITEADDR(q, addrval, asize); + xdata.q = htole64(addrval); data->data = xdata.b; data->type = OUT_RAWDATA; - asize = 0; /* No longer an address */ + asize = amax = 0; /* No longer an address */ } break; + case OUT_SEGMENT: + nasm_assert(data->size <= 8); + asize = data->size; + amax = 2; + break; + default: - asize = 0; /* Not an address */ + asize = amax = 0; /* Not an address */ break; } - lfmt->output(data); - /* * this call to src_get determines when we call the * debug-format-specific "linenum" function @@ -404,28 +405,35 @@ static void out(struct out_data *data) if (src_get(&lineno, &lnfname)) dfmt->linenum(lnfname, lineno, data->segment); - if (asize && asize > amax) { - if (data->type != OUT_ADDRESS || data->sign == OUT_SIGNED) { + if (asize > amax) { + if (data->type == OUT_RELADDR || data->sign == OUT_SIGNED) { nasm_error(ERR_NONFATAL, - "%d-bit signed relocation unsupported by output format %s\n", - asize << 3, ofmt->shortname); + "%u-bit signed relocation unsupported by output format %s", + (unsigned int)(asize << 3), ofmt->shortname); } else { nasm_error(ERR_WARNING | ERR_WARN_ZEXTRELOC, - "%d-bit unsigned relocation zero-extended from %d bits\n", - asize << 3, ofmt->maxbits); - data->size = amax; - ofmt->output(data); - data->insoffs += amax; - data->offset += amax; - data->size = size = asize - amax; + "%u-bit %s relocation zero-extended from %u bits", + (unsigned int)(asize << 3), + data->type == OUT_SEGMENT ? "segment" : "unsigned", + (unsigned int)(amax << 3)); } - data->data = zero_buffer; - data->type = OUT_RAWDATA; + zeropad = data->size - amax; + data->size = amax; } - + lfmt->output(data); ofmt->output(data); - data->offset += size; - data->insoffs += size; + data->offset += data->size; + data->insoffs += data->size; + + if (zeropad) { + data->type = OUT_ZERODATA; + data->size = zeropad; + lfmt->output(data); + ofmt->output(data); + data->offset += zeropad; + data->insoffs += zeropad; + data->size += zeropad; /* Restore original size value */ + } } static inline void out_rawdata(struct out_data *data, const void *rawdata, @@ -452,13 +460,37 @@ static inline void out_reserve(struct out_data *data, uint64_t size) out(data); } -static inline void out_imm(struct out_data *data, const struct operand *opx, - int size, enum out_sign sign) +static void out_segment(struct out_data *data, const struct operand *opx) { - data->type = - (opx->opflags & OPFLAG_RELATIVE) ? OUT_RELADDR : OUT_ADDRESS; + if (opx->opflags & OPFLAG_RELATIVE) + nasm_error(ERR_NONFATAL, "segment references cannot be relative"); + + data->type = OUT_SEGMENT; + data->sign = OUT_UNSIGNED; + data->size = 2; + data->toffset = opx->offset; + data->tsegment = ofmt->segbase(opx->segment | 1); + data->twrt = opx->wrt; + out(data); +} + +static void out_imm(struct out_data *data, const struct operand *opx, + int size, enum out_sign sign) +{ + if (opx->segment != NO_SEG && (opx->segment & 1)) { + /* + * This is actually a segment reference, but eval() has + * already called ofmt->segbase() for us. Sigh. + */ + if (size < 2) + nasm_error(ERR_NONFATAL, "segment reference must be 16 bits"); + + data->type = OUT_SEGMENT; + } else { + data->type = (opx->opflags & OPFLAG_RELATIVE) + ? OUT_RELADDR : OUT_ADDRESS; + } data->sign = sign; - data->size = size; data->toffset = opx->offset; data->tsegment = opx->segment; data->twrt = opx->wrt; @@ -470,6 +502,7 @@ static inline void out_imm(struct out_data *data, const struct operand *opx, * already occurred. */ data->relbase = 0; + data->size = size; out(data); } @@ -489,18 +522,6 @@ static void out_reladdr(struct out_data *data, const struct operand *opx, out(data); } -static inline void out_segment(struct out_data *data, - const struct operand *opx) -{ - data->type = OUT_SEGMENT; - data->sign = OUT_UNSIGNED; - data->size = 2; - data->toffset = opx->offset; /* Is this really needed/wanted? */ - data->tsegment = ofmt->segbase(opx->segment + 1); - data->twrt = opx->wrt; - out(data); -} - static bool jmp_match(int32_t segment, int64_t offset, int bits, insn * ins, const struct itemplate *temp) { @@ -552,7 +573,6 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction) data.offset = start; data.segment = segment; data.itemp = NULL; - data.sign = OUT_WRAP; data.bits = bits; wsize = db_bytes(instruction->opcode); @@ -570,12 +590,19 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction) " instruction"); } else { data.insoffs = 0; - data.type = e->relative ? OUT_RELADDR : OUT_ADDRESS; data.inslen = data.size = wsize; data.toffset = e->offset; - data.tsegment = e->segment; data.twrt = e->wrt; data.relbase = 0; + if (e->segment != NO_SEG && (e->segment & 1)) { + data.tsegment = e->segment; + data.type = OUT_SEGMENT; + data.sign = OUT_UNSIGNED; + } else { + data.tsegment = e->segment; + data.type = e->relative ? OUT_RELADDR : OUT_ADDRESS; + data.sign = OUT_WRAP; + } out(&data); } } else if (e->type == EOT_DB_STRING || diff --git a/asm/directiv.dat b/asm/directiv.dat index 4c23c711e..da743a86d 100644 --- a/asm/directiv.dat +++ b/asm/directiv.dat @@ -89,3 +89,4 @@ uppercase ; outieee, outobj subsections_via_symbols ; macho no_dead_strip ; macho maxdump ; dbg +noseclabels ; dbg diff --git a/asm/listing.c b/asm/listing.c index 05ef00122..9409aa90c 100644 --- a/asm/listing.c +++ b/asm/listing.c @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------- * - * + * * Copyright 1996-2016 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. @@ -14,7 +14,7 @@ * 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 COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF @@ -114,7 +114,7 @@ static void list_emit(void) fprintf(listfp, "%6"PRId32" ", listlineno); for (i = 0; i < LIST_HEXBIT; i++) putc('*', listfp); - + if (listlevel_e) fprintf(listfp, " %s<%d>", (listlevel < 10 ? " " : ""), listlevel_e); @@ -202,15 +202,23 @@ static void list_output(const struct out_data *data) char q[20]; uint64_t size = data->size; uint64_t offset = data->offset; + const uint8_t *p = data->data; + if (!listp || suppress || user_nolist) return; switch (data->type) { + case OUT_ZERODATA: + if (size > 16) { + snprintf(q, sizeof(q), "", size); + list_out(offset, q); + } else { + p = zero_buffer; + /* fall through */ + } case OUT_RAWDATA: { - const uint8_t *p = data->data; - if (size == 0 && !listdata[0]) listoffset = data->offset; while (size--) { diff --git a/include/nasm.h b/include/nasm.h index a50062efc..9abfe5d9f 100644 --- a/include/nasm.h +++ b/include/nasm.h @@ -88,6 +88,7 @@ struct ofmt; enum out_type { OUT_RAWDATA, /* Plain bytes */ OUT_RESERVE, /* Reserved bytes (RESB et al) */ + OUT_ZERODATA, /* Initialized data, but all zero */ OUT_ADDRESS, /* An address (symbol value) */ OUT_RELADDR, /* A relative address */ OUT_SEGMENT, /* A segment number */ diff --git a/output/legacy.c b/output/legacy.c index 38d6d7e03..39793205e 100644 --- a/output/legacy.c +++ b/output/legacy.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 2016 The NASM Authors - All Rights Reserved + * Copyright 2016-2017 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -89,8 +89,9 @@ void nasm_do_legacy_output(const struct out_data *data) case OUT_SEGMENT: type = OUT_ADDRESS; - dptr = &zero_buffer; + dptr = zero_buffer; size = (data->sign == OUT_SIGNED) ? -data->size : data->size; + tsegment |= 1; break; case OUT_ADDRESS: @@ -103,6 +104,17 @@ void nasm_do_legacy_output(const struct out_data *data) tsegment = twrt = NO_SEG; break; + case OUT_ZERODATA: + tsegment = twrt = NO_SEG; + type = OUT_RAWDATA; + dptr = zero_buffer; + while (size > ZERO_BUF_SIZE) { + ofmt->legacy_output(data->segment, dptr, type, + ZERO_BUF_SIZE, tsegment, twrt); + size -= ZERO_BUF_SIZE; + } + break; + default: panic(); break; diff --git a/output/outdbg.c b/output/outdbg.c index 130c9d72e..139955957 100644 --- a/output/outdbg.c +++ b/output/outdbg.c @@ -59,6 +59,7 @@ struct Section { } *dbgsect; static unsigned long dbg_max_data_dump = 128; +static bool section_labels = true; const struct ofmt of_dbg; static void dbg_init(void) @@ -78,7 +79,8 @@ static void dbg_cleanup(void) } } -static int32_t dbg_section_names(char *name, int pass, int *bits) +static int32_t dbg_add_section(char *name, int pass, int *bits, + const char *whatwecallit) { int seg; @@ -88,12 +90,13 @@ static int32_t dbg_section_names(char *name, int pass, int *bits) if (!name) *bits = 16; - if (!name) + if (!name) { fprintf(ofile, "section_name on init: returning %d\n", seg = seg_alloc()); - else { + } else { int n = strcspn(name, " \t"); char *sname = nasm_strndup(name, n); + char *tail = nasm_skip_spaces(name+n); struct Section *s; seg = NO_SEG; @@ -107,13 +110,21 @@ static int32_t dbg_section_names(char *name, int pass, int *bits) s->number = seg = seg_alloc(); s->next = dbgsect; dbgsect = s; - fprintf(ofile, "section_name %s (pass %d): returning %d\n", - name, pass, seg); + fprintf(ofile, "%s %s (%s) pass %d: returning %d\n", + whatwecallit, name, tail, pass, seg); + + if (section_labels) + define_label(s->name, s->number + 1, 0, NULL, false, false); } } return seg; } +static int32_t dbg_section_names(char *name, int pass, int *bits) +{ + return dbg_add_section(name, pass, bits, "section_names"); +} + static void dbg_deflabel(char *name, int32_t segment, int64_t offset, int is_global, char *special) { @@ -128,6 +139,7 @@ static const char *out_type(enum out_type type) static const char *out_types[] = { "rawdata", "reserve", + "zerodata", "address", "reladdr", "segment" @@ -288,6 +300,23 @@ static int32_t dbg_segbase(int32_t segment) static enum directive_result dbg_directive(enum directive directive, char *value, int pass) { + switch (directive) { + /* + * The .obj GROUP directive is nontrivial to emulate in a macro. + * It effectively creates a "pseudo-section" containing the first + * space-separated argument; the rest we ignore. + */ + case D_GROUP: + { + int dummy; + dbg_add_section(value, pass, &dummy, "directive:group"); + break; + } + + default: + break; + } + fprintf(ofile, "directive [%s] value [%s] (pass %d)\n", directive_dname(directive), value, pass); return DIRR_OK; @@ -309,26 +338,34 @@ dbg_pragma(const struct pragma *pragma) pragma->opname, directive_dname(pragma->opcode), pragma->tail); - if (pragma->facility == &dbg_pragma_list[0] && - pragma->opcode == D_MAXDUMP) { - if (!nasm_stricmp(pragma->tail, "unlimited")) { - dbg_max_data_dump = -1UL; - } else { - char *ep; - unsigned long arg; - - errno = 0; - arg = strtoul(pragma->tail, &ep, 0); - if (errno || *nasm_skip_spaces(ep)) { - nasm_error(ERR_WARNING | ERR_WARN_BAD_PRAGMA | ERR_PASS2, - "invalid %%pragma dbg maxdump argument"); - return DIRR_ERROR; + if (pragma->facility == &dbg_pragma_list[0]) { + switch (pragma->opcode) { + case D_MAXDUMP: + if (!nasm_stricmp(pragma->tail, "unlimited")) { + dbg_max_data_dump = -1UL; } else { - dbg_max_data_dump = arg; + char *ep; + unsigned long arg; + + errno = 0; + arg = strtoul(pragma->tail, &ep, 0); + if (errno || *nasm_skip_spaces(ep)) { + nasm_error(ERR_WARNING | ERR_WARN_BAD_PRAGMA | ERR_PASS2, + "invalid %%pragma dbg maxdump argument"); + return DIRR_ERROR; + } else { + dbg_max_data_dump = arg; + } } + break; + case D_NOSECLABELS: + section_labels = false; + break; + + default: + break; } } - return DIRR_OK; } @@ -401,6 +438,8 @@ static const struct dfmt * const debug_debug_arr[3] = { NULL }; +extern macros_t dbg_stdmac[]; + const struct ofmt of_dbg = { "Trace of all info passed to output stage", "dbg", @@ -408,7 +447,7 @@ const struct ofmt of_dbg = { 64, debug_debug_arr, &debug_debug_form, - NULL, + dbg_stdmac, dbg_init, dbg_out, dbg_legacy_out, diff --git a/output/outdbg.mac b/output/outdbg.mac new file mode 100644 index 000000000..4f68d63cd --- /dev/null +++ b/output/outdbg.mac @@ -0,0 +1,53 @@ +;; -------------------------------------------------------------------------- +;; +;; Copyright 1996-2017 The NASM Authors - All Rights Reserved +;; See the file AUTHORS included with the NASM distribution for +;; the specific copyright holders. +;; +;; Redistribution and use in source and binary forms, with or without +;; modification, are permitted provided that the following +;; conditions are met: +;; +;; * Redistributions of source code must retain the above copyright +;; notice, this list of conditions and the following disclaimer. +;; * 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 COPYRIGHT HOLDERS AND +;; 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 COPYRIGHT OWNER OR +;; 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 a few macros which lets the dbg format process files intended +; for the .obj format. +; +OUT: dbg +%define __SECT__ [section .text] +%imacro group 1+.nolist +[group %1] +%endmacro +%imacro uppercase 0+.nolist + %pragma dbg uppercase %1 +%endmacro +%imacro export 1+.nolist + %pragma dbg export %1 +%endmacro +%imacro import 1+.nolist + %pragma dbg import %1 +%endmacro +%macro __NASM_CDecl__ 1 +%endmacro diff --git a/test/objtest.asm b/test/objtest.asm index 03b7f9e28..c68f7cbbe 100644 --- a/test/objtest.asm +++ b/test/objtest.asm @@ -35,8 +35,8 @@ common _commvar 2 ; [3] extern _printf ; [6] - group mygroup mybss mydata ; [10] - group mygroup2 mycode mycode2 ; [10] + group mygroup mybss mydata + group mygroup2 mycode mycode2 segment mycode private @@ -67,6 +67,8 @@ _function push bp retf .printf dw _printf, seg _printf ; [2] [4] [16] +.printfd dd _printf, seg _printf ; [2] [4] [16] +.printfq dq _printf, seg _printf ; [2] [4] [16] segment mycode2 private