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