tools: Add a shared header for common helper functions.
[wine.git] / tools / winebuild / utils.c
blobf646831290273cfd8bd7246774c7449a3329c010
1 /*
2 * Small utility functions for winebuild
4 * Copyright 2000 Alexandre Julliard
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
35 #endif
37 #include "build.h"
39 static struct strarray tmp_files;
40 static const char *output_file_source_name;
42 static const struct
44 const char *name;
45 enum target_cpu cpu;
46 } cpu_names[] =
48 { "i386", CPU_x86 },
49 { "i486", CPU_x86 },
50 { "i586", CPU_x86 },
51 { "i686", CPU_x86 },
52 { "i786", CPU_x86 },
53 { "amd64", CPU_x86_64 },
54 { "x86_64", CPU_x86_64 },
55 { "powerpc", CPU_POWERPC },
56 { "arm", CPU_ARM },
57 { "armv5", CPU_ARM },
58 { "armv6", CPU_ARM },
59 { "armv7", CPU_ARM },
60 { "armv7a", CPU_ARM },
61 { "arm64", CPU_ARM64 },
62 { "aarch64", CPU_ARM64 },
65 /* atexit handler to clean tmp files */
66 void cleanup_tmp_files(void)
68 unsigned int i;
69 for (i = 0; i < tmp_files.count; i++) if (tmp_files.str[i]) unlink( tmp_files.str[i] );
73 char *strupper(char *s)
75 char *p;
76 for (p = s; *p; p++) *p = toupper(*p);
77 return s;
80 void fatal_error( const char *msg, ... )
82 va_list valist;
83 va_start( valist, msg );
84 if (input_file_name)
86 fprintf( stderr, "%s:", input_file_name );
87 if (current_line)
88 fprintf( stderr, "%d:", current_line );
89 fputc( ' ', stderr );
91 else fprintf( stderr, "winebuild: " );
92 vfprintf( stderr, msg, valist );
93 va_end( valist );
94 exit(1);
97 void fatal_perror( const char *msg, ... )
99 va_list valist;
100 va_start( valist, msg );
101 if (input_file_name)
103 fprintf( stderr, "%s:", input_file_name );
104 if (current_line)
105 fprintf( stderr, "%d:", current_line );
106 fputc( ' ', stderr );
108 vfprintf( stderr, msg, valist );
109 perror( " " );
110 va_end( valist );
111 exit(1);
114 void error( const char *msg, ... )
116 va_list valist;
117 va_start( valist, msg );
118 if (input_file_name)
120 fprintf( stderr, "%s:", input_file_name );
121 if (current_line)
122 fprintf( stderr, "%d:", current_line );
123 fputc( ' ', stderr );
125 vfprintf( stderr, msg, valist );
126 va_end( valist );
127 nb_errors++;
130 void warning( const char *msg, ... )
132 va_list valist;
134 if (!display_warnings) return;
135 va_start( valist, msg );
136 if (input_file_name)
138 fprintf( stderr, "%s:", input_file_name );
139 if (current_line)
140 fprintf( stderr, "%d:", current_line );
141 fputc( ' ', stderr );
143 fprintf( stderr, "warning: " );
144 vfprintf( stderr, msg, valist );
145 va_end( valist );
148 int output( const char *format, ... )
150 int ret;
151 va_list valist;
153 va_start( valist, format );
154 ret = vfprintf( output_file, format, valist );
155 va_end( valist );
156 if (ret < 0) fatal_perror( "Output error" );
157 return ret;
160 static struct strarray get_tools_path(void)
162 static int done;
163 static struct strarray dirs;
165 if (!done)
167 strarray_addall( &dirs, tools_path );
168 strarray_addall( &dirs, strarray_frompath( getenv( "PATH" )));
169 done = 1;
171 return dirs;
174 /* find a binary in the path */
175 static const char *find_binary( const char *prefix, const char *name )
177 struct strarray dirs = get_tools_path();
178 unsigned int i, maxlen = 0;
179 struct stat st;
180 char *p, *file;
182 if (strchr( name, '/' )) return name;
183 if (!prefix) prefix = "";
184 for (i = 0; i < dirs.count; i++) maxlen = max( maxlen, strlen(dirs.str[i]) + 2 );
185 file = xmalloc( maxlen + strlen(prefix) + strlen(name) + sizeof(EXEEXT) + 1 );
187 for (i = 0; i < dirs.count; i++)
189 strcpy( file, dirs.str[i] );
190 p = file + strlen(file);
191 if (p == file) *p++ = '.';
192 if (p[-1] != '/') *p++ = '/';
193 if (*prefix)
195 strcpy( p, prefix );
196 p += strlen(p);
197 *p++ = '-';
199 strcpy( p, name );
200 strcat( p, EXEEXT );
201 if (!stat( file, &st ) && S_ISREG(st.st_mode) && (st.st_mode & 0111)) return file;
203 free( file );
204 return NULL;
207 void spawn( struct strarray args )
209 unsigned int i;
210 int status;
211 const char *argv0 = find_binary( NULL, args.str[0] );
213 if (argv0) args.str[0] = argv0;
214 strarray_add( &args, NULL );
215 if (verbose)
216 for (i = 0; args.str[i]; i++)
217 fprintf( stderr, "%s%c", args.str[i], args.str[i+1] ? ' ' : '\n' );
219 if ((status = _spawnvp( _P_WAIT, args.str[0], args.str )))
221 if (status > 0) fatal_error( "%s failed with status %u\n", args.str[0], status );
222 else fatal_perror( "winebuild" );
223 exit( 1 );
227 static const char *find_clang_tool( struct strarray clang, const char *tool )
229 const char *out = get_temp_file_name( "print_tool", ".out" );
230 struct strarray args = empty_strarray;
231 int sout = -1;
232 char *path, *p;
233 struct stat st;
234 size_t cnt;
236 strarray_addall( &args, clang );
237 strarray_add( &args, strmake( "-print-prog-name=%s", tool ));
238 if (verbose) strarray_add( &args, "-v" );
240 sout = dup( fileno(stdout) );
241 freopen( out, "w", stdout );
242 spawn( args );
243 if (sout >= 0)
245 dup2( sout, fileno(stdout) );
246 close( sout );
249 if (stat(out, &st) || !st.st_size) return NULL;
251 path = xmalloc(st.st_size + 1);
252 sout = open(out, O_RDONLY);
253 if (sout == -1) return NULL;
254 cnt = read(sout, path, st.st_size);
255 close(sout);
256 path[cnt] = 0;
257 if ((p = strchr(path, '\n'))) *p = 0;
258 /* clang returns passed command instead of full path if the tool could not be found */
259 if (!strcmp(path, tool))
261 free( path );
262 return NULL;
264 return path;
267 /* find a build tool in the path, trying the various names */
268 struct strarray find_tool( const char *name, const char * const *names )
270 struct strarray ret = empty_strarray;
271 const char *file;
272 const char *alt_names[2];
274 if (!names)
276 alt_names[0] = name;
277 alt_names[1] = NULL;
278 names = alt_names;
281 while (*names)
283 if ((file = find_binary( target_alias, *names ))) break;
284 names++;
287 if (!file && names == alt_names + 1)
289 if (cc_command.count) file = find_clang_tool( cc_command, "lld-link" );
290 if (!file && !(file = find_binary( "llvm", name )))
292 struct strarray clang = empty_strarray;
293 strarray_add( &clang, "clang" );
294 file = find_clang_tool( clang, strmake( "llvm-%s", name ));
297 if (!file) fatal_error( "cannot find the '%s' tool\n", name );
299 strarray_add( &ret, file );
300 return ret;
303 /* find a link tool in the path */
304 struct strarray find_link_tool(void)
306 struct strarray ret = empty_strarray;
307 const char *file = NULL;
309 if (cc_command.count) file = find_clang_tool( cc_command, "lld-link" );
310 if (!file) file = find_binary( NULL, "lld-link" );
311 if (!file)
313 struct strarray clang = empty_strarray;
314 strarray_add( &clang, "clang" );
315 file = find_clang_tool( clang, "lld-link" );
318 if (!file) fatal_error( "cannot find the 'lld-link' tool\n" );
319 strarray_add( &ret, file );
320 return ret;
323 struct strarray get_as_command(void)
325 struct strarray args = empty_strarray;
326 unsigned int i;
328 if (cc_command.count)
330 strarray_addall( &args, cc_command );
331 strarray_add( &args, "-xassembler" );
332 strarray_add( &args, "-c" );
333 if (force_pointer_size)
334 strarray_add( &args, (force_pointer_size == 8) ? "-m64" : "-m32" );
335 if (cpu_option) strarray_add( &args, strmake("-mcpu=%s", cpu_option) );
336 if (fpu_option) strarray_add( &args, strmake("-mfpu=%s", fpu_option) );
337 if (arch_option) strarray_add( &args, strmake("-march=%s", arch_option) );
338 for (i = 0; i < tools_path.count; i++)
339 strarray_add( &args, strmake("-B%s", tools_path.str[i] ));
340 return args;
343 if (!as_command.count)
345 static const char * const commands[] = { "gas", "as", NULL };
346 as_command = find_tool( "as", commands );
349 strarray_addall( &args, as_command );
351 if (force_pointer_size)
353 switch (target_platform)
355 case PLATFORM_APPLE:
356 strarray_add( &args, "-arch" );
357 strarray_add( &args, (force_pointer_size == 8) ? "x86_64" : "i386" );
358 break;
359 default:
360 switch(target_cpu)
362 case CPU_POWERPC:
363 strarray_add( &args, (force_pointer_size == 8) ? "-a64" : "-a32" );
364 break;
365 default:
366 strarray_add( &args, (force_pointer_size == 8) ? "--64" : "--32" );
367 break;
369 break;
373 if (cpu_option) strarray_add( &args, strmake("-mcpu=%s", cpu_option) );
374 if (fpu_option) strarray_add( &args, strmake("-mfpu=%s", fpu_option) );
375 return args;
378 struct strarray get_ld_command(void)
380 struct strarray args = empty_strarray;
382 if (!ld_command.count)
384 static const char * const commands[] = { "ld", "gld", NULL };
385 ld_command = find_tool( "ld", commands );
388 strarray_addall( &args, ld_command );
390 if (force_pointer_size)
392 switch (target_platform)
394 case PLATFORM_APPLE:
395 strarray_add( &args, "-arch" );
396 strarray_add( &args, (force_pointer_size == 8) ? "x86_64" : "i386" );
397 break;
398 case PLATFORM_FREEBSD:
399 strarray_add( &args, "-m" );
400 strarray_add( &args, (force_pointer_size == 8) ? "elf_x86_64_fbsd" : "elf_i386_fbsd" );
401 break;
402 case PLATFORM_MINGW:
403 case PLATFORM_WINDOWS:
404 strarray_add( &args, "-m" );
405 strarray_add( &args, (force_pointer_size == 8) ? "i386pep" : "i386pe" );
406 break;
407 default:
408 switch(target_cpu)
410 case CPU_POWERPC:
411 strarray_add( &args, "-m" );
412 strarray_add( &args, (force_pointer_size == 8) ? "elf64ppc" : "elf32ppc" );
413 break;
414 default:
415 strarray_add( &args, "-m" );
416 strarray_add( &args, (force_pointer_size == 8) ? "elf_x86_64" : "elf_i386" );
417 break;
419 break;
423 if (target_cpu == CPU_ARM && !is_pe())
424 strarray_add( &args, "--no-wchar-size-warning" );
426 return args;
429 const char *get_nm_command(void)
431 if (!nm_command.count)
433 static const char * const commands[] = { "nm", "gnm", NULL };
434 nm_command = find_tool( "nm", commands );
436 if (nm_command.count > 1)
437 fatal_error( "multiple arguments in nm command not supported yet\n" );
438 return nm_command.str[0];
441 /* get a name for a temp file, automatically cleaned up on exit */
442 char *get_temp_file_name( const char *prefix, const char *suffix )
444 char *name;
445 const char *ext, *basename;
446 int fd;
448 if (!prefix || !prefix[0]) prefix = "winebuild";
449 if (!suffix) suffix = "";
450 if ((basename = strrchr( prefix, '/' ))) basename++;
451 else basename = prefix;
452 if (!(ext = strchr( basename, '.' ))) ext = prefix + strlen(prefix);
453 name = xmalloc( sizeof("/tmp/") + (ext - prefix) + sizeof(".XXXXXX") + strlen(suffix) );
454 memcpy( name, prefix, ext - prefix );
455 strcpy( name + (ext - prefix), ".XXXXXX" );
456 strcat( name, suffix );
458 if ((fd = mkstemps( name, strlen(suffix) )) == -1)
460 strcpy( name, "/tmp/" );
461 memcpy( name + 5, basename, ext - basename );
462 strcpy( name + 5 + (ext - basename), ".XXXXXX" );
463 strcat( name, suffix );
464 if ((fd = mkstemps( name, strlen(suffix) )) == -1)
465 fatal_error( "could not generate a temp file\n" );
468 close( fd );
469 strarray_add( &tmp_files, name );
470 return name;
473 /*******************************************************************
474 * buffer management
476 * Function for reading from/writing to a memory buffer.
479 int byte_swapped = 0;
480 const char *input_buffer_filename;
481 const unsigned char *input_buffer;
482 size_t input_buffer_pos;
483 size_t input_buffer_size;
484 unsigned char *output_buffer;
485 size_t output_buffer_pos;
486 size_t output_buffer_size;
488 static void check_output_buffer_space( size_t size )
490 if (output_buffer_pos + size >= output_buffer_size)
492 output_buffer_size = max( output_buffer_size * 2, output_buffer_pos + size );
493 output_buffer = xrealloc( output_buffer, output_buffer_size );
497 void init_input_buffer( const char *file )
499 int fd;
500 struct stat st;
501 unsigned char *buffer;
503 if ((fd = open( file, O_RDONLY | O_BINARY )) == -1) fatal_perror( "Cannot open %s", file );
504 if ((fstat( fd, &st ) == -1)) fatal_perror( "Cannot stat %s", file );
505 if (!st.st_size) fatal_error( "%s is an empty file\n", file );
506 input_buffer = buffer = xmalloc( st.st_size );
507 if (read( fd, buffer, st.st_size ) != st.st_size) fatal_error( "Cannot read %s\n", file );
508 close( fd );
509 input_buffer_filename = xstrdup( file );
510 input_buffer_size = st.st_size;
511 input_buffer_pos = 0;
512 byte_swapped = 0;
515 void init_output_buffer(void)
517 output_buffer_size = 1024;
518 output_buffer_pos = 0;
519 output_buffer = xmalloc( output_buffer_size );
522 void flush_output_buffer(void)
524 open_output_file();
525 if (fwrite( output_buffer, 1, output_buffer_pos, output_file ) != output_buffer_pos)
526 fatal_error( "Error writing to %s\n", output_file_name );
527 close_output_file();
528 free( output_buffer );
531 unsigned char get_byte(void)
533 if (input_buffer_pos >= input_buffer_size)
534 fatal_error( "%s is a truncated file\n", input_buffer_filename );
535 return input_buffer[input_buffer_pos++];
538 unsigned short get_word(void)
540 unsigned short ret;
542 if (input_buffer_pos + sizeof(ret) > input_buffer_size)
543 fatal_error( "%s is a truncated file\n", input_buffer_filename );
544 memcpy( &ret, input_buffer + input_buffer_pos, sizeof(ret) );
545 if (byte_swapped) ret = (ret << 8) | (ret >> 8);
546 input_buffer_pos += sizeof(ret);
547 return ret;
550 unsigned int get_dword(void)
552 unsigned int ret;
554 if (input_buffer_pos + sizeof(ret) > input_buffer_size)
555 fatal_error( "%s is a truncated file\n", input_buffer_filename );
556 memcpy( &ret, input_buffer + input_buffer_pos, sizeof(ret) );
557 if (byte_swapped)
558 ret = ((ret << 24) | ((ret << 8) & 0x00ff0000) | ((ret >> 8) & 0x0000ff00) | (ret >> 24));
559 input_buffer_pos += sizeof(ret);
560 return ret;
563 void put_data( const void *data, size_t size )
565 check_output_buffer_space( size );
566 memcpy( output_buffer + output_buffer_pos, data, size );
567 output_buffer_pos += size;
570 void put_byte( unsigned char val )
572 check_output_buffer_space( 1 );
573 output_buffer[output_buffer_pos++] = val;
576 void put_word( unsigned short val )
578 if (byte_swapped) val = (val << 8) | (val >> 8);
579 put_data( &val, sizeof(val) );
582 void put_dword( unsigned int val )
584 if (byte_swapped)
585 val = ((val << 24) | ((val << 8) & 0x00ff0000) | ((val >> 8) & 0x0000ff00) | (val >> 24));
586 put_data( &val, sizeof(val) );
589 void put_qword( unsigned int val )
591 if (byte_swapped)
593 put_dword( 0 );
594 put_dword( val );
596 else
598 put_dword( val );
599 put_dword( 0 );
603 /* pointer-sized word */
604 void put_pword( unsigned int val )
606 if (get_ptr_size() == 8) put_qword( val );
607 else put_dword( val );
610 void align_output( unsigned int align )
612 size_t size = align - (output_buffer_pos % align);
614 if (size == align) return;
615 check_output_buffer_space( size );
616 memset( output_buffer + output_buffer_pos, 0, size );
617 output_buffer_pos += size;
620 /* output a standard header for generated files */
621 void output_standard_file_header(void)
623 if (spec_file_name)
624 output( "/* File generated automatically from %s; do not edit! */\n", spec_file_name );
625 else
626 output( "/* File generated automatically; do not edit! */\n" );
627 output( "/* This file can be copied, modified and distributed without restriction. */\n\n" );
628 if (safe_seh)
630 output( "\t.def @feat.00\n\t.scl 3\n\t.type 0\n\t.endef\n" );
631 output( "\t.globl @feat.00\n" );
632 output( ".set @feat.00, 1\n" );
634 if (thumb_mode)
636 output( "\t.syntax unified\n" );
637 output( "\t.thumb\n" );
641 /* dump a byte stream into the assembly code */
642 void dump_bytes( const void *buffer, unsigned int size )
644 unsigned int i;
645 const unsigned char *ptr = buffer;
647 if (!size) return;
648 output( "\t.byte " );
649 for (i = 0; i < size - 1; i++, ptr++)
651 if ((i % 16) == 15) output( "0x%02x\n\t.byte ", *ptr );
652 else output( "0x%02x,", *ptr );
654 output( "0x%02x\n", *ptr );
658 /*******************************************************************
659 * open_input_file
661 * Open a file in the given srcdir and set the input_file_name global variable.
663 FILE *open_input_file( const char *srcdir, const char *name )
665 char *fullname;
666 FILE *file = fopen( name, "r" );
668 if (!file && srcdir)
670 fullname = strmake( "%s/%s", srcdir, name );
671 file = fopen( fullname, "r" );
673 else fullname = xstrdup( name );
675 if (!file) fatal_error( "Cannot open file '%s'\n", fullname );
676 input_file_name = fullname;
677 current_line = 1;
678 return file;
682 /*******************************************************************
683 * close_input_file
685 * Close the current input file (must have been opened with open_input_file).
687 void close_input_file( FILE *file )
689 fclose( file );
690 free( input_file_name );
691 input_file_name = NULL;
692 current_line = 0;
696 /*******************************************************************
697 * open_output_file
699 void open_output_file(void)
701 if (output_file_name)
703 if (strendswith( output_file_name, ".o" ))
704 output_file_source_name = open_temp_output_file( ".s" );
705 else
706 if (!(output_file = fopen( output_file_name, "w" )))
707 fatal_error( "Unable to create output file '%s'\n", output_file_name );
709 else output_file = stdout;
713 /*******************************************************************
714 * close_output_file
716 void close_output_file(void)
718 if (!output_file || !output_file_name) return;
719 if (fclose( output_file ) < 0) fatal_perror( "fclose" );
720 if (output_file_source_name) assemble_file( output_file_source_name, output_file_name );
721 output_file = NULL;
725 /*******************************************************************
726 * open_temp_output_file
728 char *open_temp_output_file( const char *suffix )
730 char *tmp_file = get_temp_file_name( output_file_name, suffix );
731 if (!(output_file = fopen( tmp_file, "w" )))
732 fatal_error( "Unable to create output file '%s'\n", tmp_file );
733 return tmp_file;
737 /*******************************************************************
738 * remove_stdcall_decoration
740 * Remove a possible @xx suffix from a function name.
741 * Return the numerical value of the suffix, or -1 if none.
743 int remove_stdcall_decoration( char *name )
745 char *p, *end = strrchr( name, '@' );
746 if (!end || !end[1] || end == name) return -1;
747 if (target_cpu != CPU_x86) return -1;
748 /* make sure all the rest is digits */
749 for (p = end + 1; *p; p++) if (!isdigit(*p)) return -1;
750 *end = 0;
751 return atoi( end + 1 );
755 /*******************************************************************
756 * assemble_file
758 * Run a file through the assembler.
760 void assemble_file( const char *src_file, const char *obj_file )
762 struct strarray args = get_as_command();
763 strarray_add( &args, "-o" );
764 strarray_add( &args, obj_file );
765 strarray_add( &args, src_file );
766 spawn( args );
770 /*******************************************************************
771 * alloc_dll_spec
773 * Create a new dll spec file descriptor
775 DLLSPEC *alloc_dll_spec(void)
777 DLLSPEC *spec;
779 spec = xmalloc( sizeof(*spec) );
780 memset( spec, 0, sizeof(*spec) );
781 spec->type = SPEC_WIN32;
782 spec->base = MAX_ORDINALS;
783 spec->characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
784 spec->subsystem = 0;
785 spec->subsystem_major = 4;
786 spec->subsystem_minor = 0;
787 spec->syscall_table = 0;
788 if (get_ptr_size() > 4)
789 spec->characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
790 else
791 spec->characteristics |= IMAGE_FILE_32BIT_MACHINE;
792 spec->dll_characteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
793 return spec;
797 /*******************************************************************
798 * free_dll_spec
800 * Free dll spec file descriptor
802 void free_dll_spec( DLLSPEC *spec )
804 int i;
806 for (i = 0; i < spec->nb_entry_points; i++)
808 ORDDEF *odp = &spec->entry_points[i];
809 free( odp->name );
810 free( odp->export_name );
811 free( odp->link_name );
813 free( spec->file_name );
814 free( spec->dll_name );
815 free( spec->c_name );
816 free( spec->init_func );
817 free( spec->entry_points );
818 free( spec->names );
819 free( spec->ordinals );
820 free( spec->resources );
821 free( spec );
825 /*******************************************************************
826 * make_c_identifier
828 * Map a string to a valid C identifier.
830 char *make_c_identifier( const char *str )
832 char *p, buffer[256];
834 for (p = buffer; *str && p < buffer+sizeof(buffer)-1; p++, str++)
836 if (isalnum(*str)) *p = *str;
837 else *p = '_';
839 *p = 0;
840 return xstrdup( buffer );
844 /*******************************************************************
845 * get_stub_name
847 * Generate an internal name for a stub entry point.
849 const char *get_stub_name( const ORDDEF *odp, const DLLSPEC *spec )
851 static char *buffer;
853 free( buffer );
854 if (odp->name || odp->export_name)
856 char *p;
857 buffer = strmake( "__wine_stub_%s", odp->name ? odp->name : odp->export_name );
858 /* make sure name is a legal C identifier */
859 for (p = buffer; *p; p++) if (!isalnum(*p) && *p != '_') break;
860 if (!*p) return buffer;
861 free( buffer );
863 buffer = strmake( "__wine_stub_%s_%d", make_c_identifier(spec->file_name), odp->ordinal );
864 return buffer;
867 /* return the stdcall-decorated name for an entry point */
868 const char *get_link_name( const ORDDEF *odp )
870 static char *buffer;
871 char *ret;
873 if (target_cpu != CPU_x86) return odp->link_name;
875 switch (odp->type)
877 case TYPE_STDCALL:
878 if (is_pe())
880 if (odp->flags & FLAG_THISCALL) return odp->link_name;
881 if (odp->flags & FLAG_FASTCALL) ret = strmake( "@%s@%u", odp->link_name, get_args_size( odp ));
882 else if (!kill_at) ret = strmake( "%s@%u", odp->link_name, get_args_size( odp ));
883 else return odp->link_name;
885 else
887 if (odp->flags & FLAG_THISCALL) ret = strmake( "__thiscall_%s", odp->link_name );
888 else if (odp->flags & FLAG_FASTCALL) ret = strmake( "__fastcall_%s", odp->link_name );
889 else return odp->link_name;
891 break;
893 case TYPE_PASCAL:
894 if (is_pe() && !kill_at)
896 int args = get_args_size( odp );
897 if (odp->flags & FLAG_REGISTER) args += get_ptr_size(); /* context argument */
898 ret = strmake( "%s@%u", odp->link_name, args );
900 else return odp->link_name;
901 break;
903 default:
904 return odp->link_name;
907 free( buffer );
908 buffer = ret;
909 return ret;
912 /*******************************************************************
913 * sort_func_list
915 * Sort a list of functions, removing duplicates.
917 int sort_func_list( ORDDEF **list, int count, int (*compare)(const void *, const void *) )
919 int i, j;
921 if (!count) return 0;
922 qsort( list, count, sizeof(*list), compare );
923 for (i = j = 0; i < count; i++) if (compare( &list[j], &list[i] )) list[++j] = list[i];
924 return j + 1;
928 /* parse a cpu name and return the corresponding value */
929 int get_cpu_from_name( const char *name )
931 unsigned int i;
933 for (i = 0; i < ARRAY_SIZE(cpu_names); i++)
934 if (!strcmp( cpu_names[i].name, name )) return cpu_names[i].cpu;
935 return -1;
938 /*****************************************************************
939 * Function: get_alignment
941 * Description:
942 * According to the info page for gas, the .align directive behaves
943 * differently on different systems. On some architectures, the
944 * argument of a .align directive is the number of bytes to pad to, so
945 * to align on an 8-byte boundary you'd say
946 * .align 8
947 * On other systems, the argument is "the number of low-order zero bits
948 * that the location counter must have after advancement." So to
949 * align on an 8-byte boundary you'd say
950 * .align 3
952 * The reason gas is written this way is that it's trying to mimic
953 * native assemblers for the various architectures it runs on. gas
954 * provides other directives that work consistently across
955 * architectures, but of course we want to work on all arches with or
956 * without gas. Hence this function.
959 * Parameters:
960 * align -- the number of bytes to align to. Must be a power of 2.
962 unsigned int get_alignment(unsigned int align)
964 unsigned int n;
966 assert( !(align & (align - 1)) );
968 switch(target_cpu)
970 case CPU_x86:
971 case CPU_x86_64:
972 if (target_platform != PLATFORM_APPLE) return align;
973 /* fall through */
974 case CPU_POWERPC:
975 case CPU_ARM:
976 case CPU_ARM64:
977 n = 0;
978 while ((1u << n) != align) n++;
979 return n;
981 /* unreached */
982 assert(0);
983 return 0;
986 /* return the page size for the target CPU */
987 unsigned int get_page_size(void)
989 return 0x1000; /* same on all platforms */
992 /* return the size of a pointer on the target CPU */
993 unsigned int get_ptr_size(void)
995 switch(target_cpu)
997 case CPU_x86:
998 case CPU_POWERPC:
999 case CPU_ARM:
1000 return 4;
1001 case CPU_x86_64:
1002 case CPU_ARM64:
1003 return 8;
1005 /* unreached */
1006 assert(0);
1007 return 0;
1010 /* return the total size in bytes of the arguments on the stack */
1011 unsigned int get_args_size( const ORDDEF *odp )
1013 int i, size;
1015 for (i = size = 0; i < odp->u.func.nb_args; i++)
1017 switch (odp->u.func.args[i])
1019 case ARG_INT64:
1020 case ARG_DOUBLE:
1021 if (target_cpu == CPU_ARM) size = (size + 7) & ~7;
1022 size += 8;
1023 break;
1024 case ARG_INT128:
1025 /* int128 is passed as pointer on x86_64 */
1026 if (target_cpu != CPU_x86_64)
1028 size += 16;
1029 break;
1031 /* fall through */
1032 default:
1033 size += get_ptr_size();
1034 break;
1037 return size;
1040 /* return the assembly name for a C symbol */
1041 const char *asm_name( const char *sym )
1043 static char *buffer;
1045 switch (target_platform)
1047 case PLATFORM_MINGW:
1048 case PLATFORM_WINDOWS:
1049 if (target_cpu != CPU_x86) return sym;
1050 if (sym[0] == '@') return sym; /* fastcall */
1051 /* fall through */
1052 case PLATFORM_APPLE:
1053 if (sym[0] == '.' && sym[1] == 'L') return sym;
1054 free( buffer );
1055 buffer = strmake( "_%s", sym );
1056 return buffer;
1057 default:
1058 return sym;
1062 /* return an assembly function declaration for a C function name */
1063 const char *func_declaration( const char *func )
1065 static char *buffer;
1067 switch (target_platform)
1069 case PLATFORM_APPLE:
1070 return "";
1071 case PLATFORM_MINGW:
1072 case PLATFORM_WINDOWS:
1073 free( buffer );
1074 buffer = strmake( ".def %s\n\t.scl 2\n\t.type 32\n\t.endef%s", asm_name(func),
1075 thumb_mode ? "\n\t.thumb_func" : "" );
1076 break;
1077 default:
1078 free( buffer );
1079 switch(target_cpu)
1081 case CPU_ARM:
1082 buffer = strmake( ".type %s,%%function%s", func,
1083 thumb_mode ? "\n\t.thumb_func" : "" );
1084 break;
1085 case CPU_ARM64:
1086 buffer = strmake( ".type %s,%%function", func );
1087 break;
1088 default:
1089 buffer = strmake( ".type %s,@function", func );
1090 break;
1092 break;
1094 return buffer;
1097 /* output a size declaration for an assembly function */
1098 void output_function_size( const char *name )
1100 switch (target_platform)
1102 case PLATFORM_APPLE:
1103 case PLATFORM_MINGW:
1104 case PLATFORM_WINDOWS:
1105 break;
1106 default:
1107 output( "\t.size %s, .-%s\n", name, name );
1108 break;
1112 /* output a .cfi directive */
1113 void output_cfi( const char *format, ... )
1115 va_list valist;
1117 if (!unwind_tables) return;
1118 va_start( valist, format );
1119 fputc( '\t', output_file );
1120 vfprintf( output_file, format, valist );
1121 fputc( '\n', output_file );
1122 va_end( valist );
1125 /* output an RVA pointer */
1126 void output_rva( const char *format, ... )
1128 va_list valist;
1130 va_start( valist, format );
1131 switch (target_platform)
1133 case PLATFORM_MINGW:
1134 case PLATFORM_WINDOWS:
1135 output( "\t.rva " );
1136 vfprintf( output_file, format, valist );
1137 fputc( '\n', output_file );
1138 break;
1139 default:
1140 output( "\t.long " );
1141 vfprintf( output_file, format, valist );
1142 output( " - .L__wine_spec_rva_base\n" );
1143 break;
1145 va_end( valist );
1148 /* output the GNU note for non-exec stack */
1149 void output_gnu_stack_note(void)
1151 switch (target_platform)
1153 case PLATFORM_MINGW:
1154 case PLATFORM_WINDOWS:
1155 case PLATFORM_APPLE:
1156 break;
1157 default:
1158 switch(target_cpu)
1160 case CPU_ARM:
1161 case CPU_ARM64:
1162 output( "\t.section .note.GNU-stack,\"\",%%progbits\n" );
1163 break;
1164 default:
1165 output( "\t.section .note.GNU-stack,\"\",@progbits\n" );
1166 break;
1168 break;
1172 /* return a global symbol declaration for an assembly symbol */
1173 const char *asm_globl( const char *func )
1175 static char *buffer;
1177 free( buffer );
1178 switch (target_platform)
1180 case PLATFORM_APPLE:
1181 buffer = strmake( "\t.globl _%s\n\t.private_extern _%s\n_%s:", func, func, func );
1182 break;
1183 case PLATFORM_MINGW:
1184 case PLATFORM_WINDOWS:
1185 buffer = strmake( "\t.globl %s%s\n%s%s:", target_cpu == CPU_x86 ? "_" : "", func,
1186 target_cpu == CPU_x86 ? "_" : "", func );
1187 break;
1188 default:
1189 buffer = strmake( "\t.globl %s\n\t.hidden %s\n%s:", func, func, func );
1190 break;
1192 return buffer;
1195 const char *get_asm_ptr_keyword(void)
1197 switch(get_ptr_size())
1199 case 4: return ".long";
1200 case 8: return ".quad";
1202 assert(0);
1203 return NULL;
1206 const char *get_asm_string_keyword(void)
1208 switch (target_platform)
1210 case PLATFORM_APPLE:
1211 return ".asciz";
1212 default:
1213 return ".string";
1217 const char *get_asm_export_section(void)
1219 switch (target_platform)
1221 case PLATFORM_APPLE: return ".data";
1222 case PLATFORM_MINGW:
1223 case PLATFORM_WINDOWS: return ".section .edata";
1224 default: return ".section .data";
1228 const char *get_asm_rodata_section(void)
1230 switch (target_platform)
1232 case PLATFORM_APPLE: return ".const";
1233 default: return ".section .rodata";
1237 const char *get_asm_rsrc_section(void)
1239 switch (target_platform)
1241 case PLATFORM_APPLE: return ".data";
1242 case PLATFORM_MINGW:
1243 case PLATFORM_WINDOWS: return ".section .rsrc";
1244 default: return ".section .data";
1248 const char *get_asm_string_section(void)
1250 switch (target_platform)
1252 case PLATFORM_APPLE: return ".cstring";
1253 default: return ".section .rodata";
1257 const char *arm64_page( const char *sym )
1259 static char *buffer;
1261 switch (target_platform)
1263 case PLATFORM_APPLE:
1264 free( buffer );
1265 buffer = strmake( "%s@PAGE", sym );
1266 return buffer;
1267 default:
1268 return sym;
1272 const char *arm64_pageoff( const char *sym )
1274 static char *buffer;
1276 free( buffer );
1277 switch (target_platform)
1279 case PLATFORM_APPLE:
1280 buffer = strmake( "%s@PAGEOFF", sym );
1281 break;
1282 default:
1283 buffer = strmake( ":lo12:%s", sym );
1284 break;
1286 return buffer;