* doc/as.texinfo (Reloc): Document.
authorAlan Modra <amodra@gmail.com>
Mon, 26 Mar 2007 12:23:48 +0000 (12:23 +0000)
committerAlan Modra <amodra@gmail.com>
Mon, 26 Mar 2007 12:23:48 +0000 (12:23 +0000)
* read.c (potable): Add "reloc".
(s_reloc): New function.
* write.c (reloc_list): New global var.
(resolve_reloc_expr_symbols): New function.
(write_object_file): Call it.
(write_relocs): Process reloc_list.
* write.h (struct reloc_list): New.
(reloc_list): Declare.

gas/ChangeLog
gas/doc/as.texinfo
gas/read.c
gas/write.c
gas/write.h

index 8b9bf90..bcddbf1 100644 (file)
@@ -1,3 +1,15 @@
+2007-03-26  Alan Modra  <amodra@bigpond.net.au>
+
+       * doc/as.texinfo (Reloc): Document.
+       * read.c (potable): Add "reloc".
+       (s_reloc): New function.
+       * write.c (reloc_list): New global var.
+       (resolve_reloc_expr_symbols): New function.
+       (write_object_file): Call it.
+       (write_relocs): Process reloc_list.
+       * write.h (struct reloc_list): New.
+       (reloc_list): Declare.
+
 2007-03-24  Paul Brook  <paul@codesourcery.com>
 
        * config/tc-arm.c (do_t_ldmstm): Error on Thumb-2 addressing modes.
index 41c80a9..01f2bf8 100644 (file)
@@ -3886,6 +3886,7 @@ Some machine configurations provide additional directives.
 @end ifset
 
 * Quad::                        @code{.quad @var{bignums}}
+* Reloc::                      @code{.reloc @var{offset}, @var{reloc_name}[, @var{expression}]}
 * Rept::                       @code{.rept @var{count}}
 * Sbttl::                       @code{.sbttl "@var{subheading}"}
 @ifset COFF
@@ -5433,6 +5434,20 @@ warning message; and just takes the lowest order 16 bytes of the bignum.
 @cindex integer, 16-byte
 @end ifset
 
+@node Reloc
+@section @code{.reloc @var{offset}, @var{reloc_name}[, @var{expression}]}
+
+@cindex @code{reloc} directive
+Generate a relocation at @var{offset} of type @var{reloc_name} with value
+@var{expression}.  If @var{offset} is a number, the relocation is generated in
+the current section.  If @var{offset} is an expression that resolves to a
+symbol plus offset, the relocation is generated in the given symbol's section.
+@var{expression}, if present, must resolve to a symbol plus addend or to an
+absolute value, but note that not all targets support an addend.  e.g. ELF REL
+targets such as i386 store an addend in the section contents rather than in the
+relocation.  This low level interface does not support addends stored in the
+section.
+
 @node Rept
 @section @code{.rept @var{count}}
 
index c622eb2..5782f23 100644 (file)
@@ -213,6 +213,7 @@ static void do_align (int, char *, int, int);
 static void s_align (int, int);
 static void s_altmacro (int);
 static void s_bad_end (int);
+static void s_reloc (int);
 static int hex_float (int, char *);
 static segT get_known_segmented_expression (expressionS * expP);
 static void pobegin (void);
@@ -391,6 +392,7 @@ static const pseudo_typeS potable[] = {
   {"psize", listing_psize, 0}, /* Set paper size.  */
   {"purgem", s_purgem, 0},
   {"quad", cons, 8},
+  {"reloc", s_reloc, 0},
   {"rep", s_rept, 0},
   {"rept", s_rept, 0},
   {"rva", s_rva, 4},
@@ -3669,6 +3671,113 @@ s_rva (int size)
   cons_worker (size, 1);
 }
 
+/* .reloc offset, reloc_name, symbol+addend.  */
+
+void
+s_reloc (int ignore ATTRIBUTE_UNUSED)
+{
+  char *stop = NULL;
+  char stopc = 0;
+  expressionS exp;
+  char *r_name;
+  int c;
+  struct reloc_list *reloc;
+
+  reloc = xmalloc (sizeof (*reloc));
+
+  if (flag_mri)
+    stop = mri_comment_field (&stopc);
+
+  expression (&exp);
+  switch (exp.X_op)
+    {
+    case O_illegal:
+    case O_absent:
+    case O_big:
+    case O_register:
+      as_bad (_("missing or bad offset expression"));
+      goto err_out;
+    case O_constant:
+      exp.X_add_symbol = section_symbol (now_seg);
+      exp.X_op = O_symbol;
+      /* Fall thru */
+    case O_symbol:
+      if (exp.X_add_number == 0)
+       {
+         reloc->u.a.offset_sym = exp.X_add_symbol;
+         break;
+       }
+      /* Fall thru */
+    default:
+      reloc->u.a.offset_sym = make_expr_symbol (&exp);
+      break;
+    }
+
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer != ',')
+    {
+      as_bad (_("missing reloc type"));
+      goto err_out;
+    }
+
+  ++input_line_pointer;
+  SKIP_WHITESPACE ();
+  r_name = input_line_pointer;
+  c = get_symbol_end ();
+  reloc->u.a.howto = bfd_reloc_name_lookup (stdoutput, r_name);
+  *input_line_pointer = c;
+  if (reloc->u.a.howto == NULL)
+    {
+      as_bad (_("unrecognized reloc type"));
+      goto err_out;
+    }
+
+  exp.X_op = O_absent;
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == ',')
+    {
+      ++input_line_pointer;
+      expression_and_evaluate (&exp);
+    }
+  switch (exp.X_op)
+    {
+    case O_illegal:
+    case O_big:
+    case O_register:
+      as_bad (_("bad reloc expression"));
+    err_out:
+      ignore_rest_of_line ();
+      free (reloc);
+      if (flag_mri)
+       mri_comment_end (stop, stopc);
+      return;
+    case O_absent:
+      reloc->u.a.sym = NULL;
+      reloc->u.a.addend = 0;
+      break;
+    case O_constant:
+      reloc->u.a.sym = NULL;
+      reloc->u.a.addend = exp.X_add_number;
+      break;
+    case O_symbol:
+      reloc->u.a.sym = exp.X_add_symbol;
+      reloc->u.a.addend = exp.X_add_number;
+      break;
+    default:
+      reloc->u.a.sym = make_expr_symbol (&exp);
+      reloc->u.a.addend = 0;
+      break;
+    }
+
+  as_where (&reloc->file, &reloc->line);
+  reloc->next = reloc_list;
+  reloc_list = reloc;
+
+  demand_empty_rest_of_line ();
+  if (flag_mri)
+    mri_comment_end (stop, stopc);
+}
+
 /* Put the contents of expression EXP into the object file using
    NBYTES bytes.  If need_pass_2 is 1, this does nothing.  */
 
index df858a3..29ea284 100644 (file)
@@ -117,6 +117,9 @@ symbolS *abs_section_sym;
 /* Remember the value of dot when parsing expressions.  */
 addressT dot_value;
 
+/* Relocs generated by ".reloc" pseudo.  */
+struct reloc_list* reloc_list;
+
 void print_fixup (fixS *);
 
 /* We generally attach relocs to frag chains.  However, after we have
@@ -624,6 +627,86 @@ dump_section_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, FILE *stream)
 #define EMIT_SECTION_SYMBOLS 1
 #endif
 
+/* Resolve U.A.OFFSET_SYM and U.A.SYM fields of RELOC_LIST entries,
+   and check for validity.  Convert RELOC_LIST from using U.A fields
+   to U.B fields.  */
+static void
+resolve_reloc_expr_symbols (void)
+{
+  struct reloc_list *r;
+
+  for (r = reloc_list; r; r = r->next)
+    {
+      expressionS *symval;
+      symbolS *sym;
+      bfd_vma offset, addend;
+      asection *sec;
+      reloc_howto_type *howto;
+
+      resolve_symbol_value (r->u.a.offset_sym);
+      symval = symbol_get_value_expression (r->u.a.offset_sym);
+
+      offset = 0;
+      sym = NULL;
+      if (symval->X_op == O_constant)
+       sym = r->u.a.offset_sym;
+      else if (symval->X_op == O_symbol)
+       {
+         sym = symval->X_add_symbol;
+         offset = symval->X_add_number;
+         symval = symbol_get_value_expression (symval->X_add_symbol);
+       }
+      if (sym == NULL
+         || symval->X_op != O_constant
+         || (sec = S_GET_SEGMENT (sym)) == NULL
+         || !SEG_NORMAL (sec))
+       {
+         as_bad_where (r->file, r->line, _("invalid offset expression"));
+         sec = NULL;
+       }
+      else
+       offset += S_GET_VALUE (sym);
+
+      sym = NULL;
+      addend = r->u.a.addend;
+      if (r->u.a.sym != NULL)
+       {
+         resolve_symbol_value (r->u.a.sym);
+         symval = symbol_get_value_expression (r->u.a.sym);
+         if (symval->X_op == O_constant)
+           sym = r->u.a.sym;
+         else if (symval->X_op == O_symbol)
+           {
+             sym = symval->X_add_symbol;
+             addend += symval->X_add_number;
+             symval = symbol_get_value_expression (symval->X_add_symbol);
+           }
+         if (symval->X_op != O_constant)
+           {
+             as_bad_where (r->file, r->line, _("invalid reloc expression"));
+             sec = NULL;
+           }
+         else if (sym != NULL)
+           symbol_mark_used_in_reloc (sym);
+       }
+      if (sym == NULL)
+       {
+         if (abs_section_sym == NULL)
+           abs_section_sym = section_symbol (absolute_section);
+         sym = abs_section_sym;
+       }
+
+      howto = r->u.a.howto;
+
+      r->u.b.sec = sec;
+      r->u.b.s = symbol_get_bfdsym (sym);
+      r->u.b.r.sym_ptr_ptr = &r->u.b.s;
+      r->u.b.r.address = offset;
+      r->u.b.r.addend = addend;
+      r->u.b.r.howto = howto;
+    }
+}
+
 /* This pass over fixups decides whether symbols can be replaced with
    section symbols.  */
 
@@ -1027,6 +1110,7 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   segment_info_type *seginfo = seg_info (sec);
   unsigned int i;
   unsigned int n;
+  struct reloc_list *my_reloc_list, **rp, *r;
   arelent **relocs;
   fixS *fixp;
 
@@ -1044,6 +1128,22 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   n *= MAX_RELOC_EXPANSION;
 #endif
 
+  /* Extract relocs for this section from reloc_list.  */
+  rp = &reloc_list;
+  my_reloc_list = NULL;
+  while ((r = *rp) != NULL)
+    {
+      if (r->u.b.sec == sec)
+       {
+         *rp = r->next;
+         r->next = my_reloc_list;
+         my_reloc_list = r;
+         n++;
+       }
+      else
+       rp = &r->next;
+    }
+
   relocs = xcalloc (n, sizeof (arelent *));
 
   i = 0;
@@ -1107,6 +1207,23 @@ write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   }
 #endif
 
+  for (r = my_reloc_list; r != NULL; r = r->next)
+    {
+      fragS *f;
+      for (f = seginfo->frchainP->frch_root; f; f = f->fr_next)
+       if (f->fr_address <= r->u.b.r.address
+           && r->u.b.r.address < f->fr_address + f->fr_fix)
+         break;
+      if (f == NULL)
+       as_bad_where (r->file, r->line,
+                     _("reloc not within (fixed part of) section"));
+      else
+       {
+         relocs[n++] = &r->u.b.r;
+         install_reloc (sec, &r->u.b.r, f, r->file, r->line);
+       }
+    }
+
   if (n)
     {
       flagword flags = bfd_get_section_flags (abfd, sec);
@@ -1564,6 +1681,7 @@ write_object_file (void)
        resolve_symbol_value (symp);
     }
   resolve_local_symbol_values ();
+  resolve_reloc_expr_symbols ();
 
   PROGRESS (1);
 
index 6e691a2..2cc1bdd 100644 (file)
@@ -142,11 +142,35 @@ struct fix
 
 typedef struct fix fixS;
 
+struct reloc_list
+{
+  struct reloc_list *next;
+  union
+  {
+    struct
+    {
+      symbolS *offset_sym;
+      reloc_howto_type *howto;
+      symbolS *sym;
+      bfd_vma addend;
+    } a;
+    struct
+    {
+      asection *sec;
+      asymbol *s;
+      arelent r;
+    } b;
+  } u;
+  char *file;
+  unsigned int line;
+};
+
 extern int finalize_syms;
 extern symbolS *abs_section_sym;
 extern addressT dot_value;
 extern long string_byte_count;
 extern int section_alignment[];
+extern struct reloc_list* reloc_list;
 
 extern void append (char **charPP, char *fromP, unsigned long length);
 extern void record_alignment (segT seg, int align);