data: replace data->sign with a flags field

Signed and unsigned are really two flags; might as well allow this
field to contain additional flags.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin (Intel) 2020-07-09 20:58:10 -07:00
parent f399172a83
commit 79fd2b9645
4 changed files with 67 additions and 56 deletions

View file

@ -301,24 +301,16 @@ static void warn_overflow_const(int64_t data, int size)
warn_overflow(size);
}
static void warn_overflow_out(int64_t data, int size, enum out_sign sign)
static void warn_overflow_out(int64_t data, int size, enum out_flags flags)
{
bool err;
switch (sign) {
case OUT_WRAP:
err = overflow_general(data, size);
break;
case OUT_SIGNED:
if (flags & OUT_SIGNED)
err = overflow_signed(data, size);
break;
case OUT_UNSIGNED:
else if (flags & OUT_UNSIGNED)
err = overflow_unsigned(data, size);
break;
default:
panic();
break;
}
else
err = overflow_general(data, size);
if (err)
warn_overflow(size);
@ -393,11 +385,14 @@ static void out(struct out_data *data)
nasm_assert(data->size <= 8);
asize = data->size;
amax = ofmt->maxbits >> 3; /* Maximum address size in bytes */
if ((ofmt->flags & OFMT_KEEP_ADDR) == 0 && data->tsegment == fixseg &&
if (!(ofmt->flags & OFMT_KEEP_ADDR) &&
data->tsegment == fixseg &&
data->twrt == NO_SEG) {
if (asize >= (size_t)(data->bits >> 3))
data->sign = OUT_WRAP; /* Support address space wrapping for low-bit modes */
warn_overflow_out(addrval, asize, data->sign);
if (asize >= (size_t)(data->bits >> 3)) {
/* Support address space wrapping for low-bit modes */
data->flags &= ~OUT_SIGNMASK;
}
warn_overflow_out(addrval, asize, data->flags);
xdata.q = cpu_to_le64(addrval);
data->data = xdata.b;
data->type = OUT_RAWDATA;
@ -428,7 +423,7 @@ static void out(struct out_data *data)
dfmt->linenum(lnfname, lineno, data->segment);
if (asize > amax) {
if (data->type == OUT_RELADDR || data->sign == OUT_SIGNED) {
if (data->type == OUT_RELADDR || (data->flags & OUT_SIGNED)) {
nasm_nonfatal("%u-bit signed relocation unsupported by output format %s",
(unsigned int)(asize << 3), ofmt->shortname);
} else {
@ -506,17 +501,17 @@ static void out_segment(struct out_data *data, const struct operand *opx)
if (opx->opflags & OPFLAG_RELATIVE)
nasm_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;
data->type = OUT_SEGMENT;
data->flags = 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)
int size, enum out_flags sign)
{
if (opx->segment != NO_SEG && (opx->segment & 1)) {
/*
@ -531,10 +526,10 @@ static void out_imm(struct out_data *data, const struct operand *opx,
data->type = (opx->opflags & OPFLAG_RELATIVE)
? OUT_RELADDR : OUT_ADDRESS;
}
data->sign = sign;
data->toffset = opx->offset;
data->flags = sign;
data->toffset = opx->offset;
data->tsegment = opx->segment;
data->twrt = opx->wrt;
data->twrt = opx->wrt;
/*
* XXX: improve this if at some point in the future we can
* distinguish the subtrahend in expressions like [foo - bar]
@ -553,13 +548,13 @@ static void out_reladdr(struct out_data *data, const struct operand *opx,
if (opx->opflags & OPFLAG_RELATIVE)
nasm_nonfatal("invalid use of self-relative expression");
data->type = OUT_RELADDR;
data->sign = OUT_SIGNED;
data->size = size;
data->toffset = opx->offset;
data->type = OUT_RELADDR;
data->flags = OUT_SIGNED;
data->size = size;
data->toffset = opx->offset;
data->tsegment = opx->segment;
data->twrt = opx->wrt;
data->relbase = data->offset + (data->inslen - data->insoffs);
data->twrt = opx->wrt;
data->relbase = data->offset + (data->inslen - data->insoffs);
out(data);
}
@ -660,12 +655,12 @@ static void out_eops(struct out_data *data, const extop *e)
data->relbase = 0;
if (e->val.num.segment != NO_SEG &&
(e->val.num.segment & 1)) {
data->type = OUT_SEGMENT;
data->sign = OUT_UNSIGNED;
data->type = OUT_SEGMENT;
data->flags = OUT_UNSIGNED;
} else {
data->type = e->val.num.relative
? OUT_RELADDR : OUT_ADDRESS;
data->sign = OUT_WRAP;
data->flags = OUT_WRAP;
}
out(data);
}

View file

@ -111,10 +111,11 @@ enum out_type {
OUT_REL8ADR
};
enum out_sign {
OUT_WRAP, /* Undefined signedness (wraps) */
OUT_SIGNED, /* Value is signed */
OUT_UNSIGNED /* Value is unsigned */
enum out_flags {
OUT_WRAP = 0, /* Undefined signedness (wraps) */
OUT_SIGNED = 1, /* Value is signed */
OUT_UNSIGNED = 2, /* Value is unsigned */
OUT_SIGNMASK = 3 /* Mask for signedness bits */
};
/*
@ -126,7 +127,7 @@ struct out_data {
int64_t offset; /* Offset within segment */
int32_t segment; /* Segment written to */
enum out_type type; /* See above */
enum out_sign sign; /* See above */
enum out_flags flags; /* See above */
int inslen; /* Length of instruction */
int insoffs; /* Offset inside instruction */
int bits; /* Bits mode of compilation */
@ -908,7 +909,7 @@ struct ofmt {
* It is allowed to modify the string it is given a pointer to.
*
* It is also allowed to specify a default instruction size for
* the segment, by setting `*bits' to 16 or 32. Or, if it
* the segment, by setting `*bits' to 16, 32 or 64. Or, if it
* doesn't wish to define a default, it can leave `bits' alone.
*/
int32_t (*section)(char *name, int *bits);

View file

@ -90,13 +90,13 @@ void nasm_do_legacy_output(const struct out_data *data)
case OUT_SEGMENT:
type = OUT_ADDRESS;
dptr = zero_buffer;
size = (data->sign == OUT_SIGNED) ? -data->size : data->size;
size = (data->flags & OUT_SIGNED) ? -data->size : data->size;
tsegment |= 1;
break;
case OUT_ADDRESS:
dptr = &data->toffset;
size = (data->sign == OUT_SIGNED) ? -data->size : data->size;
size = (data->flags & OUT_SIGNED) ? -data->size : data->size;
break;
case OUT_RAWDATA:

View file

@ -181,30 +181,45 @@ static const char *out_type(enum out_type type)
return out_types[type];
}
static const char *out_sign(enum out_sign sign)
static const char *out_flags(enum out_flags flags)
{
static const char *out_signs[] = {
"wrap",
static const char *out_flags[] = {
"signed",
"unsigned"
};
static char invalid_buf[64];
static char flags_buf[1024];
unsigned long flv = flags;
size_t n;
size_t left = sizeof flags_buf - 1;
char *p = flags_buf;
unsigned int i;
if (sign >= sizeof(out_signs)/sizeof(out_signs[0])) {
sprintf(invalid_buf, "[invalid sign %d]", sign);
return invalid_buf;
for (i = 0; flv; flv >>= 1, i++) {
if (flv & 1) {
if (i < ARRAY_SIZE(out_flags))
n = snprintf(p, left, "%s,", out_flags[i]);
else
n = snprintf(p, left, "%u,", i);
if (n >= left)
break;
left -= n;
p += n;
}
}
if (p > flags_buf)
p--; /* Delete final comma */
*p = '\0';
return out_signs[sign];
return flags_buf;
}
static void dbg_out(const struct out_data *data)
{
fprintf(ofile,
"out to %"PRIx32":%"PRIx64" %s %s bits %d insoffs %d/%d "
"out to %"PRIx32":%"PRIx64" %s(%s) bits %d insoffs %d/%d "
"size %"PRIu64,
data->segment, data->offset,
out_type(data->type), out_sign(data->sign),
out_type(data->type), out_flags(data->flags),
data->bits, data->insoffs, data->inslen, data->size);
if (data->itemp) {
fprintf(ofile, " ins %s(%d)",
@ -521,7 +536,7 @@ const struct ofmt of_dbg = {
"Trace of all info passed to output stage",
"dbg",
".dbg",
OFMT_TEXT,
OFMT_TEXT|OFMT_KEEP_ADDR,
64,
debug_debug_arr,
&debug_debug_form,