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