home *** CD-ROM | disk | FTP | other *** search
- #include "c.h"
- #include "asm.h"
- #include "i386.h"
- #include "i386-opc.h"
- #include "cv.h"
- extern void * _stdcall GlobalAlloc(unsigned int,unsigned int);
- extern void _stdcall GlobalFree(void *);
- #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 *,char * );
- 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 );
- #ifndef ASM_LIB
- static
- #else
- extern
- #endif
- 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];
- #ifndef ASM_LIB
- static
- #endif
- char register_chars[256];
- static char operand_chars[256];
- static char space_chars[256];
- static char identifier_chars[256];
- static char digit_chars[256];
- #ifndef ASM_LIB
- static
- #endif
- char RegisterNames[MAX_REG_NAMES * 6];
-
- static char *SourceFileName = "";
- 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(¬es, name, name_length);
- p = obstack_finish(¬es);
- preserved_copy_of_name = p;
- p = obstack_alloc(¬es, 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;
- }
- /*
- * 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;
- expressionP->X_subtract_symbol = NULL;
- expressionP->X_add_symbol = NULL;
- InputPointer--; /* Restore following character. */
- SKIP_WHITESPACE(); /* -> 1st char after operand. */
- know(*InputPointer != ' ');
- return (expressionP->X_seg);
- }
- else if (c == '.' && !is_part_of_name(*InputPointer)) {
- extern struct obstack frags;
- /* '.' 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.
- i, disp_expressions, and im_expressions should be continguous in memory */
- 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));
- }
- }
- // This should be tested each time a new instruction is added
- // We suppose that we have no two operands with a name that
- // has the same length and the same first two letters.
- #if 0
- for (c=0; c<HASHSIZE;c++) {
- register struct HASH_LIST *rvp;
- char tab[70000];
- printf("[%3d] ",c);
-
- rvp = ((struct HASH_LIST **)op_hash->Data)[c & (HASHSIZE-1)];
- memset(tab,0,66000);
- while (rvp) {
- if (tab[*(unsigned short *)rvp->Name]) {
- printf("*****\nTotal collision char %c\n",rvp->Name[1]);
- }
- tab[*(unsigned short *)rvp->Name] = 1;
- printf("%s ",rvp->Name);
- rvp = rvp->Next;
- }
- printf("\n");
- }
- #endif
- /* 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++;
- }
- // printf("number of registers: %d\n",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;
- int h,lasth;
- register struct HASH_LIST *rvp;
- 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_balanced;
- unsigned short first_two_chars;
- 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. */
- // We assume that there is no opcode shorter than two bytes
- lasth = 0 ^ *l++;
- h = (lasth << 2) ^ *l++;
- while (is_opcode_char(*l)) {
- lasth = h;
- h = (h << 2) ^ *l++;
- }
- /* 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. */
- rvp = ((struct HASH_LIST **)op_hash->Data)[h & (HASHSIZE-1)];
- h = l - token_start;
- first_two_chars = *(unsigned short *)token_start;
- while (rvp) {
- if ((rvp->len == h) && first_two_chars == *(unsigned short *)rvp->Name) {
- current_templates = (templates *)rvp->Data;
- goto suite;
- }
- rvp = rvp->Next;
- }
-
- h--;
- switch (token_start[h]) {
- case DWORD_OPCODE_SUFFIX:
- case WORD_OPCODE_SUFFIX:
- case BYTE_OPCODE_SUFFIX:
- rvp = ((struct HASH_LIST **)op_hash->Data)[lasth & (HASHSIZE-1)];
- while (rvp) {
- if ((rvp->len == h) &&
- first_two_chars == *(unsigned short *)rvp->Name) {
- current_templates = (templates *)rvp->Data;
- i.suffix = token_start[h];
- goto suite;
- }
- rvp = rvp->Next;
- }
- }
- printf("No such instruction %s\n",token_start);
- InternalError(1024);
- suite:
- /* 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)
- Since lcc never generates those arguments this test has been dropped
- */
- ) {
- /* parse operands */
- do {
- /* skip optional white space before operand */
- while (is_space_char(*l))
- l++;
- token_start = l; /* after white space */
- paren_not_balanced = 0;
- while (paren_not_balanced || *l != ',') {
- if (*l == END_OF_INSN) {
- if (paren_not_balanced) {
- 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 {
- printf("incorrect char %c\n",*l);
- h = 0;
- while (line[h] != '\n') {
- printf("%c",line[h++]);
- }
- printf("\n");
- InternalError(1028);
- }
- }
- if (*l == '(')
- ++paren_not_balanced;
- if (*l == ')')
- --paren_not_balanced;
- l++;
- }
- if (l != token_start) { /* yes, we've read in another operand */
- 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);
- h = i386_operand(token_start,l);
- RESTORE_END_STRING(l); /* restore old contents */
- if (!h)
- 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. */
- for (h = 0; h < MAX_OPERANDS; h++)
- if (i.types[h] & Reg) {
- i.suffix = (i.types[h] == Reg8) ? BYTE_OPCODE_SUFFIX :
- (i.types[h] == 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) {
- h = t->operand_types[0];
- t->operand_types[0] = t->operand_types[1];
- t->operand_types[1] = h;
- }
- 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;
- }
- if (obstack_room(&frags) <= 14) {
- frag_wane(frag_now);
- frag_new(0);
- }
- /* We are ready to output the insn. */
- /* Output jumps. */
- if (t->opcode_modifier & Jump) {
- h = i.disps[0]->X_add_number;
- if (i.disps[0]->X_seg != SEG_ABSOLUTE) {
- char *p;
- /* 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 */
- p = frag_more(1);
- *p = (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,
- h, p);
- }
- else {
- if (FITS_IN_SIGNED_BYTE(h)) {
- *frags.next_free++ = (char)(t->base_opcode);
- *frags.next_free++ = (char)h;
- }
- else { /* It's an absolute dword displacement. */
- if (t->base_opcode == JUMP_PC_RELATIVE) { /* pace */
- /* unconditional jump */
- *frags.next_free++ = (unsigned char) 0xe9;
- *(unsigned long *)(frags.next_free) = h;
- frags.next_free += 4;
- }
- else {
- /* conditional jump */
- *frags.next_free++ = (char)TWO_BYTE_OPCODE_ESCAPE;
- *frags.next_free++ = t->base_opcode + 0x10;
- *(unsigned long *)(frags.next_free) = h;
- frags.next_free += 4;
- }
- }
- }
- return;
- }
- else if (t->opcode_modifier & (JumpByte | JumpDword)) {
- int size = (t->opcode_modifier & JumpByte) ? 1 : 4;
- h = i.disps[0]->X_add_number;
- if (t->base_opcode <= 255) {
- *frags.next_free++ = t->base_opcode;
- }
- else {
- /* put out high byte first */
- *frags.next_free++ = (char)((t->base_opcode >> 8) & 0xff);
- *frags.next_free++ = (char)(t->base_opcode & 0xff);
- }
- if (i.disps[0]->X_seg == SEG_ABSOLUTE) {
- if (size == 1) {
- if (!FITS_IN_SIGNED_BYTE(h))
- InternalError(1039);
- *frags.next_free = h;
- }
- else
- *(unsigned long *)frags.next_free = h;
- }
- else {
- /* Fixup. Here comes the fixup for the call instructions for
- instance */
- newFixup(frag_now, frags.next_free - frag_now->fr_literal, (short int) size,
- i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol,
- h, 1);
- }
- frags.next_free += size;
- return;
- }
- else if (t->opcode_modifier & JumpInterSegment) {
- /* lcall and ljmp instructions */
- *frags.next_free++ = (char)(t->base_opcode);
- if (i.imms[1]->X_seg == SEG_ABSOLUTE) {
- *(unsigned long *)(frags.next_free) = i.imms[1]->X_add_number;
- frags.next_free += 4;
- }
- else {
- newFixup(frag_now, frags.next_free - 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);
- frags.next_free += 4;
- }
- if (i.imms[0]->X_seg != SEG_ABSOLUTE) {
- InternalError(1040);
- }
- *(unsigned short *)(frags.next_free) = (unsigned short)(i.imms[0]->X_add_number);
- frags.next_free += 2;
- return;
- }
- /* Output normal instructions here. */
- /* First the prefix bytes. */
- for (q = i.prefix; q < i.prefix + i.prefixes; q++) {
- *frags.next_free++ = (unsigned char )*q;
- }
- /* Now the opcode; be careful about word order here! */
- if (t->base_opcode <= 255) {
- *frags.next_free++ = t->base_opcode;
- }
- else if (t->base_opcode <= 65535) {
- /* put out high byte first */
- *frags.next_free = (char)((t->base_opcode >> 8) & 0xff);
- frags.next_free[1] = (char)(t->base_opcode & 0xff);
- frags.next_free += 2;
- }
- else { /* opcode is either 3 or 4 bytes */
- if (t->base_opcode & 0xff000000) {
- *frags.next_free++ = (char)((t->base_opcode >> 24) & 0xff);
- }
- *frags.next_free = (char)((t->base_opcode >> 16) & 0xff);
- frags.next_free[1] = (char)((t->base_opcode >> 8) & 0xff);
- frags.next_free[2] = (char)((t->base_opcode) & 0xff);
- frags.next_free += 3;
- }
- /* Now the modrm byte and base index byte (if present). */
- if (t->opcode_modifier & Modrm) {
- *frags.next_free++ = (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) {
- *frags.next_free++ = (char)(0xFF & (i.bi.base << 0 | i.bi.index << 3 | i.bi.scale << 6));
- }
- }
- if (i.disp_operands) {
- int number;
- for (h = 0; h < (int)i.operands; h++) {
- if (i.disps[h]) {
- if (i.disps[h]->X_seg == SEG_ABSOLUTE) {
- number = (i.disps[h]->X_add_number);
- if (i.types[h] & (Disp8 | Abs8)) {
- *frags.next_free++ = (char)(0xFF & number);
- }
- else if (i.types[h] & (Disp16 | Abs16)) {
- *(unsigned short *)(frags.next_free) = (unsigned short)number;
- frags.next_free += 2;
- }
- else { /* Disp32|Abs32 */
- *(unsigned long *)(frags.next_free) = number;
- frags.next_free += 4;
- }
- }
- else { /* not SEG_ABSOLUTE */
- /* need a 32-bit fixup (don't support 8bit non-absolute
- disps) */
- newFixup(frag_now, frags.next_free - frag_now->fr_literal, 4,
- i.disps[h]->X_add_symbol, i.disps[h]->X_subtract_symbol,
- i.disps[h]->X_add_number, 0);
- frags.next_free += 4;
- }
- }
- }
- } /* end displacement output */
- /* output immediate */
- if (i.imm_operands) {
- int number;
- for (h = 0; h < (int)i.operands; h++) {
- if (i.imms[h]) {
- if (i.imms[h]->X_seg == SEG_ABSOLUTE) {
- number = i.imms[h]->X_add_number;
- if (i.types[h] & (Imm8 | Imm8S)) {
- *frags.next_free++ = (char)(0xFF & number);
- }
- else if (i.types[h] & Imm16) {
- *(unsigned short *)(frags.next_free) = (unsigned short)number;
- frags.next_free += 2;
- }
- else {
- *(unsigned long *)(frags.next_free) = number;
- frags.next_free += 4;
-
- }
- }
- else { /* not SEG_ABSOLUTE */
- /* need a 32-bit fixup (don't support 8bit non-absolute
- ims) */
- int size;
- if (i.types[h] & (Imm8 | Imm8S))
- size = 1;
- else if (i.types[h] & Imm16)
- size = 2;
- else
- size = 4;
- /* FIXUPS This just fills the fieds of the fixup
- structure */
- newFixup(frag_now, frags.next_free - frag_now->fr_literal, (short int) size,
- i.imms[h]->X_add_symbol, i.imms[h]->X_subtract_symbol,
- i.imms[h]->X_add_number, 0);
- frags.next_free += size;
- }
- }
- }
- } /* end immediate output */
- }
- /* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero
- on error. */
- static int i386_operand(char *operand_string,char *end_of_operand_string)
- {
- register char *op_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;
- end_of_operand_string = q;
- }
- #endif
- op_string = 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 == ')') {
- /* 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 == '(')
- break;
- } while(1);
- 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;
- 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))) {
- switch (*++base_string) { /* 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;
- }
- #ifndef ASM_LIB
- /* 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;
-
- *((unsigned long *)reg_name_given) = 0;
- s++; /* skip REGISTER_PREFIX */
- p = reg_name_given;
- *p++ = *s++;
- *p++ = *s++;
- if (is_register_char (*s)) {
- *p++ = *s++;
- if (is_register_char(*s))
- *p = *s;
- }
- l = *((unsigned long *)reg_name_given);
- pl = (unsigned long *)RegisterNames;
- for (i=0; i<MAX_REG_NAMES; i++) {
- if (pl[i] == l) return(&i386_regtab[i]);
- }
- return(NULL);
- }
- #endif
- 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((char *)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((char *)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((char *)Section,".debug$T");
- else strcpy((char *)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((char *)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((char *)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 = (unsigned char *)xmalloc(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(¬es, 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(¬es, 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;
- }
-