PR gdb/1914
[deliverable/binutils-gdb.git] / binutils / rescoff.c
index 65df9bfbd735940350cb2d11bd5b3d902628acce..fdd9aad9982e5ac8d19923f90054d77305f671bd 100644 (file)
@@ -1,5 +1,6 @@
-/* resrc.c -- read and write Windows rc files.
-   Copyright 1997 Free Software Foundation, Inc.
+/* rescoff.c -- read and write resources in Windows COFF files.
+   Copyright 1997, 1998, 1999, 2000, 2003
+   Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support.
 
    This file is part of GNU Binutils.
@@ -16,8 +17,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 /* This file contains function that read and write Windows resources
    in COFF files.  */
@@ -27,6 +28,8 @@
 #include "libiberty.h"
 #include "windres.h"
 
+#include <assert.h>
+
 /* In order to use the address of a resource data entry, we need to
    get the image base of the file.  Right now we extract it from
    internal BFD information.  FIXME.  */
@@ -95,23 +98,22 @@ struct extern_res_data
 
 /* Macros to swap in values.  */
 
-#define get_16(fi, s) ((fi)->big_endian ? bfd_getb16 (s) : bfd_getl16 (s))
-#define get_32(fi, s) ((fi)->big_endian ? bfd_getb32 (s) : bfd_getl32 (s))
+#define getfi_16(fi, s) ((fi)->big_endian ? bfd_getb16 (s) : bfd_getl16 (s))
+#define getfi_32(fi, s) ((fi)->big_endian ? bfd_getb32 (s) : bfd_getl32 (s))
 
 /* Local functions.  */
 
-static void overrun PARAMS ((const struct coff_file_info *, const char *));
+static void overrun (const struct coff_file_info *, const char *);
 static struct res_directory *read_coff_res_dir
-  PARAMS ((const bfd_byte *, const struct coff_file_info *));
+  (const bfd_byte *, const struct coff_file_info *,
+   const struct res_id *, int);
 static struct res_resource *read_coff_data_entry
-  PARAMS ((const bfd_byte *, const struct coff_file_info *));
+  (const bfd_byte *, const struct coff_file_info *, const struct res_id *);
 \f
 /* Read the resources in a COFF file.  */
 
 struct res_directory *
-read_coff_rsrc (filename, target)
-     const char *filename;
-     const char *target;
+read_coff_rsrc (const char *filename, const char *target)
 {
   bfd *abfd;
   char **matching;
@@ -120,6 +122,9 @@ read_coff_rsrc (filename, target)
   bfd_byte *data;
   struct coff_file_info finfo;
 
+  if (filename == NULL)
+    fatal (_("filename required for COFF input"));
+
   abfd = bfd_openr (filename, target);
   if (abfd == NULL)
     bfd_fatal (filename);
@@ -135,16 +140,14 @@ read_coff_rsrc (filename, target)
   sec = bfd_get_section_by_name (abfd, ".rsrc");
   if (sec == NULL)
     {
-      fprintf (stderr, "%s: %s: no resource section\n", program_name,
-              filename);
-      xexit (1);
+      fatal (_("%s: no resource section"), filename);
     }
 
   size = bfd_section_size (abfd, sec);
-  data = (bfd_byte *) xmalloc (size);
+  data = (bfd_byte *) res_alloc (size);
 
   if (! bfd_get_section_contents (abfd, sec, data, 0, size))
-    bfd_fatal ("can't read resource section");
+    bfd_fatal (_("can't read resource section"));
 
   finfo.filename = filename;
   finfo.data = data;
@@ -160,25 +163,22 @@ read_coff_rsrc (filename, target)
      it.  If we ever want to free up the resource information we read,
      this will have to be cleaned up.  */
 
-  return read_coff_res_dir (data, &finfo);
+  return read_coff_res_dir (data, &finfo, (const struct res_id *) NULL, 0);
 }
 
 /* Give an error if we are out of bounds.  */
 
 static void
-overrun (finfo, msg)
-     const struct coff_file_info *finfo;
-     const char *msg;
+overrun (const struct coff_file_info *finfo, const char *msg)
 {
-  fatal ("%s: %s: address out of bounds", finfo->filename, msg);
+  fatal (_("%s: %s: address out of bounds"), finfo->filename, msg);
 }
 
 /* Read a resource directory.  */
 
 static struct res_directory *
-read_coff_res_dir (data, finfo)
-     const bfd_byte *data;
-     const struct coff_file_info *finfo;
+read_coff_res_dir (const bfd_byte *data, const struct coff_file_info *finfo,
+                  const struct res_id *type, int level)
 {
   const struct extern_res_directory *erd;
   struct res_directory *rd;
@@ -186,20 +186,20 @@ read_coff_res_dir (data, finfo)
   struct res_entry **pp;
   const struct extern_res_entry *ere;
 
-  if (finfo->data_end - data < sizeof (struct extern_res_directory))
-    overrun (finfo, "directory");
+  if ((size_t) (finfo->data_end - data) < sizeof (struct extern_res_directory))
+    overrun (finfo, _("directory"));
 
   erd = (const struct extern_res_directory *) data;
 
-  rd = (struct res_directory *) xmalloc (sizeof *rd);
-  rd->characteristics = get_32 (finfo, erd->characteristics);
-  rd->time = get_32 (finfo, erd->time);
-  rd->major = get_16 (finfo, erd->major);
-  rd->minor = get_16 (finfo, erd->minor);
+  rd = (struct res_directory *) res_alloc (sizeof *rd);
+  rd->characteristics = getfi_32 (finfo, erd->characteristics);
+  rd->time = getfi_32 (finfo, erd->time);
+  rd->major = getfi_16 (finfo, erd->major);
+  rd->minor = getfi_16 (finfo, erd->minor);
   rd->entries = NULL;
 
-  name_count = get_16 (finfo, erd->name_count);
-  id_count = get_16 (finfo, erd->id_count);
+  name_count = getfi_16 (finfo, erd->name_count);
+  id_count = getfi_16 (finfo, erd->id_count);
 
   pp = &rd->entries;
 
@@ -215,43 +215,46 @@ read_coff_res_dir (data, finfo)
       int length, j;
 
       if ((const bfd_byte *) ere >= finfo->data_end)
-       overrun (finfo, "named directory entry");
+       overrun (finfo, _("named directory entry"));
 
-      name = get_32 (finfo, ere->name);
-      rva = get_32 (finfo, ere->rva);
+      name = getfi_32 (finfo, ere->name);
+      rva = getfi_32 (finfo, ere->rva);
 
       /* For some reason the high bit in NAME is set.  */
       name &=~ 0x80000000;
 
-      if (name > finfo->data_end - finfo->data)
-       overrun (finfo, "directory entry name");
+      if (name > (size_t) (finfo->data_end - finfo->data))
+       overrun (finfo, _("directory entry name"));
 
       ers = finfo->data + name;
 
-      re = (struct res_entry *) xmalloc (sizeof *re);
+      re = (struct res_entry *) res_alloc (sizeof *re);
       re->next = NULL;
       re->id.named = 1;
-      length = get_16 (finfo, ers);
+      length = getfi_16 (finfo, ers);
       re->id.u.n.length = length;
-      re->id.u.n.name = ((unsigned short *)
-                        xmalloc (length * sizeof (unsigned short)));
+      re->id.u.n.name = (unichar *) res_alloc (length * sizeof (unichar));
       for (j = 0; j < length; j++)
-       re->id.u.n.name[j] = get_16 (finfo, ers + j * 2 + 2);
+       re->id.u.n.name[j] = getfi_16 (finfo, ers + j * 2 + 2);
+
+      if (level == 0)
+       type = &re->id;
 
       if ((rva & 0x80000000) != 0)
        {
          rva &=~ 0x80000000;
-         if (rva >= finfo->data_end - finfo->data)
-           overrun (finfo, "named subdirectory");
+         if (rva >= (size_t) (finfo->data_end - finfo->data))
+           overrun (finfo, _("named subdirectory"));
          re->subdir = 1;
-         re->u.dir = read_coff_res_dir (finfo->data + rva, finfo);
+         re->u.dir = read_coff_res_dir (finfo->data + rva, finfo, type,
+                                        level + 1);
        }
       else
        {
-         if (rva >= finfo->data_end - finfo->data)
-           overrun (finfo, "named resource");
+         if (rva >= (size_t) (finfo->data_end - finfo->data))
+           overrun (finfo, _("named resource"));
          re->subdir = 0;
-         re->u.res = read_coff_data_entry (finfo->data + rva, finfo);
+         re->u.res = read_coff_data_entry (finfo->data + rva, finfo, type);
        }
 
       *pp = re;
@@ -264,30 +267,34 @@ read_coff_res_dir (data, finfo)
       struct res_entry *re;
 
       if ((const bfd_byte *) ere >= finfo->data_end)
-       overrun (finfo, "ID directory entry");
+       overrun (finfo, _("ID directory entry"));
 
-      name = get_32 (finfo, ere->name);
-      rva = get_32 (finfo, ere->rva);
+      name = getfi_32 (finfo, ere->name);
+      rva = getfi_32 (finfo, ere->rva);
 
-      re = (struct res_entry *) xmalloc (sizeof *re);
+      re = (struct res_entry *) res_alloc (sizeof *re);
       re->next = NULL;
       re->id.named = 0;
       re->id.u.id = name;
 
+      if (level == 0)
+       type = &re->id;
+
       if ((rva & 0x80000000) != 0)
        {
          rva &=~ 0x80000000;
-         if (rva >= finfo->data_end - finfo->data)
-           overrun (finfo, "ID subdirectory");
+         if (rva >= (size_t) (finfo->data_end - finfo->data))
+           overrun (finfo, _("ID subdirectory"));
          re->subdir = 1;
-         re->u.dir = read_coff_res_dir (finfo->data + rva, finfo);
+         re->u.dir = read_coff_res_dir (finfo->data + rva, finfo, type,
+                                        level + 1);
        }
       else
        {
-         if (rva >= finfo->data_end - finfo->data)
-           overrun (finfo, "ID resource");
+         if (rva >= (size_t) (finfo->data_end - finfo->data))
+           overrun (finfo, _("ID resource"));
          re->subdir = 0;
-         re->u.res = read_coff_data_entry (finfo->data + rva, finfo);
+         re->u.res = read_coff_data_entry (finfo->data + rva, finfo, type);
        }
 
       *pp = re;
@@ -300,43 +307,460 @@ read_coff_res_dir (data, finfo)
 /* Read a resource data entry.  */
 
 static struct res_resource *
-read_coff_data_entry (data, finfo)
-     const bfd_byte *data;
-     const struct coff_file_info *finfo;
+read_coff_data_entry (const bfd_byte *data, const struct coff_file_info *finfo, const struct res_id *type)
 {
   const struct extern_res_data *erd;
   struct res_resource *r;
   unsigned long size, rva;
   const bfd_byte *resdata;
 
-  if (finfo->data_end - data < sizeof (struct extern_res_data))
-    overrun (finfo, "data entry");
+  if (type == NULL)
+    fatal (_("resource type unknown"));
 
-  erd = (const struct extern_res_data *) data;
+  if ((size_t) (finfo->data_end - data) < sizeof (struct extern_res_data))
+    overrun (finfo, _("data entry"));
 
-  r = (struct res_resource *) xmalloc (sizeof *r);
-  memset (&r->res_info, 0, sizeof (struct res_res_info));
-  r->coff_info.codepage = get_32 (finfo, erd->codepage);
-  r->coff_info.reserved = get_32 (finfo, erd->reserved);
+  erd = (const struct extern_res_data *) data;
 
-  size = get_32 (finfo, erd->size);
-  rva = get_32 (finfo, erd->rva);
+  size = getfi_32 (finfo, erd->size);
+  rva = getfi_32 (finfo, erd->rva);
   if (rva < finfo->secaddr
-      || rva - finfo->secaddr >= finfo->data_end - finfo->data)
-    overrun (finfo, "resource data");
+      || rva - finfo->secaddr >= (size_t) (finfo->data_end - finfo->data))
+    overrun (finfo, _("resource data"));
 
   resdata = finfo->data + (rva - finfo->secaddr);
 
-  r->type = RES_TYPE_USERDATA;
-  r->u.userdata = ((struct rcdata_data *)
-                  xmalloc (sizeof (struct rcdata_data)));
-  r->u.userdata->first = ((struct rcdata_item *)
-                         xmalloc (sizeof (struct rcdata_item)));
-  r->u.userdata->last = r->u.userdata->first;
-  r->u.userdata->first->next = NULL;
-  r->u.userdata->first->type = RCDATA_BUFFER;
-  r->u.userdata->first->u.buffer.length = size;
-  r->u.userdata->first->u.buffer.data = (unsigned char *) resdata;
+  if (size > (size_t) (finfo->data_end - resdata))
+    overrun (finfo, _("resource data size"));
+
+  r = bin_to_res (*type, resdata, size, finfo->big_endian);
+
+  memset (&r->res_info, 0, sizeof (struct res_res_info));
+  r->coff_info.codepage = getfi_32 (finfo, erd->codepage);
+  r->coff_info.reserved = getfi_32 (finfo, erd->reserved);
 
   return r;
 }
+\f
+/* This structure is used to build a list of bindata structures.  */
+
+struct bindata_build
+{
+  /* The data.  */
+  struct bindata *d;
+  /* The last structure we have added to the list.  */
+  struct bindata *last;
+  /* The size of the list as a whole.  */
+  unsigned long length;
+};
+
+/* This structure keeps track of information as we build the directory
+   tree.  */
+
+struct coff_write_info
+{
+  /* These fields are based on the BFD.  */
+  /* The BFD itself.  */
+  bfd *abfd;
+  /* Non-zero if the file is big endian.  */
+  int big_endian;
+  /* Pointer to section symbol used to build RVA relocs.  */
+  asymbol **sympp;
+
+  /* These fields are computed initially, and then not changed.  */
+  /* Length of directory tables and entries.  */
+  unsigned long dirsize;
+  /* Length of directory entry strings.  */
+  unsigned long dirstrsize;
+  /* Length of resource data entries.  */
+  unsigned long dataentsize;
+
+  /* These fields are updated as we add data.  */
+  /* Directory tables and entries.  */
+  struct bindata_build dirs;
+  /* Directory entry strings.  */
+  struct bindata_build dirstrs;
+  /* Resource data entries.  */
+  struct bindata_build dataents;
+  /* Actual resource data.  */
+  struct bindata_build resources;
+  /* Relocations.  */
+  arelent **relocs;
+  /* Number of relocations.  */
+  unsigned int reloc_count;
+};
+
+/* Macros to swap out values.  */
+
+#define putcwi_16(cwi, v, s) \
+  ((cwi->big_endian) ? bfd_putb16 ((v), (s)) : bfd_putl16 ((v), (s)))
+#define putcwi_32(cwi, v, s) \
+  ((cwi->big_endian) ? bfd_putb32 ((v), (s)) : bfd_putl32 ((v), (s)))
+
+static void coff_bin_sizes
+  (const struct res_directory *, struct coff_write_info *);
+static unsigned char *coff_alloc (struct bindata_build *, size_t);
+static void coff_to_bin
+  (const struct res_directory *, struct coff_write_info *);
+static void coff_res_to_bin
+  (const struct res_resource *, struct coff_write_info *);
+
+/* Write resources to a COFF file.  RESOURCES should already be
+   sorted.
+
+   Right now we always create a new file.  Someday we should also
+   offer the ability to merge resources into an existing file.  This
+   would require doing the basic work of objcopy, just modifying or
+   adding the .rsrc section.  */
+
+void
+write_coff_file (const char *filename, const char *target,
+                const struct res_directory *resources)
+{
+  bfd *abfd;
+  asection *sec;
+  struct coff_write_info cwi;
+  struct bindata *d;
+  unsigned long length, offset;
+
+  if (filename == NULL)
+    fatal (_("filename required for COFF output"));
+
+  abfd = bfd_openw (filename, target);
+  if (abfd == NULL)
+    bfd_fatal (filename);
+
+  if (! bfd_set_format (abfd, bfd_object))
+    bfd_fatal ("bfd_set_format");
+
+#if defined DLLTOOL_SH
+  if (! bfd_set_arch_mach (abfd, bfd_arch_sh, 0))
+    bfd_fatal ("bfd_set_arch_mach(sh)");
+#elif defined DLLTOOL_MIPS
+  if (! bfd_set_arch_mach (abfd, bfd_arch_mips, 0))
+    bfd_fatal ("bfd_set_arch_mach(mips)");
+#elif defined DLLTOOL_ARM
+  if (! bfd_set_arch_mach (abfd, bfd_arch_arm, 0))
+    bfd_fatal ("bfd_set_arch_mach(arm)");
+#else
+  /* FIXME: This is obviously i386 specific.  */
+  if (! bfd_set_arch_mach (abfd, bfd_arch_i386, 0))
+    bfd_fatal ("bfd_set_arch_mach(i386)");
+#endif
+
+  if (! bfd_set_file_flags (abfd, HAS_SYMS | HAS_RELOC))
+    bfd_fatal ("bfd_set_file_flags");
+
+  sec = bfd_make_section (abfd, ".rsrc");
+  if (sec == NULL)
+    bfd_fatal ("bfd_make_section");
+
+  if (! bfd_set_section_flags (abfd, sec,
+                              (SEC_HAS_CONTENTS | SEC_ALLOC
+                               | SEC_LOAD | SEC_DATA)))
+    bfd_fatal ("bfd_set_section_flags");
+
+  if (! bfd_set_symtab (abfd, sec->symbol_ptr_ptr, 1))
+    bfd_fatal ("bfd_set_symtab");
+
+  /* Requiring this is probably a bug in BFD.  */
+  sec->output_section = sec;
+
+  /* The order of data in the .rsrc section is
+       resource directory tables and entries
+       resource directory strings
+       resource data entries
+       actual resource data
+
+     We build these different types of data in different lists.  */
+
+  cwi.abfd = abfd;
+  cwi.big_endian = bfd_big_endian (abfd);
+  cwi.sympp = sec->symbol_ptr_ptr;
+  cwi.dirsize = 0;
+  cwi.dirstrsize = 0;
+  cwi.dataentsize = 0;
+  cwi.dirs.d = NULL;
+  cwi.dirs.last = NULL;
+  cwi.dirs.length = 0;
+  cwi.dirstrs.d = NULL;
+  cwi.dirstrs.last = NULL;
+  cwi.dirstrs.length = 0;
+  cwi.dataents.d = NULL;
+  cwi.dataents.last = NULL;
+  cwi.dataents.length = 0;
+  cwi.resources.d = NULL;
+  cwi.resources.last = NULL;
+  cwi.resources.length = 0;
+  cwi.relocs = NULL;
+  cwi.reloc_count = 0;
+
+  /* Work out the sizes of the resource directory entries, so that we
+     know the various offsets we will need.  */
+  coff_bin_sizes (resources, &cwi);
+
+  /* Force the directory strings to be 32 bit aligned.  Every other
+     structure is 32 bit aligned anyhow.  */
+  cwi.dirstrsize = (cwi.dirstrsize + 3) &~ 3;
+
+  /* Actually convert the resources to binary.  */
+  coff_to_bin (resources, &cwi);
+
+  /* Add another 2 bytes to the directory strings if needed for
+     alignment.  */
+  if ((cwi.dirstrs.length & 3) != 0)
+    {
+      unsigned char *ex;
+
+      ex = coff_alloc (&cwi.dirstrs, 2);
+      ex[0] = 0;
+      ex[1] = 0;
+    }
+
+  /* Make sure that the data we built came out to the same size as we
+     calculated initially.  */
+  assert (cwi.dirs.length == cwi.dirsize);
+  assert (cwi.dirstrs.length == cwi.dirstrsize);
+  assert (cwi.dataents.length == cwi.dataentsize);
+
+  length = (cwi.dirsize
+           + cwi.dirstrsize
+           + cwi.dataentsize
+           + cwi.resources.length);
+
+  if (! bfd_set_section_size (abfd, sec, length))
+    bfd_fatal ("bfd_set_section_size");
+
+  bfd_set_reloc (abfd, sec, cwi.relocs, cwi.reloc_count);
+
+  offset = 0;
+  for (d = cwi.dirs.d; d != NULL; d = d->next)
+    {
+      if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
+       bfd_fatal ("bfd_set_section_contents");
+      offset += d->length;
+    }
+  for (d = cwi.dirstrs.d; d != NULL; d = d->next)
+    {
+      if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
+       bfd_fatal ("bfd_set_section_contents");
+      offset += d->length;
+    }
+  for (d = cwi.dataents.d; d != NULL; d = d->next)
+    {
+      if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
+       bfd_fatal ("bfd_set_section_contents");
+      offset += d->length;
+    }
+  for (d = cwi.resources.d; d != NULL; d = d->next)
+    {
+      if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
+       bfd_fatal ("bfd_set_section_contents");
+      offset += d->length;
+    }
+
+  assert (offset == length);
+
+  if (! bfd_close (abfd))
+    bfd_fatal ("bfd_close");
+
+  /* We allocated the relocs array using malloc.  */
+  free (cwi.relocs);
+}
+
+/* Work out the sizes of the various fixed size resource directory
+   entries.  This updates fields in CWI.  */
+
+static void
+coff_bin_sizes (const struct res_directory *resdir,
+               struct coff_write_info *cwi)
+{
+  const struct res_entry *re;
+
+  cwi->dirsize += sizeof (struct extern_res_directory);
+
+  for (re = resdir->entries; re != NULL; re = re->next)
+    {
+      cwi->dirsize += sizeof (struct extern_res_entry);
+
+      if (re->id.named)
+       cwi->dirstrsize += re->id.u.n.length * 2 + 2;
+
+      if (re->subdir)
+       coff_bin_sizes (re->u.dir, cwi);
+      else
+       cwi->dataentsize += sizeof (struct extern_res_data);
+    }
+}
+
+/* Allocate data for a particular list.  */
+
+static unsigned char *
+coff_alloc (struct bindata_build *bb, size_t size)
+{
+  struct bindata *d;
+
+  d = (struct bindata *) reswr_alloc (sizeof *d);
+
+  d->next = NULL;
+  d->data = (unsigned char *) reswr_alloc (size);
+  d->length = size;
+
+  if (bb->d == NULL)
+    bb->d = d;
+  else
+    bb->last->next = d;
+  bb->last = d;
+  bb->length += size;
+
+  return d->data;
+}
+
+/* Convert the resource directory RESDIR to binary.  */
+
+static void
+coff_to_bin (const struct res_directory *resdir, struct coff_write_info *cwi)
+{
+  struct extern_res_directory *erd;
+  int ci, cn;
+  const struct res_entry *e;
+  struct extern_res_entry *ere;
+
+  /* Write out the directory table.  */
+
+  erd = ((struct extern_res_directory *)
+        coff_alloc (&cwi->dirs, sizeof (*erd)));
+
+  putcwi_32 (cwi, resdir->characteristics, erd->characteristics);
+  putcwi_32 (cwi, resdir->time, erd->time);
+  putcwi_16 (cwi, resdir->major, erd->major);
+  putcwi_16 (cwi, resdir->minor, erd->minor);
+
+  ci = 0;
+  cn = 0;
+  for (e = resdir->entries; e != NULL; e = e->next)
+    {
+      if (e->id.named)
+       ++cn;
+      else
+       ++ci;
+    }
+
+  putcwi_16 (cwi, cn, erd->name_count);
+  putcwi_16 (cwi, ci, erd->id_count);
+
+  /* Write out the data entries.  Note that we allocate space for all
+     the entries before writing them out.  That permits a recursive
+     call to work correctly when writing out subdirectories.  */
+
+  ere = ((struct extern_res_entry *)
+        coff_alloc (&cwi->dirs, (ci + cn) * sizeof (*ere)));
+  for (e = resdir->entries; e != NULL; e = e->next, ere++)
+    {
+      if (! e->id.named)
+       putcwi_32 (cwi, e->id.u.id, ere->name);
+      else
+       {
+         unsigned char *str;
+         int i;
+
+         /* For some reason existing files seem to have the high bit
+             set on the address of the name, although that is not
+             documented.  */
+         putcwi_32 (cwi,
+                    0x80000000 | (cwi->dirsize + cwi->dirstrs.length),
+                    ere->name);
+
+         str = coff_alloc (&cwi->dirstrs, e->id.u.n.length * 2 + 2);
+         putcwi_16 (cwi, e->id.u.n.length, str);
+         for (i = 0; i < e->id.u.n.length; i++)
+           putcwi_16 (cwi, e->id.u.n.name[i], str + i * 2 + 2);
+       }
+
+      if (e->subdir)
+       {
+         putcwi_32 (cwi, 0x80000000 | cwi->dirs.length, ere->rva);
+         coff_to_bin (e->u.dir, cwi);
+       }
+      else
+       {
+         putcwi_32 (cwi,
+                    cwi->dirsize + cwi->dirstrsize + cwi->dataents.length,
+                    ere->rva);
+
+         coff_res_to_bin (e->u.res, cwi);
+       }
+    }
+}
+
+/* Convert the resource RES to binary.  */
+
+static void
+coff_res_to_bin (const struct res_resource *res, struct coff_write_info *cwi)
+{
+  arelent *r;
+  struct extern_res_data *erd;
+  struct bindata *d;
+  unsigned long length;
+
+  /* For some reason, although every other address is a section
+     offset, the address of the resource data itself is an RVA.  That
+     means that we need to generate a relocation for it.  We allocate
+     the relocs array using malloc so that we can use realloc.  FIXME:
+     This relocation handling is correct for the i386, but probably
+     not for any other target.  */
+
+  r = (arelent *) reswr_alloc (sizeof (arelent));
+  r->sym_ptr_ptr = cwi->sympp;
+  r->address = cwi->dirsize + cwi->dirstrsize + cwi->dataents.length;
+  r->addend = 0;
+  r->howto = bfd_reloc_type_lookup (cwi->abfd, BFD_RELOC_RVA);
+  if (r->howto == NULL)
+    bfd_fatal (_("can't get BFD_RELOC_RVA relocation type"));
+
+  cwi->relocs = xrealloc (cwi->relocs,
+                         (cwi->reloc_count + 2) * sizeof (arelent *));
+  cwi->relocs[cwi->reloc_count] = r;
+  cwi->relocs[cwi->reloc_count + 1] = NULL;
+  ++cwi->reloc_count;
+
+  erd = (struct extern_res_data *) coff_alloc (&cwi->dataents, sizeof (*erd));
+
+  putcwi_32 (cwi,
+            (cwi->dirsize
+             + cwi->dirstrsize
+             + cwi->dataentsize
+             + cwi->resources.length),
+            erd->rva);
+  putcwi_32 (cwi, res->coff_info.codepage, erd->codepage);
+  putcwi_32 (cwi, res->coff_info.reserved, erd->reserved);
+
+  d = res_to_bin (res, cwi->big_endian);
+
+  if (cwi->resources.d == NULL)
+    cwi->resources.d = d;
+  else
+    cwi->resources.last->next = d;
+
+  length = 0;
+  for (; d->next != NULL; d = d->next)
+    length += d->length;
+  length += d->length;
+  cwi->resources.last = d;
+  cwi->resources.length += length;
+
+  putcwi_32 (cwi, length, erd->size);
+
+  /* Force the next resource to have 32 bit alignment.  */
+
+  if ((length & 3) != 0)
+    {
+      int add;
+      unsigned char *ex;
+
+      add = 4 - (length & 3);
+
+      ex = coff_alloc (&cwi->resources, add);
+      memset (ex, 0, add);
+    }
+}
This page took 0.032626 seconds and 4 git commands to generate.