NASM 0.98.03

This commit is contained in:
H. Peter Anvin 2002-04-30 20:59:21 +00:00
parent 41bf8002b2
commit af535c16cf
31 changed files with 1670 additions and 895 deletions

View file

@ -66,7 +66,7 @@ insnsd.o: insnsd.c nasm.h insnsi.h insns.h
labels.o: labels.c nasm.h insnsi.h nasmlib.h labels.o: labels.c nasm.h insnsi.h nasmlib.h
listing.o: listing.c nasm.h insnsi.h nasmlib.h listing.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 \ 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 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 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 outaout.o: outaout.c nasm.h insnsi.h nasmlib.h outform.h

View file

@ -13,7 +13,7 @@
# You may need to adjust these values. # You may need to adjust these values.
CC = gcc CC = gcc -s
CFLAGS = -O2 -I. CFLAGS = -O2 -I.
# You _shouldn't_ need to adjust anything below this line. # You _shouldn't_ need to adjust anything below this line.

49
README03.txt Normal file
View file

@ -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)

View file

@ -32,12 +32,19 @@
* \70, \71, \72 - a long relative operand, from operand 0, 1 or 2 * \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 * \1ab - a ModRM, calculated on EA in operand a, with the spare
* field the register value of operand b. * 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 * \2ab - a ModRM, calculated on EA in operand a, with the spare
* field equal to digit b. * field equal to digit b.
* \30x - might be an 0x67 byte, depending on the address size of * \30x - might be an 0x67 byte, depending on the address size of
* the memory reference in operand x. * the memory reference in operand x.
* \310 - indicates fixed 16-bit address size, i.e. optional 0x67. * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
* \311 - indicates fixed 32-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. * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
* \321 - indicates fixed 32-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 * \322 - indicates that this instruction is only valid when the
@ -52,6 +59,9 @@
* as a literal byte in order to aid the disassembler. * as a literal byte in order to aid the disassembler.
* \340 - reserve <operand 0> bytes of uninitialised storage. * \340 - reserve <operand 0> bytes of uninitialised storage.
* Operand 0 had better be a segmentless constant. * 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> #include <stdio.h>
@ -71,6 +81,7 @@ typedef struct {
unsigned char modrm, sib; /* the bytes themselves */ unsigned char modrm, sib; /* the bytes themselves */
} ea; } ea;
static unsigned long cpu; /* cpu level received from nasm.c */
static efunc errfunc; static efunc errfunc;
static struct ofmt *outfmt; static struct ofmt *outfmt;
static ListGen *list; 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); 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, insn *instruction, struct ofmt *output, efunc error,
ListGen *listgen) ListGen *listgen)
{ {
@ -147,6 +176,7 @@ long assemble (long segment, long offset, int bits,
long wsize = 0; /* size for DB etc. */ long wsize = 0; /* size for DB etc. */
errfunc = error; /* to pass to other functions */ errfunc = error; /* to pass to other functions */
cpu = cp;
outfmt = output; /* likewise */ outfmt = output; /* likewise */
list = listgen; /* and again */ list = listgen; /* and again */
@ -305,6 +335,8 @@ long assemble (long segment, long offset, int bits,
temp = nasm_instructions[instruction->opcode]; temp = nasm_instructions[instruction->opcode];
while (temp->opcode != -1) { while (temp->opcode != -1) {
int m = matches (temp, instruction); int m = matches (temp, instruction);
if (m == 99)
m += jmp_match(segment, offset, bits, instruction, temp->code);
if (m == 100) /* matches! */ if (m == 100) /* matches! */
{ {
@ -371,7 +403,7 @@ long assemble (long segment, long offset, int bits,
if (instruction->times > 1) if (instruction->times > 1)
list->downlevel (LIST_TIMES); list->downlevel (LIST_TIMES);
return offset - start; return offset - start;
} else if (m > 0) { } else if (m > 0 && m > size_prob) {
size_prob = m; size_prob = m;
} }
temp++; temp++;
@ -382,6 +414,8 @@ long assemble (long segment, long offset, int bits,
error (ERR_NONFATAL, "operation size not specified"); error (ERR_NONFATAL, "operation size not specified");
else if (size_prob == 2) else if (size_prob == 2)
error (ERR_NONFATAL, "mismatch in operand sizes"); error (ERR_NONFATAL, "mismatch in operand sizes");
else if (size_prob == 3)
error (ERR_NONFATAL, "no instruction for this cpu level");
else else
error (ERR_NONFATAL, error (ERR_NONFATAL,
"invalid combination of opcode and operands"); "invalid combination of opcode and operands");
@ -389,12 +423,13 @@ long assemble (long segment, long offset, int bits,
return 0; 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) insn *instruction, efunc error)
{ {
struct itemplate *temp; struct itemplate *temp;
errfunc = error; /* to pass to other functions */ errfunc = error; /* to pass to other functions */
cpu = cp;
if (instruction->opcode == -1) if (instruction->opcode == -1)
return 0; return 0;
@ -472,7 +507,11 @@ long insn_size (long segment, long offset, int bits,
temp = nasm_instructions[instruction->opcode]; temp = nasm_instructions[instruction->opcode];
while (temp->opcode != -1) { 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. */ /* we've matched an instruction. */
long isize; long isize;
char * codes = temp->code; char * codes = temp->code;
@ -498,6 +537,22 @@ long insn_size (long segment, long offset, int bits,
return -1; /* didn't match any instruction */ 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, static long calcsize (long segment, long offset, int bits,
insn *ins, char *codes) 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; ins->oprs[c-064].addr_size : bits) == 16 ? 2 : 4); break;
case 070: case 071: case 072: case 070: case 071: case 072:
length += 4; break; 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: case 0300: case 0301: case 0302:
length += chsize (&ins->oprs[c-0300], bits); length += chsize (&ins->oprs[c-0300], bits);
break; break;
@ -573,6 +636,10 @@ static long calcsize (long segment, long offset, int bits,
else else
length += ins->oprs[0].offset << (c-0340); length += ins->oprs[0].offset << (c-0340);
break; break;
case 0370: case 0371: case 0372:
break;
case 0373:
length++; break;
default: /* can't do it by 'case' statements */ default: /* can't do it by 'case' statements */
if (c>=0100 && c<=0277) { /* it's an EA */ if (c>=0100 && c<=0277) { /* it's an EA */
ea ea_data; ea ea_data;
@ -801,6 +868,51 @@ static void gencode (long segment, long offset, int bits,
offset += 4; offset += 4;
break; 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: case 0300: case 0301: case 0302:
if (chsize (&ins->oprs[c-0300], bits)) { if (chsize (&ins->oprs[c-0300], bits)) {
*bytes = 0x67; *bytes = 0x67;
@ -858,7 +970,7 @@ static void gencode (long segment, long offset, int bits,
break; break;
case 0330: case 0330:
*bytes = *codes++ + condval[ins->condition]; *bytes = *codes++ ^ condval[ins->condition];
out (offset, segment, bytes, out (offset, segment, bytes,
OUT_RAWDATA+1, NO_SEG, NO_SEG); OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
@ -887,6 +999,16 @@ static void gencode (long segment, long offset, int bits,
} }
break; 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 */ default: /* can't do it by 'case' statements */
if (c>=0100 && c<=0277) { /* it's an EA */ if (c>=0100 && c<=0277) { /* it's an EA */
ea ea_data; ea ea_data;
@ -1014,7 +1136,8 @@ static int matches (struct itemplate *itemp, insn *instruction)
(instruction->oprs[i].type & SIZE_MASK)) (instruction->oprs[i].type & SIZE_MASK))
return 0; return 0;
else 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++) for (i=0; i<itemp->operands; i++)
if (!(itemp->opd[i] & SIZE_MASK) && if (!(itemp->opd[i] & SIZE_MASK) &&
(instruction->oprs[i].type & SIZE_MASK & ~size[i])) (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; return ret;
} }

View file

@ -9,9 +9,9 @@
#ifndef NASM_ASSEMBLE_H #ifndef NASM_ASSEMBLE_H
#define 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); 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, insn *instruction, struct ofmt *output, efunc error,
ListGen *listgen); ListGen *listgen);

4
eval.c
View file

@ -760,8 +760,8 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
if (hint) if (hint)
hint->type = EAH_NOHINT; hint->type = EAH_NOHINT;
if (critical & 0x10) { if (critical & CRITICAL) {
critical &= ~0x10; critical &= ~CRITICAL;
bexpr = rexp0; bexpr = rexp0;
} else } else
bexpr = expr0; bexpr = expr0;

110
insns.dat
View file

@ -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 rm32,imm8 \321\300\1\x83\202\15 386
ADC reg_al,imm \1\x14\21 8086,SM ADC reg_al,imm \1\x14\21 8086,SM
ADC reg_ax,imm \320\1\x15\31 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 reg_eax,imm \321\1\x15\41 386,SM
ADC rm8,imm \300\1\x80\202\21 8086,SM ADC rm8,imm \300\1\x80\202\21 8086,SM
ADC rm16,imm \320\300\1\x81\202\31 8086,SM ADC rm16,imm \320\300\134\1\x81\202\131 8086,SM,ND
ADC rm32,imm \321\300\1\x81\202\41 386,SM 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,imm8 \300\1\x80\202\21 8086,SM
ADC mem,imm16 \320\300\1\x81\202\31 8086,SM ADC mem,imm16 \320\300\134\1\x81\202\131 8086,SM,ND
ADC mem,imm32 \321\300\1\x81\202\41 386,SM ADC mem,imm32 \321\300\144\1\x81\202\141 386,SM,ND
ADD mem,reg8 \300\17\101 8086,SM ADD mem,reg8 \300\17\101 8086,SM
ADD reg8,reg8 \300\17\101 8086 ADD reg8,reg8 \300\17\101 8086
ADD mem,reg16 \320\300\1\x01\101 8086,SM 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 rm32,imm8 \321\300\1\x83\200\15 386
ADD reg_al,imm \1\x04\21 8086,SM ADD reg_al,imm \1\x04\21 8086,SM
ADD reg_ax,imm \320\1\x05\31 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 reg_eax,imm \321\1\x05\41 386,SM
ADD rm8,imm \300\1\x80\200\21 8086,SM ADD rm8,imm \300\1\x80\200\21 8086,SM
ADD rm16,imm \320\300\1\x81\200\31 8086,SM ADD rm16,imm \320\300\134\1\x81\200\131 8086,SM,ND
ADD rm32,imm \321\300\1\x81\200\41 386,SM 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,imm8 \300\1\x80\200\21 8086,SM
ADD mem,imm16 \320\300\1\x81\200\31 8086,SM ADD mem,imm16 \320\300\134\1\x81\200\131 8086,SM,ND
ADD mem,imm32 \321\300\1\x81\200\41 386,SM ADD mem,imm32 \321\300\144\1\x81\200\141 386,SM,ND
AND mem,reg8 \300\1\x20\101 8086,SM AND mem,reg8 \300\1\x20\101 8086,SM
AND reg8,reg8 \300\1\x20\101 8086 AND reg8,reg8 \300\1\x20\101 8086
AND mem,reg16 \320\300\1\x21\101 8086,SM 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 rm32,imm8 \321\300\1\x83\204\15 386
AND reg_al,imm \1\x24\21 8086,SM AND reg_al,imm \1\x24\21 8086,SM
AND reg_ax,imm \320\1\x25\31 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 reg_eax,imm \321\1\x25\41 386,SM
AND rm8,imm \300\1\x80\204\21 8086,SM AND rm8,imm \300\1\x80\204\21 8086,SM
AND rm16,imm \320\300\1\x81\204\31 8086,SM AND rm16,imm \320\300\134\1\x81\204\131 8086,SM,ND
AND rm32,imm \321\300\1\x81\204\41 386,SM 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,imm8 \300\1\x80\204\21 8086,SM
AND mem,imm16 \320\300\1\x81\204\31 8086,SM AND mem,imm16 \320\300\134\1\x81\204\131 8086,SM,ND
AND mem,imm32 \321\300\1\x81\204\41 386,SM AND mem,imm32 \321\300\144\1\x81\204\141 386,SM,ND
ARPL mem,reg16 \300\1\x63\101 286,PROT,SM ARPL mem,reg16 \300\1\x63\101 286,PROT,SM
ARPL reg16,reg16 \300\1\x63\101 286,PROT ARPL reg16,reg16 \300\1\x63\101 286,PROT
BOUND reg16,mem \320\301\1\x62\110 186 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 rm32,imm8 \321\300\1\x83\207\15 386
CMP reg_al,imm \1\x3C\21 8086,SM CMP reg_al,imm \1\x3C\21 8086,SM
CMP reg_ax,imm \320\1\x3D\31 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 reg_eax,imm \321\1\x3D\41 386,SM
CMP rm8,imm \300\1\x80\207\21 8086,SM CMP rm8,imm \300\1\x80\207\21 8086,SM
CMP rm16,imm \320\300\1\x81\207\31 8086,SM CMP rm16,imm \320\300\134\1\x81\207\131 8086,SM,ND
CMP rm32,imm \321\300\1\x81\207\41 386,SM 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,imm8 \300\1\x80\207\21 8086,SM
CMP mem,imm16 \320\300\1\x81\207\31 8086,SM CMP mem,imm16 \320\300\134\1\x81\207\131 8086,SM,ND
CMP mem,imm32 \321\300\1\x81\207\41 386,SM CMP mem,imm32 \321\300\144\1\x81\207\141 386,SM,ND
CMPSB void \332\1\xA6 8086 CMPSB void \332\1\xA6 8086
CMPSD void \332\321\1\xA7 386 CMPSD void \332\321\1\xA7 386
CMPSW void \332\320\1\xA7 8086 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 rm16 \320\300\1\xF7\205 8086
IMUL rm32 \321\300\1\xF7\205 386 IMUL rm32 \321\300\1\xF7\205 386
IMUL reg16,mem \320\301\2\x0F\xAF\110 386,SM 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,mem \321\301\2\x0F\xAF\110 386,SM
IMUL reg32,reg32 \321\301\2\x0F\xAF\110 386 IMUL reg32,reg32 \321\2\x0F\xAF\110 386
IMUL reg16,mem,imm8 \320\301\1\x6B\110\16 286,SM IMUL reg16,mem,imm8 \320\301\1\x6B\110\16 186,SM
IMUL reg16,reg16,imm8 \320\301\1\x6B\110\16 286 IMUL reg16,reg16,imm8 \320\301\1\x6B\110\16 186
IMUL reg16,mem,imm \320\301\1\x69\110\32 286,SM IMUL reg16,mem,imm \320\301\135\1\x69\110\132 186,SM
IMUL reg16,reg16,imm \320\301\1\x69\110\32 286,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,mem,imm8 \321\301\1\x6B\110\16 386,SM
IMUL reg32,reg32,imm8 \321\301\1\x6B\110\16 386 IMUL reg32,reg32,imm8 \321\1\x6B\110\16 386
IMUL reg32,mem,imm \321\301\1\x69\110\42 386,SM IMUL reg32,mem,imm \321\301\145\1\x69\110\142 386,SM
IMUL reg32,reg32,imm \321\301\1\x69\110\42 386,SM IMUL reg32,reg32,imm \321\145\1\x69\110\142 386,SM
IMUL reg16,imm8 \320\1\x6B\100\15 286 IMUL reg16,imm8 \320\1\x6B\100\15 186
IMUL reg16,imm \320\1\x69\100\31 286,SM IMUL reg16,imm \320\134\1\x69\100\131 186,SM
IMUL reg32,imm8 \321\1\x6B\100\15 386 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_al,imm \1\xE4\25 8086,SB
IN reg_ax,imm \320\1\xE5\25 8086,SB IN reg_ax,imm \320\1\xE5\25 8086,SB
IN reg_eax,imm \321\1\xE5\25 386,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 JCXZ imm \320\1\xE3\50 8086
JECXZ imm \321\1\xE3\50 386 JECXZ imm \321\1\xE3\50 386
JMP imm|short \1\xEB\50 8086 JMP imm|short \1\xEB\50 8086
JMP imm \370\1\xEB\50 8086,ND
JMP imm \322\1\xE9\64 8086 JMP imm \322\1\xE9\64 8086
JMP imm|near \322\1\xE9\64 8086,ND JMP imm|near \322\1\xE9\64 8086,ND
JMP imm|far \322\1\xEA\34\37 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 rm32,imm8 \321\300\1\x83\201\15 386
OR reg_al,imm \1\x0C\21 8086,SM OR reg_al,imm \1\x0C\21 8086,SM
OR reg_ax,imm \320\1\x0D\31 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 reg_eax,imm \321\1\x0D\41 386,SM
OR rm8,imm \300\1\x80\201\21 8086,SM OR rm8,imm \300\1\x80\201\21 8086,SM
OR rm16,imm \320\300\1\x81\201\31 8086,SM OR rm16,imm \320\300\134\1\x81\201\131 8086,SM,ND
OR rm32,imm \321\300\1\x81\201\41 386,SM 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,imm8 \300\1\x80\201\21 8086,SM
OR mem,imm16 \320\300\1\x81\201\31 8086,SM OR mem,imm16 \320\300\134\1\x81\201\131 8086,SM,ND
OR mem,imm32 \321\300\1\x81\201\41 386,SM 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_al \1\xE6\24 8086,SB
OUT imm,reg_ax \320\1\xE7\24 8086,SB OUT imm,reg_ax \320\1\xE7\24 8086,SB
OUT imm,reg_eax \321\1\xE7\24 386,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 rm32 \321\300\1\xFF\206 386
PUSH reg_fsgs \1\x0F\7 386 PUSH reg_fsgs \1\x0F\7 386
PUSH reg_sreg \6 8086 PUSH reg_sreg \6 8086
PUSH imm8 \1\x6A\14 286 PUSH imm8 \1\x6A\14 186
PUSH imm16 \320\1\x68\30 286 PUSH sbyte \1\x6A\14 186,ND
PUSH imm32 \321\1\x68\40 386 PUSH imm16 \320\133\1\x68\130 186
PUSH imm32 \321\143\1\x68\140 386
PUSHA void \322\1\x60 186 PUSHA void \322\1\x60 186
PUSHAD void \321\1\x60 386 PUSHAD void \321\1\x60 386
PUSHAW void \320\1\x60 186 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 rm32,imm8 \321\300\1\x83\203\15 8086
SBB reg_al,imm \1\x1C\21 8086,SM SBB reg_al,imm \1\x1C\21 8086,SM
SBB reg_ax,imm \320\1\x1D\31 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 reg_eax,imm \321\1\x1D\41 386,SM
SBB rm8,imm \300\1\x80\203\21 8086,SM SBB rm8,imm \300\1\x80\203\21 8086,SM
SBB rm16,imm \320\300\1\x81\203\31 8086,SM SBB rm16,imm \320\300\134\1\x81\203\131 8086,SM,ND
SBB rm32,imm \321\300\1\x81\203\41 386,SM 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,imm8 \300\1\x80\203\21 8086,SM
SBB mem,imm16 \320\300\1\x81\203\31 8086,SM SBB mem,imm16 \320\300\134\1\x81\203\131 8086,SM,ND
SBB mem,imm32 \321\300\1\x81\203\41 386,SM SBB mem,imm32 \321\300\144\1\x81\203\141 386,SM,ND
SCASB void \332\1\xAE 8086 SCASB void \332\1\xAE 8086
SCASD void \332\321\1\xAF 386 SCASD void \332\321\1\xAF 386
SCASW void \332\320\1\xAF 8086 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 rm32,imm8 \321\300\1\x83\205\15 386
SUB reg_al,imm \1\x2C\21 8086,SM SUB reg_al,imm \1\x2C\21 8086,SM
SUB reg_ax,imm \320\1\x2D\31 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 reg_eax,imm \321\1\x2D\41 386,SM
SUB rm8,imm \300\1\x80\205\21 8086,SM SUB rm8,imm \300\1\x80\205\21 8086,SM
SUB rm16,imm \320\300\1\x81\205\31 8086,SM SUB rm16,imm \320\300\134\1\x81\205\131 8086,SM,ND
SUB rm32,imm \321\300\1\x81\205\41 386,SM 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,imm8 \300\1\x80\205\21 8086,SM
SUB mem,imm16 \320\300\1\x81\205\31 8086,SM SUB mem,imm16 \320\300\134\1\x81\205\131 8086,SM,ND
SUB mem,imm32 \321\300\1\x81\205\41 386,SM 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 SVDC mem80,reg_sreg \300\2\x0F\x78\101 486,CYRIX,SMM
SVLDT mem80 \300\2\x0F\x7A\200 486,CYRIX,SMM SVLDT mem80 \300\2\x0F\x7A\200 486,CYRIX,SMM
SVTS mem80 \300\2\x0F\x7C\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 mem,reg32 \321\300\1\x87\101 386,SM
XCHG reg32,reg32 \321\300\1\x87\101 386 XCHG reg32,reg32 \321\300\1\x87\101 386
XLATB void \1\xD7 8086 XLATB void \1\xD7 8086
XLAT void \1\xD7 8086
XOR mem,reg8 \300\1\x30\101 8086,SM XOR mem,reg8 \300\1\x30\101 8086,SM
XOR reg8,reg8 \300\1\x30\101 8086 XOR reg8,reg8 \300\1\x30\101 8086
XOR mem,reg16 \320\300\1\x31\101 8086,SM 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 rm32,imm8 \321\300\1\x83\206\15 386
XOR reg_al,imm \1\x34\21 8086,SM XOR reg_al,imm \1\x34\21 8086,SM
XOR reg_ax,imm \320\1\x35\31 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 reg_eax,imm \321\1\x35\41 386,SM
XOR rm8,imm \300\1\x80\206\21 8086,SM XOR rm8,imm \300\1\x80\206\21 8086,SM
XOR rm16,imm \320\300\1\x81\206\31 8086,SM XOR rm16,imm \320\300\134\1\x81\206\131 8086,SM,ND
XOR rm32,imm \321\300\1\x81\206\41 386,SM 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,imm8 \300\1\x80\206\21 8086,SM
XOR mem,imm16 \320\300\1\x81\206\31 8086,SM XOR mem,imm16 \320\300\134\1\x81\206\131 8086,SM,ND
XOR mem,imm32 \321\300\1\x81\206\41 386,SM 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,mem \320\301\1\x0F\330\x40\110 P6,SM
CMOVcc reg16,reg16 \320\301\1\x0F\330\x40\110 P6 CMOVcc reg16,reg16 \320\301\1\x0F\330\x40\110 P6
CMOVcc reg32,mem \321\301\1\x0F\330\x40\110 P6,SM 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 imm|near \322\1\x0F\330\x80\64 386
Jcc imm16|near \320\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 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|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 mem \300\1\x0F\330\x90\200 386,SB
SETcc reg8 \300\1\x0F\330\x90\200 386 SETcc reg8 \300\1\x0F\330\x90\200 386

View file

@ -63,6 +63,8 @@ struct itemplate {
#define IF_3DNOW 0x00008000UL /* it's a 3DNow! instruction */ #define IF_3DNOW 0x00008000UL /* it's a 3DNow! instruction */
#define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */ #define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */
#define IF_PMASK 0xFF000000UL /* the mask for processor types */ #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_PFMASK 0xF001FF00UL /* the mask for disassembly "prefer" */
#define IF_8086 0x00000000UL /* 8086 instruction */ #define IF_8086 0x00000000UL /* 8086 instruction */
#define IF_186 0x01000000UL /* 186+ instruction */ #define IF_186 0x01000000UL /* 186+ instruction */

235
labels.c
View file

@ -18,15 +18,15 @@
*/ */
#define islocal(l) ((l)[0] == '.' && (l)[1] != '.') #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 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 END_BLOCK -2
#define BOGUS_VALUE -4 #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 */ /* values for label.defn.is_global */
#define DEFINED_BIT 1 #define DEFINED_BIT 1
@ -39,24 +39,26 @@
#define GLOBAL_PLACEHOLDER (GLOBAL_BIT) #define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
#define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT) #define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
union label { /* actual label structures */ union label { /* actual label structures */
struct { struct {
long segment, offset; long segment, offset;
char *label, *special; char *label, *special;
int is_global, is_norm; int is_global, is_norm;
} defn; } defn;
struct { struct {
long movingon, dummy; long movingon, dummy;
union label *next; union label *next;
} admin; } admin;
}; };
struct permts { /* permanent text storage */ struct permts { /* permanent text storage */
struct permts *next; /* for the linked list */ struct permts *next; /* for the linked list */
int size, usage; /* size and used space in ... */ int size, usage; /* size and used space in ... */
char data[PERMTS_SIZE]; /* ... the data block itself */ 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 *ltab[LABEL_HASHES];/* using a hash table */
static union label *lfree[LABEL_HASHES];/* pointer into the above */ static union label *lfree[LABEL_HASHES];/* pointer into the above */
static struct permts *perm_head; /* start of perm. text storage */ 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; union label *lptr;
if (islocal(label)) if (islocal(label))
prev = prevlabel; prev = prevlabel;
else else
prev = ""; prev = "";
prevlen = strlen(prev); prevlen = strlen(prev);
p = prev; p = prev;
while (*p) hash += *p++; while (*p) hash += *p++;
@ -93,34 +95,34 @@ static union label *find_label (char *label, int create)
hash %= LABEL_HASHES; hash %= LABEL_HASHES;
lptr = ltab[hash]; lptr = ltab[hash];
while (lptr->admin.movingon != END_LIST) { while (lptr->admin.movingon != END_LIST) {
if (lptr->admin.movingon == END_BLOCK) { if (lptr->admin.movingon == END_BLOCK) {
lptr = lptr->admin.next; lptr = lptr->admin.next;
if (!lptr) if (!lptr)
break; break;
} }
if (!strncmp(lptr->defn.label, prev, prevlen) && if (!strncmp(lptr->defn.label, prev, prevlen) &&
!strcmp(lptr->defn.label+prevlen, label)) !strcmp(lptr->defn.label+prevlen, label))
return lptr; return lptr;
lptr++; lptr++;
} }
if (create) { if (create) {
if (lfree[hash]->admin.movingon == END_BLOCK) { if (lfree[hash]->admin.movingon == END_BLOCK) {
/* /*
* must allocate a new block * must allocate a new block
*/ */
lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE); lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
lfree[hash] = lfree[hash]->admin.next; lfree[hash] = lfree[hash]->admin.next;
init_block(lfree[hash]); init_block(lfree[hash]);
} }
lfree[hash]->admin.movingon = BOGUS_VALUE; lfree[hash]->admin.movingon = BOGUS_VALUE;
lfree[hash]->defn.label = perm_copy (prev, label); lfree[hash]->defn.label = perm_copy (prev, label);
lfree[hash]->defn.special = NULL; lfree[hash]->defn.special = NULL;
lfree[hash]->defn.is_global = NOT_DEFINED_YET; lfree[hash]->defn.is_global = NOT_DEFINED_YET;
return lfree[hash]++; return lfree[hash]++;
} }
else else
return NULL; return NULL;
} }
int lookup_label (char *label, long *segment, long *offset) 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; union label *lptr;
if (!initialised) if (!initialised)
return 0; return 0;
lptr = find_label (label, 0); lptr = find_label (label, 0);
if (lptr && (lptr->defn.is_global & DEFINED_BIT)) { if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
*segment = lptr->defn.segment; *segment = lptr->defn.segment;
*offset = lptr->defn.offset; *offset = lptr->defn.offset;
return 1; return 1;
} }
else else
return 0; return 0;
} }
int is_extern (char *label) int is_extern (char *label)
@ -145,17 +147,17 @@ int is_extern (char *label)
union label *lptr; union label *lptr;
if (!initialised) if (!initialised)
return 0; return 0;
lptr = find_label (label, 0); lptr = find_label (label, 0);
if (lptr && (lptr->defn.is_global & EXTERN_BIT)) if (lptr && (lptr->defn.is_global & EXTERN_BIT))
return 1; return 1;
else else
return 0; return 0;
} }
void redefine_label (char *label, long segment, long offset, char *special, 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; 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) 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) special; /* Don't warn that this parameter is unused */
(void) is_norm; /* 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) isextrn; /* Don't warn that this parameter is unused */
(void) ofmt; /* Don't warn that this parameter is unused */ (void) ofmt; /* Don't warn that this parameter is unused */
#ifdef DEBUG #ifdef DEBUG
#if DEBUG<3
if (!strncmp(label, "debugdump", 9)) if (!strncmp(label, "debugdump", 9))
fprintf(stderr, "debug: redefine_label (%s, %ld, %08lx, %s, %d, %d)\n", #endif
label, segment, offset, special, is_norm, isextrn); error(ERR_DEBUG, "redefine_label (%s, %ld, %08lx, %s, %d, %d)",
label, segment, offset, special, is_norm, isextrn);
#endif #endif
lptr = find_label (label, 1);
if (!lptr)
error (ERR_PANIC, "can't find label `%s' on pass two", label);
if (!islocal(label)) { if (!islocal(label)) {
lptr = find_label (label, 1); if (*label != '.' && lptr->defn.is_norm)
if (!lptr) prevlabel = lptr->defn.label;
error (ERR_PANIC, "can't find label `%s' on pass two", 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, 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; union label *lptr;
#ifdef DEBUG #ifdef DEBUG
#if DEBUG<3
if (!strncmp(label, "debugdump", 9)) if (!strncmp(label, "debugdump", 9))
fprintf(stderr, "debug: define_label (%s, %ld, %08lx, %s, %d, %d)\n", #endif
label, segment, offset, special, is_norm, isextrn); error(ERR_DEBUG, "define_label (%s, %ld, %08lx, %s, %d, %d)",
label, segment, offset, special, is_norm, isextrn);
#endif #endif
lptr = find_label (label, 1); lptr = find_label (label, 1);
if (lptr->defn.is_global & DEFINED_BIT) { if (lptr->defn.is_global & DEFINED_BIT) {
error(ERR_NONFATAL, "symbol `%s' redefined", label); error(ERR_NONFATAL, "symbol `%s' redefined", label);
return; return;
} }
lptr->defn.is_global |= DEFINED_BIT; lptr->defn.is_global |= DEFINED_BIT;
if (isextrn) 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 */ 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) else if (label[0] == '.' && label[1] != '.' && !*prevlabel)
error(ERR_NONFATAL, "attempt to define a local label before any" error(ERR_NONFATAL, "attempt to define a local label before any"
" non-local labels"); " non-local labels");
lptr->defn.segment = segment; lptr->defn.segment = segment;
lptr->defn.offset = offset; 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 ) { if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) {
ofmt->symdef (lptr->defn.label, segment, offset, ofmt->symdef (lptr->defn.label, segment, offset,
!!(lptr->defn.is_global & GLOBAL_BIT), !!(lptr->defn.is_global & GLOBAL_BIT),
special ? special : lptr->defn.special); special ? special : lptr->defn.special);
ofmt->current_dfmt->debug_deflabel (label, segment, offset, ofmt->current_dfmt->debug_deflabel (label, segment, offset,
!!(lptr->defn.is_global & GLOBAL_BIT), !!(lptr->defn.is_global & GLOBAL_BIT),
special ? special : lptr->defn.special); special ? special : lptr->defn.special);
} }
} }
void define_common (char *label, long segment, long size, char *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; union label *lptr;
lptr = find_label (label, 1); lptr = find_label (label, 1);
if (lptr->defn.is_global & DEFINED_BIT) { if (lptr->defn.is_global & DEFINED_BIT) {
error(ERR_NONFATAL, "symbol `%s' redefined", label); error(ERR_NONFATAL, "symbol `%s' redefined", label);
return; return;
} }
lptr->defn.is_global |= DEFINED_BIT; lptr->defn.is_global |= DEFINED_BIT;
if (label[0] != '.') /* not local, but not special either */ if (label[0] != '.') /* not local, but not special either */
prevlabel = lptr->defn.label; prevlabel = lptr->defn.label;
else else
error(ERR_NONFATAL, "attempt to define a local label as a " error(ERR_NONFATAL, "attempt to define a local label as a "
"common variable"); "common variable");
lptr->defn.segment = segment; lptr->defn.segment = segment;
lptr->defn.offset = 0; lptr->defn.offset = 0;
ofmt->symdef (lptr->defn.label, segment, size, 2, 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, 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) 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; union label *lptr;
if (islocal(label)) { if (islocal(label)) {
error(ERR_NONFATAL, "attempt to declare local symbol `%s' as" error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
" global", label); " global", label);
return; return;
} }
lptr = find_label (label, 1); lptr = find_label (label, 1);
switch (lptr->defn.is_global & TYPE_MASK) { switch (lptr->defn.is_global & TYPE_MASK) {
case NOT_DEFINED_YET: case NOT_DEFINED_YET:
lptr->defn.is_global = GLOBAL_PLACEHOLDER; lptr->defn.is_global = GLOBAL_PLACEHOLDER;
lptr->defn.special = special ? perm_copy(special, "") : NULL; lptr->defn.special = special ? perm_copy(special, "") : NULL;
break; break;
case GLOBAL_PLACEHOLDER: /* already done: silently ignore */ case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
case GLOBAL_SYMBOL: case GLOBAL_SYMBOL:
break; break;
case LOCAL_SYMBOL: case LOCAL_SYMBOL:
if (!lptr->defn.is_global & EXTERN_BIT) if (!lptr->defn.is_global & EXTERN_BIT)
error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must" error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
" appear before symbol definition", label); " appear before symbol definition", label);
break; break;
} }
} }
@ -283,18 +292,18 @@ int init_labels (void)
int i; int i;
for (i=0; i<LABEL_HASHES; i++) { for (i=0; i<LABEL_HASHES; i++) {
ltab[i] = (union label *) nasm_malloc (LBLK_SIZE); ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
if (!ltab[i]) if (!ltab[i])
return -1; /* can't initialise, panic */ return -1; /* can't initialise, panic */
init_block (ltab[i]); init_block (ltab[i]);
lfree[i] = ltab[i]; lfree[i] = ltab[i];
} }
perm_head = perm_head =
perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts)); perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
if (!perm_head) if (!perm_head)
return -1; return -1;
perm_head->next = NULL; perm_head->next = NULL;
perm_head->size = PERMTS_SIZE; perm_head->size = PERMTS_SIZE;
@ -314,22 +323,22 @@ void cleanup_labels (void)
initialised = FALSE; initialised = FALSE;
for (i=0; i<LABEL_HASHES; i++) { 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) {
while (lptr->admin.movingon != END_BLOCK) lptr++; while (lptr->admin.movingon != END_BLOCK) lptr++;
lptr = lptr->admin.next; lptr = lptr->admin.next;
nasm_free (lhold); nasm_free (lhold);
lhold = lptr; lhold = lptr;
} }
} }
while (perm_head) { while (perm_head) {
perm_tail = perm_head; perm_tail = perm_head;
perm_head = perm_head->next; perm_head = perm_head->next;
nasm_free (perm_tail); nasm_free (perm_tail);
} }
} }
@ -338,7 +347,7 @@ static void init_block (union label *blk)
int j; int j;
for (j=0; j<LABEL_BLOCK-1; 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.movingon = END_BLOCK;
blk[LABEL_BLOCK-1].admin.next = NULL; 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; int len = strlen(string1)+strlen(string2)+1;
if (perm_tail->size - perm_tail->usage < len) { if (perm_tail->size - perm_tail->usage < len) {
perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts)); perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
perm_tail = perm_tail->next; perm_tail = perm_tail->next;
perm_tail->next = NULL; perm_tail->next = NULL;
perm_tail->size = PERMTS_SIZE; perm_tail->size = PERMTS_SIZE;
perm_tail->usage = 0; perm_tail->usage = 0;
} }
p = q = perm_tail->data + perm_tail->usage; p = q = perm_tail->data + perm_tail->usage;
while ( (*q = *string1++) ) q++; while ( (*q = *string1++) ) q++;

View file

@ -57,6 +57,12 @@ static char *stdmac[] = {
"%imacro bits 1+.nolist", "%imacro bits 1+.nolist",
"[bits %1]", "[bits %1]",
"%endmacro", "%endmacro",
"%imacro use16 0.nolist",
"[bits 16]",
"%endmacro",
"%imacro use32 0.nolist",
"[bits 32]",
"%endmacro",
"%imacro global 1-*.nolist", "%imacro global 1-*.nolist",
"%rep %0", "%rep %0",
"[global %1]", "[global %1]",
@ -69,5 +75,8 @@ static char *stdmac[] = {
"%rotate 1", "%rotate 1",
"%endrep", "%endrep",
"%endmacro", "%endmacro",
"%imacro cpu 1+.nolist",
"[cpu %1]",
"%endmacro",
NULL NULL
}; };

View file

@ -2,7 +2,7 @@
MAJORVER=`grep NASM_MAJOR_VER nasm.h | head -1 | cut -f3 -d' '` MAJORVER=`grep NASM_MAJOR_VER nasm.h | head -1 | cut -f3 -d' '`
MINORVER=`grep NASM_MINOR_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}" DOSVERSION="${MAJORVER}${MINORVER}"
NASM_TAR_GZ=dist/nasm-${VERSION}.tar.gz NASM_TAR_GZ=dist/nasm-${VERSION}.tar.gz
NASM_ZIP=dist/nasm${DOSVERSION}s.zip 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 if [ -f dist/nasm.tar.gz ]; then rm dist/nasm.tar.gz; fi
mkdir nasm-${VERSION} mkdir nasm-${VERSION}
(cd nasm-${VERSION}; ln -s ../* .; (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 GNUmakefile > tar-exclude
find nasm-${VERSION}/ -follow -name RCS >> tar-exclude find nasm-${VERSION}/ -follow -name RCS >> tar-exclude
find nasm-${VERSION}/ -follow -name '*.exe' >> tar-exclude find nasm-${VERSION}/ -follow -name '*.exe' >> tar-exclude

1104
nasm.c

File diff suppressed because it is too large Load diff

39
nasm.h
View file

@ -13,7 +13,7 @@
#define NASM_MAJOR_VER 0 #define NASM_MAJOR_VER 0
#define NASM_MINOR_VER 98 #define NASM_MINOR_VER 98
#define NASM_VER "0.98" #define NASM_VER "0.98.03"
#ifndef NULL #ifndef NULL
#define NULL 0 #define NULL 0
@ -64,26 +64,28 @@ typedef void (*efunc) (int severity, char *fmt, ...);
* argument to an efunc. * argument to an efunc.
*/ */
#define ERR_WARNING 0 /* warn only: no further action */ #define ERR_DEBUG 0x00000008 /* put out debugging message */
#define ERR_NONFATAL 1 /* terminate assembly after phase */ #define ERR_WARNING 0x00000000 /* warn only: no further action */
#define ERR_FATAL 2 /* instantly fatal: exit with error */ #define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */
#define ERR_PANIC 3 /* internal error: panic instantly #define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */
#define ERR_PANIC 0x00000003 /* internal error: panic instantly
* and dump core for reference */ * and dump core for reference */
#define ERR_MASK 0x0F /* mask off the above codes */ #define ERR_MASK 0x0000000F /* mask off the above codes */
#define ERR_NOFILE 0x10 /* don't give source file name/line */ #define ERR_NOFILE 0x00000010 /* don't give source file name/line */
#define ERR_USAGE 0x20 /* print a usage message */ #define ERR_USAGE 0x00000020 /* print a usage message */
#define ERR_PASS1 0x80 /* only print this error on pass one */ #define ERR_PASS1 0x00000040 /* only print this error on pass one */
/* /*
* These codes define specific types of suppressible warning. * These codes define specific types of suppressible warning.
*/ */
#define ERR_WARN_MNP 0x0100 /* macro-num-parameters warning */ #define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */
#define ERR_WARN_OL 0x0200 /* orphan label (no colon, and #define ERR_WARN_MSR 0x00000200 /* macro self-reference */
#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and
* alone on line) */ * alone on line) */
#define ERR_WARN_NOV 0x0300 /* numeric overflow */ #define ERR_WARN_NOV 0x00000400 /* numeric overflow */
#define ERR_WARN_MASK 0xFF00 /* the mask for this feature */ #define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */
#define ERR_WARN_SHR 8 /* how far to shift right */ #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 * defined before use", whereas if `critical' is 2, the error will
* be "symbol undefined". * be "symbol undefined".
* *
* If `critical' has bit 4 set (in addition to its main value: 0x11 * If `critical' has bit 8 set (in addition to its main value: 0x101
* and 0x12 correspond to 1 and 2) then an extended expression * and 0x102 correspond to 1 and 2) then an extended expression
* syntax is recognised, in which relational operators such as =, < * syntax is recognised, in which relational operators such as =, <
* and >= are accepted, as well as low-precedence logical operators * and >= are accepted, as well as low-precedence logical operators
* &&, ^^ and ||. * &&, ^^ and ||.
@ -259,6 +261,7 @@ struct eval_hints {
* If `hints' is non-NULL, it gets filled in with some hints as to * If `hints' is non-NULL, it gets filled in with some hints as to
* the base register in complex effective addresses. * the base register in complex effective addresses.
*/ */
#define CRITICAL 0x100
typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv,
int *fwref, int critical, efunc error, int *fwref, int critical, efunc error,
struct eval_hints *hints); struct eval_hints *hints);
@ -411,7 +414,9 @@ enum {
/* special type of immediate operand */ /* special type of immediate operand */
#define ONENESS 0x00800000L /* so UNITY == IMMEDIATE | ONENESS */ #define ONENESS 0x00800000L /* so UNITY == IMMEDIATE | ONENESS */
#define UNITY 0x00802000L /* for shift/rotate instructions */ #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 * Next, the codes returned from the parser, for registers and
* instructions. * instructions.

View file

@ -125,29 +125,33 @@ char *nasm_strndup (char *s, size_t len)
return p; return p;
} }
#if !defined(stricmp) && !defined(strcasecmp)
int nasm_stricmp (const char *s1, const char *s2) int nasm_stricmp (const char *s1, const char *s2)
{ {
while (*s1 && toupper(*s1) == toupper(*s2)) while (*s1 && tolower(*s1) == tolower(*s2))
s1++, s2++; s1++, s2++;
if (!*s1 && !*s2) if (!*s1 && !*s2)
return 0; return 0;
else if (toupper(*s1) < toupper(*s2)) else if (tolower(*s1) < tolower(*s2))
return -1; return -1;
else else
return 1; return 1;
} }
#endif
#if !defined(strnicmp) && !defined(strncasecmp)
int nasm_strnicmp (const char *s1, const char *s2, int n) 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--; s1++, s2++, n--;
if ((!*s1 && !*s2) || n==0) if ((!*s1 && !*s2) || n==0)
return 0; return 0;
else if (toupper(*s1) < toupper(*s2)) else if (tolower(*s1) < tolower(*s2))
return -1; return -1;
else else
return 1; return 1;
} }
#endif
#define lib_isnumchar(c) ( isalnum(c) || (c) == '$') #define lib_isnumchar(c) ( isalnum(c) || (c) == '$')
#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') #define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0')

View file

@ -51,8 +51,25 @@ char *nasm_strndup_log (char *, int, char *, size_t);
* ANSI doesn't guarantee the presence of `stricmp' or * ANSI doesn't guarantee the presence of `stricmp' or
* `strcasecmp'. * `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 *); 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); int nasm_strnicmp (const char *, const char *, int);
#endif
/* /*
* Convert a string into a number, using NASM number rules. Sets * Convert a string into a number, using NASM number rules. Sets

View file

@ -76,7 +76,7 @@
* next operation. * 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 OBJ_PARMS 3 /* maximum .parm used by any .ori routine */
#define FIX_08_LOW 0x8000 /* location type for various fixup subrecords */ #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 */ LEDATA = 0xA0, /* logical enumerated data */
FIXUPP = 0x9C, /* fixups (relocations) */ FIXUPP = 0x9C, /* fixups (relocations) */
FIXU32 = 0x9D, /* 32-bit fixups (relocations) */
MODEND = 0x8A /* module end */ MODEND = 0x8A /* module end */
}; };
@ -139,8 +140,6 @@ static void ori_ledata(ObjRecord *orp);
static void ori_pubdef(ObjRecord *orp); static void ori_pubdef(ObjRecord *orp);
static void ori_null(ObjRecord *orp); static void ori_null(ObjRecord *orp);
static ObjRecord *obj_commit(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 */ 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"); " 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, static void obj_out (long segto, void *data, unsigned long type,
long segment, long wrt) long segment, long wrt)
{ {
@ -1049,7 +1052,7 @@ static void obj_out (long segto, void *data, unsigned long type,
if (segment != NO_SEG) if (segment != NO_SEG)
obj_write_fixup (orp, rsize, obj_write_fixup (orp, rsize,
(realtype == OUT_ADDRESS ? 0x4000 : 0), (realtype == OUT_ADDRESS ? 0x4000 : 0),
segment, wrt); segment, wrt, seg);
seg->currentpos += size; seg->currentpos += size;
} else if (realtype == OUT_RESERVE) { } else if (realtype == OUT_RESERVE) {
if (orp->committed) 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, 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 locat, method;
int base; int base;
@ -1080,6 +1083,11 @@ static void obj_write_fixup (ObjRecord *orp, int bytes,
if (forp == NULL) { if (forp == NULL) {
orp->child = forp = obj_new(); orp->child = forp = obj_new();
forp->up = &(orp->child); 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; forp->type = FIXUPP;
} }

View file

@ -647,8 +647,13 @@ insn *parse_line (int pass, char *buffer, insn *result,
result->oprs[operand].offset = reloc_value(value); result->oprs[operand].offset = reloc_value(value);
result->oprs[operand].segment = reloc_seg(value); result->oprs[operand].segment = reloc_seg(value);
result->oprs[operand].wrt = reloc_wrt(value); result->oprs[operand].wrt = reloc_wrt(value);
if (is_simple(value) && reloc_value(value)==1) if (is_simple(value)) {
result->oprs[operand].type |= UNITY; 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 */ else /* it's a register */
{ {

509
preproc.c
View file

@ -34,6 +34,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
@ -100,6 +101,7 @@ struct MMacro {
Token *iline; /* invocation line */ Token *iline; /* invocation line */
int nparam, rotate, *paramlen; int nparam, rotate, *paramlen;
unsigned long unique; unsigned long unique;
int lineno; /* Current line number on expansion */
}; };
/* /*
@ -267,8 +269,9 @@ static char *directives[] = {
"%endrep", "%error", "%exitrep", "%iassign", "%idefine", "%if", "%endrep", "%error", "%exitrep", "%iassign", "%idefine", "%if",
"%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifnctx", "%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifnctx",
"%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnnum", "%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnnum",
"%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", "%line", "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", "%ixdefine",
"%macro", "%pop", "%push", "%rep", "%repl", "%rotate", "%undef" "%line", "%macro", "%pop", "%push", "%rep", "%repl", "%rotate",
"%undef", "%xdefine"
}; };
enum { enum {
PP_ASSIGN, PP_CLEAR, PP_DEFINE, PP_ELIF, PP_ELIFCTX, PP_ELIFDEF, 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_ENDREP, PP_ERROR, PP_EXITREP, PP_IASSIGN, PP_IDEFINE, PP_IF,
PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFNCTX, PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFNCTX,
PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNNUM, PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNNUM,
PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, PP_LINE, PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, PP_IXDEFINE,
PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, PP_UNDEF 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 Include *istk;
static IncPath *ipath = NULL; static IncPath *ipath = NULL;
static efunc error; static efunc __error; /* Pointer to client-provided error reporting function */
static evalfunc evaluate; static evalfunc evaluate;
static int pass; /* HACK: pass 0 = generate dependencies only */ 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_mmac_params (Token *tline);
static Token *expand_smacro (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 make_tok_num(Token *tok, long val);
static void error (int severity, char *fmt, ...);
/* /*
* Macros for safe checking of token pointers, avoid *(NULL) * Macros for safe checking of token pointers, avoid *(NULL)
@ -586,8 +593,10 @@ static Token *tokenise (char *line)
while (*line) { while (*line) {
p = line; p = line;
if (*p == '%' && ( isdigit(p[1]) || if (*p == '%' &&
((p[1] == '-' || p[1] == '+') && isdigit(p[2])))) (isdigit(p[1]) ||
((p[1] == '-' || p[1] == '+') && isdigit(p[2])) ||
((p[1] == '+') && (isspace (p[2]) || !p[2]))))
{ {
p++; p++;
do { do {
@ -702,8 +711,10 @@ static Token *tokenise (char *line)
/* /*
* Convert a line of tokens back into text. * 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; Token *t;
int len; int len;
@ -719,6 +730,24 @@ char *detoken (Token *tlist)
else else
t->text = NULL; 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) if (t->text)
len += strlen(t->text); len += strlen(t->text);
} }
@ -826,44 +855,63 @@ static int ppscan(void *private_data, struct tokenval *tokval)
return tokval->t_type = tline->text[0]; return tokval->t_type = tline->text[0];
} }
/*
* 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 * Return the Context structure associated with a %$ token. Return
* NULL, having _already_ reported an error condition, if the * NULL, having _already_ reported an error condition, if the
* context stack isn't deep enough for the supplied number of $ * context stack isn't deep enough for the supplied number of $
* signs. * 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; Context *ctx;
SMacro *m;
int i; int i;
if (!name || name[0] != '%' || name[1] != '$')
return NULL;
if (!cstk) { if (!cstk) {
error (ERR_NONFATAL, "`%s': context stack is empty", name); error (ERR_NONFATAL, "`%s': context stack is empty", name);
return NULL; return NULL;
} }
i = 1; for (i = strspn (name+2, "$"), ctx = cstk; (i > 0) && ctx; i--) {
ctx = cstk;
while (name[i+1] == '$') {
i++;
ctx = ctx->next; ctx = ctx->next;
i--;
}
if (!ctx) { if (!ctx) {
error (ERR_NONFATAL, "`%s': context stack is only" error (ERR_NONFATAL, "`%s': context stack is only"
" %d level%s deep", name, i-1, (i==2 ? "" : "s")); " %d level%s deep", name, i-1, (i==2 ? "" : "s"));
return NULL; return NULL;
} }
} if (!all_contexts)
return ctx; return ctx;
}
/* do {
* Compare a string to the name of an existing macro; this is a /* Search for this smacro in found context */
* simple wrapper which calls either strcmp or nasm_stricmp m = ctx->localmac;
* depending on the value of the `casesense' parameter. while (m) {
*/ if (!mstrcmp(m->name, name, m->casesense))
static int mstrcmp(char *p, char *q, int casesense) return ctx;
{ m = m->next;
return casesense ? strcmp(p,q) : nasm_stricmp(p,q); }
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 * Note that this is also called with nparam zero to resolve
* `ifdef'. * `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; SMacro *m;
Context *ctx;
char *p;
if (name[0] == '%' && name[1] == '$') { if (ctx)
ctx = get_ctx (name); m = ctx->localmac;
else if (name[0] == '%' && name[1] == '$') {
if (cstk)
ctx = get_ctx (name, FALSE);
if (!ctx) if (!ctx)
return FALSE; /* got to return _something_ */ return FALSE; /* got to return _something_ */
m = ctx->localmac; m = ctx->localmac;
p = name+1; } else
p += strspn(p, "$");
} else {
m = smacros[hash(name)]; m = smacros[hash(name)];
p = name;
}
while (m) { 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)) { (nparam <= 0 || m->nparam == 0 || nparam == m->nparam)) {
if (defn) { if (defn) {
if (nparam == m->nparam || nparam == -1) 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; m = m->next;
} }
return FALSE; return FALSE;
} }
@ -1021,10 +1073,7 @@ static int if_condition (Token *tline, int i)
case PP_IFCTX: case PP_ELIFCTX: case PP_IFCTX: case PP_ELIFCTX:
case PP_IFNCTX: case PP_ELIFNCTX: case PP_IFNCTX: case PP_ELIFNCTX:
j = FALSE; /* have we matched yet? */ j = FALSE; /* have we matched yet? */
if (!cstk) while (cstk && tline) {
error(ERR_FATAL,
"`%s': context stack is empty", directives[i]);
else while (tline) {
skip_white_(tline); skip_white_(tline);
if (!tline || tline->type != TOK_ID) { if (!tline || tline->type != TOK_ID) {
error(ERR_NONFATAL, error(ERR_NONFATAL,
@ -1055,7 +1104,7 @@ static int if_condition (Token *tline, int i)
free_tlist (origline); free_tlist (origline);
return -1; return -1;
} }
if (smacro_defined(tline->text, 0, NULL, 1)) if (smacro_defined (NULL, tline->text, 0, NULL, 1))
j = TRUE; j = TRUE;
tline = tline->next; tline = tline->next;
} }
@ -1143,7 +1192,7 @@ static int if_condition (Token *tline, int i)
tptr = &t; tptr = &t;
tokval.t_type = TOKEN_INVALID; tokval.t_type = TOKEN_INVALID;
evalresult = evaluate (ppscan, tptr, &tokval, evalresult = evaluate (ppscan, tptr, &tokval,
NULL, pass | 0x10, error, NULL); NULL, pass | CRITICAL, error, NULL);
free_tlist (tline); free_tlist (tline);
if (!evalresult) if (!evalresult)
return -1; return -1;
@ -1166,6 +1215,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 * Find out if a line contains a preprocessor directive, and deal
* with it if so. * with it if so.
@ -1303,11 +1364,12 @@ static int do_directive (Token *tline)
p[strlen(p)-1] = '\0'; /* remove the trailing quote */ p[strlen(p)-1] = '\0'; /* remove the trailing quote */
} else } else
p = tline->text; /* internal_string is easier */ p = tline->text; /* internal_string is easier */
expand_macros_in_string (&p);
inc = nasm_malloc(sizeof(Include)); inc = nasm_malloc(sizeof(Include));
inc->next = istk; inc->next = istk;
inc->conds = NULL; inc->conds = NULL;
inc->fp = inc_fopen(p); 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->lineno = src_set_linnum(0);
inc->lineinc = 1; inc->lineinc = 1;
inc->expansion = NULL; inc->expansion = NULL;
@ -1320,6 +1382,7 @@ static int do_directive (Token *tline)
case PP_PUSH: case PP_PUSH:
tline = tline->next; tline = tline->next;
skip_white_(tline); skip_white_(tline);
tline = expand_id (tline);
if (!tok_type_(tline, TOK_ID)) { if (!tok_type_(tline, TOK_ID)) {
error(ERR_NONFATAL, error(ERR_NONFATAL,
"`%%push' expects a context identifier"); "`%%push' expects a context identifier");
@ -1341,6 +1404,7 @@ static int do_directive (Token *tline)
case PP_REPL: case PP_REPL:
tline = tline->next; tline = tline->next;
skip_white_(tline); skip_white_(tline);
tline = expand_id (tline);
if (!tok_type_(tline, TOK_ID)) { if (!tok_type_(tline, TOK_ID)) {
error(ERR_NONFATAL, error(ERR_NONFATAL,
"`%%repl' expects a context identifier"); "`%%repl' expects a context identifier");
@ -1379,10 +1443,12 @@ static int do_directive (Token *tline)
if (tok_type_(tline, TOK_STRING)) { if (tok_type_(tline, TOK_STRING)) {
p = tline->text+1; /* point past the quote to the name */ p = tline->text+1; /* point past the quote to the name */
p[strlen(p)-1] = '\0'; /* remove the trailing quote */ 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 { } else {
p = detoken(tline); p = detoken(tline, FALSE);
error(ERR_WARNING, "user error: %s", p); error (ERR_WARNING, "%s", p);
nasm_free(p); nasm_free(p);
} }
free_tlist (origline); free_tlist (origline);
@ -1409,15 +1475,7 @@ static int do_directive (Token *tline)
j = if_condition(tline->next, i); j = if_condition(tline->next, i);
tline->next = NULL; /* it got freed */ tline->next = NULL; /* it got freed */
free_tlist (origline); free_tlist (origline);
if (j < 0) j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
/*
* 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;
} }
cond = nasm_malloc(sizeof(Cond)); cond = nasm_malloc(sizeof(Cond));
cond->next = istk->conds; cond->next = istk->conds;
@ -1449,14 +1507,7 @@ static int do_directive (Token *tline)
j = if_condition(expand_mmac_params(tline->next), i); j = if_condition(expand_mmac_params(tline->next), i);
tline->next = NULL; /* it got freed */ tline->next = NULL; /* it got freed */
free_tlist (origline); free_tlist (origline);
if (j < 0) istk->conds->state = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
/*
* 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;
} }
return (istk->conds->state == COND_IF_TRUE ? 5 : 1); return (istk->conds->state == COND_IF_TRUE ? 5 : 1);
@ -1495,6 +1546,7 @@ static int do_directive (Token *tline)
(i == PP_IMACRO ? "i" : "")); (i == PP_IMACRO ? "i" : ""));
tline = tline->next; tline = tline->next;
skip_white_(tline); skip_white_(tline);
tline = expand_id (tline);
if (!tok_type_(tline, TOK_ID)) { if (!tok_type_(tline, TOK_ID)) {
error (ERR_NONFATAL, error (ERR_NONFATAL,
"`%%%smacro' expects a macro name", "`%%%smacro' expects a macro name",
@ -1508,7 +1560,7 @@ static int do_directive (Token *tline)
defining->nolist = FALSE; defining->nolist = FALSE;
defining->in_progress = FALSE; defining->in_progress = FALSE;
defining->rep_nest = NULL; defining->rep_nest = NULL;
tline = tline->next; tline = expand_smacro (tline->next);
skip_white_(tline); skip_white_(tline);
if (!tok_type_(tline, TOK_NUMBER)) { if (!tok_type_(tline, TOK_NUMBER)) {
error (ERR_NONFATAL, error (ERR_NONFATAL,
@ -1717,36 +1769,38 @@ static int do_directive (Token *tline)
free_tlist (origline); free_tlist (origline);
return 1; return 1;
case PP_XDEFINE:
case PP_IXDEFINE:
case PP_DEFINE: case PP_DEFINE:
case PP_IDEFINE: case PP_IDEFINE:
tline = tline->next; tline = tline->next;
skip_white_(tline); skip_white_(tline);
tline = expand_id (tline);
if (!tline || (tline->type != TOK_ID && if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID || (tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) { tline->text[1] != '$'))) {
error (ERR_NONFATAL, error (ERR_NONFATAL,
"`%%%sdefine' expects a macro identifier", "`%%%s%sdefine' expects a macro identifier",
(i == PP_IDEFINE ? "i" : "")); ((i == PP_IDEFINE || i == PP_IXDEFINE) ? "i" : ""),
((i == PP_XDEFINE || i == PP_IXDEFINE) ? "x" : ""));
free_tlist (origline); free_tlist (origline);
return 3; return 3;
} }
mname = tline->text;
if (tline->type == TOK_ID) { ctx = get_ctx (tline->text, FALSE);
p = tline->text; if (!ctx)
smhead = &smacros[hash(mname)]; smhead = &smacros[hash(tline->text)];
} else { else
ctx = get_ctx (tline->text);
if (ctx == NULL)
return 3;
else {
p = tline->text+1;
p += strspn(p, "$");
smhead = &ctx->localmac; smhead = &ctx->localmac;
} mname = tline->text;
}
last = tline; last = tline;
param_start = tline = tline->next; param_start = tline = tline->next;
nparam = 0; 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, "(")) { if (tok_is_(tline, "(")) {
/* /*
* This macro has parameters. * This macro has parameters.
@ -1811,7 +1865,7 @@ static int do_directive (Token *tline)
* carefully re-terminated after chopping off the expansion * carefully re-terminated after chopping off the expansion
* from the end). * from the end).
*/ */
if (smacro_defined (mname, nparam, &smac, i==PP_DEFINE)) { if (smacro_defined (ctx, mname, nparam, &smac, i == PP_DEFINE)) {
if (!smac) { if (!smac) {
error (ERR_WARNING, error (ERR_WARNING,
"single-line macro `%s' defined both with and" "single-line macro `%s' defined both with and"
@ -1833,8 +1887,8 @@ static int do_directive (Token *tline)
smac->next = *smhead; smac->next = *smhead;
*smhead = smac; *smhead = smac;
} }
smac->name = nasm_strdup(p); smac->name = nasm_strdup(mname);
smac->casesense = (i == PP_DEFINE); smac->casesense = ((i == PP_DEFINE) || (i == PP_XDEFINE));
smac->nparam = nparam; smac->nparam = nparam;
smac->expansion = macro_start; smac->expansion = macro_start;
smac->in_progress = FALSE; smac->in_progress = FALSE;
@ -1844,6 +1898,7 @@ static int do_directive (Token *tline)
case PP_UNDEF: case PP_UNDEF:
tline = tline->next; tline = tline->next;
skip_white_(tline); skip_white_(tline);
tline = expand_id (tline);
if (!tline || (tline->type != TOK_ID && if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID || (tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) { tline->text[1] != '$'))) {
@ -1852,33 +1907,26 @@ static int do_directive (Token *tline)
free_tlist (origline); free_tlist (origline);
return 3; return 3;
} }
mname = tline->text; if (tline->next) {
if (tline->type == TOK_ID) { error (ERR_WARNING,
p = tline->text; "trailing garbage after macro name ignored");
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;
}
} }
last = tline;
tline = tline->next;
last->next = NULL;
if (tline) /* Find the context that symbol belongs to */
error(ERR_WARNING, ctx = get_ctx (tline->text, FALSE);
"trailing garbage after macro name ignored"); if (!ctx)
smhead = &smacros[hash(tline->text)];
else
smhead = &ctx->localmac;
mname = tline->text;
last = tline;
last->next = NULL;
/* /*
* We now have a macro name... go hunt for it. * 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 */ /* Defined, so we need to find its predecessor and nuke it */
SMacro **s; SMacro **s;
for ( s = smhead ; *s && *s != smac ; s = &(*s)->next ); for ( s = smhead ; *s && *s != smac ; s = &(*s)->next );
@ -1889,12 +1937,14 @@ static int do_directive (Token *tline)
nasm_free(smac); nasm_free(smac);
} }
} }
free_tlist (origline);
return 3; return 3;
case PP_ASSIGN: case PP_ASSIGN:
case PP_IASSIGN: case PP_IASSIGN:
tline = tline->next; tline = tline->next;
skip_white_(tline); skip_white_(tline);
tline = expand_id (tline);
if (!tline || (tline->type != TOK_ID && if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID || (tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) { tline->text[1] != '$'))) {
@ -1904,26 +1954,16 @@ static int do_directive (Token *tline)
free_tlist (origline); free_tlist (origline);
return 3; return 3;
} }
mname = tline->text; ctx = get_ctx (tline->text, FALSE);
if (tline->type == TOK_ID) { if (!ctx)
p = tline->text; smhead = &smacros[hash(tline->text)];
smhead = &smacros[hash(mname)]; else
} 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; smhead = &ctx->localmac;
} mname = tline->text;
}
last = tline; last = tline;
tline = tline->next; tline = expand_smacro (tline->next);
last->next = NULL; last->next = NULL;
tline = expand_smacro (tline);
t = tline; t = tline;
tptr = &t; tptr = &t;
tokval.t_type = TOKEN_INVALID; 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 * zero, and a numeric token to use as an expansion. Create
* and store an SMacro. * 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) if (!smac)
error (ERR_WARNING, error (ERR_WARNING,
"single-line macro `%s' defined both with and" "single-line macro `%s' defined both with and"
@ -1976,7 +2016,7 @@ static int do_directive (Token *tline)
smac->next = *smhead; smac->next = *smhead;
*smhead = smac; *smhead = smac;
} }
smac->name = nasm_strdup(p); smac->name = nasm_strdup(mname);
smac->casesense = (i == PP_ASSIGN); smac->casesense = (i == PP_ASSIGN);
smac->nparam = 0; smac->nparam = 0;
smac->expansion = macro_start; smac->expansion = macro_start;
@ -2013,7 +2053,7 @@ static int do_directive (Token *tline)
src_set_linnum(k); src_set_linnum(k);
istk->lineinc = m; istk->lineinc = m;
if (tline) { if (tline) {
nasm_free ( src_set_fname ( detoken(tline) ) ); nasm_free (src_set_fname (detoken (tline, FALSE)));
} }
free_tlist (origline); free_tlist (origline);
return 5; return 5;
@ -2077,7 +2117,7 @@ static Token *expand_mmac_params (Token *tline)
while (tline) { while (tline) {
if (tline->type == TOK_PREPROC_ID && 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] == '%' ||
(tline->text[1] >= '0' && tline->text[1] <= '9'))) { (tline->text[1] >= '0' && tline->text[1] <= '9'))) {
char *text = NULL; char *text = NULL;
@ -2244,26 +2284,38 @@ static Token *expand_smacro (Token *tline)
SMacro *head = NULL, *m; SMacro *head = NULL, *m;
Token **params; Token **params;
int *paramsize; int *paramsize;
int nparam, sparam, brackets; int nparam, sparam, brackets, rescan;
char *p; 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; tail = &thead;
thead = NULL; thead = NULL;
while (tline) { /* main token loop */ while (tline) { /* main token loop */
p = NULL; if ((mname = tline->text)) {
if (tline->type == TOK_ID) { /* if this token is a local macro, look in local context */
head = smacros[hash(tline->text)]; if (tline->type == TOK_ID || tline->type == TOK_PREPROC_ID)
p = tline->text; ctx = get_ctx (mname, TRUE);
} else if (tline->type == TOK_PREPROC_ID && tline->text[1] == '$') { else
Context *ctx = get_ctx (tline->text); ctx = NULL;
if (ctx) { if (!ctx)
head = smacros[hash(mname)];
else
head = ctx->localmac; head = ctx->localmac;
p = tline->text+2;
p += strspn(p, "$");
}
}
if (p) {
/* /*
* We've hit an identifier. As in is_mmacro below, we first * We've hit an identifier. As in is_mmacro below, we first
* check whether the identifier is a single-line macro at * check whether the identifier is a single-line macro at
@ -2271,7 +2323,7 @@ static Token *expand_smacro (Token *tline)
* necessary. * necessary.
*/ */
for (m = head; m; m = m->next) for (m = head; m; m = m->next)
if (!mstrcmp(m->name, p, m->casesense)) if (!mstrcmp(m->name, mname, m->casesense))
break; break;
if (m) { if (m) {
mstart = tline; mstart = tline;
@ -2303,8 +2355,7 @@ static Token *expand_smacro (Token *tline)
nasm_free (t); nasm_free (t);
continue; continue;
} }
} } else {
else {
/* /*
* Complicated case: at least one macro with this name * Complicated case: at least one macro with this name
* exists and takes parameters. We must find the * exists and takes parameters. We must find the
@ -2393,7 +2444,7 @@ static Token *expand_smacro (Token *tline)
} /* parameter loop */ } /* parameter loop */
nparam++; nparam++;
while (m && (m->nparam != nparam || while (m && (m->nparam != nparam ||
mstrcmp(m->name, p, m->casesense))) mstrcmp(m->name, mname, m->casesense)))
m = m->next; m = m->next;
if (!m) if (!m)
error (ERR_WARNING|ERR_WARN_MNP, error (ERR_WARNING|ERR_WARN_MNP,
@ -2415,8 +2466,7 @@ static Token *expand_smacro (Token *tline)
nasm_free (params); nasm_free (params);
nasm_free (paramsize); nasm_free (paramsize);
tline = mstart; tline = mstart;
} } else {
else {
/* /*
* Expand the macro: we are placed on the last token of the * Expand the macro: we are placed on the last token of the
* call, so that we can easily split the call from the * call, so that we can easily split the call from the
@ -2485,26 +2535,137 @@ static Token *expand_smacro (Token *tline)
t->mac = NULL; t->mac = NULL;
t->next = NULL; t->next = NULL;
tail = &t->next; 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);
nasm_free (t->text);
t->text = p;
}
}
} }
} }
/*
* 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; 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 * Determine whether the given line constitutes a multi-line macro
* call, and return the MMacro structure called if so. Doesn't have * call, and return the MMacro structure called if so. Doesn't have
@ -2709,6 +2870,7 @@ static int expand_mmacro (Token *tline)
m->rotate = 0; m->rotate = 0;
m->paramlen = paramlen; m->paramlen = paramlen;
m->unique = unique++; m->unique = unique++;
m->lineno = 0;
m->next_active = istk->mstk; m->next_active = istk->mstk;
istk->mstk = m; 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 * If we had a label, push it on as the first line of
* the macro expansion. * the macro expansion.
*/ */
if (label) if (label) {
if (dont_prepend<0) if (dont_prepend<0)
free_tlist(startline); free_tlist(startline);
else { else {
@ -2764,18 +2926,45 @@ static int expand_mmacro (Token *tline)
tt->text = nasm_strdup(":"); tt->text = nasm_strdup(":");
} }
} }
}
list->uplevel (m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); list->uplevel (m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
return 1; 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, static void pp_reset (char *file, int apass, efunc errfunc, evalfunc eval,
ListGen *listgen) ListGen *listgen)
{ {
int h; int h;
error = errfunc; __error = errfunc;
cstk = NULL; cstk = NULL;
istk = nasm_malloc(sizeof(Include)); istk = nasm_malloc(sizeof(Include));
istk->next = NULL; istk->next = NULL;
@ -2903,10 +3092,12 @@ static char *pp_getline (void)
if (istk->expansion) { /* from a macro expansion */ if (istk->expansion) { /* from a macro expansion */
char *p; char *p;
Line *l = istk->expansion; Line *l = istk->expansion;
if (istk->mstk)
istk->mstk->lineno++;
tline = l->first; tline = l->first;
istk->expansion = l->next; istk->expansion = l->next;
nasm_free (l); nasm_free (l);
p = detoken(tline); p = detoken (tline, FALSE);
list->line (LIST_MACRO, p); list->line (LIST_MACRO, p);
nasm_free(p); nasm_free(p);
break; break;
@ -2994,7 +3185,7 @@ static char *pp_getline (void)
/* /*
* De-tokenise the line again, and emit it. * De-tokenise the line again, and emit it.
*/ */
line = detoken(tline); line = detoken(tline, TRUE);
free_tlist (tline); free_tlist (tline);
break; break;
} else { } else {

View file

@ -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 RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o hash.o
.c.o: .c.o:
$(CC) -c $(CFLAGS) $< $(CC) -c $(CFLAGS) -o $@ $<
all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com

View file

@ -71,6 +71,13 @@ __SECT__
[bits %1] [bits %1]
%endmacro %endmacro
%imacro use16 0.nolist
[bits 16]
%endmacro
%imacro use32 0.nolist
[bits 32]
%endmacro
%imacro global 1-*.nolist %imacro global 1-*.nolist
%rep %0 %rep %0
[global %1] [global %1]
@ -84,3 +91,8 @@ __SECT__
%rotate 1 %rotate 1
%endrep %endrep
%endmacro %endmacro
%imacro cpu 1+.nolist
[cpu %1]
%endmacro

62
test/test1.asm Normal file
View file

@ -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

18
test/test2.asm Normal file
View file

@ -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

22
test/test2a.asm Normal file
View file

@ -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

45
test/test3.asm Normal file
View file

@ -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

16
test/test4.asm Normal file
View file

@ -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

16
test/test4a.asm Normal file
View file

@ -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

17
test/test4b.asm Normal file
View file

@ -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

17
test/test4c.asm Normal file
View file

@ -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

43
test/test5.asm Normal file
View file

@ -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

9
test/test6.asm Normal file
View file

@ -0,0 +1,9 @@
; test6.asm
; assemble with; nasm -O2 ...
;
%rep 20000
jmp forward
%endrep
forward: dd forward

View file

@ -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); ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset);
else else
ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset); ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset);
if (debuginfo) if (debuginfo) {
if (pub->type >= 0x100) if (pub->type >= 0x100)
ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100); ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100);
else else
ieee_putascii("ATI%X,%X.\r\n", i, pub->type); ieee_putascii("ATI%X,%X.\r\n", i, pub->type);
}
i++; 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); ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset);
else else
ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset); ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset);
if (debuginfo) if (debuginfo) {
if (pub->type >= 0x100) if (pub->type >= 0x100)
ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100); ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100);
else else
ieee_putascii("ATI%X,%X.\r\n", i, pub->type); ieee_putascii("ATI%X,%X.\r\n", i, pub->type);
}
i++; i++;
pub = pub->next; 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); ieee_putascii("ASN%X,R%X,%lX,+.\r\n", i, loc->index,loc->offset);
else else
ieee_putascii("ASN%X,%lX,%lX,+.\r\n", i, loc->segment*16,loc->offset); ieee_putascii("ASN%X,%lX,%lX,+.\r\n", i, loc->segment*16,loc->offset);
if (debuginfo) if (debuginfo) {
if (loc->type >= 0x100) if (loc->type >= 0x100)
ieee_putascii("ATN%X,T%X.\r\n", i, loc->type - 0x100); ieee_putascii("ATN%X,T%X.\r\n", i, loc->type - 0x100);
else else
ieee_putascii("ATN%X,%X.\r\n", i, loc->type); ieee_putascii("ATN%X,%X.\r\n", i, loc->type);
}
i++; i++;
} }
} }