184865Sobrien/* Support for the generic parts of PE/PEI, for BFD.
2218822Sdim   Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3218822Sdim   2005, 2006 Free Software Foundation, Inc.
484865Sobrien   Written by Cygnus Solutions.
584865Sobrien
6130561Sobrien   This file is part of BFD, the Binary File Descriptor library.
784865Sobrien
8130561Sobrien   This program is free software; you can redistribute it and/or modify
9130561Sobrien   it under the terms of the GNU General Public License as published by
10130561Sobrien   the Free Software Foundation; either version 2 of the License, or
11130561Sobrien   (at your option) any later version.
1284865Sobrien
13130561Sobrien   This program is distributed in the hope that it will be useful,
14130561Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
15130561Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16130561Sobrien   GNU General Public License for more details.
1784865Sobrien
18130561Sobrien   You should have received a copy of the GNU General Public License
19130561Sobrien   along with this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2184865Sobrien
22130561Sobrien/* Most of this hacked by  Steve Chamberlain,
2384865Sobrien			sac@cygnus.com
2484865Sobrien
25130561Sobrien   PE/PEI rearrangement (and code added): Donn Terry
26130561Sobrien                                       Softway Systems, Inc.  */
2784865Sobrien
2884865Sobrien/* Hey look, some documentation [and in a place you expect to find it]!
2984865Sobrien
3084865Sobrien   The main reference for the pei format is "Microsoft Portable Executable
3184865Sobrien   and Common Object File Format Specification 4.1".  Get it if you need to
3284865Sobrien   do some serious hacking on this code.
3384865Sobrien
3484865Sobrien   Another reference:
3584865Sobrien   "Peering Inside the PE: A Tour of the Win32 Portable Executable
3684865Sobrien   File Format", MSJ 1994, Volume 9.
3784865Sobrien
3884865Sobrien   The *sole* difference between the pe format and the pei format is that the
3984865Sobrien   latter has an MSDOS 2.0 .exe header on the front that prints the message
4084865Sobrien   "This app must be run under Windows." (or some such).
4184865Sobrien   (FIXME: Whether that statement is *really* true or not is unknown.
4284865Sobrien   Are there more subtle differences between pe and pei formats?
4384865Sobrien   For now assume there aren't.  If you find one, then for God sakes
4484865Sobrien   document it here!)
4584865Sobrien
4684865Sobrien   The Microsoft docs use the word "image" instead of "executable" because
4784865Sobrien   the former can also refer to a DLL (shared library).  Confusion can arise
4884865Sobrien   because the `i' in `pei' also refers to "image".  The `pe' format can
4984865Sobrien   also create images (i.e. executables), it's just that to run on a win32
5084865Sobrien   system you need to use the pei format.
5184865Sobrien
5284865Sobrien   FIXME: Please add more docs here so the next poor fool that has to hack
5384865Sobrien   on this code has a chance of getting something accomplished without
54130561Sobrien   wasting too much time.  */
5584865Sobrien
5684865Sobrien#include "libpei.h"
5784865Sobrien
58218822Sdimstatic bfd_boolean (*pe_saved_coff_bfd_print_private_bfd_data) (bfd *, void *) =
5984865Sobrien#ifndef coff_bfd_print_private_bfd_data
6084865Sobrien     NULL;
6184865Sobrien#else
6284865Sobrien     coff_bfd_print_private_bfd_data;
6384865Sobrien#undef coff_bfd_print_private_bfd_data
6484865Sobrien#endif
6584865Sobrien
66218822Sdimstatic bfd_boolean                      pe_print_private_bfd_data (bfd *, void *);
6784865Sobrien#define coff_bfd_print_private_bfd_data pe_print_private_bfd_data
6884865Sobrien
69218822Sdimstatic bfd_boolean (*pe_saved_coff_bfd_copy_private_bfd_data) (bfd *, bfd *) =
7084865Sobrien#ifndef coff_bfd_copy_private_bfd_data
7184865Sobrien     NULL;
7284865Sobrien#else
7384865Sobrien     coff_bfd_copy_private_bfd_data;
7484865Sobrien#undef coff_bfd_copy_private_bfd_data
7584865Sobrien#endif
7684865Sobrien
77218822Sdimstatic bfd_boolean                     pe_bfd_copy_private_bfd_data (bfd *, bfd *);
7884865Sobrien#define coff_bfd_copy_private_bfd_data pe_bfd_copy_private_bfd_data
7984865Sobrien
8084865Sobrien#define coff_mkobject      pe_mkobject
8184865Sobrien#define coff_mkobject_hook pe_mkobject_hook
8284865Sobrien
8384865Sobrien#ifdef COFF_IMAGE_WITH_PE
8484865Sobrien/* This structure contains static variables used by the ILF code.  */
8584865Sobrientypedef asection * asection_ptr;
8684865Sobrien
8784865Sobrientypedef struct
8884865Sobrien{
8984865Sobrien  bfd *			abfd;
9084865Sobrien  bfd_byte *		data;
9184865Sobrien  struct bfd_in_memory * bim;
9284865Sobrien  unsigned short        magic;
9384865Sobrien
9484865Sobrien  arelent *		reltab;
9584865Sobrien  unsigned int 		relcount;
9684865Sobrien
9784865Sobrien  coff_symbol_type * 	sym_cache;
9884865Sobrien  coff_symbol_type * 	sym_ptr;
9984865Sobrien  unsigned int       	sym_index;
10084865Sobrien
10184865Sobrien  unsigned int * 	sym_table;
10284865Sobrien  unsigned int * 	table_ptr;
10384865Sobrien
10484865Sobrien  combined_entry_type * native_syms;
10584865Sobrien  combined_entry_type * native_ptr;
10684865Sobrien
10784865Sobrien  coff_symbol_type **	sym_ptr_table;
10884865Sobrien  coff_symbol_type **	sym_ptr_ptr;
10984865Sobrien
11084865Sobrien  unsigned int		sec_index;
11184865Sobrien
11284865Sobrien  char *                string_table;
11384865Sobrien  char *                string_ptr;
11484865Sobrien  char *		end_string_ptr;
11584865Sobrien
11684865Sobrien  SYMENT *              esym_table;
11784865Sobrien  SYMENT *              esym_ptr;
11884865Sobrien
11984865Sobrien  struct internal_reloc * int_reltab;
12084865Sobrien}
12184865Sobrienpe_ILF_vars;
12284865Sobrien#endif /* COFF_IMAGE_WITH_PE */
123218822Sdim
12484865Sobrien#ifndef NO_COFF_RELOCS
12584865Sobrienstatic void
126218822Sdimcoff_swap_reloc_in (bfd * abfd, void * src, void * dst)
12784865Sobrien{
12884865Sobrien  RELOC *reloc_src = (RELOC *) src;
12984865Sobrien  struct internal_reloc *reloc_dst = (struct internal_reloc *) dst;
13084865Sobrien
131218822Sdim  reloc_dst->r_vaddr  = H_GET_32 (abfd, reloc_src->r_vaddr);
13294536Sobrien  reloc_dst->r_symndx = H_GET_S32 (abfd, reloc_src->r_symndx);
133218822Sdim  reloc_dst->r_type   = H_GET_16 (abfd, reloc_src->r_type);
13484865Sobrien#ifdef SWAP_IN_RELOC_OFFSET
13594536Sobrien  reloc_dst->r_offset = SWAP_IN_RELOC_OFFSET (abfd, reloc_src->r_offset);
13684865Sobrien#endif
13784865Sobrien}
13884865Sobrien
13984865Sobrienstatic unsigned int
140218822Sdimcoff_swap_reloc_out (bfd * abfd, void * src, void * dst)
14184865Sobrien{
142218822Sdim  struct internal_reloc *reloc_src = (struct internal_reloc *) src;
143218822Sdim  struct external_reloc *reloc_dst = (struct external_reloc *) dst;
144218822Sdim
14594536Sobrien  H_PUT_32 (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr);
14694536Sobrien  H_PUT_32 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx);
14794536Sobrien  H_PUT_16 (abfd, reloc_src->r_type, reloc_dst->r_type);
14884865Sobrien
149218822Sdim#ifdef SWAP_OUT_RELOC_OFFSET
15094536Sobrien  SWAP_OUT_RELOC_OFFSET (abfd, reloc_src->r_offset, reloc_dst->r_offset);
15184865Sobrien#endif
15284865Sobrien#ifdef SWAP_OUT_RELOC_EXTRA
153218822Sdim  SWAP_OUT_RELOC_EXTRA (abfd, reloc_src, reloc_dst);
15484865Sobrien#endif
15584865Sobrien  return RELSZ;
15684865Sobrien}
15784865Sobrien#endif /* not NO_COFF_RELOCS */
15884865Sobrien
15984865Sobrienstatic void
160218822Sdimcoff_swap_filehdr_in (bfd * abfd, void * src, void * dst)
16184865Sobrien{
16284865Sobrien  FILHDR *filehdr_src = (FILHDR *) src;
16384865Sobrien  struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst;
16484865Sobrien
165218822Sdim  filehdr_dst->f_magic  = H_GET_16 (abfd, filehdr_src->f_magic);
166218822Sdim  filehdr_dst->f_nscns  = H_GET_16 (abfd, filehdr_src->f_nscns);
167218822Sdim  filehdr_dst->f_timdat = H_GET_32 (abfd, filehdr_src->f_timdat);
168218822Sdim  filehdr_dst->f_nsyms  = H_GET_32 (abfd, filehdr_src->f_nsyms);
169218822Sdim  filehdr_dst->f_flags  = H_GET_16 (abfd, filehdr_src->f_flags);
17094536Sobrien  filehdr_dst->f_symptr = H_GET_32 (abfd, filehdr_src->f_symptr);
17184865Sobrien
17284865Sobrien  /* Other people's tools sometimes generate headers with an nsyms but
17384865Sobrien     a zero symptr.  */
17484865Sobrien  if (filehdr_dst->f_nsyms != 0 && filehdr_dst->f_symptr == 0)
17584865Sobrien    {
17684865Sobrien      filehdr_dst->f_nsyms = 0;
17784865Sobrien      filehdr_dst->f_flags |= F_LSYMS;
17884865Sobrien    }
17984865Sobrien
18094536Sobrien  filehdr_dst->f_opthdr = H_GET_16 (abfd, filehdr_src-> f_opthdr);
18184865Sobrien}
18284865Sobrien
18384865Sobrien#ifdef COFF_IMAGE_WITH_PE
18484865Sobrien# define coff_swap_filehdr_out _bfd_XXi_only_swap_filehdr_out
185218822Sdim#elif defined COFF_WITH_pex64
186218822Sdim# define coff_swap_filehdr_out _bfd_pex64_only_swap_filehdr_out
187218822Sdim#elif defined COFF_WITH_pep
188218822Sdim# define coff_swap_filehdr_out _bfd_pep_only_swap_filehdr_out
18984865Sobrien#else
19084865Sobrien# define coff_swap_filehdr_out _bfd_pe_only_swap_filehdr_out
19184865Sobrien#endif
19284865Sobrien
19384865Sobrienstatic void
194218822Sdimcoff_swap_scnhdr_in (bfd * abfd, void * ext, void * in)
19584865Sobrien{
19684865Sobrien  SCNHDR *scnhdr_ext = (SCNHDR *) ext;
19784865Sobrien  struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
19884865Sobrien
199218822Sdim  memcpy (scnhdr_int->s_name, scnhdr_ext->s_name, sizeof (scnhdr_int->s_name));
200218822Sdim
201218822Sdim  scnhdr_int->s_vaddr   = GET_SCNHDR_VADDR (abfd, scnhdr_ext->s_vaddr);
202218822Sdim  scnhdr_int->s_paddr   = GET_SCNHDR_PADDR (abfd, scnhdr_ext->s_paddr);
203218822Sdim  scnhdr_int->s_size    = GET_SCNHDR_SIZE (abfd, scnhdr_ext->s_size);
204218822Sdim  scnhdr_int->s_scnptr  = GET_SCNHDR_SCNPTR (abfd, scnhdr_ext->s_scnptr);
205218822Sdim  scnhdr_int->s_relptr  = GET_SCNHDR_RELPTR (abfd, scnhdr_ext->s_relptr);
20694536Sobrien  scnhdr_int->s_lnnoptr = GET_SCNHDR_LNNOPTR (abfd, scnhdr_ext->s_lnnoptr);
207218822Sdim  scnhdr_int->s_flags   = H_GET_32 (abfd, scnhdr_ext->s_flags);
20884865Sobrien
20984865Sobrien  /* MS handles overflow of line numbers by carrying into the reloc
21084865Sobrien     field (it appears).  Since it's supposed to be zero for PE
21184865Sobrien     *IMAGE* format, that's safe.  This is still a bit iffy.  */
21284865Sobrien#ifdef COFF_IMAGE_WITH_PE
21394536Sobrien  scnhdr_int->s_nlnno = (H_GET_16 (abfd, scnhdr_ext->s_nlnno)
21494536Sobrien			 + (H_GET_16 (abfd, scnhdr_ext->s_nreloc) << 16));
21584865Sobrien  scnhdr_int->s_nreloc = 0;
21684865Sobrien#else
21794536Sobrien  scnhdr_int->s_nreloc = H_GET_16 (abfd, scnhdr_ext->s_nreloc);
21894536Sobrien  scnhdr_int->s_nlnno = H_GET_16 (abfd, scnhdr_ext->s_nlnno);
21984865Sobrien#endif
22084865Sobrien
22184865Sobrien  if (scnhdr_int->s_vaddr != 0)
22284865Sobrien    {
22384865Sobrien      scnhdr_int->s_vaddr += pe_data (abfd)->pe_opthdr.ImageBase;
224218822Sdim      /* Do not cut upper 32-bits for 64-bit vma.  */
225218822Sdim#ifndef COFF_WITH_pex64
22684865Sobrien      scnhdr_int->s_vaddr &= 0xffffffff;
227218822Sdim#endif
22884865Sobrien    }
22984865Sobrien
23084865Sobrien#ifndef COFF_NO_HACK_SCNHDR_SIZE
231130561Sobrien  /* If this section holds uninitialized data and is from an object file
232130561Sobrien     or from an executable image that has not initialized the field,
233130561Sobrien     or if the image is an executable file and the physical size is padded,
234130561Sobrien     use the virtual size (stored in s_paddr) instead.  */
235130561Sobrien  if (scnhdr_int->s_paddr > 0
236130561Sobrien      && (((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0
237130561Sobrien	   && (! bfd_pe_executable_p (abfd) || scnhdr_int->s_size == 0))
238130561Sobrien          || (bfd_pe_executable_p (abfd) && scnhdr_int->s_size > scnhdr_int->s_paddr)))
239218822Sdim  /* This code used to set scnhdr_int->s_paddr to 0.  However,
240218822Sdim     coff_set_alignment_hook stores s_paddr in virt_size, which
241218822Sdim     only works if it correctly holds the virtual size of the
242218822Sdim     section.  */
243218822Sdim    scnhdr_int->s_size = scnhdr_int->s_paddr;
24484865Sobrien#endif
24584865Sobrien}
24684865Sobrien
247130561Sobrienstatic bfd_boolean
248218822Sdimpe_mkobject (bfd * abfd)
24984865Sobrien{
25084865Sobrien  pe_data_type *pe;
25194536Sobrien  bfd_size_type amt = sizeof (pe_data_type);
25284865Sobrien
25394536Sobrien  abfd->tdata.pe_obj_data = (struct pe_tdata *) bfd_zalloc (abfd, amt);
25494536Sobrien
25584865Sobrien  if (abfd->tdata.pe_obj_data == 0)
256130561Sobrien    return FALSE;
25784865Sobrien
25884865Sobrien  pe = pe_data (abfd);
25984865Sobrien
26084865Sobrien  pe->coff.pe = 1;
26184865Sobrien
26284865Sobrien  /* in_reloc_p is architecture dependent.  */
26384865Sobrien  pe->in_reloc_p = in_reloc_p;
26484865Sobrien
26584865Sobrien#ifdef PEI_FORCE_MINIMUM_ALIGNMENT
26684865Sobrien  pe->force_minimum_alignment = 1;
26784865Sobrien#endif
26884865Sobrien#ifdef PEI_TARGET_SUBSYSTEM
26984865Sobrien  pe->target_subsystem = PEI_TARGET_SUBSYSTEM;
27084865Sobrien#endif
27184865Sobrien
272130561Sobrien  return TRUE;
27384865Sobrien}
27484865Sobrien
27584865Sobrien/* Create the COFF backend specific information.  */
276218822Sdim
277218822Sdimstatic void *
278218822Sdimpe_mkobject_hook (bfd * abfd,
279218822Sdim		  void * filehdr,
280218822Sdim		  void * aouthdr ATTRIBUTE_UNUSED)
28184865Sobrien{
28284865Sobrien  struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
28384865Sobrien  pe_data_type *pe;
28484865Sobrien
285107492Sobrien  if (! pe_mkobject (abfd))
28684865Sobrien    return NULL;
28784865Sobrien
28884865Sobrien  pe = pe_data (abfd);
28984865Sobrien  pe->coff.sym_filepos = internal_f->f_symptr;
29084865Sobrien  /* These members communicate important constants about the symbol
29184865Sobrien     table to GDB's symbol-reading code.  These `constants'
29284865Sobrien     unfortunately vary among coff implementations...  */
29384865Sobrien  pe->coff.local_n_btmask = N_BTMASK;
29484865Sobrien  pe->coff.local_n_btshft = N_BTSHFT;
29584865Sobrien  pe->coff.local_n_tmask = N_TMASK;
29684865Sobrien  pe->coff.local_n_tshift = N_TSHIFT;
29784865Sobrien  pe->coff.local_symesz = SYMESZ;
29884865Sobrien  pe->coff.local_auxesz = AUXESZ;
29984865Sobrien  pe->coff.local_linesz = LINESZ;
30084865Sobrien
30184865Sobrien  pe->coff.timestamp = internal_f->f_timdat;
30284865Sobrien
30384865Sobrien  obj_raw_syment_count (abfd) =
30484865Sobrien    obj_conv_table_size (abfd) =
30584865Sobrien      internal_f->f_nsyms;
30684865Sobrien
30784865Sobrien  pe->real_flags = internal_f->f_flags;
30884865Sobrien
30984865Sobrien  if ((internal_f->f_flags & F_DLL) != 0)
31084865Sobrien    pe->dll = 1;
31184865Sobrien
31284865Sobrien  if ((internal_f->f_flags & IMAGE_FILE_DEBUG_STRIPPED) == 0)
31384865Sobrien    abfd->flags |= HAS_DEBUG;
31484865Sobrien
31584865Sobrien#ifdef COFF_IMAGE_WITH_PE
31684865Sobrien  if (aouthdr)
317218822Sdim    pe->pe_opthdr = ((struct internal_aouthdr *) aouthdr)->pe;
31884865Sobrien#endif
31984865Sobrien
32084865Sobrien#ifdef ARM
32184865Sobrien  if (! _bfd_coff_arm_set_private_flags (abfd, internal_f->f_flags))
32284865Sobrien    coff_data (abfd) ->flags = 0;
32384865Sobrien#endif
32484865Sobrien
325218822Sdim  return (void *) pe;
32684865Sobrien}
32784865Sobrien
328130561Sobrienstatic bfd_boolean
329218822Sdimpe_print_private_bfd_data (bfd *abfd, void * vfile)
33084865Sobrien{
33184865Sobrien  FILE *file = (FILE *) vfile;
33284865Sobrien
33384865Sobrien  if (!_bfd_XX_print_private_bfd_data_common (abfd, vfile))
334130561Sobrien    return FALSE;
33584865Sobrien
336218822Sdim  if (pe_saved_coff_bfd_print_private_bfd_data == NULL)
337218822Sdim    return TRUE;
33884865Sobrien
339218822Sdim  fputc ('\n', file);
34084865Sobrien
341218822Sdim  return pe_saved_coff_bfd_print_private_bfd_data (abfd, vfile);
34284865Sobrien}
34384865Sobrien
34484865Sobrien/* Copy any private info we understand from the input bfd
34584865Sobrien   to the output bfd.  */
34684865Sobrien
347130561Sobrienstatic bfd_boolean
348218822Sdimpe_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
34984865Sobrien{
350218822Sdim  /* PR binutils/716: Copy the large address aware flag.
351218822Sdim     XXX: Should we be copying other flags or other fields in the pe_data()
352218822Sdim     structure ?  */
353218822Sdim  if (pe_data (obfd) != NULL
354218822Sdim      && pe_data (ibfd) != NULL
355218822Sdim      && pe_data (ibfd)->real_flags & IMAGE_FILE_LARGE_ADDRESS_AWARE)
356218822Sdim    pe_data (obfd)->real_flags |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
357218822Sdim
35884865Sobrien  if (!_bfd_XX_bfd_copy_private_bfd_data_common (ibfd, obfd))
359130561Sobrien    return FALSE;
36084865Sobrien
36184865Sobrien  if (pe_saved_coff_bfd_copy_private_bfd_data)
36284865Sobrien    return pe_saved_coff_bfd_copy_private_bfd_data (ibfd, obfd);
36384865Sobrien
364130561Sobrien  return TRUE;
36584865Sobrien}
36684865Sobrien
36784865Sobrien#define coff_bfd_copy_private_section_data \
36884865Sobrien  _bfd_XX_bfd_copy_private_section_data
36984865Sobrien
37084865Sobrien#define coff_get_symbol_info _bfd_XX_get_symbol_info
37184865Sobrien
37284865Sobrien#ifdef COFF_IMAGE_WITH_PE
37384865Sobrien
37484865Sobrien/* Code to handle Microsoft's Image Library Format.
37584865Sobrien   Also known as LINK6 format.
37684865Sobrien   Documentation about this format can be found at:
37784865Sobrien
37884865Sobrien   http://msdn.microsoft.com/library/specs/pecoff_section8.htm  */
37984865Sobrien
38084865Sobrien/* The following constants specify the sizes of the various data
38184865Sobrien   structures that we have to create in order to build a bfd describing
38284865Sobrien   an ILF object file.  The final "+ 1" in the definitions of SIZEOF_IDATA6
38384865Sobrien   and SIZEOF_IDATA7 below is to allow for the possibility that we might
38484865Sobrien   need a padding byte in order to ensure 16 bit alignment for the section's
38584865Sobrien   contents.
38684865Sobrien
38784865Sobrien   The value for SIZEOF_ILF_STRINGS is computed as follows:
38884865Sobrien
38984865Sobrien      There will be NUM_ILF_SECTIONS section symbols.  Allow 9 characters
39084865Sobrien      per symbol for their names (longest section name is .idata$x).
39184865Sobrien
39284865Sobrien      There will be two symbols for the imported value, one the symbol name
39384865Sobrien      and one with _imp__ prefixed.  Allowing for the terminating nul's this
39484865Sobrien      is strlen (symbol_name) * 2 + 8 + 21 + strlen (source_dll).
39584865Sobrien
39684865Sobrien      The strings in the string table must start STRING__SIZE_SIZE bytes into
39784865Sobrien      the table in order to for the string lookup code in coffgen/coffcode to
39884865Sobrien      work.  */
39984865Sobrien#define NUM_ILF_RELOCS		8
40084865Sobrien#define NUM_ILF_SECTIONS        6
40184865Sobrien#define NUM_ILF_SYMS 		(2 + NUM_ILF_SECTIONS)
40284865Sobrien
403218822Sdim#define SIZEOF_ILF_SYMS		 (NUM_ILF_SYMS * sizeof (* vars.sym_cache))
404218822Sdim#define SIZEOF_ILF_SYM_TABLE	 (NUM_ILF_SYMS * sizeof (* vars.sym_table))
405218822Sdim#define SIZEOF_ILF_NATIVE_SYMS	 (NUM_ILF_SYMS * sizeof (* vars.native_syms))
40684865Sobrien#define SIZEOF_ILF_SYM_PTR_TABLE (NUM_ILF_SYMS * sizeof (* vars.sym_ptr_table))
407218822Sdim#define SIZEOF_ILF_EXT_SYMS	 (NUM_ILF_SYMS * sizeof (* vars.esym_table))
408218822Sdim#define SIZEOF_ILF_RELOCS	 (NUM_ILF_RELOCS * sizeof (* vars.reltab))
409218822Sdim#define SIZEOF_ILF_INT_RELOCS	 (NUM_ILF_RELOCS * sizeof (* vars.int_reltab))
410218822Sdim#define SIZEOF_ILF_STRINGS	 (strlen (symbol_name) * 2 + 8 \
41184865Sobrien					+ 21 + strlen (source_dll) \
41284865Sobrien					+ NUM_ILF_SECTIONS * 9 \
41384865Sobrien					+ STRING_SIZE_SIZE)
41484865Sobrien#define SIZEOF_IDATA2		(5 * 4)
415218822Sdim
416218822Sdim/* For PEx64 idata4 & 5 have thumb size of 8 bytes.  */
417218822Sdim#ifdef COFF_WITH_pex64
418218822Sdim#define SIZEOF_IDATA4		(2 * 4)
419218822Sdim#define SIZEOF_IDATA5		(2 * 4)
420218822Sdim#else
42184865Sobrien#define SIZEOF_IDATA4		(1 * 4)
42284865Sobrien#define SIZEOF_IDATA5		(1 * 4)
423218822Sdim#endif
424218822Sdim
42584865Sobrien#define SIZEOF_IDATA6		(2 + strlen (symbol_name) + 1 + 1)
42684865Sobrien#define SIZEOF_IDATA7		(strlen (source_dll) + 1 + 1)
42784865Sobrien#define SIZEOF_ILF_SECTIONS     (NUM_ILF_SECTIONS * sizeof (struct coff_section_tdata))
42884865Sobrien
42984865Sobrien#define ILF_DATA_SIZE				\
43084865Sobrien      sizeof (* vars.bim)			\
43184865Sobrien    + SIZEOF_ILF_SYMS				\
43284865Sobrien    + SIZEOF_ILF_SYM_TABLE			\
43384865Sobrien    + SIZEOF_ILF_NATIVE_SYMS			\
43484865Sobrien    + SIZEOF_ILF_SYM_PTR_TABLE			\
43584865Sobrien    + SIZEOF_ILF_EXT_SYMS			\
43684865Sobrien    + SIZEOF_ILF_RELOCS				\
43784865Sobrien    + SIZEOF_ILF_INT_RELOCS			\
43884865Sobrien    + SIZEOF_ILF_STRINGS			\
43984865Sobrien    + SIZEOF_IDATA2				\
44084865Sobrien    + SIZEOF_IDATA4				\
44184865Sobrien    + SIZEOF_IDATA5				\
44284865Sobrien    + SIZEOF_IDATA6				\
44384865Sobrien    + SIZEOF_IDATA7				\
44484865Sobrien    + SIZEOF_ILF_SECTIONS			\
44584865Sobrien    + MAX_TEXT_SECTION_SIZE
44684865Sobrien
44784865Sobrien/* Create an empty relocation against the given symbol.  */
448218822Sdim
44984865Sobrienstatic void
450218822Sdimpe_ILF_make_a_symbol_reloc (pe_ILF_vars *               vars,
451218822Sdim			    bfd_vma                     address,
452218822Sdim			    bfd_reloc_code_real_type    reloc,
453218822Sdim			    struct bfd_symbol **  	sym,
454218822Sdim			    unsigned int                sym_index)
45584865Sobrien{
45684865Sobrien  arelent * entry;
45784865Sobrien  struct internal_reloc * internal;
45884865Sobrien
45984865Sobrien  entry = vars->reltab + vars->relcount;
46084865Sobrien  internal = vars->int_reltab + vars->relcount;
46184865Sobrien
46284865Sobrien  entry->address     = address;
46384865Sobrien  entry->addend      = 0;
46484865Sobrien  entry->howto       = bfd_reloc_type_lookup (vars->abfd, reloc);
46584865Sobrien  entry->sym_ptr_ptr = sym;
46684865Sobrien
46784865Sobrien  internal->r_vaddr  = address;
46884865Sobrien  internal->r_symndx = sym_index;
46984865Sobrien  internal->r_type   = entry->howto->type;
47084865Sobrien
47184865Sobrien  vars->relcount ++;
47284865Sobrien
47384865Sobrien  BFD_ASSERT (vars->relcount <= NUM_ILF_RELOCS);
47484865Sobrien}
47584865Sobrien
47684865Sobrien/* Create an empty relocation against the given section.  */
477218822Sdim
47884865Sobrienstatic void
47984865Sobrienpe_ILF_make_a_reloc (pe_ILF_vars *             vars,
48084865Sobrien		     bfd_vma                   address,
48184865Sobrien		     bfd_reloc_code_real_type  reloc,
48284865Sobrien		     asection_ptr              sec)
48384865Sobrien{
48484865Sobrien  pe_ILF_make_a_symbol_reloc (vars, address, reloc, sec->symbol_ptr_ptr,
48584865Sobrien			      coff_section_data (vars->abfd, sec)->i);
48684865Sobrien}
48784865Sobrien
48884865Sobrien/* Move the queued relocs into the given section.  */
489218822Sdim
49084865Sobrienstatic void
49184865Sobrienpe_ILF_save_relocs (pe_ILF_vars * vars,
49284865Sobrien		    asection_ptr  sec)
49384865Sobrien{
49484865Sobrien  /* Make sure that there is somewhere to store the internal relocs.  */
49584865Sobrien  if (coff_section_data (vars->abfd, sec) == NULL)
49684865Sobrien    /* We should probably return an error indication here.  */
49784865Sobrien    abort ();
49884865Sobrien
49984865Sobrien  coff_section_data (vars->abfd, sec)->relocs = vars->int_reltab;
500130561Sobrien  coff_section_data (vars->abfd, sec)->keep_relocs = TRUE;
50184865Sobrien
50284865Sobrien  sec->relocation  = vars->reltab;
50384865Sobrien  sec->reloc_count = vars->relcount;
50484865Sobrien  sec->flags      |= SEC_RELOC;
50584865Sobrien
50684865Sobrien  vars->reltab     += vars->relcount;
50784865Sobrien  vars->int_reltab += vars->relcount;
50884865Sobrien  vars->relcount   = 0;
50984865Sobrien
51094536Sobrien  BFD_ASSERT ((bfd_byte *) vars->int_reltab < (bfd_byte *) vars->string_table);
51184865Sobrien}
51284865Sobrien
51384865Sobrien/* Create a global symbol and add it to the relevant tables.  */
514218822Sdim
51584865Sobrienstatic void
51684865Sobrienpe_ILF_make_a_symbol (pe_ILF_vars *  vars,
51784865Sobrien		      const char *   prefix,
51884865Sobrien		      const char *   symbol_name,
51984865Sobrien		      asection_ptr   section,
52084865Sobrien		      flagword       extra_flags)
52184865Sobrien{
52284865Sobrien  coff_symbol_type * sym;
52384865Sobrien  combined_entry_type * ent;
52484865Sobrien  SYMENT * esym;
52584865Sobrien  unsigned short sclass;
52684865Sobrien
52784865Sobrien  if (extra_flags & BSF_LOCAL)
52884865Sobrien    sclass = C_STAT;
52984865Sobrien  else
53084865Sobrien    sclass = C_EXT;
53184865Sobrien
53284865Sobrien#ifdef THUMBPEMAGIC
53384865Sobrien  if (vars->magic == THUMBPEMAGIC)
53484865Sobrien    {
53584865Sobrien      if (extra_flags & BSF_FUNCTION)
53684865Sobrien	sclass = C_THUMBEXTFUNC;
53784865Sobrien      else if (extra_flags & BSF_LOCAL)
53884865Sobrien	sclass = C_THUMBSTAT;
53984865Sobrien      else
54084865Sobrien	sclass = C_THUMBEXT;
54184865Sobrien    }
54284865Sobrien#endif
54384865Sobrien
54484865Sobrien  BFD_ASSERT (vars->sym_index < NUM_ILF_SYMS);
54584865Sobrien
54684865Sobrien  sym = vars->sym_ptr;
54784865Sobrien  ent = vars->native_ptr;
54884865Sobrien  esym = vars->esym_ptr;
54984865Sobrien
55084865Sobrien  /* Copy the symbol's name into the string table.  */
55184865Sobrien  sprintf (vars->string_ptr, "%s%s", prefix, symbol_name);
55284865Sobrien
55384865Sobrien  if (section == NULL)
55484865Sobrien    section = (asection_ptr) & bfd_und_section;
55584865Sobrien
55684865Sobrien  /* Initialise the external symbol.  */
55794536Sobrien  H_PUT_32 (vars->abfd, vars->string_ptr - vars->string_table,
55894536Sobrien	    esym->e.e.e_offset);
55994536Sobrien  H_PUT_16 (vars->abfd, section->target_index, esym->e_scnum);
56084865Sobrien  esym->e_sclass[0] = sclass;
56184865Sobrien
56284865Sobrien  /* The following initialisations are unnecessary - the memory is
56384865Sobrien     zero initialised.  They are just kept here as reminders.  */
56484865Sobrien
56584865Sobrien  /* Initialise the internal symbol structure.  */
56684865Sobrien  ent->u.syment.n_sclass          = sclass;
56784865Sobrien  ent->u.syment.n_scnum           = section->target_index;
56884865Sobrien  ent->u.syment._n._n_n._n_offset = (long) sym;
56984865Sobrien
57084865Sobrien  sym->symbol.the_bfd = vars->abfd;
57184865Sobrien  sym->symbol.name    = vars->string_ptr;
57284865Sobrien  sym->symbol.flags   = BSF_EXPORT | BSF_GLOBAL | extra_flags;
57384865Sobrien  sym->symbol.section = section;
57484865Sobrien  sym->native         = ent;
57584865Sobrien
57684865Sobrien  * vars->table_ptr = vars->sym_index;
57784865Sobrien  * vars->sym_ptr_ptr = sym;
57884865Sobrien
57984865Sobrien  /* Adjust pointers for the next symbol.  */
58084865Sobrien  vars->sym_index ++;
58184865Sobrien  vars->sym_ptr ++;
58284865Sobrien  vars->sym_ptr_ptr ++;
58384865Sobrien  vars->table_ptr ++;
58484865Sobrien  vars->native_ptr ++;
58584865Sobrien  vars->esym_ptr ++;
58684865Sobrien  vars->string_ptr += strlen (symbol_name) + strlen (prefix) + 1;
58784865Sobrien
58884865Sobrien  BFD_ASSERT (vars->string_ptr < vars->end_string_ptr);
58984865Sobrien}
59084865Sobrien
59184865Sobrien/* Create a section.  */
592218822Sdim
59384865Sobrienstatic asection_ptr
59484865Sobrienpe_ILF_make_a_section (pe_ILF_vars * vars,
59584865Sobrien		       const char *  name,
59684865Sobrien		       unsigned int  size,
59784865Sobrien		       flagword      extra_flags)
59884865Sobrien{
59984865Sobrien  asection_ptr sec;
60084865Sobrien  flagword     flags;
60184865Sobrien
60284865Sobrien  sec = bfd_make_section_old_way (vars->abfd, name);
60384865Sobrien  if (sec == NULL)
60484865Sobrien    return NULL;
60584865Sobrien
60684865Sobrien  flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_IN_MEMORY;
60784865Sobrien
60884865Sobrien  bfd_set_section_flags (vars->abfd, sec, flags | extra_flags);
60984865Sobrien
610223262Sbenl  (void) bfd_set_section_alignment (vars->abfd, sec, 2);
61184865Sobrien
61284865Sobrien  /* Check that we will not run out of space.  */
61384865Sobrien  BFD_ASSERT (vars->data + size < vars->bim->buffer + vars->bim->size);
61484865Sobrien
61584865Sobrien  /* Set the section size and contents.  The actual
61684865Sobrien     contents are filled in by our parent.  */
61794536Sobrien  bfd_set_section_size (vars->abfd, sec, (bfd_size_type) size);
61884865Sobrien  sec->contents = vars->data;
61984865Sobrien  sec->target_index = vars->sec_index ++;
62084865Sobrien
62184865Sobrien  /* Advance data pointer in the vars structure.  */
62284865Sobrien  vars->data += size;
62384865Sobrien
62484865Sobrien  /* Skip the padding byte if it was not needed.
62584865Sobrien     The logic here is that if the string length is odd,
62684865Sobrien     then the entire string length, including the null byte,
62784865Sobrien     is even and so the extra, padding byte, is not needed.  */
62884865Sobrien  if (size & 1)
62984865Sobrien    vars->data --;
63084865Sobrien
63184865Sobrien  /* Create a coff_section_tdata structure for our use.  */
63284865Sobrien  sec->used_by_bfd = (struct coff_section_tdata *) vars->data;
63384865Sobrien  vars->data += sizeof (struct coff_section_tdata);
63484865Sobrien
63584865Sobrien  BFD_ASSERT (vars->data <= vars->bim->buffer + vars->bim->size);
63684865Sobrien
63784865Sobrien  /* Create a symbol to refer to this section.  */
63884865Sobrien  pe_ILF_make_a_symbol (vars, "", name, sec, BSF_LOCAL);
63984865Sobrien
64084865Sobrien  /* Cache the index to the symbol in the coff_section_data structure.  */
64184865Sobrien  coff_section_data (vars->abfd, sec)->i = vars->sym_index - 1;
64284865Sobrien
64384865Sobrien  return sec;
64484865Sobrien}
64584865Sobrien
64684865Sobrien/* This structure contains the code that goes into the .text section
64784865Sobrien   in order to perform a jump into the DLL lookup table.  The entries
64884865Sobrien   in the table are index by the magic number used to represent the
64984865Sobrien   machine type in the PE file.  The contents of the data[] arrays in
65084865Sobrien   these entries are stolen from the jtab[] arrays in ld/pe-dll.c.
65184865Sobrien   The SIZE field says how many bytes in the DATA array are actually
65284865Sobrien   used.  The OFFSET field says where in the data array the address
65384865Sobrien   of the .idata$5 section should be placed.  */
65484865Sobrien#define MAX_TEXT_SECTION_SIZE 32
65584865Sobrien
65684865Sobrientypedef struct
65784865Sobrien{
65884865Sobrien  unsigned short magic;
65984865Sobrien  unsigned char  data[MAX_TEXT_SECTION_SIZE];
66084865Sobrien  unsigned int   size;
66184865Sobrien  unsigned int   offset;
66284865Sobrien}
66384865Sobrienjump_table;
66484865Sobrien
66584865Sobrienstatic jump_table jtab[] =
66684865Sobrien{
66784865Sobrien#ifdef I386MAGIC
66884865Sobrien  { I386MAGIC,
66984865Sobrien    { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 },
67084865Sobrien    8, 2
67184865Sobrien  },
67284865Sobrien#endif
67384865Sobrien
674218822Sdim#ifdef AMD64MAGIC
675218822Sdim  { AMD64MAGIC,
676218822Sdim    { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90 },
677218822Sdim    8, 2
678218822Sdim  },
679218822Sdim#endif
680218822Sdim
68184865Sobrien#ifdef  MC68MAGIC
682218822Sdim  { MC68MAGIC,
683218822Sdim    { /* XXX fill me in */ },
684218822Sdim    0, 0
685218822Sdim  },
68684865Sobrien#endif
687218822Sdim
68884865Sobrien#ifdef  MIPS_ARCH_MAGIC_WINCE
68984865Sobrien  { MIPS_ARCH_MAGIC_WINCE,
69084865Sobrien    { 0x00, 0x00, 0x08, 0x3c, 0x00, 0x00, 0x08, 0x8d,
69184865Sobrien      0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 },
69284865Sobrien    16, 0
69384865Sobrien  },
69484865Sobrien#endif
69584865Sobrien
69684865Sobrien#ifdef  SH_ARCH_MAGIC_WINCE
69784865Sobrien  { SH_ARCH_MAGIC_WINCE,
69884865Sobrien    { 0x01, 0xd0, 0x02, 0x60, 0x2b, 0x40,
69984865Sobrien      0x09, 0x00, 0x00, 0x00, 0x00, 0x00 },
70084865Sobrien    12, 8
70184865Sobrien  },
70284865Sobrien#endif
70384865Sobrien
70484865Sobrien#ifdef  ARMPEMAGIC
70584865Sobrien  { ARMPEMAGIC,
70684865Sobrien    { 0x00, 0xc0, 0x9f, 0xe5, 0x00, 0xf0,
70784865Sobrien      0x9c, 0xe5, 0x00, 0x00, 0x00, 0x00},
70884865Sobrien    12, 8
70984865Sobrien  },
71084865Sobrien#endif
71184865Sobrien
71284865Sobrien#ifdef  THUMBPEMAGIC
71384865Sobrien  { THUMBPEMAGIC,
71484865Sobrien    { 0x40, 0xb4, 0x02, 0x4e, 0x36, 0x68, 0xb4, 0x46,
71584865Sobrien      0x40, 0xbc, 0x60, 0x47, 0x00, 0x00, 0x00, 0x00 },
71684865Sobrien    16, 12
71784865Sobrien  },
71884865Sobrien#endif
71984865Sobrien  { 0, { 0 }, 0, 0 }
72084865Sobrien};
72184865Sobrien
72284865Sobrien#ifndef NUM_ENTRIES
72384865Sobrien#define NUM_ENTRIES(a) (sizeof (a) / sizeof (a)[0])
72484865Sobrien#endif
72584865Sobrien
72684865Sobrien/* Build a full BFD from the information supplied in a ILF object.  */
727218822Sdim
728130561Sobrienstatic bfd_boolean
72984865Sobrienpe_ILF_build_a_bfd (bfd *           abfd,
73094536Sobrien		    unsigned int    magic,
731218822Sdim		    char *          symbol_name,
732218822Sdim		    char *          source_dll,
73384865Sobrien		    unsigned int    ordinal,
73484865Sobrien		    unsigned int    types)
73584865Sobrien{
73684865Sobrien  bfd_byte *               ptr;
73784865Sobrien  pe_ILF_vars              vars;
73884865Sobrien  struct internal_filehdr  internal_f;
73984865Sobrien  unsigned int             import_type;
74084865Sobrien  unsigned int             import_name_type;
74184865Sobrien  asection_ptr             id4, id5, id6 = NULL, text = NULL;
74284865Sobrien  coff_symbol_type **      imp_sym;
74384865Sobrien  unsigned int             imp_index;
74484865Sobrien
74584865Sobrien  /* Decode and verify the types field of the ILF structure.  */
74684865Sobrien  import_type = types & 0x3;
74784865Sobrien  import_name_type = (types & 0x1c) >> 2;
74884865Sobrien
74984865Sobrien  switch (import_type)
75084865Sobrien    {
75184865Sobrien    case IMPORT_CODE:
75284865Sobrien    case IMPORT_DATA:
75384865Sobrien      break;
75484865Sobrien
75584865Sobrien    case IMPORT_CONST:
75684865Sobrien      /* XXX code yet to be written.  */
757218822Sdim      _bfd_error_handler (_("%B: Unhandled import type; %x"),
758218822Sdim			  abfd, import_type);
759130561Sobrien      return FALSE;
76084865Sobrien
76184865Sobrien    default:
762218822Sdim      _bfd_error_handler (_("%B: Unrecognised import type; %x"),
763218822Sdim			  abfd, import_type);
764130561Sobrien      return FALSE;
76584865Sobrien    }
76684865Sobrien
76784865Sobrien  switch (import_name_type)
76884865Sobrien    {
76984865Sobrien    case IMPORT_ORDINAL:
77084865Sobrien    case IMPORT_NAME:
77184865Sobrien    case IMPORT_NAME_NOPREFIX:
77284865Sobrien    case IMPORT_NAME_UNDECORATE:
77384865Sobrien      break;
77484865Sobrien
77584865Sobrien    default:
776218822Sdim      _bfd_error_handler (_("%B: Unrecognised import name type; %x"),
777218822Sdim			  abfd, import_name_type);
778130561Sobrien      return FALSE;
77984865Sobrien    }
78084865Sobrien
78184865Sobrien  /* Initialise local variables.
78284865Sobrien
78384865Sobrien     Note these are kept in a structure rather than being
78484865Sobrien     declared as statics since bfd frowns on global variables.
78584865Sobrien
78684865Sobrien     We are going to construct the contents of the BFD in memory,
78784865Sobrien     so allocate all the space that we will need right now.  */
78894536Sobrien  ptr = bfd_zalloc (abfd, (bfd_size_type) ILF_DATA_SIZE);
78984865Sobrien  if (ptr == NULL)
790130561Sobrien    return FALSE;
79184865Sobrien
79284865Sobrien  /* Create a bfd_in_memory structure.  */
79384865Sobrien  vars.bim = (struct bfd_in_memory *) ptr;
79484865Sobrien  vars.bim->buffer = ptr;
79584865Sobrien  vars.bim->size   = ILF_DATA_SIZE;
79684865Sobrien  ptr += sizeof (* vars.bim);
79784865Sobrien
79884865Sobrien  /* Initialise the pointers to regions of the memory and the
79984865Sobrien     other contents of the pe_ILF_vars structure as well.  */
80084865Sobrien  vars.sym_cache = (coff_symbol_type *) ptr;
80184865Sobrien  vars.sym_ptr   = (coff_symbol_type *) ptr;
80284865Sobrien  vars.sym_index = 0;
80384865Sobrien  ptr += SIZEOF_ILF_SYMS;
80484865Sobrien
80584865Sobrien  vars.sym_table = (unsigned int *) ptr;
80684865Sobrien  vars.table_ptr = (unsigned int *) ptr;
80784865Sobrien  ptr += SIZEOF_ILF_SYM_TABLE;
80884865Sobrien
80984865Sobrien  vars.native_syms = (combined_entry_type *) ptr;
81084865Sobrien  vars.native_ptr  = (combined_entry_type *) ptr;
81184865Sobrien  ptr += SIZEOF_ILF_NATIVE_SYMS;
81284865Sobrien
81384865Sobrien  vars.sym_ptr_table = (coff_symbol_type **) ptr;
81484865Sobrien  vars.sym_ptr_ptr   = (coff_symbol_type **) ptr;
81584865Sobrien  ptr += SIZEOF_ILF_SYM_PTR_TABLE;
81684865Sobrien
81784865Sobrien  vars.esym_table = (SYMENT *) ptr;
81884865Sobrien  vars.esym_ptr   = (SYMENT *) ptr;
81984865Sobrien  ptr += SIZEOF_ILF_EXT_SYMS;
82084865Sobrien
82184865Sobrien  vars.reltab   = (arelent *) ptr;
82284865Sobrien  vars.relcount = 0;
82384865Sobrien  ptr += SIZEOF_ILF_RELOCS;
82484865Sobrien
82584865Sobrien  vars.int_reltab  = (struct internal_reloc *) ptr;
82684865Sobrien  ptr += SIZEOF_ILF_INT_RELOCS;
82784865Sobrien
828218822Sdim  vars.string_table = (char *) ptr;
829218822Sdim  vars.string_ptr   = (char *) ptr + STRING_SIZE_SIZE;
83084865Sobrien  ptr += SIZEOF_ILF_STRINGS;
831218822Sdim  vars.end_string_ptr = (char *) ptr;
83284865Sobrien
83384865Sobrien  /* The remaining space in bim->buffer is used
83484865Sobrien     by the pe_ILF_make_a_section() function.  */
83584865Sobrien  vars.data = ptr;
83684865Sobrien  vars.abfd = abfd;
83784865Sobrien  vars.sec_index = 0;
83884865Sobrien  vars.magic = magic;
83984865Sobrien
84084865Sobrien  /* Create the initial .idata$<n> sections:
84184865Sobrien     [.idata$2:  Import Directory Table -- not needed]
84284865Sobrien     .idata$4:  Import Lookup Table
84384865Sobrien     .idata$5:  Import Address Table
84484865Sobrien
84584865Sobrien     Note we do not create a .idata$3 section as this is
84684865Sobrien     created for us by the linker script.  */
84784865Sobrien  id4 = pe_ILF_make_a_section (& vars, ".idata$4", SIZEOF_IDATA4, 0);
84884865Sobrien  id5 = pe_ILF_make_a_section (& vars, ".idata$5", SIZEOF_IDATA5, 0);
84984865Sobrien  if (id4 == NULL || id5 == NULL)
850130561Sobrien    return FALSE;
85184865Sobrien
85284865Sobrien  /* Fill in the contents of these sections.  */
85384865Sobrien  if (import_name_type == IMPORT_ORDINAL)
85484865Sobrien    {
85584865Sobrien      if (ordinal == 0)
85684865Sobrien	/* XXX - treat as IMPORT_NAME ??? */
85784865Sobrien	abort ();
85884865Sobrien
859218822Sdim#ifdef COFF_WITH_pex64
860218822Sdim      ((unsigned int *) id4->contents)[0] = ordinal;
861218822Sdim      ((unsigned int *) id4->contents)[1] = 0x80000000;
862218822Sdim      ((unsigned int *) id5->contents)[0] = ordinal;
863218822Sdim      ((unsigned int *) id5->contents)[1] = 0x80000000;
864218822Sdim#else
86584865Sobrien      * (unsigned int *) id4->contents = ordinal | 0x80000000;
86684865Sobrien      * (unsigned int *) id5->contents = ordinal | 0x80000000;
867218822Sdim#endif
86884865Sobrien    }
86984865Sobrien  else
87084865Sobrien    {
87184865Sobrien      char * symbol;
872218822Sdim      unsigned int len;
87384865Sobrien
87484865Sobrien      /* Create .idata$6 - the Hint Name Table.  */
87584865Sobrien      id6 = pe_ILF_make_a_section (& vars, ".idata$6", SIZEOF_IDATA6, 0);
87684865Sobrien      if (id6 == NULL)
877130561Sobrien	return FALSE;
87884865Sobrien
87984865Sobrien      /* If necessary, trim the import symbol name.  */
88084865Sobrien      symbol = symbol_name;
88184865Sobrien
882218822Sdim      /* As used by MS compiler, '_', '@', and '?' are alternative
883218822Sdim	 forms of USER_LABEL_PREFIX, with '?' for c++ mangled names,
884218822Sdim	 '@' used for fastcall (in C),  '_' everywhere else.  Only one
885218822Sdim	 of these is used for a symbol.  We strip this leading char for
886218822Sdim	 IMPORT_NAME_NOPREFIX and IMPORT_NAME_UNDECORATE as per the
887218822Sdim	 PE COFF 6.0 spec (section 8.3, Import Name Type).  */
888218822Sdim
88984865Sobrien      if (import_name_type != IMPORT_NAME)
890130561Sobrien	{
891218822Sdim	  char c = symbol[0];
892218822Sdim	  if (c == '_' || c == '@' || c == '?')
893218822Sdim	    symbol++;
894130561Sobrien	}
895130561Sobrien
896218822Sdim      len = strlen (symbol);
89784865Sobrien      if (import_name_type == IMPORT_NAME_UNDECORATE)
89884865Sobrien	{
899218822Sdim	  /* Truncate at the first '@'.  */
900218822Sdim	  char *at = strchr (symbol, '@');
90184865Sobrien
902218822Sdim	  if (at != NULL)
903218822Sdim	    len = at - symbol;
90484865Sobrien	}
90584865Sobrien
90684865Sobrien      id6->contents[0] = ordinal & 0xff;
90784865Sobrien      id6->contents[1] = ordinal >> 8;
90884865Sobrien
909218822Sdim      memcpy ((char *) id6->contents + 2, symbol, len);
910218822Sdim      id6->contents[len + 2] = '\0';
91184865Sobrien    }
91284865Sobrien
91384865Sobrien  if (import_name_type != IMPORT_ORDINAL)
91484865Sobrien    {
91594536Sobrien      pe_ILF_make_a_reloc (&vars, (bfd_vma) 0, BFD_RELOC_RVA, id6);
91694536Sobrien      pe_ILF_save_relocs (&vars, id4);
91784865Sobrien
91894536Sobrien      pe_ILF_make_a_reloc (&vars, (bfd_vma) 0, BFD_RELOC_RVA, id6);
91994536Sobrien      pe_ILF_save_relocs (&vars, id5);
92084865Sobrien    }
92184865Sobrien
92284865Sobrien  /* Create extra sections depending upon the type of import we are dealing with.  */
92384865Sobrien  switch (import_type)
92484865Sobrien    {
92584865Sobrien      int i;
92684865Sobrien
92784865Sobrien    case IMPORT_CODE:
92884865Sobrien      /* Create a .text section.
92984865Sobrien	 First we need to look up its contents in the jump table.  */
93084865Sobrien      for (i = NUM_ENTRIES (jtab); i--;)
93184865Sobrien	{
93284865Sobrien	  if (jtab[i].size == 0)
93384865Sobrien	    continue;
93484865Sobrien	  if (jtab[i].magic == magic)
93584865Sobrien	    break;
93684865Sobrien	}
93784865Sobrien      /* If we did not find a matching entry something is wrong.  */
93884865Sobrien      if (i < 0)
93984865Sobrien	abort ();
94084865Sobrien
94184865Sobrien      /* Create the .text section.  */
94284865Sobrien      text = pe_ILF_make_a_section (& vars, ".text", jtab[i].size, SEC_CODE);
94384865Sobrien      if (text == NULL)
944130561Sobrien	return FALSE;
94584865Sobrien
94684865Sobrien      /* Copy in the jump code.  */
94784865Sobrien      memcpy (text->contents, jtab[i].data, jtab[i].size);
94884865Sobrien
94984865Sobrien      /* Create an import symbol.  */
95084865Sobrien      pe_ILF_make_a_symbol (& vars, "__imp_", symbol_name, id5, 0);
95184865Sobrien      imp_sym   = vars.sym_ptr_ptr - 1;
95284865Sobrien      imp_index = vars.sym_index - 1;
95384865Sobrien
95484865Sobrien      /* Create a reloc for the data in the text section.  */
95584865Sobrien#ifdef MIPS_ARCH_MAGIC_WINCE
95684865Sobrien      if (magic == MIPS_ARCH_MAGIC_WINCE)
95784865Sobrien	{
95894536Sobrien	  pe_ILF_make_a_symbol_reloc (&vars, (bfd_vma) 0, BFD_RELOC_HI16_S,
959130561Sobrien				      (struct bfd_symbol **) imp_sym,
96094536Sobrien				      imp_index);
96194536Sobrien	  pe_ILF_make_a_reloc (&vars, (bfd_vma) 0, BFD_RELOC_LO16, text);
96294536Sobrien	  pe_ILF_make_a_symbol_reloc (&vars, (bfd_vma) 4, BFD_RELOC_LO16,
963130561Sobrien				      (struct bfd_symbol **) imp_sym,
96494536Sobrien				      imp_index);
96584865Sobrien	}
96684865Sobrien      else
96784865Sobrien#endif
96894536Sobrien	pe_ILF_make_a_symbol_reloc (&vars, (bfd_vma) jtab[i].offset,
96994536Sobrien				    BFD_RELOC_32, (asymbol **) imp_sym,
97094536Sobrien				    imp_index);
97184865Sobrien
97284865Sobrien      pe_ILF_save_relocs (& vars, text);
97384865Sobrien      break;
97484865Sobrien
97584865Sobrien    case IMPORT_DATA:
97684865Sobrien      break;
97784865Sobrien
97884865Sobrien    default:
97984865Sobrien      /* XXX code not yet written.  */
98084865Sobrien      abort ();
98184865Sobrien    }
98284865Sobrien
98384865Sobrien  /* Initialise the bfd.  */
98484865Sobrien  memset (& internal_f, 0, sizeof (internal_f));
98584865Sobrien
98684865Sobrien  internal_f.f_magic  = magic;
98784865Sobrien  internal_f.f_symptr = 0;
98884865Sobrien  internal_f.f_nsyms  = 0;
98984865Sobrien  internal_f.f_flags  = F_AR32WR | F_LNNO; /* XXX is this correct ?  */
99084865Sobrien
99194536Sobrien  if (   ! bfd_set_start_address (abfd, (bfd_vma) 0)
99284865Sobrien      || ! bfd_coff_set_arch_mach_hook (abfd, & internal_f))
993130561Sobrien    return FALSE;
99484865Sobrien
995218822Sdim  if (bfd_coff_mkobject_hook (abfd, (void *) & internal_f, NULL) == NULL)
996130561Sobrien    return FALSE;
99784865Sobrien
99884865Sobrien  coff_data (abfd)->pe = 1;
99984865Sobrien#ifdef THUMBPEMAGIC
100084865Sobrien  if (vars.magic == THUMBPEMAGIC)
100184865Sobrien    /* Stop some linker warnings about thumb code not supporting interworking.  */
100284865Sobrien    coff_data (abfd)->flags |= F_INTERWORK | F_INTERWORK_SET;
100384865Sobrien#endif
100484865Sobrien
100584865Sobrien  /* Switch from file contents to memory contents.  */
100684865Sobrien  bfd_cache_close (abfd);
100784865Sobrien
1008218822Sdim  abfd->iostream = (void *) vars.bim;
100984865Sobrien  abfd->flags |= BFD_IN_MEMORY /* | HAS_LOCALS */;
101084865Sobrien  abfd->where = 0;
101184865Sobrien  obj_sym_filepos (abfd) = 0;
101284865Sobrien
101384865Sobrien  /* Now create a symbol describing the imported value.  */
101484865Sobrien  switch (import_type)
101584865Sobrien    {
101684865Sobrien    case IMPORT_CODE:
101784865Sobrien      pe_ILF_make_a_symbol (& vars, "", symbol_name, text,
101884865Sobrien			    BSF_NOT_AT_END | BSF_FUNCTION);
101984865Sobrien
102084865Sobrien      /* Create an import symbol for the DLL, without the
102184865Sobrien       .dll suffix.  */
1022218822Sdim      ptr = (bfd_byte *) strrchr (source_dll, '.');
102384865Sobrien      if (ptr)
102484865Sobrien	* ptr = 0;
102584865Sobrien      pe_ILF_make_a_symbol (& vars, "__IMPORT_DESCRIPTOR_", source_dll, NULL, 0);
102684865Sobrien      if (ptr)
102784865Sobrien	* ptr = '.';
102884865Sobrien      break;
102984865Sobrien
103084865Sobrien    case IMPORT_DATA:
103184865Sobrien      /* Nothing to do here.  */
103284865Sobrien      break;
103384865Sobrien
103484865Sobrien    default:
103584865Sobrien      /* XXX code not yet written.  */
103684865Sobrien      abort ();
103784865Sobrien    }
103884865Sobrien
103984865Sobrien  /* Point the bfd at the symbol table.  */
104084865Sobrien  obj_symbols (abfd) = vars.sym_cache;
104184865Sobrien  bfd_get_symcount (abfd) = vars.sym_index;
104284865Sobrien
104384865Sobrien  obj_raw_syments (abfd) = vars.native_syms;
104484865Sobrien  obj_raw_syment_count (abfd) = vars.sym_index;
104584865Sobrien
1046218822Sdim  obj_coff_external_syms (abfd) = (void *) vars.esym_table;
1047130561Sobrien  obj_coff_keep_syms (abfd) = TRUE;
104884865Sobrien
104984865Sobrien  obj_convert (abfd) = vars.sym_table;
105084865Sobrien  obj_conv_table_size (abfd) = vars.sym_index;
105184865Sobrien
105284865Sobrien  obj_coff_strings (abfd) = vars.string_table;
1053130561Sobrien  obj_coff_keep_strings (abfd) = TRUE;
105484865Sobrien
105584865Sobrien  abfd->flags |= HAS_SYMS;
105684865Sobrien
1057130561Sobrien  return TRUE;
105884865Sobrien}
105984865Sobrien
106084865Sobrien/* We have detected a Image Library Format archive element.
106184865Sobrien   Decode the element and return the appropriate target.  */
1062218822Sdim
106384865Sobrienstatic const bfd_target *
106484865Sobrienpe_ILF_object_p (bfd * abfd)
106584865Sobrien{
106684865Sobrien  bfd_byte        buffer[16];
106784865Sobrien  bfd_byte *      ptr;
1068218822Sdim  char *          symbol_name;
1069218822Sdim  char *          source_dll;
107084865Sobrien  unsigned int    machine;
107194536Sobrien  bfd_size_type   size;
107284865Sobrien  unsigned int    ordinal;
107384865Sobrien  unsigned int    types;
107494536Sobrien  unsigned int    magic;
107584865Sobrien
107684865Sobrien  /* Upon entry the first four buyes of the ILF header have
107784865Sobrien      already been read.  Now read the rest of the header.  */
107894536Sobrien  if (bfd_bread (buffer, (bfd_size_type) 16, abfd) != 16)
107984865Sobrien    return NULL;
108084865Sobrien
108184865Sobrien  ptr = buffer;
108284865Sobrien
108384865Sobrien  /*  We do not bother to check the version number.
108494536Sobrien      version = H_GET_16 (abfd, ptr);  */
108584865Sobrien  ptr += 2;
108684865Sobrien
108794536Sobrien  machine = H_GET_16 (abfd, ptr);
108884865Sobrien  ptr += 2;
108984865Sobrien
109084865Sobrien  /* Check that the machine type is recognised.  */
109184865Sobrien  magic = 0;
109284865Sobrien
109384865Sobrien  switch (machine)
109484865Sobrien    {
109584865Sobrien    case IMAGE_FILE_MACHINE_UNKNOWN:
109684865Sobrien    case IMAGE_FILE_MACHINE_ALPHA:
109784865Sobrien    case IMAGE_FILE_MACHINE_ALPHA64:
109884865Sobrien    case IMAGE_FILE_MACHINE_IA64:
109984865Sobrien      break;
110084865Sobrien
110184865Sobrien    case IMAGE_FILE_MACHINE_I386:
110284865Sobrien#ifdef I386MAGIC
110384865Sobrien      magic = I386MAGIC;
110484865Sobrien#endif
110584865Sobrien      break;
110684865Sobrien
1107218822Sdim    case IMAGE_FILE_MACHINE_AMD64:
1108218822Sdim#ifdef AMD64MAGIC
1109218822Sdim      magic = AMD64MAGIC;
1110218822Sdim#endif
1111218822Sdim      break;
1112218822Sdim
111384865Sobrien    case IMAGE_FILE_MACHINE_M68K:
111484865Sobrien#ifdef MC68AGIC
111584865Sobrien      magic = MC68MAGIC;
111684865Sobrien#endif
111784865Sobrien      break;
111884865Sobrien
111984865Sobrien    case IMAGE_FILE_MACHINE_R3000:
112084865Sobrien    case IMAGE_FILE_MACHINE_R4000:
112184865Sobrien    case IMAGE_FILE_MACHINE_R10000:
112284865Sobrien
112384865Sobrien    case IMAGE_FILE_MACHINE_MIPS16:
112484865Sobrien    case IMAGE_FILE_MACHINE_MIPSFPU:
112584865Sobrien    case IMAGE_FILE_MACHINE_MIPSFPU16:
112684865Sobrien#ifdef MIPS_ARCH_MAGIC_WINCE
112784865Sobrien      magic = MIPS_ARCH_MAGIC_WINCE;
112884865Sobrien#endif
112984865Sobrien      break;
113084865Sobrien
113184865Sobrien    case IMAGE_FILE_MACHINE_SH3:
113284865Sobrien    case IMAGE_FILE_MACHINE_SH4:
113384865Sobrien#ifdef SH_ARCH_MAGIC_WINCE
113484865Sobrien      magic = SH_ARCH_MAGIC_WINCE;
113584865Sobrien#endif
113684865Sobrien      break;
113784865Sobrien
113884865Sobrien    case IMAGE_FILE_MACHINE_ARM:
113984865Sobrien#ifdef ARMPEMAGIC
114084865Sobrien      magic = ARMPEMAGIC;
114184865Sobrien#endif
114284865Sobrien      break;
114384865Sobrien
114484865Sobrien    case IMAGE_FILE_MACHINE_THUMB:
114584865Sobrien#ifdef THUMBPEMAGIC
114684865Sobrien      {
114784865Sobrien	extern const bfd_target TARGET_LITTLE_SYM;
114884865Sobrien
114984865Sobrien	if (abfd->xvec == & TARGET_LITTLE_SYM)
115084865Sobrien	  magic = THUMBPEMAGIC;
115184865Sobrien      }
115284865Sobrien#endif
115384865Sobrien      break;
115484865Sobrien
115584865Sobrien    case IMAGE_FILE_MACHINE_POWERPC:
115684865Sobrien      /* We no longer support PowerPC.  */
115784865Sobrien    default:
115884865Sobrien      _bfd_error_handler
1159218822Sdim	(_("%B: Unrecognised machine type (0x%x)"
1160218822Sdim	   " in Import Library Format archive"),
1161218822Sdim	 abfd, machine);
116284865Sobrien      bfd_set_error (bfd_error_malformed_archive);
116384865Sobrien
116484865Sobrien      return NULL;
116584865Sobrien      break;
116684865Sobrien    }
116784865Sobrien
116884865Sobrien  if (magic == 0)
116984865Sobrien    {
117084865Sobrien      _bfd_error_handler
1171218822Sdim	(_("%B: Recognised but unhandled machine type (0x%x)"
1172218822Sdim	   " in Import Library Format archive"),
1173218822Sdim	 abfd, machine);
117484865Sobrien      bfd_set_error (bfd_error_wrong_format);
117584865Sobrien
117684865Sobrien      return NULL;
117784865Sobrien    }
117884865Sobrien
117984865Sobrien  /* We do not bother to check the date.
118094536Sobrien     date = H_GET_32 (abfd, ptr);  */
118184865Sobrien  ptr += 4;
118284865Sobrien
118394536Sobrien  size = H_GET_32 (abfd, ptr);
118484865Sobrien  ptr += 4;
118584865Sobrien
118684865Sobrien  if (size == 0)
118784865Sobrien    {
118884865Sobrien      _bfd_error_handler
1189218822Sdim	(_("%B: size field is zero in Import Library Format header"), abfd);
119084865Sobrien      bfd_set_error (bfd_error_malformed_archive);
119184865Sobrien
119284865Sobrien      return NULL;
119384865Sobrien    }
119484865Sobrien
119594536Sobrien  ordinal = H_GET_16 (abfd, ptr);
119684865Sobrien  ptr += 2;
119784865Sobrien
119894536Sobrien  types = H_GET_16 (abfd, ptr);
119984865Sobrien  /* ptr += 2; */
120084865Sobrien
120184865Sobrien  /* Now read in the two strings that follow.  */
120284865Sobrien  ptr = bfd_alloc (abfd, size);
120384865Sobrien  if (ptr == NULL)
120484865Sobrien    return NULL;
120584865Sobrien
120694536Sobrien  if (bfd_bread (ptr, size, abfd) != size)
1207107492Sobrien    {
1208107492Sobrien      bfd_release (abfd, ptr);
1209107492Sobrien      return NULL;
1210107492Sobrien    }
121184865Sobrien
1212218822Sdim  symbol_name = (char *) ptr;
1213218822Sdim  source_dll  = symbol_name + strlen (symbol_name) + 1;
121484865Sobrien
121584865Sobrien  /* Verify that the strings are null terminated.  */
1216218822Sdim  if (ptr[size - 1] != 0
1217218822Sdim      || (bfd_size_type) ((bfd_byte *) source_dll - ptr) >= size)
121884865Sobrien    {
121984865Sobrien      _bfd_error_handler
1220218822Sdim	(_("%B: string not null terminated in ILF object file."), abfd);
122184865Sobrien      bfd_set_error (bfd_error_malformed_archive);
1222107492Sobrien      bfd_release (abfd, ptr);
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))
1229107492Sobrien    {
1230107492Sobrien      bfd_release (abfd, ptr);
1231107492Sobrien      return NULL;
1232107492Sobrien    }
123384865Sobrien
123484865Sobrien  return abfd->xvec;
123584865Sobrien}
123684865Sobrien
1237218822Sdimenum arch_type
1238218822Sdim{
1239218822Sdim  arch_type_unknown,
1240218822Sdim  arch_type_i386,
1241218822Sdim  arch_type_x86_64
1242218822Sdim};
1243218822Sdim
1244218822Sdimstatic enum arch_type
1245218822Sdimpe_arch (const char *arch)
1246218822Sdim{
1247218822Sdim  if (strcmp (arch, "i386") == 0 || strcmp (arch, "ia32") == 0)
1248218822Sdim    return arch_type_i386;
1249218822Sdim
1250218822Sdim  if (strcmp (arch, "x86_64") == 0 || strcmp (arch, "x86-64") == 0)
1251218822Sdim    return arch_type_x86_64;
1252218822Sdim
1253218822Sdim  return arch_type_unknown;
1254218822Sdim}
1255218822Sdim
125684865Sobrienstatic const bfd_target *
125784865Sobrienpe_bfd_object_p (bfd * abfd)
125884865Sobrien{
125984865Sobrien  bfd_byte buffer[4];
126084865Sobrien  struct external_PEI_DOS_hdr dos_hdr;
126184865Sobrien  struct external_PEI_IMAGE_hdr image_hdr;
126284865Sobrien  file_ptr offset;
1263218822Sdim  const bfd_target *target;
126484865Sobrien
126584865Sobrien  /* Detect if this a Microsoft Import Library Format element.  */
126694536Sobrien  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
126794536Sobrien      || bfd_bread (buffer, (bfd_size_type) 4, abfd) != 4)
126884865Sobrien    {
126984865Sobrien      if (bfd_get_error () != bfd_error_system_call)
127084865Sobrien	bfd_set_error (bfd_error_wrong_format);
127184865Sobrien      return NULL;
127284865Sobrien    }
127384865Sobrien
127494536Sobrien  if (H_GET_32 (abfd, buffer) == 0xffff0000)
127584865Sobrien    return pe_ILF_object_p (abfd);
127684865Sobrien
127794536Sobrien  if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
127894536Sobrien      || bfd_bread (&dos_hdr, (bfd_size_type) sizeof (dos_hdr), abfd)
127984865Sobrien	 != sizeof (dos_hdr))
128084865Sobrien    {
128184865Sobrien      if (bfd_get_error () != bfd_error_system_call)
128284865Sobrien	bfd_set_error (bfd_error_wrong_format);
128384865Sobrien      return NULL;
128484865Sobrien    }
128584865Sobrien
128684865Sobrien  /* There are really two magic numbers involved; the magic number
128784865Sobrien     that says this is a NT executable (PEI) and the magic number that
128884865Sobrien     determines the architecture.  The former is DOSMAGIC, stored in
128984865Sobrien     the e_magic field.  The latter is stored in the f_magic field.
129084865Sobrien     If the NT magic number isn't valid, the architecture magic number
129184865Sobrien     could be mimicked by some other field (specifically, the number
129284865Sobrien     of relocs in section 3).  Since this routine can only be called
129384865Sobrien     correctly for a PEI file, check the e_magic number here, and, if
129484865Sobrien     it doesn't match, clobber the f_magic number so that we don't get
129584865Sobrien     a false match.  */
129694536Sobrien  if (H_GET_16 (abfd, dos_hdr.e_magic) != DOSMAGIC)
129784865Sobrien    {
129884865Sobrien      bfd_set_error (bfd_error_wrong_format);
129984865Sobrien      return NULL;
130084865Sobrien    }
130184865Sobrien
130294536Sobrien  offset = H_GET_32 (abfd, dos_hdr.e_lfanew);
130394536Sobrien  if (bfd_seek (abfd, offset, SEEK_SET) != 0
130494536Sobrien      || (bfd_bread (&image_hdr, (bfd_size_type) sizeof (image_hdr), abfd)
130594536Sobrien	  != sizeof (image_hdr)))
130684865Sobrien    {
130784865Sobrien      if (bfd_get_error () != bfd_error_system_call)
130884865Sobrien	bfd_set_error (bfd_error_wrong_format);
130984865Sobrien      return NULL;
131084865Sobrien    }
131184865Sobrien
131294536Sobrien  if (H_GET_32 (abfd, image_hdr.nt_signature) != 0x4550)
131384865Sobrien    {
131484865Sobrien      bfd_set_error (bfd_error_wrong_format);
131584865Sobrien      return NULL;
131684865Sobrien    }
131784865Sobrien
131884865Sobrien  /* Here is the hack.  coff_object_p wants to read filhsz bytes to
131984865Sobrien     pick up the COFF header for PE, see "struct external_PEI_filehdr"
132084865Sobrien     in include/coff/pe.h.  We adjust so that that will work. */
132194536Sobrien  if (bfd_seek (abfd, (file_ptr) (offset - sizeof (dos_hdr)), SEEK_SET) != 0)
132284865Sobrien    {
132384865Sobrien      if (bfd_get_error () != bfd_error_system_call)
132484865Sobrien	bfd_set_error (bfd_error_wrong_format);
132584865Sobrien      return NULL;
132684865Sobrien    }
132784865Sobrien
1328218822Sdim  target = coff_object_p (abfd);
1329218822Sdim  if (target)
1330218822Sdim    {
1331218822Sdim      pe_data_type *pe = pe_data (abfd);
1332218822Sdim      struct internal_extra_pe_aouthdr *i = &pe->pe_opthdr;
1333218822Sdim      bfd_boolean efi = i->Subsystem == IMAGE_SUBSYSTEM_EFI_APPLICATION;
1334218822Sdim      enum arch_type arch;
1335218822Sdim      const bfd_target * const *target_ptr;
1336218822Sdim
1337218822Sdim      /* Get the machine.  */
1338218822Sdim      if (bfd_target_efi_p (abfd->xvec))
1339218822Sdim	arch = pe_arch (bfd_target_efi_arch (abfd->xvec));
1340218822Sdim      else
1341218822Sdim	arch = pe_arch (bfd_target_pei_arch (abfd->xvec));
1342218822Sdim
1343218822Sdim      for (target_ptr = bfd_target_vector; *target_ptr != NULL;
1344218822Sdim	   target_ptr++)
1345218822Sdim	{
1346218822Sdim	  if (*target_ptr == target
1347218822Sdim	      || (*target_ptr)->flavour != bfd_target_coff_flavour)
1348218822Sdim	    continue;
1349218822Sdim
1350218822Sdim	  if (bfd_target_efi_p (*target_ptr))
1351218822Sdim	    {
1352218822Sdim	      /* Skip incompatible arch.  */
1353218822Sdim	      if (pe_arch (bfd_target_efi_arch (*target_ptr)) != arch)
1354218822Sdim		continue;
1355218822Sdim
1356357351Sdim	      if (efi)
1357357351Sdim		{
1358357351Sdim		  /* TARGET_PTR is an EFI backend.  Don't match
1359357351Sdim		     TARGET with a EFI file.  */
1360357351Sdim		  bfd_set_error (bfd_error_wrong_format);
1361357351Sdim		  return NULL;
1362357351Sdim		}
1363218822Sdim	    }
1364218822Sdim	  else if (bfd_target_pei_p (*target_ptr))
1365218822Sdim	    {
1366218822Sdim	      /* Skip incompatible arch.  */
1367218822Sdim	      if (pe_arch (bfd_target_pei_arch (*target_ptr)) != arch)
1368218822Sdim		continue;
1369218822Sdim
1370357351Sdim	      if (!efi)
1371357351Sdim		{
1372357351Sdim		  /* TARGET_PTR is a PE backend.  Don't match
1373357351Sdim		     TARGET with a PE file.  */
1374357351Sdim		  bfd_set_error (bfd_error_wrong_format);
1375357351Sdim		  return NULL;
1376357351Sdim		}
1377218822Sdim	    }
1378218822Sdim	}
1379218822Sdim    }
1380218822Sdim
1381218822Sdim  return target;
138284865Sobrien}
138384865Sobrien
138484865Sobrien#define coff_object_p pe_bfd_object_p
138584865Sobrien#endif /* COFF_IMAGE_WITH_PE */
1386