Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Functions
rescoff.c File Reference
#include "bfd.h"
#include "bucomm.h"
#include "libiberty.h"
#include "windres.h"
#include <assert.h>
#include "coff/internal.h"
#include "libcoff.h"

Go to the source code of this file.

Classes

struct  coff_file_info
struct  extern_res_directory
struct  extern_res_entry
struct  extern_res_data
struct  bindata_build
struct  coff_write_info

Defines

#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))
#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)))

Functions

static void overrun (const struct coff_file_info *, const char *)
static struct res_directoryread_coff_res_dir (const bfd_byte *, const struct coff_file_info *, const struct res_id *, int)
static struct res_resourceread_coff_data_entry (const bfd_byte *, const struct coff_file_info *, const struct res_id *)
struct res_directoryread_coff_rsrc (const char *filename, const char *target)
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 *)
void write_coff_file (const char *filename, const char *target, const struct res_directory *resources)

Class Documentation

struct coff_file_info

Definition at line 42 of file rescoff.c.

Class Members
int big_endian
const bfd_byte * data
const bfd_byte * data_end
const char * filename
bfd_vma secaddr
struct extern_res_directory

Definition at line 58 of file rescoff.c.

Class Members
bfd_byte characteristics
bfd_byte id_count
bfd_byte major
bfd_byte minor
bfd_byte name_count
bfd_byte time
struct extern_res_entry

Definition at line 76 of file rescoff.c.

Class Members
bfd_byte name
bfd_byte rva
struct extern_res_data

Definition at line 86 of file rescoff.c.

Class Members
bfd_byte codepage
bfd_byte reserved
bfd_byte rva
bfd_byte size
struct bindata_build

Definition at line 347 of file rescoff.c.

Collaboration diagram for bindata_build:
Class Members
struct bindata * d
struct bindata * last
unsigned long length
struct coff_write_info

Definition at line 360 of file rescoff.c.

Collaboration diagram for coff_write_info:
Class Members
bfd * abfd
int big_endian
unsigned long dataentsize
unsigned long dirsize
unsigned long dirstrsize
unsigned int reloc_count
arelent ** relocs
asymbol ** sympp

Define Documentation

#define getfi_16 (   fi,
  s 
)    ((fi)->big_endian ? bfd_getb16 (s) : bfd_getl16 (s))

Definition at line 101 of file rescoff.c.

#define getfi_32 (   fi,
  s 
)    ((fi)->big_endian ? bfd_getb32 (s) : bfd_getl32 (s))

Definition at line 102 of file rescoff.c.

#define putcwi_16 (   cwi,
  v,
  s 
)    ((cwi->big_endian) ? bfd_putb16 ((v), (s)) : bfd_putl16 ((v), (s)))

Definition at line 395 of file rescoff.c.

#define putcwi_32 (   cwi,
  v,
  s 
)    ((cwi->big_endian) ? bfd_putb32 ((v), (s)) : bfd_putl32 ((v), (s)))

Definition at line 397 of file rescoff.c.


Function Documentation

static unsigned char * coff_alloc ( struct bindata_build bb,
size_t  size 
) [static]

Definition at line 599 of file rescoff.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void coff_bin_sizes ( const struct res_directory resdir,
struct coff_write_info cwi 
) [static]

Definition at line 575 of file rescoff.c.

{
  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);
    }
}

Here is the caller graph for this function:

static void coff_res_to_bin ( const struct res_resource res,
struct coff_write_info cwi 
) [static]

Definition at line 699 of file rescoff.c.

{
  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);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void coff_to_bin ( const struct res_directory resdir,
struct coff_write_info cwi 
) [static]

Definition at line 622 of file rescoff.c.

{
  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);
       }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void overrun ( const struct coff_file_info finfo,
const char *  msg 
) [static]

Definition at line 172 of file rescoff.c.

{
  fatal (_("%s: %s: address out of bounds"), finfo->filename, msg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct res_resource * read_coff_data_entry ( const bfd_byte data,
const struct coff_file_info finfo,
const struct res_id type 
) [static, read]

Definition at line 310 of file rescoff.c.

{
  const struct extern_res_data *erd;
  struct res_resource *r;
  unsigned long size, rva;
  const bfd_byte *resdata;

  if (type == NULL)
    fatal (_("resource type unknown"));

  if ((size_t) (finfo->data_end - data) < sizeof (struct extern_res_data))
    overrun (finfo, _("data entry"));

  erd = (const struct extern_res_data *) data;

  size = getfi_32 (finfo, erd->size);
  rva = getfi_32 (finfo, erd->rva);
  if (rva < finfo->secaddr
      || rva - finfo->secaddr >= (size_t) (finfo->data_end - finfo->data))
    overrun (finfo, _("resource data"));

  resdata = finfo->data + (rva - finfo->secaddr);

  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct res_directory * read_coff_res_dir ( const bfd_byte data,
const struct coff_file_info finfo,
const struct res_id type,
int  level 
) [static, read]

Definition at line 180 of file rescoff.c.

{
  const struct extern_res_directory *erd;
  struct res_directory *rd;
  int name_count, id_count, i;
  struct res_entry **pp;
  const struct extern_res_entry *ere;

  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 *) 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 = getfi_16 (finfo, erd->name_count);
  id_count = getfi_16 (finfo, erd->id_count);

  pp = &rd->entries;

  /* The resource directory entries immediately follow the directory
     table.  */
  ere = (const struct extern_res_entry *) (erd + 1);

  for (i = 0; i < name_count; i++, ere++)
    {
      unsigned long name, rva;
      struct res_entry *re;
      const bfd_byte *ers;
      int length, j;

      if ((const bfd_byte *) ere >= finfo->data_end)
       overrun (finfo, _("named directory entry"));

      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 > (size_t) (finfo->data_end - finfo->data))
       overrun (finfo, _("directory entry name"));

      ers = finfo->data + name;

      re = (struct res_entry *) res_alloc (sizeof *re);
      re->next = NULL;
      re->id.named = 1;
      length = getfi_16 (finfo, ers);
      re->id.u.n.length = length;
      re->id.u.n.name = (unichar *) res_alloc (length * sizeof (unichar));
      for (j = 0; j < length; j++)
       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 >= (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, type,
                                    level + 1);
       }
      else
       {
         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, type);
       }

      *pp = re;
      pp = &re->next;
    }

  for (i = 0; i < id_count; i++, ere++)
    {
      unsigned long name, rva;
      struct res_entry *re;

      if ((const bfd_byte *) ere >= finfo->data_end)
       overrun (finfo, _("ID directory entry"));

      name = getfi_32 (finfo, ere->name);
      rva = getfi_32 (finfo, ere->rva);

      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 >= (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, type,
                                    level + 1);
       }
      else
       {
         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, type);
       }

      *pp = re;
      pp = &re->next;
    }

  return rd;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct res_directory* read_coff_rsrc ( const char *  filename,
const char *  target 
) [read]

Definition at line 116 of file rescoff.c.

{
  bfd *abfd;
  char **matching;
  asection *sec;
  bfd_size_type size;
  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);

  if (! bfd_check_format_matches (abfd, bfd_object, &matching))
    {
      bfd_nonfatal (bfd_get_filename (abfd));
      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
       list_matching_formats (matching);
      xexit (1);
    }

  sec = bfd_get_section_by_name (abfd, ".rsrc");
  if (sec == NULL)
    {
      fatal (_("%s: no resource section"), filename);
    }

  size = bfd_section_size (abfd, sec);
  data = (bfd_byte *) res_alloc (size);

  if (! bfd_get_section_contents (abfd, sec, data, 0, size))
    bfd_fatal (_("can't read resource section"));

  finfo.filename = filename;
  finfo.data = data;
  finfo.data_end = data + size;
  finfo.secaddr = (bfd_get_section_vma (abfd, sec)
                 - pe_data (abfd)->pe_opthdr.ImageBase);
  finfo.big_endian = bfd_big_endian (abfd);

  bfd_close (abfd);

  /* Now just read in the top level resource directory.  Note that we
     don't free data, since we create resource entries that point into
     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, (const struct res_id *) NULL, 0);
}

Here is the call graph for this function:

void write_coff_file ( const char *  filename,
const char *  target,
const struct res_directory resources 
)

Definition at line 417 of file rescoff.c.

{
  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);
}

Here is the call graph for this function: