From: ian AT cygnus DOT com (Ian Lance Taylor) Subject: Declare function types correctly for cygwin32 2 Jul 1998 16:25:35 -0700 Message-ID: <199807022251.SAA27079.cygnus.cygwin32.developers@subrogation.cygnus.com> To: egcs-patches AT cygnus DOT com Cc: cygwin32-developers AT cygnus DOT com The Microsoft Windows linker requires that the n_type field of each symbol which represents a function be set to indicate that the symbol is a function. This includes undefined symbols used for external called functions. The Microsoft documentation indicates that type is used to support incremental linking. The appended patch modifies the cygwin32 toolchain to emit this information. This changes gcc to emit .type directives as needed for cygwin32. This is based on similar patches to the Irix 5 port to declare all external function symbols. Ian Thu Jul 2 18:47:12 1998 Ian Lance Taylor * i386/cygwin32.h: Add some declaration of external functions. (ASM_DECLARE_FUNCTION_NAME): Define. (ASM_OUTPUT_EXTERNAL, ASM_OUTPUT_EXTERNAL_LIBCALL): Define. (ASM_FILE_END): Define. * i386/winnt.c (i386_pe_declare_function_type): New function. (struct extern_list, extern_head): Define. (i386_pe_record_external_function): New function. (i386_pe_asm_file_end): New function. Index: cygwin32.h =================================================================== RCS file: /cvs/cvsfiles/devo/gcc/config/i386/cygwin32.h,v retrieving revision 1.22 diff -p -r1.22 cygwin32.h *** cygwin32.h 1998/05/08 20:36:53 1.22 --- cygwin32.h 1998/07/02 22:46:52 *************** do { \ *** 224,229 **** --- 224,259 ---- ? "discard" : "same_size"); \ } while (0) + /* Write the extra assembler code needed to declare a function + properly. If we are generating SDB debugging information, this + will happen automatically, so we only need to handle other cases. */ + #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ + do \ + { \ + if (write_symbols != SDB_DEBUG) \ + i386_pe_declare_function_type (FILE, NAME, TREE_PUBLIC (DECL)); \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + } \ + while (0) + + /* Add an external function to the list of functions to be declared at + the end of the file. */ + #define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + do \ + { \ + if (TREE_CODE (DECL) == FUNCTION_DECL) \ + i386_pe_record_external_function (NAME); \ + } \ + while (0) + + /* Declare the type properly for any external libcall. */ + #define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \ + i386_pe_declare_function_type (FILE, XSTR (FUN, 0), 1) + + /* Output function declarations at the end of the file. */ + #define ASM_FILE_END(FILE) \ + i386_pe_asm_file_end (FILE) + #undef ASM_COMMENT_START #define ASM_COMMENT_START " #" *************** do { \ *** 232,234 **** --- 262,284 ---- /* Don't assume anything about the header files. */ #define NO_IMPLICIT_EXTERN_C + + /* External function declarations. */ + + #ifndef PROTO + #if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__) + #define PROTO(ARGS) ARGS + #else + #define PROTO(ARGS) () + #endif + #endif + + #ifdef BUFSIZE /* stdio.h has been included, ok to use FILE * */ + #define STDIO_PROTO(ARGS) PROTO(ARGS) + #else + #define STDIO_PROTO(ARGS) () + #endif + + extern void i386_pe_record_external_function PROTO((char *)); + extern void i386_pe_declare_function_type STDIO_PROTO((FILE *, char *, int)); + extern void i386_pe_asm_file_end STDIO_PROTO((FILE *)); Index: winnt.c =================================================================== RCS file: /cvs/cvsfiles/devo/gcc/config/i386/winnt.c,v retrieving revision 1.11 diff -p -r1.11 winnt.c *** winnt.c 1998/05/08 20:38:18 1.11 --- winnt.c 1998/07/02 22:46:52 *************** i386_pe_unique_section (decl, reloc) *** 98,100 **** --- 98,177 ---- DECL_SECTION_NAME (decl) = build_string (len, string); } + + /* The Microsoft linker requires that every function be marked as + DT_FCN. When using gas on cygwin32, we must emit appropriate .type + directives. */ + + #include "gsyms.h" + + /* Mark a function appropriately. This should only be called for + functions for which we are not emitting COFF debugging information. + FILE is the assembler output file, NAME is the name of the + function, and PUBLIC is non-zero if the function is globally + visible. */ + + void + i386_pe_declare_function_type (file, name, public) + FILE *file; + char *name; + int public; + { + fprintf (file, "\t.def\t"); + assemble_name (file, name); + fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n", + public ? (int) C_EXT : (int) C_STAT, + (int) DT_FCN << N_BTSHFT); + } + + /* Keep a list of external functions. */ + + struct extern_list + { + struct extern_list *next; + char *name; + }; + + static struct extern_list *extern_head; + + /* Assemble an external function reference. We need to keep a list of + these, so that we can output the function types at the end of the + assembly. We can't output the types now, because we might see a + definition of the function later on and emit debugging information + for it then. */ + + void + i386_pe_record_external_function (name) + char *name; + { + struct extern_list *p; + + p = (struct extern_list *) permalloc (sizeof *p); + p->next = extern_head; + p->name = name; + extern_head = p; + } + + /* This is called at the end of assembly. For each external function + which has not been defined, we output a declaration now. */ + + void + i386_pe_asm_file_end (file) + FILE *file; + { + struct extern_list *p; + + for (p = extern_head; p != NULL; p = p->next) + { + tree decl; + + decl = get_identifier (p->name); + + /* Positively ensure only one declaration for any given symbol. */ + if (! TREE_ASM_WRITTEN (decl)) + { + TREE_ASM_WRITTEN (decl) = 1; + i386_pe_declare_function_type (file, p->name, TREE_PUBLIC (decl)); + } + } + }