Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT sources DOT redhat DOT com Delivered-To: mailing list cygwin AT sources DOT redhat DOT com From: "Ralf Habacker" To: "Cygwin" Subject: RE: Linking to commercial dll's Date: Fri, 16 Nov 2001 22:02:36 +0100 Message-ID: <000901c16ee2$05054420$fa6607d5@BRAMSCHE> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_000A_01C16EEA.66C9AC20" X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook 8.5, Build 4.71.2173.0 In-Reply-To: X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400 Importance: Normal ------=_NextPart_000_000A_01C16EEA.66C9AC20 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 8bit > -----Ursprüngliche Nachricht----- > Von: cygwin-owner AT sources DOT redhat DOT com > [mailto:cygwin-owner AT sources DOT redhat DOT com]Im Auftrag von David Westbury > Gesendet am: Donnerstag, 15. November 2001 17:11 > An: cygwin AT cygwin DOT com > Betreff: Linking to commercial dll's > > I'm attempting to link a C program that I've written to a commercial dll > (non-MS) using gcc in cygwin. I've read about everything I can find about > dll's but I can't seem to make my program access functions in the dll > correctly. My program compiles/links without errors using gcc, and even > runs correctly to some extent. Some functions work, others don't. The > functions that don't work seem to corrupt memory as evidenced by changes in > random variable values. This occurs even when the function return status > indicates success. The commercial package provides a ".dll" file, a ".lib" > file, and a ".h" file. These are obviously intended for use in a Windows > programming environment. I would appreciate if someone knowledgable would > tell me what steps would typically be required to link a program to a well > established commercial dll. For example, what might a typical gcc string > look like? Do gcc switches like "-L", and "-l" apply? Should I be linking > to the .dll or the .lib file? > > Dll's seem to be an especially difficult subject in cygwin, requiring > detailed knowlege of the MS way of doing things. Are dll's not > standardized? Is a "cookbook" approach to dll linking not possible? The > issue seems to be a steep hill for an average working programmer, like me, > to climb. This limits the usefulness of cygwin as a programming environment > for me. > > BTW, is cygwin intended for MS programmers wanting to explore the Unix > world or is it of more interest to Unix programmers who, like me, have an > occasional need to run Unix programs on Windows? Programmers coming from > Unix typically won't know much about dll's so a little more introductory > documentation or pointers to such material would seem appropriate for the > cygwin site. I've been to the bookstores and haven't found much help there, > even in Windows programming texts. Apparently dll's simply work correctly > in Windows and require little explanation. One text did say something that > seemed to indicate that I should be linking against the .lib file as it > contains pointers into the .dll fine. This doesn't work for me at all > however. > > Here's the gcc string I'm using that results in a partially working > executable: > > gcc -g myprog.c -o myprog //filename.dll > > Any help or pointers to information would be greatly appreciated. > 1. For a deeply explanation of the windows dll format look at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwbgen/html/ms dn_peeringpe.asp. 2. You have to create a ld compatible import library. You can use the tools impgen and dlltool for doing this. impgen comes from the libtool package and is appended to this mail. dlltool is a part of the basic cygwin. Here is an example for a dll named 'libxslt.dll': 1. compile the tool impgen with the appended source file gcc -o impgen impgen.c cp ./impgen /usr/local/bin 2. create a file with all exported symbols from the dll (it's called 'def' file). impgen libxslt.dll >libxslt.def 3. create an import library with this def file dlltool -d libxslt.def -l libxslt.a 4. Now you can link your app with the dll (in truth with the import library) Note: There may be some compiling problems with the include file from your dll in case of redefined symbols or compiler syntay. It may be nessesary to patch this. gcc -o yourapp yourapp.c -L. -lxslt Note2: You can verify using the import library with the -Wl,--verbose flag in you command line. gcc -o yourapp yourapp.c -L. -lxslt -Wl,--verbose Then you see some lines with ... attempt to open /usr/lib/w32api/libkernel32.dll.a failed attempt to open /usr/lib/w32api/libkernel32.a succeeded ... which shows, that you are linking the .a file, not the dll. Perhaps that helps PS: To the cygwin cracks: If I have written something wrong, please correct this. Regards Ralf Habacker ------=_NextPart_000_000A_01C16EEA.66C9AC20 Content-Type: application/octet-stream; name="impgen.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="impgen.c" /* impgen.c starts here */ /* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU libtool. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include /* for printf() */ #include /* for open(), lseek(), read() */ #include /* for O_RDONLY, O_BINARY */ #include /* for strdup() */ /* O_BINARY isn't required (or even defined sometimes) under Unix */ #ifndef O_BINARY #define O_BINARY 0 #endif static unsigned int pe_get16 (fd, offset) int fd; int offset; { unsigned char b[2]; lseek (fd, offset, SEEK_SET); read (fd, b, 2); return b[0] + (b[1]<<8); } static unsigned int pe_get32 (fd, offset) int fd; int offset; { unsigned char b[4]; lseek (fd, offset, SEEK_SET); read (fd, b, 4); return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); } static unsigned int pe_as32 (ptr) void *ptr; { unsigned char *b = ptr; return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); } int main (argc, argv) int argc; char *argv[]; { int dll; unsigned long pe_header_offset, opthdr_ofs, num_entries, i; unsigned long export_rva, export_size, nsections, secptr, expptr; unsigned long name_rvas, nexp; unsigned char *expdata, *erva; char *filename, *dll_name; filename = argv[1]; dll = open(filename, O_RDONLY|O_BINARY); if (dll < 1) return 1; dll_name = filename; for (i=0; filename[i]; i++) if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') dll_name = filename + i +1; pe_header_offset = pe_get32 (dll, 0x3c); opthdr_ofs = pe_header_offset + 4 + 20; num_entries = pe_get32 (dll, opthdr_ofs + 92); if (num_entries < 1) /* no exports */ return 1; export_rva = pe_get32 (dll, opthdr_ofs + 96); export_size = pe_get32 (dll, opthdr_ofs + 100); nsections = pe_get16 (dll, pe_header_offset + 4 +2); secptr = (pe_header_offset + 4 + 20 + pe_get16 (dll, pe_header_offset + 4 + 16)); expptr = 0; for (i = 0; i < nsections; i++) { char sname[8]; unsigned long secptr1 = secptr + 40 * i; unsigned long vaddr = pe_get32 (dll, secptr1 + 12); unsigned long vsize = pe_get32 (dll, secptr1 + 16); unsigned long fptr = pe_get32 (dll, secptr1 + 20); lseek(dll, secptr1, SEEK_SET); read(dll, sname, 8); if (vaddr <= export_rva && vaddr+vsize > export_rva) { expptr = fptr + (export_rva - vaddr); if (export_rva + export_size > vaddr + vsize) export_size = vsize - (export_rva - vaddr); break; } } expdata = (unsigned char*)malloc(export_size); lseek (dll, expptr, SEEK_SET); read (dll, expdata, export_size); erva = expdata - export_rva; nexp = pe_as32 (expdata+24); name_rvas = pe_as32 (expdata+32); printf ("EXPORTS\n"); for (i = 0; i