Line 1... |
Line 1... |
/* Support for the generic parts of PE/PEI, for BFD.
|
/* Support for the generic parts of PE/PEI, for BFD.
|
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
Written by Cygnus Solutions.
|
Written by Cygnus Solutions.
|
|
|
This file is part of BFD, the Binary File Descriptor library.
|
This file is part of BFD, the Binary File Descriptor library.
|
|
|
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
Line 234... |
Line 234... |
or from an executable image that has not initialized the field,
|
or from an executable image that has not initialized the field,
|
or if the image is an executable file and the physical size is padded,
|
or if the image is an executable file and the physical size is padded,
|
use the virtual size (stored in s_paddr) instead. */
|
use the virtual size (stored in s_paddr) instead. */
|
if (scnhdr_int->s_paddr > 0
|
if (scnhdr_int->s_paddr > 0
|
&& (((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0
|
&& (((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0
|
&& (! bfd_pe_executable_p (abfd) || scnhdr_int->s_size == 0))
|
&& (! bfd_pei_p (abfd) || scnhdr_int->s_size == 0))
|
|| (bfd_pe_executable_p (abfd) && (scnhdr_int->s_size > scnhdr_int->s_paddr))))
|
|| (bfd_pei_p (abfd) && (scnhdr_int->s_size > scnhdr_int->s_paddr))))
|
/* This code used to set scnhdr_int->s_paddr to 0. However,
|
/* This code used to set scnhdr_int->s_paddr to 0. However,
|
coff_set_alignment_hook stores s_paddr in virt_size, which
|
coff_set_alignment_hook stores s_paddr in virt_size, which
|
only works if it correctly holds the virtual size of the
|
only works if it correctly holds the virtual size of the
|
section. */
|
section. */
|
scnhdr_int->s_size = scnhdr_int->s_paddr;
|
scnhdr_int->s_size = scnhdr_int->s_paddr;
|
Line 262... |
Line 262... |
pe->coff.pe = 1;
|
pe->coff.pe = 1;
|
|
|
/* in_reloc_p is architecture dependent. */
|
/* in_reloc_p is architecture dependent. */
|
pe->in_reloc_p = in_reloc_p;
|
pe->in_reloc_p = in_reloc_p;
|
|
|
#ifdef PEI_FORCE_MINIMUM_ALIGNMENT
|
|
pe->force_minimum_alignment = 1;
|
|
#endif
|
|
#ifdef PEI_TARGET_SUBSYSTEM
|
|
pe->target_subsystem = PEI_TARGET_SUBSYSTEM;
|
|
#endif
|
|
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
/* Create the COFF backend specific information. */
|
/* Create the COFF backend specific information. */
|
|
|
Line 427... |
Line 420... |
#define SIZEOF_IDATA6 (2 + strlen (symbol_name) + 1 + 1)
|
#define SIZEOF_IDATA6 (2 + strlen (symbol_name) + 1 + 1)
|
#define SIZEOF_IDATA7 (strlen (source_dll) + 1 + 1)
|
#define SIZEOF_IDATA7 (strlen (source_dll) + 1 + 1)
|
#define SIZEOF_ILF_SECTIONS (NUM_ILF_SECTIONS * sizeof (struct coff_section_tdata))
|
#define SIZEOF_ILF_SECTIONS (NUM_ILF_SECTIONS * sizeof (struct coff_section_tdata))
|
|
|
#define ILF_DATA_SIZE \
|
#define ILF_DATA_SIZE \
|
sizeof (* vars.bim) \
|
|
+ SIZEOF_ILF_SYMS \
|
+ SIZEOF_ILF_SYMS \
|
+ SIZEOF_ILF_SYM_TABLE \
|
+ SIZEOF_ILF_SYM_TABLE \
|
+ SIZEOF_ILF_NATIVE_SYMS \
|
+ SIZEOF_ILF_NATIVE_SYMS \
|
+ SIZEOF_ILF_SYM_PTR_TABLE \
|
+ SIZEOF_ILF_SYM_PTR_TABLE \
|
+ SIZEOF_ILF_EXT_SYMS \
|
+ SIZEOF_ILF_EXT_SYMS \
|
Line 785... |
Line 777... |
Note these are kept in a structure rather than being
|
Note these are kept in a structure rather than being
|
declared as statics since bfd frowns on global variables.
|
declared as statics since bfd frowns on global variables.
|
|
|
We are going to construct the contents of the BFD in memory,
|
We are going to construct the contents of the BFD in memory,
|
so allocate all the space that we will need right now. */
|
so allocate all the space that we will need right now. */
|
ptr = bfd_zalloc (abfd, (bfd_size_type) ILF_DATA_SIZE);
|
vars.bim
|
if (ptr == NULL)
|
= (struct bfd_in_memory *) bfd_malloc ((bfd_size_type) sizeof (*vars.bim));
|
|
if (vars.bim == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
/* Create a bfd_in_memory structure. */
|
ptr = (bfd_byte *) bfd_zmalloc ((bfd_size_type) ILF_DATA_SIZE);
|
vars.bim = (struct bfd_in_memory *) ptr;
|
|
vars.bim->buffer = ptr;
|
vars.bim->buffer = ptr;
|
vars.bim->size = ILF_DATA_SIZE;
|
vars.bim->size = ILF_DATA_SIZE;
|
ptr += sizeof (* vars.bim);
|
if (ptr == NULL)
|
|
goto error_return;
|
|
|
/* Initialise the pointers to regions of the memory and the
|
/* Initialise the pointers to regions of the memory and the
|
other contents of the pe_ILF_vars structure as well. */
|
other contents of the pe_ILF_vars structure as well. */
|
vars.sym_cache = (coff_symbol_type *) ptr;
|
vars.sym_cache = (coff_symbol_type *) ptr;
|
vars.sym_ptr = (coff_symbol_type *) ptr;
|
vars.sym_ptr = (coff_symbol_type *) ptr;
|
Line 847... |
Line 840... |
Note we do not create a .idata$3 section as this is
|
Note we do not create a .idata$3 section as this is
|
created for us by the linker script. */
|
created for us by the linker script. */
|
id4 = pe_ILF_make_a_section (& vars, ".idata$4", SIZEOF_IDATA4, 0);
|
id4 = pe_ILF_make_a_section (& vars, ".idata$4", SIZEOF_IDATA4, 0);
|
id5 = pe_ILF_make_a_section (& vars, ".idata$5", SIZEOF_IDATA5, 0);
|
id5 = pe_ILF_make_a_section (& vars, ".idata$5", SIZEOF_IDATA5, 0);
|
if (id4 == NULL || id5 == NULL)
|
if (id4 == NULL || id5 == NULL)
|
return FALSE;
|
goto error_return;
|
|
|
/* Fill in the contents of these sections. */
|
/* Fill in the contents of these sections. */
|
if (import_name_type == IMPORT_ORDINAL)
|
if (import_name_type == IMPORT_ORDINAL)
|
{
|
{
|
if (ordinal == 0)
|
if (ordinal == 0)
|
Line 874... |
Line 867... |
unsigned int len;
|
unsigned int len;
|
|
|
/* Create .idata$6 - the Hint Name Table. */
|
/* Create .idata$6 - the Hint Name Table. */
|
id6 = pe_ILF_make_a_section (& vars, ".idata$6", SIZEOF_IDATA6, 0);
|
id6 = pe_ILF_make_a_section (& vars, ".idata$6", SIZEOF_IDATA6, 0);
|
if (id6 == NULL)
|
if (id6 == NULL)
|
return FALSE;
|
goto error_return;
|
|
|
/* If necessary, trim the import symbol name. */
|
/* If necessary, trim the import symbol name. */
|
symbol = symbol_name;
|
symbol = symbol_name;
|
|
|
/* As used by MS compiler, '_', '@', and '?' are alternative
|
/* As used by MS compiler, '_', '@', and '?' are alternative
|
Line 941... |
Line 934... |
abort ();
|
abort ();
|
|
|
/* Create the .text section. */
|
/* Create the .text section. */
|
text = pe_ILF_make_a_section (& vars, ".text", jtab[i].size, SEC_CODE);
|
text = pe_ILF_make_a_section (& vars, ".text", jtab[i].size, SEC_CODE);
|
if (text == NULL)
|
if (text == NULL)
|
return FALSE;
|
goto error_return;
|
|
|
/* Copy in the jump code. */
|
/* Copy in the jump code. */
|
memcpy (text->contents, jtab[i].data, jtab[i].size);
|
memcpy (text->contents, jtab[i].data, jtab[i].size);
|
|
|
/* Create an import symbol. */
|
/* Create an import symbol. */
|
Line 990... |
Line 983... |
internal_f.f_nsyms = 0;
|
internal_f.f_nsyms = 0;
|
internal_f.f_flags = F_AR32WR | F_LNNO; /* XXX is this correct ? */
|
internal_f.f_flags = F_AR32WR | F_LNNO; /* XXX is this correct ? */
|
|
|
if ( ! bfd_set_start_address (abfd, (bfd_vma) 0)
|
if ( ! bfd_set_start_address (abfd, (bfd_vma) 0)
|
|| ! bfd_coff_set_arch_mach_hook (abfd, & internal_f))
|
|| ! bfd_coff_set_arch_mach_hook (abfd, & internal_f))
|
return FALSE;
|
goto error_return;
|
|
|
if (bfd_coff_mkobject_hook (abfd, (void *) & internal_f, NULL) == NULL)
|
if (bfd_coff_mkobject_hook (abfd, (void *) & internal_f, NULL) == NULL)
|
return FALSE;
|
goto error_return;
|
|
|
coff_data (abfd)->pe = 1;
|
coff_data (abfd)->pe = 1;
|
#ifdef THUMBPEMAGIC
|
#ifdef THUMBPEMAGIC
|
if (vars.magic == THUMBPEMAGIC)
|
if (vars.magic == THUMBPEMAGIC)
|
/* Stop some linker warnings about thumb code not supporting interworking. */
|
/* Stop some linker warnings about thumb code not supporting interworking. */
|
Line 1055... |
Line 1048... |
obj_coff_keep_strings (abfd) = TRUE;
|
obj_coff_keep_strings (abfd) = TRUE;
|
|
|
abfd->flags |= HAS_SYMS;
|
abfd->flags |= HAS_SYMS;
|
|
|
return TRUE;
|
return TRUE;
|
|
|
|
error_return:
|
|
if (vars.bim->buffer != NULL)
|
|
free (vars.bim->buffer);
|
|
free (vars.bim);
|
|
return FALSE;
|
}
|
}
|
|
|
/* We have detected a Image Library Format archive element.
|
/* We have detected a Image Library Format archive element.
|
Decode the element and return the appropriate target. */
|
Decode the element and return the appropriate target. */
|
|
|
Line 1199... |
Line 1198... |
|
|
types = H_GET_16 (abfd, ptr);
|
types = H_GET_16 (abfd, ptr);
|
/* ptr += 2; */
|
/* ptr += 2; */
|
|
|
/* Now read in the two strings that follow. */
|
/* Now read in the two strings that follow. */
|
ptr = bfd_alloc (abfd, size);
|
ptr = (bfd_byte *) bfd_alloc (abfd, size);
|
if (ptr == NULL)
|
if (ptr == NULL)
|
return NULL;
|
return NULL;
|
|
|
if (bfd_bread (ptr, size, abfd) != size)
|
if (bfd_bread (ptr, size, abfd) != size)
|
{
|
{
|
Line 1234... |
Line 1233... |
}
|
}
|
|
|
return abfd->xvec;
|
return abfd->xvec;
|
}
|
}
|
|
|
enum arch_type
|
|
{
|
|
arch_type_unknown,
|
|
arch_type_i386,
|
|
arch_type_x86_64
|
|
};
|
|
|
|
static enum arch_type
|
|
pe_arch (const char *arch)
|
|
{
|
|
if (strcmp (arch, "i386") == 0 || strcmp (arch, "ia32") == 0)
|
|
return arch_type_i386;
|
|
|
|
if (strcmp (arch, "x86_64") == 0 || strcmp (arch, "x86-64") == 0)
|
|
return arch_type_x86_64;
|
|
|
|
return arch_type_unknown;
|
|
}
|
|
|
|
static const bfd_target *
|
static const bfd_target *
|
pe_bfd_object_p (bfd * abfd)
|
pe_bfd_object_p (bfd * abfd)
|
{
|
{
|
bfd_byte buffer[4];
|
bfd_byte buffer[4];
|
struct external_PEI_DOS_hdr dos_hdr;
|
struct external_PEI_DOS_hdr dos_hdr;
|
struct external_PEI_IMAGE_hdr image_hdr;
|
struct external_PEI_IMAGE_hdr image_hdr;
|
file_ptr offset;
|
file_ptr offset;
|
const bfd_target *target;
|
|
struct bfd_preserve preserve;
|
|
|
|
/* Detect if this a Microsoft Import Library Format element. */
|
/* Detect if this a Microsoft Import Library Format element. */
|
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
|
if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
|
|| bfd_bread (buffer, (bfd_size_type) 4, abfd) != 4)
|
|| bfd_bread (buffer, (bfd_size_type) 4, abfd) != 4)
|
{
|
{
|
Line 1326... |
Line 1304... |
if (bfd_get_error () != bfd_error_system_call)
|
if (bfd_get_error () != bfd_error_system_call)
|
bfd_set_error (bfd_error_wrong_format);
|
bfd_set_error (bfd_error_wrong_format);
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|
preserve.marker = NULL;
|
return coff_object_p (abfd);
|
if (! bfd_preserve_save (abfd, &preserve))
|
|
return NULL;
|
|
|
|
target = coff_object_p (abfd);
|
|
if (target)
|
|
{
|
|
pe_data_type *pe = pe_data (abfd);
|
|
struct internal_extra_pe_aouthdr *i = &pe->pe_opthdr;
|
|
bfd_boolean efi = i->Subsystem == IMAGE_SUBSYSTEM_EFI_APPLICATION
|
|
|| i->Subsystem == IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
|
|
|| i->Subsystem == IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
|
|
enum arch_type arch;
|
|
const bfd_target * const *target_ptr;
|
|
|
|
/* Get the machine. */
|
|
if (bfd_target_efi_app_p (abfd->xvec))
|
|
arch = pe_arch (bfd_target_efi_app_arch (abfd->xvec));
|
|
else if (bfd_target_efi_bsdrv_p (abfd->xvec))
|
|
arch = pe_arch (bfd_target_efi_bsdrv_arch (abfd->xvec));
|
|
else if (bfd_target_efi_rtdrv_p (abfd->xvec))
|
|
arch = pe_arch (bfd_target_efi_rtdrv_arch (abfd->xvec));
|
|
else
|
|
arch = pe_arch (bfd_target_pei_arch (abfd->xvec));
|
|
|
|
/* Don't check PE vs. EFI if arch is unknown. */
|
|
if (arch == arch_type_unknown)
|
|
{
|
|
bfd_preserve_finish (abfd, &preserve);
|
|
return target;
|
|
}
|
|
|
|
for (target_ptr = bfd_target_vector; *target_ptr != NULL;
|
|
target_ptr++)
|
|
{
|
|
if (*target_ptr == target
|
|
|| (*target_ptr)->flavour != bfd_target_coff_flavour)
|
|
continue;
|
|
|
|
if (bfd_target_efi_app_p (*target_ptr))
|
|
{
|
|
/* Skip incompatible arch. */
|
|
if (pe_arch (bfd_target_efi_app_arch (*target_ptr)) != arch)
|
|
continue;
|
|
|
|
if (efi)
|
|
{
|
|
/* TARGET_PTR is an EFI backend. Don't match
|
|
TARGET with a EFI file. */
|
|
bfd_set_error (bfd_error_wrong_format);
|
|
return NULL;
|
|
}
|
|
}
|
|
else if (bfd_target_efi_bsdrv_p (*target_ptr))
|
|
{
|
|
/* Skip incompatible arch. */
|
|
if (pe_arch (bfd_target_efi_bsdrv_arch (*target_ptr)) != arch)
|
|
continue;
|
|
|
|
if (efi)
|
|
{
|
|
/* TARGET_PTR is an EFI backend. Don't match
|
|
TARGET with a EFI file. */
|
|
bfd_set_error (bfd_error_wrong_format);
|
|
return NULL;
|
|
}
|
|
}
|
|
else if (bfd_target_efi_rtdrv_p (*target_ptr))
|
|
{
|
|
/* Skip incompatible arch. */
|
|
if (pe_arch (bfd_target_efi_rtdrv_arch (*target_ptr)) != arch)
|
|
continue;
|
|
|
|
if (efi)
|
|
{
|
|
no_match:
|
|
/* TARGET_PTR is an EFI backend. Don't match
|
|
TARGET with a EFI file. */
|
|
bfd_preserve_restore (abfd, &preserve);
|
|
bfd_set_error (bfd_error_wrong_format);
|
|
return NULL;
|
|
}
|
|
}
|
|
else if (bfd_target_pei_p (*target_ptr))
|
|
{
|
|
/* Skip incompatible arch. */
|
|
if (pe_arch (bfd_target_pei_arch (*target_ptr)) != arch)
|
|
continue;
|
|
|
|
if (!efi)
|
|
{
|
|
/* TARGET_PTR is a PE backend. Don't match
|
|
TARGET with a PE file. */
|
|
goto no_match;
|
|
}
|
|
}
|
|
}
|
|
|
|
bfd_preserve_finish (abfd, &preserve);
|
|
}
|
|
else
|
|
bfd_preserve_restore (abfd, &preserve);
|
|
|
|
return target;
|
|
}
|
}
|
|
|
#define coff_object_p pe_bfd_object_p
|
#define coff_object_p pe_bfd_object_p
|
#endif /* COFF_IMAGE_WITH_PE */
|
#endif /* COFF_IMAGE_WITH_PE */
|
|
|
No newline at end of file
|
No newline at end of file
|