Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/winebuild/import.c
8693 views
1
/*
2
* DLL imports support
3
*
4
* Copyright 2000, 2004 Alexandre Julliard
5
* Copyright 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20
*/
21
22
#include "config.h"
23
24
#include <assert.h>
25
#include <ctype.h>
26
#include <fcntl.h>
27
#include <stdio.h>
28
#include <string.h>
29
#include <stdarg.h>
30
31
#include "build.h"
32
#include "wine/list.h"
33
34
/* standard C functions that are also exported from ntdll */
35
static const char *stdc_names[] =
36
{
37
"abs",
38
"atan",
39
"atoi",
40
"atol",
41
"bsearch",
42
"ceil",
43
"cos",
44
"fabs",
45
"floor",
46
"isalnum",
47
"isalpha",
48
"iscntrl",
49
"isdigit",
50
"isgraph",
51
"islower",
52
"isprint",
53
"ispunct",
54
"isspace",
55
"isupper",
56
"iswalpha",
57
"iswctype",
58
"iswdigit",
59
"iswlower",
60
"iswspace",
61
"iswxdigit",
62
"isxdigit",
63
"labs",
64
"log",
65
"longjmp",
66
"mbstowcs",
67
"memchr",
68
"memcmp",
69
"memcpy",
70
"memmove",
71
"memset",
72
"pow",
73
"qsort",
74
"sin",
75
"sprintf",
76
"sqrt",
77
"sscanf",
78
"strcat",
79
"strchr",
80
"strcmp",
81
"strcpy",
82
"strcspn",
83
"strlen",
84
"strncat",
85
"strncmp",
86
"strncpy",
87
"strnlen",
88
"strpbrk",
89
"strrchr",
90
"strspn",
91
"strstr",
92
"strtol",
93
"strtoul",
94
"swprintf",
95
"tan",
96
"tolower",
97
"toupper",
98
"towlower",
99
"towupper",
100
"vsprintf",
101
"wcscat",
102
"wcschr",
103
"wcscmp",
104
"wcscpy",
105
"wcscspn",
106
"wcslen",
107
"wcsncat",
108
"wcsncmp",
109
"wcsncpy",
110
"wcspbrk",
111
"wcsrchr",
112
"wcsspn",
113
"wcsstr",
114
"wcstok",
115
"wcstol",
116
"wcstombs",
117
"wcstoul"
118
};
119
120
static const struct strarray stdc_functions = { ARRAY_SIZE(stdc_names), ARRAY_SIZE(stdc_names), stdc_names };
121
122
struct import_func
123
{
124
const char *name;
125
const char *export_name;
126
int ordinal;
127
int hint;
128
};
129
130
struct import
131
{
132
struct list entry; /* entry in global dll list */
133
char *dll_name; /* exported file name of the dll */
134
char *c_name; /* dll name as a C-compatible identifier */
135
char *full_name; /* full name of the input file */
136
dev_t dev; /* device/inode of the input file */
137
ino_t ino;
138
ORDDEF **exports; /* functions exported from this dll */
139
int nb_exports; /* number of exported functions */
140
struct array imports; /* functions we want to import from this dll */
141
};
142
143
static struct strarray undef_symbols; /* list of undefined symbols */
144
static struct strarray extra_ld_symbols; /* list of extra symbols that ld should resolve */
145
static struct strarray delayed_imports; /* list of delayed import dlls */
146
static struct strarray ext_link_imports; /* list of external symbols to link to */
147
148
static struct list dll_imports = LIST_INIT( dll_imports );
149
static struct list dll_delayed = LIST_INIT( dll_delayed );
150
151
static struct strarray as_files;
152
153
static const char import_func_prefix[] = "__wine$func$";
154
static const char import_ord_prefix[] = "__wine$ord$";
155
156
/* compare function names; helper for resolve_imports */
157
static int name_cmp( const char **name, const char **entry )
158
{
159
return strcmp( *name, *entry );
160
}
161
162
/* compare function names; helper for resolve_imports */
163
static int func_cmp( const void *func1, const void *func2 )
164
{
165
const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
166
const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
167
return strcmp( odp1->name ? odp1->name : odp1->export_name,
168
odp2->name ? odp2->name : odp2->export_name );
169
}
170
171
/* remove a name from a name table */
172
static inline void remove_name( struct strarray *table, unsigned int idx )
173
{
174
assert( idx < table->count );
175
memmove( table->str + idx, table->str + idx + 1,
176
(table->count - idx - 1) * sizeof(*table->str) );
177
table->count--;
178
}
179
180
/* locate a name in a (sorted) list */
181
static inline const char *find_name( const char *name, struct strarray table )
182
{
183
return strarray_bsearch( table, name, name_cmp );
184
}
185
186
/* sort a name table */
187
static inline void sort_names( struct strarray *table )
188
{
189
strarray_qsort( table, name_cmp );
190
}
191
192
/* locate an export in a (sorted) export list */
193
static inline ORDDEF *find_export( const char *name, ORDDEF **table, int size )
194
{
195
ORDDEF func, *odp, **res = NULL;
196
197
func.name = func.export_name = xstrdup(name);
198
odp = &func;
199
if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
200
free( func.name );
201
return res ? *res : NULL;
202
}
203
204
static const char valid_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.";
205
206
/* encode a dll name into a linker-compatible name */
207
static char *encode_dll_name( const char *name )
208
{
209
char *p, *ret, *ret_end;
210
int len = strlen(name);
211
212
if (strendswith( name, ".dll" )) len -= 4;
213
if (strspn( name, valid_chars ) >= len) return strmake( "%.*s", len, name );
214
215
ret = p = xmalloc( len * 4 + 1 );
216
ret_end = ret + (len * 4 + 1);
217
for ( ; len > 0; len--, name++)
218
{
219
if (!strchr( valid_chars, *name ))
220
p += snprintf( p, ret_end - p, "$x%02x", *name );
221
else *p++ = *name;
222
}
223
*p = 0;
224
return ret;
225
}
226
227
/* decode a linker-compatible dll name */
228
static char *decode_dll_name( const char **name )
229
{
230
const char *src = *name;
231
char *p, *ret;
232
233
ret = p = xmalloc( strlen( src ) + 5 );
234
for ( ; *src; src++, p++)
235
{
236
if (*src != '$')
237
{
238
*p = *src;
239
}
240
else if (src[1] == 'x') /* hex escape */
241
{
242
int val = 0;
243
src += 2;
244
if (*src >= '0' && *src <= '9') val += *src - '0';
245
else if (*src >= 'A' && *src <= 'F') val += *src - 'A' + 10;
246
else if (*src >= 'a' && *src <= 'f') val += *src - 'a' + 10;
247
else return NULL;
248
val *= 16;
249
src++;
250
if (*src >= '0' && *src <= '9') val += *src - '0';
251
else if (*src >= 'A' && *src <= 'F') val += *src - 'A' + 10;
252
else if (*src >= 'a' && *src <= 'f') val += *src - 'a' + 10;
253
else return NULL;
254
*p = val;
255
}
256
else break; /* end of dll name */
257
}
258
*p = 0;
259
if (!strchr( ret, '.' )) strcpy( p, ".dll" );
260
*name = src;
261
return ret;
262
}
263
264
/* check whether a given dll is imported in delayed mode */
265
static int is_delayed_import( const char *name )
266
{
267
STRARRAY_FOR_EACH( imp, &delayed_imports ) if (!strcmp( imp, name )) return 1;
268
return 0;
269
}
270
271
/* find an imported dll from its name */
272
static struct import *find_import_dll( const char *name )
273
{
274
struct import *import;
275
276
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
277
if (!strcasecmp( import->dll_name, name )) return import;
278
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
279
if (!strcasecmp( import->dll_name, name )) return import;
280
return NULL;
281
}
282
283
/* build the dll exported name from the import lib name */
284
static char *get_dll_name( const char *name )
285
{
286
char *ret = xmalloc( strlen(name) + 5 );
287
288
strcpy( ret, name );
289
if (!strchr( ret, '.' )) strcat( ret, ".dll" );
290
return ret;
291
}
292
293
/* add a library to the list of delayed imports */
294
void add_delayed_import( const char *name )
295
{
296
struct import *imp;
297
char *fullname = get_dll_name( name );
298
299
strarray_add( &delayed_imports, fullname );
300
if ((imp = find_import_dll( fullname )))
301
{
302
list_remove( &imp->entry );
303
list_add_tail( &dll_delayed, &imp->entry );
304
}
305
}
306
307
/* add a symbol to the list of extra symbols that ld must resolve */
308
void add_extra_ld_symbol( const char *name )
309
{
310
strarray_add( &extra_ld_symbols, name );
311
}
312
313
/* retrieve an imported dll, adding one if necessary */
314
static struct import *add_static_import_dll( const char *name )
315
{
316
struct import *import;
317
318
if ((import = find_import_dll( name ))) return import;
319
320
import = xmalloc( sizeof(*import) );
321
memset( import, 0, sizeof(*import) );
322
323
import->dll_name = xstrdup( name );
324
import->full_name = xstrdup( name );
325
import->c_name = make_c_identifier( name );
326
327
if (is_delayed_import( name ))
328
list_add_tail( &dll_delayed, &import->entry );
329
else
330
list_add_tail( &dll_imports, &import->entry );
331
return import;
332
}
333
334
/* add a function to the list of imports from a given dll */
335
static void add_import_func( struct import *imp, const char *name, const char *export_name,
336
int ordinal, int hint )
337
{
338
struct import_func *func = ARRAY_ADD( &imp->imports, struct import_func );
339
340
func->name = name;
341
func->export_name = export_name;
342
func->ordinal = ordinal;
343
func->hint = hint;
344
}
345
346
/* add an import for an undefined function of the form __wine$func$ */
347
static void add_undef_import( const char *name, int is_ordinal )
348
{
349
char *dll_name = decode_dll_name( &name );
350
int ordinal = 0;
351
struct import *import;
352
353
if (!dll_name) return;
354
if (*name++ != '$') return;
355
while (*name >= '0' && *name <= '9') ordinal = 10 * ordinal + *name++ - '0';
356
if (*name++ != '$') return;
357
358
if (!use_msvcrt && find_name( name, stdc_functions )) return;
359
360
import = add_static_import_dll( dll_name );
361
if (is_ordinal)
362
add_import_func( import, NULL, xstrdup( name ), ordinal, 0 );
363
else
364
add_import_func( import, xstrdup( name ), NULL, ordinal, 0 );
365
free( dll_name );
366
}
367
368
/* check if the spec file exports any stubs */
369
static int has_stubs( const struct exports *exports )
370
{
371
int i;
372
373
for (i = 0; i < exports->nb_entry_points; i++)
374
{
375
ORDDEF *odp = exports->entry_points[i];
376
if (odp->type == TYPE_STUB) return 1;
377
}
378
return 0;
379
}
380
381
/* add the extra undefined symbols that will be contained in the generated spec file itself */
382
static void add_extra_undef_symbols( DLLSPEC *spec )
383
{
384
add_extra_ld_symbol( spec->init_func );
385
if (spec->type == SPEC_WIN16) add_extra_ld_symbol( "DllMain" );
386
if (has_stubs( &spec->exports )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
387
if (delayed_imports.count) add_extra_ld_symbol( "__delayLoadHelper2" );
388
}
389
390
/* check if a given imported dll is not needed, taking forwards into account */
391
static int check_unused( const struct import* imp, const struct exports *exports )
392
{
393
int i;
394
const char *file_name = imp->dll_name;
395
size_t len = strlen( file_name );
396
const char *p = strchr( file_name, '.' );
397
if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
398
399
for (i = exports->base; i <= exports->limit; i++)
400
{
401
ORDDEF *odp = exports->ordinals[i];
402
if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
403
if (!strncasecmp( odp->link_name, file_name, len ) &&
404
odp->link_name[len] == '.')
405
return 0; /* found a forward, it is used */
406
}
407
return 1;
408
}
409
410
/* check if a given forward does exist in one of the imported dlls */
411
static void check_undefined_forwards( DLLSPEC *spec )
412
{
413
struct import *imp;
414
char *link_name, *api_name, *dll_name, *p;
415
int i;
416
417
for (i = 0; i < spec->exports.nb_entry_points; i++)
418
{
419
ORDDEF *odp = spec->exports.entry_points[i];
420
421
if (!(odp->flags & FLAG_FORWARD)) continue;
422
423
link_name = xstrdup( odp->link_name );
424
p = strrchr( link_name, '.' );
425
*p = 0;
426
api_name = p + 1;
427
dll_name = get_dll_name( link_name );
428
429
if ((imp = find_import_dll( dll_name )))
430
{
431
if (!find_export( api_name, imp->exports, imp->nb_exports ))
432
warning( "%s:%d: forward '%s' not found in %s\n",
433
spec->src_name, odp->lineno, odp->link_name, imp->dll_name );
434
}
435
else warning( "%s:%d: forward '%s' not found in the imported dll list\n",
436
spec->src_name, odp->lineno, odp->link_name );
437
free( link_name );
438
free( dll_name );
439
}
440
}
441
442
/* flag the dll exports that link to an undefined symbol */
443
static void check_undefined_exports( DLLSPEC *spec )
444
{
445
int i;
446
447
for (i = 0; i < spec->exports.nb_entry_points; i++)
448
{
449
ORDDEF *odp = spec->exports.entry_points[i];
450
if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
451
if (odp->flags & FLAG_FORWARD) continue;
452
if (find_name( odp->link_name, undef_symbols ))
453
{
454
switch(odp->type)
455
{
456
case TYPE_PASCAL:
457
case TYPE_STDCALL:
458
case TYPE_CDECL:
459
case TYPE_VARARGS:
460
if (link_ext_symbols)
461
{
462
odp->flags |= FLAG_EXT_LINK;
463
strarray_add( &ext_link_imports, odp->link_name );
464
}
465
else error( "%s:%d: function '%s' not defined\n",
466
spec->src_name, odp->lineno, odp->link_name );
467
break;
468
default:
469
error( "%s:%d: external symbol '%s' is not a function\n",
470
spec->src_name, odp->lineno, odp->link_name );
471
break;
472
}
473
}
474
}
475
}
476
477
/* create a .o file that references all the undefined symbols we want to resolve */
478
static char *create_undef_symbols_file( DLLSPEC *spec )
479
{
480
char *as_file, *obj_file;
481
int i;
482
483
as_file = open_temp_output_file( ".s" );
484
output( "\t.data\n" );
485
486
for (i = 0; i < spec->exports.nb_entry_points; i++)
487
{
488
ORDDEF *odp = spec->exports.entry_points[i];
489
if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
490
if (odp->flags & FLAG_FORWARD) continue;
491
output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( get_link_name( odp )));
492
}
493
STRARRAY_FOR_EACH( sym, &extra_ld_symbols )
494
output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(sym) );
495
496
output_gnu_stack_note();
497
fclose( output_file );
498
499
obj_file = make_temp_file( output_file_name, ".o" );
500
assemble_file( as_file, obj_file );
501
return obj_file;
502
}
503
504
/* combine a list of object files with ld into a single object file */
505
/* returns the name of the combined file */
506
static const char *ldcombine_files( DLLSPEC *spec, struct strarray files )
507
{
508
char *ld_tmp_file, *undef_file;
509
struct strarray args = get_ld_command();
510
511
undef_file = create_undef_symbols_file( spec );
512
ld_tmp_file = make_temp_file( output_file_name, ".o" );
513
514
strarray_add( &args, "-r" );
515
strarray_add( &args, "-o" );
516
strarray_add( &args, ld_tmp_file );
517
if (undef_file) strarray_add( &args, undef_file );
518
strarray_addall( &args, files );
519
spawn( args );
520
return ld_tmp_file;
521
}
522
523
/* read in the list of undefined symbols */
524
void read_undef_symbols( DLLSPEC *spec, struct strarray files )
525
{
526
size_t prefix_len;
527
FILE *f;
528
const char *prog = get_nm_command();
529
char *cmd, buffer[1024], name_prefix[16];
530
int err;
531
const char *name;
532
533
if (!files.count) return;
534
535
add_extra_undef_symbols( spec );
536
537
strcpy( name_prefix, asm_name("") );
538
prefix_len = strlen( name_prefix );
539
540
name = ldcombine_files( spec, files );
541
542
cmd = strmake( "%s -u %s", prog, name );
543
if (verbose)
544
fprintf( stderr, "%s\n", cmd );
545
if (!(f = popen( cmd, "r" )))
546
fatal_error( "Cannot execute '%s'\n", cmd );
547
548
while (fgets( buffer, sizeof(buffer), f ))
549
{
550
char *p = buffer + strlen(buffer) - 1;
551
if (p < buffer) continue;
552
if (*p == '\n') *p-- = 0;
553
p = buffer;
554
while (*p == ' ') p++;
555
if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
556
if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
557
if (!strncmp( p, import_func_prefix, strlen(import_func_prefix) ))
558
add_undef_import( p + strlen( import_func_prefix ), 0 );
559
else if (!strncmp( p, import_ord_prefix, strlen(import_ord_prefix) ))
560
add_undef_import( p + strlen( import_ord_prefix ), 1 );
561
else if (use_msvcrt || !find_name( p, stdc_functions ))
562
strarray_add( &undef_symbols, xstrdup( p ));
563
}
564
if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
565
}
566
567
void resolve_dll_imports( DLLSPEC *spec, struct list *list )
568
{
569
unsigned int j;
570
struct import *imp, *next;
571
ORDDEF *odp;
572
573
LIST_FOR_EACH_ENTRY_SAFE( imp, next, list, struct import, entry )
574
{
575
for (j = 0; j < undef_symbols.count; j++)
576
{
577
odp = find_export( undef_symbols.str[j], imp->exports, imp->nb_exports );
578
if (odp)
579
{
580
if (odp->flags & FLAG_PRIVATE) continue;
581
if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
582
warning( "winebuild: Data export '%s' cannot be imported from %s\n",
583
odp->link_name, imp->dll_name );
584
else
585
{
586
add_import_func( imp, (odp->flags & FLAG_NONAME) ? NULL : odp->name,
587
odp->export_name, odp->ordinal, odp->hint );
588
remove_name( &undef_symbols, j-- );
589
}
590
}
591
}
592
if (!imp->imports.count)
593
{
594
/* the dll is not used, get rid of it */
595
if (check_unused( imp, &spec->exports ))
596
warning( "winebuild: %s imported but no symbols used\n", imp->dll_name );
597
list_remove( &imp->entry );
598
}
599
}
600
}
601
602
/* resolve the imports for a Win32 module */
603
void resolve_imports( DLLSPEC *spec )
604
{
605
check_undefined_forwards( spec );
606
resolve_dll_imports( spec, &dll_imports );
607
resolve_dll_imports( spec, &dll_delayed );
608
sort_names( &undef_symbols );
609
check_undefined_exports( spec );
610
}
611
612
/* check if symbol is still undefined */
613
int is_undefined( const char *name )
614
{
615
return find_name( name, undef_symbols ) != NULL;
616
}
617
618
/* output the get_pc thunk if needed */
619
void output_get_pc_thunk(void)
620
{
621
assert( target.cpu == CPU_i386 );
622
output_function_header( "__wine_spec_get_pc_thunk_eax", 0 );
623
output( "\tmovl (%%esp),%%eax\n" );
624
output( "\tret\n" );
625
output_function_size( "__wine_spec_get_pc_thunk_eax" );
626
}
627
628
/* output a single import thunk */
629
static void output_import_thunk( const char *name, const char *table, int pos )
630
{
631
output_function_header( name, 1 );
632
633
switch (target.cpu)
634
{
635
case CPU_i386:
636
if (!UsePIC)
637
{
638
output( "\tjmp *(%s+%d)\n", table, pos );
639
}
640
else
641
{
642
output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
643
output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
644
needs_get_pc_thunk = 1;
645
}
646
break;
647
case CPU_x86_64:
648
output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
649
break;
650
default:
651
assert( 0 );
652
break;
653
}
654
output_function_size( name );
655
}
656
657
/* check if we need an import directory */
658
int has_imports(void)
659
{
660
return !list_empty( &dll_imports );
661
}
662
663
/* check if we need a delayed import directory */
664
int has_delay_imports(void)
665
{
666
return !list_empty( &dll_delayed );
667
}
668
669
/* output the import table of a Win32 module */
670
static void output_immediate_imports(void)
671
{
672
int i, j;
673
struct import *import;
674
675
if (list_empty( &dll_imports )) return; /* no immediate imports */
676
677
/* main import header */
678
679
output( "\n/* import table */\n" );
680
output( "\n\t.data\n" );
681
output( "\t.balign 4\n" );
682
output( ".L__wine_spec_imports:\n" );
683
684
/* list of dlls */
685
686
j = 0;
687
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
688
{
689
output_rva( ".L__wine_spec_import_data_names + %d", j * get_ptr_size() ); /* OriginalFirstThunk */
690
output( "\t.long 0\n" ); /* TimeDateStamp */
691
output( "\t.long 0\n" ); /* ForwarderChain */
692
output_rva( ".L__wine_spec_import_name_%s", import->c_name ); /* Name */
693
output_rva( ".L__wine_spec_import_data_ptrs + %d", j * get_ptr_size() ); /* FirstThunk */
694
j += import->imports.count + 1;
695
}
696
output( "\t.long 0\n" ); /* OriginalFirstThunk */
697
output( "\t.long 0\n" ); /* TimeDateStamp */
698
output( "\t.long 0\n" ); /* ForwarderChain */
699
output( "\t.long 0\n" ); /* Name */
700
output( "\t.long 0\n" ); /* FirstThunk */
701
702
output( "\n\t.balign %u\n", get_ptr_size() );
703
/* output the names twice, once for OriginalFirstThunk and once for FirstThunk */
704
for (i = 0; i < 2; i++)
705
{
706
output( ".L__wine_spec_import_data_%s:\n", i ? "ptrs" : "names" );
707
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
708
{
709
ARRAY_FOR_EACH( func, &import->imports, struct import_func )
710
{
711
if (i)
712
{
713
if (func->name) output( "__imp_%s:\n", asm_name( func->name ));
714
else if (func->export_name) output( "__imp_%s:\n", asm_name( func->export_name ));
715
}
716
output_thunk_rva( func->name ? -1 : func->ordinal,
717
".L__wine_spec_import_data_%s_%s", import->c_name, func->name );
718
}
719
output( "\t%s 0\n", get_asm_ptr_keyword() );
720
}
721
}
722
output( ".L__wine_spec_imports_end:\n" );
723
724
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
725
{
726
ARRAY_FOR_EACH( func, &import->imports, struct import_func )
727
{
728
if (!func->name) continue;
729
output( "\t.balign 2\n" );
730
output( ".L__wine_spec_import_data_%s_%s:\n", import->c_name, func->name );
731
output( "\t.short %d\n", func->hint );
732
output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
733
}
734
}
735
736
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
737
{
738
output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
739
import->c_name, get_asm_string_keyword(), import->dll_name );
740
}
741
}
742
743
/* output the import thunks of a Win32 module */
744
static void output_immediate_import_thunks(void)
745
{
746
int pos;
747
struct import *import;
748
static const char import_thunks[] = "__wine_spec_import_thunks";
749
750
if (list_empty( &dll_imports )) return;
751
752
output( "\n/* immediate import thunks */\n\n" );
753
output( "\t.text\n" );
754
output( "\t.balign 8\n" );
755
output( "%s:\n", asm_name(import_thunks));
756
757
pos = 0;
758
LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
759
{
760
ARRAY_FOR_EACH( func, &import->imports, struct import_func )
761
{
762
output_import_thunk( func->name ? func->name : func->export_name,
763
".L__wine_spec_import_data_ptrs", pos );
764
pos += get_ptr_size();
765
}
766
pos += get_ptr_size();
767
}
768
output_function_size( import_thunks );
769
}
770
771
/* output the delayed import table of a Win32 module */
772
static void output_delayed_imports( const DLLSPEC *spec )
773
{
774
int iat_pos, int_pos, mod_pos;
775
struct import *import;
776
777
if (list_empty( &dll_delayed )) return;
778
779
output( "\n/* delayed imports */\n\n" );
780
output( "\t.data\n" );
781
output( "\t.balign %u\n", get_ptr_size() );
782
output( ".L__wine_spec_delay_imports:\n" );
783
784
/* list of dlls */
785
786
iat_pos = int_pos = mod_pos = 0;
787
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
788
{
789
output( "\t.long 1\n" ); /* Attributes */
790
output_rva( ".L__wine_delay_name_%s", import->c_name ); /* DllNameRVA */
791
output_rva( ".L__wine_delay_modules+%d", mod_pos ); /* ModuleHandleRVA */
792
output_rva( ".L__wine_delay_IAT+%d", iat_pos ); /* ImportAddressTableRVA */
793
output_rva( ".L__wine_delay_INT+%d", int_pos ); /* ImportNameTableRVA */
794
output( "\t.long 0\n" ); /* BoundImportAddressTableRVA */
795
output( "\t.long 0\n" ); /* UnloadInformationTableRVA */
796
output( "\t.long 0\n" ); /* TimeDateStamp */
797
iat_pos += import->imports.count * get_ptr_size();
798
int_pos += (import->imports.count + 1) * get_ptr_size();
799
mod_pos += get_ptr_size();
800
}
801
output( "\t.long 0,0,0,0,0,0,0,0\n" );
802
output( ".L__wine_spec_delay_imports_end:\n" );
803
804
output( "\n.L__wine_delay_IAT:\n" );
805
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
806
{
807
ARRAY_FOR_EACH( func, &import->imports, struct import_func )
808
{
809
const char *name = func->name ? func->name : func->export_name;
810
output( "__imp_%s:\n", asm_name( name ));
811
output( "\t%s __wine_delay_imp_%s_%s\n",
812
get_asm_ptr_keyword(), import->c_name, name );
813
}
814
}
815
816
output( "\n.L__wine_delay_INT:\n" );
817
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
818
{
819
ARRAY_FOR_EACH( func, &import->imports, struct import_func )
820
output_thunk_rva( func->name ? -1 : func->ordinal,
821
".L__wine_delay_data_%s_%s", import->c_name, func->name );
822
output( "\t%s 0\n", get_asm_ptr_keyword() );
823
}
824
825
output( "\n.L__wine_delay_modules:\n" );
826
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
827
{
828
output( "\t%s 0\n", get_asm_ptr_keyword() );
829
}
830
831
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
832
{
833
output( ".L__wine_delay_name_%s:\n", import->c_name );
834
output( "\t%s \"%s\"\n", get_asm_string_keyword(), import->dll_name );
835
}
836
837
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
838
{
839
ARRAY_FOR_EACH( func, &import->imports, struct import_func )
840
{
841
if (!func->name) continue;
842
output( "\t.balign 2\n" );
843
output( ".L__wine_delay_data_%s_%s:\n", import->c_name, func->name );
844
output( "\t.short %d\n", func->hint );
845
output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
846
}
847
}
848
}
849
850
/* output the delayed import thunks of a Win32 module */
851
static void output_delayed_import_thunks( const DLLSPEC *spec )
852
{
853
int pos, iat_pos;
854
struct import *import;
855
static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
856
static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
857
858
if (list_empty( &dll_delayed )) return;
859
860
output( "\n/* delayed import thunks */\n\n" );
861
output( "\t.text\n" );
862
output( "\t.balign 8\n" );
863
output( "%s:\n", asm_name(delayed_import_loaders));
864
865
pos = iat_pos = 0;
866
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
867
{
868
char *module_func = strmake( "__wine_delay_load_asm_%s", import->c_name );
869
output_function_header( module_func, 0 );
870
output_cfi( ".cfi_startproc" );
871
switch (target.cpu)
872
{
873
case CPU_i386:
874
output( "\tpushl %%ecx\n" );
875
output_cfi( ".cfi_adjust_cfa_offset 4" );
876
output( "\tpushl %%edx\n" );
877
output_cfi( ".cfi_adjust_cfa_offset 4" );
878
output( "\tpushl %%eax\n" );
879
output_cfi( ".cfi_adjust_cfa_offset 4" );
880
if (UsePIC)
881
{
882
output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
883
output( "1:\tleal .L__wine_spec_delay_imports+%d-1b(%%eax),%%eax\n", pos );
884
output( "\tpushl %%eax\n" );
885
output_cfi( ".cfi_adjust_cfa_offset 4" );
886
needs_get_pc_thunk = 1;
887
}
888
else
889
{
890
output( "\tpushl $.L__wine_spec_delay_imports+%d\n", pos );
891
output_cfi( ".cfi_adjust_cfa_offset 4" );
892
}
893
output( "\tcall %s\n", asm_name("__delayLoadHelper2") );
894
output_cfi( ".cfi_adjust_cfa_offset -8" );
895
output( "\tpopl %%edx\n" );
896
output_cfi( ".cfi_adjust_cfa_offset -4" );
897
output( "\tpopl %%ecx\n" );
898
output_cfi( ".cfi_adjust_cfa_offset -4" );
899
output( "\tjmp *%%eax\n" );
900
break;
901
case CPU_x86_64:
902
output( "\tsubq $0x98,%%rsp\n" );
903
output_cfi( ".cfi_adjust_cfa_offset 0x98" );
904
output( "\tmovq %%rdx,0x88(%%rsp)\n" );
905
output( "\tmovq %%rcx,0x80(%%rsp)\n" );
906
output( "\tmovq %%r8,0x78(%%rsp)\n" );
907
output( "\tmovq %%r9,0x70(%%rsp)\n" );
908
output( "\tmovq %%r10,0x68(%%rsp)\n" );
909
output( "\tmovq %%r11,0x60(%%rsp)\n" );
910
output( "\tmovups %%xmm0,0x50(%%rsp)\n" );
911
output( "\tmovups %%xmm1,0x40(%%rsp)\n" );
912
output( "\tmovups %%xmm2,0x30(%%rsp)\n" );
913
output( "\tmovups %%xmm3,0x20(%%rsp)\n" );
914
output( "\tleaq .L__wine_spec_delay_imports+%d(%%rip),%%rcx\n", pos );
915
output( "\tmovq %%rax,%%rdx\n" );
916
output( "\tcall %s\n", asm_name("__delayLoadHelper2") );
917
output( "\tmovups 0x20(%%rsp),%%xmm3\n" );
918
output( "\tmovups 0x30(%%rsp),%%xmm2\n" );
919
output( "\tmovups 0x40(%%rsp),%%xmm1\n" );
920
output( "\tmovups 0x50(%%rsp),%%xmm0\n" );
921
output( "\tmovq 0x60(%%rsp),%%r11\n" );
922
output( "\tmovq 0x68(%%rsp),%%r10\n" );
923
output( "\tmovq 0x70(%%rsp),%%r9\n" );
924
output( "\tmovq 0x78(%%rsp),%%r8\n" );
925
output( "\tmovq 0x80(%%rsp),%%rcx\n" );
926
output( "\tmovq 0x88(%%rsp),%%rdx\n" );
927
output( "\taddq $0x98,%%rsp\n" );
928
output_cfi( ".cfi_adjust_cfa_offset -0x98" );
929
output( "\tjmp *%%rax\n" );
930
break;
931
default:
932
assert( 0 );
933
break;
934
}
935
output_cfi( ".cfi_endproc" );
936
output_function_size( module_func );
937
output( "\n" );
938
939
ARRAY_FOR_EACH( func, &import->imports, struct import_func )
940
{
941
const char *name = func->name ? func->name : func->export_name;
942
943
output( "__wine_delay_imp_%s_%s:\n", import->c_name, name );
944
switch (target.cpu)
945
{
946
case CPU_i386:
947
if (UsePIC)
948
{
949
output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
950
output( "1:\tleal .L__wine_delay_IAT+%d-1b(%%eax),%%eax\n", iat_pos );
951
needs_get_pc_thunk = 1;
952
}
953
else output( "\tmovl $.L__wine_delay_IAT+%d,%%eax\n", iat_pos );
954
output( "\tjmp %s\n", asm_name(module_func) );
955
break;
956
case CPU_x86_64:
957
output( "\tleaq .L__wine_delay_IAT+%d(%%rip),%%rax\n", iat_pos );
958
output( "\tjmp %s\n", asm_name(module_func) );
959
break;
960
default:
961
assert( 0 );
962
break;
963
}
964
iat_pos += get_ptr_size();
965
}
966
pos += 8 * 4; /* IMAGE_DELAYLOAD_DESCRIPTOR is 8 DWORDs */
967
}
968
output_function_size( delayed_import_loaders );
969
970
output( "\n\t.balign %u\n", get_ptr_size() );
971
output( "%s:\n", asm_name(delayed_import_thunks));
972
pos = 0;
973
LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
974
{
975
ARRAY_FOR_EACH( func, &import->imports, struct import_func )
976
{
977
output_import_thunk( func->name ? func->name : func->export_name,
978
".L__wine_delay_IAT", pos );
979
pos += get_ptr_size();
980
}
981
}
982
output_function_size( delayed_import_thunks );
983
}
984
985
/* output import stubs for exported entry points that link to external symbols */
986
static void output_external_link_imports( DLLSPEC *spec )
987
{
988
unsigned int i, pos = 0;
989
990
if (!ext_link_imports.count) return; /* nothing to do */
991
992
sort_names( &ext_link_imports );
993
994
/* get rid of duplicate names */
995
for (i = 1; i < ext_link_imports.count; i++)
996
{
997
if (!strcmp( ext_link_imports.str[i-1], ext_link_imports.str[i] ))
998
remove_name( &ext_link_imports, i-- );
999
}
1000
1001
output( "\n/* external link thunks */\n\n" );
1002
output( "\t.data\n" );
1003
output( "\t.balign %u\n", get_ptr_size() );
1004
output( ".L__wine_spec_external_links:\n" );
1005
STRARRAY_FOR_EACH( imp, &ext_link_imports )
1006
output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(imp) );
1007
1008
output( "\n\t.text\n" );
1009
output( "\t.balign %u\n", get_ptr_size() );
1010
output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1011
1012
STRARRAY_FOR_EACH( imp, &ext_link_imports )
1013
{
1014
char *buffer = strmake( "__wine_spec_ext_link_%s", imp );
1015
output_import_thunk( buffer, ".L__wine_spec_external_links", pos );
1016
pos += get_ptr_size();
1017
}
1018
output_function_size( "__wine_spec_external_link_thunks" );
1019
}
1020
1021
/*******************************************************************
1022
* output_stubs
1023
*
1024
* Output the functions for stub entry points
1025
*/
1026
void output_stubs( DLLSPEC *spec )
1027
{
1028
struct exports *exports = &spec->exports;
1029
const char *name, *exp_name;
1030
int i;
1031
1032
if (!has_stubs( exports )) return;
1033
1034
output( "\n/* stub functions */\n\n" );
1035
1036
for (i = 0; i < exports->nb_entry_points; i++)
1037
{
1038
ORDDEF *odp = exports->entry_points[i];
1039
if (odp->type != TYPE_STUB) continue;
1040
if (odp->flags & FLAG_SYSCALL) continue;
1041
1042
name = get_link_name( odp );
1043
exp_name = odp->name ? odp->name : odp->export_name;
1044
output_function_header( name, 0 );
1045
1046
switch (target.cpu)
1047
{
1048
case CPU_i386:
1049
output_cfi( ".cfi_startproc" );
1050
/* flesh out the stub a bit to make safedisc happy */
1051
output(" \tnop\n" );
1052
output(" \tnop\n" );
1053
output(" \tnop\n" );
1054
output(" \tnop\n" );
1055
output(" \tnop\n" );
1056
output(" \tnop\n" );
1057
output(" \tnop\n" );
1058
output(" \tnop\n" );
1059
output(" \tnop\n" );
1060
1061
output( "\tsubl $12,%%esp\n" );
1062
output_cfi( ".cfi_adjust_cfa_offset 12" );
1063
if (UsePIC)
1064
{
1065
output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1066
output( "1:" );
1067
needs_get_pc_thunk = 1;
1068
if (exp_name)
1069
{
1070
output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name );
1071
output( "\tmovl %%ecx,4(%%esp)\n" );
1072
}
1073
else
1074
output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1075
output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1076
output( "\tmovl %%ecx,(%%esp)\n" );
1077
}
1078
else
1079
{
1080
if (exp_name)
1081
output( "\tmovl $.L%s_string,4(%%esp)\n", name );
1082
else
1083
output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1084
output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
1085
}
1086
output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1087
output_cfi( ".cfi_endproc" );
1088
break;
1089
case CPU_x86_64:
1090
output_cfi( ".cfi_startproc" );
1091
output_seh( ".seh_proc %s", asm_name(name) );
1092
output( "\tsubq $0x28,%%rsp\n" );
1093
output_cfi( ".cfi_adjust_cfa_offset 0x28" );
1094
output_seh( ".seh_stackalloc 0x28" );
1095
output_seh( ".seh_endprologue" );
1096
output( "\tleaq .L__wine_spec_file_name(%%rip),%%rcx\n" );
1097
if (exp_name)
1098
output( "leaq .L%s_string(%%rip),%%rdx\n", name );
1099
else
1100
output( "\tmovq $%d,%%rdx\n", odp->ordinal );
1101
output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1102
output_cfi( ".cfi_endproc" );
1103
output_seh( ".seh_endproc" );
1104
break;
1105
case CPU_ARM:
1106
output( "\t.seh_proc %s\n", asm_name(name) );
1107
output( "\t.seh_endprologue\n" );
1108
output( "\tmovw r0,:lower16:.L__wine_spec_file_name\n");
1109
output( "\tmovt r0,:upper16:.L__wine_spec_file_name\n");
1110
if (exp_name)
1111
{
1112
output( "\tmovw r1,:lower16:.L%s_string\n", name );
1113
output( "\tmovt r1,:upper16:.L%s_string\n", name );
1114
}
1115
else output( "\tmov r1,#%u\n", odp->ordinal );
1116
output( "\tb %s\n", asm_name("__wine_spec_unimplemented_stub") );
1117
output( "\t.seh_endproc\n" );
1118
break;
1119
case CPU_ARM64:
1120
case CPU_ARM64EC:
1121
output( "\t.seh_proc %s\n", arm64_name(name) );
1122
output( "\t.seh_endprologue\n" );
1123
output( "\tadrp x0, .L__wine_spec_file_name\n" );
1124
output( "\tadd x0, x0, #:lo12:.L__wine_spec_file_name\n" );
1125
if (exp_name)
1126
{
1127
output( "\tadrp x1, .L%s_string\n", name );
1128
output( "\tadd x1, x1, #:lo12:.L%s_string\n", name );
1129
}
1130
else
1131
output( "\tmov x1, %u\n", odp->ordinal );
1132
output( "\tb %s\n", arm64_name("__wine_spec_unimplemented_stub") );
1133
output( "\t.seh_endproc\n" );
1134
break;
1135
}
1136
output_function_size( name );
1137
}
1138
1139
output( "\t%s\n", get_asm_string_section() );
1140
output( ".L__wine_spec_file_name:\n" );
1141
output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1142
for (i = 0; i < exports->nb_entry_points; i++)
1143
{
1144
ORDDEF *odp = exports->entry_points[i];
1145
if (odp->type != TYPE_STUB) continue;
1146
if (odp->flags & FLAG_SYSCALL) continue;
1147
exp_name = odp->name ? odp->name : odp->export_name;
1148
if (exp_name)
1149
{
1150
name = get_link_name( odp );
1151
output( ".L%s_string:\n", name );
1152
output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
1153
}
1154
}
1155
}
1156
1157
/* output the import and delayed import tables of a Win32 module */
1158
void output_imports( DLLSPEC *spec )
1159
{
1160
if (is_pe()) return;
1161
output_immediate_imports();
1162
output_delayed_imports( spec );
1163
output_immediate_import_thunks();
1164
output_delayed_import_thunks( spec );
1165
output_external_link_imports( spec );
1166
}
1167
1168
/* create a new asm temp file */
1169
static void new_output_as_file(void)
1170
{
1171
char *name;
1172
1173
if (output_file) fclose( output_file );
1174
name = open_temp_output_file( ".s" );
1175
strarray_add( &as_files, name );
1176
}
1177
1178
/* assemble all the asm files */
1179
static void assemble_files( const char *prefix )
1180
{
1181
unsigned int i;
1182
1183
if (output_file) fclose( output_file );
1184
output_file = NULL;
1185
1186
for (i = 0; i < as_files.count; i++)
1187
{
1188
char *obj = make_temp_file( prefix, ".o" );
1189
assemble_file( as_files.str[i], obj );
1190
as_files.str[i] = obj;
1191
}
1192
}
1193
1194
static const char *get_target_machine(void)
1195
{
1196
static const char *machine_names[] =
1197
{
1198
[CPU_i386] = "x86",
1199
[CPU_x86_64] = "x64",
1200
[CPU_ARM] = "arm",
1201
[CPU_ARM64] = "arm64",
1202
[CPU_ARM64EC] = "arm64ec",
1203
};
1204
1205
return machine_names[target.cpu];
1206
}
1207
1208
/* build a library from the current asm files and any additional object files in argv */
1209
void output_static_lib( const char *output_name, struct strarray files, int create )
1210
{
1211
struct strarray args;
1212
1213
if (!create || target.platform != PLATFORM_WINDOWS)
1214
{
1215
args = find_tool( "ar", NULL );
1216
strarray_add( &args, create ? "rc" : "r" );
1217
strarray_add( &args, output_name );
1218
}
1219
else
1220
{
1221
args = find_link_tool();
1222
strarray_add( &args, "/lib" );
1223
strarray_add( &args, strmake( "-machine:%s", get_target_machine() ));
1224
strarray_add( &args, strmake( "-out:%s", output_name ));
1225
}
1226
strarray_addall( &args, as_files );
1227
strarray_addall( &args, files );
1228
if (create) unlink( output_name );
1229
spawn( args );
1230
1231
if (target.platform != PLATFORM_WINDOWS)
1232
{
1233
struct strarray ranlib = find_tool( "ranlib", NULL );
1234
strarray_add( &ranlib, output_name );
1235
spawn( ranlib );
1236
}
1237
}
1238
1239
/* create a Windows-style import library using dlltool */
1240
static void build_dlltool_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files )
1241
{
1242
const char *def_file, *native_def_file = NULL;
1243
struct strarray args;
1244
1245
def_file = open_temp_output_file( ".def" );
1246
output_def_file( spec, &spec->exports, 1 );
1247
fclose( output_file );
1248
1249
if (native_arch != -1)
1250
{
1251
native_def_file = open_temp_output_file( ".def" );
1252
output_def_file( spec, &spec->native_exports, 1 );
1253
fclose( output_file );
1254
}
1255
1256
args = find_tool( "dlltool", NULL );
1257
strarray_add( &args, "-k" );
1258
strarray_add( &args, strendswith( lib_name, ".delay.a" ) ? "-y" : "-l" );
1259
strarray_add( &args, lib_name );
1260
strarray_add( &args, "-d" );
1261
strarray_add( &args, def_file );
1262
if (native_def_file)
1263
{
1264
strarray_add( &args, "-N" );
1265
strarray_add( &args, native_def_file );
1266
}
1267
1268
switch (target.cpu)
1269
{
1270
case CPU_i386:
1271
strarray_add( &args, "-m" );
1272
strarray_add( &args, "i386" );
1273
strarray_add( &args, "--as-flags=--32" );
1274
break;
1275
case CPU_x86_64:
1276
strarray_add( &args, "-m" );
1277
strarray_add( &args, "i386:x86-64" );
1278
strarray_add( &args, "--as-flags=--64" );
1279
break;
1280
case CPU_ARM:
1281
strarray_add( &args, "-m" );
1282
strarray_add( &args, "arm" );
1283
break;
1284
case CPU_ARM64:
1285
strarray_add( &args, "-m" );
1286
strarray_add( &args, "arm64" );
1287
break;
1288
case CPU_ARM64EC:
1289
strarray_add( &args, "-m" );
1290
strarray_add( &args, "arm64ec" );
1291
break;
1292
default:
1293
break;
1294
}
1295
1296
spawn( args );
1297
1298
if (files.count) output_static_lib( output_file_name, files, 0 );
1299
}
1300
1301
static void output_import_section( int index, int is_delay )
1302
{
1303
if (!is_delay)
1304
output( "\n\t.section .idata$%d\n", index );
1305
else if (index == 5)
1306
output( "\n\t.section .data$didat%d\n", index );
1307
else
1308
output( "\n\t.section .rdata$didat%d\n", index );
1309
}
1310
1311
/* create a Windows-style import library */
1312
static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files )
1313
{
1314
char *dll_name, *import_desc, *import_name, *delay_load;
1315
struct strarray objs = empty_strarray;
1316
int i, total, by_name;
1317
int is_delay = strendswith( lib_name, ".delay.a" );
1318
const char *name;
1319
1320
/* make sure assemble_files doesn't strip suffixes */
1321
dll_name = encode_dll_name( spec->file_name );
1322
for (i = 0; i < strlen( dll_name ); ++i) if (dll_name[i] == '.') dll_name[i] = '_';
1323
1324
import_desc = strmake( "__wine_import_%s_desc", dll_name );
1325
import_name = strmake( "__wine_import_%s_name", dll_name );
1326
delay_load = strmake( "__wine_delay_load_%s", dll_name );
1327
1328
new_output_as_file();
1329
1330
if (is_delay)
1331
{
1332
output_function_header( delay_load, 1 );
1333
1334
switch (target.cpu)
1335
{
1336
case CPU_i386:
1337
output_cfi( ".cfi_startproc" );
1338
output( "\tpushl %%ecx\n" );
1339
output_cfi( ".cfi_adjust_cfa_offset 4" );
1340
output( "\tpushl %%edx\n" );
1341
output_cfi( ".cfi_adjust_cfa_offset 4" );
1342
output( "\tpushl %%eax\n" );
1343
output_cfi( ".cfi_adjust_cfa_offset 4" );
1344
output( "\tpushl $%s\n", asm_name( import_desc ) );
1345
output( "\tcalll ___delayLoadHelper2@8\n" );
1346
output_cfi( ".cfi_adjust_cfa_offset -8" );
1347
output( "\tpopl %%edx\n" );
1348
output_cfi( ".cfi_adjust_cfa_offset -4" );
1349
output( "\tpopl %%ecx\n" );
1350
output_cfi( ".cfi_adjust_cfa_offset -4" );
1351
output( "\tjmp *%%eax\n" );
1352
output_cfi( ".cfi_endproc" );
1353
break;
1354
case CPU_x86_64:
1355
output_seh( ".seh_proc %s", asm_name( delay_load ) );
1356
output( "\tsubq $0x48, %%rsp\n" );
1357
output_seh( ".seh_stackalloc 0x48" );
1358
output_seh( ".seh_endprologue" );
1359
output( "\tmovq %%rcx, 0x40(%%rsp)\n" );
1360
output( "\tmovq %%rdx, 0x38(%%rsp)\n" );
1361
output( "\tmovq %%r8, 0x30(%%rsp)\n" );
1362
output( "\tmovq %%r9, 0x28(%%rsp)\n" );
1363
output( "\tmovq %%rax, %%rdx\n" );
1364
output( "\tleaq %s(%%rip), %%rcx\n", asm_name( import_desc ) );
1365
output( "\tcall __delayLoadHelper2\n" );
1366
output( "\tmovq 0x28(%%rsp), %%r9\n" );
1367
output( "\tmovq 0x30(%%rsp), %%r8\n" );
1368
output( "\tmovq 0x38(%%rsp), %%rdx\n" );
1369
output( "\tmovq 0x40(%%rsp), %%rcx\n" );
1370
output( "\taddq $0x48, %%rsp\n" );
1371
output( "\tjmp *%%rax\n" );
1372
output_seh( ".seh_endproc" );
1373
break;
1374
case CPU_ARM:
1375
output( "\t.seh_proc %s\n", asm_name( delay_load ) );
1376
output( "\tpush {r0-r3, FP, LR}\n" );
1377
output( "\t.seh_save_regs {r0-r3,fp,lr}\n" );
1378
output( "\t.seh_endprologue\n" );
1379
output( "\tmov r1, IP\n" );
1380
output( "\tldr r0, 1f\n" );
1381
output( "\tldr r0, [r0]\n" );
1382
output( "\tbl __delayLoadHelper2\n" );
1383
output( "\tmov IP, r0\n" );
1384
output( "\tpop {r0-r3, FP, LR}\n" );
1385
output( "\tbx IP\n" );
1386
output( "1:\t.long %s\n", asm_name( import_desc ) );
1387
output( "\t.seh_endproc\n" );
1388
break;
1389
case CPU_ARM64:
1390
output( "\t.seh_proc %s\n", asm_name( delay_load ) );
1391
output( "\tstp x29, x30, [sp, #-80]!\n" );
1392
output( "\t.seh_save_fplr_x 80\n" );
1393
output( "\tmov x29, sp\n" );
1394
output( "\t.seh_set_fp\n" );
1395
output( "\t.seh_endprologue\n" );
1396
output( "\tstp x0, x1, [sp, #16]\n" );
1397
output( "\tstp x2, x3, [sp, #32]\n" );
1398
output( "\tstp x4, x5, [sp, #48]\n" );
1399
output( "\tstp x6, x7, [sp, #64]\n" );
1400
output( "\tmov x1, x16\n" );
1401
output( "\tadrp x0, %s\n", asm_name( import_desc ) );
1402
output( "\tadd x0, x0, #:lo12:%s\n", asm_name( import_desc ) );
1403
output( "\tbl __delayLoadHelper2\n" );
1404
output( "\tmov x16, x0\n" );
1405
output( "\tldp x0, x1, [sp, #16]\n" );
1406
output( "\tldp x2, x3, [sp, #32]\n" );
1407
output( "\tldp x4, x5, [sp, #48]\n" );
1408
output( "\tldp x6, x7, [sp, #64]\n" );
1409
output( "\tldp x29, x30, [sp], #80\n" );
1410
output( "\tbr x16\n" );
1411
output( "\t.seh_endproc\n" );
1412
break;
1413
case CPU_ARM64EC:
1414
assert( 0 );
1415
break;
1416
}
1417
output_function_size( delay_load );
1418
output_gnu_stack_note();
1419
1420
output( "\n\t.data\n" );
1421
output( ".L__wine_delay_import_handle:\n" );
1422
output( "\t%s 0\n", get_asm_ptr_keyword() );
1423
1424
output( "%s\n", asm_globl( import_desc ) );
1425
output( "\t.long 1\n" ); /* DllAttributes */
1426
output_rva( "%s", asm_name( import_name ) ); /* DllNameRVA */
1427
output_rva( ".L__wine_delay_import_handle" ); /* ModuleHandleRVA */
1428
output_rva( ".L__wine_import_addrs" ); /* ImportAddressTableRVA */
1429
output_rva( ".L__wine_import_names" ); /* ImportNameTableRVA */
1430
output( "\t.long 0\n" ); /* BoundImportAddressTableRVA */
1431
output( "\t.long 0\n" ); /* UnloadInformationTableRVA */
1432
output( "\t.long 0\n" ); /* TimeDateStamp */
1433
1434
output_import_section( 5, is_delay );
1435
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */
1436
output( ".L__wine_import_addrs:\n" );
1437
1438
output_import_section( 4, is_delay );
1439
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */
1440
output( ".L__wine_import_names:\n" );
1441
1442
/* required to avoid internal linker errors with some binutils versions */
1443
output_import_section( 2, is_delay );
1444
}
1445
else
1446
{
1447
output_import_section( 2, is_delay );
1448
output( "%s\n", asm_globl( import_desc ) );
1449
output_rva( ".L__wine_import_names" ); /* OriginalFirstThunk */
1450
output( "\t.long 0\n" ); /* TimeDateStamp */
1451
output( "\t.long 0\n" ); /* ForwarderChain */
1452
output_rva( "%s", asm_name( import_name ) ); /* Name */
1453
output_rva( ".L__wine_import_addrs" ); /* FirstThunk */
1454
1455
output_import_section( 4, is_delay );
1456
output( ".L__wine_import_names:\n" ); /* OriginalFirstThunk head */
1457
1458
output_import_section( 5, is_delay );
1459
output( ".L__wine_import_addrs:\n" ); /* FirstThunk head */
1460
}
1461
1462
/* _head suffix to keep this object sections first */
1463
assemble_files( strmake( "%s_head", dll_name ) );
1464
strarray_addall( &objs, as_files );
1465
as_files = empty_strarray;
1466
1467
new_output_as_file();
1468
1469
output_import_section( 4, is_delay );
1470
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */
1471
output_import_section( 5, is_delay );
1472
output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */
1473
output_import_section( 7, is_delay );
1474
output( "%s\n", asm_globl( import_name ) );
1475
output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1476
1477
/* _tail suffix to keep this object sections last */
1478
assemble_files( strmake( "%s_tail", dll_name ) );
1479
strarray_addall( &objs, as_files );
1480
as_files = empty_strarray;
1481
1482
for (i = total = 0; i < spec->exports.nb_entry_points; i++)
1483
{
1484
const ORDDEF *odp = spec->exports.entry_points[i];
1485
const char *abi_name;
1486
char *imp_name;
1487
1488
if (odp->name) name = odp->name;
1489
else if (odp->export_name) name = odp->export_name;
1490
else continue;
1491
1492
if (odp->flags & FLAG_PRIVATE) continue;
1493
total++;
1494
1495
/* C++ mangled names cannot be imported */
1496
if (strpbrk( name, "?@" )) continue;
1497
1498
switch (odp->type)
1499
{
1500
case TYPE_VARARGS:
1501
case TYPE_CDECL:
1502
case TYPE_STDCALL:
1503
by_name = odp->name && !(odp->flags & FLAG_ORDINAL);
1504
abi_name = get_abi_name( odp, name );
1505
imp_name = strmake( "%s_imp_%s", target.cpu != CPU_i386 ? "_" : "",
1506
asm_name( abi_name ) );
1507
1508
new_output_as_file();
1509
output_function_header( abi_name, 1 );
1510
1511
switch (target.cpu)
1512
{
1513
case CPU_i386:
1514
output( "\tjmp *%s\n", asm_name( imp_name ) );
1515
if (is_delay)
1516
{
1517
output( "\n\t.section .text$1\n" );
1518
output( ".L__wine_delay_import:\n" );
1519
output( "\tmov $%s,%%eax\n", asm_name( imp_name ) );
1520
output( "\tjmp %s\n", asm_name( delay_load ) );
1521
}
1522
break;
1523
case CPU_x86_64:
1524
output( "\tjmp *%s(%%rip)\n", asm_name( imp_name ) );
1525
if (is_delay)
1526
{
1527
output( "\n\t.section .text$1\n" );
1528
output( ".L__wine_delay_import:\n" );
1529
output( "\tlea %s(%%rip),%%rax\n", asm_name( imp_name ) );
1530
output( "\tjmp %s\n", asm_name( delay_load ) );
1531
}
1532
break;
1533
case CPU_ARM:
1534
output( "\tldr IP, 1f\n" );
1535
output( "\tldr PC, [IP]\n" );
1536
if (is_delay)
1537
{
1538
output( "\n\t.section .text$1\n" );
1539
output( ".L__wine_delay_import:\n" );
1540
output( "\tldr IP, 1f\n" );
1541
output( "\tldr IP, [IP]\n" );
1542
output( "\tb %s\n", asm_name( delay_load ) );
1543
}
1544
output( "1:\t.long %s\n", asm_name( imp_name ) );
1545
break;
1546
case CPU_ARM64:
1547
output( "\tadrp x16, %s\n", asm_name( imp_name ) );
1548
output( "\tadd x16, x16, #:lo12:%s\n", asm_name( imp_name ) );
1549
output( "\tbr x16\n" );
1550
if (is_delay)
1551
{
1552
output( "\n\t.section .text$1\n" );
1553
output( ".L__wine_delay_import:\n" );
1554
output( "\tadrp x16, %s\n", asm_name( imp_name ) );
1555
output( "\tadd x16, x16, #:lo12:%s\n", asm_name( imp_name ) );
1556
output( "\tb %s\n", asm_name( delay_load ) );
1557
}
1558
break;
1559
case CPU_ARM64EC:
1560
assert( 0 );
1561
break;
1562
}
1563
1564
output_import_section( 4, is_delay );
1565
output_thunk_rva( by_name ? -1 : odp->ordinal, ".L__wine_import_name" );
1566
1567
output_import_section( 5, is_delay );
1568
output( "%s\n", asm_globl( imp_name ) );
1569
if (is_delay)
1570
output( "\t%s .L__wine_delay_import\n", get_asm_ptr_keyword() );
1571
else
1572
output_thunk_rva( by_name ? -1 : odp->ordinal, ".L__wine_import_name" );
1573
1574
if (by_name)
1575
{
1576
output_import_section( 6, is_delay );
1577
output( ".L__wine_import_name:\n" );
1578
output( "\t.short %d\n", odp->hint );
1579
output( "\t%s \"%s\"\n", get_asm_string_keyword(), name );
1580
}
1581
1582
/* reference head object to always pull its sections */
1583
output_import_section( 7, is_delay );
1584
output_rva( "%s", asm_name( import_desc ) );
1585
break;
1586
1587
default:
1588
break;
1589
}
1590
}
1591
1592
/* _syms suffix to keep these objects sections in between _head and _tail */
1593
assemble_files( strmake( "%s_syms", dll_name ) );
1594
strarray_addall( &objs, as_files );
1595
as_files = objs;
1596
1597
output_static_lib( output_file_name, files, 1 );
1598
}
1599
1600
/* create a Unix-style import library */
1601
static void build_unix_import_lib( DLLSPEC *spec, struct strarray files )
1602
{
1603
int i, total;
1604
const char *name, *prefix;
1605
char *dll_name = encode_dll_name( spec->file_name );
1606
1607
/* entry points */
1608
1609
for (i = total = 0; i < spec->exports.nb_entry_points; i++)
1610
{
1611
const ORDDEF *odp = spec->exports.entry_points[i];
1612
1613
if (odp->name) name = odp->name;
1614
else if (odp->export_name) name = odp->export_name;
1615
else continue;
1616
1617
if (odp->flags & FLAG_PRIVATE) continue;
1618
total++;
1619
1620
/* C++ mangled names cannot be imported */
1621
if (strpbrk( name, "?@" )) continue;
1622
1623
switch(odp->type)
1624
{
1625
case TYPE_VARARGS:
1626
case TYPE_CDECL:
1627
case TYPE_STDCALL:
1628
prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
1629
new_output_as_file();
1630
output_function_header( name, 1 );
1631
output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
1632
asm_name( prefix ), dll_name, odp->ordinal, name );
1633
output_function_size( name );
1634
output_gnu_stack_note();
1635
break;
1636
1637
default:
1638
break;
1639
}
1640
}
1641
if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
1642
1643
if (!as_files.count) /* create a dummy file to avoid empty import libraries */
1644
{
1645
new_output_as_file();
1646
output( "\t.text\n" );
1647
}
1648
1649
assemble_files( spec->file_name );
1650
output_static_lib( output_file_name, files, 1 );
1651
}
1652
1653
/* output an import library for a Win32 module and additional object files */
1654
void output_import_lib( DLLSPEC *spec, struct strarray files )
1655
{
1656
if (!is_pe()) build_unix_import_lib( spec, files );
1657
else if (use_dlltool) build_dlltool_import_lib( output_file_name, spec, files );
1658
else build_windows_import_lib( output_file_name, spec, files );
1659
}
1660
1661