Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/winebuild/utils.c
8602 views
1
/*
2
* Small utility functions for winebuild
3
*
4
* Copyright 2000 Alexandre Julliard
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*/
20
21
#include "config.h"
22
23
#include <assert.h>
24
#include <ctype.h>
25
#include <stdarg.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
30
#include "build.h"
31
32
const char *temp_dir = NULL;
33
struct strarray temp_files = { 0 };
34
static const char *output_file_source_name;
35
36
char *strupper(char *s)
37
{
38
char *p;
39
for (p = s; *p; p++) *p = toupper(*p);
40
return s;
41
}
42
43
void fatal_error( const char *msg, ... )
44
{
45
va_list valist;
46
va_start( valist, msg );
47
if (input_file_name)
48
{
49
fprintf( stderr, "%s:", input_file_name );
50
if (current_line)
51
fprintf( stderr, "%d:", current_line );
52
fputc( ' ', stderr );
53
}
54
else fprintf( stderr, "winebuild: " );
55
vfprintf( stderr, msg, valist );
56
va_end( valist );
57
exit(1);
58
}
59
60
void error( const char *msg, ... )
61
{
62
va_list valist;
63
va_start( valist, msg );
64
if (input_file_name)
65
{
66
fprintf( stderr, "%s:", input_file_name );
67
if (current_line)
68
fprintf( stderr, "%d:", current_line );
69
fputc( ' ', stderr );
70
}
71
vfprintf( stderr, msg, valist );
72
va_end( valist );
73
nb_errors++;
74
}
75
76
void warning( const char *msg, ... )
77
{
78
va_list valist;
79
80
if (!display_warnings) return;
81
va_start( valist, msg );
82
if (input_file_name)
83
{
84
fprintf( stderr, "%s:", input_file_name );
85
if (current_line)
86
fprintf( stderr, "%d:", current_line );
87
fputc( ' ', stderr );
88
}
89
fprintf( stderr, "warning: " );
90
vfprintf( stderr, msg, valist );
91
va_end( valist );
92
}
93
94
int output( const char *format, ... )
95
{
96
int ret;
97
va_list valist;
98
99
va_start( valist, format );
100
ret = vfprintf( output_file, format, valist );
101
va_end( valist );
102
if (ret < 0) fatal_perror( "Output error" );
103
return ret;
104
}
105
106
static struct strarray get_tools_path(void)
107
{
108
static int done;
109
static struct strarray dirs;
110
111
if (!done)
112
{
113
strarray_addall( &dirs, tools_path );
114
strarray_addall( &dirs, strarray_frompath( getenv( "PATH" )));
115
done = 1;
116
}
117
return dirs;
118
}
119
120
/* find a binary in the path */
121
static const char *find_binary( const char *prefix, const char *name )
122
{
123
struct strarray dirs = get_tools_path();
124
unsigned int maxlen = 0;
125
struct stat st;
126
char *p, *file;
127
128
if (strchr( name, '/' )) return name;
129
if (!prefix) prefix = "";
130
STRARRAY_FOR_EACH( dir, &dirs ) maxlen = max( maxlen, strlen(dir) + 2 );
131
file = xmalloc( maxlen + strlen(prefix) + strlen(name) + sizeof(EXEEXT) + 1 );
132
133
STRARRAY_FOR_EACH( dir, &dirs )
134
{
135
strcpy( file, dir );
136
p = file + strlen(file);
137
if (p == file) *p++ = '.';
138
if (p[-1] != '/') *p++ = '/';
139
if (*prefix)
140
{
141
strcpy( p, prefix );
142
p += strlen(p);
143
*p++ = '-';
144
}
145
strcpy( p, name );
146
strcat( p, EXEEXT );
147
if (!stat( file, &st ) && S_ISREG(st.st_mode) && (st.st_mode & 0111)) return file;
148
}
149
free( file );
150
return NULL;
151
}
152
153
void spawn( struct strarray args )
154
{
155
int status;
156
const char *argv0 = find_binary( NULL, args.str[0] );
157
158
if (argv0) args.str[0] = argv0;
159
if (verbose) strarray_trace( args );
160
161
if ((status = strarray_spawn( args )))
162
{
163
if (status > 0) fatal_error( "%s failed with status %u\n", args.str[0], status );
164
else fatal_perror( "winebuild" );
165
exit( 1 );
166
}
167
}
168
169
static const char *find_clang_tool( struct strarray clang, const char *tool )
170
{
171
const char *out = make_temp_file( "print_tool", ".out" );
172
struct strarray args = empty_strarray;
173
int sout = -1;
174
char *path, *p;
175
struct stat st;
176
size_t cnt;
177
178
strarray_addall( &args, clang );
179
if (!args.count) strarray_add( &args, "clang" );
180
strarray_add( &args, strmake( "-print-prog-name=%s", tool ));
181
if (verbose) strarray_add( &args, "-v" );
182
183
sout = dup( fileno(stdout) );
184
freopen( out, "w", stdout );
185
spawn( args );
186
if (sout >= 0)
187
{
188
dup2( sout, fileno(stdout) );
189
close( sout );
190
}
191
192
if (stat(out, &st) || !st.st_size) return NULL;
193
194
path = xmalloc(st.st_size + 1);
195
sout = open(out, O_RDONLY);
196
if (sout == -1) return NULL;
197
cnt = read(sout, path, st.st_size);
198
close(sout);
199
path[cnt] = 0;
200
if ((p = strchr(path, '\n'))) *p = 0;
201
/* clang returns passed command instead of full path if the tool could not be found */
202
if (!strcmp(path, tool))
203
{
204
free( path );
205
return NULL;
206
}
207
return path;
208
}
209
210
/* find a build tool in the path, trying the various names */
211
struct strarray find_tool( const char *name, const char * const *names )
212
{
213
struct strarray ret = empty_strarray;
214
const char *file;
215
const char *alt_names[2];
216
217
if (!names)
218
{
219
alt_names[0] = name;
220
alt_names[1] = NULL;
221
names = alt_names;
222
}
223
224
while (*names)
225
{
226
if ((file = find_binary( target_alias, *names ))) break;
227
names++;
228
}
229
230
if (!file && cc_command.count) file = find_clang_tool( cc_command, name );
231
if (!file) file = find_binary( "llvm", name );
232
if (!file) file = find_clang_tool( empty_strarray, strmake( "llvm-%s", name ));
233
if (!file) file = find_clang_tool( empty_strarray, name );
234
235
if (!file) fatal_error( "cannot find the '%s' tool\n", name );
236
237
strarray_add( &ret, file );
238
return ret;
239
}
240
241
/* find a link tool in the path */
242
struct strarray find_link_tool(void)
243
{
244
struct strarray ret = empty_strarray;
245
const char *file = NULL;
246
247
if (cc_command.count) file = find_clang_tool( cc_command, "lld-link" );
248
if (!file) file = find_binary( NULL, "lld-link" );
249
if (!file) file = find_clang_tool( empty_strarray, "lld-link" );
250
251
if (!file) fatal_error( "cannot find the 'lld-link' tool\n" );
252
strarray_add( &ret, file );
253
return ret;
254
}
255
256
struct strarray get_as_command(void)
257
{
258
struct strarray args = empty_strarray;
259
const char *file;
260
int using_cc = 0;
261
262
if (cc_command.count)
263
{
264
strarray_addall( &args, cc_command );
265
using_cc = 1;
266
}
267
else if (as_command.count)
268
{
269
strarray_addall( &args, as_command );
270
}
271
else if ((file = find_binary( target_alias, "as" )) || (file = find_binary( target_alias, "gas ")))
272
{
273
strarray_add( &args, file );
274
}
275
else if ((file = find_binary( NULL, "clang" )))
276
{
277
strarray_add( &args, file );
278
if (target_alias)
279
{
280
strarray_add( &args, "-target" );
281
strarray_add( &args, target_alias );
282
}
283
using_cc = 1;
284
}
285
286
if (using_cc)
287
{
288
strarray_add( &args, "-xassembler" );
289
strarray_add( &args, "-c" );
290
if (force_pointer_size)
291
strarray_add( &args, (force_pointer_size == 8) ? "-m64" : "-m32" );
292
if (cpu_option) strarray_add( &args, strmake("-mcpu=%s", cpu_option) );
293
if (fpu_option) strarray_add( &args, strmake("-mfpu=%s", fpu_option) );
294
if (arch_option) strarray_add( &args, strmake("-march=%s", arch_option) );
295
STRARRAY_FOR_EACH( path, &tools_path ) strarray_add( &args, strmake("-B%s", path ));
296
return args;
297
}
298
299
if (force_pointer_size)
300
{
301
switch (target.platform)
302
{
303
case PLATFORM_APPLE:
304
strarray_add( &args, "-arch" );
305
strarray_add( &args, (force_pointer_size == 8) ? "x86_64" : "i386" );
306
break;
307
default:
308
strarray_add( &args, (force_pointer_size == 8) ? "--64" : "--32" );
309
break;
310
}
311
}
312
313
if (cpu_option) strarray_add( &args, strmake("-mcpu=%s", cpu_option) );
314
if (fpu_option) strarray_add( &args, strmake("-mfpu=%s", fpu_option) );
315
return args;
316
}
317
318
struct strarray get_ld_command(void)
319
{
320
struct strarray args = empty_strarray;
321
322
if (!ld_command.count)
323
{
324
static const char * const commands[] = { "ld", "gld", NULL };
325
ld_command = find_tool( "ld", commands );
326
}
327
328
strarray_addall( &args, ld_command );
329
330
if (force_pointer_size)
331
{
332
switch (target.platform)
333
{
334
case PLATFORM_APPLE:
335
strarray_add( &args, "-arch" );
336
strarray_add( &args, (force_pointer_size == 8) ? "x86_64" : "i386" );
337
break;
338
case PLATFORM_FREEBSD:
339
strarray_add( &args, "-m" );
340
strarray_add( &args, (force_pointer_size == 8) ? "elf_x86_64_fbsd" : "elf_i386_fbsd" );
341
break;
342
case PLATFORM_MINGW:
343
case PLATFORM_WINDOWS:
344
strarray_add( &args, "-m" );
345
strarray_add( &args, (force_pointer_size == 8) ? "i386pep" : "i386pe" );
346
break;
347
default:
348
strarray_add( &args, "-m" );
349
strarray_add( &args, (force_pointer_size == 8) ? "elf_x86_64" : "elf_i386" );
350
break;
351
}
352
}
353
return args;
354
}
355
356
const char *get_nm_command(void)
357
{
358
if (!nm_command.count)
359
{
360
static const char * const commands[] = { "nm", "gnm", NULL };
361
nm_command = find_tool( "nm", commands );
362
}
363
if (nm_command.count > 1)
364
fatal_error( "multiple arguments in nm command not supported yet\n" );
365
return nm_command.str[0];
366
}
367
368
369
/*******************************************************************
370
* buffer management
371
*
372
* Function for reading from/writing to a memory buffer.
373
*/
374
375
int byte_swapped = 0;
376
const char *input_buffer_filename;
377
const unsigned char *input_buffer;
378
size_t input_buffer_pos;
379
size_t input_buffer_size;
380
unsigned char *output_buffer;
381
size_t output_buffer_pos;
382
size_t output_buffer_size;
383
384
void init_input_buffer( const char *file )
385
{
386
if (!(input_buffer = read_file( file, &input_buffer_size ))) fatal_perror( "Cannot read %s", file );
387
if (!input_buffer_size) fatal_error( "%s is an empty file\n", file );
388
input_buffer_filename = xstrdup( file );
389
input_buffer_pos = 0;
390
byte_swapped = 0;
391
}
392
393
unsigned char get_byte(void)
394
{
395
if (input_buffer_pos >= input_buffer_size)
396
fatal_error( "%s is a truncated file\n", input_buffer_filename );
397
return input_buffer[input_buffer_pos++];
398
}
399
400
unsigned short get_word(void)
401
{
402
unsigned short ret;
403
404
if (input_buffer_pos + sizeof(ret) > input_buffer_size)
405
fatal_error( "%s is a truncated file\n", input_buffer_filename );
406
memcpy( &ret, input_buffer + input_buffer_pos, sizeof(ret) );
407
if (byte_swapped) ret = (ret << 8) | (ret >> 8);
408
input_buffer_pos += sizeof(ret);
409
return ret;
410
}
411
412
unsigned int get_dword(void)
413
{
414
unsigned int ret;
415
416
if (input_buffer_pos + sizeof(ret) > input_buffer_size)
417
fatal_error( "%s is a truncated file\n", input_buffer_filename );
418
memcpy( &ret, input_buffer + input_buffer_pos, sizeof(ret) );
419
if (byte_swapped)
420
ret = ((ret << 24) | ((ret << 8) & 0x00ff0000) | ((ret >> 8) & 0x0000ff00) | (ret >> 24));
421
input_buffer_pos += sizeof(ret);
422
return ret;
423
}
424
425
/* pointer-sized word */
426
void put_pword( unsigned int val )
427
{
428
if (get_ptr_size() == 8) put_qword( val );
429
else put_dword( val );
430
}
431
432
/* output a standard header for generated files */
433
void output_standard_file_header(void)
434
{
435
if (spec_file_name)
436
output( "/* File generated automatically from %s; do not edit! */\n", spec_file_name );
437
else
438
output( "/* File generated automatically; do not edit! */\n" );
439
output( "/* This file can be copied, modified and distributed without restriction. */\n\n" );
440
if (safe_seh)
441
{
442
output( "\t.def @feat.00\n\t.scl 3\n\t.type 0\n\t.endef\n" );
443
output( "\t.globl @feat.00\n" );
444
output( ".set @feat.00, 1\n" );
445
}
446
}
447
448
/* dump a byte stream into the assembly code */
449
void dump_bytes( const void *buffer, unsigned int size )
450
{
451
unsigned int i;
452
const unsigned char *ptr = buffer;
453
454
if (!size) return;
455
output( "\t.byte " );
456
for (i = 0; i < size - 1; i++, ptr++)
457
{
458
if ((i % 16) == 15) output( "0x%02x\n\t.byte ", *ptr );
459
else output( "0x%02x,", *ptr );
460
}
461
output( "0x%02x\n", *ptr );
462
}
463
464
465
/*******************************************************************
466
* open_input_file
467
*
468
* Open a file in the given srcdir and set the input_file_name global variable.
469
*/
470
FILE *open_input_file( const char *srcdir, const char *name )
471
{
472
char *fullname;
473
FILE *file = fopen( name, "r" );
474
475
if (!file && srcdir)
476
{
477
fullname = strmake( "%s/%s", srcdir, name );
478
file = fopen( fullname, "r" );
479
}
480
else fullname = xstrdup( name );
481
482
if (!file) fatal_error( "Cannot open file '%s'\n", fullname );
483
input_file_name = fullname;
484
current_line = 1;
485
return file;
486
}
487
488
489
/*******************************************************************
490
* close_input_file
491
*
492
* Close the current input file (must have been opened with open_input_file).
493
*/
494
void close_input_file( FILE *file )
495
{
496
fclose( file );
497
free( input_file_name );
498
input_file_name = NULL;
499
current_line = 0;
500
}
501
502
503
/*******************************************************************
504
* open_output_file
505
*/
506
void open_output_file(void)
507
{
508
if (output_file_name)
509
{
510
if (strendswith( output_file_name, ".o" ))
511
output_file_source_name = open_temp_output_file( ".s" );
512
else
513
if (!(output_file = fopen( output_file_name, "w" )))
514
fatal_error( "Unable to create output file '%s'\n", output_file_name );
515
}
516
else output_file = stdout;
517
}
518
519
520
/*******************************************************************
521
* close_output_file
522
*/
523
void close_output_file(void)
524
{
525
if (!output_file || !output_file_name) return;
526
if (fclose( output_file ) < 0) fatal_perror( "fclose" );
527
if (output_file_source_name) assemble_file( output_file_source_name, output_file_name );
528
output_file = NULL;
529
}
530
531
532
/*******************************************************************
533
* open_temp_output_file
534
*/
535
char *open_temp_output_file( const char *suffix )
536
{
537
char *tmp_file = make_temp_file( output_file_name, suffix );
538
if (!(output_file = fopen( tmp_file, "w" )))
539
fatal_error( "Unable to create output file '%s'\n", tmp_file );
540
return tmp_file;
541
}
542
543
544
/*******************************************************************
545
* remove_stdcall_decoration
546
*
547
* Remove a possible @xx suffix from a function name.
548
* Return the numerical value of the suffix, or -1 if none.
549
*/
550
int remove_stdcall_decoration( char *name )
551
{
552
char *p, *end = strrchr( name, '@' );
553
if (!end || !end[1] || end == name) return -1;
554
if (target.cpu != CPU_i386) return -1;
555
/* make sure all the rest is digits */
556
for (p = end + 1; *p; p++) if (!isdigit(*p)) return -1;
557
*end = 0;
558
return atoi( end + 1 );
559
}
560
561
562
/*******************************************************************
563
* assemble_file
564
*
565
* Run a file through the assembler.
566
*/
567
void assemble_file( const char *src_file, const char *obj_file )
568
{
569
struct strarray args = get_as_command();
570
strarray_add( &args, "-o" );
571
strarray_add( &args, obj_file );
572
strarray_add( &args, src_file );
573
spawn( args );
574
}
575
576
577
/*******************************************************************
578
* alloc_dll_spec
579
*
580
* Create a new dll spec file descriptor
581
*/
582
DLLSPEC *alloc_dll_spec(void)
583
{
584
DLLSPEC *spec;
585
586
spec = xmalloc( sizeof(*spec) );
587
memset( spec, 0, sizeof(*spec) );
588
spec->type = SPEC_WIN32;
589
spec->characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
590
spec->subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
591
spec->subsystem_major = 4;
592
spec->subsystem_minor = 0;
593
spec->dll_characteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
594
spec->exports.base = MAX_ORDINALS;
595
spec->native_exports.base = MAX_ORDINALS;
596
return spec;
597
}
598
599
600
/*******************************************************************
601
* make_c_identifier
602
*
603
* Map a string to a valid C identifier.
604
*/
605
char *make_c_identifier( const char *str )
606
{
607
char *p, buffer[256];
608
609
for (p = buffer; *str && p < buffer+sizeof(buffer)-1; p++, str++)
610
{
611
if (isalnum(*str)) *p = *str;
612
else *p = '_';
613
}
614
*p = 0;
615
return xstrdup( buffer );
616
}
617
618
619
/*******************************************************************
620
* get_stub_name
621
*
622
* Generate an internal name for a stub entry point.
623
*/
624
static const char *get_stub_name( const ORDDEF *odp )
625
{
626
if (odp->name || odp->export_name)
627
{
628
char *p, *buffer = strmake( "__wine_stub_%s", odp->name ? odp->name : odp->export_name );
629
/* make sure name is a legal C identifier */
630
for (p = buffer; *p; p++) if (!isalnum(*p) && *p != '_') break;
631
if (!*p) return buffer;
632
}
633
return strmake( "__wine_stub_%d", odp->ordinal );
634
}
635
636
/* return the stdcall-decorated name for an entry point */
637
const char *get_abi_name( const ORDDEF *odp, const char *name )
638
{
639
if (target.cpu != CPU_i386) return name;
640
641
switch (odp->type)
642
{
643
case TYPE_STUB:
644
case TYPE_STDCALL:
645
if (is_pe())
646
{
647
if (odp->flags & FLAG_THISCALL) return name;
648
if (odp->flags & FLAG_FASTCALL) return strmake( "@%s@%u", name, get_args_size( odp ));
649
if (!kill_at) return strmake( "%s@%u", name, get_args_size( odp ));
650
}
651
else
652
{
653
if (odp->flags & FLAG_THISCALL) return strmake( "__thiscall_%s", name );
654
if (odp->flags & FLAG_FASTCALL) return strmake( "__fastcall_%s", name );
655
}
656
break;
657
658
case TYPE_PASCAL:
659
if (is_pe() && !kill_at)
660
{
661
int args = get_args_size( odp );
662
if (odp->flags & FLAG_REGISTER) args += get_ptr_size(); /* context argument */
663
return strmake( "%s@%u", name, args );
664
}
665
break;
666
667
default:
668
break;
669
}
670
return name;
671
}
672
673
const char *get_link_name( const ORDDEF *odp )
674
{
675
if (odp->type == TYPE_STUB && !(odp->flags & FLAG_SYSCALL)) return get_stub_name( odp );
676
677
return get_abi_name( odp, odp->link_name );
678
}
679
680
/*******************************************************************
681
* sort_func_list
682
*
683
* Sort a list of functions, removing duplicates.
684
*/
685
int sort_func_list( ORDDEF **list, int count, int (*compare)(const void *, const void *) )
686
{
687
int i, j;
688
689
if (!count) return 0;
690
qsort( list, count, sizeof(*list), compare );
691
for (i = j = 0; i < count; i++) if (compare( &list[j], &list[i] )) list[++j] = list[i];
692
return j + 1;
693
}
694
695
696
/* return the section alignment for the target CPU */
697
unsigned int get_section_alignment(void)
698
{
699
switch (target.cpu)
700
{
701
case CPU_ARM64:
702
case CPU_ARM64EC:
703
return 0x10000;
704
default:
705
return 0x1000;
706
}
707
}
708
709
/* return the total size in bytes of the arguments on the stack */
710
unsigned int get_args_size( const ORDDEF *odp )
711
{
712
int i, size;
713
714
for (i = size = 0; i < odp->u.func.nb_args; i++)
715
{
716
switch (odp->u.func.args[i])
717
{
718
case ARG_INT64:
719
case ARG_DOUBLE:
720
if (target.cpu == CPU_ARM) size = (size + 7) & ~7;
721
size += 8;
722
break;
723
case ARG_INT128:
724
/* int128 is passed as pointer on x86_64 */
725
if (target.cpu != CPU_x86_64)
726
{
727
size += 16;
728
break;
729
}
730
/* fall through */
731
default:
732
size += get_ptr_size();
733
break;
734
}
735
}
736
return size;
737
}
738
739
/* return the assembly name for a C symbol */
740
const char *asm_name( const char *sym )
741
{
742
switch (target.platform)
743
{
744
case PLATFORM_MINGW:
745
case PLATFORM_WINDOWS:
746
if (target.cpu != CPU_i386) return sym;
747
if (sym[0] == '@') return sym; /* fastcall */
748
/* fall through */
749
case PLATFORM_APPLE:
750
if (sym[0] == '.' && sym[1] == 'L') return sym;
751
return strmake( "_%s", sym );
752
default:
753
return sym;
754
}
755
}
756
757
/* return the assembly name for an ARM64/ARM64EC function */
758
const char *arm64_name( const char *sym )
759
{
760
if (target.cpu == CPU_ARM64EC) return strmake( "\"#%s\"", sym );
761
return asm_name( sym );
762
}
763
764
/* return an assembly function declaration for a C function name */
765
void output_function_header( const char *func, int global )
766
{
767
const char *name = arm64_name( func );
768
769
output( "\t.text\n" );
770
771
switch (target.platform)
772
{
773
case PLATFORM_APPLE:
774
if (global) output( "\t.globl %s\n\t.private_extern %s\n", name, name );
775
break;
776
case PLATFORM_MINGW:
777
case PLATFORM_WINDOWS:
778
if (target.cpu == CPU_ARM64EC) output( ".section .text,\"xr\",discard,%s\n\t", name );
779
output( "\t.def %s\n\t.scl 2\n\t.type 32\n\t.endef\n", name );
780
if (global) output( "\t.globl %s\n", name );
781
break;
782
default:
783
output( "\t.type %s,@function\n", name );
784
if (global) output( "\t.globl %s\n\t.hidden %s\n", name, name );
785
break;
786
}
787
output( "\t.balign 4\n" );
788
output( "%s:\n", name );
789
}
790
791
/* output a size declaration for an assembly function */
792
void output_function_size( const char *name )
793
{
794
switch (target.platform)
795
{
796
case PLATFORM_APPLE:
797
case PLATFORM_MINGW:
798
case PLATFORM_WINDOWS:
799
break;
800
default:
801
output( "\t.size %s, .-%s\n", name, name );
802
break;
803
}
804
}
805
806
/* output a .cfi directive */
807
void output_cfi( const char *format, ... )
808
{
809
va_list valist;
810
811
if (!unwind_tables) return;
812
va_start( valist, format );
813
fputc( '\t', output_file );
814
vfprintf( output_file, format, valist );
815
fputc( '\n', output_file );
816
va_end( valist );
817
}
818
819
/* output a .seh directive */
820
void output_seh( const char *format, ... )
821
{
822
va_list valist;
823
824
if (!is_pe()) return;
825
va_start( valist, format );
826
fputc( '\t', output_file );
827
vfprintf( output_file, format, valist );
828
fputc( '\n', output_file );
829
va_end( valist );
830
}
831
832
/* output an RVA pointer */
833
void output_rva( const char *format, ... )
834
{
835
va_list valist;
836
837
va_start( valist, format );
838
if (is_pe())
839
{
840
output( "\t.rva " );
841
vfprintf( output_file, format, valist );
842
fputc( '\n', output_file );
843
}
844
else
845
{
846
output( "\t.long " );
847
vfprintf( output_file, format, valist );
848
output( " - .L__wine_spec_rva_base\n" );
849
}
850
va_end( valist );
851
}
852
853
/* output an RVA pointer or ordinal for a function thunk */
854
void output_thunk_rva( int ordinal, const char *format, ... )
855
{
856
if (ordinal == -1)
857
{
858
va_list valist;
859
860
va_start( valist, format );
861
if (is_pe())
862
{
863
output( "\t.rva " );
864
vfprintf( output_file, format, valist );
865
fputc( '\n', output_file );
866
if (get_ptr_size() == 8) output( "\t.long 0\n" );
867
}
868
else
869
{
870
output( "\t%s ", get_asm_ptr_keyword() );
871
vfprintf( output_file, format, valist );
872
output( " - .L__wine_spec_rva_base\n" );
873
}
874
va_end( valist );
875
}
876
else
877
{
878
if (get_ptr_size() == 4) output( "\t.long 0x8000%04x\n", ordinal );
879
else output( "\t.quad 0x800000000000%04x\n", ordinal );
880
}
881
}
882
883
/* output the GNU note for non-exec stack */
884
void output_gnu_stack_note(void)
885
{
886
switch (target.platform)
887
{
888
case PLATFORM_MINGW:
889
case PLATFORM_WINDOWS:
890
case PLATFORM_APPLE:
891
break;
892
default:
893
output( "\t.section .note.GNU-stack,\"\",@progbits\n" );
894
break;
895
}
896
}
897
898
/* return a global symbol declaration for an assembly symbol */
899
const char *asm_globl( const char *func )
900
{
901
switch (target.platform)
902
{
903
case PLATFORM_APPLE:
904
return strmake( "\t.globl _%s\n\t.private_extern _%s\n_%s:", func, func, func );
905
case PLATFORM_MINGW:
906
case PLATFORM_WINDOWS:
907
{
908
const char *name = asm_name( func );
909
return strmake( "\t.globl %s\n%s:", name, name );
910
}
911
default:
912
return strmake( "\t.globl %s\n\t.hidden %s\n%s:", func, func, func );
913
}
914
}
915
916
const char *get_asm_ptr_keyword(void)
917
{
918
switch(get_ptr_size())
919
{
920
case 4: return ".long";
921
case 8: return ".quad";
922
}
923
assert(0);
924
return NULL;
925
}
926
927
const char *get_asm_string_keyword(void)
928
{
929
switch (target.platform)
930
{
931
case PLATFORM_APPLE:
932
return ".asciz";
933
default:
934
return ".string";
935
}
936
}
937
938
const char *get_asm_export_section(void)
939
{
940
switch (target.platform)
941
{
942
case PLATFORM_APPLE: return ".data";
943
case PLATFORM_MINGW:
944
case PLATFORM_WINDOWS: return ".section .edata";
945
default: return ".section .data";
946
}
947
}
948
949
const char *get_asm_rodata_section(void)
950
{
951
switch (target.platform)
952
{
953
case PLATFORM_APPLE: return ".const";
954
case PLATFORM_MINGW:
955
case PLATFORM_WINDOWS: return ".section .rdata";
956
default: return ".section .rodata";
957
}
958
}
959
960
const char *get_asm_rsrc_section(void)
961
{
962
switch (target.platform)
963
{
964
case PLATFORM_APPLE: return ".data";
965
case PLATFORM_MINGW:
966
case PLATFORM_WINDOWS: return ".section .rsrc";
967
default: return ".section .data";
968
}
969
}
970
971
const char *get_asm_string_section(void)
972
{
973
switch (target.platform)
974
{
975
case PLATFORM_APPLE: return ".cstring";
976
case PLATFORM_MINGW:
977
case PLATFORM_WINDOWS: return ".section .rdata";
978
default: return ".section .rodata";
979
}
980
}
981
982