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
32 const char *temp_dir
= NULL
;
33 struct strarray temp_files
= { 0 };
34 static const char *output_file_source_name
;
36 char *strupper(char *s
)
39 for (p
= s
; *p
; p
++) *p
= toupper(*p
);
43 void fatal_error( const char *msg
, ... )
46 va_start( valist
, msg
);
49 fprintf( stderr
, "%s:", input_file_name
);
51 fprintf( stderr
, "%d:", current_line
);
54 else fprintf( stderr
, "winebuild: " );
55 vfprintf( stderr
, msg
, valist
);
60 void fatal_perror( const char *msg
, ... )
63 va_start( valist
, msg
);
66 fprintf( stderr
, "%s:", input_file_name
);
68 fprintf( stderr
, "%d:", current_line
);
71 vfprintf( stderr
, msg
, valist
);
77 void error( const char *msg
, ... )
80 va_start( valist
, msg
);
83 fprintf( stderr
, "%s:", input_file_name
);
85 fprintf( stderr
, "%d:", current_line
);
88 vfprintf( stderr
, msg
, valist
);
93 void warning( const char *msg
, ... )
97 if (!display_warnings
) return;
98 va_start( valist
, msg
);
101 fprintf( stderr
, "%s:", input_file_name
);
103 fprintf( stderr
, "%d:", current_line
);
104 fputc( ' ', stderr
);
106 fprintf( stderr
, "warning: " );
107 vfprintf( stderr
, msg
, valist
);
111 int output( const char *format
, ... )
116 va_start( valist
, format
);
117 ret
= vfprintf( output_file
, format
, valist
);
119 if (ret
< 0) fatal_perror( "Output error" );
123 static struct strarray
get_tools_path(void)
126 static struct strarray dirs
;
130 strarray_addall( &dirs
, tools_path
);
131 strarray_addall( &dirs
, strarray_frompath( getenv( "PATH" )));
137 /* find a binary in the path */
138 static const char *find_binary( const char *prefix
, const char *name
)
140 struct strarray dirs
= get_tools_path();
141 unsigned int i
, maxlen
= 0;
145 if (strchr( name
, '/' )) return name
;
146 if (!prefix
) prefix
= "";
147 for (i
= 0; i
< dirs
.count
; i
++) maxlen
= max( maxlen
, strlen(dirs
.str
[i
]) + 2 );
148 file
= xmalloc( maxlen
+ strlen(prefix
) + strlen(name
) + sizeof(EXEEXT
) + 1 );
150 for (i
= 0; i
< dirs
.count
; i
++)
152 strcpy( file
, dirs
.str
[i
] );
153 p
= file
+ strlen(file
);
154 if (p
== file
) *p
++ = '.';
155 if (p
[-1] != '/') *p
++ = '/';
164 if (!stat( file
, &st
) && S_ISREG(st
.st_mode
) && (st
.st_mode
& 0111)) return file
;
170 void spawn( struct strarray args
)
173 const char *argv0
= find_binary( NULL
, args
.str
[0] );
175 if (argv0
) args
.str
[0] = argv0
;
176 if (verbose
) strarray_trace( args
);
178 if ((status
= strarray_spawn( args
)))
180 if (status
> 0) fatal_error( "%s failed with status %u\n", args
.str
[0], status
);
181 else fatal_perror( "winebuild" );
186 static const char *find_clang_tool( struct strarray clang
, const char *tool
)
188 const char *out
= make_temp_file( "print_tool", ".out" );
189 struct strarray args
= empty_strarray
;
195 strarray_addall( &args
, clang
);
196 strarray_add( &args
, strmake( "-print-prog-name=%s", tool
));
197 if (verbose
) strarray_add( &args
, "-v" );
199 sout
= dup( fileno(stdout
) );
200 freopen( out
, "w", stdout
);
204 dup2( sout
, fileno(stdout
) );
208 if (stat(out
, &st
) || !st
.st_size
) return NULL
;
210 path
= xmalloc(st
.st_size
+ 1);
211 sout
= open(out
, O_RDONLY
);
212 if (sout
== -1) return NULL
;
213 cnt
= read(sout
, path
, st
.st_size
);
216 if ((p
= strchr(path
, '\n'))) *p
= 0;
217 /* clang returns passed command instead of full path if the tool could not be found */
218 if (!strcmp(path
, tool
))
226 /* find a build tool in the path, trying the various names */
227 struct strarray
find_tool( const char *name
, const char * const *names
)
229 struct strarray ret
= empty_strarray
;
231 const char *alt_names
[2];
242 if ((file
= find_binary( target_alias
, *names
))) break;
248 if (cc_command
.count
) file
= find_clang_tool( cc_command
, name
);
249 if (!file
&& !(file
= find_binary( "llvm", name
)))
251 struct strarray clang
= empty_strarray
;
252 strarray_add( &clang
, "clang" );
253 file
= find_clang_tool( clang
, strmake( "llvm-%s", name
));
256 if (!file
) fatal_error( "cannot find the '%s' tool\n", name
);
258 strarray_add( &ret
, file
);
262 /* find a link tool in the path */
263 struct strarray
find_link_tool(void)
265 struct strarray ret
= empty_strarray
;
266 const char *file
= NULL
;
268 if (cc_command
.count
) file
= find_clang_tool( cc_command
, "lld-link" );
269 if (!file
) file
= find_binary( NULL
, "lld-link" );
272 struct strarray clang
= empty_strarray
;
273 strarray_add( &clang
, "clang" );
274 file
= find_clang_tool( clang
, "lld-link" );
277 if (!file
) fatal_error( "cannot find the 'lld-link' tool\n" );
278 strarray_add( &ret
, file
);
282 struct strarray
get_as_command(void)
284 struct strarray args
= empty_strarray
;
289 if (cc_command
.count
)
291 strarray_addall( &args
, cc_command
);
294 else if (as_command
.count
)
296 strarray_addall( &args
, as_command
);
298 else if ((file
= find_binary( target_alias
, "as" )) || (file
= find_binary( target_alias
, "gas ")))
300 strarray_add( &args
, file
);
302 else if ((file
= find_binary( NULL
, "clang" )))
304 strarray_add( &args
, file
);
307 strarray_add( &args
, "-target" );
308 strarray_add( &args
, target_alias
);
315 strarray_add( &args
, "-xassembler" );
316 strarray_add( &args
, "-c" );
317 if (force_pointer_size
)
318 strarray_add( &args
, (force_pointer_size
== 8) ? "-m64" : "-m32" );
319 if (cpu_option
) strarray_add( &args
, strmake("-mcpu=%s", cpu_option
) );
320 if (fpu_option
) strarray_add( &args
, strmake("-mfpu=%s", fpu_option
) );
321 if (arch_option
) strarray_add( &args
, strmake("-march=%s", arch_option
) );
322 for (i
= 0; i
< tools_path
.count
; i
++)
323 strarray_add( &args
, strmake("-B%s", tools_path
.str
[i
] ));
327 if (force_pointer_size
)
329 switch (target
.platform
)
332 strarray_add( &args
, "-arch" );
333 strarray_add( &args
, (force_pointer_size
== 8) ? "x86_64" : "i386" );
336 strarray_add( &args
, (force_pointer_size
== 8) ? "--64" : "--32" );
341 if (cpu_option
) strarray_add( &args
, strmake("-mcpu=%s", cpu_option
) );
342 if (fpu_option
) strarray_add( &args
, strmake("-mfpu=%s", fpu_option
) );
346 struct strarray
get_ld_command(void)
348 struct strarray args
= empty_strarray
;
350 if (!ld_command
.count
)
352 static const char * const commands
[] = { "ld", "gld", NULL
};
353 ld_command
= find_tool( "ld", commands
);
356 strarray_addall( &args
, ld_command
);
358 if (force_pointer_size
)
360 switch (target
.platform
)
363 strarray_add( &args
, "-arch" );
364 strarray_add( &args
, (force_pointer_size
== 8) ? "x86_64" : "i386" );
366 case PLATFORM_FREEBSD
:
367 strarray_add( &args
, "-m" );
368 strarray_add( &args
, (force_pointer_size
== 8) ? "elf_x86_64_fbsd" : "elf_i386_fbsd" );
371 case PLATFORM_WINDOWS
:
372 strarray_add( &args
, "-m" );
373 strarray_add( &args
, (force_pointer_size
== 8) ? "i386pep" : "i386pe" );
376 strarray_add( &args
, "-m" );
377 strarray_add( &args
, (force_pointer_size
== 8) ? "elf_x86_64" : "elf_i386" );
382 if (target
.cpu
== CPU_ARM
&& !is_pe())
383 strarray_add( &args
, "--no-wchar-size-warning" );
388 const char *get_nm_command(void)
390 if (!nm_command
.count
)
392 static const char * const commands
[] = { "nm", "gnm", NULL
};
393 nm_command
= find_tool( "nm", commands
);
395 if (nm_command
.count
> 1)
396 fatal_error( "multiple arguments in nm command not supported yet\n" );
397 return nm_command
.str
[0];
401 /*******************************************************************
404 * Function for reading from/writing to a memory buffer.
407 int byte_swapped
= 0;
408 const char *input_buffer_filename
;
409 const unsigned char *input_buffer
;
410 size_t input_buffer_pos
;
411 size_t input_buffer_size
;
412 unsigned char *output_buffer
;
413 size_t output_buffer_pos
;
414 size_t output_buffer_size
;
416 void init_input_buffer( const char *file
)
418 if (!(input_buffer
= read_file( file
, &input_buffer_size
))) fatal_perror( "Cannot read %s", file
);
419 if (!input_buffer_size
) fatal_error( "%s is an empty file\n", file
);
420 input_buffer_filename
= xstrdup( file
);
421 input_buffer_pos
= 0;
425 unsigned char get_byte(void)
427 if (input_buffer_pos
>= input_buffer_size
)
428 fatal_error( "%s is a truncated file\n", input_buffer_filename
);
429 return input_buffer
[input_buffer_pos
++];
432 unsigned short get_word(void)
436 if (input_buffer_pos
+ sizeof(ret
) > input_buffer_size
)
437 fatal_error( "%s is a truncated file\n", input_buffer_filename
);
438 memcpy( &ret
, input_buffer
+ input_buffer_pos
, sizeof(ret
) );
439 if (byte_swapped
) ret
= (ret
<< 8) | (ret
>> 8);
440 input_buffer_pos
+= sizeof(ret
);
444 unsigned int get_dword(void)
448 if (input_buffer_pos
+ sizeof(ret
) > input_buffer_size
)
449 fatal_error( "%s is a truncated file\n", input_buffer_filename
);
450 memcpy( &ret
, input_buffer
+ input_buffer_pos
, sizeof(ret
) );
452 ret
= ((ret
<< 24) | ((ret
<< 8) & 0x00ff0000) | ((ret
>> 8) & 0x0000ff00) | (ret
>> 24));
453 input_buffer_pos
+= sizeof(ret
);
457 /* pointer-sized word */
458 void put_pword( unsigned int val
)
460 if (get_ptr_size() == 8) put_qword( val
);
461 else put_dword( val
);
464 /* output a standard header for generated files */
465 void output_standard_file_header(void)
468 output( "/* File generated automatically from %s; do not edit! */\n", spec_file_name
);
470 output( "/* File generated automatically; do not edit! */\n" );
471 output( "/* This file can be copied, modified and distributed without restriction. */\n\n" );
474 output( "\t.def @feat.00\n\t.scl 3\n\t.type 0\n\t.endef\n" );
475 output( "\t.globl @feat.00\n" );
476 output( ".set @feat.00, 1\n" );
480 output( "\t.syntax unified\n" );
481 output( "\t.thumb\n" );
485 /* dump a byte stream into the assembly code */
486 void dump_bytes( const void *buffer
, unsigned int size
)
489 const unsigned char *ptr
= buffer
;
492 output( "\t.byte " );
493 for (i
= 0; i
< size
- 1; i
++, ptr
++)
495 if ((i
% 16) == 15) output( "0x%02x\n\t.byte ", *ptr
);
496 else output( "0x%02x,", *ptr
);
498 output( "0x%02x\n", *ptr
);
502 /*******************************************************************
505 * Open a file in the given srcdir and set the input_file_name global variable.
507 FILE *open_input_file( const char *srcdir
, const char *name
)
510 FILE *file
= fopen( name
, "r" );
514 fullname
= strmake( "%s/%s", srcdir
, name
);
515 file
= fopen( fullname
, "r" );
517 else fullname
= xstrdup( name
);
519 if (!file
) fatal_error( "Cannot open file '%s'\n", fullname
);
520 input_file_name
= fullname
;
526 /*******************************************************************
529 * Close the current input file (must have been opened with open_input_file).
531 void close_input_file( FILE *file
)
534 free( input_file_name
);
535 input_file_name
= NULL
;
540 /*******************************************************************
543 void open_output_file(void)
545 if (output_file_name
)
547 if (strendswith( output_file_name
, ".o" ))
548 output_file_source_name
= open_temp_output_file( ".s" );
550 if (!(output_file
= fopen( output_file_name
, "w" )))
551 fatal_error( "Unable to create output file '%s'\n", output_file_name
);
553 else output_file
= stdout
;
557 /*******************************************************************
560 void close_output_file(void)
562 if (!output_file
|| !output_file_name
) return;
563 if (fclose( output_file
) < 0) fatal_perror( "fclose" );
564 if (output_file_source_name
) assemble_file( output_file_source_name
, output_file_name
);
569 /*******************************************************************
570 * open_temp_output_file
572 char *open_temp_output_file( const char *suffix
)
574 char *tmp_file
= make_temp_file( output_file_name
, suffix
);
575 if (!(output_file
= fopen( tmp_file
, "w" )))
576 fatal_error( "Unable to create output file '%s'\n", tmp_file
);
581 /*******************************************************************
582 * remove_stdcall_decoration
584 * Remove a possible @xx suffix from a function name.
585 * Return the numerical value of the suffix, or -1 if none.
587 int remove_stdcall_decoration( char *name
)
589 char *p
, *end
= strrchr( name
, '@' );
590 if (!end
|| !end
[1] || end
== name
) return -1;
591 if (target
.cpu
!= CPU_i386
) return -1;
592 /* make sure all the rest is digits */
593 for (p
= end
+ 1; *p
; p
++) if (!isdigit(*p
)) return -1;
595 return atoi( end
+ 1 );
599 /*******************************************************************
602 * Run a file through the assembler.
604 void assemble_file( const char *src_file
, const char *obj_file
)
606 struct strarray args
= get_as_command();
607 strarray_add( &args
, "-o" );
608 strarray_add( &args
, obj_file
);
609 strarray_add( &args
, src_file
);
614 /*******************************************************************
617 * Create a new dll spec file descriptor
619 DLLSPEC
*alloc_dll_spec(void)
623 spec
= xmalloc( sizeof(*spec
) );
624 memset( spec
, 0, sizeof(*spec
) );
625 spec
->type
= SPEC_WIN32
;
626 spec
->base
= MAX_ORDINALS
;
627 spec
->characteristics
= IMAGE_FILE_EXECUTABLE_IMAGE
;
628 spec
->subsystem
= IMAGE_SUBSYSTEM_WINDOWS_CUI
;
629 spec
->subsystem_major
= 4;
630 spec
->subsystem_minor
= 0;
631 spec
->syscall_table
= 0;
632 if (get_ptr_size() > 4)
633 spec
->characteristics
|= IMAGE_FILE_LARGE_ADDRESS_AWARE
;
635 spec
->characteristics
|= IMAGE_FILE_32BIT_MACHINE
;
636 spec
->dll_characteristics
= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
;
641 /*******************************************************************
644 * Free dll spec file descriptor
646 void free_dll_spec( DLLSPEC
*spec
)
650 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
652 ORDDEF
*odp
= &spec
->entry_points
[i
];
654 free( odp
->export_name
);
655 free( odp
->link_name
);
657 free( spec
->file_name
);
658 free( spec
->dll_name
);
659 free( spec
->c_name
);
660 free( spec
->init_func
);
661 free( spec
->entry_points
);
663 free( spec
->ordinals
);
664 free( spec
->resources
);
669 /*******************************************************************
672 * Map a string to a valid C identifier.
674 char *make_c_identifier( const char *str
)
676 char *p
, buffer
[256];
678 for (p
= buffer
; *str
&& p
< buffer
+sizeof(buffer
)-1; p
++, str
++)
680 if (isalnum(*str
)) *p
= *str
;
684 return xstrdup( buffer
);
688 /*******************************************************************
691 * Generate an internal name for a stub entry point.
693 const char *get_stub_name( const ORDDEF
*odp
, const DLLSPEC
*spec
)
698 if (odp
->name
|| odp
->export_name
)
701 buffer
= strmake( "__wine_stub_%s", odp
->name
? odp
->name
: odp
->export_name
);
702 /* make sure name is a legal C identifier */
703 for (p
= buffer
; *p
; p
++) if (!isalnum(*p
) && *p
!= '_') break;
704 if (!*p
) return buffer
;
707 buffer
= strmake( "__wine_stub_%s_%d", make_c_identifier(spec
->file_name
), odp
->ordinal
);
711 /* return the stdcall-decorated name for an entry point */
712 const char *get_abi_name( const ORDDEF
*odp
, const char *name
)
717 if (target
.cpu
!= CPU_i386
) return name
;
724 if (odp
->flags
& FLAG_THISCALL
) return name
;
725 if (odp
->flags
& FLAG_FASTCALL
) ret
= strmake( "@%s@%u", name
, get_args_size( odp
));
726 else if (!kill_at
) ret
= strmake( "%s@%u", name
, get_args_size( odp
));
731 if (odp
->flags
& FLAG_THISCALL
) ret
= strmake( "__thiscall_%s", name
);
732 else if (odp
->flags
& FLAG_FASTCALL
) ret
= strmake( "__fastcall_%s", name
);
738 if (is_pe() && !kill_at
)
740 int args
= get_args_size( odp
);
741 if (odp
->flags
& FLAG_REGISTER
) args
+= get_ptr_size(); /* context argument */
742 ret
= strmake( "%s@%u", name
, args
);
756 const char *get_link_name( const ORDDEF
*odp
)
758 return get_abi_name( odp
, odp
->link_name
);
761 /*******************************************************************
764 * Sort a list of functions, removing duplicates.
766 int sort_func_list( ORDDEF
**list
, int count
, int (*compare
)(const void *, const void *) )
770 if (!count
) return 0;
771 qsort( list
, count
, sizeof(*list
), compare
);
772 for (i
= j
= 0; i
< count
; i
++) if (compare( &list
[j
], &list
[i
] )) list
[++j
] = list
[i
];
777 /*****************************************************************
778 * Function: get_alignment
781 * According to the info page for gas, the .align directive behaves
782 * differently on different systems. On some architectures, the
783 * argument of a .align directive is the number of bytes to pad to, so
784 * to align on an 8-byte boundary you'd say
786 * On other systems, the argument is "the number of low-order zero bits
787 * that the location counter must have after advancement." So to
788 * align on an 8-byte boundary you'd say
791 * The reason gas is written this way is that it's trying to mimic
792 * native assemblers for the various architectures it runs on. gas
793 * provides other directives that work consistently across
794 * architectures, but of course we want to work on all arches with or
795 * without gas. Hence this function.
799 * align -- the number of bytes to align to. Must be a power of 2.
801 unsigned int get_alignment(unsigned int align
)
805 assert( !(align
& (align
- 1)) );
811 if (target
.platform
!= PLATFORM_APPLE
) return align
;
816 while ((1u << n
) != align
) n
++;
824 /* return the page size for the target CPU */
825 unsigned int get_page_size(void)
827 return 0x1000; /* same on all platforms */
830 /* return the total size in bytes of the arguments on the stack */
831 unsigned int get_args_size( const ORDDEF
*odp
)
835 for (i
= size
= 0; i
< odp
->u
.func
.nb_args
; i
++)
837 switch (odp
->u
.func
.args
[i
])
841 if (target
.cpu
== CPU_ARM
) size
= (size
+ 7) & ~7;
845 /* int128 is passed as pointer on x86_64 */
846 if (target
.cpu
!= CPU_x86_64
)
853 size
+= get_ptr_size();
860 /* return the assembly name for a C symbol */
861 const char *asm_name( const char *sym
)
865 switch (target
.platform
)
868 case PLATFORM_WINDOWS
:
869 if (target
.cpu
!= CPU_i386
) return sym
;
870 if (sym
[0] == '@') return sym
; /* fastcall */
873 if (sym
[0] == '.' && sym
[1] == 'L') return sym
;
875 buffer
= strmake( "_%s", sym
);
882 /* return an assembly function declaration for a C function name */
883 const char *func_declaration( const char *func
)
887 switch (target
.platform
)
892 case PLATFORM_WINDOWS
:
894 buffer
= strmake( ".def %s\n\t.scl 2\n\t.type 32\n\t.endef%s", asm_name(func
),
895 thumb_mode
? "\n\t.thumb_func" : "" );
902 buffer
= strmake( ".type %s,%%function%s", func
,
903 thumb_mode
? "\n\t.thumb_func" : "" );
906 buffer
= strmake( ".type %s,%%function", func
);
909 buffer
= strmake( ".type %s,@function", func
);
917 /* output a size declaration for an assembly function */
918 void output_function_size( const char *name
)
920 switch (target
.platform
)
924 case PLATFORM_WINDOWS
:
927 output( "\t.size %s, .-%s\n", name
, name
);
932 /* output a .cfi directive */
933 void output_cfi( const char *format
, ... )
937 if (!unwind_tables
) return;
938 va_start( valist
, format
);
939 fputc( '\t', output_file
);
940 vfprintf( output_file
, format
, valist
);
941 fputc( '\n', output_file
);
945 /* output an RVA pointer */
946 void output_rva( const char *format
, ... )
950 va_start( valist
, format
);
951 switch (target
.platform
)
954 case PLATFORM_WINDOWS
:
956 vfprintf( output_file
, format
, valist
);
957 fputc( '\n', output_file
);
960 output( "\t.long " );
961 vfprintf( output_file
, format
, valist
);
962 output( " - .L__wine_spec_rva_base\n" );
968 /* output an RVA pointer or ordinal for a function thunk */
969 void output_thunk_rva( int ordinal
, const char *format
, ... )
975 va_start( valist
, format
);
976 switch (target
.platform
)
979 case PLATFORM_WINDOWS
:
981 vfprintf( output_file
, format
, valist
);
982 fputc( '\n', output_file
);
983 if (get_ptr_size() == 8) output( "\t.long 0\n" );
986 output( "\t%s ", get_asm_ptr_keyword() );
987 vfprintf( output_file
, format
, valist
);
988 output( " - .L__wine_spec_rva_base\n" );
995 if (get_ptr_size() == 4) output( "\t.long 0x8000%04x\n", ordinal
);
996 else output( "\t.quad 0x800000000000%04x\n", ordinal
);
1000 /* output the GNU note for non-exec stack */
1001 void output_gnu_stack_note(void)
1003 switch (target
.platform
)
1005 case PLATFORM_MINGW
:
1006 case PLATFORM_WINDOWS
:
1007 case PLATFORM_APPLE
:
1014 output( "\t.section .note.GNU-stack,\"\",%%progbits\n" );
1017 output( "\t.section .note.GNU-stack,\"\",@progbits\n" );
1024 /* return a global symbol declaration for an assembly symbol */
1025 const char *asm_globl( const char *func
)
1027 static char *buffer
;
1030 switch (target
.platform
)
1032 case PLATFORM_APPLE
:
1033 buffer
= strmake( "\t.globl _%s\n\t.private_extern _%s\n_%s:", func
, func
, func
);
1035 case PLATFORM_MINGW
:
1036 case PLATFORM_WINDOWS
:
1038 const char *name
= asm_name( func
);
1039 buffer
= strmake( "\t.globl %s\n%s:", name
, name
);
1043 buffer
= strmake( "\t.globl %s\n\t.hidden %s\n%s:", func
, func
, func
);
1049 const char *get_asm_ptr_keyword(void)
1051 switch(get_ptr_size())
1053 case 4: return ".long";
1054 case 8: return ".quad";
1060 const char *get_asm_string_keyword(void)
1062 switch (target
.platform
)
1064 case PLATFORM_APPLE
:
1071 const char *get_asm_export_section(void)
1073 switch (target
.platform
)
1075 case PLATFORM_APPLE
: return ".data";
1076 case PLATFORM_MINGW
:
1077 case PLATFORM_WINDOWS
: return ".section .edata";
1078 default: return ".section .data";
1082 const char *get_asm_rodata_section(void)
1084 switch (target
.platform
)
1086 case PLATFORM_APPLE
: return ".const";
1087 default: return ".section .rodata";
1091 const char *get_asm_rsrc_section(void)
1093 switch (target
.platform
)
1095 case PLATFORM_APPLE
: return ".data";
1096 case PLATFORM_MINGW
:
1097 case PLATFORM_WINDOWS
: return ".section .rsrc";
1098 default: return ".section .data";
1102 const char *get_asm_string_section(void)
1104 switch (target
.platform
)
1106 case PLATFORM_APPLE
: return ".cstring";
1107 default: return ".section .rodata";
1111 const char *arm64_page( const char *sym
)
1113 static char *buffer
;
1115 switch (target
.platform
)
1117 case PLATFORM_APPLE
:
1119 buffer
= strmake( "%s@PAGE", sym
);
1126 const char *arm64_pageoff( const char *sym
)
1128 static char *buffer
;
1131 switch (target
.platform
)
1133 case PLATFORM_APPLE
:
1134 buffer
= strmake( "%s@PAGEOFF", sym
);
1137 buffer
= strmake( ":lo12:%s", sym
);