* config/tc-i386.c (md_assemble): Make sure the opcode suffix
authorIan Lance Taylor <ian@airs.com>
Wed, 15 May 1996 16:26:20 +0000 (16:26 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 15 May 1996 16:26:20 +0000 (16:26 +0000)
matches the register size.
PR 9700.

gas/ChangeLog
gas/config/tc-i386.c

index 81f8839bf761456d144a5494afde87d304e73c23..115b3ea46765305165ce62e39265f0e298b3e6a0 100644 (file)
@@ -1,3 +1,8 @@
+Wed May 15 12:23:53 1996  Ian Lance Taylor  <ian@cygnus.com>
+
+       * config/tc-i386.c (md_assemble): Make sure the opcode suffix
+       matches the register size.
+
 Wed May 15 08:33:37 1996  Jeffrey A Law  (law@cygnus.com)
 
        * config/obj-coff.c (count_entries_in_chain): Ignore Fixups with
index 741a4ec5586ad3cf9b69b7767f712cfe7ea588fb..70622c253d9c850a1faa0ad82e2c19e744c04823 100644 (file)
@@ -240,6 +240,71 @@ const relax_typeS md_relax_table[] =
 
 };
 
+
+void
+i386_align_code (fragP, count)
+     fragS *fragP;
+     int count;
+{
+  /* Various efficient no-op patterns for aligning code labels.  */
+  static const char f32_1[] = {0x90};
+  static const char f32_2[] = {0x8d,0x36};
+  static const char f32_3[] = {0x8d,0x76,0x00};
+  static const char f32_4[] = {0x8d,0x74,0x26,0x00};
+  static const char f32_5[] = {0x90,
+                              0x8d,0x74,0x26,0x00};
+  static const char f32_6[] = {0x8d,0xb6,0x00,0x00,0x00,0x00};
+  static const char f32_7[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};
+  static const char f32_8[] = {0x90,
+                              0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};
+  static const char f32_9[] = {0x8d,0x36,
+                              0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};
+  static const char f32_10[] = {0x8d,0x76,0x00,
+                               0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};
+  static const char f32_11[] = {0x8d,0x74,0x26,0x00,
+                               0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};
+  static const char f32_12[] = {0x8d,0xb6,0x00,0x00,0x00,0x00,
+                               0x8d,0xb6,0x00,0x00,0x00,0x00};
+  static const char f32_13[] = {0x8d,0xb6,0x00,0x00,0x00,0x00,
+                               0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};
+  static const char f32_14[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00,
+                               0x8d,0xb4,0x26,0x00,0x00,0x00,0x00};
+  static const char f32_15[] = {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90,
+                               0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};
+  static const char f16_4[] = {0x8d,0xb6,0x00,0x00};
+  static const char f16_5[] = {0x90,
+                              0x8d,0xb6,0x00,0x00};
+  static const char f16_6[] = {0x8d,0x36,
+                              0x8d,0xb6,0x00,0x00};
+  static const char f16_7[] = {0x8d,0x76,0x00,
+                              0x8d,0xb6,0x00,0x00};
+  static const char f16_8[] = {0x8d,0xb6,0x00,0x00,
+                              0x8d,0xb6,0x00,0x00};
+  static const char *const f32_patt[] = {
+    f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8,
+    f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15
+  };
+  static const char *const f16_patt[] = {
+    f32_1, f32_2, f32_3, f16_4, f16_5, f16_6, f16_7, f16_8,
+    f32_15, f32_15, f32_15, f32_15, f32_15, f32_15, f32_15
+  };
+
+  if (count > 0 && count <= 15)
+    {
+      if (flag_16bit_code)
+       {
+         memcpy(fragP->fr_literal + fragP->fr_fix,
+                f16_patt[count - 1], count);
+         if (count > 8) /* adjust jump offset */
+           fragP->fr_literal[fragP->fr_fix + 1] = count - 2;
+       }
+      else
+       memcpy(fragP->fr_literal + fragP->fr_fix,
+              f32_patt[count - 1], count);
+      fragP->fr_var = count;
+    }
+}
+
 static char *output_invalid PARAMS ((int c));
 static int i386_operand PARAMS ((char *operand_string));
 static reg_entry *parse_register PARAMS ((char *reg_string));
@@ -495,6 +560,15 @@ md_begin ()
   record_alignment (bss_section, 2);
 #endif
 }
+
+void
+i386_print_statistics (file)
+     FILE *file;
+{
+  hash_print_statistics (file, "i386 opcode", op_hash);
+  hash_print_statistics (file, "i386 register", reg_hash);
+  hash_print_statistics (file, "i386 prefix", prefix_hash);
+}
 \f
 
 #ifdef DEBUG386
@@ -1085,6 +1159,32 @@ md_assemble (line)
                          DWORD_OPCODE_SUFFIX);
            }
       }
+    else if (i.suffix != 0
+            && i.reg_operands != 0
+            && (i.types[i.operands - 1] & Reg) != 0)
+      {
+       int want;
+
+       /* If the last operand is a register, make sure it is
+           compatible with the suffix.  */
+
+       switch (i.suffix)
+         {
+         default:
+           abort ();
+         case BYTE_OPCODE_SUFFIX:
+           want = Reg8;
+           break;
+         case WORD_OPCODE_SUFFIX:
+           want = Reg16;
+           break;
+         case DWORD_OPCODE_SUFFIX:
+           want = Reg32;
+           break;
+         }
+       if ((i.types[i.operands - 1] & want) == 0)
+         as_bad ("register does not match opcode suffix");
+      }
 
     /* Make still unresolved immediate matches conform to size of immediate
        given in i.suffix. Note:  overlap2 cannot be an immediate!
@@ -1531,11 +1631,7 @@ md_assemble (line)
            /* It's a symbol; end frag & setup for relax.
               Make sure there are more than 6 chars left in the current frag;
               if not we'll have to start a new one. */
-           if (obstack_room (&frags) <= 6)
-             {
-               frag_wane (frag_now);
-               frag_new (0);
-             }
+           frag_grow (7);
            p = frag_more (1);
            insn_size += 1;
            p[0] = t->base_opcode;
@@ -2374,8 +2470,9 @@ md_estimate_size_before_relax (fragP, segment)
  */
 #ifndef BFD_ASSEMBLER
 void
-md_convert_frag (headers, fragP)
+md_convert_frag (headers, sec, fragP)
      object_headers *headers;
+     segT sec;
      register fragS *fragP;
 #else
 void
@@ -2515,12 +2612,14 @@ md_number_to_chars (con, value, nbytes)
    the same (little-endian) format, so we don't need to care about which
    we are handling.  */
 
-static void
-md_apply_fix_1 (fixP, value)
-     fixS *fixP;               /* The fix we're to put in */
-     long value;               /* The value of the bits. */
+int
+md_apply_fix3 (fixP, valp, seg)
+     fixS *fixP;               /* The fix we're to put in.  */
+     valueT *valp;             /* Pointer to the value of the bits.  */
+     segT seg;                 /* Segment fix is from.  */
 {
   register char *p = fixP->fx_where + fixP->fx_frag->fr_literal;
+  valueT value = *valp;
 
 #if defined (BFD_ASSEMBLER) && !defined (TE_Mach)
   /*
@@ -2531,7 +2630,8 @@ md_apply_fix_1 (fixP, value)
     {
       value += fixP->fx_where + fixP->fx_frag->fr_address;
 #ifdef OBJ_ELF
-      if (S_GET_SEGMENT (fixP->fx_addsy) != undefined_section)
+      if (S_GET_SEGMENT (fixP->fx_addsy) == seg
+         || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
        {
          /* Yes, we add the values in twice.  This is because
             bfd_perform_relocation subtracts them out again.  I think
@@ -2606,26 +2706,9 @@ md_apply_fix_1 (fixP, value)
 
 #endif
   md_number_to_chars (p, value, fixP->fx_size);
-}
 
-#ifdef BFD_ASSEMBLER
-int
-md_apply_fix (fixP, valp)
-     fixS *fixP;
-     valueT *valp;
-{
-  md_apply_fix_1 (fixP, *valp);
   return 1;
 }
-#else
-void
-md_apply_fix (fixP, val)
-     fixS *fixP;
-     long val;
-{
-  md_apply_fix_1 (fixP, val);
-}
-#endif
 
 #if 0
 /* This is never used.  */
@@ -2731,7 +2814,7 @@ parse_register (reg_string)
 }
 \f
 #ifdef OBJ_ELF
-CONST char *md_shortopts = "mVQ:";
+CONST char *md_shortopts = "kmVQ:";
 #else
 CONST char *md_shortopts = "m";
 #endif
@@ -2752,6 +2835,10 @@ md_parse_option (c, arg)
       break;
 
 #ifdef OBJ_ELF
+      /* -k: Ignore for FreeBSD compatibility.  */
+    case 'k':
+      break;
+
       /* -V: SVR4 argument to print version ID.  */
     case 'V':
       print_version_id ();
@@ -2881,7 +2968,7 @@ tc_gen_reloc (section, fixp)
          MAP (4, 1, BFD_RELOC_32_PCREL);
        default:
          as_bad ("Can not do %d byte %srelocation", fixp->fx_size,
-                 fixp->fx_pcrel ? "pc-relative" : "");
+                 fixp->fx_pcrel ? "pc-relative " : "");
        }
     }
 #undef MAP
@@ -2960,6 +3047,9 @@ short
 tc_coff_fix2rtype (fixP)
      fixS *fixP;
 {
+  if (fixP->fx_r_type == R_IMAGEBASE)
+    return R_IMAGEBASE;
+
   return (fixP->fx_pcrel ?
          (fixP->fx_size == 1 ? R_PCRBYTE :
           fixP->fx_size == 2 ? R_PCRWORD :
@@ -2982,5 +3072,100 @@ tc_coff_sizemachdep (frag)
 #endif /* I386COFF */
 
 #endif /* BFD_ASSEMBLER? */
+\f
+#ifdef SCO_ELF
+
+/* Heavily plagarized from obj_elf_version.  The idea is to emit the
+   SCO specific identifier in the .notes section to satisfy the SCO
+   linker.
+
+   This looks more complicated than it really is.  As opposed to the
+   "obvious" solution, this should handle the cross dev cases
+   correctly.  (i.e, hosting on a 64 bit big endian processor, but
+   generating SCO Elf code) Efficiency isn't a concern, as there
+   should be exactly one of these sections per object module.
+
+   SCO OpenServer 5 identifies it's ELF modules with a standard ELF
+   .note section.
+
+   int_32 namesz  = 4 ;  Name size 
+   int_32 descsz  = 12 ; Descriptive information 
+   int_32 type    = 1 ;  
+   char   name[4] = "SCO" ; Originator name ALWAYS SCO + NULL 
+   int_32 version = (major ver # << 16)  | version of tools ;
+   int_32 source  = (tool_id << 16 ) | 1 ;
+   int_32 info    = 0 ;    These are set by the SCO tools, but we
+                           don't know enough about the source 
+                          environment to set them.  SCO ld currently
+                          ignores them, and recommends we set them
+                          to zero.  */
+
+#define SCO_MAJOR_VERSION 0x1
+#define SCO_MINOR_VERSION 0x1
+
+void
+sco_id ()
+{
+  char *name;
+  unsigned int c;
+  char ch;
+  char *p;
+  asection *seg = now_seg;
+  subsegT subseg = now_subseg;
+  Elf_Internal_Note i_note;
+  Elf_External_Note e_note;
+  asection *note_secp = (asection *) NULL;
+  int i, len;
+
+  /* create the .note section */
+
+  note_secp = subseg_new (".note", 0);
+  bfd_set_section_flags (stdoutput,
+                        note_secp,
+                        SEC_HAS_CONTENTS | SEC_READONLY);
+
+  /* process the version string */
+
+  i_note.namesz = 4; 
+  i_note.descsz = 12;          /* 12 descriptive bytes */
+  i_note.type = NT_VERSION;    /* Contains a version string */
+
+  p = frag_more (sizeof (i_note.namesz));
+  md_number_to_chars (p, (valueT) i_note.namesz, 4);
+
+  p = frag_more (sizeof (i_note.descsz));
+  md_number_to_chars (p, (valueT) i_note.descsz, 4);
+
+  p = frag_more (sizeof (i_note.type));
+  md_number_to_chars (p, (valueT) i_note.type, 4);
+
+  p = frag_more (4);
+  strcpy (p, "SCO"); 
+
+  /* Note: this is the version number of the ELF we're representing */
+  p = frag_more (4);
+  md_number_to_chars (p, (SCO_MAJOR_VERSION << 16) | (SCO_MINOR_VERSION), 4);
+
+  /* Here, we pick a magic number for ourselves (yes, I "registered"
+     it with SCO.  The bottom bit shows that we are compat with the
+     SCO ABI.  */
+  p = frag_more (4);
+  md_number_to_chars (p, 0x4c520000 | 0x0001, 4);
+
+  /* If we knew (or cared) what the source language options were, we'd
+     fill them in here.  SCO has given us permission to ignore these
+     and just set them to zero.  */
+  p = frag_more (4);
+  md_number_to_chars (p, 0x0000, 4);
+  frag_align (2, 0); 
+
+  /* We probably can't restore the current segment, for there likely
+     isn't one yet...  */
+  if (seg && subseg)
+    subseg_set (seg, subseg);
+}
+
+#endif /* SCO_ELF */
 
 /* end of tc-i386.c */