This is the mail archive of the mailing list for the binutils project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[RFA] [pei-386] prevent ld (auto-import) from generating broken code

This patch includes a (slightly) modified version of Paul Sokolovsky's 
fix for this bug, and updates to the ld.texinfo file to explain the new 

The bug: accessing, from client code, a complex variable imported from a 
DLL (an array or struct; possibly others) with a constant (nonzero) 
offset leads to incorrect "fixups" --- e.g. a[2] is the same as a[0] if 
array 'a' is imported from a DLL.  s.secondfield is the same as 
s.firstfield if struct 's' is imported from a DLL.

The compiled client code has a nonzero addend, but the windows loader 
can't seem to handle "additional" offsets when doing the dynamic 

The fix: Paul's patch identifies these problematic accesses (if they 
exist; seems to be rare), prints out the following message, and aborts. 
(Actually, my modification to Paul's patch merely switches the order of 
the two suggested remedies in this message):

stringtest.o: In function `main':
/usr/src/binutils/tmp/stringtest.c:9: aggregate 'hwstr1' is referenced 
in direct addressing mode with constant offset - auto-import failed. 
Workarounds: a) use a 'volatile' auxilliary variable; b) mark the symbol 
with __declspec(dllimport)
collect2: ld returned 1 exit status

ld.texinfo is updated to provide more information on this bug/message, 
and elaborate on the possible workarounds.

See this thread:

[ A serious bug of "ld --enable-auto-import"]

and this one

Re: Serious bug in auto-import

2001-09-10  Paul Sokolovsky  <>

	* emultempl/pe.em(make_import_fixup): change signature to
	take asection as well as arelec; we need this for proper
	error reporting.  Only call pe_create_import_fixup() if 
	there is no attempt to add a constant addend to the reloc;
	otherwise, report error condition.
	* pe-dll.c(pe_walk_relocs_of_symbol): change signature,
	since final argument is a pointer to make_import_fixup().
	Change call to cb() to match make_import_fixup() signature.
	(make_import_fixup_mark): make buffer_len unsigned.
	* pe-dll.h: change signature of pe_walk_relocs_of_symbol.

2001-09-10  Charles Wilson  <>

	* ld.texinfo: add verbose documentation for auto-import
	direct-addressing workaround, to compliment the terse 
	error message.

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/11 02:17:35
@@ -1728,7 +1728,98 @@
 @item --enable-auto-import
 Do sophisticalted 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:
+"aggregate '<var>' is referenced in direct addressing mode with constant
+offset - auto-import failed. Workarounds: a) use 'volatile' auxilliary 
+variable; b) mark the symbol with __declspec(dllimport)"
+This message occurs when some (sub)expression accesses an address 
+ultimately given by the sum of two constants, such as member fields 
+of struct variables imported from a DLL, or using a constant index into 
+an array variable imported from a DLL.  The solution is to force one
+'constant' 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:
+extern type extern_array[];
+extern_array[1] --> 
+   @{ volatile type *t=extern_array; t[1] @}
+@end 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:
+extern struct s extern_struct;
+extern_struct.field --> 
+   @{ volatile struct s *t=&extern_struct; t->field @}
+@end example
+Of course, you can also just give up on 'auto-import' for the offending
+symbol and mark it with @code{__declspec(dllimport)}.  However, 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 two methods of resolving the 'direct address with constant
+offset' problem, you should consider typical real-world usage:
+extern int arr[];
+#include "foo.h"
+void main(int argc, char **argv)@{
+  printf("%d\n",arr[1]);
+@end example
+Solution 1:
+extern int arr[];
+#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:
+/* 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)
+#define FOO_IMPORT
+extern FOO_IMPORT int arr[];
+#include "foo.h"
+void main(int argc, char **argv)@{
+  printf("%d\n",arr[1]);
+@end example
+A final 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
 @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/11 02:17:38
@@ -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)
-	  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/11 02:17:38
@@ -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/11 02:17:42
@@ -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));
@@ -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: aggregate '%T' is referenced in direct addressing mode with constant offset - auto-import failed. Workarounds: a) use a 'volatile' auxilliary variable; b) mark the symbol with __declspec(dllimport)\n"),
+               s->owner, s, rel->address, sym->name);
+        einfo ("%X");
+      }
+  }
   return 1;
@@ -931,6 +947,8 @@
   struct bfd_hash_entry *h;
+  (void)string;
   if (pe_dll_extra_pe_debug)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]