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