Topic: How to call a 32 bit DLL function ?
Author: Allan_W@my-dejanews.com (Allan W)
Date: Wed, 22 May 2002 16:14:02 CST Raw View
Steve Clamage <clamage@eng.sun.com> wrote
> On Thu, 16 May 2002, Allan W wrote:
> > The first is called "decorated names." This used to be called "name
> > mangling" (and you'll still see that term a lot), but "name mangling"
> > sounds like a gross compiler error -- while "decorated names"
> > is obviously a feature :-) Decorated names were originally created
> > to allow C++ to work with legacy linkers (that might not understand
> > uppercase/lowercase, namespaces, class names, and overloading). In
> > practice these "decorated names" are still around for reasons of
> > compatibility with older versions of the same compiler.
>
> And because few implementations (if any) have any way to
> distinguish functions with the same name that are nevertheless
> different, other than by varying spelling of the function names
> in the generated code.
That's pretty much what I meant. I think that a lot of linkers have
evolved to the point where they can understand uppercase/lowercase,
namespaces, and even overloaded function names, not just for C++ but
any other case-sensitive language. However, even on systems that now
have modern linkers in place, the compiler still uses decorated names.
> > Note that
> > there isn't any standard for how names get decorated, which is why
> > it's nearly impossible to mix C++ object code from two different
> > compilers.
>
> You have it backwards.
>
> C++ implementations have many degrees of freedom -- object layout,
> virtual function mechanism, function calling sequence, exception
> mechanisms, RTTI mechanisms, and so on.
>
> Because different implementations differ in these choices, you
> cannot usually get object code from different compilers to
> interoperate.
>
> To help ensure that you don't accidently succeed in linking
> incompatible code together, compiler implementors often take
> pains to enusure their name decoration scheme is unlike other
> implementations.
Essentially you're saying that since different compilers use
incompatible assumptions, they also intentionally make the names
different so they can't link together.
But this isn't usually done for extern "C" functions!
Also, some platforms have well-defined hardware-assisted calling
sequences used essentially the same way by all vendors -- my most
recent experience was with the VAX (which probably few use anymore)
but I'm sure there are others. I suspect that the name decoration
on these platforms differs by compiler vendor too.
The reasons you give above might be good reasons to avoid "fixing"
the situation -- but I don't think they give the reasons that the
incompatibility developed in the first place.
I invite any compiler vendor (Mr. Comeu?) to shed light on this.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Steve Clamage <clamage@eng.sun.com>
Date: Thu, 23 May 2002 21:21:57 GMT Raw View
On Wed, 22 May 2002, Allan W wrote:
>
> Steve Clamage <clamage@eng.sun.com> wrote
>
> > > Note that
> > > there isn't any standard for how names get decorated, which is why
> > > it's nearly impossible to mix C++ object code from two different
> > > compilers.
> >
> > You have it backwards.
> >
> > C++ implementations have many degrees of freedom -- object layout,
> > virtual function mechanism, function calling sequence, exception
> > mechanisms, RTTI mechanisms, and so on.
> >
> > Because different implementations differ in these choices, you
> > cannot usually get object code from different compilers to
> > interoperate.
> >
> > To help ensure that you don't accidently succeed in linking
> > incompatible code together, compiler implementors often take
> > pains to enusure their name decoration scheme is unlike other
> > implementations.
>
> But this isn't usually done for extern "C" functions!
Often the ABI for C is the platform ABI, and is the "lingua franca"
for language interoperation. A function is normally declared extern
"C" so that it can be called from non-C++ code. In that case, it
uses only C types in its interface.
(ABI = Application Binary Interface, the specification of data and
code layout and calling sequences.)
The only issue is whether the C types and C function calling sequence
is the same for different C compilers on the same platform. If not,
the code will not interoperate. A C++ compiler could decorate the
names of extern "C" functions, but then the code would not link
with C code, which is the major reason for declaring the function
extern "C"!
You can't have everything. I consider it a benefit that you cannot
accidently link together C++ code that will not interoperate. The
situation with extern "C" code is exactly the same as when using
two different C compilers on the platform: The code will run if
the two compilers use compatible C ABIs.
>
> Also, some platforms have well-defined hardware-assisted calling
> sequences used essentially the same way by all vendors
Yes, true on many platforms. But just because functions are called
the same way doesn't mean that class layout is the same, or that
virtual functions are accessed in the same way, or that RTTI data
is stored and accessed in the same way, or that pointers to members
are used in the same way, or that vtables are implemented the same way,
or that the interface to compiler helper routines is the same, or ...
>
> The reasons you give above might be good reasons to avoid "fixing"
> the situation -- but I don't think they give the reasons that the
> incompatibility developed in the first place.
>
> I invite any compiler vendor (Mr. Comeu?) to shed light on this.
I'm a C++ compiler vendor, and I've been one since 1987.
C++ has evolved over time, and so have implementation techniques.
An older compiler might choose to stay with an older technique
to maintain binary compatibility of the generated object code.
Or vendor B might invent a new technique that didn't occur to
vendor A.
Some vendors have patented implementation techniques. Another vendor
might not want to get involved with licensing the technology, even
if no royalties were involved. (There's no such thing as a free
lunch; you wind up paying somehow.)
Different implementation techniques can involve different tradeoffs:
run-time size vs run-time speed, compile-time vs run-time speed,
compile time vs program size. (An example of the latter would be
doing the analysis to determine how to share data space and vtable
space in an object, versus always generating a simple layout.)
An of course potential added compiler complexity to use an
implementation technique that is more efficient at run time.
Different vendors make those tradeoffs in different ways, sometimes
due to wanting to appeal to different customer bases.
Here's one well-worn example.
In the presence of multiple inheritance, calling a virtual function
sometimes involves adjusting the value of the "this" pointer. Most
functions most of the time require no adjustment. You can store the
adjustment in the vtable, making the vtable bigger for all class
types, and generating code to do the adjustment for all functions,
even when no adjustment is needed. Or you can generate code
stubs that do the adjustment only for the functions that need it.
(See the ARM pages 217-237 for details.)
On different platforms, one choice might be more efficient at run
time than the other. A multi-platform compiler might not want to
support both methods, but just pick one, even if the other might be
better for some platform. Apart from that, implementors can have
different opinions on the importance of vtable size vs code stubs.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Eugene Kuznetsov" <ekuznetsov@divxnetworks.com>
Date: Wed, 15 May 2002 17:59:02 GMT Raw View
"Evert Vrieze" <bbi@bbi.fol.nl> wrote in message
news:abplga$ami$1@rubens.telebyte.nl...
> I am trying to get a simple program to call a DLL function from MSVC6
> (VC98).
> I would expect that it is as simple as it would be in VB using the same
> function.
> But after three days of browsing around the msdn site, I still haven't
found
> the ansewer. I found out that I need to create an import library using
stubs
> like :
> _declspec(dllimport) int Thefunction(DWORD)
return
> 0;} or
> _declspec(dllimport) int APIENTRY Thefunction(DWORD) { return 0;}
>
> Building without the APIENTRY compiles to an executable, but this messes
up
> the stack as it uses C calling convention then. Trying it with the
APIENTRY
> mangles the entry names e.g. _Thefunction@4 such that it can't find the
name
> in the DLL anymore.
> How to do it properly ??
>
Use the same calling convention for this function in DLL and in the code
that calls it.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Allan_W@my-dejanews.com (Allan W)
Date: Thu, 16 May 2002 19:24:36 GMT Raw View
> "Evert Vrieze" <bbi@bbi.fol.nl> wrote
> > I am trying to get a simple program to call a DLL function from
> > MSVC6 (VC98). I would expect that it is as simple as it would be
> > in VB using the same function. But after three days of browsing
> > around the msdn site, I still haven't found the ansewer. I found
> > out that I need to create an import library using stubs like:
> > _declspec(dllimport) int Thefunction(DWORD) { return 0;}
> > or
> > _declspec(dllimport) int APIENTRY Thefunction(DWORD) { return 0;}
> >
> > Building without the APIENTRY compiles to an executable, but this
> > messes up the stack as it uses C calling convention then. Trying it
> > with the APIENTRY mangles the entry names e.g. _Thefunction@4 such
> > that it can't find the name in the DLL anymore.
> >
> > How to do it properly ??
"Eugene Kuznetsov" <ekuznetsov@divxnetworks.com> wrote
> Use the same calling convention for this function in DLL and in the code
> that calls it.
You're dealing with two issues here.
The first is called "decorated names." This used to be called "name
mangling" (and you'll still see that term a lot), but "name mangling"
sounds like a gross compiler error -- while "decorated names"
is obviously a feature :-) Decorated names were originally created
to allow C++ to work with legacy linkers (that might not understand
uppercase/lowercase, namespaces, class names, and overloading). In
practice these "decorated names" are still around for reasons of
compatibility with older versions of the same compiler. Note that
there isn't any standard for how names get decorated, which is why
it's nearly impossible to mix C++ object code from two different
compilers.
The second is the calling convention. When one subroutine calls
another, the calling convention specifies how parameters and
return values are passed. Some of the parameters might be passed
in a register or in a special memory location, instead of on the
stack; also, parameters on the stack might be pushed right-to-left,
left-to-right, or some other strange combination; and the called
function might be expected to remove them from the stack before
returning, or might be expected to leave them there.
APIENTRY is typically defined as either extern "C" or extern "PASCAL",
along with some Microsoft-specific extensions. The net effect is to
both turn off name decoration, and also to specify a specific calling
convention different from the default. In short, these two things are
usually linked together in Microsoft DLL's.
Fortunately, C++ understands name decoration. If a function is NOT
declared as APIENTRY, then the definition gets a decorated name and
and the normal calling convention; on the other hand, when C++ calls
this function, that's exactly what is expected.
The bottom line is: When you want to call your function from non-C++
code, you should use APIENTRY to make sure that the name and calling
convention are known everywhere. If you want to use C++ features
such as overloading, you should NOT use APIENTRY -- you'll still be
able to call your function from C++ code, but not other languages.
(For purposes of this statement, consider a C++ compiler from some
other vendor to be "another language.")
Followups should probably be directed to a Microsoft-specific newsgroup;
they'll probably have more details on the above anyway, including ways
to use one of (name decoration, C calling convention) without the other.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: James Kanze <kanze@alex.gabi-soft.de>
Date: Fri, 17 May 2002 16:38:39 GMT Raw View
Allan_W@my-dejanews.com (Allan W) writes:
|> You're dealing with two issues here.
|> The first is called "decorated names." This used to be called
|> "name mangling" (and you'll still see that term a lot), but "name
|> mangling" sounds like a gross compiler error -- while "decorated
|> names" is obviously a feature :-)
The documentation still speaks of name mangling on the systems I use.
I think that the difference is one of environment, not time: it's
decorated names on Windows, and name mangling everywhere else.
|> Decorated names were originally created to allow C++ to work with
|> legacy linkers (that might not understand uppercase/lowercase,
|> namespaces, class names, and overloading). In practice these
|> "decorated names" are still around for reasons of compatibility
|> with older versions of the same compiler. Note that there isn't
|> any standard for how names get decorated, which is why it's nearly
|> impossible to mix C++ object code from two different compilers.
In practice, name mangling is still around because we're still using
the legacy linkers. Both Sun and g++ (to speak of the two compilers I
know best) have changed the object format in the past, and code
compiled with older compilers will not work with code compiled with
the newer ones. Both intentionally changed the name mangling each
time they did this, so that the code won't link; a behavior largely
superior to the alternative of subtle bugs and strange crashes in the
linked code.
--=20
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany Tel. +49(0)179 2607481
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Steve Clamage <clamage@eng.sun.com>
Date: Fri, 17 May 2002 20:54:59 GMT Raw View
On Thu, 16 May 2002, Allan W wrote:
>
> The first is called "decorated names." This used to be called "name
> mangling" (and you'll still see that term a lot), but "name mangling"
> sounds like a gross compiler error -- while "decorated names"
> is obviously a feature :-) Decorated names were originally created
> to allow C++ to work with legacy linkers (that might not understand
> uppercase/lowercase, namespaces, class names, and overloading). In
> practice these "decorated names" are still around for reasons of
> compatibility with older versions of the same compiler.
And because few implementations (if any) have any way to
distinguish functions with the same name that are nevertheless
different, other than by varying spelling of the function names
in the generated code.
> Note that
> there isn't any standard for how names get decorated, which is why
> it's nearly impossible to mix C++ object code from two different
> compilers.
You have it backwards.
C++ implementations have many degrees of freedom -- object layout,
virtual function mechanism, function calling sequence, exception
mechanisms, RTTI mechanisms, and so on.
Because different implementations differ in these choices, you
cannot usually get object code from different compilers to
interoperate.
To help ensure that you don't accidently succeed in linking
incompatible code together, compiler implementors often take
pains to enusure their name decoration scheme is unlike other
implementations.
Why don't all compilers use the same implementation method so
you can link object code together?
- An implementation sometimes must adhere to externally-
imposed object-code requirements. For example, to be certified
compatible with a brand name, you have to follow the requirements
of the brand name.
- An implementation might want to retain binary compatibility
with an earlier compiler.
- An efficient implementation on one platform might be inefficient
on another. Even on the same platform, one implementation might want
to support a wider range of variations within the platform. (For
example, passing floating-point values in floating-point registers
instead of on the stack might be more effient, but exclude some
hardware versions.)
- Implementor often patent implementation details. Other implementors
might want to avoid the legal issues surrounding getting a license to
use that method.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]