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