Linker switches [ was: Re: API's that certainly do work. ]
marcus@bighorn.dr.lucent.com
marcus@bighorn.dr.lucent.com
Fri Mar 28 10:32:00 GMT 1997
Colin Peters wrote:
] To summarize the summary: Don't link with -lkernel32 on your command
] line.
DRS <drs@inxpress.net> asks:
> I guess my question is, why would you want to do this anyway? I have
> been using -mwindows, which I thought was the recommended linker
> switch for compiling a GUI app. I don't claim to know anything
> about ld, except that it works for all the examples I have tried.
>
> I have been unable to find any documentation about the
> linker switch in question (-lkernel32) except that it appears
> to be mentioned in earlier versions of the distribution.
> If someone wants to explain the in's and outs of these
> various (win32 specific) switches and how they are supposed
> to work, I'm all ears. Do doubt this information would be
> of general interest.
The -lkernel32 is not a switch itself, but a library to be included. The
-l<library> option tells the linker to look for lib<library>.a in the library
directories, so -lkernel32 tells it to search the libkernel32.a library.
One is tempted to do this if they reference some routines from the kernel32
library, especially if you don't remember that -mwindows already does that
for you. With a normal archive library, this is not a problem, but with
a DLL library it is.
The problem is that including the DLL library has to build an import descriptor
table which is a fairly complex structure. The contents depend on the library
routines actually referenced. Each routine referenced by the program is
resolved by a stub file in the library which places a jump in the .text
segment, one pointer into each of .idata$4 and .idata$5, and the function
name in .idata$6. Additionally, the stub file references a symbol that will
be resolved by another file from the library. This file supplies the head
of the structure in .idata$2 and leaves more undefined symbols to bring in
a file that terminates the .idata$4 and .idata$5 lists (for this DLL only)
and a terminator for the entire descriptor list in .idata$3. The cygwin32
strategy is slightly different, and they forgot the .idata$3 terminator, but
it is similar.
So, what happens when the kernel32 library is included twice is that the
undefined references from the program get resolved by the first -lkernel32
and the import table is built for that, then by the time that the libraries
get processed for the -mwindows, there are more references to routines from
the kernel32 library from other library routines (processing the library
twice would be OK if there were not any new references to the library). These
routines cause the jump instruction to be put into the .text section, pointers
in the .idata$4 and .idata$5 sections, and the function name in .idata$6,
but the reference that is supposed to bring in an import library header
into .idata$2 is resolved to the already present header from the first
include. However, since that import structure has already been built, the
new functions do not get incorporated into the structure, so when the program
is eventually loaded, these functions do not get their pointers updated to
point into the DLL since they are not really in the import table. Then,
when the function is called, the jump heads into the function name, not the
function itself, and things crash.
That's the problem with processing a DLL library twice. I'm pretty sure that
it would occur with Microsoft LINK as well, but I haven't verified it. It's
an intricate dance of the various segments to build the DLL import table, so
some things like this are difficult to handle. I suppose it could be dealt
with my using more .idata segments, something like .idata$4_kernel32 or some
such, but this would definately be non-standard.
marucs hall
Lucent Technologies
-
For help on using this list, send a message to
"gnu-win32-request@cygnus.com" with one line of text: "help".
More information about the Cygwin
mailing list