mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-04-12 18:40:23 +08:00
NASM 0.98.03
This commit is contained in:
parent
41bf8002b2
commit
af535c16cf
@ -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,8 +1192,19 @@ static int matches (struct itemplate *itemp, insn *instruction)
|
||||
for (i=0; i<itemp->operands; i++)
|
||||
if (!(itemp->opd[i] & SIZE_MASK) &&
|
||||
(instruction->oprs[i].type & SIZE_MASK & ~size[i]))
|
||||
ret = 2;
|
||||
/* ret = 2; */
|
||||
return 2;
|
||||
|
||||
/*
|
||||
* Check template is okay at the set cpu level
|
||||
*/
|
||||
if ((itemp->flags & IF_PLEVEL) > cpu) return 3;
|
||||
|
||||
/*
|
||||
* Check if special handling needed for Jumps
|
||||
*/
|
||||
if ((unsigned char)(itemp->code[0]) >= 0370) return 99;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
235
labels.c
235
labels.c
@ -18,15 +18,15 @@
|
||||
*/
|
||||
#define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
|
||||
|
||||
#define LABEL_BLOCK 320 /* no. of labels/block */
|
||||
#define LABEL_BLOCK 32 /* no. of labels/block */
|
||||
#define LBLK_SIZE (LABEL_BLOCK*sizeof(union label))
|
||||
#define LABEL_HASHES 32 /* no. of hash table entries */
|
||||
#define LABEL_HASHES 37 /* no. of hash table entries */
|
||||
|
||||
#define END_LIST -3 /* don't clash with NO_SEG! */
|
||||
#define END_LIST -3 /* don't clash with NO_SEG! */
|
||||
#define END_BLOCK -2
|
||||
#define BOGUS_VALUE -4
|
||||
|
||||
#define PERMTS_SIZE 4096 /* size of text blocks */
|
||||
#define PERMTS_SIZE 4096 /* size of text blocks */
|
||||
|
||||
/* values for label.defn.is_global */
|
||||
#define DEFINED_BIT 1
|
||||
@ -39,24 +39,26 @@
|
||||
#define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
|
||||
#define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
|
||||
|
||||
union label { /* actual label structures */
|
||||
union label { /* actual label structures */
|
||||
struct {
|
||||
long segment, offset;
|
||||
long segment, offset;
|
||||
char *label, *special;
|
||||
int is_global, is_norm;
|
||||
int is_global, is_norm;
|
||||
} defn;
|
||||
struct {
|
||||
long movingon, dummy;
|
||||
union label *next;
|
||||
long movingon, dummy;
|
||||
union label *next;
|
||||
} admin;
|
||||
};
|
||||
|
||||
struct permts { /* permanent text storage */
|
||||
struct permts *next; /* for the linked list */
|
||||
int size, usage; /* size and used space in ... */
|
||||
char data[PERMTS_SIZE]; /* ... the data block itself */
|
||||
struct permts { /* permanent text storage */
|
||||
struct permts *next; /* for the linked list */
|
||||
int size, usage; /* size and used space in ... */
|
||||
char data[PERMTS_SIZE]; /* ... the data block itself */
|
||||
};
|
||||
|
||||
extern int global_offset_changed; /* defined in nasm.c */
|
||||
|
||||
static union label *ltab[LABEL_HASHES];/* using a hash table */
|
||||
static union label *lfree[LABEL_HASHES];/* pointer into the above */
|
||||
static struct permts *perm_head; /* start of perm. text storage */
|
||||
@ -82,9 +84,9 @@ static union label *find_label (char *label, int create)
|
||||
union label *lptr;
|
||||
|
||||
if (islocal(label))
|
||||
prev = prevlabel;
|
||||
prev = prevlabel;
|
||||
else
|
||||
prev = "";
|
||||
prev = "";
|
||||
prevlen = strlen(prev);
|
||||
p = prev;
|
||||
while (*p) hash += *p++;
|
||||
@ -93,34 +95,34 @@ static union label *find_label (char *label, int create)
|
||||
hash %= LABEL_HASHES;
|
||||
lptr = ltab[hash];
|
||||
while (lptr->admin.movingon != END_LIST) {
|
||||
if (lptr->admin.movingon == END_BLOCK) {
|
||||
lptr = lptr->admin.next;
|
||||
if (!lptr)
|
||||
break;
|
||||
}
|
||||
if (!strncmp(lptr->defn.label, prev, prevlen) &&
|
||||
!strcmp(lptr->defn.label+prevlen, label))
|
||||
return lptr;
|
||||
lptr++;
|
||||
if (lptr->admin.movingon == END_BLOCK) {
|
||||
lptr = lptr->admin.next;
|
||||
if (!lptr)
|
||||
break;
|
||||
}
|
||||
if (!strncmp(lptr->defn.label, prev, prevlen) &&
|
||||
!strcmp(lptr->defn.label+prevlen, label))
|
||||
return lptr;
|
||||
lptr++;
|
||||
}
|
||||
if (create) {
|
||||
if (lfree[hash]->admin.movingon == END_BLOCK) {
|
||||
/*
|
||||
* must allocate a new block
|
||||
*/
|
||||
lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
|
||||
lfree[hash] = lfree[hash]->admin.next;
|
||||
init_block(lfree[hash]);
|
||||
}
|
||||
if (lfree[hash]->admin.movingon == END_BLOCK) {
|
||||
/*
|
||||
* must allocate a new block
|
||||
*/
|
||||
lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
|
||||
lfree[hash] = lfree[hash]->admin.next;
|
||||
init_block(lfree[hash]);
|
||||
}
|
||||
|
||||
lfree[hash]->admin.movingon = BOGUS_VALUE;
|
||||
lfree[hash]->defn.label = perm_copy (prev, label);
|
||||
lfree[hash]->defn.special = NULL;
|
||||
lfree[hash]->defn.is_global = NOT_DEFINED_YET;
|
||||
return lfree[hash]++;
|
||||
lfree[hash]->admin.movingon = BOGUS_VALUE;
|
||||
lfree[hash]->defn.label = perm_copy (prev, label);
|
||||
lfree[hash]->defn.special = NULL;
|
||||
lfree[hash]->defn.is_global = NOT_DEFINED_YET;
|
||||
return lfree[hash]++;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int lookup_label (char *label, long *segment, long *offset)
|
||||
@ -128,16 +130,16 @@ int lookup_label (char *label, long *segment, long *offset)
|
||||
union label *lptr;
|
||||
|
||||
if (!initialised)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
lptr = find_label (label, 0);
|
||||
if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
|
||||
*segment = lptr->defn.segment;
|
||||
*offset = lptr->defn.offset;
|
||||
return 1;
|
||||
*segment = lptr->defn.segment;
|
||||
*offset = lptr->defn.offset;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_extern (char *label)
|
||||
@ -145,17 +147,17 @@ int is_extern (char *label)
|
||||
union label *lptr;
|
||||
|
||||
if (!initialised)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
lptr = find_label (label, 0);
|
||||
if (lptr && (lptr->defn.is_global & EXTERN_BIT))
|
||||
return 1;
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void redefine_label (char *label, long segment, long offset, char *special,
|
||||
int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
|
||||
int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
|
||||
{
|
||||
union label *lptr;
|
||||
|
||||
@ -165,51 +167,58 @@ void redefine_label (char *label, long segment, long offset, char *special,
|
||||
*/
|
||||
|
||||
(void) segment; /* Don't warn that this parameter is unused */
|
||||
(void) offset; /* Don't warn that this parameter is unused */
|
||||
(void) special; /* Don't warn that this parameter is unused */
|
||||
(void) is_norm; /* Don't warn that this parameter is unused */
|
||||
(void) isextrn; /* Don't warn that this parameter is unused */
|
||||
(void) ofmt; /* Don't warn that this parameter is unused */
|
||||
|
||||
#ifdef DEBUG
|
||||
#if DEBUG<3
|
||||
if (!strncmp(label, "debugdump", 9))
|
||||
fprintf(stderr, "debug: redefine_label (%s, %ld, %08lx, %s, %d, %d)\n",
|
||||
label, segment, offset, special, is_norm, isextrn);
|
||||
#endif
|
||||
error(ERR_DEBUG, "redefine_label (%s, %ld, %08lx, %s, %d, %d)",
|
||||
label, segment, offset, special, is_norm, isextrn);
|
||||
#endif
|
||||
|
||||
lptr = find_label (label, 1);
|
||||
if (!lptr)
|
||||
error (ERR_PANIC, "can't find label `%s' on pass two", label);
|
||||
|
||||
if (!islocal(label)) {
|
||||
lptr = find_label (label, 1);
|
||||
if (!lptr)
|
||||
error (ERR_PANIC, "can't find label `%s' on pass two", label);
|
||||
if (*label != '.' && lptr->defn.is_norm)
|
||||
prevlabel = lptr->defn.label;
|
||||
if (*label != '.' && lptr->defn.is_norm)
|
||||
prevlabel = lptr->defn.label;
|
||||
}
|
||||
|
||||
global_offset_changed |= (lptr->defn.offset != offset);
|
||||
lptr->defn.offset = offset;
|
||||
}
|
||||
|
||||
void define_label (char *label, long segment, long offset, char *special,
|
||||
int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
|
||||
int is_norm, int isextrn, struct ofmt *ofmt, efunc error)
|
||||
{
|
||||
union label *lptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
#if DEBUG<3
|
||||
if (!strncmp(label, "debugdump", 9))
|
||||
fprintf(stderr, "debug: define_label (%s, %ld, %08lx, %s, %d, %d)\n",
|
||||
label, segment, offset, special, is_norm, isextrn);
|
||||
#endif
|
||||
error(ERR_DEBUG, "define_label (%s, %ld, %08lx, %s, %d, %d)",
|
||||
label, segment, offset, special, is_norm, isextrn);
|
||||
#endif
|
||||
lptr = find_label (label, 1);
|
||||
if (lptr->defn.is_global & DEFINED_BIT) {
|
||||
error(ERR_NONFATAL, "symbol `%s' redefined", label);
|
||||
return;
|
||||
error(ERR_NONFATAL, "symbol `%s' redefined", label);
|
||||
return;
|
||||
}
|
||||
lptr->defn.is_global |= DEFINED_BIT;
|
||||
if (isextrn)
|
||||
lptr->defn.is_global |= EXTERN_BIT;
|
||||
lptr->defn.is_global |= EXTERN_BIT;
|
||||
|
||||
if (label[0] != '.' && is_norm) /* not local, but not special either */
|
||||
prevlabel = lptr->defn.label;
|
||||
prevlabel = lptr->defn.label;
|
||||
else if (label[0] == '.' && label[1] != '.' && !*prevlabel)
|
||||
error(ERR_NONFATAL, "attempt to define a local label before any"
|
||||
" non-local labels");
|
||||
error(ERR_NONFATAL, "attempt to define a local label before any"
|
||||
" non-local labels");
|
||||
|
||||
lptr->defn.segment = segment;
|
||||
lptr->defn.offset = offset;
|
||||
@ -217,39 +226,39 @@ void define_label (char *label, long segment, long offset, char *special,
|
||||
|
||||
if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) {
|
||||
ofmt->symdef (lptr->defn.label, segment, offset,
|
||||
!!(lptr->defn.is_global & GLOBAL_BIT),
|
||||
special ? special : lptr->defn.special);
|
||||
!!(lptr->defn.is_global & GLOBAL_BIT),
|
||||
special ? special : lptr->defn.special);
|
||||
ofmt->current_dfmt->debug_deflabel (label, segment, offset,
|
||||
!!(lptr->defn.is_global & GLOBAL_BIT),
|
||||
special ? special : lptr->defn.special);
|
||||
!!(lptr->defn.is_global & GLOBAL_BIT),
|
||||
special ? special : lptr->defn.special);
|
||||
}
|
||||
}
|
||||
|
||||
void define_common (char *label, long segment, long size, char *special,
|
||||
struct ofmt *ofmt, efunc error)
|
||||
struct ofmt *ofmt, efunc error)
|
||||
{
|
||||
union label *lptr;
|
||||
|
||||
lptr = find_label (label, 1);
|
||||
if (lptr->defn.is_global & DEFINED_BIT) {
|
||||
error(ERR_NONFATAL, "symbol `%s' redefined", label);
|
||||
return;
|
||||
error(ERR_NONFATAL, "symbol `%s' redefined", label);
|
||||
return;
|
||||
}
|
||||
lptr->defn.is_global |= DEFINED_BIT;
|
||||
|
||||
if (label[0] != '.') /* not local, but not special either */
|
||||
prevlabel = lptr->defn.label;
|
||||
if (label[0] != '.') /* not local, but not special either */
|
||||
prevlabel = lptr->defn.label;
|
||||
else
|
||||
error(ERR_NONFATAL, "attempt to define a local label as a "
|
||||
"common variable");
|
||||
error(ERR_NONFATAL, "attempt to define a local label as a "
|
||||
"common variable");
|
||||
|
||||
lptr->defn.segment = segment;
|
||||
lptr->defn.offset = 0;
|
||||
|
||||
ofmt->symdef (lptr->defn.label, segment, size, 2,
|
||||
special ? special : lptr->defn.special);
|
||||
special ? special : lptr->defn.special);
|
||||
ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2,
|
||||
special ? special : lptr->defn.special);
|
||||
special ? special : lptr->defn.special);
|
||||
}
|
||||
|
||||
void declare_as_global (char *label, char *special, efunc error)
|
||||
@ -257,24 +266,24 @@ void declare_as_global (char *label, char *special, efunc error)
|
||||
union label *lptr;
|
||||
|
||||
if (islocal(label)) {
|
||||
error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
|
||||
" global", label);
|
||||
return;
|
||||
error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
|
||||
" global", label);
|
||||
return;
|
||||
}
|
||||
lptr = find_label (label, 1);
|
||||
switch (lptr->defn.is_global & TYPE_MASK) {
|
||||
case NOT_DEFINED_YET:
|
||||
lptr->defn.is_global = GLOBAL_PLACEHOLDER;
|
||||
lptr->defn.special = special ? perm_copy(special, "") : NULL;
|
||||
break;
|
||||
case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
|
||||
lptr->defn.is_global = GLOBAL_PLACEHOLDER;
|
||||
lptr->defn.special = special ? perm_copy(special, "") : NULL;
|
||||
break;
|
||||
case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
|
||||
case GLOBAL_SYMBOL:
|
||||
break;
|
||||
break;
|
||||
case LOCAL_SYMBOL:
|
||||
if (!lptr->defn.is_global & EXTERN_BIT)
|
||||
error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
|
||||
" appear before symbol definition", label);
|
||||
break;
|
||||
if (!lptr->defn.is_global & EXTERN_BIT)
|
||||
error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
|
||||
" appear before symbol definition", label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,18 +292,18 @@ int init_labels (void)
|
||||
int i;
|
||||
|
||||
for (i=0; i<LABEL_HASHES; i++) {
|
||||
ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
|
||||
if (!ltab[i])
|
||||
return -1; /* can't initialise, panic */
|
||||
init_block (ltab[i]);
|
||||
lfree[i] = ltab[i];
|
||||
ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
|
||||
if (!ltab[i])
|
||||
return -1; /* can't initialise, panic */
|
||||
init_block (ltab[i]);
|
||||
lfree[i] = ltab[i];
|
||||
}
|
||||
|
||||
perm_head =
|
||||
perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
|
||||
perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
|
||||
|
||||
if (!perm_head)
|
||||
return -1;
|
||||
return -1;
|
||||
|
||||
perm_head->next = NULL;
|
||||
perm_head->size = PERMTS_SIZE;
|
||||
@ -314,22 +323,22 @@ void cleanup_labels (void)
|
||||
initialised = FALSE;
|
||||
|
||||
for (i=0; i<LABEL_HASHES; i++) {
|
||||
union label *lptr, *lhold;
|
||||
union label *lptr, *lhold;
|
||||
|
||||
lptr = lhold = ltab[i];
|
||||
lptr = lhold = ltab[i];
|
||||
|
||||
while (lptr) {
|
||||
while (lptr->admin.movingon != END_BLOCK) lptr++;
|
||||
lptr = lptr->admin.next;
|
||||
nasm_free (lhold);
|
||||
lhold = lptr;
|
||||
}
|
||||
while (lptr) {
|
||||
while (lptr->admin.movingon != END_BLOCK) lptr++;
|
||||
lptr = lptr->admin.next;
|
||||
nasm_free (lhold);
|
||||
lhold = lptr;
|
||||
}
|
||||
}
|
||||
|
||||
while (perm_head) {
|
||||
perm_tail = perm_head;
|
||||
perm_head = perm_head->next;
|
||||
nasm_free (perm_tail);
|
||||
perm_tail = perm_head;
|
||||
perm_head = perm_head->next;
|
||||
nasm_free (perm_tail);
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,7 +347,7 @@ static void init_block (union label *blk)
|
||||
int j;
|
||||
|
||||
for (j=0; j<LABEL_BLOCK-1; j++)
|
||||
blk[j].admin.movingon = END_LIST;
|
||||
blk[j].admin.movingon = END_LIST;
|
||||
blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK;
|
||||
blk[LABEL_BLOCK-1].admin.next = NULL;
|
||||
}
|
||||
@ -349,11 +358,11 @@ static char *perm_copy (char *string1, char *string2)
|
||||
int len = strlen(string1)+strlen(string2)+1;
|
||||
|
||||
if (perm_tail->size - perm_tail->usage < len) {
|
||||
perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
|
||||
perm_tail = perm_tail->next;
|
||||
perm_tail->next = NULL;
|
||||
perm_tail->size = PERMTS_SIZE;
|
||||
perm_tail->usage = 0;
|
||||
perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
|
||||
perm_tail = perm_tail->next;
|
||||
perm_tail->next = NULL;
|
||||
perm_tail->size = PERMTS_SIZE;
|
||||
perm_tail->usage = 0;
|
||||
}
|
||||
p = q = perm_tail->data + perm_tail->usage;
|
||||
while ( (*q = *string1++) ) q++;
|
||||
|
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
|
||||
|
39
nasm.h
39
nasm.h
@ -13,7 +13,7 @@
|
||||
|
||||
#define NASM_MAJOR_VER 0
|
||||
#define NASM_MINOR_VER 98
|
||||
#define NASM_VER "0.98"
|
||||
#define NASM_VER "0.98.03"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
@ -64,26 +64,28 @@ typedef void (*efunc) (int severity, char *fmt, ...);
|
||||
* argument to an efunc.
|
||||
*/
|
||||
|
||||
#define ERR_WARNING 0 /* warn only: no further action */
|
||||
#define ERR_NONFATAL 1 /* terminate assembly after phase */
|
||||
#define ERR_FATAL 2 /* instantly fatal: exit with error */
|
||||
#define ERR_PANIC 3 /* internal error: panic instantly
|
||||
#define ERR_DEBUG 0x00000008 /* put out debugging message */
|
||||
#define ERR_WARNING 0x00000000 /* warn only: no further action */
|
||||
#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */
|
||||
#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */
|
||||
#define ERR_PANIC 0x00000003 /* internal error: panic instantly
|
||||
* and dump core for reference */
|
||||
#define ERR_MASK 0x0F /* mask off the above codes */
|
||||
#define ERR_NOFILE 0x10 /* don't give source file name/line */
|
||||
#define ERR_USAGE 0x20 /* print a usage message */
|
||||
#define ERR_PASS1 0x80 /* only print this error on pass one */
|
||||
#define ERR_MASK 0x0000000F /* mask off the above codes */
|
||||
#define ERR_NOFILE 0x00000010 /* don't give source file name/line */
|
||||
#define ERR_USAGE 0x00000020 /* print a usage message */
|
||||
#define ERR_PASS1 0x00000040 /* only print this error on pass one */
|
||||
|
||||
/*
|
||||
* These codes define specific types of suppressible warning.
|
||||
*/
|
||||
#define ERR_WARN_MNP 0x0100 /* macro-num-parameters warning */
|
||||
#define ERR_WARN_OL 0x0200 /* orphan label (no colon, and
|
||||
#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */
|
||||
#define ERR_WARN_MSR 0x00000200 /* macro self-reference */
|
||||
#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and
|
||||
* alone on line) */
|
||||
#define ERR_WARN_NOV 0x0300 /* numeric overflow */
|
||||
#define ERR_WARN_MASK 0xFF00 /* the mask for this feature */
|
||||
#define ERR_WARN_NOV 0x00000400 /* numeric overflow */
|
||||
#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */
|
||||
#define ERR_WARN_SHR 8 /* how far to shift right */
|
||||
#define ERR_WARN_MAX 3 /* the highest numbered one */
|
||||
#define ERR_WARN_MAX 4 /* the highest numbered one */
|
||||
|
||||
/*
|
||||
* -----------------------
|
||||
@ -250,8 +252,8 @@ struct eval_hints {
|
||||
* defined before use", whereas if `critical' is 2, the error will
|
||||
* be "symbol undefined".
|
||||
*
|
||||
* If `critical' has bit 4 set (in addition to its main value: 0x11
|
||||
* and 0x12 correspond to 1 and 2) then an extended expression
|
||||
* If `critical' has bit 8 set (in addition to its main value: 0x101
|
||||
* and 0x102 correspond to 1 and 2) then an extended expression
|
||||
* syntax is recognised, in which relational operators such as =, <
|
||||
* and >= are accepted, as well as low-precedence logical operators
|
||||
* &&, ^^ and ||.
|
||||
@ -259,6 +261,7 @@ struct eval_hints {
|
||||
* If `hints' is non-NULL, it gets filled in with some hints as to
|
||||
* the base register in complex effective addresses.
|
||||
*/
|
||||
#define CRITICAL 0x100
|
||||
typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv,
|
||||
int *fwref, int critical, efunc error,
|
||||
struct eval_hints *hints);
|
||||
@ -411,7 +414,9 @@ enum {
|
||||
/* special type of immediate operand */
|
||||
#define ONENESS 0x00800000L /* so UNITY == IMMEDIATE | ONENESS */
|
||||
#define UNITY 0x00802000L /* for shift/rotate instructions */
|
||||
|
||||
#define BYTENESS 0x80000000L /* so SBYTE == IMMEDIATE | BYTENESS */
|
||||
#define SBYTE 0x80002000L /* for op r16/32,immediate instrs. */
|
||||
|
||||
/*
|
||||
* Next, the codes returned from the parser, for registers and
|
||||
* instructions.
|
||||
|
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;
|
||||
}
|
||||
|
||||
|
9
parser.c
9
parser.c
@ -647,8 +647,13 @@ insn *parse_line (int pass, char *buffer, insn *result,
|
||||
result->oprs[operand].offset = reloc_value(value);
|
||||
result->oprs[operand].segment = reloc_seg(value);
|
||||
result->oprs[operand].wrt = reloc_wrt(value);
|
||||
if (is_simple(value) && reloc_value(value)==1)
|
||||
result->oprs[operand].type |= UNITY;
|
||||
if (is_simple(value)) {
|
||||
if (reloc_value(value)==1)
|
||||
result->oprs[operand].type |= UNITY;
|
||||
if (reloc_value(value) >= -128 &&
|
||||
reloc_value(value) <= 127)
|
||||
result->oprs[operand].type |= SBYTE;
|
||||
}
|
||||
}
|
||||
else /* it's a register */
|
||||
{
|
||||
|
509
preproc.c
509
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,44 +855,63 @@ static int ppscan(void *private_data, struct tokenval *tokval)
|
||||
return tokval->t_type = tline->text[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare a string to the name of an existing macro; this is a
|
||||
* simple wrapper which calls either strcmp or nasm_stricmp
|
||||
* depending on the value of the `casesense' parameter.
|
||||
*/
|
||||
static int mstrcmp(char *p, char *q, int casesense)
|
||||
{
|
||||
return casesense ? strcmp(p,q) : nasm_stricmp(p,q);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the Context structure associated with a %$ token. Return
|
||||
* NULL, having _already_ reported an error condition, if the
|
||||
* context stack isn't deep enough for the supplied number of $
|
||||
* signs.
|
||||
* If all_contexts == TRUE, contexts that enclose current are
|
||||
* also scanned for such smacro, until it is found; if not -
|
||||
* only the context that directly results from the number of $'s
|
||||
* in variable's name.
|
||||
*/
|
||||
static Context *get_ctx (char *name)
|
||||
static Context *get_ctx (char *name, int all_contexts)
|
||||
{
|
||||
Context *ctx;
|
||||
SMacro *m;
|
||||
int i;
|
||||
|
||||
if (!name || name[0] != '%' || name[1] != '$')
|
||||
return NULL;
|
||||
|
||||
if (!cstk) {
|
||||
error (ERR_NONFATAL, "`%s': context stack is empty", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i = 1;
|
||||
ctx = cstk;
|
||||
while (name[i+1] == '$') {
|
||||
i++;
|
||||
for (i = strspn (name+2, "$"), ctx = cstk; (i > 0) && ctx; i--) {
|
||||
ctx = ctx->next;
|
||||
i--;
|
||||
}
|
||||
if (!ctx) {
|
||||
error (ERR_NONFATAL, "`%s': context stack is only"
|
||||
" %d level%s deep", name, i-1, (i==2 ? "" : "s"));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (!all_contexts)
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare a string to the name of an existing macro; this is a
|
||||
* simple wrapper which calls either strcmp or nasm_stricmp
|
||||
* depending on the value of the `casesense' parameter.
|
||||
*/
|
||||
static int mstrcmp(char *p, char *q, int casesense)
|
||||
{
|
||||
return casesense ? strcmp(p,q) : nasm_stricmp(p,q);
|
||||
do {
|
||||
/* Search for this smacro in found context */
|
||||
m = ctx->localmac;
|
||||
while (m) {
|
||||
if (!mstrcmp(m->name, name, m->casesense))
|
||||
return ctx;
|
||||
m = m->next;
|
||||
}
|
||||
ctx = ctx->next;
|
||||
} while (ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -922,27 +970,30 @@ static FILE *inc_fopen(char *file)
|
||||
*
|
||||
* Note that this is also called with nparam zero to resolve
|
||||
* `ifdef'.
|
||||
*
|
||||
* If you already know which context macro belongs to, you can pass
|
||||
* the context pointer as first parameter; if you won't but name begins
|
||||
* with %$ the context will be automatically computed. If all_contexts
|
||||
* is true, macro will be searched in outer contexts as well.
|
||||
*/
|
||||
static int smacro_defined (char *name, int nparam, SMacro **defn, int nocase)
|
||||
static int smacro_defined (Context *ctx, char *name, int nparam, SMacro **defn,
|
||||
int nocase)
|
||||
{
|
||||
SMacro *m;
|
||||
Context *ctx;
|
||||
char *p;
|
||||
|
||||
if (name[0] == '%' && name[1] == '$') {
|
||||
ctx = get_ctx (name);
|
||||
if (ctx)
|
||||
m = ctx->localmac;
|
||||
else if (name[0] == '%' && name[1] == '$') {
|
||||
if (cstk)
|
||||
ctx = get_ctx (name, FALSE);
|
||||
if (!ctx)
|
||||
return FALSE; /* got to return _something_ */
|
||||
m = ctx->localmac;
|
||||
p = name+1;
|
||||
p += strspn(p, "$");
|
||||
} else {
|
||||
} else
|
||||
m = smacros[hash(name)];
|
||||
p = name;
|
||||
}
|
||||
|
||||
while (m) {
|
||||
if (!mstrcmp(m->name, p, m->casesense & nocase) &&
|
||||
if (!mstrcmp(m->name, name, m->casesense && nocase) &&
|
||||
(nparam <= 0 || m->nparam == 0 || nparam == m->nparam)) {
|
||||
if (defn) {
|
||||
if (nparam == m->nparam || nparam == -1)
|
||||
@ -954,6 +1005,7 @@ static int smacro_defined (char *name, int nparam, SMacro **defn, int nocase)
|
||||
}
|
||||
m = m->next;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1021,10 +1073,7 @@ static int if_condition (Token *tline, int i)
|
||||
case PP_IFCTX: case PP_ELIFCTX:
|
||||
case PP_IFNCTX: case PP_ELIFNCTX:
|
||||
j = FALSE; /* have we matched yet? */
|
||||
if (!cstk)
|
||||
error(ERR_FATAL,
|
||||
"`%s': context stack is empty", directives[i]);
|
||||
else while (tline) {
|
||||
while (cstk && tline) {
|
||||
skip_white_(tline);
|
||||
if (!tline || tline->type != TOK_ID) {
|
||||
error(ERR_NONFATAL,
|
||||
@ -1055,7 +1104,7 @@ static int if_condition (Token *tline, int i)
|
||||
free_tlist (origline);
|
||||
return -1;
|
||||
}
|
||||
if (smacro_defined(tline->text, 0, NULL, 1))
|
||||
if (smacro_defined (NULL, tline->text, 0, NULL, 1))
|
||||
j = TRUE;
|
||||
tline = tline->next;
|
||||
}
|
||||
@ -1143,7 +1192,7 @@ static int if_condition (Token *tline, int i)
|
||||
tptr = &t;
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
evalresult = evaluate (ppscan, tptr, &tokval,
|
||||
NULL, pass | 0x10, error, NULL);
|
||||
NULL, pass | CRITICAL, error, NULL);
|
||||
free_tlist (tline);
|
||||
if (!evalresult)
|
||||
return -1;
|
||||
@ -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;
|
||||
}
|
||||
if (tline->next) {
|
||||
error (ERR_WARNING,
|
||||
"trailing garbage after macro name ignored");
|
||||
}
|
||||
last = tline;
|
||||
tline = tline->next;
|
||||
last->next = NULL;
|
||||
|
||||
if (tline)
|
||||
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);
|
||||
nasm_free (t->text);
|
||||
t->text = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now scan the entire line and look for successive TOK_IDs that resulted
|
||||
* after expansion (they can't be produced by tokenise()). The successive
|
||||
* TOK_IDs should be concatenated.
|
||||
* Also we look for %+ tokens and concatenate the tokens before and after
|
||||
* them (without white spaces in between).
|
||||
*/
|
||||
t = thead;
|
||||
rescan = 0;
|
||||
while (t) {
|
||||
while (t && t->type != TOK_ID && t->type != TOK_PREPROC_ID)
|
||||
t = t->next;
|
||||
if (!t || !t->next)
|
||||
break;
|
||||
if (t->next->type == TOK_ID ||
|
||||
t->next->type == TOK_PREPROC_ID ||
|
||||
t->next->type == TOK_NUMBER) {
|
||||
Token *next = t->next->next;
|
||||
char *p = nasm_malloc (strlen (t->text) + strlen (t->next->text) + 1);
|
||||
strcpy (p, t->text);
|
||||
strcat (p, t->next->text);
|
||||
nasm_free (t->text);
|
||||
nasm_free (t->next->text);
|
||||
nasm_free (t->next);
|
||||
t->next = next;
|
||||
t->text = p;
|
||||
rescan = 1;
|
||||
} else if (t->next->type == TOK_WHITESPACE && t->next->next &&
|
||||
t->next->next->type == TOK_PREPROC_ID &&
|
||||
strcmp (t->next->next->text, "%+") == 0) {
|
||||
/* free the next whitespace, the %+ token and next whitespace */
|
||||
int i;
|
||||
for (i = 1; i <= 3; i++)
|
||||
{
|
||||
Token *next;
|
||||
if (!t->next || (i != 2 && t->next->type != TOK_WHITESPACE))
|
||||
break;
|
||||
next = t->next->next;
|
||||
nasm_free (t->next->text);
|
||||
nasm_free (t->next);
|
||||
t->next = next;
|
||||
} /* endfor */
|
||||
} else
|
||||
t = t->next;
|
||||
}
|
||||
/* If we concatenaded something, re-scan the line for macros */
|
||||
if (rescan) {
|
||||
tline = thead;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (org_tline)
|
||||
{
|
||||
if (thead) {
|
||||
*org_tline = *thead;
|
||||
nasm_free (thead);
|
||||
} else
|
||||
{
|
||||
/* the expression expanded to empty line;
|
||||
we can't return NULL for some reasons
|
||||
we just set the line to a single WHITESPACE token. */
|
||||
memset (org_tline, 0, sizeof (*org_tline));
|
||||
org_tline->text = nasm_strdup (" ");
|
||||
org_tline->type = TOK_WHITESPACE;
|
||||
}
|
||||
thead = org_tline;
|
||||
}
|
||||
|
||||
return thead;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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…
x
Reference in New Issue
Block a user