#include "c.h"
#include "asm.h"
#include "i386.h"
#include "i386-opc.h"
#include "cv.h"
#define BUFFER_SIZE (32 * 1024)
typedef char operator_rankT;
extern int OptimizeFlag;
/* Prototypes */
static char * xmalloc (long n );
static void StringAppend (char * * charPP ,char * fromP ,unsigned long length );
static void subsegs_begin (void);
static void subseg_change (register segT seg ,register int subseg );
static void subseg_new (register segT seg ,register subsegT subseg );
static void symbol_begin (void);
static symbolS * symbol_new (char * name ,unsigned char type ,valueT value ,struct frag * frag );
static void colon (register char * sym_name );
static void symbol_table_insert (symbolS * symbolP );
static void SetFlags(symbolS *coffS);
static symbolS * symbol_find_or_make (char * name );
static void frag_grow (unsigned int nchars );
static void frag_new (int old_frags_var_max_size );
static char * frag_more (int nchars );
static char * frag_var (relax_stateT type ,int max_chars ,int var ,relax_substateT subtype ,symbolS * symbol ,long int offset ,char * opcode );
static void frag_wane (fragS * fragP );
static void frag_align (int alignment ,int fill_character );
static segT operand (register expressionS * expressionP );
static void clean_up_expression (register expressionS * expressionP );
static segT expr_part (symbolS * * symbol_1_PP ,symbolS * symbol_2_P );
static segT AsmExpression (register operator_rankT rank ,register expressionS * resultP );
static char get_symbol_end (void);
static char * input_file_give_next_buffer (char * where );
static void InitAsmInput (void);
static char * SetObjFileName (char * filename );
static char * input_scrub_next_buffer (char * * bufp );
static void bump_line_counters (void);
static void as_where (void);
static void as_perror (char * gripe ,char * filename );
static void _obstack_begin (struct obstack * h ,int size ,int alignment ,void *(*chunkfun )(int),void (* freefun )(void *));
static void _obstack_newchunk (struct obstack * h ,int length );
static void read_begin (void);
static char * hash_insert (struct HASH_LIST * where ,char * name ,char * data );
static char * hash_find (struct HASH_LIST * w ,char * n );
static struct HASH_LIST * hash_new (void);
static char * hash_jam (struct HASH_LIST * where ,char * n ,char * data );
static void s_align (void);
static void s_byte(void);
static void s_short(void);
static void s_int(void);
static void s_comm (void);
static void s_data (void);
static void s_file (void);
static void s_globl (void);
static void s_lcomm (void);
static void s_line (void);
static void s_lsym (void);
static void s_space (void);
static void s_text (void);
static void s_section(void);
static void s_type (void);
static void s_size (void);
static void demand_empty_rest_of_line (void);
static void ignore_rest_of_line (void);
static void stab (int what );
static void pseudo_set (symbolS * symbolP );
static void cons (int nbytes );
static void stringer (int append_zero );
static int next_char_of_string (void);
static segT get_segmented_expression (register expressionS * expP );
static segT get_known_segmented_expression (expressionS * expP );
static long int get_absolute_expression (void);
static char get_absolute_expression_and_terminator (long int * val_pointer );
static char * demand_copy_C_string (int * len_pointer );
static char * demand_copy_string (int * lenP );
static int is_it_end_of_statement (void);
static void equals (char * sym_name );
static void InitializeAsmTables (void);
static int i386_operand (char * operand_string );
static int md_estimate_size_before_relax (register fragS * fragP ,register int segment_type );
static void md_convert_frag (register fragS * fragP );
static void md_number_to_chars (char con [ ] ,long int value ,int nbytes );
static char * output_invalid (char c );
static reg_entry * parse_register (char * reg_string );
static void WriteCoffHeader (void);
static long WriteTextSection (long siz ,long nfixups );
static long WriteDataSection (long siz ,long nfixups ,int addr );
static long WriteBssSection (long siz );
static int ArrangeDataSection (int ordinal );
static int ArrangeOrdinalNumbers (char * name );
static int SortFun (const void * f1 ,const void * f2 );
static int WriteRelocations (int which);
static STRING * NewString (char * s ,int len );
static int AddStringToStringTable (char * str );
static long WriteStringTable (void);
static int SortSymbols (const void * f1 ,const void * f2 );
static int WriteLineNumbers (int PosCodeSection );
static int WriteOneSymbol (char * p );
static int WriteFunctionRecords (symbolS * coffS );
static int SymbolToChars (symbolS * coffS );
static int WriteDataSymbols (int count );
static int WriteSpecialSymbols (int result );
static int WriteAllCoffSymbols (int startCount );
static int WriteFileName (char * name );
static COFF_RELOC * AddCoffRelocation (symbolS * coffS ,int where ,int pcrel );
static void newFixup(fragS * frag ,int where ,short int size ,symbolS * add_symbol ,symbolS * sub_symbol ,long int offset ,int pcrel );
static void relax_segment (struct frag * segment_frag_root ,segT segment_type );
static relax_addressT relax_align (register relax_addressT address ,register long int alignment );
static long int fixup_segment (fixS * fixP ,int this_segment_type );
static int FixRelocations(register fixS * fixP);
#ifdef ASM_LIB
extern int is_dnrange (struct frag *f1,struct frag *f2);
#else
static int is_dnrange (struct frag * f1 ,struct frag * f2 );
#endif
int main (int argc ,char * * argv );
void WriteError(void);
void InternalError(int err);
static void MakeBssSymbol(symbolS *symbolP,int siz,int localflag);

#define HASHSIZE 1024
fixS *   text_fix_root;  /* Chains fixSs. */
fixS *   data_fix_root;  /* Chains fixSs. */
fixS **  seg_fix_rootP;  /* -> one of above. */

/* --------------------------------------------------Sections stuff */
static int IsSpecialSection = 0;
static int NumberOfSpecialSections,NumberOfDebugSections;
NewSection *SectionList,*CurrentSpecialSection;

static void Asm386Instruction(char *line);
static struct obstack frags;    /* All, and only, frags live here. */
static	char	* InputPointer; /* -> char we are parsing now. */
static STRING_TABLE *StringTable;
int	need_pass_2;	/* TRUE if we need a second pass. */
/* used by is_... macros. our ctype[] */
static char lex_type[256] = {
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */
	0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */
													/* @ is part of name */
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, /* PQRSTUVWXYZ[\]^_ */
	0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, /* pqrstuvwxyz{|}~. */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static char *buffer_limit;  /* -> 1 + last char in buffer. */
static char *old_buffer = 0;    /* JF a hack */
static char *old_input;
static char *old_limit;
static pseudo_typeS potable[] =
{
	{"align", s_align},
	{"byte", s_byte},
	{"comm", s_comm},
	{"data", s_data},
	{"file", s_file},
	{"globl", s_globl},
	{"int", s_int},
	{"lcomm", s_lcomm},
	{"line", s_line},
	{"long", s_int},
	{"lsym", s_lsym},
	{"short", s_short},
	{"space", s_space},
	{"text", s_text},
	{"type", s_type},
	{"size", s_size},
	{"extern", s_globl},
	{"bss", s_data},
	{"section",s_section},
	{"word", s_short},
	{NULL}              /* end sentinel */
};

/*
Interface to relax_segment.
There are 2 relax states for 386 jump insns: one for conditional & one
for unconditional jumps.  This is because the these two types of jumps
add different sizes to frags when we're figuring out what sort of jump
to choose to reach a given label.  */
/* types */
#define COND_JUMP 1     /* conditional jump */
#define UNCOND_JUMP 2   /* unconditional jump */
/* sizes */
#define BYTE 0
#define WORD 1
#define DWORD 2
#define UNKNOWN_SIZE 3
#define ENCODE_RELAX_STATE(type,size) ((type<<2) | (size))
#define SIZE_FROM_RELAX_STATE(s) \
  ( (((s) & 0x3) == BYTE ? 1 : (((s) & 0x3) == WORD ? 2 : 4)) )
static relax_typeS md_relax_table[] = {
/*
  The fields are:
   1) most positive reach of this state,
   2) most negative reach of this state,
   3) how many bytes this mode will add to the size of the current frag
   4) which index into the table to try if we can't fit into this one.
*/
	{1, 1, 0, 0},
	{1, 1, 0, 0},
	{1, 1, 0, 0},
	{1, 1, 0, 0},
	/* For now we don't use word displacement jumps:  they may be
	untrustworthy. */
	{127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE(COND_JUMP, DWORD)},
	/* word conditionals add 3 bytes to frag: 2 opcode prefix; 1 displacement
	bytes */
	{32767 + 2, -32768 + 2, 3, ENCODE_RELAX_STATE(COND_JUMP, DWORD)},
	/* dword conditionals adds 4 bytes to frag: 1 opcode prefix; 3
	displacement bytes */
	{0, 0, 4, 0},
	{1, 1, 0, 0},
	{127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE(UNCOND_JUMP, DWORD)},
	/* word jmp adds 2 bytes to frag: 1 opcode prefix; 1 displacement bytes */
	{32767 + 2, -32768 + 2, 2, ENCODE_RELAX_STATE(UNCOND_JUMP, DWORD)},
	/* dword jmp adds 3 bytes to frag: 0 opcode prefix; 3 displacement bytes */
	{0, 0, 3, 0},
	{1, 1, 0, 0},
};
static frchainS *frchain_root, *frchain_now, 
			*data0_frchainP;
static fragS *	frag_now;	/* -> current frag we are building. */
				/* This frag is incomplete. */
				/* It is, however, included in frchain_now. */
				/* Frag_now->fr_fix is bogus. Use: */
/* Virtual frag_now->fr_fix==obstack_next_free(&frags)-frag_now->fr_literal.*/
static fragS zero_address_frag = {
	0,                  /* fr_address */
	NULL,               /* fr_next */
	0,                  /* fr_fix */
	0,                  /* fr_var */
	0,                  /* fr_symbol */
	0,                  /* fr_offset */
	NULL,               /* fr_opcode */
	rs_fill,            /* fr_type */
	0,                  /* fr_subtype */
	0                   /* fr_literal [0] */
};
static fragS bss_address_frag = {
	0,                  /* fr_address. Gets filled in to make up SymbolValue-s. */
	NULL,               /* fr_next */
	0,                  /* fr_fix */
	0,                  /* fr_var */
	0,                  /* fr_symbol */
	0,                  /* fr_offset */
	NULL,               /* fr_opcode */
	rs_fill,            /* fr_type */
	0,                  /* fr_subtype */
	0                   /* fr_literal [0] */
};
static subsegT			now_subseg;
				/* What subseg we are accreting now? */


static segT			now_seg;
				/* Segment our instructions emit to. */
				/* Only OK values are SEG_TEXT or SEG_DATA. */
static struct hash_control *sy_hash;    /* symbol-name => struct symbol
						pointer */
static unsigned int local_bss_counter;
static symbolS *symbol_rootP;
static symbolS *symbol_lastP;
static symbolS abs_symbol;
static struct obstack notes;
/* tables for lexical analysis */
static char opcode_chars[256];
static char register_chars[256];
static char operand_chars[256];
static char space_chars[256];
static char identifier_chars[256];
static char digit_chars[256];
static char RegisterNames[MAX_REG_NAMES * 6];

static char *SourceFileName = "d:\\asm\\test.asm";
static char *OutputFileName;

/*
Errors
------
1000	Symbol is already defined
1001	Symbol %s already defined.
1002	Inserting symnol into symbol table failed
1003	Can't extend frag
1004	"integer overflow in constant"
1005	"No floating point constants supported"
1006	"Source line too long.
1007	error constructing pseudo-op table
1008	bad .type construct
1009	"Internal Error:  Can't hash %s: %s", prev_name, hash_err
1010	Unknown pseudo-op:
1011	Spurious digit
1012	Synchronization problem at character ...
1013	Alignment too large
2014	Alignment negative
2015	Expected comma after symbol-name
2016	Bad expression
1017	Unknown expression: symbols %s and %s are in different frags
1018	invalid character %s in opcode"
1019	expecting prefix; got nothing"
1020	no such opcode prefix ('%s')", token_start)
1021	same prefix used twice; you don't really want this!
1022	too many opcode prefixes
1023	expecting opcode; got nothing
1024	no such 386 instruction: `%s'", token_start
1025	expecting string instruction after rep/repne
1026	invalid character %s before %s operand",
1027	unbalenced parenthesis in %s operand.",
1028	invalid character %s in %s operand",
1029	spurious operands; (%d operands/instruction max)
1030	expecting operand after ','; got nothing
1031	expecting operand before ','; got nothing
1032	operands given don't match any known 386 instruction
1033	no opcode suffix given; can't determine immediate size
1034	no opcode suffix given; can't determine immediate size
1035	no opcode suffix given and no register operands; can't size instruction
1036	%d prefixes given and 'w' opcode suffix gives too many prefixes",
1037	you can't 'pop cs' on the 386."
1038	%d prefixes given and %s segment override gives too many prefixes",
1039	"loop/jecx only takes byte displacement
1040	can't handle non absolute segment in long call/jmp"
1041	bad register name
1042	bad memory operand after segment override"
1043	only 1 or 2 immediate operands are allowed"
1044	missing or invalid immediate expression '%s'
1045	Unimplemented segment type %d in parse_operand"
1046	more than 1 memory reference in instruction"
1047	can't find base register name
1048	bad base register name
1049	expecting ',' or ')' after base register
1050	bad index register name
1051	can't find a scale factor after ','
1052	can't find a scale factor after ','
1053	expecting scale factor of 1, 2, 4, 8;
1054	expecting index register or scale factor after ','
2055	Ignoring junk '%s' after expression", InputPointer);
1056	missing or invalid displacement
1057	register size mismatch in (base,index,scale) expression
1058	base/index register must be 32 bit register"
1059	may not be used as an index register
1060	invalid char %s begining %s operand '%s'
3061	Missing ')' assumed"
3062	Unary operator %c ignored because bad operand follows", c);
1063	Expression too complex
1064	.COMMon length (%d.) <0!
1065	not used
1066	Missing operand value
1067	Expression too complex:
1068	Relocation error.
1069	Division by 0
2070	Partial line at end of file ignored
1071	Length of .comm \"%s\" is already %d
1072	Expected comma after name
1073	BSS length (%d.) <0! Ignored.
1074	Ignoring attempt to re-define symbol
1075	Expected comma after name
1076	Repeat < 0,in .space
2077	Rest of line ignored.
1078	need a comma after symbol's name
1079	want a comma after the n_type expression
1080	want a comma after the n_other expression
1081	I want a comma after the n_desc expression
1082	Missing expression
1083	%s number illegal
1084	No expression
1085	expression too complex
1086	Unknown expression
1087	Substracting expression too complicated
1088	number illegal
1089	missing expression
1090	Value x%x truncated to x%x
1091	Expected "-ed string
1092	Bad escaped character in string
1093	Expected address expression: absolute 0 assumed
1094	Symbols are undefined
1095	Symbol is undefined
1096	Bad Absolute Expression
2097	This string may not contain zeros
1098	Missing string
1099	Illegal segment %d.
1100	Negative of non-absolute symbol
1101	Can't emit reloc
1102	Fixup of %d too large for field width
1103	Bad case in cleanup_expression
1104	Bad case in function expr
1105	Bad case in function stab
1106	not used
1107	Bad case in cons
1108	Bad case in md_convert_frag
1109	Bad case in WriteCoffFile
1110	Bad case in relax_segment
1111	Bad case in relax_segment
1112	Bad case in fixup_segment
1113    Null pointer in symbol->FnInfo field
1114    input and output file names are the same
1115    error in adding up symbol types info
1116    Relocation to another special section needed
*/
#undef __
#define __ (42)         /* blatently illegal digit value */
						/* exceeds any normal radix */
static const char hex_value[256] = {    /* for fast ASCII -> binary */
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, __, __, __, __, __, __,
	__, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, 10, 11, 12, 13, 14, 15, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __
};
static char *xmalloc(long n)
{
	char *retval;
	if (!(retval = malloc((unsigned) n))) {
		error("virtual memory exceeded");
		exit(1);
	}
	memset(retval, 0, n);
	return (retval);
}
/* Append a string onto another string */
static void StringAppend(char **charPP, char *fromP, unsigned long length)
{
	if (length) {       /* Don't trust bcopy() of 0 chars. */
		memcpy(*charPP, fromP, (int) length);
		*charPP += length;
	}
}
static const int        /* in: segT   out: N_TYPE bits */
seg_N_TYPE[] = {
	N_ABS,
	N_TEXT,
	N_DATA,
	N_BSS,
	N_UNDF,
	N_UNDF,
	N_UNDF,
	N_UNDF,
	N_UNDF,
	N_UNDF
};
static const segT N_TYPE_seg[N_TYPE + 2] =  /* N_TYPE == 0x1E = 32-2 */
{
	SEG_UNKNOWN,        /* N_UNDF == 0 */
	SEG_GOOF,
	SEG_ABSOLUTE,       /* N_ABS == 2 */
	SEG_GOOF,
	SEG_TEXT,           /* N_TEXT == 4 */
	SEG_GOOF,
	SEG_DATA,           /* N_DATA == 6 */
	SEG_GOOF,
	SEG_BSS,            /* N_BSS == 8 */
	SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
	SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
	SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF
};
static void subsegs_begin(void)
{
	/* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
	know(SEG_ABSOLUTE == 0);
	know(SEG_TEXT == 1);
	know(SEG_DATA == 2);
	know(SEG_BSS == 3);
	know(SEG_UNKNOWN == 4);
	know(SEG_NONE == 5);
	know(SEG_PASS1 == 6);
	know(SEG_GOOF == 7);
	know(SEG_BIG == 8);
	know(SEG_DIFFERENCE == 9);
	know(SEG_MAXIMUM_ORDINAL == SEG_DIFFERENCE);
	obstack_begin(&frags, 50000);
	frchain_root = NULL;
	frchain_now = NULL; /* Warn new_subseg() that we are booting. */
	/* Fake up 1st frag. */
	/* It won't be used=> is ok if obstack... */
	/* pads the end of it for alignment. */
	frag_now = (fragS *) obstack_alloc(&frags, SIZEOF_STRUCT_FRAG);
	/* obstack_1blank( &frags, SIZEOF_STRUCT_FRAG, & frag_now ); */
	/* This 1st frag will not be in any frchain. */
	/* We simply give subseg_new somewhere to scribble. */
	now_subseg = 42;    /* Lie for 1st call to subseg_new. */
	subseg_new(SEG_DATA, 0);    /* .data 0 */
	data0_frchainP = frchain_now;
	IsSpecialSection = 0;
	NumberOfSpecialSections = 0;
	if (glevel > 1)
		NumberOfDebugSections = 2;
	else
		NumberOfDebugSections = 0;
}
/* subseg_change()
 * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
 * subsegment. If we are already in the correct subsegment, change nothing.
 * This is used eg as a worker for subseg_new [which does make a new frag_now]
 * and for changing segments after we have read the source. We construct eg
 * fixSs even after the source file is read, so we do have to keep the
 * segment context correct.
 */
static void subseg_change(register segT seg, register int subseg)
{
	now_seg = seg;
	now_subseg = subseg;
	if (seg == SEG_DATA) {
		seg_fix_rootP = &data_fix_root;
	}
	else {
		know(seg == SEG_TEXT);
		seg_fix_rootP = &text_fix_root;
	}
}
/* subseg_new()
 * If you attempt to change to the current subsegment, nothing happens.
 * In:  segT, subsegT code for new subsegment.
 *  frag_now -> incomplete frag for current subsegment.
 *  If frag_now==NULL, then there is no old, incomplete frag, so
 *  the old frag is not closed off.
 * Out: now_subseg, now_seg updated.
 *  Frchain_now points to the (possibly new) struct frchain for this
 *  sub-segment.
 *  Frchain_root updated if needed.
 */
static void subseg_new(register segT seg,register subsegT subseg) /* begin assembly for a new sub-segment */
{
	long tmp;           /* JF for obstack alignment hacking */
	know(seg == SEG_DATA || seg == SEG_TEXT);
	if (seg != now_seg || subseg != now_subseg) {   /* we just changed
						sub-segments */
		register frchainS *frcP;    /* crawl frchain chain */
		register frchainS **lastPP; /* address of last pointer */
		frchainS *newP; /* address of new frchain */
		register fragS *former_last_fragP;
		register fragS *new_fragP;
		if (frag_now) { /* If not bootstrapping. */
			frag_now->fr_fix = obstack_next_free(&frags) - frag_now->fr_literal;
			frag_wane(frag_now);    /* Close off any frag in old subseg. */
		}
		/* It would be nice to keep an obstack for each subsegment, if we
		swap subsegments a lot. Hence we would have much fewer
		frag_wanes(). */
		obstack_finish(&frags);
		/* If we don't do the above, the next object we put on obstack frags
		will appear to start at the fr_literal of the current frag. Also,
		above ensures that the next object will begin on a address that is
		aligned correctly for the engine that runs this program. */
		subseg_change(seg, (int) subseg);
		/* Attempt to find or make a frchain for that sub seg. Crawl along
		chain of frchainSs, begins @ frchain_root. If we need to make a
		frchainS, link it into correct position of chain rooted in
		frchain_root. */
		lastPP = &frchain_root;
		frcP = *(lastPP);
		for (; frcP && (int) (frcP->frch_seg) <= (int) seg; frcP = *(lastPP = &frcP->frch_next)) {
			if ((int) (frcP->frch_seg) == (int) seg && frcP->frch_subseg >= subseg) {
				break;
			}
		}
		/* frcP:      Address of the 1st frchainS in correct segment with
		frch_subseg >= subseg. We want to either use this frchainS, or we
		want to insert a new frchainS just before it.

		If frcP==NULL, then we are at the end of the chain of frchainS-s. A
		NULL frcP means we fell off the end of the chain looking for a
		frch_subseg >= subseg, so we must make a new frchainS.

		If we ever maintain a pointer to the last frchainS in the chain, we
		change that pointer ONLY when frcP==NULL.

		lastPP:    Address of the pointer with value frcP; Never NULL. May
		point to frchain_root.

		*/
		if (!frcP
				|| ((int) (frcP->frch_seg) > (int) seg
					|| frcP->frch_subseg > subseg)) {   /* Kinky logic only
						works with 2 segments. */
			/* This should be the only code that creates a frchainS. */
			newP = (frchainS *) obstack_alloc(&frags, sizeof(frchainS));
			/* obstack_1blank( &frags, sizeof(frchainS), &newP);This begines on a
			   good boundary because a obstack_done() preceeded  it.
			   It implies an obstack_done(), so we expect the next object allocated
			   to begin on a correct boundary. */
			*lastPP = newP;
			newP->frch_next = frcP; /* perhaps NULL */
			(frcP = newP)->frch_subseg = subseg;
			newP->frch_seg = seg;
			newP->frch_last = NULL;
		}
		/* Here with frcP ->ing to the frchainS for subseg. */
		frchain_now = frcP;
		/* Make a fresh frag for the subsegment. We expect this to happen on a
		   correct boundary since it was proceeded by a obstack_done(). */
		tmp = obstack_alignment_mask(&frags);
		obstack_alignment_mask(&frags) = 0;
		frag_now = (fragS *) obstack_alloc(&frags, SIZEOF_STRUCT_FRAG);
		obstack_alignment_mask(&frags) = tmp;
		/* But we want any more chars to come immediately after the structure we
		   just made. */
		new_fragP = frag_now;
		new_fragP->fr_next = NULL;
		/* Append new frag to current frchain. */
		former_last_fragP = frcP->frch_last;
		if (former_last_fragP) {
			know(former_last_fragP->fr_next == NULL);
			know(frchain_now->frch_root);
			former_last_fragP->fr_next = new_fragP;
		}
		else {
			frcP->frch_root = new_fragP;
		}
		frcP->frch_last = new_fragP;
	}                   /* if (changing subsegments) */
}                       /* subseg_new() */

/* symbol_new()
 * Return a pointer to a new symbol. Die if we can't make a new symbol.
 * Fill in the symbol's values. Add symbol to end of symbol chain.
 */
static symbolS *symbol_new(
	char *name,         /* We copy this: OK to alter your copy. */
	unsigned char type, /* One of the types defined in the table seg_N_TYPE */
	valueT value,       /* As in <a.out.h>, often an address. */
						/* Often used as offset from frag address. */
	struct frag *frag)  /* For sy_frag. */
{
	register symbolS *symbolP;
	register char *preserved_copy_of_name;
	register unsigned int name_length;
	char *p;
	name_length = strlen(name) + 1;
	obstack_grow(&notes, name, name_length);
	p = obstack_finish(&notes);
	preserved_copy_of_name = p;
	p = obstack_alloc(&notes, sizeof(symbolS));
	symbolP = (symbolS *) p;
	symbolP->Name = preserved_copy_of_name;
	symbolP->sy_type = type;
	symbolP->SymbolValue = value;
	symbolP->sy_frag = frag;
	symbolP->Next = NULL;    /* End of chain. */
	symbolP->sy_forward = NULL;
	SetFlags(symbolP);
	/* Link to end of symbol chain. */
	if (symbol_lastP) {
		symbol_lastP->Next = symbolP;
	}
	else {
		symbol_rootP = symbolP;
	}
	symbol_lastP = symbolP;
	return (symbolP);
}
/* colon()
 * We have just seen "<name>:". Creates a struct symbol unless it already exists.
 * Gripes if we are redefining a symbol incompatibly (and ignores it).
 */
static void colon(register char *sym_name)
{                       /* just seen "x:" - rattle symbols & frags */
	/* symbol name, as a cannonical string  We copy this string: OK to alter
	later. */
	register symbolS *symbolP;    /* symbol we are working with */

	if ((symbolP = symbol_table_lookup(sym_name)) != NULL) {
		/* Now check for undefined symbols */
		if ((symbolP->sy_type & N_TYPE) == N_UNDF) {
			if (symbolP->SymbolValue == 0) {
				symbolP->sy_frag = frag_now;
				symbolP->SymbolValue = obstack_next_free(&frags) - frag_now->fr_literal;
				know(N_UNDF == 0);
				symbolP->sy_type |= seg_N_TYPE[(int) now_seg];  /* keep N_EXT bit */

				if (symbolP->StorageClass == 0) {
					if (now_seg == SEG_TEXT)
						symbolP->StorageClass = 6;    /* Code label within a module */
					else
						symbolP->StorageClass = 3;

				}
				SetFlags(symbolP);
				if (symbolP->Flags & IS_TEXT) {
					symbolP->SectionNumber = SECTION_TEXT;
				}
				else if (symbolP->Flags & IS_DATA) {
					symbolP->SectionNumber = SECTION_DATA;
				}
			}
			else {
				InternalError(1000);
			}
		}
		else {
			InternalError(1001);
		}
	}
	else {
		symbolP = symbol_new(sym_name,
							(unsigned char) (seg_N_TYPE[(int) now_seg]),
				(valueT) (obstack_next_free(&frags) - frag_now->fr_literal),
							frag_now);
		symbol_table_insert(symbolP);
		if (symbolP->StorageClass == 0) {
			if (now_seg == SEG_TEXT)
				symbolP->StorageClass = 6;  /* Code label within a module */
			else
				symbolP->StorageClass = 3;
		}
		SetFlags(symbolP);
		if (symbolP->Flags & IS_TEXT) {
			symbolP->SectionNumber = SECTION_TEXT;
		}
		else if (symbolP->Flags & IS_DATA) {
			symbolP->SectionNumber = SECTION_DATA;
		}
	}
}

static void SetFlags(symbolS *coffS)
{
	if (now_seg == SEG_TEXT) {
		coffS->Flags |= IS_TEXT;
		coffS->Flags &= ~(IS_DATA | IS_BSS);
	}
	else if (now_seg == SEG_DATA) {
		coffS->Flags |= IS_DATA;
		coffS->Flags &= ~(IS_TEXT | IS_BSS);
	}
}

/*
 *          symbol_find_or_make()
 * If a symbol name does not exist, create it as undefined, and insert
 * it into the symbol table. Return a pointer to it.
 */
static symbolS *symbol_find_or_make(char *name)
{
	register symbolS *symbolP;
	symbolP = symbol_table_lookup(name);
	if (symbolP == NULL) {
		symbolP = symbol_new(name, N_UNDF,  0, &zero_address_frag);
		symbol_table_insert(symbolP);
	}
    return (symbolP);
}

/*
 *          frag_grow()
 *
 * Internal.
 * Try to augment current frag by nchars chars.
 * If there is no room, close of the current frag with a ".fill 0"
 * and begin a new frag. Unless the new frag has nchars chars available
 * do not return. Do not set up any fields of *now_frag.
 */
static void frag_grow(unsigned int nchars)
{
	if (obstack_room(&frags) < nchars) {
		unsigned int n, oldn;
		long oldc;
		frag_wane(frag_now);
		frag_new(0);
		oldn = (unsigned) -1;
		oldc = frags.chunk_size;
		frags.chunk_size = 2 * nchars;
		while ((n = obstack_room(&frags)) < nchars && n < oldn) {
			frag_wane(frag_now);
			frag_new(0);
			oldn = n;
		}
		frags.chunk_size = oldc;
	}
	else return;
	if (obstack_room(&frags) < nchars) {
		InternalError(1003);
	}
}
/* frag_new()
 * Call this to close off a completed frag, and start up a new (empty)
 * frag, in the same subsegment as the old frag.
 * [frchain_now remains the same but frag_now is updated.]
 * Because this calculates the correct value of fr_fix by
 * looking at the obstack 'frags', it needs to know how many
 * characters at the end of the old frag belong to (the maximal)
 * fr_var: the rest must belong to fr_fix.
 * It doesn't actually set up the old frag's fr_var: you may have
 * set fr_var == 1, but allocated 10 chars to the end of the frag:
 * in this case you pass old_frags_var_max_size == 10.
 * Make a new frag, initialising some components. Link new frag at end
 * of frchain_now.
 * input: old_frags_var_max_size Number of chars 
 * (already allocated on obstack frags) in variable_length part of frag.
 */
static void frag_new(int old_frags_var_max_size)
{
	register fragS *former_last_fragP;
	register frchainS *frchP;
	long tmp;
	frag_now->fr_fix = (char *) (obstack_next_free(&frags)) -
		(frag_now->fr_literal) - old_frags_var_max_size;
	/* Fix up old frag's fr_fix. */
	obstack_finish(&frags);
	/* This will align the obstack so the */
	/* next struct we allocate on it will */
	/* begin at a correct boundary. */
	frchP = frchain_now;
	know(frchP);
	former_last_fragP = frchP->frch_last;
	know(former_last_fragP);
	know(former_last_fragP == frag_now);
	obstack_blank(&frags, SIZEOF_STRUCT_FRAG);
	/* We expect this will begin at a correct */
	/* boundary for a struct. */
	tmp = obstack_alignment_mask(&frags);
	obstack_alignment_mask(&frags) = 0; /* Turn off alignment */
	frag_now = (fragS *) obstack_finish(&frags);
	obstack_alignment_mask(&frags) = tmp;   /* Restore alignment */
	/* Just in case we don't get zero'd bytes */
	memset(frag_now,0, SIZEOF_STRUCT_FRAG);
	/* Generally, frag_now->points to an address rounded up to next
	alignment. */
	/* However, characters will add to obstack frags IMMEDIATELY after the
	struct frag, */
	/* even if they are not starting at an alignment address. */
	former_last_fragP->fr_next = frag_now;
	frchP->frch_last = frag_now;
	frag_now->fr_next = NULL;
}                       /* frag_new() */
/* frag_more()
 * Start a new frag unless we have n more chars of room in the current frag.
 * Close off the old frag with a .fill 0.
 * Return the address of the 1st char to write into. Advance
 * frag_now_growth past the new chars.
 */
static char *frag_more(int nchars)
{
	register char *retval;
	frag_grow(nchars);
	retval = obstack_next_free(&frags);
	obstack_blank_fast(&frags, nchars);
	return (retval);
}                       /* frag_more() */
/*
 *          frag_var()
 * Start a new frag unless we have max_chars more chars of room in the current frag.
 * Close off the old frag with a .fill 0.
 *
 * Set up a machine_dependent relaxable frag, then start a new frag.
 * Return the address of the 1st char of the var part of the old frag
 * to write into.
 */
static char *frag_var(
	relax_stateT type,
	int max_chars,
	int var,
	relax_substateT subtype,
	symbolS *symbol,
	long int offset,
	char *opcode)
{
	register char *retval;
	frag_grow(max_chars);
	retval = obstack_next_free(&frags);
	obstack_blank_fast(&frags, max_chars);
	frag_now->fr_var = var;
	frag_now->fr_type = type;
	frag_now->fr_subtype = subtype;
	frag_now->fr_symbol = symbol;
	frag_now->fr_offset = offset;
	frag_now->fr_opcode = opcode;
	frag_new(max_chars);
	return (retval);
}                       /* frag_var() */
/*
 *  frag_wane() Reduce the variable end of a frag to a harmless state.
 */
static void frag_wane(fragS * fragP)
{
	fragP->fr_type = rs_fill;
	fragP->fr_offset = 0;
	fragP->fr_var = 0;
}
/*
 *          frag_align()
 * Make a frag for ".align foo,bar". Call is "frag_align (foo,bar);".
 * Foo & bar are absolute integers.
 * Call to close off the current frag with a ".align", then start a new
 * (so far empty) frag, in the same subsegment as the last frag.
 */
static void frag_align(int alignment, int fill_character)
{
	*(frag_var(rs_align, 1, 1, (relax_substateT) 0, (symbolS *) 0,
			(long) alignment, (char *) 0)) = fill_character;
}


/*
 * Summary of operand().
 * in:  InputPointer points to 1st char of operand, which may
 *  be a space.
 * out: A expressionS. X_seg determines how to understand the rest of the
 *  expressionS.
 *  The operand may have been empty: in this case X_seg == SEG_NONE.
 *  InputPointer -> (next non-blank) char after operand.
 */
static segT operand(register expressionS *expressionP)
{
	register char c;
	register char *name;/* points to name of symbol */
	register symbolS *symbolP;    /* Points to symbol */
	SKIP_WHITESPACE();  /* Leading whitespace is part of operand. */
	c = *InputPointer++;  /* InputPointer -> past char in c. */
	if (isdigit(c)) {
		register valueT number; /* offset or (absolute) value */
		register short int digit;   /* value of next digit in current radix */
		/* invented for humans only, hope */
		/* optimising compiler flushes it! */
		register short int radix;   /* 8, 10 or 16 */
		/* 0 means we saw start of a floating- */
		/* point constant. */
		register short int maxdig;  /* Highest permitted digit value. */
		register int too_many_digits;   /* If we see >= this number of */
		/* digits, assume it is a bignum. */
		register char *digit_2; /* -> 2nd digit of number. */
		int small;      /* TRUE if fits in 32 bits. */
		if (c == '0') { /* non-decimal radix */
			if ((c = *InputPointer++) == 'x' || c == 'X') {
				c = *InputPointer++;  /* read past "0x" or "0X" */
				maxdig = radix = 16;
				too_many_digits = 9;
			}
			else {
				/* If it says '0f' and the line ends or it DOESN'T look like
				a floating point #, its a local label ref.  DTRT */
				if (c == 'f' && (!*InputPointer ||
							(!index("+-.0123456789", *InputPointer)))) {
					maxdig = radix = 10;
					too_many_digits = 11;
					c = '0';
					InputPointer -= 2;
				}
				else {  /* By elimination, assume octal radix. */
					radix = 8;
					maxdig = 10;    /* Un*x sux. Compatibility. */
					too_many_digits = 11;
				}
			}
			/* c == char after "0" or "0x" or "0X" or "0e" etc. */
		}
		else {
			maxdig = radix = 10;
			too_many_digits = 11;
		}
		if (radix) {    /* Fixed-point integer constant. */
/*
 * Most numbers fit into 32 bits, and we want this case to be fast.So we pretend it
   will fit into 32 bits. If, after making up a 32 bit number, we realise that we
   have scanned more digits than comfortably fit into 32 bits, we re-scan the digits
   coding them into a bignum. For decimal and octal numbers we are conservative:
   some numbers may be assumed bignums when in fact they do fit into 32 bits.Numbers
   of any radix can have excess leading zeros: we strive to recognise this and cast
   them back into 32 bits. The number we are looking for is expected to be positive,
   but if it fits into 32 bits as an unsigned number, we let it be a 32-bit
   number. The cavalier approach is for speed in ordinary cases.
 */
			digit_2 = InputPointer;
			for (number = 0; (digit = hex_value[c]) < maxdig; c = *InputPointer++) {
				number = number * radix + digit;
			}
			/* C contains character after number. */
			/* InputPointer -> char after C. */
			small = InputPointer - digit_2 < too_many_digits;
			if (!small) {
				InternalError(1004);
			}
			/* Here with number, in correct radix. c is the next char. Note
			that unlike Un*x, we allow "011f" "0x9f" to both mean the same
			as the (conventional) "9f". This is simply easier than checking
			for strict canonical form. Syntax sux! */
			expressionP->X_add_number = number;
			expressionP->X_seg = SEG_ABSOLUTE;
			InputPointer--;   /* Restore following character. */
		}               /* (If integer constant) */
		else {          /* InputPointer -> */
			InternalError(1005);
		}               /* if (not floating-point constant) */
	}
	else if (c == '.' && !is_part_of_name(*InputPointer)) {
		extern struct obstack frags;
		/* JF:  '.' is pseudo symbol with value of current location in
		current segment. . . */
		symbolP = symbol_new("L0\001",
							(unsigned char) (seg_N_TYPE[(int) now_seg]),
				(valueT) (obstack_next_free(&frags) - frag_now->fr_literal),
							frag_now);
		expressionP->X_add_number = 0;
		expressionP->X_add_symbol = symbolP;
		expressionP->X_seg = now_seg;
	}
	else if (is_name_beginner(c)) { /* here if did not begin with a digit */
		/* Identifier begins here. This is kludged for speed, so code is
		repeated. */
		name = --InputPointer;
		c = get_symbol_end();
		symbolP = symbol_table_lookup(name);
		if (symbolP) {
			/* If we have an absolute symbol, then we know it's value now. */
			register segT seg;
			seg = N_TYPE_seg[(int) symbolP->sy_type & N_TYPE];
			if ((expressionP->X_seg = seg) == SEG_ABSOLUTE) {
				expressionP->X_add_number = symbolP->SymbolValue;
			}
			else {
				expressionP->X_add_number = 0;
				expressionP->X_add_symbol = symbolP;
			}
		}
		else {
			expressionP->X_add_symbol
				= symbolP
				= symbol_new(name, N_UNDF,  0, &zero_address_frag);
			expressionP->X_add_number = 0;
			expressionP->X_seg = SEG_UNKNOWN;
			symbol_table_insert(symbolP);
		}
		*InputPointer = c;
		expressionP->X_subtract_symbol = NULL;
	}
	else if (c == '(') {/* didn't begin with digit & not a name */
		(void) expression(expressionP);
		/* Expression() will pass trailing whitespace */
		if (*InputPointer++ != ')') {
			InternalError(3061);
			InputPointer--;
		}
		/* here with InputPointer -> char after "(...)" */
	}
	else if (c == '~' || c == '-') {    /* unary operator: hope for
						SEG_ABSOLUTE */
		switch (operand(expressionP)) {
		case SEG_ABSOLUTE:
			/* InputPointer -> char after operand */
			if (c == '-') {
				expressionP->X_add_number = -expressionP->X_add_number;
/*
 * Notice: '-' may  overflow: no warning is given. This is compatible
 * with other people's assemblers. Sigh.
 */
			}
			else {
				expressionP->X_add_number = ~expressionP->X_add_number;
			}
			break;
		case SEG_TEXT:
		case SEG_DATA:
		case SEG_BSS:
		case SEG_PASS1:
		case SEG_UNKNOWN:
			if (c == '-') {
				expressionP->X_subtract_symbol = expressionP->X_add_symbol;
				expressionP->X_add_symbol = 0;
				expressionP->X_seg = SEG_DIFFERENCE;
				break;
			}
		default:       /* unary on non-absolute is unsuported */
			InternalError(3062);
			break;
			/* Expression undisturbed from operand(). */
		}
	}
	else {
		/* can't imagine any other kind of operand */
		expressionP->X_seg = SEG_NONE;
		InputPointer--;
	}
/*
 * It is more 'efficient' to clean up the expressions when they are created.
 * Doing it here saves lines of code.
 */
	clean_up_expression(expressionP);
	SKIP_WHITESPACE();  /* -> 1st char after operand. */
	know(*InputPointer != ' ');
	return (expressionP->X_seg);
}                       /* operand */
/* Internal. Simplify a struct expression for use by AsmExpression()
 * In:  address of a expressionS.
 *  The X_seg field of the expressionS may only take certain values.
 *  Now, we permit SEG_PASS1 to make code smaller & faster.
 *  Elsewise we waste time special-case testing. Sigh. Ditto SEG_NONE.
 * Out: expressionS may have been modified:
 *  'foo-foo' symbol references cancelled to 0,
 *      which changes X_seg from SEG_DIFFERENCE to SEG_ABSOLUTE;
 *  Unused fields zeroed to help AsmExpression().
 */
static void clean_up_expression(register expressionS *expressionP)
{
	switch (expressionP->X_seg) {
	case SEG_NONE:
	case SEG_PASS1:
		expressionP->X_add_symbol = NULL;
		expressionP->X_subtract_symbol = NULL;
		expressionP->X_add_number = 0;
		break;
	case SEG_BIG:
	case SEG_ABSOLUTE:
		expressionP->X_subtract_symbol = NULL;
		expressionP->X_add_symbol = NULL;
		break;
	case SEG_TEXT:
	case SEG_DATA:
	case SEG_BSS:
	case SEG_UNKNOWN:
		expressionP->X_subtract_symbol = NULL;
		break;
	case SEG_DIFFERENCE:
		/* It does not hurt to 'cancel' NULL==NULL when comparing symbols for
		'eq'ness. It is faster to re-cancel them to NULL than to check for
		this special case. */
		if (expressionP->X_subtract_symbol == expressionP->X_add_symbol
				|| (expressionP->X_subtract_symbol
					&& expressionP->X_add_symbol
					&& expressionP->X_subtract_symbol->sy_frag == expressionP->X_add_symbol->sy_frag
					&& expressionP->X_subtract_symbol->SymbolValue == expressionP->X_add_symbol->SymbolValue)) {
			expressionP->X_subtract_symbol = NULL;
			expressionP->X_add_symbol = NULL;
			expressionP->X_seg = SEG_ABSOLUTE;
		}
		break;
	default:
		InternalError(1103);
		break;
	}
}
/*
 *          expr_part ()
 * Internal. Made a function because this code is used in 2 places.
 * Generate error or correct X_?????_symbol of expressionS.
 * symbol_1 += symbol_2 ... well ... sort of.
 */
static segT expr_part(symbolS **symbol_1_PP,symbolS * symbol_2_P)
{
	segT return_value;
	know((*symbol_1_PP) == NULL
		|| ((*symbol_1_PP)->sy_type & N_TYPE) == N_TEXT
		|| ((*symbol_1_PP)->sy_type & N_TYPE) == N_DATA
		|| ((*symbol_1_PP)->sy_type & N_TYPE) == N_BSS
		|| ((*symbol_1_PP)->sy_type & N_TYPE) == N_UNDF
		);
	know(symbol_2_P == NULL
		|| (symbol_2_P->sy_type & N_TYPE) == N_TEXT
		|| (symbol_2_P->sy_type & N_TYPE) == N_DATA
		|| (symbol_2_P->sy_type & N_TYPE) == N_BSS
		|| (symbol_2_P->sy_type & N_TYPE) == N_UNDF
		);
	if (*symbol_1_PP) {
		if (((*symbol_1_PP)->sy_type & N_TYPE) == N_UNDF) {
			if (symbol_2_P) {
				return_value = SEG_PASS1;
				*symbol_1_PP = NULL;
			}
			else {
				know(((*symbol_1_PP)->sy_type & N_TYPE) == N_UNDF);
				return_value = SEG_UNKNOWN;
			}
		}
		else {
			if (symbol_2_P) {
				if ((symbol_2_P->sy_type & N_TYPE) == N_UNDF) {
					*symbol_1_PP = NULL;
					return_value = SEG_PASS1;
				}
				else {
					/* {seg1} - {seg2} */
					InternalError(1063);
				}
			}
			else {
				return_value = N_TYPE_seg[(*symbol_1_PP)->sy_type & N_TYPE];
			}
		}
	}
	else {              /* (* symbol_1_PP) == NULL */
		if (symbol_2_P) {
			*symbol_1_PP = symbol_2_P;
			return_value = N_TYPE_seg[(symbol_2_P)->sy_type & N_TYPE];
		}
		else {
			*symbol_1_PP = NULL;
			return_value = SEG_ABSOLUTE;
		}
	}
	know(return_value == SEG_ABSOLUTE
		|| return_value == SEG_TEXT
		|| return_value == SEG_DATA
		|| return_value == SEG_BSS
		|| return_value == SEG_UNKNOWN
		|| return_value == SEG_PASS1
		);
	know((*symbol_1_PP) == NULL
	|| ((*symbol_1_PP)->sy_type & N_TYPE) == seg_N_TYPE[(int) return_value]);
	return (return_value);
}                       /* expr_part() */
/* Expression parser. */
/*
 * We allow an empty expression, and just assume (absolute,0) silently.
 * Unary operators and parenthetical expressions are treated as operands.
 * As usual, Q==quantity==operand, O==operator, X==expression mnemonics.
 * We used to do a aho/ullman shift-reduce parser, but the logic got so
 * warped that I flushed it and wrote a recursive-descent parser instead.
 * Now things are stable, would anybody like to write a fast parser?
 * Most expressions are either register (which does not even reach here)
 * or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common.
 * So I guess it doesn't really matter how inefficient more complex expressions
 * are parsed.
 * After AsmExpression(RANK,resultP) InputPointer -> operator of rank <= RANK.
 * Also, we have consumed any leading or trailing spaces (operand does that)
 * and done all intervening operators.
 */
typedef enum {
	O_illegal,          /* (0)  what we get for illegal op */
	O_multiply,         /* (1)  * */
	O_divide,           /* (2)  / */
	O_modulus,          /* (3)  % */
	O_left_shift,       /* (4)  < */
	O_right_shift,      /* (5)  > */
	O_bit_inclusive_or, /* (6)  | */
	O_bit_or_not,       /* (7)  ! */
	O_bit_exclusive_or, /* (8)  ^ */
	O_bit_and,          /* (9)  & */
	O_add,              /* (10) + */
	O_subtract          /* (11) - */
}
operatorT;
#undef __
#define __ O_illegal
static const operatorT op_encoding[256] = { /* maps ASCII -> operators */
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __,
	__, __, O_multiply, O_add, __, O_subtract, __, O_divide,
	__, __, __, __, __, __, __, __,
	__, __, __, __, O_left_shift, __, O_right_shift, __,
	__, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __,
	__, __, __, __, __, __, O_bit_exclusive_or, __,
	__, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __,
	__, __, __, __, O_bit_inclusive_or, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __,
	__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __
};
/*
 *  Rank    Examples
 *  0   operand, (expression)
 *  1   + -
 *  2   & ^ ! |
 *  3   * / % < >
 */
static const operator_rankT
op_rank[] = {0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1};
static segT             /* Return resultP -> X_seg. */
AsmExpression(register operator_rankT rank,   /* Larger # is higher rank. */
	register expressionS *resultP)  /* Deliver result here. */
{
	expressionS right;
	register operatorT op_left;
	register char c_left;   /* 1st operator character. */
	register operatorT op_right;
	register char c_right;
	know(rank >= 0);
	(void) operand(resultP);
	know(*InputPointer != ' ');   /* Operand() gobbles spaces. */
	c_left = *InputPointer;   /* Potential operator character. */
	op_left = op_encoding[c_left];
	while (op_left != O_illegal && op_rank[(int) op_left] > rank) {
		InputPointer++;   /* -> after 1st character of operator. */
		/* Operators "<<" and ">>" have 2 characters. */
		if (*InputPointer == c_left && (c_left == '<' || c_left == '>')) {
			InputPointer++;
		}               /* -> after operator. */
		if (SEG_NONE == AsmExpression(op_rank[(int) op_left], &right)) {
			InternalError(1066);
		}
		know(*InputPointer != ' ');
		c_right = *InputPointer;
		op_right = op_encoding[c_right];
		if (*InputPointer == c_right && (c_right == '<' || c_right == '>')) {
			InputPointer++;
		}               /* -> after operator. */
		know((int) op_right == 0
			|| op_rank[(int) op_right] <= op_rank[(int) op_left]);
		/* InputPointer -> after right-hand quantity. */
		/* left-hand quantity in resultP */
		/* right-hand quantity in right. */
		/* operator in op_left. */
		if (resultP->X_seg == SEG_PASS1 || right.X_seg == SEG_PASS1) {
			resultP->X_seg = SEG_PASS1;
		}
		else {
			if (op_left == O_subtract) {
				/* Convert - into + by exchanging symbols and negating
				number. I know -infinity can't be negated in 2's
				complement: but then it can't be subtracted either. This
				trick does not cause any further inaccuracy. */
				register symbolS *symbolP;
				right.X_add_number = -right.X_add_number;
				symbolP = right.X_add_symbol;
				right.X_add_symbol = right.X_subtract_symbol;
				right.X_subtract_symbol = symbolP;
				if (symbolP) {
					right.X_seg = SEG_DIFFERENCE;
				}
				op_left = O_add;
			}
			if (op_left == O_add) {
				segT seg1;
				segT seg2;
				know(resultP->X_seg == SEG_DATA
					|| resultP->X_seg == SEG_TEXT
					|| resultP->X_seg == SEG_BSS
					|| resultP->X_seg == SEG_UNKNOWN
					|| resultP->X_seg == SEG_DIFFERENCE
					|| resultP->X_seg == SEG_ABSOLUTE
					|| resultP->X_seg == SEG_PASS1
					);
				know(right.X_seg == SEG_DATA
					|| right.X_seg == SEG_TEXT
					|| right.X_seg == SEG_BSS
					|| right.X_seg == SEG_UNKNOWN
					|| right.X_seg == SEG_DIFFERENCE
					|| right.X_seg == SEG_ABSOLUTE
					|| right.X_seg == SEG_PASS1
					);
				clean_up_expression(&right);
				clean_up_expression(resultP);
				seg1 = expr_part(&resultP->X_add_symbol, right.X_add_symbol);
				seg2 = expr_part(&resultP->X_subtract_symbol, right.X_subtract_symbol);
				if (seg1 == SEG_PASS1 || seg2 == SEG_PASS1) {
					need_pass_2 = TRUE;
					resultP->X_seg = SEG_PASS1;
				}
				else if (seg2 == SEG_ABSOLUTE)
					resultP->X_seg = seg1;
				else if (seg1 != SEG_UNKNOWN
						&& seg1 != SEG_ABSOLUTE
						&& seg2 != SEG_UNKNOWN
						&& seg1 != seg2) {
					know(seg2 != SEG_ABSOLUTE);
					know(resultP->X_subtract_symbol);
					know(seg1 == SEG_TEXT || seg1 == SEG_DATA || seg1 == SEG_BSS);
					know(seg2 == SEG_TEXT || seg2 == SEG_DATA || seg2 == SEG_BSS);
					know(resultP->X_add_symbol);
					know(resultP->X_subtract_symbol);
					InternalError(1067);
				}
				else
					resultP->X_seg = SEG_DIFFERENCE;
				resultP->X_add_number += right.X_add_number;
				clean_up_expression(resultP);
			}
			else {      /* Not +. */
				if (resultP->X_seg == SEG_UNKNOWN || right.X_seg == SEG_UNKNOWN) {
					resultP->X_seg = SEG_PASS1;
					need_pass_2 = TRUE;
				}
				else {
					resultP->X_subtract_symbol = NULL;
					resultP->X_add_symbol = NULL;
					/* Will be SEG_ABSOLUTE. */
					if (resultP->X_seg != SEG_ABSOLUTE || right.X_seg != SEG_ABSOLUTE) {
						InternalError(1068);
					}
					else {
						switch (op_left) {
						case O_bit_inclusive_or:
							resultP->X_add_number |= right.X_add_number;
							break;
						case O_modulus:
							if (right.X_add_number) {
								resultP->X_add_number %= right.X_add_number;
							}
							else {
								InternalError(1069);
							}
							break;
						case O_bit_and:
							resultP->X_add_number &= right.X_add_number;
							break;
						case O_multiply:
							resultP->X_add_number *= right.X_add_number;
							break;
						case O_divide:
							if (right.X_add_number) {
								resultP->X_add_number /= right.X_add_number;
							}
							else {
								InternalError(1069); /* division par zero */
							}
							break;
						case O_left_shift:
							resultP->X_add_number <<= right.X_add_number;
							break;
						case O_right_shift:
							resultP->X_add_number >>= right.X_add_number;
							break;
						case O_bit_exclusive_or:
							resultP->X_add_number ^= right.X_add_number;
							break;
						case O_bit_or_not:
							resultP->X_add_number |= ~right.X_add_number;
							break;
						default:
							InternalError(1104);
							break;
						}   /* switch(operator) */
					}
				}       /* If we have to force need_pass_2. */
			}           /* If operator was +. */
		}               /* If we didn't set need_pass_2. */
		op_left = op_right;
	}                   /* While next operator is >= this rank. */
	return (resultP->X_seg);
}
/* get_symbol_end()
 * Assume InputPointer is at start of symbol name.
 * Advance InputPointer past symbol name.
 * Turn that character into a '\0', returning its former value.
 * This allows a string compare of the symbol name.
 * There will always be a char following symbol name, because all good
 * lines end in end-of-line.
 */
static char get_symbol_end()
{
	register char c;
	while (is_part_of_name(c = *InputPointer++));
	*--InputPointer = 0;
	return (c);
}
char *file_name;
/*
 * We expect the following sanitation has already been done.
 * No comments, reduce a comment to a space.
 * Reduce a tab to a space unless it is 1st char of line.
 * All multiple tabs and spaces collapsed into 1 char. Tab only
 * legal if 1st char of line.
 * # line file statements converted to .line x;.file y; statements.
 * Escaped newlines at end of line: remove them but add as many newlines
 * to end of statement as you removed in the middle, to synch line numbers.
 */
#define BEFORE_STRING ("\n")
#define AFTER_STRING ("\0") /* bcopy of 0 chars might choke. */
#define BEFORE_SIZE (1)
#define AFTER_SIZE  (1)
static char *buffer_start;  /* -> 1st char of full buffer area. */
static char *partial_where; /* -> after last full line in buffer. */
static int partial_size;/* >=0. Number of chars in partial line in buffer. */
/* Because we need AFTER_STRING just after last full line, it clobbers 1st part of
   partial line. So we preserve 1st part of partial line here. */
static char save_source[AFTER_SIZE];
/* What is the largest size buffer that input_file_give_next_buffer()
could return to us? */
static int buffer_length;
/*
We must track the physical file and line number for error messages.
We also track a "logical" file and line number corresponding to lcc
source line numbers.
*/

static int physical_input_line, logical_input_line;
static void InitAsmInput(void)
{
	buffer_length = BUFFER_SIZE;
	buffer_start = xmalloc((long) (BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE));
	bcopy(BEFORE_STRING, buffer_start, (int) BEFORE_SIZE);
	/* Line number things. */
	logical_input_line = 0;
}
/* Return start of caller's part of buffer. */
static char *SetObjFileName(char *filename)
{
	char *p;
	file_name = filename;
	physical_input_line = 0;
	partial_size = 0;
	OutputFileName = xmalloc(256);
	p = strrchr(filename,'\\');
	if (p == NULL) p = filename;
	else p++;
	strcpy(OutputFileName,p);
	p = strrchr(OutputFileName,'.');
	if (p) *p = 0;
	else p = OutputFileName + strlen(filename);
	strcat(p,".obj");
	if (!strcmp(OutputFileName,filename)) {
		InternalError(1114); /* input and output file names are the same? */
	}
	return (buffer_start + BEFORE_SIZE);
}
static void bump_line_counters(void)
{
	++physical_input_line;
	++logical_input_line;
}

/* Nonzero if we've hit a 'bad error', and should not write an obj file,
   and exit with a nonzero error code */
static int bad_error = 0;
void InternalError(int err)
{
	if (err < 2000) {
		fprintf(stderr,"Internal error %d\t",err);
	}
	else if (err < 3000) {
		fprintf(stderr,"Internal error %d\t",err);
		bad_error++;
	}
	else if (err < 4000) {
		fprintf(stderr,"Warning %d\t",err);
	}
	printf("line %d\n",physical_input_line);
	if (err < 2000) exit(err);
}
void WriteError(void)
{
	fprintf(stderr,"Write error. Disk Full?\n");
	exit(1);
}
/* obstack.c - subroutines used implicitly by object stack macros */
/* Determine default alignment.  */
struct fooalign {
	char x;
	double d;
};
#define DEFAULT_ALIGNMENT ((char *)&((struct fooalign *) 0)->d - (char *)0)
/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
   But in fact it might be less smart and round addresses to as much as
   DEFAULT_ROUNDING.  So we prepare for it to do that.  */
#define DEFAULT_ROUNDING 4
/* When we copy a long block of data, this is the unit to do it with. */
#ifndef COPYING_UNIT
#define COPYING_UNIT int
#endif
static void _obstack_begin(struct obstack * h, int size, int alignment, void *(*chunkfun) (int), void (*freefun) (void *))
{
	register struct _obstack_chunk *chunk;  /* points to new chunk */
	if (alignment == 0)
		alignment = DEFAULT_ALIGNMENT;
	if (size == 0) {
		/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. Use the
		values for range checking, because if range checking is off, the
		extra bytes won't be missed terribly, but if range checking is on
		and we used a larger request, a whole extra 4096 bytes would be
		allocated.

		These number are irrelevant to the new GNU malloc.  I suspect it is
		less sensitive to the size of the request.  */
		int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
					+ 4 + DEFAULT_ROUNDING - 1)
					& ~(DEFAULT_ROUNDING - 1));
		size = 4096 - extra;
	}
	h->chunkfun = (struct _obstack_chunk * (*) (int)) chunkfun;
	h->freefun = freefun;
	h->chunk_size = size;
	h->alignment_mask = alignment - 1;
	chunk = h->chunk = (*h->chunkfun) (h->chunk_size);
	h->next_free = h->object_base = chunk->contents;
	h->chunk_limit = chunk->limit
		= (char *) chunk + h->chunk_size;
	chunk->prev = 0;
}
/* Allocate a new current chunk for the obstack *H on the assumption that LENGTH
   bytes need to be added to the current object, or a new object of length LENGTH
   allocated. Copies any partial object from the end of the old chunk to the
   beginning of the new one.
*/
static void _obstack_newchunk(struct obstack * h, int length)
{
	register struct _obstack_chunk *old_chunk = h->chunk;
	register struct _obstack_chunk *new_chunk;
	register long new_size;
	register int obj_size = h->next_free - h->object_base;
	register int i;
	int already;
	/* Compute size for new chunk.  */
	new_size = (obj_size + length) + (obj_size >> 3) + 100;
	if (new_size < h->chunk_size)
		new_size = h->chunk_size;
	/* Allocate and initialize the new chunk.  */
	new_chunk = h->chunk = (*h->chunkfun) (new_size);
	new_chunk->prev = old_chunk;
	new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
	/* Move the existing object to the new chunk. Word at a time is fast and
	is safe if the object is sufficiently aligned.  */
	if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) {
		for (i = obj_size / sizeof(COPYING_UNIT) - 1;
				i >= 0; i--)
			((COPYING_UNIT *) new_chunk->contents)[i]
				= ((COPYING_UNIT *) h->object_base)[i];
		/* We used to copy the odd few remaining bytes as one extra
		COPYING_UNIT, but that can cross a page boundary on a machine which
		does not do strict alignment for COPYING_UNITS.  */
		already = obj_size / sizeof(COPYING_UNIT) * sizeof(COPYING_UNIT);
	}
	else
		already = 0;
	/* Copy remaining bytes one by one.  */
	for (i = already; i < obj_size; i++)
		new_chunk->contents[i] = h->object_base[i];
	/* If the object just copied was the only data in OLD_CHUNK, free that
	chunk and remove it from the chain.  */
	if (h->object_base == old_chunk->contents) {
		new_chunk->prev = old_chunk->prev;
		(*h->freefun) (old_chunk);
	}
	h->object_base = new_chunk->contents;
	h->next_free = h->object_base + obj_size;
}
/*
 * In: a character.
 * Out: TRUE if this character ends a line.
 */
#define _ (0)
static const char is_end_of_line[256] = {
	_, _, _, _, _, _, _, _, _, _, 99, _, _, _, _, _,    /* @abcdefghijklmno */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, 99, _, _, _, _,    /* 0123456789:;<=>? */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* */
	_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _  /* */
};
#undef _
static char *hash_insert(struct HASH_LIST * where, char *name, char *data)
{
	struct HASH_LIST *rvp, *result,**slots;
	register int h;
	register char *p = name;
	int len;
	
	for (h = 0; *p;)
		h = (h << 2) ^ *p++;
	h &= HASHSIZE-1;
	slots = (struct HASH_LIST **)where->Data;
	rvp = slots[h];
	len = p - name;
	while (rvp) {
		if (rvp->len == len && !strcmp(name, rvp->Name)) return(rvp->Name);
		rvp = rvp->Next;
	}
	rvp = slots[h];
	result = (struct HASH_LIST *)allocate(sizeof(struct HASH_LIST),4);
	result->Next = rvp;
	result->Name = name;
	result->len = len;
	slots[h] = result;
	result->Data = data;
	return ("");
}
static char *hash_find(struct HASH_LIST * w, char *n)
{
	register struct HASH_LIST *rvp;
	register int h;
	register char *p = n;

	for (h = 0; *p;)
		h = (h << 2) ^ *p++;
	rvp = ((struct HASH_LIST **)w->Data)[h & (HASHSIZE-1)];
	h = p - n;
	while (rvp) {
		if ((rvp->len == h) && !strcmp(n, rvp->Name)) return(rvp->Data);
		rvp = rvp->Next;
	}
	return (NULL);
}
static struct HASH_LIST *hash_new(void)
{
	struct HASH_LIST *r;
	r = (struct HASH_LIST *) allocate(sizeof(struct HASH_LIST),4);
	r->Name = xmalloc(1);
	r->Data = xmalloc((HASHSIZE+1)*sizeof(struct HASH_LIST *));
	return (r);
}
static void symbol_table_insert(symbolS *symbolP)
{
	struct HASH_LIST *rvp;
	struct HASH_LIST *result,**slots;
	register int h;
	register char *p = symbolP->Name;
	char *n = p;

	for (h = 0; *p;)
		h = (h << 2) ^ *p++;
	h &= HASHSIZE-1;
	slots = (struct HASH_LIST **)sy_hash->Data;
	rvp = slots[h];
	result = (struct HASH_LIST *) allocate(sizeof(struct HASH_LIST),4);
	result->Next = rvp;
	result->Name = n;
	result->len = p - n;
	result->Data = (char *)symbolP;
	slots[h] = result;
	return;
}
/* set up pseudo-op tables */
static struct hash_control *po_hash = NULL; /* use before set up: NULL->
						address error */
static symbolS *CurrentFunctionSymbol;

static char *input_buffer(char *inbuffer,int len)
{
	register char *limit;   /* -> just after last char of buffer. */
	if (partial_size) {
		bcopy(partial_where, buffer_start + BEFORE_SIZE, (int) partial_size);
		bcopy(save_source, buffer_start + BEFORE_SIZE, (int) AFTER_SIZE);
	}
	memcpy(buffer_start + BEFORE_SIZE + partial_size,inbuffer,len);
	limit = buffer_start + BEFORE_SIZE + partial_size + len;
	if (len) {
		register char *p;   /* Find last newline. */
		for (p = limit; *--p != '\n';) {
		}
		++p;
		if (p <= buffer_start + BEFORE_SIZE) {
			InternalError(1006);
		}
		partial_where = p;
		partial_size = limit - p;
		bcopy(partial_where, save_source, (int) AFTER_SIZE);
		bcopy(AFTER_STRING, partial_where, (int) AFTER_SIZE);
	}
	else {
		partial_where = 0;
		if (partial_size > 0) {
			InternalError(2070);
		}
	}
	return (partial_where);
}

/* AsmReadBuffer()
 * File has already been opened, and will be closed by our caller.
 * We read the file, putting things into a web that
 * represents what we have been reading.
 */
void AsmReadBuffer(char *buffer,int len)
{
	register char c;
	register char *s;   /* string of symbol, '\0' appended */
	pseudo_typeS *pop;

	buffer_limit = input_buffer(buffer,len);   /* We have
						another line to parse. */
	know(buffer_limit[-1] == '\n'); /* Must have a sentinel. */
	InputPointer = buffer_start + BEFORE_SIZE;
contin:
	while (InputPointer < buffer_limit) { /* We have more of this
						buffer to parse. */
		/* We now have InputPointer -> 1st char of next line. If
		InputPointer [-1] == '\n' then we just scanned another
		line: so bump line counters. */
		if (InputPointer[-1] == '\n') {
			bump_line_counters();
		}
		/* We are at the begining of a line, or similar place. We expect
			a well-formed assembler statement. A "symbol-name:" is a
			statement. */
		while ((c = *InputPointer++) == '\t' || c == ' ') {
			;
		}
		know(c != ' '); /* No further leading whitespace. */
		/* c is the 1st significant character. InputPointer points
			after that character. */
		if (c == '\n') {
			continue;
		}
		if (c == ';') {
			while (*InputPointer != '\n')
				InputPointer++;
				continue;
		}
		if (is_name_beginner(c)) {  /* want user-defined label or
						pseudo/opcode */
			s = --InputPointer;
			while (is_part_of_name(c = *InputPointer++));
			*--InputPointer = 0;
			/* C is character after symbol. That character's place in the
				input line is now '\0'. S points to the beginning of the
				symbol. [In case of pseudo-op, s -> '.'.]
				InputPointer -> '\0' where c was. */
			if (c == ':') {
				colon(s);   /* user-defined label */
				*InputPointer++ = ':';    /* Put ':' back for error
						messages' sake. */
					/* InputPointer -> after ':'. */
				SKIP_WHITESPACE();
			}
			else {  /* expect pseudo-op or machine instruction */
				if (*s == '.') {
					/* PSEUDO - OP.
						WARNING: c has next char, which may be end-of-line.
						We lookup the pseudo-op table with s+1 because we
						already know that the pseudo-op begins with a '.'. */
					pop = (pseudo_typeS *) hash_find(po_hash, s + 1);
						/* Print the error msg now, while we still can */
					if (!pop) {
						InternalError(1010);
					}
					/* Put it back for error messages etc. */
					*InputPointer = c;
					/* The following skip of whitespace is compulsory. */
					/* A well shaped space is sometimes all that
					seperates keyword from operands. */
					if (c == ' ' || c == '\t') {    /* Skip seperator
					after keyword. */
						InputPointer++;
					}
					/* Input_line is restored. InputPointer -> 1st
						non-blank char after pseudo-operation. */
					if (!pop) {
						ignore_rest_of_line();
						break;
					}
					else
						(*pop->poc_handler)();
				}
				else {  /* machine instruction */
					/* WARNING: c has char, which may be end-of-line. */
					/* Also: InputPointer -> `\0` where c was. */
					*InputPointer = c;
					while (!is_end_of_line[*InputPointer]) {
						InputPointer++;
					}
					c = *InputPointer;
					*InputPointer = '\0';
					Asm386Instruction(s); /* Assemble 1 instruction. */
					*InputPointer++ = c;
					/* We resume loop AFTER the end-of-line from this
						instruction */
				}   /* if (*s=='.') */
			}       /* if c==':' */
			continue;
		}           /* if (is_name_beginner(c) */
		if (is_end_of_line[c]) {    /* empty statement */
			continue;
		}
		if (isdigit(c)) {   /* local label  ("4:") unsupported */
			InternalError(1011);
			InputPointer--;
			ignore_rest_of_line();
			continue;
		}
		{
			int i;
			for (i=0; i<40;i++) putchar(InputPointer[i]);
			putchar('\n');
		}
		InternalError(1012);
		ignore_rest_of_line();
	}               /* while (InputPointer<buffer_limit ) */
	if (old_buffer) {
		bump_line_counters();
		if (old_input == 0)
			return;
		buffer = old_buffer;
		InputPointer = old_input;
		buffer_limit = old_limit;
		old_buffer = 0;
		goto contin;
	}
}                       /* AsmReadBuffer() */

static void s_byte(void)
{
	cons(1);
}
static void s_int(void)
{
	cons(4);
}

static void s_short(void)
{
	cons(2);
}

static void s_align(void)
{
	register int temp;
	register long int temp_fill;
	temp = get_absolute_expression();
#define MAX_ALIGNMENT (15)
	if (temp > MAX_ALIGNMENT) {
		InternalError(1013);
	}
	else if (temp < 0) {
		InternalError(2014);
		temp = 0;
	}
	if (*InputPointer == ',') {
		InputPointer++;
		temp_fill = get_absolute_expression();
	}
	else
		temp_fill = 0;
	/* Only make a frag if we HAVE to. . . */
	if (temp && !need_pass_2)
		frag_align(temp, (int) temp_fill);
	demand_empty_rest_of_line();
}
static void s_comm(void)
{
	register char *name, *sname;
	register char c;
	register char *p;
	register int temp;
	register symbolS *symbolP;

	name = InputPointer;
	c = get_symbol_end();
	/* just after name is now '\0' */
	p = InputPointer;
	*p = c;
	SKIP_WHITESPACE();
	if (*InputPointer != ',') {
		InternalError(2015);
		ignore_rest_of_line();
		return;
	}
	InputPointer++;   /* skip ',' */
	if ((temp = get_absolute_expression()) < 0) {
		InternalError(1064);
	}
	*p = 0;
	symbolP = symbol_find_or_make(name);
	sname = xmalloc(strlen(name) + 1);
	strcpy(sname, name);
	*p = c;
	if (symbolP->SymbolValue) {
		if (symbolP->SymbolValue != (unsigned) temp) {
			InternalError(1071);
		}
	}
	else {
		symbolP->SymbolValue = temp;
		symbolP->sy_type |= N_EXT;
	}
	MakeBssSymbol(symbolP,temp,0);
	know(symbolP->sy_frag == &zero_address_frag);
	free(sname);
	demand_empty_rest_of_line();
}
static void s_data(void)
{
	register int temp;
	temp = get_absolute_expression();
	subseg_new(SEG_DATA, (subsegT) temp);
	demand_empty_rest_of_line();
}
static char fbuf[256];
static void s_file(void)
{
	int length;
	/* Some assemblers tolerate immediately following '"' */
	SKIP_WHITESPACE();
	memset(fbuf, 0, 256);
	if (*InputPointer == '"')
		InputPointer++;
	length = 0;
	while (*InputPointer != '"') {
		fbuf[length] = *InputPointer++;
		length++;
		if (length > 254)
			break;
	}
	SourceFileName = fbuf;
	if (*InputPointer == '"')
		InputPointer++;
	demand_empty_rest_of_line();
}
static void s_globl(void)
{
	register char *name;
	register int c;
	register symbolS *symbolP;
	
	do {
		name = InputPointer;
		c = get_symbol_end();
		symbolP = symbol_find_or_make(name);
		symbolP->StorageClass = 2;  /* external symbol */
		*InputPointer = c;
		SKIP_WHITESPACE();
		symbolP->sy_type |= N_EXT;
		if (c == ',') {
			InputPointer++;
			SKIP_WHITESPACE();
			if (*InputPointer == '\n')
				c = '\n';
		}
	} while (c == ',');
	demand_empty_rest_of_line();
}
static void MakeBssSymbol(symbolS *symbolP,int siz,int localflag)
{
	if (localflag)
		symbolP->SymbolValue = local_bss_counter;
	else
		symbolP->SymbolValue = siz;
	symbolP->sy_type = N_BSS;
	symbolP->Flags = IS_BSS;
	local_bss_counter += siz;
	if (localflag)
		symbolP->StorageClass = 3;  /* static symbol */
	else
		symbolP->StorageClass = 2;  /* external symbol */
	if (localflag)
		symbolP->SectionNumber = SECTION_BSS;
	else
		symbolP->SectionNumber = 0;
}
static void s_lcomm(void)
{
	register char *name;
	register char c;
	register char *p;
	register int temp;
	register symbolS *symbolP;
	name = InputPointer;
	c = get_symbol_end();
	p = InputPointer;                                
	SKIP_WHITESPACE();						  
	*p = c;
	if (*InputPointer != ',') {
		InternalError(1072);
	}
	InputPointer++;
	if ((temp = get_absolute_expression()) < 0) {
		InternalError(1073);
	}
	*p = 0;
	symbolP = symbol_find_or_make(name);
	*p = c;
	if (((symbolP->sy_type == N_BSS
				&& symbolP->SymbolValue == local_bss_counter)
				|| ((symbolP->sy_type & N_TYPE) == N_UNDF
					&& symbolP->SymbolValue == 0))) {
		MakeBssSymbol(symbolP,temp,1);
	}
	else {
		InternalError(1074);
	}
	demand_empty_rest_of_line();
}
static COFF_LINE *lastLine;
static void s_line(void)
{
	int l,c;

	do {
		c = *InputPointer++;
	} while (c == '\t' || c == ' ');
	InputPointer--;
	l = atoi(InputPointer);
	while (*InputPointer != '\n') InputPointer++; 
	if (CurrentFunctionSymbol) {
		COFF_LINE *coffL, *rvpL;
		if (CurrentFunctionSymbol->StartLine == 0) {
			CurrentFunctionSymbol->StartLine = l;
		}
		else {
			coffL = (COFF_LINE *) allocate(sizeof(COFF_LINE),3);
			coffL->Next = NULL;
			coffL->Frag = frag_now;
			coffL->Line = l - CurrentFunctionSymbol->StartLine;
			coffL->fragOffset = obstack_next_free(&frags) - frag_now->fr_literal;
			rvpL = CurrentFunctionSymbol->Lines;
			if (rvpL == NULL) {
				CurrentFunctionSymbol->Lines = coffL;
				lastLine = coffL;
			}
			else {
				lastLine->Next = coffL;
				lastLine = coffL;
			}
			CurrentFunctionSymbol->EndLine = l;
		}
	}
	if (l > 0)
		logical_input_line = l;
	demand_empty_rest_of_line();
}
static void s_lsym(void)
{
	register char *name;
	register char c;
	register char *p;
	register segT segment;
	expressionS exp;

	name = InputPointer;
	c = get_symbol_end();
	p = InputPointer;
	*p = c;
	SKIP_WHITESPACE();
	if (*InputPointer != ',') {
		*p = 0;
		InternalError(1075);
	}
	InputPointer++;
	segment = expression(&exp);
	if (segment != SEG_ABSOLUTE && segment != SEG_DATA &&
			segment != SEG_TEXT && segment != SEG_BSS) {
		InternalError(2016);
		ignore_rest_of_line();
		return;
	}
	know(segment == SEG_ABSOLUTE || segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS);
	*p = 0;
	symbol_new(name, (unsigned char) (seg_N_TYPE[(int) segment]),
					  (valueT) (exp.X_add_number), &zero_address_frag);
	*p = c;
	demand_empty_rest_of_line();
}
static void s_space(void)
{
	long int temp_repeat;
	register long int temp_fill;
	register char *p;
	/* Just like .fill, but temp_size = 1 */
	if (get_absolute_expression_and_terminator(&temp_repeat) == ',') {
		temp_fill = get_absolute_expression();
	}
	else {
		InputPointer--;   /* Backup over what was not a ','. */
		temp_fill = 0;
	}
	if (temp_repeat <= 0) {
		InternalError(1076);
	}
	if (!need_pass_2) {
		p = frag_var(rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0,
					temp_repeat, (char *) 0);
		*p = (char) temp_fill;
	}
	demand_empty_rest_of_line();
}
static void s_text(void)
{
	register int temp;
	temp = get_absolute_expression();
	subseg_new(SEG_TEXT, (subsegT) temp);
	demand_empty_rest_of_line();
}

static void CreateNewSection(char *name)
{
	NewSection *aNewSection;

	CurrentSpecialSection = aNewSection = (NewSection *)xmalloc(sizeof(NewSection));
	if (SectionList == NULL) {
		SectionList = aNewSection;
	}
	else {
		NewSection *rvp;

		rvp = SectionList;
		while (rvp->Next) rvp = rvp->Next;
		rvp->Next = aNewSection;
	}
	strcpy(aNewSection->Name,name);
	aNewSection->Number = 3 + NumberOfSpecialSections++;
}


static void s_section(void)
{
	char *name,delim;

	name = InputPointer;
	delim = get_symbol_end();
	if (!strcmp(name,".text")) {
		IsSpecialSection = 0;
		subseg_new(SEG_TEXT,0);
	}
	else if (!strcmp(name,".data")) {
		IsSpecialSection = 0;
		subseg_new(SEG_DATA,0);
	}
	else {
		IsSpecialSection = 1;
		CreateNewSection(name);
	}
	*InputPointer = delim;
	demand_empty_rest_of_line();
}

static void s_type(void)
{
	char *name;
	char delim;
	symbolS *symbolP;

	name = InputPointer;
	delim = get_symbol_end();
	symbolP = symbol_find_or_make(name);
	*InputPointer++ = delim;
	SKIP_WHITESPACE();
	if (*InputPointer == ',')
		InputPointer++;
	switch (*InputPointer) {
	case 'f':          /* function */
		symbolP->Flags |= IS_TEXT | IS_FUNCTION;
		symbolP->Flags &= ~IS_DATA;
		symbolP->SectionNumber = SECTION_TEXT;
		if (symbolP->StorageClass == 0)
			symbolP->StorageClass = 3; /* Static */
		symbolP->Type = 0x20;
		symbolP->FnInfo = (COFF_FN *) xmalloc(sizeof(COFF_FN));
		CurrentFunctionSymbol = symbolP;
		break;
	case 'o':          /* data */
		symbolP->Flags |= IS_DATA;
		symbolP->Flags &= ~(IS_TEXT|IS_BSS);
		symbolP->SectionNumber = SECTION_DATA;
		if (symbolP->StorageClass == 0)
			symbolP->StorageClass = 3;
		break;
	default:
		InternalError(1008);
	}
	while (!is_end_of_line[*InputPointer]) {
		delim = *InputPointer++;
	}
	demand_empty_rest_of_line();
}
static void s_size(void)
{
	char *name;
	char delim;
	int c;
	symbolS *coffS, *endS;

	name = InputPointer;
	delim = get_symbol_end();
	coffS = symbol_find_or_make(name);
	*InputPointer++ = delim;
	SKIP_WHITESPACE();
	c = *InputPointer;
	if (c <= '9' && c >= '0') {
		get_absolute_expression();
	}
	else {
		name = InputPointer;
		delim = get_symbol_end();
		endS = symbol_find_or_make(name);
		coffS->FnInfo->End = endS;
		coffS->FnInfo->Start = coffS;
	}
	while (!is_end_of_line[*InputPointer])
		InputPointer++;
	demand_empty_rest_of_line();
}
static void demand_empty_rest_of_line(void)
{
	SKIP_WHITESPACE();
	if (is_end_of_line[*InputPointer]) {
		InputPointer++;
	}
	else {
		ignore_rest_of_line();
	}
}                       /* Return pointing just after end-of-line. */

static void ignore_rest_of_line(void)
{                       /* For suspect lines: gives warning. */
	if (!is_end_of_line[*InputPointer]) {
		InternalError(2077);
		while (InputPointer < buffer_limit
				&& !is_end_of_line[*InputPointer]) {
			InputPointer++;
		}
	}
	InputPointer++;   /* Return pointing just after end-of-line. */
	know(is_end_of_line[InputPointer[-1]]);
}
/*
 *          cons()
 * CONStruct more frag of .bytes, or .words etc.
 * Should need_pass_2 be TRUE then emit no frag(s).
 * This understands EXPRESSIONS, as opposed to big_cons().
 * Bug (?)
 * This has a split personality. We use expression() to read the
 * value. We can detect if the value won't fit in a byte or word.
 * But we can't detect if expression() discarded significant digits
 * in the case of a long. Not worth the crocks required to fix it.
 */
static void cons(int nbytes)
{                       /* worker to do .byte etc statements */
	/* clobbers InputPointer, checks */
	/* end-of-line. */
	/* 1=.byte, 2=.word, 4=.long */
	register char c;
	register long int mask; /* High-order bits we will left-truncate, */
	/* but includes sign bit also. */
	register long int get;  /* what we get */
	register long int use;  /* get after truncation. */
	register long int unmask;   /* what bits we will store */
	register char *p;
	register segT segment;
	expressionS exp;
	/* InputPointer -> 1st char after pseudo-op-code and could legally
	be a end-of-line. (Or, less legally an eof - which we cope with.) */
	if (nbytes >= sizeof(long int))
		mask = 0;
	else
		mask = ~0 << (8 * nbytes);  /* Don't store these bits. */
	unmask = ~mask;     /* Do store these bits. */
	/* The following awkward logic is to parse ZERO or more expressions,
	comma seperated. Recall an expression includes its leading & trailing
	blanks. We fake a leading ',' if there is (supposed to be) a 1st
	expression, and keep demanding 1 expression for each ','. */
	if (is_it_end_of_statement()) {
		c = 0;          /* Skip loop. */
		InputPointer++;   /* Matches end-of-loop 'correction'. */
	}
	else
		c = ',';        /* Do loop. */
	while (c == ',') {
		segment = expression(&exp); /* At least scan over the expression. */
		if (!need_pass_2) { /* Still worthwhile making frags. */
			/* Don't call this if we are going to junk this pass anyway! */
			know(segment != SEG_PASS1);
			if (segment == SEG_DIFFERENCE && exp.X_add_symbol == NULL) {
				InternalError(1087);
			}
			if (!IsSpecialSection) {
				p = frag_more(nbytes);
			}
			else {
				char *tmp = CurrentSpecialSection->data;
				CurrentSpecialSection->data = xmalloc(CurrentSpecialSection->DataSize + nbytes);
				if (tmp) {
					memcpy(CurrentSpecialSection->data,tmp,CurrentSpecialSection->DataSize);
					p = CurrentSpecialSection->data + CurrentSpecialSection->DataSize;
				}
				else p = CurrentSpecialSection->data;
				CurrentSpecialSection->DataSize += nbytes;
			}
			switch (segment) {
			case SEG_BIG:
				InternalError(1088);
				break;
			case SEG_NONE:
				InternalError(1089);
				/* fall into SEG_ABSOLUTE */
			case SEG_ABSOLUTE:
				get = exp.X_add_number;
				use = get & unmask;
				if ((get & mask) && (get & mask) != mask) { /* Leading bits
						contain both 0s & 1s. */
					InternalError(1090);
				}
				switch(nbytes) {
					case 1:
						p[0] = (unsigned char)use;
						break;
					case 2:
						*(unsigned short *)(p) = (unsigned short)use;
						break;
					case 4:
						*(unsigned long *)(p) = use;
						break;
					default:
						printf("Internal error nbytes=%d\n",nbytes);
						break;
				}
				break;
			case SEG_DIFFERENCE:
			case SEG_BSS:
			case SEG_UNKNOWN:
			case SEG_TEXT:
			case SEG_DATA:
				if (IsSpecialSection) {
					InternalError(1116);
				}
				newFixup(frag_now, p - frag_now->fr_literal, (short int) nbytes,
						exp.X_add_symbol, exp.X_subtract_symbol,
						exp.X_add_number, 0);
				break;
			default:
				InternalError(1107);
				break;
			}           /* switch(segment) */
		}               /* if(!need_pass_2) */
		c = *InputPointer++;
	}                   /* while(c==',') */
	InputPointer--;   /* Put terminator back into stream. */
	demand_empty_rest_of_line();
}                       /* cons() */

static long int get_absolute_expression(void)
{
	expressionS exp;
	register segT s;
	if ((s = expression(&exp)) != SEG_ABSOLUTE) {
		if (s != SEG_NONE) {
			InternalError(1096);
		}
		exp.X_add_number = 0;
	}
	return (exp.X_add_number);
}
static char get_absolute_expression_and_terminator(long int *val_pointer)
{
	*val_pointer = get_absolute_expression();
	return (*InputPointer++);
}

/* is_it_end_of_statement()
 * In:  InputPointer -> next character.
 * Do:  Skip InputPointer over all whitespace.
 * Out: TRUE if InputPointer -> end-of-line.
 */
static int is_it_end_of_statement(void)
{
	while (*InputPointer == ' ' || *InputPointer == '\t')
		InputPointer++;
	return (is_end_of_line[*InputPointer]);
}

/* lexical macros */
#define is_opcode_char(x) (opcode_chars[(unsigned char) x])
#define is_operand_char(x) (operand_chars[(unsigned char) x])
#define is_register_char(x) (register_chars[(unsigned char) x])
#define is_space_char(x) (space_chars[(unsigned char) x])
#define is_identifier_char(x) (identifier_chars[(unsigned char) x])
#define is_digit_char(x) (digit_chars[(unsigned char) x])
/* put here all non-digit non-letter charcters that may occur in an operand */
static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:";
/* Asm386Instruction() always leaves the strings it's passed unaltered.To
   effect this we maintain a stack of saved characters that we've smashed
   with '\0's (indicating end of strings for various sub-fields of the
   assembler instruction). */
static char save_stack[32];
static char *save_stack_p;  /* stack pointer */
#define END_STRING_AND_SAVE(s)      *save_stack_p++ = *s; *s = '\0'
#define RESTORE_END_STRING(s)       *s = *--save_stack_p
/* The instruction we're assembling. */
static i386_insn i;
/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */
static expressionS disp_expressions[2], im_expressions[2];
/* pointers to ebp & esp entries in reg_hash hash table */
static reg_entry *ebp, *esp; 
static int this_operand;/* current operand we are working on */
/* for interface with expression () */
extern char *InputPointer;
/* obstack for constructing various things in InitializeAsmTables */
static struct obstack o;
/* hash table for opcode lookup */
static struct hash_control *op_hash = (struct hash_control *) 0;

/* hash table for prefix lookup */
static struct hash_control *prefix_hash = (struct hash_control *) 0;
static void InitializeAsmTables(void)
{
	char *hash_err;
	template *optab;
	templates *core_optab;
	char *prev_name;
	reg_entry *regtab;
	prefix_entry *prefixtab;
	unsigned int c,j,k;
	symbolS *symbolP;
	pseudo_typeS *pop;

	obstack_begin(&o, 4096);
	/* initialize op_hash hash table */
	op_hash = hash_new();   /* xmalloc handles error */
	optab = i386_optab; /* setup for loop */
	prev_name = optab->name;
	obstack_grow(&o, optab, sizeof(template));
	core_optab = (templates *) xmalloc(sizeof(templates));
	for (optab++; optab < i386_optab_end; optab++) {
		if (!strcmp(optab->name, prev_name)) {
			/* same name as before --> append to current template list */
			obstack_grow(&o, optab, sizeof(template));
		}
		else {
			/* different name --> ship out current template list; add to hash
			table; & begin anew Note: end must be set before start! since
			obstack_next_free changes upon opstack_finish */
			core_optab->end = (template *) obstack_next_free(&o);
			core_optab->start = (template *) obstack_finish(&o);
			hash_err = hash_insert(op_hash, prev_name, (char *) core_optab);
			if (hash_err && *hash_err) {
		hash_error:
				InternalError(1009);
			}
			prev_name = optab->name;
			core_optab = (templates *) xmalloc(sizeof(templates));
			obstack_grow(&o, optab, sizeof(template));
		}
	}
	/* initialize reg_hash hash table */
	c = j = 0;
	for (regtab = i386_regtab; regtab < i386_regtab_end; regtab++) {
		for (k=0;k<4;k++) {
			if (regtab->reg_name[k] == 0) {
				while (k < 4) {
					RegisterNames[j++] = 0; k++;
				}
				break;
			}
			RegisterNames[j++] = regtab->reg_name[k];
		}
		if (!strncmp(regtab->reg_name,"esp",3)) {
			esp = regtab;
		}
		else if (!strncmp(regtab->reg_name,"ebp",3)) {
			ebp = regtab;
		}
		c++;
	}
	/* initialize reg_hash hash table */
	prefix_hash = hash_new();
	for (prefixtab = i386_prefixtab;
			prefixtab < i386_prefixtab_end; prefixtab++) {
		hash_err = hash_insert(prefix_hash, prefixtab->prefix_name, (char *) prefixtab);
		if (hash_err && *hash_err)
			goto hash_error;
	}
	/* fill in lexical tables:  opcode_chars, operand_chars, space_chars */
	memset(opcode_chars,0, sizeof(opcode_chars));
	memset(operand_chars,0, sizeof(operand_chars));
	memset(space_chars,0, sizeof(space_chars));
	memset(identifier_chars,0, sizeof(identifier_chars));
	memset(digit_chars,0, sizeof(digit_chars));
	for (c = 0; c < 256; c++) {
		if (islower(c) || isdigit(c)) {
			opcode_chars[c] = c;
			register_chars[c] = c;
		}
		else if (isupper(c)) {
			opcode_chars[c] = tolower(c);
			register_chars[c] = opcode_chars[c];
		}
		else if (c == PREFIX_SEPERATOR) {
			opcode_chars[c] = c;
		}
		else if (c == ')' || c == '(') {
			register_chars[c] = c;
		}
		if (isupper(c) || islower(c) || isdigit(c))
			operand_chars[c] = c;
		else if (c && index(operand_special_chars, c))
			operand_chars[c] = c;
		if (isdigit(c) || c == '-')
			digit_chars[c] = c;
		if (isalpha(c) || c == '_' || c == '.' || isdigit(c))
			identifier_chars[c] = c;
		if (c == ' ' || c == '\t')
			space_chars[c] = c;
	}
	operand_chars['@'] = '@'; /* This is needed to support the stdcall feature */
	symbolP = symbol_new(".text",N_TEXT,0,NULL);
	symbol_table_insert(symbolP);
	symbolP->SectionNumber = SECTION_TEXT;
	symbolP->Flags = IS_TEXT;
	symbolP->StorageClass = 3;
	symbolP->NumberOfAuxSymbols = 1;

	symbolP = symbol_new(".data",N_DATA,0,NULL);
	symbol_table_insert(symbolP);
	symbolP->SectionNumber = SECTION_DATA;
	symbolP->Flags = IS_DATA;
	symbolP->StorageClass = 3;
	symbolP->NumberOfAuxSymbols = 1;

	symbolP = symbol_new(".bss",N_BSS,0,NULL);
	symbol_table_insert(symbolP);
	symbolP->SectionNumber = SECTION_BSS;
	symbolP->StorageClass = 3;
	symbolP->NumberOfAuxSymbols = 1;
	symbolP->Flags = IS_BSS;
	/* Initialize the pseudo operations table */
	po_hash = hash_new();
	hash_err = "";        /* OK so far */
	for (pop = potable; pop->poc_name && !*hash_err; pop++) {
		hash_err = hash_insert(po_hash, pop->poc_name, (char *) pop);
	}
	if (*hash_err) {
		InternalError(1007);
	}
}
/*
  This is the guts of the machine-dependent assembler.  LINE points to a
  i386 instruction.  This function emits the bytes it assembles to.
 */
static void Asm386Instruction(char *line)
{
	/* Holds template once we've found it. */
	register template *t;
	register char *p;
	register unsigned int overlap0, overlap1;
	expressionS *exp;
	unsigned int overlap2;
	unsigned int found_reverse_match;
	char *q;
	register char *l = line;    /* Fast place to put LINE. */
	/* TRUE if operand is pending after ','. */
	unsigned int expecting_operand = 0;
	/* TRUE if we found a prefix only acceptable with string insns. */
	unsigned int expecting_string_instruction = 0;
	/* Non-zero if operand parens not balenced. */
	unsigned int paren_not_balenced;
	char *token_start = l;
	/* Possible templates for current insn */
	templates *current_templates = (templates *) 0;
	/* Initialize globals. */
	memset(&i,0, sizeof(i));
	memset(disp_expressions,0, sizeof(disp_expressions));
	memset(im_expressions,0, sizeof(im_expressions));
	save_stack_p = save_stack;  /* reset stack pointer */
	/* Fist parse an opcode & call i386_operand for the operands. We assume
	that the scrubber has arranged it so that line[0] is the valid start of
	a (possibly prefixed) opcode. */
	while (!is_space_char(*l) && *l != END_OF_INSN) {
		if (!is_opcode_char(*l)) {
			InternalError(1018);
		}
		else if (*l != PREFIX_SEPERATOR) {
			l++;
		}
		else {          /* this opcode's got a prefix */
			register unsigned int q;
			register prefix_entry *prefix;
			if (l == token_start) {
				InternalError(1019);
			}
			END_STRING_AND_SAVE(l);
			prefix = (prefix_entry *) hash_find(prefix_hash, token_start);
			if (!prefix) {
				InternalError(1020);
			}
			RESTORE_END_STRING(l);
			/* check for repeated prefix */
			for (q = 0; q < i.prefixes; q++)
				if (i.prefix[q] == prefix->prefix_code) {
					InternalError(1021);
				}
			if (i.prefixes == MAX_PREFIXES) {
				InternalError(1022);
			}
			i.prefix[i.prefixes++] = prefix->prefix_code;
			if (prefix->prefix_code == REPE || prefix->prefix_code == REPNE)
				expecting_string_instruction = TRUE;
			/* skip past PREFIX_SEPERATOR and reset token_start */
			token_start = ++l;
		}
	}
	END_STRING_AND_SAVE(l);
	if (token_start == l) {
		InternalError(1023);
	}
	/* Lookup insn in hash; try intel & att naming conventions if
	appropriate; that is:  we only use the opcode suffix 'b' 'w' or 'l' if
	we need to. */
	current_templates = (templates *) hash_find(op_hash, token_start);
	if (!current_templates) {
		int last_index = strlen(token_start) - 1;
		char last_char = token_start[last_index];
		switch (last_char) {
		case DWORD_OPCODE_SUFFIX:
		case WORD_OPCODE_SUFFIX:
		case BYTE_OPCODE_SUFFIX:
			token_start[last_index] = '\0';
			current_templates = (templates *) hash_find(op_hash, token_start);
			token_start[last_index] = last_char;
			i.suffix = last_char;
		}
		if (!current_templates) {
			printf("No such instruction %s\n",token_start);
			InternalError(1024);
		}
	}
	RESTORE_END_STRING(l);
	/* check for rep/repne without a string instruction */
	if (expecting_string_instruction &&
			!IS_STRING_INSTRUCTION(current_templates->
								start->base_opcode)) {
		InternalError(1025);
	}
	/* There may be operands to parse. */
	if (*l != END_OF_INSN &&
	/* For string instructions, we ignore any operands if given.  This
	kludges, for example, 'rep/movsb %ds:(%esi), %es:(%edi)' where the
	operands are always going to be the same, and are not really encoded in
	machine code. */
			!IS_STRING_INSTRUCTION(current_templates->
								start->base_opcode)) {
		/* parse operands */
		do {
			/* skip optional white space before operand */
			while (!is_operand_char(*l) && *l != END_OF_INSN) {
				if (!is_space_char(*l)) {
					InternalError(1026);
				}
				l++;
			}
			token_start = l;    /* after white space */
			paren_not_balenced = 0;
			while (paren_not_balenced || *l != ',') {
				if (*l == END_OF_INSN) {
					if (paren_not_balenced) {
						InternalError(1027);
					}
					else
						break;  /* we are done */
				}
				else if (!is_operand_char(*l)) {
					while (*l == ' ' || *l == '\t') l++;
					if (*l == ';' || *l == END_OF_INSN) {
						break;
					}
					else {
						int i;

						printf("incorrect char %c\n",*l);
						i = 0;
						while (line[i] != '\n') {
							printf("%c",line[i++]);
						}
						printf("\n");
						InternalError(1028);
					}
				}
				if (*l == '(')
					++paren_not_balenced;
				if (*l == ')')
					--paren_not_balenced;
				l++;
			}
			if (l != token_start) { /* yes, we've read in another operand */
				unsigned int operand_ok;
				this_operand = i.operands++;
				if (i.operands > MAX_OPERANDS) {
					InternalError(1029);
				}
				/* now parse operand adding info to 'i' as we go along */
				END_STRING_AND_SAVE(l);
				operand_ok = i386_operand(token_start);
				RESTORE_END_STRING(l);  /* restore old contents */
				if (!operand_ok)
					return;
			}
			else {
				if (expecting_operand) {
			expecting_operand_after_comma:
					InternalError(1030);
				}
				if (*l == ',') {
					InternalError(1031);
				}
			}
			/* now *l must be either ',' or END_OF_INSN */
			if (*l == ',') {
				if (*++l == END_OF_INSN) {  /* just skip it, if it's \n
						complain */
					goto expecting_operand_after_comma;
				}
				expecting_operand = TRUE;
			}
		} while (*l != END_OF_INSN);    /* until we get end of insn */
	}
	/* Now we've parsed the opcode into a set of templates, and have the
	operands at hand. Next, we find a template that matches the given insn,
	making sure the overlap of the given operands types is consistent with
	the template operand types. */
#define MATCH(overlap,given_type) \
  (overlap && \
   (overlap & (JumpAbsolute|BaseIndex|Mem8)) \
   == (given_type & (JumpAbsolute|BaseIndex|Mem8)))
	/* If m0 and m1 are register matches they must be consistent with the
	expected operand types t0 and t1. That is, if both m0 & m1 are register
	matches i.e. ( ((m0 & (Reg)) && (m1 & (Reg)) ) ? then, either 1. or 2.
	must be true: 1. the expected operand type register overlap is null:
	(t0 & t1 & Reg) == 0 AND the given register overlap is null: (m0 & m1 &
	Reg) == 0 2. the expected operand type register overlap == the given
	operand type overlap:  (t0 & t1 & m0 & m1 & Reg). */
#define CONSISTENT_REGISTER_MATCH(m0, m1, t0, t1) \
	( ((m0 & (Reg)) && (m1 & (Reg))) ? \
	( ((t0 & t1 & (Reg)) == 0 && (m0 & m1 & (Reg)) == 0) || \
		((t0 & t1) & (m0 & m1) & (Reg)) \
	) : 1)
	overlap0 = overlap1 = overlap2 = found_reverse_match = 0;
	for (t = current_templates->start;
			t < current_templates->end;
			t++) {
		/* must have right number of operands */
		if (i.operands != t->operands)
			continue;
		else if (!t->operands)
			break;      /* 0 operands always matches */
		overlap0 = i.types[0] & t->operand_types[0];
		switch (t->operands) {
		case 1:
			if (!MATCH(overlap0, i.types[0]))
				continue;
			break;
		case 2:
		case 3:
			overlap1 = i.types[1] & t->operand_types[1];
			if (!MATCH(overlap0, i.types[0]) ||
					!MATCH(overlap1, i.types[1]) ||
					!CONSISTENT_REGISTER_MATCH(overlap0, overlap1,
											t->operand_types[0],
											t->operand_types[1])) {
				/* check if other direction is valid ... */
				if (!(t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS))
					continue;
				/* try reversing direction of operands */
				overlap0 = i.types[0] & t->operand_types[1];
				overlap1 = i.types[1] & t->operand_types[0];
				if (!MATCH(overlap0, i.types[0]) ||
						!MATCH(overlap1, i.types[1]) ||
						!CONSISTENT_REGISTER_MATCH(overlap0, overlap1,
												t->operand_types[0],
												t->operand_types[1])) {
					/* does not match either direction */
					continue;
				}
				/* found a reverse match here -- slip through */
				/* found_reverse_match holds which of D or FloatD we've found */
				found_reverse_match = t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS;
			}           /* endif: not forward match */
			/* found either forward/reverse 2 operand match here */
			if (t->operands == 3) {
				overlap2 = i.types[2] & t->operand_types[2];
				if (!MATCH(overlap2, i.types[2]) ||
						!CONSISTENT_REGISTER_MATCH(overlap0, overlap2,
												t->operand_types[0],
												t->operand_types[2]) ||
						!CONSISTENT_REGISTER_MATCH(overlap1, overlap2,
												t->operand_types[1],
												t->operand_types[2]))
					continue;
			}
			/* found either forward/reverse 2 or 3 operand match here: slip
			through to break */
		}
		break;          /* we've found a match; break out of loop */
	}                   /* for (t = ... */
	if (t == current_templates->end) {  /* we found no match */
		InternalError(1032);
	}
	/* Copy the template we found (we may change it!). */
	bcopy(t, &i.tm, sizeof(template));
	t = &i.tm;          /* alter new copy of template */
	/* If there's no opcode suffix we try to invent one based on register
	operands. */
	if (!i.suffix && i.reg_operands) {
		/* We take i.suffix from the LAST register operand specified. This
		assumes that the last register operands is the destination register
		operand. */
		int o;
		for (o = 0; o < MAX_OPERANDS; o++)
			if (i.types[o] & Reg) {
				i.suffix = (i.types[o] == Reg8) ? BYTE_OPCODE_SUFFIX :
					(i.types[o] == Reg16) ? WORD_OPCODE_SUFFIX :
					DWORD_OPCODE_SUFFIX;
			}
	}
	/* Make still unresolved immediate matches conform to size of immediate
	given in i.suffix. Note:  overlap2 cannot be an immediate! We assume
	this. */
	if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32))
			&& overlap0 != Imm8 && overlap0 != Imm8S
			&& overlap0 != Imm16 && overlap0 != Imm32) {
		if (!i.suffix) {
			InternalError(1033);
		}
		overlap0 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8 | Imm8S) :
					(i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
	}
	if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32))
			&& overlap1 != Imm8 && overlap1 != Imm8S
			&& overlap1 != Imm16 && overlap1 != Imm32) {
		if (!i.suffix) {
			InternalError(1034);
		}
		overlap1 &= (i.suffix == BYTE_OPCODE_SUFFIX ? (Imm8 | Imm8S) :
					(i.suffix == WORD_OPCODE_SUFFIX ? Imm16 : Imm32));
	}
	i.types[0] = overlap0;
	i.types[1] = overlap1;
	i.types[2] = overlap2;
	if (overlap0 & ImplicitRegister)
		i.reg_operands--;
	if (overlap1 & ImplicitRegister)
		i.reg_operands--;
	if (overlap2 & ImplicitRegister)
		i.reg_operands--;
	if (overlap0 & Imm1)
		i.imm_operands = 0; /* kludge for shift insns */
	if (found_reverse_match) {
		unsigned int save;
		save = t->operand_types[0];
		t->operand_types[0] = t->operand_types[1];
		t->operand_types[1] = save;
	}
	if (i.tm.base_opcode == 136 && i.operands == 2 && i.mem_operands == 0 &&
	    i.regs[0] == i.regs[1]) {
/*		printf("%s %s,%s\n",i.tm.name,i.regs[0]->reg_name,i.regs[1]->reg_name); */
		return;
	}
	if (!i.suffix && (t->opcode_modifier & W)) {
		InternalError(1035);
	}
	/* Finalize opcode.  First, we change the opcode based on the operand
	size given by i.suffix: we never have to change things for byte insns,
	or when no opcode suffix is need to size the operands. */
	if (i.suffix && i.suffix != BYTE_OPCODE_SUFFIX) {
		/* Select between byte and word/dword operations. */
		if (t->opcode_modifier & W)
			t->base_opcode |= W;
		/* Now select between word & dword operations via the operand size
		prefix. */
		if (i.suffix == WORD_OPCODE_SUFFIX) {
			if (i.prefixes == MAX_PREFIXES) {
				InternalError(1036);
			}
			i.prefix[i.prefixes++] = WORD_PREFIX_OPCODE;
		}
	}
	/* For insns with operands there are more diddles to do to the opcode. */
	if (i.operands) {
		/* If we found a reverse match we must alter the opcode direction bit
		found_reverse_match holds bit to set (different for int & float
		insns). */
		if (found_reverse_match) {
			t->base_opcode |= found_reverse_match;
		}
		/* The imul $imm, %reg instruction is converted into imul $imm, %reg,
		%reg. */
		if (t->opcode_modifier & imulKludge) {
			i.regs[2] = i.regs[1];  /* Pretend we saw the 3 operand case. */
			i.reg_operands = 2;
		}
		/* Certain instructions expect the destination to be in the i.rm.reg
		field. They are:
		  "movzb","movzwl","imul","imul","imul","bsf","bsr","lar","lsl"
		For these instructions, if the source operand is a register, we must 
		reverse the i.rm.reg and i.rm.regmem fields.  We accomplish this by faking
		that the two register operands were given in the reverse order. */
		if ((t->opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2) {
			unsigned int first_reg_operand = (i.types[0] & Reg) ? 0 : 1;
			unsigned int second_reg_operand = first_reg_operand + 1;
			reg_entry *tmp = i.regs[first_reg_operand];
			i.regs[first_reg_operand] = i.regs[second_reg_operand];
			i.regs[second_reg_operand] = tmp;
		}
		if (t->opcode_modifier & ShortForm) {
			/* The register or float register operand is in operand 0 or 1. */
			unsigned int o = (i.types[0] & (Reg | FloatReg)) ? 0 : 1;
			/* Register goes in low 3 bits of opcode. */
			t->base_opcode |= i.regs[o]->reg_num;
		}
		else if (t->opcode_modifier & ShortFormW) {
			/* Short form with 0x8 width bit.  Register is always dest.
			operand */
			t->base_opcode |= i.regs[1]->reg_num;
			if (i.suffix == WORD_OPCODE_SUFFIX ||
					i.suffix == DWORD_OPCODE_SUFFIX)
				t->base_opcode |= 0x8;
		}
		else if (t->opcode_modifier & Seg2ShortForm) {
			if (t->base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1) {
				InternalError(1037);
			}
			t->base_opcode |= (i.regs[0]->reg_num << 3);
		}
		else if (t->opcode_modifier & Seg3ShortForm) {
			/* 'push %fs' is 0x0fa0; 'pop %fs' is 0x0fa1. 'push %gs' is
			0x0fa8; 'pop %fs' is 0x0fa9. So, only if i.regs[0]->reg_num ==
			5 (%gs) do we need to change the opcode. */
			if (i.regs[0]->reg_num == 5)
				t->base_opcode |= 0x08;
		}
		else if (t->opcode_modifier & Modrm) {
			/* The opcode is completed (modulo t->extension_opcode which must
			be put into the modrm byte. Now, we make the modrm & index base
			bytes based on all the info we've collected. */
			/* i.reg_operands MUST be the number of real register operands;
			implicit registers do not count. */
			if (i.reg_operands == 2) {
				unsigned int source, dest;
				source = (i.types[0] & (Reg | SReg2 | SReg3 | Control | Debug | Test | MmxReg)) ? 0 : 1;
				dest = source + 1;
				i.rm.mode = 3;
				/* We must be careful to make sure that all
				segment/control/test/ debug registers go into the i.rm.reg
				field (despite the whether they are source or destination
				operands). */
				if (i.regs[dest]->reg_type & (SReg2 | SReg3 | Control | Debug | Test | MmxReg)) {
					i.rm.reg = i.regs[dest]->reg_num;
					i.rm.regmem = i.regs[source]->reg_num;
				}
				else {
					i.rm.reg = i.regs[source]->reg_num;
					i.rm.regmem = i.regs[dest]->reg_num;
				}
			}
			else {      /* if it's not 2 reg operands... */
				if (i.mem_operands) {
					unsigned int fake_zero_displacement = FALSE;
					unsigned int o = (i.types[0] & Mem) ? 0 : ((i.types[1] & Mem) ? 1 : 2);
					/* Encode memory operand into modrm byte and base index
					byte. */
					if (i.base_reg == esp && !i.index_reg) {
						/* <disp>(%esp) becomes two byte modrm with no index
						register. */
						i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
						i.rm.mode = MODE_FROM_DISP_SIZE(i.types[o]);
						i.bi.base = ESP_REG_NUM;
						i.bi.index = NO_INDEX_REGISTER;
						i.bi.scale = 0; /* Must be zero! */
					}
					else if (i.base_reg == ebp && !i.index_reg) {
						if (!(i.types[o] & Disp)) {
							/* Must fake a zero byte displacement. There is
							no direct way to code '(%ebp)' directly. */
							fake_zero_displacement = TRUE;
							/* fake_zero_displacement code does not set this. */
							i.types[o] |= Disp8;
						}
						i.rm.mode = MODE_FROM_DISP_SIZE(i.types[o]);
						i.rm.regmem = EBP_REG_NUM;
					}
					else if (!i.base_reg && (i.types[o] & BaseIndex)) {
						/* There are three cases here. Case 1:  '<32bit
						disp>(,1)' -- indirect absolute. (Same as cases 2 &
						3 with NO index register) Case 2: <32bit disp>
						(,<index>) -- no base register with disp Case 3: (,
						<index>)       --- no base register; no disp (must
						add 32bit 0 disp). */
						i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
						i.rm.mode = 0;  /* 32bit mode */
						i.bi.base = NO_BASE_REGISTER;
						i.types[o] &= ~Disp;
						i.types[o] |= Disp32;   /* Must be 32bit! */
						if (i.index_reg) {  /* case 2 or case 3 */
							i.bi.index = i.index_reg->reg_num;
							i.bi.scale = i.log2_scale_factor;
							if (i.disp_operands == 0)
								fake_zero_displacement = TRUE;  /* case 3 */
						}
						else {
							i.bi.index = NO_INDEX_REGISTER;
							i.bi.scale = 0;
						}
					}
					else if (i.disp_operands && !i.base_reg && !i.index_reg) {
						/* Operand is just <32bit disp> */
						i.rm.regmem = EBP_REG_NUM;
						i.rm.mode = 0;
						i.types[o] &= ~Disp;
						i.types[o] |= Disp32;
					}
					else {
						/* It's not a special case; rev'em up. */
						i.rm.regmem = i.base_reg->reg_num;
						i.rm.mode = MODE_FROM_DISP_SIZE(i.types[o]);
						if (i.index_reg) {
							i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
							i.bi.base = i.base_reg->reg_num;
							i.bi.index = i.index_reg->reg_num;
							i.bi.scale = i.log2_scale_factor;
							if (i.base_reg == ebp && i.disp_operands == 0) {
								/* p ace */
								fake_zero_displacement = TRUE;
								i.types[o] |= Disp8;
								i.rm.mode = MODE_FROM_DISP_SIZE(i.types[o]);
							}
						}
					}
					if (fake_zero_displacement) {
						/* Fakes a zero displacement assuming that i.types[o]
						holds the correct displacement size. */
						exp = &disp_expressions[i.disp_operands++];
						i.disps[o] = exp;
						exp->X_seg = SEG_ABSOLUTE;
						exp->X_add_number = 0;
						exp->X_add_symbol = (symbolS *) 0;
						exp->X_subtract_symbol = (symbolS *) 0;
					}
					/* Select the correct segment for the memory operand. */
					if (i.seg) {
						unsigned int seg_index;
						seg_entry *default_seg;
						if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING) {
							seg_index = (i.rm.mode << 3) | i.bi.base;
							default_seg = two_byte_segment_defaults[seg_index];
						}
						else {
							seg_index = (i.rm.mode << 3) | i.rm.regmem;
							default_seg = one_byte_segment_defaults[seg_index];
						}
						/* If the specified segment is not the default, use
						an opcode prefix to select it */
						if (i.seg != default_seg) {
							if (i.prefixes == MAX_PREFIXES) {
								InternalError(1038);
							}
							i.prefix[i.prefixes++] = (char)(i.seg->seg_prefix);
						}
					}
				}
				/* Fill in i.rm.reg or i.rm.regmem field with register
				operand (if any) based on t->extension_opcode. Again, we
				must be careful to make sure that
				segment/control/debug/test registers are coded into the
				i.rm.reg field. */
				if (i.reg_operands) {
					unsigned int o =
					(i.types[0] & (Reg | SReg2 | SReg3 | Control | Debug | Test | MmxReg)) ? 0 :
					(i.types[1] & (Reg | SReg2 | SReg3 | Control | Debug | Test | MmxReg)) ? 1 : 2;
					/* If there is an extension opcode to put here, the
					register number must be put into the regmem field. */
					if (t->extension_opcode != None)
						i.rm.regmem = i.regs[o]->reg_num;
					else
						i.rm.reg = i.regs[o]->reg_num;
					/* Now, if no memory operand has set i.rm.mode = 0, 1, 2
					we must set it to 3 to indicate this is a register
					operand int the regmem field */
					if (!i.mem_operands)
						i.rm.mode = 3;
				}
				/* Fill in i.rm.reg field with extension opcode (if any). */
				if (t->extension_opcode != None)
					i.rm.reg = t->extension_opcode;
			}
		}
	}
	/* Handle conversion of 'int $3' --> special int3 insn. */
	if (t->base_opcode == INT_OPCODE && i.imms[0]->X_add_number == 3) {
		t->base_opcode = INT3_OPCODE;
		i.imm_operands = 0;
	}
	/* We are ready to output the insn. */
	/* Output jumps. */
	if (t->opcode_modifier & Jump) {
		int n = i.disps[0]->X_add_number;
		if (i.disps[0]->X_seg != SEG_ABSOLUTE) {
			/* It's a symbol; end frag & setup for relax. Make sure there are
			6 chars left in the current frag; if not we'll have to start a
			new one. I caught it failing with obstack_room == 6, so I changed to <=
			pace */
			if (obstack_room(&frags) <= 6) {
				frag_wane(frag_now);
				frag_new(0);
			}
			p = frag_more(1);
			p[0] = (char)(t->base_opcode);
			frag_var(rs_machine_dependent,
					6, /* 2 opcode/prefix + 4 displacement */
					1,
					((uchar) * p == JUMP_PC_RELATIVE
					? ENCODE_RELAX_STATE(UNCOND_JUMP, BYTE)
					: ENCODE_RELAX_STATE(COND_JUMP, BYTE)),
					i.disps[0]->X_add_symbol,
					n, p);
		}
		else {
			if (FITS_IN_SIGNED_BYTE(n)) {
				p = frag_more(2);
				p[0] = (char)(t->base_opcode);
				p[1] = (char)n;
			}
			else {      /* It's an absolute dword displacement. */
				if (t->base_opcode == JUMP_PC_RELATIVE) {   /* pace */
					/* unconditional jump */
					p = frag_more(5);
					p[0] = (unsigned char) 0xe9;
					*(unsigned long *)(p+1) = n;
				}
				else {
					/* conditional jump */
					p = frag_more(6);
					p[0] = (char)TWO_BYTE_OPCODE_ESCAPE;
					p[1] = t->base_opcode + 0x10;
					*(unsigned long *)(p+2) = n;
				}
			}
		}
		return;
	}
	else if (t->opcode_modifier & (JumpByte | JumpDword)) {
		int size = (t->opcode_modifier & JumpByte) ? 1 : 4;
		int n = i.disps[0]->X_add_number;
		if (t->base_opcode <= 255) {
			FRAG_APPEND_1_CHAR(t->base_opcode);
		}
		else {
			p = frag_more(2);   /* opcode can be at most two bytes */
			/* put out high byte first */
			*p++ = (char)((t->base_opcode >> 8) & 0xff);
			*p = (char)(t->base_opcode & 0xff);
		}
		p = frag_more(size);
		switch (i.disps[0]->X_seg) {
		case SEG_ABSOLUTE:
			memcpy(p,&n,size);
			if (size == 1 && !FITS_IN_SIGNED_BYTE(n)) {
				InternalError(1039);
			}
			break;
		default:
			/* Fixup. Here comes the fixup for the call instructions for
			instance  */
			newFixup(frag_now, p - frag_now->fr_literal, (short int) size,
					i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol,
					i.disps[0]->X_add_number, 1);
			break;
		}
		return;
	}
	else if (t->opcode_modifier & JumpInterSegment) {
		/* lcall and ljmp instructions */
		p = frag_more(1 + 2 + 4);   /* 1 opcode; 2 segment; 4 offset */
		p[0] = (char)(t->base_opcode);
		if (i.imms[1]->X_seg == SEG_ABSOLUTE) {
			*(unsigned long *)(p+1) = i.imms[1]->X_add_number;
		}
		else
			newFixup(frag_now, p + 1 - frag_now->fr_literal, (short int) 4,
					i.imms[1]->X_add_symbol,
					i.imms[1]->X_subtract_symbol,
					i.imms[1]->X_add_number, 0);
		if (i.imms[0]->X_seg != SEG_ABSOLUTE) {
			InternalError(1040);
		}
		*(unsigned short *)(p+5) = (unsigned short)(i.imms[0]->X_add_number);
		return;
	}
	/* Output normal instructions here. */
	/* First the prefix bytes. */
	for (q = i.prefix; q < i.prefix + i.prefixes; q++) {
		p = frag_more(1);
		*p = (unsigned char )*q;
	}
	/* Now the opcode; be careful about word order here! */
	if (t->base_opcode <= 255) {
		if (obstack_room(&frags) <= 1) {
			frag_wane(frag_now);
			frag_new(0);
		}
		obstack_1grow(&frags, t->base_opcode);
	}
	else if (t->base_opcode <= 65535) {
		p = frag_more(2);
		/* put out high byte first */
		*p++ = (char)((t->base_opcode >> 8) & 0xff);
		*p = (char)(t->base_opcode & 0xff);
	}
	else {              /* opcode is either 3 or 4 bytes */
		if (t->base_opcode & 0xff000000) {
			p = frag_more(4);
			*p++ = (char)((t->base_opcode >> 24) & 0xff);
		}
		else
			p = frag_more(3);
		*p++ = (char)((t->base_opcode >> 16) & 0xff);
		*p++ = (char)((t->base_opcode >> 8) & 0xff);
		*p = (char)((t->base_opcode) & 0xff);
	}
	/* Now the modrm byte and base index byte (if present). */
	if (t->opcode_modifier & Modrm) {
		p = frag_more(1);
		*p = (char)(0xFF & (i.rm.regmem << 0 | i.rm.reg << 3 | i.rm.mode << 6));
		/* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode)
		==> need second modrm byte. */
		if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING && i.rm.mode != 3) {
			p = frag_more(1);
			*p = (char)(0xFF & (i.bi.base << 0 | i.bi.index << 3 | i.bi.scale << 6));
		}
	}
	if (i.disp_operands) {
		register unsigned int n;
		int number;
		for (n = 0; n < i.operands; n++) {
			if (i.disps[n]) {
				if (i.disps[n]->X_seg == SEG_ABSOLUTE) {
					number = (i.disps[n]->X_add_number);
					if (i.types[n] & (Disp8 | Abs8)) {
						p = frag_more(1);
						*p = (char)(0xFF & number);
					}
					else if (i.types[n] & (Disp16 | Abs16)) {
						p = frag_more(2);
						*(unsigned short *)(p) = (unsigned short)number;
					}
					else {  /* Disp32|Abs32 */
						p = frag_more(4);
						*(unsigned long *)(p) = number;
					}
				}
				else {  /* not SEG_ABSOLUTE */
					/* need a 32-bit fixup (don't support 8bit non-absolute
					disps) */
					p = frag_more(4);
					newFixup(frag_now, p - frag_now->fr_literal, 4,
					i.disps[n]->X_add_symbol, i.disps[n]->X_subtract_symbol,
							i.disps[n]->X_add_number, 0);
				}
			}
		}
	}                   /* end displacement output */
	/* output immediate */
	if (i.imm_operands) {
		register unsigned int n;
		int number;
		for (n = 0; n < i.operands; n++) {
			if (i.imms[n]) {
				if (i.imms[n]->X_seg == SEG_ABSOLUTE) {
					number = i.imms[n]->X_add_number;
					if (i.types[n] & (Imm8 | Imm8S)) {
						p = frag_more(1);
						*p = (char)(0xFF & number);
					}
					else if (i.types[n] & Imm16) {
						p = frag_more(2);
						*(unsigned short *)(p) = (unsigned short)number;
					}
					else {
						p = frag_more(4);
						*(unsigned long *)(p) = number;

					}
				}
				else {  /* not SEG_ABSOLUTE */
					/* need a 32-bit fixup (don't support 8bit non-absolute
					ims) */
					int size;
					if (i.types[n] & (Imm8 | Imm8S))
						size = 1;
					else if (i.types[n] & Imm16)
						size = 2;
					else
						size = 4;
					p = frag_more(size);
					/* FIXUPS This just fills the fieds of the fixup
					structure */
					newFixup(frag_now, p - frag_now->fr_literal, (short int) size,
						i.imms[n]->X_add_symbol, i.imms[n]->X_subtract_symbol,
							i.imms[n]->X_add_number, 0);
				}
			}
		}
	}                   /* end immediate output */
}
/* Parse OPERAND_STRING into the i386_insn structure I.  Returns non-zero
   on error. */
static int i386_operand(char *operand_string)
{
	register char *op_string;
	/* Address of '\0' at end of operand_string. */
	char *end_of_operand_string;
	/* Start and end of displacement string expression (if found). */
	char *displacement_string_start = 0;
	char *displacement_string_end;
	if (*operand_string == '0' && operand_string[1] == '(') {
		operand_string++;
	}
#if 1
	if (OptimizeFlag && *operand_string == '(' && operand_string[1] == ',' &&
		operand_string[2] == '%' && operand_string[6] == ')') {
		char *p = &operand_string[2];
		char *q = &operand_string[1];

		while (*p) {
			*q++ = *p++;
		}
		*q = 0;
	}
#endif
	op_string = operand_string;
	end_of_operand_string = operand_string + strlen(operand_string);
	/* We check for an absolute prefix (differentiating, for example, 'jmp
	pc_relative_label' from 'jmp *absolute_label'. */
	if (*op_string == ABSOLUTE_PREFIX) {
		op_string++;
		i.types[this_operand] |= JumpAbsolute;
	}
	/* Check if operand is a register. */
	if (*op_string == REGISTER_PREFIX) {
		register reg_entry *r;
		if (!(r = parse_register(op_string))) {
			InternalError(1041);
		}
		/* Check for segment override, rather than segment register by
		searching for ':' after %<x>s where <x> = s, c, d, e, f, g. */
		if ((r->reg_type & (SReg2 | SReg3)) && op_string[3] == ':') {
			switch (r->reg_num) {
			case 0:
				i.seg = &es;
				break;
			case 1:
				i.seg = &cs;
				break;
			case 2:
				i.seg = &ss;
				break;
			case 3:
				i.seg = &ds;
				break;
			case 4:
				i.seg = &fs;
				break;
			case 5:
				i.seg = &gs;
				break;
			}
			op_string += 4; /* skip % <x> s : */
			operand_string = op_string; /* Pretend given string starts here. */
			if (!is_digit_char(*op_string) && !is_identifier_char(*op_string)
					&& *op_string != '(' && *op_string != ABSOLUTE_PREFIX) {
				InternalError(1042);
			}
			/* Handle case of %es:*foo. */
			if (*op_string == ABSOLUTE_PREFIX) {
				op_string++;
				i.types[this_operand] |= JumpAbsolute;
			}
			goto do_memory_reference;
		}
		i.types[this_operand] |= r->reg_type;
		i.regs[this_operand] = r;
		i.reg_operands++;
	}
	else if (*op_string == IMMEDIATE_PREFIX) {  /* ... or an immediate */
		char *save_InputPointer;
		register expressionS *exp;
		segT exp_seg;
		if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) {
			InternalError(1043);
		}
		exp = &im_expressions[i.imm_operands++];
		i.imms[this_operand] = exp;
		save_InputPointer = InputPointer;
		InputPointer = ++op_string;   /* must advance op_string! */
		exp_seg = expression(exp);
		InputPointer = save_InputPointer;
		switch (exp_seg) {
		case SEG_NONE: /* missing or bad expr becomes absolute 0 */
			InternalError(1044);
			break;
		case SEG_ABSOLUTE:
			i.types[this_operand] |= SMALLEST_IMM_TYPE(exp->X_add_number);
			break;
		case SEG_TEXT:
		case SEG_DATA:
		case SEG_BSS:
		case SEG_UNKNOWN:
			i.types[this_operand] |= Imm32; /* this is an address ==> 32bit */
			break;
		default:
	seg_unimplemented:
			InternalError(1045);
		}
		/* shorten this type of this operand if the instruction wants fewer
		bits than are present in the immediate.*/
		switch (i.suffix) {
		case WORD_OPCODE_SUFFIX:
			i.types[this_operand] |= Imm16;
			break;
		case BYTE_OPCODE_SUFFIX:
			i.types[this_operand] |= Imm16 | Imm8 | Imm8S;
			break;
		}
	}
	else if (is_digit_char(*op_string) || is_identifier_char(*op_string)
			|| *op_string == '(') {
		/* This is a memory reference of some sort. */
		register char *base_string;
		unsigned int found_base_index_form;
do_memory_reference:
		if (i.mem_operands == MAX_MEMORY_OPERANDS) {
			InternalError(1046);
		}
		i.mem_operands++;
		/* Determine type of memory operand from opcode_suffix; no opcode
		suffix implies general memory references. */
		switch (i.suffix) {
		case BYTE_OPCODE_SUFFIX:
			i.types[this_operand] |= Mem8;
			break;
		case WORD_OPCODE_SUFFIX:
			i.types[this_operand] |= Mem16;
			break;
		case DWORD_OPCODE_SUFFIX:
		default:
			i.types[this_operand] |= Mem32;
		}
		/* Check for base index form.  We detect the base index form by
		looking for an ')' at the end of the operand, searching for the '('
		matching it, and finding a REGISTER_PREFIX or ',' after it. */
		base_string = end_of_operand_string - 1;
		while (*base_string == ' ') base_string--;
		found_base_index_form = FALSE;
		if (*base_string == ')') {
			unsigned int parens_balenced = 1;
			/* We've already checked that the number of left & right ()'s are
			equal, so this loop will not be infinite. */
			do {
				base_string--;
				if (*base_string == ')')
					parens_balenced++;
				if (*base_string == '(')
					parens_balenced--;
			} while (parens_balenced);
			base_string++;  /* Skip past '('. */
			if (*base_string == REGISTER_PREFIX || *base_string == ',')
				found_base_index_form = TRUE;
		}
		/* If we can't parse a base index register expression, we've found a
		pure displacement expression.  We set up displacement_string_start
		and displacement_string_end for the code below. */
		if (!found_base_index_form) {
			displacement_string_start = op_string;
			displacement_string_end = end_of_operand_string;
		}
		else {
			char *base_reg_name, *index_reg_name, *num_string;
			int num;
			i.types[this_operand] |= BaseIndex;
			/* If there is a displacement set-up for it to be parsed later. */
			if (base_string != op_string + 1) {
				displacement_string_start = op_string;
				displacement_string_end = base_string - 1;
			}
			/* Find base register (if any). */
			if (*base_string != ',') {
				base_reg_name = base_string++;
				/* skip past register name & parse it */
				while (isalpha(*base_string))
					base_string++;
				if (base_string == base_reg_name + 1) {
					InternalError(1047);
				}
				END_STRING_AND_SAVE(base_string);
				if (!(i.base_reg = parse_register(base_reg_name))) {
					InternalError(1048);
				}
				RESTORE_END_STRING(base_string);
			}
			/* Now check seperator; must be ',' ==> index reg OR num ==> no
			index reg. just scale factor OR ')' ==> end. (scale factor = 1) */
			if (*base_string != ',' && *base_string != ')') {
				InternalError(1049);
			}
			/* There may index reg here; and there may be a scale factor. */
			if (*base_string == ',' && *(base_string + 1) == REGISTER_PREFIX) {
				index_reg_name = ++base_string;
				while (isalpha(*++base_string));
				END_STRING_AND_SAVE(base_string);
				if (!(i.index_reg = parse_register(index_reg_name))) {
					InternalError(1050);
				}
				RESTORE_END_STRING(base_string);
			}
			/* Check for scale factor. */
			if (*base_string == ',' && isdigit(*(base_string + 1))) {
				num_string = ++base_string;
				while (is_digit_char(*base_string))
					base_string++;
				if (base_string == num_string) {
					InternalError(1051);
				}
				END_STRING_AND_SAVE(base_string);
				/* We've got a scale factor. */
				if (!sscanf(num_string, "%d", &num)) {
					InternalError(1052);
				}
				RESTORE_END_STRING(base_string);
				switch (num) {  /* must be 1 digit scale */
				case 1:
					i.log2_scale_factor = 0;
					break;
				case 2:
					i.log2_scale_factor = 1;
					break;
				case 4:
					i.log2_scale_factor = 2;
					break;
				case 8:
					i.log2_scale_factor = 3;
					break;
				default:
					InternalError(1053);
				}
			}
			else {
				if (!i.index_reg && *base_string == ',') {
					InternalError(1054);
				}
			}
		}
		/* If there's an expression begining the operand, parse it, assuming
		displacement_string_start and displacement_string_end are
		meaningful. */
		if (displacement_string_start) {
			register expressionS *exp;
			segT exp_seg;
			char *save_InputPointer;
			exp = &disp_expressions[i.disp_operands];
			i.disps[this_operand] = exp;
			i.disp_operands++;
			save_InputPointer = InputPointer;
			InputPointer = displacement_string_start;
			END_STRING_AND_SAVE(displacement_string_end);
			exp_seg = expression(exp);
			if (*InputPointer) {
				InternalError(2055);
			}
			RESTORE_END_STRING(displacement_string_end);
			InputPointer = save_InputPointer;
			switch (exp_seg) {
			case SEG_NONE:
				/* missing expr becomes absolute 0 */
				InternalError(1056);
				break;
			case SEG_ABSOLUTE:	/*!!!!*/
				i.types[this_operand] |= SMALLEST_DISP_TYPE(exp->X_add_number);
				break;
			case SEG_TEXT:
			case SEG_DATA:
			case SEG_BSS:
			case SEG_UNKNOWN:  /* must be 32 bit displacement (i.e. address) */
				i.types[this_operand] |= Disp32;
				break;
			default:
				goto seg_unimplemented;
			}
		}
		/* Make sure the memory operand we've been dealt is valid. */
		if (i.base_reg && i.index_reg &&
				!(i.base_reg->reg_type & i.index_reg->reg_type & Reg)) {
			InternalError(1057);
		}
		if ((i.base_reg && (i.base_reg->reg_type & Reg32) == 0) ||
				(i.index_reg && (i.index_reg->reg_type & Reg32) == 0)) {
			InternalError(1058);
		}
		if (i.index_reg && i.index_reg == esp) {
			InternalError(1059);
		}
	}
	else {              /* it's not a memory operand; argh! */
		InternalError(1060);
	}
	return 1;           /* normal return */
}
/* md_estimate_size_before_relax()
 * Called just before relax().
 * Any symbol that is now undefined will not become defined.
 * Return the correct fr_subtype in the frag.
 * Return the initial "guess for fr_var" to caller.
 * The guess for fr_var is ACTUALLY the growth beyond fr_fix.
 * Whatever we do to grow fr_fix or fr_var contributes to our returned value.
 * Although it may not be explicit in the frag, pretend fr_var starts with a
 * 0 value.
 */
static int md_estimate_size_before_relax(register fragS *fragP,
					register int segment_type) /* N_DATA or N_TEXT. */
{
	register uchar *opcode;
	register int old_fr_fix;
	old_fr_fix = fragP->fr_fix;
	opcode = (uchar *) fragP->fr_opcode;
	/* We've already got fragP->fr_subtype right;  all we have to do is check
	for un-relaxable symbols. */
	if ((fragP->fr_symbol->sy_type & N_TYPE) != segment_type) {
		/* symbol is undefined in this segment */
		switch (opcode[0]) {
		case JUMP_PC_RELATIVE: /* make jmp (0xeb) a dword displacement jump */
			opcode[0] = 0xe9;   /* dword disp jmp */
			fragP->fr_fix += 4;
			newFixup(fragP, old_fr_fix, 4,
					fragP->fr_symbol,
					(symbolS *) 0,
					fragP->fr_offset, 1);
			break;
		default:
			/* This changes the byte-displacement jump 0x7N --> the
			dword-displacement jump 0x0f8N */
			opcode[1] = opcode[0] + 0x10;
			opcode[0] = TWO_BYTE_OPCODE_ESCAPE; /* two-byte escape */
			fragP->fr_fix += 1 + 4; /* we've added an opcode byte */
			newFixup(fragP, old_fr_fix + 1, 4,
					fragP->fr_symbol,
					(symbolS *) 0,
					fragP->fr_offset, 1);
			break;
		}
		frag_wane(fragP);
	}
	return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
}                       /* md_estimate_size_before_relax() */
/* md_convert_frag();
 * Called after relax() is finished.
 * In:  Address of frag.
 *  fr_type == rs_machine_dependent.
 *  fr_subtype is what the address relaxed to.
 * Out: Any fixSs and constants are set up. Caller will turn frag into a ".space 0".
 */
static void md_convert_frag(register fragS *fragP)
{
	register uchar *opcode;
	uchar *where_to_put_displacement;
	unsigned int target_address, opcode_address;
	unsigned int extension,subtype;
	int displacement_from_opcode_start;
	opcode = (uchar *) fragP->fr_opcode;
	/* Address we want to reach in file space. */
	target_address = fragP->fr_symbol->SymbolValue + fragP->fr_offset;
	/* Address opcode resides at in file space. */
	opcode_address = fragP->fr_address + fragP->fr_fix;
	/* Displacement from opcode start to fill into instruction. */
	displacement_from_opcode_start = target_address - opcode_address;
	subtype = fragP->fr_subtype;
	switch (subtype) {
	case ENCODE_RELAX_STATE(COND_JUMP, BYTE):
	case ENCODE_RELAX_STATE(UNCOND_JUMP, BYTE):
		/* don't have to change opcode */
		extension = 1;  /* 1 opcode + 1 displacement */
		where_to_put_displacement = &opcode[1];
		break;
	case ENCODE_RELAX_STATE(COND_JUMP, WORD):
		opcode[1] = TWO_BYTE_OPCODE_ESCAPE;
		opcode[2] = opcode[0] + 0x10;
		opcode[0] = WORD_PREFIX_OPCODE;
		extension = 4;  /* 3 opcode + 2 displacement */
		where_to_put_displacement = &opcode[3];
		break;
	case ENCODE_RELAX_STATE(UNCOND_JUMP, WORD):
		opcode[1] = 0xe9;
		opcode[0] = WORD_PREFIX_OPCODE;
		extension = 3;  /* 2 opcode + 2 displacement */
		where_to_put_displacement = &opcode[2];
		break;
	case ENCODE_RELAX_STATE(COND_JUMP, DWORD):
		opcode[1] = opcode[0] + 0x10;
		opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
		extension = 5;  /* 2 opcode + 4 displacement */
		where_to_put_displacement = &opcode[2];
		break;
	case ENCODE_RELAX_STATE(UNCOND_JUMP, DWORD):
		opcode[0] = 0xe9;
		extension = 4;  /* 1 opcode + 4 displacement */
		where_to_put_displacement = &opcode[1];
		break;
	default:
		InternalError(1108);
		break;
	}
	/* now put displacement after opcode */
	displacement_from_opcode_start  -= extension;
	memcpy(where_to_put_displacement,&displacement_from_opcode_start,
			SIZE_FROM_RELAX_STATE(fragP->fr_subtype));

	fragP->fr_fix += extension;
}
/* reg_string starts *before* REGISTER_PREFIX */
static reg_entry *parse_register(char *reg_string)
{
	register char *s = reg_string;
	register char *p;
	char reg_name_given[MAX_REG_NAME_SIZE+2];
	unsigned long l,*pl;
	int i;
	s++;                /* skip REGISTER_PREFIX */
	for (p = reg_name_given; is_register_char(*s); p++, s++) {
		*p = register_chars[*s];
		if (p >= reg_name_given + MAX_REG_NAME_SIZE)
			return (reg_entry *) 0;
	}
	*p++ = '\0';
	*p++ = 0;
	*p++ = 0;
	pl = (unsigned long *)reg_name_given;
	l = *pl;
	pl = (unsigned long *)RegisterNames;
	for (i=0; i<MAX_REG_NAMES; i++,pl++) {
		if (*pl == l) break;
	}
	if (i >= MAX_REG_NAMES) 
		return(NULL);
	else
		return(&i386_regtab[i]);
}

static int NrOfTextFixups = 0, NrOfDataFixups = 0, NrOfLineNumbers = 0;
static long int CodeSize, DataSize, NrOfCoffSymbols;
static int PosCodeSection, PosDataSection, PosBssSection, 
		PosRawData,PosDebugSymbolsSection,PosDebugTypesSection,
		PosDebugSSpecialSymbol,PosDebugTSpecialSymbol;
static FILE *CoffFile;
static void WriteCoffHeader(void)
{                       /* Number of symbols ns */
	unsigned char Header[20];
	unsigned short *pus;
	unsigned long *pul;
	symbolS *coffS;
	int count;
	memset(Header, 0, 20);
	/* Write the machine type: I386 */
	pus = (unsigned short *) (&Header[0]);
	*pus = 0x14c;
	/* Write the number of sections */
	pus = (unsigned short *) (&Header[2]);
	*pus = 3 + NumberOfDebugSections + NumberOfSpecialSections;
	/* Write the time stamp */
	pul = (unsigned long *) (&Header[4]);
	*pul = time(NULL);
	/* Write the pointer to the symbol table */
	/* null for now */
	/* Write the number of symbols */
	pul = (unsigned long *) (&Header[12]);
	coffS = symbol_rootP;
	count = 0;
	while (coffS) {
		count++;
		coffS = coffS->Next;
	}
	*pul = count;
	if (20 != fwrite(Header, 1, 20, CoffFile)) {
		WriteError();
	}
	/* the optional header and the characteristics fields are zero for object
	files */
}
static long WriteTextSection(long siz, long nfixups)
{
	unsigned char Section[40];
	unsigned long *pul;
	unsigned short *pus;
	unsigned long result;
	memset(Section, 0, 40);
	strcpy(Section, ".text");
	/* Write the virtual size */
	pul = (unsigned long *) (&Section[8]);
	/* Write the RVA Offset. Should be zero */
	/* Write the size of the raw data */
	pul = (unsigned long *) (&Section[16]);
	*pul = siz;
	/* Write a pointer to the raw data position in the file. 0 for now */
	/* Write a pointer to the location of the relocs. 0 for now */
	/* Write a pointer to the line numbers. Zero for now */
	/* Write the number of relocations */
	pus = (unsigned short *) (&Section[32]);
	*pus = (unsigned short) nfixups;
	/* the number of linenumbers is left to zero for now */
	/* the flags field is left empty */
	pul = (unsigned long *) (&Section[36]);
	/* CODE MEM_EXECUTE MEM_READ */
	*pul = 0x00000020L | 0x20000000L | 0x40000000L;
	result = ftell(CoffFile);
	if (40 != fwrite(Section, 1, 40, CoffFile)) {
		WriteError();
	}
	return (result);
}
static long WriteDataSection(long siz, long nfixups, int addr)
{
	unsigned char Section[40];
	unsigned long *pul;
	unsigned short *pus;
	unsigned long result;
	memset(Section, 0, 40);
	strcpy(Section, ".data");
	/* Write the virtual size */
	pul = (unsigned long *) (&Section[8]);
	*pul = CodeSize; 
	/* Write the RVA Offset. */
	pul = (unsigned long *) (&Section[12]);
	*pul = addr;
	/* Write the size of the raw data */
	pul = (unsigned long *) (&Section[16]);
	*pul = siz;
	/* Write a pointer to the raw data position in the file. 0 for now */
	/* Write a pointer to the location of the relocs. 0 for now */
	/* Write a pointer to the line numbers. Zero for now */
	/* Write the number of relocations */
	pus = (unsigned short *) (&Section[32]);
	*pus = (unsigned short) nfixups;
	/* the number of linenumbers is left to zero for now */
	/* the flags field is left empty */
	pul = (unsigned long *) (&Section[36]);
	/* INITIALIZED_DATA MEM_WRITE MEM_READ */
	*pul = 0x00000040L | 0x80000000L | 0x40000000L;
	result = ftell(CoffFile);
	if (40 != fwrite(Section, 1, 40, CoffFile)) {
		WriteError();
	}
	return (result);
}
static long WriteDebugSection(int typesFlag)
{
	unsigned char Section[40];
	unsigned long *pul;
	unsigned long result;

	memset(Section, 0, 40);
	if (typesFlag) strcpy(Section,".debug$T");
	else strcpy(Section, ".debug$S");
	/* Write the virtual size */
	/* Write the RVA Offset. */
	/* Write the size of the raw data */
	/* Write a pointer to the raw data position in the file. 0 for now */
	/* Write a pointer to the location of the relocs. 0 for now */
	/* Write a pointer to the line numbers. Zero for now */
	/* Write the number of relocations */
	/* the number of linenumbers is left to zero for now */
	/* the flags field is left empty */
	pul = (unsigned long *) (&Section[36]);
	/* INITIALIZED_DATA MEM_READ MEM_DISCARDABLE ALIGN 1 byte no padding*/
	*pul = 0x00000040L | 0x40000000L|0x02000000|0x00100000|0x8;
	result = ftell(CoffFile);
	if (40 != fwrite(Section, 1, 40, CoffFile)) {
		WriteError();
	}
	return (result);
}

static long WriteBssSection(long siz)
{
	unsigned char Section[40];
	unsigned long *pul;
	unsigned short *pus;
	unsigned long result;
	memset(Section, 0, 40);
	strcpy(Section, ".bss");
	/* Write the virtual size */
	pul = (unsigned long *) (&Section[8]);
	*pul = CodeSize+DataSize;
	/* Write the RVA Offset. Should be zero */
	/* Write the size of the raw data */
	pul = (unsigned long *) (&Section[16]);
	*pul = siz;
	/* Write a pointer to the raw data position in the file. 0 for now */
	/* Write a pointer to the location of the relocs. 0 for now */
	/* Write a pointer to the line numbers. Zero for now */
	/* Write the number of relocations */
	pus = (unsigned short *) (&Section[32]);
	*pus = (unsigned short) 0;
	/* the number of linenumbers is left to zero for now */
	pul = (unsigned long *) (&Section[36]);
	/* UNINITIALIZED_DATA MEM_WRITE MEM_READ */
	*pul = 0x00000080L| 0x80000000L | 0x40000000L;
	result = ftell(CoffFile);
	if (40 != fwrite(Section, 1, 40, CoffFile)) {
		WriteError();
	}
	return (result);
}

static void WriteSpecialSectionHeaders(void)
{
	unsigned char Section[40];
	unsigned long *pul;
	unsigned short *pus;
	unsigned long result;
	NewSection *rvp;
	int ssectionSize;

	rvp = SectionList;
	ssectionSize = 0;
	while (rvp) {
		memset(Section, 0, 40);
		strcpy(Section, rvp->Name);
		/* Write the virtual size */
		pul = (unsigned long *) (&Section[8]);
		*pul = CodeSize+DataSize+local_bss_counter+ssectionSize;
		/* Write the RVA Offset. Should be zero */
		/* Write the size of the raw data */
		pul = (unsigned long *) (&Section[16]);
		*pul = rvp->DataSize;
		ssectionSize += rvp->DataSize;
		/* Write a pointer to the raw data position in the file. 0 for now */
		/* Write a pointer to the location of the relocs. 0 for now */
		/* Write a pointer to the line numbers. Zero for now */
		/* Write the number of relocations */
		pus = (unsigned short *) (&Section[32]);
		*pus = (unsigned short) 0;
		/* the number of linenumbers is left to zero for now */
		pul = (unsigned long *) (&Section[36]);
		/* INITIALIZED_DATA MEM_WRITE MEM_READ */
		/* guess the section flags */
		if (!strcmp(rvp->Name,".rdata"))
			/* Initialized data, mem_read */
			*pul = 0x40000040;
		else	/* initialized data mem_read mem_write */
			*pul = 0x00000040L | 0x80000000L | 0x40000000L;
		result = ftell(CoffFile);
		if (40 != fwrite(Section, 1, 40, CoffFile)) {
			WriteError();
		}
		rvp->HeaderPosition = result;
		rvp = rvp->Next;
	}
}

void WriteSpecialSectionData(void)
{
	NewSection *rvp;
	int PosNow;

	rvp = SectionList;
	while (rvp) {
		if (rvp->data) {
			fseek(CoffFile,0,SEEK_END);
			PosNow = ftell(CoffFile);
			fwrite(rvp->data,1,rvp->DataSize,CoffFile);
			fseek(CoffFile,rvp->HeaderPosition+20,SEEK_SET);
			fwrite(&PosNow, 1, 4, CoffFile);
		}
		rvp = rvp->Next;
	}
	fseek(CoffFile,0,SEEK_END);
}

static int ArrangeDataSection(int ordinal)
{
	symbolS *coffS;
	symbolS *symbolP;

	symbolP = symbol_table_lookup(".data");
	symbolP->OrdinalNumber = ordinal;
	ordinal++;
	ordinal++;          /* count the auxiliary symbol */
	symbolP->Flags |= COUNTED;
	symbolP = symbol_table_lookup(".bss");
	symbolP->Flags |= COUNTED;
	coffS = symbol_rootP;
	while (coffS) {
		if ((coffS->Flags & COUNTED) == 0) {
			if (coffS->Flags & IS_DATA) {
				coffS->OrdinalNumber = ordinal;
				ordinal++;
				coffS->Flags |= COUNTED;
			}
		}
		coffS = coffS->Next;
	}
	symbolP = symbol_table_lookup(".bss");
	symbolP->OrdinalNumber = ordinal;
	symbolP->Flags |= COUNTED;
	ordinal++;
	ordinal++;
	coffS = symbol_rootP;
	while (coffS) {
		if ((coffS->Flags & COUNTED) == 0) {
			if (coffS->Flags & IS_BSS) {
				coffS->OrdinalNumber = ordinal;
				ordinal++;
				coffS->Flags |= COUNTED;
			}
		}
		coffS = coffS->Next;
	}
	symbolP = symbol_table_lookup(".text");
	symbolP->Flags |= COUNTED;
	symbolP->OrdinalNumber = ordinal;
	ordinal++;
	ordinal++;
	return (ordinal);
}
static int ArrangeOrdinalNumbers(char *name)
{
	int ordinal,len;
	symbolS *coffS,*lastS;

	len = strlen(name);
	ordinal = (len / 18);
	if (len % 18) ordinal++;
	ordinal++;
	ordinal = ArrangeDataSection(ordinal);
	coffS = symbol_rootP;
	lastS = NULL;
	while (coffS) {
		if ((coffS->Flags & COUNTED) == 0) {
			coffS->OrdinalNumber = ordinal;
			ordinal++;
			if (glevel && coffS->Flags & IS_FUNCTION) {   /* Function */
				if (lastS) {
					lastS->FnInfo->NextFnIdx = coffS->OrdinalNumber;
				}
				lastS = coffS;
				ordinal++;  /* count the auxiliary symbol */
				coffS->NumberOfAuxSymbols = 1;
				ordinal += 3;   /* count the .bf .lf and .ef records */
				ordinal += 2;   /* .bf and .ef have aux. symbols */
			}
			else {
				if (coffS->NumberOfAuxSymbols)
					ordinal++;
			}
		}
		coffS = coffS->Next;
	}
	coffS = symbol_rootP;
	while (coffS) {
		coffS->Flags &= ~COUNTED;
		coffS = coffS->Next;
	}
	return (ordinal);
}
static int SortFun(const void *f1, const void *f2)
{
	COFF_RELOC *s1, *s2;
	s1 = *(COFF_RELOC **) f1;
	s2 = *(COFF_RELOC **) f2;
	if (s1->Offset > s2->Offset)
		return (1);
	else if (s1->Offset < s2->Offset)
		return (-1);
	else
		return (0);
}
static int WriteRelocations(int which)
{
	symbolS *coffS;
	int count, ordinal, i;
	char reloc[10];
	unsigned long *pul;
	unsigned short *pus;
	COFF_RELOC *rvp, **table;
	fixS *fixP;

	coffS = symbol_rootP;
	count = 0;
	while (coffS) {
		rvp = coffS->Relocations;
		while (rvp) {
			fixP = rvp->pfixS;
			if (coffS->Flags & (IS_DATA | IS_BSS))
				rvp->Offset = fixP->fx_frag->fr_address + fixP->fx_where;
			if (rvp->TargetSegment & which)
				count++;
			rvp = rvp->Next;
		}
		coffS = coffS->Next;
	}
	table = (COFF_RELOC **) xmalloc(sizeof(COFF_RELOC *) * count);
	coffS = symbol_rootP;
	count = 0;
	while (coffS) {
		rvp = coffS->Relocations;
		while (rvp) {
			if (rvp->TargetSegment & which) {
				table[count++] = rvp;
			}
			rvp = rvp->Next;
		}
		coffS = coffS->Next;
	}
	qsort(table, count, sizeof(COFF_RELOC *), SortFun);
	for (i = 0; i < count; i++) {
		memset(reloc, 0, 10);
		coffS = table[i]->Symbol;
		if (table[i]->TargetSegment & which) {
			pul = (unsigned long *) reloc;
			*pul++ = table[i]->Offset;
			ordinal = coffS->OrdinalNumber;
			*pul++ = ordinal;
			pus = (unsigned short *) pul;
			if (table[i]->TargetSegment & IS_DATA)
				*pus = 0x6;
			else
				*pus = table[i]->Type;
			if (10 != fwrite(reloc, 1, 10, CoffFile)) {
				WriteError();
			}
		}
	}
	free(table);
	return (count);
}

static STRING *NewString(char *s, int len)
{
	STRING *result;

	result = (STRING *) xmalloc(sizeof(STRING));
	result->len = len;
	result->String = xmalloc(len);
	strcpy(result->String, s);
	return (result);
}
static int AddStringToStringTable(char *str)
{
	STRING *s;
	int len, pos;
	if (StringTable == NULL) {
		StringTable = (STRING_TABLE *) xmalloc(sizeof(STRING_TABLE));
	}
	s = StringTable->Strings;
	len = strlen(str) + 1;
	pos = 4;
	while (s && s->Next) {
		if (s->len == len && !strcmp(str, s->String)) {
			return (pos);
		}
		pos += s->len;
		s = s->Next;
	}
	if (s == NULL) {
		s = NewString(str, len);
		StringTable->Strings = s;
		StringTable->Size = len;
	}
	else {
		pos += s->len;
		s->Next = NewString(str, len);
		StringTable->Size += len;
	}
	return (pos);
}
static long WriteStringTable(void)
{
	long pos, total;
	STRING *s;
	pos = ftell(CoffFile);
	/* Contrary to the documentation of microsoft the length of the string
	table header IS included in the total length of the string table. */
	total = 4;
	fwrite(&total, 1, 4, CoffFile);
	if (StringTable == NULL)
		return (pos + 4);
	s = StringTable->Strings;
	while (s) {
		if (s->len != (int) fwrite(s->String, 1, s->len, CoffFile)) {
			WriteError();
		}
		total += s->len;
		s = s->Next;
	}
	fseek(CoffFile, pos, SEEK_SET);
	fwrite(&total, 1, 4, CoffFile);
	fseek(CoffFile, 0, SEEK_END);
	return (pos);
}

void WriteFunctionsDebugRelocations(int *offsets,symbolS **table,int n)
{
	unsigned char reloc[10],*p;
	int i,relocPos;

	relocPos = ftell(CoffFile);
	for (i=0; i<n;i++) {
		memset(reloc,0,10);
		p = reloc;
		*(unsigned long *)p = offsets[i];
		p += sizeof(int);
		*(unsigned long *)p = table[i]->OrdinalNumber;
		p += sizeof(int);
		*(unsigned short *)p = 0xB;
		fwrite(reloc,1,10,CoffFile);
		*(unsigned short *)p = 0xA;
		p = reloc;
		*(unsigned long *)p = 4 + offsets[i];
		fwrite(reloc,1,10,CoffFile);
	}
	fseek(CoffFile,PosDebugSymbolsSection+24,SEEK_SET);
	fwrite(&relocPos,1,4,CoffFile);
	fseek(CoffFile,PosDebugSymbolsSection+32,SEEK_SET);
	n = n + n;
	fwrite(&n,1,4,CoffFile);
	fseek(CoffFile,0,SEEK_END);
}
static int GetDebugDataSymbolsLength(int *n)
{
	DataList *rvp;
	int result,c;

	rvp = DataSymbolsInfo;
	result = 0;
	*n = 0;
	c = 0;
	while (rvp) {
		if (symbol_table_lookup(rvp->Name)) {
			result += rvp->len;
			c++;
		}
		rvp = rvp->Next;
	}
	*n = c;
	return(result);
}

static char *PutDebugDataSymbols(char *where,int *offsets,symbolS **table,int start,int startoffset)
{
	char *p = where;
	DataList *rvp;

	rvp = DataSymbolsInfo;
	while (rvp) {
		table[start] = symbol_table_lookup(rvp->Name);
		if (table[start] != NULL) {
			memcpy(p,rvp->data,rvp->len);
			offsets[start] = (p - where) + 4 + startoffset;
			start++;
			p += rvp->len;
		}
		rvp = rvp->Next;
	}
	return(p);
}
void WriteDebugTypes(void)
{
	int len;
	unsigned char *data,*p;
	int pos;
	DataList *dl;

	dl = DataTypesInfo;
	len = 0;
	while (dl) {
		len += dl->len;
		dl = dl->Next;
	}
	len += 4;
	data = malloc(len);
	p = data;
	*(unsigned long *)p = 1;
	p += 4;
	dl = DataTypesInfo;
	while (dl) {
		memcpy(p,dl->data,dl->len);
		p += dl->len;
		dl = dl->Next;
	}
	pos = ftell(CoffFile);
	fwrite(data,1,len,CoffFile);
	fseek(CoffFile,PosDebugTypesSection+16,SEEK_SET);
	fwrite(&len,1,4,CoffFile);
	fwrite(&pos,1,4,CoffFile);
	/* Fix the data size in the .debug$T symbol */
	fseek(CoffFile,PosDebugTSpecialSymbol,SEEK_SET);
	fwrite(&len,1,4,CoffFile);
	fseek(CoffFile,0,SEEK_END);
	free(data);
}

static char *wccSignature = "Logiciels/Informatique lcc-win32 version 1.1";
void WriteDebugData(void)
{
	int len=0,nameLen,debugdataPos,proclen,nrOfFunctions,*relocAddr;
	unsigned short nrOfRelocations;
	int dataSymbolsLen,nrOfDataSymbols;
	int objNameRecordLen;
	ProcList *pl;
	char *data,*p,*n;
	symbolS *coffS,**table;

	pl = ProceduresList;
	nrOfFunctions = 0;
	while (pl) {
		len += pl->len + sizeof(struct procInfo)+2+2;
		len -= 4;
		len += strlen(pl->procInfo.u.Name)+1;
		pl = pl->Next;
		nrOfFunctions++;
	}
	len += 4; /* 1 signature as a long */
	/* Count the length of the object record name */
	p = strrchr(OutputFileName,'\\');
	if (p) p++;
	else p = OutputFileName;
	nameLen = strlen(p);
	n = p;
	objNameRecordLen = nameLen + 1 + 2 + 2 + 4;
	len += objNameRecordLen;
	/* Add the block end record for each function */
	len += 4 * nrOfFunctions;
	/* add the compiler info */
	len += 8 + strlen(wccSignature)+1;

	dataSymbolsLen = GetDebugDataSymbolsLength(&nrOfDataSymbols);
	len += dataSymbolsLen;
	data = xmalloc(len);
	relocAddr = (int *)xmalloc(sizeof(int)*(nrOfFunctions+nrOfDataSymbols));
	table = (symbolS **)xmalloc(sizeof(symbolS *)*(nrOfFunctions+nrOfDataSymbols));
	*(unsigned long *)data = 1;	
	p = data + 4;
	*(unsigned short *)p = objNameRecordLen - 2;
	p += 2;
	*(unsigned short *)p = 0x9;
	p += 2;
	*(unsigned long *)p = 0;
	p += 4;
	*p++ = nameLen;
	while (*n) {
		*p++ = *n++;
	}
	pl = ProceduresList;
	nrOfFunctions = 0;
	while (pl) {
		proclen = 2 + sizeof(struct procInfo)-4;
		n = pl->procInfo.u.Name;
		nameLen = strlen(n);
		proclen += nameLen +1;
		*(unsigned short *)p = proclen;
		p += 2;
		if (pl->Sym->sclass == STATIC) {
			*(unsigned short *)p = 0x204; /* Local procedure */
		}
		else
			*(unsigned short *)p = 0x205; /* Global procedure */

		p += 2;
		coffS = symbol_table_lookup(n);
		assert(coffS->FnInfo);
		pl->procInfo.procLength = coffS->FnInfo->End->SymbolValue - coffS->FnInfo->Start->SymbolValue;
		pl->procInfo.debugStart = pl->Sym->x.PrologueEnd;
		if (pl->procInfo.procLength > 4)
			pl->procInfo.debugEnd = pl->procInfo.procLength - 5;
		else
			pl->procInfo.debugEnd = pl->procInfo.debugStart;
		memcpy(p,&pl->procInfo,sizeof(struct procInfo)-4);
		table[nrOfFunctions] = coffS;
		relocAddr[nrOfFunctions] = (p - data) + 24;
		p += sizeof(struct procInfo) - 4;
		p = PutLengthPrefixedName(p,n);
		memcpy(p,pl->data,pl->len);
		p += pl->len;
		*(unsigned short *)p = 2;
		p += 2;
		*(unsigned short *)p = 0x06; /* S_END */
		p += 2;
		pl = pl->Next;
		nrOfFunctions++;
	}
	p = PutDebugDataSymbols(p,relocAddr,table,nrOfFunctions,p - data);
	*(unsigned short *)p = 8 + strlen(wccSignature) + 1 - 2;
	p += 2;
	*(unsigned short *)p = 0x1; /* S_COMPILE */
	p += 2;
	*p++ = 4; /* Processor 80486 for now */
	p += 3; /* Flags empty for now */
	p = PutLengthPrefixedName(p,wccSignature);
	debugdataPos = ftell(CoffFile);
	fwrite(data,1,len,CoffFile);
	fseek(CoffFile,PosDebugSymbolsSection+16,SEEK_SET);
	fwrite(&len,1,4,CoffFile);
	fwrite(&debugdataPos,1,4,CoffFile);
	fseek(CoffFile,0,SEEK_END);
	nrOfRelocations = nrOfFunctions+nrOfDataSymbols;
	WriteFunctionsDebugRelocations(relocAddr,table,nrOfRelocations);
	/* Fix the .debug$S special symbol */
	fseek(CoffFile,PosDebugSSpecialSymbol,SEEK_SET);
	fwrite(&len,1,4,CoffFile);
	nrOfRelocations *= 2;
	fwrite(&nrOfRelocations,1,2,CoffFile);
	fseek(CoffFile,0,SEEK_END);
	WriteDebugTypes();
	free(data);
	free(relocAddr);
}


static int SortSymbols(const void *f1, const void *f2)
{
	symbolS *s1, *s2;
	s1 = *(symbolS **) f1;
	s2 = *(symbolS **) f2;
	if (s1->SymbolValue > s2->SymbolValue)
		return (1);
	else if (s1->SymbolValue < s2->SymbolValue)
		return (-1);
	else
		return (0);
}
static int WriteLineNumbers(int PosCodeSection)
{
	symbolS *coffS, **coffSTable;
	unsigned long *pul;
	unsigned short *pus;
	int count, functions, size, totalCount, i;
	long pos;
	unsigned short LineNumbers;
	char *table, *p;
	unsigned short Short;
	COFF_LINE *coffL;

	coffS = symbol_rootP;
	count = 0;
	functions = 0;
	while (coffS) {
		if ((coffS->Flags & IS_FUNCTION) && coffS->Lines) {
			functions++;
			coffL = coffS->Lines;
			while (coffL) {
				count++;
				coffL = coffL->Next;
			}
		}
		coffS = coffS->Next;
	}
	if (functions == 0) return(0);
	coffSTable = (symbolS **) xmalloc(functions * sizeof(symbolS *));
	coffS = symbol_rootP;
	i = 0;
	while (coffS) {
		if ((coffS->Flags & IS_FUNCTION) && coffS->Lines) {
			coffSTable[i++] = coffS;
		}
		coffS = coffS->Next;
	}
	qsort(coffSTable, functions, sizeof(symbolS *), SortSymbols);
	pos = ftell(CoffFile);
	size = 6 * (functions + count);
	totalCount = functions + count;
	table = xmalloc(size);
	p = table;
	coffS = symbol_rootP;
	LineNumbers = 0;
	for (i = 0; i < functions; i++) {
		coffS = coffSTable[i];
		if ((coffS->Flags & IS_FUNCTION) && coffS->Lines) {
			pul = (unsigned long *) p;
			*pul = coffS->OrdinalNumber;
			pus = (unsigned short *) (&p[4]);
			*pus = 0;
			coffL = coffS->Lines;
			if (coffS->FnInfo)
				coffS->FnInfo->LineNumbersFileOffset = pos + (p - table);
			else
				InternalError(1113);
			p += 6;
			LineNumbers++;
			while (coffL) {
				pul = (unsigned long *) p;
				*pul = coffL->Frag->fr_address + coffL->fragOffset;
				pus = (unsigned short *) (&p[4]);
				*pus = (unsigned short)coffL->Line;
				p += 6;
				LineNumbers++;
				coffL = coffL->Next;
			}
		}
	}
	if (size != (int) fwrite(table, 1, size, CoffFile)) {
		WriteError();
	}
	free(table);
	free(coffSTable);
	fseek(CoffFile, PosCodeSection + 28, SEEK_SET);
	fwrite(&pos, 1, 4, CoffFile);
	fseek(CoffFile, PosCodeSection + 34, SEEK_SET);
	Short = (unsigned short) LineNumbers;
	fwrite(&Short, 1, 2, CoffFile);

	if (glevel > 1) {
		fseek(CoffFile,PosDebugSymbolsSection + 28,SEEK_SET);
		fwrite(&pos, 1, 4, CoffFile);
		fseek(CoffFile, PosDebugSymbolsSection + 34, SEEK_SET);
		fwrite(&Short,1,2,CoffFile);
	}
	fseek(CoffFile, 0, SEEK_END);
	return (totalCount);
}
static int WriteOneSymbol(char *p)
{
	if (18 != (int) fwrite(p, 1, 18, CoffFile)) {
		WriteError();
	}
	return (1);
}
static int WriteFunctionRecords(symbolS * coffS)
{
	char AuxSymbol[18];
	unsigned long *pul;
	unsigned short *pus;
	int size, count;
	symbolS *start, *end;
	COFF_LINE *rvpCL;

	/* 1. Write the auxiliary symbol for the function */
	memset(AuxSymbol, 0, 18);
	/* 1.A Tag index */
	pul = (unsigned long *) AuxSymbol;
	*pul++ = coffS->FnInfo->Tag;
	start = coffS->FnInfo->Start;
	end = coffS->FnInfo->End;
	size = 0;
	if (start && end) {
		size = end->SymbolValue - start->SymbolValue;
	}
	*pul++ = size;
	/* 1.B write the linenumbers record. */
	if (coffS->FnInfo)
		*pul++ = coffS->FnInfo->LineNumbersFileOffset;
	else
		*pul++ = 0;
	/* 1.C Write the pointer to the next function */
	*pul = coffS->FnInfo->NextFnIdx;
	WriteOneSymbol(AuxSymbol);
	/* Write the .bf record */
	memset(AuxSymbol, 0, 18);
	strcpy(AuxSymbol, ".bf");
	pul = (unsigned long *) (&AuxSymbol[8]);
	*pul = coffS->SymbolValue;
	pus = (unsigned short *) (&AuxSymbol[12]);
	*pus = SECTION_TEXT;
	pus = (unsigned short *) (&AuxSymbol[14]);
	*pus++ = 0;         /* function */
	*pus = 101;
	AuxSymbol[17] = 1;
	WriteOneSymbol(AuxSymbol);
	/* Write the auxiliary record for the .bf symbol */
	memset(AuxSymbol, 0, 18);
	/* Write the linenumbers */
	pus = (unsigned short *) (&AuxSymbol[4]);
	*pus = (unsigned short)coffS->StartLine;
	pul = (unsigned long *) (&AuxSymbol[12]);
	*pul = coffS->FnInfo->NextFnIdx;
	WriteOneSymbol(AuxSymbol);
	/* Write the .lf record */
	memset(AuxSymbol, 0, 18);
	strcpy(AuxSymbol, ".lf");
	pul = (unsigned long *) (&AuxSymbol[8]);
	rvpCL = coffS->Lines;
	count = 0;
	while (rvpCL) {
		count++;
		rvpCL = rvpCL->Next;
	}
	*pul = count + 1;
	pus = (unsigned short *) (&AuxSymbol[12]);
	*pus = SECTION_TEXT;
	pus = (unsigned short *) (&AuxSymbol[14]);
	*pus++ = 0x0;
	*pus = 101;
	WriteOneSymbol(AuxSymbol);
	/* Write .ef record */
	memset(AuxSymbol, 0, 18);
	strcpy(AuxSymbol, ".ef");
	pul = (unsigned long *) (&AuxSymbol[8]);
	*pul = coffS->SymbolValue + size;
	pus = (unsigned short *) (&AuxSymbol[12]);
	*pus = SECTION_TEXT;
	pus = (unsigned short *) (&AuxSymbol[14]);
	*pus++ = 0;
	*pus = 101;
	AuxSymbol[17] = 1;
	WriteOneSymbol(AuxSymbol);
	/* Write the auxiliary record for the .ef symbol */
	memset(AuxSymbol, 0, 18);
	/* Write the linenumbers */
	pus = (unsigned short *) (&AuxSymbol[4]);
	*pus = (unsigned short)coffS->EndLine;
	return (WriteOneSymbol(AuxSymbol));
}
static int SymbolToChars(symbolS * coffS)
{
	char Symbol[18];
	unsigned long *pul, Pos;
	unsigned short *pus;
	unsigned char *puc;
	char *temp;

	memset(Symbol, 0, 18);
	temp = coffS->Name;
	if (strlen(temp) > 8) {
		Pos = AddStringToStringTable(temp);
		pul = (unsigned long *) (&Symbol[4]);
		*pul = Pos;
	}
	else {
		strncpy(Symbol, temp, 8);
	}
	/* Write the value */
	pul = (unsigned long *) (&Symbol[8]);
	*pul = coffS->SymbolValue;
	/* Write the section One based index */
	pus = (unsigned short *) (&Symbol[12]);
	*pus = (unsigned short)coffS->SectionNumber;
	/* Write the type */
	pus = (unsigned short *) (&Symbol[14]);
	*pus = (unsigned short)coffS->Type; /* static */
	/* Write the storage class */
	puc = (unsigned char *) (&Symbol[16]);
	*puc = (unsigned char)coffS->StorageClass;
	puc = (unsigned char *) (&Symbol[17]);
	*puc = (unsigned char)coffS->NumberOfAuxSymbols;
	return (WriteOneSymbol(Symbol));
}
static int WriteDataSymbols(int count)
{
	symbolS *coffS,*sdata,*sbss;
	char AuxSymbol[18];
	unsigned long *pul;

	sdata = symbol_table_lookup(".data");
	sbss = symbol_table_lookup(".bss");
	coffS = symbol_rootP;
	while (coffS) {
		if (coffS->Flags & IS_DATA) {
			if (coffS != sdata) {
				if (coffS != sbss) {
					if (coffS->Flags & (IS_TEXT|IS_BSS)) {
						fprintf(stderr,"Symbol %s has all flags\n",coffS->Name);
						coffS->Flags &= ~(IS_TEXT|IS_BSS);
					}
					SymbolToChars(coffS);
					count++;
				}
			}
		}
		coffS = coffS->Next;
	}
	SymbolToChars(symbol_table_lookup(".bss"));
	memset(AuxSymbol, 0, 18);
	pul = (unsigned long *) AuxSymbol;
	*pul = local_bss_counter;
	WriteOneSymbol(AuxSymbol);
	count += 2;
	coffS = symbol_rootP;
	while (coffS) {
		if (coffS->Flags & IS_BSS) {
			if (coffS != sdata) {
				if (coffS != sbss) {
					if (coffS->Flags & (IS_TEXT|IS_DATA)) {
						fprintf(stderr,"Symbol %s has all flags\n",coffS->Name);
						coffS->Flags &= ~(IS_TEXT|IS_DATA);
					}
					SymbolToChars(coffS);
					count++;
				}
			}
		}
		coffS = coffS->Next;
	}

	return (count);
}
static int WriteSpecialSymbols(int result)
{
	symbolS *coffS;
	char AuxSymbol[18];
	unsigned long *pul;
	unsigned short *pus;

	/* Write the special ".data" symbol */
	SymbolToChars(symbol_table_lookup(".data"));
	memset(AuxSymbol, 0, 18);
	pul = (unsigned long *) AuxSymbol;
	*pul = DataSize;
	pus = (unsigned short *) (&AuxSymbol[4]);
	*pus = (unsigned short)NrOfDataFixups;
	pus = (unsigned short *) (&AuxSymbol[6]);
	*pus = 0;
	pus = (unsigned short *) (&AuxSymbol[12]);
	/* The section number should be zero. If it is not, the line numbers
	   will not be recognized. Please, do not ask why is this so */
	*pus = 0;
	WriteOneSymbol(AuxSymbol);
	result = WriteDataSymbols(result + 2);

	/* Write the special ".text" symbol */
	coffS = symbol_table_lookup(".text");
	SymbolToChars(coffS);
	memset(AuxSymbol, 0, 18);
	pul = (unsigned long *) AuxSymbol;
	*pul = CodeSize;
	pus = (unsigned short *) (&AuxSymbol[4]);
	*pus = (unsigned short)NrOfTextFixups;
	pus = (unsigned short *) (&AuxSymbol[6]);
	*pus = (unsigned short)NrOfLineNumbers;
	pus = (unsigned short *) (&AuxSymbol[12]);
	*pus = 0;
	WriteOneSymbol(AuxSymbol);
	result += 2;
	return (result);
}
static int WriteDebugSpecialSymbols(int result)
{
	symbolS coffS;
	char AuxSymbol[18];

	if (glevel < 2) return(0);
	memset(&coffS,0,sizeof(coffS));
	coffS.Name = ".debug$S";
	coffS.SectionNumber = NumberOfSpecialSections + 4;
	coffS.OrdinalNumber = result++;
	coffS.NumberOfAuxSymbols = 1;
	coffS.StorageClass = 3;
	/* Write the special ".debug$S" symbol */
	SymbolToChars(&coffS);
	PosDebugSSpecialSymbol = ftell(CoffFile);
	memset(AuxSymbol, 0, 18);
	WriteOneSymbol(AuxSymbol);
	result++;
	/* Write the special ".debug$T" symbol */
	memset(&coffS,0,sizeof(coffS));
	coffS.Name = ".debug$T";
	coffS.SectionNumber = NumberOfSpecialSections + 5;
	coffS.OrdinalNumber = result++;
	coffS.NumberOfAuxSymbols = 1;
	coffS.StorageClass = 3;
	SymbolToChars(&coffS);
	PosDebugTSpecialSymbol = ftell(CoffFile);
	memset(AuxSymbol, 0, 18);
	WriteOneSymbol(AuxSymbol);
	result++;
	return (4);
}
static int WriteSpecialSectionSymbols(int startCount)
{
	symbolS coffS;
	char AuxSymbol[18];
	int symbolsWritten = 0;
	NewSection *rvp;

	rvp = SectionList;
	while (rvp) {
		memset(&coffS,0,sizeof(coffS));
		coffS.Name = rvp->Name;
		coffS.SectionNumber = rvp->Number;
		coffS.OrdinalNumber = startCount++;
		coffS.NumberOfAuxSymbols = 1;
		coffS.StorageClass = 3;
		SymbolToChars(&coffS);
		symbolsWritten++;
		memset(AuxSymbol, 0, 18);
		*(unsigned long *)AuxSymbol = rvp->DataSize;
		WriteOneSymbol(AuxSymbol);
		symbolsWritten++;
		startCount++;
		rvp = rvp->Next;
	}
	return (symbolsWritten);
}
static int WriteAllCoffSymbols(int startCount)
{
	symbolS *coffS;
	int count;

	count = startCount;
	count = WriteSpecialSymbols(count);
	coffS = symbol_rootP;
	while (coffS) {
		if (coffS->Flags & IS_TEXT) {
			if (strncmp(coffS->Name, ".text", 5)) {
				SymbolToChars(coffS);
				count++;
			}
		}
		if (glevel && coffS->Flags & IS_FUNCTION) {
			coffS->FnInfo->Tag = count + 1;
			WriteFunctionRecords(coffS);
			count += 6;
		}
		coffS = coffS->Next;
	}
	count += WriteDebugSpecialSymbols(count);
	count += WriteSpecialSectionSymbols(count);
	return (count);
}
static int WriteFileName(char *name)
{
	char Symbol[18], AuxSymbol[18];
	unsigned short *pus;
	int AuxSym, i, len, j,c;

	memset(Symbol, 0, 18);
	strcpy(Symbol, ".file");
	/* Write the section */
	pus = (unsigned short *) (&Symbol[12]);
	*pus = (unsigned short) -2; /* used for .file symbols */
	/* Write the storage class (103) */
	pus = (unsigned short *) (&Symbol[16]);
	*pus = 103;
	/* Write the number of auxiliary symbols */
	len = strlen(name);
	AuxSym = (len / 18);
	if (len % 18) AuxSym++;
	Symbol[17] = (char)AuxSym;
	if (18 != fwrite(Symbol, 1, 18, CoffFile)) {
		WriteError();
	}
	i = 0;
	while (i < len) {
		memset(AuxSymbol, 0, 18);
		for (j = 0; j < 18; j++) {
			if (i < len) {
				c = name[i];
				if (c >= 'a' && c <= 'z') c -= ' ';
				AuxSymbol[j] = c;
				i++;
			}
		}
		if (18 != fwrite(AuxSymbol, 1, 18, CoffFile)) {
			WriteError();
		}
	}
	return (AuxSym+1);
}

#ifdef DOT_LABEL_PREFIX
#define LOCAL_LABEL(name) (name[0] =='.' \
						&& ( name [1] == 'L' || name [1] == '.' ))
#else                   /* not defined DOT_LABEL_PREFIX */
#define LOCAL_LABEL(name) (name [0] == 'L' )
#endif                  /* not defined DOT_LABEL_PREFIX */
static struct frag *text_frag_root;
static struct frag *data_frag_root;
static struct frag *text_last_frag; /* Last frag in segment. */
static struct frag *data_last_frag; /* Last frag in segment. */
static COFF_RELOC *AddCoffRelocation(symbolS * coffS, int where, int pcrel)
{
	COFF_RELOC *coffR;

	coffR = coffS->Relocations;
	while (coffR && coffR->Next)
		coffR = coffR->Next;
	if (coffR == NULL) {
		coffS->Relocations = coffR = (COFF_RELOC *) xmalloc(sizeof(COFF_RELOC));
	}
	else {
		coffR->Next = (COFF_RELOC *) xmalloc(sizeof(COFF_RELOC));
		coffR = coffR->Next;
	}
	coffR->Offset = where;
	coffR->Symbol = coffS;
	if (pcrel) {
		coffR->Type = 0x14; /* Program counter relative relocation */
	}
	else
		coffR->Type = 6;
	return (coffR);
}
/* newFixup()
 * Create a fixS in obstack 'notes'.
 */
static void newFixup(fragS * frag,   /* Which frag? */
					int where, /* Where in that frag? */
					short int size,    /* 1, 2  or 4 usually. */
					symbolS * add_symbol,  /* X_add_sym bol. */
					symbolS * sub_symbol,  /* X_subtract_symbol. */
					long int offset,   /* X_add_number. */
					int pcrel)
{                       /* TRUE if PC-relative relocation. */
	register fixS *fixP;
	COFF_RELOC *coffR;

	fixP = (fixS *) obstack_alloc(&notes, sizeof(fixS));
	fixP->fx_frag = frag;
	fixP->fx_where = where;
	fixP->fx_size = size;
	fixP->fx_addsy = add_symbol;
	fixP->fx_subsy = sub_symbol;
	fixP->fx_offset = offset;
	fixP->fx_pcrel = (char)pcrel;
	fixP->fx_next = *seg_fix_rootP;
	*seg_fix_rootP = fixP;
	/* --------------------------------------------- */
	/* add the relocations to the symbol */
	coffR = AddCoffRelocation(add_symbol, where, pcrel);
	coffR->pfixS = fixP;
	coffR->TargetSegment = (now_seg == SEG_TEXT)? IS_TEXT : IS_DATA;
	fixP->CoffReloc = coffR;
}
int WriteCoffFile(void)
{
	register struct frchain *frchainP;  /* Track along all frchains. */
	register fragS *fragP;  /* Track along all frags. */
	register struct frchain *next_frchainP;
	register fragS **prev_fragPP;
	register char *name;
	register symbolS *symbolP;
	int PosNow;
	register symbolS **symbolPP;
	unsigned TextSize, data_siz;
	char *CodeBuffer, *CodeBufferP;
	int EndOfTextSeen;
	char *DataBuffer;
	char Nop[50];
	char Filler[50];
	unsigned short Short;

	if (bad_error) return(0);
	memset(Nop, 0x90, 50);
	memset(Filler,0,50);
	/* After every sub-segment, we fake an ".align ...". This conforms to
	BSD4.2 brane-damage. We then fake ".fill 0" because that is the kind of
	frag that requires least thought. ".align" frags like to have a
	following frag since that makes calculating their intended length
	trivial. */
#define SUB_SEGMENT_ALIGN (2)
	for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next) {
		subseg_new(frchainP->frch_seg, frchainP->frch_subseg);
		frag_align(SUB_SEGMENT_ALIGN, 0);
		/* frag_align will have left a new frag. */
		/* Use this last frag for an empty ".fill". */
		/* For this segment ... Create a last frag. Do not leave a "being
		filled in frag". */
		frag_wane(frag_now);
		frag_now->fr_fix = 0;
		know(frag_now->fr_next == NULL);
	}
	/* From now on, we don't care about sub-segments. Build one frag chain
	for each segment. Linked thru fr_next. We know that there is at least 1
	text frchain & at least 1 data frchain. */
	prev_fragPP = &text_frag_root;
	for (frchainP = frchain_root; frchainP; frchainP = next_frchainP) {
		know(frchainP->frch_root);
		*prev_fragPP = frchainP->frch_root;
		prev_fragPP = &frchainP->frch_last->fr_next;
		if (((next_frchainP = frchainP->frch_next) == NULL)
				|| next_frchainP == data0_frchainP) {
			prev_fragPP = &data_frag_root;
			if (next_frchainP) {
				text_last_frag = frchainP->frch_last;
			}
			else {
				data_last_frag = frchainP->frch_last;
			}
		}
	}                   /* for(each struct frchain) */
	relax_segment(text_frag_root, SEG_TEXT);
	relax_segment(data_frag_root, SEG_DATA);
	/* Now the addresses of frags are correct within the segment. */
	know(text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0);
	TextSize = text_last_frag->fr_address;
	/* Join the 2 segments into 1 huge segment. To do this, re-compute every
	rn_address in the SEG_DATA frags. Then join the data frags after the
	text frags.

	Determine a_data [length of data segment]. */
	if (data_frag_root) {
		know(text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0);
		data_siz = data_last_frag->fr_address;
		know(text_last_frag);
		text_last_frag->fr_next = data_frag_root;
		data_siz = data_last_frag->fr_address;
		text_last_frag->fr_next = data_frag_root;
	}
	else {
		data_siz = 0;
	}
	bss_address_frag.fr_address = TextSize + data_siz;
	/* Crawl the symbol chain. For each symbol whose value depends on a frag,
	take the address of that frag and subsume it into the value of the
	symbol. After this, there is just one way to lookup a symbol value.
	Values are left in their final state for object file emission. We
	adjust the values of 'L' local symbols, even if we do not intend to
	emit them to the object file, because their values are needed for
	fix-ups.

	Count the (length of the nlists of the) (remaining) symbols. Assign a
	symbol number to each symbol. Count the number of string-table chars we
	will emit. */
	know(zero_address_frag.fr_address == 0);
	/* JF deal with forward references first. . . */
	for (symbolP = symbol_rootP; symbolP; symbolP = symbolP->Next) {
		if (symbolP->sy_forward) {
			symbolP->SymbolValue += symbolP->sy_forward->SymbolValue + symbolP->sy_forward->sy_frag->fr_address;
			symbolP->sy_forward = 0;
		}
	}
	symbolPP = &symbol_rootP;   /* -> last symbol chain link. */
	while ((symbolP = *symbolPP) != NULL) {
		name = symbolP->Name;
		if (symbolP->sy_frag)
			symbolP->SymbolValue += symbolP->sy_frag->fr_address;
		if (!name || (symbolP->sy_type & N_STAB) || (name[2] != '\001' )) {
			symbolPP = &(symbolP->Next);
		}
		else
			*symbolPP = symbolP->Next;
	}                   /* for each symbol */
	/* Addresses of frags now reflect addresses we use in the object file.
	Symbol values are correct. Scan the frags, converting any ".org"s and
	".align"s to ".fill"s. Also converting any machine-dependent frags
	using md_convert_frag(); */
	subseg_change(SEG_TEXT, 0);
	for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
		switch (fragP->fr_type) {
		case rs_align:
		case rs_org:
			fragP->fr_type = rs_fill;
			know(fragP->fr_var == 1);
			know(fragP->fr_next);
			fragP->fr_offset
				= fragP->fr_next->fr_address
				- fragP->fr_address
				- fragP->fr_fix;
			break;
		case rs_fill:
			break;
		case rs_machine_dependent:
			md_convert_frag(fragP);
			/* After md_convert_frag, we make the frag into a ".space 0".
			Md_convert_frag() should set up any fixSs and constants
			required. */
			frag_wane(fragP);
			break;
		default:
			InternalError(1109);
			break;
		}               /* switch (fr_type) */
	}                   /* for each frag. */
	/* Scan every FixS performing fixups. We had to wait until now to do this
	because md_convert_frag() may have made some fixSs. */
	NrOfTextFixups = fixup_segment(text_fix_root, N_TEXT);
	NrOfDataFixups = fixup_segment(data_fix_root, N_DATA);

	/* ------------------Create and initialize the coff file */
	CoffFile = fopen(OutputFileName, "wb");
	if (CoffFile == NULL) {
		fprintf(stderr,"Can't create the output file %s", OutputFileName);
		return(0);
	}
	WriteCoffHeader();
	CodeSize = 0;
	DataSize = 0;
	EndOfTextSeen = 0;
	/* Emit code. */
	for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
		register long int count;
		register long int fill_size;
		know(fragP->fr_type == rs_fill);
		if (!EndOfTextSeen)
			CodeSize += fragP->fr_fix;
		else
			DataSize += fragP->fr_fix;
		fill_size = fragP->fr_var;
		know(fragP->fr_offset >= 0);
		for (count = fragP->fr_offset; count; count--) {
			if (!EndOfTextSeen)
				CodeSize += fill_size;
			else
				DataSize += fill_size;
		}
		if (text_last_frag == fragP)
			EndOfTextSeen = 1;
	}                   /* for each code frag. */
	/* allocate the code buffer */
	CodeBuffer = xmalloc(CodeSize);
	CodeBufferP = CodeBuffer;
	DataBuffer = xmalloc(DataSize);
	/* Append code to CodeBuffer */
	for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) {
		register long int count;
		register long int fill_size;
		know(fragP->fr_type == rs_fill);
		StringAppend(&CodeBufferP, fragP->fr_literal, (unsigned long) fragP->fr_fix);
		fill_size = fragP->fr_var;
		know(fragP->fr_offset >= 0);
		for (count = fragP->fr_offset; count; count--) {
			StringAppend(&CodeBufferP, Filler, (unsigned long) fill_size);
		}
		if (text_last_frag == fragP)
			CodeBufferP = DataBuffer;
	}                   /* for each code frag. */
	/* Emit relocations. */
	NrOfTextFixups = FixRelocations(text_fix_root);
	PosCodeSection = WriteTextSection(CodeSize, NrOfTextFixups);
	NrOfDataFixups = FixRelocations(data_fix_root);
	PosDataSection = WriteDataSection(data_siz, NrOfDataFixups, 0);
	PosBssSection = WriteBssSection(local_bss_counter);
	WriteSpecialSectionHeaders();
	if (glevel > 1) {
		PosDebugSymbolsSection = WriteDebugSection(0);
		PosDebugTypesSection = WriteDebugSection(1);
	}
	/* Now we can write the raw data sections We begin by the text section
	raw data */
	PosRawData = ftell(CoffFile);
	if ((unsigned) CodeSize != fwrite(CodeBuffer, 1, CodeSize, CoffFile)) {
		WriteError();
	}
	PosNow = ftell(CoffFile);
	fseek(CoffFile, PosCodeSection + 20, SEEK_SET);
	fwrite(&PosRawData, 1, 4, CoffFile);
	fseek(CoffFile, PosNow, SEEK_SET);
	/* We write the data section */
	PosRawData = ftell(CoffFile);
	if ((unsigned) DataSize != fwrite(DataBuffer, 1, DataSize, CoffFile)) {
		WriteError();
	}
	PosNow = ftell(CoffFile);
	fseek(CoffFile, PosDataSection + 20, SEEK_SET);
	fwrite(&PosRawData, 1, 4, CoffFile);
	fseek(CoffFile, PosNow, SEEK_SET);
	for (symbolP = symbol_rootP; symbolP; symbolP = symbolP->Next) {
		register char *temp;
		temp = symbolP->Name;
		if (symbolP->sy_type == N_UNDF) {
			symbolP->SectionNumber = 0;
		}
		if (symbolP->sy_type == N_UNDF) {
			symbolP->sy_type |= N_EXT;  /* Any undefined symbols become	N_EXT. */
		}
		symbolP->Name = temp;
	}                   /* for each symbol */
	ArrangeOrdinalNumbers(SourceFileName);
	/* Write the relocations for the code section */
	fseek(CoffFile, 0, SEEK_END);
	PosNow = ftell(CoffFile);   /* save the position */
	NrOfTextFixups = WriteRelocations(IS_TEXT);
	/* Write the file pointer to the relocations of the text section */
	fseek(CoffFile, PosCodeSection + 24, SEEK_SET);
	fwrite(&PosNow, 1, 4, CoffFile);
	/* Write the number of relocations into the section header */
	fseek(CoffFile, PosCodeSection + 32, SEEK_SET);
	Short = (unsigned short) NrOfTextFixups;
	fwrite(&Short, 1, 2, CoffFile);
	fseek(CoffFile, 0, SEEK_END);   /* position again at EOF */

	/* Write the relocations for the data section */
	PosNow = ftell(CoffFile);   /* save the position */
	NrOfDataFixups = WriteRelocations(IS_DATA);
	/* Write the file pointer to the relocations of the text section */
	fseek(CoffFile, PosDataSection + 24, SEEK_SET);
	fwrite(&PosNow, 1, 4, CoffFile);
	/* Write the number of relocations */
	fseek(CoffFile, PosDataSection + 32, SEEK_SET);
	Short = (unsigned short) NrOfDataFixups;
	fwrite(&Short, 1, 2, CoffFile);
	fseek(CoffFile, 0, SEEK_END);   /* position again at EOF */

	if (glevel)
		NrOfLineNumbers = WriteLineNumbers(PosCodeSection);
	else
		NrOfLineNumbers = 0;
	WriteSpecialSectionData();
	/* Emit all symbols left in the symbol chain. Any symbol still undefined
	is made N_EXT. */
	PosNow = ftell(CoffFile);
	PosRawData = PosNow;
	NrOfCoffSymbols = WriteFileName(SourceFileName);
	NrOfCoffSymbols = WriteAllCoffSymbols(NrOfCoffSymbols);
	/* Write the pointer to the symbol table */
	PosNow = ftell(CoffFile);
	fseek(CoffFile, 8L, SEEK_SET);
	fwrite(&PosRawData, 1, 4, CoffFile);
	/* Update the number of symbols written */
	fseek(CoffFile, 12L, SEEK_SET);
	fwrite(&NrOfCoffSymbols, 1, 4, CoffFile);
	fseek(CoffFile, 0, SEEK_END);
	/* Write the String Table */
	WriteStringTable();
	if (glevel > 1) WriteDebugData();
	free(CodeBuffer);
	fclose(CoffFile);
	return(1);
}                       /* WriteCoffFile() */
/* relax_segment()
 * Now we have a segment, not a crowd of sub-segments, we can make fr_address
 * values.
 * Relax the frags.
 * After this, all frags in this segment have addresses that are correct
 * within the segment. Since segments live in different file addresses,
 * these frag addresses may not be the same as final object-file addresses.
  segment_type:  N_DATA or N_TEXT
 */
static void relax_segment(struct frag * segment_frag_root, segT segment_type)
{
	register struct frag *fragP;
	register relax_addressT address;
	register long int stretch;  /* May be any size, 0 or negative. */
	/* Cumulative number of addresses we have relaxed this pass. */
	/* We may have relaxed more than one address. */
	register long int stretched;    /* Have we stretched on this pass? */
	/* This is 'cuz stretch may be zero, when, in fact some piece of code
	grew, and another shrank.  If a branch instruction doesn't fit anymore,
	we could be scrod */
	know(segment_type == SEG_DATA || segment_type == SEG_TEXT);
	/* In case md_estimate_size_before_relax() wants to make fixSs. */
	subseg_change(segment_type, 0);
	/* For each frag in segment: count and store  (a 1st guess of)
	fr_address. */
	address = 0;
	for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) {
		fragP->fr_address = address;
		address += fragP->fr_fix;
		switch (fragP->fr_type) {
		case rs_fill:
			address += fragP->fr_offset * fragP->fr_var;
			break;
		case rs_align:
			address += relax_align(address, fragP->fr_offset);
			break;
		case rs_org:
			/* Assume .org is nugatory. It will grow with 1st relax. */
			break;
		case rs_machine_dependent:
			address += md_estimate_size_before_relax(fragP, seg_N_TYPE[(int) segment_type]);
			break;
		default:
			InternalError(1110);
			break;
		}               /* switch(fr_type) */
	}                   /* for each frag in the segment */
	/* Do relax(). */
	do {
		stretch = stretched = 0;
		for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) {
			register long int growth=0;
			register unsigned long int was_address;
			/* register long int    var; */
			register long int offset;
			register symbolS *symbolP;
			register long int target;
			register long int after;
			register long int aim;
			was_address = fragP->fr_address;
			address = fragP->fr_address += stretch;
			symbolP = fragP->fr_symbol;
			offset = fragP->fr_offset;
			/* var = fragP -> fr_var; */
			switch (fragP->fr_type) {
			case rs_fill:  /* .fill never relaxes. */
				growth = 0;
				break;
			case rs_align:
				growth = relax_align((relax_addressT) (address + fragP->fr_fix), offset)
					- relax_align((relax_addressT) (was_address + fragP->fr_fix), offset);
				break;
			case rs_org:
				target = offset;
				if (symbolP) {
					know(((symbolP->sy_type & N_TYPE) == N_ABS) || ((symbolP->sy_type & N_TYPE) == N_DATA) || ((symbolP->sy_type & N_TYPE) == N_TEXT));
					know(symbolP->sy_frag);
					know((symbolP->sy_type & N_TYPE) != N_ABS || symbolP->sy_frag == &zero_address_frag);
					target +=
						symbolP->SymbolValue
						+ symbolP->sy_frag->fr_address;
				}
				know(fragP->fr_next);
				after = fragP->fr_next->fr_address;
				growth = ((target - after) > 0) ? (target - after) : 0;
				/* Growth may be -ve, but variable part */
				/* of frag cannot have < 0 chars. */
				/* That is, we can't .org backwards. */
				growth -= stretch;  /* This is an absolute growth factor */
				break;
			case rs_machine_dependent:
				{
					register const relax_typeS *this_type;
					register const relax_typeS *start_type;
					register relax_substateT next_state;
					register relax_substateT this_state;
					start_type = this_type
						= md_relax_table + (this_state = fragP->fr_subtype);
					target = offset;
					if (symbolP) {
						know(((symbolP->sy_type & N_TYPE) == N_ABS) || ((symbolP->sy_type &
																		N_TYPE) == N_DATA) || ((symbolP->sy_type & N_TYPE) == N_TEXT));
						know(symbolP->sy_frag);
						know((symbolP->sy_type & N_TYPE) != N_ABS || symbolP->sy_frag == &zero_address_frag);
						target +=
							symbolP->SymbolValue
							+ symbolP->sy_frag->fr_address;
						if (symbolP->sy_frag->fr_address >= was_address && is_dnrange(fragP, symbolP->sy_frag))
							target += stretch;
					}
					aim = target - address - fragP->fr_fix;
					if (aim < 0) {
						/* Look backwards. */
						for (next_state = this_type->rlx_more; next_state;) {
							if (aim >= this_type->rlx_backward)
								next_state = 0;
							else {  /* Grow to next state. */
								this_type = md_relax_table + (this_state = next_state);
								next_state = this_type->rlx_more;
							}
						}
					}
					else {
						/* Look forwards. */
						for (next_state = this_type->rlx_more; next_state;) {
							if (aim <= this_type->rlx_forward)
								next_state = 0;
							else {  /* Grow to next state. */
								this_type = md_relax_table + (this_state = next_state);
								next_state = this_type->rlx_more;
							}
						}
					}
					if ((growth = this_type->rlx_length - start_type->rlx_length) != 0)
						fragP->fr_subtype = this_state;
				}
				break;
			default:
				InternalError(1111);
				break;
			}
			if (growth) {
				stretch += growth;
				stretched++;
			}
		}               /* For each frag in the segment. */
	} while (stretched);/* Until nothing further to relax. */
	/* We now have valid fr_address'es for each frag. */
	/* All fr_address's are correct, relative to their own segment. We have
	made all the fixS we will ever make. */
}                       /* relax_segment() */
/* Relax_align. Advance location counter to next address that has 'alignment'
 * lowest order bits all 0s.result is how many addresses does the .align take?
 */
static relax_addressT relax_align(register relax_addressT address, /* Address now. */
								register long int alignment)
{                       /* Alignment (binary). */
	relax_addressT mask;
	relax_addressT new_address;
	mask = ~((~0) << alignment);
	new_address = (address + mask) & (~mask);
	return (new_address - address);
}
/* fixup_segment() */
static long int fixup_segment(fixS * fixP, int this_segment_type)
{
	register long int seg_reloc_count;
	register symbolS *add_symbolP;
	register symbolS *sub_symbolP;
	long int add_number;
	register int size;
	register char *place;
	register long int where;
	register char pcrel;
	register fragS *fragP;
	register int add_symbol_N_TYPE;
	int wasPcRel;
	COFF_RELOC *coffR;

	seg_reloc_count = 0;
	for (; fixP; fixP = fixP->fx_next) {
		wasPcRel = 0;
		fragP = fixP->fx_frag;
		know(fragP);
		where = fixP->fx_where;
		place = fragP->fr_literal + where;
		size = fixP->fx_size;
		add_symbolP = fixP->fx_addsy;
		sub_symbolP = fixP->fx_subsy;
		add_number = fixP->fx_offset;
		pcrel = fixP->fx_pcrel;
		if (add_symbolP)
			add_symbol_N_TYPE = add_symbolP->sy_type & N_TYPE;
		if (sub_symbolP) {
			if (!add_symbolP) { /* Its just -sym */
				if (sub_symbolP->sy_type != N_ABS) {
					InternalError(1100);
				}
				add_number -= sub_symbolP->SymbolValue;
			}
			else if (((sub_symbolP->sy_type ^ add_symbol_N_TYPE) & N_TYPE) == 0
					&& (add_symbol_N_TYPE == N_DATA
						|| add_symbol_N_TYPE == N_TEXT
						|| add_symbol_N_TYPE == N_BSS
						|| add_symbol_N_TYPE == N_ABS)) {
				/* Difference of 2 symbols from same segment. */
				/* Can't make difference of 2 undefineds: 'value' means */
				/* something different for N_UNDF. */
				add_number += add_symbolP->SymbolValue - sub_symbolP->SymbolValue;
				add_symbolP = NULL;
				fixP->fx_addsy = NULL;
			}
			else {
				/* Different segments in subtraction. */
				know(sub_symbolP->sy_type != (N_ABS | N_EXT));
				if (sub_symbolP->sy_type == N_ABS)
					add_number -= sub_symbolP->SymbolValue;
				else {
					InternalError(1101);
				}
			}
		}
		if (add_symbolP) {
			if (add_symbol_N_TYPE == this_segment_type && pcrel) {
				/* This fixup was made when the symbol's segment was
				SEG_UNKNOWN, but it is now in the local segment. So we know
				how to do the address without relocation. Here arrive all
				the calls to the functions in the same module for instance */
				add_number += add_symbolP->SymbolValue;
				add_number -=
					size +
					where + fragP->fr_address;
				pcrel = 0;  /* Don't want further pcrel processing. */
				fixP->fx_addsy = NULL;  /* No relocations please. */
#if 0
				printf("relocation to %s eliminated\n",add_symbolP->Name);
#endif
				coffR = add_symbolP->Relocations;
				if (coffR == fixP->CoffReloc) {
					add_symbolP->Relocations = coffR->Next;
					free(coffR);
					fixP->CoffReloc = NULL;
				}
				else {
					while (coffR) {
						if (coffR->Next == fixP->CoffReloc) {
							coffR->Next = fixP->CoffReloc->Next;
							free(fixP->CoffReloc);
							fixP->CoffReloc = NULL;
							break;
						}
						coffR = coffR->Next;
					}
				}
				wasPcRel = 1;
				/* It would be nice to check that the address does not
				overflow. I didn't do this check because: +  It is machine
				dependent in the general case (eg 32032) + Compiler output
				will never need this checking, so why slow down the usual
				case? */
			}
			else {
				switch (add_symbol_N_TYPE) {
				case N_ABS:
					add_number += add_symbolP->SymbolValue;
					fixP->fx_addsy = NULL;
					add_symbolP = NULL;
					break;
				case N_DATA:
				case N_BSS:
					seg_reloc_count++;
					break;
				case N_TEXT:
					seg_reloc_count++;
					if (this_segment_type == N_TEXT)
						add_number += add_symbolP->SymbolValue;
					break;
				case N_UNDF:
					seg_reloc_count++;
					break;
				default:
					InternalError(1112);
					break;
				}       /* switch on symbol seg */
			}           /* if not in local seg */
		}               /* if there was a + symbol */
		if (pcrel) {
			add_number -= size + where + fragP->fr_address;
			if (add_symbolP == 0) {
				fixP->fx_addsy = &abs_symbol;
				seg_reloc_count++;
			}
		}
		if (add_symbolP && add_symbol_N_TYPE == N_UNDF && pcrel) {
			pcrel = 0;
			add_number = 0;
		}
		if ((size == 1 &&
	   			(add_number & ~0xFF) && (add_number & ~0xFF != (-1 & ~0xFF))) ||
				(size == 2 &&
				(add_number & ~0xFFFF) &&
				(add_number & ~0xFFFF != (-1 & ~0xFFFF)))) {
					InternalError(1102);
		}
		if (!(wasPcRel) && 
			add_number && 
			this_segment_type == N_TEXT && add_symbol_N_TYPE == N_TEXT) {
/*			printf("relocation to %s changed from %d to zero\n",add_symbolP->Name,add_number);*/
			add_number = 0;
		}
		memcpy(place,&add_number,size);
	}                   /* For each fixS in this segment. */
	return (seg_reloc_count);
}                       /* fixup_segment() */
/* FixRelocations() Crawl along a fixS chain. Fix the segment's relocations. */
static int FixRelocations(register fixS * fixP)
{
	int result;
	COFF_RELOC *rvpR;

	result = 0;
	for (; fixP; fixP = fixP->fx_next) {
		if (fixP->fx_addsy != NULL) {
			rvpR = fixP->CoffReloc;
			while (rvpR) {
				if (rvpR->pfixS == fixP) {
					rvpR->Offset = fixP->fx_frag->fr_address + fixP->fx_where;
				}
				rvpR = rvpR->Next;
			}
			result++;
		}
	}
	return (result);
}
#ifndef ASM_LIB
static int is_dnrange(struct frag * f1, struct frag * f2)
{
	while (f1) {
		if (f1->fr_next == f2)
			return 1;
		f1 = f1->fr_next;
	}
	return 0;
}
#endif
int AsmInit(char *fname)
{
	symbol_lastP = NULL;
	symbol_rootP = NULL;
	sy_hash = hash_new();
	memset((char *) (&abs_symbol),0, sizeof(abs_symbol));
	abs_symbol.sy_type = N_ABS; 
	local_bss_counter = 0;

	subsegs_begin();
	obstack_begin(&notes, 5000);

	InitializeAsmTables();
	InitAsmInput();

	text_fix_root = NULL;
	data_fix_root = NULL;
	need_pass_2 = FALSE;
	SetObjFileName(fname);
	subseg_new(SEG_TEXT, 0);
	return (1);
}

int IsWithinSpecialSection(void)
{
	return (IsSpecialSection)? 1: 0;
}
