Changed the GDI driver interface to pass an opaque PHYSDEV pointer
[wine] / tools / winebuild / import.c
1 /*
2  * DLL imports support
3  *
4  * Copyright 2000 Alexandre Julliard
5  *           2000 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "build.h"
29
30 struct import
31 {
32     char        *dll;         /* dll name */
33     int          delay;       /* delay or not dll loading ? */
34     char       **exports;     /* functions exported from this dll */
35     int          nb_exports;  /* number of exported functions */
36     char       **imports;     /* functions we want to import from this dll */
37     int          nb_imports;  /* number of imported functions */
38     int          lineno;      /* line in .spec file where import is defined */
39 };
40
41 static char **undef_symbols;  /* list of undefined symbols */
42 static int nb_undef_symbols = -1;
43 static int undef_size;
44
45 static char **ignore_symbols; /* list of symbols to ignore */
46 static int nb_ignore_symbols;
47 static int ignore_size;
48
49 static struct import **dll_imports = NULL;
50 static int nb_imports = 0;      /* number of imported dlls (delayed or not) */
51 static int nb_delayed = 0;      /* number of delayed dlls */
52 static int total_imports = 0;   /* total number of imported functions */
53 static int total_delayed = 0;   /* total number of imported functions in delayed DLLs */
54
55 /* compare function names; helper for resolve_imports */
56 static int name_cmp( const void *name, const void *entry )
57 {
58     return strcmp( *(char **)name, *(char **)entry );
59 }
60
61 /* locate a symbol in a (sorted) list */
62 inline static const char *find_symbol( const char *name, char **table, int size )
63 {
64     char **res = NULL;
65
66     if (table) {
67         res = bsearch( &name, table, size, sizeof(*table), name_cmp );
68     }
69
70     return res ? *res : NULL;
71 }
72
73 /* sort a symbol table */
74 inline static void sort_symbols( char **table, int size )
75 {
76     if (table )
77         qsort( table, size, sizeof(*table), name_cmp );
78 }
79
80 /* open the .so library for a given dll in a specified path */
81 static char *try_library_path( const char *path, const char *name )
82 {
83     char *buffer;
84     int fd;
85
86     buffer = xmalloc( strlen(path) + strlen(name) + 9 );
87     sprintf( buffer, "%s/%s", path, name );
88     if (!strchr( name, '.' )) strcat( buffer, ".dll" );
89     strcat( buffer, ".so" );
90     /* check if the file exists */
91     if ((fd = open( buffer, O_RDONLY )) != -1)
92     {
93         close( fd );
94         return buffer;
95     }
96     free( buffer );
97     return NULL;
98 }
99
100 /* open the .so library for a given dll */
101 static char *open_library( const char *name )
102 {
103     char *fullname;
104     int i;
105
106     for (i = 0; i < nb_lib_paths; i++)
107     {
108         if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
109     }
110     if (!(fullname = try_library_path( ".", name )))
111         fatal_error( "could not open .so file for %s\n", name );
112     return fullname;
113 }
114
115 /* read in the list of exported symbols of a .so */
116 static void read_exported_symbols( const char *name, struct import *imp )
117 {
118     FILE *f;
119     char buffer[1024];
120     char *fullname, *cmdline;
121     const char *ext;
122     int size, err;
123
124     imp->exports    = NULL;
125     imp->nb_exports = size = 0;
126
127     if (!(ext = strrchr( name, '.' ))) ext = name + strlen(name);
128
129     if (!(fullname = open_library( name ))) return;
130     cmdline = xmalloc( strlen(fullname) + 7 );
131     sprintf( cmdline, "nm -D %s", fullname );
132     free( fullname );
133
134     if (!(f = popen( cmdline, "r" )))
135         fatal_error( "Cannot execute '%s'\n", cmdline );
136
137     while (fgets( buffer, sizeof(buffer), f ))
138     {
139         char *p = buffer + strlen(buffer) - 1;
140         if (p < buffer) continue;
141         if (*p == '\n') *p-- = 0;
142         if (!(p = strstr( buffer, "__wine_dllexport_" ))) continue;
143         p += 17;
144         if (strncmp( p, name, ext - name )) continue;
145         p += ext - name;
146         if (*p++ != '_') continue;
147
148         if (imp->nb_exports == size)
149         {
150             size += 128;
151             imp->exports = xrealloc( imp->exports, size * sizeof(*imp->exports) );
152         }
153         imp->exports[imp->nb_exports++] = xstrdup( p );
154     }
155     if ((err = pclose( f ))) fatal_error( "%s error %d\n", cmdline, err );
156     free( cmdline );
157     sort_symbols( imp->exports, imp->nb_exports );
158 }
159
160 /* add a dll to the list of imports */
161 void add_import_dll( const char *name, int delay )
162 {
163     struct import *imp = xmalloc( sizeof(*imp) );
164     imp->dll        = xstrdup( name );
165     imp->delay      = delay;
166     imp->imports    = NULL;
167     imp->nb_imports = 0;
168     /* GetToken for the file name has swallowed the '\n', hence pointing to next line */
169     imp->lineno = current_line - 1;
170
171     if (delay) nb_delayed++;
172     read_exported_symbols( name, imp );
173
174     dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
175     dll_imports[nb_imports++] = imp;
176 }
177
178 /* Add a symbol to the ignored symbol list */
179 void add_ignore_symbol( const char *name )
180 {
181     if (nb_ignore_symbols == ignore_size)
182     {
183         ignore_size += 32;
184         ignore_symbols = xrealloc( ignore_symbols, ignore_size * sizeof(*ignore_symbols) );
185     }
186     ignore_symbols[nb_ignore_symbols++] = xstrdup( name );
187 }
188
189 /* add a function to the list of imports from a given dll */
190 static void add_import_func( struct import *imp, const char *name )
191 {
192     imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
193     imp->imports[imp->nb_imports++] = xstrdup( name );
194     total_imports++;
195     if (imp->delay) total_delayed++;
196 }
197
198 /* add a symbol to the undef list */
199 inline static void add_undef_symbol( const char *name )
200 {
201     if (nb_undef_symbols == undef_size)
202     {
203         undef_size += 128;
204         undef_symbols = xrealloc( undef_symbols, undef_size * sizeof(*undef_symbols) );
205     }
206     undef_symbols[nb_undef_symbols++] = xstrdup( name );
207 }
208
209 /* remove all the holes in the undefined symbol list; return the number of removed symbols */
210 static int remove_symbol_holes(void)
211 {
212     int i, off;
213     for (i = off = 0; i < nb_undef_symbols; i++)
214     {
215         if (!undef_symbols[i]) off++;
216         else undef_symbols[i - off] = undef_symbols[i];
217     }
218     nb_undef_symbols -= off;
219     return off;
220 }
221
222 /* add the extra undefined symbols that will be contained in the generated spec file itself */
223 static void add_extra_undef_symbols(void)
224 {
225     const char *extras[10];
226     int i, count = 0;
227
228 #define ADD_SYM(name) \
229     do { if (!find_symbol( extras[count] = (name), undef_symbols, \
230                            nb_undef_symbols )) count++; } while(0)
231
232     sort_symbols( undef_symbols, nb_undef_symbols );
233
234     /* add symbols that will be contained in the spec file itself */
235     switch (SpecMode)
236     {
237     case SPEC_MODE_DLL:
238         break;
239     case SPEC_MODE_GUIEXE:
240         ADD_SYM( "GetCommandLineA" );
241         ADD_SYM( "GetStartupInfoA" );
242         ADD_SYM( "GetModuleHandleA" );
243         /* fall through */
244     case SPEC_MODE_CUIEXE:
245         ADD_SYM( "__wine_get_main_args" );
246         ADD_SYM( "ExitProcess" );
247         break;
248     case SPEC_MODE_GUIEXE_UNICODE:
249         ADD_SYM( "GetCommandLineA" );
250         ADD_SYM( "GetStartupInfoA" );
251         ADD_SYM( "GetModuleHandleA" );
252         /* fall through */
253     case SPEC_MODE_CUIEXE_UNICODE:
254         ADD_SYM( "__wine_get_wmain_args" );
255         ADD_SYM( "ExitProcess" );
256         break;
257     }
258     ADD_SYM( "RtlRaiseException" );
259     if (nb_delayed)
260     {
261        ADD_SYM( "LoadLibraryA" );
262        ADD_SYM( "GetProcAddress" );
263     }
264
265     for (i = 0; i < nb_entry_points; i++)
266     {
267         ORDDEF *odp = EntryPoints[i];
268         if (odp->flags & FLAG_REGISTER)
269         {
270             ADD_SYM( "__wine_call_from_32_regs" );
271             break;
272         }
273     }
274
275     if (count)
276     {
277         for (i = 0; i < count; i++) add_undef_symbol( extras[i] );
278         sort_symbols( undef_symbols, nb_undef_symbols );
279     }
280 }
281
282 /* warn if a given dll is not used, but check forwards first */
283 static void warn_unused( const struct import* imp )
284 {
285     int i, curline;
286     size_t len = strlen(imp->dll);
287     const char *p = strchr( imp->dll, '.' );
288     if (p && !strcasecmp( p, ".dll" )) len = p - imp->dll;
289
290     for (i = Base; i <= Limit; i++)
291     {
292         ORDDEF *odp = Ordinals[i];
293         if (!odp || odp->type != TYPE_FORWARD) continue;
294         if (!strncasecmp( odp->link_name, imp->dll, len ) &&
295             odp->link_name[len] == '.')
296             return;  /* found an import, do not warn */
297     }
298     /* switch current_line temporarily to the line of the import declaration */
299     curline = current_line;
300     current_line = imp->lineno;
301     warning( "%s imported but no symbols used\n", imp->dll );
302     current_line = curline;
303 }
304
305 /* read in the list of undefined symbols */
306 void read_undef_symbols( const char *name )
307 {
308     FILE *f;
309     char buffer[1024];
310     int err;
311
312     undef_size = nb_undef_symbols = 0;
313
314     sprintf( buffer, "nm -u %s", name );
315     if (!(f = popen( buffer, "r" )))
316         fatal_error( "Cannot execute '%s'\n", buffer );
317
318     while (fgets( buffer, sizeof(buffer), f ))
319     {
320         char *p = buffer + strlen(buffer) - 1;
321         if (p < buffer) continue;
322         if (*p == '\n') *p-- = 0;
323         p = buffer; while (*p == ' ') p++;
324         add_undef_symbol( p );
325     }
326     if ((err = pclose( f ))) fatal_error( "nm -u %s error %d\n", name, err );
327 }
328
329 static void remove_ignored_symbols(void)
330 {
331     int i;
332
333     sort_symbols( ignore_symbols, nb_ignore_symbols );
334     for (i = 0; i < nb_undef_symbols; i++)
335     {
336         if (find_symbol( undef_symbols[i], ignore_symbols, nb_ignore_symbols ))
337         {
338             free( undef_symbols[i] );
339             undef_symbols[i] = NULL;
340         }
341     }
342     remove_symbol_holes();
343 }
344
345 /* resolve the imports for a Win32 module */
346 int resolve_imports( void )
347 {
348     int i, j;
349
350     if (nb_undef_symbols == -1) return 0; /* no symbol file specified */
351
352     add_extra_undef_symbols();
353     remove_ignored_symbols();
354
355     for (i = 0; i < nb_imports; i++)
356     {
357         struct import *imp = dll_imports[i];
358
359         for (j = 0; j < nb_undef_symbols; j++)
360         {
361             const char *res = find_symbol( undef_symbols[j], imp->exports, imp->nb_exports );
362             if (res)
363             {
364                 add_import_func( imp, res );
365                 free( undef_symbols[j] );
366                 undef_symbols[j] = NULL;
367             }
368         }
369         /* remove all the holes in the undef symbols list */
370         if (!remove_symbol_holes()) warn_unused( imp );
371     }
372     return 1;
373 }
374
375 /* output the import table of a Win32 module */
376 static int output_immediate_imports( FILE *outfile )
377 {
378     int i, j, pos;
379     int nb_imm = nb_imports - nb_delayed;
380
381     if (!nb_imm) goto done;
382
383     /* main import header */
384
385     fprintf( outfile, "\nstatic struct {\n" );
386     fprintf( outfile, "  struct {\n" );
387     fprintf( outfile, "    void        *OriginalFirstThunk;\n" );
388     fprintf( outfile, "    unsigned int TimeDateStamp;\n" );
389     fprintf( outfile, "    unsigned int ForwarderChain;\n" );
390     fprintf( outfile, "    const char  *Name;\n" );
391     fprintf( outfile, "    void        *FirstThunk;\n" );
392     fprintf( outfile, "  } imp[%d];\n", nb_imm+1 );
393     fprintf( outfile, "  const char *data[%d];\n",
394              total_imports - total_delayed + nb_imm );
395     fprintf( outfile, "} imports = {\n  {\n" );
396
397     /* list of dlls */
398
399     for (i = j = 0; i < nb_imports; i++)
400     {
401         if (dll_imports[i]->delay) continue;
402         fprintf( outfile, "    { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
403                  dll_imports[i]->dll, j );
404         j += dll_imports[i]->nb_imports + 1;
405     }
406
407     fprintf( outfile, "    { 0, 0, 0, 0, 0 },\n" );
408     fprintf( outfile, "  },\n  {\n" );
409
410     /* list of imported functions */
411
412     for (i = 0; i < nb_imports; i++)
413     {
414         if (dll_imports[i]->delay) continue;
415         fprintf( outfile, "    /* %s */\n", dll_imports[i]->dll );
416         for (j = 0; j < dll_imports[i]->nb_imports; j++)
417             fprintf( outfile, "    \"\\0\\0%s\",\n", dll_imports[i]->imports[j] );
418         fprintf( outfile, "    0,\n" );
419     }
420     fprintf( outfile, "  }\n};\n\n" );
421
422     /* thunks for imported functions */
423
424     fprintf( outfile, "#ifndef __GNUC__\nstatic void __asm__dummy_import(void) {\n#endif\n\n" );
425     pos = 20 * (nb_imm + 1);  /* offset of imports.data from start of imports */
426     fprintf( outfile, "asm(\".data\\n\\t.align %d\\n\"\n", get_alignment(8) );
427     for (i = 0; i < nb_imports; i++)
428     {
429         if (dll_imports[i]->delay) continue;
430         for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
431         {
432             fprintf( outfile, "    \"\\t" __ASM_FUNC("%s") "\\n\"\n",
433                      dll_imports[i]->imports[j] );
434             fprintf( outfile, "    \"\\t.globl " PREFIX "%s\\n\"\n",
435                      dll_imports[i]->imports[j] );
436
437
438
439
440             fprintf( outfile, "    \"" PREFIX "%s:\\n\\t", dll_imports[i]->imports[j] );
441
442 #if defined(__i386__)
443             if (strstr( dll_imports[i]->imports[j], "__wine_call_from_16" ))
444                 fprintf( outfile, ".byte 0x2e\\n\\tjmp *(imports+%d)\\n\\tnop\\n", pos );
445             else
446                 fprintf( outfile, "jmp *(imports+%d)\\n\\tmovl %%esi,%%esi\\n", pos );
447 #elif defined(__sparc__)
448             if ( !UsePIC )
449             {
450                 fprintf( outfile, "sethi %%hi(imports+%d), %%g1\\n\\t", pos );
451                 fprintf( outfile, "ld [%%g1+%%lo(imports+%d)], %%g1\\n\\t", pos );
452                 fprintf( outfile, "jmp %%g1\\n\\tnop\\n" );
453             }
454             else
455             {
456                 /* Hmpf.  Stupid sparc assembler always interprets global variable
457                    names as GOT offsets, so we have to do it the long way ... */
458                 fprintf( outfile, "save %%sp, -96, %%sp\\n" );
459                 fprintf( outfile, "0:\\tcall 1f\\n\\tnop\\n" );
460                 fprintf( outfile, "1:\\tsethi %%hi(imports+%d-0b), %%g1\\n\\t", pos );
461                 fprintf( outfile, "or %%g1, %%lo(imports+%d-0b), %%g1\\n\\t", pos );
462                 fprintf( outfile, "ld [%%g1+%%o7], %%g1\\n\\t" );
463                 fprintf( outfile, "jmp %%g1\\n\\trestore\\n" );
464             }
465
466 #elif defined(__PPC__)
467             fprintf(outfile, "\taddi 1, 1, -0x4\\n\"\n");
468             fprintf(outfile, "\t\"\\tstw 9, 0(1)\\n\"\n");
469             fprintf(outfile, "\t\"\\taddi 1, 1, -0x4\\n\"\n");
470             fprintf(outfile, "\t\"\\tstw 8, 0(1)\\n\"\n");
471             fprintf(outfile, "\t\"\\taddi 1, 1, -0x4\\n\"\n");
472             fprintf(outfile, "\t\"\\tstw 7, 0(1)\\n\"\n");
473
474             fprintf(outfile, "\t\"\\tlis 9,imports+%d@ha\\n\"\n", pos);
475             fprintf(outfile, "\t\"\\tla 8,imports+%d@l(9)\\n\"\n", pos);
476             fprintf(outfile, "\t\"\\tlwz 7, 0(8)\\n\"\n");
477             fprintf(outfile, "\t\"\\tmtctr 7\\n\"\n");
478
479             fprintf(outfile, "\t\"\\tlwz 7, 0(1)\\n\"\n");
480             fprintf(outfile, "\t\"\\taddi 1, 1, 0x4\\n\"\n");
481             fprintf(outfile, "\t\"\\tlwz 8, 0(1)\\n\"\n");
482             fprintf(outfile, "\t\"\\taddi 1, 1, 0x4\\n\"\n");
483             fprintf(outfile, "\t\"\\tlwz 9, 0(1)\\n\"\n");
484             fprintf(outfile, "\t\"\\taddi 1, 1, 0x4\\n\"\n");
485             fprintf(outfile, "\t\"\\tbctr\\n");
486 #else
487 #error You need to define import thunks for your architecture!
488 #endif
489             fprintf( outfile, "\"\n" );
490         }
491         pos += 4;
492     }
493     fprintf( outfile, "\".previous\");\n#ifndef __GNUC__\n}\n#endif\n\n" );
494
495  done:
496     return nb_imm;
497 }
498
499 /* output the delayed import table of a Win32 module */
500 static int output_delayed_imports( FILE *outfile )
501 {
502     int i, idx, j, pos;
503
504     if (!nb_delayed) goto done;
505
506     for (i = 0; i < nb_imports; i++)
507     {
508         if (!dll_imports[i]->delay) continue;
509         fprintf( outfile, "static void *__wine_delay_imp_%d_hmod;\n", i);
510         for (j = 0; j < dll_imports[i]->nb_imports; j++)
511         {
512             fprintf( outfile, "void __wine_delay_imp_%d_%s();\n",
513                      i, dll_imports[i]->imports[j] );
514         }
515     }
516     fprintf( outfile, "\n" );
517     fprintf( outfile, "static struct {\n" );
518     fprintf( outfile, "  struct ImgDelayDescr {\n" );
519     fprintf( outfile, "    unsigned int  grAttrs;\n" );
520     fprintf( outfile, "    const char   *szName;\n" );
521     fprintf( outfile, "    void        **phmod;\n" );
522     fprintf( outfile, "    void        **pIAT;\n" );
523     fprintf( outfile, "    const char  **pINT;\n" );
524     fprintf( outfile, "    void*         pBoundIAT;\n" );
525     fprintf( outfile, "    void*         pUnloadIAT;\n" );
526     fprintf( outfile, "    unsigned long dwTimeStamp;\n" );
527     fprintf( outfile, "  } imp[%d];\n", nb_delayed );
528     fprintf( outfile, "  void         *IAT[%d];\n", total_delayed );
529     fprintf( outfile, "  const char   *INT[%d];\n", total_delayed );
530     fprintf( outfile, "} delay_imports = {\n" );
531     fprintf( outfile, "  {\n" );
532     for (i = j = 0; i < nb_imports; i++)
533     {
534         if (!dll_imports[i]->delay) continue;
535         fprintf( outfile, "    { 0, \"%s\", &__wine_delay_imp_%d_hmod, &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
536                  dll_imports[i]->dll, i, j, j );
537         j += dll_imports[i]->nb_imports;
538     }
539     fprintf( outfile, "  },\n  {\n" );
540     for (i = 0; i < nb_imports; i++)
541     {
542         if (!dll_imports[i]->delay) continue;
543         fprintf( outfile, "    /* %s */\n", dll_imports[i]->dll );
544         for (j = 0; j < dll_imports[i]->nb_imports; j++)
545         {
546             fprintf( outfile, "    &__wine_delay_imp_%d_%s,\n", i, dll_imports[i]->imports[j] );
547         }
548     }
549     fprintf( outfile, "  },\n  {\n" );
550     for (i = 0; i < nb_imports; i++)
551     {
552         if (!dll_imports[i]->delay) continue;
553         fprintf( outfile, "    /* %s */\n", dll_imports[i]->dll );
554         for (j = 0; j < dll_imports[i]->nb_imports; j++)
555         {
556             fprintf( outfile, "    \"\\0\\0%s\",\n", dll_imports[i]->imports[j] );
557         }
558     }
559     fprintf( outfile, "  }\n};\n\n" );
560
561     /* check if there's some stub defined. if so, exception struct 
562      *  is already defined, so don't emit it twice 
563      */
564     for (i = 0; i < nb_entry_points; i++) if (EntryPoints[i]->type == TYPE_STUB) break;
565
566     if (i == nb_entry_points) {
567        fprintf( outfile, "struct exc_record {\n" );
568        fprintf( outfile, "  unsigned int code, flags;\n" );
569        fprintf( outfile, "  void *rec, *addr;\n" );
570        fprintf( outfile, "  unsigned int params;\n" );
571        fprintf( outfile, "  const void *info[15];\n" );
572        fprintf( outfile, "};\n\n" );
573        fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n" );
574     }
575
576     fprintf( outfile, "extern void * __stdcall LoadLibraryA(const char*);\n");
577     fprintf( outfile, "extern void * __stdcall GetProcAddress(void *, const char*);\n");
578     fprintf( outfile, "\n" );
579
580     fprintf( outfile, "void *__stdcall __wine_delay_load( int idx_nr )\n" );
581     fprintf( outfile, "{\n" );
582     fprintf( outfile, "  int idx = idx_nr >> 16, nr = idx_nr & 0xffff;\n" );
583     fprintf( outfile, "  struct ImgDelayDescr *imd = delay_imports.imp + idx;\n" );
584     fprintf( outfile, "  void **pIAT = imd->pIAT + nr;\n" );
585     fprintf( outfile, "  const char** pINT = imd->pINT + nr;\n" );
586     fprintf( outfile, "  void *fn;\n\n" );
587
588     fprintf( outfile, "  if (!*imd->phmod) *imd->phmod = LoadLibraryA(imd->szName);\n" );
589     fprintf( outfile, "  if (*imd->phmod && (fn = GetProcAddress(*imd->phmod, *pINT + 2)))\n");
590     fprintf( outfile, "    /* patch IAT with final value */\n" );
591     fprintf( outfile, "    return *pIAT = fn;\n" );
592     fprintf( outfile, "  else {\n");
593     fprintf( outfile, "    struct exc_record rec;\n" );
594     fprintf( outfile, "    rec.code    = 0x80000100;\n" );
595     fprintf( outfile, "    rec.flags   = 1;\n" );
596     fprintf( outfile, "    rec.rec     = 0;\n" );
597     fprintf( outfile, "    rec.params  = 2;\n" );
598     fprintf( outfile, "    rec.info[0] = imd->szName;\n" );
599     fprintf( outfile, "    rec.info[1] = *pINT + 2;\n" );
600     fprintf( outfile, "#ifdef __GNUC__\n" );
601     fprintf( outfile, "    rec.addr = __builtin_return_address(1);\n" );
602     fprintf( outfile, "#else\n" );
603     fprintf( outfile, "    rec.addr = 0;\n" );
604     fprintf( outfile, "#endif\n" );
605     fprintf( outfile, "    for (;;) RtlRaiseException( &rec );\n" );
606     fprintf( outfile, "    return 0; /* shouldn't go here */\n" );
607     fprintf( outfile, "  }\n}\n\n" );
608
609     fprintf( outfile, "#ifndef __GNUC__\n" );
610     fprintf( outfile, "static void __asm__dummy_delay_import(void) {\n" );
611     fprintf( outfile, "#endif\n" );
612
613     fprintf( outfile, "asm(\".align %d\\n\"\n", get_alignment(8) );
614     fprintf( outfile, "    \"\\t" __ASM_FUNC("__wine_delay_load_asm") "\\n\"\n" );
615     fprintf( outfile, "    \"" PREFIX "__wine_delay_load_asm:\\n\"\n" );
616 #if defined(__i386__)
617     fprintf( outfile, "    \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
618     fprintf( outfile, "    \"\\tcall __wine_delay_load\\n\"\n" );
619     fprintf( outfile, "    \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
620 #elif defined(__sparc__)
621     fprintf( outfile, "    \"\\tsave %%sp, -96, %%sp\\n\"\n" );
622     fprintf( outfile, "    \"\\tcall __wine_delay_load\\n\"\n" );
623     fprintf( outfile, "    \"\\tmov %%g1, %%o0\\n\"\n" );
624     fprintf( outfile, "    \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
625 #elif defined(__PPC__)
626     fprintf(outfile, "#error: DELAYED IMPORTS NOT SUPPORTED ON PPC!!!\n");
627 #else
628 #error You need to defined delayed import thunks for your architecture!
629 #endif
630
631     for (i = idx = 0; i < nb_imports; i++)
632     {
633         if (!dll_imports[i]->delay) continue;
634         for (j = 0; j < dll_imports[i]->nb_imports; j++)
635         {
636             char buffer[128];
637             sprintf( buffer, "__wine_delay_imp_%d_%s", i, dll_imports[i]->imports[j]);
638             fprintf( outfile, "    \"\\t" __ASM_FUNC("%s") "\\n\"\n", buffer );
639             fprintf( outfile, "    \"" PREFIX "%s:\\n\"\n", buffer );
640 #if defined(__i386__)
641             fprintf( outfile, "    \"\\tmovl $%d, %%eax\\n\"\n", (idx << 16) | j );
642             fprintf( outfile, "    \"\\tjmp __wine_delay_load_asm\\n\"\n" );
643 #elif defined(__sparc__)
644             fprintf( outfile, "    \"\\tset %d, %%g1\\n\"\n", (idx << 16) | j );
645             fprintf( outfile, "    \"\\tb,a __wine_delay_load_asm\\n\"\n" );
646 #elif defined(__PPC__)
647             fprintf(outfile, "#error: DELAYED IMPORTS NOT SUPPORTED ON PPC!!!\n");
648 #else
649 #error You need to defined delayed import thunks for your architecture!
650 #endif
651         }
652         idx++;
653     }
654
655     fprintf( outfile, "\n    \".data\\n\\t.align %d\\n\"\n", get_alignment(8) );
656     pos = nb_delayed * 32;
657     for (i = 0; i < nb_imports; i++)
658     {
659         if (!dll_imports[i]->delay) continue;
660         for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
661         {
662             fprintf( outfile, "    \"\\t" __ASM_FUNC("%s") "\\n\"\n",
663                      dll_imports[i]->imports[j] );
664             fprintf( outfile, "    \"\\t.globl " PREFIX "%s\\n\"\n",
665                      dll_imports[i]->imports[j] );
666             fprintf( outfile, "    \"" PREFIX "%s:\\n\\t", dll_imports[i]->imports[j] );
667 #if defined(__i386__)
668             if (strstr( dll_imports[i]->imports[j], "__wine_call_from_16" ))
669                 fprintf( outfile, ".byte 0x2e\\n\\tjmp *(delay_imports+%d)\\n\\tnop\\n", pos );
670             else
671                 fprintf( outfile, "jmp *(delay_imports+%d)\\n\\tmovl %%esi,%%esi\\n", pos );
672 #elif defined(__sparc__)
673             if ( !UsePIC )
674             {
675                 fprintf( outfile, "sethi %%hi(delay_imports+%d), %%g1\\n\\t", pos );
676                 fprintf( outfile, "ld [%%g1+%%lo(delay_imports+%d)], %%g1\\n\\t", pos );
677                 fprintf( outfile, "jmp %%g1\\n\\tnop\\n" );
678             }
679             else
680             {
681                 /* Hmpf.  Stupid sparc assembler always interprets global variable
682                    names as GOT offsets, so we have to do it the long way ... */
683                 fprintf( outfile, "save %%sp, -96, %%sp\\n" );
684                 fprintf( outfile, "0:\\tcall 1f\\n\\tnop\\n" );
685                 fprintf( outfile, "1:\\tsethi %%hi(delay_imports+%d-0b), %%g1\\n\\t", pos );
686                 fprintf( outfile, "or %%g1, %%lo(delay_imports+%d-0b), %%g1\\n\\t", pos );
687                 fprintf( outfile, "ld [%%g1+%%o7], %%g1\\n\\t" );
688                 fprintf( outfile, "jmp %%g1\\n\\trestore\\n" );
689             }
690
691 #elif defined(__PPC__)
692             fprintf(outfile, "#error: DELAYED IMPORTS NOT SUPPORTED ON PPC!!!\n");
693 #else
694 #error You need to define delayed import thunks for your architecture!
695 #endif
696             fprintf( outfile, "\"\n" );
697         }
698     }
699     fprintf( outfile, "\".previous\");\n" );
700     fprintf( outfile, "#ifndef __GNUC__\n" );
701     fprintf( outfile, "}\n" );
702     fprintf( outfile, "#endif\n" );
703     fprintf( outfile, "\n" );
704
705  done:
706     return nb_delayed;
707 }
708
709 /* output the import and delayed import tables of a Win32 module
710  * returns number of DLLs exported in 'immediate' mode
711  */
712 int output_imports( FILE *outfile )
713 {
714    output_delayed_imports( outfile );
715    return output_immediate_imports( outfile );
716 }