(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.
This commit is contained in:
parent
648acaa0c0
commit
4acf8c78e6
1 changed files with 98 additions and 20 deletions
118
gas/write.c
118
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 */
|
||||
|
|
Loading…
Reference in a new issue