aboutsummaryrefslogtreecommitdiff
path: root/ld/pe-dll.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/pe-dll.c')
-rw-r--r--ld/pe-dll.c143
1 files changed, 135 insertions, 8 deletions
diff --git a/ld/pe-dll.c b/ld/pe-dll.c
index af0cd51..d9e4078 100644
--- a/ld/pe-dll.c
+++ b/ld/pe-dll.c
@@ -141,6 +141,7 @@ static bfd *filler_bfd;
static struct sec *edata_s, *reloc_s;
static unsigned char *edata_d, *reloc_d;
static size_t edata_sz, reloc_sz;
+static int runtime_pseudo_relocs_created = 0;
typedef struct
{
@@ -305,6 +306,10 @@ static bfd *make_singleton_name_thunk PARAMS ((const char *, bfd *));
static char *make_import_fixup_mark PARAMS ((arelent *));
static bfd *make_import_fixup_entry
PARAMS ((const char *, const char *, const char *, bfd *));
+static bfd *make_runtime_pseudo_reloc
+ PARAMS ((const char *, const char *, int, bfd *));
+static bfd *pe_create_runtime_relocator_reference
+ PARAMS ((bfd *));
static unsigned int pe_get16 PARAMS ((bfd *, int));
static unsigned int pe_get32 PARAMS ((bfd *, int));
static unsigned int pe_as32 PARAMS ((void *));
@@ -2094,15 +2099,112 @@ make_import_fixup_entry (name, fixup_name, dll_symname, parent)
return abfd;
}
+/* .section .rdata_runtime_pseudo_reloc
+ .long addend
+ .rva __fuNN_SYM (pointer to reference (address) in text) */
+
+static bfd *
+make_runtime_pseudo_reloc (name, fixup_name, addend, parent)
+ const char *name ATTRIBUTE_UNUSED;
+ const char *fixup_name;
+ int addend;
+ bfd *parent;
+{
+ asection *rt_rel;
+ unsigned char *rt_rel_d;
+ char *oname;
+ bfd *abfd;
+
+ oname = (char *) xmalloc (20);
+ sprintf (oname, "rtr%06d.o", tmp_seq);
+ tmp_seq++;
+
+ 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 = (asymbol **) xmalloc (2 * sizeof (asymbol *));
+ rt_rel = quick_section (abfd, ".rdata_runtime_pseudo_reloc", SEC_HAS_CONTENTS, 2);
+
+ quick_symbol (abfd, "", fixup_name, "", UNDSEC, BSF_GLOBAL, 0);
+
+ bfd_set_section_size (abfd, rt_rel, 8);
+ rt_rel_d = (unsigned char *) xmalloc (8);
+ rt_rel->contents = rt_rel_d;
+ memset (rt_rel_d, 0, 8);
+ bfd_put_32 (abfd, addend, rt_rel_d);
+
+ quick_reloc (abfd, 4, BFD_RELOC_RVA, 1);
+ save_relocs (rt_rel);
+
+ bfd_set_symtab (abfd, symtab, symptr);
+
+ bfd_set_section_contents (abfd, rt_rel, rt_rel_d, 0, 8);
+
+ bfd_make_readable (abfd);
+ return abfd;
+}
+
+/* .section .rdata
+ .rva __pei386_runtime_relocator */
+
+static bfd *
+pe_create_runtime_relocator_reference (parent)
+ bfd *parent;
+{
+ asection *extern_rt_rel;
+ unsigned char *extern_rt_rel_d;
+ char *oname;
+ bfd *abfd;
+
+ oname = (char *) xmalloc (20);
+ sprintf (oname, "ertr%06d.o", tmp_seq);
+ tmp_seq++;
+
+ 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 = (asymbol **) xmalloc (2 * sizeof (asymbol *));
+ extern_rt_rel = quick_section (abfd, ".rdata", SEC_HAS_CONTENTS, 2);
+
+ quick_symbol (abfd, "", "__pei386_runtime_relocator", "", UNDSEC, BSF_NO_FLAGS, 0);
+
+ bfd_set_section_size (abfd, extern_rt_rel, 4);
+ extern_rt_rel_d = (unsigned char *) xmalloc (4);
+ extern_rt_rel->contents = extern_rt_rel_d;
+
+ quick_reloc (abfd, 0, BFD_RELOC_RVA, 1);
+ save_relocs (extern_rt_rel);
+
+ bfd_set_symtab (abfd, symtab, symptr);
+
+ bfd_set_section_contents (abfd, extern_rt_rel, extern_rt_rel_d, 0, 4);
+
+ bfd_make_readable (abfd);
+ return abfd;
+}
+
void
-pe_create_import_fixup (rel)
+pe_create_import_fixup (rel, s, addend)
arelent *rel;
+ asection *s;
+ int addend;
{
char buf[300];
struct symbol_cache_entry *sym = *rel->sym_ptr_ptr;
struct bfd_link_hash_entry *name_thunk_sym;
const char *name = sym->name;
char *fixup_name = make_import_fixup_mark (rel);
+ bfd *b;
sprintf (buf, U ("_nm_thnk_%s"), name);
@@ -2117,14 +2219,39 @@ pe_create_import_fixup (rel)
config.text_read_only = false;
}
- {
- extern char * pe_data_import_dll;
- char * dll_symname = pe_data_import_dll ? pe_data_import_dll : "unknown";
+ if (addend == 0 || link_info.pei386_runtime_pseudo_reloc)
+ {
+ extern char * pe_data_import_dll;
+ char * dll_symname = pe_data_import_dll ? pe_data_import_dll : "unknown";
- bfd *b = make_import_fixup_entry (name, fixup_name, dll_symname,
- output_bfd);
- add_bfd_to_link (b, b->filename, &link_info);
- }
+ b = make_import_fixup_entry (name, fixup_name, dll_symname, output_bfd);
+ add_bfd_to_link (b, b->filename, &link_info);
+ }
+
+ if (addend != 0)
+ {
+ if (link_info.pei386_runtime_pseudo_reloc)
+ {
+ if (pe_dll_extra_pe_debug)
+ printf ("creating runtime pseudo-reloc entry for %s (addend=%d)\n",
+ fixup_name, addend);
+ b = make_runtime_pseudo_reloc (name, fixup_name, addend, output_bfd);
+ add_bfd_to_link (b, b->filename, &link_info);
+
+ if (runtime_pseudo_relocs_created == 0)
+ {
+ b = pe_create_runtime_relocator_reference (output_bfd);
+ add_bfd_to_link (b, b->filename, &link_info);
+ }
+ runtime_pseudo_relocs_created++;
+ }
+ else
+ {
+ einfo (_("%C: variable '%T' can't be auto-imported. Please read the documentation for ld's --enable-auto-import for details.\n"),
+ s->owner, s, rel->address, sym->name);
+ einfo ("%X");
+ }
+ }
}