4 * Copyright 2000 Alexandre Julliard
17 char *dll
; /* dll name */
18 char **exports
; /* functions exported from this dll */
19 int nb_exports
; /* number of exported functions */
20 char **imports
; /* functions we want to import from this dll */
21 int nb_imports
; /* number of imported functions */
22 int lineno
; /* line in .spec file where import is defined */
25 static char **undef_symbols
; /* list of undefined symbols */
26 static int nb_undef_symbols
= -1;
27 static int undef_size
;
29 static char **ignore_symbols
; /* list of symbols to ignore */
30 static int nb_ignore_symbols
;
31 static int ignore_size
;
33 static struct import
**dll_imports
= NULL
;
34 static int nb_imports
= 0; /* number of imported dlls */
35 static int total_imports
= 0; /* total number of imported functions */
38 /* compare function names; helper for resolve_imports */
39 static int name_cmp( const void *name
, const void *entry
)
41 return strcmp( *(char **)name
, *(char **)entry
);
44 /* locate a symbol in a (sorted) list */
45 inline static const char *find_symbol( const char *name
, char **table
, int size
)
47 char **res
= bsearch( &name
, table
, size
, sizeof(*table
), name_cmp
);
48 return res
? *res
: NULL
;
51 /* sort a symbol table */
52 inline static void sort_symbols( char **table
, int size
)
54 qsort( table
, size
, sizeof(*table
), name_cmp
);
57 /* open the .so library for a given dll in a specified path */
58 static char *try_library_path( const char *path
, const char *name
)
63 buffer
= xmalloc( strlen(path
) + strlen(name
) + 8 );
64 sprintf( buffer
, "%s/lib%s", path
, name
);
65 p
= buffer
+ strlen(buffer
) - 4;
66 if (!strcmp( p
, ".dll" )) *p
= 0;
67 strcat( buffer
, ".so" );
68 /* check if the file exists */
69 if ((fd
= open( buffer
, O_RDONLY
)) == -1) return NULL
;
74 /* open the .so library for a given dll */
75 static char *open_library( const char *name
)
80 for (i
= 0; i
< nb_lib_paths
; i
++)
82 if ((fullname
= try_library_path( lib_path
[i
], name
))) return fullname
;
84 if (!(fullname
= try_library_path( ".", name
)))
85 fatal_error( "could not open .so file for %s\n", name
);
89 /* read in the list of exported symbols of a .so */
90 static void read_exported_symbols( const char *name
, struct import
*imp
)
94 char *fullname
, *cmdline
;
99 imp
->nb_exports
= size
= 0;
101 if (!(ext
= strrchr( name
, '.' ))) ext
= name
+ strlen(name
);
103 if (!(fullname
= open_library( name
))) return;
104 cmdline
= xmalloc( strlen(fullname
) + 4 );
105 sprintf( cmdline
, "nm %s", fullname
);
108 if (!(f
= popen( cmdline
, "r" )))
109 fatal_error( "Cannot execute '%s'\n", cmdline
);
111 while (fgets( buffer
, sizeof(buffer
), f
))
113 char *p
= buffer
+ strlen(buffer
) - 1;
114 if (p
< buffer
) continue;
115 if (*p
== '\n') *p
-- = 0;
116 if (!(p
= strstr( buffer
, "__wine_dllexport_" ))) continue;
118 if (strncmp( p
, name
, ext
- name
)) continue;
120 if (*p
++ != '_') continue;
122 if (imp
->nb_exports
== size
)
125 imp
->exports
= xrealloc( imp
->exports
, size
* sizeof(*imp
->exports
) );
127 imp
->exports
[imp
->nb_exports
++] = xstrdup( p
);
129 if ((err
= pclose( f
))) fatal_error( "%s error %d\n", cmdline
, err
);
131 sort_symbols( imp
->exports
, imp
->nb_exports
);
134 /* add a dll to the list of imports */
135 void add_import_dll( const char *name
)
137 struct import
*imp
= xmalloc( sizeof(*imp
) );
138 imp
->dll
= xstrdup( name
);
141 /* GetToken for the file name has swallowed the '\n', hence pointing to next line */
142 imp
->lineno
= current_line
- 1;
144 read_exported_symbols( name
, imp
);
146 dll_imports
= xrealloc( dll_imports
, (nb_imports
+1) * sizeof(*dll_imports
) );
147 dll_imports
[nb_imports
++] = imp
;
150 /* Add a symbol to the ignored symbol list */
151 void add_ignore_symbol( const char *name
)
153 if (nb_ignore_symbols
== ignore_size
)
156 ignore_symbols
= xrealloc( ignore_symbols
, ignore_size
* sizeof(*ignore_symbols
) );
158 ignore_symbols
[nb_ignore_symbols
++] = xstrdup( name
);
161 /* add a function to the list of imports from a given dll */
162 static void add_import_func( struct import
*imp
, const char *name
)
164 imp
->imports
= xrealloc( imp
->imports
, (imp
->nb_imports
+1) * sizeof(*imp
->imports
) );
165 imp
->imports
[imp
->nb_imports
++] = xstrdup( name
);
169 /* add a symbol to the undef list */
170 inline static void add_undef_symbol( const char *name
)
172 if (nb_undef_symbols
== undef_size
)
175 undef_symbols
= xrealloc( undef_symbols
, undef_size
* sizeof(*undef_symbols
) );
177 undef_symbols
[nb_undef_symbols
++] = xstrdup( name
);
180 /* remove all the holes in the undefined symbol list; return the number of removed symbols */
181 static int remove_symbol_holes(void)
184 for (i
= off
= 0; i
< nb_undef_symbols
; i
++)
186 if (!undef_symbols
[i
]) off
++;
187 else undef_symbols
[i
- off
] = undef_symbols
[i
];
189 nb_undef_symbols
-= off
;
193 /* add the extra undefined symbols that will be contained in the generated spec file itself */
194 static void add_extra_undef_symbols(void)
196 const char *extras
[8];
199 #define ADD_SYM(name) \
200 do { if (!find_symbol( extras[count] = (name), undef_symbols, \
201 nb_undef_symbols )) count++; } while(0)
203 sort_symbols( undef_symbols
, nb_undef_symbols
);
205 /* add symbols that will be contained in the spec file itself */
208 case SPEC_MODE_GUIEXE
:
209 ADD_SYM( "GetCommandLineA" );
210 ADD_SYM( "GetStartupInfoA" );
211 ADD_SYM( "GetModuleHandleA" );
213 case SPEC_MODE_CUIEXE
:
214 ADD_SYM( "__wine_get_main_args" );
215 ADD_SYM( "ExitProcess" );
218 case SPEC_MODE_GUIEXE_NO_MAIN
:
219 case SPEC_MODE_CUIEXE_NO_MAIN
:
220 ADD_SYM( "RtlRaiseException" );
225 for (i
= 0; i
< count
; i
++) add_undef_symbol( extras
[i
] );
226 sort_symbols( undef_symbols
, nb_undef_symbols
);
230 /* warn if a given dll is not used, but check forwards first */
231 static void warn_unused( const struct import
* imp
)
234 size_t len
= strlen(imp
->dll
);
235 const char *p
= strchr( imp
->dll
, '.' );
236 if (p
&& !strcasecmp( p
, ".dll" )) len
= p
- imp
->dll
;
238 for (i
= Base
; i
<= Limit
; i
++)
240 ORDDEF
*odp
= Ordinals
[i
];
241 if (!odp
|| odp
->type
!= TYPE_FORWARD
) continue;
242 if (!strncasecmp( odp
->u
.fwd
.link_name
, imp
->dll
, len
) &&
243 odp
->u
.fwd
.link_name
[len
] == '.')
244 return; /* found an import, do not warn */
246 /* switch current_line temporarily to the line of the import declaration */
247 curline
= current_line
;
248 current_line
= imp
->lineno
;
249 warning( "%s imported but no symbols used\n", imp
->dll
);
250 current_line
= curline
;
253 /* read in the list of undefined symbols */
254 void read_undef_symbols( const char *name
)
260 undef_size
= nb_undef_symbols
= 0;
262 sprintf( buffer
, "nm -u %s", name
);
263 if (!(f
= popen( buffer
, "r" )))
264 fatal_error( "Cannot execute '%s'\n", buffer
);
266 while (fgets( buffer
, sizeof(buffer
), f
))
268 char *p
= buffer
+ strlen(buffer
) - 1;
269 if (p
< buffer
) continue;
270 if (*p
== '\n') *p
-- = 0;
271 add_undef_symbol( buffer
);
273 if ((err
= pclose( f
))) fatal_error( "nm -u %s error %d\n", name
, err
);
276 static void remove_ignored_symbols(void)
280 sort_symbols( ignore_symbols
, nb_ignore_symbols
);
281 for (i
= 0; i
< nb_undef_symbols
; i
++)
283 if (find_symbol( undef_symbols
[i
], ignore_symbols
, nb_ignore_symbols
))
285 free( undef_symbols
[i
] );
286 undef_symbols
[i
] = NULL
;
289 remove_symbol_holes();
292 /* resolve the imports for a Win32 module */
293 int resolve_imports( FILE *outfile
)
297 if (nb_undef_symbols
== -1) return 0; /* no symbol file specified */
299 add_extra_undef_symbols();
300 remove_ignored_symbols();
302 for (i
= 0; i
< nb_imports
; i
++)
304 struct import
*imp
= dll_imports
[i
];
306 for (j
= 0; j
< nb_undef_symbols
; j
++)
308 const char *res
= find_symbol( undef_symbols
[j
], imp
->exports
, imp
->nb_exports
);
311 add_import_func( imp
, res
);
312 free( undef_symbols
[j
] );
313 undef_symbols
[j
] = NULL
;
316 /* remove all the holes in the undef symbols list */
317 if (!remove_symbol_holes()) warn_unused( imp
);
322 /* output the import table of a Win32 module */
323 int output_imports( FILE *outfile
)
327 if (!nb_imports
) goto done
;
329 /* main import header */
331 fprintf( outfile
, "\nstatic struct {\n" );
332 fprintf( outfile
, " struct {\n" );
333 fprintf( outfile
, " void *OriginalFirstThunk;\n" );
334 fprintf( outfile
, " unsigned int TimeDateStamp;\n" );
335 fprintf( outfile
, " unsigned int ForwarderChain;\n" );
336 fprintf( outfile
, " const char *Name;\n" );
337 fprintf( outfile
, " void *FirstThunk;\n" );
338 fprintf( outfile
, " } imp[%d];\n", nb_imports
+1 );
339 fprintf( outfile
, " const char *data[%d];\n", total_imports
+ nb_imports
);
340 fprintf( outfile
, "} imports = {\n {\n" );
344 for (i
= j
= 0; i
< nb_imports
; i
++)
346 fprintf( outfile
, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
347 dll_imports
[i
]->dll
, j
);
348 j
+= dll_imports
[i
]->nb_imports
+ 1;
350 fprintf( outfile
, " { 0, 0, 0, 0, 0 },\n" );
351 fprintf( outfile
, " },\n {\n" );
353 /* list of imported functions */
355 for (i
= 0; i
< nb_imports
; i
++)
357 fprintf( outfile
, " /* %s */\n", dll_imports
[i
]->dll
);
358 for (j
= 0; j
< dll_imports
[i
]->nb_imports
; j
++)
359 fprintf( outfile
, " \"\\0\\0%s\",\n", dll_imports
[i
]->imports
[j
] );
360 fprintf( outfile
, " 0,\n" );
362 fprintf( outfile
, " }\n};\n\n" );
364 /* thunks for imported functions */
366 fprintf( outfile
, "#ifndef __GNUC__\nstatic void __asm__dummy_import(void) {\n#endif\n\n" );
367 pos
= 20 * (nb_imports
+ 1); /* offset of imports.data from start of imports */
368 fprintf( outfile
, "asm(\".align 8\\n\"\n" );
369 for (i
= 0; i
< nb_imports
; i
++, pos
+= 4)
371 for (j
= 0; j
< dll_imports
[i
]->nb_imports
; j
++, pos
+= 4)
373 fprintf( outfile
, " \"\\t" __ASM_FUNC("%s") "\\n\"\n",
374 dll_imports
[i
]->imports
[j
] );
375 fprintf( outfile
, " \"\\t.globl " PREFIX
"%s\\n\"\n",
376 dll_imports
[i
]->imports
[j
] );
377 fprintf( outfile
, " \"" PREFIX
"%s:\\t", dll_imports
[i
]->imports
[j
] );
378 if (strstr( dll_imports
[i
]->imports
[j
], "__wine_call_from_16" ))
379 fprintf( outfile
, ".byte 0x2e\\n\\tjmp *(imports+%d)\\n\\tnop\\n\"\n", pos
);
381 fprintf( outfile
, "jmp *(imports+%d)\\n\\tmovl %%esi,%%esi\\n\"\n", pos
);
384 fprintf( outfile
, ");\n#ifndef __GNUC__\n}\n#endif\n\n" );