/* Routines to help build PEI-format DLLs (Win32 etc)
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008 Free Software Foundation, Inc.
+ 2008, 2009 Free Software Foundation, Inc.
Written by DJ Delorie <dj@cygnus.com>
This file is part of the GNU Binutils.
int pe_dll_warn_dup_exports = 0;
int pe_dll_compat_implib = 0;
int pe_dll_extra_pe_debug = 0;
+int pe_use_nul_prefixed_import_tables = 0;
+int pe_use_coff_long_section_names = -1;
/* Static variables and types. */
}
static void
-process_def_file (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
+process_def_file_and_drectve (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
{
int i, j;
struct bfd_link_hash_entry *blhe;
}
}
+ /* Process aligned common symbol information from the
+ .drectve sections now; common symbol allocation is
+ done before final link, so it will be too late to
+ process them in process_embedded_commands() called
+ from _bfd_coff_link_input_bfd(). */
+ if (pe_def_file->aligncomms)
+ {
+ def_file_aligncomm *ac = pe_def_file->aligncomms;
+ while (ac)
+ {
+ struct coff_link_hash_entry *sym_hash;
+ sym_hash = coff_link_hash_lookup (coff_hash_table (info),
+ ac->symbol_name, FALSE, FALSE, FALSE);
+ if (sym_hash && sym_hash->root.type == bfd_link_hash_common
+ && sym_hash->root.u.c.p->alignment_power < (unsigned) ac->alignment)
+ {
+ sym_hash->root.u.c.p->alignment_power = (unsigned) ac->alignment;
+ }
+ ac = ac->next;
+ }
+ }
+
/* If we are not building a DLL, when there are no exports
we do not build an export table at all. */
if (!pe_dll_export_everything && pe_def_file->num_exports == 0
/* We should export symbols which are either global or not
anything at all. (.bss data is the latter)
We should not export undefined symbols. */
- if (symbols[j]->section != &bfd_und_section
- && ((symbols[j]->flags & BSF_GLOBAL)
- || (symbols[j]->flags == 0)))
+ bfd_boolean would_export = symbols[j]->section != &bfd_und_section
+ && ((symbols[j]->flags & BSF_GLOBAL)
+ || (symbols[j]->flags == 0));
+ if (lang_elf_version_info && would_export)
+ {
+ bfd_boolean hide = 0;
+ char ofs = pe_details->underscored && symbols[j]->name[0] == '_';
+ (void) bfd_find_version_for_sym (lang_elf_version_info,
+ symbols[j]->name + ofs, &hide);
+ would_export = !hide;
+ }
+ if (would_export)
{
const char *sn = symbols[j]->name;
#undef NE
#define NE pe_def_file->num_exports
+ /* Don't create an empty export table. */
+ if (NE == 0)
+ return;
+
/* Canonicalize the export list. */
if (pe_dll_kill_ats)
{
}
/* Fill the exported symbol offsets. The preliminary work has already
- been done in process_def_file(). */
+ been done in process_def_file_and_drectve(). */
static void
fill_exported_offsets (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info)
static asymbol **symtab;
static int symptr;
static int tmp_seq;
+static int tmp_seq2;
static const char *dll_filename;
static char *dll_symname;
d2 = xmalloc (20);
id2->contents = d2;
memset (d2, 0, 20);
- d2[0] = d2[16] = PE_IDATA5_SIZE; /* Reloc addend. */
+ if (pe_use_nul_prefixed_import_tables)
+ d2[0] = d2[16] = PE_IDATA5_SIZE; /* Reloc addend. */
quick_reloc (abfd, 0, BFD_RELOC_RVA, 2);
quick_reloc (abfd, 12, BFD_RELOC_RVA, 4);
quick_reloc (abfd, 16, BFD_RELOC_RVA, 1);
save_relocs (id2);
- bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE);
+ if (pe_use_nul_prefixed_import_tables)
+ bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE);
+ else
+ bfd_set_section_size (abfd, id5, 0);
d5 = xmalloc (PE_IDATA5_SIZE);
id5->contents = d5;
memset (d5, 0, PE_IDATA5_SIZE);
-
- bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE);
+ if (pe_use_nul_prefixed_import_tables)
+ bfd_set_section_size (abfd, id4, PE_IDATA4_SIZE);
+ else
+ bfd_set_section_size (abfd, id4, 0);
d4 = xmalloc (PE_IDATA4_SIZE);
id4->contents = d4;
memset (d4, 0, PE_IDATA4_SIZE);
bfd_set_symtab (abfd, symtab, symptr);
bfd_set_section_contents (abfd, id2, d2, 0, 20);
- bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE);
- bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE);
+ if (pe_use_nul_prefixed_import_tables)
+ {
+ bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA5_SIZE);
+ bfd_set_section_contents (abfd, id4, d4, 0, PE_IDATA4_SIZE);
+ }
+ else
+ {
+ bfd_set_section_contents (abfd, id5, d5, 0, 0);
+ bfd_set_section_contents (abfd, id4, d4, 0, 0);
+ }
bfd_make_readable (abfd);
return abfd;
return abfd;
}
+static bfd *
+make_singleton_name_imp (const char *import, bfd *parent)
+{
+ /* Name thunks go to idata$4. */
+ asection *id5;
+ unsigned char *d5;
+ char *oname;
+ bfd *abfd;
+
+ oname = xmalloc (20);
+ sprintf (oname, "nmimp%06d.o", tmp_seq2);
+ tmp_seq2++;
+
+ abfd = bfd_create (oname, parent);
+ bfd_find_target (pe_details->object_target, abfd);
+ bfd_make_writable (abfd);
+
+ bfd_set_format (abfd, bfd_object);
+ bfd_set_arch_mach (abfd, pe_details->bfd_arch, 0);
+
+ symptr = 0;
+ symtab = xmalloc (3 * sizeof (asymbol *));
+ id5 = quick_section (abfd, ".idata$5", SEC_HAS_CONTENTS, 2);
+ quick_symbol (abfd, U ("_imp_"), import, "", id5, BSF_GLOBAL, 0);
+
+ /* We need space for the real thunk and for the null terminator. */
+ bfd_set_section_size (abfd, id5, PE_IDATA5_SIZE * 2);
+ d5 = xmalloc (PE_IDATA5_SIZE * 2);
+ id5->contents = d5;
+ memset (d5, 0, PE_IDATA5_SIZE * 2);
+ quick_reloc (abfd, 0, BFD_RELOC_RVA, 2);
+ save_relocs (id5);
+
+ bfd_set_symtab (abfd, symtab, symptr);
+
+ bfd_set_section_contents (abfd, id5, d5, 0, PE_IDATA4_SIZE * 2);
+
+ bfd_make_readable (abfd);
+ return abfd;
+}
+
static bfd *
make_singleton_name_thunk (const char *import, bfd *parent)
{
quick_symbol (abfd, U ("_nm_thnk_"), name, "", UNDSEC, BSF_GLOBAL, 0);
quick_symbol (abfd, U (""), dll_symname, "_iname", UNDSEC, BSF_GLOBAL, 0);
- quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0);
+ /* For relocator v2 we have to use the .idata$5 element and not
+ fixup_name. */
+ if (link_info.pei386_runtime_pseudo_reloc == 2)
+ quick_symbol (abfd, U ("_imp_"), name, "", UNDSEC, BSF_GLOBAL, 0);
+ else
+ quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0);
bfd_set_section_size (abfd, id2, 20);
d2 = xmalloc (20);
id2->contents = d2;
memset (d2, 0, 20);
- d2[0] = d2[16] = PE_IDATA5_SIZE; /* Reloc addend. */
quick_reloc (abfd, 0, BFD_RELOC_RVA, 1);
quick_reloc (abfd, 12, BFD_RELOC_RVA, 2);
quick_symbol (abfd, "", U ("_pei386_runtime_relocator"), "", UNDSEC,
BSF_NO_FLAGS, 0);
- bfd_set_section_size (abfd, extern_rt_rel, 4);
- extern_rt_rel_d = xmalloc (4);
+ bfd_set_section_size (abfd, extern_rt_rel, PE_IDATA5_SIZE);
+ extern_rt_rel_d = xmalloc (PE_IDATA5_SIZE);
extern_rt_rel->contents = extern_rt_rel_d;
quick_reloc (abfd, 0, BFD_RELOC_RVA, 1);
bfd_set_symtab (abfd, symtab, symptr);
- bfd_set_section_contents (abfd, extern_rt_rel, extern_rt_rel_d, 0, 4);
+ bfd_set_section_contents (abfd, extern_rt_rel, extern_rt_rel_d, 0, PE_IDATA5_SIZE);
bfd_make_readable (abfd);
return abfd;
char buf[300];
struct bfd_symbol *sym = *rel->sym_ptr_ptr;
struct bfd_link_hash_entry *name_thunk_sym;
+ struct bfd_link_hash_entry *name_imp_sym;
const char *name = sym->name;
char *fixup_name = make_import_fixup_mark (rel);
bfd *b;
+ int need_import_table = 1;
+
+ sprintf (buf, U ("_imp_%s"), name);
+ name_imp_sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1);
sprintf (buf, U ("_nm_thnk_%s"), name);
name_thunk_sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1);
- if (!name_thunk_sym || name_thunk_sym->type != bfd_link_hash_defined)
+ /* For version 2 pseudo relocation we don't need to add an import
+ if the import symbol is already present. */
+ if (link_info.pei386_runtime_pseudo_reloc == 2
+ && name_imp_sym
+ && name_imp_sym->type == bfd_link_hash_defined)
+ need_import_table = 0;
+
+ if (need_import_table == 1
+ && (!name_thunk_sym || name_thunk_sym->type != bfd_link_hash_defined))
{
bfd *b = make_singleton_name_thunk (name, link_info.output_bfd);
add_bfd_to_link (b, b->filename, &link_info);
- /* If we ever use autoimport, we have to cast text section writable. */
- config.text_read_only = FALSE;
- link_info.output_bfd->flags &= ~WP_TEXT;
+ /* If we ever use autoimport, we have to cast text section writable.
+ But not for version 2. */
+ if (link_info.pei386_runtime_pseudo_reloc != 2)
+ {
+ config.text_read_only = FALSE;
+ link_info.output_bfd->flags &= ~WP_TEXT;
+ }
+ if (link_info.pei386_runtime_pseudo_reloc == 2)
+ {
+ b = make_singleton_name_imp (name, link_info.output_bfd);
+ add_bfd_to_link (b, b->filename, &link_info);
+ }
}
- if (addend == 0 || link_info.pei386_runtime_pseudo_reloc)
+ if ((addend == 0 || link_info.pei386_runtime_pseudo_reloc)
+ && need_import_table == 1)
{
extern char * pe_data_import_dll;
char * dll_symname = pe_data_import_dll ? pe_data_import_dll : "unknown";
/* xgettext:c-format */
info_msg (_("Creating library file: %s\n"), impfilename);
-
+
bfd_set_format (outarch, bfd_archive);
outarch->has_armap = 1;
it into the archive member chain. */
if (found)
{
- bfd *newbfd = bfd_openr (ibfd->my_archive
+ bfd *newbfd = bfd_openr (ibfd->my_archive
? ibfd->my_archive->filename : ibfd->filename, NULL);
if (!newbfd)
{
bfd *arbfd = newbfd;
if (!bfd_check_format_matches (arbfd, bfd_archive, NULL))
{
- einfo (_("%X%s(%s): can't find member in non-archive file"),
+ einfo (_("%X%s(%s): can't find member in non-archive file"),
ibfd->my_archive->filename, ibfd->filename);
return;
}
}
if (!newbfd)
{
- einfo (_("%X%s(%s): can't find member in archive"),
+ einfo (_("%X%s(%s): can't find member in archive"),
ibfd->my_archive->filename, ibfd->filename);
return;
}
char *internal = def->exports[i].internal_name;
bfd *n;
- /* Don't add PRIVATE entries to import lib. */
+ /* Don't add PRIVATE entries to import lib. */
if (pe_def_file->exports[i].flag_private)
continue;
def->exports[i].internal_name = def->exports[i].name;
if (!blhe || (blhe && blhe->type != bfd_link_hash_undefined))
{
if (lead_at)
- sprintf (name, "%s%s", "__imp_",
+ sprintf (name, "%s%s", "__imp_",
pe_def_file->imports[i].internal_name);
else
sprintf (name, "%s%s%s", "__imp_", U (""),
export_rva = pe_get32 (dll, opthdr_ofs + 96);
export_size = pe_get32 (dll, opthdr_ofs + 100);
#endif
-
+
nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
secptr = (pe_header_offset + 4 + 20 +
pe_get16 (dll, pe_header_offset + 4 + 16));
return TRUE;
}
+void
+pe_output_file_set_long_section_names (bfd *abfd)
+{
+ if (pe_use_coff_long_section_names < 0)
+ return;
+ if (!bfd_coff_set_long_section_names (abfd, pe_use_coff_long_section_names))
+ einfo (_("%XError: can't use long section names on this arch\n"));
+}
+
/* These are the main functions, called from the emulation. The first
is called after the bfds are read, so we can guess at how much space
we need. The second is called after everything is placed, so we
pe_dll_build_sections (bfd *abfd, struct bfd_link_info *info)
{
pe_dll_id_target (bfd_get_target (abfd));
- process_def_file (abfd, info);
+ pe_output_file_set_long_section_names (abfd);
+ process_def_file_and_drectve (abfd, info);
if (pe_def_file->num_exports == 0 && !info->shared)
return;
generate_edata (abfd, info);
build_filler_bfd (1);
+ pe_output_file_set_long_section_names (filler_bfd);
}
void
pe_exe_build_sections (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
pe_dll_id_target (bfd_get_target (abfd));
+ pe_output_file_set_long_section_names (abfd);
build_filler_bfd (0);
+ pe_output_file_set_long_section_names (filler_bfd);
}
void
pe_dll_fill_sections (bfd *abfd, struct bfd_link_info *info)
{
pe_dll_id_target (bfd_get_target (abfd));
+ pe_output_file_set_long_section_names (abfd);
image_base = pe_data (abfd)->pe_opthdr.ImageBase;
generate_reloc (abfd, info);
pe_exe_fill_sections (bfd *abfd, struct bfd_link_info *info)
{
pe_dll_id_target (bfd_get_target (abfd));
+ pe_output_file_set_long_section_names (abfd);
image_base = pe_data (abfd)->pe_opthdr.ImageBase;
generate_reloc (abfd, info);