Subject: Re: Modifications of standard headers for PECOFF
To: TAMURA Kent <kent@netbsd.org>
From: Bang Jun-Young <junyoung@mogua.com>
List: tech-userlevel
Date: 05/25/2002 11:25:00
On Fri, May 24, 2002 at 10:42:03PM +0900, TAMURA Kent wrote:
>
> In message "Re: Modifications of standard headers for PECOFF"
> on 02/05/24, TAMURA Kent <kent@netbsd.org> writes:
> > > These changes don't even look reasonable to me. Why don't you use
> > > --enable-auto-export and --enable-auto-import features of recent
> > > binutils (the former is default now, AFAIK)?
> >
> > Oh, I have not known --enable-auto-import. I'll try it. Thank
> > you.
>
> I have tried it and found --enable-auto-import does not work in
> many cases. It seems to work for simple variables but not for
> arrays and struct variables.
Arrgh. It's a known problem. ld(1) manual says (sorry for long
excerption):
--enable-auto-import
Do sophisticated linking of _symbol to __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:
"variable '<var>' can't be auto-imported. Please read the
documentation for ld's --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. Any multiword variable (arrays,
structs, long long, etc) may trigger this error condition.
However, regardless of the exact data type of the offending
exported variable, ld will always detect it, issue the warning,
and exit.
There are several ways to address this difficulty, regardless
of the data type of the exported variable:
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:
extern type extern_array[];
extern_array[1] -->
{ volatile type *t=extern_array; t[1] }
or
extern type extern_array[];
extern_array[1] -->
{ volatile int t=1; extern_array[t] }
For structs (and most other multiword data types) the only
option is to make the struct itself (or the long long, or the
...) variable:
extern struct s extern_struct;
extern_struct.field -->
{ volatile struct s *t=&extern_struct; t->field }
or
extern long long extern_ll;
extern_ll -->
{ volatile long long * local_ll=&extern_ll; *local_ll }
A second method of dealing with this difficulty is to abandon
'auto-import' for the offending symbol and mark it with
__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:
--foo.h
extern int arr[];
--foo.c
#include "foo.h"
void main(int argc, char **argv){
printf("%d\n",arr[1]);
}
Solution 1:
--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]);
}
Solution 2:
--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]);
}
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).
> I'll commit __libc_extern change later.
I still believe __declspec(dllexport) is not necessary at all since
--enable-auto-export is enabled by default, and __declspec(dllimport)
can be omitted for simple variables if --enable-auto-import is given
to ld(1).
BTW, how many multiword variables are exported from libc to
outer modules?
Jun-Young
--
Bang Jun-Young <junyoung@mogua.com>