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
22 #include "wine/port.h"
33 #ifdef HAVE_SYS_STAT_H
34 # include <sys/stat.h>
39 static struct strarray tmp_files
;
40 static const char *output_file_source_name
;
53 { "amd64", CPU_x86_64
},
54 { "x86_64", CPU_x86_64
},
55 { "powerpc", CPU_POWERPC
},
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)
69 for (i
= 0; i
< tmp_files
.count
; i
++) if (tmp_files
.str
[i
]) unlink( tmp_files
.str
[i
] );
73 char *strupper(char *s
)
76 for (p
= s
; *p
; p
++) *p
= toupper(*p
);
80 void fatal_error( const char *msg
, ... )
83 va_start( valist
, msg
);
86 fprintf( stderr
, "%s:", input_file_name
);
88 fprintf( stderr
, "%d:", current_line
);
91 else fprintf( stderr
, "winebuild: " );
92 vfprintf( stderr
, msg
, valist
);
97 void fatal_perror( const char *msg
, ... )
100 va_start( valist
, msg
);
103 fprintf( stderr
, "%s:", input_file_name
);
105 fprintf( stderr
, "%d:", current_line
);
106 fputc( ' ', stderr
);
108 vfprintf( stderr
, msg
, valist
);
114 void error( const char *msg
, ... )
117 va_start( valist
, msg
);
120 fprintf( stderr
, "%s:", input_file_name
);
122 fprintf( stderr
, "%d:", current_line
);
123 fputc( ' ', stderr
);
125 vfprintf( stderr
, msg
, valist
);
130 void warning( const char *msg
, ... )
134 if (!display_warnings
) return;
135 va_start( valist
, msg
);
138 fprintf( stderr
, "%s:", input_file_name
);
140 fprintf( stderr
, "%d:", current_line
);
141 fputc( ' ', stderr
);
143 fprintf( stderr
, "warning: " );
144 vfprintf( stderr
, msg
, valist
);
148 int output( const char *format
, ... )
153 va_start( valist
, format
);
154 ret
= vfprintf( output_file
, format
, valist
);
156 if (ret
< 0) fatal_perror( "Output error" );
160 static struct strarray
get_tools_path(void)
163 static struct strarray dirs
;
167 strarray_addall( &dirs
, tools_path
);
168 strarray_addall( &dirs
, strarray_frompath( getenv( "PATH" )));
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;
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
++ = '/';
201 if (!stat( file
, &st
) && S_ISREG(st
.st_mode
) && (st
.st_mode
& 0111)) return file
;
207 void spawn( struct strarray args
)
211 const char *argv0
= find_binary( NULL
, args
.str
[0] );
213 if (argv0
) args
.str
[0] = argv0
;
214 strarray_add( &args
, NULL
);
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" );
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
;
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
);
245 dup2( sout
, fileno(stdout
) );
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
);
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
))
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
;
272 const char *alt_names
[2];
283 if ((file
= find_binary( target_alias
, *names
))) break;
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
);
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" );
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
);
323 struct strarray
get_as_command(void)
325 struct strarray args
= empty_strarray
;
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
] ));
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
)
356 strarray_add( &args
, "-arch" );
357 strarray_add( &args
, (force_pointer_size
== 8) ? "x86_64" : "i386" );
363 strarray_add( &args
, (force_pointer_size
== 8) ? "-a64" : "-a32" );
366 strarray_add( &args
, (force_pointer_size
== 8) ? "--64" : "--32" );
373 if (cpu_option
) strarray_add( &args
, strmake("-mcpu=%s", cpu_option
) );
374 if (fpu_option
) strarray_add( &args
, strmake("-mfpu=%s", fpu_option
) );
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
)
395 strarray_add( &args
, "-arch" );
396 strarray_add( &args
, (force_pointer_size
== 8) ? "x86_64" : "i386" );
398 case PLATFORM_FREEBSD
:
399 strarray_add( &args
, "-m" );
400 strarray_add( &args
, (force_pointer_size
== 8) ? "elf_x86_64_fbsd" : "elf_i386_fbsd" );
403 case PLATFORM_WINDOWS
:
404 strarray_add( &args
, "-m" );
405 strarray_add( &args
, (force_pointer_size
== 8) ? "i386pep" : "i386pe" );
411 strarray_add( &args
, "-m" );
412 strarray_add( &args
, (force_pointer_size
== 8) ? "elf64ppc" : "elf32ppc" );
415 strarray_add( &args
, "-m" );
416 strarray_add( &args
, (force_pointer_size
== 8) ? "elf_x86_64" : "elf_i386" );
423 if (target_cpu
== CPU_ARM
&& !is_pe())
424 strarray_add( &args
, "--no-wchar-size-warning" );
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
)
445 const char *ext
, *basename
;
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" );
469 strarray_add( &tmp_files
, name
);
473 /*******************************************************************
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
)
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
);
509 input_buffer_filename
= xstrdup( file
);
510 input_buffer_size
= st
.st_size
;
511 input_buffer_pos
= 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)
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
);
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)
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
);
550 unsigned int get_dword(void)
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
) );
558 ret
= ((ret
<< 24) | ((ret
<< 8) & 0x00ff0000) | ((ret
>> 8) & 0x0000ff00) | (ret
>> 24));
559 input_buffer_pos
+= sizeof(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
)
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
)
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)
624 output( "/* File generated automatically from %s; do not edit! */\n", spec_file_name
);
626 output( "/* File generated automatically; do not edit! */\n" );
627 output( "/* This file can be copied, modified and distributed without restriction. */\n\n" );
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" );
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
)
645 const unsigned char *ptr
= buffer
;
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 /*******************************************************************
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
)
666 FILE *file
= fopen( name
, "r" );
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
;
682 /*******************************************************************
685 * Close the current input file (must have been opened with open_input_file).
687 void close_input_file( FILE *file
)
690 free( input_file_name
);
691 input_file_name
= NULL
;
696 /*******************************************************************
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" );
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 /*******************************************************************
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
);
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
);
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;
751 return atoi( end
+ 1 );
755 /*******************************************************************
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
);
770 /*******************************************************************
773 * Create a new dll spec file descriptor
775 DLLSPEC
*alloc_dll_spec(void)
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
;
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
;
791 spec
->characteristics
|= IMAGE_FILE_32BIT_MACHINE
;
792 spec
->dll_characteristics
= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
;
797 /*******************************************************************
800 * Free dll spec file descriptor
802 void free_dll_spec( DLLSPEC
*spec
)
806 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
808 ORDDEF
*odp
= &spec
->entry_points
[i
];
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
);
819 free( spec
->ordinals
);
820 free( spec
->resources
);
825 /*******************************************************************
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
;
840 return xstrdup( buffer
);
844 /*******************************************************************
847 * Generate an internal name for a stub entry point.
849 const char *get_stub_name( const ORDDEF
*odp
, const DLLSPEC
*spec
)
854 if (odp
->name
|| odp
->export_name
)
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
;
863 buffer
= strmake( "__wine_stub_%s_%d", make_c_identifier(spec
->file_name
), odp
->ordinal
);
867 /* return the stdcall-decorated name for an entry point */
868 const char *get_link_name( const ORDDEF
*odp
)
873 if (target_cpu
!= CPU_x86
) return odp
->link_name
;
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
;
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
;
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
;
904 return odp
->link_name
;
912 /*******************************************************************
915 * Sort a list of functions, removing duplicates.
917 int sort_func_list( ORDDEF
**list
, int count
, int (*compare
)(const void *, const void *) )
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
];
928 /* parse a cpu name and return the corresponding value */
929 int get_cpu_from_name( const char *name
)
933 for (i
= 0; i
< ARRAY_SIZE(cpu_names
); i
++)
934 if (!strcmp( cpu_names
[i
].name
, name
)) return cpu_names
[i
].cpu
;
938 /*****************************************************************
939 * Function: get_alignment
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
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
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.
960 * align -- the number of bytes to align to. Must be a power of 2.
962 unsigned int get_alignment(unsigned int align
)
966 assert( !(align
& (align
- 1)) );
972 if (target_platform
!= PLATFORM_APPLE
) return align
;
978 while ((1u << n
) != align
) n
++;
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)
1010 /* return the total size in bytes of the arguments on the stack */
1011 unsigned int get_args_size( const ORDDEF
*odp
)
1015 for (i
= size
= 0; i
< odp
->u
.func
.nb_args
; i
++)
1017 switch (odp
->u
.func
.args
[i
])
1021 if (target_cpu
== CPU_ARM
) size
= (size
+ 7) & ~7;
1025 /* int128 is passed as pointer on x86_64 */
1026 if (target_cpu
!= CPU_x86_64
)
1033 size
+= get_ptr_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 */
1052 case PLATFORM_APPLE
:
1053 if (sym
[0] == '.' && sym
[1] == 'L') return sym
;
1055 buffer
= strmake( "_%s", 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
:
1071 case PLATFORM_MINGW
:
1072 case PLATFORM_WINDOWS
:
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" : "" );
1082 buffer
= strmake( ".type %s,%%function%s", func
,
1083 thumb_mode
? "\n\t.thumb_func" : "" );
1086 buffer
= strmake( ".type %s,%%function", func
);
1089 buffer
= strmake( ".type %s,@function", func
);
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
:
1107 output( "\t.size %s, .-%s\n", name
, name
);
1112 /* output a .cfi directive */
1113 void output_cfi( const char *format
, ... )
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
);
1125 /* output an RVA pointer */
1126 void output_rva( const char *format
, ... )
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
);
1140 output( "\t.long " );
1141 vfprintf( output_file
, format
, valist
);
1142 output( " - .L__wine_spec_rva_base\n" );
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
:
1162 output( "\t.section .note.GNU-stack,\"\",%%progbits\n" );
1165 output( "\t.section .note.GNU-stack,\"\",@progbits\n" );
1172 /* return a global symbol declaration for an assembly symbol */
1173 const char *asm_globl( const char *func
)
1175 static char *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
);
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
);
1189 buffer
= strmake( "\t.globl %s\n\t.hidden %s\n%s:", func
, func
, func
);
1195 const char *get_asm_ptr_keyword(void)
1197 switch(get_ptr_size())
1199 case 4: return ".long";
1200 case 8: return ".quad";
1206 const char *get_asm_string_keyword(void)
1208 switch (target_platform
)
1210 case PLATFORM_APPLE
:
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
:
1265 buffer
= strmake( "%s@PAGE", sym
);
1272 const char *arm64_pageoff( const char *sym
)
1274 static char *buffer
;
1277 switch (target_platform
)
1279 case PLATFORM_APPLE
:
1280 buffer
= strmake( "%s@PAGEOFF", sym
);
1283 buffer
= strmake( ":lo12:%s", sym
);