Subject: Re: .def files for stdcall functions (was: linking problems with the minimalist version)
From: [email-masked] (Mikey)

17 Sep 1997 05:22:39 -0700
Message-ID: <[email-masked]>
References: <01BCC380.AA4AF2C0@gbird0>
Reply-To: [email-masked]
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
To: Colin Peters <[email-masked]>, [email-masked]

This stuff is from dlltool.c, the comments at the top of the file.

The important thing in here, for people building dll's is

asm (".section .drectve;.ascii \42-export:Funcname@24\12\0\42;.section .text;");
int __stdcall Funcname(int *, long *, int, char, long)
(

ptr=4
int=4
char=4 (unless you do something weird with __attribute__((__aligned__)) )
short = 4              "
long = 8
long long = 16 (I think)
float = ?

put the above anywhere in the file except inside a function.

then run dlltool over the .o files like this
dlltool --dll mydll.dll --output-lib libmydll.a mydll.o

But Collin's basic premise still holds, this is inconvenient, and
incompatible, cc1/plus should be able to generate the above
code in response to a dllexport in the .c or .cc file.

isn't dlltool supposed to go away here shortly??????

/*
   This program allows you to build the files necessary to create
   DLLs to run on a system which understands PE format image files.
   (eg, Windows NT)

   See "Peering Inside the PE: A Tour of the Win32 Portable Executable
   File Format", MSJ 1994, Volume 9 for more information.
   Also see "Microsoft Portable Executable and Common Object File Format,
   Specification 4.1" for more information.

   A DLL contains an export table which contains the information
   which the runtime loader needs to tie up references from a
   referencing program. 

   The export table is generated by this program by reading
   in a .DEF file or scanning the .a and .o files which will be in the
   DLL.  A .o file can contain information in special  ".drectve" sections
   with export information.  

   A DEF file contains any number of the following commands:

   NAME <name> [ , <base> ] 
   The result is going to be <name>.EXE

   LIBRARY <name> [ , <base> ]    
   The result is going to be <name>.DLL

   EXPORTS  ( <name1> [ = <name2> ] [ @ <integer> ] [ NONAME ] [CONSTANT] ) *
   Declares name1 as an exported symbol from the
   DLL, with optional ordinal number <integer>

   IMPORTS  ( [ <name> = ] <name> . <name> ) *
   Ignored for compatibility

   DESCRIPTION <string>
   Puts <string> into output .exp file in the .rdata section

   [STACKSIZE|HEAPSIZE] <number-reserve> [ , <number-commit> ]
   Generates --stack|--heap <number-reserve>,<number-commit>
   in the output .drectve section.  The linker will
   see this and act upon it.

   [CODE|DATA] <attr>+
   SECTIONS ( <sectionname> <attr>+ )*
   <attr> = READ | WRITE | EXECUTE | SHARED
   Generates --attr <sectionname> <attr> in the output
   .drectve section.  The linker will see this and act
   upon it.

   A -export:<name> in a .drectve section in an input .o or .a
   file to this program is equivalent to a EXPORTS <name>
   in a .DEF file.

   The program generates output files with the prefix supplied
   on the command line, or in the def file, or taken from the first 
   supplied argument.

   The .exp.s file contains the information necessary to export
   the routines in the DLL.  The .lib.s file contains the information
   necessary to use the DLL's routines from a referencing program.

   Example:

   file1.c: 
   asm (".section .drectve");  
   asm (".ascii \"-export:adef\"");

   adef(char *s)
   {
   printf("hello from the dll %s\n",s);
   }

   bdef(char *s)
   {
   printf("hello from the dll and the other entry point %s\n",s);
   }

   file2.c:
   asm (".section .drectve");
   asm (".ascii \"-export:cdef\"");
   asm (".ascii \"-export:ddef\"");
   cdef(char *s)
   {
   printf("hello from the dll %s\n",s);
   }

   ddef(char *s)
   {
   printf("hello from the dll and the other entry point %s\n",s);
   }

   printf()
   {
   return 9;
   }

   main.c

   main()
   {
   cdef();
   }

   thedll.def

   LIBRARY thedll
   HEAPSIZE 0x40000, 0x2000
   EXPORTS bdef @ 20
   cdef @ 30 NONAME 

   SECTIONS donkey READ WRITE
   aardvark EXECUTE

   # compile up the parts of the dll

   gcc -c file1.c       
   gcc -c file2.c

   # put them in a library (you don't have to, you
   # could name all the .os on the dlltool line)

   ar  qcv thedll.in file1.o file2.o
   ranlib thedll.in

   # run this tool over the library and the def file
   ./dlltool --def thedll.def --output-exp thedll.o --output-lib thedll.a

   # build the dll with the library with file1.o, file2.o and the export table
   ld -o thedll.dll thedll.o thedll.in

   # build the mainline
   gcc -c themain.c 

   # link the executable with the import library
   ld -e main -Tthemain.ld -o themain.exe themain.o thedll.a

 */

/* .idata section description

   The .idata section is the import table.  It is a collection of several
   subsections used to keep the pieces for each dll together: .idata$[234567].
   IE: Each dll's .idata$2's are catenated together, each .idata$3's, etc.

   .idata$2 = Import Directory Table
   = array of IMAGE_IMPORT_DESCRIPTOR's.

	DWORD   Characteristics;      - pointer to .idata$4
	DWORD   TimeDateStamp;        - currently always 0
	DWORD   ForwarderChain;       - currently always 0
	DWORD   Name;                 - pointer to dll's name
	PIMAGE_THUNK_DATA FirstThunk; - pointer to .idata$5

   .idata$3 = null terminating entry for .idata$2.

   .idata$4 = Import Lookup Table
   = array of array of pointers to hint name table.
   There is one for each dll being imported from, and each dll's set is
   terminated by a trailing NULL.

   .idata$5 = Import Address Table
   = array of array of pointers to hint name table.
   There is one for each dll being imported from, and each dll's set is
   terminated by a trailing NULL.
   Initially, this table is identical to the Import Lookup Table.  However,
   at load time, the loader overwrites the entries with the address of the
   function.

   .idata$6 = Hint Name Table
   = Array of { short, asciz } entries, one for each imported function.
   The `short' is the function's ordinal number.

   .idata$7 = dll name (eg: "kernel32.dll"). (.idata$6 for ppc)
*/

On Wed, 17 Sep 1997 15:45:02 +0900, you wrote:

>Gunther Ebert[SMTP:[email-masked]] wrote:
>>Colin Peters wrote:
>>> My beef with all this is: why does GCC do it this way at all? What purpose
>>> does the @NN serve? After all, GCC knows how to generate the correct
>>> function call given a prototype, it *generates* the @NN, so it doesn't
>>> need it to know what to do. 
>>
>[snip]
>
>This (enforcing agreement between caller and callee about the state of the
>stack, which would be very painful to debug otherwise) is, indeed, a good
>reason and I stand enlightened. What we have here is an inadequacy of tools.
>
>True, pedump can be used to pick the names out of an import library
>generated by MSVC (which are mangled in the same way), and in fact I think
>the tool I mentioned earlier (dumpexts) is a version of pedump made to
>perform exactly this operation.
>
>It remains true, however, that sometimes one does not have a .def or .lib
>file, like, for example, when you are generating the DLL yourself. In these
>cases we are stuck going back and figuring out by hand (or via repeated
>experiences with unresolved externals) the number of bytes on the stack to
>add to the name. In this situation it would be nice to be able to either:
>
>  1) Get GCC (or another tool) to generate the .def file (or even better
>     the .a file), based on the prototypes (something like the __dll...
>     keywords in MSVC). The intelligence is there in the code, more or
>     less. Someone just needs to put it together.
>
>  2) Get GCC to not generate the @NN for stdcall function calls, probably
>     through a command line switch, in which case we could use dlltool
>     and the plain function names in a .def file (which, while still
>     painful, is a lot easier than trying to figure out the stack sizes
>     by hand).
>
>It would also be nice to get all of these different functions to do with
>dynamic linking integrated somehow. Just out of curiosity, how different
>is the way shared libraries are done under UNIX?
>
>>1) If there are any problems with wrong or missing prototypes for
>>   _stdcall functions the linker would complain with an 'unresolved external' 
>>   message. You will never get a program with wrong function calls.
>>2) In order to get all Win32 API functions working there must not be any
>>   function prototype containing parameters which are less than 4 bytes
>>   in size, even if the parameters are actually WORD or CHAR or BYTE or 
>>   something else. Please check your windows header files if they
>>   contain prototypes with WORD or CHAR parameters. Replace WORD
>>   or CHAR parameters by DWORD parameters.
>
>Isn't there an option to force stack alignment? If there is then shouldn't
>it be on by default, at least for -mwindows programs? I admit I can't find
>it in the docs right now... sounds like a candidate for a function attribute.
>
>>In fact, MSVC mangles _stdcall names in the same manner as Cygnus gcc does.
>
>As pointed out by another, this is another good reason.
>
>I don't really expect much to be done about this, it's just a rant. Still
>maybe someone with the appropriate tools at hand will decide to make the
>effort. I can always hope...
>
>Colin.
>
>-- Colin Peters - Saga Univ. Dept. of Information Science
>-- [email-masked] - finger for PGP public key
>-- http://www.fu.is.saga-u.ac.jp/~colin/index.html
>-- http://www.geocities.com/Tokyo/Towers/6162/
>
>-
>For help on using this list (especially unsubscribing), send a message to
>"[email-masked]" with one line of text: "help".
>

([email-masked])
delete REMOVETHIS from the above to reply
         Mikey
-
For help on using this list (especially unsubscribing), send a message to
"[email-masked]" with one line of text: "help".