peicode.h revision 94536
184865Sobrien/* Support for the generic parts of PE/PEI, for BFD.
284865Sobrien   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
384865Sobrien   Free Software Foundation, Inc.
484865Sobrien   Written by Cygnus Solutions.
584865Sobrien
684865SobrienThis file is part of BFD, the Binary File Descriptor library.
784865Sobrien
884865SobrienThis program is free software; you can redistribute it and/or modify
984865Sobrienit under the terms of the GNU General Public License as published by
1084865Sobrienthe Free Software Foundation; either version 2 of the License, or
1184865Sobrien(at your option) any later version.
1284865Sobrien
1384865SobrienThis program is distributed in the hope that it will be useful,
1484865Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of
1584865SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1684865SobrienGNU General Public License for more details.
1784865Sobrien
1884865SobrienYou should have received a copy of the GNU General Public License
1984865Sobrienalong with this program; if not, write to the Free Software
2084865SobrienFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2184865Sobrien
2284865Sobrien/*
2384865SobrienMost of this hacked by  Steve Chamberlain,
2484865Sobrien			sac@cygnus.com
2584865Sobrien
2684865SobrienPE/PEI rearrangement (and code added): Donn Terry
2784865Sobrien                                       Softway Systems, Inc.
2884865Sobrien*/
2984865Sobrien
3084865Sobrien/* Hey look, some documentation [and in a place you expect to find it]!
3184865Sobrien
3284865Sobrien   The main reference for the pei format is "Microsoft Portable Executable
3384865Sobrien   and Common Object File Format Specification 4.1".  Get it if you need to
3484865Sobrien   do some serious hacking on this code.
3584865Sobrien
3684865Sobrien   Another reference:
3784865Sobrien   "Peering Inside the PE: A Tour of the Win32 Portable Executable
3884865Sobrien   File Format", MSJ 1994, Volume 9.
3984865Sobrien
4084865Sobrien   The *sole* difference between the pe format and the pei format is that the
4184865Sobrien   latter has an MSDOS 2.0 .exe header on the front that prints the message
4284865Sobrien   "This app must be run under Windows." (or some such).
4384865Sobrien   (FIXME: Whether that statement is *really* true or not is unknown.
4484865Sobrien   Are there more subtle differences between pe and pei formats?
4584865Sobrien   For now assume there aren't.  If you find one, then for God sakes
4684865Sobrien   document it here!)
4784865Sobrien
4884865Sobrien   The Microsoft docs use the word "image" instead of "executable" because
4984865Sobrien   the former can also refer to a DLL (shared library).  Confusion can arise
5084865Sobrien   because the `i' in `pei' also refers to "image".  The `pe' format can
5184865Sobrien   also create images (i.e. executables), it's just that to run on a win32
5284865Sobrien   system you need to use the pei format.
5384865Sobrien
5484865Sobrien   FIXME: Please add more docs here so the next poor fool that has to hack
5584865Sobrien   on this code has a chance of getting something accomplished without
5684865Sobrien   wasting too much time.
5784865Sobrien*/
5884865Sobrien
5984865Sobrien#include "libpei.h"
6084865Sobrien
6184865Sobrienstatic boolean (*pe_saved_coff_bfd_print_private_bfd_data)
6284865Sobrien    PARAMS ((bfd *, PTR)) =
6384865Sobrien#ifndef coff_bfd_print_private_bfd_data
6484865Sobrien     NULL;
6584865Sobrien#else
6684865Sobrien     coff_bfd_print_private_bfd_data;
6784865Sobrien#undef coff_bfd_print_private_bfd_data
6884865Sobrien#endif
6984865Sobrien
7084865Sobrienstatic boolean pe_print_private_bfd_data PARAMS ((bfd *, PTR));
7184865Sobrien#define coff_bfd_print_private_bfd_data pe_print_private_bfd_data
7284865Sobrien
7384865Sobrienstatic boolean (*pe_saved_coff_bfd_copy_private_bfd_data)
7484865Sobrien    PARAMS ((bfd *, bfd *)) =
7584865Sobrien#ifndef coff_bfd_copy_private_bfd_data
7684865Sobrien     NULL;
7784865Sobrien#else
7884865Sobrien     coff_bfd_copy_private_bfd_data;
7984865Sobrien#undef coff_bfd_copy_private_bfd_data
8084865Sobrien#endif
8184865Sobrien
8284865Sobrienstatic boolean pe_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *));
8384865Sobrien#define coff_bfd_copy_private_bfd_data pe_bfd_copy_private_bfd_data
8484865Sobrien
8584865Sobrien#define coff_mkobject      pe_mkobject
8684865Sobrien#define coff_mkobject_hook pe_mkobject_hook
8784865Sobrien
8884865Sobrien#ifndef NO_COFF_RELOCS
8984865Sobrienstatic void coff_swap_reloc_in PARAMS ((bfd *, PTR, PTR));
9084865Sobrienstatic unsigned int coff_swap_reloc_out PARAMS ((bfd *, PTR, PTR));
9184865Sobrien#endif
9284865Sobrienstatic void coff_swap_filehdr_in PARAMS ((bfd *, PTR, PTR));
9384865Sobrienstatic void coff_swap_scnhdr_in PARAMS ((bfd *, PTR, PTR));
9484865Sobrienstatic boolean pe_mkobject PARAMS ((bfd *));
9584865Sobrienstatic PTR pe_mkobject_hook PARAMS ((bfd *, PTR, PTR));
9684865Sobrien
9784865Sobrien#ifdef COFF_IMAGE_WITH_PE
9884865Sobrien/* This structure contains static variables used by the ILF code.  */
9984865Sobrientypedef asection * asection_ptr;
10084865Sobrien
10184865Sobrientypedef struct
10284865Sobrien{
10384865Sobrien  bfd *			abfd;
10484865Sobrien  bfd_byte *		data;
10584865Sobrien  struct bfd_in_memory * bim;
10684865Sobrien  unsigned short        magic;
10784865Sobrien
10884865Sobrien  arelent *		reltab;
10984865Sobrien  unsigned int 		relcount;
11084865Sobrien
11184865Sobrien  coff_symbol_type * 	sym_cache;
11284865Sobrien  coff_symbol_type * 	sym_ptr;
11384865Sobrien  unsigned int       	sym_index;
11484865Sobrien
11584865Sobrien  unsigned int * 	sym_table;
11684865Sobrien  unsigned int * 	table_ptr;
11784865Sobrien
11884865Sobrien  combined_entry_type * native_syms;
11984865Sobrien  combined_entry_type * native_ptr;
12084865Sobrien
12184865Sobrien  coff_symbol_type **	sym_ptr_table;
12284865Sobrien  coff_symbol_type **	sym_ptr_ptr;
12384865Sobrien
12484865Sobrien  unsigned int		sec_index;
12584865Sobrien
12684865Sobrien  char *                string_table;
12784865Sobrien  char *                string_ptr;
12884865Sobrien  char *		end_string_ptr;
12984865Sobrien
13084865Sobrien  SYMENT *              esym_table;
13184865Sobrien  SYMENT *              esym_ptr;
13284865Sobrien
13384865Sobrien  struct internal_reloc * int_reltab;
13484865Sobrien}
13584865Sobrienpe_ILF_vars;
13684865Sobrien
13784865Sobrienstatic asection_ptr       pe_ILF_make_a_section   PARAMS ((pe_ILF_vars *, const char *, unsigned int, flagword));
13884865Sobrienstatic void               pe_ILF_make_a_reloc     PARAMS ((pe_ILF_vars *, bfd_vma, bfd_reloc_code_real_type, asection_ptr));
13984865Sobrienstatic void               pe_ILF_make_a_symbol    PARAMS ((pe_ILF_vars *, const char *, const char *, asection_ptr, flagword));
14084865Sobrienstatic void               pe_ILF_save_relocs      PARAMS ((pe_ILF_vars *, asection_ptr));
14184865Sobrienstatic void		  pe_ILF_make_a_symbol_reloc  PARAMS ((pe_ILF_vars *, bfd_vma, bfd_reloc_code_real_type, struct symbol_cache_entry **, unsigned int));
14294536Sobrienstatic boolean            pe_ILF_build_a_bfd      PARAMS ((bfd *, unsigned int, bfd_byte *, bfd_byte *, unsigned int, unsigned int));
14384865Sobrienstatic const bfd_target * pe_ILF_object_p         PARAMS ((bfd *));
14484865Sobrienstatic const bfd_target * pe_bfd_object_p 	  PARAMS ((bfd *));
14584865Sobrien#endif /* COFF_IMAGE_WITH_PE */
14684865Sobrien
14784865Sobrien/**********************************************************************/
14884865Sobrien
14984865Sobrien#ifndef NO_COFF_RELOCS
15084865Sobrienstatic void
15184865Sobriencoff_swap_reloc_in (abfd, src, dst)
15284865Sobrien     bfd *abfd;
15384865Sobrien     PTR src;
15484865Sobrien     PTR dst;
15584865Sobrien{
15684865Sobrien  RELOC *reloc_src = (RELOC *) src;
15784865Sobrien  struct internal_reloc *reloc_dst = (struct internal_reloc *) dst;
15884865Sobrien
15994536Sobrien  reloc_dst->r_vaddr = H_GET_32 (abfd, reloc_src->r_vaddr);
16094536Sobrien  reloc_dst->r_symndx = H_GET_S32 (abfd, reloc_src->r_symndx);
16184865Sobrien
16294536Sobrien  reloc_dst->r_type = H_GET_16 (abfd, reloc_src->r_type);
16384865Sobrien
16484865Sobrien#ifdef SWAP_IN_RELOC_OFFSET
16594536Sobrien  reloc_dst->r_offset = SWAP_IN_RELOC_OFFSET (abfd, reloc_src->r_offset);
16684865Sobrien#endif
16784865Sobrien}
16884865Sobrien
16984865Sobrienstatic unsigned int
17084865Sobriencoff_swap_reloc_out (abfd, src, dst)
17184865Sobrien     bfd       *abfd;
17284865Sobrien     PTR	src;
17384865Sobrien     PTR	dst;
17484865Sobrien{
17584865Sobrien  struct internal_reloc *reloc_src = (struct internal_reloc *)src;
17684865Sobrien  struct external_reloc *reloc_dst = (struct external_reloc *)dst;
17794536Sobrien  H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr);
17894536Sobrien  H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx);
17984865Sobrien
18094536Sobrien  H_PUT_16 (abfd, reloc_src->r_type, reloc_dst->r_type);
18184865Sobrien
18284865Sobrien#ifdef SWAP_OUT_RELOC_OFFSET
18394536Sobrien  SWAP_OUT_RELOC_OFFSET (abfd, reloc_src->r_offset, reloc_dst->r_offset);
18484865Sobrien#endif
18584865Sobrien#ifdef SWAP_OUT_RELOC_EXTRA
18694536Sobrien  SWAP_OUT_RELOC_EXTRA(abfd, reloc_src, reloc_dst);
18784865Sobrien#endif
18884865Sobrien  return RELSZ;
18984865Sobrien}
19084865Sobrien#endif /* not NO_COFF_RELOCS */
19184865Sobrien
19284865Sobrienstatic void
19384865Sobriencoff_swap_filehdr_in (abfd, src, dst)
19484865Sobrien     bfd            *abfd;
19584865Sobrien     PTR	     src;
19684865Sobrien     PTR	     dst;
19784865Sobrien{
19884865Sobrien  FILHDR *filehdr_src = (FILHDR *) src;
19984865Sobrien  struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst;
20094536Sobrien  filehdr_dst->f_magic = H_GET_16 (abfd, filehdr_src->f_magic);
20194536Sobrien  filehdr_dst->f_nscns = H_GET_16 (abfd, filehdr_src-> f_nscns);
20294536Sobrien  filehdr_dst->f_timdat = H_GET_32 (abfd, filehdr_src-> f_timdat);
20384865Sobrien
20494536Sobrien  filehdr_dst->f_nsyms = H_GET_32 (abfd, filehdr_src-> f_nsyms);
20594536Sobrien  filehdr_dst->f_flags = H_GET_16 (abfd, filehdr_src-> f_flags);
20694536Sobrien  filehdr_dst->f_symptr = H_GET_32 (abfd, filehdr_src->f_symptr);
20784865Sobrien
20884865Sobrien  /* Other people's tools sometimes generate headers with an nsyms but
20984865Sobrien     a zero symptr.  */
21084865Sobrien  if (filehdr_dst->f_nsyms != 0 && filehdr_dst->f_symptr == 0)
21184865Sobrien    {
21284865Sobrien      filehdr_dst->f_nsyms = 0;
21384865Sobrien      filehdr_dst->f_flags |= F_LSYMS;
21484865Sobrien    }
21584865Sobrien
21694536Sobrien  filehdr_dst->f_opthdr = H_GET_16 (abfd, filehdr_src-> f_opthdr);
21784865Sobrien}
21884865Sobrien
21984865Sobrien#ifdef COFF_IMAGE_WITH_PE
22084865Sobrien# define coff_swap_filehdr_out _bfd_XXi_only_swap_filehdr_out
22184865Sobrien#else
22284865Sobrien# define coff_swap_filehdr_out _bfd_pe_only_swap_filehdr_out
22384865Sobrien#endif
22484865Sobrien
22584865Sobrienstatic void
22684865Sobriencoff_swap_scnhdr_in (abfd, ext, in)
22784865Sobrien     bfd            *abfd;
22884865Sobrien     PTR	     ext;
22984865Sobrien     PTR	     in;
23084865Sobrien{
23184865Sobrien  SCNHDR *scnhdr_ext = (SCNHDR *) ext;
23284865Sobrien  struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
23384865Sobrien
23484865Sobrien  memcpy(scnhdr_int->s_name, scnhdr_ext->s_name, sizeof (scnhdr_int->s_name));
23594536Sobrien  scnhdr_int->s_vaddr = GET_SCNHDR_VADDR (abfd, scnhdr_ext->s_vaddr);
23694536Sobrien  scnhdr_int->s_paddr = GET_SCNHDR_PADDR (abfd, scnhdr_ext->s_paddr);
23794536Sobrien  scnhdr_int->s_size = GET_SCNHDR_SIZE (abfd, scnhdr_ext->s_size);
23894536Sobrien  scnhdr_int->s_scnptr = GET_SCNHDR_SCNPTR (abfd, scnhdr_ext->s_scnptr);
23994536Sobrien  scnhdr_int->s_relptr = GET_SCNHDR_RELPTR (abfd, scnhdr_ext->s_relptr);
24094536Sobrien  scnhdr_int->s_lnnoptr = GET_SCNHDR_LNNOPTR (abfd, scnhdr_ext->s_lnnoptr);
24194536Sobrien  scnhdr_int->s_flags = H_GET_32 (abfd, scnhdr_ext->s_flags);
24284865Sobrien
24384865Sobrien  /* MS handles overflow of line numbers by carrying into the reloc
24484865Sobrien     field (it appears).  Since it's supposed to be zero for PE
24584865Sobrien     *IMAGE* format, that's safe.  This is still a bit iffy.  */
24684865Sobrien#ifdef COFF_IMAGE_WITH_PE
24794536Sobrien  scnhdr_int->s_nlnno = (H_GET_16 (abfd, scnhdr_ext->s_nlnno)
24894536Sobrien			 + (H_GET_16 (abfd, scnhdr_ext->s_nreloc) << 16));
24984865Sobrien  scnhdr_int->s_nreloc = 0;
25084865Sobrien#else
25194536Sobrien  scnhdr_int->s_nreloc = H_GET_16 (abfd, scnhdr_ext->s_nreloc);
25294536Sobrien  scnhdr_int->s_nlnno = H_GET_16 (abfd, scnhdr_ext->s_nlnno);
25384865Sobrien#endif
25484865Sobrien
25584865Sobrien  if (scnhdr_int->s_vaddr != 0)
25684865Sobrien    {
25784865Sobrien      scnhdr_int->s_vaddr += pe_data (abfd)->pe_opthdr.ImageBase;
25884865Sobrien      scnhdr_int->s_vaddr &= 0xffffffff;
25984865Sobrien    }
26084865Sobrien
26184865Sobrien#ifndef COFF_NO_HACK_SCNHDR_SIZE
26284865Sobrien  /* If this section holds uninitialized data, use the virtual size
26384865Sobrien     (stored in s_paddr) instead of the physical size.  */
26484865Sobrien  if ((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0
26584865Sobrien      && (scnhdr_int->s_paddr > 0))
26684865Sobrien    {
26784865Sobrien      scnhdr_int->s_size = scnhdr_int->s_paddr;
26884865Sobrien      /* This code used to set scnhdr_int->s_paddr to 0.  However,
26984865Sobrien         coff_set_alignment_hook stores s_paddr in virt_size, which
27084865Sobrien         only works if it correctly holds the virtual size of the
27184865Sobrien         section.  */
27284865Sobrien    }
27384865Sobrien#endif
27484865Sobrien}
27584865Sobrien
27684865Sobrienstatic boolean
27784865Sobrienpe_mkobject (abfd)
27884865Sobrien     bfd * abfd;
27984865Sobrien{
28084865Sobrien  pe_data_type *pe;
28194536Sobrien  bfd_size_type amt = sizeof (pe_data_type);
28284865Sobrien
28394536Sobrien  abfd->tdata.pe_obj_data = (struct pe_tdata *) bfd_zalloc (abfd, amt);
28494536Sobrien
28584865Sobrien  if (abfd->tdata.pe_obj_data == 0)
28684865Sobrien    return false;
28784865Sobrien
28884865Sobrien  pe = pe_data (abfd);
28984865Sobrien
29084865Sobrien  pe->coff.pe = 1;
29184865Sobrien
29284865Sobrien  /* in_reloc_p is architecture dependent.  */
29384865Sobrien  pe->in_reloc_p = in_reloc_p;
29484865Sobrien
29584865Sobrien#ifdef PEI_FORCE_MINIMUM_ALIGNMENT
29684865Sobrien  pe->force_minimum_alignment = 1;
29784865Sobrien#endif
29884865Sobrien#ifdef PEI_TARGET_SUBSYSTEM
29984865Sobrien  pe->target_subsystem = PEI_TARGET_SUBSYSTEM;
30084865Sobrien#endif
30184865Sobrien
30284865Sobrien  return true;
30384865Sobrien}
30484865Sobrien
30584865Sobrien/* Create the COFF backend specific information.  */
30684865Sobrienstatic PTR
30784865Sobrienpe_mkobject_hook (abfd, filehdr, aouthdr)
30884865Sobrien     bfd * abfd;
30984865Sobrien     PTR filehdr;
31084865Sobrien     PTR aouthdr ATTRIBUTE_UNUSED;
31184865Sobrien{
31284865Sobrien  struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
31384865Sobrien  pe_data_type *pe;
31484865Sobrien
31584865Sobrien  if (pe_mkobject (abfd) == false)
31684865Sobrien    return NULL;
31784865Sobrien
31884865Sobrien  pe = pe_data (abfd);
31984865Sobrien  pe->coff.sym_filepos = internal_f->f_symptr;
32084865Sobrien  /* These members communicate important constants about the symbol
32184865Sobrien     table to GDB's symbol-reading code.  These `constants'
32284865Sobrien     unfortunately vary among coff implementations...  */
32384865Sobrien  pe->coff.local_n_btmask = N_BTMASK;
32484865Sobrien  pe->coff.local_n_btshft = N_BTSHFT;
32584865Sobrien  pe->coff.local_n_tmask = N_TMASK;
32684865Sobrien  pe->coff.local_n_tshift = N_TSHIFT;
32784865Sobrien  pe->coff.local_symesz = SYMESZ;
32884865Sobrien  pe->coff.local_auxesz = AUXESZ;
32984865Sobrien  pe->coff.local_linesz = LINESZ;
33084865Sobrien
33184865Sobrien  pe->coff.timestamp = internal_f->f_timdat;
33284865Sobrien
33384865Sobrien  obj_raw_syment_count (abfd) =
33484865Sobrien    obj_conv_table_size (abfd) =
33584865Sobrien      internal_f->f_nsyms;
33684865Sobrien
33784865Sobrien  pe->real_flags = internal_f->f_flags;
33884865Sobrien
33984865Sobrien  if ((internal_f->f_flags & F_DLL) != 0)
34084865Sobrien    pe->dll = 1;
34184865Sobrien
34284865Sobrien  if ((internal_f->f_flags & IMAGE_FILE_DEBUG_STRIPPED) == 0)
34384865Sobrien    abfd->flags |= HAS_DEBUG;
34484865Sobrien
34584865Sobrien#ifdef COFF_IMAGE_WITH_PE
34684865Sobrien  if (aouthdr)
34784865Sobrien    pe->pe_opthdr = ((struct internal_aouthdr *)aouthdr)->pe;
34884865Sobrien#endif
34984865Sobrien
35084865Sobrien#ifdef ARM
35184865Sobrien  if (! _bfd_coff_arm_set_private_flags (abfd, internal_f->f_flags))
35284865Sobrien    coff_data (abfd) ->flags = 0;
35384865Sobrien#endif
35484865Sobrien
35584865Sobrien  return (PTR) pe;
35684865Sobrien}
35784865Sobrien
35884865Sobrienstatic boolean
35984865Sobrienpe_print_private_bfd_data (abfd, vfile)
36084865Sobrien     bfd *abfd;
36184865Sobrien     PTR vfile;
36284865Sobrien{
36384865Sobrien  FILE *file = (FILE *) vfile;
36484865Sobrien
36584865Sobrien  if (!_bfd_XX_print_private_bfd_data_common (abfd, vfile))
36684865Sobrien    return false;
36784865Sobrien
36884865Sobrien  if (pe_saved_coff_bfd_print_private_bfd_data != NULL)
36984865Sobrien    {
37084865Sobrien      fputc ('\n', file);
37184865Sobrien
37284865Sobrien      return pe_saved_coff_bfd_print_private_bfd_data (abfd, vfile);
37384865Sobrien    }
37484865Sobrien
37584865Sobrien  return true;
37684865Sobrien}
37784865Sobrien
37884865Sobrien/* Copy any private info we understand from the input bfd
37984865Sobrien   to the output bfd.  */
38084865Sobrien
38184865Sobrienstatic boolean
38284865Sobrienpe_bfd_copy_private_bfd_data (ibfd, obfd)
38384865Sobrien     bfd *ibfd, *obfd;
38484865Sobrien{
38584865Sobrien  if (!_bfd_XX_bfd_copy_private_bfd_data_common (ibfd, obfd))
38684865Sobrien    return false;
38784865Sobrien
38884865Sobrien  if (pe_saved_coff_bfd_copy_private_bfd_data)
38984865Sobrien    return pe_saved_coff_bfd_copy_private_bfd_data (ibfd, obfd);
39084865Sobrien
39184865Sobrien  return true;
39284865Sobrien}
39384865Sobrien
39484865Sobrien#define coff_bfd_copy_private_section_data \
39584865Sobrien  _bfd_XX_bfd_copy_private_section_data
39684865Sobrien
39784865Sobrien#define coff_get_symbol_info _bfd_XX_get_symbol_info
39884865Sobrien
39984865Sobrien#ifdef COFF_IMAGE_WITH_PE
40084865Sobrien
40184865Sobrien/* Code to handle Microsoft's Image Library Format.
40284865Sobrien   Also known as LINK6 format.
40384865Sobrien   Documentation about this format can be found at:
40484865Sobrien
40584865Sobrien   http://msdn.microsoft.com/library/specs/pecoff_section8.htm  */
40684865Sobrien
40784865Sobrien/* The following constants specify the sizes of the various data
40884865Sobrien   structures that we have to create in order to build a bfd describing
40984865Sobrien   an ILF object file.  The final "+ 1" in the definitions of SIZEOF_IDATA6
41084865Sobrien   and SIZEOF_IDATA7 below is to allow for the possibility that we might
41184865Sobrien   need a padding byte in order to ensure 16 bit alignment for the section's
41284865Sobrien   contents.
41384865Sobrien
41484865Sobrien   The value for SIZEOF_ILF_STRINGS is computed as follows:
41584865Sobrien
41684865Sobrien      There will be NUM_ILF_SECTIONS section symbols.  Allow 9 characters
41784865Sobrien      per symbol for their names (longest section name is .idata$x).
41884865Sobrien
41984865Sobrien      There will be two symbols for the imported value, one the symbol name
42084865Sobrien      and one with _imp__ prefixed.  Allowing for the terminating nul's this
42184865Sobrien      is strlen (symbol_name) * 2 + 8 + 21 + strlen (source_dll).
42284865Sobrien
42384865Sobrien      The strings in the string table must start STRING__SIZE_SIZE bytes into
42484865Sobrien      the table in order to for the string lookup code in coffgen/coffcode to
42584865Sobrien      work.  */
42684865Sobrien#define NUM_ILF_RELOCS		8
42784865Sobrien#define NUM_ILF_SECTIONS        6
42884865Sobrien#define NUM_ILF_SYMS 		(2 + NUM_ILF_SECTIONS)
42984865Sobrien
43084865Sobrien#define SIZEOF_ILF_SYMS		(NUM_ILF_SYMS * sizeof (* vars.sym_cache))
43184865Sobrien#define SIZEOF_ILF_SYM_TABLE	(NUM_ILF_SYMS * sizeof (* vars.sym_table))
43284865Sobrien#define SIZEOF_ILF_NATIVE_SYMS	(NUM_ILF_SYMS * sizeof (* vars.native_syms))
43384865Sobrien#define SIZEOF_ILF_SYM_PTR_TABLE (NUM_ILF_SYMS * sizeof (* vars.sym_ptr_table))
43484865Sobrien#define SIZEOF_ILF_EXT_SYMS	(NUM_ILF_SYMS * sizeof (* vars.esym_table))
43584865Sobrien#define SIZEOF_ILF_RELOCS	(NUM_ILF_RELOCS * sizeof (* vars.reltab))
43684865Sobrien#define SIZEOF_ILF_INT_RELOCS	(NUM_ILF_RELOCS * sizeof (* vars.int_reltab))
43784865Sobrien#define SIZEOF_ILF_STRINGS	(strlen (symbol_name) * 2 + 8 \
43884865Sobrien					+ 21 + strlen (source_dll) \
43984865Sobrien					+ NUM_ILF_SECTIONS * 9 \
44084865Sobrien					+ STRING_SIZE_SIZE)
44184865Sobrien#define SIZEOF_IDATA2		(5 * 4)
44284865Sobrien#define SIZEOF_IDATA4		(1 * 4)
44384865Sobrien#define SIZEOF_IDATA5		(1 * 4)
44484865Sobrien#define SIZEOF_IDATA6		(2 + strlen (symbol_name) + 1 + 1)
44584865Sobrien#define SIZEOF_IDATA7		(strlen (source_dll) + 1 + 1)
44684865Sobrien#define SIZEOF_ILF_SECTIONS     (NUM_ILF_SECTIONS * sizeof (struct coff_section_tdata))
44784865Sobrien
44884865Sobrien#define ILF_DATA_SIZE				\
44984865Sobrien      sizeof (* vars.bim)			\
45084865Sobrien    + SIZEOF_ILF_SYMS				\
45184865Sobrien    + SIZEOF_ILF_SYM_TABLE			\
45284865Sobrien    + SIZEOF_ILF_NATIVE_SYMS			\
45384865Sobrien    + SIZEOF_ILF_SYM_PTR_TABLE			\
45484865Sobrien    + SIZEOF_ILF_EXT_SYMS			\
45584865Sobrien    + SIZEOF_ILF_RELOCS				\
45684865Sobrien    + SIZEOF_ILF_INT_RELOCS			\
45784865Sobrien    + SIZEOF_ILF_STRINGS			\
45884865Sobrien    + SIZEOF_IDATA2				\
45984865Sobrien    + SIZEOF_IDATA4				\
46084865Sobrien    + SIZEOF_IDATA5				\
46184865Sobrien    + SIZEOF_IDATA6				\
46284865Sobrien    + SIZEOF_IDATA7				\
46384865Sobrien    + SIZEOF_ILF_SECTIONS			\
46484865Sobrien    + MAX_TEXT_SECTION_SIZE
46584865Sobrien
46684865Sobrien/* Create an empty relocation against the given symbol.  */
46784865Sobrienstatic void
46884865Sobrienpe_ILF_make_a_symbol_reloc (pe_ILF_vars *                 vars,
46984865Sobrien			    bfd_vma                       address,
47084865Sobrien			    bfd_reloc_code_real_type      reloc,
47184865Sobrien			    struct symbol_cache_entry **  sym,
47284865Sobrien			    unsigned int                  sym_index)
47384865Sobrien{
47484865Sobrien  arelent * entry;
47584865Sobrien  struct internal_reloc * internal;
47684865Sobrien
47784865Sobrien  entry = vars->reltab + vars->relcount;
47884865Sobrien  internal = vars->int_reltab + vars->relcount;
47984865Sobrien
48084865Sobrien  entry->address     = address;
48184865Sobrien  entry->addend      = 0;
48284865Sobrien  entry->howto       = bfd_reloc_type_lookup (vars->abfd, reloc);
48384865Sobrien  entry->sym_ptr_ptr = sym;
48484865Sobrien
48584865Sobrien  internal->r_vaddr  = address;
48684865Sobrien  internal->r_symndx = sym_index;
48784865Sobrien  internal->r_type   = entry->howto->type;
48884865Sobrien#if 0  /* These fields do not need to be initialised.  */
48984865Sobrien  internal->r_size   = 0;
49084865Sobrien  internal->r_extern = 0;
49184865Sobrien  internal->r_offset = 0;
49284865Sobrien#endif
49384865Sobrien
49484865Sobrien  vars->relcount ++;
49584865Sobrien
49684865Sobrien  BFD_ASSERT (vars->relcount <= NUM_ILF_RELOCS);
49784865Sobrien}
49884865Sobrien
49984865Sobrien/* Create an empty relocation against the given section.  */
50084865Sobrienstatic void
50184865Sobrienpe_ILF_make_a_reloc (pe_ILF_vars *             vars,
50284865Sobrien		     bfd_vma                   address,
50384865Sobrien		     bfd_reloc_code_real_type  reloc,
50484865Sobrien		     asection_ptr              sec)
50584865Sobrien{
50684865Sobrien  pe_ILF_make_a_symbol_reloc (vars, address, reloc, sec->symbol_ptr_ptr,
50784865Sobrien			      coff_section_data (vars->abfd, sec)->i);
50884865Sobrien}
50984865Sobrien
51084865Sobrien/* Move the queued relocs into the given section.  */
51184865Sobrienstatic void
51284865Sobrienpe_ILF_save_relocs (pe_ILF_vars * vars,
51384865Sobrien		    asection_ptr  sec)
51484865Sobrien{
51584865Sobrien  /* Make sure that there is somewhere to store the internal relocs.  */
51684865Sobrien  if (coff_section_data (vars->abfd, sec) == NULL)
51784865Sobrien    /* We should probably return an error indication here.  */
51884865Sobrien    abort ();
51984865Sobrien
52084865Sobrien  coff_section_data (vars->abfd, sec)->relocs = vars->int_reltab;
52184865Sobrien  coff_section_data (vars->abfd, sec)->keep_relocs = true;
52284865Sobrien
52384865Sobrien  sec->relocation  = vars->reltab;
52484865Sobrien  sec->reloc_count = vars->relcount;
52584865Sobrien  sec->flags      |= SEC_RELOC;
52684865Sobrien
52784865Sobrien  vars->reltab     += vars->relcount;
52884865Sobrien  vars->int_reltab += vars->relcount;
52984865Sobrien  vars->relcount   = 0;
53084865Sobrien
53194536Sobrien  BFD_ASSERT ((bfd_byte *) vars->int_reltab < (bfd_byte *) vars->string_table);
53284865Sobrien}
53384865Sobrien
53484865Sobrien/* Create a global symbol and add it to the relevant tables.  */
53584865Sobrienstatic void
53684865Sobrienpe_ILF_make_a_symbol (pe_ILF_vars *  vars,
53784865Sobrien		      const char *   prefix,
53884865Sobrien		      const char *   symbol_name,
53984865Sobrien		      asection_ptr   section,
54084865Sobrien		      flagword       extra_flags)
54184865Sobrien{
54284865Sobrien  coff_symbol_type * sym;
54384865Sobrien  combined_entry_type * ent;
54484865Sobrien  SYMENT * esym;
54584865Sobrien  unsigned short sclass;
54684865Sobrien
54784865Sobrien  if (extra_flags & BSF_LOCAL)
54884865Sobrien    sclass = C_STAT;
54984865Sobrien  else
55084865Sobrien    sclass = C_EXT;
55184865Sobrien
55284865Sobrien#ifdef THUMBPEMAGIC
55384865Sobrien  if (vars->magic == THUMBPEMAGIC)
55484865Sobrien    {
55584865Sobrien      if (extra_flags & BSF_FUNCTION)
55684865Sobrien	sclass = C_THUMBEXTFUNC;
55784865Sobrien      else if (extra_flags & BSF_LOCAL)
55884865Sobrien	sclass = C_THUMBSTAT;
55984865Sobrien      else
56084865Sobrien	sclass = C_THUMBEXT;
56184865Sobrien    }
56284865Sobrien#endif
56384865Sobrien
56484865Sobrien  BFD_ASSERT (vars->sym_index < NUM_ILF_SYMS);
56584865Sobrien
56684865Sobrien  sym = vars->sym_ptr;
56784865Sobrien  ent = vars->native_ptr;
56884865Sobrien  esym = vars->esym_ptr;
56984865Sobrien
57084865Sobrien  /* Copy the symbol's name into the string table.  */
57184865Sobrien  sprintf (vars->string_ptr, "%s%s", prefix, symbol_name);
57284865Sobrien
57384865Sobrien  if (section == NULL)
57484865Sobrien    section = (asection_ptr) & bfd_und_section;
57584865Sobrien
57684865Sobrien  /* Initialise the external symbol.  */
57794536Sobrien  H_PUT_32 (vars->abfd, vars->string_ptr - vars->string_table,
57894536Sobrien	    esym->e.e.e_offset);
57994536Sobrien  H_PUT_16 (vars->abfd, section->target_index, esym->e_scnum);
58084865Sobrien  esym->e_sclass[0] = sclass;
58184865Sobrien
58284865Sobrien  /* The following initialisations are unnecessary - the memory is
58384865Sobrien     zero initialised.  They are just kept here as reminders.  */
58484865Sobrien#if 0
58584865Sobrien  esym->e.e.e_zeroes = 0;
58684865Sobrien  esym->e_value = 0;
58784865Sobrien  esym->e_type = T_NULL;
58884865Sobrien  esym->e_numaux = 0;
58984865Sobrien#endif
59084865Sobrien
59184865Sobrien  /* Initialise the internal symbol structure.  */
59284865Sobrien  ent->u.syment.n_sclass          = sclass;
59384865Sobrien  ent->u.syment.n_scnum           = section->target_index;
59484865Sobrien  ent->u.syment._n._n_n._n_offset = (long) sym;
59584865Sobrien
59684865Sobrien#if 0 /* See comment above.  */
59784865Sobrien  ent->u.syment.n_value  = 0;
59884865Sobrien  ent->u.syment.n_flags  = 0;
59984865Sobrien  ent->u.syment.n_type   = T_NULL;
60084865Sobrien  ent->u.syment.n_numaux = 0;
60184865Sobrien  ent->fix_value         = 0;
60284865Sobrien#endif
60384865Sobrien
60484865Sobrien  sym->symbol.the_bfd = vars->abfd;
60584865Sobrien  sym->symbol.name    = vars->string_ptr;
60684865Sobrien  sym->symbol.flags   = BSF_EXPORT | BSF_GLOBAL | extra_flags;
60784865Sobrien  sym->symbol.section = section;
60884865Sobrien  sym->native         = ent;
60984865Sobrien
61084865Sobrien#if 0 /* See comment above.  */
61184865Sobrien  sym->symbol.value   = 0;
61284865Sobrien  sym->symbol.udata.i = 0;
61384865Sobrien  sym->done_lineno    = false;
61484865Sobrien  sym->lineno         = NULL;
61584865Sobrien#endif
61684865Sobrien
61784865Sobrien  * vars->table_ptr = vars->sym_index;
61884865Sobrien  * vars->sym_ptr_ptr = sym;
61984865Sobrien
62084865Sobrien  /* Adjust pointers for the next symbol.  */
62184865Sobrien  vars->sym_index ++;
62284865Sobrien  vars->sym_ptr ++;
62384865Sobrien  vars->sym_ptr_ptr ++;
62484865Sobrien  vars->table_ptr ++;
62584865Sobrien  vars->native_ptr ++;
62684865Sobrien  vars->esym_ptr ++;
62784865Sobrien  vars->string_ptr += strlen (symbol_name) + strlen (prefix) + 1;
62884865Sobrien
62984865Sobrien  BFD_ASSERT (vars->string_ptr < vars->end_string_ptr);
63084865Sobrien}
63184865Sobrien
63284865Sobrien/* Create a section.  */
63384865Sobrienstatic asection_ptr
63484865Sobrienpe_ILF_make_a_section (pe_ILF_vars * vars,
63584865Sobrien		       const char *  name,
63684865Sobrien		       unsigned int  size,
63784865Sobrien		       flagword      extra_flags)
63884865Sobrien{
63984865Sobrien  asection_ptr sec;
64084865Sobrien  flagword     flags;
64184865Sobrien
64284865Sobrien  sec = bfd_make_section_old_way (vars->abfd, name);
64384865Sobrien  if (sec == NULL)
64484865Sobrien    return NULL;
64584865Sobrien
64684865Sobrien  flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_IN_MEMORY;
64784865Sobrien
64884865Sobrien  bfd_set_section_flags (vars->abfd, sec, flags | extra_flags);
64984865Sobrien
65084865Sobrien  bfd_set_section_alignment (vars->abfd, sec, 2);
65184865Sobrien
65284865Sobrien  /* Check that we will not run out of space.  */
65384865Sobrien  BFD_ASSERT (vars->data + size < vars->bim->buffer + vars->bim->size);
65484865Sobrien
65584865Sobrien  /* Set the section size and contents.  The actual
65684865Sobrien     contents are filled in by our parent.  */
65794536Sobrien  bfd_set_section_size (vars->abfd, sec, (bfd_size_type) size);
65884865Sobrien  sec->contents = vars->data;
65984865Sobrien  sec->target_index = vars->sec_index ++;
66084865Sobrien
66184865Sobrien  /* Advance data pointer in the vars structure.  */
66284865Sobrien  vars->data += size;
66384865Sobrien
66484865Sobrien  /* Skip the padding byte if it was not needed.
66584865Sobrien     The logic here is that if the string length is odd,
66684865Sobrien     then the entire string length, including the null byte,
66784865Sobrien     is even and so the extra, padding byte, is not needed.  */
66884865Sobrien  if (size & 1)
66984865Sobrien    vars->data --;
67084865Sobrien
67184865Sobrien  /* Create a coff_section_tdata structure for our use.  */
67284865Sobrien  sec->used_by_bfd = (struct coff_section_tdata *) vars->data;
67384865Sobrien  vars->data += sizeof (struct coff_section_tdata);
67484865Sobrien
67584865Sobrien  BFD_ASSERT (vars->data <= vars->bim->buffer + vars->bim->size);
67684865Sobrien
67784865Sobrien  /* Create a symbol to refer to this section.  */
67884865Sobrien  pe_ILF_make_a_symbol (vars, "", name, sec, BSF_LOCAL);
67984865Sobrien
68084865Sobrien  /* Cache the index to the symbol in the coff_section_data structure.  */
68184865Sobrien  coff_section_data (vars->abfd, sec)->i = vars->sym_index - 1;
68284865Sobrien
68384865Sobrien  return sec;
68484865Sobrien}
68584865Sobrien
68684865Sobrien/* This structure contains the code that goes into the .text section
68784865Sobrien   in order to perform a jump into the DLL lookup table.  The entries
68884865Sobrien   in the table are index by the magic number used to represent the
68984865Sobrien   machine type in the PE file.  The contents of the data[] arrays in
69084865Sobrien   these entries are stolen from the jtab[] arrays in ld/pe-dll.c.
69184865Sobrien   The SIZE field says how many bytes in the DATA array are actually
69284865Sobrien   used.  The OFFSET field says where in the data array the address
69384865Sobrien   of the .idata$5 section should be placed.  */
69484865Sobrien#define MAX_TEXT_SECTION_SIZE 32
69584865Sobrien
69684865Sobrientypedef struct
69784865Sobrien{
69884865Sobrien  unsigned short magic;
69984865Sobrien  unsigned char  data[MAX_TEXT_SECTION_SIZE];
70084865Sobrien  unsigned int   size;
70184865Sobrien  unsigned int   offset;
70284865Sobrien}
70384865Sobrienjump_table;
70484865Sobrien
70584865Sobrienstatic jump_table jtab[] =
70684865Sobrien{
70784865Sobrien#ifdef I386MAGIC
70884865Sobrien  { I386MAGIC,
70984865Sobrien    { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 },
71084865Sobrien    8, 2
71184865Sobrien  },
71284865Sobrien#endif
71384865Sobrien
71484865Sobrien#ifdef  MC68MAGIC
71584865Sobrien  { MC68MAGIC, { /* XXX fill me in */ }, 0, 0 },
71684865Sobrien#endif
71784865Sobrien#ifdef  MIPS_ARCH_MAGIC_WINCE
71884865Sobrien  { MIPS_ARCH_MAGIC_WINCE,
71984865Sobrien    { 0x00, 0x00, 0x08, 0x3c, 0x00, 0x00, 0x08, 0x8d,
72084865Sobrien      0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 },
72184865Sobrien    16, 0
72284865Sobrien  },
72384865Sobrien#endif
72484865Sobrien
72584865Sobrien#ifdef  SH_ARCH_MAGIC_WINCE
72684865Sobrien  { SH_ARCH_MAGIC_WINCE,
72784865Sobrien    { 0x01, 0xd0, 0x02, 0x60, 0x2b, 0x40,
72884865Sobrien      0x09, 0x00, 0x00, 0x00, 0x00, 0x00 },
72984865Sobrien    12, 8
73084865Sobrien  },
73184865Sobrien#endif
73284865Sobrien
73384865Sobrien#ifdef  ARMPEMAGIC
73484865Sobrien  { ARMPEMAGIC,
73584865Sobrien    { 0x00, 0xc0, 0x9f, 0xe5, 0x00, 0xf0,
73684865Sobrien      0x9c, 0xe5, 0x00, 0x00, 0x00, 0x00},
73784865Sobrien    12, 8
73884865Sobrien  },
73984865Sobrien#endif
74084865Sobrien
74184865Sobrien#ifdef  THUMBPEMAGIC
74284865Sobrien  { THUMBPEMAGIC,
74384865Sobrien    { 0x40, 0xb4, 0x02, 0x4e, 0x36, 0x68, 0xb4, 0x46,
74484865Sobrien      0x40, 0xbc, 0x60, 0x47, 0x00, 0x00, 0x00, 0x00 },
74584865Sobrien    16, 12
74684865Sobrien  },
74784865Sobrien#endif
74884865Sobrien  { 0, { 0 }, 0, 0 }
74984865Sobrien};
75084865Sobrien
75184865Sobrien#ifndef NUM_ENTRIES
75284865Sobrien#define NUM_ENTRIES(a) (sizeof (a) / sizeof (a)[0])
75384865Sobrien#endif
75484865Sobrien
75584865Sobrien/* Build a full BFD from the information supplied in a ILF object.  */
75684865Sobrienstatic boolean
75784865Sobrienpe_ILF_build_a_bfd (bfd *           abfd,
75894536Sobrien		    unsigned int    magic,
75984865Sobrien		    bfd_byte *      symbol_name,
76084865Sobrien		    bfd_byte *      source_dll,
76184865Sobrien		    unsigned int    ordinal,
76284865Sobrien		    unsigned int    types)
76384865Sobrien{
76484865Sobrien  bfd_byte *               ptr;
76584865Sobrien  pe_ILF_vars              vars;
76684865Sobrien  struct internal_filehdr  internal_f;
76784865Sobrien  unsigned int             import_type;
76884865Sobrien  unsigned int             import_name_type;
76984865Sobrien  asection_ptr             id4, id5, id6 = NULL, text = NULL;
77084865Sobrien  coff_symbol_type **      imp_sym;
77184865Sobrien  unsigned int             imp_index;
77284865Sobrien
77384865Sobrien  /* Decode and verify the types field of the ILF structure.  */
77484865Sobrien  import_type = types & 0x3;
77584865Sobrien  import_name_type = (types & 0x1c) >> 2;
77684865Sobrien
77784865Sobrien  switch (import_type)
77884865Sobrien    {
77984865Sobrien    case IMPORT_CODE:
78084865Sobrien    case IMPORT_DATA:
78184865Sobrien      break;
78284865Sobrien
78384865Sobrien    case IMPORT_CONST:
78484865Sobrien      /* XXX code yet to be written.  */
78584865Sobrien      _bfd_error_handler (_("%s: Unhandled import type; %x"),
78694536Sobrien			  bfd_archive_filename (abfd), import_type);
78784865Sobrien      return false;
78884865Sobrien
78984865Sobrien    default:
79084865Sobrien      _bfd_error_handler (_("%s: Unrecognised import type; %x"),
79194536Sobrien			  bfd_archive_filename (abfd), import_type);
79284865Sobrien      return false;
79384865Sobrien    }
79484865Sobrien
79584865Sobrien  switch (import_name_type)
79684865Sobrien    {
79784865Sobrien    case IMPORT_ORDINAL:
79884865Sobrien    case IMPORT_NAME:
79984865Sobrien    case IMPORT_NAME_NOPREFIX:
80084865Sobrien    case IMPORT_NAME_UNDECORATE:
80184865Sobrien      break;
80284865Sobrien
80384865Sobrien    default:
80484865Sobrien      _bfd_error_handler (_("%s: Unrecognised import name type; %x"),
80594536Sobrien			  bfd_archive_filename (abfd), import_name_type);
80684865Sobrien      return false;
80784865Sobrien    }
80884865Sobrien
80984865Sobrien  /* Initialise local variables.
81084865Sobrien
81184865Sobrien     Note these are kept in a structure rather than being
81284865Sobrien     declared as statics since bfd frowns on global variables.
81384865Sobrien
81484865Sobrien     We are going to construct the contents of the BFD in memory,
81584865Sobrien     so allocate all the space that we will need right now.  */
81694536Sobrien  ptr = bfd_zalloc (abfd, (bfd_size_type) ILF_DATA_SIZE);
81784865Sobrien  if (ptr == NULL)
81884865Sobrien    return false;
81984865Sobrien
82084865Sobrien  /* Create a bfd_in_memory structure.  */
82184865Sobrien  vars.bim = (struct bfd_in_memory *) ptr;
82284865Sobrien  vars.bim->buffer = ptr;
82384865Sobrien  vars.bim->size   = ILF_DATA_SIZE;
82484865Sobrien  ptr += sizeof (* vars.bim);
82584865Sobrien
82684865Sobrien  /* Initialise the pointers to regions of the memory and the
82784865Sobrien     other contents of the pe_ILF_vars structure as well.  */
82884865Sobrien  vars.sym_cache = (coff_symbol_type *) ptr;
82984865Sobrien  vars.sym_ptr   = (coff_symbol_type *) ptr;
83084865Sobrien  vars.sym_index = 0;
83184865Sobrien  ptr += SIZEOF_ILF_SYMS;
83284865Sobrien
83384865Sobrien  vars.sym_table = (unsigned int *) ptr;
83484865Sobrien  vars.table_ptr = (unsigned int *) ptr;
83584865Sobrien  ptr += SIZEOF_ILF_SYM_TABLE;
83684865Sobrien
83784865Sobrien  vars.native_syms = (combined_entry_type *) ptr;
83884865Sobrien  vars.native_ptr  = (combined_entry_type *) ptr;
83984865Sobrien  ptr += SIZEOF_ILF_NATIVE_SYMS;
84084865Sobrien
84184865Sobrien  vars.sym_ptr_table = (coff_symbol_type **) ptr;
84284865Sobrien  vars.sym_ptr_ptr   = (coff_symbol_type **) ptr;
84384865Sobrien  ptr += SIZEOF_ILF_SYM_PTR_TABLE;
84484865Sobrien
84584865Sobrien  vars.esym_table = (SYMENT *) ptr;
84684865Sobrien  vars.esym_ptr   = (SYMENT *) ptr;
84784865Sobrien  ptr += SIZEOF_ILF_EXT_SYMS;
84884865Sobrien
84984865Sobrien  vars.reltab   = (arelent *) ptr;
85084865Sobrien  vars.relcount = 0;
85184865Sobrien  ptr += SIZEOF_ILF_RELOCS;
85284865Sobrien
85384865Sobrien  vars.int_reltab  = (struct internal_reloc *) ptr;
85484865Sobrien  ptr += SIZEOF_ILF_INT_RELOCS;
85584865Sobrien
85684865Sobrien  vars.string_table = ptr;
85784865Sobrien  vars.string_ptr   = ptr + STRING_SIZE_SIZE;
85884865Sobrien  ptr += SIZEOF_ILF_STRINGS;
85984865Sobrien  vars.end_string_ptr = ptr;
86084865Sobrien
86184865Sobrien  /* The remaining space in bim->buffer is used
86284865Sobrien     by the pe_ILF_make_a_section() function.  */
86384865Sobrien  vars.data = ptr;
86484865Sobrien  vars.abfd = abfd;
86584865Sobrien  vars.sec_index = 0;
86684865Sobrien  vars.magic = magic;
86784865Sobrien
86884865Sobrien  /* Create the initial .idata$<n> sections:
86984865Sobrien     [.idata$2:  Import Directory Table -- not needed]
87084865Sobrien     .idata$4:  Import Lookup Table
87184865Sobrien     .idata$5:  Import Address Table
87284865Sobrien
87384865Sobrien     Note we do not create a .idata$3 section as this is
87484865Sobrien     created for us by the linker script.  */
87584865Sobrien  id4 = pe_ILF_make_a_section (& vars, ".idata$4", SIZEOF_IDATA4, 0);
87684865Sobrien  id5 = pe_ILF_make_a_section (& vars, ".idata$5", SIZEOF_IDATA5, 0);
87784865Sobrien  if (id4 == NULL || id5 == NULL)
87884865Sobrien    return false;
87984865Sobrien
88084865Sobrien  /* Fill in the contents of these sections.  */
88184865Sobrien  if (import_name_type == IMPORT_ORDINAL)
88284865Sobrien    {
88384865Sobrien      if (ordinal == 0)
88484865Sobrien	/* XXX - treat as IMPORT_NAME ??? */
88584865Sobrien	abort ();
88684865Sobrien
88784865Sobrien      * (unsigned int *) id4->contents = ordinal | 0x80000000;
88884865Sobrien      * (unsigned int *) id5->contents = ordinal | 0x80000000;
88984865Sobrien    }
89084865Sobrien  else
89184865Sobrien    {
89284865Sobrien      char * symbol;
89384865Sobrien
89484865Sobrien      /* Create .idata$6 - the Hint Name Table.  */
89584865Sobrien      id6 = pe_ILF_make_a_section (& vars, ".idata$6", SIZEOF_IDATA6, 0);
89684865Sobrien      if (id6 == NULL)
89784865Sobrien	return false;
89884865Sobrien
89984865Sobrien      /* If necessary, trim the import symbol name.  */
90084865Sobrien      symbol = symbol_name;
90184865Sobrien
90284865Sobrien      if (import_name_type != IMPORT_NAME)
90384865Sobrien	/* Skip any prefix in symbol_name.  */
90484865Sobrien	while (*symbol == '@' || * symbol == '?' || * symbol == '_')
90584865Sobrien	  ++ symbol;
90684865Sobrien
90784865Sobrien      if (import_name_type == IMPORT_NAME_UNDECORATE)
90884865Sobrien	{
90984865Sobrien	  /* Truncate at the first '@'  */
91084865Sobrien	  while (* symbol != 0 && * symbol != '@')
91184865Sobrien	    symbol ++;
91284865Sobrien
91384865Sobrien	  * symbol = 0;
91484865Sobrien	}
91584865Sobrien
91684865Sobrien      id6->contents[0] = ordinal & 0xff;
91784865Sobrien      id6->contents[1] = ordinal >> 8;
91884865Sobrien
91984865Sobrien      strcpy (id6->contents + 2, symbol);
92084865Sobrien    }
92184865Sobrien
92284865Sobrien  if (import_name_type != IMPORT_ORDINAL)
92384865Sobrien    {
92494536Sobrien      pe_ILF_make_a_reloc (&vars, (bfd_vma) 0, BFD_RELOC_RVA, id6);
92594536Sobrien      pe_ILF_save_relocs (&vars, id4);
92684865Sobrien
92794536Sobrien      pe_ILF_make_a_reloc (&vars, (bfd_vma) 0, BFD_RELOC_RVA, id6);
92894536Sobrien      pe_ILF_save_relocs (&vars, id5);
92984865Sobrien    }
93084865Sobrien
93184865Sobrien  /* Create extra sections depending upon the type of import we are dealing with.  */
93284865Sobrien  switch (import_type)
93384865Sobrien    {
93484865Sobrien      int i;
93584865Sobrien
93684865Sobrien    case IMPORT_CODE:
93784865Sobrien      /* Create a .text section.
93884865Sobrien	 First we need to look up its contents in the jump table.  */
93984865Sobrien      for (i = NUM_ENTRIES (jtab); i--;)
94084865Sobrien	{
94184865Sobrien	  if (jtab[i].size == 0)
94284865Sobrien	    continue;
94384865Sobrien	  if (jtab[i].magic == magic)
94484865Sobrien	    break;
94584865Sobrien	}
94684865Sobrien      /* If we did not find a matching entry something is wrong.  */
94784865Sobrien      if (i < 0)
94884865Sobrien	abort ();
94984865Sobrien
95084865Sobrien      /* Create the .text section.  */
95184865Sobrien      text = pe_ILF_make_a_section (& vars, ".text", jtab[i].size, SEC_CODE);
95284865Sobrien      if (text == NULL)
95384865Sobrien	return false;
95484865Sobrien
95584865Sobrien      /* Copy in the jump code.  */
95684865Sobrien      memcpy (text->contents, jtab[i].data, jtab[i].size);
95784865Sobrien
95884865Sobrien      /* Create an import symbol.  */
95984865Sobrien      pe_ILF_make_a_symbol (& vars, "__imp_", symbol_name, id5, 0);
96084865Sobrien      imp_sym   = vars.sym_ptr_ptr - 1;
96184865Sobrien      imp_index = vars.sym_index - 1;
96284865Sobrien
96384865Sobrien      /* Create a reloc for the data in the text section.  */
96484865Sobrien#ifdef MIPS_ARCH_MAGIC_WINCE
96584865Sobrien      if (magic == MIPS_ARCH_MAGIC_WINCE)
96684865Sobrien	{
96794536Sobrien	  pe_ILF_make_a_symbol_reloc (&vars, (bfd_vma) 0, BFD_RELOC_HI16_S,
96894536Sobrien				      (struct symbol_cache_entry **) imp_sym,
96994536Sobrien				      imp_index);
97094536Sobrien	  pe_ILF_make_a_reloc (&vars, (bfd_vma) 0, BFD_RELOC_LO16, text);
97194536Sobrien	  pe_ILF_make_a_symbol_reloc (&vars, (bfd_vma) 4, BFD_RELOC_LO16,
97294536Sobrien				      (struct symbol_cache_entry **) imp_sym,
97394536Sobrien				      imp_index);
97484865Sobrien	}
97584865Sobrien      else
97684865Sobrien#endif
97794536Sobrien	pe_ILF_make_a_symbol_reloc (&vars, (bfd_vma) jtab[i].offset,
97894536Sobrien				    BFD_RELOC_32, (asymbol **) imp_sym,
97994536Sobrien				    imp_index);
98084865Sobrien
98184865Sobrien      pe_ILF_save_relocs (& vars, text);
98284865Sobrien      break;
98384865Sobrien
98484865Sobrien    case IMPORT_DATA:
98584865Sobrien      break;
98684865Sobrien
98784865Sobrien    default:
98884865Sobrien      /* XXX code not yet written.  */
98984865Sobrien      abort ();
99084865Sobrien    }
99184865Sobrien
99284865Sobrien  /* Initialise the bfd.  */
99384865Sobrien  memset (& internal_f, 0, sizeof (internal_f));
99484865Sobrien
99584865Sobrien  internal_f.f_magic  = magic;
99684865Sobrien  internal_f.f_symptr = 0;
99784865Sobrien  internal_f.f_nsyms  = 0;
99884865Sobrien  internal_f.f_flags  = F_AR32WR | F_LNNO; /* XXX is this correct ?  */
99984865Sobrien
100094536Sobrien  if (   ! bfd_set_start_address (abfd, (bfd_vma) 0)
100184865Sobrien      || ! bfd_coff_set_arch_mach_hook (abfd, & internal_f))
100284865Sobrien    return false;
100384865Sobrien
100484865Sobrien  if (bfd_coff_mkobject_hook (abfd, (PTR) & internal_f, NULL) == NULL)
100584865Sobrien    return false;
100684865Sobrien
100784865Sobrien  coff_data (abfd)->pe = 1;
100884865Sobrien#ifdef THUMBPEMAGIC
100984865Sobrien  if (vars.magic == THUMBPEMAGIC)
101084865Sobrien    /* Stop some linker warnings about thumb code not supporting interworking.  */
101184865Sobrien    coff_data (abfd)->flags |= F_INTERWORK | F_INTERWORK_SET;
101284865Sobrien#endif
101384865Sobrien
101484865Sobrien  /* Switch from file contents to memory contents.  */
101584865Sobrien  bfd_cache_close (abfd);
101684865Sobrien
101784865Sobrien  abfd->iostream = (PTR) vars.bim;
101884865Sobrien  abfd->flags |= BFD_IN_MEMORY /* | HAS_LOCALS */;
101984865Sobrien  abfd->where = 0;
102084865Sobrien  obj_sym_filepos (abfd) = 0;
102184865Sobrien
102284865Sobrien  /* Now create a symbol describing the imported value.  */
102384865Sobrien  switch (import_type)
102484865Sobrien    {
102584865Sobrien    case IMPORT_CODE:
102684865Sobrien      pe_ILF_make_a_symbol (& vars, "", symbol_name, text,
102784865Sobrien			    BSF_NOT_AT_END | BSF_FUNCTION);
102884865Sobrien
102984865Sobrien      /* Create an import symbol for the DLL, without the
103084865Sobrien       .dll suffix.  */
103184865Sobrien      ptr = strrchr (source_dll, '.');
103284865Sobrien      if (ptr)
103384865Sobrien	* ptr = 0;
103484865Sobrien      pe_ILF_make_a_symbol (& vars, "__IMPORT_DESCRIPTOR_", source_dll, NULL, 0);
103584865Sobrien      if (ptr)
103684865Sobrien	* ptr = '.';
103784865Sobrien      break;
103884865Sobrien
103984865Sobrien    case IMPORT_DATA:
104084865Sobrien      /* Nothing to do here.  */
104184865Sobrien      break;
104284865Sobrien
104384865Sobrien    default:
104484865Sobrien      /* XXX code not yet written.  */
104584865Sobrien      abort ();
104684865Sobrien    }
104784865Sobrien
104884865Sobrien  /* Point the bfd at the symbol table.  */
104984865Sobrien  obj_symbols (abfd) = vars.sym_cache;
105084865Sobrien  bfd_get_symcount (abfd) = vars.sym_index;
105184865Sobrien
105284865Sobrien  obj_raw_syments (abfd) = vars.native_syms;
105384865Sobrien  obj_raw_syment_count (abfd) = vars.sym_index;
105484865Sobrien
105584865Sobrien  obj_coff_external_syms (abfd) = (PTR) vars.esym_table;
105684865Sobrien  obj_coff_keep_syms (abfd) = true;
105784865Sobrien
105884865Sobrien  obj_convert (abfd) = vars.sym_table;
105984865Sobrien  obj_conv_table_size (abfd) = vars.sym_index;
106084865Sobrien
106184865Sobrien  obj_coff_strings (abfd) = vars.string_table;
106284865Sobrien  obj_coff_keep_strings (abfd) = true;
106384865Sobrien
106484865Sobrien  abfd->flags |= HAS_SYMS;
106584865Sobrien
106684865Sobrien  return true;
106784865Sobrien}
106884865Sobrien
106984865Sobrien/* We have detected a Image Library Format archive element.
107084865Sobrien   Decode the element and return the appropriate target.  */
107184865Sobrienstatic const bfd_target *
107284865Sobrienpe_ILF_object_p (bfd * abfd)
107384865Sobrien{
107484865Sobrien  bfd_byte        buffer[16];
107584865Sobrien  bfd_byte *      ptr;
107684865Sobrien  bfd_byte *      symbol_name;
107784865Sobrien  bfd_byte *      source_dll;
107884865Sobrien  unsigned int    machine;
107994536Sobrien  bfd_size_type   size;
108084865Sobrien  unsigned int    ordinal;
108184865Sobrien  unsigned int    types;
108294536Sobrien  unsigned int    magic;
108384865Sobrien
108484865Sobrien  /* Upon entry the first four buyes of the ILF header have
108584865Sobrien      already been read.  Now read the rest of the header.  */
108694536Sobrien  if (bfd_bread (buffer, (bfd_size_type) 16, abfd) != 16)
108784865Sobrien    return NULL;
108884865Sobrien
108984865Sobrien  ptr = buffer;
109084865Sobrien
109184865Sobrien  /*  We do not bother to check the version number.
109294536Sobrien      version = H_GET_16 (abfd, ptr);  */
109384865Sobrien  ptr += 2;
109484865Sobrien
109594536Sobrien  machine = H_GET_16 (abfd, ptr);
109684865Sobrien  ptr += 2;
109784865Sobrien
109884865Sobrien  /* Check that the machine type is recognised.  */
109984865Sobrien  magic = 0;
110084865Sobrien
110184865Sobrien  switch (machine)
110284865Sobrien    {
110384865Sobrien    case IMAGE_FILE_MACHINE_UNKNOWN:
110484865Sobrien    case IMAGE_FILE_MACHINE_ALPHA:
110584865Sobrien    case IMAGE_FILE_MACHINE_ALPHA64:
110684865Sobrien    case IMAGE_FILE_MACHINE_IA64:
110784865Sobrien      break;
110884865Sobrien
110984865Sobrien    case IMAGE_FILE_MACHINE_I386:
111084865Sobrien#ifdef I386MAGIC
111184865Sobrien      magic = I386MAGIC;
111284865Sobrien#endif
111384865Sobrien      break;
111484865Sobrien
111584865Sobrien    case IMAGE_FILE_MACHINE_M68K:
111684865Sobrien#ifdef MC68AGIC
111784865Sobrien      magic = MC68MAGIC;
111884865Sobrien#endif
111984865Sobrien      break;
112084865Sobrien
112184865Sobrien    case IMAGE_FILE_MACHINE_R3000:
112284865Sobrien    case IMAGE_FILE_MACHINE_R4000:
112384865Sobrien    case IMAGE_FILE_MACHINE_R10000:
112484865Sobrien
112584865Sobrien    case IMAGE_FILE_MACHINE_MIPS16:
112684865Sobrien    case IMAGE_FILE_MACHINE_MIPSFPU:
112784865Sobrien    case IMAGE_FILE_MACHINE_MIPSFPU16:
112884865Sobrien#ifdef MIPS_ARCH_MAGIC_WINCE
112984865Sobrien      magic = MIPS_ARCH_MAGIC_WINCE;
113084865Sobrien#endif
113184865Sobrien      break;
113284865Sobrien
113384865Sobrien    case IMAGE_FILE_MACHINE_SH3:
113484865Sobrien    case IMAGE_FILE_MACHINE_SH4:
113584865Sobrien#ifdef SH_ARCH_MAGIC_WINCE
113684865Sobrien      magic = SH_ARCH_MAGIC_WINCE;
113784865Sobrien#endif
113884865Sobrien      break;
113984865Sobrien
114084865Sobrien    case IMAGE_FILE_MACHINE_ARM:
114184865Sobrien#ifdef ARMPEMAGIC
114284865Sobrien      magic = ARMPEMAGIC;
114384865Sobrien#endif
114484865Sobrien      break;
114584865Sobrien
114684865Sobrien    case IMAGE_FILE_MACHINE_THUMB:
114784865Sobrien#ifdef THUMBPEMAGIC
114884865Sobrien      {
114984865Sobrien	extern const bfd_target TARGET_LITTLE_SYM;
115084865Sobrien
115184865Sobrien	if (abfd->xvec == & TARGET_LITTLE_SYM)
115284865Sobrien	  magic = THUMBPEMAGIC;
115384865Sobrien      }
115484865Sobrien#endif
115584865Sobrien      break;
115684865Sobrien
115784865Sobrien    case IMAGE_FILE_MACHINE_POWERPC:
115884865Sobrien      /* We no longer support PowerPC.  */
115984865Sobrien    default:
116084865Sobrien      _bfd_error_handler
116184865Sobrien	(
116284865Sobrien_("%s: Unrecognised machine type (0x%x) in Import Library Format archive"),
116394536Sobrien         bfd_archive_filename (abfd), machine);
116484865Sobrien      bfd_set_error (bfd_error_malformed_archive);
116584865Sobrien
116684865Sobrien      return NULL;
116784865Sobrien      break;
116884865Sobrien    }
116984865Sobrien
117084865Sobrien  if (magic == 0)
117184865Sobrien    {
117284865Sobrien      _bfd_error_handler
117384865Sobrien	(
117484865Sobrien_("%s: Recognised but unhandled machine type (0x%x) in Import Library Format archive"),
117594536Sobrien	 bfd_archive_filename (abfd), machine);
117684865Sobrien      bfd_set_error (bfd_error_wrong_format);
117784865Sobrien
117884865Sobrien      return NULL;
117984865Sobrien    }
118084865Sobrien
118184865Sobrien  /* We do not bother to check the date.
118294536Sobrien     date = H_GET_32 (abfd, ptr);  */
118384865Sobrien  ptr += 4;
118484865Sobrien
118594536Sobrien  size = H_GET_32 (abfd, ptr);
118684865Sobrien  ptr += 4;
118784865Sobrien
118884865Sobrien  if (size == 0)
118984865Sobrien    {
119084865Sobrien      _bfd_error_handler
119184865Sobrien	(_("%s: size field is zero in Import Library Format header"),
119294536Sobrien	 bfd_archive_filename (abfd));
119384865Sobrien      bfd_set_error (bfd_error_malformed_archive);
119484865Sobrien
119584865Sobrien      return NULL;
119684865Sobrien    }
119784865Sobrien
119894536Sobrien  ordinal = H_GET_16 (abfd, ptr);
119984865Sobrien  ptr += 2;
120084865Sobrien
120194536Sobrien  types = H_GET_16 (abfd, ptr);
120284865Sobrien  /* ptr += 2; */
120384865Sobrien
120484865Sobrien  /* Now read in the two strings that follow.  */
120584865Sobrien  ptr = bfd_alloc (abfd, size);
120684865Sobrien  if (ptr == NULL)
120784865Sobrien    return NULL;
120884865Sobrien
120994536Sobrien  if (bfd_bread (ptr, size, abfd) != size)
121084865Sobrien    return NULL;
121184865Sobrien
121284865Sobrien  symbol_name = ptr;
121384865Sobrien  source_dll  = ptr + strlen (ptr) + 1;
121484865Sobrien
121584865Sobrien  /* Verify that the strings are null terminated.  */
121684865Sobrien  if (ptr[size - 1] != 0 || ((unsigned long) (source_dll - ptr) >= size))
121784865Sobrien    {
121884865Sobrien      _bfd_error_handler
121984865Sobrien	(_("%s: string not null terminated in ILF object file."),
122094536Sobrien	 bfd_archive_filename (abfd));
122184865Sobrien      bfd_set_error (bfd_error_malformed_archive);
122284865Sobrien
122384865Sobrien      return NULL;
122484865Sobrien    }
122584865Sobrien
122684865Sobrien  /* Now construct the bfd.  */
122784865Sobrien  if (! pe_ILF_build_a_bfd (abfd, magic, symbol_name,
122884865Sobrien			    source_dll, ordinal, types))
122984865Sobrien    return NULL;
123084865Sobrien
123184865Sobrien  return abfd->xvec;
123284865Sobrien}
123384865Sobrien
123484865Sobrienstatic const bfd_target *
123584865Sobrienpe_bfd_object_p (bfd * abfd)
123684865Sobrien{
123784865Sobrien  bfd_byte buffer[4];
123884865Sobrien  struct external_PEI_DOS_hdr dos_hdr;
123984865Sobrien  struct external_PEI_IMAGE_hdr image_hdr;
124084865Sobrien  file_ptr offset;
124184865Sobrien
124284865Sobrien  /* Detect if this a Microsoft Import Library Format element.  */
124394536Sobrien  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
124494536Sobrien      || bfd_bread (buffer, (bfd_size_type) 4, abfd) != 4)
124584865Sobrien    {
124684865Sobrien      if (bfd_get_error () != bfd_error_system_call)
124784865Sobrien	bfd_set_error (bfd_error_wrong_format);
124884865Sobrien      return NULL;
124984865Sobrien    }
125084865Sobrien
125194536Sobrien  if (H_GET_32 (abfd, buffer) == 0xffff0000)
125284865Sobrien    return pe_ILF_object_p (abfd);
125384865Sobrien
125494536Sobrien  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
125594536Sobrien      || bfd_bread (&dos_hdr, (bfd_size_type) sizeof (dos_hdr), abfd)
125684865Sobrien	 != sizeof (dos_hdr))
125784865Sobrien    {
125884865Sobrien      if (bfd_get_error () != bfd_error_system_call)
125984865Sobrien	bfd_set_error (bfd_error_wrong_format);
126084865Sobrien      return NULL;
126184865Sobrien    }
126284865Sobrien
126384865Sobrien  /* There are really two magic numbers involved; the magic number
126484865Sobrien     that says this is a NT executable (PEI) and the magic number that
126584865Sobrien     determines the architecture.  The former is DOSMAGIC, stored in
126684865Sobrien     the e_magic field.  The latter is stored in the f_magic field.
126784865Sobrien     If the NT magic number isn't valid, the architecture magic number
126884865Sobrien     could be mimicked by some other field (specifically, the number
126984865Sobrien     of relocs in section 3).  Since this routine can only be called
127084865Sobrien     correctly for a PEI file, check the e_magic number here, and, if
127184865Sobrien     it doesn't match, clobber the f_magic number so that we don't get
127284865Sobrien     a false match.  */
127394536Sobrien  if (H_GET_16 (abfd, dos_hdr.e_magic) != DOSMAGIC)
127484865Sobrien    {
127584865Sobrien      bfd_set_error (bfd_error_wrong_format);
127684865Sobrien      return NULL;
127784865Sobrien    }
127884865Sobrien
127994536Sobrien  offset = H_GET_32 (abfd, dos_hdr.e_lfanew);
128094536Sobrien  if (bfd_seek (abfd, offset, SEEK_SET) != 0
128194536Sobrien      || (bfd_bread (&image_hdr, (bfd_size_type) sizeof (image_hdr), abfd)
128294536Sobrien	  != sizeof (image_hdr)))
128384865Sobrien    {
128484865Sobrien      if (bfd_get_error () != bfd_error_system_call)
128584865Sobrien	bfd_set_error (bfd_error_wrong_format);
128684865Sobrien      return NULL;
128784865Sobrien    }
128884865Sobrien
128994536Sobrien  if (H_GET_32 (abfd, image_hdr.nt_signature) != 0x4550)
129084865Sobrien    {
129184865Sobrien      bfd_set_error (bfd_error_wrong_format);
129284865Sobrien      return NULL;
129384865Sobrien    }
129484865Sobrien
129584865Sobrien  /* Here is the hack.  coff_object_p wants to read filhsz bytes to
129684865Sobrien     pick up the COFF header for PE, see "struct external_PEI_filehdr"
129784865Sobrien     in include/coff/pe.h.  We adjust so that that will work. */
129894536Sobrien  if (bfd_seek (abfd, (file_ptr) (offset - sizeof (dos_hdr)), SEEK_SET) != 0)
129984865Sobrien    {
130084865Sobrien      if (bfd_get_error () != bfd_error_system_call)
130184865Sobrien	bfd_set_error (bfd_error_wrong_format);
130284865Sobrien      return NULL;
130384865Sobrien    }
130484865Sobrien
130584865Sobrien  return coff_object_p (abfd);
130684865Sobrien}
130784865Sobrien
130884865Sobrien#define coff_object_p pe_bfd_object_p
130984865Sobrien#endif /* COFF_IMAGE_WITH_PE */
1310