summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2002-04-30 20:59:21 +0000
committerH. Peter Anvin <hpa@zytor.com>2002-04-30 20:59:21 +0000
commitaf535c16cf3f9f628384ec834e3aa325709cb37b (patch)
treec582b65fc34ae4e66aa559ebe901c76aefa05bd5
parent41bf8002b2fa402bd344a290fcc9f65de328859c (diff)
downloadnasm-0.98.03.tar.gz
NASM 0.98.03nasm-0.98.03
-rw-r--r--Makefile.in2
-rw-r--r--Mkfiles/Makefile.dj2
-rw-r--r--README03.txt49
-rw-r--r--assemble.c148
-rw-r--r--assemble.h4
-rw-r--r--eval.c4
-rw-r--r--insns.dat110
-rw-r--r--insns.h2
-rw-r--r--labels.c237
-rw-r--r--macros.c9
-rwxr-xr-xmakedist.sh4
-rw-r--r--nasm.c1130
-rw-r--r--nasm.h39
-rw-r--r--nasmlib.c12
-rw-r--r--nasmlib.h17
-rw-r--r--outobj.c18
-rw-r--r--parser.c9
-rw-r--r--preproc.c501
-rw-r--r--rdoff/Makefile.in2
-rw-r--r--standard.mac12
-rw-r--r--test/test1.asm62
-rw-r--r--test/test2.asm18
-rw-r--r--test/test2a.asm22
-rw-r--r--test/test3.asm45
-rw-r--r--test/test4.asm16
-rw-r--r--test/test4a.asm16
-rw-r--r--test/test4b.asm17
-rw-r--r--test/test4c.asm17
-rw-r--r--test/test5.asm43
-rw-r--r--test/test6.asm9
-rw-r--r--zoutieee.c9
31 files changed, 1680 insertions, 905 deletions
diff --git a/Makefile.in b/Makefile.in
index 3a94ae3b..3d31f563 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -66,7 +66,7 @@ insnsd.o: insnsd.c nasm.h insnsi.h insns.h
labels.o: labels.c nasm.h insnsi.h nasmlib.h
listing.o: listing.c nasm.h insnsi.h nasmlib.h listing.h
nasm.o: nasm.c nasm.h insnsi.h nasmlib.h preproc.h parser.h assemble.h labels.h \
- outform.h listing.h
+ outform.h listing.h insns.h
nasmlib.o: nasmlib.c nasm.h insnsi.h nasmlib.h names.c insnsn.c
ndisasm.o: ndisasm.c nasm.h insnsi.h nasmlib.h sync.h disasm.h
outaout.o: outaout.c nasm.h insnsi.h nasmlib.h outform.h
diff --git a/Mkfiles/Makefile.dj b/Mkfiles/Makefile.dj
index 7cb2399d..fb337481 100644
--- a/Mkfiles/Makefile.dj
+++ b/Mkfiles/Makefile.dj
@@ -13,7 +13,7 @@
# You may need to adjust these values.
-CC = gcc
+CC = gcc -s
CFLAGS = -O2 -I.
# You _shouldn't_ need to adjust anything below this line.
diff --git a/README03.txt b/README03.txt
new file mode 100644
index 00000000..8d353908
--- /dev/null
+++ b/README03.txt
@@ -0,0 +1,49 @@
+
+ README
+ NASM, the Netwide Assembler
+
+
+ Changes from 0.98 release to 98.03 as of 27-Jul-2000
+ ====================================================
+
+1. Added signed byte optimizations for the 0x81/0x83 class
+of instructions: ADC, ADD, AND, CMP, OR, SBB, SUB, XOR:
+when used as 'ADD reg16,imm' or 'ADD reg32,imm.' Also
+optimization of signed byte form of 'PUSH imm' and 'IMUL
+reg,imm'/'IMUL reg,reg,imm.' No size specification is needed.
+
+2. Added multi-pass JMP and Jcc offset optimization. Offsets
+on forward references will preferentially use the short form,
+without the need to code a specific size (short or near) for
+the branch. Added instructions for 'Jcc label' to use the
+form 'Jnotcc $+3/JMP label', in cases where a short offset
+is out of bounds. If compiling for a 386 or higher CPU, then
+the 386 form of Jcc will be used instead.
+
+This feature is controlled by a new command-line switch: "O",
+(upper case letter O). "-O0" reverts the assembler to no
+extra optimization passes, "-O1" allows up to 5 extra passes,
+and "-O2"(default), allows up to 10 extra optimization passes.
+
+3. Added a new directive: 'cpu XXX', where XXX is any of:
+8086, 186, 286, 386, 486, 586, pentium, 686, PPro, P2, P3 or
+Katmai. All are case insensitive. All instructions will
+be selected only if they apply to the selected cpu or lower.
+Corrected a couple of bugs in cpu-dependence in 'insns.dat'.
+
+4. Added to 'standard.mac', the "use16" and "use32" forms of
+the "bits 16/32" directive. This is nothing new, just conforms
+to a lot of other assemblers. (minor)
+
+5. Changed label allocation from 320/32 (10000 labels @ 200K+)
+to 32/37 (1000 labels); makes running under DOS much easier.
+Since additional label space is allocated dynamically, this
+should have no effect on large programs with lots of labels.
+The 37 is a prime, believed to be better for hashing. (minor)
+
+6. Integrated patchfile 0.98-0.98.01. I call this version
+0.98.03, for historical reasons: 0.98.02 was trashed.
+
+--John Coffman <johninsd@san.rr.com> 27-Jul-2000
+
+(end) \ No newline at end of file
diff --git a/assemble.c b/assemble.c
index fef2ab77..21c5729a 100644
--- a/assemble.c
+++ b/assemble.c
@@ -32,12 +32,19 @@
* \70, \71, \72 - a long relative operand, from operand 0, 1 or 2
* \1ab - a ModRM, calculated on EA in operand a, with the spare
* field the register value of operand b.
+ * \130,\131,\132 - an immediate word or signed byte for operand 0, 1, or 2
+ * \133,\134,\135 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2
+ * is a signed byte rather than a word.
+ * \140,\141,\142 - an immediate dword or signed byte for operand 0, 1, or 2
+ * \143,\144,\145 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2
+ * is a signed byte rather than a dword.
* \2ab - a ModRM, calculated on EA in operand a, with the spare
* field equal to digit b.
* \30x - might be an 0x67 byte, depending on the address size of
* the memory reference in operand x.
* \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
* \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
+ * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
* \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
* \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
* \322 - indicates that this instruction is only valid when the
@@ -52,6 +59,9 @@
* as a literal byte in order to aid the disassembler.
* \340 - reserve <operand 0> bytes of uninitialised storage.
* Operand 0 had better be a segmentless constant.
+ * \370,\371,\372 - match only if operand 0, 1, 2 meets byte jump criteria.
+ * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
+ * used for conditional jump over longer jump
*/
#include <stdio.h>
@@ -71,6 +81,7 @@ typedef struct {
unsigned char modrm, sib; /* the bytes themselves */
} ea;
+static unsigned long cpu; /* cpu level received from nasm.c */
static efunc errfunc;
static struct ofmt *outfmt;
static ListGen *list;
@@ -134,7 +145,25 @@ static void out (long offset, long segto, void *data, unsigned long type,
outfmt->output (segto, data, type, segment, wrt);
}
-long assemble (long segment, long offset, int bits,
+static int jmp_match (long segment, long offset, int bits,
+ insn *ins, char *code)
+{ long isize;
+ unsigned char c = code[0];
+
+
+ if (c != 0370) return 0;
+ if (ins->oprs[0].opflags & OPFLAG_FORWARD) return 1; /* match a forward reference */
+
+ isize = calcsize (segment, offset, bits, ins, code);
+ if (ins->oprs[0].segment != segment) return 0;
+ isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
+ if (isize >= -128L && isize <= 127L) return 1; /* it is byte size */
+
+ return 0;
+}
+
+
+long assemble (long segment, long offset, int bits, unsigned long cp,
insn *instruction, struct ofmt *output, efunc error,
ListGen *listgen)
{
@@ -147,6 +176,7 @@ long assemble (long segment, long offset, int bits,
long wsize = 0; /* size for DB etc. */
errfunc = error; /* to pass to other functions */
+ cpu = cp;
outfmt = output; /* likewise */
list = listgen; /* and again */
@@ -305,6 +335,8 @@ long assemble (long segment, long offset, int bits,
temp = nasm_instructions[instruction->opcode];
while (temp->opcode != -1) {
int m = matches (temp, instruction);
+ if (m == 99)
+ m += jmp_match(segment, offset, bits, instruction, temp->code);
if (m == 100) /* matches! */
{
@@ -371,7 +403,7 @@ long assemble (long segment, long offset, int bits,
if (instruction->times > 1)
list->downlevel (LIST_TIMES);
return offset - start;
- } else if (m > 0) {
+ } else if (m > 0 && m > size_prob) {
size_prob = m;
}
temp++;
@@ -382,6 +414,8 @@ long assemble (long segment, long offset, int bits,
error (ERR_NONFATAL, "operation size not specified");
else if (size_prob == 2)
error (ERR_NONFATAL, "mismatch in operand sizes");
+ else if (size_prob == 3)
+ error (ERR_NONFATAL, "no instruction for this cpu level");
else
error (ERR_NONFATAL,
"invalid combination of opcode and operands");
@@ -389,12 +423,13 @@ long assemble (long segment, long offset, int bits,
return 0;
}
-long insn_size (long segment, long offset, int bits,
+long insn_size (long segment, long offset, int bits, unsigned long cp,
insn *instruction, efunc error)
{
struct itemplate *temp;
errfunc = error; /* to pass to other functions */
+ cpu = cp;
if (instruction->opcode == -1)
return 0;
@@ -472,7 +507,11 @@ long insn_size (long segment, long offset, int bits,
temp = nasm_instructions[instruction->opcode];
while (temp->opcode != -1) {
- if (matches(temp, instruction) == 100) {
+ int m = matches(temp, instruction);
+ if (m == 99)
+ m += jmp_match(segment, offset, bits, instruction, temp->code);
+
+ if (m == 100) {
/* we've matched an instruction. */
long isize;
char * codes = temp->code;
@@ -498,6 +537,22 @@ long insn_size (long segment, long offset, int bits,
return -1; /* didn't match any instruction */
}
+
+/* check that opn[op] is a signed byte of size 16 or 32,
+ and return the signed value*/
+static int is_sbyte (insn *ins, int op, int size)
+{
+ signed long v;
+ int ret;
+
+ ret = !(ins->forw_ref && ins->oprs[op].opflags ) && /* dead in the water on forward reference or External */
+ ins->oprs[op].wrt==NO_SEG && ins->oprs[op].segment==NO_SEG;
+ v = ins->oprs[op].offset;
+ if (size==16) v = (signed short)v; /* sign extend if 16 bits */
+
+ return ret && v>=-128L && v<=127L;
+}
+
static long calcsize (long segment, long offset, int bits,
insn *ins, char *codes)
{
@@ -540,6 +595,14 @@ static long calcsize (long segment, long offset, int bits,
ins->oprs[c-064].addr_size : bits) == 16 ? 2 : 4); break;
case 070: case 071: case 072:
length += 4; break;
+ case 0130: case 0131: case 0132:
+ length += is_sbyte(ins, c-0130, 16) ? 1 : 2; break;
+ case 0133: case 0134: case 0135:
+ codes+=2; length++; break;
+ case 0140: case 0141: case 0142:
+ length += is_sbyte(ins, c-0140, 32) ? 1 : 4; break;
+ case 0143: case 0144: case 0145:
+ codes+=2; length++; break;
case 0300: case 0301: case 0302:
length += chsize (&ins->oprs[c-0300], bits);
break;
@@ -573,6 +636,10 @@ static long calcsize (long segment, long offset, int bits,
else
length += ins->oprs[0].offset << (c-0340);
break;
+ case 0370: case 0371: case 0372:
+ break;
+ case 0373:
+ length++; break;
default: /* can't do it by 'case' statements */
if (c>=0100 && c<=0277) { /* it's an EA */
ea ea_data;
@@ -801,6 +868,51 @@ static void gencode (long segment, long offset, int bits,
offset += 4;
break;
+ case 0130: case 0131: case 0132:
+ data = ins->oprs[c-0130].offset;
+ if (is_sbyte(ins, c-0130, 16)) {
+ out (offset, segment, &data, OUT_RAWDATA+1, NO_SEG, NO_SEG);
+ offset++;
+ } else {
+ if (ins->oprs[c-0130].segment == NO_SEG &&
+ ins->oprs[c-0130].wrt == NO_SEG &&
+ (data < -65536L || data > 65535L)) {
+ errfunc (ERR_WARNING, "word value exceeds bounds");
+ }
+ out (offset, segment, &data, OUT_ADDRESS+2,
+ ins->oprs[c-0130].segment, ins->oprs[c-0130].wrt);
+ offset += 2;
+ }
+ break;
+
+ case 0133: case 0134: case 0135:
+ codes++;
+ bytes[0] = *codes++;
+ if (is_sbyte(ins, c-0133, 16)) bytes[0] |= 2; /* s-bit */
+ out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
+ offset++;
+ break;
+
+ case 0140: case 0141: case 0142:
+ data = ins->oprs[c-0140].offset;
+ if (is_sbyte(ins, c-0140, 32)) {
+ out (offset, segment, &data, OUT_RAWDATA+1, NO_SEG, NO_SEG);
+ offset++;
+ } else {
+ out (offset, segment, &data, OUT_ADDRESS+4,
+ ins->oprs[c-0140].segment, ins->oprs[c-0140].wrt);
+ offset += 4;
+ }
+ break;
+
+ case 0143: case 0144: case 0145:
+ codes++;
+ bytes[0] = *codes++;
+ if (is_sbyte(ins, c-0143, 32)) bytes[0] |= 2; /* s-bit */
+ out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
+ offset++;
+ break;
+
case 0300: case 0301: case 0302:
if (chsize (&ins->oprs[c-0300], bits)) {
*bytes = 0x67;
@@ -858,7 +970,7 @@ static void gencode (long segment, long offset, int bits,
break;
case 0330:
- *bytes = *codes++ + condval[ins->condition];
+ *bytes = *codes++ ^ condval[ins->condition];
out (offset, segment, bytes,
OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1;
@@ -887,6 +999,16 @@ static void gencode (long segment, long offset, int bits,
}
break;
+ case 0370: case 0371: case 0372:
+ break;
+
+ case 0373:
+ *bytes = bits==16 ? 3 : 5;
+ out (offset, segment, bytes,
+ OUT_RAWDATA+1, NO_SEG, NO_SEG);
+ offset += 1;
+ break;
+
default: /* can't do it by 'case' statements */
if (c>=0100 && c<=0277) { /* it's an EA */
ea ea_data;
@@ -1014,7 +1136,8 @@ static int matches (struct itemplate *itemp, insn *instruction)
(instruction->oprs[i].type & SIZE_MASK))
return 0;
else
- ret = 1;
+/* ret = 1; */
+ return 1;
}
/*
@@ -1069,8 +1192,19 @@ static int matches (struct itemplate *itemp, insn *instruction)
for (i=0; i<itemp->operands; i++)
if (!(itemp->opd[i] & SIZE_MASK) &&
(instruction->oprs[i].type & SIZE_MASK & ~size[i]))
- ret = 2;
+/* ret = 2; */
+ return 2;
+ /*
+ * Check template is okay at the set cpu level
+ */
+ if ((itemp->flags & IF_PLEVEL) > cpu) return 3;
+
+ /*
+ * Check if special handling needed for Jumps
+ */
+ if ((unsigned char)(itemp->code[0]) >= 0370) return 99;
+
return ret;
}
diff --git a/assemble.h b/assemble.h
index 2ead91f9..b08ceb13 100644
--- a/assemble.h
+++ b/assemble.h
@@ -9,9 +9,9 @@
#ifndef NASM_ASSEMBLE_H
#define NASM_ASSEMBLE_H
-long insn_size (long segment, long offset, int bits,
+long insn_size (long segment, long offset, int bits, unsigned long cpu,
insn *instruction, efunc error);
-long assemble (long segment, long offset, int bits,
+long assemble (long segment, long offset, int bits, unsigned long cpu,
insn *instruction, struct ofmt *output, efunc error,
ListGen *listgen);
diff --git a/eval.c b/eval.c
index a44ff7b3..d97127c9 100644
--- a/eval.c
+++ b/eval.c
@@ -760,8 +760,8 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
if (hint)
hint->type = EAH_NOHINT;
- if (critical & 0x10) {
- critical &= ~0x10;
+ if (critical & CRITICAL) {
+ critical &= ~CRITICAL;
bexpr = rexp0;
} else
bexpr = expr0;
diff --git a/insns.dat b/insns.dat
index 2df98934..08bb7116 100644
--- a/insns.dat
+++ b/insns.dat
@@ -37,13 +37,14 @@ ADC rm16,imm8 \320\300\1\x83\202\15 8086
ADC rm32,imm8 \321\300\1\x83\202\15 386
ADC reg_al,imm \1\x14\21 8086,SM
ADC reg_ax,imm \320\1\x15\31 8086,SM
+ADC reg_eax,sbyte \321\1\x83\202\15 386,ND
ADC reg_eax,imm \321\1\x15\41 386,SM
ADC rm8,imm \300\1\x80\202\21 8086,SM
-ADC rm16,imm \320\300\1\x81\202\31 8086,SM
-ADC rm32,imm \321\300\1\x81\202\41 386,SM
+ADC rm16,imm \320\300\134\1\x81\202\131 8086,SM,ND
+ADC rm32,imm \321\300\144\1\x81\202\141 386,SM,ND
ADC mem,imm8 \300\1\x80\202\21 8086,SM
-ADC mem,imm16 \320\300\1\x81\202\31 8086,SM
-ADC mem,imm32 \321\300\1\x81\202\41 386,SM
+ADC mem,imm16 \320\300\134\1\x81\202\131 8086,SM,ND
+ADC mem,imm32 \321\300\144\1\x81\202\141 386,SM,ND
ADD mem,reg8 \300\17\101 8086,SM
ADD reg8,reg8 \300\17\101 8086
ADD mem,reg16 \320\300\1\x01\101 8086,SM
@@ -60,13 +61,14 @@ ADD rm16,imm8 \320\300\1\x83\200\15 8086
ADD rm32,imm8 \321\300\1\x83\200\15 386
ADD reg_al,imm \1\x04\21 8086,SM
ADD reg_ax,imm \320\1\x05\31 8086,SM
+ADD reg_eax,sbyte \321\1\x83\200\15 386,ND
ADD reg_eax,imm \321\1\x05\41 386,SM
ADD rm8,imm \300\1\x80\200\21 8086,SM
-ADD rm16,imm \320\300\1\x81\200\31 8086,SM
-ADD rm32,imm \321\300\1\x81\200\41 386,SM
+ADD rm16,imm \320\300\134\1\x81\200\131 8086,SM,ND
+ADD rm32,imm \321\300\144\1\x81\200\141 386,SM,ND
ADD mem,imm8 \300\1\x80\200\21 8086,SM
-ADD mem,imm16 \320\300\1\x81\200\31 8086,SM
-ADD mem,imm32 \321\300\1\x81\200\41 386,SM
+ADD mem,imm16 \320\300\134\1\x81\200\131 8086,SM,ND
+ADD mem,imm32 \321\300\144\1\x81\200\141 386,SM,ND
AND mem,reg8 \300\1\x20\101 8086,SM
AND reg8,reg8 \300\1\x20\101 8086
AND mem,reg16 \320\300\1\x21\101 8086,SM
@@ -83,13 +85,14 @@ AND rm16,imm8 \320\300\1\x83\204\15 8086
AND rm32,imm8 \321\300\1\x83\204\15 386
AND reg_al,imm \1\x24\21 8086,SM
AND reg_ax,imm \320\1\x25\31 8086,SM
+AND reg_eax,sbyte \321\1\x83\204\15 386,ND
AND reg_eax,imm \321\1\x25\41 386,SM
AND rm8,imm \300\1\x80\204\21 8086,SM
-AND rm16,imm \320\300\1\x81\204\31 8086,SM
-AND rm32,imm \321\300\1\x81\204\41 386,SM
+AND rm16,imm \320\300\134\1\x81\204\131 8086,SM,ND
+AND rm32,imm \321\300\144\1\x81\204\141 386,SM,ND
AND mem,imm8 \300\1\x80\204\21 8086,SM
-AND mem,imm16 \320\300\1\x81\204\31 8086,SM
-AND mem,imm32 \321\300\1\x81\204\41 386,SM
+AND mem,imm16 \320\300\134\1\x81\204\131 8086,SM,ND
+AND mem,imm32 \321\300\144\1\x81\204\141 386,SM,ND
ARPL mem,reg16 \300\1\x63\101 286,PROT,SM
ARPL reg16,reg16 \300\1\x63\101 286,PROT
BOUND reg16,mem \320\301\1\x62\110 186
@@ -175,13 +178,14 @@ CMP rm16,imm8 \320\300\1\x83\207\15 8086
CMP rm32,imm8 \321\300\1\x83\207\15 386
CMP reg_al,imm \1\x3C\21 8086,SM
CMP reg_ax,imm \320\1\x3D\31 8086,SM
+CMP reg_eax,sbyte \321\1\x83\207\15 386,ND
CMP reg_eax,imm \321\1\x3D\41 386,SM
CMP rm8,imm \300\1\x80\207\21 8086,SM
-CMP rm16,imm \320\300\1\x81\207\31 8086,SM
-CMP rm32,imm \321\300\1\x81\207\41 386,SM
+CMP rm16,imm \320\300\134\1\x81\207\131 8086,SM,ND
+CMP rm32,imm \321\300\144\1\x81\207\141 386,SM,ND
CMP mem,imm8 \300\1\x80\207\21 8086,SM
-CMP mem,imm16 \320\300\1\x81\207\31 8086,SM
-CMP mem,imm32 \321\300\1\x81\207\41 386,SM
+CMP mem,imm16 \320\300\134\1\x81\207\131 8086,SM,ND
+CMP mem,imm32 \321\300\144\1\x81\207\141 386,SM,ND
CMPSB void \332\1\xA6 8086
CMPSD void \332\321\1\xA7 386
CMPSW void \332\320\1\xA7 8086
@@ -414,21 +418,21 @@ IMUL rm8 \300\1\xF6\205 8086
IMUL rm16 \320\300\1\xF7\205 8086
IMUL rm32 \321\300\1\xF7\205 386
IMUL reg16,mem \320\301\2\x0F\xAF\110 386,SM
-IMUL reg16,reg16 \320\301\2\x0F\xAF\110 386
+IMUL reg16,reg16 \320\2\x0F\xAF\110 386
IMUL reg32,mem \321\301\2\x0F\xAF\110 386,SM
-IMUL reg32,reg32 \321\301\2\x0F\xAF\110 386
-IMUL reg16,mem,imm8 \320\301\1\x6B\110\16 286,SM
-IMUL reg16,reg16,imm8 \320\301\1\x6B\110\16 286
-IMUL reg16,mem,imm \320\301\1\x69\110\32 286,SM
-IMUL reg16,reg16,imm \320\301\1\x69\110\32 286,SM
+IMUL reg32,reg32 \321\2\x0F\xAF\110 386
+IMUL reg16,mem,imm8 \320\301\1\x6B\110\16 186,SM
+IMUL reg16,reg16,imm8 \320\301\1\x6B\110\16 186
+IMUL reg16,mem,imm \320\301\135\1\x69\110\132 186,SM
+IMUL reg16,reg16,imm \320\135\1\x69\110\132 186,SM
IMUL reg32,mem,imm8 \321\301\1\x6B\110\16 386,SM
-IMUL reg32,reg32,imm8 \321\301\1\x6B\110\16 386
-IMUL reg32,mem,imm \321\301\1\x69\110\42 386,SM
-IMUL reg32,reg32,imm \321\301\1\x69\110\42 386,SM
-IMUL reg16,imm8 \320\1\x6B\100\15 286
-IMUL reg16,imm \320\1\x69\100\31 286,SM
+IMUL reg32,reg32,imm8 \321\1\x6B\110\16 386
+IMUL reg32,mem,imm \321\301\145\1\x69\110\142 386,SM
+IMUL reg32,reg32,imm \321\145\1\x69\110\142 386,SM
+IMUL reg16,imm8 \320\1\x6B\100\15 186
+IMUL reg16,imm \320\134\1\x69\100\131 186,SM
IMUL reg32,imm8 \321\1\x6B\100\15 386
-IMUL reg32,imm \321\1\x69\100\41 386,SM
+IMUL reg32,imm \321\144\1\x69\100\141 386,SM
IN reg_al,imm \1\xE4\25 8086,SB
IN reg_ax,imm \320\1\xE5\25 8086,SB
IN reg_eax,imm \321\1\xE5\25 386,SB
@@ -458,6 +462,7 @@ IRETW void \320\1\xCF 8086
JCXZ imm \320\1\xE3\50 8086
JECXZ imm \321\1\xE3\50 386
JMP imm|short \1\xEB\50 8086
+JMP imm \370\1\xEB\50 8086,ND
JMP imm \322\1\xE9\64 8086
JMP imm|near \322\1\xE9\64 8086,ND
JMP imm|far \322\1\xEA\34\37 8086,ND
@@ -631,13 +636,14 @@ OR rm16,imm8 \320\300\1\x83\201\15 8086
OR rm32,imm8 \321\300\1\x83\201\15 386
OR reg_al,imm \1\x0C\21 8086,SM
OR reg_ax,imm \320\1\x0D\31 8086,SM
+OR reg_eax,sbyte \321\1\x83\201\15 386,ND
OR reg_eax,imm \321\1\x0D\41 386,SM
OR rm8,imm \300\1\x80\201\21 8086,SM
-OR rm16,imm \320\300\1\x81\201\31 8086,SM
-OR rm32,imm \321\300\1\x81\201\41 386,SM
+OR rm16,imm \320\300\134\1\x81\201\131 8086,SM,ND
+OR rm32,imm \321\300\144\1\x81\201\141 386,SM,ND
OR mem,imm8 \300\1\x80\201\21 8086,SM
-OR mem,imm16 \320\300\1\x81\201\31 8086,SM
-OR mem,imm32 \321\300\1\x81\201\41 386,SM
+OR mem,imm16 \320\300\134\1\x81\201\131 8086,SM,ND
+OR mem,imm32 \321\300\144\1\x81\201\141 386,SM,ND
OUT imm,reg_al \1\xE6\24 8086,SB
OUT imm,reg_ax \320\1\xE7\24 8086,SB
OUT imm,reg_eax \321\1\xE7\24 386,SB
@@ -818,9 +824,10 @@ PUSH rm16 \320\300\1\xFF\206 8086
PUSH rm32 \321\300\1\xFF\206 386
PUSH reg_fsgs \1\x0F\7 386
PUSH reg_sreg \6 8086
-PUSH imm8 \1\x6A\14 286
-PUSH imm16 \320\1\x68\30 286
-PUSH imm32 \321\1\x68\40 386
+PUSH imm8 \1\x6A\14 186
+PUSH sbyte \1\x6A\14 186,ND
+PUSH imm16 \320\133\1\x68\130 186
+PUSH imm32 \321\143\1\x68\140 386
PUSHA void \322\1\x60 186
PUSHAD void \321\1\x60 386
PUSHAW void \320\1\x60 186
@@ -919,13 +926,14 @@ SBB rm16,imm8 \320\300\1\x83\203\15 8086
SBB rm32,imm8 \321\300\1\x83\203\15 8086
SBB reg_al,imm \1\x1C\21 8086,SM
SBB reg_ax,imm \320\1\x1D\31 8086,SM
+SBB reg_eax,sbyte \321\1\x83\203\15 386,ND
SBB reg_eax,imm \321\1\x1D\41 386,SM
SBB rm8,imm \300\1\x80\203\21 8086,SM
-SBB rm16,imm \320\300\1\x81\203\31 8086,SM
-SBB rm32,imm \321\300\1\x81\203\41 386,SM
+SBB rm16,imm \320\300\134\1\x81\203\131 8086,SM,ND
+SBB rm32,imm \321\300\144\1\x81\203\141 386,SM,ND
SBB mem,imm8 \300\1\x80\203\21 8086,SM
-SBB mem,imm16 \320\300\1\x81\203\31 8086,SM
-SBB mem,imm32 \321\300\1\x81\203\41 386,SM
+SBB mem,imm16 \320\300\134\1\x81\203\131 8086,SM,ND
+SBB mem,imm32 \321\300\144\1\x81\203\141 386,SM,ND
SCASB void \332\1\xAE 8086
SCASD void \332\321\1\xAF 386
SCASW void \332\320\1\xAF 8086
@@ -1000,13 +1008,14 @@ SUB rm16,imm8 \320\300\1\x83\205\15 8086
SUB rm32,imm8 \321\300\1\x83\205\15 386
SUB reg_al,imm \1\x2C\21 8086,SM
SUB reg_ax,imm \320\1\x2D\31 8086,SM
+SUB reg_eax,sbyte \321\1\x83\205\15 386,ND
SUB reg_eax,imm \321\1\x2D\41 386,SM
SUB rm8,imm \300\1\x80\205\21 8086,SM
-SUB rm16,imm \320\300\1\x81\205\31 8086,SM
-SUB rm32,imm \321\300\1\x81\205\41 386,SM
+SUB rm16,imm \320\300\134\1\x81\205\131 8086,SM,ND
+SUB rm32,imm \321\300\144\1\x81\205\141 386,SM,ND
SUB mem,imm8 \300\1\x80\205\21 8086,SM
-SUB mem,imm16 \320\300\1\x81\205\31 8086,SM
-SUB mem,imm32 \321\300\1\x81\205\41 386,SM
+SUB mem,imm16 \320\300\134\1\x81\205\131 8086,SM,ND
+SUB mem,imm32 \321\300\144\1\x81\205\141 386,SM,ND
SVDC mem80,reg_sreg \300\2\x0F\x78\101 486,CYRIX,SMM
SVLDT mem80 \300\2\x0F\x7A\200 486,CYRIX,SMM
SVTS mem80 \300\2\x0F\x7C\200 486,CYRIX,SMM
@@ -1083,6 +1092,7 @@ XCHG reg16,reg16 \320\300\1\x87\101 8086
XCHG mem,reg32 \321\300\1\x87\101 386,SM
XCHG reg32,reg32 \321\300\1\x87\101 386
XLATB void \1\xD7 8086
+XLAT void \1\xD7 8086
XOR mem,reg8 \300\1\x30\101 8086,SM
XOR reg8,reg8 \300\1\x30\101 8086
XOR mem,reg16 \320\300\1\x31\101 8086,SM
@@ -1099,13 +1109,14 @@ XOR rm16,imm8 \320\300\1\x83\206\15 8086
XOR rm32,imm8 \321\300\1\x83\206\15 386
XOR reg_al,imm \1\x34\21 8086,SM
XOR reg_ax,imm \320\1\x35\31 8086,SM
+XOR reg_eax,sbyte \321\1\x83\206\15 386,ND
XOR reg_eax,imm \321\1\x35\41 386,SM
XOR rm8,imm \300\1\x80\206\21 8086,SM
-XOR rm16,imm \320\300\1\x81\206\31 8086,SM
-XOR rm32,imm \321\300\1\x81\206\41 386,SM
+XOR rm16,imm \320\300\134\1\x81\206\131 8086,SM,ND
+XOR rm32,imm \321\300\144\1\x81\206\141 386,SM,ND
XOR mem,imm8 \300\1\x80\206\21 8086,SM
-XOR mem,imm16 \320\300\1\x81\206\31 8086,SM
-XOR mem,imm32 \321\300\1\x81\206\41 386,SM
+XOR mem,imm16 \320\300\134\1\x81\206\131 8086,SM,ND
+XOR mem,imm32 \321\300\144\1\x81\206\141 386,SM,ND
CMOVcc reg16,mem \320\301\1\x0F\330\x40\110 P6,SM
CMOVcc reg16,reg16 \320\301\1\x0F\330\x40\110 P6
CMOVcc reg32,mem \321\301\1\x0F\330\x40\110 P6,SM
@@ -1113,8 +1124,11 @@ CMOVcc reg32,reg32 \321\301\1\x0F\330\x40\110 P6
Jcc imm|near \322\1\x0F\330\x80\64 386
Jcc imm16|near \320\1\x0F\330\x80\64 386
Jcc imm32|near \321\1\x0F\330\x80\64 386
-Jcc imm \330\x70\50 8086
Jcc imm|short \330\x70\50 8086,ND
+Jcc imm \370\330\x70\50 8086,ND
+Jcc imm \1\x0F\330\x80\64 386,ND
+Jcc imm \330\x71\373\1\xE9\64 8086,ND
+Jcc imm \330\x70\50 8086
SETcc mem \300\1\x0F\330\x90\200 386,SB
SETcc reg8 \300\1\x0F\330\x90\200 386
diff --git a/insns.h b/insns.h
index af911eea..294dd271 100644
--- a/insns.h
+++ b/insns.h
@@ -63,6 +63,8 @@ struct itemplate {
#define IF_3DNOW 0x00008000UL /* it's a 3DNow! instruction */
#define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */
#define IF_PMASK 0xFF000000UL /* the mask for processor types */
+#define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */
+ /* also the highest possible processor */
#define IF_PFMASK 0xF001FF00UL /* the mask for disassembly "prefer" */
#define IF_8086 0x00000000UL /* 8086 instruction */
#define IF_186 0x01000000UL /* 186+ instruction */
diff --git a/labels.c b/labels.c
index 6259986a..c47d34c4 100644
--- a/labels.c
+++ b/labels.c
@@ -18,15 +18,15 @@
*/
#define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
-#define LABEL_BLOCK 320 /* no. of labels/block */
+#define LABEL_BLOCK 32 /* no. of labels/block */
#define LBLK_SIZE (LABEL_BLOCK*sizeof(union label))
-#define LABEL_HASHES 32 /* no. of hash table entries */
+#define LABEL_HASHES 37 /* no. of hash table entries */
-#define END_LIST -3 /* don't clash with NO_SEG! */
+#define END_LIST -3 /* don't clash with NO_SEG! */
#define END_BLOCK -2
#define BOGUS_VALUE -4
-#define PERMTS_SIZE 4096 /* size of text blocks */
+#define PERMTS_SIZE 4096 /* size of text blocks */
/* values for label.defn.is_global */
#define DEFINED_BIT 1
@@ -39,24 +39,26 @@
#define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
#define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
-union label { /* actual label structures */
+union label { /* actual label structures */
struct {
- long segment, offset;
+ long segment, offset;
char *label, *special;
- int is_global, is_norm;
+ int is_global, is_norm;
} defn;
struct {
- long movingon, dummy;
- union label *next;
+ long movingon, dummy;
+ union label *next;
} admin;
};
-struct permts { /* permanent text storage */
- struct permts *next; /* for the linked list */
- int size, usage; /* size and used space in ... */
- char data[PERMTS_SIZE]; /* ... the data block itself */
+struct permts { /* permanent text storage */
+ struct permts *next; /* for the linked list */
+ int size, usage; /* size and used space in ... */
+ char data[PERMTS_SIZE]; /* ... the data block itself */
};
+extern int global_offset_changed; /* defined in nasm.c */
+
static union label *ltab[LABEL_HASHES];/* using a hash table */
static union label *lfree[LABEL_HASHES];/* pointer into the above */
static struct permts *perm_head; /* start of perm. text storage */
@@ -82,9 +84,9 @@ static union label *find_label (char *label, int create)
union label *lptr;
if (islocal(label))
- prev = prevlabel;
+ prev = prevlabel;
else
- prev = "";
+ prev = "";
prevlen = strlen(prev);
p = prev;
while (*p) hash += *p++;
@@ -93,34 +95,34 @@ static union label *find_label (char *label, int create)
hash %= LABEL_HASHES;
lptr = ltab[hash];
while (lptr->admin.movingon != END_LIST) {
- if (lptr->admin.movingon == END_BLOCK) {
- lptr = lptr->admin.next;
- if (!lptr)
- break;
- }
- if (!strncmp(lptr->defn.label, prev, prevlen) &&
- !strcmp(lptr->defn.label+prevlen, label))
- return lptr;
- lptr++;
+ if (lptr->admin.movingon == END_BLOCK) {
+ lptr = lptr->admin.next;
+ if (!lptr)
+ break;
+ }
+ if (!strncmp(lptr->defn.label, prev, prevlen) &&
+ !strcmp(lptr->defn.label+prevlen, label))
+ return lptr;
+ lptr++;
}
if (create) {
- if (lfree[hash]->admin.movingon == END_BLOCK) {
- /*
- * must allocate a new block
- */
- lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
- lfree[hash] = lfree[hash]->admin.next;
- init_block(lfree[hash]);
- }
-
- lfree[hash]->admin.movingon = BOGUS_VALUE;
- lfree[hash]->defn.label = perm_copy (prev, label);
- lfree[hash]->defn.special = NULL;
- lfree[hash]->defn.is_global = NOT_DEFINED_YET;
- return lfree[hash]++;
+ if (lfree[hash]->admin.movingon == END_BLOCK) {
+ /*
+ * must allocate a new block
+ */
+ lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
+ lfree[hash] = lfree[hash]->admin.next;
+ init_block(lfree[hash]);
+ }
+
+ lfree[hash]->admin.movingon = BOGUS_VALUE;
+ lfree[hash]->defn.label = perm_copy (prev, label);
+ lfree[hash]->defn.special = NULL;
+ lfree[hash]->defn.is_global = NOT_DEFINED_YET;
+ return lfree[hash]++;
}
else
- return NULL;
+ return NULL;
}
int lookup_label (char *label, long *segment, long *offset)
@@ -128,16 +130,16 @@ int lookup_label (char *label, long *segment, long *offset)
union label *lptr;
if (!initialised)
- return 0;
+ return 0;
lptr = find_label (label, 0);
if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
- *segment = lptr->defn.segment;
- *offset = lptr->defn.offset;
- return 1;
+ *segment = lptr->defn.segment;
+ *offset = lptr->defn.offset;
+ return 1;
}
else
- return 0;
+ return 0;
}
int is_extern (char *label)
@@ -145,17 +147,17 @@ int is_extern (char *label)
union label *lptr;
if (!initialised)
- return 0;
+ return 0;
lptr = find_label (label, 0);
if (lptr && (lptr->defn.is_global & EXTERN_BIT))
- return 1;
+ return 1;
else
- return 0;
+ return 0;
}
void redefine_label (char *label, long segment, long offset, char *special,
- int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
+ int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
{
union label *lptr;
@@ -165,51 +167,58 @@ void redefine_label (char *label, long segment, long offset, char *special,
*/
(void) segment; /* Don't warn that this parameter is unused */
- (void) offset; /* Don't warn that this parameter is unused */
(void) special; /* Don't warn that this parameter is unused */
(void) is_norm; /* Don't warn that this parameter is unused */
(void) isextrn; /* Don't warn that this parameter is unused */
(void) ofmt; /* Don't warn that this parameter is unused */
#ifdef DEBUG
+#if DEBUG<3
if (!strncmp(label, "debugdump", 9))
- fprintf(stderr, "debug: redefine_label (%s, %ld, %08lx, %s, %d, %d)\n",
- label, segment, offset, special, is_norm, isextrn);
+#endif
+ error(ERR_DEBUG, "redefine_label (%s, %ld, %08lx, %s, %d, %d)",
+ label, segment, offset, special, is_norm, isextrn);
#endif
+ lptr = find_label (label, 1);
+ if (!lptr)
+ error (ERR_PANIC, "can't find label `%s' on pass two", label);
+
if (!islocal(label)) {
- lptr = find_label (label, 1);
- if (!lptr)
- error (ERR_PANIC, "can't find label `%s' on pass two", label);
- if (*label != '.' && lptr->defn.is_norm)
- prevlabel = lptr->defn.label;
+ if (*label != '.' && lptr->defn.is_norm)
+ prevlabel = lptr->defn.label;
}
+
+ global_offset_changed |= (lptr->defn.offset != offset);
+ lptr->defn.offset = offset;
}
void define_label (char *label, long segment, long offset, char *special,
- int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
+ int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
{
union label *lptr;
#ifdef DEBUG
+#if DEBUG<3
if (!strncmp(label, "debugdump", 9))
- fprintf(stderr, "debug: define_label (%s, %ld, %08lx, %s, %d, %d)\n",
- label, segment, offset, special, is_norm, isextrn);
+#endif
+ error(ERR_DEBUG, "define_label (%s, %ld, %08lx, %s, %d, %d)",
+ label, segment, offset, special, is_norm, isextrn);
#endif
lptr = find_label (label, 1);
if (lptr->defn.is_global & DEFINED_BIT) {
- error(ERR_NONFATAL, "symbol `%s' redefined", label);
- return;
+ error(ERR_NONFATAL, "symbol `%s' redefined", label);
+ return;
}
lptr->defn.is_global |= DEFINED_BIT;
if (isextrn)
- lptr->defn.is_global |= EXTERN_BIT;
+ lptr->defn.is_global |= EXTERN_BIT;
if (label[0] != '.' && is_norm) /* not local, but not special either */
- prevlabel = lptr->defn.label;
+ prevlabel = lptr->defn.label;
else if (label[0] == '.' && label[1] != '.' && !*prevlabel)
- error(ERR_NONFATAL, "attempt to define a local label before any"
- " non-local labels");
+ error(ERR_NONFATAL, "attempt to define a local label before any"
+ " non-local labels");
lptr->defn.segment = segment;
lptr->defn.offset = offset;
@@ -217,39 +226,39 @@ void define_label (char *label, long segment, long offset, char *special,
if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) {
ofmt->symdef (lptr->defn.label, segment, offset,
- !!(lptr->defn.is_global & GLOBAL_BIT),
- special ? special : lptr->defn.special);
+ !!(lptr->defn.is_global & GLOBAL_BIT),
+ special ? special : lptr->defn.special);
ofmt->current_dfmt->debug_deflabel (label, segment, offset,
- !!(lptr->defn.is_global & GLOBAL_BIT),
- special ? special : lptr->defn.special);
+ !!(lptr->defn.is_global & GLOBAL_BIT),
+ special ? special : lptr->defn.special);
}
}
void define_common (char *label, long segment, long size, char *special,
- struct ofmt *ofmt, efunc error)
+ struct ofmt *ofmt, efunc error)
{
union label *lptr;
lptr = find_label (label, 1);
if (lptr->defn.is_global & DEFINED_BIT) {
- error(ERR_NONFATAL, "symbol `%s' redefined", label);
- return;
+ error(ERR_NONFATAL, "symbol `%s' redefined", label);
+ return;
}
lptr->defn.is_global |= DEFINED_BIT;
- if (label[0] != '.') /* not local, but not special either */
- prevlabel = lptr->defn.label;
+ if (label[0] != '.') /* not local, but not special either */
+ prevlabel = lptr->defn.label;
else
- error(ERR_NONFATAL, "attempt to define a local label as a "
- "common variable");
+ error(ERR_NONFATAL, "attempt to define a local label as a "
+ "common variable");
lptr->defn.segment = segment;
lptr->defn.offset = 0;
ofmt->symdef (lptr->defn.label, segment, size, 2,
- special ? special : lptr->defn.special);
+ special ? special : lptr->defn.special);
ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2,
- special ? special : lptr->defn.special);
+ special ? special : lptr->defn.special);
}
void declare_as_global (char *label, char *special, efunc error)
@@ -257,24 +266,24 @@ void declare_as_global (char *label, char *special, efunc error)
union label *lptr;
if (islocal(label)) {
- error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
- " global", label);
- return;
+ error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
+ " global", label);
+ return;
}
lptr = find_label (label, 1);
switch (lptr->defn.is_global & TYPE_MASK) {
case NOT_DEFINED_YET:
- lptr->defn.is_global = GLOBAL_PLACEHOLDER;
- lptr->defn.special = special ? perm_copy(special, "") : NULL;
- break;
- case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
+ lptr->defn.is_global = GLOBAL_PLACEHOLDER;
+ lptr->defn.special = special ? perm_copy(special, "") : NULL;
+ break;
+ case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
case GLOBAL_SYMBOL:
- break;
+ break;
case LOCAL_SYMBOL:
- if (!lptr->defn.is_global & EXTERN_BIT)
- error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
- " appear before symbol definition", label);
- break;
+ if (!lptr->defn.is_global & EXTERN_BIT)
+ error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
+ " appear before symbol definition", label);
+ break;
}
}
@@ -283,18 +292,18 @@ int init_labels (void)
int i;
for (i=0; i<LABEL_HASHES; i++) {
- ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
- if (!ltab[i])
- return -1; /* can't initialise, panic */
- init_block (ltab[i]);
- lfree[i] = ltab[i];
+ ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
+ if (!ltab[i])
+ return -1; /* can't initialise, panic */
+ init_block (ltab[i]);
+ lfree[i] = ltab[i];
}
perm_head =
- perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
+ perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
if (!perm_head)
- return -1;
+ return -1;
perm_head->next = NULL;
perm_head->size = PERMTS_SIZE;
@@ -314,22 +323,22 @@ void cleanup_labels (void)
initialised = FALSE;
for (i=0; i<LABEL_HASHES; i++) {
- union label *lptr, *lhold;
+ union label *lptr, *lhold;
- lptr = lhold = ltab[i];
+ lptr = lhold = ltab[i];
- while (lptr) {
- while (lptr->admin.movingon != END_BLOCK) lptr++;
- lptr = lptr->admin.next;
- nasm_free (lhold);
- lhold = lptr;
- }
+ while (lptr) {
+ while (lptr->admin.movingon != END_BLOCK) lptr++;
+ lptr = lptr->admin.next;
+ nasm_free (lhold);
+ lhold = lptr;
+ }
}
while (perm_head) {
- perm_tail = perm_head;
- perm_head = perm_head->next;
- nasm_free (perm_tail);
+ perm_tail = perm_head;
+ perm_head = perm_head->next;
+ nasm_free (perm_tail);
}
}
@@ -338,7 +347,7 @@ static void init_block (union label *blk)
int j;
for (j=0; j<LABEL_BLOCK-1; j++)
- blk[j].admin.movingon = END_LIST;
+ blk[j].admin.movingon = END_LIST;
blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK;
blk[LABEL_BLOCK-1].admin.next = NULL;
}
@@ -349,11 +358,11 @@ static char *perm_copy (char *string1, char *string2)
int len = strlen(string1)+strlen(string2)+1;
if (perm_tail->size - perm_tail->usage < len) {
- perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
- perm_tail = perm_tail->next;
- perm_tail->next = NULL;
- perm_tail->size = PERMTS_SIZE;
- perm_tail->usage = 0;
+ perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
+ perm_tail = perm_tail->next;
+ perm_tail->next = NULL;
+ perm_tail->size = PERMTS_SIZE;
+ perm_tail->usage = 0;
}
p = q = perm_tail->data + perm_tail->usage;
while ( (*q = *string1++) ) q++;
diff --git a/macros.c b/macros.c
index ed70a75e..8a47c808 100644
--- a/macros.c
+++ b/macros.c
@@ -57,6 +57,12 @@ static char *stdmac[] = {
"%imacro bits 1+.nolist",
"[bits %1]",
"%endmacro",
+ "%imacro use16 0.nolist",
+ "[bits 16]",
+ "%endmacro",
+ "%imacro use32 0.nolist",
+ "[bits 32]",
+ "%endmacro",
"%imacro global 1-*.nolist",
"%rep %0",
"[global %1]",
@@ -69,5 +75,8 @@ static char *stdmac[] = {
"%rotate 1",
"%endrep",
"%endmacro",
+ "%imacro cpu 1+.nolist",
+ "[cpu %1]",
+ "%endmacro",
NULL
};
diff --git a/makedist.sh b/makedist.sh
index 5b7abfcc..78f078a9 100755
--- a/makedist.sh
+++ b/makedist.sh
@@ -2,7 +2,7 @@
MAJORVER=`grep NASM_MAJOR_VER nasm.h | head -1 | cut -f3 -d' '`
MINORVER=`grep NASM_MINOR_VER nasm.h | head -1 | cut -f3 -d' '`
-VERSION="${MAJORVER}.${MINORVER}"
+VERSION=`grep NASM_VER nasm.h | head -1 | cut -f3 -d' ' | sed s/\"//g`
DOSVERSION="${MAJORVER}${MINORVER}"
NASM_TAR_GZ=dist/nasm-${VERSION}.tar.gz
NASM_ZIP=dist/nasm${DOSVERSION}s.zip
@@ -15,7 +15,7 @@ if [ ! -d dist ]; then mkdir dist; fi
if [ -f dist/nasm.tar.gz ]; then rm dist/nasm.tar.gz; fi
mkdir nasm-${VERSION}
(cd nasm-${VERSION}; ln -s ../* .;
- rm -f nasm-${VERSION} dist Checklist GNUmakefile z*)
+ rm -f nasm-${VERSION} dist Checklist GNUmakefile)
find nasm-${VERSION}/ -follow -name GNUmakefile > tar-exclude
find nasm-${VERSION}/ -follow -name RCS >> tar-exclude
find nasm-${VERSION}/ -follow -name '*.exe' >> tar-exclude
diff --git a/nasm.c b/nasm.c
index 3c5327a4..841640cd 100644
--- a/nasm.c
+++ b/nasm.c
@@ -14,6 +14,7 @@
#include "nasm.h"
#include "nasmlib.h"
+#include "insns.h"
#include "preproc.h"
#include "parser.h"
#include "eval.h"
@@ -27,6 +28,8 @@ struct forwrefinfo { /* info held on forward refs. */
int operand;
};
+static int get_bits (char *value);
+static unsigned long get_cpu (char *cpu_str);
static void report_error (int, char *, ...);
static void parse_cmdline (int, char **);
static void assemble_file (char *);
@@ -40,13 +43,17 @@ static char inname[FILENAME_MAX];
static char outname[FILENAME_MAX];
static char listname[FILENAME_MAX];
static int globallineno; /* for forward-reference tracking */
-static int pass;
+static int pass = 0;
static struct ofmt *ofmt = NULL;
static FILE *error_file; /* Where to write error messages */
static FILE *ofile = NULL;
-static int sb = 16; /* by default */
+static int optimizing = 10; /* number of optimization passes to take */
+static int sb, cmd_sb = 16; /* by default */
+static unsigned long cmd_cpu = IF_PLEVEL; /* highest level by default */
+static unsigned long cpu = IF_PLEVEL; /* passed to insn_size & assemble.c */
+int global_offset_changed; /* referenced in labels.c */
static loc_t location;
int in_abs_seg; /* Flag we are in ABSOLUTE seg */
@@ -73,7 +80,7 @@ static enum op_type operating_mode;
* doesn't do anything. Initial defaults are given here.
*/
static char suppressed[1+ERR_WARN_MAX] = {
- 0, TRUE, TRUE, FALSE
+ 0, TRUE, TRUE, TRUE, FALSE
};
/*
@@ -81,7 +88,7 @@ static char suppressed[1+ERR_WARN_MAX] = {
* zero does nothing.
*/
static char *suppressed_names[1+ERR_WARN_MAX] = {
- NULL, "macro-params", "orphan-labels", "number-overflow"
+ NULL, "macro-params", "macro-selfref", "orphan-labels", "number-overflow",
};
/*
@@ -89,7 +96,9 @@ static char *suppressed_names[1+ERR_WARN_MAX] = {
* zero does nothing.
*/
static char *suppressed_what[1+ERR_WARN_MAX] = {
- NULL, "macro calls with wrong no. of params",
+ NULL,
+ "macro calls with wrong no. of params",
+ "cyclic macro self-references",
"labels alone on lines without trailing `:'",
"numeric constants greater than 0xFFFFFFFF"
};
@@ -112,9 +121,9 @@ static Preproc no_pp = {
/*
* get/set current offset...
*/
-#define get_curr_ofs (in_abs_seg?abs_offset:\
+#define GET_CURR_OFFS (in_abs_seg?abs_offset:\
raa_read(offsets,location.segment))
-#define set_curr_ofs(x) (in_abs_seg?(void)(abs_offset=(x)):\
+#define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\
(void)(offsets=raa_write(offsets,location.segment,(x))))
static int want_usage;
@@ -160,6 +169,13 @@ int main(int argc, char **argv)
parser_global_info (ofmt, &location);
eval_global_info (ofmt, lookup_label, &location);
+ /* define some macros dependent of command-line */
+ {
+ char temp [64];
+ sprintf (temp, "__OUTPUT_FORMAT__=%s\n", ofmt->shortname);
+ pp_pre_define (temp);
+ }
+
switch ( operating_mode ) {
case op_depend:
{
@@ -193,6 +209,7 @@ int main(int argc, char **argv)
location.known = FALSE;
+ pass = 1;
preproc->reset (inname, 2, report_error, evaluate, &nasmlist);
while ( (line = preproc->getline()) ) {
/*
@@ -253,9 +270,7 @@ int main(int argc, char **argv)
if (!terminate_after_phase) {
ofmt->cleanup (using_debug_info);
cleanup_labels ();
- }
- else {
-
+ } else {
/*
* We had an fclose on the output file here, but we
* actually do that in all the object file drivers as well,
@@ -330,6 +345,7 @@ static int process_arg (char *p, char *q)
error_file = stdout;
break;
case 'o': /* these parameters take values */
+ case 'O':
case 'f':
case 'p':
case 'd':
@@ -352,6 +368,12 @@ static int process_arg (char *p, char *q)
}
else
ofmt->current_dfmt = ofmt->debug_formats[0];
+ } else if (p[1]=='O') { /* Optimization level */
+ if (!isdigit(*param)) report_error(ERR_FATAL,
+ "command line optimization level must be 0..3");
+ optimizing = atoi(param);
+ if (optimizing <= 0) optimizing = 0;
+ else if (optimizing <= 3) optimizing *= 5; /* 5 passes for each level */
} else if (p[1]=='P' || p[1]=='p') { /* pre-include */
pp_pre_include (param);
} else if (p[1]=='D' || p[1]=='d') { /* pre-define */
@@ -396,6 +418,7 @@ static int process_arg (char *p, char *q)
" -g enable debug info\n"
" -F format select a debugging format\n\n"
" -I<path> adds a pathname to the include file path\n"
+ " -O<digit> optimize branch offsets -O0 disables, -O2 default\n"
" -P<file> pre-includes a file\n"
" -D<macro>[=<value>] pre-defines a macro\n"
" -U<macro> undefines a macro\n"
@@ -579,13 +602,14 @@ static void parse_cmdline(int argc, char **argv)
int i;
argv++;
if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') {
- if ((p = get_param (argv[0], argc > 1 ? argv[1] : NULL, &i)))
+ if ((p = get_param (argv[0], argc > 1 ? argv[1] : NULL, &i))) {
if ((rfile = fopen(p, "r"))) {
process_respfile (rfile);
fclose(rfile);
} else
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"unable to open response file `%s'", p);
+ }
} else
i = process_arg (argv[0], argc > 1 ? argv[1] : NULL);
argv += i, argc -= i;
@@ -596,6 +620,7 @@ static void parse_cmdline(int argc, char **argv)
"no input file specified");
}
+
static void assemble_file (char *fname)
{
char * value, * p, * q, * special, * line, debugid[80];
@@ -604,529 +629,493 @@ static void assemble_file (char *fname)
long seg, offs;
struct tokenval tokval;
expr * e;
+ int pass_max;
+ int pass_cnt = 0; /* count actual passes */
- /*
- * pass one
- */
- pass = 1;
- in_abs_seg = FALSE;
- location.segment = ofmt->section(NULL, pass, &sb);
- preproc->reset(fname, 1, report_error, evaluate, &nasmlist);
- globallineno = 0;
- location.known = TRUE;
- location.offset = offs = get_curr_ofs;
-
- while ( (line = preproc->getline()) )
- {
- globallineno++;
-
- /* here we parse our directives; this is not handled by the 'real'
- * parser. */
- if ( (i = getkw (line, &value)) )
- {
- switch (i) {
- case 1: /* [SEGMENT n] */
- seg = ofmt->section (value, pass, &sb);
- if (seg == NO_SEG) {
- report_error (ERR_NONFATAL,
- "segment name `%s' not recognised",
- value);
- } else {
- in_abs_seg = FALSE;
- location.segment = seg;
- }
- break;
- case 2: /* [EXTERN label:special] */
- if (*value == '$')
- value++; /* skip initial $ if present */
- q = value;
- validid = TRUE;
- if (!isidstart(*q))
- validid = FALSE;
- while (*q && *q != ':') {
- if (!isidchar(*q))
- validid = FALSE;
- q++;
- }
- if (!validid) {
- report_error (ERR_NONFATAL,
- "identifier expected after EXTERN");
- break;
- }
- if (*q == ':') {
- *q++ = '\0';
- special = q;
- } else
- special = NULL;
- if (!is_extern(value)) { /* allow re-EXTERN to be ignored */
- declare_as_global (value, special, report_error);
- define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE,
- ofmt, report_error);
- }
- break;
- case 3: /* [BITS bits] */
- switch (atoi(value)) {
- case 16:
- case 32:
- sb = atoi(value);
- break;
- default:
- report_error(ERR_NONFATAL,
- "`%s' is not a valid argument to [BITS]",
- value);
- break;
- }
- break;
- case 4: /* [GLOBAL symbol:special] */
- if (*value == '$')
- value++; /* skip initial $ if present */
- q = value;
- validid = TRUE;
- if (!isidstart(*q))
- validid = FALSE;
- while (*q && *q != ':') {
- if (!isidchar(*q))
- validid = FALSE;
- q++;
- }
- if (!validid) {
- report_error (ERR_NONFATAL,
- "identifier expected after GLOBAL");
- break;
- }
- if (*q == ':') {
- *q++ = '\0';
- special = q;
- } else
- special = NULL;
- declare_as_global (value, special, report_error);
- break;
- case 5: /* [COMMON symbol size:special] */
- p = value;
- validid = TRUE;
- if (!isidstart(*p))
- validid = FALSE;
- while (*p && !isspace(*p)) {
- if (!isidchar(*p))
- validid = FALSE;
- p++;
- }
- if (!validid) {
- report_error (ERR_NONFATAL,
- "identifier expected after COMMON");
- break;
- }
- if (*p) {
- long size;
-
- while (*p && isspace(*p))
- *p++ = '\0';
- q = p;
- while (*q && *q != ':')
- q++;
- if (*q == ':') {
- *q++ = '\0';
- special = q;
- } else
- special = NULL;
- size = readnum (p, &rn_error);
- if (rn_error)
- report_error (ERR_NONFATAL, "invalid size specified"
- " in COMMON declaration");
- else
- define_common (value, seg_alloc(), size,
- special, ofmt, report_error);
- } else
- report_error (ERR_NONFATAL, "no size specified in"
- " COMMON declaration");
- break;
- case 6: /* [ABSOLUTE address] */
- stdscan_reset();
- stdscan_bufptr = value;
- tokval.t_type = TOKEN_INVALID;
- e = evaluate(stdscan, NULL, &tokval, NULL, 1, report_error,
- NULL);
- if (e) {
- if (!is_reloc(e))
- report_error (ERR_NONFATAL, "cannot use non-"
- "relocatable expression as ABSOLUTE"
- " address");
- else {
- abs_seg = reloc_seg(e);
- abs_offset = reloc_value(e);
- }
- } else
- abs_offset = 0x100;/* don't go near zero in case of / */
- in_abs_seg = TRUE;
- location.segment = abs_seg;
- break;
- case 7:
- p = value;
- validid = TRUE;
- if (!isidstart(*p))
- validid = FALSE;
- while (*p && !isspace(*p)) {
- if (!isidchar(*p))
- validid = FALSE;
- p++;
- }
- if (!validid) {
- report_error (ERR_NONFATAL,
- "identifier expected after DEBUG");
- break;
- }
- while (*p && isspace(*p)) p++;
- break;
- default:
- if (!ofmt->directive (line+1, value, 1))
- report_error (ERR_NONFATAL, "unrecognised directive [%s]",
- line+1);
- break;
- }
- }
- else /* it isn't a directive */
- {
- parse_line (1, line, &output_ins,
- report_error, evaluate, define_label);
-
- if (output_ins.forw_ref)
- {
- for(i = 0; i < output_ins.operands; i++)
- {
- if (output_ins.oprs[i].opflags & OPFLAG_FORWARD)
- {
- struct forwrefinfo *fwinf =
- (struct forwrefinfo *)saa_wstruct(forwrefs);
- fwinf->lineno = globallineno;
- fwinf->operand = i;
- }
- }
- }
+ if (cmd_sb == 32 && cmd_cpu < IF_386)
+ report_error(ERR_FATAL, "command line: "
+ "32-bit segment size requires a higher cpu");
- if (output_ins.opcode == I_EQU)
- {
- /*
- * Special `..' EQUs get processed in pass two,
- * except `..@' macro-processor EQUs which are done
- * in the normal place.
- */
- if (!output_ins.label)
- report_error (ERR_NONFATAL,
- "EQU not preceded by label");
-
- else if (output_ins.label[0] != '.' ||
- output_ins.label[1] != '.' ||
- output_ins.label[2] == '@')
- {
- if (output_ins.operands == 1 &&
- (output_ins.oprs[0].type & IMMEDIATE) &&
- output_ins.oprs[0].wrt == NO_SEG)
- {
- int isext = output_ins.oprs[0].opflags & OPFLAG_EXTERN;
- define_label (output_ins.label,
- output_ins.oprs[0].segment,
- output_ins.oprs[0].offset,
- NULL, FALSE, isext, ofmt, report_error);
- }
- else if (output_ins.operands == 2 &&
- (output_ins.oprs[0].type & IMMEDIATE) &&
- (output_ins.oprs[0].type & COLON) &&
- output_ins.oprs[0].segment == NO_SEG &&
- output_ins.oprs[0].wrt == NO_SEG &&
- (output_ins.oprs[1].type & IMMEDIATE) &&
- output_ins.oprs[1].segment == NO_SEG &&
- output_ins.oprs[1].wrt == NO_SEG)
- {
- define_label (output_ins.label,
- output_ins.oprs[0].offset | SEG_ABS,
- output_ins.oprs[1].offset,
- NULL, FALSE, FALSE, ofmt, report_error);
- }
- else
- report_error(ERR_NONFATAL, "bad syntax for EQU");
- }
- }
- else /* instruction isn't an EQU */
- {
- long l = insn_size (location.segment, offs, sb,
- &output_ins, report_error);
- if (using_debug_info && output_ins.opcode != -1) {
- /* this is done here so we can do debug type info */
- long typeinfo = TYS_ELEMENTS(output_ins.operands);
- switch (output_ins.opcode) {
- case I_RESB:
- typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE;
- break;
- case I_RESW:
- typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD;
- break;
- case I_RESD:
- typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD;
- break;
- case I_RESQ:
- typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD;
- break;
- case I_REST:
- typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE;
- break;
- case I_DB:
- typeinfo |= TY_BYTE;
- break;
- case I_DW:
- typeinfo |= TY_WORD;
- break;
- case I_DD:
- if (output_ins.eops_float)
- typeinfo |= TY_FLOAT;
- else
- typeinfo |= TY_DWORD;
- break;
- case I_DQ:
- typeinfo |= TY_QWORD;
- break;
- case I_DT:
- typeinfo |= TY_TBYTE;
- break;
- default:
- typeinfo = TY_LABEL;
- }
- ofmt->current_dfmt->debug_typevalue(typeinfo);
- }
- if (l != -1) {
- offs += l;
- set_curr_ofs (offs);
- }
- /*
- * else l == -1 => invalid instruction, which will be
- * flagged as an error on pass 2
- */
- }
- cleanup_insn (&output_ins);
- }
- nasm_free (line);
- location.offset = offs = get_curr_ofs;
- }
-
- preproc->cleanup();
-
- if (terminate_after_phase) {
- fclose(ofile);
- remove(outname);
- if (want_usage)
- usage();
- exit (1);
- }
+ pass_max = optimizing + 2; /* passes 1, optimizing, then 2 */
+ for (pass = 1; pass <= pass_max; pass++) {
+ int pass1, pass2;
+ ldfunc def_label;
- /*
- * pass two
- */
-
- pass = 2;
- saa_rewind (forwrefs);
- if (*listname)
- nasmlist.init(listname, report_error);
- forwref = saa_rstruct (forwrefs);
- in_abs_seg = FALSE;
- location.segment = ofmt->section(NULL, pass, &sb);
- raa_free (offsets);
- offsets = raa_init();
- preproc->reset(fname, 2, report_error, evaluate, &nasmlist);
- globallineno = 0;
- location.offset = offs = get_curr_ofs;
-
- while ( (line = preproc->getline()) )
- {
- globallineno++;
-
- /* here we parse our directives; this is not handled by
- * the 'real' parser. */
- if ( (i = getkw (line, &value)) ) {
- switch (i) {
- case 1: /* [SEGMENT n] */
- seg = ofmt->section (value, pass, &sb);
- if (seg == NO_SEG) {
- report_error (ERR_PANIC,
- "invalid segment name on pass two");
- } else
- in_abs_seg = FALSE;
- location.segment = seg;
- break;
- case 2: /* [EXTERN label] */
- q = value;
- while (*q && *q != ':')
- q++;
- if (*q == ':') {
- *q++ = '\0';
- ofmt->symdef(value, 0L, 0L, 3, q);
- }
- break;
- case 3: /* [BITS bits] */
- switch (atoi(value)) {
- case 16:
- case 32:
- sb = atoi(value);
- break;
- default:
- report_error(ERR_PANIC,
- "invalid [BITS] value on pass two",
- value);
- break;
- }
- break;
- case 4: /* [GLOBAL symbol] */
- q = value;
- while (*q && *q != ':')
- q++;
- if (*q == ':') {
- *q++ = '\0';
- ofmt->symdef(value, 0L, 0L, 3, q);
- }
- break;
- case 5: /* [COMMON symbol size] */
- q = value;
- while (*q && *q != ':') {
- if (isspace(*q))
- *q = '\0';
- q++;
- }
- if (*q == ':') {
- *q++ = '\0';
- ofmt->symdef(value, 0L, 0L, 3, q);
- }
- break;
- case 6: /* [ABSOLUTE addr] */
- stdscan_reset();
- stdscan_bufptr = value;
- tokval.t_type = TOKEN_INVALID;
- e = evaluate(stdscan, NULL, &tokval, NULL, 2, report_error,
- NULL);
- if (e) {
- if (!is_reloc(e))
- report_error (ERR_PANIC, "non-reloc ABSOLUTE address"
- " in pass two");
- else {
- abs_seg = reloc_seg(e);
- abs_offset = reloc_value(e);
- }
- } else
- report_error (ERR_PANIC, "invalid ABSOLUTE address "
- "in pass two");
- in_abs_seg = TRUE;
- location.segment = abs_seg;
- break;
- case 7:
- p = value;
- q = debugid;
- validid = TRUE;
- if (!isidstart(*p))
- validid = FALSE;
- while (*p && !isspace(*p)) {
- if (!isidchar(*p))
- validid = FALSE;
- *q++ = *p++;
- }
- *q++ = 0;
- if (!validid) {
- report_error (ERR_PANIC,
- "identifier expected after DEBUG in pass 2");
- break;
- }
- while (*p && isspace(*p))
- p++;
- ofmt->current_dfmt->debug_directive (debugid, p);
- break;
- default:
- if (!ofmt->directive (line+1, value, 2))
- report_error (ERR_PANIC, "invalid directive on pass two");
- break;
- }
- }
- else /* not a directive */
- {
- parse_line (2, line, &output_ins,
- report_error, evaluate, redefine_label);
- if (forwref != NULL && globallineno == forwref->lineno) {
- output_ins.forw_ref = TRUE;
- do {
- output_ins.oprs[forwref->operand].opflags|= OPFLAG_FORWARD;
- forwref = saa_rstruct (forwrefs);
- } while (forwref != NULL && forwref->lineno == globallineno);
- } else
- output_ins.forw_ref = FALSE;
-
- /*
- * Hack to prevent phase error in the code
- * rol ax,x
- * x equ 1
- *
- * If the second operand is a forward reference,
- * the UNITY property of the number 1 in that
- * operand is cancelled. Otherwise the above
- * sequence will cause a phase error.
- *
- * This hack means that the above code will
- * generate 286+ code.
- *
- * The forward reference will mean that the
- * operand will not have the UNITY property on
- * the first pass, so the pass behaviours will
- * be consistent.
- */
-
- if (output_ins.forw_ref &&
- output_ins.operands >= 2 &&
- (output_ins.oprs[1].opflags & OPFLAG_FORWARD))
- {
- output_ins.oprs[1].type &= ~ONENESS;
- }
+ pass1 = pass < pass_max ? 1 : 2; /* seq is 1, 1, 1,..., 1, 2 */
+ pass2 = pass > 1 ? 2 : 1; /* seq is 1, 2, 2,..., 2, 2 */
+ def_label = pass > 1 ? redefine_label : define_label;
+
- if (output_ins.opcode == I_EQU)
- {
- /*
- * Special `..' EQUs get processed here, except
- * `..@' macro processor EQUs which are done above.
- */
- if (output_ins.label[0] == '.' &&
- output_ins.label[1] == '.' &&
- output_ins.label[2] != '@')
- {
- if (output_ins.operands == 1 &&
- (output_ins.oprs[0].type & IMMEDIATE)) {
- define_label (output_ins.label,
- output_ins.oprs[0].segment,
- output_ins.oprs[0].offset,
- NULL, FALSE, FALSE, ofmt, report_error);
- }
- else if (output_ins.operands == 2 &&
- (output_ins.oprs[0].type & IMMEDIATE) &&
- (output_ins.oprs[0].type & COLON) &&
- output_ins.oprs[0].segment == NO_SEG &&
- (output_ins.oprs[1].type & IMMEDIATE) &&
- output_ins.oprs[1].segment == NO_SEG)
- {
- define_label (output_ins.label,
- output_ins.oprs[0].offset | SEG_ABS,
- output_ins.oprs[1].offset,
- NULL, FALSE, FALSE, ofmt, report_error);
- }
- else
- report_error(ERR_NONFATAL, "bad syntax for EQU");
- }
- }
- offs += assemble (location.segment, offs, sb,
- &output_ins, ofmt, report_error, &nasmlist);
- cleanup_insn (&output_ins);
- set_curr_ofs (offs);
- }
+ sb = cmd_sb; /* set 'bits' to command line default */
+ cpu = cmd_cpu;
+ if (pass == pass_max) {
+ if (*listname)
+ nasmlist.init(listname, report_error);
+ }
+ in_abs_seg = FALSE;
+ global_offset_changed = FALSE; /* set by redefine_label */
+ location.segment = ofmt->section(NULL, pass2, &sb);
+ if (pass > 1) {
+ saa_rewind (forwrefs);
+ forwref = saa_rstruct (forwrefs);
+ raa_free (offsets);
+ offsets = raa_init();
+ }
+ preproc->reset(fname, pass1, report_error, evaluate, &nasmlist);
+ globallineno = 0;
+ if (pass == 1) location.known = TRUE;
+ location.offset = offs = GET_CURR_OFFS;
- nasm_free (line);
+ while ( (line = preproc->getline()) )
+ {
+ globallineno++;
+
+ /* here we parse our directives; this is not handled by the 'real'
+ * parser. */
+ if ( (i = getkw (line, &value)) )
+ {
+ switch (i) {
+ case 1: /* [SEGMENT n] */
+ seg = ofmt->section (value, pass2, &sb);
+ if (seg == NO_SEG) {
+ report_error (pass1==1 ? ERR_NONFATAL : ERR_PANIC,
+ "segment name `%s' not recognised",
+ value);
+ } else {
+ in_abs_seg = FALSE;
+ location.segment = seg;
+ }
+ break;
+ case 2: /* [EXTERN label:special] */
+ if (pass == pass_max) {
+ q = value;
+ while (*q && *q != ':')
+ q++;
+ if (*q == ':') {
+ *q++ = '\0';
+ ofmt->symdef(value, 0L, 0L, 3, q);
+ }
+ } else if (pass == 1) { /* pass == 1 */
+ if (*value == '$')
+ value++; /* skip initial $ if present */
+ q = value;
+ validid = TRUE;
+ if (!isidstart(*q))
+ validid = FALSE;
+ while (*q && *q != ':') {
+ if (!isidchar(*q))
+ validid = FALSE;
+ q++;
+ }
+ if (!validid) {
+ report_error (ERR_NONFATAL,
+ "identifier expected after EXTERN");
+ break;
+ }
+ if (*q == ':') {
+ *q++ = '\0';
+ special = q;
+ } else
+ special = NULL;
+ if (!is_extern(value)) { /* allow re-EXTERN to be ignored */
+ declare_as_global (value, special, report_error);
+ define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE,
+ ofmt, report_error);
+ }
+ } /* else pass == 1 */
+ break;
+ case 3: /* [BITS bits] */
+ sb = get_bits(value);
+ break;
+ case 4: /* [GLOBAL symbol:special] */
+ if (pass == pass_max) { /* pass 2 */
+ q = value;
+ while (*q && *q != ':')
+ q++;
+ if (*q == ':') {
+ *q++ = '\0';
+ ofmt->symdef(value, 0L, 0L, 3, q);
+ }
+ } else if (pass == 1) { /* pass == 1 */
+ if (*value == '$')
+ value++; /* skip initial $ if present */
+ q = value;
+ validid = TRUE;
+ if (!isidstart(*q))
+ validid = FALSE;
+ while (*q && *q != ':') {
+ if (!isidchar(*q))
+ validid = FALSE;
+ q++;
+ }
+ if (!validid) {
+ report_error (ERR_NONFATAL,
+ "identifier expected after GLOBAL");
+ break;
+ }
+ if (*q == ':') {
+ *q++ = '\0';
+ special = q;
+ } else
+ special = NULL;
+ declare_as_global (value, special, report_error);
+ } /* pass == 1 */
+ break;
+ case 5: /* [COMMON symbol size:special] */
+ if (pass == 1) {
+ p = value;
+ validid = TRUE;
+ if (!isidstart(*p))
+ validid = FALSE;
+ while (*p && !isspace(*p)) {
+ if (!isidchar(*p))
+ validid = FALSE;
+ p++;
+ }
+ if (!validid) {
+ report_error (ERR_NONFATAL,
+ "identifier expected after COMMON");
+ break;
+ }
+ if (*p) {
+ long size;
+
+ while (*p && isspace(*p))
+ *p++ = '\0';
+ q = p;
+ while (*q && *q != ':')
+ q++;
+ if (*q == ':') {
+ *q++ = '\0';
+ special = q;
+ } else
+ special = NULL;
+ size = readnum (p, &rn_error);
+ if (rn_error)
+ report_error (ERR_NONFATAL, "invalid size specified"
+ " in COMMON declaration");
+ else
+ define_common (value, seg_alloc(), size,
+ special, ofmt, report_error);
+ } else
+ report_error (ERR_NONFATAL, "no size specified in"
+ " COMMON declaration");
+ } else if (pass == pass_max) { /* pass == 2 */
+ q = value;
+ while (*q && *q != ':') {
+ if (isspace(*q))
+ *q = '\0';
+ q++;
+ }
+ if (*q == ':') {
+ *q++ = '\0';
+ ofmt->symdef(value, 0L, 0L, 3, q);
+ }
+ }
+ break;
+ case 6: /* [ABSOLUTE address] */
+ stdscan_reset();
+ stdscan_bufptr = value;
+ tokval.t_type = TOKEN_INVALID;
+ e = evaluate(stdscan, NULL, &tokval, NULL, pass2, report_error,
+ NULL);
+ if (e) {
+ if (!is_reloc(e))
+ report_error (pass==1 ? ERR_NONFATAL : ERR_PANIC,
+ "cannot use non-relocatable expression as "
+ "ABSOLUTE address");
+ else {
+ abs_seg = reloc_seg(e);
+ abs_offset = reloc_value(e);
+ }
+ } else
+ if (pass==1) abs_offset = 0x100;/* don't go near zero in case of / */
+ else report_error (ERR_PANIC, "invalid ABSOLUTE address "
+ "in pass two");
+ in_abs_seg = TRUE;
+ location.segment = abs_seg;
+ break;
+ case 7: /* DEBUG */
+ p = value;
+ q = debugid;
+ validid = TRUE;
+ if (!isidstart(*p))
+ validid = FALSE;
+ while (*p && !isspace(*p)) {
+ if (!isidchar(*p))
+ validid = FALSE;
+ *q++ = *p++;
+ }
+ *q++ = 0;
+ if (!validid) {
+ report_error (pass==1 ? ERR_NONFATAL : ERR_PANIC,
+ "identifier expected after DEBUG");
+ break;
+ }
+ while (*p && isspace(*p)) p++;
+ if (pass==pass_max) ofmt->current_dfmt->debug_directive (debugid, p);
+ break;
+ case 8: /* [WARNING {+|-}warn-name] */
+ if (pass1 == 1) {
+ while (*value && isspace(*value))
+ value++;
+
+ if (*value == '+' || *value == '-') {
+ validid = (*value == '-') ? TRUE : FALSE;
+ value++;
+ } else
+ validid = FALSE;
+
+ for (i=1; i<=ERR_WARN_MAX; i++)
+ if (!nasm_stricmp(value, suppressed_names[i]))
+ break;
+ if (i <= ERR_WARN_MAX)
+ suppressed[i] = validid;
+ else
+ report_error (ERR_NONFATAL, "invalid warning id in WARNING directive");
+ }
+ break;
+ case 9: /* cpu */
+ cpu = get_cpu (value);
+ break;
+ default:
+ if (!ofmt->directive (line+1, value, pass1))
+ report_error (pass1==1 ? ERR_NONFATAL : ERR_PANIC,
+ "unrecognised directive [%s]",
+ line+1);
+ break;
+ }
+ }
+ else /* it isn't a directive */
+ {
+ parse_line (pass2, line, &output_ins,
+ report_error, evaluate,
+ def_label);
+
+ if (!optimizing && pass == 2) {
+ if (forwref != NULL && globallineno == forwref->lineno) {
+ output_ins.forw_ref = TRUE;
+ do {
+ output_ins.oprs[forwref->operand].opflags|= OPFLAG_FORWARD;
+ forwref = saa_rstruct (forwrefs);
+ } while (forwref != NULL && forwref->lineno == globallineno);
+ } else
+ output_ins.forw_ref = FALSE;
+ }
+
+
+ if (!optimizing && output_ins.forw_ref)
+ {
+ if (pass == 1) {
+ for(i = 0; i < output_ins.operands; i++)
+ {
+ if (output_ins.oprs[i].opflags & OPFLAG_FORWARD)
+ {
+ struct forwrefinfo *fwinf =
+ (struct forwrefinfo *)saa_wstruct(forwrefs);
+ fwinf->lineno = globallineno;
+ fwinf->operand = i;
+ }
+ }
+ } else { /* pass == 2 */
+ /*
+ * Hack to prevent phase error in the code
+ * rol ax,x
+ * x equ 1
+ *
+ * If the second operand is a forward reference,
+ * the UNITY property of the number 1 in that
+ * operand is cancelled. Otherwise the above
+ * sequence will cause a phase error.
+ *
+ * This hack means that the above code will
+ * generate 286+ code.
+ *
+ * The forward reference will mean that the
+ * operand will not have the UNITY property on
+ * the first pass, so the pass behaviours will
+ * be consistent.
+ */
+
+ if (output_ins.operands >= 2 &&
+ (output_ins.oprs[1].opflags & OPFLAG_FORWARD))
+ {
+ output_ins.oprs[1].type &= ~(ONENESS|BYTENESS);
+ }
+
+ } /* pass == 2 */
+
+ } /* forw_ref */
+
+
+ if (output_ins.opcode == I_EQU) {
+ if (pass1 == 1)
+ {
+ /*
+ * Special `..' EQUs get processed in pass two,
+ * except `..@' macro-processor EQUs which are done
+ * in the normal place.
+ */
+ if (!output_ins.label)
+ report_error (ERR_NONFATAL,
+ "EQU not preceded by label");
+
+ else if (output_ins.label[0] != '.' ||
+ output_ins.label[1] != '.' ||
+ output_ins.label[2] == '@')
+ {
+ if (output_ins.operands == 1 &&
+ (output_ins.oprs[0].type & IMMEDIATE) &&
+ output_ins.oprs[0].wrt == NO_SEG)
+ {
+ int isext = output_ins.oprs[0].opflags & OPFLAG_EXTERN;
+ def_label (output_ins.label,
+ output_ins.oprs[0].segment,
+ output_ins.oprs[0].offset,
+ NULL, FALSE, isext, ofmt, report_error);
+ }
+ else if (output_ins.operands == 2 &&
+ (output_ins.oprs[0].type & IMMEDIATE) &&
+ (output_ins.oprs[0].type & COLON) &&
+ output_ins.oprs[0].segment == NO_SEG &&
+ output_ins.oprs[0].wrt == NO_SEG &&
+ (output_ins.oprs[1].type & IMMEDIATE) &&
+ output_ins.oprs[1].segment == NO_SEG &&
+ output_ins.oprs[1].wrt == NO_SEG)
+ {
+ def_label (output_ins.label,
+ output_ins.oprs[0].offset | SEG_ABS,
+ output_ins.oprs[1].offset,
+ NULL, FALSE, FALSE, ofmt, report_error);
+ }
+ else
+ report_error(ERR_NONFATAL, "bad syntax for EQU");
+ }
+ } else { /* pass == 2 */
+ /*
+ * Special `..' EQUs get processed here, except
+ * `..@' macro processor EQUs which are done above.
+ */
+ if (output_ins.label[0] == '.' &&
+ output_ins.label[1] == '.' &&
+ output_ins.label[2] != '@')
+ {
+ if (output_ins.operands == 1 &&
+ (output_ins.oprs[0].type & IMMEDIATE)) {
+ define_label (output_ins.label,
+ output_ins.oprs[0].segment,
+ output_ins.oprs[0].offset,
+ NULL, FALSE, FALSE, ofmt, report_error);
+ }
+ else if (output_ins.operands == 2 &&
+ (output_ins.oprs[0].type & IMMEDIATE) &&
+ (output_ins.oprs[0].type & COLON) &&
+ output_ins.oprs[0].segment == NO_SEG &&
+ (output_ins.oprs[1].type & IMMEDIATE) &&
+ output_ins.oprs[1].segment == NO_SEG)
+ {
+ define_label (output_ins.label,
+ output_ins.oprs[0].offset | SEG_ABS,
+ output_ins.oprs[1].offset,
+ NULL, FALSE, FALSE, ofmt, report_error);
+ }
+ else
+ report_error(ERR_NONFATAL, "bad syntax for EQU");
+ }
+ } /* pass == 2 */
+ } else { /* instruction isn't an EQU */
+
+ if (pass1 == 1) {
+ long l = insn_size (location.segment, offs, sb, cpu,
+ &output_ins, report_error);
+ if (using_debug_info && output_ins.opcode != -1) {
+ /* this is done here so we can do debug type info */
+ long typeinfo = TYS_ELEMENTS(output_ins.operands);
+ switch (output_ins.opcode) {
+ case I_RESB:
+ typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE;
+ break;
+ case I_RESW:
+ typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD;
+ break;
+ case I_RESD:
+ typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD;
+ break;
+ case I_RESQ:
+ typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD;
+ break;
+ case I_REST:
+ typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE;
+ break;
+ case I_DB:
+ typeinfo |= TY_BYTE;
+ break;
+ case I_DW:
+ typeinfo |= TY_WORD;
+ break;
+ case I_DD:
+ if (output_ins.eops_float)
+ typeinfo |= TY_FLOAT;
+ else
+ typeinfo |= TY_DWORD;
+ break;
+ case I_DQ:
+ typeinfo |= TY_QWORD;
+ break;
+ case I_DT:
+ typeinfo |= TY_TBYTE;
+ break;
+ default:
+ typeinfo = TY_LABEL;
+ }
+ ofmt->current_dfmt->debug_typevalue(typeinfo);
+ }
+ if (l != -1) {
+ offs += l;
+ SET_CURR_OFFS (offs);
+ }
+ /*
+ * else l == -1 => invalid instruction, which will be
+ * flagged as an error on pass 2
+ */
+
+ } else { /* pass == 2 */
+ offs += assemble (location.segment, offs, sb, cpu,
+ &output_ins, ofmt, report_error, &nasmlist);
+ SET_CURR_OFFS (offs);
+
+ }
+ } /* not an EQU */
+ cleanup_insn (&output_ins);
+ }
+ nasm_free (line);
+ location.offset = offs = GET_CURR_OFFS;
+ } /* end while (line = preproc->getline... */
+
+ if (pass1==2 && global_offset_changed)
+ report_error(ERR_NONFATAL, "phase error detected at end of assembly.");
+
+ if (pass1 == 1) preproc->cleanup();
+
+ if (pass1==1 && terminate_after_phase) {
+ fclose(ofile);
+ remove(outname);
+ if (want_usage)
+ usage();
+ exit (1);
+ }
+ pass_cnt++;
+ if (pass>1 && !global_offset_changed && pass<pass_max) pass = pass_max-1;
+ } /* for (pass=1; pass<=2; pass++) */
- location.offset = offs = get_curr_ofs;
- }
+ nasmlist.cleanup();
+#if 1
+ if (optimizing)
+ fprintf(error_file,
+ "info:: assembly required 1+%d+1 passes\n", pass_cnt-2);
+#endif
+} /* exit from assemble_file (...) */
- preproc->cleanup();
- nasmlist.cleanup();
-}
static int getkw (char *buf, char **value)
{
@@ -1164,22 +1153,28 @@ static int getkw (char *buf, char **value)
while (*buf!=']') buf++;
*buf++ = '\0';
}
+#if 0
for (q=p; *q; q++)
*q = tolower(*q);
- if (!strcmp(p, "segment") || !strcmp(p, "section"))
+#endif
+ if (!nasm_stricmp(p, "segment") || !nasm_stricmp(p, "section"))
return 1;
- if (!strcmp(p, "extern"))
+ if (!nasm_stricmp(p, "extern"))
return 2;
- if (!strcmp(p, "bits"))
+ if (!nasm_stricmp(p, "bits"))
return 3;
- if (!strcmp(p, "global"))
+ if (!nasm_stricmp(p, "global"))
return 4;
- if (!strcmp(p, "common"))
+ if (!nasm_stricmp(p, "common"))
return 5;
- if (!strcmp(p, "absolute"))
+ if (!nasm_stricmp(p, "absolute"))
return 6;
- if (!strcmp(p, "debug"))
+ if (!nasm_stricmp(p, "debug"))
return 7;
+ if (!nasm_stricmp(p, "warning"))
+ return 8;
+ if (!nasm_stricmp(p, "cpu"))
+ return 9;
return -1;
}
@@ -1211,11 +1206,19 @@ static void report_error (int severity, char *fmt, ...)
nasm_free (currentfile);
}
- if ( (severity & ERR_MASK) == ERR_WARNING)
- fputs ("warning: ", error_file);
- else if ( (severity & ERR_MASK) == ERR_PANIC)
- fputs ("panic: ", error_file);
-
+ switch (severity & ERR_MASK) {
+ case ERR_WARNING:
+ fputs ("warning: ", error_file); break;
+ case ERR_NONFATAL:
+ fputs ("error: ", error_file); break;
+ case ERR_FATAL:
+ fputs ("fatal: ", error_file); break;
+ case ERR_PANIC:
+ fputs ("panic: ", error_file); break;
+ case ERR_DEBUG:
+ fputs("debug: ", error_file); break;
+ }
+
va_start (ap, fmt);
vfprintf (error_file, fmt, ap);
fputc ('\n', error_file);
@@ -1224,7 +1227,7 @@ static void report_error (int severity, char *fmt, ...)
want_usage = TRUE;
switch (severity & ERR_MASK) {
- case ERR_WARNING:
+ case ERR_WARNING: case ERR_DEBUG:
/* no further action, by definition */
break;
case ERR_NONFATAL:
@@ -1241,7 +1244,8 @@ static void report_error (int severity, char *fmt, ...)
break; /* placate silly compilers */
case ERR_PANIC:
fflush(NULL);
- abort(); /* halt, catch fire, and dump core */
+/* abort(); */ /* halt, catch fire, and dump core */
+ exit(3);
break;
}
}
@@ -1342,3 +1346,47 @@ static void no_pp_cleanup (void)
{
fclose(no_pp_fp);
}
+
+static unsigned long get_cpu (char *value)
+{
+
+ if (!strcmp(value, "8086")) return IF_8086;
+ if (!strcmp(value, "186")) return IF_186;
+ if (!strcmp(value, "286")) return IF_286;
+ if (!strcmp(value, "386")) return IF_386;
+ if (!strcmp(value, "486")) return IF_486;
+ if (!strcmp(value, "586") ||
+ !nasm_stricmp(value, "pentium") ) return IF_PENT;
+ if (!strcmp(value, "686") ||
+ !nasm_stricmp(value, "ppro") ||
+ !nasm_stricmp(value, "p2") ) return IF_P6;
+ if (!nasm_stricmp(value, "p3") ||
+ !nasm_stricmp(value, "katmai") ) return IF_KATMAI;
+
+ report_error (pass ? ERR_NONFATAL : ERR_FATAL, "unknown 'cpu' type");
+
+ return IF_PLEVEL; /* the maximum level */
+}
+
+
+static int get_bits (char *value)
+{
+ int i;
+
+ if ((i = atoi(value)) == 16) return i; /* set for a 16-bit segment */
+ else if (i == 32) {
+ if (cpu < IF_386) {
+ report_error(ERR_NONFATAL,
+ "cannot specify 32-bit segment on processor below a 386");
+ i = 16;
+ }
+ } else {
+ report_error(pass ? ERR_NONFATAL : ERR_FATAL,
+ "`%s' is not a valid segment size; must be 16 or 32",
+ value);
+ i = 16;
+ }
+ return i;
+}
+
+/* end of nasm.c */
diff --git a/nasm.h b/nasm.h
index 240d2d49..75202aac 100644
--- a/nasm.h
+++ b/nasm.h
@@ -13,7 +13,7 @@
#define NASM_MAJOR_VER 0
#define NASM_MINOR_VER 98
-#define NASM_VER "0.98"
+#define NASM_VER "0.98.03"
#ifndef NULL
#define NULL 0
@@ -64,26 +64,28 @@ typedef void (*efunc) (int severity, char *fmt, ...);
* argument to an efunc.
*/
-#define ERR_WARNING 0 /* warn only: no further action */
-#define ERR_NONFATAL 1 /* terminate assembly after phase */
-#define ERR_FATAL 2 /* instantly fatal: exit with error */
-#define ERR_PANIC 3 /* internal error: panic instantly
+#define ERR_DEBUG 0x00000008 /* put out debugging message */
+#define ERR_WARNING 0x00000000 /* warn only: no further action */
+#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */
+#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */
+#define ERR_PANIC 0x00000003 /* internal error: panic instantly
* and dump core for reference */
-#define ERR_MASK 0x0F /* mask off the above codes */
-#define ERR_NOFILE 0x10 /* don't give source file name/line */
-#define ERR_USAGE 0x20 /* print a usage message */
-#define ERR_PASS1 0x80 /* only print this error on pass one */
+#define ERR_MASK 0x0000000F /* mask off the above codes */
+#define ERR_NOFILE 0x00000010 /* don't give source file name/line */
+#define ERR_USAGE 0x00000020 /* print a usage message */
+#define ERR_PASS1 0x00000040 /* only print this error on pass one */
/*
* These codes define specific types of suppressible warning.
*/
-#define ERR_WARN_MNP 0x0100 /* macro-num-parameters warning */
-#define ERR_WARN_OL 0x0200 /* orphan label (no colon, and
+#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */
+#define ERR_WARN_MSR 0x00000200 /* macro self-reference */
+#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and
* alone on line) */
-#define ERR_WARN_NOV 0x0300 /* numeric overflow */
-#define ERR_WARN_MASK 0xFF00 /* the mask for this feature */
+#define ERR_WARN_NOV 0x00000400 /* numeric overflow */
+#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */
#define ERR_WARN_SHR 8 /* how far to shift right */
-#define ERR_WARN_MAX 3 /* the highest numbered one */
+#define ERR_WARN_MAX 4 /* the highest numbered one */
/*
* -----------------------
@@ -250,8 +252,8 @@ struct eval_hints {
* defined before use", whereas if `critical' is 2, the error will
* be "symbol undefined".
*
- * If `critical' has bit 4 set (in addition to its main value: 0x11
- * and 0x12 correspond to 1 and 2) then an extended expression
+ * If `critical' has bit 8 set (in addition to its main value: 0x101
+ * and 0x102 correspond to 1 and 2) then an extended expression
* syntax is recognised, in which relational operators such as =, <
* and >= are accepted, as well as low-precedence logical operators
* &&, ^^ and ||.
@@ -259,6 +261,7 @@ struct eval_hints {
* If `hints' is non-NULL, it gets filled in with some hints as to
* the base register in complex effective addresses.
*/
+#define CRITICAL 0x100
typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv,
int *fwref, int critical, efunc error,
struct eval_hints *hints);
@@ -411,7 +414,9 @@ enum {
/* special type of immediate operand */
#define ONENESS 0x00800000L /* so UNITY == IMMEDIATE | ONENESS */
#define UNITY 0x00802000L /* for shift/rotate instructions */
-
+#define BYTENESS 0x80000000L /* so SBYTE == IMMEDIATE | BYTENESS */
+#define SBYTE 0x80002000L /* for op r16/32,immediate instrs. */
+
/*
* Next, the codes returned from the parser, for registers and
* instructions.
diff --git a/nasmlib.c b/nasmlib.c
index 86ed6c47..64f2b7f3 100644
--- a/nasmlib.c
+++ b/nasmlib.c
@@ -125,29 +125,33 @@ char *nasm_strndup (char *s, size_t len)
return p;
}
+#if !defined(stricmp) && !defined(strcasecmp)
int nasm_stricmp (const char *s1, const char *s2)
{
- while (*s1 && toupper(*s1) == toupper(*s2))
+ while (*s1 && tolower(*s1) == tolower(*s2))
s1++, s2++;
if (!*s1 && !*s2)
return 0;
- else if (toupper(*s1) < toupper(*s2))
+ else if (tolower(*s1) < tolower(*s2))
return -1;
else
return 1;
}
+#endif
+#if !defined(strnicmp) && !defined(strncasecmp)
int nasm_strnicmp (const char *s1, const char *s2, int n)
{
- while (n > 0 && *s1 && toupper(*s1) == toupper(*s2))
+ while (n > 0 && *s1 && tolower(*s1) == tolower(*s2))
s1++, s2++, n--;
if ((!*s1 && !*s2) || n==0)
return 0;
- else if (toupper(*s1) < toupper(*s2))
+ else if (tolower(*s1) < tolower(*s2))
return -1;
else
return 1;
}
+#endif
#define lib_isnumchar(c) ( isalnum(c) || (c) == '$')
#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0')
diff --git a/nasmlib.h b/nasmlib.h
index d2997b18..0f9af790 100644
--- a/nasmlib.h
+++ b/nasmlib.h
@@ -51,8 +51,25 @@ char *nasm_strndup_log (char *, int, char *, size_t);
* ANSI doesn't guarantee the presence of `stricmp' or
* `strcasecmp'.
*/
+#if defined(stricmp) || defined(strcasecmp)
+#if defined(stricmp)
+#define nasm_stricmp stricmp
+#else
+#define nasm_stricmp strcasecmp
+#endif
+#else
int nasm_stricmp (const char *, const char *);
+#endif
+
+#if defined(strnicmp) || defined(strncasecmp)
+#if defined(strnicmp)
+#define nasm_strnicmp strnicmp
+#else
+#define nasm_strnicmp strncasecmp
+#endif
+#else
int nasm_strnicmp (const char *, const char *, int);
+#endif
/*
* Convert a string into a number, using NASM number rules. Sets
diff --git a/outobj.c b/outobj.c
index 0a7544d6..f4619d9e 100644
--- a/outobj.c
+++ b/outobj.c
@@ -76,7 +76,7 @@
* next operation.
*/
-#define RECORD_MAX 1024 /* maximum size of _any_ record */
+#define RECORD_MAX 1024-3 /* maximal size of any record except type+reclen */
#define OBJ_PARMS 3 /* maximum .parm used by any .ori routine */
#define FIX_08_LOW 0x8000 /* location type for various fixup subrecords */
@@ -103,6 +103,7 @@ enum RecordID { /* record ID codes */
LEDATA = 0xA0, /* logical enumerated data */
FIXUPP = 0x9C, /* fixups (relocations) */
+ FIXU32 = 0x9D, /* 32-bit fixups (relocations) */
MODEND = 0x8A /* module end */
};
@@ -139,8 +140,6 @@ static void ori_ledata(ObjRecord *orp);
static void ori_pubdef(ObjRecord *orp);
static void ori_null(ObjRecord *orp);
static ObjRecord *obj_commit(ObjRecord *orp);
-static void obj_write_fixup (ObjRecord *orp, int bytes,
- int segrel, long seg, long wrt);
static int obj_uppercase; /* Flag: all names in uppercase */
@@ -949,6 +948,10 @@ static void obj_deflabel (char *name, long segment,
" for this symbol type");
}
+/* forward declaration */
+static void obj_write_fixup (ObjRecord *orp, int bytes,
+ int segrel, long seg, long wrt, struct Segment *segto);
+
static void obj_out (long segto, void *data, unsigned long type,
long segment, long wrt)
{
@@ -1049,7 +1052,7 @@ static void obj_out (long segto, void *data, unsigned long type,
if (segment != NO_SEG)
obj_write_fixup (orp, rsize,
(realtype == OUT_ADDRESS ? 0x4000 : 0),
- segment, wrt);
+ segment, wrt, seg);
seg->currentpos += size;
} else if (realtype == OUT_RESERVE) {
if (orp->committed)
@@ -1060,7 +1063,7 @@ static void obj_out (long segto, void *data, unsigned long type,
}
static void obj_write_fixup (ObjRecord *orp, int bytes,
- int segrel, long seg, long wrt)
+ int segrel, long seg, long wrt, struct Segment *segto)
{
int locat, method;
int base;
@@ -1080,6 +1083,11 @@ static void obj_write_fixup (ObjRecord *orp, int bytes,
if (forp == NULL) {
orp->child = forp = obj_new();
forp->up = &(orp->child);
+ /* We should choose between FIXUPP and FIXU32 record type */
+ /* If we're targeting a 32-bit segment, use a FIXU32 record */
+ if (segto->use32)
+ forp->type = FIXU32;
+ else
forp->type = FIXUPP;
}
diff --git a/parser.c b/parser.c
index 1a9c9e4e..0a85c9e1 100644
--- a/parser.c
+++ b/parser.c
@@ -647,8 +647,13 @@ insn *parse_line (int pass, char *buffer, insn *result,
result->oprs[operand].offset = reloc_value(value);
result->oprs[operand].segment = reloc_seg(value);
result->oprs[operand].wrt = reloc_wrt(value);
- if (is_simple(value) && reloc_value(value)==1)
- result->oprs[operand].type |= UNITY;
+ if (is_simple(value)) {
+ if (reloc_value(value)==1)
+ result->oprs[operand].type |= UNITY;
+ if (reloc_value(value) >= -128 &&
+ reloc_value(value) <= 127)
+ result->oprs[operand].type |= SBYTE;
+ }
}
else /* it's a register */
{
diff --git a/preproc.c b/preproc.c
index 5286dd0c..5753cf2c 100644
--- a/preproc.c
+++ b/preproc.c
@@ -34,6 +34,7 @@
*/
#include <stdio.h>
+#include <stdarg.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
@@ -100,6 +101,7 @@ struct MMacro {
Token *iline; /* invocation line */
int nparam, rotate, *paramlen;
unsigned long unique;
+ int lineno; /* Current line number on expansion */
};
/*
@@ -267,8 +269,9 @@ static char *directives[] = {
"%endrep", "%error", "%exitrep", "%iassign", "%idefine", "%if",
"%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifnctx",
"%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnnum",
- "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", "%line",
- "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", "%undef"
+ "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", "%ixdefine",
+ "%line", "%macro", "%pop", "%push", "%rep", "%repl", "%rotate",
+ "%undef", "%xdefine"
};
enum {
PP_ASSIGN, PP_CLEAR, PP_DEFINE, PP_ELIF, PP_ELIFCTX, PP_ELIFDEF,
@@ -278,8 +281,9 @@ enum {
PP_ENDREP, PP_ERROR, PP_EXITREP, PP_IASSIGN, PP_IDEFINE, PP_IF,
PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFNCTX,
PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNNUM,
- PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, PP_LINE,
- PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, PP_UNDEF
+ PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, PP_IXDEFINE,
+ PP_LINE, PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE,
+ PP_UNDEF, PP_XDEFINE
};
@@ -287,7 +291,7 @@ static Context *cstk;
static Include *istk;
static IncPath *ipath = NULL;
-static efunc error;
+static efunc __error; /* Pointer to client-provided error reporting function */
static evalfunc evaluate;
static int pass; /* HACK: pass 0 = generate dependencies only */
@@ -345,7 +349,10 @@ int any_extrastdmac;
*/
static Token *expand_mmac_params (Token *tline);
static Token *expand_smacro (Token *tline);
+static Token *expand_id (Token *tline);
+static Context *get_ctx (char *name, int all_contexts);
static void make_tok_num(Token *tok, long val);
+static void error (int severity, char *fmt, ...);
/*
* Macros for safe checking of token pointers, avoid *(NULL)
@@ -586,8 +593,10 @@ static Token *tokenise (char *line)
while (*line) {
p = line;
- if (*p == '%' && ( isdigit(p[1]) ||
- ((p[1] == '-' || p[1] == '+') && isdigit(p[2]))))
+ if (*p == '%' &&
+ (isdigit(p[1]) ||
+ ((p[1] == '-' || p[1] == '+') && isdigit(p[2])) ||
+ ((p[1] == '+') && (isspace (p[2]) || !p[2]))))
{
p++;
do {
@@ -702,8 +711,10 @@ static Token *tokenise (char *line)
/*
* Convert a line of tokens back into text.
+ * If expand_locals is not zero, identifiers of the form "%$*xxx"
+ * will be transformed into ..@ctxnum.xxx
*/
-char *detoken (Token *tlist)
+static char *detoken (Token *tlist, int expand_locals)
{
Token *t;
int len;
@@ -719,6 +730,24 @@ char *detoken (Token *tlist)
else
t->text = NULL;
}
+ /* Expand local macros here and not during preprocessing */
+ if (expand_locals &&
+ t->type == TOK_PREPROC_ID && t->text &&
+ t->text[0] == '%' && t->text [1] == '$') {
+ Context *ctx = get_ctx (t->text, FALSE);
+ if (ctx) {
+ char buffer [40];
+ char *p, *q = t->text + 2;
+
+ q += strspn (q, "$");
+ sprintf (buffer, "..@%lu.", ctx->number);
+ p = nasm_malloc (strlen(buffer)+strlen(q)+1);
+ strcpy (p, buffer);
+ strcat (p, q);
+ nasm_free (t->text);
+ t->text = p;
+ }
+ }
if (t->text)
len += strlen(t->text);
}
@@ -827,43 +856,62 @@ static int ppscan(void *private_data, struct tokenval *tokval)
}
/*
+ * Compare a string to the name of an existing macro; this is a
+ * simple wrapper which calls either strcmp or nasm_stricmp
+ * depending on the value of the `casesense' parameter.
+ */
+static int mstrcmp(char *p, char *q, int casesense)
+{
+ return casesense ? strcmp(p,q) : nasm_stricmp(p,q);
+}
+
+/*
* Return the Context structure associated with a %$ token. Return
* NULL, having _already_ reported an error condition, if the
* context stack isn't deep enough for the supplied number of $
* signs.
+ * If all_contexts == TRUE, contexts that enclose current are
+ * also scanned for such smacro, until it is found; if not -
+ * only the context that directly results from the number of $'s
+ * in variable's name.
*/
-static Context *get_ctx (char *name)
+static Context *get_ctx (char *name, int all_contexts)
{
Context *ctx;
+ SMacro *m;
int i;
+ if (!name || name[0] != '%' || name[1] != '$')
+ return NULL;
+
if (!cstk) {
error (ERR_NONFATAL, "`%s': context stack is empty", name);
return NULL;
}
- i = 1;
- ctx = cstk;
- while (name[i+1] == '$') {
- i++;
+ for (i = strspn (name+2, "$"), ctx = cstk; (i > 0) && ctx; i--) {
ctx = ctx->next;
+ i--;
+ }
if (!ctx) {
error (ERR_NONFATAL, "`%s': context stack is only"
" %d level%s deep", name, i-1, (i==2 ? "" : "s"));
return NULL;
}
- }
+ if (!all_contexts)
return ctx;
-}
-/*
- * Compare a string to the name of an existing macro; this is a
- * simple wrapper which calls either strcmp or nasm_stricmp
- * depending on the value of the `casesense' parameter.
- */
-static int mstrcmp(char *p, char *q, int casesense)
-{
- return casesense ? strcmp(p,q) : nasm_stricmp(p,q);
+ do {
+ /* Search for this smacro in found context */
+ m = ctx->localmac;
+ while (m) {
+ if (!mstrcmp(m->name, name, m->casesense))
+ return ctx;
+ m = m->next;
+ }
+ ctx = ctx->next;
+ } while (ctx);
+ return NULL;
}
/*
@@ -922,27 +970,30 @@ static FILE *inc_fopen(char *file)
*
* Note that this is also called with nparam zero to resolve
* `ifdef'.
+ *
+ * If you already know which context macro belongs to, you can pass
+ * the context pointer as first parameter; if you won't but name begins
+ * with %$ the context will be automatically computed. If all_contexts
+ * is true, macro will be searched in outer contexts as well.
*/
-static int smacro_defined (char *name, int nparam, SMacro **defn, int nocase)
+static int smacro_defined (Context *ctx, char *name, int nparam, SMacro **defn,
+ int nocase)
{
SMacro *m;
- Context *ctx;
- char *p;
- if (name[0] == '%' && name[1] == '$') {
- ctx = get_ctx (name);
+ if (ctx)
+ m = ctx->localmac;
+ else if (name[0] == '%' && name[1] == '$') {
+ if (cstk)
+ ctx = get_ctx (name, FALSE);
if (!ctx)
return FALSE; /* got to return _something_ */
m = ctx->localmac;
- p = name+1;
- p += strspn(p, "$");
- } else {
+ } else
m = smacros[hash(name)];
- p = name;
- }
while (m) {
- if (!mstrcmp(m->name, p, m->casesense & nocase) &&
+ if (!mstrcmp(m->name, name, m->casesense && nocase) &&
(nparam <= 0 || m->nparam == 0 || nparam == m->nparam)) {
if (defn) {
if (nparam == m->nparam || nparam == -1)
@@ -954,6 +1005,7 @@ static int smacro_defined (char *name, int nparam, SMacro **defn, int nocase)
}
m = m->next;
}
+
return FALSE;
}
@@ -1021,10 +1073,7 @@ static int if_condition (Token *tline, int i)
case PP_IFCTX: case PP_ELIFCTX:
case PP_IFNCTX: case PP_ELIFNCTX:
j = FALSE; /* have we matched yet? */
- if (!cstk)
- error(ERR_FATAL,
- "`%s': context stack is empty", directives[i]);
- else while (tline) {
+ while (cstk && tline) {
skip_white_(tline);
if (!tline || tline->type != TOK_ID) {
error(ERR_NONFATAL,
@@ -1055,7 +1104,7 @@ static int if_condition (Token *tline, int i)
free_tlist (origline);
return -1;
}
- if (smacro_defined(tline->text, 0, NULL, 1))
+ if (smacro_defined (NULL, tline->text, 0, NULL, 1))
j = TRUE;
tline = tline->next;
}
@@ -1143,7 +1192,7 @@ static int if_condition (Token *tline, int i)
tptr = &t;
tokval.t_type = TOKEN_INVALID;
evalresult = evaluate (ppscan, tptr, &tokval,
- NULL, pass | 0x10, error, NULL);
+ NULL, pass | CRITICAL, error, NULL);
free_tlist (tline);
if (!evalresult)
return -1;
@@ -1167,6 +1216,18 @@ static int if_condition (Token *tline, int i)
}
/*
+ * Expand macros in a string. Used in %error and %include directives.
+ * First tokenise the string, apply "expand_smacro" and then de-tokenise back.
+ * The returned variable should ALWAYS be freed after usage.
+ */
+void expand_macros_in_string (char **p)
+{
+ Token *line = tokenise (*p);
+ line = expand_smacro (line);
+ *p = detoken (line, FALSE);
+}
+
+/*
* Find out if a line contains a preprocessor directive, and deal
* with it if so.
*
@@ -1303,11 +1364,12 @@ static int do_directive (Token *tline)
p[strlen(p)-1] = '\0'; /* remove the trailing quote */
} else
p = tline->text; /* internal_string is easier */
+ expand_macros_in_string (&p);
inc = nasm_malloc(sizeof(Include));
inc->next = istk;
inc->conds = NULL;
inc->fp = inc_fopen(p);
- inc->fname = src_set_fname(nasm_strdup(p));
+ inc->fname = src_set_fname (p);
inc->lineno = src_set_linnum(0);
inc->lineinc = 1;
inc->expansion = NULL;
@@ -1320,6 +1382,7 @@ static int do_directive (Token *tline)
case PP_PUSH:
tline = tline->next;
skip_white_(tline);
+ tline = expand_id (tline);
if (!tok_type_(tline, TOK_ID)) {
error(ERR_NONFATAL,
"`%%push' expects a context identifier");
@@ -1341,6 +1404,7 @@ static int do_directive (Token *tline)
case PP_REPL:
tline = tline->next;
skip_white_(tline);
+ tline = expand_id (tline);
if (!tok_type_(tline, TOK_ID)) {
error(ERR_NONFATAL,
"`%%repl' expects a context identifier");
@@ -1379,10 +1443,12 @@ static int do_directive (Token *tline)
if (tok_type_(tline, TOK_STRING)) {
p = tline->text+1; /* point past the quote to the name */
p[strlen(p)-1] = '\0'; /* remove the trailing quote */
- error(ERR_NONFATAL, "user error: %s", p);
+ expand_macros_in_string (&p);
+ error (ERR_NONFATAL, "%s", p);
+ nasm_free (p);
} else {
- p = detoken(tline);
- error(ERR_WARNING, "user error: %s", p);
+ p = detoken(tline, FALSE);
+ error (ERR_WARNING, "%s", p);
nasm_free(p);
}
free_tlist (origline);
@@ -1409,15 +1475,7 @@ static int do_directive (Token *tline)
j = if_condition(tline->next, i);
tline->next = NULL; /* it got freed */
free_tlist (origline);
- if (j < 0)
- /*
- * Bogus expression in %if, but we should pretend
- * it was OK anyway, so that we don't get an error
- * cascade on the subsequent %else / %endif.
- */
- j = COND_NEVER;
- else
- j = j ? COND_IF_TRUE : COND_IF_FALSE;
+ j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
}
cond = nasm_malloc(sizeof(Cond));
cond->next = istk->conds;
@@ -1449,14 +1507,7 @@ static int do_directive (Token *tline)
j = if_condition(expand_mmac_params(tline->next), i);
tline->next = NULL; /* it got freed */
free_tlist (origline);
- if (j < 0)
- /*
- * The expression was bogus, but let's make
- * %endif not complain about missing %if
- */
- j = COND_NEVER;
- else
- istk->conds->state = j ? COND_IF_TRUE : COND_IF_FALSE;
+ istk->conds->state = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
}
return (istk->conds->state == COND_IF_TRUE ? 5 : 1);
@@ -1495,6 +1546,7 @@ static int do_directive (Token *tline)
(i == PP_IMACRO ? "i" : ""));
tline = tline->next;
skip_white_(tline);
+ tline = expand_id (tline);
if (!tok_type_(tline, TOK_ID)) {
error (ERR_NONFATAL,
"`%%%smacro' expects a macro name",
@@ -1508,7 +1560,7 @@ static int do_directive (Token *tline)
defining->nolist = FALSE;
defining->in_progress = FALSE;
defining->rep_nest = NULL;
- tline = tline->next;
+ tline = expand_smacro (tline->next);
skip_white_(tline);
if (!tok_type_(tline, TOK_NUMBER)) {
error (ERR_NONFATAL,
@@ -1717,36 +1769,38 @@ static int do_directive (Token *tline)
free_tlist (origline);
return 1;
+ case PP_XDEFINE:
+ case PP_IXDEFINE:
case PP_DEFINE:
case PP_IDEFINE:
tline = tline->next;
skip_white_(tline);
+ tline = expand_id (tline);
if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) {
error (ERR_NONFATAL,
- "`%%%sdefine' expects a macro identifier",
- (i == PP_IDEFINE ? "i" : ""));
+ "`%%%s%sdefine' expects a macro identifier",
+ ((i == PP_IDEFINE || i == PP_IXDEFINE) ? "i" : ""),
+ ((i == PP_XDEFINE || i == PP_IXDEFINE) ? "x" : ""));
free_tlist (origline);
return 3;
}
- mname = tline->text;
- if (tline->type == TOK_ID) {
- p = tline->text;
- smhead = &smacros[hash(mname)];
- } else {
- ctx = get_ctx (tline->text);
- if (ctx == NULL)
- return 3;
- else {
- p = tline->text+1;
- p += strspn(p, "$");
+
+ ctx = get_ctx (tline->text, FALSE);
+ if (!ctx)
+ smhead = &smacros[hash(tline->text)];
+ else
smhead = &ctx->localmac;
- }
- }
+ mname = tline->text;
last = tline;
param_start = tline = tline->next;
nparam = 0;
+
+ /* Expand the macro definition now for %xdefine and %ixdefine */
+ if ((i == PP_XDEFINE) || (i == PP_IXDEFINE))
+ tline = expand_smacro (tline);
+
if (tok_is_(tline, "(")) {
/*
* This macro has parameters.
@@ -1811,7 +1865,7 @@ static int do_directive (Token *tline)
* carefully re-terminated after chopping off the expansion
* from the end).
*/
- if (smacro_defined (mname, nparam, &smac, i==PP_DEFINE)) {
+ if (smacro_defined (ctx, mname, nparam, &smac, i == PP_DEFINE)) {
if (!smac) {
error (ERR_WARNING,
"single-line macro `%s' defined both with and"
@@ -1833,8 +1887,8 @@ static int do_directive (Token *tline)
smac->next = *smhead;
*smhead = smac;
}
- smac->name = nasm_strdup(p);
- smac->casesense = (i == PP_DEFINE);
+ smac->name = nasm_strdup(mname);
+ smac->casesense = ((i == PP_DEFINE) || (i == PP_XDEFINE));
smac->nparam = nparam;
smac->expansion = macro_start;
smac->in_progress = FALSE;
@@ -1844,6 +1898,7 @@ static int do_directive (Token *tline)
case PP_UNDEF:
tline = tline->next;
skip_white_(tline);
+ tline = expand_id (tline);
if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) {
@@ -1852,33 +1907,26 @@ static int do_directive (Token *tline)
free_tlist (origline);
return 3;
}
- mname = tline->text;
- if (tline->type == TOK_ID) {
- p = tline->text;
- smhead = &smacros[hash(mname)];
- } else {
- ctx = get_ctx (tline->text);
- if (ctx == NULL) {
- free_tlist (origline);
- return 3;
- } else {
- p = tline->text+1;
- p += strspn(p, "$");
- smhead = &ctx->localmac;
- }
+ if (tline->next) {
+ error (ERR_WARNING,
+ "trailing garbage after macro name ignored");
}
+
+ /* Find the context that symbol belongs to */
+ ctx = get_ctx (tline->text, FALSE);
+ if (!ctx)
+ smhead = &smacros[hash(tline->text)];
+ else
+ smhead = &ctx->localmac;
+
+ mname = tline->text;
last = tline;
- tline = tline->next;
last->next = NULL;
- if (tline)
- error(ERR_WARNING,
- "trailing garbage after macro name ignored");
-
/*
* We now have a macro name... go hunt for it.
*/
- while (smacro_defined (mname, -1, &smac, 1)) {
+ while (smacro_defined (ctx, mname, -1, &smac, 1)) {
/* Defined, so we need to find its predecessor and nuke it */
SMacro **s;
for ( s = smhead ; *s && *s != smac ; s = &(*s)->next );
@@ -1889,12 +1937,14 @@ static int do_directive (Token *tline)
nasm_free(smac);
}
}
+ free_tlist (origline);
return 3;
case PP_ASSIGN:
case PP_IASSIGN:
tline = tline->next;
skip_white_(tline);
+ tline = expand_id (tline);
if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) {
@@ -1904,26 +1954,16 @@ static int do_directive (Token *tline)
free_tlist (origline);
return 3;
}
- mname = tline->text;
- if (tline->type == TOK_ID) {
- p = tline->text;
- smhead = &smacros[hash(mname)];
- } else {
- ctx = get_ctx (tline->text);
- if (ctx == NULL) {
- free_tlist (origline);
- return 3;
- } else {
- p = tline->text+1;
- p += strspn(p, "$");
+ ctx = get_ctx (tline->text, FALSE);
+ if (!ctx)
+ smhead = &smacros[hash(tline->text)];
+ else
smhead = &ctx->localmac;
- }
- }
+ mname = tline->text;
last = tline;
- tline = tline->next;
+ tline = expand_smacro (tline->next);
last->next = NULL;
- tline = expand_smacro (tline);
t = tline;
tptr = &t;
tokval.t_type = TOKEN_INVALID;
@@ -1956,7 +1996,7 @@ static int do_directive (Token *tline)
* zero, and a numeric token to use as an expansion. Create
* and store an SMacro.
*/
- if (smacro_defined (mname, 0, &smac, i==PP_ASSIGN)) {
+ if (smacro_defined (ctx, mname, 0, &smac, i == PP_ASSIGN)) {
if (!smac)
error (ERR_WARNING,
"single-line macro `%s' defined both with and"
@@ -1976,7 +2016,7 @@ static int do_directive (Token *tline)
smac->next = *smhead;
*smhead = smac;
}
- smac->name = nasm_strdup(p);
+ smac->name = nasm_strdup(mname);
smac->casesense = (i == PP_ASSIGN);
smac->nparam = 0;
smac->expansion = macro_start;
@@ -2013,7 +2053,7 @@ static int do_directive (Token *tline)
src_set_linnum(k);
istk->lineinc = m;
if (tline) {
- nasm_free ( src_set_fname ( detoken(tline) ) );
+ nasm_free (src_set_fname (detoken (tline, FALSE)));
}
free_tlist (origline);
return 5;
@@ -2077,7 +2117,7 @@ static Token *expand_mmac_params (Token *tline)
while (tline) {
if (tline->type == TOK_PREPROC_ID &&
- (tline->text[1] == '+' || tline->text[1] == '-' ||
+ (((tline->text[1] == '+' || tline->text[1] == '-') && tline->text [2]) ||
tline->text[1] == '%' ||
(tline->text[1] >= '0' && tline->text[1] <= '9'))) {
char *text = NULL;
@@ -2244,26 +2284,38 @@ static Token *expand_smacro (Token *tline)
SMacro *head = NULL, *m;
Token **params;
int *paramsize;
- int nparam, sparam, brackets;
- char *p;
+ int nparam, sparam, brackets, rescan;
+ Token *org_tline = tline;
+ Context *ctx;
+ char *mname;
+
+ /*
+ * Trick: we should avoid changing the start token pointer since it can
+ * be contained in "next" field of other token. Because of this
+ * we allocate a copy of first token and work with it; at the end of
+ * routine we copy it back
+ */
+ if (org_tline)
+ {
+ tline = nasm_malloc (sizeof (Token));
+ *tline = *org_tline;
+ }
+again:
tail = &thead;
thead = NULL;
while (tline) { /* main token loop */
- p = NULL;
- if (tline->type == TOK_ID) {
- head = smacros[hash(tline->text)];
- p = tline->text;
- } else if (tline->type == TOK_PREPROC_ID && tline->text[1] == '$') {
- Context *ctx = get_ctx (tline->text);
- if (ctx) {
+ if ((mname = tline->text)) {
+ /* if this token is a local macro, look in local context */
+ if (tline->type == TOK_ID || tline->type == TOK_PREPROC_ID)
+ ctx = get_ctx (mname, TRUE);
+ else
+ ctx = NULL;
+ if (!ctx)
+ head = smacros[hash(mname)];
+ else
head = ctx->localmac;
- p = tline->text+2;
- p += strspn(p, "$");
- }
- }
- if (p) {
/*
* We've hit an identifier. As in is_mmacro below, we first
* check whether the identifier is a single-line macro at
@@ -2271,7 +2323,7 @@ static Token *expand_smacro (Token *tline)
* necessary.
*/
for (m = head; m; m = m->next)
- if (!mstrcmp(m->name, p, m->casesense))
+ if (!mstrcmp(m->name, mname, m->casesense))
break;
if (m) {
mstart = tline;
@@ -2303,8 +2355,7 @@ static Token *expand_smacro (Token *tline)
nasm_free (t);
continue;
}
- }
- else {
+ } else {
/*
* Complicated case: at least one macro with this name
* exists and takes parameters. We must find the
@@ -2393,7 +2444,7 @@ static Token *expand_smacro (Token *tline)
} /* parameter loop */
nparam++;
while (m && (m->nparam != nparam ||
- mstrcmp(m->name, p, m->casesense)))
+ mstrcmp(m->name, mname, m->casesense)))
m = m->next;
if (!m)
error (ERR_WARNING|ERR_WARN_MNP,
@@ -2415,8 +2466,7 @@ static Token *expand_smacro (Token *tline)
nasm_free (params);
nasm_free (paramsize);
tline = mstart;
- }
- else {
+ } else {
/*
* Expand the macro: we are placed on the last token of the
* call, so that we can easily split the call from the
@@ -2485,27 +2535,138 @@ static Token *expand_smacro (Token *tline)
t->mac = NULL;
t->next = NULL;
tail = &t->next;
- if (t->type == TOK_PREPROC_ID && t->text[1] == '$') {
- Context *c = get_ctx (t->text);
- char *p, *q, buffer[40];
-
- t->type = TOK_ID;
- if (c) {
- q = t->text+1;
- q += strspn(q, "$");
- sprintf(buffer, "..@%lu.", c->number);
- p = nasm_strcat (buffer,q);
+ }
+ }
+
+ /*
+ * Now scan the entire line and look for successive TOK_IDs that resulted
+ * after expansion (they can't be produced by tokenise()). The successive
+ * TOK_IDs should be concatenated.
+ * Also we look for %+ tokens and concatenate the tokens before and after
+ * them (without white spaces in between).
+ */
+ t = thead;
+ rescan = 0;
+ while (t) {
+ while (t && t->type != TOK_ID && t->type != TOK_PREPROC_ID)
+ t = t->next;
+ if (!t || !t->next)
+ break;
+ if (t->next->type == TOK_ID ||
+ t->next->type == TOK_PREPROC_ID ||
+ t->next->type == TOK_NUMBER) {
+ Token *next = t->next->next;
+ char *p = nasm_malloc (strlen (t->text) + strlen (t->next->text) + 1);
+ strcpy (p, t->text);
+ strcat (p, t->next->text);
nasm_free (t->text);
+ nasm_free (t->next->text);
+ nasm_free (t->next);
+ t->next = next;
t->text = p;
+ rescan = 1;
+ } else if (t->next->type == TOK_WHITESPACE && t->next->next &&
+ t->next->next->type == TOK_PREPROC_ID &&
+ strcmp (t->next->next->text, "%+") == 0) {
+ /* free the next whitespace, the %+ token and next whitespace */
+ int i;
+ for (i = 1; i <= 3; i++)
+ {
+ Token *next;
+ if (!t->next || (i != 2 && t->next->type != TOK_WHITESPACE))
+ break;
+ next = t->next->next;
+ nasm_free (t->next->text);
+ nasm_free (t->next);
+ t->next = next;
+ } /* endfor */
+ } else
+ t = t->next;
}
+ /* If we concatenaded something, re-scan the line for macros */
+ if (rescan) {
+ tline = thead;
+ goto again;
}
- }
+
+ if (org_tline)
+ {
+ if (thead) {
+ *org_tline = *thead;
+ nasm_free (thead);
+ } else
+ {
+ /* the expression expanded to empty line;
+ we can't return NULL for some reasons
+ we just set the line to a single WHITESPACE token. */
+ memset (org_tline, 0, sizeof (*org_tline));
+ org_tline->text = nasm_strdup (" ");
+ org_tline->type = TOK_WHITESPACE;
+ }
+ thead = org_tline;
}
return thead;
}
/*
+ * Similar to expand_smacro but used exclusively with macro identifiers
+ * right before they are fetched in. The reason is that there can be
+ * identifiers consisting of several subparts. We consider that if there
+ * are more than one element forming the name, user wants a expansion,
+ * otherwise it will be left as-is. Example:
+ *
+ * %define %$abc cde
+ *
+ * the identifier %$abc will be left as-is so that the handler for %define
+ * will suck it and define the corresponding value. Other case:
+ *
+ * %define _%$abc cde
+ *
+ * In this case user wants name to be expanded *before* %define starts
+ * working, so we'll expand %$abc into something (if it has a value;
+ * otherwise it will be left as-is) then concatenate all successive
+ * PP_IDs into one.
+ */
+static Token *expand_id (Token *tline)
+{
+ Token *cur, *oldnext = NULL;
+
+ if (!tline ||
+ !tline->next)
+ return tline;
+
+ cur = tline;
+ while (cur->next &&
+ (cur->next->type == TOK_ID ||
+ cur->next->type == TOK_PREPROC_ID ||
+ cur->next->type == TOK_NUMBER))
+ cur = cur->next;
+
+ /* If identifier consists of just one token, don't expand */
+ if (cur == tline)
+ return tline;
+
+ if (cur) {
+ oldnext = cur->next; /* Detach the tail past identifier */
+ cur->next = NULL; /* so that expand_smacro stops here */
+ }
+
+ tline = expand_smacro (tline);
+
+ if (cur) {
+ /* expand_smacro possibly changhed tline; re-scan for EOL */
+ cur = tline;
+ while (cur && cur->next)
+ cur = cur->next;
+ if (cur)
+ cur->next = oldnext;
+ }
+
+ return tline;
+}
+
+/*
* Determine whether the given line constitutes a multi-line macro
* call, and return the MMacro structure called if so. Doesn't have
* to check for an initial label - that's taken care of in
@@ -2709,6 +2870,7 @@ static int expand_mmacro (Token *tline)
m->rotate = 0;
m->paramlen = paramlen;
m->unique = unique++;
+ m->lineno = 0;
m->next_active = istk->mstk;
istk->mstk = m;
@@ -2745,7 +2907,7 @@ static int expand_mmacro (Token *tline)
* If we had a label, push it on as the first line of
* the macro expansion.
*/
- if (label)
+ if (label) {
if (dont_prepend<0)
free_tlist(startline);
else {
@@ -2764,18 +2926,45 @@ static int expand_mmacro (Token *tline)
tt->text = nasm_strdup(":");
}
}
+ }
list->uplevel (m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
return 1;
}
+/*
+ * Since preprocessor always operate only on the line that didn't
+ * arrived yet, we should always use ERR_OFFBY1. Also since user
+ * won't want to see same error twice (preprocessing is done once
+ * per pass) we will want to show errors only during pass one.
+ */
+static void error (int severity, char *fmt, ...)
+{
+ va_list arg;
+ char buff [1024];
+
+ /* If we're in a dead branch of IF or something like it, ignore the error */
+ if (istk->conds && !emitting(istk->conds->state))
+ return;
+
+ va_start (arg, fmt);
+ vsprintf (buff, fmt, arg);
+ va_end (arg);
+
+ if (istk->mstk && istk->mstk->name)
+ __error (severity|ERR_PASS1, "(%s:%d) %s", istk->mstk->name,
+ istk->mstk->lineno, buff);
+ else
+ __error (severity|ERR_PASS1, "%s", buff);
+}
+
static void pp_reset (char *file, int apass, efunc errfunc, evalfunc eval,
ListGen *listgen)
{
int h;
- error = errfunc;
+ __error = errfunc;
cstk = NULL;
istk = nasm_malloc(sizeof(Include));
istk->next = NULL;
@@ -2903,10 +3092,12 @@ static char *pp_getline (void)
if (istk->expansion) { /* from a macro expansion */
char *p;
Line *l = istk->expansion;
+ if (istk->mstk)
+ istk->mstk->lineno++;
tline = l->first;
istk->expansion = l->next;
nasm_free (l);
- p = detoken(tline);
+ p = detoken (tline, FALSE);
list->line (LIST_MACRO, p);
nasm_free(p);
break;
@@ -2994,7 +3185,7 @@ static char *pp_getline (void)
/*
* De-tokenise the line again, and emit it.
*/
- line = detoken(tline);
+ line = detoken(tline, TRUE);
free_tlist (tline);
break;
} else {
diff --git a/rdoff/Makefile.in b/rdoff/Makefile.in
index c55851db..37cc1119 100644
--- a/rdoff/Makefile.in
+++ b/rdoff/Makefile.in
@@ -29,7 +29,7 @@ LDRDFLIBS = rdoff.o nasmlib.o symtab.o collectn.o rdlib.o segtab.o hash.o
RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o hash.o
.c.o:
- $(CC) -c $(CFLAGS) $<
+ $(CC) -c $(CFLAGS) -o $@ $<
all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com
diff --git a/standard.mac b/standard.mac
index 5f862980..05905d61 100644
--- a/standard.mac
+++ b/standard.mac
@@ -71,6 +71,13 @@ __SECT__
[bits %1]
%endmacro
+%imacro use16 0.nolist
+[bits 16]
+%endmacro
+%imacro use32 0.nolist
+[bits 32]
+%endmacro
+
%imacro global 1-*.nolist
%rep %0
[global %1]
@@ -84,3 +91,8 @@ __SECT__
%rotate 1
%endrep
%endmacro
+
+%imacro cpu 1+.nolist
+[cpu %1]
+%endmacro
+
diff --git a/test/test1.asm b/test/test1.asm
new file mode 100644
index 00000000..ce24ca15
--- /dev/null
+++ b/test/test1.asm
@@ -0,0 +1,62 @@
+ segment text
+ bits 16
+
+ imul edx,[addr],10
+ imul eax,20
+ imul edx,eax,130
+
+ push 0x40
+ push word 0x40
+ push word 4095
+ push byte 0x40
+ push dword 0x40
+ push dword 4095
+
+ add ax,1
+ add bx,1
+ cmp cx,0
+ sub dx,3
+ sbb si,-1
+ xor ax,0xffff
+ xor ax,-1
+ xor bx,0xffff
+ xor bx,-1
+
+
+ adc bx,add1
+ adc bx,-7
+ adc bx,-128
+ adc bx,-129
+ adc bx,addr
+ adc bx,byte -7
+add1: adc bx,word -7
+ adc bx,add1
+ resb 256
+addr: nop
+ adc bx,addr
+ adc eax,5
+ adc eax,500
+ adc eax,byte 5
+ adc ax,4
+ adc ebx,7
+ adc ebx,700
+ adc ebx,byte 7
+ adc ecx,1
+ adc eax,1
+
+ shr edx,mmm
+ shr edx,one
+ adc ebx,byte mmm
+m1: adc ebx,mmm
+mmm equ 9
+m2: adc ebx,mmm
+one equ 1
+ shr edx,mmm
+ shr edx,one
+ shr edx,1
+tend dw tend
+
+ segment data
+ db 'abc'
+ db '', 12, 13, 0
+
diff --git a/test/test2.asm b/test/test2.asm
new file mode 100644
index 00000000..5bbb034c
--- /dev/null
+++ b/test/test2.asm
@@ -0,0 +1,18 @@
+ USE16
+ CPU 386
+
+debugdump001:
+goo: jmp foo
+ jc near foo
+ mov ax,[si+5]
+ mov ax,[si-7]
+ mov ax,[si+n]
+ nop
+ resb 10
+foo: jmp goo
+ jc goo
+ jmp short goo
+debugdump002: push 0
+n equ 3
+
+
diff --git a/test/test2a.asm b/test/test2a.asm
new file mode 100644
index 00000000..2ed09a76
--- /dev/null
+++ b/test/test2a.asm
@@ -0,0 +1,22 @@
+ use32
+ cpu P3
+
+debugdump001:
+goo: jmp foo
+; cpu 386
+ jc near foo
+ mov ax,[si+5]
+ mov ax,[si-7]
+ mov ax,[si+n]
+ align 16
+; cpu 486
+ bswap edx
+; cpu 186
+ resb 10
+foo: jmp goo
+ jc goo
+ jmp short goo
+debugdump002: push 0
+n equ 3
+
+
diff --git a/test/test3.asm b/test/test3.asm
new file mode 100644
index 00000000..457ed44d
--- /dev/null
+++ b/test/test3.asm
@@ -0,0 +1,45 @@
+debugdump001:
+ jc baker
+ jmp able - 20
+ jmp able
+baker: nop
+ times 125 nop
+able: jmp baker
+ jmp baker + 20
+ times 122 nop
+ jmp able
+loc: nop
+ jc able+20
+
+ jmp able1 - 20
+ jmp able1
+baker1: nop
+ times 126 nop
+able1: jmp near baker1
+ jmp baker1 + 20
+ times 122 nop
+ jmp able1
+loc1: nop
+
+able2: jmp baker2
+ times 124 nop
+ jmp able2
+ nop
+baker2: nop
+
+
+
+able3: jmp baker3
+ times 124 nop
+ jmp able3
+ nop
+ nop
+baker3: nop
+debugdump099: nop
+
+
+
+
+
+
+
diff --git a/test/test4.asm b/test/test4.asm
new file mode 100644
index 00000000..357553e2
--- /dev/null
+++ b/test/test4.asm
@@ -0,0 +1,16 @@
+ cpu 186
+
+start: jmp able
+ xor ax,ax
+ jc start
+ jnc able
+ jc charlie
+ times 100 nop
+able: jc start
+ times 100 nop
+baker: jc start
+ times 100 nop
+charlie: jc baker
+ jnc able
+ jmp start
+end: db 0
diff --git a/test/test4a.asm b/test/test4a.asm
new file mode 100644
index 00000000..bbf85a31
--- /dev/null
+++ b/test/test4a.asm
@@ -0,0 +1,16 @@
+ cpu 386
+
+start: jmp able
+ xor ax,ax
+ jc start
+ jnc able
+ jc charlie
+ times 100 nop
+able: jc start
+ times 100 nop
+baker: jc start
+ times 100 nop
+charlie: jc baker
+ jnc able
+ jmp start
+end: db 0
diff --git a/test/test4b.asm b/test/test4b.asm
new file mode 100644
index 00000000..63448817
--- /dev/null
+++ b/test/test4b.asm
@@ -0,0 +1,17 @@
+ use32
+ cpu 186
+
+start: jmp able
+ xor ax,ax
+ jc start
+ jnc able
+ jc charlie
+ times 100 nop
+able: jc start
+ times 100 nop
+baker: jc start
+ times 100 nop
+charlie: jc baker
+ jnc able
+ jmp start
+end: db 0
diff --git a/test/test4c.asm b/test/test4c.asm
new file mode 100644
index 00000000..5d873490
--- /dev/null
+++ b/test/test4c.asm
@@ -0,0 +1,17 @@
+ use32
+ cpu 386
+
+start: jmp able
+ xor ax,ax
+ jc start
+ jnc able
+ jc charlie
+ times 100 nop
+able: jc start
+ times 100 nop
+baker: jc start
+ times 100 nop
+charlie: jc baker
+ jnc able
+ jmp start
+end: db 0
diff --git a/test/test5.asm b/test/test5.asm
new file mode 100644
index 00000000..12b0ee42
--- /dev/null
+++ b/test/test5.asm
@@ -0,0 +1,43 @@
+%macro pushm 1-*
+%rep %0
+%rotate -1
+push %1
+%endrep
+%endmacro
+
+%macro popm 1-*
+%rep %0
+pop %1
+%rotate 1
+%endrep
+%endmacro
+
+%macro pusha 0
+push ax
+push cx
+push dx
+push bx
+push bp
+mov bp,sp
+lea bp,[bp+10]
+xchg bp,[bp-10]
+push bp
+push si
+push di
+%endmacro
+
+%macro popa 0
+pop di
+pop si
+pop bp
+pop bx
+pop bx
+pop dx
+pop cx
+pop ax
+%endmacro
+
+ pushm ax,bx,cx,dx
+ popm ax,bx,cx,dx
+ pusha
+ popa
diff --git a/test/test6.asm b/test/test6.asm
new file mode 100644
index 00000000..cf6dca0d
--- /dev/null
+++ b/test/test6.asm
@@ -0,0 +1,9 @@
+; test6.asm
+; assemble with; nasm -O2 ...
+;
+%rep 20000
+ jmp forward
+%endrep
+forward: dd forward
+
+ \ No newline at end of file
diff --git a/zoutieee.c b/zoutieee.c
index 8475e95f..0bcdb5c3 100644
--- a/zoutieee.c
+++ b/zoutieee.c
@@ -954,11 +954,12 @@ static void ieee_write_file (int debuginfo) {
ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset);
else
ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset);
- if (debuginfo)
+ if (debuginfo) {
if (pub->type >= 0x100)
ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100);
else
ieee_putascii("ATI%X,%X.\r\n", i, pub->type);
+ }
i++;
}
}
@@ -972,11 +973,12 @@ static void ieee_write_file (int debuginfo) {
ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset);
else
ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset);
- if (debuginfo)
+ if (debuginfo) {
if (pub->type >= 0x100)
ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100);
else
ieee_putascii("ATI%X,%X.\r\n", i, pub->type);
+ }
i++;
pub = pub->next;
}
@@ -1019,11 +1021,12 @@ static void ieee_write_file (int debuginfo) {
ieee_putascii("ASN%X,R%X,%lX,+.\r\n", i, loc->index,loc->offset);
else
ieee_putascii("ASN%X,%lX,%lX,+.\r\n", i, loc->segment*16,loc->offset);
- if (debuginfo)
+ if (debuginfo) {
if (loc->type >= 0x100)
ieee_putascii("ATN%X,T%X.\r\n", i, loc->type - 0x100);
else
ieee_putascii("ATN%X,%X.\r\n", i, loc->type);
+ }
i++;
}
}