This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: bfin, h8300, mmix, sh, stormy lax in fixup size
Some more tidying of the gas reloc handling code, and a bug fix for
the test whether a fixup is fully contained within a frag. When this
code runs, all frags have been converted to rs_fill type. rs_fill
frags have fr_fix bytes of data at fr_literal, followed by fr_var
bytes of fill pattern. The fill pattern is repeated fr_offset times.
Now, we can only install relocs into fr_literal, ie. fr_fix + fr_var
bytes, so testing for a reloc within fr_fix + fr_offset is totally
bogus. The correct test, if we want to allow relocs in the fill
pattern, would be fr_fix + fr_var, but I don't think it makes much
sense to allow relocs in the fill pattern. So just test that the
reloc is contained within fr_fix bytes.
BTW, the reason I'm looking at this code is that I intend to add
a low level means of emitting relocations in gas. Something like
.reloc offset, reloc_name, symbol+addend
eg.
.reloc __speelf__+50, R_PPC_ADDR32, stdout
The particular use I have in mind is in embedspu, where it will be
useful to to apply relocations to a block of code inserted by .incbin,
but I guess this might be a generally useful feature so I'll make it
available on all targets.
* write.c (size_seg): Always clear SEC_RELOC here.
(install_reloc): New function, extracted from..
(write_relocs): ..here. Combine RELOC_EXPANSION_POSSIBLE code
with !RELOC_EXPANSION_POSSIBLE code. Don't add fr_offset when
testing frag size. Set SEC_RELOC here.
Index: gas/write.c
===================================================================
RCS file: /cvs/src/src/gas/write.c,v
retrieving revision 1.109
diff -u -p -r1.109 write.c
--- gas/write.c 17 Feb 2007 23:13:48 -0000 1.109
+++ gas/write.c 22 Feb 2007 04:51:46 -0000
@@ -553,11 +556,7 @@ size_seg (bfd *abfd, asection *sec, void
if (size > 0 && ! seginfo->bss)
flags |= SEC_HAS_CONTENTS;
- /* @@ This is just an approximation. */
- if (seginfo && seginfo->fix_root)
- flags |= SEC_RELOC;
- else
- flags &= ~SEC_RELOC;
+ flags &= ~SEC_RELOC;
x = bfd_set_section_flags (abfd, sec, flags);
assert (x);
@@ -1000,14 +1078,39 @@ fix_segment (bfd *abfd ATTRIBUTE_UNUSED,
}
static void
+install_reloc (asection *sec, arelent *reloc, fragS *fragp,
+ char *file, unsigned int line)
+{
+ char *err;
+ bfd_reloc_status_type s;
+
+ s = bfd_install_relocation (stdoutput, reloc,
+ fragp->fr_literal, fragp->fr_address,
+ sec, &err);
+ switch (s)
+ {
+ case bfd_reloc_ok:
+ break;
+ case bfd_reloc_overflow:
+ as_bad_where (file, line, _("relocation overflow"));
+ break;
+ case bfd_reloc_outofrange:
+ as_bad_where (file, line, _("relocation out of range"));
+ break;
+ default:
+ as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
+ file, line, s);
+ }
+}
+
+static void
write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
{
segment_info_type *seginfo = seg_info (sec);
unsigned int i;
unsigned int n;
arelent **relocs;
fixS *fixp;
- char *err;
/* If seginfo is NULL, we did not create this section; don't do
anything with it. */
@@ -1016,129 +1120,57 @@ write_relocs (bfd *abfd, asection *sec,
n = 0;
for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
- n++;
+ if (!fixp->fx_done)
+ n++;
-#ifndef RELOC_EXPANSION_POSSIBLE
- /* Set up reloc information as well. */
- relocs = xcalloc (n, sizeof (arelent *));
+#ifdef RELOC_EXPANSION_POSSIBLE
+ n *= MAX_RELOC_EXPANSION;
+#endif
- i = 0;
- for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
- {
- arelent *reloc;
- bfd_reloc_status_type s;
- int fx_size, slack;
- offsetT loc;
-
- if (fixp->fx_done)
- {
- n--;
- continue;
- }
-
- reloc = tc_gen_reloc (sec, fixp);
- if (!reloc)
- {
- n--;
- continue;
- }
-
- fx_size = fixp->fx_size;
- slack = TC_FX_SIZE_SLACK (fixp);
- if (slack > 0)
- fx_size = fx_size > slack ? fx_size - slack : 0;
- loc = fixp->fx_where + fx_size;
- if (slack >= 0
- && loc > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("internal error: fixup not contained within frag"));
-
- s = bfd_install_relocation (stdoutput, reloc,
- fixp->fx_frag->fr_literal,
- fixp->fx_frag->fr_address,
- sec, &err);
- switch (s)
- {
- case bfd_reloc_ok:
- break;
- case bfd_reloc_overflow:
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("relocation overflow"));
- break;
- case bfd_reloc_outofrange:
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("relocation out of range"));
- break;
- default:
- as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
- fixp->fx_file, fixp->fx_line, s);
- }
- relocs[i++] = reloc;
- }
-#else
- n = n * MAX_RELOC_EXPANSION;
- /* Set up reloc information as well. */
relocs = xcalloc (n, sizeof (arelent *));
i = 0;
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
{
- arelent **reloc;
- bfd_reloc_status_type s;
int j;
int fx_size, slack;
offsetT loc;
if (fixp->fx_done)
- {
- n--;
- continue;
- }
-
- reloc = tc_gen_reloc (sec, fixp);
-
- for (j = 0; reloc[j]; j++)
- {
- relocs[i++] = reloc[j];
- assert (i <= n);
- }
+ continue;
fx_size = fixp->fx_size;
slack = TC_FX_SIZE_SLACK (fixp);
if (slack > 0)
fx_size = fx_size > slack ? fx_size - slack : 0;
loc = fixp->fx_where + fx_size;
- if (slack >= 0
- && loc > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset)
+ if (slack >= 0 && loc > fixp->fx_frag->fr_fix)
as_bad_where (fixp->fx_file, fixp->fx_line,
_("internal error: fixup not contained within frag"));
- for (j = 0; reloc[j]; j++)
- {
- s = bfd_install_relocation (stdoutput, reloc[j],
- fixp->fx_frag->fr_literal,
- fixp->fx_frag->fr_address,
- sec, &err);
- switch (s)
- {
- case bfd_reloc_ok:
- break;
- case bfd_reloc_overflow:
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("relocation overflow"));
- break;
- case bfd_reloc_outofrange:
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("relocation out of range"));
- break;
- default:
- as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"),
- fixp->fx_file, fixp->fx_line, s);
- }
- }
+#ifndef RELOC_EXPANSION_POSSIBLE
+ {
+ arelent *reloc = tc_gen_reloc (sec, fixp);
+
+ if (!reloc)
+ continue;
+ relocs[i++] = reloc;
+ j = 1;
+ }
+#else
+ {
+ arelent **reloc = tc_gen_reloc (sec, fixp);
+
+ for (j = 0; reloc[j]; j++)
+ relocs[i++] = reloc[j];
+ }
+#endif
+
+ for ( ; j != 0; --j)
+ install_reloc (sec, relocs[i - j], fixp->fx_frag,
+ fixp->fx_file, fixp->fx_line);
}
n = i;
-#endif
#ifdef DEBUG4
{
@@ -1159,11 +1206,12 @@ write_relocs (bfd *abfd, asection *sec,
#endif
if (n)
- bfd_set_reloc (stdoutput, sec, relocs, n);
- else
- bfd_set_section_flags (abfd, sec,
- (bfd_get_section_flags (abfd, sec)
- & (flagword) ~SEC_RELOC));
+ {
+ flagword flags = bfd_get_section_flags (abfd, sec);
+ flags |= SEC_RELOC;
+ bfd_set_section_flags (abfd, sec, flags);
+ bfd_set_reloc (stdoutput, sec, relocs, n);
+ }
#ifdef SET_SECTION_RELOCS
SET_SECTION_RELOCS (sec, relocs, n);
--
Alan Modra
IBM OzLabs - Linux Technology Centre