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 static struct strarray tmp_files
;
33 static const char *output_file_source_name
;
35 /* atexit handler to clean tmp files */
36 void cleanup_tmp_files(void)
39 for (i
= 0; i
< tmp_files
.count
; i
++) if (tmp_files
.str
[i
]) unlink( tmp_files
.str
[i
] );
43 char *strupper(char *s
)
46 for (p
= s
; *p
; p
++) *p
= toupper(*p
);
50 void fatal_error( const char *msg
, ... )
53 va_start( valist
, msg
);
56 fprintf( stderr
, "%s:", input_file_name
);
58 fprintf( stderr
, "%d:", current_line
);
61 else fprintf( stderr
, "winebuild: " );
62 vfprintf( stderr
, msg
, valist
);
67 void fatal_perror( const char *msg
, ... )
70 va_start( valist
, msg
);
73 fprintf( stderr
, "%s:", input_file_name
);
75 fprintf( stderr
, "%d:", current_line
);
78 vfprintf( stderr
, msg
, valist
);
84 void error( const char *msg
, ... )
87 va_start( valist
, msg
);
90 fprintf( stderr
, "%s:", input_file_name
);
92 fprintf( stderr
, "%d:", current_line
);
95 vfprintf( stderr
, msg
, valist
);
100 void warning( const char *msg
, ... )
104 if (!display_warnings
) return;
105 va_start( valist
, msg
);
108 fprintf( stderr
, "%s:", input_file_name
);
110 fprintf( stderr
, "%d:", current_line
);
111 fputc( ' ', stderr
);
113 fprintf( stderr
, "warning: " );
114 vfprintf( stderr
, msg
, valist
);
118 int output( const char *format
, ... )
123 va_start( valist
, format
);
124 ret
= vfprintf( output_file
, format
, valist
);
126 if (ret
< 0) fatal_perror( "Output error" );
130 static struct strarray
get_tools_path(void)
133 static struct strarray dirs
;
137 strarray_addall( &dirs
, tools_path
);
138 strarray_addall( &dirs
, strarray_frompath( getenv( "PATH" )));
144 /* find a binary in the path */
145 static const char *find_binary( const char *prefix
, const char *name
)
147 struct strarray dirs
= get_tools_path();
148 unsigned int i
, maxlen
= 0;
152 if (strchr( name
, '/' )) return name
;
153 if (!prefix
) prefix
= "";
154 for (i
= 0; i
< dirs
.count
; i
++) maxlen
= max( maxlen
, strlen(dirs
.str
[i
]) + 2 );
155 file
= xmalloc( maxlen
+ strlen(prefix
) + strlen(name
) + sizeof(EXEEXT
) + 1 );
157 for (i
= 0; i
< dirs
.count
; i
++)
159 strcpy( file
, dirs
.str
[i
] );
160 p
= file
+ strlen(file
);
161 if (p
== file
) *p
++ = '.';
162 if (p
[-1] != '/') *p
++ = '/';
171 if (!stat( file
, &st
) && S_ISREG(st
.st_mode
) && (st
.st_mode
& 0111)) return file
;
177 void spawn( struct strarray args
)
180 const char *argv0
= find_binary( NULL
, args
.str
[0] );
182 if (argv0
) args
.str
[0] = argv0
;
183 if (verbose
) strarray_trace( args
);
185 if ((status
= strarray_spawn( args
)))
187 if (status
> 0) fatal_error( "%s failed with status %u\n", args
.str
[0], status
);
188 else fatal_perror( "winebuild" );
193 static const char *find_clang_tool( struct strarray clang
, const char *tool
)
195 const char *out
= get_temp_file_name( "print_tool", ".out" );
196 struct strarray args
= empty_strarray
;
202 strarray_addall( &args
, clang
);
203 strarray_add( &args
, strmake( "-print-prog-name=%s", tool
));
204 if (verbose
) strarray_add( &args
, "-v" );
206 sout
= dup( fileno(stdout
) );
207 freopen( out
, "w", stdout
);
211 dup2( sout
, fileno(stdout
) );
215 if (stat(out
, &st
) || !st
.st_size
) return NULL
;
217 path
= xmalloc(st
.st_size
+ 1);
218 sout
= open(out
, O_RDONLY
);
219 if (sout
== -1) return NULL
;
220 cnt
= read(sout
, path
, st
.st_size
);
223 if ((p
= strchr(path
, '\n'))) *p
= 0;
224 /* clang returns passed command instead of full path if the tool could not be found */
225 if (!strcmp(path
, tool
))
233 /* find a build tool in the path, trying the various names */
234 struct strarray
find_tool( const char *name
, const char * const *names
)
236 struct strarray ret
= empty_strarray
;
238 const char *alt_names
[2];
249 if ((file
= find_binary( target_alias
, *names
))) break;
253 if (!file
&& strcmp( name
, "as" )) /* llvm-as is not a gas replacement */
255 if (cc_command
.count
) file
= find_clang_tool( cc_command
, name
);
256 if (!file
&& !(file
= find_binary( "llvm", name
)))
258 struct strarray clang
= empty_strarray
;
259 strarray_add( &clang
, "clang" );
260 file
= find_clang_tool( clang
, strmake( "llvm-%s", name
));
263 if (!file
) fatal_error( "cannot find the '%s' tool\n", name
);
265 strarray_add( &ret
, file
);
269 /* find a link tool in the path */
270 struct strarray
find_link_tool(void)
272 struct strarray ret
= empty_strarray
;
273 const char *file
= NULL
;
275 if (cc_command
.count
) file
= find_clang_tool( cc_command
, "lld-link" );
276 if (!file
) file
= find_binary( NULL
, "lld-link" );
279 struct strarray clang
= empty_strarray
;
280 strarray_add( &clang
, "clang" );
281 file
= find_clang_tool( clang
, "lld-link" );
284 if (!file
) fatal_error( "cannot find the 'lld-link' tool\n" );
285 strarray_add( &ret
, file
);
289 struct strarray
get_as_command(void)
291 struct strarray args
= empty_strarray
;
294 if (cc_command
.count
)
296 strarray_addall( &args
, cc_command
);
297 strarray_add( &args
, "-xassembler" );
298 strarray_add( &args
, "-c" );
299 if (force_pointer_size
)
300 strarray_add( &args
, (force_pointer_size
== 8) ? "-m64" : "-m32" );
301 if (cpu_option
) strarray_add( &args
, strmake("-mcpu=%s", cpu_option
) );
302 if (fpu_option
) strarray_add( &args
, strmake("-mfpu=%s", fpu_option
) );
303 if (arch_option
) strarray_add( &args
, strmake("-march=%s", arch_option
) );
304 for (i
= 0; i
< tools_path
.count
; i
++)
305 strarray_add( &args
, strmake("-B%s", tools_path
.str
[i
] ));
309 if (!as_command
.count
)
311 static const char * const commands
[] = { "gas", "as", NULL
};
312 as_command
= find_tool( "as", commands
);
315 strarray_addall( &args
, as_command
);
317 if (force_pointer_size
)
319 switch (target
.platform
)
322 strarray_add( &args
, "-arch" );
323 strarray_add( &args
, (force_pointer_size
== 8) ? "x86_64" : "i386" );
326 strarray_add( &args
, (force_pointer_size
== 8) ? "--64" : "--32" );
331 if (cpu_option
) strarray_add( &args
, strmake("-mcpu=%s", cpu_option
) );
332 if (fpu_option
) strarray_add( &args
, strmake("-mfpu=%s", fpu_option
) );
336 struct strarray
get_ld_command(void)
338 struct strarray args
= empty_strarray
;
340 if (!ld_command
.count
)
342 static const char * const commands
[] = { "ld", "gld", NULL
};
343 ld_command
= find_tool( "ld", commands
);
346 strarray_addall( &args
, ld_command
);
348 if (force_pointer_size
)
350 switch (target
.platform
)
353 strarray_add( &args
, "-arch" );
354 strarray_add( &args
, (force_pointer_size
== 8) ? "x86_64" : "i386" );
356 case PLATFORM_FREEBSD
:
357 strarray_add( &args
, "-m" );
358 strarray_add( &args
, (force_pointer_size
== 8) ? "elf_x86_64_fbsd" : "elf_i386_fbsd" );
361 case PLATFORM_WINDOWS
:
362 strarray_add( &args
, "-m" );
363 strarray_add( &args
, (force_pointer_size
== 8) ? "i386pep" : "i386pe" );
366 strarray_add( &args
, "-m" );
367 strarray_add( &args
, (force_pointer_size
== 8) ? "elf_x86_64" : "elf_i386" );
372 if (target
.cpu
== CPU_ARM
&& !is_pe())
373 strarray_add( &args
, "--no-wchar-size-warning" );
378 const char *get_nm_command(void)
380 if (!nm_command
.count
)
382 static const char * const commands
[] = { "nm", "gnm", NULL
};
383 nm_command
= find_tool( "nm", commands
);
385 if (nm_command
.count
> 1)
386 fatal_error( "multiple arguments in nm command not supported yet\n" );
387 return nm_command
.str
[0];
390 /* get a name for a temp file, automatically cleaned up on exit */
391 char *get_temp_file_name( const char *prefix
, const char *suffix
)
396 if (prefix
) prefix
= get_basename_noext( prefix
);
397 fd
= make_temp_file( prefix
, suffix
, &name
);
399 strarray_add( &tmp_files
, name
);
403 /*******************************************************************
406 * Function for reading from/writing to a memory buffer.
409 int byte_swapped
= 0;
410 const char *input_buffer_filename
;
411 const unsigned char *input_buffer
;
412 size_t input_buffer_pos
;
413 size_t input_buffer_size
;
414 unsigned char *output_buffer
;
415 size_t output_buffer_pos
;
416 size_t output_buffer_size
;
418 void init_input_buffer( const char *file
)
422 unsigned char *buffer
;
424 if ((fd
= open( file
, O_RDONLY
| O_BINARY
)) == -1) fatal_perror( "Cannot open %s", file
);
425 if ((fstat( fd
, &st
) == -1)) fatal_perror( "Cannot stat %s", file
);
426 if (!st
.st_size
) fatal_error( "%s is an empty file\n", file
);
427 input_buffer
= buffer
= xmalloc( st
.st_size
);
428 if (read( fd
, buffer
, st
.st_size
) != st
.st_size
) fatal_error( "Cannot read %s\n", file
);
430 input_buffer_filename
= xstrdup( file
);
431 input_buffer_size
= st
.st_size
;
432 input_buffer_pos
= 0;
436 unsigned char get_byte(void)
438 if (input_buffer_pos
>= input_buffer_size
)
439 fatal_error( "%s is a truncated file\n", input_buffer_filename
);
440 return input_buffer
[input_buffer_pos
++];
443 unsigned short get_word(void)
447 if (input_buffer_pos
+ sizeof(ret
) > input_buffer_size
)
448 fatal_error( "%s is a truncated file\n", input_buffer_filename
);
449 memcpy( &ret
, input_buffer
+ input_buffer_pos
, sizeof(ret
) );
450 if (byte_swapped
) ret
= (ret
<< 8) | (ret
>> 8);
451 input_buffer_pos
+= sizeof(ret
);
455 unsigned int get_dword(void)
459 if (input_buffer_pos
+ sizeof(ret
) > input_buffer_size
)
460 fatal_error( "%s is a truncated file\n", input_buffer_filename
);
461 memcpy( &ret
, input_buffer
+ input_buffer_pos
, sizeof(ret
) );
463 ret
= ((ret
<< 24) | ((ret
<< 8) & 0x00ff0000) | ((ret
>> 8) & 0x0000ff00) | (ret
>> 24));
464 input_buffer_pos
+= sizeof(ret
);
468 /* pointer-sized word */
469 void put_pword( unsigned int val
)
471 if (get_ptr_size() == 8) put_qword( val
);
472 else put_dword( val
);
475 /* output a standard header for generated files */
476 void output_standard_file_header(void)
479 output( "/* File generated automatically from %s; do not edit! */\n", spec_file_name
);
481 output( "/* File generated automatically; do not edit! */\n" );
482 output( "/* This file can be copied, modified and distributed without restriction. */\n\n" );
485 output( "\t.def @feat.00\n\t.scl 3\n\t.type 0\n\t.endef\n" );
486 output( "\t.globl @feat.00\n" );
487 output( ".set @feat.00, 1\n" );
491 output( "\t.syntax unified\n" );
492 output( "\t.thumb\n" );
496 /* dump a byte stream into the assembly code */
497 void dump_bytes( const void *buffer
, unsigned int size
)
500 const unsigned char *ptr
= buffer
;
503 output( "\t.byte " );
504 for (i
= 0; i
< size
- 1; i
++, ptr
++)
506 if ((i
% 16) == 15) output( "0x%02x\n\t.byte ", *ptr
);
507 else output( "0x%02x,", *ptr
);
509 output( "0x%02x\n", *ptr
);
513 /*******************************************************************
516 * Open a file in the given srcdir and set the input_file_name global variable.
518 FILE *open_input_file( const char *srcdir
, const char *name
)
521 FILE *file
= fopen( name
, "r" );
525 fullname
= strmake( "%s/%s", srcdir
, name
);
526 file
= fopen( fullname
, "r" );
528 else fullname
= xstrdup( name
);
530 if (!file
) fatal_error( "Cannot open file '%s'\n", fullname
);
531 input_file_name
= fullname
;
537 /*******************************************************************
540 * Close the current input file (must have been opened with open_input_file).
542 void close_input_file( FILE *file
)
545 free( input_file_name
);
546 input_file_name
= NULL
;
551 /*******************************************************************
554 void open_output_file(void)
556 if (output_file_name
)
558 if (strendswith( output_file_name
, ".o" ))
559 output_file_source_name
= open_temp_output_file( ".s" );
561 if (!(output_file
= fopen( output_file_name
, "w" )))
562 fatal_error( "Unable to create output file '%s'\n", output_file_name
);
564 else output_file
= stdout
;
568 /*******************************************************************
571 void close_output_file(void)
573 if (!output_file
|| !output_file_name
) return;
574 if (fclose( output_file
) < 0) fatal_perror( "fclose" );
575 if (output_file_source_name
) assemble_file( output_file_source_name
, output_file_name
);
580 /*******************************************************************
581 * open_temp_output_file
583 char *open_temp_output_file( const char *suffix
)
585 char *tmp_file
= get_temp_file_name( output_file_name
, suffix
);
586 if (!(output_file
= fopen( tmp_file
, "w" )))
587 fatal_error( "Unable to create output file '%s'\n", tmp_file
);
592 /*******************************************************************
593 * remove_stdcall_decoration
595 * Remove a possible @xx suffix from a function name.
596 * Return the numerical value of the suffix, or -1 if none.
598 int remove_stdcall_decoration( char *name
)
600 char *p
, *end
= strrchr( name
, '@' );
601 if (!end
|| !end
[1] || end
== name
) return -1;
602 if (target
.cpu
!= CPU_i386
) return -1;
603 /* make sure all the rest is digits */
604 for (p
= end
+ 1; *p
; p
++) if (!isdigit(*p
)) return -1;
606 return atoi( end
+ 1 );
610 /*******************************************************************
613 * Run a file through the assembler.
615 void assemble_file( const char *src_file
, const char *obj_file
)
617 struct strarray args
= get_as_command();
618 strarray_add( &args
, "-o" );
619 strarray_add( &args
, obj_file
);
620 strarray_add( &args
, src_file
);
625 /*******************************************************************
628 * Create a new dll spec file descriptor
630 DLLSPEC
*alloc_dll_spec(void)
634 spec
= xmalloc( sizeof(*spec
) );
635 memset( spec
, 0, sizeof(*spec
) );
636 spec
->type
= SPEC_WIN32
;
637 spec
->base
= MAX_ORDINALS
;
638 spec
->characteristics
= IMAGE_FILE_EXECUTABLE_IMAGE
;
640 spec
->subsystem_major
= 4;
641 spec
->subsystem_minor
= 0;
642 spec
->syscall_table
= 0;
643 if (get_ptr_size() > 4)
644 spec
->characteristics
|= IMAGE_FILE_LARGE_ADDRESS_AWARE
;
646 spec
->characteristics
|= IMAGE_FILE_32BIT_MACHINE
;
647 spec
->dll_characteristics
= IMAGE_DLLCHARACTERISTICS_NX_COMPAT
;
652 /*******************************************************************
655 * Free dll spec file descriptor
657 void free_dll_spec( DLLSPEC
*spec
)
661 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
663 ORDDEF
*odp
= &spec
->entry_points
[i
];
665 free( odp
->export_name
);
666 free( odp
->link_name
);
668 free( spec
->file_name
);
669 free( spec
->dll_name
);
670 free( spec
->c_name
);
671 free( spec
->init_func
);
672 free( spec
->entry_points
);
674 free( spec
->ordinals
);
675 free( spec
->resources
);
680 /*******************************************************************
683 * Map a string to a valid C identifier.
685 char *make_c_identifier( const char *str
)
687 char *p
, buffer
[256];
689 for (p
= buffer
; *str
&& p
< buffer
+sizeof(buffer
)-1; p
++, str
++)
691 if (isalnum(*str
)) *p
= *str
;
695 return xstrdup( buffer
);
699 /*******************************************************************
702 * Generate an internal name for a stub entry point.
704 const char *get_stub_name( const ORDDEF
*odp
, const DLLSPEC
*spec
)
709 if (odp
->name
|| odp
->export_name
)
712 buffer
= strmake( "__wine_stub_%s", odp
->name
? odp
->name
: odp
->export_name
);
713 /* make sure name is a legal C identifier */
714 for (p
= buffer
; *p
; p
++) if (!isalnum(*p
) && *p
!= '_') break;
715 if (!*p
) return buffer
;
718 buffer
= strmake( "__wine_stub_%s_%d", make_c_identifier(spec
->file_name
), odp
->ordinal
);
722 /* return the stdcall-decorated name for an entry point */
723 const char *get_link_name( const ORDDEF
*odp
)
728 if (target
.cpu
!= CPU_i386
) return odp
->link_name
;
735 if (odp
->flags
& FLAG_THISCALL
) return odp
->link_name
;
736 if (odp
->flags
& FLAG_FASTCALL
) ret
= strmake( "@%s@%u", odp
->link_name
, get_args_size( odp
));
737 else if (!kill_at
) ret
= strmake( "%s@%u", odp
->link_name
, get_args_size( odp
));
738 else return odp
->link_name
;
742 if (odp
->flags
& FLAG_THISCALL
) ret
= strmake( "__thiscall_%s", odp
->link_name
);
743 else if (odp
->flags
& FLAG_FASTCALL
) ret
= strmake( "__fastcall_%s", odp
->link_name
);
744 else return odp
->link_name
;
749 if (is_pe() && !kill_at
)
751 int args
= get_args_size( odp
);
752 if (odp
->flags
& FLAG_REGISTER
) args
+= get_ptr_size(); /* context argument */
753 ret
= strmake( "%s@%u", odp
->link_name
, args
);
755 else return odp
->link_name
;
759 return odp
->link_name
;
767 /*******************************************************************
770 * Sort a list of functions, removing duplicates.
772 int sort_func_list( ORDDEF
**list
, int count
, int (*compare
)(const void *, const void *) )
776 if (!count
) return 0;
777 qsort( list
, count
, sizeof(*list
), compare
);
778 for (i
= j
= 0; i
< count
; i
++) if (compare( &list
[j
], &list
[i
] )) list
[++j
] = list
[i
];
783 /*****************************************************************
784 * Function: get_alignment
787 * According to the info page for gas, the .align directive behaves
788 * differently on different systems. On some architectures, the
789 * argument of a .align directive is the number of bytes to pad to, so
790 * to align on an 8-byte boundary you'd say
792 * On other systems, the argument is "the number of low-order zero bits
793 * that the location counter must have after advancement." So to
794 * align on an 8-byte boundary you'd say
797 * The reason gas is written this way is that it's trying to mimic
798 * native assemblers for the various architectures it runs on. gas
799 * provides other directives that work consistently across
800 * architectures, but of course we want to work on all arches with or
801 * without gas. Hence this function.
805 * align -- the number of bytes to align to. Must be a power of 2.
807 unsigned int get_alignment(unsigned int align
)
811 assert( !(align
& (align
- 1)) );
817 if (target
.platform
!= PLATFORM_APPLE
) return align
;
822 while ((1u << n
) != align
) n
++;
830 /* return the page size for the target CPU */
831 unsigned int get_page_size(void)
833 return 0x1000; /* same on all platforms */
836 /* return the total size in bytes of the arguments on the stack */
837 unsigned int get_args_size( const ORDDEF
*odp
)
841 for (i
= size
= 0; i
< odp
->u
.func
.nb_args
; i
++)
843 switch (odp
->u
.func
.args
[i
])
847 if (target
.cpu
== CPU_ARM
) size
= (size
+ 7) & ~7;
851 /* int128 is passed as pointer on x86_64 */
852 if (target
.cpu
!= CPU_x86_64
)
859 size
+= get_ptr_size();
866 /* return the assembly name for a C symbol */
867 const char *asm_name( const char *sym
)
871 switch (target
.platform
)
874 case PLATFORM_WINDOWS
:
875 if (target
.cpu
!= CPU_i386
) return sym
;
876 if (sym
[0] == '@') return sym
; /* fastcall */
879 if (sym
[0] == '.' && sym
[1] == 'L') return sym
;
881 buffer
= strmake( "_%s", sym
);
888 /* return an assembly function declaration for a C function name */
889 const char *func_declaration( const char *func
)
893 switch (target
.platform
)
898 case PLATFORM_WINDOWS
:
900 buffer
= strmake( ".def %s\n\t.scl 2\n\t.type 32\n\t.endef%s", asm_name(func
),
901 thumb_mode
? "\n\t.thumb_func" : "" );
908 buffer
= strmake( ".type %s,%%function%s", func
,
909 thumb_mode
? "\n\t.thumb_func" : "" );
912 buffer
= strmake( ".type %s,%%function", func
);
915 buffer
= strmake( ".type %s,@function", func
);
923 /* output a size declaration for an assembly function */
924 void output_function_size( const char *name
)
926 switch (target
.platform
)
930 case PLATFORM_WINDOWS
:
933 output( "\t.size %s, .-%s\n", name
, name
);
938 /* output a .cfi directive */
939 void output_cfi( const char *format
, ... )
943 if (!unwind_tables
) return;
944 va_start( valist
, format
);
945 fputc( '\t', output_file
);
946 vfprintf( output_file
, format
, valist
);
947 fputc( '\n', output_file
);
951 /* output an RVA pointer */
952 void output_rva( const char *format
, ... )
956 va_start( valist
, format
);
957 switch (target
.platform
)
960 case PLATFORM_WINDOWS
:
962 vfprintf( output_file
, format
, valist
);
963 fputc( '\n', output_file
);
966 output( "\t.long " );
967 vfprintf( output_file
, format
, valist
);
968 output( " - .L__wine_spec_rva_base\n" );
974 /* output the GNU note for non-exec stack */
975 void output_gnu_stack_note(void)
977 switch (target
.platform
)
980 case PLATFORM_WINDOWS
:
988 output( "\t.section .note.GNU-stack,\"\",%%progbits\n" );
991 output( "\t.section .note.GNU-stack,\"\",@progbits\n" );
998 /* return a global symbol declaration for an assembly symbol */
999 const char *asm_globl( const char *func
)
1001 static char *buffer
;
1004 switch (target
.platform
)
1006 case PLATFORM_APPLE
:
1007 buffer
= strmake( "\t.globl _%s\n\t.private_extern _%s\n_%s:", func
, func
, func
);
1009 case PLATFORM_MINGW
:
1010 case PLATFORM_WINDOWS
:
1011 buffer
= strmake( "\t.globl %s%s\n%s%s:", target
.cpu
== CPU_i386
? "_" : "", func
,
1012 target
.cpu
== CPU_i386
? "_" : "", func
);
1015 buffer
= strmake( "\t.globl %s\n\t.hidden %s\n%s:", func
, func
, func
);
1021 const char *get_asm_ptr_keyword(void)
1023 switch(get_ptr_size())
1025 case 4: return ".long";
1026 case 8: return ".quad";
1032 const char *get_asm_string_keyword(void)
1034 switch (target
.platform
)
1036 case PLATFORM_APPLE
:
1043 const char *get_asm_export_section(void)
1045 switch (target
.platform
)
1047 case PLATFORM_APPLE
: return ".data";
1048 case PLATFORM_MINGW
:
1049 case PLATFORM_WINDOWS
: return ".section .edata";
1050 default: return ".section .data";
1054 const char *get_asm_rodata_section(void)
1056 switch (target
.platform
)
1058 case PLATFORM_APPLE
: return ".const";
1059 default: return ".section .rodata";
1063 const char *get_asm_rsrc_section(void)
1065 switch (target
.platform
)
1067 case PLATFORM_APPLE
: return ".data";
1068 case PLATFORM_MINGW
:
1069 case PLATFORM_WINDOWS
: return ".section .rsrc";
1070 default: return ".section .data";
1074 const char *get_asm_string_section(void)
1076 switch (target
.platform
)
1078 case PLATFORM_APPLE
: return ".cstring";
1079 default: return ".section .rodata";
1083 const char *arm64_page( const char *sym
)
1085 static char *buffer
;
1087 switch (target
.platform
)
1089 case PLATFORM_APPLE
:
1091 buffer
= strmake( "%s@PAGE", sym
);
1098 const char *arm64_pageoff( const char *sym
)
1100 static char *buffer
;
1103 switch (target
.platform
)
1105 case PLATFORM_APPLE
:
1106 buffer
= strmake( "%s@PAGEOFF", sym
);
1109 buffer
= strmake( ":lo12:%s", sym
);