Fix region length calculations when regions end with .align padding.
[deliverable/binutils-gdb.git] / gas / config / tc-m68hc11.c
index 38d45fe99946591938a9377bf82d80a93e616967..780f773fc91bc1a93863118b1b1e9fcd4d4c2927 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-m68hc11.c -- Assembler code for the Motorola 68HC11 & 68HC12.
-   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Written by Stephane Carrez (stcarrez@nerim.fr)
 
    This file is part of GAS, the GNU Assembler.
@@ -19,7 +19,6 @@
    the Free Software Foundation, 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <stdio.h>
 #include "as.h"
 #include "safe-ctype.h"
 #include "subsegs.h"
@@ -37,8 +36,9 @@ const char FLT_CHARS[] = "dD";
 #define STATE_CONDITIONAL_BRANCH       (1)
 #define STATE_PC_RELATIVE              (2)
 #define STATE_INDEXED_OFFSET            (3)
-#define STATE_XBCC_BRANCH               (4)
-#define STATE_CONDITIONAL_BRANCH_6812  (5)
+#define STATE_INDEXED_PCREL             (4)
+#define STATE_XBCC_BRANCH               (5)
+#define STATE_CONDITIONAL_BRANCH_6812  (6)
 
 #define STATE_BYTE                     (0)
 #define STATE_BITS5                     (0)
@@ -90,6 +90,14 @@ relax_typeS md_relax_table[] = {
   {0, 0, 2, 0},
   {1, 1, 0, 0},
 
+  /* Relax for PC relative offset: 5-bits, 9-bits, 16-bits.
+     For the 9-bit case, there will be a -1 correction to take into
+     account the new byte that's why the range is -255..256.  */
+  {(15), (-16), 0, ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS9)},
+  {(256), (-255), 1, ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS16)},
+  {0, 0, 2, 0},
+  {1, 1, 0, 0},
+
   /* Relax for dbeq/ibeq/tbeq r,<L>:
      These insns are translated into db!cc +3 jmp L.  */
   {(255), (-256), 0, ENCODE_RELAX (STATE_XBCC_BRANCH, STATE_WORD)},
@@ -151,48 +159,45 @@ static alias alias_opcodes[] = {
 };
 
 /* Local functions.  */
-static register_id reg_name_search PARAMS ((char *));
-static register_id register_name PARAMS ((void));
-static int cmp_opcode PARAMS ((struct m68hc11_opcode *,
-                               struct m68hc11_opcode *));
-static char *print_opcode_format PARAMS ((struct m68hc11_opcode *, int));
-static char *skip_whites PARAMS ((char *));
-static int check_range PARAMS ((long, int));
-static void print_opcode_list PARAMS ((void));
-static void get_default_target PARAMS ((void));
-static void print_insn_format PARAMS ((char *));
-static int get_operand PARAMS ((operand *, int, long));
-static void fixup8 PARAMS ((expressionS *, int, int));
-static void fixup16 PARAMS ((expressionS *, int, int));
-static void fixup24 PARAMS ((expressionS *, int, int));
-static unsigned char convert_branch PARAMS ((unsigned char));
-static char *m68hc11_new_insn PARAMS ((int));
-static void build_dbranch_insn PARAMS ((struct m68hc11_opcode *,
-                                        operand *, int, int));
-static int build_indexed_byte PARAMS ((operand *, int, int));
-static int build_reg_mode PARAMS ((operand *, int));
-
-static struct m68hc11_opcode *find
-  PARAMS ((struct m68hc11_opcode_def *, operand *, int));
-static struct m68hc11_opcode *find_opcode
-  PARAMS ((struct m68hc11_opcode_def *, operand *, int *));
-static void build_jump_insn
-  PARAMS ((struct m68hc11_opcode *, operand *, int, int));
-static void build_insn
-  PARAMS ((struct m68hc11_opcode *, operand *, int));
-static int relaxable_symbol PARAMS ((symbolS *));
+static register_id reg_name_search (char *);
+static register_id register_name (void);
+static int cmp_opcode (struct m68hc11_opcode *, struct m68hc11_opcode *);
+static char *print_opcode_format (struct m68hc11_opcode *, int);
+static char *skip_whites (char *);
+static int check_range (long, int);
+static void print_opcode_list (void);
+static void get_default_target (void);
+static void print_insn_format (char *);
+static int get_operand (operand *, int, long);
+static void fixup8 (expressionS *, int, int);
+static void fixup16 (expressionS *, int, int);
+static void fixup24 (expressionS *, int, int);
+static unsigned char convert_branch (unsigned char);
+static char *m68hc11_new_insn (int);
+static void build_dbranch_insn (struct m68hc11_opcode *,
+                                operand *, int, int);
+static int build_indexed_byte (operand *, int, int);
+static int build_reg_mode (operand *, int);
+
+static struct m68hc11_opcode *find (struct m68hc11_opcode_def *,
+                                    operand *, int);
+static struct m68hc11_opcode *find_opcode (struct m68hc11_opcode_def *,
+                                           operand *, int *);
+static void build_jump_insn (struct m68hc11_opcode *, operand *, int, int);
+static void build_insn (struct m68hc11_opcode *, operand *, int);
+static int relaxable_symbol (symbolS *);
 
 /* Pseudo op to indicate a relax group.  */
-static void s_m68hc11_relax PARAMS((int));
+static void s_m68hc11_relax (int);
 
 /* Pseudo op to control the ELF flags.  */
-static void s_m68hc11_mode PARAMS ((int));
+static void s_m68hc11_mode (int);
 
 /* Mark the symbols with STO_M68HC12_FAR to indicate the functions
    are using 'rtc' for returning.  It is necessary to use 'call'
    to invoke them.  This is also used by the debugger to correctly
    find the stack frame.  */
-static void s_m68hc11_mark_symbol PARAMS ((int));
+static void s_m68hc11_mark_symbol (int);
 
 /* Controls whether relative branches can be turned into long branches.
    When the relative offset is too large, the insn are changed:
@@ -228,7 +233,7 @@ static short flag_print_opcodes = 0;
 static struct hash_control *m68hc11_hash;
 
 /* Current cpu (either cpu6811 or cpu6812).  This is determined automagically
-   by 'get_default_target' by looking at default BFD vector.  This is overriden
+   by 'get_default_target' by looking at default BFD vector.  This is overridden
    with the -m<cpu> option.  */
 static int current_architecture = 0;
 
@@ -242,7 +247,7 @@ static int num_opcodes;
 static struct m68hc11_opcode *m68hc11_sorted_opcodes;
 
 /* ELF flags to set in the output file header.  */
-static int elf_flags = 0;
+static int elf_flags = E_M68HC11_F64;
 
 /* These are the machine dependent pseudo-ops.  These are included so
    the assembler can work on the output from the SUN C compiler, which
@@ -260,10 +265,6 @@ const pseudo_typeS md_pseudo_table[] = {
   {"fcc", stringer, 1},
   {"rmb", s_space, 0},
 
-  /* Dwarf2 support for Gcc.  */
-  {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
-  {"loc", dwarf2_directive_loc, 0},
-
   /* Motorola ALIS.  */
   {"xrefb", s_ignore, 0}, /* Same as xref  */
 
@@ -305,6 +306,18 @@ struct option md_longopts[] = {
 #define OPTION_GENERATE_EXAMPLE  (OPTION_MD_BASE + 5)
   {"generate-example", no_argument, NULL, OPTION_GENERATE_EXAMPLE},
 
+#define OPTION_MSHORT  (OPTION_MD_BASE + 6)
+  {"mshort", no_argument, NULL, OPTION_MSHORT},
+
+#define OPTION_MLONG  (OPTION_MD_BASE + 7)
+  {"mlong", no_argument, NULL, OPTION_MLONG},
+
+#define OPTION_MSHORT_DOUBLE  (OPTION_MD_BASE + 8)
+  {"mshort-double", no_argument, NULL, OPTION_MSHORT_DOUBLE},
+
+#define OPTION_MLONG_DOUBLE  (OPTION_MD_BASE + 9)
+  {"mlong-double", no_argument, NULL, OPTION_MLONG_DOUBLE},
+
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
@@ -313,7 +326,7 @@ size_t md_longopts_size = sizeof (md_longopts);
    options and on the -m68hc11/-m68hc12 option.  If no option is specified,
    we must get the default.  */
 const char *
-m68hc11_arch_format ()
+m68hc11_arch_format (void)
 {
   get_default_target ();
   if (current_architecture & cpu6811)
@@ -323,7 +336,7 @@ m68hc11_arch_format ()
 }
 
 enum bfd_architecture
-m68hc11_arch ()
+m68hc11_arch (void)
 {
   get_default_target ();
   if (current_architecture & cpu6811)
@@ -333,14 +346,14 @@ m68hc11_arch ()
 }
 
 int
-m68hc11_mach ()
+m68hc11_mach (void)
 {
   return 0;
 }
 
 /* Listing header selected according to cpu.  */
 const char *
-m68hc11_listing_header ()
+m68hc11_listing_header (void)
 {
   if (current_architecture & cpu6811)
     return "M68HC11 GAS ";
@@ -349,13 +362,17 @@ m68hc11_listing_header ()
 }
 
 void
-md_show_usage (stream)
-     FILE *stream;
+md_show_usage (FILE *stream)
 {
   get_default_target ();
   fprintf (stream, _("\
-Motorola 68HC11/68HC12 options:\n\
-  -m68hc11 | -m68hc12     specify the processor [default %s]\n\
+Motorola 68HC11/68HC12/68HCS12 options:\n\
+  -m68hc11 | -m68hc12 |\n\
+  -m68hcs12               specify the processor [default %s]\n\
+  -mshort                 use 16-bit int ABI (default)\n\
+  -mlong                  use 32-bit int ABI\n\
+  -mshort-double          use 32-bit double ABI\n\
+  -mlong-double           use 64-bit double ABI (default)\n\
   --force-long-branchs    always turn relative branchs into absolute ones\n\
   -S,--short-branchs      do not turn relative branchs into absolute ones\n\
                           when the offset is out of range\n\
@@ -370,7 +387,7 @@ Motorola 68HC11/68HC12 options:\n\
 
 /* Try to identify the default target based on the BFD library.  */
 static void
-get_default_target ()
+get_default_target (void)
 {
   const bfd_target *target;
   bfd abfd;
@@ -400,8 +417,7 @@ get_default_target ()
 }
 
 void
-m68hc11_print_statistics (file)
-     FILE *file;
+m68hc11_print_statistics (FILE *file)
 {
   int i;
   struct m68hc11_opcode_def *opc;
@@ -424,9 +440,7 @@ m68hc11_print_statistics (file)
 }
 
 int
-md_parse_option (c, arg)
-     int c;
-     char *arg;
+md_parse_option (int c, char *arg)
 {
   get_default_target ();
   switch (c)
@@ -457,11 +471,29 @@ md_parse_option (c, arg)
       flag_print_opcodes = 2;
       break;
 
+    case OPTION_MSHORT:
+      elf_flags &= ~E_M68HC11_I32;
+      break;
+
+    case OPTION_MLONG:
+      elf_flags |= E_M68HC11_I32;
+      break;
+
+    case OPTION_MSHORT_DOUBLE:
+      elf_flags &= ~E_M68HC11_F64;
+      break;
+
+    case OPTION_MLONG_DOUBLE:
+      elf_flags |= E_M68HC11_F64;
+      break;
+
     case 'm':
       if (strcasecmp (arg, "68hc11") == 0)
        current_architecture = cpu6811;
       else if (strcasecmp (arg, "68hc12") == 0)
        current_architecture = cpu6812;
+      else if (strcasecmp (arg, "68hcs12") == 0)
+       current_architecture = cpu6812 | cpu6812s;
       else
        as_bad (_("Option `%s' is not recognized."), arg);
       break;
@@ -474,8 +506,7 @@ md_parse_option (c, arg)
 }
 \f
 symbolS *
-md_undefined_symbol (name)
-     char *name ATTRIBUTE_UNUSED;
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
 {
   return 0;
 }
@@ -488,10 +519,7 @@ md_undefined_symbol (name)
    of LITTLENUMS emitted is stored in *SIZEP.  An error message is
    returned, or NULL on OK.  */
 char *
-md_atof (type, litP, sizeP)
-     char type;
-     char *litP;
-     int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
 {
   int prec;
   LITTLENUM_TYPE words[MAX_LITTLENUMS];
@@ -542,18 +570,14 @@ md_atof (type, litP, sizeP)
 }
 
 valueT
-md_section_align (seg, addr)
-     asection *seg;
-     valueT addr;
+md_section_align (asection *seg, valueT addr)
 {
   int align = bfd_get_section_alignment (stdoutput, seg);
   return ((addr + (1 << align) - 1) & (-1 << align));
 }
 
 static int
-cmp_opcode (op1, op2)
-     struct m68hc11_opcode *op1;
-     struct m68hc11_opcode *op2;
+cmp_opcode (struct m68hc11_opcode *op1, struct m68hc11_opcode *op2)
 {
   return strcmp (op1->name, op2->name);
 }
@@ -566,7 +590,7 @@ cmp_opcode (op1, op2)
    (sorted on the names) with the M6811 opcode table
    (from opcode library).  */
 void
-md_begin ()
+md_begin (void)
 {
   char *prev_name = "";
   struct m68hc11_opcode *opcodes;
@@ -606,7 +630,8 @@ md_begin ()
              }
        }
     }
-  qsort (opcodes, num_opcodes, sizeof (struct m68hc11_opcode), cmp_opcode);
+  qsort (opcodes, num_opcodes, sizeof (struct m68hc11_opcode),
+         (int (*) (const void*, const void*)) cmp_opcode);
 
   opc = (struct m68hc11_opcode_def *)
     xmalloc (num_opcodes * sizeof (struct m68hc11_opcode_def));
@@ -631,7 +656,7 @@ md_begin ()
          opc->nb_modes = 0;
          opc->opcode = opcodes;
          opc->used = 0;
-         hash_insert (m68hc11_hash, opcodes->name, (char *) opc);
+         hash_insert (m68hc11_hash, opcodes->name, opc);
        }
       opc->nb_modes++;
       opc->format |= opcodes->format;
@@ -669,7 +694,7 @@ md_begin ()
 }
 
 void
-m68hc11_init_after_args ()
+m68hc11_init_after_args (void)
 {
 }
 \f
@@ -679,9 +704,7 @@ m68hc11_init_after_args ()
    When example is true, this generates an example of operand.  This is used
    to give an example and also to generate a test.  */
 static char *
-print_opcode_format (opcode, example)
-     struct m68hc11_opcode *opcode;
-     int example;
+print_opcode_format (struct m68hc11_opcode *opcode, int example)
 {
   static char buf[128];
   int format = opcode->format;
@@ -799,7 +822,7 @@ print_opcode_format (opcode, example)
 
 /* Prints the list of instructions with the possible operands.  */
 static void
-print_opcode_list ()
+print_opcode_list (void)
 {
   int i;
   char *prev_name = "";
@@ -845,8 +868,7 @@ print_opcode_list ()
    instruction is not correct.  Instruction format is printed as an
    error message.  */
 static void
-print_insn_format (name)
-     char *name;
+print_insn_format (char *name)
 {
   struct m68hc11_opcode_def *opc;
   struct m68hc11_opcode *opcode;
@@ -879,8 +901,7 @@ print_insn_format (name)
 /* reg_name_search() finds the register number given its name.
    Returns the register number or REG_NONE on failure.  */
 static register_id
-reg_name_search (name)
-     char *name;
+reg_name_search (char *name)
 {
   if (strcasecmp (name, "x") == 0 || strcasecmp (name, "ix") == 0)
     return REG_X;
@@ -903,8 +924,7 @@ reg_name_search (name)
 }
 
 static char *
-skip_whites (p)
-     char *p;
+skip_whites (char *p)
 {
   while (*p == ' ' || *p == '\t')
     p++;
@@ -915,7 +935,7 @@ skip_whites (p)
 /* Check the string at input_line_pointer
    to see if it is a valid register name.  */
 static register_id
-register_name ()
+register_name (void)
 {
   register_id reg_number;
   char c, *p = input_line_pointer;
@@ -945,6 +965,8 @@ register_name ()
 
   return reg_number;
 }
+#define M6811_OP_CALL_ADDR    0x00800000
+#define M6811_OP_PAGE_ADDR    0x04000000
 
 /* Parse a string of operands and return an array of expressions.
 
@@ -962,10 +984,7 @@ register_name ()
    [D,r]        M6811_OP_D_IDX  M6812_OP_REG  O_register   O_register
    [n,r]        M6811_OP_D_IDX_2 M6812_OP_REG  O_constant   O_register  */
 static int
-get_operand (oper, which, opmode)
-     operand *oper;
-     int which;
-     long opmode;
+get_operand (operand *oper, int which, long opmode)
 {
   char *p = input_line_pointer;
   int mode;
@@ -1010,6 +1029,24 @@ get_operand (oper, which, opmode)
          p += 3;
          mode |= M6811_OP_LOW_ADDR;
        }
+      /* %page modifier is used to obtain only the page number
+         of the address of a function.  */
+      else if (strncmp (p, "%page", 5) == 0)
+       {
+         p += 5;
+         mode |= M6811_OP_PAGE_ADDR;
+       }
+
+      /* %addr modifier is used to obtain the physical address part
+         of the function (16-bit).  For 68HC12 the function will be
+         mapped in the 16K window at 0x8000 and the value will be
+         within that window (although the function address may not fit
+         in 16-bit).  See bfd/elf32-m68hc12.c for the translation.  */
+      else if (strncmp (p, "%addr", 5) == 0)
+       {
+         p += 5;
+         mode |= M6811_OP_CALL_ADDR;
+       }
     }
   else if (*p == '.' && (p[1] == '+' || p[1] == '-'))
     {
@@ -1042,6 +1079,12 @@ get_operand (oper, which, opmode)
       as_bad (_("Spurious `,' or bad indirect register addressing mode."));
       return -1;
     }
+  /* Handle 68HC12 page specification in 'call foo,%page(bar)'.  */
+  else if ((opmode & M6812_OP_PAGE) && strncmp (p, "%page", 5) == 0)
+    {
+      p += 5;
+      mode = M6811_OP_PAGE_ADDR | M6812_OP_PAGE | M6811_OP_IND16;
+    }
   input_line_pointer = p;
 
   if (mode == M6811_OP_NONE || mode == M6812_OP_D_IDX)
@@ -1275,9 +1318,7 @@ get_operand (oper, which, opmode)
 
 /* Checks that the number 'num' fits for a given mode.  */
 static int
-check_range (num, mode)
-     long num;
-     int mode;
+check_range (long num, int mode)
 {
   /* Auto increment and decrement are ok for [-8..8] without 0.  */
   if (mode & M6812_AUTO_INC_DEC)
@@ -1332,10 +1373,7 @@ check_range (num, mode)
 /* Put a 1 byte expression described by 'oper'.  If this expression contains
    unresolved symbols, generate an 8-bit fixup.  */
 static void
-fixup8 (oper, mode, opmode)
-     expressionS *oper;
-     int mode;
-     int opmode;
+fixup8 (expressionS *oper, int mode, int opmode)
 {
   char *f;
 
@@ -1378,16 +1416,24 @@ fixup8 (oper, mode, opmode)
        }
       else
        {
-         /* Now create an 8-bit fixup.  If there was some %hi or %lo
-            modifier, generate the reloc accordingly.  */
-         fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
-                      oper, FALSE,
-                      ((opmode & M6811_OP_HIGH_ADDR)
-                       ? BFD_RELOC_M68HC11_HI8
-                       : ((opmode & M6811_OP_LOW_ADDR)
-                          ? BFD_RELOC_M68HC11_LO8
-                           : ((mode & M6812_OP_PAGE)
-                              ? BFD_RELOC_M68HC11_PAGE : BFD_RELOC_8))));
+         fixS *fixp;
+          int reloc;
+
+         /* Now create an 8-bit fixup.  If there was some %hi, %lo
+            or %page modifier, generate the reloc accordingly.  */
+          if (opmode & M6811_OP_HIGH_ADDR)
+            reloc = BFD_RELOC_M68HC11_HI8;
+          else if (opmode & M6811_OP_LOW_ADDR)
+            reloc = BFD_RELOC_M68HC11_LO8;
+          else if (opmode & M6811_OP_PAGE_ADDR)
+            reloc = BFD_RELOC_M68HC11_PAGE;
+          else
+            reloc = BFD_RELOC_8;
+
+         fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
+                              oper, FALSE, reloc);
+          if (reloc != BFD_RELOC_8)
+            fixp->fx_no_overflow = 1;
        }
       number_to_chars_bigendian (f, 0, 1);
     }
@@ -1400,10 +1446,7 @@ fixup8 (oper, mode, opmode)
 /* Put a 2 byte expression described by 'oper'.  If this expression contains
    unresolved symbols, generate a 16-bit fixup.  */
 static void
-fixup16 (oper, mode, opmode)
-     expressionS *oper;
-     int mode;
-     int opmode ATTRIBUTE_UNUSED;
+fixup16 (expressionS *oper, int mode, int opmode ATTRIBUTE_UNUSED)
 {
   char *f;
 
@@ -1421,18 +1464,27 @@ fixup16 (oper, mode, opmode)
   else if (oper->X_op != O_register)
     {
       fixS *fixp;
+      int reloc;
+
+      if ((opmode & M6811_OP_CALL_ADDR) && (mode & M6811_OP_IMM16))
+        reloc = BFD_RELOC_M68HC11_LO16;
+      else if (mode & M6812_OP_JUMP_REL16)
+        reloc = BFD_RELOC_16_PCREL;
+      else if (mode & M6812_OP_PAGE)
+        reloc = BFD_RELOC_M68HC11_LO16;
+      else
+        reloc = BFD_RELOC_16;
 
       /* Now create a 16-bit fixup.  */
       fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2,
                          oper,
-                         (mode & M6812_OP_JUMP_REL16 ? TRUE : FALSE),
-                         (mode & M6812_OP_JUMP_REL16
-                          ? BFD_RELOC_16_PCREL
-                           : (mode & M6812_OP_PAGE)
-                           ? BFD_RELOC_M68HC11_LO16 : BFD_RELOC_16));
+                         reloc == BFD_RELOC_16_PCREL,
+                          reloc);
       number_to_chars_bigendian (f, 0, 2);
-      if (mode & M6812_OP_JUMP_REL16)
+      if (reloc == BFD_RELOC_16_PCREL)
        fixp->fx_pcrel_adjust = 2;
+      if (reloc == BFD_RELOC_M68HC11_LO16)
+        fixp->fx_no_overflow = 1;
     }
   else
     {
@@ -1443,10 +1495,7 @@ fixup16 (oper, mode, opmode)
 /* Put a 3 byte expression described by 'oper'.  If this expression contains
    unresolved symbols, generate a 24-bit fixup.  */
 static void
-fixup24 (oper, mode, opmode)
-     expressionS *oper;
-     int mode;
-     int opmode ATTRIBUTE_UNUSED;
+fixup24 (expressionS *oper, int mode, int opmode ATTRIBUTE_UNUSED)
 {
   char *f;
 
@@ -1480,8 +1529,7 @@ fixup24 (oper, mode, opmode)
 
 /* Translate the short branch/bsr instruction into a long branch.  */
 static unsigned char
-convert_branch (code)
-     unsigned char code;
+convert_branch (unsigned char code)
 {
   if (IS_OPCODE (code, M6812_BSR))
     return M6812_JSR;
@@ -1499,8 +1547,7 @@ convert_branch (code)
 /* Start a new insn that contains at least 'size' bytes.  Record the
    line information of that insn in the dwarf2 debug sections.  */
 static char *
-m68hc11_new_insn (size)
-     int size;
+m68hc11_new_insn (int size)
 {
   char *f;
 
@@ -1513,11 +1560,8 @@ m68hc11_new_insn (size)
 
 /* Builds a jump instruction (bra, bcc, bsr).  */
 static void
-build_jump_insn (opcode, operands, nb_operands, jmp_mode)
-     struct m68hc11_opcode *opcode;
-     operand operands[];
-     int nb_operands;
-     int jmp_mode;
+build_jump_insn (struct m68hc11_opcode *opcode, operand operands[],
+                 int nb_operands, int jmp_mode)
 {
   unsigned char code;
   char *f;
@@ -1525,7 +1569,7 @@ build_jump_insn (opcode, operands, nb_operands, jmp_mode)
   fragS *frag;
   int where;
 
-  /* The relative branch convertion is not supported for
+  /* The relative branch conversion is not supported for
      brclr and brset.  */
   assert ((opcode->format & M6811_OP_BITMASK) == 0);
   assert (nb_operands == 1);
@@ -1668,17 +1712,14 @@ build_jump_insn (opcode, operands, nb_operands, jmp_mode)
 
 /* Builds a dbne/dbeq/tbne/tbeq instruction.  */
 static void
-build_dbranch_insn (opcode, operands, nb_operands, jmp_mode)
-     struct m68hc11_opcode *opcode;
-     operand operands[];
-     int nb_operands;
-     int jmp_mode;
+build_dbranch_insn (struct m68hc11_opcode *opcode, operand operands[],
+                    int nb_operands, int jmp_mode)
 {
   unsigned char code;
   char *f;
   unsigned long n;
 
-  /* The relative branch convertion is not supported for
+  /* The relative branch conversion is not supported for
      brclr and brset.  */
   assert ((opcode->format & M6811_OP_BITMASK) == 0);
   assert (nb_operands == 2);
@@ -1763,10 +1804,7 @@ build_dbranch_insn (opcode, operands, nb_operands, jmp_mode)
 
 /* Assemble the post index byte for 68HC12 extended addressing modes.  */
 static int
-build_indexed_byte (op, format, move_insn)
-     operand *op;
-     int format ATTRIBUTE_UNUSED;
-     int move_insn;
+build_indexed_byte (operand *op, int format ATTRIBUTE_UNUSED, int move_insn)
 {
   unsigned char byte = 0;
   char *f;
@@ -1901,23 +1939,55 @@ build_indexed_byte (op, format, move_insn)
         }
       else if (op->reg1 != REG_PC)
        {
-         byte = (byte << 3) | 0xe2;
+          symbolS *sym;
+          offsetT off;
+
          f = frag_more (1);
          number_to_chars_bigendian (f, byte, 1);
-
-         f = frag_more (2);
-         fix_new_exp (frag_now, f - frag_now->fr_literal, 2,
-                      &op->exp, FALSE, BFD_RELOC_16);
-         number_to_chars_bigendian (f, 0, 2);
+          sym = op->exp.X_add_symbol;
+          off = op->exp.X_add_number;
+          if (op->exp.X_op != O_symbol)
+            {
+              sym = make_expr_symbol (&op->exp);
+              off = 0;
+            }
+         /* movb/movw cannot be relaxed.  */
+         if (move_insn)
+           {
+             byte <<= 6;
+             number_to_chars_bigendian (f, byte, 1);
+             fix_new (frag_now, f - frag_now->fr_literal, 1,
+                      sym, off, 0, BFD_RELOC_M68HC12_5B);
+             return 1;
+           }
+         else
+           {
+             number_to_chars_bigendian (f, byte, 1);
+             frag_var (rs_machine_dependent, 2, 2,
+                       ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_UNDF),
+                       sym, off, f);
+           }
        }
       else
        {
          f = frag_more (1);
-         number_to_chars_bigendian (f, byte, 1);
-         frag_var (rs_machine_dependent, 2, 2,
-                   ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_UNDF),
-                   op->exp.X_add_symbol,
-                   op->exp.X_add_number, f);
+         /* movb/movw cannot be relaxed.  */
+         if (move_insn)
+           {
+             byte <<= 6;
+             number_to_chars_bigendian (f, byte, 1);
+             fix_new (frag_now, f - frag_now->fr_literal, 1,
+                      op->exp.X_add_symbol, op->exp.X_add_number, 0, BFD_RELOC_M68HC12_5B);
+             return 1;
+           }
+         else
+           {
+             number_to_chars_bigendian (f, byte, 1);
+             frag_var (rs_machine_dependent, 2, 2,
+                       ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_UNDF),
+                       op->exp.X_add_symbol,
+                       op->exp.X_add_number, f);
+           }
        }
       return 3;
     }
@@ -1985,9 +2055,7 @@ build_indexed_byte (op, format, move_insn)
 
 /* Assemble the 68HC12 register mode byte.  */
 static int
-build_reg_mode (op, format)
-     operand *op;
-     int format;
+build_reg_mode (operand *op, int format)
 {
   unsigned char byte;
   char *f;
@@ -2015,30 +2083,23 @@ build_reg_mode (op, format)
 }
 
 /* build_insn takes a pointer to the opcode entry in the opcode table,
-   the array of operand expressions and builds the correspding instruction.
+   the array of operand expressions and builds the corresponding instruction.
    This operation only deals with non relative jumps insn (need special
    handling).  */
 static void
-build_insn (opcode, operands, nb_operands)
-     struct m68hc11_opcode *opcode;
-     operand operands[];
-     int nb_operands ATTRIBUTE_UNUSED;
+build_insn (struct m68hc11_opcode *opcode, operand operands[],
+            int nb_operands ATTRIBUTE_UNUSED)
 {
   int i;
   char *f;
   long format;
   int move_insn = 0;
-  fragS *frag;
-  int where;
 
   /* Put the page code instruction if there is one.  */
   format = opcode->format;
 
-  frag = frag_now;
-  where = frag_now_fix ();
-
   if (format & M6811_OP_BRANCH)
-    fix_new (frag, where, 1,
+    fix_new (frag_now, frag_now_fix (), 1,
              &abs_symbol, 0, 1, BFD_RELOC_M68HC11_RL_JUMP);
 
   if (format & OP_EXTENDED)
@@ -2150,10 +2211,7 @@ build_insn (opcode, operands, nb_operands)
    opcodes with the same name and use the operands to choose the correct
    opcode.  Returns the opcode pointer if there was a match and 0 if none.  */
 static struct m68hc11_opcode *
-find (opc, operands, nb_operands)
-     struct m68hc11_opcode_def *opc;
-     operand operands[];
-     int nb_operands;
+find (struct m68hc11_opcode_def *opc, operand operands[], int nb_operands)
 {
   int i, match, pos;
   struct m68hc11_opcode *opcode;
@@ -2323,10 +2381,8 @@ find (opc, operands, nb_operands)
    Returns the opcode pointer that matches the opcode name in the
    source line and the associated operands.  */
 static struct m68hc11_opcode *
-find_opcode (opc, operands, nb_operands)
-     struct m68hc11_opcode_def *opc;
-     operand operands[];
-     int *nb_operands;
+find_opcode (struct m68hc11_opcode_def *opc, operand operands[],
+             int *nb_operands)
 {
   struct m68hc11_opcode *opcode;
   int i;
@@ -2359,6 +2415,11 @@ find_opcode (opc, operands, nb_operands)
       if (i >= opc->min_operands)
        {
          opcode = find (opc, operands, i);
+
+          /* Another special case for 'call foo,page' instructions.
+             Since we support 'call foo' and 'call foo,page' we must look
+             if the optional page specification is present otherwise we will
+             assemble immediately and treat the page spec as garbage.  */
           if (opcode && !(opcode->format & M6812_OP_PAGE))
              return opcode;
 
@@ -2383,8 +2444,7 @@ find_opcode (opc, operands, nb_operands)
    points to a machine-dependent instruction.  This function is supposed to
    emit the frags/bytes it assembles to.  */
 void
-md_assemble (str)
-     char *str;
+md_assemble (char *str)
 {
   struct m68hc11_opcode_def *opc;
   struct m68hc11_opcode *opcode;
@@ -2549,8 +2609,7 @@ md_assemble (str)
 \f
 /* Pseudo op to control the ELF flags.  */
 static void
-s_m68hc11_mode (x)
-     int x ATTRIBUTE_UNUSED;
+s_m68hc11_mode (int x ATTRIBUTE_UNUSED)
 {
   char *name = input_line_pointer, ch;
 
@@ -2588,8 +2647,7 @@ s_m68hc11_mode (x)
    to invoke them.  This is also used by the debugger to correctly
    find the stack frame.  */
 static void
-s_m68hc11_mark_symbol (mark)
-     int mark;
+s_m68hc11_mark_symbol (int mark)
 {
   char *name;
   int c;
@@ -2630,8 +2688,7 @@ s_m68hc11_mark_symbol (mark)
 }
 
 static void
-s_m68hc11_relax (ignore)
-     int ignore ATTRIBUTE_UNUSED;
+s_m68hc11_relax (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS ex;
 
@@ -2644,7 +2701,7 @@ s_m68hc11_relax (ignore)
       return;
     }
 
-  fix_new_exp (frag_now, frag_now_fix (), 1, &ex, 1,
+  fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1,
                BFD_RELOC_M68HC11_RL_GROUP);
 
   demand_empty_rest_of_line ();
@@ -2657,8 +2714,7 @@ s_m68hc11_relax (ignore)
    next instruction.  That is, the address of the offset, plus its
    size, since the offset is always the last part of the insn.  */
 long
-md_pcrel_from (fixP)
-     fixS *fixP;
+md_pcrel_from (fixS *fixP)
 {
   if (fixP->fx_r_type == BFD_RELOC_M68HC11_RL_JUMP)
     return 0;
@@ -2669,9 +2725,7 @@ md_pcrel_from (fixP)
 /* If while processing a fixup, a reloc really needs to be created
    then it is done here.  */
 arelent *
-tc_gen_reloc (section, fixp)
-     asection *section;
-     fixS *fixp;
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
 {
   arelent *reloc;
 
@@ -2700,11 +2754,101 @@ tc_gen_reloc (section, fixp)
   return reloc;
 }
 
+/* We need a port-specific relaxation function to cope with sym2 - sym1
+   relative expressions with both symbols in the same segment (but not
+   necessarily in the same frag as this insn), for example:
+     ldab sym2-(sym1-2),pc
+    sym1:
+   The offset can be 5, 9 or 16 bits long.  */
+
+long
+m68hc11_relax_frag (segT seg ATTRIBUTE_UNUSED, fragS *fragP,
+                    long stretch ATTRIBUTE_UNUSED)
+{
+  long growth;
+  offsetT aim = 0;
+  symbolS *symbolP;
+  const relax_typeS *this_type;
+  const relax_typeS *start_type;
+  relax_substateT next_state;
+  relax_substateT this_state;
+  const relax_typeS *table = TC_GENERIC_RELAX_TABLE;
+
+  /* We only have to cope with frags as prepared by
+     md_estimate_size_before_relax.  The STATE_BITS16 case may geet here
+     because of the different reasons that it's not relaxable.  */
+  switch (fragP->fr_subtype)
+    {
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS16):
+    case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS16):
+      /* When we get to this state, the frag won't grow any more.  */
+      return 0;
+
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS5):
+    case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS5):
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS9):
+    case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS9):
+      if (fragP->fr_symbol == NULL
+         || S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+       as_fatal (_("internal inconsistency problem in %s: fr_symbol %lx"),
+                 __FUNCTION__, (long) fragP->fr_symbol);
+      symbolP = fragP->fr_symbol;
+      if (symbol_resolved_p (symbolP))
+       as_fatal (_("internal inconsistency problem in %s: resolved symbol"),
+                 __FUNCTION__);
+      aim = S_GET_VALUE (symbolP);
+      break;
+
+    default:
+      as_fatal (_("internal inconsistency problem in %s: fr_subtype %d"),
+                 __FUNCTION__, fragP->fr_subtype);
+    }
+
+  /* The rest is stolen from relax_frag.  There's no obvious way to
+     share the code, but fortunately no requirement to keep in sync as
+     long as fragP->fr_symbol does not have its segment changed.  */
+
+  this_state = fragP->fr_subtype;
+  start_type = this_type = table + this_state;
+
+  if (aim < 0)
+    {
+      /* Look backwards.  */
+      for (next_state = this_type->rlx_more; next_state;)
+       if (aim >= this_type->rlx_backward)
+         next_state = 0;
+       else
+         {
+           /* Grow to next state.  */
+           this_state = next_state;
+           this_type = table + this_state;
+           next_state = this_type->rlx_more;
+         }
+    }
+  else
+    {
+      /* Look forwards.  */
+      for (next_state = this_type->rlx_more; next_state;)
+       if (aim <= this_type->rlx_forward)
+         next_state = 0;
+       else
+         {
+           /* Grow to next state.  */
+           this_state = next_state;
+           this_type = table + this_state;
+           next_state = this_type->rlx_more;
+         }
+    }
+
+  growth = this_type->rlx_length - start_type->rlx_length;
+  if (growth != 0)
+    fragP->fr_subtype = this_state;
+  return growth;
+}
+
 void
-md_convert_frag (abfd, sec, fragP)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     asection *sec ATTRIBUTE_UNUSED;
-     fragS *fragP;
+md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec ATTRIBUTE_UNUSED,
+                 fragS *fragP)
 {
   fixS *fixp;
   long value;
@@ -2766,31 +2910,44 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_fix += 2;
       break;
 
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS5):
+      if (fragP->fr_symbol != 0
+          && S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+        value = disp;
+      /* fall through  */
+
     case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS5):
       fragP->fr_opcode[0] = fragP->fr_opcode[0] << 6;
-      if ((fragP->fr_opcode[0] & 0x0ff) == 0x0c0)
-       fragP->fr_opcode[0] |= disp & 0x1f;
-      else
-       fragP->fr_opcode[0] |= value & 0x1f;
+      fragP->fr_opcode[0] |= value & 0x1f;
       break;
 
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS9):
+      /* For a PC-relative offset, use the displacement with a -1 correction
+         to take into account the additional byte of the insn.  */
+      if (fragP->fr_symbol != 0
+          && S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+        value = disp - 1;
+      /* fall through  */
+
     case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS9):
       fragP->fr_opcode[0] = (fragP->fr_opcode[0] << 3);
       fragP->fr_opcode[0] |= 0xE0;
-      fix_new (fragP, fragP->fr_fix, 1,
-              fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_8);
+      fragP->fr_opcode[0] |= (value >> 8) & 1;
+      fragP->fr_opcode[1] = value;
       fragP->fr_fix += 1;
       break;
 
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS16):
     case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS16):
       fragP->fr_opcode[0] = (fragP->fr_opcode[0] << 3);
       fragP->fr_opcode[0] |= 0xe2;
-      if ((fragP->fr_opcode[0] & 0x0ff) == 0x0fa)
+      if ((fragP->fr_opcode[0] & 0x0ff) == 0x0fa
+          && fragP->fr_symbol != 0
+          && S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
        {
          fixp = fix_new (fragP, fragP->fr_fix, 2,
                          fragP->fr_symbol, fragP->fr_offset,
                          1, BFD_RELOC_16_PCREL);
-         fixp->fx_pcrel_adjust = 2;
        }
       else
        {
@@ -2827,8 +2984,7 @@ md_convert_frag (abfd, sec, fragP)
    relax externally visible symbol because there is no shared library
    and such symbol can't be overridden (unless they are weak).  */
 static int
-relaxable_symbol (symbol)
-     symbolS *symbol;
+relaxable_symbol (symbolS *symbol)
 {
   return ! S_IS_WEAK (symbol);
 }
@@ -2836,14 +2992,14 @@ relaxable_symbol (symbol)
 /* Force truly undefined symbols to their maximum size, and generally set up
    the frag list to be relaxed.  */
 int
-md_estimate_size_before_relax (fragP, segment)
-     fragS *fragP;
-     asection *segment;
+md_estimate_size_before_relax (fragS *fragP, asection *segment)
 {
   if (RELAX_LENGTH (fragP->fr_subtype) == STATE_UNDF)
     {
       if (S_GET_SEGMENT (fragP->fr_symbol) != segment
-         || !relaxable_symbol (fragP->fr_symbol))
+         || !relaxable_symbol (fragP->fr_symbol)
+          || (segment != absolute_section
+              && RELAX_STATE (fragP->fr_subtype) == STATE_INDEXED_OFFSET))
        {
          /* Non-relaxable cases.  */
          int old_fr_fix;
@@ -2895,13 +3051,46 @@ md_estimate_size_before_relax (fragP, segment)
            case STATE_INDEXED_OFFSET:
              assert (current_architecture & cpu6812);
 
-             /* Switch the indexed operation to 16-bit mode.  */
-             fragP->fr_opcode[0] = fragP->fr_opcode[0] << 3;
-             fragP->fr_opcode[0] |= 0xe2;
-             fragP->fr_fix++;
-             fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-                      fragP->fr_offset, 0, BFD_RELOC_16);
-             fragP->fr_fix++;
+              if (fragP->fr_symbol
+                  && S_GET_SEGMENT (fragP->fr_symbol) == absolute_section)
+                {
+                   fragP->fr_subtype = ENCODE_RELAX (STATE_INDEXED_OFFSET,
+                                                     STATE_BITS5);
+                   /* Return the size of the variable part of the frag. */
+                   return md_relax_table[fragP->fr_subtype].rlx_length;
+                }
+              else
+                {
+                   /* Switch the indexed operation to 16-bit mode.  */
+                   fragP->fr_opcode[0] = fragP->fr_opcode[0] << 3;
+                   fragP->fr_opcode[0] |= 0xe2;
+                   fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
+                            fragP->fr_offset, 0, BFD_RELOC_16);
+                   fragP->fr_fix += 2;
+                }
+             break;
+
+           case STATE_INDEXED_PCREL:
+             assert (current_architecture & cpu6812);
+
+              if (fragP->fr_symbol
+                  && S_GET_SEGMENT (fragP->fr_symbol) == absolute_section)
+                {
+                   fragP->fr_subtype = ENCODE_RELAX (STATE_INDEXED_PCREL,
+                                                     STATE_BITS5);
+                   /* Return the size of the variable part of the frag. */
+                   return md_relax_table[fragP->fr_subtype].rlx_length;
+                }
+              else
+                {
+                   fixS* fixp;
+
+                   fragP->fr_opcode[0] = fragP->fr_opcode[0] << 3;
+                   fragP->fr_opcode[0] |= 0xe2;
+                   fixp = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
+                                   fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
+                   fragP->fr_fix += 2;
+                }
              break;
 
            case STATE_XBCC_BRANCH:
@@ -2967,6 +3156,13 @@ md_estimate_size_before_relax (fragP, segment)
                                            STATE_BITS5);
          break;
 
+       case STATE_INDEXED_PCREL:
+         assert (current_architecture & cpu6812);
+
+         fragP->fr_subtype = ENCODE_RELAX (STATE_INDEXED_PCREL,
+                                           STATE_BITS5);
+         break;
+
        case STATE_XBCC_BRANCH:
          assert (current_architecture & cpu6812);
 
@@ -2991,21 +3187,12 @@ md_estimate_size_before_relax (fragP, segment)
 
 /* See whether we need to force a relocation into the output file.  */
 int
-tc_m68hc11_force_relocation (fixP)
-     fixS * fixP;
+tc_m68hc11_force_relocation (fixS *fixP)
 {
-  switch (fixP->fx_r_type)
-    {
-    case BFD_RELOC_VTABLE_INHERIT:
-    case BFD_RELOC_VTABLE_ENTRY:
-    case BFD_RELOC_M68HC11_RL_GROUP:
-      return 1;
-
-    default:
-      break;
-    }
+  if (fixP->fx_r_type == BFD_RELOC_M68HC11_RL_GROUP)
+    return 1;
 
-  return S_FORCE_RELOC (fixP->fx_addsy);
+  return generic_force_reloc (fixP);
 }
 
 /* Here we decide which fixups can be adjusted to make them relative
@@ -3014,32 +3201,33 @@ tc_m68hc11_force_relocation (fixP)
    correctly, so in some cases we force the original symbol to be
    used.  */
 int
-tc_m68hc11_fix_adjustable (fixP)
-     fixS *fixP;
+tc_m68hc11_fix_adjustable (fixS *fixP)
 {
   switch (fixP->fx_r_type)
     {
       /* For the linker relaxation to work correctly, these relocs
          need to be on the symbol itself.  */
     case BFD_RELOC_16:
-    case BFD_RELOC_LO16:
     case BFD_RELOC_M68HC11_RL_JUMP:
     case BFD_RELOC_M68HC11_RL_GROUP:
     case BFD_RELOC_VTABLE_INHERIT:
     case BFD_RELOC_VTABLE_ENTRY:
+    case BFD_RELOC_32:
+
+      /* The memory bank addressing translation also needs the original
+         symbol.  */
+    case BFD_RELOC_M68HC11_LO16:
+    case BFD_RELOC_M68HC11_PAGE:
+    case BFD_RELOC_M68HC11_24:
       return 0;
 
-    case BFD_RELOC_32:
     default:
       return 1;
     }
 }
 
 void
-md_apply_fix3 (fixP, valP, seg)
-     fixS *fixP;
-     valueT *valP;
-     segT seg ATTRIBUTE_UNUSED;
+md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 {
   char *where;
   long value = * valP;
@@ -3124,6 +3312,17 @@ md_apply_fix3 (fixP, valP, seg)
       where[0] = where[0] | (value & 0x07);
       break;
 
+    case BFD_RELOC_M68HC12_5B:
+      if (value < -16 || value > 15)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     _("Offset out of 5-bit range for movw/movb insn: %ld"),
+                     value);
+      if (value >= 0)
+       where[0] |= value;
+      else 
+       where[0] |= (0x10 | (16 + value));
+      break;
+
     case BFD_RELOC_M68HC11_RL_JUMP:
     case BFD_RELOC_M68HC11_RL_GROUP:
     case BFD_RELOC_VTABLE_INHERIT:
@@ -3139,8 +3338,10 @@ md_apply_fix3 (fixP, valP, seg)
 
 /* Set the ELF specific flags.  */
 void
-m68hc11_elf_final_processing ()
+m68hc11_elf_final_processing (void)
 {
+  if (current_architecture & cpu6812s)
+    elf_flags |= EF_M68HCS12_MACH;
   elf_elfheader (stdoutput)->e_flags &= ~EF_M68HC11_ABI;
   elf_elfheader (stdoutput)->e_flags |= elf_flags;
 }
This page took 0.03643 seconds and 4 git commands to generate.