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