+/* Get the name of a symbol. The caller must pass in a buffer of size
+ >= SYMNMLEN + 1. */
+
+const char *
+_bfd_coff_internal_syment_name (abfd, sym, buf)
+ bfd *abfd;
+ const struct internal_syment *sym;
+ char *buf;
+{
+ /* FIXME: It's not clear this will work correctly if sizeof
+ (_n_zeroes) != 4. */
+ if (sym->_n._n_n._n_zeroes != 0
+ || sym->_n._n_n._n_offset == 0)
+ {
+ memcpy (buf, sym->_n._n_name, SYMNMLEN);
+ buf[SYMNMLEN] = '\0';
+ return buf;
+ }
+ else
+ {
+ const char *strings;
+
+ BFD_ASSERT (sym->_n._n_n._n_offset >= STRING_SIZE_SIZE);
+ strings = obj_coff_strings (abfd);
+ if (strings == NULL)
+ {
+ strings = _bfd_coff_read_string_table (abfd);
+ if (strings == NULL)
+ return NULL;
+ }
+ return strings + sym->_n._n_n._n_offset;
+ }
+}
+
+/* Read in and swap the relocs. This returns a buffer holding the
+ relocs for section SEC in file ABFD. If CACHE is true and
+ INTERNAL_RELOCS is NULL, the relocs read in will be saved in case
+ the function is called again. If EXTERNAL_RELOCS is not NULL, it
+ is a buffer large enough to hold the unswapped relocs. If
+ INTERNAL_RELOCS is not NULL, it is a buffer large enough to hold
+ the swapped relocs. If REQUIRE_INTERNAL is true, then the return
+ value must be INTERNAL_RELOCS. The function returns NULL on error. */
+
+struct internal_reloc *
+_bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs,
+ require_internal, internal_relocs)
+ bfd *abfd;
+ asection *sec;
+ boolean cache;
+ bfd_byte *external_relocs;
+ boolean require_internal;
+ struct internal_reloc *internal_relocs;
+{
+ bfd_size_type relsz;
+ bfd_byte *free_external = NULL;
+ struct internal_reloc *free_internal = NULL;
+ bfd_byte *erel;
+ bfd_byte *erel_end;
+ struct internal_reloc *irel;
+
+ if (coff_section_data (abfd, sec) != NULL
+ && coff_section_data (abfd, sec)->relocs != NULL)
+ {
+ if (! require_internal)
+ return coff_section_data (abfd, sec)->relocs;
+ memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs,
+ sec->reloc_count * sizeof (struct internal_reloc));
+ return internal_relocs;
+ }
+
+ relsz = bfd_coff_relsz (abfd);
+
+ if (external_relocs == NULL)
+ {
+ free_external = (bfd_byte *) bfd_malloc (sec->reloc_count * relsz);
+ if (free_external == NULL && sec->reloc_count > 0)
+ goto error_return;
+ external_relocs = free_external;
+ }
+
+ if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
+ || (bfd_read (external_relocs, relsz, sec->reloc_count, abfd)
+ != relsz * sec->reloc_count))
+ goto error_return;
+
+ if (internal_relocs == NULL)
+ {
+ free_internal = ((struct internal_reloc *)
+ bfd_malloc (sec->reloc_count
+ * sizeof (struct internal_reloc)));
+ if (free_internal == NULL && sec->reloc_count > 0)
+ goto error_return;
+ internal_relocs = free_internal;
+ }
+
+ /* Swap in the relocs. */
+ erel = external_relocs;
+ erel_end = erel + relsz * sec->reloc_count;
+ irel = internal_relocs;
+ for (; erel < erel_end; erel += relsz, irel++)
+ bfd_coff_swap_reloc_in (abfd, (PTR) erel, (PTR) irel);
+
+ if (free_external != NULL)
+ {
+ free (free_external);
+ free_external = NULL;
+ }
+
+ if (cache && free_internal != NULL)
+ {
+ if (coff_section_data (abfd, sec) == NULL)
+ {
+ sec->used_by_bfd =
+ (PTR) bfd_zalloc (abfd,
+ sizeof (struct coff_section_tdata));
+ if (sec->used_by_bfd == NULL)
+ goto error_return;
+ coff_section_data (abfd, sec)->contents = NULL;
+ }
+ coff_section_data (abfd, sec)->relocs = free_internal;
+ }
+
+ return internal_relocs;
+
+ error_return:
+ if (free_external != NULL)
+ free (free_external);
+ if (free_internal != NULL)
+ free (free_internal);
+ return NULL;
+}
+