This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: [RFA] [pei-386] prevent ld (auto-import) from generating broken code
Charles Wilson wrote:
> DJ Delorie wrote:
>
>> Why is this one needed? That's what the ATTRIBUTE_UNUSED is for...
>>
>> The rest of it looks OK to me. I assume you're done the usual
>> build/test cycle, yes?
>>
>
>
> Yes. Well, I have rebuilt & and tested with those revised patches, but
> it wasn't a full "clean" test; I didn't wipe out my build dir and start
> over from scratch. I'll do that now.
>
>>
>>> @@ -931,6 +947,8 @@
>>> struct bfd_hash_entry *h;
>>> PTR string ATTRIBUTE_UNUSED;
>>> {
>>> + (void)string;
>>> +
>>> if (pe_dll_extra_pe_debug)
>>
>
>
> Ah -- I think that's because Paul was using non-current-cvs sources when
> he developed the original patch. (However, I have been, so *my* version
> of the patch has both the ATTRIBUTE_UNUSED thing and the (void)string
> thing). The PTR string ATTRIBUTE_UNUSED thing was added sometime after
> the late July/early August round of testing on auto-import.
>
> I'm removing the (void)string thing, and then I'll do a complete (clean)
> rebuild/test cycle.
Okay, with the (void)string part of the patch removed, I did a complete,
clear-out-the-build-dir-and-rebuild cycle. The rebuilt ld works as
expected.
The re-revised patch, as tested, is attached. Okay to apply?
--Chuck
Index: ld/ld.texinfo
===================================================================
RCS file: /cvs/src/src/ld/ld.texinfo,v
retrieving revision 1.48
diff -u -r1.48 ld.texinfo
--- ld.texinfo 2001/09/05 16:00:13 1.48
+++ ld.texinfo 2001/09/12 02:28:18
@@ -1726,9 +1726,103 @@
@kindex --enable-auto-import
@item --enable-auto-import
-Do sophisticalted linking of @code{_symbol} to @code{__imp__symbol} for
+Do sophisticated linking of @code{_symbol} to @code{__imp__symbol} for
DATA imports from DLLs, and create the necessary thunking symbols when
-building the DLLs with those DATA exports.
+building the DLLs with those DATA exports. This generally will 'just
+work' -- but sometimes you may see this message:
+
+"variable '<var>' can't be auto-imported. Please read the
+documentation for ld's @code{--enable-auto-import} for details."
+
+This message occurs when some (sub)expression accesses an address
+ultimately given by the sum of two constants (Win32 import tables only
+allow one). Instances where this may occur include accesses to member
+fields of struct variables imported from a DLL, as well as using a
+constant index into an array variable imported from a DLL. There are
+several ways to address this difficulty.
+
+One solution is to force one of the 'constants' to be a variable --
+that is, unknown and un-optimizable at compile time. For arrays,
+there are two possibilities: a) make the indexee (the array's address)
+a variable, or b) make the 'constant' index a variable. Thus:
+
+@example
+extern type extern_array[];
+extern_array[1] -->
+ @{ volatile type *t=extern_array; t[1] @}
+@end example
+
+or
+
+@example
+extern type extern_array[];
+extern_array[1] -->
+ @{ volatile int t=1; extern_array[t] @}
+@end example
+
+For structs, the only option is to make the struct itself variable:
+
+@example
+extern struct s extern_struct;
+extern_struct.field -->
+ @{ volatile struct s *t=&extern_struct; t->field @}
+@end example
+
+A second method of dealing with this difficulty is to abandon
+'auto-import' for the offending symbol and mark it with
+@code{__declspec(dllimport)}. However, in practice that
+requires using compile-time #defines to indicate whether you are
+building a DLL, building client code that will link to the DLL, or
+merely building/linking to a static library. In making the choice
+between the various methods of resolving the 'direct address with
+constant offset' problem, you should consider typical real-world usage:
+
+Original:
+@example
+--foo.h
+extern int arr[];
+--foo.c
+#include "foo.h"
+void main(int argc, char **argv)@{
+ printf("%d\n",arr[1]);
+@}
+@end example
+
+Solution 1:
+@example
+--foo.h
+extern int arr[];
+--foo.c
+#include "foo.h"
+void main(int argc, char **argv)@{
+ /* This workaround is for win32 and cygwin; do not "optimize" */
+ volatile int *parr = arr;
+ printf("%d\n",parr[1]);
+@}
+@end example
+
+Solution 2:
+@example
+--foo.h
+/* Note: auto-export is assumed (no __declspec(dllexport)) */
+#if (defined(_WIN32) || defined(__CYGWIN__)) && \
+ !(defined(FOO_BUILD_DLL) || defined(FOO_STATIC))
+#define FOO_IMPORT __declspec(dllimport)
+#else
+#define FOO_IMPORT
+#endif
+extern FOO_IMPORT int arr[];
+--foo.c
+#include "foo.h"
+void main(int argc, char **argv)@{
+ printf("%d\n",arr[1]);
+@}
+@end example
+
+A third way to avoid this problem is to re-code your
+library to use a functional interface rather than a data interface
+for the offending variables (e.g. set_foo() and get_foo() accessor
+functions).
@kindex --disable-auto-import
@item --disable-auto-import
Index: ld/pe-dll.c
===================================================================
RCS file: /cvs/src/src/ld/pe-dll.c,v
retrieving revision 1.26
diff -u -r1.26 pe-dll.c
--- pe-dll.c 2001/08/21 11:42:57 1.26
+++ pe-dll.c 2001/09/12 02:28:21
@@ -982,10 +982,10 @@
pe_walk_relocs_of_symbol (info, name, cb)
struct bfd_link_info *info;
CONST char *name;
- int (*cb) (arelent *);
+ int (*cb) (arelent *, asection *);
{
bfd *b;
- struct sec *s;
+ asection *s;
for (b = info->input_bfds; b; b = b->link_next)
{
@@ -1003,7 +1003,7 @@
&& s->output_section == bfd_abs_section_ptr)
continue;
- current_sec=s;
+ current_sec = s;
symsize = bfd_get_symtab_upper_bound (b);
symbols = (asymbol **) xmalloc (symsize);
@@ -1016,7 +1016,7 @@
for (i = 0; i < nrelocs; i++)
{
struct symbol_cache_entry *sym = *relocs[i]->sym_ptr_ptr;
- if (!strcmp(name,sym->name)) cb(relocs[i]);
+ if (!strcmp(name,sym->name)) cb(relocs[i], s);
}
free (relocs);
/* Warning: the allocated symbols are remembered in BFD and reused
@@ -1908,7 +1908,7 @@
/* we convert reloc to symbol, for later reference */
static int counter;
static char *fixup_name = NULL;
- static int buffer_len = 0;
+ static unsigned int buffer_len = 0;
struct symbol_cache_entry *sym = *rel->sym_ptr_ptr;
Index: ld/pe-dll.h
===================================================================
RCS file: /cvs/src/src/ld/pe-dll.h,v
retrieving revision 1.4
diff -u -r1.4 pe-dll.h
--- pe-dll.h 2001/08/02 23:12:02 1.4
+++ pe-dll.h 2001/09/12 02:28:21
@@ -48,7 +48,7 @@
extern void pe_walk_relocs_of_symbol PARAMS ((struct bfd_link_info * info,
CONST char *name,
- int (*cb) (arelent *)));
+ int (*cb) (arelent *, asection *)));
extern void pe_create_import_fixup PARAMS ((arelent * rel));
#endif /* PE_DLL_H */
Index: ld/emultempl/pe.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/pe.em,v
retrieving revision 1.50
diff -u -r1.50 pe.em
--- pe.em 2001/08/31 13:30:12 1.50
+++ pe.em 2001/09/12 02:28:24
@@ -127,7 +127,7 @@
static boolean pe_undef_cdecl_match
PARAMS ((struct bfd_link_hash_entry *, PTR));
static void pe_fixup_stdcalls PARAMS ((void));
-static int make_import_fixup PARAMS ((arelent *));
+static int make_import_fixup PARAMS ((arelent *, asection *));
static void pe_find_data_imports PARAMS ((void));
#endif
@@ -845,20 +845,36 @@
}
static int
-make_import_fixup (rel)
+make_import_fixup (rel, s)
arelent *rel;
+ asection *s;
{
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);
+
+ {
+ int addend = 0;
+ if (!bfd_get_section_contents(s->owner, s, &addend, rel->address, sizeof(addend)))
+ {
+ einfo (_("%C: Cannot get section contents - auto-import exception\n"),
+ s->owner, s, rel->address);
+ }
+
+ if (addend == 0)
+ pe_create_import_fixup (rel);
+ 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");
+ }
+ }
+
return 1;
}