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
DJ Delorie wrote:
> Ok, I'm cynical of the average user. How about this:
>
> stringtest.o: In function `main':
> /usr/src/binutils/tmp/stringtest.c:9: variable 'hwstr1' can't be
> auto-imported. Please read the documentation for ld's
> --enable-auto-import for details.
>
> By not hinting at workarounds in the message, we force them to read
> the more complete documentation of the issue. And teach them to read
> documentation in general too ;-)
Sounds fine to me. Any comments on the proposed changes to that
particular section of ld.texinfo? (Reproduced here for discussion:)
------------------------------------------------------
@kindex --enable-auto-import
@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. 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:
@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
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:
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 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
functions).