aboutsummaryrefslogtreecommitdiff
path: root/gas/write.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/write.c')
-rw-r--r--gas/write.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/gas/write.c b/gas/write.c
index df858a3..29ea284 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -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);