+/* This is function is called after the symbol table has been
+ completed, but before md_convert_frag has been called. If we have
+ seen any .uses pseudo-ops, they point to an instruction which loads
+ a register with the address of a function. We look through the
+ fixups to find where the function address is being loaded from. We
+ then generate a COUNT reloc giving the number of times that
+ function address is referred to. The linker uses this information
+ when doing relaxing, to decide when it can eliminate the stored
+ function address entirely. */
+
+void
+sh_coff_frob_file ()
+{
+ int iseg;
+
+ if (! sh_relax)
+ return;
+
+ for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++)
+ {
+ fixS *fix;
+
+ for (fix = segment_info[iseg].fix_root; fix != NULL; fix = fix->fx_next)
+ {
+ symbolS *sym;
+ bfd_vma val;
+ bfd_vma paddr;
+ fixS *fscan;
+ int iscan;
+ int count;
+
+ if (fix->fx_r_type != R_SH_USES)
+ continue;
+
+ /* The R_SH_USES reloc should refer to a defined local
+ symbol in the same section. */
+ sym = fix->fx_addsy;
+ if (sym == NULL
+ || fix->fx_subsy != NULL
+ || fix->fx_addnumber != 0
+ || S_GET_SEGMENT (sym) != iseg
+ || S_GET_STORAGE_CLASS (sym) == C_EXT)
+ {
+ as_warn_where (fix->fx_file, fix->fx_line,
+ ".uses does not refer to a local symbol in the same section");
+ continue;
+ }
+
+ /* Look through the fixups again, this time looking for one
+ at the same location as sym. */
+ val = S_GET_VALUE (sym);
+ paddr = segment_info[iseg].scnhdr.s_paddr;
+ for (fscan = segment_info[iseg].fix_root;
+ fscan != NULL;
+ fscan = fscan->fx_next)
+ if (val == paddr + fscan->fx_frag->fr_address + fscan->fx_where)
+ break;
+ if (fscan == NULL)
+ {
+ as_warn_where (fix->fx_file, fix->fx_line,
+ "can't find fixup pointed to by .uses");
+ continue;
+ }
+
+ if (fscan->fx_tcbit)
+ {
+ /* We've already done this one. */
+ continue;
+ }
+
+ /* fscan should also be a fixup to a local symbol in the same
+ section. */
+ sym = fscan->fx_addsy;
+ if (sym == NULL
+ || fscan->fx_subsy != NULL
+ || fscan->fx_addnumber != 0
+ || S_GET_SEGMENT (sym) != iseg
+ || S_GET_STORAGE_CLASS (sym) == C_EXT)
+ {
+ as_warn_where (fix->fx_file, fix->fx_line,
+ ".uses target does not refer to a local symbol in the same section");
+ continue;
+ }
+
+ /* Now we look through all the fixups of all the sections,
+ counting the number of times we find a reference to sym. */
+ count = 0;
+ for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++)
+ {
+ paddr = segment_info[iscan].scnhdr.s_paddr;
+ for (fscan = segment_info[iscan].fix_root;
+ fscan != NULL;
+ fscan = fscan->fx_next)
+ {
+ if (fscan->fx_addsy == sym)
+ {
+ ++count;
+ fscan->fx_tcbit = 1;
+ }
+ }
+ }
+
+ if (count < 1)
+ abort ();
+
+ /* Generate a R_SH_COUNT fixup at the location of sym. We
+ have already adjusted the value of sym to include the
+ fragment address, so we undo that adjustment here. */
+ subseg_change (iseg, 0);
+ fix_new (sym->sy_frag, S_GET_VALUE (sym) - sym->sy_frag->fr_address,
+ 4, &abs_symbol, count, 0, R_SH_COUNT);
+ }
+ }
+}
+
+/* Called after relaxing. Set the correct sizes of the fragments, and
+ create relocs so that md_apply_fix will fill in the correct values. */
+