Home | History | Annotate | Download | only in binutils
      1 /* rescoff.c -- read and write resources in Windows COFF files.
      2    Copyright (C) 1997-2014 Free Software Foundation, Inc.
      3    Written by Ian Lance Taylor, Cygnus Support.
      4    Rewritten by Kai Tietz, Onevision.
      5 
      6    This file is part of GNU Binutils.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
     21    02110-1301, USA.  */
     22 
     23 /* This file contains function that read and write Windows resources
     24    in COFF files.  */
     25 
     26 #include "sysdep.h"
     27 #include "bfd.h"
     28 #include "bucomm.h"
     29 #include "libiberty.h"
     30 #include "windres.h"
     31 
     32 #include <assert.h>
     33 
     34 /* In order to use the address of a resource data entry, we need to
     35    get the image base of the file.  Right now we extract it from
     36    internal BFD information.  FIXME.  */
     37 
     38 #include "coff/internal.h"
     39 #include "libcoff.h"
     40 
     41 /* Information we extract from the file.  */
     42 
     43 struct coff_file_info
     44 {
     45   /* File name.  */
     46   const char *filename;
     47   /* Data read from the file.  */
     48   const bfd_byte *data;
     49   /* End of data read from file.  */
     50   const bfd_byte *data_end;
     51   /* Address of the resource section minus the image base of the file.  */
     52   rc_uint_type secaddr;
     53 };
     54 
     55 /* A resource directory table in a COFF file.  */
     56 
     57 struct __attribute__ ((__packed__)) extern_res_directory
     58 {
     59   /* Characteristics.  */
     60   bfd_byte characteristics[4];
     61   /* Time stamp.  */
     62   bfd_byte time[4];
     63   /* Major version number.  */
     64   bfd_byte major[2];
     65   /* Minor version number.  */
     66   bfd_byte minor[2];
     67   /* Number of named directory entries.  */
     68   bfd_byte name_count[2];
     69   /* Number of directory entries with IDs.  */
     70   bfd_byte id_count[2];
     71 };
     72 
     73 /* A resource directory entry in a COFF file.  */
     74 
     75 struct extern_res_entry
     76 {
     77   /* Name or ID.  */
     78   bfd_byte name[4];
     79   /* Address of resource entry or subdirectory.  */
     80   bfd_byte rva[4];
     81 };
     82 
     83 /* A resource data entry in a COFF file.  */
     84 
     85 struct extern_res_data
     86 {
     87   /* Address of resource data.  This is apparently a file relative
     88      address, rather than a section offset.  */
     89   bfd_byte rva[4];
     90   /* Size of resource data.  */
     91   bfd_byte size[4];
     92   /* Code page.  */
     93   bfd_byte codepage[4];
     94   /* Reserved.  */
     95   bfd_byte reserved[4];
     96 };
     97 
     98 /* Local functions.  */
     99 
    100 static void overrun (const struct coff_file_info *, const char *);
    101 static rc_res_directory *read_coff_res_dir (windres_bfd *, const bfd_byte *,
    102 					    const struct coff_file_info *,
    103 					    const rc_res_id *, int);
    104 static rc_res_resource *read_coff_data_entry (windres_bfd *, const bfd_byte *,
    105 					      const struct coff_file_info *,
    106 					      const rc_res_id *);
    107 
    108 /* Read the resources in a COFF file.  */
    110 
    111 rc_res_directory *
    112 read_coff_rsrc (const char *filename, const char *target)
    113 {
    114   rc_res_directory *ret;
    115   bfd *abfd;
    116   windres_bfd wrbfd;
    117   char **matching;
    118   asection *sec;
    119   bfd_size_type size;
    120   bfd_byte *data;
    121   struct coff_file_info flaginfo;
    122 
    123   if (filename == NULL)
    124     fatal (_("filename required for COFF input"));
    125 
    126   abfd = bfd_openr (filename, target);
    127   if (abfd == NULL)
    128     bfd_fatal (filename);
    129 
    130   if (! bfd_check_format_matches (abfd, bfd_object, &matching))
    131     {
    132       bfd_nonfatal (bfd_get_filename (abfd));
    133       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
    134 	list_matching_formats (matching);
    135       xexit (1);
    136     }
    137 
    138   sec = bfd_get_section_by_name (abfd, ".rsrc");
    139   if (sec == NULL)
    140     {
    141       fatal (_("%s: no resource section"), filename);
    142     }
    143 
    144   set_windres_bfd (&wrbfd, abfd, sec, WR_KIND_BFD);
    145   size = bfd_section_size (abfd, sec);
    146   data = (bfd_byte *) res_alloc (size);
    147 
    148   get_windres_bfd_content (&wrbfd, data, 0, size);
    149 
    150   flaginfo.filename = filename;
    151   flaginfo.data = data;
    152   flaginfo.data_end = data + size;
    153   flaginfo.secaddr = (bfd_get_section_vma (abfd, sec)
    154 		   - pe_data (abfd)->pe_opthdr.ImageBase);
    155 
    156   /* Now just read in the top level resource directory.  Note that we
    157      don't free data, since we create resource entries that point into
    158      it.  If we ever want to free up the resource information we read,
    159      this will have to be cleaned up.  */
    160 
    161   ret = read_coff_res_dir (&wrbfd, data, &flaginfo, (const rc_res_id *) NULL, 0);
    162 
    163   bfd_close (abfd);
    164 
    165   return ret;
    166 }
    167 
    168 /* Give an error if we are out of bounds.  */
    169 
    170 static void
    171 overrun (const struct coff_file_info *flaginfo, const char *msg)
    172 {
    173   fatal (_("%s: %s: address out of bounds"), flaginfo->filename, msg);
    174 }
    175 
    176 /* Read a resource directory.  */
    177 
    178 static rc_res_directory *
    179 read_coff_res_dir (windres_bfd *wrbfd, const bfd_byte *data,
    180 		   const struct coff_file_info *flaginfo,
    181 		   const rc_res_id *type, int level)
    182 {
    183   const struct extern_res_directory *erd;
    184   rc_res_directory *rd;
    185   int name_count, id_count, i;
    186   rc_res_entry **pp;
    187   const struct extern_res_entry *ere;
    188 
    189   if ((size_t) (flaginfo->data_end - data) < sizeof (struct extern_res_directory))
    190     overrun (flaginfo, _("directory"));
    191 
    192   erd = (const struct extern_res_directory *) data;
    193 
    194   rd = (rc_res_directory *) res_alloc (sizeof (rc_res_directory));
    195   rd->characteristics = windres_get_32 (wrbfd, erd->characteristics, 4);
    196   rd->time = windres_get_32 (wrbfd, erd->time, 4);
    197   rd->major = windres_get_16 (wrbfd, erd->major, 2);
    198   rd->minor = windres_get_16 (wrbfd, erd->minor, 2);
    199   rd->entries = NULL;
    200 
    201   name_count = windres_get_16 (wrbfd, erd->name_count, 2);
    202   id_count = windres_get_16 (wrbfd, erd->id_count, 2);
    203 
    204   pp = &rd->entries;
    205 
    206   /* The resource directory entries immediately follow the directory
    207      table.  */
    208   ere = (const struct extern_res_entry *) (erd + 1);
    209 
    210   for (i = 0; i < name_count; i++, ere++)
    211     {
    212       rc_uint_type name, rva;
    213       rc_res_entry *re;
    214       const bfd_byte *ers;
    215       int length, j;
    216 
    217       if ((const bfd_byte *) ere >= flaginfo->data_end)
    218 	overrun (flaginfo, _("named directory entry"));
    219 
    220       name = windres_get_32 (wrbfd, ere->name, 4);
    221       rva = windres_get_32 (wrbfd, ere->rva, 4);
    222 
    223       /* For some reason the high bit in NAME is set.  */
    224       name &=~ 0x80000000;
    225 
    226       if (name > (rc_uint_type) (flaginfo->data_end - flaginfo->data))
    227 	overrun (flaginfo, _("directory entry name"));
    228 
    229       ers = flaginfo->data + name;
    230 
    231       re = (rc_res_entry *) res_alloc (sizeof *re);
    232       re->next = NULL;
    233       re->id.named = 1;
    234       length = windres_get_16 (wrbfd, ers, 2);
    235       re->id.u.n.length = length;
    236       re->id.u.n.name = (unichar *) res_alloc (length * sizeof (unichar));
    237       for (j = 0; j < length; j++)
    238 	re->id.u.n.name[j] = windres_get_16 (wrbfd, ers + j * 2 + 2, 2);
    239 
    240       if (level == 0)
    241 	type = &re->id;
    242 
    243       if ((rva & 0x80000000) != 0)
    244 	{
    245 	  rva &=~ 0x80000000;
    246 	  if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
    247 	    overrun (flaginfo, _("named subdirectory"));
    248 	  re->subdir = 1;
    249 	  re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo, type,
    250 					 level + 1);
    251 	}
    252       else
    253 	{
    254 	  if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
    255 	    overrun (flaginfo, _("named resource"));
    256 	  re->subdir = 0;
    257 	  re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva, flaginfo, type);
    258 	}
    259 
    260       *pp = re;
    261       pp = &re->next;
    262     }
    263 
    264   for (i = 0; i < id_count; i++, ere++)
    265     {
    266       unsigned long name, rva;
    267       rc_res_entry *re;
    268 
    269       if ((const bfd_byte *) ere >= flaginfo->data_end)
    270 	overrun (flaginfo, _("ID directory entry"));
    271 
    272       name = windres_get_32 (wrbfd, ere->name, 4);
    273       rva = windres_get_32 (wrbfd, ere->rva, 4);
    274 
    275       re = (rc_res_entry *) res_alloc (sizeof *re);
    276       re->next = NULL;
    277       re->id.named = 0;
    278       re->id.u.id = name;
    279 
    280       if (level == 0)
    281 	type = &re->id;
    282 
    283       if ((rva & 0x80000000) != 0)
    284 	{
    285 	  rva &=~ 0x80000000;
    286 	  if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
    287 	    overrun (flaginfo, _("ID subdirectory"));
    288 	  re->subdir = 1;
    289 	  re->u.dir = read_coff_res_dir (wrbfd, flaginfo->data + rva, flaginfo, type,
    290 					 level + 1);
    291 	}
    292       else
    293 	{
    294 	  if (rva >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
    295 	    overrun (flaginfo, _("ID resource"));
    296 	  re->subdir = 0;
    297 	  re->u.res = read_coff_data_entry (wrbfd, flaginfo->data + rva, flaginfo, type);
    298 	}
    299 
    300       *pp = re;
    301       pp = &re->next;
    302     }
    303 
    304   return rd;
    305 }
    306 
    307 /* Read a resource data entry.  */
    308 
    309 static rc_res_resource *
    310 read_coff_data_entry (windres_bfd *wrbfd, const bfd_byte *data,
    311 		      const struct coff_file_info *flaginfo,
    312 		      const rc_res_id *type)
    313 {
    314   const struct extern_res_data *erd;
    315   rc_res_resource *r;
    316   rc_uint_type size, rva;
    317   const bfd_byte *resdata;
    318 
    319   if (type == NULL)
    320     fatal (_("resource type unknown"));
    321 
    322   if ((size_t) (flaginfo->data_end - data) < sizeof (struct extern_res_data))
    323     overrun (flaginfo, _("data entry"));
    324 
    325   erd = (const struct extern_res_data *) data;
    326 
    327   size = windres_get_32 (wrbfd, erd->size, 4);
    328   rva = windres_get_32 (wrbfd, erd->rva, 4);
    329   if (rva < flaginfo->secaddr
    330       || rva - flaginfo->secaddr >= (rc_uint_type) (flaginfo->data_end - flaginfo->data))
    331     overrun (flaginfo, _("resource data"));
    332 
    333   resdata = flaginfo->data + (rva - flaginfo->secaddr);
    334 
    335   if (size > (rc_uint_type) (flaginfo->data_end - resdata))
    336     overrun (flaginfo, _("resource data size"));
    337 
    338   r = bin_to_res (wrbfd, *type, resdata, size);
    339 
    340   memset (&r->res_info, 0, sizeof (rc_res_res_info));
    341   r->coff_info.codepage = windres_get_32 (wrbfd, erd->codepage, 4);
    342   r->coff_info.reserved = windres_get_32 (wrbfd, erd->reserved, 4);
    343 
    344   return r;
    345 }
    346 
    347 /* This structure is used to build a list of bindata structures.  */
    349 
    350 struct bindata_build
    351 {
    352   /* The data.  */
    353   bindata *d;
    354   /* The last structure we have added to the list.  */
    355   bindata *last;
    356   /* The size of the list as a whole.  */
    357   unsigned long length;
    358 };
    359 
    360 struct coff_res_data_build
    361 {
    362   /* The data.  */
    363   coff_res_data *d;
    364   /* The last structure we have added to the list.  */
    365   coff_res_data *last;
    366   /* The size of the list as a whole.  */
    367   unsigned long length;
    368 };
    369 
    370 /* This structure keeps track of information as we build the directory
    371    tree.  */
    372 
    373 struct coff_write_info
    374 {
    375   /* These fields are based on the BFD.  */
    376   /* The BFD itself.  */
    377   windres_bfd *wrbfd;
    378   /* Pointer to section symbol used to build RVA relocs.  */
    379   asymbol **sympp;
    380 
    381   /* These fields are computed initially, and then not changed.  */
    382   /* Length of directory tables and entries.  */
    383   unsigned long dirsize;
    384   /* Length of directory entry strings.  */
    385   unsigned long dirstrsize;
    386   /* Length of resource data entries.  */
    387   unsigned long dataentsize;
    388 
    389   /* These fields are updated as we add data.  */
    390   /* Directory tables and entries.  */
    391   struct bindata_build dirs;
    392   /* Directory entry strings.  */
    393   struct bindata_build dirstrs;
    394   /* Resource data entries.  */
    395   struct bindata_build dataents;
    396   /* Actual resource data.  */
    397   struct coff_res_data_build resources;
    398   /* Relocations.  */
    399   arelent **relocs;
    400   /* Number of relocations.  */
    401   unsigned int reloc_count;
    402 };
    403 
    404 static void coff_bin_sizes (const rc_res_directory *, struct coff_write_info *);
    405 static bfd_byte *coff_alloc (struct bindata_build *, rc_uint_type);
    406 static void coff_to_bin
    407   (const rc_res_directory *, struct coff_write_info *);
    408 static void coff_res_to_bin
    409   (const rc_res_resource *, struct coff_write_info *);
    410 
    411 /* Write resources to a COFF file.  RESOURCES should already be
    412    sorted.
    413 
    414    Right now we always create a new file.  Someday we should also
    415    offer the ability to merge resources into an existing file.  This
    416    would require doing the basic work of objcopy, just modifying or
    417    adding the .rsrc section.  */
    418 
    419 void
    420 write_coff_file (const char *filename, const char *target,
    421 		 const rc_res_directory *resources)
    422 {
    423   bfd *abfd;
    424   asection *sec;
    425   struct coff_write_info cwi;
    426   windres_bfd wrbfd;
    427   bindata *d;
    428   coff_res_data *rd;
    429   unsigned long length, offset;
    430 
    431   if (filename == NULL)
    432     fatal (_("filename required for COFF output"));
    433 
    434   abfd = bfd_openw (filename, target);
    435   if (abfd == NULL)
    436     bfd_fatal (filename);
    437 
    438   if (! bfd_set_format (abfd, bfd_object))
    439     bfd_fatal ("bfd_set_format");
    440 
    441 #if defined DLLTOOL_SH
    442   if (! bfd_set_arch_mach (abfd, bfd_arch_sh, 0))
    443     bfd_fatal ("bfd_set_arch_mach(sh)");
    444 #elif defined DLLTOOL_MIPS
    445   if (! bfd_set_arch_mach (abfd, bfd_arch_mips, 0))
    446     bfd_fatal ("bfd_set_arch_mach(mips)");
    447 #elif defined DLLTOOL_ARM
    448   if (! bfd_set_arch_mach (abfd, bfd_arch_arm, 0))
    449     bfd_fatal ("bfd_set_arch_mach(arm)");
    450 #else
    451   /* FIXME: This is obviously i386 specific.  */
    452   if (! bfd_set_arch_mach (abfd, bfd_arch_i386, 0))
    453     bfd_fatal ("bfd_set_arch_mach(i386)");
    454 #endif
    455 
    456   if (! bfd_set_file_flags (abfd, HAS_SYMS | HAS_RELOC))
    457     bfd_fatal ("bfd_set_file_flags");
    458 
    459   sec = bfd_make_section_with_flags (abfd, ".rsrc",
    460 				     (SEC_HAS_CONTENTS | SEC_ALLOC
    461 				      | SEC_LOAD | SEC_DATA));
    462   if (sec == NULL)
    463     bfd_fatal ("bfd_make_section");
    464 
    465   if (! bfd_set_symtab (abfd, sec->symbol_ptr_ptr, 1))
    466     bfd_fatal ("bfd_set_symtab");
    467 
    468   /* Requiring this is probably a bug in BFD.  */
    469   sec->output_section = sec;
    470 
    471   /* The order of data in the .rsrc section is
    472        resource directory tables and entries
    473        resource directory strings
    474        resource data entries
    475        actual resource data
    476 
    477      We build these different types of data in different lists.  */
    478 
    479   set_windres_bfd (&wrbfd, abfd, sec, WR_KIND_BFD);
    480 
    481   cwi.wrbfd = &wrbfd;
    482   cwi.sympp = sec->symbol_ptr_ptr;
    483   cwi.dirsize = 0;
    484   cwi.dirstrsize = 0;
    485   cwi.dataentsize = 0;
    486   cwi.dirs.d = NULL;
    487   cwi.dirs.last = NULL;
    488   cwi.dirs.length = 0;
    489   cwi.dirstrs.d = NULL;
    490   cwi.dirstrs.last = NULL;
    491   cwi.dirstrs.length = 0;
    492   cwi.dataents.d = NULL;
    493   cwi.dataents.last = NULL;
    494   cwi.dataents.length = 0;
    495   cwi.resources.d = NULL;
    496   cwi.resources.last = NULL;
    497   cwi.resources.length = 0;
    498   cwi.relocs = NULL;
    499   cwi.reloc_count = 0;
    500 
    501   /* Work out the sizes of the resource directory entries, so that we
    502      know the various offsets we will need.  */
    503   coff_bin_sizes (resources, &cwi);
    504 
    505   /* Force the directory strings to be 64 bit aligned.  Every other
    506      structure is 64 bit aligned anyhow.  */
    507   cwi.dirstrsize = (cwi.dirstrsize + 7) & ~7;
    508 
    509   /* Actually convert the resources to binary.  */
    510   coff_to_bin (resources, &cwi);
    511 
    512   /* Add another few bytes to the directory strings if needed for
    513      alignment.  */
    514   if ((cwi.dirstrs.length & 7) != 0)
    515     {
    516       rc_uint_type pad = 8 - (cwi.dirstrs.length & 7);
    517       bfd_byte *ex;
    518 
    519       ex = coff_alloc (& cwi.dirstrs, pad);
    520       memset (ex, 0, pad);
    521     }
    522 
    523   /* Make sure that the data we built came out to the same size as we
    524      calculated initially.  */
    525   assert (cwi.dirs.length == cwi.dirsize);
    526   assert (cwi.dirstrs.length == cwi.dirstrsize);
    527   assert (cwi.dataents.length == cwi.dataentsize);
    528 
    529   length = (cwi.dirsize
    530 	    + cwi.dirstrsize
    531 	    + cwi.dataentsize
    532 	    + cwi.resources.length);
    533 
    534   if (! bfd_set_section_size (abfd, sec, length))
    535     bfd_fatal ("bfd_set_section_size");
    536 
    537   bfd_set_reloc (abfd, sec, cwi.relocs, cwi.reloc_count);
    538 
    539   offset = 0;
    540   for (d = cwi.dirs.d; d != NULL; d = d->next)
    541     {
    542       if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
    543 	bfd_fatal ("bfd_set_section_contents");
    544       offset += d->length;
    545     }
    546   for (d = cwi.dirstrs.d; d != NULL; d = d->next)
    547     {
    548       set_windres_bfd_content (&wrbfd, d->data, offset, d->length);
    549       offset += d->length;
    550     }
    551   for (d = cwi.dataents.d; d != NULL; d = d->next)
    552     {
    553       set_windres_bfd_content (&wrbfd, d->data, offset, d->length);
    554       offset += d->length;
    555     }
    556   for (rd = cwi.resources.d; rd != NULL; rd = rd->next)
    557     {
    558       res_to_bin (cwi.wrbfd, (rc_uint_type) offset, rd->res);
    559       offset += rd->length;
    560     }
    561 
    562   assert (offset == length);
    563 
    564   if (! bfd_close (abfd))
    565     bfd_fatal ("bfd_close");
    566 
    567   /* We allocated the relocs array using malloc.  */
    568   free (cwi.relocs);
    569 }
    570 
    571 /* Work out the sizes of the various fixed size resource directory
    572    entries.  This updates fields in CWI.  */
    573 
    574 static void
    575 coff_bin_sizes (const rc_res_directory *resdir,
    576 		struct coff_write_info *cwi)
    577 {
    578   const rc_res_entry *re;
    579 
    580   cwi->dirsize += sizeof (struct extern_res_directory);
    581 
    582   for (re = resdir->entries; re != NULL; re = re->next)
    583     {
    584       cwi->dirsize += sizeof (struct extern_res_entry);
    585 
    586       if (re->id.named)
    587 	cwi->dirstrsize += re->id.u.n.length * 2 + 2;
    588 
    589       if (re->subdir)
    590 	coff_bin_sizes (re->u.dir, cwi);
    591       else
    592 	cwi->dataentsize += sizeof (struct extern_res_data);
    593     }
    594 }
    595 
    596 /* Allocate data for a particular list.  */
    597 
    598 static bfd_byte *
    599 coff_alloc (struct bindata_build *bb, rc_uint_type size)
    600 {
    601   bindata *d;
    602 
    603   d = (bindata *) reswr_alloc (sizeof (bindata));
    604 
    605   d->next = NULL;
    606   d->data = (bfd_byte *) reswr_alloc (size);
    607   d->length = size;
    608 
    609   if (bb->d == NULL)
    610     bb->d = d;
    611   else
    612     bb->last->next = d;
    613   bb->last = d;
    614   bb->length += size;
    615 
    616   return d->data;
    617 }
    618 
    619 /* Convert the resource directory RESDIR to binary.  */
    620 
    621 static void
    622 coff_to_bin (const rc_res_directory *resdir, struct coff_write_info *cwi)
    623 {
    624   struct extern_res_directory *erd;
    625   int ci, cn;
    626   const rc_res_entry *e;
    627   struct extern_res_entry *ere;
    628 
    629   /* Write out the directory table.  */
    630 
    631   erd = ((struct extern_res_directory *)
    632 	 coff_alloc (&cwi->dirs, sizeof (*erd)));
    633 
    634   windres_put_32 (cwi->wrbfd, erd->characteristics, resdir->characteristics);
    635   windres_put_32 (cwi->wrbfd, erd->time, resdir->time);
    636   windres_put_16 (cwi->wrbfd, erd->major, resdir->major);
    637   windres_put_16 (cwi->wrbfd, erd->minor, resdir->minor);
    638 
    639   ci = 0;
    640   cn = 0;
    641   for (e = resdir->entries; e != NULL; e = e->next)
    642     {
    643       if (e->id.named)
    644 	++cn;
    645       else
    646 	++ci;
    647     }
    648 
    649   windres_put_16 (cwi->wrbfd, erd->name_count, cn);
    650   windres_put_16 (cwi->wrbfd, erd->id_count, ci);
    651 
    652   /* Write out the data entries.  Note that we allocate space for all
    653      the entries before writing them out.  That permits a recursive
    654      call to work correctly when writing out subdirectories.  */
    655 
    656   ere = ((struct extern_res_entry *)
    657 	 coff_alloc (&cwi->dirs, (ci + cn) * sizeof (*ere)));
    658   for (e = resdir->entries; e != NULL; e = e->next, ere++)
    659     {
    660       if (! e->id.named)
    661 	windres_put_32 (cwi->wrbfd, ere->name, e->id.u.id);
    662       else
    663 	{
    664 	  bfd_byte *str;
    665 	  rc_uint_type i;
    666 
    667 	  /* For some reason existing files seem to have the high bit
    668              set on the address of the name, although that is not
    669              documented.  */
    670 	  windres_put_32 (cwi->wrbfd, ere->name,
    671 		     0x80000000 | (cwi->dirsize + cwi->dirstrs.length));
    672 
    673 	  str = coff_alloc (&cwi->dirstrs, e->id.u.n.length * 2 + 2);
    674 	  windres_put_16 (cwi->wrbfd, str, e->id.u.n.length);
    675 	  for (i = 0; i < e->id.u.n.length; i++)
    676 	    windres_put_16 (cwi->wrbfd, str + (i + 1) * sizeof (unichar), e->id.u.n.name[i]);
    677 	}
    678 
    679       if (e->subdir)
    680 	{
    681 	  windres_put_32 (cwi->wrbfd, ere->rva, 0x80000000 | cwi->dirs.length);
    682 	  coff_to_bin (e->u.dir, cwi);
    683 	}
    684       else
    685 	{
    686 	  windres_put_32 (cwi->wrbfd, ere->rva,
    687 		     cwi->dirsize + cwi->dirstrsize + cwi->dataents.length);
    688 
    689 	  coff_res_to_bin (e->u.res, cwi);
    690 	}
    691     }
    692 }
    693 
    694 /* Convert the resource RES to binary.  */
    695 
    696 static void
    697 coff_res_to_bin (const rc_res_resource *res, struct coff_write_info *cwi)
    698 {
    699   arelent *r;
    700   struct extern_res_data *erd;
    701   coff_res_data *d;
    702 
    703   /* For some reason, although every other address is a section
    704      offset, the address of the resource data itself is an RVA.  That
    705      means that we need to generate a relocation for it.  We allocate
    706      the relocs array using malloc so that we can use realloc.  FIXME:
    707      This relocation handling is correct for the i386, but probably
    708      not for any other target.  */
    709 
    710   r = (arelent *) reswr_alloc (sizeof (arelent));
    711   r->sym_ptr_ptr = cwi->sympp;
    712   r->address = cwi->dirsize + cwi->dirstrsize + cwi->dataents.length;
    713   r->addend = 0;
    714   r->howto = bfd_reloc_type_lookup (WR_BFD (cwi->wrbfd), BFD_RELOC_RVA);
    715   if (r->howto == NULL)
    716     bfd_fatal (_("can't get BFD_RELOC_RVA relocation type"));
    717 
    718   cwi->relocs = xrealloc (cwi->relocs,
    719 			  (cwi->reloc_count + 2) * sizeof (arelent *));
    720   cwi->relocs[cwi->reloc_count] = r;
    721   cwi->relocs[cwi->reloc_count + 1] = NULL;
    722   ++cwi->reloc_count;
    723 
    724   erd = (struct extern_res_data *) coff_alloc (&cwi->dataents, sizeof (*erd));
    725 
    726   windres_put_32 (cwi->wrbfd, erd->rva,
    727 	     (cwi->dirsize
    728 	      + cwi->dirstrsize
    729 	      + cwi->dataentsize
    730 	      + cwi->resources.length));
    731   windres_put_32 (cwi->wrbfd, erd->codepage, res->coff_info.codepage);
    732   windres_put_32 (cwi->wrbfd, erd->reserved, res->coff_info.reserved);
    733 
    734   d = (coff_res_data *) reswr_alloc (sizeof (coff_res_data));
    735   d->length = res_to_bin (NULL, (rc_uint_type) 0, res);
    736   d->res = res;
    737   d->next = NULL;
    738 
    739   if (cwi->resources.d == NULL)
    740     cwi->resources.d = d;
    741   else
    742     cwi->resources.last->next = d;
    743 
    744   cwi->resources.last = d;
    745   cwi->resources.length += (d->length + 7) & ~7;
    746 
    747   windres_put_32 (cwi->wrbfd, erd->size, d->length);
    748 
    749   /* Force the next resource to have 64 bit alignment.  */
    750   d->length = (d->length + 7) & ~7;
    751 }
    752