# This shell script emits a C file. -*- C -*-
# It does some substitutions.
+if [ -z "$MACHINE" ]; then
+ OUTPUT_ARCH=${ARCH}
+else
+ OUTPUT_ARCH=${ARCH}:${MACHINE}
+fi
rm -f e${EMULATION_NAME}.c
(echo;echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-)
cat >>e${EMULATION_NAME}.c <<EOF
/* This file is part of GLD, the Gnu Linker.
- Copyright 1995, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
+ Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "deffile.h"
#include "pe-dll.h"
+#include <ctype.h>
+
#define TARGET_IS_${EMULATION_NAME}
/* Permit the emulation parameters to override the default section
static void
gld_${EMULATION_NAME}_before_parse()
{
+ const bfd_arch_info_type *arch = bfd_scan_arch ("${OUTPUT_ARCH}");
+ if (arch)
+ {
+ ldfile_output_architecture = arch->arch;
+ ldfile_output_machine = arch->mach;
+ ldfile_output_machine_name = arch->printable_name;
+ }
+ else
+ ldfile_output_architecture = bfd_arch_${ARCH};
output_filename = "${EXECUTABLE_NAME:-a.exe}";
- ldfile_output_architecture = bfd_arch_${ARCH};
#ifdef DLL_SUPPORT
+ config.dynamic_link = true;
config.has_shared = 1;
+/* link_info.pei386_auto_import = true; */
#if (PE_DEF_SUBSYSTEM == 9) || (PE_DEF_SUBSYSTEM == 2)
#if defined TARGET_IS_mipspe || defined TARGET_IS_armpe
#define OPTION_IMP_COMPAT (OPTION_WARN_DUPLICATE_EXPORTS + 1)
#define OPTION_ENABLE_AUTO_IMAGE_BASE (OPTION_IMP_COMPAT + 1)
#define OPTION_DISABLE_AUTO_IMAGE_BASE (OPTION_ENABLE_AUTO_IMAGE_BASE + 1)
-#define OPTION_DLL_SEARCH_PREFIX (OPTION_DISABLE_AUTO_IMAGE_BASE + 1)
+#define OPTION_DLL_SEARCH_PREFIX (OPTION_DISABLE_AUTO_IMAGE_BASE + 1)
+#define OPTION_NO_DEFAULT_EXCLUDES (OPTION_DLL_SEARCH_PREFIX + 1)
+#define OPTION_DLL_ENABLE_AUTO_IMPORT (OPTION_NO_DEFAULT_EXCLUDES + 1)
+#define OPTION_DLL_DISABLE_AUTO_IMPORT (OPTION_DLL_ENABLE_AUTO_IMPORT + 1)
+#define OPTION_ENABLE_EXTRA_PE_DEBUG (OPTION_DLL_DISABLE_AUTO_IMPORT + 1)
-static struct option longopts[] =
-{
+static struct option longopts[] = {
/* PE options */
{"base-file", required_argument, NULL, OPTION_BASE_FILE},
{"dll", no_argument, NULL, OPTION_DLL},
{"enable-auto-image-base", no_argument, NULL, OPTION_ENABLE_AUTO_IMAGE_BASE},
{"disable-auto-image-base", no_argument, NULL, OPTION_DISABLE_AUTO_IMAGE_BASE},
{"dll-search-prefix", required_argument, NULL, OPTION_DLL_SEARCH_PREFIX},
+ {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES},
+ {"enable-auto-import", no_argument, NULL, OPTION_DLL_ENABLE_AUTO_IMPORT},
+ {"disable-auto-import", no_argument, NULL, OPTION_DLL_DISABLE_AUTO_IMPORT},
+ {"enable-extra-pe-debug", no_argument, NULL, OPTION_ENABLE_EXTRA_PE_DEBUG},
#endif
{NULL, no_argument, NULL, 0}
};
#endif
D(MinorSubsystemVersion,"__minor_subsystem_version__", 0),
D(Subsystem,"__subsystem__", ${SUBSYSTEM}),
- D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x2000000),
+ D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x200000),
D(SizeOfStackCommit,"__size_of_stack_commit__", 0x1000),
D(SizeOfHeapReserve,"__size_of_heap_reserve__", 0x100000),
D(SizeOfHeapCommit,"__size_of_heap_commit__", 0x1000),
fprintf (file, _(" --dll-search-prefix=<string> When linking dynamically to a dll witout an\n"));
fprintf (file, _(" importlib, use <string><basename>.dll \n"));
fprintf (file, _(" in preference to lib<basename>.dll \n"));
+ fprintf (file, _(" --enable-auto-import Do sophistcated linking of _sym to \n"));
+ fprintf (file, _(" __imp_sym for DATA references\n"));
+ fprintf (file, _(" --disable-auto-import Do not auto-import DATA items from DLLs\n"));
+ fprintf (file, _(" --enable-extra-pe-debug Enable verbose debug output when building\n"));
+ fprintf (file, _(" or linking to DLLs (esp. auto-import)\n"));
#endif
}
case OPTION_DLL_SEARCH_PREFIX:
pe_dll_search_prefix = xstrdup( optarg );
break;
+ case OPTION_NO_DEFAULT_EXCLUDES:
+ pe_dll_do_default_excludes = 0;
+ break;
+ case OPTION_DLL_ENABLE_AUTO_IMPORT:
+ link_info.pei386_auto_import = true;
+ break;
+ case OPTION_DLL_DISABLE_AUTO_IMPORT:
+ link_info.pei386_auto_import = false;
+ break;
+ case OPTION_ENABLE_EXTRA_PE_DEBUG:
+ pe_dll_extra_pe_debug = 1;
+ break;
#endif
}
return 1;
struct bfd_link_hash_entry *h;
PTR string;
{
- int sl = strlen (string);
+ int sl;
+ sl = strlen (string); /* silence compiler warning */
if (h->type == bfd_link_hash_defined
&& strncmp (h->root.string, string, sl) == 0
&& h->root.string[sl] == '@')
- {
- pe_undef_found_sym = h;
- return false;
- }
+ {
+ pe_undef_found_sym = h;
+ return false;
+ }
return true;
}
static int gave_warning_message = 0;
struct bfd_link_hash_entry *undef, *sym;
char *at;
+ if (pe_dll_extra_pe_debug)
+ {
+ printf ("%s\n", __FUNCTION__);
+ }
+
for (undef = link_info.hash->undefs; undef; undef=undef->next)
if (undef->type == bfd_link_hash_undefined)
{
}
}
}
+
+static int
+make_import_fixup (rel)
+ arelent *rel;
+{
+ struct symbol_cache_entry *sym = *rel->sym_ptr_ptr;
+/*
+ bfd *b;
+*/
+
+ if (pe_dll_extra_pe_debug)
+ {
+ printf ("arelent: %s@%#x: add=%li\n", sym->name,
+ (int) rel->address, rel->addend);
+ }
+ pe_create_import_fixup (rel);
+ return 1;
+}
+
+char *pe_data_import_dll;
+
+static void
+pe_find_data_imports ()
+{
+ struct bfd_link_hash_entry *undef, *sym;
+ for (undef = link_info.hash->undefs; undef; undef=undef->next)
+ {
+ if (undef->type == bfd_link_hash_undefined)
+ {
+ /* C++ symbols are *long* */
+ char buf[4096];
+ if (pe_dll_extra_pe_debug)
+ {
+ printf ("%s:%s\n", __FUNCTION__, undef->root.string);
+ }
+ sprintf (buf, "__imp_%s", undef->root.string);
+
+ sym = bfd_link_hash_lookup (link_info.hash, buf, 0, 0, 1);
+ if (sym && sym->type == bfd_link_hash_defined)
+ {
+ einfo (_("Warning: resolving %s by linking to %s (auto-import)\n"),
+ undef->root.string, buf);
+ {
+ bfd *b = sym->u.def.section->owner;
+ asymbol **symbols;
+ int nsyms, symsize, i;
+
+ symsize = bfd_get_symtab_upper_bound (b);
+ symbols = (asymbol **) xmalloc (symsize);
+ nsyms = bfd_canonicalize_symtab (b, symbols);
+
+ for (i = 0; i < nsyms; i++)
+ {
+ if (memcmp(symbols[i]->name, "__head_",
+ sizeof ("__head_") - 1))
+ continue;
+ if (pe_dll_extra_pe_debug)
+ {
+ printf ("->%s\n", symbols[i]->name);
+ }
+ pe_data_import_dll = (char*) (symbols[i]->name +
+ sizeof ("__head_") - 1);
+ break;
+ }
+ }
+
+ pe_walk_relocs_of_symbol (&link_info, undef->root.string,
+ make_import_fixup);
+
+ /* let's differentiate it somehow from defined */
+ undef->type = bfd_link_hash_defweak;
+ /* we replace original name with __imp_ prefixed, this
+ 1) may trash memory 2) leads to duplicate symbol generation.
+ Still, IMHO it's better than having name poluted. */
+ undef->root.string = sym->root.string;
+ undef->u.def.value = sym->u.def.value;
+ undef->u.def.section = sym->u.def.section;
+ }
+ }
+ }
+}
#endif /* DLL_SUPPORT */
+static boolean
+pr_sym (h, string)
+ struct bfd_hash_entry *h;
+ PTR string;
+{
+ if (pe_dll_extra_pe_debug)
+ {
+ printf("+%s\n",h->string);
+ }
+ return true;
+}
+
+
static void
gld_${EMULATION_NAME}_after_open ()
{
+
+ if (pe_dll_extra_pe_debug)
+ {
+ bfd *a;
+ struct bfd_link_hash_entry *sym;
+ printf ("%s()\n", __FUNCTION__);
+
+ for (sym = link_info.hash->undefs; sym; sym=sym->next)
+ printf ("-%s\n", sym->root.string);
+ bfd_hash_traverse (&link_info.hash->table, pr_sym,NULL);
+
+ for (a = link_info.input_bfds; a; a = a->link_next)
+ {
+ printf("*%s\n",a->filename);
+ }
+ }
+
/* Pass the wacky PE command line options into the output bfd.
FIXME: This should be done via a function, rather than by
including an internal BFD header. */
- if (!coff_data (output_bfd)->pe)
+ if (coff_data (output_bfd) == NULL || coff_data (output_bfd)->pe == NULL)
einfo (_("%F%P: PE operations on non PE file.\n"));
pe_data (output_bfd)->pe_opthdr = pe;
if (pe_enable_stdcall_fixup) /* -1=warn or 1=disable */
pe_fixup_stdcalls ();
+ pe_find_data_imports (output_bfd, &link_info);
+
pe_process_import_defs(output_bfd, &link_info);
if (link_info.shared)
pe_dll_build_sections (output_bfd, &link_info);
{
int idata2 = 0, reloc_count=0, is_imp = 0;
asection *sec;
- /* See if this is an import library thunk */
+
+ /* See if this is an import library thunk. */
for (sec = is->the_bfd->sections; sec; sec = sec->next)
{
if (strcmp (sec->name, ".idata\$2") == 0)
is_imp = 1;
reloc_count += sec->reloc_count;
}
+
if (is_imp && !idata2 && reloc_count)
{
- /* it is, look for the reference to head and see if it's
- from our own library */
+ /* It is, look for the reference to head and see if it's
+ from our own library. */
for (sec = is->the_bfd->sections; sec; sec = sec->next)
{
int i;
- int symsize = bfd_get_symtab_upper_bound (is->the_bfd);
- asymbol **symbols = (asymbol **) xmalloc (symsize);
- int relsize = bfd_get_reloc_upper_bound (is->the_bfd, sec);
- arelent **relocs = (arelent **) xmalloc ((size_t) relsize);
- int nrelocs = bfd_canonicalize_reloc (is->the_bfd, sec,
+ long symsize;
+ long relsize;
+ asymbol **symbols;
+ arelent **relocs;
+ int nrelocs;
+
+ symsize = bfd_get_symtab_upper_bound (is->the_bfd);
+ if (symsize < 1)
+ break;
+ relsize = bfd_get_reloc_upper_bound (is->the_bfd, sec);
+ if (relsize < 1)
+ break;
+
+ symbols = (asymbol **) xmalloc (symsize);
+ symsize = bfd_canonicalize_symtab (is->the_bfd, symbols);
+ if (symsize < 0)
+ {
+ einfo ("%X%P: unable to process symbols: %E");
+ return;
+ }
+
+ relocs = (arelent **) xmalloc ((size_t) relsize);
+ nrelocs = bfd_canonicalize_reloc (is->the_bfd, sec,
relocs, symbols);
- for (i=0; i<nrelocs; i++)
+ if (nrelocs < 0)
+ {
+ free (relocs);
+ einfo ("%X%P: unable to process relocs: %E");
+ return;
+ }
+
+ for (i = 0; i < nrelocs; i++)
{
struct symbol_cache_entry *s;
+ struct bfd_link_hash_entry * blhe;
+ bfd *other_bfd;
+ char *n;
+
s = (relocs[i]->sym_ptr_ptr)[0];
- if (!s->flags & BSF_LOCAL)
- {
- /* thunk section with reloc to another bfd... */
- struct bfd_link_hash_entry *blhe;
- blhe = bfd_link_hash_lookup (link_info.hash,
- s->name,
- false, false, true);
- if (blhe && blhe->type == bfd_link_hash_defined)
- {
- bfd *other_bfd = blhe->u.def.section->owner;
- if (strcmp (is->the_bfd->my_archive->filename,
- other_bfd->my_archive->filename))
- {
- /* Rename this implib to match the other */
- char *n = (char *) xmalloc (strlen (other_bfd->my_archive->filename) + 1);
- strcpy (n, other_bfd->my_archive->filename);
- is->the_bfd->my_archive->filename = n;
- }
- }
- }
+
+ if (s->flags & BSF_LOCAL)
+ continue;
+
+ /* Thunk section with reloc to another bfd. */
+ blhe = bfd_link_hash_lookup (link_info.hash,
+ s->name,
+ false, false, true);
+
+ if (blhe == NULL
+ || blhe->type != bfd_link_hash_defined)
+ continue;
+
+ other_bfd = blhe->u.def.section->owner;
+
+ if (strcmp (is->the_bfd->my_archive->filename,
+ other_bfd->my_archive->filename) == 0)
+ continue;
+
+ /* Rename this implib to match the other. */
+ n = (char *) xmalloc (strlen (other_bfd->my_archive->filename) + 1);
+
+ strcpy (n, other_bfd->my_archive->filename);
+
+ is->the_bfd->my_archive->filename = n;
}
free (relocs);
+ /* Note - we do not free the symbols,
+ they are now cached in the BFD. */
}
}
}
if (pe_out_def_filename)
pe_dll_generate_def_file (pe_out_def_filename);
#endif /* DLL_SUPPORT */
+
+ /* I don't know where .idata gets set as code, but it shouldn't be */
+ {
+ asection *asec = bfd_get_section_by_name (output_bfd, ".idata");
+ if (asec)
+ {
+ asec->flags &= ~SEC_CODE;
+ asec->flags |= SEC_DATA;
+ }
+ }
}
\f
const char *secname;
char *hold_section_name;
char *dollar = NULL;
+ const char *ps = NULL;
lang_output_section_statement_type *os;
lang_statement_list_type add_child;
&& os->bfd_section != NULL
&& ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)
{
- wild_doit (&add_child, s, os, file);
+ lang_add_section (&add_child, s, os, file);
}
else
{
stat_ptr = &add;
lang_list_init (stat_ptr);
+ if (config.build_constructors)
+ {
+ /* If the name of the section is representable in C, then create
+ symbols to mark the start and the end of the section. */
+ for (ps = outsecname; *ps != '\0'; ps++)
+ if (! isalnum ((unsigned char) *ps) && *ps != '_')
+ break;
+ if (*ps == '\0')
+ {
+ char *symname;
+ etree_type *e_align;
+
+ symname = (char *) xmalloc (ps - outsecname + sizeof "___start_");
+ sprintf (symname, "___start_%s", outsecname);
+ e_align = exp_unop (ALIGN_K,
+ exp_intop ((bfd_vma) 1 << s->alignment_power));
+ lang_add_assignment (exp_assop ('=', symname, e_align));
+ }
+ }
+
if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
address = exp_intop ((bfd_vma) 0);
else
(etree_type *) NULL,
(etree_type *) NULL);
- wild_doit (&add_child, s, os, file);
+ lang_add_section (&add_child, s, os, file);
lang_leave_output_section_statement
((bfd_vma) 0, "*default*",
(struct lang_output_section_phdr_list *) NULL, "*default*");
+ if (config.build_constructors && *ps == '\0')
+ {
+ char *symname;
+
+ /* lang_leave_ouput_section_statement resets stat_ptr. Put
+ stat_ptr back where we want it. */
+ if (place != NULL)
+ stat_ptr = &add;
+
+ symname = (char *) xmalloc (ps - outsecname + sizeof "___stop_");
+ sprintf (symname, "___stop_%s", outsecname);
+ lang_add_assignment (exp_assop ('=', symname,
+ exp_nameop (NAME, ".")));
+ }
+
stat_ptr = old;
if (place != NULL)