* Extensive changes to permit symbols to contain any expression
authorIan Lance Taylor <ian@airs.com>
Wed, 21 Jul 1993 00:41:42 +0000 (00:41 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 21 Jul 1993 00:41:42 +0000 (00:41 +0000)
type and to delay the computation of the expression until the
value is actually needed.  This permits setting symbols to values
calculated based on object code size.  Expressions were changed to
no longer be in a section, to stop the overloading of segment and
expression type that previously occurred.

* as.c (big_section, pass1_section, diff_section, absent_section):
Removed.
(expr_section): Added (used for dummy symbols which hold
intermediate expression values).
(perform_an_assembly_pass): Create expr_section, do not create the
sections now removed.
* as.h (segT): Removed SEG_ABSENT, SEG_PASS1, SEG_BIG, and
SEG_DIFFERENCE.  Added SEG_EXPR.
(SEG_NORMAL): Corresponding changes.
* subsegs.c (seg_name, subsegs_begin): Changed accordingly.
* write.c (write_object_file): Ditto.
* config/obj-aout.c (seg_N_TYPE): Ditto.
* config/obj-bout.c (seg_N_TYPE): Ditto.
* config/obj-coff.c (seg_N_TYPE): Ditto.
* config/obj-coffbfd.c (seg_N_TYPE): Ditto.
* config/obj-vms.c (seg_N_TYPE): Ditto.

* expr.h (operatorT): Moved in from expr.c, added some values.
(expressionS): Added X_op field, removed X_seg field; renamed
X_subtract_symbol to X_op_symbol.
* expr.c: Extensive changes to assign expression types rather than
sections and to simplify the parsing.
* write.c (fix_new_internal): New static function.
(fix_new): Removed sub_symbol argument.
(fix_new_exp): New function, takes expression argument.
* write.h: Prototype changes for fix_new and fix_new_exp.
* cond.c (s_if): Changed accordingly.
* read.c (s_lsym, pseudo_set, emit_expr, parse_bitfield_cons,
parse_repeat_cons, get_segmented_expression,
get_known_segmented_expression, get_absolute_expression): Ditto.
* symbols.c (resolve_symbol_value, S_GET_VALUE, S_SET_VALUE):
Ditto.
* write.c (write_object_file): Ditto.
* config/obj-coff.c (obj_coff_def, obj_coff_val): Ditto.
* config/obj-coffbfd.c (obj_coff_def, obj_coff_val,
obj_coff_endef, yank_symbols): Ditto.
* config/obj-elf.c (obj_elf_stab_generic, obj_elf_size): Ditto.
* config/tc-a29k.c (md_assemble, parse_operand, machine_ip,
print_insn, md_operand): Ditto.
* config/tc-h8300.c (parse_exp, colonmod24, check_operand,
do_a_fix_imm, build_bytes): Ditto.
* config/tc-h8500.c (parse_exp, skip_colonthing, parse_reglist,
get_specific, check, insert, md_convert_frag): Ditto.
* config/tc-hppa.c (the_insn, fix_new_hppa, cons_fix_new_hppa,
md_assemble, pa_ip, getExpression, getAbsoluteExpression,
evaluateAbsolute, pa_build_unwind_subspace, pa_entry,
process_exit): Ditto.
* config/tc-hppa.h (STAB_FIXUP, is_DP_relative, is_PC_relative,
is_complex): Ditto.
* config/tc-i386.c (pe, md_assemble, i386_operand,
md_estimate_size_before_relax, md_create_long_jump): Ditto.
* config/tc-i860.c (md_assemble, getExpression, print_insn):
Ditto.
* config/tc-i960.c (parse_expr, subs, segs, md_convert_frag,
get_cdisp, mem_fmt, parse_ldconst, relax_cobr, s_sysproc,
i960_handle_align): Ditto.
* config/tc-m68k.c (struct m68k_exp, struct m68k_it, seg, op,
subs, add_fix, isvar, m68k_ip, md_assemble, md_convert_frag_1,
md_estimate_size_before_relax, md_create_long_jump, get_num):
Ditto.
* config/tc-m88k.c (md_assemble, get_imm16, get_pcr,
md_create_short_jump, md_create_long_jump): Ditto.
* config/tc-mips.c (md_assemble, append_insn, gp_reference,
macro_build, macro, my_getExpression): Ditto.  Also removed
get_optional_absolute_expression; just use get_absolute_expression
instead.
* config/tc-ns32k.c (get_addr_mode, evaluate_expr, convert_iif,
fix_new_ns32k, fix_new_ns32k_exp, cons_fix_new_ns32k): Ditto.
* config/tc-ns32k.h (fix_new_ns32k prototype): Ditto.
* config/tc-sh.c (parse_exp, check, insert, md_convert_frag):
Ditto.
* config/tc-sparc.c (md_assemble, sparc_ip, getExpression,
print_insn): Ditto.
* config/tc-tahoe.c (struct top, md_estimate_size_before_relax,
tip_op, md_assemble): Ditto.
* config/tc-vax.c (seg_of_operand, md_assemble,
md_estimate_size_before_relax, md_create_long_jump): Ditto.
* config/tc-z8k.c (parse_exp, check_operand, newfix): Ditto.

19 files changed:
gas/ChangeLog
gas/config/obj-aout.c
gas/config/obj-bout.c
gas/config/obj-coffbfd.c
gas/config/obj-elf.c
gas/config/obj-vms.c
gas/config/tc-a29k.c
gas/config/tc-h8300.c
gas/config/tc-h8500.c
gas/config/tc-i386.c
gas/config/tc-i960.c
gas/config/tc-m88k.c
gas/config/tc-mips.c
gas/config/tc-sparc.c
gas/config/tc-tahoe.c
gas/expr.c
gas/read.c
gas/symbols.c
gas/write.c

index 0874510..6ca7c10 100644 (file)
@@ -1,3 +1,91 @@
+Tue Jul 20 19:28:56 1993  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
+
+       * Extensive changes to permit symbols to contain any expression
+       type and to delay the computation of the expression until the
+       value is actually needed.  This permits setting symbols to values
+       calculated based on object code size.  Expressions were changed to
+       no longer be in a section, to stop the overloading of segment and
+       expression type that previously occurred.
+
+       * as.c (big_section, pass1_section, diff_section, absent_section):
+       Removed.
+       (expr_section): Added (used for dummy symbols which hold
+       intermediate expression values).
+       (perform_an_assembly_pass): Create expr_section, do not create the
+       sections now removed.
+       * as.h (segT): Removed SEG_ABSENT, SEG_PASS1, SEG_BIG, and
+       SEG_DIFFERENCE.  Added SEG_EXPR.
+       (SEG_NORMAL): Corresponding changes.
+       * subsegs.c (seg_name, subsegs_begin): Changed accordingly.
+       * write.c (write_object_file): Ditto.
+       * config/obj-aout.c (seg_N_TYPE): Ditto.
+       * config/obj-bout.c (seg_N_TYPE): Ditto.
+       * config/obj-coff.c (seg_N_TYPE): Ditto.
+       * config/obj-coffbfd.c (seg_N_TYPE): Ditto.
+       * config/obj-vms.c (seg_N_TYPE): Ditto.
+
+       * expr.h (operatorT): Moved in from expr.c, added some values.
+       (expressionS): Added X_op field, removed X_seg field; renamed
+       X_subtract_symbol to X_op_symbol.
+       * expr.c: Extensive changes to assign expression types rather than
+       sections and to simplify the parsing.
+       * write.c (fix_new_internal): New static function.
+       (fix_new): Removed sub_symbol argument.
+       (fix_new_exp): New function, takes expression argument.
+       * write.h: Prototype changes for fix_new and fix_new_exp.
+       * cond.c (s_if): Changed accordingly.
+       * read.c (s_lsym, pseudo_set, emit_expr, parse_bitfield_cons,
+       parse_repeat_cons, get_segmented_expression,
+       get_known_segmented_expression, get_absolute_expression): Ditto.
+       * symbols.c (resolve_symbol_value, S_GET_VALUE, S_SET_VALUE):
+       Ditto.
+       * write.c (write_object_file): Ditto.
+       * config/obj-coff.c (obj_coff_def, obj_coff_val): Ditto.
+       * config/obj-coffbfd.c (obj_coff_def, obj_coff_val,
+       obj_coff_endef, yank_symbols): Ditto.
+       * config/obj-elf.c (obj_elf_stab_generic, obj_elf_size): Ditto.
+       * config/tc-a29k.c (md_assemble, parse_operand, machine_ip,
+       print_insn, md_operand): Ditto.
+       * config/tc-h8300.c (parse_exp, colonmod24, check_operand,
+       do_a_fix_imm, build_bytes): Ditto.
+       * config/tc-h8500.c (parse_exp, skip_colonthing, parse_reglist,
+       get_specific, check, insert, md_convert_frag): Ditto.
+       * config/tc-hppa.c (the_insn, fix_new_hppa, cons_fix_new_hppa,
+       md_assemble, pa_ip, getExpression, getAbsoluteExpression,
+       evaluateAbsolute, pa_build_unwind_subspace, pa_entry,
+       process_exit): Ditto.
+       * config/tc-hppa.h (STAB_FIXUP, is_DP_relative, is_PC_relative,
+       is_complex): Ditto.
+       * config/tc-i386.c (pe, md_assemble, i386_operand,
+       md_estimate_size_before_relax, md_create_long_jump): Ditto.
+       * config/tc-i860.c (md_assemble, getExpression, print_insn):
+       Ditto.
+       * config/tc-i960.c (parse_expr, subs, segs, md_convert_frag,
+       get_cdisp, mem_fmt, parse_ldconst, relax_cobr, s_sysproc,
+       i960_handle_align): Ditto.
+       * config/tc-m68k.c (struct m68k_exp, struct m68k_it, seg, op,
+       subs, add_fix, isvar, m68k_ip, md_assemble, md_convert_frag_1,
+       md_estimate_size_before_relax, md_create_long_jump, get_num):
+       Ditto.
+       * config/tc-m88k.c (md_assemble, get_imm16, get_pcr,
+       md_create_short_jump, md_create_long_jump): Ditto.
+       * config/tc-mips.c (md_assemble, append_insn, gp_reference,
+       macro_build, macro, my_getExpression): Ditto.  Also removed
+       get_optional_absolute_expression; just use get_absolute_expression
+       instead.
+       * config/tc-ns32k.c (get_addr_mode, evaluate_expr, convert_iif,
+       fix_new_ns32k, fix_new_ns32k_exp, cons_fix_new_ns32k): Ditto.
+       * config/tc-ns32k.h (fix_new_ns32k prototype): Ditto.
+       * config/tc-sh.c (parse_exp, check, insert, md_convert_frag):
+       Ditto.
+       * config/tc-sparc.c (md_assemble, sparc_ip, getExpression,
+       print_insn): Ditto.
+       * config/tc-tahoe.c (struct top, md_estimate_size_before_relax,
+       tip_op, md_assemble): Ditto.
+       * config/tc-vax.c (seg_of_operand, md_assemble,
+       md_estimate_size_before_relax, md_create_long_jump): Ditto.
+       * config/tc-z8k.c (parse_exp, check_operand, newfix): Ditto.
+
 Tue Jul 20 12:17:16 1993  david d `zoo' zuhn  (zoo@rtl.cygnus.com)
 
        * configure.in: i386-lynx is the same as i386-coff
index 38fead5..9b293fc 100644 (file)
@@ -30,11 +30,8 @@ const short seg_N_TYPE[] =
   N_DATA,
   N_BSS,
   N_UNDF,                      /* unknown */
-  N_UNDF,                      /* absent */
-  N_UNDF,                      /* pass1 */
   N_UNDF,                      /* error */
-  N_UNDF,                      /* bignum/flonum */
-  N_UNDF,                      /* difference */
+  N_UNDF,                      /* expression */
   N_UNDF,                      /* debug */
   N_UNDF,                      /* ntv */
   N_UNDF,                      /* ptv */
index d467715..6fc5b37 100644 (file)
@@ -28,11 +28,11 @@ const short                 /* in: segT   out: N_TYPE bits */
   N_DATA,
   N_BSS,
   N_UNDF,                      /* unknown */
-  N_UNDF,                      /* absent */
-  N_UNDF,                      /* pass1 */
   N_UNDF,                      /* error */
-  N_UNDF,                      /* bignum/flonum */
-  N_UNDF,                      /* difference */
+  N_UNDF,                      /* expression */
+  N_UNDF,                      /* debug */
+  N_UNDF,                      /* ntv */
+  N_UNDF,                      /* ptv */
   N_REGISTER,                  /* register */
 };
 
index 88f815d..adbf2ab 100644 (file)
@@ -1,5 +1,5 @@
 /* coff object file format with bfd
-   Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1990, 1991, 1993 Free Software Foundation, Inc.
 
 This file is part of GAS.
 
@@ -68,11 +68,8 @@ const short seg_N_TYPE[] =
   9,
   10,
   C_UNDEF_SECTION,             /* SEG_UNKNOWN */
-  C_UNDEF_SECTION,             /* SEG_ABSENT */
-  C_UNDEF_SECTION,             /* SEG_PASS1 */
   C_UNDEF_SECTION,             /* SEG_GOOF */
-  C_UNDEF_SECTION,             /* SEG_BIG */
-  C_UNDEF_SECTION,             /* SEG_DIFFERENCE */
+  C_UNDEF_SECTION,             /* SEG_EXPR */
   C_DEBUG_SECTION,             /* SEG_DEBUG */
   C_NTV_SECTION,               /* SEG_NTV */
   C_PTV_SECTION,               /* SEG_PTV */
@@ -879,6 +876,7 @@ DEFUN (obj_coff_def, (what),
   def_symbol_in_progress->sy_name_offset = ~0;
   def_symbol_in_progress->sy_number = ~0;
   def_symbol_in_progress->sy_frag = &zero_address_frag;
+  S_SET_VALUE (def_symbol_in_progress, 0);
 
   if (S_IS_STRING (def_symbol_in_progress))
     {
@@ -994,7 +992,7 @@ DEFUN_VOID (obj_coff_endef)
       || (S_GET_SEGMENT (def_symbol_in_progress) == SEG_DEBUG
          && !SF_GET_TAG (def_symbol_in_progress))
       || S_GET_SEGMENT (def_symbol_in_progress) == SEG_ABSOLUTE
-      || def_symbol_in_progress->sy_value.X_seg != absolute_section
+      || def_symbol_in_progress->sy_value.X_op != O_constant
       || (symbolP = symbol_find_base (S_GET_NAME (def_symbol_in_progress), DO_NOT_STRIP)) == NULL
       || (SF_GET_TAG (def_symbol_in_progress) != SF_GET_TAG (symbolP)))
     {
@@ -1242,11 +1240,11 @@ obj_coff_val ()
        }
       else if (strcmp (S_GET_NAME (def_symbol_in_progress), symbol_name))
        {
+         def_symbol_in_progress->sy_value.X_op = O_symbol;
          def_symbol_in_progress->sy_value.X_add_symbol =
            symbol_find_or_make (symbol_name);
-         def_symbol_in_progress->sy_value.X_subtract_symbol = NULL;
+         def_symbol_in_progress->sy_value.X_op_symbol = NULL;
          def_symbol_in_progress->sy_value.X_add_number = 0;
-         def_symbol_in_progress->sy_value.X_seg = undefined_section;
 
          /* If the segment is undefined when the forward reference is
             resolved, then copy the segment id from the forward
@@ -1377,7 +1375,7 @@ DEFUN_VOID (yank_symbols)
          /* L* and C_EFCN symbols never merge. */
          if (!SF_GET_LOCAL (symbolP)
              && S_GET_STORAGE_CLASS (symbolP) != C_LABEL
-             && symbolP->sy_value.X_seg == absolute_section
+             && symbolP->sy_value.X_op == O_constant
              && (real_symbolP = symbol_find_base (S_GET_NAME (symbolP), DO_NOT_STRIP))
              && real_symbolP != symbolP)
            {
index 5f4f181..7d99c9a 100644 (file)
@@ -530,7 +530,7 @@ obj_elf_stab_generic (what, secname)
       subseg_new ((char *) saved_seg->name, subseg);
 
       if ((what == 's' || what == 'n')
-         && symbolP->sy_value.X_seg == absolute_section)
+         && symbolP->sy_value.X_op == O_constant)
        {
          /* symbol is not needed in the regular symbol table */
          symbol_remove (symbolP, &symbol_rootP, &symbol_lastP);
@@ -718,7 +718,6 @@ obj_elf_size ()
   char c = get_symbol_end ();
   char *p;
   expressionS exp;
-  segT sec;
   symbolS *sym;
 
   p = input_line_pointer;
@@ -733,17 +732,17 @@ obj_elf_size ()
       return;
     }
   input_line_pointer++;
-  sec = expression (&exp);
-  if (sec == absent_section)
+  expression (&exp);
+  if (exp.X_op == O_absent)
     {
       as_bad ("missing expression in .size directive");
-      exp.X_seg = absolute_section;
+      exp.X_op = O_constant;
       exp.X_add_number = 0;
     }
   *p = 0;
   sym = symbol_find_or_make (name);
   *p = c;
-  if (sec == absolute_section)
+  if (exp.X_op == O_constant)
     S_SET_SIZE (sym, exp.X_add_number);
   else
     {
index 3c29d18..b8c75e2 100644 (file)
@@ -287,11 +287,8 @@ const short seg_N_TYPE[] =
   N_DATA,
   N_BSS,
   N_UNDF,                      /* unknown */
-  N_UNDF,                      /* absent */
-  N_UNDF,                      /* pass1 */
   N_UNDF,                      /* error */
-  N_UNDF,                      /* bignum/flonum */
-  N_UNDF,                      /* difference */
+  N_UNDF,                      /* expression */
   N_UNDF,                      /* debug */
   N_UNDF,                      /* ntv */
   N_UNDF,                      /* ptv */
index f14bf96..1ed07df 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-a29k.c -- Assemble for the AMD 29000.
-   Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -385,16 +385,12 @@ md_assemble (str)
   /* put out the symbol-dependent stuff */
   if (the_insn.reloc != NO_RELOC)
     {
-      fix_new (
-               frag_now,       /* which frag */
-               (toP - frag_now->fr_literal + the_insn.reloc_offset),   /* where */
-               4,              /* size */
-               the_insn.exp.X_add_symbol,
-               the_insn.exp.X_subtract_symbol,
-               the_insn.exp.X_add_number,
-               the_insn.pcrel,
-               the_insn.reloc
-       );
+      fix_new_exp (frag_now,
+                  (toP - frag_now->fr_literal + the_insn.reloc_offset),
+                  4,           /* size */
+                  &the_insn.exp,
+                  the_insn.pcrel,
+                  the_insn.reloc);
     }
 }
 
@@ -405,15 +401,12 @@ parse_operand (s, operandp)
 {
   char *save = input_line_pointer;
   char *new;
-  segT seg;
 
   input_line_pointer = s;
-  seg = expr (0, operandp);
+  if (expression (operandp) == O_absent)
+    as_bad ("missing operand");
   new = input_line_pointer;
   input_line_pointer = save;
-
-  if (seg == SEG_ABSENT)
-    as_bad ("Missing operand");
   return new;
 }
 
@@ -501,7 +494,7 @@ machine_ip (str)
          break;
 
        case 'v':               /* Trap numbers (immediate field) */
-         if (operand->X_seg == SEG_ABSOLUTE)
+         if (operand->X_op == O_constant)
            {
              if (operand->X_add_number < 256)
                {
@@ -524,11 +517,11 @@ machine_ip (str)
        case 'i':
          /* We treat the two cases identically since we mashed
                           them together in the opcode table.  */
-         if (operand->X_seg == SEG_REGISTER)
+         if (operand->X_op == O_register)
            goto general_reg;
 
          opcode |= IMMEDIATE_BIT;
-         if (operand->X_seg == SEG_ABSOLUTE)
+         if (operand->X_op == O_constant)
            {
              if (operand->X_add_number < 256)
                {
@@ -551,10 +544,10 @@ machine_ip (str)
        case 'c':
        general_reg:
          /* lrNNN or grNNN or %%expr or a user-def register name */
-         if (operand->X_seg != SEG_REGISTER)
+         if (operand->X_op != O_register)
            break;              /* Only registers */
          know (operand->X_add_symbol == 0);
-         know (operand->X_subtract_symbol == 0);
+         know (operand->X_op_symbol == 0);
          reg = operand->X_add_number;
          if (reg >= SREG)
            break;              /* No special registers */
@@ -583,7 +576,7 @@ machine_ip (str)
 
        case 'x':               /* 16 bit constant, zero-extended */
        case 'X':               /* 16 bit constant, one-extended */
-         if (operand->X_seg == SEG_ABSOLUTE)
+         if (operand->X_op == O_constant)
            {
              opcode |= (operand->X_add_number & 0xFF) << 0 |
                ((operand->X_add_number & 0xFF00) << 8);
@@ -594,7 +587,7 @@ machine_ip (str)
          continue;
 
        case 'h':
-         if (operand->X_seg == SEG_ABSOLUTE)
+         if (operand->X_op == O_constant)
            {
              opcode |= (operand->X_add_number & 0x00FF0000) >> 16 |
                (((unsigned long) operand->X_add_number
@@ -608,8 +601,8 @@ machine_ip (str)
        case 'P':               /* PC-relative jump address */
        case 'A':               /* Absolute jump address */
          /* These two are treated together since we folded the
-                          opcode table entries together.  */
-         if (operand->X_seg == SEG_ABSOLUTE)
+            opcode table entries together.  */
+         if (operand->X_op == O_constant)
            {
              opcode |= ABSOLUTE_BIT |
                (operand->X_add_number & 0x0003FC00) << 6 |
@@ -623,7 +616,7 @@ machine_ip (str)
          continue;
 
        case 'e':               /* Coprocessor enable bit for LOAD/STORE insn */
-         if (operand->X_seg == SEG_ABSOLUTE)
+         if (operand->X_op == O_constant)
            {
              if (operand->X_add_number == 0)
                continue;
@@ -636,7 +629,7 @@ machine_ip (str)
          break;
 
        case 'n':               /* Control bits for LOAD/STORE instructions */
-         if (operand->X_seg == SEG_ABSOLUTE &&
+         if (operand->X_op == O_constant &&
              operand->X_add_number < 128)
            {
              opcode |= (operand->X_add_number << 16);
@@ -645,7 +638,7 @@ machine_ip (str)
          break;
 
        case 's':               /* Special register number */
-         if (operand->X_seg != SEG_REGISTER)
+         if (operand->X_op != O_register)
            break;              /* Only registers */
          if (operand->X_add_number < SREG)
            break;              /* Not a special register */
@@ -653,7 +646,7 @@ machine_ip (str)
          continue;
 
        case 'u':               /* UI bit of CONVERT */
-         if (operand->X_seg == SEG_ABSOLUTE)
+         if (operand->X_op == O_constant)
            {
              if (operand->X_add_number == 0)
                continue;
@@ -666,7 +659,7 @@ machine_ip (str)
          break;
 
        case 'r':               /* RND bits of CONVERT */
-         if (operand->X_seg == SEG_ABSOLUTE &&
+         if (operand->X_op == O_constant &&
              operand->X_add_number < 8)
            {
              opcode |= operand->X_add_number << 4;
@@ -675,7 +668,7 @@ machine_ip (str)
          break;
 
        case 'd':               /* FD bits of CONVERT */
-         if (operand->X_seg == SEG_ABSOLUTE &&
+         if (operand->X_op == O_constant &&
              operand->X_add_number < 4)
            {
              opcode |= operand->X_add_number << 2;
@@ -685,7 +678,7 @@ machine_ip (str)
 
 
        case 'f':               /* FS bits of CONVERT */
-         if (operand->X_seg == SEG_ABSOLUTE &&
+         if (operand->X_op == O_constant &&
              operand->X_add_number < 4)
            {
              opcode |= operand->X_add_number << 0;
@@ -694,7 +687,7 @@ machine_ip (str)
          break;
 
        case 'C':
-         if (operand->X_seg == SEG_ABSOLUTE &&
+         if (operand->X_op == O_constant &&
              operand->X_add_number < 4)
            {
              opcode |= operand->X_add_number << 16;
@@ -703,7 +696,7 @@ machine_ip (str)
          break;
 
        case 'F':
-         if (operand->X_seg == SEG_ABSOLUTE &&
+         if (operand->X_op == O_constant &&
              operand->X_add_number < 16)
            {
              opcode |= operand->X_add_number << 18;
@@ -1031,10 +1024,10 @@ print_insn (insn)
           insn->exp.X_add_symbol ?
           (S_GET_NAME (insn->exp.X_add_symbol) ?
            S_GET_NAME (insn->exp.X_add_symbol) : "???") : "0");
-  fprintf (stderr, "\t\tX_sub_symbol = %s\n",
-          insn->exp.X_subtract_symbol ?
-          (S_GET_NAME (insn->exp.X_subtract_symbol) ?
-           S_GET_NAME (insn->exp.X_subtract_symbol) : "???") : "0");
+  fprintf (stderr, "\t\tX_op_symbol = %s\n",
+          insn->exp.X_op_symbol ?
+          (S_GET_NAME (insn->exp.X_op_symbol) ?
+           S_GET_NAME (insn->exp.X_op_symbol) : "???") : "0");
   fprintf (stderr, "\t\tX_add_number = %d\n",
           insn->exp.X_add_number);
   fprintf (stderr, "}\n");
@@ -1141,22 +1134,22 @@ md_operand (expressionP)
       /* We have a numeric register expression.  No biggy.  */
       input_line_pointer += 2; /* Skip %% */
       (void) expression (expressionP);
-      if (expressionP->X_seg != SEG_ABSOLUTE
+      if (expressionP->X_op != O_constant
          || expressionP->X_add_number > 255)
        as_bad ("Invalid expression after %%%%\n");
-      expressionP->X_seg = SEG_REGISTER;
+      expressionP->X_op = O_register;
     }
   else if (input_line_pointer[0] == '&')
     {
       /* We are taking the 'address' of a register...this one is not
-                      in the manual, but it *is* in traps/fpsymbol.h!  What they
-                      seem to want is the register number, as an absolute number.  */
+        in the manual, but it *is* in traps/fpsymbol.h!  What they
+        seem to want is the register number, as an absolute number.  */
       input_line_pointer++;    /* Skip & */
       (void) expression (expressionP);
-      if (expressionP->X_seg != SEG_REGISTER)
+      if (expressionP->X_op != O_register)
        as_bad ("Invalid register in & expression");
       else
-       expressionP->X_seg = SEG_ABSOLUTE;
+       expressionP->X_op = O_constant;
     }
 }
 
index 4f31bb1..a7a1fc8 100644 (file)
@@ -269,29 +269,13 @@ DEFUN (parse_exp, (s, op),
 {
   char *save = input_line_pointer;
   char *new;
-  segT seg;
 
   input_line_pointer = s;
-  seg = expr (0, op);
+  if (expression (op) == O_absent)
+    as_bad ("missing operand");
   new = input_line_pointer;
   input_line_pointer = save;
-  if (SEG_NORMAL (seg))
-    return new;
-  switch (seg)
-    {
-    case SEG_ABSOLUTE:
-    case SEG_UNKNOWN:
-    case SEG_DIFFERENCE:
-    case SEG_BIG:
-    case SEG_REGISTER:
-      return new;
-    case SEG_ABSENT:
-      as_bad ("Missing operand");
-      return new;
-    default:
-      as_bad ("Don't understand operand of type %s", segment_name (seg));
-      return new;
-    }
+  return new;
 }
 
 static char *
@@ -365,7 +349,7 @@ colonmod24 (op, src)
            mode = L_16;
       }
       else if (op->exp.X_add_symbol
-              || op->exp.X_subtract_symbol)
+              || op->exp.X_op_symbol)
        mode = DSYMMODE;
       else
        mode = DMODE;
@@ -722,7 +706,7 @@ DEFUN (check_operand, (operand, width, string),
        char *string)
 {
   if (operand->exp.X_add_symbol == 0
-      && operand->exp.X_subtract_symbol == 0)
+      && operand->exp.X_op_symbol == 0)
     {
 
       /* No symbol involved, let's look at offset, it's dangerous if any of
@@ -814,14 +798,13 @@ do_a_fix_imm (offset, operand, relaxing)
        }
 
 
-      fix_new (frag_now,
-              offset + where,
-              size,
-              operand->exp.X_add_symbol,
-              operand->exp.X_subtract_symbol,
-              (short) (operand->exp.X_add_number),
-              0,
-              idx);
+      operand->exp.X_add_number = (short) operand->exp.X_add_number;
+      fix_new_exp (frag_now,
+                  offset + where,
+                  size,
+                  &operand->exp,
+                  0,
+                  idx);
     }
 
 }
@@ -970,27 +953,25 @@ build_bytes (this_try, operand)
                       operand->exp.X_add_number);
            }
 
-         fix_new (frag_now,
-                  output - frag_now->fr_literal + where,
-                  size,
-                  operand[i].exp.X_add_symbol,
-                  operand[i].exp.X_subtract_symbol,
-                  (char) (operand[i].exp.X_add_number - 1),
-                  1,
-                  type);
+         oeprand[i].exp.X_add_number =
+           (char) (operand[i].exp.X_add_number - 1);
+         fix_new_exp (frag_now,
+                      output - frag_now->fr_literal + where,
+                      size,
+                      &operand[i].exp,
+                      1,
+                      type);
        }
       else if (x & MEMIND)
        {
 
          check_operand (operand + i, 0xff, "@@");
-         fix_new (frag_now,
-                  output - frag_now->fr_literal + 1,
-                  1,
-                  operand[i].exp.X_add_symbol,
-                  operand[i].exp.X_subtract_symbol,
-                  operand[i].exp.X_add_number,
-                  0,
-                  R_RELBYTE);
+         fix_new_exp (frag_now,
+                      output - frag_now->fr_literal + 1,
+                      1,
+                      &operand[i].exp,
+                      0,
+                      R_RELBYTE);
        }
 
       else if (x & ABSMOV)
@@ -1009,14 +990,13 @@ build_bytes (this_try, operand)
              as_warn ("branch operand has odd offset (%x)\n",
                       operand->exp.X_add_number);
            }
-         fix_new (frag_now,
-                  output - frag_now->fr_literal,
-                  4,
-                  operand[i].exp.X_add_symbol,
-                  operand[i].exp.X_subtract_symbol,
-                  (short) (operand[i].exp.X_add_number),
-                  0,
-                  R_JMPL1);
+         operand[i].exp = (short) operand[i].exp.X_add_number;
+         fix_new_exp (frag_now,
+                      output - frag_now->fr_literal,
+                      4,
+                      &operand[i].exp,
+                      0,
+                      R_JMPL1);
        }
     }
 
index 4ad462e..404db3a 100644 (file)
@@ -258,7 +258,6 @@ parse_exp (s, op, page)
 {
   char *save;
   char *new;
-  segT seg;
 
   save = input_line_pointer;
 
@@ -284,26 +283,11 @@ parse_exp (s, op, page)
 
   input_line_pointer = s;
 
-  seg = expr (0, op);
+  if (expression (op) == O_absent)
+    as_bad ("missing operand");
   new = input_line_pointer;
   input_line_pointer = save;
-  if (SEG_NORMAL (seg))
-    return new;
-  switch (seg)
-    {
-    case SEG_ABSOLUTE:
-    case SEG_UNKNOWN:
-    case SEG_DIFFERENCE:
-    case SEG_BIG:
-    case SEG_REGISTER:
-      return new;
-    case SEG_ABSENT:
-      as_bad ("Missing operand");
-      return new;
-    default:
-      as_bad ("Don't understand operand of type %s", segment_name (seg));
-      return new;
-    }
+  return new;
 }
 
 typedef enum
@@ -366,7 +350,7 @@ skip_colonthing (sign, ptr, exp, def, size8, size16, size24)
          /* Let's work out the size from the context */
          int n = exp->exp.X_add_number;
          if (size8
-             && exp->exp.X_seg == SEG_ABSOLUTE
+             && exp->exp.X_op == O_constant
              && ((sign == exp_signed && (n >= -128 && n <= 127))
                  || (sign == exp_unsigned && (n >= 0 && (n <= 255)))
                  || (sign == exp_sandu && (n >= -128 && (n <= 255)))))
@@ -430,9 +414,9 @@ parse_reglist (src, op)
     }
   idx++;
   op->exp.X_add_symbol = 0;
-  op->exp.X_subtract_symbol = 0;
+  op->exp.X_op_symbol = 0;
   op->exp.X_add_number = mask;
-  op->exp.X_seg = SEG_ABSOLUTE;
+  op->exp.X_op = O_constant;
   op->type = IMM8;
   return idx;
 
@@ -795,7 +779,7 @@ get_specific (opcode, operands)
              break;
            case QIM:
              if (user->type == IMM8
-                 && user->exp.X_seg == SEG_ABSOLUTE
+                 && user->exp.X_op == O_constant
                  &&
                  (user->exp.X_add_number == -2
                   || user->exp.X_add_number == -1
@@ -871,7 +855,7 @@ check (operand, low, high)
      int low;
      int high;
 {
-  if (operand->X_seg != SEG_ABSOLUTE
+  if (operand->X_op != O_constant
       || operand->X_add_number < low
       || operand->X_add_number > high)
     {
@@ -889,14 +873,12 @@ insert (output, index, exp, reloc, pcrel)
      int reloc;
      int pcrel;
 {
-  fix_new (frag_now,
-          output - frag_now->fr_literal + index,
-          4,                   /* always say size is 4, but we know better */
-          exp->X_add_symbol,
-          exp->X_subtract_symbol,
-          exp->X_add_number,
-          pcrel,
-          reloc);
+  fix_new_exp (frag_now,
+              output - frag_now->fr_literal + index,
+              4,               /* always say size is 4, but we know better */
+              &exp,
+              pcrel,
+              reloc);
 }
 
 void
@@ -1399,7 +1381,6 @@ md_convert_frag (headers, fragP)
               fragP->fr_fix + inst_size,
               4,
               fragP->fr_symbol,
-              0,
               fragP->fr_offset,
               0,
               R_H8500_PCREL16);
index 3774d93..3694ac2 100644 (file)
@@ -1,5 +1,5 @@
 /* i386.c -- Assemble code for the Intel 80386
-   Copyright (C) 1989, 1991, 1992 Free Software Foundation.
+   Copyright (C) 1989, 1991, 1992, 1993 Free Software Foundation.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -522,7 +522,7 @@ static void
 pe (e)
      expressionS *e;
 {
-  fprintf (stdout, "    segment       %s\n", segment_name (e->X_seg));
+  fprintf (stdout, "    operation       %d\n", e->X_op);
   fprintf (stdout, "    add_number    %d (%x)\n",
           e->X_add_number, e->X_add_number);
   if (e->X_add_symbol)
@@ -531,10 +531,10 @@ pe (e)
       ps (e->X_add_symbol);
       fprintf (stdout, "\n");
     }
-  if (e->X_subtract_symbol)
+  if (e->X_op_symbol)
     {
-      fprintf (stdout, "    sub_symbol    ");
-      ps (e->X_subtract_symbol);
+      fprintf (stdout, "    op_symbol    ");
+      ps (e->X_op_symbol);
       fprintf (stdout, "\n");
     }
 }
@@ -1254,10 +1254,10 @@ md_assemble (line)
                           holds the correct displacement size. */
                        exp = &disp_expressions[i.disp_operands++];
                        i.disps[o] = exp;
-                       exp->X_seg = absolute_section;
+                       exp->X_op = O_constant;
                        exp->X_add_number = 0;
                        exp->X_add_symbol = (symbolS *) 0;
-                       exp->X_subtract_symbol = (symbolS *) 0;
+                       exp->X_op_symbol = (symbolS *) 0;
                      }
 
                    /* Select the correct segment for the memory operand. */
@@ -1337,11 +1337,8 @@ md_assemble (line)
     if (t->opcode_modifier & Jump)
       {
        int n = i.disps[0]->X_add_number;
-       segT seg;
 
-       seg = i.disps[0]->X_seg;
-
-       if (seg == absolute_section)
+       if (i.disps[0]->X_op == O_constant)
          {
            if (fits_in_signed_byte (n))
              {
@@ -1417,7 +1414,7 @@ md_assemble (line)
          }
 
        p = frag_more (size);
-       if (i.disps[0]->X_seg == absolute_section)
+       if (i.disps[0]->X_op == O_constant)
          {
            md_number_to_chars (p, n, size);
            if (size == 1 && !fits_in_signed_byte (n))
@@ -1428,23 +1425,20 @@ md_assemble (line)
          }
        else
          {
-           fix_new (frag_now, p - frag_now->fr_literal, size,
-                    i.disps[0]->X_add_symbol, i.disps[0]->X_subtract_symbol,
-                    i.disps[0]->X_add_number, 1, NO_RELOC);
+           fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+                        i.disps[0], 1, NO_RELOC);
          }
       }
     else if (t->opcode_modifier & JumpInterSegment)
       {
        p = frag_more (1 + 2 + 4);      /* 1 opcode; 2 segment; 4 offset */
        p[0] = t->base_opcode;
-       if (i.imms[1]->X_seg == absolute_section)
+       if (i.imms[1]->X_op == O_constant)
          md_number_to_chars (p + 1, i.imms[1]->X_add_number, 4);
        else
-         fix_new (frag_now, p + 1 - frag_now->fr_literal, 4,
-                  i.imms[1]->X_add_symbol,
-                  i.imms[1]->X_subtract_symbol,
-                  i.imms[1]->X_add_number, 0, NO_RELOC);
-       if (i.imms[0]->X_seg != absolute_section)
+         fix_new_exp (frag_now, p + 1 - frag_now->fr_literal, 4,
+                      i.imms[1], 0, NO_RELOC);
+       if (i.imms[0]->X_op != O_constant)
          as_bad ("can't handle non absolute segment in long call/jmp");
        md_number_to_chars (p + 5, i.imms[0]->X_add_number, 2);
       }
@@ -1510,7 +1504,7 @@ md_assemble (line)
              {
                if (i.disps[n])
                  {
-                   if (i.disps[n]->X_seg == absolute_section)
+                   if (i.disps[n]->X_op == O_constant)
                      {
                        if (i.types[n] & (Disp8 | Abs8))
                          {
@@ -1532,9 +1526,8 @@ md_assemble (line)
                      {         /* not absolute_section */
                        /* need a 32-bit fixup (don't support 8bit non-absolute disps) */
                        p = frag_more (4);
-                       fix_new (frag_now, p - frag_now->fr_literal, 4,
-                                i.disps[n]->X_add_symbol, i.disps[n]->X_subtract_symbol,
-                                i.disps[n]->X_add_number, 0, NO_RELOC);
+                       fix_new_exp (frag_now, p - frag_now->fr_literal, 4,
+                                    i.disps[n], 0, NO_RELOC);
                      }
                  }
              }
@@ -1549,7 +1542,7 @@ md_assemble (line)
              {
                if (i.imms[n])
                  {
-                   if (i.imms[n]->X_seg == absolute_section)
+                   if (i.imms[n]->X_op == O_constant)
                      {
                        if (i.types[n] & (Imm8 | Imm8S))
                          {
@@ -1579,9 +1572,8 @@ md_assemble (line)
                        else
                          size = 4;
                        p = frag_more (size);
-                       fix_new (frag_now, p - frag_now->fr_literal, size,
-                                i.imms[n]->X_add_symbol, i.imms[n]->X_subtract_symbol,
-                                i.imms[n]->X_add_number, 0, NO_RELOC);
+                       fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+                                    i.imms[n], 0, NO_RELOC);
                      }
                  }
              }
@@ -1696,18 +1688,18 @@ i386_operand (operand_string)
       exp_seg = expression (exp);
       input_line_pointer = save_input_line_pointer;
 
-      if (exp_seg == absent_section)
+      if (exp.X_op == O_absent)
        {
          /* missing or bad expr becomes absolute 0 */
          as_bad ("missing or invalid immediate expression '%s' taken as 0",
                  operand_string);
-         exp->X_seg = absolute_section;
+         exp->X_op = O_constant;
          exp->X_add_number = 0;
          exp->X_add_symbol = (symbolS *) 0;
-         exp->X_subtract_symbol = (symbolS *) 0;
+         exp->X_op_symbol = (symbolS *) 0;
          i.types[this_operand] |= Imm;
        }
-      else if (exp_seg == absolute_section)
+      else if (exp.X_op == O_constant)
        {
          i.types[this_operand] |= smallest_imm_type (exp->X_add_number);
        }
@@ -1937,18 +1929,18 @@ i386_operand (operand_string)
            as_bad ("Ignoring junk '%s' after expression", input_line_pointer);
          RESTORE_END_STRING (displacement_string_end);
          input_line_pointer = save_input_line_pointer;
-         if (exp_seg == absent_section)
+         if (exp.X_op == O_absent)
            {
              /* missing expr becomes absolute 0 */
              as_bad ("missing or invalid displacement '%s' taken as 0",
                      operand_string);
              i.types[this_operand] |= (Disp | Abs);
-             exp->X_seg = absolute_section;
+             exp->X_op = O_constant;
              exp->X_add_number = 0;
              exp->X_add_symbol = (symbolS *) 0;
-             exp->X_subtract_symbol = (symbolS *) 0;
+             exp->X_op_symbol = (symbolS *) 0;
            }
-         else if (exp_seg == absolute_section)
+         else if (exp.X_op == O_constant)
            {
              i.types[this_operand] |= SMALLEST_DISP_TYPE (exp->X_add_number);
            }
@@ -2042,7 +2034,6 @@ md_estimate_size_before_relax (fragP, segment)
          fragP->fr_fix += 4;
          fix_new (fragP, old_fr_fix, 4,
                   fragP->fr_symbol,
-                  (symbolS *) 0,
                   fragP->fr_offset, 1, NO_RELOC);
          break;
 
@@ -2054,7 +2045,6 @@ md_estimate_size_before_relax (fragP, segment)
          fragP->fr_fix += 1 + 4;       /* we've added an opcode byte */
          fix_new (fragP, old_fr_fix + 1, 4,
                   fragP->fr_symbol,
-                  (symbolS *) 0,
                   fragP->fr_offset, 1, NO_RELOC);
          break;
        }
@@ -2187,7 +2177,7 @@ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
       md_number_to_chars (ptr, 0xe9, 1);       /* opcode for long jmp */
       md_number_to_chars (ptr + 1, offset, 4);
       fix_new (frag, (ptr + 1) - frag->fr_literal, 4,
-              to_symbol, (symbolS *) 0, (long) 0, 0, NO_RELOC);
+              to_symbol, (offsetT) 0, 0, NO_RELOC);
     }
   else
     {
index 773efc0..e2ed93d 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-i960.c - All the i80960-specific stuff
-   Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
 
    This file is part of GAS.
 
@@ -113,7 +113,7 @@ static int get_regnum ();   /* Translate text to register number */
 static int i_scan ();          /* Lexical scan of instruction source */
 static void mem_fmt ();                /* Generate MEMA or MEMB instruction */
 static void mema_to_memb ();   /* Convert MEMA instruction to MEMB format */
-static segT parse_expr ();     /* Parse an expression */
+static void parse_expr ();     /* Parse an expression */
 static int parse_ldconst ();   /* Parse and replace a 'ldconst' pseudo-op */
 static void parse_memop ();    /* Parse a memory operand */
 static void parse_po ();       /* Parse machine-dependent pseudo-op */
@@ -208,9 +208,7 @@ const pseudo_typeS md_pseudo_table[] =
 \f
 /* Macros to extract info from an 'expressionS' structure 'e' */
 #define adds(e)        e.X_add_symbol
-#define subs(e)        e.X_subtract_symbol
 #define offs(e)        e.X_add_number
-#define segs(e)        e.X_seg
 
 
 /* Branch-prediction bits for CTRL/COBR format opcodes */
@@ -1050,7 +1048,6 @@ md_convert_frag (headers, fragP)
                      fragP->fr_opcode - fragP->fr_literal,
                      4,
                      fragP->fr_symbol,
-                     0,
                      fragP->fr_offset,
                      1,
                      NO_RELOC);
@@ -1239,7 +1236,6 @@ brtab_emit ()
                      symbol_find (buf),
                      0,
                      0,
-                     0,
                      NO_RELOC);
       fixP->fx_im_disp = 2;    /* 32-bit displacement fix */
     }
@@ -1502,51 +1498,49 @@ get_cdisp (dispP, ifmtP, instr, numbits, var_frag, callj)
 
   fixP = NULL;
 
-  switch (parse_expr (dispP, &e))
+  parse_expr (dispP, &e);
+  switch (e.X_op)
     {
-
-    case SEG_GOOF:
+    case O_illegal:
       as_bad ("expression syntax error");
-      break;
 
-    case SEG_TEXT:
-    case SEG_UNKNOWN:
-      if (var_frag)
-       {
-         outP = frag_more (8); /* Allocate worst-case storage */
-         md_number_to_chars (outP, instr, 4);
-         frag_variant (rs_machine_dependent, 4, 4, 1,
-                       adds (e), offs (e), outP, 0, 0);
+    case O_symbol:
+      if (S_GET_SEGMENT (e.X_add_symbol) == text_section
+         || S_GET_SEGMENT (e.X_add_symbol) == undefined_section)
+       {       
+         if (var_frag)
+           {
+             outP = frag_more (8); /* Allocate worst-case storage */
+             md_number_to_chars (outP, instr, 4);
+             frag_variant (rs_machine_dependent, 4, 4, 1,
+                           adds (e), offs (e), outP, 0, 0);
+           }
+         else
+           {
+             /* Set up a new fix structure, so address can be updated
+              * when all symbol values are known.
+              */
+             outP = emit (instr);
+             fixP = fix_new (frag_now,
+                             outP - frag_now->fr_literal,
+                             4,
+                             adds (e),
+                             offs (e),
+                             1,
+                             NO_RELOC);
+
+             fixP->fx_callj = callj;
+
+             /* We want to modify a bit field when the address is
+              * known.  But we don't need all the garbage in the
+              * bit_fix structure.  So we're going to lie and store
+              * the number of bits affected instead of a pointer.
+              */
+             fixP->fx_bit_fixP = (bit_fixS *) numbits;
+           }
        }
       else
-       {
-         /* Set up a new fix structure, so address can be updated
-          * when all symbol values are known.
-          */
-         outP = emit (instr);
-         fixP = fix_new (frag_now,
-                         outP - frag_now->fr_literal,
-                         4,
-                         adds (e),
-                         0,
-                         offs (e),
-                         1,
-                         NO_RELOC);
-
-         fixP->fx_callj = callj;
-
-         /* We want to modify a bit field when the address is
-          * known.  But we don't need all the garbage in the
-          * bit_fix structure.  So we're going to lie and store
-          * the number of bits affected instead of a pointer.
-          */
-         fixP->fx_bit_fixP = (bit_fixS *) numbits;
-       }
-      break;
-
-    case SEG_DATA:
-    case SEG_BSS:
-      as_bad ("attempt to branch into different segment");
+       as_bad ("attempt to branch into different segment");
       break;
 
     default:
@@ -1722,14 +1716,14 @@ mem_fmt (args, oP, callx)
     }
 
   /* Parse and process the displacement */
-  switch (parse_expr (instr.e, &expr))
+  parse_expr (instr.e, &expr);
+  switch (expr.X_op)
     {
-
-    case SEG_GOOF:
+    case O_illegal:
       as_bad ("expression syntax error");
       break;
 
-    case SEG_ABSOLUTE:
+    case O_constant:
       if (instr.disp == 32)
        {
          (void) emit (offs (expr));    /* Output displacement */
@@ -1740,28 +1734,24 @@ mem_fmt (args, oP, callx)
          if (offs (expr) & ~0xfff)
            {
              /* Won't fit in 12 bits: convert already-output
-                                * instruction to MEMB format, output
-                                * displacement.
-                                */
+              * instruction to MEMB format, output
+              * displacement.
+              */
              mema_to_memb (outP);
              (void) emit (offs (expr));
            }
          else
            {
              /* WILL fit in 12 bits:  OR into opcode and
-                                * overwrite the binary we already put out
-                                */
+              * overwrite the binary we already put out
+              */
              instr.opcode |= offs (expr);
              md_number_to_chars (outP, instr.opcode, 4);
            }
        }
       break;
 
-    case SEG_DIFFERENCE:
-    case SEG_TEXT:
-    case SEG_DATA:
-    case SEG_BSS:
-    case SEG_UNKNOWN:
+    default:
       if (instr.disp == 12)
        {
          /* Displacement is dependent on a symbol, whose value
@@ -1775,21 +1765,15 @@ mem_fmt (args, oP, callx)
        * this symbol's value becomes known.
        */
       outP = emit ((long) 0);
-      fixP = fix_new (frag_now,
-                     outP - frag_now->fr_literal,
-                     4,
-                     adds (expr),
-                     subs (expr),
-                     offs (expr),
-                     0,
-                     NO_RELOC);
+      fixP = fix_new_exp (frag_now,
+                         outP - frag_now->fr_literal,
+                         4,
+                         &expr,
+                         0,
+                         NO_RELOC);
       fixP->fx_im_disp = 2;    /* 32-bit displacement fix */
       fixP->fx_bsr = callx;    /*SAC LD RELAX HACK *//* Mark reloc as being in i stream */
       break;
-
-    default:
-      BAD_CASE (segs (expr));
-      break;
     }
 }                              /* memfmt() */
 
@@ -1836,19 +1820,16 @@ mema_to_memb (opcodeP)
  *
  *     An empty expression string is treated as an absolute 0.
  *
- *     Return "segment" to which the expression evaluates.
- *     Return SEG_GOOF regardless of expression evaluation if entire input
+ *     Sets O_illegal regardless of expression evaluation if entire input
  *     string is not consumed in the evaluation -- tolerate no dangling junk!
  *
  **************************************************************************** */
-static
-  segT
+static void
 parse_expr (textP, expP)
      char *textP;              /* Text of expression to be parsed */
      expressionS *expP;                /* Where to put the results of parsing */
 {
   char *save_in;               /* Save global here */
-  segT seg;                    /* Segment to which expression evaluates */
   symbolS *symP;
 
   know (textP);
@@ -1856,10 +1837,9 @@ parse_expr (textP, expP)
   if (*textP == '\0')
     {
       /* Treat empty string as absolute 0 */
-      expP->X_add_symbol = expP->X_subtract_symbol = NULL;
+      expP->X_add_symbol = expP->X_op_symbol = NULL;
       expP->X_add_number = 0;
-      seg = expP->X_seg = SEG_ABSOLUTE;
-
+      exp->X_op = O_constant;
     }
   else
     {
@@ -1870,13 +1850,14 @@ parse_expr (textP, expP)
       if (input_line_pointer - textP != strlen (textP))
        {
          /* Did not consume all of the input */
-         seg = SEG_GOOF;
+         expP->X_op = O_illegal;
        }
       symP = expP->X_add_symbol;
       if (symP && (hash_find (reg_hash, S_GET_NAME (symP))))
        {
          /* Register name in an expression */
-         seg = SEG_GOOF;
+         /* FIXME: this isn't much of a check any more.  */
+         expP->X_op = O_illegal;
        }
 
       input_line_pointer = save_in;    /* Restore global */
@@ -1914,31 +1895,27 @@ parse_ldconst (arg)
 
   arg[3] = NULL;               /* So we can tell at the end if it got used or not */
 
-  switch (parse_expr (arg[1], &e))
+  parse_expr (arg[1], &e);
+  switch (e.X_op)
     {
-
-    case SEG_TEXT:
-    case SEG_DATA:
-    case SEG_BSS:
-    case SEG_UNKNOWN:
-    case SEG_DIFFERENCE:
+    default:
       /* We're dependent on one or more symbols -- use "lda" */
       arg[0] = "lda";
       break;
 
-    case SEG_ABSOLUTE:
+    case O_constant:
       /* Try the following mappings:
-                *      ldconst 0,<reg>  ->mov  0,<reg>
-                *      ldconst 31,<reg> ->mov  31,<reg>
-                *      ldconst 32,<reg> ->addo 1,31,<reg>
-                *      ldconst 62,<reg> ->addo 31,31,<reg>
-                *      ldconst 64,<reg> ->shlo 8,3,<reg>
-                *      ldconst -1,<reg> ->subo 1,0,<reg>
-                *      ldconst -31,<reg>->subo 31,0,<reg>
-                *
-                * anthing else becomes:
-                *      lda xxx,<reg>
-                */
+             ldconst 0,<reg>  ->mov  0,<reg>
+             ldconst 31,<reg> ->mov  31,<reg>
+             ldconst 32,<reg> ->addo 1,31,<reg>
+             ldconst 62,<reg> ->addo 31,31,<reg>
+             ldconst 64,<reg> ->shlo 8,3,<reg>
+             ldconst -1,<reg> ->subo 1,0,<reg>
+             ldconst -31,<reg>->subo 31,0,<reg>
+       *
+       * anthing else becomes:
+             lda xxx,<reg>
+       */
       n = offs (e);
       if ((0 <= n) && (n <= 31))
        {
@@ -1979,7 +1956,7 @@ parse_ldconst (arg)
        }
       break;
 
-    default:
+    case O_illegal:
       as_bad ("invalid constant");
       return -1;
       break;
@@ -2362,7 +2339,8 @@ parse_regop (regopP, optext, opdesc)
        }
       else
        {                       /* fixed point literal acceptable */
-         if ((parse_expr (optext, &e) != SEG_ABSOLUTE)
+         parse_expr (optext, &e);
+         if (e.X_op != O_constant
              || (offs (e) < 0) || (offs (e) > 31))
            {
              as_bad ("illegal literal");
@@ -2537,7 +2515,6 @@ relax_cobr (fragP)
                  iP + 4 - fragP->fr_literal,
                  4,
                  fragP->fr_symbol,
-                 0,
                  fragP->fr_offset,
                  1,
                  NO_RELOC);
@@ -2711,7 +2688,8 @@ s_sysproc (n_ops, args)
     }                          /* bad arg count */
 
   /* Parse "entry_num" argument and check it for validity. */
-  if ((parse_expr (args[2], &exp) != SEG_ABSOLUTE)
+  parse_expr (args[2], &exp);
+  if (exp.X_op != O_constant
       || (offs (exp) < 0)
       || (offs (exp) > 31))
     {
@@ -3214,7 +3192,7 @@ i960_handle_align (fragp)
     }
 
   /* alignment directive */
-  fixp = fix_new (fragp, fragp->fr_fix, fragp->fr_offset, 0, 0, 0, 0,
+  fixp = fix_new (fragp, fragp->fr_fix, fragp->fr_offset, 0, 0, 0,
                  (int) fragp->fr_type);
 }
 
index 1092250..801748f 100644 (file)
@@ -1,7 +1,7 @@
 /* m88k.c -- Assembler for the Motorola 88000
    Contributed by Devon Bowen of Buffalo University
    and Torbjorn Granlund of the Swedish Institute of Computer Science.
-   Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1990, 1991, 1993 Free Software Foundation, Inc.
 
 This file is part of GAS, the GNU Assembler.
 
@@ -274,9 +274,9 @@ md_assemble (op)
   /* try parsing this instruction into insn */
 
   insn.exp.X_add_symbol = 0;
-  insn.exp.X_subtract_symbol = 0;
+  insn.exp.X_op_symbol = 0;
   insn.exp.X_add_number = 0;
-  insn.exp.X_seg = 0;
+  insn.exp.X_op = O_illegal;
   insn.reloc = NO_RELOC;
 
   while (!calcop (format, param, &insn))
@@ -306,47 +306,39 @@ md_assemble (op)
 
     case RELOC_LO16:
     case RELOC_HI16:
-      fix_new (frag_now,
-              thisfrag - frag_now->fr_literal + 2,
-              2,
-              insn.exp.X_add_symbol,
-              insn.exp.X_subtract_symbol,
-              insn.exp.X_add_number,
-              0,
-              insn.reloc);
+      fix_new_exp (frag_now,
+                  thisfrag - frag_now->fr_literal + 2,
+                  2,
+                  &insn.exp,
+                  0,
+                  insn.reloc);
       break;
 
     case RELOC_IW16:
-      fix_new (frag_now,
-              thisfrag - frag_now->fr_literal,
-              4,
-              insn.exp.X_add_symbol,
-              insn.exp.X_subtract_symbol,
-              insn.exp.X_add_number,
-              0,
-              insn.reloc);
+      fix_new_exp (frag_now,
+                  thisfrag - frag_now->fr_literal,
+                  4,
+                  &insn.exp,
+                  0,
+                  insn.reloc);
       break;
 
     case RELOC_PC16:
-      fix_new (frag_now,
-              thisfrag - frag_now->fr_literal + 2,
-              2,
-              insn.exp.X_add_symbol,
-              insn.exp.X_subtract_symbol,
-              insn.exp.X_add_number,
-              1,
-              insn.reloc);
+      fix_new_exp (frag_now,
+                  thisfrag - frag_now->fr_literal + 2,
+                  2,
+                  &insn.exp,
+                  1,
+                  insn.reloc);
       break;
 
     case RELOC_PC26:
-      fix_new (frag_now,
-              thisfrag - frag_now->fr_literal,
-              4,
-              insn.exp.X_add_symbol,
-              insn.exp.X_subtract_symbol,
-              insn.exp.X_add_number,
-              1,
-              insn.reloc);
+      fix_new_exp (frag_now,
+                  thisfrag - frag_now->fr_literal,
+                  4,
+                  &insn.exp,
+                  1,
+                  insn.reloc);
       break;
 
     default:
@@ -542,7 +534,6 @@ get_imm16 (param, insn)
 {
   enum reloc_type reloc = NO_RELOC;
   unsigned int val;
-  segT seg;
   char *save_ptr;
 
   if (!strncmp (param, "hi16", 4) && !isalnum (param[4]))
@@ -563,13 +554,13 @@ get_imm16 (param, insn)
 
   save_ptr = input_line_pointer;
   input_line_pointer = param;
-  seg = expression (&insn->exp);
+  expression (&insn->exp);
   param = input_line_pointer;
   input_line_pointer = save_ptr;
 
   val = insn->exp.X_add_number;
 
-  if (seg == SEG_ABSOLUTE)
+  if (insn->exp.X_op == O_constant)
     {
       /* Insert the value now, and reset reloc to NO_RELOC.  */
       if (reloc == NO_RELOC)
@@ -602,17 +593,16 @@ get_pcr (param, insn, reloc)
      enum reloc_type reloc;
 {
   char *saveptr, *saveparam;
-  segT seg;
 
   saveptr = input_line_pointer;
   input_line_pointer = param;
 
-  seg = expression (&insn->exp);
+  expression (&insn->exp);
 
   saveparam = input_line_pointer;
   input_line_pointer = saveptr;
 
-  /* Botch: We should relocate now if SEG_ABSOLUTE.  */
+  /* Botch: We should relocate now if O_constant.  */
   insn->reloc = reloc;
 
   return saveparam;
@@ -1148,8 +1138,7 @@ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
           ptr - frag->fr_literal,
           4,
           to_symbol,
-          (symbolS *) 0,
-          (long int) 0,
+          (offsetT) 0,
           0,
           RELOC_PC26);         /* Botch: Shouldn't this be RELOC_PC16? */
 }
@@ -1171,8 +1160,7 @@ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
           ptr - frag->fr_literal,
           4,
           to_symbol,
-          (symbolS *) 0,
-          (long int) 0,
+          (offsetT) 0,
           0,
           RELOC_PC26);
 }
index 9075b26..db0671e 100644 (file)
@@ -161,7 +161,6 @@ static void mips_ip PARAMS ((char *str, struct mips_cl_insn * ip));
 static int my_getSmallExpression PARAMS ((expressionS * ep, char *str));
 static void my_getExpression PARAMS ((expressionS * ep, char *str));
 static symbolS *get_symbol PARAMS ((void));
-static long get_optional_absolute_expression PARAMS ((void));
 static void mips_align PARAMS ((int to, int fill));
 static void s_align PARAMS ((int));
 static void s_stringer PARAMS ((int));
@@ -336,8 +335,8 @@ md_assemble (str)
       init = 1;
     }
 
-  imm_expr.X_seg = absent_section;
-  offset_expr.X_seg = absent_section;
+  imm_expr.X_op = O_absent;
+  offset_expr.X_op = O_absent;
 
   mips_ip (str, &insn);
   if (insn_error)
@@ -351,9 +350,9 @@ md_assemble (str)
     }
   else
     {
-      if (imm_expr.X_seg != absent_section)
+      if (imm_expr.X_op != O_absent)
        append_insn (&insn, &imm_expr, imm_reloc);
-      else if (offset_expr.X_seg != absent_section)
+      else if (offset_expr.X_op != O_absent)
        append_insn (&insn, &offset_expr, offset_reloc);
       else
        append_insn (&insn, NULL, BFD_RELOC_UNUSED);
@@ -571,7 +570,7 @@ append_insn (ip, address_expr, reloc_type)
   fixp = NULL;
   if (address_expr != NULL)
     {
-      if (address_expr->X_seg == &bfd_abs_section)
+      if (address_expr->X_op == O_constant)
        {
          switch (reloc_type)
            {
@@ -595,12 +594,10 @@ append_insn (ip, address_expr, reloc_type)
        {
          assert (reloc_type != BFD_RELOC_UNUSED);
        need_reloc:
-         fixp = fix_new (frag_now, f - frag_now->fr_literal, 4,
-                         address_expr->X_add_symbol,
-                         address_expr->X_subtract_symbol,
-                         address_expr->X_add_number,
-                         reloc_type == BFD_RELOC_16_PCREL_S2,
-                         reloc_type);
+         fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
+                             address_expr,
+                             reloc_type == BFD_RELOC_16_PCREL_S2,
+                             reloc_type);
        }
     }
 
@@ -816,7 +813,7 @@ gp_reference (ep)
 
   sym = ep->X_add_symbol;
   if (sym == (symbolS *) NULL
-      || ep->X_subtract_symbol != (symbolS *) NULL)
+      || ep->X_op_symbol != (symbolS *) NULL)
     return 0;
 
   /* Certain symbols can not be referenced off the GP, although it
@@ -968,7 +965,7 @@ macro_build (counter, ep, name, fmt, va_alist)
           * input, in which case the value is not checked for range nor
           * is a relocation entry generated (yuck).
           */
-         if (ep->X_add_symbol == NULL && ep->X_seg == &bfd_abs_section)
+         if (ep->X_op == O_constant)
            {
              insn.insn_opcode |= (ep->X_add_number >> 2) & 0xffff;
              ep = NULL;
@@ -1010,7 +1007,7 @@ macro_build_lui (counter, ep, regnum)
 
   high_expr = *ep;
 
-  if (high_expr.X_seg == &bfd_abs_section)
+  if (high_expr.X_op == O_constant)
     {
       /* we can compute the instruction now without a relocation entry */
       if (high_expr.X_add_number & 0x8000)
@@ -1112,7 +1109,7 @@ check_absolute_expr (ip, expr)
      expressionS *expr;
 {
 
-  if (expr->X_seg != &bfd_abs_section)
+  if (expr->X_op != O_constant)
     as_warn ("Instruction %s requires absolute expression", ip->insn_mo->name);
 }
 
@@ -1182,8 +1179,8 @@ macro (ip)
   sreg = breg = (ip->insn_opcode >> 21) & 0x1f;
   mask = ip->insn_mo->mask;
 
-  expr1.X_seg = &bfd_abs_section;
-  expr1.X_subtract_symbol = NULL;
+  expr1.X_op = O_constant;
+  expr1.X_op_symbol = NULL;
   expr1.X_add_symbol = NULL;
   expr1.X_add_number = 1;
 
@@ -1582,7 +1579,7 @@ macro (ip)
       return;
 
     case M_LA:
-      if (offset_expr.X_seg == &bfd_abs_section)
+      if (offset_expr.X_op == O_constant)
        {
          load_register (&icnt, ip, treg, &offset_expr);
          return;
@@ -1598,7 +1595,7 @@ macro (ip)
 
     case M_LA_AB:
       tempreg = (breg == treg) ? AT : treg;
-      if (offset_expr.X_seg == &bfd_abs_section)
+      if (offset_expr.X_op == O_constant)
        load_register (&icnt, ip, tempreg, &offset_expr);
       else if (gp_reference (&offset_expr))
        macro_build (&icnt, &offset_expr, "addiu", "t,r,j", tempreg, GP);
@@ -2221,7 +2218,7 @@ macro (ip)
     case M_ULH_A:
     case M_ULHU_A:
     case M_ULW_A:
-      if (offset_expr.X_seg == &bfd_abs_section)
+      if (offset_expr.X_op == O_constant)
        load_register (&icnt, ip, AT, &offset_expr);
       else if (gp_reference (&offset_expr))
        macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, GP);
@@ -2264,7 +2261,7 @@ macro (ip)
 
     case M_USH_A:
     case M_USW_A:
-      if (offset_expr.X_seg == &bfd_abs_section)
+      if (offset_expr.X_op == O_constant)
        load_register (&icnt, ip, AT, &offset_expr);
       else if (gp_reference (&offset_expr))
        macro_build (&icnt, &offset_expr, "addiu", "t,r,j", AT, GP);
@@ -2414,7 +2411,7 @@ mips_ip (str, ip)
                  imm_expr.X_add_number = imm_expr.X_add_number % 32;
                }
              ip->insn_opcode |= imm_expr.X_add_number << 6;
-             imm_expr.X_seg = absent_section;
+             imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
@@ -2424,7 +2421,7 @@ mips_ip (str, ip)
              if ((unsigned) imm_expr.X_add_number > 1023)
                as_warn ("Illegal break code (%d)", imm_expr.X_add_number);
              ip->insn_opcode |= imm_expr.X_add_number << 16;
-             imm_expr.X_seg = absent_section;
+             imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
@@ -2434,7 +2431,7 @@ mips_ip (str, ip)
              if ((unsigned) imm_expr.X_add_number > 0xfffff)
                as_warn ("Illegal syscall code (%d)", imm_expr.X_add_number);
              ip->insn_opcode |= imm_expr.X_add_number << 6;
-             imm_expr.X_seg = absent_section;
+             imm_expr.X_op = O_absent;
              s = expr_end;
              continue;
 
@@ -2625,7 +2622,7 @@ mips_ip (str, ip)
                {
                  if (c != 'l')
                    {
-                     if (imm_expr.X_seg == &bfd_abs_section)
+                     if (imm_expr.X_op == O_constant)
                        imm_expr.X_add_number =
                          (imm_expr.X_add_number >> 16) & 0xffff;
                      else if (c == 'h')
@@ -2668,8 +2665,8 @@ mips_ip (str, ip)
               * code pattern.
               */
              if ((offset_expr.X_add_symbol
-                  && offset_expr.X_seg != &bfd_abs_section)
-                 || offset_expr.X_subtract_symbol
+                  && offset_expr.X_op != O_constant)
+                 || offset_expr.X_op_symbol
                  || offset_expr.X_add_number > 32767
                  || offset_expr.X_add_number < -32768)
                break;
@@ -2696,7 +2693,7 @@ mips_ip (str, ip)
                {
                  if (c != 'l')
                    {
-                     if (imm_expr.X_seg == &bfd_abs_section)
+                     if (imm_expr.X_op == O_constant)
                        imm_expr.X_add_number =
                          (imm_expr.X_add_number >> 16) & 0xffff;
                      else if (c == 'h')
@@ -2797,16 +2794,16 @@ my_getSmallExpression (ep, str)
                  if (c)
                    {
                      /* %xx(reg) is an error */
-                     ep->X_seg = absent_section;
+                     ep->X_op = O_absent;
                      expr_end = str - 3;
                    }
                  else
                    {
-                     ep->X_seg = &bfd_abs_section;
+                     ep->X_op = O_absent;
                      expr_end = sp;
                    }
                  ep->X_add_symbol = NULL;
-                 ep->X_subtract_symbol = NULL;
+                 ep->X_op_symbol = NULL;
                  ep->X_add_number = 0;
                }
              else
@@ -2829,11 +2826,10 @@ my_getExpression (ep, str)
      char *str;
 {
   char *save_in;
-  asection *seg;
 
   save_in = input_line_pointer;
   input_line_pointer = str;
-  seg = expression (ep);
+  expression (ep);
   expr_end = input_line_pointer;
   input_line_pointer = save_in;
 }
@@ -3157,20 +3153,6 @@ get_symbol ()
   return p;
 }
 
-static long
-get_optional_absolute_expression ()
-{
-  expressionS exp;
-  asection *s;
-
-  s = expression (&exp);
-  if (!(s == &bfd_abs_section || s == big_section || s == absent_section))
-    {
-      as_bad ("Bad Absolute Expression.");
-    }
-  return exp.X_add_number;
-}
-
 /* Align the current frag to a given power of two.  The MIPS assembler
    also automatically adjusts any preceding label.  */
 
@@ -3325,7 +3307,7 @@ s_extern (x)
   symbolP = get_symbol ();
   if (*input_line_pointer == ',')
     input_line_pointer++;
-  size = get_optional_absolute_expression ();
+  size = get_absolute_expression ();
   S_SET_VALUE (symbolP, size);
   S_SET_EXTERNAL (symbolP);
 
@@ -3765,7 +3747,7 @@ s_frame (x)
   frame_reg = tc_get_register ();
   if (*input_line_pointer == ',')
     input_line_pointer++;
-  frame_off = get_optional_absolute_expression ();
+  frame_off = get_absolute_expression ();
   if (*input_line_pointer == ',')
     input_line_pointer++;
   pcreg = tc_get_register ();
index 62df7b4..075308f 100644 (file)
@@ -689,7 +689,7 @@ md_assemble (str)
 
   /* See if "set" operand is absolute and small; skip sethi if so. */
   if (special_case == SPECIAL_CASE_SET
-      && the_insn.exp.X_seg == absolute_section)
+      && the_insn.exp.X_op == O_constant)
     {
       if (the_insn.exp.X_add_number >= -(1 << 12)
          && the_insn.exp.X_add_number < (1 << 12))
@@ -709,14 +709,12 @@ md_assemble (str)
   /* put out the symbol-dependent stuff */
   if (the_insn.reloc != BFD_RELOC_NONE)
     {
-      fix_new (frag_now,       /* which frag */
-              (toP - frag_now->fr_literal),    /* where */
-              4,               /* size */
-              the_insn.exp.X_add_symbol,
-              the_insn.exp.X_subtract_symbol,
-              the_insn.exp.X_add_number,
-              the_insn.pcrel,
-              the_insn.reloc);
+      fix_new_exp (frag_now,   /* which frag */
+                  (toP - frag_now->fr_literal),        /* where */
+                  4,           /* size */
+                  &the_insn.exp,
+                  the_insn.pcrel,
+                  the_insn.reloc);
     }
 
   switch (special_case)
@@ -725,22 +723,19 @@ md_assemble (str)
       special_case = 0;
       assert (the_insn.reloc == BFD_RELOC_HI22);
       /* See if "set" operand has no low-order bits; skip OR if so. */
-      if (the_insn.exp.X_seg == absolute_section
+      if (the_insn.exp.X_op == O_constant
          && ((the_insn.exp.X_add_number & 0x3FF) == 0))
        return;
       toP = frag_more (4);
       rsd = (the_insn.opcode >> 25) & 0x1f;
       the_insn.opcode = 0x80102000 | (rsd << 25) | (rsd << 14);
       md_number_to_chars (toP, (valueT) the_insn.opcode, 4);
-      fix_new (frag_now,       /* which frag */
-              (toP - frag_now->fr_literal),    /* where */
-              4,               /* size */
-              the_insn.exp.X_add_symbol,
-              the_insn.exp.X_subtract_symbol,
-              the_insn.exp.X_add_number,
-              the_insn.pcrel,
-              BFD_RELOC_LO10
-              );
+      fix_new_exp (frag_now,   /* which frag */
+                  (toP - frag_now->fr_literal),        /* where */
+                  4,           /* size */
+                  &the_insn.exp,
+                  the_insn.pcrel,
+                  BFD_RELOC_LO10);
       return;
 
     case SPECIAL_CASE_FDIV:
@@ -1545,8 +1540,8 @@ sparc_ip (str)
 #endif
              /* end-sanitize-v9 */
                  && the_insn.exp.X_add_symbol == 0
-                 && the_insn.exp.X_subtract_symbol == 0
-                 && the_insn.exp.X_seg == absolute_section
+                 && the_insn.exp.X_op_symbol == 0
+                 && the_insn.exp.X_op == O_constant
                  && (the_insn.exp.X_add_number > immediate_max
                      || the_insn.exp.X_add_number < ~immediate_max))
                as_bad ("constant value must be between %ld and %ld",
@@ -1574,7 +1569,8 @@ sparc_ip (str)
 
                input_line_pointer = s;
 
-               if (expression (&e) == absolute_section)
+               expression (&e);
+               if (e.X_op == O_constant)
                  {
                    opcode |= e.X_add_number << 5;
                    s = input_line_pointer;
@@ -1793,10 +1789,7 @@ getExpression (str)
       || seg == text_section
       || seg == data_section
       || seg == bss_section
-      || seg == undefined_section
-      || seg == diff_section
-      || seg == big_section
-      || seg == absent_section)
+      || seg == undefined_section)
     /* ok */;
   else
     {
@@ -2322,9 +2315,9 @@ print_insn (insn)
               : "???")
            : "0"));
   fprintf (stderr, "\t\tX_sub_symbol = %s\n",
-          ((insn->exp.X_subtract_symbol != NULL)
-           ? (S_GET_NAME (insn->exp.X_subtract_symbol)
-              ? S_GET_NAME (insn->exp.X_subtract_symbol)
+          ((insn->exp.X_op_symbol != NULL)
+           ? (S_GET_NAME (insn->exp.X_op_symbol)
+              ? S_GET_NAME (insn->exp.X_op_symbol)
               : "???")
            : "0"));
   fprintf (stderr, "\t\tX_add_number = %d\n",
index 7bd97b5..5fc47d3 100644 (file)
@@ -30,6 +30,8 @@ struct top                    /* tahoe instruction operand */
 
   char *top_error;             /* Say if operand is inappropriate         */
 
+  segT seg_of_operand;         /* segment as returned by expression()*/
+
   expressionS exp_of_operand;  /* The expression as parsed by expression()*/
 
   byte top_dispsize;           /* Number of bytes in the displacement if we
@@ -665,7 +667,7 @@ md_estimate_size_before_relax (fragP, segment_type)
          *p |= TAHOE_PC_OR_LONG;
          /* We now know how big it will be, one long word. */
          fragP->fr_fix += 1 + 4;
-         fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol, 0,
+         fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol,
                   fragP->fr_offset, FX_PCREL32, NULL);
          frag_wane (fragP);
        }
@@ -684,7 +686,7 @@ md_estimate_size_before_relax (fragP, segment_type)
          *p++ = TAHOE_JMP;
          *p++ = TAHOE_PC_REL_LONG;
          fragP->fr_fix += 1 + 1 + 1 + 4;
-         fix_new (fragP, old_fr_fix + 3, fragP->fr_symbol, 0,
+         fix_new (fragP, old_fr_fix + 3, fragP->fr_symbol,
                   fragP->fr_offset, FX_PCREL32, NULL);
          frag_wane (fragP);
        }
@@ -705,7 +707,7 @@ md_estimate_size_before_relax (fragP, segment_type)
          *p++ = TAHOE_JMP;
          *p++ = TAHOE_PC_REL_LONG;
          fragP->fr_fix += 2 + 2 + 4;
-         fix_new (fragP, old_fr_fix + 4, fragP->fr_symbol, 0,
+         fix_new (fragP, old_fr_fix + 4, fragP->fr_symbol,
                   fragP->fr_offset, FX_PCREL32, NULL);
          frag_wane (fragP);
        }
@@ -726,7 +728,7 @@ md_estimate_size_before_relax (fragP, segment_type)
          *p++ = TAHOE_JMP;
          *p++ = TAHOE_PC_REL_LONG;
          fragP->fr_fix += 2 + 2 + 2 + 4;
-         fix_new (fragP, old_fr_fix + 6, fragP->fr_symbol, 0,
+         fix_new (fragP, old_fr_fix + 6, fragP->fr_symbol,
                   fragP->fr_offset, FX_PCREL32, NULL);
          frag_wane (fragP);
        }
@@ -743,7 +745,7 @@ md_estimate_size_before_relax (fragP, segment_type)
          *fragP->fr_opcode = TAHOE_JMP;
          *p++ = TAHOE_PC_REL_LONG;
          fragP->fr_fix += 1 + 4;
-         fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol, 0,
+         fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol,
                   fragP->fr_offset, FX_PCREL32, NULL);
          frag_wane (fragP);
        }
@@ -1261,64 +1263,52 @@ tip_op (optex, topP)
       /* statement has no syntax goofs yet: lets sniff the expression */
       input_line_pointer = point;
       expP = &(topP->exp_of_operand);
-      switch (expression (expP))
+      topP->seg_of_operand = expression (expP);
+      switch (expP->X_op)
        {
-         /* If expression == SEG_PASS1, expression() will have set
-        need_pass_2 = 1. */
-       case SEG_ABSENT:
+       case O_absent:
          /* No expression. For BSD4.2 compatibility, missing expression is
-        absolute 0 */
-         expP->X_seg = SEG_ABSOLUTE;
+            absolute 0 */
+         expP->X_op = O_constant;
          expP->X_add_number = 0;
          really_none = 1;
-       case SEG_ABSOLUTE:
-         /* for SEG_ABSOLUTE, we shouldnt need to set X_subtract_symbol,
-        X_add_symbol to any particular value. */
+       case O_constant:
+         /* for SEG_ABSOLUTE, we shouldnt need to set X_op_symbol,
+            X_add_symbol to any particular value. */
          /* But, we will program defensively. Since this situation occurs
-        rarely so it costs us little to do so. */
+            rarely so it costs us little to do so. */
          expP->X_add_symbol = NULL;
-         expP->X_subtract_symbol = NULL;
+         expP->X_op_symbol = NULL;
          /* How many bytes are needed to express this abs value? */
          abs_width =
            ((((expP->X_add_number & 0xFFFFFF80) == 0) ||
              ((expP->X_add_number & 0xFFFFFF80) == 0xFFFFFF80)) ? 1 :
             (((expP->X_add_number & 0xFFFF8000) == 0) ||
              ((expP->X_add_number & 0xFFFF8000) == 0xFFFF8000)) ? 2 : 4);
-       case SEG_TEXT:
-       case SEG_DATA:
-       case SEG_BSS:
-       case SEG_UNKNOWN:
+
+       case O_symbol:
          break;
 
-       case SEG_DIFFERENCE:
+       default:
          /*
-       * Major bug. We can't handle the case of a
-       * SEG_DIFFERENCE expression in a synthetic opcode
-       * variable-length instruction.
-       * We don't have a frag type that is smart enough to
-       * relax a SEG_DIFFERENCE, and so we just force all
-       * SEG_DIFFERENCEs to behave like SEG_PASS1s.
-       * Clearly, if there is a demand we can invent a new or
-       * modified frag type and then coding up a frag for this
-       * case will be easy. SEG_DIFFERENCE was invented for the
-       * .words after a CASE opcode, and was never intended for
-       * instruction operands.
-       */
+          * Major bug. We can't handle the case of a operator
+          * expression in a synthetic opcode variable-length
+          * instruction.  We don't have a frag type that is smart
+          * enough to relax a operator, and so we just force all
+          * operators to behave like SEG_PASS1s.  Clearly, if there is
+          * a demand we can invent a new or modified frag type and
+          * then coding up a frag for this case will be easy.
+          */
          need_pass_2 = 1;
-       case SEG_PASS1:
          op_bad = "Can't relocate expression error.";
          break;
 
-       case SEG_BIG:
+       case O_big:
          /* This is an error. Tahoe doesn't allow any expressions
-        bigger that a 32 bit long word. Any bigger has to be referenced
-        by address. */
+            bigger that a 32 bit long word. Any bigger has to be referenced
+            by address. */
          op_bad = "Expression is too large for a 32 bits.";
          break;
-
-       default:
-         as_fatal ("Complier Bug: I got segment %d in tip_op.", expP->X_seg);
-         break;
        }
       if (*input_line_pointer != '\0')
        {
@@ -1706,7 +1696,7 @@ md_assemble (instruction_string)
          /* Here to make main operand frag(s). */
          this_add_number = expP->X_add_number;
          this_add_symbol = expP->X_add_symbol;
-         to_seg = expP->X_seg;
+         to_seg = operandP->seg_of_operand;
          know (to_seg == SEG_UNKNOWN || \
                to_seg == SEG_ABSOLUTE || \
                to_seg == SEG_DATA || \
@@ -1731,7 +1721,7 @@ md_assemble (instruction_string)
               branch), so I set up the frag, and let GAS do the rest. */
                      p = frag_more (dispsize);
                      fix_new (frag_now, p - frag_now->fr_literal,
-                              this_add_symbol, 0, this_add_number,
+                              this_add_symbol, this_add_number,
                               size_to_fx (dispsize, 1),
                               NULL);
                    }
@@ -1810,7 +1800,7 @@ md_assemble (instruction_string)
                              TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
                              TAHOE_PC_REL_LONG);
                      fix_new (frag_now, p - frag_now->fr_literal,
-                              this_add_symbol, 0, this_add_number,
+                              this_add_symbol, this_add_number,
                       (to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
                      /*
             * Now (eg) BLEQ    1f
@@ -1826,7 +1816,7 @@ md_assemble (instruction_string)
                              TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
                              TAHOE_PC_REL_LONG);
                      fix_new (frag_now, p - frag_now->fr_literal,
-                              this_add_symbol, 0, this_add_number,
+                              this_add_symbol, this_add_number,
                       (to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
                      /* Now (eg) JMP foo */
                      break;
@@ -1840,7 +1830,7 @@ md_assemble (instruction_string)
                              TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
                              TAHOE_PC_REL_LONG);
                      fix_new (frag_now, p - frag_now->fr_literal,
-                              this_add_symbol, 0, this_add_number,
+                              this_add_symbol, this_add_number,
                       (to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
                      /*
             * Now (eg) ACBx    1f
@@ -1859,7 +1849,7 @@ md_assemble (instruction_string)
                              TAHOE_ABSOLUTE_ADDR ? TAHOE_ABSOLUTE_ADDR :
                              TAHOE_PC_REL_LONG);
                      fix_new (frag_now, p - frag_now->fr_literal,
-                              this_add_symbol, 0, this_add_number,
+                              this_add_symbol, this_add_number,
                       (to_seg != SEG_ABSOLUTE) ? FX_PCREL32 : FX_32, NULL);
                      /*
             * Now (eg) xOBxxx  1f
@@ -1916,7 +1906,7 @@ md_assemble (instruction_string)
                      p = frag_more (5);
                      *p++ = TAHOE_IMMEDIATE_LONGWORD;
                      fix_new (frag_now, p - frag_now->fr_literal,
-                              this_add_symbol, 0, this_add_number,
+                              this_add_symbol, this_add_number,
                               FX_32, NULL);
                    }
                  else
@@ -2009,7 +1999,7 @@ md_assemble (instruction_string)
                          break;
                        };
                      fix_new (frag_now, p + 1 - frag_now->fr_literal,
-                              this_add_symbol, 0, this_add_number,
+                              this_add_symbol, this_add_number,
                               size_to_fx (dispsize, pc_rel), NULL);
                    }
                  break;
index aa1b66d..a88780b 100644 (file)
 #include "obstack.h"
 
 static void clean_up_expression PARAMS ((expressionS * expressionP));
+static symbolS *make_expr_symbol PARAMS ((expressionS * expressionP));
+
 extern const char EXP_CHARS[], FLT_CHARS[];
+\f
+/* Build a dummy symbol to hold a complex expression.  This is how we
+   build expressions up out of other expressions.  The symbol is put
+   into the fake section expr_section.  */
+
+static symbolS *
+make_expr_symbol (expressionP)
+     expressionS *expressionP;
+{
+  const char *fake;
+  symbolS *symbolP;
 
+  /* FIXME: This should be something which decode_local_label_name
+     will handle.  */
+#ifdef DOT_LABEL_PREFIX
+  fake = ".L0\001";
+#else
+  fake = "L0\001";
+#endif
+  /* Putting constant symbols in absolute_section rather than
+     expr_section is convenient for the old a.out code, for which
+     S_GET_SEGMENT does not always retrieve the value put in by
+     S_SET_SEGMENT.  */
+  symbolP = symbol_new (fake,
+                       (expressionP->X_op == O_constant
+                        ? absolute_section
+                        : expr_section),
+                       0, &zero_address_frag);
+  symbolP->sy_value = *expressionP;
+  return symbolP;
+}
+\f
 /*
  * Build any floating-point literal here.
  * Also build any bignum literal here.
@@ -79,13 +112,12 @@ floating_constant (expressionP)
          as_bad ("bad floating-point constant: unknown error code=%d.", error_code);
        }
     }
-  expressionP->X_seg = big_section;
+  expressionP->X_op = O_big;
   /* input_line_pointer->just after constant, */
   /* which may point to whitespace. */
   expressionP->X_add_number = -1;
 }
 
-
 void
 integer_constant (radix, expressionP)
      int radix;
@@ -233,8 +265,8 @@ integer_constant (radix, expressionP)
                   checking absoluteness. */
                know (SEG_NORMAL (S_GET_SEGMENT (symbolP)));
 
+               expressionP->X_op = O_symbol;
                expressionP->X_add_symbol = symbolP;
-               expressionP->X_seg = S_GET_SEGMENT (symbolP);
 
              }
            else
@@ -244,7 +276,7 @@ integer_constant (radix, expressionP)
                   the parsed number.  */
                as_bad ("backw. ref to unknown label \"%d:\", 0 assumed.",
                        (int) number);
-               expressionP->X_seg = absolute_section;
+               expressionP->X_op = O_constant;
              }
 
            expressionP->X_add_number = 0;
@@ -269,9 +301,8 @@ integer_constant (radix, expressionP)
               can't have newlines in the argument.  */
            know (S_GET_SEGMENT (symbolP) == undefined_section || S_GET_SEGMENT (symbolP) == text_section || S_GET_SEGMENT (symbolP) == data_section);
 #endif
+           expressionP->X_op = O_symbol;
            expressionP->X_add_symbol = symbolP;
-           expressionP->X_seg = undefined_section;
-           expressionP->X_subtract_symbol = NULL;
            expressionP->X_add_number = 0;
 
            break;
@@ -301,9 +332,9 @@ integer_constant (radix, expressionP)
                symbolP = symbol_find_or_make (name);
              }
 
+           expressionP->X_op = O_symbol;
            expressionP->X_add_symbol = symbolP;
            expressionP->X_add_number = 0;
-           expressionP->X_seg = S_GET_SEGMENT (symbolP);
 
            break;
          }                     /* case '$' */
@@ -312,8 +343,8 @@ integer_constant (radix, expressionP)
 
        default:
          {
+           expressionP->X_op = O_constant;
            expressionP->X_add_number = number;
-           expressionP->X_seg = absolute_section;
            input_line_pointer--;       /* restore following character. */
            break;
          }                     /* really just a number */
@@ -325,8 +356,8 @@ integer_constant (radix, expressionP)
   else
     {
       /* not a small number */
+      expressionP->X_op = O_big;
       expressionP->X_add_number = number;
-      expressionP->X_seg = big_section;
       input_line_pointer--;    /*->char following number. */
     }
 }                              /* integer_constant() */
@@ -338,14 +369,10 @@ integer_constant (radix, expressionP)
  * in: Input_line_pointer 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_ABSENT.
+ * out:        A expressionS.
+ *     The operand may have been empty: in this case X_op == O_absent.
  *     Input_line_pointer->(next non-blank) char after operand.
- *
  */
-\f
-
 
 static segT
 operand (expressionP)
@@ -354,6 +381,7 @@ operand (expressionP)
   char c;
   symbolS *symbolP;    /* points to symbol */
   char *name;          /* points to name of symbol */
+  segT retval = absolute_section;
 
   /* digits, assume it is a bignum. */
 
@@ -390,7 +418,6 @@ operand (expressionP)
     case '0':
       /* non-decimal radix */
 
-
       c = *input_line_pointer;
       switch (c)
        {
@@ -404,9 +431,8 @@ operand (expressionP)
          else
            {
              /* The string was only zero */
-             expressionP->X_add_symbol = 0;
+             expressionP->X_op = O_constant;
              expressionP->X_add_number = 0;
-             expressionP->X_seg = absolute_section;
            }
 
          break;
@@ -419,6 +445,9 @@ operand (expressionP)
 
        case 'b':
 #ifdef LOCAL_LABELS_FB
+         /* FIXME: This seems to be nonsense.  At this point we know
+            for sure that *input_line_pointer is 'b'.  So why are we
+            checking it?  What is this code supposed to do?  */
          if (!*input_line_pointer
              || (!strchr ("+-.0123456789", *input_line_pointer)
                  && !strchr (EXP_CHARS, *input_line_pointer)))
@@ -449,6 +478,9 @@ operand (expressionP)
          /* if it says '0f' and the line ends or it doesn't look like
             a floating point #, its a local label ref.  dtrt */
          /* likewise for the b's.  xoxorich. */
+         /* FIXME: As in the 'b' case, we know that the
+            *input_line_pointer is 'f'.  What is this code really
+            trying to do?  */
          if (c == 'f'
              && (!*input_line_pointer ||
                  (!strchr ("+-.0123456789", *input_line_pointer) &&
@@ -482,78 +514,70 @@ operand (expressionP)
        }
 
       break;
+
     case '(':
       /* didn't begin with digit & not a name */
-      {
-       (void) expression (expressionP);
-       /* Expression() will pass trailing whitespace */
-       if (*input_line_pointer++ != ')')
-         {
-           as_bad ("Missing ')' assumed");
-           input_line_pointer--;
-         }
-       /* here with input_line_pointer->char after "(...)" */
-      }
-      return expressionP->X_seg;
-
+      retval = expression (expressionP);
+      /* Expression() will pass trailing whitespace */
+      if (*input_line_pointer++ != ')')
+       {
+         as_bad ("Missing ')' assumed");
+         input_line_pointer--;
+       }
+      /* here with input_line_pointer->char after "(...)" */
+      return retval;
 
     case '\'':
       /* Warning: to conform to other people's assemblers NO ESCAPEMENT is
         permitted for a single quote. The next character, parity errors and
         all, is taken as the value of the operand. VERY KINKY.  */
+      expressionP->X_op = O_constant;
       expressionP->X_add_number = *input_line_pointer++;
-      expressionP->X_seg = absolute_section;
       break;
 
     case '+':
-      operand (expressionP);
+      retval = operand (expressionP);
       break;
 
     case '~':
     case '-':
       {
-       /* unary operator: hope for SEG_ABSOLUTE */
-       segT opseg = operand (expressionP);
-       if (opseg == absolute_section)
+       /* When computing - foo, ignore the segment of foo.  It has
+          nothing to do with the segment of the result, which is
+          ill-defined.  */
+       operand (expressionP);
+       if (expressionP->X_op == O_constant)
          {
            /* input_line_pointer -> char after operand */
            if (c == '-')
              {
-               expressionP->X_add_number = -expressionP->X_add_number;
+               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;
-             }
+             expressionP->X_add_number = ~ expressionP->X_add_number;
          }
-       else if (opseg == text_section
-                || opseg == data_section
-                || opseg == bss_section
-                || opseg == pass1_section
-                || opseg == undefined_section)
+       else if (expressionP->X_op != O_illegal
+                && expressionP->X_op != O_absent)
          {
+           expressionP->X_add_symbol = make_expr_symbol (expressionP);
            if (c == '-')
-             {
-               expressionP->X_subtract_symbol = expressionP->X_add_symbol;
-               expressionP->X_add_symbol = 0;
-               expressionP->X_seg = diff_section;
-             }
+             expressionP->X_op = O_uminus;
            else
-             as_warn ("Unary operator %c ignored because bad operand follows",
-                      c);
+             expressionP->X_op = O_bit_not;
+           expressionP->X_add_number = 0;
          }
        else
-         as_warn ("Unary operator %c ignored because bad operand follows", c);
+         as_warn ("Unary operator %c ignored because bad operand follows",
+                  c);
       }
       break;
 
     case '.':
       if (!is_part_of_name (*input_line_pointer))
        {
-         char *fake;
-         extern struct obstack frags;
+         const char *fake;
 
          /* JF: '.' is pseudo symbol with value of current location
             in current segment.  */
@@ -564,27 +588,25 @@ operand (expressionP)
 #endif
          symbolP = symbol_new (fake,
                                now_seg,
-              (valueT) ((char*)obstack_next_free (&frags) - frag_now->fr_literal),
+                               (valueT) frag_now_fix (),
                                frag_now);
 
-         expressionP->X_add_number = 0;
+         expressionP->X_op = O_symbol;
          expressionP->X_add_symbol = symbolP;
-         expressionP->X_seg = now_seg;
+         expressionP->X_add_number = 0;
+         retval = now_seg;
          break;
-
        }
       else
        {
          goto isname;
-
-
        }
     case ',':
     case '\n':
     case '\0':
     eol:
       /* can't imagine any other kind of operand */
-      expressionP->X_seg = absent_section;
+      expressionP->X_op = O_absent;
       input_line_pointer--;
       md_operand (expressionP);
       break;
@@ -602,25 +624,33 @@ operand (expressionP)
          name = --input_line_pointer;
          c = get_symbol_end ();
          symbolP = symbol_find_or_make (name);
-         /* If we have an absolute symbol or a reg, then we know its value
-            now.  */
-         expressionP->X_seg = S_GET_SEGMENT (symbolP);
-         if (expressionP->X_seg == absolute_section
-             || expressionP->X_seg == reg_section)
-           expressionP->X_add_number = S_GET_VALUE (symbolP);
+
+         /* If we have an absolute symbol or a reg, then we know its
+            value now.  */
+         retval = S_GET_SEGMENT (symbolP);
+         if (retval == absolute_section)
+           {
+             expressionP->X_op = O_constant;
+             expressionP->X_add_number = S_GET_VALUE (symbolP);
+           }
+         else if (retval == reg_section)
+           {
+             expressionP->X_op = O_register;
+             expressionP->X_add_number = S_GET_VALUE (symbolP);
+           }
          else
            {
-             expressionP->X_add_number = 0;
+             expressionP->X_op = O_symbol;
              expressionP->X_add_symbol = symbolP;
+             expressionP->X_add_number = 0;
            }
          *input_line_pointer = c;
-         expressionP->X_subtract_symbol = NULL;
        }
       else
        {
          as_bad ("Bad expression");
+         expressionP->X_op = O_constant;
          expressionP->X_add_number = 0;
-         expressionP->X_seg = absolute_section;
        }
     }
 
@@ -631,20 +661,18 @@ operand (expressionP)
   clean_up_expression (expressionP);
   SKIP_WHITESPACE ();          /*->1st char after operand. */
   know (*input_line_pointer != ' ');
-  return (expressionP->X_seg);
+  return expressionP->X_op == O_constant ? absolute_section : retval;
 }                              /* operand() */
 \f
-
 /* Internal. Simplify a struct expression for use by expr() */
 
 /*
  * 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.
+ *     The X_op field of the expressionS may only take certain values.
  *     Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT.
  * Out:        expressionS may have been modified:
  *     'foo-foo' symbol references cancelled to 0,
- *             which changes X_seg from SEG_DIFFERENCE to SEG_ABSOLUTE;
+ *             which changes X_op from O_subtract to O_constant.
  *     Unused fields zeroed to help expr().
  */
 
@@ -652,158 +680,38 @@ static void
 clean_up_expression (expressionP)
      expressionS *expressionP;
 {
-  segT s = expressionP->X_seg;
-  if (s == absent_section
-      || s == pass1_section)
+  switch (expressionP->X_op)
     {
-      expressionP->X_add_symbol = NULL;
-      expressionP->X_subtract_symbol = NULL;
+    case O_illegal:
+    case O_absent:
       expressionP->X_add_number = 0;
-    }
-  else if (s == big_section
-          || s == absolute_section)
-    {
-      expressionP->X_subtract_symbol = NULL;
+      /* Fall through.  */
+    case O_big:
+    case O_constant:
+    case O_register:
       expressionP->X_add_symbol = NULL;
-    }
-  else if (s == undefined_section)
-    expressionP->X_subtract_symbol = NULL;
-  else if (s == diff_section)
-    {
-      /*
-       * 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)
+      /* Fall through.  */
+    case O_symbol:
+    case O_uminus:
+    case O_bit_not:
+      expressionP->X_op_symbol = NULL;
+      break;
+    case O_subtract:
+      if (expressionP->X_op_symbol == expressionP->X_add_symbol
+         || ((expressionP->X_op_symbol->sy_frag
+              == expressionP->X_add_symbol->sy_frag)
              && SEG_NORMAL (S_GET_SEGMENT (expressionP->X_add_symbol))
-             && (S_GET_VALUE (expressionP->X_subtract_symbol)
+             && (S_GET_VALUE (expressionP->X_op_symbol)
                  == S_GET_VALUE (expressionP->X_add_symbol))))
        {
-         expressionP->X_subtract_symbol = NULL;
+         expressionP->X_op = O_constant;
          expressionP->X_add_symbol = NULL;
-         expressionP->X_seg = absolute_section;
-       }
-    }
-  else if (s == reg_section)
-    {
-      expressionP->X_add_symbol = NULL;
-      expressionP->X_subtract_symbol = NULL;
-    }
-  else
-    {
-      if (SEG_NORMAL (expressionP->X_seg))
-       {
-         expressionP->X_subtract_symbol = NULL;
-       }
-      else
-       {
-         BAD_CASE (expressionP->X_seg);
-       }
-    }
-}
-\f
-/*
- *                     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 (symbol_1_PP, symbol_2_P)
-     symbolS **symbol_1_PP;
-     symbolS *symbol_2_P;
-{
-  segT return_value;
-
-#if !defined (BFD_ASSEMBLER) && (defined (OBJ_AOUT) || defined (OBJ_BOUT))
-  int test = ((*symbol_1_PP) == NULL
-             || (S_GET_SEGMENT (*symbol_1_PP) == text_section)
-             || (S_GET_SEGMENT (*symbol_1_PP) == data_section)
-             || (S_GET_SEGMENT (*symbol_1_PP) == bss_section)
-             || (!S_IS_DEFINED (*symbol_1_PP)));
-  assert (test);
-  test = (symbol_2_P == NULL
-         || (S_GET_SEGMENT (symbol_2_P) == text_section)
-         || (S_GET_SEGMENT (symbol_2_P) == data_section)
-         || (S_GET_SEGMENT (symbol_2_P) == bss_section)
-         || (!S_IS_DEFINED (symbol_2_P)));
-  assert (test);
-#endif
-  if (*symbol_1_PP)
-    {
-      if (!S_IS_DEFINED (*symbol_1_PP))
-       {
-         if (symbol_2_P)
-           {
-             return_value = pass1_section;
-             *symbol_1_PP = NULL;
-           }
-         else
-           {
-             know (!S_IS_DEFINED (*symbol_1_PP));
-             return_value = undefined_section;
-           }
-       }
-      else
-       {
-         if (symbol_2_P)
-           {
-             if (!S_IS_DEFINED (symbol_2_P))
-               {
-                 *symbol_1_PP = NULL;
-                 return_value = pass1_section;
-               }
-             else
-               {
-                 /* {seg1} - {seg2} */
-                 as_bad ("Expression too complex, 2 symbolS forgotten: \"%s\" \"%s\"",
-                       S_GET_NAME (*symbol_1_PP), S_GET_NAME (symbol_2_P));
-                 *symbol_1_PP = NULL;
-                 return_value = absolute_section;
-               }
-           }
-         else
-           {
-             return_value = S_GET_SEGMENT (*symbol_1_PP);
-           }
-       }
-    }
-  else
-    {                          /* (* symbol_1_PP) == NULL */
-      if (symbol_2_P)
-       {
-         *symbol_1_PP = symbol_2_P;
-         return_value = S_GET_SEGMENT (symbol_2_P);
-       }
-      else
-       {
-         *symbol_1_PP = NULL;
-         return_value = absolute_section;
+         expressionP->X_op_symbol = NULL;
        }
+      break;
+    default:
+      break;
     }
-#if defined (OBJ_AOUT) && !defined (BFD_ASSEMBLER)
-  test = (return_value == absolute_section
-         || return_value == text_section
-         || return_value == data_section
-         || return_value == bss_section
-         || return_value == undefined_section
-         || return_value == pass1_section);
-  assert (test);
-#endif
-  know ((*symbol_1_PP) == NULL
-       || (S_GET_SEGMENT (*symbol_1_PP) == return_value));
-  return (return_value);
 }
 \f
 /* Expression parser. */
@@ -824,27 +732,11 @@ expr_part (symbol_1_PP, symbol_2_P)
  * After expr(RANK,resultP) input_line_pointer->operator of rank <= RANK.
  * Also, we have consumed any leading or trailing spaces (operand does that)
  * and done all intervening operators.
+ *
+ * This returns the segment of the result, which will be
+ * absolute_section or the segment of a symbol.
  */
 
-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
 
@@ -884,17 +776,37 @@ static const operatorT op_encoding[256] =
  *     1       + -
  *     2       & ^ ! |
  *     3       * / % << >>
+ *     4       unary - unary ~
  */
-static const operator_rankT
-  op_rank[] =
-{0, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1};
+static const operator_rankT op_rank[] =
+{
+  0,   /* O_illegal */
+  0,   /* O_absent */
+  0,   /* O_constant */
+  0,   /* O_symbol */
+  0,   /* O_register */
+  0,   /* O_bit */
+  4,   /* O_uminus */
+  4,   /* O_bit_now */
+  3,   /* O_multiply */
+  3,   /* O_divide */
+  3,   /* O_modulus */
+  3,   /* O_left_shift */
+  3,   /* O_right_shift */
+  2,   /* O_bit_inclusive_or */
+  2,   /* O_bit_or_not */
+  2,   /* O_bit_exclusive_or */
+  2,   /* O_bit_and */
+  1,   /* O_add */
+  1,   /* O_subtract */
+};
 \f
-/* Return resultP->X_seg. */
-segT 
+segT
 expr (rank, resultP)
      operator_rankT rank;      /* Larger # is higher rank. */
      expressionS *resultP;     /* Deliver result here. */
 {
+  segT retval;
   expressionS right;
   operatorT op_left;
   char c_left;         /* 1st operator character. */
@@ -902,223 +814,145 @@ expr (rank, resultP)
   char c_right;
 
   know (rank >= 0);
-  (void) operand (resultP);
+
+  retval = operand (resultP);
+
   know (*input_line_pointer != ' ');   /* Operand() gobbles spaces. */
+
   c_left = *input_line_pointer;        /* Potential operator character. */
   op_left = op_encoding[c_left];
   while (op_left != O_illegal && op_rank[(int) op_left] > rank)
     {
+      segT rightseg;
+
       input_line_pointer++;    /*->after 1st character of operator. */
       /* Operators "<<" and ">>" have 2 characters. */
       if (*input_line_pointer == c_left && (c_left == '<' || c_left == '>'))
+       ++input_line_pointer;
+
+      rightseg = expr (op_rank[(int) op_left], &right);
+      if (right.X_op == O_absent)
        {
-         input_line_pointer++;
-       }                       /*->after operator. */
-      if (absent_section == expr (op_rank[(int) op_left], &right))
-       {
-         as_warn ("Missing operand value assumed absolute 0.");
-         resultP->X_add_number = 0;
-         resultP->X_subtract_symbol = NULL;
+         as_warn ("missing operand; zero assumed");
+         right.X_op = O_constant;
+         right.X_add_number = 0;
          resultP->X_add_symbol = NULL;
-         resultP->X_seg = absolute_section;
+         resultP->X_op_symbol = NULL;
        }
+
       know (*input_line_pointer != ' ');
+
+      if (! SEG_NORMAL (retval))
+       retval = rightseg;
+      else if (SEG_NORMAL (rightseg)
+              && retval != rightseg)
+       as_bad ("operation combines symbols in different segments");
+
       c_right = *input_line_pointer;
       op_right = op_encoding[c_right];
       if (*input_line_pointer == c_right && (c_right == '<' || c_right == '>'))
-       {
-         input_line_pointer++;
-       }                       /*->after operator. */
-      know ((int) op_right == 0 || op_rank[(int) op_right] <= op_rank[(int) op_left]);
+       ++input_line_pointer;
+
+      know (op_right == O_illegal || op_rank[(int) op_right] <= op_rank[(int) op_left]);
+      know ((int) op_left >= (int) O_multiply && (int) op_left <= (int) O_subtract);
+
       /* input_line_pointer->after right-hand quantity. */
       /* left-hand quantity in resultP */
       /* right-hand quantity in right. */
       /* operator in op_left. */
-      if (resultP->X_seg == pass1_section || right.X_seg == pass1_section)
+
+      if (resultP->X_op == O_big)
        {
-         resultP->X_seg = pass1_section;
+         as_warn ("left operand of %c is a %s; integer 0 assumed",
+                  c_left, resultP->X_add_number > 0 ? "bignum" : "float");
+         resultP->X_op = O_constant;
+         resultP->X_add_number = 0;
+         resultP->X_add_symbol = NULL;
+         resultP->X_op_symbol = NULL;
        }
-      else
+      if (right.X_op == O_big)
        {
-         if (resultP->X_seg == big_section)
-           {
-             as_warn ("Left operand of %c is a %s.  Integer 0 assumed.",
-                   c_left, resultP->X_add_number > 0 ? "bignum" : "float");
-             resultP->X_seg = absolute_section;
-             resultP->X_add_symbol = 0;
-             resultP->X_subtract_symbol = 0;
-             resultP->X_add_number = 0;
-           }
-         if (right.X_seg == big_section)
+         as_warn ("right operand of %c is a %s; integer 0 assumed",
+                  c_left, right.X_add_number > 0 ? "bignum" : "float");
+         right.X_op = O_constant;
+         right.X_add_number = 0;
+         right.X_add_symbol = NULL;
+         right.X_op_symbol = NULL;
+       }
+
+      /* Optimize common cases.  */
+      if (op_left == O_add && right.X_op == O_constant)
+       {
+         /* X + constant.  */
+         resultP->X_add_number += right.X_add_number;
+       }
+      else if (op_left == O_subtract && right.X_op == O_constant)
+       {
+         /* X - constant.  */
+         resultP->X_add_number -= right.X_add_number;
+       }
+      else if (op_left == O_add && resultP->X_op == O_constant)
+       {
+         /* Constant + X.  */
+         resultP->X_op = right.X_op;
+         resultP->X_add_symbol = right.X_add_symbol;
+         resultP->X_op_symbol = right.X_op_symbol;
+         resultP->X_add_number += right.X_add_number;
+         retval = rightseg;
+       }
+      else if (resultP->X_op == O_constant && right.X_op == O_constant)
+       {
+         /* Constant OP constant.  */
+         offsetT v = right.X_add_number;
+         if (v == 0 && (op_left == O_divide || op_left == O_modulus))
            {
-             as_warn ("Right operand of %c is a %s.  Integer 0 assumed.",
-                      c_left, right.X_add_number > 0 ? "bignum" : "float");
-             right.X_seg = absolute_section;
-             right.X_add_symbol = 0;
-             right.X_subtract_symbol = 0;
-             right.X_add_number = 0;
+             as_warn ("division by zero");
+             v = 1;
            }
-         if (op_left == O_subtract)
+         switch (op_left)
            {
-             /*
-              * 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.
-              */
-
-             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 = diff_section;
-               }
-             op_left = O_add;
+           case O_multiply:            resultP->X_add_number *= v; break;
+           case O_divide:              resultP->X_add_number /= v; break;
+           case O_modulus:             resultP->X_add_number %= v; break;
+           case O_left_shift:          resultP->X_add_number <<= v; break;
+           case O_right_shift:         resultP->X_add_number >>= v; break;
+           case O_bit_inclusive_or:    resultP->X_add_number |= v; break;
+           case O_bit_or_not:          resultP->X_add_number |= ~v; break;
+           case O_bit_exclusive_or:    resultP->X_add_number ^= v; break;
+           case O_bit_and:             resultP->X_add_number &= v; break;
+           case O_add:                 resultP->X_add_number += v; break;
+           case O_subtract:            resultP->X_add_number -= v; break;
+           default:                    abort ();
            }
-\f
+       }
+      else if (resultP->X_op == O_symbol
+              && right.X_op == O_symbol
+              && (op_left == O_add
+                  || op_left == O_subtract
+                  || (resultP->X_add_number == 0
+                      && right.X_add_number == 0)))
+       {
+         /* Symbol OP symbol.  */
+         resultP->X_op = op_left;
+         resultP->X_op_symbol = right.X_add_symbol;
          if (op_left == O_add)
-           {
-             segT seg1;
-             segT seg2;
-#if 0 /* @@ This rejects stuff in common sections too.  Figure out some
-        reasonable test, and make it clean...  */
-#if !defined (MANY_SEGMENTS) && !defined (OBJ_ECOFF)
-             know (resultP->X_seg == data_section || resultP->X_seg == text_section || resultP->X_seg == bss_section || resultP->X_seg == undefined_section || resultP->X_seg == diff_section || resultP->X_seg == absolute_section || resultP->X_seg == pass1_section || resultP->X_seg == reg_section);
-
-             know (right.X_seg == data_section || right.X_seg == text_section || right.X_seg == bss_section || right.X_seg == undefined_section || right.X_seg == diff_section || right.X_seg == absolute_section || right.X_seg == pass1_section);
-#endif
-#endif /* 0 */
-             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 == pass1_section || seg2 == pass1_section)
-               {
-                 need_pass_2 = 1;
-                 resultP->X_seg = pass1_section;
-               }
-             else if (seg2 == absolute_section)
-               resultP->X_seg = seg1;
-             else if (seg1 != undefined_section
-                      && seg1 != absolute_section
-                      && seg2 != undefined_section
-                      && seg1 != seg2)
-               {
-                 know (seg2 != absolute_section);
-                 know (resultP->X_subtract_symbol);
-#ifndef MANY_SEGMENTS
-#ifndef OBJ_ECOFF
-                 know (seg1 == text_section || seg1 == data_section || seg1 == bss_section);
-                 know (seg2 == text_section || seg2 == data_section || seg2 == bss_section);
-#endif
-#endif
-                 know (resultP->X_add_symbol);
-                 know (resultP->X_subtract_symbol);
-                 as_bad ("Expression too complex: forgetting %s - %s",
-                         S_GET_NAME (resultP->X_add_symbol),
-                         S_GET_NAME (resultP->X_subtract_symbol));
-                 resultP->X_seg = absolute_section;
-                 /* Clean_up_expression() will do the rest. */
-               }
-             else
-               resultP->X_seg = diff_section;
-
-             resultP->X_add_number += right.X_add_number;
-             clean_up_expression (resultP);
-           }
-         else
-           {                   /* Not +. */
-             if (resultP->X_seg == undefined_section || right.X_seg == undefined_section)
-               {
-                 resultP->X_seg = pass1_section;
-                 need_pass_2 = 1;
-               }
-             else
-               {
-                 resultP->X_subtract_symbol = NULL;
-                 resultP->X_add_symbol = NULL;
-                 /* Will be absolute_section. */
-                 if (resultP->X_seg != absolute_section || right.X_seg != absolute_section)
-                   {
-                     as_bad ("Relocation error: Symbolic expressions may only involve");
-                     as_bad ("  addition and subtraction. Absolute 0 assumed.");
-                     resultP->X_seg = absolute_section;
-                     resultP->X_add_number = 0;
-                   }
-                 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
-                           {
-                             as_warn ("Division by 0.  Result of 0 substituted.");
-                             resultP->X_add_number = 0;
-                           }
-                         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
-                           {
-                             as_warn ("Division by 0. 0 assumed.");
-                             resultP->X_add_number = 0;
-                           }
-                         break;
-
-                       case O_left_shift:
-                         resultP->X_add_number <<= right.X_add_number;
-                         break;
-
-                       case O_right_shift:
-                         /* @@ We should distinguish signed versus
-                            unsigned here somehow.  */
-                         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:
-                         BAD_CASE (op_left);
-                         break;
-                       }       /* switch(operator) */
-                   }
-               }               /* If we have to force need_pass_2. */
-           }                   /* If operator was +. */
-       }                       /* If we didn't set need_pass_2. */
+           resultP->X_add_number += right.X_add_number;
+         else if (op_left == O_subtract)
+           resultP->X_add_number -= right.X_add_number;
+       }
+      else
+       {
+         /* The general case.  */
+         resultP->X_add_symbol = make_expr_symbol (resultP);
+         resultP->X_op_symbol = make_expr_symbol (&right);
+         resultP->X_op = op_left;
+         resultP->X_add_number = 0;
+       }
+         
       op_left = op_right;
     }                          /* While next operator is >= this rank. */
-  return (resultP->X_seg);
+
+  return resultP->X_op == O_constant ? absolute_section : retval;
 }
 \f
 /*
index 290f8c1..e9acac5 100644 (file)
@@ -1,5 +1,5 @@
 /* read.c - read a source file -
-   Copyright (C) 1986, 1987, 1990, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1986, 1987, 1990, 1991, 1993 Free Software Foundation, Inc.
 
 This file is part of GAS, the GNU Assembler.
 
@@ -158,6 +158,7 @@ int new_broken_words;
 static char *demand_copy_string PARAMS ((int *lenP));
 int is_it_end_of_statement PARAMS ((void));
 unsigned int next_char_of_string PARAMS ((void));
+static segT get_segmented_expression PARAMS ((expressionS *expP));
 static segT get_known_segmented_expression PARAMS ((expressionS * expP));
 static void grow_bignum PARAMS ((void));
 static void pobegin PARAMS ((void));
@@ -1161,6 +1162,7 @@ s_lsym ()
   register segT segment;
   expressionS exp;
   register symbolS *symbolP;
+  valueT val;
 
   /* we permit ANY defined expression: BSD4.2 demands constants */
   name = input_line_pointer;
@@ -1177,15 +1179,7 @@ s_lsym ()
       return;
     }
   input_line_pointer++;
-  segment = expression (&exp);
-  if (segment != absolute_section
-      && segment != reg_section
-      && ! SEG_NORMAL (segment))
-    {
-      as_bad ("Bad expression: %s", segment_name (segment));
-      ignore_rest_of_line ();
-      return;
-    }
+  val = get_absolute_expression ();
   *p = 0;
   symbolP = symbol_find_or_make (name);
 
@@ -1202,7 +1196,7 @@ s_lsym ()
       /* The name might be an undefined .global symbol; be sure to
         keep the "external" bit. */
       S_SET_SEGMENT (symbolP, segment);
-      S_SET_VALUE (symbolP, (valueT) (exp.X_add_number));
+      S_SET_VALUE (symbolP, val);
     }
   else
     {
@@ -1421,14 +1415,12 @@ ignore_rest_of_line ()          /* For suspect lines: gives warning. */
  * Out:        Input_line_pointer->just after any whitespace after expression.
  *     Tried to set symbol to value of expression.
  *     Will change symbols type, value, and frag;
- *     May set need_pass_2 == 1.
  */
 void
 pseudo_set (symbolP)
      symbolS *symbolP;
 {
   expressionS exp;
-  register segT segment;
 #if defined(OBJ_AOUT) | defined(OBJ_BOUT)
   int ext;
 #endif /* OBJ_AOUT or OBJ_BOUT */
@@ -1439,123 +1431,76 @@ pseudo_set (symbolP)
   ext = S_IS_EXTERNAL (symbolP);
 #endif /* OBJ_AOUT or OBJ_BOUT */
 
-  if ((segment = expression (&exp)) == absent_section)
-    {
-      as_bad ("Missing expression: absolute 0 assumed");
-      exp.X_seg = absolute_section;
-      exp.X_add_number = 0;
-    }
+  (void) expression (&exp);
 
-  if (segment == reg_section)
-    {
-      S_SET_SEGMENT (symbolP, reg_section);
-      S_SET_VALUE (symbolP, exp.X_add_number);
-      symbolP->sy_frag = &zero_address_frag;
-    }
-  else if (segment == big_section)
+  if (exp.X_op == O_illegal)
+    as_bad ("illegal expression; zero assumed");
+  else if (exp.X_op == O_absent)
+    as_bad ("missing expression; zero assumed");
+  else if (exp.X_op == O_big)
+    as_bad ("%s number invalid; zero assumed",
+           exp.X_add_number > 0 ? "bignum" : "floating point");
+  else if (exp.X_op == O_subtract
+          && (S_GET_SEGMENT (exp.X_add_symbol)
+              == S_GET_SEGMENT (exp.X_op_symbol))
+          && SEG_NORMAL (S_GET_SEGMENT (exp.X_add_symbol))
+          && exp.X_add_symbol->sy_frag == exp.X_op_symbol->sy_frag)
     {
-      as_bad ("%s number invalid. Absolute 0 assumed.",
-             exp.X_add_number > 0 ? "Bignum" : "Floating-Point");
-      S_SET_SEGMENT (symbolP, absolute_section);
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
-      /* @@ Fix this right for BFD.  */
-      ext ? S_SET_EXTERNAL (symbolP) :
-       S_CLEAR_EXTERNAL (symbolP);
-#endif /* OBJ_AOUT or OBJ_BOUT */
-      S_SET_VALUE (symbolP, 0);
-      symbolP->sy_frag = &zero_address_frag;
+      exp.X_op = O_constant;
+      exp.X_add_number = (S_GET_VALUE (exp.X_add_symbol)
+                         - S_GET_VALUE (exp.X_op_symbol));
     }
-  else if (segment == absent_section)
+
+  switch (exp.X_op)
     {
-      as_warn ("No expression:  Using absolute 0");
+    case O_illegal:
+    case O_absent:
+    case O_big:
+      exp.X_add_number = 0;
+      /* Fall through.  */
+    case O_constant:
       S_SET_SEGMENT (symbolP, absolute_section);
 #if defined(OBJ_AOUT) | defined(OBJ_BOUT)
       /* @@ Fix this right for BFD.  */
-      ext ? S_SET_EXTERNAL (symbolP) :
-       S_CLEAR_EXTERNAL (symbolP);
-#endif /* OBJ_AOUT or OBJ_BOUT */
-      S_SET_VALUE (symbolP, 0);
-      symbolP->sy_frag = &zero_address_frag;
-    }
-  else if (segment == diff_section)
-    {
-      if (exp.X_add_symbol && exp.X_subtract_symbol
-         && (S_GET_SEGMENT (exp.X_add_symbol) ==
-             S_GET_SEGMENT (exp.X_subtract_symbol)))
-       {
-         if (exp.X_add_symbol->sy_frag == exp.X_subtract_symbol->sy_frag)
-           {
-             exp.X_add_number += S_GET_VALUE (exp.X_add_symbol) -
-               S_GET_VALUE (exp.X_subtract_symbol);
-             goto abs;
-           }
-         symbolP->sy_value = exp;
-       }
+      if (ext)
+       S_SET_EXTERNAL (symbolP);
       else
-       {
-         as_bad ("Complex expression. Absolute segment assumed.");
-         goto abs;
-       }
-    }
-  else if (segment == absolute_section)
-    {
-    abs:
-      S_SET_SEGMENT (symbolP, absolute_section);
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
-      /* @@ Fix this right for BFD.  */
-      ext ? S_SET_EXTERNAL (symbolP) :
        S_CLEAR_EXTERNAL (symbolP);
 #endif /* OBJ_AOUT or OBJ_BOUT */
       S_SET_VALUE (symbolP, exp.X_add_number);
       symbolP->sy_frag = &zero_address_frag;
-    }
-  else if (segment == pass1_section)
-    {
-      symbolP->sy_value.X_add_symbol = exp.X_add_symbol;
-      symbolP->sy_value.X_subtract_symbol = NULL;
-      symbolP->sy_value.X_add_number = 0;
-      symbolP->sy_value.X_seg = undefined_section;
-      as_bad ("Unknown expression");
-      know (need_pass_2 == 1);
-    }
-  else if (segment == undefined_section)
-    {
-      symbolP->sy_value.X_add_symbol = exp.X_add_symbol;
-      symbolP->sy_value.X_subtract_symbol = NULL;
-      symbolP->sy_value.X_add_number = 0;
-      symbolP->sy_value.X_seg = undefined_section;
-    }
-  else
-    {
-#ifndef BFD_ASSEMBLER
-#ifndef MANY_SEGMENTS
-      switch (segment)
-       {
-       case SEG_DATA:
-       case SEG_TEXT:
-       case SEG_BSS:
-         break;
+      break;
 
-       default:
-         as_fatal ("failed sanity check.");
-       }                       /* switch on segment */
-#endif
-#endif
-      S_SET_SEGMENT (symbolP, segment);
-#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
-      /* @@ Fix this right for BFD!  */
-      if (ext)
-       {
-         S_SET_EXTERNAL (symbolP);
-       }
+    case O_register:
+      S_SET_SEGMENT (symbolP, reg_section);
+      S_SET_VALUE (symbolP, exp.X_add_number);
+      symbolP->sy_frag = &zero_address_frag;
+      break;
+
+    case O_symbol:
+      if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section)
+       symbolP->sy_value = exp;
       else
        {
-         S_CLEAR_EXTERNAL (symbolP);
-       }                       /* if external */
+         S_SET_SEGMENT (symbolP, S_GET_SEGMENT (exp.X_add_symbol));
+#if defined(OBJ_AOUT) | defined(OBJ_BOUT)
+         /* @@ Fix this right for BFD!  */
+         if (ext)
+           S_SET_EXTERNAL (symbolP);
+         else
+           S_CLEAR_EXTERNAL (symbolP);
 #endif /* OBJ_AOUT or OBJ_BOUT */
+         S_SET_VALUE (symbolP,
+                      exp.X_add_number + S_GET_VALUE (exp.X_add_symbol));
+         symbolP->sy_frag = exp.X_add_symbol->sy_frag;
+       }
+      break;
 
-      S_SET_VALUE (symbolP, exp.X_add_number + S_GET_VALUE (exp.X_add_symbol));
-      symbolP->sy_frag = exp.X_add_symbol->sy_frag;
+    default:
+      /* The value is some complex expression.
+        FIXME: Should we set the segment to anything?  */
+      symbolP->sy_value = exp;
+      break;
     }
 }
 \f
@@ -1641,39 +1586,32 @@ emit_expr (exp, nbytes)
      expressionS *exp;
      unsigned int nbytes;
 {
-  segT segment;
+  operatorT op;
   register char *p;
 
   /* Don't do anything if we are going to make another pass.  */
   if (need_pass_2)
     return;
 
-  segment = exp->X_seg;
-
-  /* Don't call this if we are going to junk this pass anyway! */
-  know (segment != pass1_section);
+  op = exp->X_op;
 
-  if (segment == diff_section && exp->X_add_symbol == NULL)
+  if (op == O_absent || op == O_illegal)
     {
-      as_bad ("Subtracting symbol \"%s\" (segment \"%s\") is too hard.  Absolute segment assumed.",
-             S_GET_NAME (exp->X_subtract_symbol),
-             segment_name (S_GET_SEGMENT (exp->X_subtract_symbol)));
-      segment = absolute_section;
-      /* Leave exp->X_add_number alone. */
+      as_warn ("zero assumed for missing expression");
+      exp->X_add_number = 0;
+      op = O_constant;
     }
-  else if (segment == absent_section)
+  else if (op == O_big)
     {
-      as_warn ("0 assumed for missing expression");
+      as_bad ("%s number invalid; zero assumed",
+             exp->X_add_number > 0 ? "bignum" : "floating point");
       exp->X_add_number = 0;
-      know (exp->X_add_symbol == NULL);
-      segment = absolute_section;
+      op = O_constant;
     }
-  else if (segment == big_section)
+  else if (op == O_register)
     {
-      as_bad ("%s number invalid.  Absolute 0 assumed.",
-             exp->X_add_number > 0 ? "Bignum" : "Floating-Point");
-      exp->X_add_number = 0;
-      segment = absolute_section;
+      as_warn ("register value used as expression");
+      op = O_constant;
     }
 
   p = frag_more (nbytes);
@@ -1681,7 +1619,7 @@ emit_expr (exp, nbytes)
 #ifndef WORKING_DOT_WORD
   /* If we have the difference of two symbols in a word, save it on
      the broken_words list.  See the code in write.c.  */
-  if (segment == diff_section && nbytes == 2)
+  if (op == O_subtract && nbytes == 2)
     {
       struct broken_word *x;
 
@@ -1692,7 +1630,7 @@ emit_expr (exp, nbytes)
       x->word_goes_here = p;
       x->dispfrag = 0;
       x->add = exp->X_add_symbol;
-      x->sub = exp->X_subtract_symbol;
+      x->sub = exp->X_op_symbol;
       x->addnum = exp->X_add_number;
       x->added = 0;
       new_broken_words++;
@@ -1700,7 +1638,7 @@ emit_expr (exp, nbytes)
     }
 #endif
 
-  if (segment == absolute_section)
+  if (op == O_constant)
     {
       register long get;
       register long use;
@@ -1743,11 +1681,9 @@ emit_expr (exp, nbytes)
         defined, and otherwise uses 0.  */
 
 #ifdef BFD_ASSEMBLER
-      fix_new (frag_now, p - frag_now->fr_literal, nbytes,
-              exp->X_add_symbol, exp->X_subtract_symbol,
-              exp->X_add_number, 0,
-              /* @@ Should look at CPU word size.  */
-              BFD_RELOC_32);
+      fix_new_exp (frag_now, p - frag_now->fr_literal, nbytes, exp, 0,
+                  /* @@ Should look at CPU word size.  */
+                  BFD_RELOC_32);
 #else
 #ifdef TC_CONS_FIX_NEW
       TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp);
@@ -1762,9 +1698,8 @@ emit_expr (exp, nbytes)
 #define TC_CONS_RELOC 0
 #endif
 #endif
-      fix_new (frag_now, p - frag_now->fr_literal, nbytes,
-              exp->X_add_symbol, exp->X_subtract_symbol,
-              exp->X_add_number, 0, TC_CONS_RELOC);
+      fix_new_exp (frag_now, p - frag_now->fr_literal, nbytes, exp, 0,
+                  TC_CONS_RELOC);
 #endif /* TC_CONS_FIX_NEW */
 #endif /* BFD_ASSEMBLER */
     }
@@ -1793,9 +1728,8 @@ parse_bitfield_cons (exp, nbytes)
 {
   unsigned int bits_available = BITS_PER_CHAR * nbytes;
   char *hold = input_line_pointer;
-  segT segment;
 
-  segment = expression (exp);
+  (void) expression (exp);
 
   if (*input_line_pointer == ':')
     {                  /* bitfields */
@@ -1829,17 +1763,17 @@ parse_bitfield_cons (exp, nbytes)
             you can use a previous .set or
             .equ type symbol.  xoxorich. */
 
-         if (segment == absent_section)
+         if (exp->X_op == O_absent)
            {
-             as_warn ("Using a bit field width of zero.");
+             as_warn ("using a bit field width of zero");
              exp->X_add_number = 0;
-             segment = absolute_section;
+             exp->X_op = O_constant;
            }                   /* implied zero width bitfield */
 
-         if (segment != absolute_section)
+         if (exp->X_op != O_constant)
            {
              *input_line_pointer = '\0';
-             as_bad ("Field width \"%s\" too complex for a bitfield.\n", hold);
+             as_bad ("field width \"%s\" too complex for a bitfield", hold);
              *input_line_pointer = ':';
              demand_empty_rest_of_line ();
              return;
@@ -1847,7 +1781,7 @@ parse_bitfield_cons (exp, nbytes)
 
          if ((width = exp->X_add_number) > (BITS_PER_CHAR * nbytes))
            {
-             as_warn ("Field width %d too big to fit in %d bytes: truncated to %d bits.",
+             as_warn ("field width %d too big to fit in %d bytes: truncated to %d bits",
                       width, nbytes, (BITS_PER_CHAR * nbytes));
              width = BITS_PER_CHAR * nbytes;
            }                   /* too big */
@@ -1862,19 +1796,20 @@ parse_bitfield_cons (exp, nbytes)
 
          hold = ++input_line_pointer; /* skip ':' */
 
-         if ((segment = expression (exp)) != absolute_section)
+         (void) expression (exp);
+         if (exp->X_op != O_constant)
            {
              char cache = *input_line_pointer;
 
              *input_line_pointer = '\0';
-             as_bad ("Field value \"%s\" too complex for a bitfield.\n", hold);
+             as_bad ("field value \"%s\" too complex for a bitfield", hold);
              *input_line_pointer = cache;
              demand_empty_rest_of_line ();
              return;
            }                   /* too complex */
 
-         value |= (~(-1 << width) & exp->X_add_number)
-           << ((BITS_PER_CHAR * nbytes) - bits_available);
+         value |= ((~(-1 << width) & exp->X_add_number)
+                   << ((BITS_PER_CHAR * nbytes) - bits_available));
 
          if ((bits_available -= width) == 0
              || is_it_end_of_statement ()
@@ -1884,11 +1819,11 @@ parse_bitfield_cons (exp, nbytes)
            }                   /* all the bitfields we're gonna get */
 
          hold = ++input_line_pointer;
-         segment = expression (exp);
+         (void) expression (exp);
        }                       /* forever loop */
 
       exp->X_add_number = value;
-      exp->X_seg = absolute_section;
+      exp->X_op = O_constant;
     }                          /* if looks like a bitfield */
 }                              /* parse_bitfield_cons() */
 
@@ -1930,9 +1865,8 @@ parse_mri_cons (exp, nbytes)
          scan++;
        }
       /* Create correct expression */
-      exp->X_add_symbol = 0;
+      exp->X_op = O_constant;
       exp->X_add_number = result;
-      exp->X_seg = absolute_section;
       /* Fake it so that we can read the next char too */
       if (input_line_pointer[0] != '\'' ||
          (input_line_pointer[0] == '\'' && input_line_pointer[1] == '\''))
@@ -1964,7 +1898,6 @@ parse_repeat_cons (exp, nbytes)
      unsigned int nbytes;
 {
   expressionS count;
-  segT segment;
   register int i;
 
   expression (exp);
@@ -1976,8 +1909,8 @@ parse_repeat_cons (exp, nbytes)
     }
 
   ++input_line_pointer;
-  segment = expression (&count);
-  if (segment != absolute_section
+  expression (&count);
+  if (count.X_op != O_constant
       || count.X_add_number <= 0)
     {
       as_warn ("Unresolvable or nonpositive repeat count; using 1");
@@ -2218,15 +2151,14 @@ float_cons (float_type)         /* Worker to do .float etc statements. */
 #ifdef REPEAT_CONS_EXPRESSIONS
          if (*input_line_pointer == ':')
            {
-             segT segment;
              expressionS count_exp;
 
              ++input_line_pointer;
-             segment = expression (&count_exp);
-             if (segment != absolute_section
+             expression (&count_exp);
+             if (count_exp.X_op != O_constant
                  || count_exp.X_add_number <= 0)
                {
-                 as_warn ("Unresolvable or nonpositive repeat count; using 1");
+                 as_warn ("unresolvable or nonpositive repeat count; using 1");
                }
              else
                count = count_exp.X_add_number;
@@ -2420,16 +2352,16 @@ get_segmented_expression (expP)
   register segT retval;
 
   retval = expression (expP);
-  if (retval == pass1_section
-      || retval == absent_section
-      || retval == big_section)
+  if (expP->X_op == O_illegal
+      || expP->X_op == O_absent
+      || expP->X_op == O_big)
     {
-      as_bad ("Expected address expression: absolute 0 assumed");
-      retval = expP->X_seg = absolute_section;
+      as_bad ("expected address expression; zero assumed");
+      expP->X_op = O_constant;
       expP->X_add_number = 0;
-      expP->X_add_symbol = expP->X_subtract_symbol = 0;
+      retval = absolute_section;
     }
-  return (retval);             /* SEG_ ABSOLUTE,UNKNOWN,DATA,TEXT,BSS */
+  return retval;
 }
 
 static segT 
@@ -2437,53 +2369,38 @@ get_known_segmented_expression (expP)
      register expressionS *expP;
 {
   register segT retval;
-  register CONST char *name1;
-  register CONST char *name2;
 
   if ((retval = get_segmented_expression (expP)) == undefined_section)
     {
-      name1 = expP->X_add_symbol ? S_GET_NAME (expP->X_add_symbol) : "";
-      name2 = expP->X_subtract_symbol ?
-       S_GET_NAME (expP->X_subtract_symbol) :
-       "";
-      if (name1 && name2)
-       {
-         as_warn ("Symbols \"%s\" \"%s\" are undefined: absolute 0 assumed.",
-                  name1, name2);
-       }
+      /* There is no easy way to extract the undefined symbol from the
+        expression.  */
+      if (expP->X_add_symbol != NULL
+         && S_GET_SEGMENT (expP->X_add_symbol) != expr_section)
+       as_warn ("symbol \"%s\" undefined; zero assumed",
+                S_GET_NAME (expP->X_add_symbol));
       else
-       {
-         as_warn ("Symbol \"%s\" undefined: absolute 0 assumed.",
-                  name1 ? name1 : name2);
-       }
-      retval = expP->X_seg = absolute_section;
+       as_warn ("some symbol undefined; zero assumed");
+      retval = absolute_section;
+      expP->X_op = O_constant;
       expP->X_add_number = 0;
-      expP->X_add_symbol = expP->X_subtract_symbol = NULL;
     }
-  know (retval == absolute_section
-       || retval == diff_section
-       || SEG_NORMAL (retval));
+  know (retval == absolute_section || SEG_NORMAL (retval));
   return (retval);
-
 }                              /* get_known_segmented_expression() */
 
-
-
 /* static */ long              /* JF was static, but can't be if the MD pseudos are to use it */
 get_absolute_expression ()
 {
   expressionS exp;
-  register segT s;
 
-  if ((s = expression (&exp)) != absolute_section)
+  expression (&exp);
+  if (exp.X_op != O_constant)
     {
-      if (s != absent_section)
-       {
-         as_bad ("Bad Absolute Expression, absolute 0 assumed.");
-       }
+      if (exp.X_op != O_absent)
+       as_bad ("bad absolute expression; zero assumed");
       exp.X_add_number = 0;
     }
-  return (exp.X_add_number);
+  return exp.X_add_number;
 }
 
 char                           /* return terminator */
index d305024..a5acf1f 100644 (file)
@@ -1,5 +1,4 @@
 /* symbols.c -symbol table-
-
    Copyright (C) 1987, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -585,12 +584,23 @@ resolve_symbol_value (symp)
     }
   else
     {
+      offsetT left, right, val;
+      segT seg_left, seg_right;
+
       symp->sy_resolving = 1;
 
-      if (symp->sy_value.X_seg == absolute_section)
-       S_SET_VALUE (symp, S_GET_VALUE (symp) + symp->sy_frag->fr_address);
-      else if (symp->sy_value.X_seg == undefined_section)
+      switch (symp->sy_value.X_op)
        {
+       case O_absent:
+         S_SET_VALUE (symp, 0);
+         /* Fall through.  */
+       case O_constant:
+         S_SET_VALUE (symp, S_GET_VALUE (symp) + symp->sy_frag->fr_address);
+         if (S_GET_SEGMENT (symp) == expr_section)
+           S_SET_SEGMENT (symp, absolute_section);
+         break;
+
+       case O_symbol:
          resolve_symbol_value (symp->sy_value.X_add_symbol);
 
 #ifdef obj_frob_forward_symbol
@@ -602,26 +612,84 @@ resolve_symbol_value (symp)
                       (symp->sy_value.X_add_number
                        + symp->sy_frag->fr_address
                        + S_GET_VALUE (symp->sy_value.X_add_symbol)));
-       }
-      else if (symp->sy_value.X_seg == diff_section)
-       {
+         if (S_GET_SEGMENT (symp) == expr_section
+             || S_GET_SEGMENT (symp) == undefined_section)
+           S_SET_SEGMENT (symp,
+                          S_GET_SEGMENT (symp->sy_value.X_add_symbol));
+         break;
+
+       case O_uminus:
+       case O_bit_not:
+         resolve_symbol_value (symp->sy_value.X_add_symbol);
+         if (symp->sy_value.X_op == O_uminus)
+           val = - S_GET_VALUE (symp->sy_value.X_add_symbol);
+         else
+           val = ~ S_GET_VALUE (symp->sy_value.X_add_symbol);
+         S_SET_VALUE (symp,
+                      (val
+                       + symp->sy_value.X_add_number
+                       + symp->sy_frag->fr_address));
+         if (S_GET_SEGMENT (symp) == expr_section
+             || S_GET_SEGMENT (symp) == undefined_section)
+           S_SET_SEGMENT (symp, absolute_section);
+         break;
+
+       case O_multiply:
+       case O_divide:
+       case O_modulus:
+       case O_left_shift:
+       case O_right_shift:
+       case O_bit_inclusive_or:
+       case O_bit_or_not:
+       case O_bit_exclusive_or:
+       case O_bit_and:
+       case O_add:
+       case O_subtract:
          resolve_symbol_value (symp->sy_value.X_add_symbol);
-         resolve_symbol_value (symp->sy_value.X_subtract_symbol);
-         if (S_GET_SEGMENT (symp->sy_value.X_add_symbol)
-             != S_GET_SEGMENT (symp->sy_value.X_subtract_symbol))
-           as_bad ("%s is difference of symbols in different sections",
+         resolve_symbol_value (symp->sy_value.X_op_symbol);
+         seg_left = S_GET_SEGMENT (symp->sy_value.X_add_symbol);
+         seg_right = S_GET_SEGMENT (symp->sy_value.X_op_symbol);
+         if (seg_left != seg_right
+             && seg_left != undefined_section
+             && seg_right != undefined_section)
+           as_bad ("%s is operation on symbols in different sections",
                    S_GET_NAME (symp));
+         if ((S_GET_SEGMENT (symp->sy_value.X_add_symbol)
+              != absolute_section)
+             && symp->sy_value.X_op != O_subtract)
+           as_bad ("%s is illegal operation on non-absolute symbols",
+                   S_GET_NAME (symp));
+         left = S_GET_VALUE (symp->sy_value.X_add_symbol);
+         right = S_GET_VALUE (symp->sy_value.X_op_symbol);
+         switch (symp->sy_value.X_op)
+           {
+           case O_multiply:            val = left * right; break;
+           case O_divide:              val = left / right; break;
+           case O_modulus:             val = left % right; break;
+           case O_left_shift:          val = left << right; break;
+           case O_right_shift:         val = left >> right; break;
+           case O_bit_inclusive_or:    val = left | right; break;
+           case O_bit_or_not:          val = left |~ right; break;
+           case O_bit_exclusive_or:    val = left ^ right; break;
+           case O_bit_and:             val = left & right; break;
+           case O_add:                 val = left + right; break;
+           case O_subtract:            val = left - right; break;
+           default:                    abort ();
+           }
          S_SET_VALUE (symp,
                       (symp->sy_value.X_add_number
                        + symp->sy_frag->fr_address
-                       + S_GET_VALUE (symp->sy_value.X_add_symbol)
-                       - S_GET_VALUE (symp->sy_value.X_subtract_symbol)));
-         S_SET_SEGMENT (symp, absolute_section);
-       }
-      else
-       {
-         /* More cases need to be added here.  */
-         abort ();
+                       + val));
+         if (S_GET_SEGMENT (symp) == expr_section
+             || S_GET_SEGMENT (symp) == undefined_section)
+           S_SET_SEGMENT (symp, absolute_section);
+         break;
+
+       case O_register:
+       case O_big:
+       case O_illegal:
+         as_bad ("bad value for symbol \"%s\"", S_GET_NAME (symp));
+         break;
        }
     }
 
@@ -1014,7 +1082,7 @@ valueT
 S_GET_VALUE (s)
      symbolS *s;
 {
-  if (s->sy_value.X_seg != absolute_section)
+  if (s->sy_value.X_op != O_constant)
     as_bad ("Attempt to get value of unresolved symbol %s", S_GET_NAME (s));
   return (valueT) s->sy_value.X_add_number;
 }
@@ -1026,7 +1094,7 @@ S_SET_VALUE (s, val)
      symbolS *s;
      valueT val;
 {
-  s->sy_value.X_seg = absolute_section;
+  s->sy_value.X_op = O_constant;
   s->sy_value.X_add_number = (offsetT) val;
 }
 
index 8a480f1..b527708 100644 (file)
@@ -58,6 +58,15 @@ int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE;
 
 #endif /* BFD_ASSEMBLER */
 
+static fixS *fix_new_internal PARAMS ((fragS *, int where, short int size,
+                                      symbolS *add, symbolS *sub,
+                                      offsetT offset, int pcrel,
+#ifdef BFD_ASSEMBLER
+                                      bfd_reloc_code_real_type r_type
+#else
+                                      int r_type
+#endif
+                                      ));
 static long fixup_segment PARAMS ((fixS * fixP, segT this_segment_type));
 static relax_addressT relax_align PARAMS ((relax_addressT addr, int align));
 void relax_segment PARAMS ((struct frag * seg_frag_root, segT seg_type));
@@ -67,13 +76,14 @@ void relax_segment PARAMS ((struct frag * seg_frag_root, segT seg_type));
  *
  * Create a fixS in obstack 'notes'.
  */
-fixS *
-fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
+static fixS *
+fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel,
+                 r_type)
      fragS *frag;              /* Which frag? */
      int where;                        /* Where in that frag? */
      short int size;           /* 1, 2, or 4 usually. */
      symbolS *add_symbol;      /* X_add_symbol. */
-     symbolS *sub_symbol;      /* X_subtract_symbol. */
+     symbolS *sub_symbol;      /* X_op_symbol. */
      offsetT offset;           /* X_add_number. */
      int pcrel;                        /* TRUE if PC-relative relocation. */
 #ifdef BFD_ASSEMBLER
@@ -142,6 +152,70 @@ fix_new (frag, where, size, add_symbol, sub_symbol, offset, pcrel, r_type)
   return fixP;
 }
 
+/* Create a fixup relative to a symbol (plus a constant).  */
+
+fixS *
+fix_new (frag, where, size, add_symbol, offset, pcrel, r_type)
+     fragS *frag;              /* Which frag? */
+     int where;                        /* Where in that frag? */
+     short int size;           /* 1, 2, or 4 usually. */
+     symbolS *add_symbol;      /* X_add_symbol. */
+     offsetT offset;           /* X_add_number. */
+     int pcrel;                        /* TRUE if PC-relative relocation. */
+#ifdef BFD_ASSEMBLER
+     bfd_reloc_code_real_type r_type; /* Relocation type */
+#else
+     int r_type;               /* Relocation type */
+#endif
+{
+  return fix_new_internal (frag, where, size, add_symbol,
+                          (symbolS *) NULL, offset, pcrel, r_type);
+}
+
+/* Create a fixup for an expression.  Currently we only support fixups
+   for difference expressions.  That is itself more than most object
+   file formats support anyhow.  */
+
+fixS *
+fix_new_exp (frag, where, size, exp, pcrel, r_type)
+     fragS *frag;              /* Which frag? */
+     int where;                        /* Where in that frag? */
+     short int size;           /* 1, 2, or 4 usually. */
+     expressionS *exp;         /* Expression.  */
+     int pcrel;                        /* TRUE if PC-relative relocation. */
+#ifdef BFD_ASSEMBLER
+     bfd_reloc_code_real_type r_type; /* Relocation type */
+#else
+     int r_type;               /* Relocation type */
+#endif
+{
+  symbolS *add = NULL;
+  symbolS *sub = NULL;
+  offsetT off = 0;
+  
+  switch (exp->X_op)
+    {
+    case O_absent:
+      break;
+
+    case O_subtract:
+      sub = exp->X_op_symbol;
+      /* Fall through.  */
+    case O_symbol:
+      add = exp->X_add_symbol;
+      /* Fall through.   */
+    case O_constant:
+      off = exp->X_add_number;
+      break;
+      
+    default:
+      as_bad ("expression too complex for fixup");
+    }
+
+  return fix_new_internal (frag, where, size, add, sub, off,
+                          pcrel, r_type);
+}
+
 /* Append a string onto another string, bumping the pointer along.  */
 void
 append (charPP, fromP, length)
@@ -763,11 +837,7 @@ write_object_file ()
     while (seclist && *seclist)
       {
        sec = *seclist;
-       while (sec == big_section
-              || sec == reg_section
-              || sec == pass1_section
-              || sec == diff_section
-              || sec == absent_section)
+       while (sec == reg_section || sec == expr_section)
          {
            sec = sec->next;
            *seclist = sec;
@@ -975,30 +1045,30 @@ write_object_file ()
     for (lie = broken_words; lie; lie = lie->next_broken_word)
       if (!lie->added)
        {
+         expressionS exp;
+
+         exp.X_op = O_subtract;
+         exp.X_add_symbol = lie->add;
+         exp.X_op_symbol = lie->sub;
+         exp.X_add_number = lie->addnum;
 #ifdef BFD_ASSEMBLER
-         fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal,
-                  2, lie->add, lie->sub, lie->addnum, 0,
-                  BFD_RELOC_NONE);
+         fix_new_exp (lie->frag,
+                      lie->word_goes_here - lie->frag->fr_literal,
+                      2, &exp, 0, BFD_RELOC_NONE);
 #else
 #if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE)
-         fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal,
-                  2, lie->add,
-                  lie->sub, lie->addnum,
-                  0, NO_RELOC);
+         fix_new_exp (lie->frag,
+                      lie->word_goes_here - lie->frag->fr_literal,
+                      2, &exp, 0, NO_RELOC);
 #else
 #ifdef TC_NS32K
-         fix_new_ns32k (lie->frag,
-                        lie->word_goes_here - lie->frag->fr_literal,
-                        2,
-                        lie->add,
-                        lie->sub,
-                        lie->addnum,
-                        0, 0, 2, 0, 0);
+         fix_new_ns32k_exp (lie->frag,
+                            lie->word_goes_here - lie->frag->fr_literal,
+                            2, &exp, 0, 0, 2, 0, 0);
 #else
-         fix_new (lie->frag, lie->word_goes_here - lie->frag->fr_literal,
-                  2, lie->add,
-                  lie->sub, lie->addnum,
-                  0, 0);
+         fix_new_exp (lie->frag,
+                      lie->word_goes_here - lie->frag->fr_literal,
+                      2, &exp, 0, 0);
 #endif /* TC_NS32K */
 #endif /* TC_SPARC|TC_A29K|NEED_FX_R_TYPE */
 #endif /* BFD_ASSEMBLER */
@@ -1191,7 +1261,7 @@ write_object_file ()
 
          if (! symp->sy_resolved)
            {
-             if (symp->sy_value.X_seg == absolute_section)
+             if (symp->sy_value.X_op == O_constant)
                {
                  /* This is the normal case; skip the call.  */
                  S_SET_VALUE (symp,