diff options
Diffstat (limited to 'gas/write.c')
-rw-r--r-- | gas/write.c | 118 |
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); |