#include "ldgram.h"
#include "ldexp.h"
#include "ldlang.h"
+#include "ldfile.h"
#include "ldemul.h"
#include "ldlex.h"
#include "ldmisc.h"
#include "ldctor.h"
-#include "ldfile.h"
#include "coff/internal.h"
/* FIXME: This is a BFD internal header file, and we should not be
static void gld_${EMULATION_NAME}_before_allocation PARAMS ((void));
static boolean gld_${EMULATION_NAME}_place_orphan
PARAMS ((lang_input_statement_type *, asection *));
-static void gld${EMULATION_NAME}_place_section
- PARAMS ((lang_statement_union_type *));
static char *gld_${EMULATION_NAME}_get_script PARAMS ((int *));
static int gld_${EMULATION_NAME}_parse_args PARAMS ((int, char **));
static void gld_${EMULATION_NAME}_finish PARAMS ((void));
+static boolean gld_${EMULATION_NAME}_open_dynamic_archive
+ PARAMS ((const char *, search_dirs_type *, lang_input_statement_type *));
static struct internal_extra_pe_aouthdr pe;
static int dll;
static char * thumb_entry_symbol = NULL;
static lang_assignment_statement_type *image_base_statement = 0;
-static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable */
#ifdef DLL_SUPPORT
-static char *pe_out_def_filename = 0;
-static char *pe_implib_filename = 0;
+static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable */
+static char *pe_out_def_filename = NULL;
+static char *pe_implib_filename = NULL;
+static int pe_enable_auto_image_base = 0;
#endif
extern const char *output_filename;
#define OPTION_THUMB_ENTRY (OPTION_IMPLIB_FILENAME + 1)
#define OPTION_WARN_DUPLICATE_EXPORTS (OPTION_THUMB_ENTRY + 1)
#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)
static struct option longopts[] =
{
{"out-implib", required_argument, NULL, OPTION_IMPLIB_FILENAME},
{"warn-duplicate-exports", no_argument, NULL, OPTION_WARN_DUPLICATE_EXPORTS},
{"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT},
+ {"enable-auto-image-base", no_argument, NULL, OPTION_ENABLE_AUTO_IMAGE_BASE},
+ {"disable-auto-image-base", no_argument, NULL, OPTION_DISABLE_AUTO_IMAGE_BASE},
#endif
{NULL, no_argument, NULL, 0}
};
fprintf (file, _(" --warn-duplicate-exports Warn about duplicate exports.\n"));
fprintf (file, _(" --compat-implib Create backward compatible import libs;\n"));
fprintf (file, _(" create __imp_<SYMBOL> as well.\n"));
+ fprintf (file, _(" --enable-auto-image-base Automatically choose image base for DLLs\n"));
+ fprintf (file, _(" unless user specifies one\n"));
+ fprintf (file, _(" --disable-auto-image-base Do not auto-choose image base. (default)\n"));
#endif
}
case OPTION_IMP_COMPAT:
pe_dll_compat_implib = 1;
break;
+ case OPTION_ENABLE_AUTO_IMAGE_BASE:
+ pe_enable_auto_image_base = 1;
+ break;
+ case OPTION_DISABLE_AUTO_IMAGE_BASE:
+ pe_enable_auto_image_base = 0;
+ break;
#endif
}
return 1;
}
\f
+
+#ifdef DLL_SUPPORT
+static unsigned long
+strhash (const char *str)
+{
+ const unsigned char *s;
+ unsigned long hash;
+ unsigned int c;
+ unsigned int len;
+
+ hash = 0;
+ len = 0;
+ s = (const unsigned char *) str;
+ while ((c = *s++) != '\0')
+ {
+ hash += c + (c << 17);
+ hash ^= hash >> 2;
+ ++len;
+ }
+ hash += len + (len << 17);
+ hash ^= hash >> 2;
+
+ return hash;
+}
+
+/* Use the output file to create a image base for relocatable DLLs. */
+static unsigned long
+compute_dll_image_base (const char *ofile)
+{
+ unsigned long hash = strhash (ofile);
+ return 0x60000000 | ((hash << 16) & 0x0FFC0000);
+}
+#endif
+
/* Assign values to the special symbols before the linker script is
read. */
if (link_info.relocateable)
init[IMAGEBASEOFF].value = 0;
else if (init[DLLOFF].value || link_info.shared)
+#ifdef DLL_SUPPORT
+ init[IMAGEBASEOFF].value = (pe_enable_auto_image_base) ?
+ compute_dll_image_base (output_filename) : NT_DLL_IMAGE_BASE;
+#else
init[IMAGEBASEOFF].value = NT_DLL_IMAGE_BASE;
+#endif
else
init[IMAGEBASEOFF].value = NT_EXE_IMAGE_BASE;
}
ldlang_add_undef (entry_symbol);
}
+#ifdef DLL_SUPPORT
static struct bfd_link_hash_entry *pe_undef_found_sym;
static boolean
return true;
}
-#ifdef DLL_SUPPORT
static void
pe_fixup_stdcalls ()
{
sprintf (new_name, "%s.%c", is->the_bfd->filename, seq);
is->the_bfd->filename = new_name;
- new_name = xmalloc (strlen(is->filename) + 3);
+ new_name = xmalloc (strlen (is->filename) + 3);
sprintf (new_name, "%s.%c", is->filename, seq);
is->filename = new_name;
}
#endif /* TARGET_IS_armpe */
}
\f
-
+#ifdef DLL_SUPPORT
/* This is called when an input file isn't recognized as a BFD. We
check here for .DEF files and pull them in automatically. */
-#ifdef DLL_SUPPORT
+
static int
saw_option(char *option)
{
return init[i].inited;
return 0;
}
-#endif
+#endif /* DLL_SUPPORT */
static boolean
gld_${EMULATION_NAME}_unrecognized_file(entry)
pe_dll_generate_implib (pe_def_file, pe_implib_filename);
}
#if defined(TARGET_IS_shpe) || defined(TARGET_IS_mipspe)
+ /* ARM doesn't need relocs. */
else
{
pe_exe_fill_sections (output_bfd, &link_info);
if (pe_out_def_filename)
pe_dll_generate_def_file (pe_out_def_filename);
-#endif
+#endif /* DLL_SUPPORT */
}
\f
default linker script using wildcards, and are sorted by
sort_sections. */
-static asection *hold_section;
-static char *hold_section_name;
-static lang_output_section_statement_type *hold_use;
-
struct orphan_save
{
lang_output_section_statement_type *os;
asection **section;
lang_statement_union_type **stmt;
};
-static struct orphan_save hold_text;
-static struct orphan_save hold_rdata;
-static struct orphan_save hold_data;
-static struct orphan_save hold_bss;
-
-/* Place an orphan section. We use this to put random SHF_ALLOC
- sections in the right segment. */
/*ARGSUSED*/
static boolean
asection *s;
{
const char *secname;
+ char *hold_section_name;
char *dollar = NULL;
+ lang_output_section_statement_type *os;
lang_statement_list_type add_child;
secname = bfd_get_section_name (s->owner, s);
/* Look through the script to see where to place this section. */
- hold_section = s;
-
hold_section_name = xstrdup (secname);
if (!link_info.relocateable)
{
*dollar = '\0';
}
- hold_use = NULL;
- lang_for_each_statement (gld${EMULATION_NAME}_place_section);
+ os = lang_output_section_find (hold_section_name);
lang_list_init (&add_child);
- if (hold_use != NULL)
+ if (os != NULL
+ && os->bfd_section != NULL
+ && ((s->flags ^ os->bfd_section->flags) & (SEC_LOAD | SEC_ALLOC)) == 0)
{
- wild_doit (&add_child, s, hold_use, file);
+ wild_doit (&add_child, s, os, file);
}
else
{
struct orphan_save *place;
+ static struct orphan_save hold_text;
+ static struct orphan_save hold_rdata;
+ static struct orphan_save hold_data;
+ static struct orphan_save hold_bss;
char *outsecname;
lang_statement_list_type *old;
lang_statement_list_type add;
/* Try to put the new output section in a reasonable place based
on the section name and section flags. */
+#define HAVE_SECTION(hold, name) \
+(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL)
+
place = NULL;
if ((s->flags & SEC_ALLOC) == 0)
;
else if ((s->flags & SEC_HAS_CONTENTS) == 0
- && hold_bss.os != NULL)
+ && HAVE_SECTION (hold_bss, ".bss"))
place = &hold_bss;
else if ((s->flags & SEC_READONLY) == 0
- && hold_data.os != NULL)
+ && HAVE_SECTION (hold_data, ".data"))
place = &hold_data;
else if ((s->flags & SEC_CODE) == 0
&& (s->flags & SEC_READONLY) != 0
- && hold_rdata.os != NULL)
+ && HAVE_SECTION (hold_rdata, ".rdata"))
place = &hold_rdata;
else if ((s->flags & SEC_READONLY) != 0
- && hold_text.os != NULL)
+ && HAVE_SECTION (hold_text, ".text"))
place = &hold_text;
+#undef HAVE_SECTION
+
/* Choose a unique name for the section. This will be needed if
the same section name appears in the input file with
different loadable or allocateable characteristics. */
exp_nameop (NAME, "__section_alignment__"));
}
- lang_enter_output_section_statement (outsecname, address, 0,
- (bfd_vma) 0,
- (etree_type *) NULL,
- (etree_type *) NULL,
- (etree_type *) NULL);
+ os = lang_enter_output_section_statement (outsecname, address, 0,
+ (bfd_vma) 0,
+ (etree_type *) NULL,
+ (etree_type *) NULL,
+ (etree_type *) NULL);
- hold_use = lang_output_section_statement_lookup (outsecname);
- wild_doit (&add_child, s, hold_use, file);
+ wild_doit (&add_child, s, os, file);
lang_leave_output_section_statement
((bfd_vma) 0, "*default*",
- (struct lang_output_section_phdr_list *) NULL,
- "*default*");
+ (struct lang_output_section_phdr_list *) NULL, "*default*");
stat_ptr = old;
{
asection *snew, **pps;
- snew = hold_use->bfd_section;
+ snew = os->bfd_section;
if (place->os->bfd_section != NULL || place->section != NULL)
{
/* Shuffle the section to make the output file look neater. */
}
{
- lang_statement_union_type **pl = &hold_use->children.head;
+ lang_statement_union_type **pl = &os->children.head;
if (dollar != NULL)
{
return true;
}
-static void
-gld${EMULATION_NAME}_place_section (s)
- lang_statement_union_type *s;
+static boolean
+gld_${EMULATION_NAME}_open_dynamic_archive (arch, search, entry)
+ const char * arch ATTRIBUTE_UNUSED;
+ search_dirs_type * search;
+ lang_input_statement_type * entry;
{
- lang_output_section_statement_type *os;
+ const char * filename;
+ char * string;
- if (s->header.type != lang_output_section_statement_enum)
- return;
+ if (! entry->is_archive)
+ return false;
- os = &s->output_section_statement;
+ filename = entry->filename;
- if (strcmp (os->name, hold_section_name) == 0
- && os->bfd_section != NULL
- && ((hold_section->flags & (SEC_LOAD | SEC_ALLOC))
- == (os->bfd_section->flags & (SEC_LOAD | SEC_ALLOC))))
- hold_use = os;
-
- if (strcmp (os->name, ".text") == 0)
- hold_text.os = os;
- else if (strcmp (os->name, ".rdata") == 0)
- hold_rdata.os = os;
- else if (strcmp (os->name, ".data") == 0)
- hold_data.os = os;
- else if (strcmp (os->name, ".bss") == 0)
- hold_bss.os = os;
+ string = (char *) xmalloc (strlen (search->name)
+ + strlen (filename)
+ + sizeof "/lib.a.dll"
+ + 1);
+
+ /* Try "libfoo.dll.a" first (preferred explicit import library for dll's */
+ sprintf (string, "%s/lib%s.dll.a", search->name, filename);
+
+ if (! ldfile_try_open_bfd (string, entry))
+ {
+ /* Try "foo.dll.a" next (alternate explicit import library for dll's */
+ sprintf (string, "%s/%s.dll.a", search->name, filename);
+ if (! ldfile_try_open_bfd (string, entry))
+ {
+/*
+ Try libfoo.a next. Normally, this would be interpreted as a static
+ library, but it *could* be an import library. For backwards compatibility,
+ libfoo.a needs to ==precede== libfoo.dll and foo.dll in the search,
+ or sometimes errors occur when building legacy packages.
+
+ Putting libfoo.a here means that in a failure case (i.e. the library
+ -lfoo is not found) we will search for libfoo.a twice before
+ giving up -- once here, and once when searching for a "static" lib.
+ for a "static" lib.
+*/
+ /* Try "libfoo.a" (import lib, or static lib, but must
+ take precedence over dll's) */
+ sprintf (string, "%s/lib%s.a", search->name, filename);
+ if (! ldfile_try_open_bfd (string, entry))
+ {
+ /* Try "libfoo.dll" (preferred dll name) */
+ sprintf (string, "%s/lib%s.dll", search->name, filename);
+ if (! ldfile_try_open_bfd (string, entry))
+ {
+ /* Finally, try "foo.dll" (alternate dll name) */
+ sprintf (string, "%s/%s.dll", search->name, filename);
+ if (! ldfile_try_open_bfd (string, entry))
+ {
+ free (string);
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ entry->filename = string;
+
+ return true;
}
static int
"${OUTPUT_FORMAT}",
gld_${EMULATION_NAME}_finish, /* finish */
NULL, /* create output section statements */
- NULL, /* open dynamic archive */
+ gld_${EMULATION_NAME}_open_dynamic_archive,
gld_${EMULATION_NAME}_place_orphan,
gld_${EMULATION_NAME}_set_symbols,
gld_${EMULATION_NAME}_parse_args,