aboutsummaryrefslogtreecommitdiff
path: root/gas/write.c
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@cygnus>1994-09-28 19:20:11 +0000
committerKen Raeburn <raeburn@cygnus>1994-09-28 19:20:11 +0000
commit4acf8c78e659833be8be047ba2f8561386a11d4b (patch)
treece05f1293027e5803305ec74c71e239ad70b9306 /gas/write.c
parent648acaa0c0427463876773336c87af4d18be8a76 (diff)
downloadfsf-binutils-gdb-4acf8c78e659833be8be047ba2f8561386a11d4b.zip
fsf-binutils-gdb-4acf8c78e659833be8be047ba2f8561386a11d4b.tar.gz
fsf-binutils-gdb-4acf8c78e659833be8be047ba2f8561386a11d4b.tar.bz2
(fix_new_exp): Handle O_add by creating an expression-valued symbol, and
calling fix_new_exp recursively. (adjust_reloc_syms): If a fixup's symbol value is a sum of an undefined symbol and a constant, fold the constant into the fixup, and refer to the undefined symbol directly. Then process the fixup again from scratch. (write_object_file): Before calling adjust_reloc_syms, make a pass through the symbol list trying to resolve values. (print_fixup): New routine, for debugging. (write_relocs): Call bfd_install_relocation. Deleted various hacks for working around problems with bfd_perform_relocation.
Diffstat (limited to 'gas/write.c')
-rw-r--r--gas/write.c118
1 files changed, 98 insertions, 20 deletions
diff --git a/gas/write.c b/gas/write.c
index 8004ef7..6c109a3 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -232,6 +232,19 @@ fix_new_exp (frag, where, size, exp, pcrel, r_type)
case O_absent:
break;
+ case O_add:
+ /* This comes up when _GLOBAL_OFFSET_TABLE_+(.-L0) is read, if
+ the difference expression cannot immediately be reduced. */
+ {
+ extern symbolS *make_expr_symbol ();
+ symbolS *stmp = make_expr_symbol (exp);
+ exp->X_op = O_symbol;
+ exp->X_op_symbol = 0;
+ exp->X_add_symbol = stmp;
+ exp->X_add_number = 0;
+ return fix_new_exp (frag, where, size, exp, pcrel, r_type);
+ }
+
case O_uminus:
sub = exp->X_add_symbol;
off = exp->X_add_number;
@@ -573,7 +586,11 @@ adjust_reloc_syms (abfd, sec, xxx)
else if (fixp->fx_addsy)
{
symbolS *sym = fixp->fx_addsy;
- asection *symsec = sym->bsym->section;
+ asection *symsec;
+
+ reduce_fixup:
+
+ symsec = sym->bsym->section;
/* If it's one of these sections, assume the symbol is
definitely going to be output. The code in
@@ -617,6 +634,27 @@ adjust_reloc_syms (abfd, sec, xxx)
}
#endif
+ /* For PIC support: We may get expressions like
+ "_GLOBAL_OFFSET_TABLE_+(.-L5)" where "." and "L5" may not
+ necessarily have had a fixed difference initially. But now
+ it should be a known constant, so we can reduce it. Since
+ we can't easily handle a symbol value that looks like
+ someUndefinedSymbol+const, though, we convert the fixup to
+ access the undefined symbol directly, and discard the
+ intermediate symbol. */
+ if (S_GET_SEGMENT (sym) == expr_section
+ && sym->sy_value.X_op == O_add
+ && (resolve_symbol_value (sym->sy_value.X_add_symbol),
+ S_GET_SEGMENT (sym->sy_value.X_add_symbol) == undefined_section)
+ && (resolve_symbol_value (sym->sy_value.X_op_symbol),
+ S_GET_SEGMENT (sym->sy_value.X_op_symbol) == absolute_section))
+ {
+ fixp->fx_offset += S_GET_VALUE (sym->sy_value.X_op_symbol);
+ fixp->fx_offset += sym->sy_value.X_add_number;
+ fixp->fx_addsy = sym = sym->sy_value.X_add_symbol;
+ goto reduce_fixup;
+ }
+
/* If the section symbol isn't going to be output, the relocs
at least should still work. If not, figure out what to do
when we run into that case. */
@@ -676,7 +714,6 @@ write_relocs (abfd, sec, xxx)
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
{
arelent *reloc;
- char *data;
bfd_reloc_status_type s;
if (fixp->fx_done)
@@ -690,24 +727,14 @@ write_relocs (abfd, sec, xxx)
n--;
continue;
}
- data = fixp->fx_frag->fr_literal + fixp->fx_where;
if (fixp->fx_where + fixp->fx_size
> fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
abort ();
- if (reloc->howto->partial_inplace == false
- && reloc->howto->pcrel_offset == true
- && reloc->howto->pc_relative == true)
- {
- /* bfd_perform_relocation screws this up */
- reloc->addend += reloc->address;
- }
- /* Pass bogus address so that when bfd_perform_relocation adds
- `reloc->address' back in, it'll come up with `data', which is where
- we want it to operate. We can't just do it by fudging reloc->address,
- since that might be used in the calculations(?). */
- s = bfd_perform_relocation (stdoutput, reloc, data - reloc->address,
- sec, stdoutput, &err);
+ s = bfd_install_relocation (stdoutput, reloc,
+ fixp->fx_frag->fr_literal,
+ fixp->fx_frag->fr_address,
+ sec, &err);
switch (s)
{
case bfd_reloc_ok:
@@ -716,7 +743,8 @@ write_relocs (abfd, sec, xxx)
as_bad_where (fixp->fx_file, fixp->fx_line, "relocation overflow");
break;
default:
- as_fatal ("bad return from bfd_perform_relocation");
+ as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+ fixp->fx_file, fixp->fx_line);
}
relocs[i++] = reloc;
}
@@ -759,8 +787,13 @@ write_relocs (abfd, sec, xxx)
{
case bfd_reloc_ok:
break;
+ case bfd_reloc_overflow:
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ "relocation overflow");
+ break;
default:
- as_fatal ("bad return from bfd_perform_relocation");
+ as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+ fixp->fx_file, fixp->fx_line);
}
}
}
@@ -843,7 +876,7 @@ write_contents (abfd, sec, xxx)
{
bfd_perror (stdoutput->filename);
as_perror ("FATAL: Can't write %s", stdoutput->filename);
- exit (42);
+ exit (EXIT_FAILURE);
}
offset += f->fr_fix;
}
@@ -866,7 +899,7 @@ write_contents (abfd, sec, xxx)
{
bfd_perror (stdoutput->filename);
as_perror ("FATAL: Can't write %s", stdoutput->filename);
- exit (42);
+ exit (EXIT_FAILURE);
}
offset += fill_size;
}
@@ -1464,6 +1497,17 @@ write_object_file ()
#endif /* VMS */
#else /* BFD_ASSEMBLER */
+ /* Resolve symbol values. This needs to be done before processing
+ the relocations. */
+ if (symbol_rootP)
+ {
+ symbolS *symp;
+
+ for (symp = symbol_rootP; symp; symp = symbol_next (symp))
+ if (!symp->sy_resolved)
+ resolve_symbol_value (symp);
+ }
+
bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *)0);
/* Set up symbol table, and write it out. */
@@ -1475,6 +1519,9 @@ write_object_file ()
{
int punt = 0;
+ /* Do it again, because adjust_reloc_syms might introduce
+ more symbols. They'll probably only be section symbols,
+ but they'll still need to have the values computed. */
if (! symp->sy_resolved)
{
if (symp->sy_value.X_op == O_constant)
@@ -2299,4 +2346,35 @@ number_to_chars_littleendian (buf, val, n)
}
}
+/* for debugging */
+extern int indent_level;
+
+void
+print_fixup (fixp)
+ fixS *fixp;
+{
+ indent_level = 1;
+ fprintf (stderr, "fix");
+ if (fixp->fx_pcrel)
+ fprintf (stderr, " pcrel");
+ if (fixp->fx_pcrel_adjust)
+ fprintf (stderr, " pcrel_adjust=%d", fixp->fx_pcrel_adjust);
+ if (fixp->fx_im_disp)
+ {
+#ifdef TC_NS32K
+ fprintf (stderr, " im_disp=%d", fixp->fx_im_disp);
+#else
+ fprintf (stderr, " im_disp");
+#endif
+ }
+ if (fixp->fx_tcbit)
+ fprintf (stderr, " tcbit");
+ if (fixp->fx_done)
+ fprintf (stderr, " done");
+ fprintf (stderr, "\n %s:%d", fixp->fx_file, fixp->fx_line);
+ fprintf (stderr, "\n size=%d frag=%lx where=%ld addnumber=%lx",
+ fixp->fx_size, (long) fixp->fx_frag, fixp->fx_where,
+ (long) fixp->fx_addnumber);
+}
+
/* end of write.c */