mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-04-12 18:40:23 +08:00
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 <hpa@linux.intel.com>
This commit is contained in:
parent
09a3f8d18a
commit
a7b6bfca68
123
asm/assemble.c
123
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 ||
|
||||
|
@ -89,3 +89,4 @@ uppercase ; outieee, outobj
|
||||
subsections_via_symbols ; macho
|
||||
no_dead_strip ; macho
|
||||
maxdump ; dbg
|
||||
noseclabels ; dbg
|
||||
|
@ -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), "<zero %08"PRIX64">", 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--) {
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
53
output/outdbg.mac
Normal file
53
output/outdbg.mac
Normal file
@ -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
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user