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 if (!args
.count
) strarray_add( &args
, "clang" );
197 strarray_add( &args
, strmake( "-print-prog-name=%s", tool
));
198 if (verbose
) strarray_add( &args
, "-v" );
200 sout
= dup( fileno(stdout
) );
201 freopen( out
, "w", stdout
);
205 dup2( sout
, fileno(stdout
) );
209 if (stat(out
, &st
) || !st
.st_size
) return NULL
;
211 path
= xmalloc(st
.st_size
+ 1);
212 sout
= open(out
, O_RDONLY
);
213 if (sout
== -1) return NULL
;
214 cnt
= read(sout
, path
, st
.st_size
);
217 if ((p
= strchr(path
, '\n'))) *p
= 0;
218 /* clang returns passed command instead of full path if the tool could not be found */
219 if (!strcmp(path
, tool
))
227 /* find a build tool in the path, trying the various names */
228 struct strarray
find_tool( const char *name
, const char * const *names
)
230 struct strarray ret
= empty_strarray
;
232 const char *alt_names
[2];
243 if ((file
= find_binary( target_alias
, *names
))) break;
247 if (!file
&& cc_command
.count
) file
= find_clang_tool( cc_command
, name
);
248 if (!file
) file
= find_binary( "llvm", name
);
249 if (!file
) file
= find_clang_tool( empty_strarray
, strmake( "llvm-%s", name
));
250 if (!file
) file
= find_clang_tool( empty_strarray
, name
);
252 if (!file
) fatal_error( "cannot find the '%s' tool\n", name
);
254 strarray_add( &ret
, file
);
258 /* find a link tool in the path */
259 struct strarray
find_link_tool(void)
261 struct strarray ret
= empty_strarray
;
262 const char *file
= NULL
;
264 if (cc_command
.count
) file
= find_clang_tool( cc_command
, "lld-link" );
265 if (!file
) file
= find_binary( NULL
, "lld-link" );
266 if (!file
) file
= find_clang_tool( empty_strarray
, "lld-link" );
268 if (!file
) fatal_error( "cannot find the 'lld-link' tool\n" );
269 strarray_add( &ret
, file
);
273 struct strarray
get_as_command(void)
275 struct strarray args
= empty_strarray
;
280 if (cc_command
.count
)
282 strarray_addall( &args
, cc_command
);
285 else if (as_command
.count
)
287 strarray_addall( &args
, as_command
);
289 else if ((file
= find_binary( target_alias
, "as" )) || (file
= find_binary( target_alias
, "gas ")))
291 strarray_add( &args
, file
);
293 else if ((file
= find_binary( NULL
, "clang" )))
295 strarray_add( &args
, file
);
298 strarray_add( &args
, "-target" );
299 strarray_add( &args
, target_alias
);
306 strarray_add( &args
, "-xassembler" );
307 strarray_add( &args
, "-c" );
308 if (force_pointer_size
)
309 strarray_add( &args
, (force_pointer_size
== 8) ? "-m64" : "-m32" );
310 if (cpu_option
) strarray_add( &args
, strmake("-mcpu=%s", cpu_option
) );
311 if (fpu_option
) strarray_add( &args
, strmake("-mfpu=%s", fpu_option
) );
312 if (arch_option
) strarray_add( &args
, strmake("-march=%s", arch_option
) );
313 for (i
= 0; i
< tools_path
.count
; i
++)
314 strarray_add( &args
, strmake("-B%s", tools_path
.str
[i
] ));
318 if (force_pointer_size
)
320 switch (target
.platform
)
323 strarray_add( &args
, "-arch" );
324 strarray_add( &args
, (force_pointer_size
== 8) ? "x86_64" : "i386" );
327 strarray_add( &args
, (force_pointer_size
== 8) ? "--64" : "--32" );
332 if (cpu_option
) strarray_add( &args
, strmake("-mcpu=%s", cpu_option
) );
333 if (fpu_option
) strarray_add( &args
, strmake("-mfpu=%s", fpu_option
) );
337 struct strarray
get_ld_command(void)
339 struct strarray args
= empty_strarray
;
341 if (!ld_command
.count
)
343 static const char * const commands
[] = { "ld", "gld", NULL
};
344 ld_command
= find_tool( "ld", commands
);
347 strarray_addall( &args
, ld_command
);
349 if (force_pointer_size
)
351 switch (target
.platform
)
354 strarray_add( &args
, "-arch" );
355 strarray_add( &args
, (force_pointer_size
== 8) ? "x86_64" : "i386" );
357 case PLATFORM_FREEBSD
:
358 strarray_add( &args
, "-m" );
359 strarray_add( &args
, (force_pointer_size
== 8) ? "elf_x86_64_fbsd" : "elf_i386_fbsd" );
362 case PLATFORM_WINDOWS
:
363 strarray_add( &args
, "-m" );
364 strarray_add( &args
, (force_pointer_size
== 8) ? "i386pep" : "i386pe" );
367 strarray_add( &args
, "-m" );
368 strarray_add( &args
, (force_pointer_size
== 8) ? "elf_x86_64" : "elf_i386" );
373 if (target
.cpu
== CPU_ARM
&& !is_pe())
374 strarray_add( &args
, "--no-wchar-size-warning" );
379 const char *get_nm_command(void)
381 if (!nm_command
.count
)
383 static const char * const commands
[] = { "nm", "gnm", NULL
};
384 nm_command
= find_tool( "nm", commands
);
386 if (nm_command
.count
> 1)
387 fatal_error( "multiple arguments in nm command not supported yet\n" );
388 return nm_command
.str
[0];
392 /*******************************************************************
395 * Function for reading from/writing to a memory buffer.
398 int byte_swapped
= 0;
399 const char *input_buffer_filename
;
400 const unsigned char *input_buffer
;
401 size_t input_buffer_pos
;
402 size_t input_buffer_size
;
403 unsigned char *output_buffer
;
404 size_t output_buffer_pos
;
405 size_t output_buffer_size
;
407 void init_input_buffer( const char *file
)
409 if (!(input_buffer
= read_file( file
, &input_buffer_size
))) fatal_perror( "Cannot read %s", file
);
410 if (!input_buffer_size
) fatal_error( "%s is an empty file\n", file
);
411 input_buffer_filename
= xstrdup( file
);
412 input_buffer_pos
= 0;
416 unsigned char get_byte(void)
418 if (input_buffer_pos
>= input_buffer_size
)
419 fatal_error( "%s is a truncated file\n", input_buffer_filename
);
420 return input_buffer
[input_buffer_pos
++];
423 unsigned short get_word(void)
427 if (input_buffer_pos
+ sizeof(ret
) > input_buffer_size
)
428 fatal_error( "%s is a truncated file\n", input_buffer_filename
);
429 memcpy( &ret
, input_buffer
+ input_buffer_pos
, sizeof(ret
) );
430 if (byte_swapped
) ret
= (ret
<< 8) | (ret
>> 8);
431 input_buffer_pos
+= sizeof(ret
);
435 unsigned int get_dword(void)
439 if (input_buffer_pos
+ sizeof(ret
) > input_buffer_size
)
440 fatal_error( "%s is a truncated file\n", input_buffer_filename
);
441 memcpy( &ret
, input_buffer
+ input_buffer_pos
, sizeof(ret
) );
443 ret
= ((ret
<< 24) | ((ret
<< 8) & 0x00ff0000) | ((ret
>> 8) & 0x0000ff00) | (ret
>> 24));
444 input_buffer_pos
+= sizeof(ret
);
448 /* pointer-sized word */
449 void put_pword( unsigned int val
)
451 if (get_ptr_size() == 8) put_qword( val
);
452 else put_dword( val
);
455 /* output a standard header for generated files */
456 void output_standard_file_header(void)
459 output( "/* File generated automatically from %s; do not edit! */\n", spec_file_name
);
461 output( "/* File generated automatically; do not edit! */\n" );
462 output( "/* This file can be copied, modified and distributed without restriction. */\n\n" );
465 output( "\t.def @feat.00\n\t.scl 3\n\t.type 0\n\t.endef\n" );
466 output( "\t.globl @feat.00\n" );
467 output( ".set @feat.00, 1\n" );
471 /* dump a byte stream into the assembly code */
472 void dump_bytes( const void *buffer
, unsigned int size
)
475 const unsigned char *ptr
= buffer
;
478 output( "\t.byte " );
479 for (i
= 0; i
< size
- 1; i
++, ptr
++)
481 if ((i
% 16) == 15) output( "0x%02x\n\t.byte ", *ptr
);
482 else output( "0x%02x,", *ptr
);
484 output( "0x%02x\n", *ptr
);
488 /*******************************************************************
491 * Open a file in the given srcdir and set the input_file_name global variable.
493 FILE *open_input_file( const char *srcdir
, const char *name
)
496 FILE *file
= fopen( name
, "r" );
500 fullname
= strmake( "%s/%s", srcdir
, name
);
501 file
= fopen( fullname
, "r" );
503 else fullname
= xstrdup( name
);
505 if (!file
) fatal_error( "Cannot open file '%s'\n", fullname
);
506 input_file_name
= fullname
;
512 /*******************************************************************
515 * Close the current input file (must have been opened with open_input_file).
517 void close_input_file( FILE *file
)
520 free( input_file_name
);
521 input_file_name
= NULL
;
526 /*******************************************************************
529 void open_output_file(void)
531 if (output_file_name
)
533 if (strendswith( output_file_name
, ".o" ))
534 output_file_source_name
= open_temp_output_file( ".s" );
536 if (!(output_file
= fopen( output_file_name
, "w" )))
537 fatal_error( "Unable to create output file '%s'\n", output_file_name
);
539 else output_file
= stdout
;
543 /*******************************************************************
546 void close_output_file(void)
548 if (!output_file
|| !output_file_name
) return;
549 if (fclose( output_file
) < 0) fatal_perror( "fclose" );
550 if (output_file_source_name
) assemble_file( output_file_source_name
, output_file_name
);
555 /*******************************************************************
556 * open_temp_output_file
558 char *open_temp_output_file( const char *suffix
)
560 char *tmp_file
= make_temp_file( output_file_name
, suffix
);
561 if (!(output_file
= fopen( tmp_file
, "w" )))
562 fatal_error( "Unable to create output file '%s'\n", tmp_file
);
567 /*******************************************************************
568 * remove_stdcall_decoration
570 * Remove a possible @xx suffix from a function name.
571 * Return the numerical value of the suffix, or -1 if none.
573 int remove_stdcall_decoration( char *name
)
575 char *p
, *end
= strrchr( name
, '@' );
576 if (!end
|| !end
[1] || end
== name
) return -1;
577 if (target
.cpu
!= CPU_i386
) return -1;
578 /* make sure all the rest is digits */
579 for (p
= end
+ 1; *p
; p
++) if (!isdigit(*p
)) return -1;
581 return atoi( end
+ 1 );
585 /*******************************************************************
588 * Run a file through the assembler.
590 void assemble_file( const char *src_file
, const char *obj_file
)
592 struct strarray args
= get_as_command();
593 strarray_add( &args
, "-o" );
594 strarray_add( &args
, obj_file
);
595 strarray_add( &args
, src_file
);
600 /*******************************************************************
603 * Create a new dll spec file descriptor
605 DLLSPEC
*alloc_dll_spec(void)
609 spec
= xmalloc( sizeof(*spec
) );
610 memset( spec
, 0, sizeof(*spec
) );
611 spec
->type
= SPEC_WIN32
;
612 spec
->characteristics
= IMAGE_FILE_EXECUTABLE_IMAGE
;
613 spec
->subsystem
= IMAGE_SUBSYSTEM_WINDOWS_CUI
;
614 spec
->subsystem_major
= 4;
615 spec
->subsystem_minor
= 0;
616 spec
->dll_characteristics
= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
| IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
;
617 spec
->exports
.base
= MAX_ORDINALS
;
622 static void free_exports( struct exports
*entries
)
624 free( entries
->entry_points
);
625 free( entries
->names
);
626 free( entries
->ordinals
);
630 /*******************************************************************
633 * Free dll spec file descriptor
635 void free_dll_spec( DLLSPEC
*spec
)
639 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
641 ORDDEF
*odp
= &spec
->entry_points
[i
];
643 free( odp
->export_name
);
644 free( odp
->link_name
);
646 free_exports( &spec
->exports
);
647 free( spec
->file_name
);
648 free( spec
->dll_name
);
649 free( spec
->c_name
);
650 free( spec
->init_func
);
651 free( spec
->entry_points
);
652 free( spec
->resources
);
657 /*******************************************************************
660 * Map a string to a valid C identifier.
662 char *make_c_identifier( const char *str
)
664 char *p
, buffer
[256];
666 for (p
= buffer
; *str
&& p
< buffer
+sizeof(buffer
)-1; p
++, str
++)
668 if (isalnum(*str
)) *p
= *str
;
672 return xstrdup( buffer
);
676 /*******************************************************************
679 * Generate an internal name for a stub entry point.
681 const char *get_stub_name( const ORDDEF
*odp
, const DLLSPEC
*spec
)
686 if (odp
->name
|| odp
->export_name
)
689 buffer
= strmake( "__wine_stub_%s", odp
->name
? odp
->name
: odp
->export_name
);
690 /* make sure name is a legal C identifier */
691 for (p
= buffer
; *p
; p
++) if (!isalnum(*p
) && *p
!= '_') break;
692 if (!*p
) return buffer
;
695 buffer
= strmake( "__wine_stub_%s_%d", make_c_identifier(spec
->file_name
), odp
->ordinal
);
699 /* return the stdcall-decorated name for an entry point */
700 const char *get_abi_name( const ORDDEF
*odp
, const char *name
)
705 if (target
.cpu
!= CPU_i386
) return name
;
712 if (odp
->flags
& FLAG_THISCALL
) return name
;
713 if (odp
->flags
& FLAG_FASTCALL
) ret
= strmake( "@%s@%u", name
, get_args_size( odp
));
714 else if (!kill_at
) ret
= strmake( "%s@%u", name
, get_args_size( odp
));
719 if (odp
->flags
& FLAG_THISCALL
) ret
= strmake( "__thiscall_%s", name
);
720 else if (odp
->flags
& FLAG_FASTCALL
) ret
= strmake( "__fastcall_%s", name
);
726 if (is_pe() && !kill_at
)
728 int args
= get_args_size( odp
);
729 if (odp
->flags
& FLAG_REGISTER
) args
+= get_ptr_size(); /* context argument */
730 ret
= strmake( "%s@%u", name
, args
);
744 const char *get_link_name( const ORDDEF
*odp
)
746 return get_abi_name( odp
, odp
->link_name
);
749 /*******************************************************************
752 * Sort a list of functions, removing duplicates.
754 int sort_func_list( ORDDEF
**list
, int count
, int (*compare
)(const void *, const void *) )
758 if (!count
) return 0;
759 qsort( list
, count
, sizeof(*list
), compare
);
760 for (i
= j
= 0; i
< count
; i
++) if (compare( &list
[j
], &list
[i
] )) list
[++j
] = list
[i
];
765 /* return the page size for the target CPU */
766 unsigned int get_page_size(void)
768 return 0x1000; /* same on all platforms */
771 /* return the total size in bytes of the arguments on the stack */
772 unsigned int get_args_size( const ORDDEF
*odp
)
776 for (i
= size
= 0; i
< odp
->u
.func
.nb_args
; i
++)
778 switch (odp
->u
.func
.args
[i
])
782 if (target
.cpu
== CPU_ARM
) size
= (size
+ 7) & ~7;
786 /* int128 is passed as pointer on x86_64 */
787 if (target
.cpu
!= CPU_x86_64
)
794 size
+= get_ptr_size();
801 /* return the assembly name for a C symbol */
802 const char *asm_name( const char *sym
)
806 switch (target
.platform
)
809 case PLATFORM_WINDOWS
:
810 if (target
.cpu
!= CPU_i386
) return sym
;
811 if (sym
[0] == '@') return sym
; /* fastcall */
814 if (sym
[0] == '.' && sym
[1] == 'L') return sym
;
816 buffer
= strmake( "_%s", sym
);
823 /* return the assembly name for an ARM64/ARM64EC function */
824 const char *arm64_name( const char *sym
)
826 if (target
.cpu
== CPU_ARM64EC
) return strmake( "\"#%s\"", sym
);
827 return asm_name( sym
);
830 /* return an assembly function declaration for a C function name */
831 void output_function_header( const char *func
, int global
)
833 const char *name
= arm64_name( func
);
835 output( "\t.text\n" );
837 switch (target
.platform
)
840 if (global
) output( "\t.globl %s\n\t.private_extern %s\n", name
, name
);
843 case PLATFORM_WINDOWS
:
844 if (target
.cpu
== CPU_ARM64EC
) output( ".section .text,\"xr\",discard,%s\n\t", name
);
845 output( "\t.def %s\n\t.scl 2\n\t.type 32\n\t.endef\n", name
);
846 if (global
) output( "\t.globl %s\n", name
);
849 output( "\t.type %s,@function\n", name
);
850 if (global
) output( "\t.globl %s\n\t.hidden %s\n", name
, name
);
853 output( "\t.balign 4\n" );
854 output( "%s:\n", name
);
857 /* output a size declaration for an assembly function */
858 void output_function_size( const char *name
)
860 switch (target
.platform
)
864 case PLATFORM_WINDOWS
:
867 output( "\t.size %s, .-%s\n", name
, name
);
872 /* output a .cfi directive */
873 void output_cfi( const char *format
, ... )
877 if (!unwind_tables
) return;
878 va_start( valist
, format
);
879 fputc( '\t', output_file
);
880 vfprintf( output_file
, format
, valist
);
881 fputc( '\n', output_file
);
885 /* output a .seh directive */
886 void output_seh( const char *format
, ... )
890 if (!is_pe()) return;
891 va_start( valist
, format
);
892 fputc( '\t', output_file
);
893 vfprintf( output_file
, format
, valist
);
894 fputc( '\n', output_file
);
898 /* output an RVA pointer */
899 void output_rva( const char *format
, ... )
903 va_start( valist
, format
);
904 switch (target
.platform
)
907 case PLATFORM_WINDOWS
:
909 vfprintf( output_file
, format
, valist
);
910 fputc( '\n', output_file
);
913 output( "\t.long " );
914 vfprintf( output_file
, format
, valist
);
915 output( " - .L__wine_spec_rva_base\n" );
921 /* output an RVA pointer or ordinal for a function thunk */
922 void output_thunk_rva( int ordinal
, const char *format
, ... )
928 va_start( valist
, format
);
929 switch (target
.platform
)
932 case PLATFORM_WINDOWS
:
934 vfprintf( output_file
, format
, valist
);
935 fputc( '\n', output_file
);
936 if (get_ptr_size() == 8) output( "\t.long 0\n" );
939 output( "\t%s ", get_asm_ptr_keyword() );
940 vfprintf( output_file
, format
, valist
);
941 output( " - .L__wine_spec_rva_base\n" );
948 if (get_ptr_size() == 4) output( "\t.long 0x8000%04x\n", ordinal
);
949 else output( "\t.quad 0x800000000000%04x\n", ordinal
);
953 /* output the GNU note for non-exec stack */
954 void output_gnu_stack_note(void)
956 switch (target
.platform
)
959 case PLATFORM_WINDOWS
:
963 output( "\t.section .note.GNU-stack,\"\",@progbits\n" );
968 /* return a global symbol declaration for an assembly symbol */
969 const char *asm_globl( const char *func
)
974 switch (target
.platform
)
977 buffer
= strmake( "\t.globl _%s\n\t.private_extern _%s\n_%s:", func
, func
, func
);
980 case PLATFORM_WINDOWS
:
982 const char *name
= asm_name( func
);
983 buffer
= strmake( "\t.globl %s\n%s:", name
, name
);
987 buffer
= strmake( "\t.globl %s\n\t.hidden %s\n%s:", func
, func
, func
);
993 const char *get_asm_ptr_keyword(void)
995 switch(get_ptr_size())
997 case 4: return ".long";
998 case 8: return ".quad";
1004 const char *get_asm_string_keyword(void)
1006 switch (target
.platform
)
1008 case PLATFORM_APPLE
:
1015 const char *get_asm_export_section(void)
1017 switch (target
.platform
)
1019 case PLATFORM_APPLE
: return ".data";
1020 case PLATFORM_MINGW
:
1021 case PLATFORM_WINDOWS
: return ".section .edata";
1022 default: return ".section .data";
1026 const char *get_asm_rodata_section(void)
1028 switch (target
.platform
)
1030 case PLATFORM_APPLE
: return ".const";
1031 default: return ".section .rodata";
1035 const char *get_asm_rsrc_section(void)
1037 switch (target
.platform
)
1039 case PLATFORM_APPLE
: return ".data";
1040 case PLATFORM_MINGW
:
1041 case PLATFORM_WINDOWS
: return ".section .rsrc";
1042 default: return ".section .data";
1046 const char *get_asm_string_section(void)
1048 switch (target
.platform
)
1050 case PLATFORM_APPLE
: return ".cstring";
1051 default: return ".section .rodata";