The testcase illustrates the problem. After "nasm -f obj
alonesym.nasm"
let's look to dump:
======
PUBDEF386(91) recnum:5, offset:0000005bh, len:03f9h, chksum:bbh(bb)
Group: 0, Seg: 1
00020000h - 'sym0000' Type:0
00020004h - 'sym0001' Type:0
....
00020134h - 'sym0077' Type:0
PUBDEF(90) recnum:6, offset:00000457h, len:000ah, chksum:b6h(b6)
Group: 0, Seg: 1
00000138h - 's' Type:2
0000b600h - '' Type:0
======
The problem is while 's' offset is 20138h it is marked as type 90h not
91h. The root cause is located in obj_x():
static ObjRecord *obj_x(ObjRecord * orp, uint32_t val)
{
if (orp->type & 1)
orp->x_size = 32;
if (val > 0xFFFF)
orp = obj_force(orp, 32);
if (orp->x_size == 32)
return (obj_dword(orp, val));
orp->x_size = 16;
return (obj_word(orp, val));
}
It sets up x_size and than writes data. In the testcase data are the
offset and this offset overflows a record. In this case the record is
emitted and its x_size is cleared. Because this is last PUBDEF the new
record with only 's' symbol is emitted also but its x_size is not 32
(it's still zero) so obj_fwrite doesn't switch to 91h type.
The problem seems to be very generic and expected to be occurred on
many other record types as well.
----
And the fix is simple:
if (orp->x_size == 32)
{
ObjRecord * nxt = obj_dword(orp, val);
nxt->x_size = 32; /* x_size is cleared when a record overflows */
return nxt;
}
ctype functions take an *int*, which the user is expected to have
taken the input character from getc() and friends, or taken a
character and cast it to (unsigned char).
We don't care about EOF (-1), so use macros that cast to (unsigned
char) for us.
Move the handling of "extra" macros (i.e. output format macros) into
the macros.pl mechanism. This allows us to change the format of the
internal macro store in the future - e.g. to a single byte store
without redundant pointers.
Also, stop using indicies into a long array when there is no good
reason to not just use different arrays.
Clean up remaining build warnings. None of this should affect code
operations. The only warnings which were actually relevant might have
been the ones in ldrdf.c, but it's not clear if anyone ever uses that.
Address data is always int64_t even if the size itself is smaller;
this was broken on bigendian hosts (still need testing!)
Create simple "write sized object" macros.
Don't combine type and size into a single argument; *every* backend
immediately breaks them apart, so it's really just a huge waste of
effort. Additionally, it avoids using short immediates in the
resulting code, which is a bad thing.
Proper use of bool and enum makes code easier to debug. Do more of
it. In particular, we really should stomp out any residual uses of
magic constants that aren't enums or, in some cases, even #defines.
Both C and C++ have "bool", "true" and "false" in lower case; C
requires <stdbool.h> for this, in C++ it is an inherent type built
into the compiler. Use those instead of the old macros; emulate with
a simple typedef enum if unavailable.
Concentrate compiler dependencies to compiler.h; make sure compiler.h
is included first in every .c file (since some prototypes may depend
on the presence of feature request macros.)
Actually use the conditional inclusion of various functions (totally
broken in previous releases.)
Finish the perfect hash tokenizer, and actually enable it.
Move stdscan() et al to a separate file, since it's not needed in any
of the clients of nasmlib other than nasm itself.
Run make alldeps.