/programs/develop/ktcc/trunk/libc/stdio/getchar.c |
---|
File deleted |
/programs/develop/ktcc/trunk/libc/stdio/gets.c |
---|
File deleted |
\ No newline at end of file |
/programs/develop/ktcc/trunk/libc/stdio/conio.c |
---|
File deleted |
/programs/develop/ktcc/trunk/libc/stdio/puts.c |
---|
File deleted |
\ No newline at end of file |
/programs/develop/ktcc/trunk/libc/stdio/printf.c |
---|
1,23 → 1,78 |
#include <stdlib.h> |
#include <stdio.h> |
#include <conio.h> |
#include <string.h> |
#include <kolibrisys.h> |
char* dllname="/sys/lib/console.obj"; |
int console_init_status; |
char* imports[] = {"START","version","con_init","con_write_asciiz","con_printf","con_exit",NULL}; |
char* caption = "Console app"; |
extern int __argc; |
extern char** __argv; |
extern char* __path; |
dword* dll_ver; |
void stdcall (* con_init)(dword wnd_width, dword wnd_height, dword scr_width, dword scr_height, const char* title); |
void stdcall (* con_write_asciiz)(const char* string); |
void cdecl (* con_printf)(const char* format,...); |
void stdcall (* con_exit)(dword bCloseWindow); |
struct import{ |
char *name; |
void *data; |
}; |
void printf_link(struct import *exp, char** imports){ |
dll_ver = (dword*) |
_ksys_cofflib_getproc(exp, imports[1]); |
con_init = (void stdcall (*)(dword , dword, dword, dword, const char*)) |
_ksys_cofflib_getproc(exp, imports[2]); |
con_printf = (void cdecl (*)(const char*,...)) |
_ksys_cofflib_getproc(exp, imports[4]); |
con_exit = (void stdcall (*)(dword)) |
_ksys_cofflib_getproc(exp, imports[5]); |
} |
int init_console(void) |
{ |
struct import * hDll; |
if((hDll = (struct import *)_ksys_cofflib_load(dllname)) == 0){ |
debug_out_str("can't load lib\n"); |
return 1; |
} |
printf_link(hDll, imports); |
// debug_out_str("dll loaded\n"); |
con_init(-1, -1, -1, -1, caption); //__argv[0] && __path dont work |
return(0); |
} |
int printf(const char *format, ...) |
{ |
int i = 0; |
int printed_simbols = 0; |
int printed_simbols; |
va_list arg; |
char simbol[]={"%s"}; |
char *s; |
va_start(arg,format); |
i=con_init_console_dll(); |
if (console_init_status==0) |
{ |
i=init_console(); |
console_init_status=1; |
} |
if (i==0) |
{ |
s=malloc(4096); |
printed_simbols=format_print(s,4096,format,arg); |
con_write_string(s, printed_simbols); |
con_printf(simbol,s); |
free(s); |
} |
return(printed_simbols); |
/programs/develop/ktcc/trunk/libc/stdio/putchar.c |
---|
1,14 → 1,7 |
#include <conio.h> |
#include <stdio.h> |
int putchar ( int ch ) |
{ |
char s[2]; |
con_init_console_dll(); |
s[0] = (char)ch; |
s[1] = '\0'; |
con_write_asciiz(s); |
printf("%c", ch); |
return ch; |
} |
/programs/develop/ktcc/trunk/libc/include/tcclib.h |
---|
File deleted |
/programs/develop/ktcc/trunk/libc/include/kos32sys1.h |
---|
File deleted |
/programs/develop/ktcc/trunk/libc/include/conio.h |
---|
File deleted |
/programs/develop/ktcc/trunk/libc/include/stdio.h |
---|
63,9 → 63,6 |
#define getc(a) fgetc(a) |
char * fgets (char * str, int num, FILE * stream); |
int putchar (int ch); |
int getchar (void); |
int puts (const char * str); |
char * gets (char * str); |
int putchar ( int character ); |
#endif |
/programs/develop/ktcc/trunk/source/RELICENSING |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/asmtest.S |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/vla_test.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/00_assignment.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/67_macro_concat.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/21_char_array.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/60_enum_redefinition.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/08_while.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/83_utf8_in_identifiers.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/39_typedef.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/20_pointer_comparison.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/16_nesting.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/62_enumerator_redefinition.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/04_for.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/31_args.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/LICENSE |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/01_comment.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/29_array_address.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/23_type_coercion.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/19_pointer_arithmetic.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/79_vla_continue.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/23_type_coercion.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/27_sizeof.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/32_led.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/47_switch_return.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/06_case.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/24_math_library.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/05_array.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/45_empty_for.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/44_scoped_declarations.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/54_goto.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/76_dollars_in_identifiers.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/38_multiple_array_index.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/37_sprintf.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/11_precedence.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/59_function_array.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/02_printf.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/67_macro_concat.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/37_sprintf.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/11_precedence.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/78_vla_label.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/56_btype_excess-1.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/73_arm64.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/14_if.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/50_logical_second_arg.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/36_array_initialisers.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/57_btype_excess-2.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/71_macro_empty_arg.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/34_array_assignment.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/33_ternary_op.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/43_void_param.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/70_floating_point_literals.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/40_stdio.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/26_character_constants.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/42_function_pointer.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/30_hanoi.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/51_static.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/80_flexarray.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/41_hashif.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/64_macro_nesting.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/09_do_while.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/02_printf.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/44_scoped_declarations.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/45_empty_for.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/41_hashif.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/15_recursion.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/49_bracket_evaluation.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/70_floating_point_literals.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/21_char_array.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/49_bracket_evaluation.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/15_recursion.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/22_floating_point.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/06_case.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/52_unnamed_enum.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/82_nocode_wanted.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/25_quicksort.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/77_push_pop_macro.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/07_function.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/12_hashdefine.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/64_macro_nesting.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/13_integer_literals.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/72_long_long_constant.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/35_sizeof.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/59_function_array.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/27_sizeof.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/28_strings.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/34_array_assignment.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/35_sizeof.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/10_pointer.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/52_unnamed_enum.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/51_static.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/78_vla_label.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/58_function_redefinition.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/77_push_pop_macro.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/07_function.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/19_pointer_arithmetic.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/000_cvttoftol.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/30_hanoi.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/57_btype_excess-2.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/01_comment.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/47_switch_return.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/17_enum.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/56_btype_excess-1.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/00_assignment.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/16_nesting.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/08_while.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/24_math_library.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/05_array.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/18_include.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/62_enumerator_redefinition.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/29_array_address.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/18_include.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/38_multiple_array_index.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/73_arm64.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/50_logical_second_arg.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/14_if.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/55_lshift_type.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/79_vla_continue.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/82_attribs_position.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/31_args.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/46_grep.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/12_hashdefine.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/75_array_in_struct_init.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/60_enum_redefinition.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/75_array_in_struct_init.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/46_grep.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/22_floating_point.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/17_enum.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/74_nocode_wanted.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/10_pointer.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/03_struct.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/42_function_pointer.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/61_undefined_enum.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/Makefile |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/03_struct.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/76_dollars_in_identifiers.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/72_long_long_constant.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/13_integer_literals.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/18_include.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/09_do_while.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/63_local_enumerator_redefinition.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/36_array_initialisers.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/58_function_redefinition.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/48_nested_break.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/32_led.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/55_lshift_type.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/39_typedef.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/20_pointer_comparison.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/83_utf8_in_identifiers.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/81_types.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/54_goto.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/82_nocode_wanted.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/71_macro_empty_arg.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/40_stdio.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/74_nocode_wanted.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/33_ternary_op.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/43_void_param.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/04_for.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/25_quicksort.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/48_nested_break.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/61_undefined_enum.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/28_strings.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tests2/26_character_constants.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/boundtest.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tcctest.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/abitest.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/CMakeLists.txt |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/Makefile |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/12.S |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/13.S |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/01.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/10.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/02.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/11.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/03.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/04.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/05.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/06.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/07.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/10.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/01.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/08.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/11.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/02.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/12.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/03.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/09.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/13.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/04.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/05.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/06.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/07.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/Makefile |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/08.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/pp/09.expect |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/gcctestsuite.sh |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/libtcc_test.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tests/tcctest.py |
---|
File deleted |
/programs/develop/ktcc/trunk/source/configure |
---|
File deleted |
/programs/develop/ktcc/trunk/source/CMakeLists.txt |
---|
File deleted |
/programs/develop/ktcc/trunk/source/texi2pod.pl |
---|
File deleted |
/programs/develop/ktcc/trunk/source/CMakeFiles/3.5.2/CompilerIdC/CMakeCCompilerId.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/CMakeFiles/3.5.2/CMakeRCCompiler.cmake |
---|
File deleted |
/programs/develop/ktcc/trunk/source/CMakeFiles/3.5.2/CMakeSystem.cmake |
---|
File deleted |
/programs/develop/ktcc/trunk/source/CMakeFiles/CMakeError.log |
---|
File deleted |
/programs/develop/ktcc/trunk/source/CMakeFiles/cmake.check_cache |
---|
File deleted |
/programs/develop/ktcc/trunk/source/CMakeFiles/CMakeOutput.log |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tccpp.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/.travis.yml |
---|
File deleted |
/programs/develop/ktcc/trunk/source/Makefile.kos32 |
---|
File deleted |
/programs/develop/ktcc/trunk/source/CodingStyle |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tcc-doc.info |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/alloca86-bt.S |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/Makefile |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/lib-arm64.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/bcheck.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/armeabi.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/libtcc1.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/alloca86_64.S |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/buildtcclib1.bat |
---|
File deleted |
\ No newline at end of file |
/programs/develop/ktcc/trunk/source/lib/alloca86_64-bt.S |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/testfp.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/alloca-arm.S |
---|
File deleted |
/programs/develop/ktcc/trunk/source/lib/alloca86.S |
---|
File deleted |
/programs/develop/ktcc/trunk/source/libtcc.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/conftest.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/include/varargs.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/include/float.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/include/stdbool.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/include/stddef.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/include/stdarg.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/.gitignore |
---|
File deleted |
/programs/develop/ktcc/trunk/source/x86_64-gen.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/stdint.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/float.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/string.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/fcntl.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/malloc.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/io.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/vadefs.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/stddef.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/wctype.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/time_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/stdlib_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/tchar_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/stdio_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/stralign_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/wchar_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/crtdbg_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/mbstring_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/search_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/string_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/sys/timeb_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/conio_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sec_api/io_s.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/process.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/stdlib.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/stdio.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/tcc/tcc_libm.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/dirent.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/math.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/time.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winsock2.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/locale.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/assert.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/windows.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/winnt.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/inaddr.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/specstrings.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/winerror.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/guiddef.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/winnls.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/windef.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/mstcpip.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/tvout.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/mswsock.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/reason.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/winbase.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/ws2def.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/basetyps.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/_bsd_types.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/winreg.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/winuser.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/poppack.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/wincon.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/winsock2.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/_timeval.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/shellapi.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/qos.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/intrin.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/psdk_inc/_ws1_undef.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/psdk_inc/_socket_types.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/psdk_inc/_ip_types.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/psdk_inc/_fd_types.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/psdk_inc/_ip_mreq1.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/psdk_inc/_xmitfile.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/psdk_inc/_wsa_errnos.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/psdk_inc/_wsadata.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/winnetwk.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/winver.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/pshpack1.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/pshpack2.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/ws2tcpip.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/pshpack4.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/wingdi.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/pshpack8.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/stralign.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/ws2ipdef.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/basetsd.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/_mingw_unicode.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/winapi/in6addr.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/tchar.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/setjmp.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/share.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/wchar.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/varargs.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/stdbool.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/conio.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/memory.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/direct.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/signal.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/mem.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/dir.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/inttypes.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/_mingw.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/excpt.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/stdarg.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/ctype.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/dos.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/errno.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sys/utime.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sys/types.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sys/locking.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sys/unistd.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sys/fcntl.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sys/stat.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sys/time.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sys/file.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/sys/timeb.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/fenv.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/values.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/include/limits.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/build-tcc-kos.bat |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/lib/crt1.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/lib/msvcrt.def |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/lib/user32.def |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/lib/dllmain.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/lib/kernel32.def |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/lib/gdi32.def |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/lib/dllcrt1.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/lib/chkstk.S |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/lib/wincrt1.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/tcc-win32.txt |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/build-tcc.bat |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/examples/hello_win.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/examples/fib.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/examples/taxi_simulator.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/examples/demo.bat |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/examples/dll.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/examples/hello_dll.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/libtcc/libtcc.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/libtcc/libtcc.def |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/vs2015/tcc.vcxproj |
---|
File deleted |
\ No newline at end of file |
/programs/develop/ktcc/trunk/source/win32/vs2015/tcc.sln |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/vs2015/libtcc.vcxproj |
---|
File deleted |
\ No newline at end of file |
/programs/develop/ktcc/trunk/source/win32/tools/tiny_impdef.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/win32/tools/tiny_libmaker.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tccgen.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/README |
---|
File deleted |
/programs/develop/ktcc/trunk/source/x86_64-asm.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/config.texi.in |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tcc-doc.texi |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tcc.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/readme_kos32.txt |
---|
File deleted |
/programs/develop/ktcc/trunk/source/tccrun.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/CMakeCache.txt |
---|
File deleted |
/programs/develop/ktcc/trunk/source/TODO |
---|
File deleted |
/programs/develop/ktcc/trunk/source/examples/ex5.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/examples/ex1.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/examples/ex2.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/examples/ex3.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/examples/ex4.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/Changelog |
---|
File deleted |
/programs/develop/ktcc/trunk/source/README.md |
---|
File deleted |
\ No newline at end of file |
/programs/develop/ktcc/trunk/source/arm64-gen.c |
---|
File deleted |
/programs/develop/ktcc/trunk/source/config.h_meos |
---|
File deleted |
/programs/develop/ktcc/trunk/source/i386-tok.h |
---|
File deleted |
/programs/develop/ktcc/trunk/source/config.h.in |
---|
File deleted |
/programs/develop/ktcc/trunk/source/Makefile |
---|
1,421 → 1,4 |
# |
# Tiny C Compiler Makefile |
# |
TOP ?= . |
include $(TOP)/config.mak |
VPATH = $(top_srcdir) |
CPPFLAGS += -I$(TOP) # for config.h |
ifneq (-$(findstring gcc,$(CC))-,-gcc-) |
ifeq (-$(findstring clang,$(CC))-,-clang-) |
# make clang accept gnuisms in libtcc1.c |
CFLAGS+=-fheinous-gnu-extensions |
endif |
endif |
CPPFLAGS_P=$(CPPFLAGS) -DCONFIG_TCC_STATIC |
CFLAGS_P=$(CFLAGS) -pg -static |
LIBS_P= |
LDFLAGS_P=$(LDFLAGS) |
ifdef CONFIG_WIN64 |
CONFIG_WIN32=yes |
endif |
ifndef CONFIG_WIN32 |
LIBS=-lm |
ifndef CONFIG_NOLDL |
LIBS+=-ldl |
endif |
endif |
# make libtcc as static or dynamic library? |
ifdef DISABLE_STATIC |
ifndef CONFIG_WIN32 |
LIBTCC=libtcc.so.1.0 |
else |
LIBTCC=libtcc.dll |
LIBTCC_DLL=yes |
LIBTCC_EXTRA=libtcc.def libtcc.a |
endif |
LINK_LIBTCC=-Wl,-rpath,"$(libdir)" |
ifdef DISABLE_RPATH |
LINK_LIBTCC= |
endif |
else |
LIBTCC=libtcc.a |
LINK_LIBTCC= |
endif |
CONFIG_$(ARCH) = yes |
NATIVE_DEFINES_$(CONFIG_i386) += -DTCC_TARGET_I386 |
NATIVE_DEFINES_$(CONFIG_x86-64) += -DTCC_TARGET_X86_64 |
NATIVE_DEFINES_$(CONFIG_WIN32) += -DTCC_TARGET_PE |
NATIVE_DEFINES_$(CONFIG_uClibc) += -DTCC_UCLIBC |
NATIVE_DEFINES_$(CONFIG_arm) += -DTCC_TARGET_ARM |
NATIVE_DEFINES_$(CONFIG_arm_eabihf) += -DTCC_ARM_EABI -DTCC_ARM_HARDFLOAT |
NATIVE_DEFINES_$(CONFIG_arm_eabi) += -DTCC_ARM_EABI |
NATIVE_DEFINES_$(CONFIG_arm_vfp) += -DTCC_ARM_VFP |
NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64 |
NATIVE_DEFINES += $(NATIVE_DEFINES_yes) |
ifeq ($(TOP),.) |
PROGS=tcc$(EXESUF) |
I386_CROSS = i386-linux-gnu-tcc$(EXESUF) |
WIN32_CROSS = i386-win-mingw32-tcc$(EXESUF) |
WIN64_CROSS = x86_64-win-mingw32-tcc$(EXESUF) |
WINCE_CROSS = arm-win-mingw32ce-tcc$(EXESUF) |
X64_CROSS = x86_64-linux-gnu-tcc$(EXESUF) |
ARM_FPA_CROSS = arm-linux-fpa-tcc$(EXESUF) |
ARM_FPA_LD_CROSS = arm-linux-fpa-ld-tcc$(EXESUF) |
ARM_VFP_CROSS = arm-linux-gnu-tcc$(EXESUF) |
ARM_EABI_CROSS = arm-linux-gnueabi-tcc$(EXESUF) |
ARM_EABIHF_CROSS = arm-linux-gnueabihf-tcc$(EXESUF) |
ARM_CROSS = $(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS) |
ARM64_CROSS = arm64-tcc$(EXESUF) |
C67_CROSS = c67-tcc$(EXESUF) |
# Legacy symlinks for cross compilers |
$(I386_CROSS)_LINK = i386-tcc$(EXESUF) |
$(WIN32_CROSS)_LINK = i386-win-tcc$(EXESUF) |
$(WIN64_CROSS)_LINK = x86_64-win-tcc$(EXESUF) |
$(WINCE_CROSS)_LINK = arm-win-tcc$(EXESUF) |
$(X64_CROSS)_LINK = x86_64-tcc$(EXESUF) |
$(ARM_FPA_CROSS)_LINK = arm-fpa-tcc$(EXESUF) |
$(ARM_FPA_LD_CROSS)_LINK = arm-fpa-ld-tcc$(EXESUF) |
$(ARM_VFP_CROSS)_LINK = arm-vfp-tcc$(EXESUF) |
$(ARM_EABI_CROSS)_LINK = arm-eabi-tcc$(EXESUF) |
ifeq ($(TARGETOS),Windows) |
ifeq ($(ARCH),i386) |
PROGS:=$($(WIN32_CROSS)_LINK) |
$($(WIN32_CROSS)_LINK)_TCC = yes |
endif |
ifeq ($(ARCH),x86-64) |
PROGS:=$($(WIN64_CROSS)_LINK) |
$($(WIN64_CROSS)_LINK)_TCC = yes |
endif |
endif |
ifeq ($(TARGETOS),Linux) |
ifeq ($(ARCH),i386) |
PROGS:=$($(I386_CROSS)_LINK) |
$($(I386_CROSS)_LINK)_TCC = yes |
endif |
ifeq ($(ARCH),x86-64) |
PROGS:=$($(X64_CROSS)_LINK) |
$($(X64_CROSS)_LINK)_TCC = yes |
endif |
endif |
CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c |
CORE_FILES += tcc.h config.h libtcc.h tcctok.h |
I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h |
WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c |
WIN64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h tccpe.c |
WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c |
X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h |
ARM_FILES = $(CORE_FILES) arm-gen.c |
ARM64_FILES = $(CORE_FILES) arm64-gen.c |
C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c |
ifdef CONFIG_WIN64 |
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) |
NATIVE_FILES=$(WIN64_FILES) |
PROGS_CROSS=$(WIN32_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) |
LIBTCC1_CROSS=lib/i386-win/libtcc1.a |
LIBTCC1=libtcc1.a |
else ifdef CONFIG_WIN32 |
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) |
NATIVE_FILES=$(WIN32_FILES) |
PROGS_CROSS=$(WIN64_CROSS) $(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) |
LIBTCC1_CROSS=lib/x86_64-win/libtcc1.a |
LIBTCC1=libtcc1.a |
else ifeq ($(ARCH),i386) |
NATIVE_FILES=$(I386_FILES) |
PROGS_CROSS=$($(X64_CROSS)_LINK) $($(WIN32_CROSS)_LINK) $($(WIN64_CROSS)_LINK) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) |
LIBTCC1_CROSS=lib/i386-win/libtcc1.a lib/x86_64-win/libtcc1.a lib/i386/libtcc1.a lib/x86_64/libtcc1.a \ |
lib/arm64/libtcc1.a |
LIBTCC1=libtcc1.a |
else ifeq ($(ARCH),x86-64) |
ifeq ($(TARGETOS),Darwin) |
NATIVE_FILES=$(X86_64_FILES) |
PROGS_CROSS=$($(I386_CROSS)_LINK) $($(WIN32_CROSS)_LINK) $($(WIN64_CROSS)_LINK) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS) |
LIBTCC1_CROSS=lib/i386-win/libtcc1.a lib/x86_64-win/libtcc1.a lib/i386/libtcc1.a lib/x86_64/libtcc1.a |
LIBTCC1=libtcc1.a |
else |
NATIVE_FILES=$(X86_64_FILES) |
PROGS_CROSS=$($(I386_CROSS)_LINK) $($(WIN32_CROSS)_LINK) $($(WIN64_CROSS)_LINK) $(ARM_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) |
LIBTCC1_CROSS=lib/i386-win/libtcc1.a lib/x86_64-win/libtcc1.a lib/i386/libtcc1.a lib/x86_64/libtcc1.a \ |
lib/arm64/libtcc1.a |
LIBTCC1=libtcc1.a |
endif |
else ifeq ($(ARCH),arm) |
NATIVE_FILES=$(ARM_FILES) |
PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM64_CROSS) $(C67_CROSS) $(WINCE_CROSS) |
LIBTCC1=libtcc1.a |
LIBTCC1_CROSS=lib/i386-win/libtcc1.a lib/x86_64-win/libtcc1.a lib/i386/libtcc1.a |
else ifeq ($(ARCH),arm64) |
NATIVE_FILES=$(ARM64_FILES) |
PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(WIN64_CROSS) $(ARM_CROSS) $(C67_CROSS) $(WINCE_CROSS) |
LIBTCC1=libtcc1.a |
LIBTCC1_CROSS=lib/i386-win/libtcc1.a lib/x86_64-win/libtcc1.a lib/i386/libtcc1.a |
endif |
PROGS_CROSS_LINK=$(foreach PROG_CROSS,$(PROGS_CROSS),$($(PROG_CROSS)_LINK)) |
ifeq ($(TARGETOS),Darwin) |
PROGS+=tiny_libmaker$(EXESUF) |
endif |
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCC_EXTRA) |
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info |
ifdef CONFIG_CROSS |
PROGS+=$(PROGS_CROSS) |
TCCLIBS+=$(LIBTCC1_CROSS) |
endif |
all: $(PROGS) $(TCCLIBS) $(TCCDOCS) |
# Host Tiny C Compiler |
tcc$(EXESUF): tcc.o $(LIBTCC) |
$(CC) -o $@ $^ $(LIBS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LINK_LIBTCC) |
# Cross Tiny C Compilers |
%-tcc$(EXESUF): tcc.c |
$(CC) -o $@ $< -DONE_SOURCE $(if $($@_TCC),$(NATIVE_DEFINES),$(DEFINES)) $(CPPFLAGS) $(CFLAGS) $(LIBS) $(LDFLAGS) |
$(if $($@_LINK),ln -sf $@ $($@_LINK)) |
$(if $($@_TCC),ln -sf $@ tcc$(EXESUF)) |
# profiling version |
tcc_p$(EXESUF): $(NATIVE_FILES) |
$(CC) -o $@ $< -DONE_SOURCE $(NATIVE_DEFINES) $(CPPFLAGS_P) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P) |
$(I386_CROSS) $($(I386_CROSS)_LINK): DEFINES = -DTCC_TARGET_I386 |
$(X64_CROSS) $($(X64_CROSS)_LINK): DEFINES = -DTCC_TARGET_X86_64 |
$(WIN32_CROSS) $($(WIN32_CROSS)_LINK): DEFINES = -DTCC_TARGET_I386 -DTCC_TARGET_PE \ |
-DCONFIG_TCCDIR="\"$(tccdir)/win32\"" \ |
-DCONFIG_TCC_LIBPATHS="\"{B}/lib/32;{B}/lib\"" |
$(WIN64_CROSS) $($(WIN64_CROSS)_LINK): DEFINES = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE \ |
-DCONFIG_TCCDIR="\"$(tccdir)/win32\"" \ |
-DCONFIG_TCC_LIBPATHS="\"{B}/lib/64;{B}/lib\"" |
$(WINCE_CROSS): DEFINES = -DTCC_TARGET_PE |
$(C67_CROSS): DEFINES = -DTCC_TARGET_C67 |
$(ARM_FPA_CROSS): DEFINES = -DTCC_TARGET_ARM |
$(ARM_FPA_LD_CROSS)$(EXESUF): DEFINES = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12 |
$(ARM_VFP_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_VFP |
$(ARM_EABI_CROSS): DEFINES = -DTCC_TARGET_ARM -DTCC_ARM_EABI -DTCC_ARM_VFP |
$(ARM64_CROSS): DEFINES = -DTCC_TARGET_ARM64 |
$(I386_CROSS) $($(I386_CROSS)_LINK): $(I386_FILES) |
$(X64_CROSS) $($(X64_CROSS)_LINK): $(X86_64_FILES) |
$(WIN32_CROSS) $($(WIN32_CROSS)_LINK): $(WIN32_FILES) |
$(WIN64_CROSS) $($(WIN64_CROSS)_LINK): $(WIN64_FILES) |
$(WINCE_CROSS) $($(WINCE_CROSS)_LINK): $(WINCE_FILES) |
$(C67_CROSS) $($(C67_CROSS)_LINK): $(C67_FILES) |
$(ARM_FPA_CROSS) $(ARM_FPA_LD_CROSS) $(ARM_VFP_CROSS) $(ARM_EABI_CROSS): $(ARM_FILES) |
$($(ARM_FPA_CROSS)_LINK) $($(ARM_FPA_LD_CROSS)_LINK) $($(ARM_VFP_CROSS)_LINK) $($(ARM_EABI_CROSS)_LINK): $(ARM_FILES) |
$(ARM64_CROSS): $(ARM64_FILES) |
# libtcc generation and test |
ifndef ONE_SOURCE |
LIBTCC_OBJ = $(filter-out tcc.o,$(patsubst %.c,%.o,$(filter %.c,$(NATIVE_FILES)))) |
LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES),$(NATIVE_FILES)) |
else |
LIBTCC_OBJ = libtcc.o |
LIBTCC_INC = $(NATIVE_FILES) |
libtcc.o : NATIVE_DEFINES += -DONE_SOURCE |
endif |
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC) |
$(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS) |
ifndef LIBTCC_DLL |
libtcc.a: $(LIBTCC_OBJ) |
$(AR) rcs $@ $^ |
endif |
libtcc.so.1.0: $(LIBTCC_OBJ) |
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS) |
libtcc.so.1.0: CFLAGS+=-fPIC |
ifdef LIBTCC_DLL |
libtcc.dll libtcc.def libtcc.a: $(LIBTCC_OBJ) |
$(CC) -shared $^ -o $@ $(LDFLAGS) -Wl,--output-def,libtcc.def,--out-implib,libtcc.a |
endif |
# windows utilities |
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c |
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) |
tiny_libmaker$(EXESUF): win32/tools/tiny_libmaker.c |
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) |
# TinyCC runtime libraries |
libtcc1.a : FORCE $(PROGS) |
$(MAKE) -C lib native |
if test ! -d $(ARCH); then mkdir $(ARCH); fi |
if test ! -L $(ARCH)/$@; then ln -sf ../$@ $(ARCH)/$@; fi |
lib/%/libtcc1.a : FORCE $(PROGS_CROSS) |
$(MAKE) -C lib cross TARGET=$* |
FORCE: |
# install |
TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h |
INSTALL=install |
ifdef STRIP_BINARIES |
INSTALLBIN=$(INSTALL) -s |
else |
INSTALLBIN=$(INSTALL) |
endif |
install-strip: install |
strip $(foreach PROG,$(PROGS),"$(bindir)"/$(PROG)) |
ifndef CONFIG_WIN32 |
install: $(PROGS) $(TCCLIBS) $(TCCDOCS) |
mkdir -p "$(bindir)" |
$(INSTALLBIN) -m755 $(PROGS) "$(bindir)" |
cp -P tcc$(EXESUF) "$(bindir)" |
mkdir -p "$(mandir)/man1" |
-$(INSTALL) -m644 tcc.1 "$(mandir)/man1" |
mkdir -p "$(infodir)" |
-$(INSTALL) -m644 tcc-doc.info "$(infodir)" |
mkdir -p "$(tccdir)" |
mkdir -p "$(tccdir)/include" |
ifneq ($(LIBTCC1),) |
mkdir -p "$(tccdir)/$(ARCH)" |
$(INSTALL) -m644 $(LIBTCC1) "$(tccdir)/$(ARCH)" |
endif |
$(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) $(top_srcdir)/tcclib.h "$(tccdir)/include" |
mkdir -p "$(libdir)" |
$(INSTALL) -m644 $(LIBTCC) "$(libdir)" |
ifdef DISABLE_STATIC |
ln -sf "$(ln_libdir)/libtcc.so.1.0" "$(libdir)/libtcc.so.1" |
ln -sf "$(ln_libdir)/libtcc.so.1.0" "$(libdir)/libtcc.so" |
endif |
mkdir -p "$(includedir)" |
$(INSTALL) -m644 $(top_srcdir)/libtcc.h "$(includedir)" |
mkdir -p "$(docdir)" |
-$(INSTALL) -m644 tcc-doc.html "$(docdir)" |
ifdef CONFIG_CROSS |
mkdir -p "$(tccdir)/win32/lib/32" |
mkdir -p "$(tccdir)/win32/lib/64" |
mkdir -p "$(tccdir)/i386" |
mkdir -p "$(tccdir)/x86-64" |
ifneq ($(HOST_OS),Darwin) |
mkdir -p "$(tccdir)/arm64" |
$(INSTALL) -m644 lib/arm64/libtcc1.a "$(tccdir)/arm64" |
endif |
$(INSTALL) -m644 lib/i386/libtcc1.a "$(tccdir)/i386" |
$(INSTALL) -m644 lib/x86_64/libtcc1.a "$(tccdir)/x86-64" |
$(INSTALL) -m644 $(top_srcdir)/win32/lib/*.def "$(tccdir)/win32/lib" |
$(INSTALL) -m644 lib/i386-win/libtcc1.a "$(tccdir)/win32/lib/32" |
$(INSTALL) -m644 lib/x86_64-win/libtcc1.a "$(tccdir)/win32/lib/64" |
cp -r $(top_srcdir)/win32/include/. "$(tccdir)/win32/include" |
cp -r "$(tccdir)/include" "$(tccdir)/win32" |
endif |
uninstall: |
rm -fv $(foreach P,$(PROGS),"$(bindir)/$P") |
rm -fv "$(bindir)/tcc$(EXESUF)" |
rm -fv $(foreach P,$(LIBTCC1),"$(tccdir)/$P") |
rm -fv $(foreach P,$(TCC_INCLUDES),"$(tccdir)/include/$P") |
rm -fv "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info" |
rm -fv "$(libdir)/$(LIBTCC)" "$(includedir)/libtcc.h" |
rm -fv "$(libdir)/libtcc.so*" |
rm -rv "$(tccdir)" |
rm -rv "$(docdir)" |
else |
# on windows |
install: $(PROGS) $(TCCLIBS) $(TCCDOCS) |
mkdir -p "$(tccdir)" |
mkdir -p "$(tccdir)/lib" |
mkdir -p "$(tccdir)/include" |
mkdir -p "$(tccdir)/examples" |
mkdir -p "$(tccdir)/doc" |
mkdir -p "$(tccdir)/libtcc" |
$(INSTALLBIN) -m755 $(PROGS) "$(tccdir)" |
$(INSTALLBIN) -m755 tcc.exe "$(tccdir)" |
$(INSTALL) -m644 $(LIBTCC1) $(top_srcdir)/win32/lib/*.def "$(tccdir)/lib" |
cp -r $(top_srcdir)/win32/include/. "$(tccdir)/include" |
cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples" |
$(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) $(top_srcdir)/tcclib.h "$(tccdir)/include" |
$(INSTALL) -m644 tcc-doc.html $(top_srcdir)/win32/tcc-win32.txt "$(tccdir)/doc" |
$(INSTALL) -m644 $(top_srcdir)/libtcc.h $(LIBTCC_EXTRA) "$(tccdir)/libtcc" |
$(INSTALL) -m644 $(LIBTCC) "$(tccdir)" |
ifdef CONFIG_CROSS |
mkdir -p "$(tccdir)/lib/32" |
mkdir -p "$(tccdir)/lib/64" |
-$(INSTALL) -m644 lib/i386-win/libtcc1.a "$(tccdir)/lib/32" |
-$(INSTALL) -m644 lib/x86_64-win/libtcc1.a "$(tccdir)/lib/64" |
endif |
uninstall: |
rm -rfv "$(tccdir)/*" |
endif |
# documentation and man page |
tcc-doc.html: tcc-doc.texi |
-makeinfo --no-split --html --number-sections -o $@ $< |
tcc.1: tcc-doc.texi |
-$(top_srcdir)/texi2pod.pl $< tcc.pod |
-pod2man --section=1 --center="Tiny C Compiler" --release=`cat $(top_srcdir)/VERSION` tcc.pod > $@ |
tcc-doc.info: tcc-doc.texi |
-makeinfo $< |
# in tests subdir |
export LIBTCC1 |
%est: |
$(MAKE) -C tests $@ 'PROGS_CROSS=$(PROGS_CROSS)' |
clean: |
rm -vf $(PROGS) tcc_p$(EXESUF) tcc.pod *~ *.o *.a *.so* *.out *.log \ |
*.exe a.out tags TAGS libtcc_test$(EXESUF) tcc$(EXESUF) |
-rm -r $(ARCH) arm64 |
ifeq ($(HOST_OS),Linux) |
-rm -r ./C: |
endif |
-rm *-tcc$(EXESUF) |
$(MAKE) -C tests $@ |
ifneq ($(LIBTCC1),) |
$(MAKE) -C lib $@ |
endif |
distclean: clean |
rm -vf config.h config.mak config.texi tcc.1 tcc-doc.info tcc-doc.html |
config.mak: |
@echo "Please run ./configure." |
@exit 1 |
tags: |
ctags $(top_srcdir)/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[chS] |
TAGS: |
ctags -e $(top_srcdir)/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[chS] |
# create release tarball from *current* git branch (including tcc-doc.html |
# and converting two files to CRLF) |
TCC-VERSION := tcc-$(shell cat $(top_srcdir)/VERSION) |
tar: tcc-doc.html |
mkdir $(TCC-VERSION) |
( cd $(TCC-VERSION) && git --git-dir ../.git checkout -f ) |
cp tcc-doc.html $(TCC-VERSION) |
for f in tcc-win32.txt build-tcc.bat ; do \ |
cat win32/$$f | sed 's,\(.*\),\1\r,g' > $(TCC-VERSION)/win32/$$f ; \ |
done |
tar cjf $(TCC-VERSION).tar.bz2 $(TCC-VERSION) |
rm -rf $(TCC-VERSION) |
git reset |
.PHONY: all clean tar tags TAGS distclean install uninstall FORCE |
endif # ifeq ($(TOP),.) |
OUTFILE = ktcc.kex |
OBJS = tcc.o console.o getcwd.o |
CGLAGS =-O2 -g -Wall -mpreferred-stack-boundary=2 -march=i386 -falign-functions=0 -fno-strict-aliasing |
include Makefile_for_program |
/programs/develop/ktcc/trunk/source/config.h |
---|
1,8 → 1,11 |
#define TCC_VERSION "0.9.26" |
#define CONFIG_TCC_STATIC |
/* Automatically generated by configure - do not modify */ |
#define CONFIG_TCCDIR "/usr/local/lib/tcc" |
#define GCC_MAJOR 3 |
#define HOST_I386 1 |
#define TCC_VERSION "0.9.23" |
//#define TCC_TARGET_PE |
#define TCC_TARGET_MEOS |
#define TCC_TARGET_I386 |
#define ONE_SOURCE |
#define COMMIT_4ad186c5ef61_IS_FIXED |
/* enable bound checking code */ |
//#define CONFIG_TCC_BCHECK 1 |
/programs/develop/ktcc/trunk/source/console.asm |
---|
0,0 → 1,85 |
format ELF |
section '.text' executable |
public console_init |
public console_printf |
public console_exit |
align 4 |
console_init: |
pushad |
mov eax,[console_init_status] |
test eax,eax |
jnz console_initializated |
mov [console_init_status],1 |
mov eax,68 |
mov ebx,19 |
mov ecx,console_path |
int 0x40 |
test eax,eax |
jz console_not_loaded |
mov ebx,[eax+4] |
mov [con_start],ebx |
mov ebx,[eax+4+16] |
mov [con_init],ebx |
mov ebx,[eax+4+32] |
mov [con_printf],ebx |
push 1 |
call [con_start] |
push caption |
push -1 |
push -1 |
push -1 |
push -1 |
call [con_init] |
console_not_loaded: |
console_initializated: |
popad |
ret |
align 4 |
console_printf: |
pop [return_addres] |
call [con_printf] |
;add esp,8 |
push [return_addres] |
ret |
align 4 |
console_exit: |
push 0 |
call [con_exit] |
ret |
;----------------------------- |
console_path db '/sys/dll/console.obj',0 |
caption db 'Console',0 |
align 4 |
con_start rd 1 |
con_init rd 1 |
con_printf rd 1 |
con_exit rd 1 |
console_init_status rd 1 |
return_addres rd 1 |
/programs/develop/ktcc/trunk/source/libtcc1.c |
---|
0,0 → 1,602 |
/* TCC runtime library. |
Parts of this code are (c) 2002 Fabrice Bellard |
Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc. |
This file is free software; you can redistribute it and/or modify it |
under the terms of the GNU General Public License as published by the |
Free Software Foundation; either version 2, or (at your option) any |
later version. |
In addition to the permissions in the GNU General Public License, the |
Free Software Foundation gives you unlimited permission to link the |
compiled version of this file into combinations with other programs, |
and to distribute those combinations without any restriction coming |
from the use of this file. (The General Public License restrictions |
do apply in other respects; for example, they cover modification of |
the file, and distribution when not linked into a combine |
executable.) |
This file is distributed in the hope that it will be useful, but |
WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; see the file COPYING. If not, write to |
the Free Software Foundation, 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. |
*/ |
#define W_TYPE_SIZE 32 |
#define BITS_PER_UNIT 8 |
typedef int Wtype; |
typedef unsigned int UWtype; |
typedef unsigned int USItype; |
typedef long long DWtype; |
typedef unsigned long long UDWtype; |
struct DWstruct { |
Wtype low, high; |
}; |
typedef union |
{ |
struct DWstruct s; |
DWtype ll; |
} DWunion; |
typedef long double XFtype; |
#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT) |
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE) |
/* the following deal with IEEE single-precision numbers */ |
#define EXCESS 126 |
#define SIGNBIT 0x80000000 |
#define HIDDEN (1 << 23) |
#define SIGN(fp) ((fp) & SIGNBIT) |
#define EXP(fp) (((fp) >> 23) & 0xFF) |
#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN) |
#define PACK(s,e,m) ((s) | ((e) << 23) | (m)) |
/* the following deal with IEEE double-precision numbers */ |
#define EXCESSD 1022 |
#define HIDDEND (1 << 20) |
#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) |
#define SIGND(fp) ((fp.l.upper) & SIGNBIT) |
#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \ |
(fp.l.lower >> 22)) |
#define HIDDEND_LL ((long long)1 << 52) |
#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) |
#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m)) |
/* the following deal with x86 long double-precision numbers */ |
#define EXCESSLD 16382 |
#define EXPLD(fp) (fp.l.upper & 0x7fff) |
#define SIGNLD(fp) ((fp.l.upper) & 0x8000) |
/* only for x86 */ |
union ldouble_long { |
long double ld; |
struct { |
unsigned long long lower; |
unsigned short upper; |
} l; |
}; |
union double_long { |
double d; |
#if 1 |
struct { |
unsigned long lower; |
long upper; |
} l; |
#else |
struct { |
long upper; |
unsigned long lower; |
} l; |
#endif |
long long ll; |
}; |
union float_long { |
float f; |
long l; |
}; |
/* XXX: use gcc/tcc intrinsic ? */ |
#if defined(__i386__) |
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ |
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \ |
: "=r" ((USItype) (sh)), \ |
"=&r" ((USItype) (sl)) \ |
: "0" ((USItype) (ah)), \ |
"g" ((USItype) (bh)), \ |
"1" ((USItype) (al)), \ |
"g" ((USItype) (bl))) |
#define umul_ppmm(w1, w0, u, v) \ |
__asm__ ("mull %3" \ |
: "=a" ((USItype) (w0)), \ |
"=d" ((USItype) (w1)) \ |
: "%0" ((USItype) (u)), \ |
"rm" ((USItype) (v))) |
#define udiv_qrnnd(q, r, n1, n0, dv) \ |
__asm__ ("divl %4" \ |
: "=a" ((USItype) (q)), \ |
"=d" ((USItype) (r)) \ |
: "0" ((USItype) (n0)), \ |
"1" ((USItype) (n1)), \ |
"rm" ((USItype) (dv))) |
#define count_leading_zeros(count, x) \ |
do { \ |
USItype __cbtmp; \ |
__asm__ ("bsrl %1,%0" \ |
: "=r" (__cbtmp) : "rm" ((USItype) (x))); \ |
(count) = __cbtmp ^ 31; \ |
} while (0) |
#else |
#error unsupported CPU type |
#endif |
/* most of this code is taken from libgcc2.c from gcc */ |
static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) |
{ |
DWunion ww; |
DWunion nn, dd; |
DWunion rr; |
UWtype d0, d1, n0, n1, n2; |
UWtype q0, q1; |
UWtype b, bm; |
nn.ll = n; |
dd.ll = d; |
d0 = dd.s.low; |
d1 = dd.s.high; |
n0 = nn.s.low; |
n1 = nn.s.high; |
#if !UDIV_NEEDS_NORMALIZATION |
if (d1 == 0) |
{ |
if (d0 > n1) |
{ |
/* 0q = nn / 0D */ |
udiv_qrnnd (q0, n0, n1, n0, d0); |
q1 = 0; |
/* Remainder in n0. */ |
} |
else |
{ |
/* qq = NN / 0d */ |
if (d0 == 0) |
d0 = 1 / d0; /* Divide intentionally by zero. */ |
udiv_qrnnd (q1, n1, 0, n1, d0); |
udiv_qrnnd (q0, n0, n1, n0, d0); |
/* Remainder in n0. */ |
} |
if (rp != 0) |
{ |
rr.s.low = n0; |
rr.s.high = 0; |
*rp = rr.ll; |
} |
} |
#else /* UDIV_NEEDS_NORMALIZATION */ |
if (d1 == 0) |
{ |
if (d0 > n1) |
{ |
/* 0q = nn / 0D */ |
count_leading_zeros (bm, d0); |
if (bm != 0) |
{ |
/* Normalize, i.e. make the most significant bit of the |
denominator set. */ |
d0 = d0 << bm; |
n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); |
n0 = n0 << bm; |
} |
udiv_qrnnd (q0, n0, n1, n0, d0); |
q1 = 0; |
/* Remainder in n0 >> bm. */ |
} |
else |
{ |
/* qq = NN / 0d */ |
if (d0 == 0) |
d0 = 1 / d0; /* Divide intentionally by zero. */ |
count_leading_zeros (bm, d0); |
if (bm == 0) |
{ |
/* From (n1 >= d0) /\ (the most significant bit of d0 is set), |
conclude (the most significant bit of n1 is set) /\ (the |
leading quotient digit q1 = 1). |
This special case is necessary, not an optimization. |
(Shifts counts of W_TYPE_SIZE are undefined.) */ |
n1 -= d0; |
q1 = 1; |
} |
else |
{ |
/* Normalize. */ |
b = W_TYPE_SIZE - bm; |
d0 = d0 << bm; |
n2 = n1 >> b; |
n1 = (n1 << bm) | (n0 >> b); |
n0 = n0 << bm; |
udiv_qrnnd (q1, n1, n2, n1, d0); |
} |
/* n1 != d0... */ |
udiv_qrnnd (q0, n0, n1, n0, d0); |
/* Remainder in n0 >> bm. */ |
} |
if (rp != 0) |
{ |
rr.s.low = n0 >> bm; |
rr.s.high = 0; |
*rp = rr.ll; |
} |
} |
#endif /* UDIV_NEEDS_NORMALIZATION */ |
else |
{ |
if (d1 > n1) |
{ |
/* 00 = nn / DD */ |
q0 = 0; |
q1 = 0; |
/* Remainder in n1n0. */ |
if (rp != 0) |
{ |
rr.s.low = n0; |
rr.s.high = n1; |
*rp = rr.ll; |
} |
} |
else |
{ |
/* 0q = NN / dd */ |
count_leading_zeros (bm, d1); |
if (bm == 0) |
{ |
/* From (n1 >= d1) /\ (the most significant bit of d1 is set), |
conclude (the most significant bit of n1 is set) /\ (the |
quotient digit q0 = 0 or 1). |
This special case is necessary, not an optimization. */ |
/* The condition on the next line takes advantage of that |
n1 >= d1 (true due to program flow). */ |
if (n1 > d1 || n0 >= d0) |
{ |
q0 = 1; |
sub_ddmmss (n1, n0, n1, n0, d1, d0); |
} |
else |
q0 = 0; |
q1 = 0; |
if (rp != 0) |
{ |
rr.s.low = n0; |
rr.s.high = n1; |
*rp = rr.ll; |
} |
} |
else |
{ |
UWtype m1, m0; |
/* Normalize. */ |
b = W_TYPE_SIZE - bm; |
d1 = (d1 << bm) | (d0 >> b); |
d0 = d0 << bm; |
n2 = n1 >> b; |
n1 = (n1 << bm) | (n0 >> b); |
n0 = n0 << bm; |
udiv_qrnnd (q0, n1, n2, n1, d1); |
umul_ppmm (m1, m0, q0, d0); |
if (m1 > n1 || (m1 == n1 && m0 > n0)) |
{ |
q0--; |
sub_ddmmss (m1, m0, m1, m0, d1, d0); |
} |
q1 = 0; |
/* Remainder in (n1n0 - m1m0) >> bm. */ |
if (rp != 0) |
{ |
sub_ddmmss (n1, n0, n1, n0, m1, m0); |
rr.s.low = (n1 << b) | (n0 >> bm); |
rr.s.high = n1 >> bm; |
*rp = rr.ll; |
} |
} |
} |
} |
ww.s.low = q0; |
ww.s.high = q1; |
return ww.ll; |
} |
#define __negdi2(a) (-(a)) |
long long __divdi3(long long u, long long v) |
{ |
int c = 0; |
DWunion uu, vv; |
DWtype w; |
uu.ll = u; |
vv.ll = v; |
if (uu.s.high < 0) { |
c = ~c; |
uu.ll = __negdi2 (uu.ll); |
} |
if (vv.s.high < 0) { |
c = ~c; |
vv.ll = __negdi2 (vv.ll); |
} |
w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0); |
if (c) |
w = __negdi2 (w); |
return w; |
} |
long long __moddi3(long long u, long long v) |
{ |
int c = 0; |
DWunion uu, vv; |
DWtype w; |
uu.ll = u; |
vv.ll = v; |
if (uu.s.high < 0) { |
c = ~c; |
uu.ll = __negdi2 (uu.ll); |
} |
if (vv.s.high < 0) |
vv.ll = __negdi2 (vv.ll); |
__udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w); |
if (c) |
w = __negdi2 (w); |
return w; |
} |
unsigned long long __udivdi3(unsigned long long u, unsigned long long v) |
{ |
return __udivmoddi4 (u, v, (UDWtype *) 0); |
} |
unsigned long long __umoddi3(unsigned long long u, unsigned long long v) |
{ |
UDWtype w; |
__udivmoddi4 (u, v, &w); |
return w; |
} |
/* XXX: fix tcc's code generator to do this instead */ |
long long __sardi3(long long a, int b) |
{ |
#ifdef __TINYC__ |
DWunion u; |
u.ll = a; |
if (b >= 32) { |
u.s.low = u.s.high >> (b - 32); |
u.s.high = u.s.high >> 31; |
} else if (b != 0) { |
u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b)); |
u.s.high = u.s.high >> b; |
} |
return u.ll; |
#else |
return a >> b; |
#endif |
} |
/* XXX: fix tcc's code generator to do this instead */ |
unsigned long long __shrdi3(unsigned long long a, int b) |
{ |
#ifdef __TINYC__ |
DWunion u; |
u.ll = a; |
if (b >= 32) { |
u.s.low = (unsigned)u.s.high >> (b - 32); |
u.s.high = 0; |
} else if (b != 0) { |
u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b)); |
u.s.high = (unsigned)u.s.high >> b; |
} |
return u.ll; |
#else |
return a >> b; |
#endif |
} |
/* XXX: fix tcc's code generator to do this instead */ |
long long __shldi3(long long a, int b) |
{ |
#ifdef __TINYC__ |
DWunion u; |
u.ll = a; |
if (b >= 32) { |
u.s.high = (unsigned)u.s.low << (b - 32); |
u.s.low = 0; |
} else if (b != 0) { |
u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b)); |
u.s.low = (unsigned)u.s.low << b; |
} |
return u.ll; |
#else |
return a << b; |
#endif |
} |
#if defined(__i386__) |
/* FPU control word for rounding to nearest mode */ |
unsigned short __tcc_fpu_control = 0x137f; |
/* FPU control word for round to zero mode for int conversion */ |
unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00; |
#endif |
/* XXX: fix tcc's code generator to do this instead */ |
float __ulltof(unsigned long long a) |
{ |
DWunion uu; |
XFtype r; |
uu.ll = a; |
if (uu.s.high >= 0) { |
return (float)uu.ll; |
} else { |
r = (XFtype)uu.ll; |
r += 18446744073709551616.0; |
return (float)r; |
} |
} |
double __ulltod(unsigned long long a) |
{ |
DWunion uu; |
XFtype r; |
uu.ll = a; |
if (uu.s.high >= 0) { |
return (double)uu.ll; |
} else { |
r = (XFtype)uu.ll; |
r += 18446744073709551616.0; |
return (double)r; |
} |
} |
long double __ulltold(unsigned long long a) |
{ |
DWunion uu; |
XFtype r; |
uu.ll = a; |
if (uu.s.high >= 0) { |
return (long double)uu.ll; |
} else { |
r = (XFtype)uu.ll; |
r += 18446744073709551616.0; |
return (long double)r; |
} |
} |
unsigned long long __fixunssfdi (float a1) |
{ |
register union float_long fl1; |
register int exp; |
register unsigned long l; |
fl1.f = a1; |
if (fl1.l == 0) |
return (0); |
exp = EXP (fl1.l) - EXCESS - 24; |
l = MANT(fl1.l); |
if (exp >= 41) |
return (unsigned long long)-1; |
else if (exp >= 0) |
return (unsigned long long)l << exp; |
else if (exp >= -23) |
return l >> -exp; |
else |
return 0; |
} |
unsigned long long __fixunsdfdi (double a1) |
{ |
register union double_long dl1; |
register int exp; |
register unsigned long long l; |
dl1.d = a1; |
if (dl1.ll == 0) |
return (0); |
exp = EXPD (dl1) - EXCESSD - 53; |
l = MANTD_LL(dl1); |
if (exp >= 12) |
return (unsigned long long)-1; |
else if (exp >= 0) |
return l << exp; |
else if (exp >= -52) |
return l >> -exp; |
else |
return 0; |
} |
unsigned long long __fixunsxfdi (long double a1) |
{ |
register union ldouble_long dl1; |
register int exp; |
register unsigned long long l; |
dl1.ld = a1; |
if (dl1.l.lower == 0 && dl1.l.upper == 0) |
return (0); |
exp = EXPLD (dl1) - EXCESSLD - 64; |
l = dl1.l.lower; |
if (exp > 0) |
return (unsigned long long)-1; |
else if (exp >= -63) |
return l >> -exp; |
else |
return 0; |
} |
/programs/develop/ktcc/trunk/source/start.asm |
---|
0,0 → 1,136 |
format ELF |
section '.text' executable |
public start |
;extrn mf_init |
extrn main |
;include 'debug2.inc' |
__DEBUG__=0 |
;start_: |
virtual at 0 |
db 'MENUET01' ; 1. Magic number (8 bytes) |
dd 0x01 ; 2. Version of executable file |
dd start ; 3. Start address |
dd 0x0 ; 4. Size of image |
dd 0x100000 ; 5. Size of needed memory |
dd 0x100000 ; 6. Pointer to stack |
hparams dd 0x0 ; 7. Pointer to program arguments |
hpath dd 0x0 ; 8. Pointer to program path |
end virtual |
start: |
;DEBUGF 'Start programm\n' |
;init heap of memory |
mov eax,68 |
mov ebx,11 |
int 0x40 |
;DEBUGF ' path "%s"\n params "%s"\n', .path, .params |
; check for overflow |
mov al, [path+buf_len-1] |
or al, [params+buf_len-1] |
jnz .crash |
; check if path written by OS |
mov eax, [hparams] |
test eax, eax |
jz .without_path |
mov eax, path |
.without_path: |
mov esi, eax |
call push_param |
; retrieving parameters |
mov esi, params |
xor edx, edx ; dl - èä¸ò ïàðàìåòð(1) èëè ðàçäåëèòåëè(0) |
; dh - ñèìâîë ñ êîòîðîãî íà÷àëñÿ ïàðàìåòð (1 êàâû÷êè, 0 îñòàëüíîå) |
mov ecx, 1 ; cl = 1 |
; ch = 0 ïðîñòî íîëü |
.parse: |
lodsb |
test al, al |
jz .run |
test dl, dl |
jnz .findendparam |
;{åñëè áûë ðàçäåëèòåëü |
cmp al, ' ' |
jz .parse ;çàãðóæåí ïðîáåë, ãðóçèì ñëåäóþùèé ñèìâîë |
mov dl, cl ;íà÷èíàåòñÿ ïàðàìåòð |
cmp al, '"' |
jz @f ;çàãðóæåíû êàâû÷êè |
mov dh, ch ;ïàðàìåòð áåç êàâû÷åê |
dec esi |
call push_param |
inc esi |
jmp .parse |
@@: |
mov dh, cl ;ïàðàìåòð â êàâû÷åêàõ |
call push_param ;åñëè íå ïðîáåë çíà÷èò íà÷èíàåòñÿ êàêîé òî ïàðàìåòð |
jmp .parse ;åñëè áûë ðàçäåëèòåëü} |
.findendparam: |
test dh, dh |
jz @f ; áåç êàâû÷åê |
cmp al, '"' |
jz .clear |
jmp .parse |
@@: |
cmp al, ' ' |
jnz .parse |
.clear: |
lea ebx, [esi - 1] |
mov [ebx], ch |
mov dl, ch |
jmp .parse |
.run: |
;DEBUGF 'call main(%x, %x) with params:\n', [argc], argv |
if __DEBUG__ = 1 |
mov ecx, [argc] |
@@: |
lea esi, [ecx * 4 + argv-4] |
DEBUGF '0x%x) "%s"\n', cx, [esi] |
loop @b |
end if |
push [argc] |
push argv |
call main |
.exit: |
;DEBUGF 'Exit from prog\n'; |
xor eax,eax |
dec eax |
int 0x40 |
dd -1 |
.crash: |
;DEBUGF 'E:buffer overflowed\n' |
jmp .exit |
;============================ |
push_param: |
;============================ |
;parameters |
; esi - pointer |
;description |
; procedure increase argc |
; and add pointer to array argv |
; procedure changes ebx |
mov ebx, [argc] |
cmp ebx, max_parameters |
jae .dont_add |
mov [argv+4*ebx], esi |
inc [argc] |
.dont_add: |
ret |
;============================== |
public params as '__argv' |
public path as '__path' |
section '.bss' |
buf_len = 0x400 |
max_parameters=0x20 |
argc rd 1 |
argv rd max_parameters |
path rb buf_len |
params rb buf_len |
;section '.data' |
;include_debug_strings ; ALWAYS present in data section |
/programs/develop/ktcc/trunk/source/tcc.c |
---|
17,234 → 17,10215 |
* License along with this library; if not, write to the Free Software |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
*/ |
#define _GNU_SOURCE |
#include "config.h" |
#ifdef ONE_SOURCE |
#include "libtcc.c" |
#ifdef CONFIG_TCCBOOT |
#include "tccboot.h" |
#define CONFIG_TCC_STATIC |
#else |
#include "tcc.h" |
#include <stdlib.h> |
#include <stdio.h> |
#include <stdarg.h> |
#include <string.h> |
//#include <errno.h> |
#include <math.h> |
#include <unistd.h> |
//#include <signal.h> |
#include <fcntl.h> |
#include <setjmp.h> |
#include <time.h> |
#ifdef WIN32 |
#include <sys/timeb.h> |
#endif |
//#ifndef WIN32 |
static void print_paths(const char *msg, char **paths, int nb_paths) |
#include <sys/time.h> |
//#include <sys/ucontext.h> |
//#endif |
#endif /* !CONFIG_TCCBOOT */ |
#include "elf.h" |
#include "stab.h" |
#ifndef O_BINARY |
#define O_BINARY 0 |
#endif |
#include "libtcc.h" |
/* parser debug */ |
//#define PARSE_DEBUG |
/* preprocessor debug */ |
//#define PP_DEBUG |
/* include file debug */ |
//#define INC_DEBUG |
//#define MEM_DEBUG |
/* assembler debug */ |
//#define ASM_DEBUG |
/* target selection */ |
//#define TCC_TARGET_I386 /* i386 code generator */ |
//#define TCC_TARGET_ARM /* ARMv4 code generator */ |
//#define TCC_TARGET_C67 /* TMS320C67xx code generator */ |
//---------------------------------------------------------------- |
#define TCC_TARGET_MEOS |
/* default target is I386 */ |
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \ |
!defined(TCC_TARGET_C67) |
#define TCC_TARGET_I386 |
#endif |
#if !defined(WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \ |
!defined(TCC_TARGET_C67) |
#define CONFIG_TCC_BCHECK /* enable bound checking code */ |
#endif |
#if defined(WIN32) && !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
#define CONFIG_TCC_STATIC |
#endif |
/* define it to include assembler support */ |
#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_C67) |
#define CONFIG_TCC_ASM |
#endif |
/* object format selection */ |
#if defined(TCC_TARGET_C67) |
#define TCC_TARGET_COFF |
#endif |
#define FALSE 0 |
#define false 0 |
#define TRUE 1 |
#define true 1 |
typedef int BOOL; |
/* path to find crt1.o, crti.o and crtn.o. Only needed when generating |
executables or dlls */ |
#define CONFIG_TCC_CRT_PREFIX "/usr/lib" |
#define INCLUDE_STACK_SIZE 32 |
#define IFDEF_STACK_SIZE 64 |
#define VSTACK_SIZE 256 |
#define STRING_MAX_SIZE 1024 |
#define PACK_STACK_SIZE 8 |
#define TOK_HASH_SIZE 8192 /* must be a power of two */ |
#define TOK_ALLOC_INCR 512 /* must be a power of two */ |
#define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ |
/* token symbol management */ |
typedef struct TokenSym { |
struct TokenSym *hash_next; |
struct Sym *sym_define; /* direct pointer to define */ |
struct Sym *sym_label; /* direct pointer to label */ |
struct Sym *sym_struct; /* direct pointer to structure */ |
struct Sym *sym_identifier; /* direct pointer to identifier */ |
int tok; /* token number */ |
int len; |
char str[1]; |
} TokenSym; |
typedef struct CString { |
int size; /* size in bytes */ |
void *data; /* either 'char *' or 'int *' */ |
int size_allocated; |
void *data_allocated; /* if non NULL, data has been malloced */ |
} CString; |
/* type definition */ |
typedef struct CType { |
int t; |
struct Sym *ref; |
} CType; |
/* constant value */ |
typedef union CValue { |
long double ld; |
double d; |
float f; |
int i; |
unsigned int ui; |
unsigned int ul; /* address (should be unsigned long on 64 bit cpu) */ |
long long ll; |
unsigned long long ull; |
struct CString *cstr; |
void *ptr; |
int tab[1]; |
} CValue; |
/* value on stack */ |
typedef struct SValue { |
CType type; /* type */ |
unsigned short r; /* register + flags */ |
unsigned short r2; /* second register, used for 'long long' |
type. If not used, set to VT_CONST */ |
CValue c; /* constant, if VT_CONST */ |
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */ |
} SValue; |
/* symbol management */ |
typedef struct Sym { |
int v; /* symbol token */ |
int r; /* associated register */ |
int c; /* associated number */ |
CType type; /* associated type */ |
struct Sym *next; /* next related symbol */ |
struct Sym *prev; /* prev symbol in stack */ |
struct Sym *prev_tok; /* previous symbol for this token */ |
} Sym; |
/* section definition */ |
/* XXX: use directly ELF structure for parameters ? */ |
/* special flag to indicate that the section should not be linked to |
the other ones */ |
#define SHF_PRIVATE 0x80000000 |
typedef struct Section { |
unsigned long data_offset; /* current data offset */ |
unsigned char *data; /* section data */ |
unsigned long data_allocated; /* used for realloc() handling */ |
int sh_name; /* elf section name (only used during output) */ |
int sh_num; /* elf section number */ |
int sh_type; /* elf section type */ |
int sh_flags; /* elf section flags */ |
int sh_info; /* elf section info */ |
int sh_addralign; /* elf section alignment */ |
int sh_entsize; /* elf entry size */ |
unsigned long sh_size; /* section size (only used during output) */ |
unsigned long sh_addr; /* address at which the section is relocated */ |
unsigned long sh_offset; /* address at which the section is relocated */ |
int nb_hashed_syms; /* used to resize the hash table */ |
struct Section *link; /* link to another section */ |
struct Section *reloc; /* corresponding section for relocation, if any */ |
struct Section *hash; /* hash table for symbols */ |
struct Section *next; |
char name[1]; /* section name */ |
} Section; |
typedef struct DLLReference { |
int level; |
char name[1]; |
} DLLReference; |
/* GNUC attribute definition */ |
typedef struct AttributeDef { |
int aligned; |
int packed; |
Section *section; |
unsigned char func_call; /* FUNC_CDECL, FUNC_STDCALL, FUNC_FASTCALLx */ |
unsigned char dllexport; |
} AttributeDef; |
#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */ |
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */ |
#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */ |
/* stored in 'Sym.c' field */ |
#define FUNC_NEW 1 /* ansi function prototype */ |
#define FUNC_OLD 2 /* old function prototype */ |
#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */ |
/* stored in 'Sym.r' field */ |
#define FUNC_CDECL 0 /* standard c call */ |
#define FUNC_STDCALL 1 /* pascal c call */ |
#define FUNC_FASTCALL1 2 /* first param in %eax */ |
#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */ |
#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */ |
/* field 'Sym.t' for macros */ |
#define MACRO_OBJ 0 /* object like macro */ |
#define MACRO_FUNC 1 /* function like macro */ |
/* field 'Sym.r' for C labels */ |
#define LABEL_DEFINED 0 /* label is defined */ |
#define LABEL_FORWARD 1 /* label is forward defined */ |
#define LABEL_DECLARED 2 /* label is declared but never used */ |
/* type_decl() types */ |
#define TYPE_ABSTRACT 1 /* type without variable */ |
#define TYPE_DIRECT 2 /* type with variable */ |
#define IO_BUF_SIZE 8192 |
typedef struct BufferedFile { |
uint8_t *buf_ptr; |
uint8_t *buf_end; |
int fd; |
int line_num; /* current line number - here to simplify code */ |
int ifndef_macro; /* #ifndef macro / #endif search */ |
int ifndef_macro_saved; /* saved ifndef_macro */ |
int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */ |
char inc_type; /* type of include */ |
char inc_filename[512]; /* filename specified by the user */ |
char filename[1024]; /* current filename - here to simplify code */ |
unsigned char buffer[IO_BUF_SIZE + 1]; /* extra size for CH_EOB char */ |
} BufferedFile; |
#define CH_EOB '\\' /* end of buffer or '\0' char in file */ |
#define CH_EOF (-1) /* end of file */ |
/* parsing state (used to save parser state to reparse part of the |
source several times) */ |
typedef struct ParseState { |
int *macro_ptr; |
int line_num; |
int tok; |
CValue tokc; |
} ParseState; |
/* used to record tokens */ |
typedef struct TokenString { |
int *str; |
int len; |
int allocated_len; |
int last_line_num; |
} TokenString; |
/* include file cache, used to find files faster and also to eliminate |
inclusion if the include file is protected by #ifndef ... #endif */ |
typedef struct CachedInclude { |
int ifndef_macro; |
int hash_next; /* -1 if none */ |
char type; /* '"' or '>' to give include type */ |
char filename[1]; /* path specified in #include */ |
} CachedInclude; |
#define CACHED_INCLUDES_HASH_SIZE 512 |
/* parser */ |
static struct BufferedFile *file; |
static int ch, tok; |
static CValue tokc; |
static CString tokcstr; /* current parsed string, if any */ |
/* additional informations about token */ |
static int tok_flags; |
#define TOK_FLAG_BOL 0x0001 /* beginning of line before */ |
#define TOK_FLAG_BOF 0x0002 /* beginning of file before */ |
#define TOK_FLAG_ENDIF 0x0004 /* a endif was found matching starting #ifdef */ |
static int *macro_ptr, *macro_ptr_allocated; |
static int *unget_saved_macro_ptr; |
static int unget_saved_buffer[TOK_MAX_SIZE + 1]; |
static int unget_buffer_enabled; |
static int parse_flags; |
#define PARSE_FLAG_PREPROCESS 0x0001 /* activate preprocessing */ |
#define PARSE_FLAG_TOK_NUM 0x0002 /* return numbers instead of TOK_PPNUM */ |
#define PARSE_FLAG_LINEFEED 0x0004 /* line feed is returned as a |
token. line feed is also |
returned at eof */ |
#define PARSE_FLAG_ASM_COMMENTS 0x0008 /* '#' can be used for line comment */ |
static Section *text_section, *data_section, *bss_section; /* predefined sections */ |
static Section *cur_text_section; /* current section where function code is |
generated */ |
#ifdef CONFIG_TCC_ASM |
static Section *last_text_section; /* to handle .previous asm directive */ |
#endif |
/* bound check related sections */ |
static Section *bounds_section; /* contains global data bound description */ |
static Section *lbounds_section; /* contains local data bound description */ |
/* symbol sections */ |
static Section *symtab_section, *strtab_section; |
/* debug sections */ |
static Section *stab_section, *stabstr_section; |
/* loc : local variable index |
ind : output code index |
rsym: return symbol |
anon_sym: anonymous symbol index |
*/ |
static int rsym, anon_sym, ind, loc; |
/* expression generation modifiers */ |
static int const_wanted; /* true if constant wanted */ |
static int nocode_wanted; /* true if no code generation wanted for an expression */ |
static int global_expr; /* true if compound literals must be allocated |
globally (used during initializers parsing */ |
static CType func_vt; /* current function return type (used by return |
instruction) */ |
static int func_vc; |
static int last_line_num, last_ind, func_ind; /* debug last line number and pc */ |
static int tok_ident; |
static TokenSym **table_ident; |
static TokenSym *hash_ident[TOK_HASH_SIZE]; |
static char token_buf[STRING_MAX_SIZE + 1]; |
static char *funcname; |
static Sym *global_stack, *local_stack; |
static Sym *define_stack; |
static Sym *global_label_stack, *local_label_stack; |
/* symbol allocator */ |
#define SYM_POOL_NB (8192 / sizeof(Sym)) |
static Sym *sym_free_first; |
static SValue vstack[VSTACK_SIZE], *vtop; |
/* some predefined types */ |
static CType char_pointer_type, func_old_type, int_type; |
/* true if isid(c) || isnum(c) */ |
static unsigned char isidnum_table[256]; |
/* compile with debug symbol (and use them if error during execution) */ |
static int do_debug = 0; |
/* compile with built-in memory and bounds checker */ |
static int do_bounds_check = 0; |
/* display benchmark infos */ |
#if !defined(LIBTCC) |
static int do_bench = 0; |
#endif |
static int total_lines; |
static int total_bytes; |
/* use GNU C extensions */ |
static int gnu_ext = 1; |
/* use Tiny C extensions */ |
static int tcc_ext = 1; |
/* max number of callers shown if error */ |
static int num_callers = 6; |
static const char **rt_bound_error_msg; |
/* XXX: get rid of this ASAP */ |
static struct TCCState *tcc_state; |
/* give the path of the tcc libraries */ |
static const char *tcc_lib_path = CONFIG_TCCDIR; |
struct TCCState { |
int output_type; |
BufferedFile **include_stack_ptr; |
int *ifdef_stack_ptr; |
/* include file handling */ |
char **include_paths; |
int nb_include_paths; |
char **sysinclude_paths; |
int nb_sysinclude_paths; |
CachedInclude **cached_includes; |
int nb_cached_includes; |
char **library_paths; |
int nb_library_paths; |
/* array of all loaded dlls (including those referenced by loaded |
dlls) */ |
DLLReference **loaded_dlls; |
int nb_loaded_dlls; |
/* sections */ |
Section **sections; |
int nb_sections; /* number of sections, including first dummy section */ |
/* got handling */ |
Section *got; |
Section *plt; |
unsigned long *got_offsets; |
int nb_got_offsets; |
/* give the correspondance from symtab indexes to dynsym indexes */ |
int *symtab_to_dynsym; |
/* temporary dynamic symbol sections (for dll loading) */ |
Section *dynsymtab_section; |
/* exported dynamic symbol section */ |
Section *dynsym; |
int nostdinc; /* if true, no standard headers are added */ |
int nostdlib; /* if true, no standard libraries are added */ |
int nocommon; /* if true, do not use common symbols for .bss data */ |
/* if true, static linking is performed */ |
int static_link; |
/* if true, all symbols are exported */ |
int rdynamic; |
/* if true, only link in referenced objects from archive */ |
int alacarte_link; |
/* address of text section */ |
unsigned long text_addr; |
int has_text_addr; |
/* output format, see TCC_OUTPUT_FORMAT_xxx */ |
int output_format; |
/* C language options */ |
int char_is_unsigned; |
int leading_underscore; |
/* warning switches */ |
int warn_write_strings; |
int warn_unsupported; |
int warn_error; |
int warn_none; |
int warn_implicit_function_declaration; |
/* error handling */ |
void *error_opaque; |
void (*error_func)(void *opaque, const char *msg); |
int error_set_jmp_enabled; |
jmp_buf error_jmp_buf; |
int nb_errors; |
/* tiny assembler state */ |
Sym *asm_labels; |
/* see include_stack_ptr */ |
BufferedFile *include_stack[INCLUDE_STACK_SIZE]; |
/* see ifdef_stack_ptr */ |
int ifdef_stack[IFDEF_STACK_SIZE]; |
/* see cached_includes */ |
int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE]; |
/* pack stack */ |
int pack_stack[PACK_STACK_SIZE]; |
int *pack_stack_ptr; |
}; |
/* The current value can be: */ |
#define VT_VALMASK 0x00ff |
#define VT_CONST 0x00f0 /* constant in vc |
(must be first non register value) */ |
#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */ |
#define VT_LOCAL 0x00f2 /* offset on stack */ |
#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */ |
#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */ |
#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */ |
#define VT_LVAL 0x0100 /* var is an lvalue */ |
#define VT_SYM 0x0200 /* a symbol value is added */ |
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for |
char/short stored in integer registers) */ |
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before |
dereferencing value */ |
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the |
bounding function call point is in vc */ |
#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */ |
#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */ |
#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */ |
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) |
/* types */ |
#define VT_INT 0 /* integer type */ |
#define VT_BYTE 1 /* signed byte type */ |
#define VT_SHORT 2 /* short type */ |
#define VT_VOID 3 /* void type */ |
#define VT_PTR 4 /* pointer */ |
#define VT_ENUM 5 /* enum definition */ |
#define VT_FUNC 6 /* function type */ |
#define VT_STRUCT 7 /* struct/union definition */ |
#define VT_FLOAT 8 /* IEEE float */ |
#define VT_DOUBLE 9 /* IEEE double */ |
#define VT_LDOUBLE 10 /* IEEE long double */ |
#define VT_BOOL 11 /* ISOC99 boolean type */ |
#define VT_LLONG 12 /* 64 bit integer */ |
#define VT_LONG 13 /* long integer (NEVER USED as type, only |
during parsing) */ |
#define VT_BTYPE 0x000f /* mask for basic type */ |
#define VT_UNSIGNED 0x0010 /* unsigned type */ |
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ |
#define VT_BITFIELD 0x0040 /* bitfield modifier */ |
#define VT_CONSTANT 0x0800 /* const modifier */ |
#define VT_VOLATILE 0x1000 /* volatile modifier */ |
#define VT_SIGNED 0x2000 /* signed type */ |
/* storage */ |
#define VT_EXTERN 0x00000080 /* extern definition */ |
#define VT_STATIC 0x00000100 /* static variable */ |
#define VT_TYPEDEF 0x00000200 /* typedef definition */ |
#define VT_INLINE 0x00000400 /* inline definition */ |
#define VT_STRUCT_SHIFT 16 /* shift for bitfield shift values */ |
/* type mask (except storage) */ |
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE) |
#define VT_TYPE (~(VT_STORAGE)) |
/* token values */ |
/* warning: the following compare tokens depend on i386 asm code */ |
#define TOK_ULT 0x92 |
#define TOK_UGE 0x93 |
#define TOK_EQ 0x94 |
#define TOK_NE 0x95 |
#define TOK_ULE 0x96 |
#define TOK_UGT 0x97 |
#define TOK_LT 0x9c |
#define TOK_GE 0x9d |
#define TOK_LE 0x9e |
#define TOK_GT 0x9f |
#define TOK_LAND 0xa0 |
#define TOK_LOR 0xa1 |
#define TOK_DEC 0xa2 |
#define TOK_MID 0xa3 /* inc/dec, to void constant */ |
#define TOK_INC 0xa4 |
#define TOK_UDIV 0xb0 /* unsigned division */ |
#define TOK_UMOD 0xb1 /* unsigned modulo */ |
#define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */ |
#define TOK_CINT 0xb3 /* number in tokc */ |
#define TOK_CCHAR 0xb4 /* char constant in tokc */ |
#define TOK_STR 0xb5 /* pointer to string in tokc */ |
#define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */ |
#define TOK_LCHAR 0xb7 |
#define TOK_LSTR 0xb8 |
#define TOK_CFLOAT 0xb9 /* float constant */ |
#define TOK_LINENUM 0xba /* line number info */ |
#define TOK_CDOUBLE 0xc0 /* double constant */ |
#define TOK_CLDOUBLE 0xc1 /* long double constant */ |
#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */ |
#define TOK_ADDC1 0xc3 /* add with carry generation */ |
#define TOK_ADDC2 0xc4 /* add with carry use */ |
#define TOK_SUBC1 0xc5 /* add with carry generation */ |
#define TOK_SUBC2 0xc6 /* add with carry use */ |
#define TOK_CUINT 0xc8 /* unsigned int constant */ |
#define TOK_CLLONG 0xc9 /* long long constant */ |
#define TOK_CULLONG 0xca /* unsigned long long constant */ |
#define TOK_ARROW 0xcb |
#define TOK_DOTS 0xcc /* three dots */ |
#define TOK_SHR 0xcd /* unsigned shift right */ |
#define TOK_PPNUM 0xce /* preprocessor number */ |
#define TOK_SHL 0x01 /* shift left */ |
#define TOK_SAR 0x02 /* signed shift right */ |
/* assignement operators : normal operator or 0x80 */ |
#define TOK_A_MOD 0xa5 |
#define TOK_A_AND 0xa6 |
#define TOK_A_MUL 0xaa |
#define TOK_A_ADD 0xab |
#define TOK_A_SUB 0xad |
#define TOK_A_DIV 0xaf |
#define TOK_A_XOR 0xde |
#define TOK_A_OR 0xfc |
#define TOK_A_SHL 0x81 |
#define TOK_A_SAR 0x82 |
#ifndef offsetof |
#define offsetof(type, field) ((size_t) &((type *)0)->field) |
#endif |
#ifndef countof |
#define countof(tab) (sizeof(tab) / sizeof((tab)[0])) |
#endif |
/* WARNING: the content of this string encodes token numbers */ |
static char tok_two_chars[] = "<=\236>=\235!=\225&&\240||\241++\244--\242==\224<<\1>>\2+=\253-=\255*=\252/=\257%=\245&=\246^=\336|=\374->\313..\250##\266"; |
#define TOK_EOF (-1) /* end of file */ |
#define TOK_LINEFEED 10 /* line feed */ |
/* all identificators and strings have token above that */ |
#define TOK_IDENT 256 |
/* only used for i386 asm opcodes definitions */ |
#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x) |
#define DEF_BWL(x) \ |
DEF(TOK_ASM_ ## x ## b, #x "b") \ |
DEF(TOK_ASM_ ## x ## w, #x "w") \ |
DEF(TOK_ASM_ ## x ## l, #x "l") \ |
DEF(TOK_ASM_ ## x, #x) |
#define DEF_WL(x) \ |
DEF(TOK_ASM_ ## x ## w, #x "w") \ |
DEF(TOK_ASM_ ## x ## l, #x "l") \ |
DEF(TOK_ASM_ ## x, #x) |
#define DEF_FP1(x) \ |
DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \ |
DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \ |
DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \ |
DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s") |
#define DEF_FP(x) \ |
DEF(TOK_ASM_ ## f ## x, "f" #x ) \ |
DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \ |
DEF_FP1(x) |
#define DEF_ASMTEST(x) \ |
DEF_ASM(x ## o) \ |
DEF_ASM(x ## no) \ |
DEF_ASM(x ## b) \ |
DEF_ASM(x ## c) \ |
DEF_ASM(x ## nae) \ |
DEF_ASM(x ## nb) \ |
DEF_ASM(x ## nc) \ |
DEF_ASM(x ## ae) \ |
DEF_ASM(x ## e) \ |
DEF_ASM(x ## z) \ |
DEF_ASM(x ## ne) \ |
DEF_ASM(x ## nz) \ |
DEF_ASM(x ## be) \ |
DEF_ASM(x ## na) \ |
DEF_ASM(x ## nbe) \ |
DEF_ASM(x ## a) \ |
DEF_ASM(x ## s) \ |
DEF_ASM(x ## ns) \ |
DEF_ASM(x ## p) \ |
DEF_ASM(x ## pe) \ |
DEF_ASM(x ## np) \ |
DEF_ASM(x ## po) \ |
DEF_ASM(x ## l) \ |
DEF_ASM(x ## nge) \ |
DEF_ASM(x ## nl) \ |
DEF_ASM(x ## ge) \ |
DEF_ASM(x ## le) \ |
DEF_ASM(x ## ng) \ |
DEF_ASM(x ## nle) \ |
DEF_ASM(x ## g) |
#define TOK_ASM_int TOK_INT |
enum tcc_token { |
TOK_LAST = TOK_IDENT - 1, |
#define DEF(id, str) id, |
#include "tcctok.h" |
#undef DEF |
}; |
static const char tcc_keywords[] = |
#define DEF(id, str) str "\0" |
#include "tcctok.h" |
#undef DEF |
; |
#define TOK_UIDENT TOK_DEFINE |
#ifdef WIN32 |
int __stdcall GetModuleFileNameA(void *, char *, int); |
void *__stdcall GetProcAddress(void *, const char *); |
void *__stdcall GetModuleHandleA(const char *); |
void *__stdcall LoadLibraryA(const char *); |
int __stdcall FreeConsole(void); |
#define snprintf _snprintf |
#define vsnprintf _vsnprintf |
#ifndef __GNUC__ |
#define strtold (long double)strtod |
#define strtof (float)strtod |
#define strtoll (long long)strtol |
#endif |
#elif defined(TCC_UCLIBC) || defined(__FreeBSD__) |
long double strtold(const char *nptr, char **endptr) |
{ |
int i; |
printf("%s:\n%s", msg, nb_paths ? "" : " -\n"); |
for(i = 0; i < nb_paths; i++) |
printf(" %s\n", paths[i]); |
return (long double)strtod(nptr, endptr); |
} |
float strtof(const char *nptr, char **endptr) |
{ |
return (float)strtod(nptr, endptr); |
} |
static void display_info(TCCState *s, int what) |
#else |
/* XXX: need to define this to use them in non ISOC99 context */ |
extern float strtof (const char *__nptr, char **__endptr); |
extern long double strtold (const char *__nptr, char **__endptr); |
//extern long long strtoll(const char *__nptr, char **__endptr, int __base) |
#endif |
#define strtold (long double)strtod |
#define strtof (float)strtod |
#define strtoll (long long)strtol |
static char *pstrcpy(char *buf, int buf_size, const char *s); |
static char *pstrcat(char *buf, int buf_size, const char *s); |
static const char *tcc_basename(const char *name); |
static void next(void); |
static void next_nomacro(void); |
static void parse_expr_type(CType *type); |
static void expr_type(CType *type); |
static void unary_type(CType *type); |
static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
int case_reg, int is_expr); |
static int expr_const(void); |
static void expr_eq(void); |
static void gexpr(void); |
static void gen_inline_functions(void); |
static void decl(int l); |
static void decl_initializer(CType *type, Section *sec, unsigned long c, |
int first, int size_only); |
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
int has_init, int v, int scope); |
int gv(int rc); |
void gv2(int rc1, int rc2); |
void move_reg(int r, int s); |
void save_regs(int n); |
void save_reg(int r); |
void vpop(void); |
void vswap(void); |
void vdup(void); |
int get_reg(int rc); |
int get_reg_ex(int rc,int rc2); |
struct macro_level { |
struct macro_level *prev; |
int *p; |
}; |
static void macro_subst(TokenString *tok_str, Sym **nested_list, |
const int *macro_str, struct macro_level **can_read_stream); |
void gen_op(int op); |
void force_charshort_cast(int t); |
static void gen_cast(CType *type); |
void vstore(void); |
static Sym *sym_find(int v); |
static Sym *sym_push(int v, CType *type, int r, int c); |
/* type handling */ |
static int type_size(CType *type, int *a); |
static inline CType *pointed_type(CType *type); |
static int pointed_size(CType *type); |
static int lvalue_type(int t); |
static int parse_btype(CType *type, AttributeDef *ad); |
static void type_decl(CType *type, AttributeDef *ad, int *v, int td); |
static int is_compatible_types(CType *type1, CType *type2); |
int ieee_finite(double d); |
void error(const char *fmt, ...); |
void vpushi(int v); |
void vrott(int n); |
void vnrott(int n); |
void lexpand_nr(void); |
static void vpush_global_sym(CType *type, int v); |
void vset(CType *type, int r, int v); |
void type_to_str(char *buf, int buf_size, |
CType *type, const char *varstr); |
char *get_tok_str(int v, CValue *cv); |
static Sym *get_sym_ref(CType *type, Section *sec, |
unsigned long offset, unsigned long size); |
static Sym *external_global_sym(int v, CType *type, int r); |
/* section generation */ |
static void section_realloc(Section *sec, unsigned long new_size); |
static void *section_ptr_add(Section *sec, unsigned long size); |
static void put_extern_sym(Sym *sym, Section *section, |
unsigned long value, unsigned long size); |
static void greloc(Section *s, Sym *sym, unsigned long addr, int type); |
static int put_elf_str(Section *s, const char *sym); |
static int put_elf_sym(Section *s, |
unsigned long value, unsigned long size, |
int info, int other, int shndx, const char *name); |
static int add_elf_sym(Section *s, unsigned long value, unsigned long size, |
int info, int other, int sh_num, const char *name); |
static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, |
int type, int symbol); |
static void put_stabs(const char *str, int type, int other, int desc, |
unsigned long value); |
static void put_stabs_r(const char *str, int type, int other, int desc, |
unsigned long value, Section *sec, int sym_index); |
static void put_stabn(int type, int other, int desc, int value); |
static void put_stabd(int type, int other, int desc); |
static int tcc_add_dll(TCCState *s, const char *filename, int flags); |
#define AFF_PRINT_ERROR 0x0001 /* print error if file not found */ |
#define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */ |
static int tcc_add_file_internal(TCCState *s, const char *filename, int flags); |
/* tcccoff.c */ |
int tcc_output_coff(TCCState *s1, FILE *f); |
/* tccpe.c */ |
void *resolve_sym(TCCState *s1, const char *sym, int type); |
int pe_load_def_file(struct TCCState *s1, FILE *fp); |
void pe_setup_paths(struct TCCState *s1, int *p_output_type, const char **p_outfile, char *first_file); |
unsigned long pe_add_runtime(struct TCCState *s1); |
int tcc_output_pe(struct TCCState *s1, const char *filename); |
/* tccasm.c */ |
#ifdef CONFIG_TCC_ASM |
typedef struct ExprValue { |
uint32_t v; |
Sym *sym; |
} ExprValue; |
#define MAX_ASM_OPERANDS 30 |
typedef struct ASMOperand { |
int id; /* GCC 3 optionnal identifier (0 if number only supported */ |
char *constraint; |
char asm_str[16]; /* computed asm string for operand */ |
SValue *vt; /* C value of the expression */ |
int ref_index; /* if >= 0, gives reference to a output constraint */ |
int input_index; /* if >= 0, gives reference to an input constraint */ |
int priority; /* priority, used to assign registers */ |
int reg; /* if >= 0, register number used for this operand */ |
int is_llong; /* true if double register value */ |
int is_memory; /* true if memory operand */ |
int is_rw; /* for '+' modifier */ |
} ASMOperand; |
static void asm_expr(TCCState *s1, ExprValue *pe); |
static int asm_int_expr(TCCState *s1); |
static int find_constraint(ASMOperand *operands, int nb_operands, |
const char *name, const char **pp); |
static int tcc_assemble(TCCState *s1, int do_preprocess); |
#endif |
static void asm_instr(void); |
static void asm_global_instr(void); |
/* true if float/double/long double type */ |
static inline int is_float(int t) |
{ |
switch (what) { |
case 0: |
printf("tcc version %s (" |
int bt; |
bt = t & VT_BTYPE; |
return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT; |
} |
#ifdef TCC_TARGET_I386 |
"i386" |
#elif defined TCC_TARGET_X86_64 |
"x86-64" |
#elif defined TCC_TARGET_C67 |
"C67" |
#elif defined TCC_TARGET_ARM |
"ARM" |
# ifdef TCC_ARM_HARDFLOAT |
" Hard Float" |
#include "i386-gen.c" |
# endif |
#elif defined TCC_TARGET_ARM64 |
"AArch64" |
# ifdef TCC_ARM_HARDFLOAT |
" Hard Float" |
#ifdef TCC_TARGET_ARM |
#include "arm-gen.c" |
# endif |
#ifdef TCC_TARGET_C67 |
#include "c67-gen.c" |
#endif |
#ifdef TCC_TARGET_PE |
" Windows" |
#elif defined TCC_TARGET_MEOS |
" KolibriOS" |
#ifdef CONFIG_TCC_STATIC |
#define RTLD_LAZY 0x001 |
#define RTLD_NOW 0x002 |
#define RTLD_GLOBAL 0x100 |
#define RTLD_DEFAULT NULL |
/* dummy function for profiling */ |
void *dlopen(const char *filename, int flag) |
{ |
return NULL; |
} |
const char *dlerror(void) |
{ |
return "error"; |
} |
typedef struct TCCSyms { |
char *str; |
void *ptr; |
} TCCSyms; |
#define TCCSYM(a) { #a, &a, }, |
/* add the symbol you want here if no dynamic linking is done */ |
static TCCSyms tcc_syms[] = { |
#if !defined(CONFIG_TCCBOOT) |
TCCSYM(printf) |
TCCSYM(printf) |
TCCSYM(fopen) |
TCCSYM(fclose) |
#endif |
{ NULL, NULL }, |
}; |
void *resolve_sym(TCCState *s1, const char *symbol, int type) |
{ |
TCCSyms *p; |
p = tcc_syms; |
while (p->str != NULL) { |
if (!strcmp(p->str, symbol)) |
return p->ptr; |
p++; |
} |
return NULL; |
} |
#elif !defined(WIN32) |
//------------------------------------------------------------------------- |
//#include <dlfcn.h> |
void *resolve_sym(TCCState *s1, const char *sym, int type) |
{ |
return(0); |
//return dlsym(RTLD_DEFAULT, sym); |
} |
//------------------------------------------------------------------------- |
#endif |
/********************************************************/ |
/* we use our own 'finite' function to avoid potential problems with |
non standard math libs */ |
/* XXX: endianness dependent */ |
int ieee_finite(double d) |
{ |
int *p = (int *)&d; |
return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; |
} |
/* copy a string and truncate it. */ |
static char *pstrcpy(char *buf, int buf_size, const char *s) |
{ |
char *q, *q_end; |
int c; |
if (buf_size > 0) { |
q = buf; |
q_end = buf + buf_size - 1; |
while (q < q_end) { |
c = *s++; |
if (c == '\0') |
break; |
*q++ = c; |
} |
*q = '\0'; |
} |
return buf; |
} |
/* strcat and truncate. */ |
static char *pstrcat(char *buf, int buf_size, const char *s) |
{ |
int len; |
len = strlen(buf); |
if (len < buf_size) |
pstrcpy(buf + len, buf_size - len, s); |
return buf; |
} |
static int strstart(const char *str, const char *val, const char **ptr) |
{ |
const char *p, *q; |
p = str; |
q = val; |
while (*q != '\0') { |
if (*p != *q) |
return 0; |
p++; |
q++; |
} |
if (ptr) |
*ptr = p; |
return 1; |
} |
/* memory management */ |
#ifdef MEM_DEBUG |
int mem_cur_size; |
int mem_max_size; |
#endif |
static inline void tcc_free(void *ptr) |
{ |
#ifdef MEM_DEBUG |
mem_cur_size -= malloc_usable_size(ptr); |
#endif |
//2016-04-27 siemargl commented to fix crash temporally. Need to fix |
// free(ptr); |
} |
static void *tcc_malloc(unsigned long size) |
{ |
void *ptr; |
ptr = malloc(size); |
if (!ptr && size) |
error("memory full"); |
#ifdef MEM_DEBUG |
mem_cur_size += malloc_usable_size(ptr); |
if (mem_cur_size > mem_max_size) |
mem_max_size = mem_cur_size; |
#endif |
return ptr; |
} |
static void *tcc_mallocz(unsigned long size) |
{ |
void *ptr; |
ptr = tcc_malloc(size); |
memset(ptr, 0, size); |
return ptr; |
} |
static inline void *tcc_realloc(void *ptr, unsigned long size) |
{ |
void *ptr1; |
#ifdef MEM_DEBUG |
mem_cur_size -= malloc_usable_size(ptr); |
#endif |
ptr1 = realloc(ptr, size); |
#ifdef MEM_DEBUG |
/* NOTE: count not correct if alloc error, but not critical */ |
mem_cur_size += malloc_usable_size(ptr1); |
if (mem_cur_size > mem_max_size) |
mem_max_size = mem_cur_size; |
#endif |
return ptr1; |
} |
static char *tcc_strdup(const char *str) |
{ |
char *ptr; |
ptr = tcc_malloc(strlen(str) + 1); |
strcpy(ptr, str); |
return ptr; |
} |
#define free(p) use_tcc_free(p) |
#define malloc(s) use_tcc_malloc(s) |
#define realloc(p, s) use_tcc_realloc(p, s) |
static void dynarray_add(void ***ptab, int *nb_ptr, void *data) |
{ |
int nb, nb_alloc; |
void **pp; |
nb = *nb_ptr; |
pp = *ptab; |
/* every power of two we double array size */ |
if ((nb & (nb - 1)) == 0) { |
if (!nb) |
nb_alloc = 1; |
else |
nb_alloc = nb * 2; |
pp = tcc_realloc(pp, nb_alloc * sizeof(void *)); |
if (!pp) |
error("memory full"); |
*ptab = pp; |
} |
pp[nb++] = data; |
*nb_ptr = nb; |
} |
/* symbol allocator */ |
static Sym *__sym_malloc(void) |
{ |
Sym *sym_pool, *sym, *last_sym; |
int i; |
sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); |
last_sym = sym_free_first; |
sym = sym_pool; |
for(i = 0; i < SYM_POOL_NB; i++) { |
sym->next = last_sym; |
last_sym = sym; |
sym++; |
} |
sym_free_first = last_sym; |
return last_sym; |
} |
static inline Sym *sym_malloc(void) |
{ |
Sym *sym; |
sym = sym_free_first; |
if (!sym) |
sym = __sym_malloc(); |
sym_free_first = sym->next; |
return sym; |
} |
static inline void sym_free(Sym *sym) |
{ |
sym->next = sym_free_first; |
sym_free_first = sym; |
} |
Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) |
{ |
Section *sec; |
sec = tcc_mallocz(sizeof(Section) + strlen(name)); |
strcpy(sec->name, name); |
sec->sh_type = sh_type; |
sec->sh_flags = sh_flags; |
switch(sh_type) { |
case SHT_HASH: |
case SHT_REL: |
case SHT_DYNSYM: |
case SHT_SYMTAB: |
case SHT_DYNAMIC: |
sec->sh_addralign = 4; |
break; |
case SHT_STRTAB: |
sec->sh_addralign = 1; |
break; |
default: |
sec->sh_addralign = 32; /* default conservative alignment */ |
break; |
} |
/* only add section if not private */ |
if (!(sh_flags & SHF_PRIVATE)) { |
sec->sh_num = s1->nb_sections; |
dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec); |
} |
return sec; |
} |
static void free_section(Section *s) |
{ |
tcc_free(s->data); |
tcc_free(s); |
} |
/* realloc section and set its content to zero */ |
static void section_realloc(Section *sec, unsigned long new_size) |
{ |
unsigned long size; |
unsigned char *data; |
size = sec->data_allocated; |
if (size == 0) |
size = 1; |
while (size < new_size) |
size = size * 2; |
data = tcc_realloc(sec->data, size); |
if (!data) |
error("memory full"); |
memset(data + sec->data_allocated, 0, size - sec->data_allocated); |
sec->data = data; |
sec->data_allocated = size; |
} |
/* reserve at least 'size' bytes in section 'sec' from |
sec->data_offset. */ |
static void *section_ptr_add(Section *sec, unsigned long size) |
{ |
unsigned long offset, offset1; |
offset = sec->data_offset; |
offset1 = offset + size; |
if (offset1 > sec->data_allocated) |
section_realloc(sec, offset1); |
sec->data_offset = offset1; |
return sec->data + offset; |
} |
/* return a reference to a section, and create it if it does not |
exists */ |
Section *find_section(TCCState *s1, const char *name) |
{ |
Section *sec; |
int i; |
for(i = 1; i < s1->nb_sections; i++) { |
sec = s1->sections[i]; |
if (!strcmp(name, sec->name)) |
return sec; |
} |
/* sections are created as PROGBITS */ |
return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC); |
} |
#define SECTION_ABS ((void *)1) |
/* update sym->c so that it points to an external symbol in section |
'section' with value 'value' */ |
static void put_extern_sym2(Sym *sym, Section *section, |
unsigned long value, unsigned long size, |
int can_add_underscore) |
{ |
int sym_type, sym_bind, sh_num, info; |
Elf32_Sym *esym; |
const char *name; |
char buf1[256]; |
if (section == NULL) |
sh_num = SHN_UNDEF; |
else if (section == SECTION_ABS) |
sh_num = SHN_ABS; |
else |
sh_num = section->sh_num; |
if (!sym->c) { |
if ((sym->type.t & VT_BTYPE) == VT_FUNC) |
sym_type = STT_FUNC; |
else |
sym_type = STT_OBJECT; |
if (sym->type.t & VT_STATIC) |
sym_bind = STB_LOCAL; |
else |
sym_bind = STB_GLOBAL; |
name = get_tok_str(sym->v, NULL); |
#ifdef CONFIG_TCC_BCHECK |
if (do_bounds_check) { |
char buf[32]; |
/* XXX: avoid doing that for statics ? */ |
/* if bound checking is activated, we change some function |
names by adding the "__bound" prefix */ |
switch(sym->v) { |
#if 0 |
/* XXX: we rely only on malloc hooks */ |
case TOK_malloc: |
case TOK_free: |
case TOK_realloc: |
case TOK_memalign: |
case TOK_calloc: |
#endif |
case TOK_memcpy: |
case TOK_memmove: |
case TOK_memset: |
case TOK_strlen: |
case TOK_strcpy: |
strcpy(buf, "__bound_"); |
strcat(buf, name); |
name = buf; |
break; |
} |
} |
#endif |
if (tcc_state->leading_underscore && can_add_underscore) { |
buf1[0] = '_'; |
pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); |
name = buf1; |
} |
info = ELF32_ST_INFO(sym_bind, sym_type); |
sym->c = add_elf_sym(symtab_section, value, size, info, 0, sh_num, name); |
} else { |
esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
esym->st_value = value; |
esym->st_size = size; |
esym->st_shndx = sh_num; |
} |
} |
static void put_extern_sym(Sym *sym, Section *section, |
unsigned long value, unsigned long size) |
{ |
put_extern_sym2(sym, section, value, size, 1); |
} |
/* add a new relocation entry to symbol 'sym' in section 's' */ |
static void greloc(Section *s, Sym *sym, unsigned long offset, int type) |
{ |
if (!sym->c) |
put_extern_sym(sym, NULL, 0, 0); |
/* now we can add ELF relocation info */ |
put_elf_reloc(symtab_section, s, offset, type, sym->c); |
} |
static inline int isid(int c) |
{ |
return (c >= 'a' && c <= 'z') || |
(c >= 'A' && c <= 'Z') || |
c == '_'; |
} |
static inline int isnum(int c) |
{ |
return c >= '0' && c <= '9'; |
} |
static inline int isoct(int c) |
{ |
return c >= '0' && c <= '7'; |
} |
static inline int toup(int c) |
{ |
if (c >= 'a' && c <= 'z') |
return c - 'a' + 'A'; |
else |
return c; |
} |
static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap) |
{ |
int len; |
len = strlen(buf); |
vsnprintf(buf + len, buf_size - len, fmt, ap); |
} |
static void strcat_printf(char *buf, int buf_size, const char *fmt, ...) |
{ |
va_list ap; |
va_start(ap, fmt); |
strcat_vprintf(buf, buf_size, fmt, ap); |
va_end(ap); |
} |
void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap) |
{ |
char buf[2048]; |
BufferedFile **f; |
buf[0] = '\0'; |
if (file) { |
for(f = s1->include_stack; f < s1->include_stack_ptr; f++) |
strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n", |
(*f)->filename, (*f)->line_num); |
if (file->line_num > 0) { |
strcat_printf(buf, sizeof(buf), |
"%s:%d: ", file->filename, file->line_num); |
} else { |
strcat_printf(buf, sizeof(buf), |
"%s: ", file->filename); |
} |
} else { |
strcat_printf(buf, sizeof(buf), |
"tcc: "); |
} |
if (is_warning) |
strcat_printf(buf, sizeof(buf), "warning: "); |
strcat_vprintf(buf, sizeof(buf), fmt, ap); |
if (!s1->error_func) { |
/* default case: stderr */ |
printf("%s\n", buf); |
} else { |
s1->error_func(s1->error_opaque, buf); |
} |
if (!is_warning || s1->warn_error) |
s1->nb_errors++; |
} |
#ifdef LIBTCC |
void tcc_set_error_func(TCCState *s, void *error_opaque, |
void (*error_func)(void *opaque, const char *msg)) |
{ |
s->error_opaque = error_opaque; |
s->error_func = error_func; |
} |
#endif |
/* error without aborting current compilation */ |
void error_noabort(const char *fmt, ...) |
{ |
TCCState *s1 = tcc_state; |
va_list ap; |
va_start(ap, fmt); |
error1(s1, 0, fmt, ap); |
va_end(ap); |
} |
void error(const char *fmt, ...) |
{ |
TCCState *s1 = tcc_state; |
va_list ap; |
va_start(ap, fmt); |
error1(s1, 0, fmt, ap); |
va_end(ap); |
/* better than nothing: in some cases, we accept to handle errors */ |
if (s1->error_set_jmp_enabled) { |
longjmp(s1->error_jmp_buf, 1); |
} else { |
/* XXX: eliminate this someday */ |
exit(1); |
} |
} |
void expect(const char *msg) |
{ |
error("%s expected", msg); |
} |
void warning(const char *fmt, ...) |
{ |
TCCState *s1 = tcc_state; |
va_list ap; |
if (s1->warn_none) |
return; |
va_start(ap, fmt); |
error1(s1, 1, fmt, ap); |
va_end(ap); |
} |
void skip(int c) |
{ |
if (tok != c) |
error("'%c' expected", c); |
next(); |
} |
static void test_lvalue(void) |
{ |
if (!(vtop->r & VT_LVAL)) |
expect("lvalue"); |
} |
/* allocate a new token */ |
static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len) |
{ |
TokenSym *ts, **ptable; |
int i; |
if (tok_ident >= SYM_FIRST_ANOM) |
error("memory full"); |
/* expand token table if needed */ |
i = tok_ident - TOK_IDENT; |
if ((i % TOK_ALLOC_INCR) == 0) { |
ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *)); |
if (!ptable) |
error("memory full"); |
table_ident = ptable; |
} |
ts = tcc_malloc(sizeof(TokenSym) + len); |
table_ident[i] = ts; |
ts->tok = tok_ident++; |
ts->sym_define = NULL; |
ts->sym_label = NULL; |
ts->sym_struct = NULL; |
ts->sym_identifier = NULL; |
ts->len = len; |
ts->hash_next = NULL; |
memcpy(ts->str, str, len); |
ts->str[len] = '\0'; |
*pts = ts; |
return ts; |
} |
#define TOK_HASH_INIT 1 |
#define TOK_HASH_FUNC(h, c) ((h) * 263 + (c)) |
/* find a token and add it if not found */ |
static TokenSym *tok_alloc(const char *str, int len) |
{ |
TokenSym *ts, **pts; |
int i; |
unsigned int h; |
h = TOK_HASH_INIT; |
for(i=0;i<len;i++) |
h = TOK_HASH_FUNC(h, ((unsigned char *)str)[i]); |
h &= (TOK_HASH_SIZE - 1); |
pts = &hash_ident[h]; |
for(;;) { |
ts = *pts; |
if (!ts) |
break; |
if (ts->len == len && !memcmp(ts->str, str, len)) |
return ts; |
pts = &(ts->hash_next); |
} |
return tok_alloc_new(pts, str, len); |
} |
/* CString handling */ |
static void cstr_realloc(CString *cstr, int new_size) |
{ |
int size; |
void *data; |
size = cstr->size_allocated; |
if (size == 0) |
size = 8; /* no need to allocate a too small first string */ |
while (size < new_size) |
size = size * 2; |
data = tcc_realloc(cstr->data_allocated, size); |
if (!data) |
error("memory full"); |
cstr->data_allocated = data; |
cstr->size_allocated = size; |
cstr->data = data; |
} |
/* add a byte */ |
static inline void cstr_ccat(CString *cstr, int ch) |
{ |
int size; |
size = cstr->size + 1; |
if (size > cstr->size_allocated) |
cstr_realloc(cstr, size); |
((unsigned char *)cstr->data)[size - 1] = ch; |
cstr->size = size; |
} |
static void cstr_cat(CString *cstr, const char *str) |
{ |
int c; |
for(;;) { |
c = *str; |
if (c == '\0') |
break; |
cstr_ccat(cstr, c); |
str++; |
} |
} |
/* add a wide char */ |
static void cstr_wccat(CString *cstr, int ch) |
{ |
int size; |
size = cstr->size + sizeof(int); |
if (size > cstr->size_allocated) |
cstr_realloc(cstr, size); |
*(int *)(((unsigned char *)cstr->data) + size - sizeof(int)) = ch; |
cstr->size = size; |
} |
static void cstr_new(CString *cstr) |
{ |
memset(cstr, 0, sizeof(CString)); |
} |
/* free string and reset it to NULL */ |
static void cstr_free(CString *cstr) |
{ |
tcc_free(cstr->data_allocated); |
cstr_new(cstr); |
} |
#define cstr_reset(cstr) cstr_free(cstr) |
/* XXX: unicode ? */ |
static void add_char(CString *cstr, int c) |
{ |
if (c == '\'' || c == '\"' || c == '\\') { |
/* XXX: could be more precise if char or string */ |
cstr_ccat(cstr, '\\'); |
} |
if (c >= 32 && c <= 126) { |
cstr_ccat(cstr, c); |
} else { |
cstr_ccat(cstr, '\\'); |
if (c == '\n') { |
cstr_ccat(cstr, 'n'); |
} else { |
cstr_ccat(cstr, '0' + ((c >> 6) & 7)); |
cstr_ccat(cstr, '0' + ((c >> 3) & 7)); |
cstr_ccat(cstr, '0' + (c & 7)); |
} |
} |
} |
/* XXX: buffer overflow */ |
/* XXX: float tokens */ |
char *get_tok_str(int v, CValue *cv) |
{ |
static char buf[STRING_MAX_SIZE + 1]; |
static CString cstr_buf; |
CString *cstr; |
unsigned char *q; |
char *p; |
int i, len; |
/* NOTE: to go faster, we give a fixed buffer for small strings */ |
cstr_reset(&cstr_buf); |
cstr_buf.data = buf; |
cstr_buf.size_allocated = sizeof(buf); |
p = buf; |
switch(v) { |
case TOK_CINT: |
case TOK_CUINT: |
/* XXX: not quite exact, but only useful for testing */ |
sprintf(p, "%u", cv->ui); |
break; |
case TOK_CLLONG: |
case TOK_CULLONG: |
/* XXX: not quite exact, but only useful for testing */ |
sprintf(p, "%Lu", cv->ull); |
break; |
case TOK_CCHAR: |
case TOK_LCHAR: |
cstr_ccat(&cstr_buf, '\''); |
add_char(&cstr_buf, cv->i); |
cstr_ccat(&cstr_buf, '\''); |
cstr_ccat(&cstr_buf, '\0'); |
break; |
case TOK_PPNUM: |
cstr = cv->cstr; |
len = cstr->size - 1; |
for(i=0;i<len;i++) |
add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
cstr_ccat(&cstr_buf, '\0'); |
break; |
case TOK_STR: |
case TOK_LSTR: |
cstr = cv->cstr; |
cstr_ccat(&cstr_buf, '\"'); |
if (v == TOK_STR) { |
len = cstr->size - 1; |
for(i=0;i<len;i++) |
add_char(&cstr_buf, ((unsigned char *)cstr->data)[i]); |
} else { |
len = (cstr->size / sizeof(int)) - 1; |
for(i=0;i<len;i++) |
add_char(&cstr_buf, ((int *)cstr->data)[i]); |
} |
cstr_ccat(&cstr_buf, '\"'); |
cstr_ccat(&cstr_buf, '\0'); |
break; |
case TOK_LT: |
v = '<'; |
goto addv; |
case TOK_GT: |
v = '>'; |
goto addv; |
case TOK_A_SHL: |
return strcpy(p, "<<="); |
case TOK_A_SAR: |
return strcpy(p, ">>="); |
default: |
if (v < TOK_IDENT) { |
/* search in two bytes table */ |
q = tok_two_chars; |
while (*q) { |
if (q[2] == v) { |
*p++ = q[0]; |
*p++ = q[1]; |
*p = '\0'; |
return buf; |
} |
q += 3; |
} |
addv: |
*p++ = v; |
*p = '\0'; |
} else if (v < tok_ident) { |
return table_ident[v - TOK_IDENT]->str; |
} else if (v >= SYM_FIRST_ANOM) { |
/* special name for anonymous symbol */ |
sprintf(p, "L.%u", v - SYM_FIRST_ANOM); |
} else { |
/* should never happen */ |
return NULL; |
} |
break; |
} |
return cstr_buf.data; |
} |
/* push, without hashing */ |
static Sym *sym_push2(Sym **ps, int v, int t, int c) |
{ |
Sym *s; |
s = sym_malloc(); |
s->v = v; |
s->type.t = t; |
s->c = c; |
s->next = NULL; |
/* add in stack */ |
s->prev = *ps; |
*ps = s; |
return s; |
} |
/* find a symbol and return its associated structure. 's' is the top |
of the symbol stack */ |
static Sym *sym_find2(Sym *s, int v) |
{ |
while (s) { |
if (s->v == v) |
return s; |
s = s->prev; |
} |
return NULL; |
} |
/* structure lookup */ |
static inline Sym *struct_find(int v) |
{ |
v -= TOK_IDENT; |
if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
return NULL; |
return table_ident[v]->sym_struct; |
} |
/* find an identifier */ |
static inline Sym *sym_find(int v) |
{ |
v -= TOK_IDENT; |
if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
return NULL; |
return table_ident[v]->sym_identifier; |
} |
/* push a given symbol on the symbol stack */ |
static Sym *sym_push(int v, CType *type, int r, int c) |
{ |
Sym *s, **ps; |
TokenSym *ts; |
if (local_stack) |
ps = &local_stack; |
else |
ps = &global_stack; |
s = sym_push2(ps, v, type->t, c); |
s->type.ref = type->ref; |
s->r = r; |
/* don't record fields or anonymous symbols */ |
/* XXX: simplify */ |
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
/* record symbol in token array */ |
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
if (v & SYM_STRUCT) |
ps = &ts->sym_struct; |
else |
ps = &ts->sym_identifier; |
s->prev_tok = *ps; |
*ps = s; |
} |
return s; |
} |
/* push a global identifier */ |
static Sym *global_identifier_push(int v, int t, int c) |
{ |
Sym *s, **ps; |
s = sym_push2(&global_stack, v, t, c); |
/* don't record anonymous symbol */ |
if (v < SYM_FIRST_ANOM) { |
ps = &table_ident[v - TOK_IDENT]->sym_identifier; |
/* modify the top most local identifier, so that |
sym_identifier will point to 's' when popped */ |
while (*ps != NULL) |
ps = &(*ps)->prev_tok; |
s->prev_tok = NULL; |
*ps = s; |
} |
return s; |
} |
/* pop symbols until top reaches 'b' */ |
static void sym_pop(Sym **ptop, Sym *b) |
{ |
Sym *s, *ss, **ps; |
TokenSym *ts; |
int v; |
s = *ptop; |
while(s != b) { |
ss = s->prev; |
v = s->v; |
/* remove symbol in token array */ |
/* XXX: simplify */ |
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
if (v & SYM_STRUCT) |
ps = &ts->sym_struct; |
else |
ps = &ts->sym_identifier; |
*ps = s->prev_tok; |
} |
sym_free(s); |
s = ss; |
} |
*ptop = b; |
} |
/* I/O layer */ |
BufferedFile *tcc_open(TCCState *s1, const char *filename) |
{ |
int fd; |
BufferedFile *bf; |
fd = open(filename, O_RDONLY | O_BINARY); |
if (fd < 0) |
return NULL; |
bf = tcc_malloc(sizeof(BufferedFile)); |
if (!bf) { |
close(fd); |
return NULL; |
} |
bf->fd = fd; |
bf->buf_ptr = bf->buffer; |
bf->buf_end = bf->buffer; |
bf->buffer[0] = CH_EOB; /* put eob symbol */ |
pstrcpy(bf->filename, sizeof(bf->filename), filename); |
bf->line_num = 1; |
bf->ifndef_macro = 0; |
bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
// printf("opening '%s'\n", filename); |
return bf; |
} |
void tcc_close(BufferedFile *bf) |
{ |
total_lines += bf->line_num; |
close(bf->fd); |
tcc_free(bf); |
} |
/* fill input buffer and peek next char */ |
static int tcc_peekc_slow(BufferedFile *bf) |
{ |
int len; |
/* only tries to read if really end of buffer */ |
if (bf->buf_ptr >= bf->buf_end) { |
if (bf->fd != -1) { |
#if defined(PARSE_DEBUG) |
len = 8; |
#else |
" Linux" |
len = IO_BUF_SIZE; |
#endif |
")\n", TCC_VERSION); |
len = read(bf->fd, bf->buffer, len); |
if (len < 0) |
len = 0; |
} else { |
len = 0; |
} |
total_bytes += len; |
bf->buf_ptr = bf->buffer; |
bf->buf_end = bf->buffer + len; |
*bf->buf_end = CH_EOB; |
} |
if (bf->buf_ptr < bf->buf_end) { |
return bf->buf_ptr[0]; |
} else { |
bf->buf_ptr = bf->buf_end; |
return CH_EOF; |
} |
} |
/* return the current character, handling end of block if necessary |
(but not stray) */ |
static int handle_eob(void) |
{ |
return tcc_peekc_slow(file); |
} |
/* read next char from current input file and handle end of input buffer */ |
static inline void input(void) |
{ |
ch = *(++(file->buf_ptr)); |
/* end of buffer/file handling */ |
if (ch == CH_EOB) |
ch = handle_eob(); |
} |
/* handle '\[\r]\n' */ |
static void handle_stray(void) |
{ |
while (ch == '\\') { |
input(); |
if (ch == '\n') { |
file->line_num++; |
input(); |
} else if (ch == '\r') { |
input(); |
if (ch != '\n') |
goto fail; |
file->line_num++; |
input(); |
} else { |
fail: |
error("stray '\\' in program"); |
} |
} |
} |
/* skip the stray and handle the \\n case. Output an error if |
incorrect char after the stray */ |
static int handle_stray1(uint8_t *p) |
{ |
int c; |
if (p >= file->buf_end) { |
file->buf_ptr = p; |
c = handle_eob(); |
p = file->buf_ptr; |
if (c == '\\') |
goto parse_stray; |
} else { |
parse_stray: |
file->buf_ptr = p; |
ch = *p; |
handle_stray(); |
p = file->buf_ptr; |
c = *p; |
} |
return c; |
} |
/* handle just the EOB case, but not stray */ |
#define PEEKC_EOB(c, p)\ |
{\ |
p++;\ |
c = *p;\ |
if (c == '\\') {\ |
file->buf_ptr = p;\ |
c = handle_eob();\ |
p = file->buf_ptr;\ |
}\ |
} |
/* handle the complicated stray case */ |
#define PEEKC(c, p)\ |
{\ |
p++;\ |
c = *p;\ |
if (c == '\\') {\ |
c = handle_stray1(p);\ |
p = file->buf_ptr;\ |
}\ |
} |
/* input with '\[\r]\n' handling. Note that this function cannot |
handle other characters after '\', so you cannot call it inside |
strings or comments */ |
static void minp(void) |
{ |
input(); |
if (ch == '\\') |
handle_stray(); |
} |
/* single line C++ comments */ |
static uint8_t *parse_line_comment(uint8_t *p) |
{ |
int c; |
p++; |
for(;;) { |
c = *p; |
redo: |
if (c == '\n' || c == CH_EOF) { |
break; |
case 1: |
printf("install: %s\n", s->tcc_lib_path); |
/* print_paths("programs", NULL, 0); */ |
print_paths("include", s->sysinclude_paths, s->nb_sysinclude_paths); |
print_paths("libraries", s->library_paths, s->nb_library_paths); |
#ifndef TCC_TARGET_PE |
print_paths("crt", s->crt_paths, s->nb_crt_paths); |
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s)); |
} else if (c == '\\') { |
file->buf_ptr = p; |
c = handle_eob(); |
p = file->buf_ptr; |
if (c == '\\') { |
PEEKC_EOB(c, p); |
if (c == '\n') { |
file->line_num++; |
PEEKC_EOB(c, p); |
} else if (c == '\r') { |
PEEKC_EOB(c, p); |
if (c == '\n') { |
file->line_num++; |
PEEKC_EOB(c, p); |
} |
} |
} else { |
goto redo; |
} |
} else { |
p++; |
} |
} |
return p; |
} |
/* C comments */ |
static uint8_t *parse_comment(uint8_t *p) |
{ |
int c; |
p++; |
for(;;) { |
/* fast skip loop */ |
for(;;) { |
c = *p; |
if (c == '\n' || c == '*' || c == '\\') |
break; |
p++; |
c = *p; |
if (c == '\n' || c == '*' || c == '\\') |
break; |
p++; |
} |
/* now we can handle all the cases */ |
if (c == '\n') { |
file->line_num++; |
p++; |
} else if (c == '*') { |
p++; |
for(;;) { |
c = *p; |
if (c == '*') { |
p++; |
} else if (c == '/') { |
goto end_of_comment; |
} else if (c == '\\') { |
file->buf_ptr = p; |
c = handle_eob(); |
p = file->buf_ptr; |
if (c == '\\') { |
/* skip '\[\r]\n', otherwise just skip the stray */ |
while (c == '\\') { |
PEEKC_EOB(c, p); |
if (c == '\n') { |
file->line_num++; |
PEEKC_EOB(c, p); |
} else if (c == '\r') { |
PEEKC_EOB(c, p); |
if (c == '\n') { |
file->line_num++; |
PEEKC_EOB(c, p); |
} |
} else { |
goto after_star; |
} |
} |
} |
} else { |
break; |
} |
} |
after_star: ; |
} else { |
/* stray, eob or eof */ |
file->buf_ptr = p; |
c = handle_eob(); |
p = file->buf_ptr; |
if (c == CH_EOF) { |
error("unexpected end of file in comment"); |
} else if (c == '\\') { |
p++; |
} |
} |
} |
end_of_comment: |
p++; |
return p; |
} |
#define cinp minp |
/* space excluding newline */ |
static inline int is_space(int ch) |
{ |
return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; |
} |
static inline void skip_spaces(void) |
{ |
while (is_space(ch)) |
cinp(); |
} |
/* parse a string without interpreting escapes */ |
static uint8_t *parse_pp_string(uint8_t *p, |
int sep, CString *str) |
{ |
int c; |
p++; |
for(;;) { |
c = *p; |
if (c == sep) { |
break; |
} else if (c == '\\') { |
file->buf_ptr = p; |
c = handle_eob(); |
p = file->buf_ptr; |
if (c == CH_EOF) { |
unterminated_string: |
/* XXX: indicate line number of start of string */ |
error("missing terminating %c character", sep); |
} else if (c == '\\') { |
/* escape : just skip \[\r]\n */ |
PEEKC_EOB(c, p); |
if (c == '\n') { |
file->line_num++; |
p++; |
} else if (c == '\r') { |
PEEKC_EOB(c, p); |
if (c != '\n') |
expect("'\n' after '\r'"); |
file->line_num++; |
p++; |
} else if (c == CH_EOF) { |
goto unterminated_string; |
} else { |
if (str) { |
cstr_ccat(str, '\\'); |
cstr_ccat(str, c); |
} |
p++; |
} |
} |
} else if (c == '\n') { |
file->line_num++; |
goto add_char; |
} else if (c == '\r') { |
PEEKC_EOB(c, p); |
if (c != '\n') { |
if (str) |
cstr_ccat(str, '\r'); |
} else { |
file->line_num++; |
goto add_char; |
} |
} else { |
add_char: |
if (str) |
cstr_ccat(str, c); |
p++; |
} |
} |
p++; |
return p; |
} |
/* skip block of text until #else, #elif or #endif. skip also pairs of |
#if/#endif */ |
void preprocess_skip(void) |
{ |
int a, start_of_line, c; |
uint8_t *p; |
p = file->buf_ptr; |
start_of_line = 1; |
a = 0; |
for(;;) { |
redo_no_start: |
c = *p; |
switch(c) { |
case ' ': |
case '\t': |
case '\f': |
case '\v': |
case '\r': |
p++; |
goto redo_no_start; |
case '\n': |
start_of_line = 1; |
file->line_num++; |
p++; |
goto redo_no_start; |
case '\\': |
file->buf_ptr = p; |
c = handle_eob(); |
if (c == CH_EOF) { |
expect("#endif"); |
} else if (c == '\\') { |
/* XXX: incorrect: should not give an error */ |
ch = file->buf_ptr[0]; |
handle_stray(); |
} |
p = file->buf_ptr; |
goto redo_no_start; |
/* skip strings */ |
case '\"': |
case '\'': |
p = parse_pp_string(p, c, NULL); |
break; |
/* skip comments */ |
case '/': |
file->buf_ptr = p; |
ch = *p; |
minp(); |
p = file->buf_ptr; |
if (ch == '*') { |
p = parse_comment(p); |
} else if (ch == '/') { |
p = parse_line_comment(p); |
} |
break; |
case '#': |
p++; |
if (start_of_line) { |
file->buf_ptr = p; |
next_nomacro(); |
p = file->buf_ptr; |
if (a == 0 && |
(tok == TOK_ELSE || tok == TOK_ELIF || tok == TOK_ENDIF)) |
goto the_end; |
if (tok == TOK_IF || tok == TOK_IFDEF || tok == TOK_IFNDEF) |
a++; |
else if (tok == TOK_ENDIF) |
a--; |
} |
break; |
default: |
p++; |
break; |
} |
start_of_line = 0; |
} |
the_end: ; |
file->buf_ptr = p; |
} |
/* ParseState handling */ |
/* XXX: currently, no include file info is stored. Thus, we cannot display |
accurate messages if the function or data definition spans multiple |
files */ |
/* save current parse state in 's' */ |
void save_parse_state(ParseState *s) |
{ |
s->line_num = file->line_num; |
s->macro_ptr = macro_ptr; |
s->tok = tok; |
s->tokc = tokc; |
} |
/* restore parse state from 's' */ |
void restore_parse_state(ParseState *s) |
{ |
file->line_num = s->line_num; |
macro_ptr = s->macro_ptr; |
tok = s->tok; |
tokc = s->tokc; |
} |
/* return the number of additional 'ints' necessary to store the |
token */ |
static inline int tok_ext_size(int t) |
{ |
switch(t) { |
/* 4 bytes */ |
case TOK_CINT: |
case TOK_CUINT: |
case TOK_CCHAR: |
case TOK_LCHAR: |
case TOK_CFLOAT: |
case TOK_LINENUM: |
return 1; |
case TOK_STR: |
case TOK_LSTR: |
case TOK_PPNUM: |
error("unsupported token"); |
return 1; |
case TOK_CDOUBLE: |
case TOK_CLLONG: |
case TOK_CULLONG: |
return 2; |
case TOK_CLDOUBLE: |
return LDOUBLE_SIZE / 4; |
default: |
return 0; |
} |
} |
/* token string handling */ |
static inline void tok_str_new(TokenString *s) |
{ |
s->str = NULL; |
s->len = 0; |
s->allocated_len = 0; |
s->last_line_num = -1; |
} |
static void tok_str_free(int *str) |
{ |
tcc_free(str); |
} |
static int *tok_str_realloc(TokenString *s) |
{ |
int *str, len; |
if (s->allocated_len == 0) { |
len = 8; |
} else { |
len = s->allocated_len * 2; |
} |
str = tcc_realloc(s->str, len * sizeof(int)); |
if (!str) |
error("memory full"); |
s->allocated_len = len; |
s->str = str; |
return str; |
} |
static void tok_str_add(TokenString *s, int t) |
{ |
int len, *str; |
len = s->len; |
str = s->str; |
if (len >= s->allocated_len) |
str = tok_str_realloc(s); |
str[len++] = t; |
s->len = len; |
} |
static void tok_str_add2(TokenString *s, int t, CValue *cv) |
{ |
int len, *str; |
len = s->len; |
str = s->str; |
/* allocate space for worst case */ |
if (len + TOK_MAX_SIZE > s->allocated_len) |
str = tok_str_realloc(s); |
str[len++] = t; |
switch(t) { |
case TOK_CINT: |
case TOK_CUINT: |
case TOK_CCHAR: |
case TOK_LCHAR: |
case TOK_CFLOAT: |
case TOK_LINENUM: |
str[len++] = cv->tab[0]; |
break; |
case TOK_PPNUM: |
case TOK_STR: |
case TOK_LSTR: |
{ |
int nb_words; |
CString *cstr; |
nb_words = (sizeof(CString) + cv->cstr->size + 3) >> 2; |
while ((len + nb_words) > s->allocated_len) |
str = tok_str_realloc(s); |
cstr = (CString *)(str + len); |
cstr->data = NULL; |
cstr->size = cv->cstr->size; |
cstr->data_allocated = NULL; |
cstr->size_allocated = cstr->size; |
memcpy((char *)cstr + sizeof(CString), |
cv->cstr->data, cstr->size); |
len += nb_words; |
} |
break; |
case TOK_CDOUBLE: |
case TOK_CLLONG: |
case TOK_CULLONG: |
#if LDOUBLE_SIZE == 8 |
case TOK_CLDOUBLE: |
#endif |
str[len++] = cv->tab[0]; |
str[len++] = cv->tab[1]; |
break; |
#if LDOUBLE_SIZE == 12 |
case TOK_CLDOUBLE: |
str[len++] = cv->tab[0]; |
str[len++] = cv->tab[1]; |
str[len++] = cv->tab[2]; |
#elif LDOUBLE_SIZE != 8 |
#error add long double size support |
#endif |
break; |
default: |
break; |
} |
s->len = len; |
} |
static void help(void) |
/* add the current parse token in token string 's' */ |
static void tok_str_add_tok(TokenString *s) |
{ |
printf("Tiny C Compiler "TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n" |
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n" |
" tcc [options...] -run infile [arguments...]\n" |
"General options:\n" |
" -c compile only - generate an object file\n" |
" -o outfile set output filename\n" |
" -run run compiled source\n" |
" -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n" |
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" |
" -w disable all warnings\n" |
" -v show version\n" |
" -vv show included files (as sole argument: show search paths)\n" |
" -dumpversion\n" |
" -bench show compilation statistics\n" |
" -xc -xa specify type of the next infile\n" |
" - use stdin pipe as infile\n" |
" @listfile read line separated arguments from 'listfile'\n" |
"Preprocessor options:\n" |
" -Idir add include path 'dir'\n" |
" -Dsym[=val] define 'sym' with value 'val'\n" |
" -Usym undefine 'sym'\n" |
" -E preprocess only\n" |
" -P[1] no/alternative output of #line directives\n" |
" -d{D|M} dump defines\n" |
" -C keep comments\n" |
"Linker options:\n" |
" -Ldir add library path 'dir'\n" |
" -llib link with dynamic or static library 'lib'\n" |
" -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n" |
" -r generate (relocatable) object file\n" |
" -rdynamic export all global symbols to dynamic linker\n" |
" -shared generate a shared library\n" |
" -soname set name for shared library to be used at runtime\n" |
" -static static linking\n" |
" -Wl,-opt[=val] set linker option (see manual)\n" |
"Debugger options:\n" |
" -g generate runtime debug info\n" |
CValue cval; |
/* save line number info */ |
if (file->line_num != s->last_line_num) { |
s->last_line_num = file->line_num; |
cval.i = s->last_line_num; |
tok_str_add2(s, TOK_LINENUM, &cval); |
} |
tok_str_add2(s, tok, &tokc); |
} |
#if LDOUBLE_SIZE == 12 |
#define LDOUBLE_GET(p, cv) \ |
cv.tab[0] = p[0]; \ |
cv.tab[1] = p[1]; \ |
cv.tab[2] = p[2]; |
#elif LDOUBLE_SIZE == 8 |
#define LDOUBLE_GET(p, cv) \ |
cv.tab[0] = p[0]; \ |
cv.tab[1] = p[1]; |
#else |
#error add long double size support |
#endif |
/* get a token from an integer array and increment pointer |
accordingly. we code it as a macro to avoid pointer aliasing. */ |
#define TOK_GET(t, p, cv) \ |
{ \ |
t = *p++; \ |
switch(t) { \ |
case TOK_CINT: \ |
case TOK_CUINT: \ |
case TOK_CCHAR: \ |
case TOK_LCHAR: \ |
case TOK_CFLOAT: \ |
case TOK_LINENUM: \ |
cv.tab[0] = *p++; \ |
break; \ |
case TOK_STR: \ |
case TOK_LSTR: \ |
case TOK_PPNUM: \ |
cv.cstr = (CString *)p; \ |
cv.cstr->data = (char *)p + sizeof(CString);\ |
p += (sizeof(CString) + cv.cstr->size + 3) >> 2;\ |
break; \ |
case TOK_CDOUBLE: \ |
case TOK_CLLONG: \ |
case TOK_CULLONG: \ |
cv.tab[0] = p[0]; \ |
cv.tab[1] = p[1]; \ |
p += 2; \ |
break; \ |
case TOK_CLDOUBLE: \ |
LDOUBLE_GET(p, cv); \ |
p += LDOUBLE_SIZE / 4; \ |
break; \ |
default: \ |
break; \ |
} \ |
} |
/* defines handling */ |
static inline void define_push(int v, int macro_type, int *str, Sym *first_arg) |
{ |
Sym *s; |
s = sym_push2(&define_stack, v, macro_type, (int)str); |
s->next = first_arg; |
table_ident[v - TOK_IDENT]->sym_define = s; |
} |
/* undefined a define symbol. Its name is just set to zero */ |
static void define_undef(Sym *s) |
{ |
int v; |
v = s->v; |
if (v >= TOK_IDENT && v < tok_ident) |
table_ident[v - TOK_IDENT]->sym_define = NULL; |
s->v = 0; |
} |
static inline Sym *define_find(int v) |
{ |
v -= TOK_IDENT; |
if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
return NULL; |
return table_ident[v]->sym_define; |
} |
/* free define stack until top reaches 'b' */ |
static void free_defines(Sym *b) |
{ |
Sym *top, *top1; |
int v; |
top = define_stack; |
while (top != b) { |
top1 = top->prev; |
/* do not free args or predefined defines */ |
if (top->c) |
tok_str_free((int *)top->c); |
v = top->v; |
if (v >= TOK_IDENT && v < tok_ident) |
table_ident[v - TOK_IDENT]->sym_define = NULL; |
sym_free(top); |
top = top1; |
} |
define_stack = b; |
} |
/* label lookup */ |
static Sym *label_find(int v) |
{ |
v -= TOK_IDENT; |
if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
return NULL; |
return table_ident[v]->sym_label; |
} |
static Sym *label_push(Sym **ptop, int v, int flags) |
{ |
Sym *s, **ps; |
s = sym_push2(ptop, v, 0, 0); |
s->r = flags; |
ps = &table_ident[v - TOK_IDENT]->sym_label; |
if (ptop == &global_label_stack) { |
/* modify the top most local identifier, so that |
sym_identifier will point to 's' when popped */ |
while (*ps != NULL) |
ps = &(*ps)->prev_tok; |
} |
s->prev_tok = *ps; |
*ps = s; |
return s; |
} |
/* pop labels until element last is reached. Look if any labels are |
undefined. Define symbols if '&&label' was used. */ |
static void label_pop(Sym **ptop, Sym *slast) |
{ |
Sym *s, *s1; |
for(s = *ptop; s != slast; s = s1) { |
s1 = s->prev; |
if (s->r == LABEL_DECLARED) { |
warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); |
} else if (s->r == LABEL_FORWARD) { |
error("label '%s' used but not defined", |
get_tok_str(s->v, NULL)); |
} else { |
if (s->c) { |
/* define corresponding symbol. A size of |
1 is put. */ |
put_extern_sym(s, cur_text_section, (long)s->next, 1); |
} |
} |
/* remove label */ |
table_ident[s->v - TOK_IDENT]->sym_label = s->prev_tok; |
sym_free(s); |
} |
*ptop = slast; |
} |
/* eval an expression for #if/#elif */ |
static int expr_preprocess(void) |
{ |
int c, t; |
TokenString str; |
tok_str_new(&str); |
while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
next(); /* do macro subst */ |
if (tok == TOK_DEFINED) { |
next_nomacro(); |
t = tok; |
if (t == '(') |
next_nomacro(); |
c = define_find(tok) != 0; |
if (t == '(') |
next_nomacro(); |
tok = TOK_CINT; |
tokc.i = c; |
} else if (tok >= TOK_IDENT) { |
/* if undefined macro */ |
tok = TOK_CINT; |
tokc.i = 0; |
} |
tok_str_add_tok(&str); |
} |
tok_str_add(&str, -1); /* simulate end of file */ |
tok_str_add(&str, 0); |
/* now evaluate C constant expression */ |
macro_ptr = str.str; |
next(); |
c = expr_const(); |
macro_ptr = NULL; |
tok_str_free(str.str); |
return c != 0; |
} |
#if defined(PARSE_DEBUG) || defined(PP_DEBUG) |
static void tok_print(int *str) |
{ |
int t; |
CValue cval; |
while (1) { |
TOK_GET(t, str, cval); |
if (!t) |
break; |
printf(" %s", get_tok_str(t, &cval)); |
} |
printf("\n"); |
} |
#endif |
/* parse after #define */ |
static void parse_define(void) |
{ |
Sym *s, *first, **ps; |
int v, t, varg, is_vaargs, c; |
TokenString str; |
v = tok; |
if (v < TOK_IDENT) |
error("invalid macro name '%s'", get_tok_str(tok, &tokc)); |
/* XXX: should check if same macro (ANSI) */ |
first = NULL; |
t = MACRO_OBJ; |
/* '(' must be just after macro definition for MACRO_FUNC */ |
c = file->buf_ptr[0]; |
if (c == '\\') |
c = handle_stray1(file->buf_ptr); |
if (c == '(') { |
next_nomacro(); |
next_nomacro(); |
ps = &first; |
while (tok != ')') { |
varg = tok; |
next_nomacro(); |
is_vaargs = 0; |
if (varg == TOK_DOTS) { |
varg = TOK___VA_ARGS__; |
is_vaargs = 1; |
} else if (tok == TOK_DOTS && gnu_ext) { |
is_vaargs = 1; |
next_nomacro(); |
} |
if (varg < TOK_IDENT) |
error("badly punctuated parameter list"); |
s = sym_push2(&define_stack, varg | SYM_FIELD, is_vaargs, 0); |
*ps = s; |
ps = &s->next; |
if (tok != ',') |
break; |
next_nomacro(); |
} |
t = MACRO_FUNC; |
} |
tok_str_new(&str); |
next_nomacro(); |
/* EOF testing necessary for '-D' handling */ |
while (tok != TOK_LINEFEED && tok != TOK_EOF) { |
tok_str_add2(&str, tok, &tokc); |
next_nomacro(); |
} |
tok_str_add(&str, 0); |
#ifdef PP_DEBUG |
printf("define %s %d: ", get_tok_str(v, NULL), t); |
tok_print(str.str); |
#endif |
define_push(v, t, str.str, first); |
} |
static inline int hash_cached_include(int type, const char *filename) |
{ |
const unsigned char *s; |
unsigned int h; |
h = TOK_HASH_INIT; |
h = TOK_HASH_FUNC(h, type); |
s = filename; |
while (*s) { |
h = TOK_HASH_FUNC(h, *s); |
s++; |
} |
h &= (CACHED_INCLUDES_HASH_SIZE - 1); |
return h; |
} |
/* XXX: use a token or a hash table to accelerate matching ? */ |
static CachedInclude *search_cached_include(TCCState *s1, |
int type, const char *filename) |
{ |
CachedInclude *e; |
int i, h; |
h = hash_cached_include(type, filename); |
i = s1->cached_includes_hash[h]; |
for(;;) { |
if (i == 0) |
break; |
e = s1->cached_includes[i - 1]; |
if (e->type == type && !strcmp(e->filename, filename)) |
return e; |
i = e->hash_next; |
} |
return NULL; |
} |
static inline void add_cached_include(TCCState *s1, int type, |
const char *filename, int ifndef_macro) |
{ |
CachedInclude *e; |
int h; |
if (search_cached_include(s1, type, filename)) |
return; |
#ifdef INC_DEBUG |
printf("adding cached '%s' %s\n", filename, get_tok_str(ifndef_macro, NULL)); |
#endif |
e = tcc_malloc(sizeof(CachedInclude) + strlen(filename)); |
if (!e) |
return; |
e->type = type; |
strcpy(e->filename, filename); |
e->ifndef_macro = ifndef_macro; |
dynarray_add((void ***)&s1->cached_includes, &s1->nb_cached_includes, e); |
/* add in hash table */ |
h = hash_cached_include(type, filename); |
e->hash_next = s1->cached_includes_hash[h]; |
s1->cached_includes_hash[h] = s1->nb_cached_includes; |
} |
static void pragma_parse(TCCState *s1) |
{ |
int val; |
next(); |
if (tok == TOK_pack) { |
/* |
This may be: |
#pragma pack(1) // set |
#pragma pack() // reset to default |
#pragma pack(push,1) // push & set |
#pragma pack(pop) // restore previous |
*/ |
next(); |
skip('('); |
if (tok == TOK_ASM_pop) { |
next(); |
if (s1->pack_stack_ptr <= s1->pack_stack) { |
stk_error: |
error("out of pack stack"); |
} |
s1->pack_stack_ptr--; |
} else { |
val = 0; |
if (tok != ')') { |
if (tok == TOK_ASM_push) { |
next(); |
if (s1->pack_stack_ptr >= s1->pack_stack + PACK_STACK_SIZE - 1) |
goto stk_error; |
s1->pack_stack_ptr++; |
skip(','); |
} |
if (tok != TOK_CINT) { |
pack_error: |
error("invalid pack pragma"); |
} |
val = tokc.i; |
if (val < 1 || val > 16 || (val & (val - 1)) != 0) |
goto pack_error; |
next(); |
} |
*s1->pack_stack_ptr = val; |
skip(')'); |
} |
} |
} |
/* is_bof is true if first non space token at beginning of file */ |
static void preprocess(int is_bof) |
{ |
TCCState *s1 = tcc_state; |
int size, i, c, n, saved_parse_flags; |
char buf[1024], *q, *p; |
char buf1[1024]; |
BufferedFile *f; |
Sym *s; |
CachedInclude *e; |
saved_parse_flags = parse_flags; |
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | |
PARSE_FLAG_LINEFEED; |
next_nomacro(); |
redo: |
switch(tok) { |
case TOK_DEFINE: |
next_nomacro(); |
parse_define(); |
break; |
case TOK_UNDEF: |
next_nomacro(); |
s = define_find(tok); |
/* undefine symbol by putting an invalid name */ |
if (s) |
define_undef(s); |
break; |
case TOK_INCLUDE: |
case TOK_INCLUDE_NEXT: |
ch = file->buf_ptr[0]; |
/* XXX: incorrect if comments : use next_nomacro with a special mode */ |
skip_spaces(); |
if (ch == '<') { |
c = '>'; |
goto read_name; |
} else if (ch == '\"') { |
c = ch; |
read_name: |
/* XXX: better stray handling */ |
minp(); |
q = buf; |
while (ch != c && ch != '\n' && ch != CH_EOF) { |
if ((q - buf) < sizeof(buf) - 1) |
*q++ = ch; |
minp(); |
} |
*q = '\0'; |
minp(); |
#if 0 |
/* eat all spaces and comments after include */ |
/* XXX: slightly incorrect */ |
while (ch1 != '\n' && ch1 != CH_EOF) |
input(); |
#endif |
} else { |
/* computed #include : either we have only strings or |
we have anything enclosed in '<>' */ |
next(); |
buf[0] = '\0'; |
if (tok == TOK_STR) { |
while (tok != TOK_LINEFEED) { |
if (tok != TOK_STR) { |
include_syntax: |
error("'#include' expects \"FILENAME\" or <FILENAME>"); |
} |
pstrcat(buf, sizeof(buf), (char *)tokc.cstr->data); |
next(); |
} |
c = '\"'; |
} else { |
int len; |
while (tok != TOK_LINEFEED) { |
pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); |
next(); |
} |
len = strlen(buf); |
/* check syntax and remove '<>' */ |
if (len < 2 || buf[0] != '<' || buf[len - 1] != '>') |
goto include_syntax; |
memmove(buf, buf + 1, len - 2); |
buf[len - 2] = '\0'; |
c = '>'; |
} |
} |
e = search_cached_include(s1, c, buf); |
if (e && define_find(e->ifndef_macro)) { |
/* no need to parse the include because the 'ifndef macro' |
is defined */ |
#ifdef INC_DEBUG |
printf("%s: skipping %s\n", file->filename, buf); |
#endif |
} else { |
if (c == '\"') { |
/* first search in current dir if "header.h" */ |
size = 0; |
p = strrchr(file->filename, '/'); |
if (p) |
size = p + 1 - file->filename; |
if (size > sizeof(buf1) - 1) |
size = sizeof(buf1) - 1; |
memcpy(buf1, file->filename, size); |
buf1[size] = '\0'; |
pstrcat(buf1, sizeof(buf1), buf); |
f = tcc_open(s1, buf1); |
if (f) { |
if (tok == TOK_INCLUDE_NEXT) |
tok = TOK_INCLUDE; |
else |
goto found; |
} |
} |
if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) |
error("#include recursion too deep"); |
/* now search in all the include paths */ |
n = s1->nb_include_paths + s1->nb_sysinclude_paths; |
for(i = 0; i < n; i++) { |
const char *path; |
if (i < s1->nb_include_paths) |
path = s1->include_paths[i]; |
else |
path = s1->sysinclude_paths[i - s1->nb_include_paths]; |
pstrcpy(buf1, sizeof(buf1), path); |
pstrcat(buf1, sizeof(buf1), "/"); |
pstrcat(buf1, sizeof(buf1), buf); |
f = tcc_open(s1, buf1); |
if (f) { |
if (tok == TOK_INCLUDE_NEXT) |
tok = TOK_INCLUDE; |
else |
goto found; |
} |
} |
error("include file '%s' not found", buf); |
f = NULL; |
found: |
#ifdef INC_DEBUG |
printf("%s: including %s\n", file->filename, buf1); |
#endif |
f->inc_type = c; |
pstrcpy(f->inc_filename, sizeof(f->inc_filename), buf); |
/* push current file in stack */ |
/* XXX: fix current line init */ |
*s1->include_stack_ptr++ = file; |
file = f; |
/* add include file debug info */ |
if (do_debug) { |
put_stabs(file->filename, N_BINCL, 0, 0, 0); |
} |
tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL; |
ch = file->buf_ptr[0]; |
goto the_end; |
} |
break; |
case TOK_IFNDEF: |
c = 1; |
goto do_ifdef; |
case TOK_IF: |
c = expr_preprocess(); |
goto do_if; |
case TOK_IFDEF: |
c = 0; |
do_ifdef: |
next_nomacro(); |
if (tok < TOK_IDENT) |
error("invalid argument for '#if%sdef'", c ? "n" : ""); |
if (is_bof) { |
if (c) { |
#ifdef INC_DEBUG |
printf("#ifndef %s\n", get_tok_str(tok, NULL)); |
#endif |
file->ifndef_macro = tok; |
} |
} |
c = (define_find(tok) != 0) ^ c; |
do_if: |
if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) |
error("memory full"); |
*s1->ifdef_stack_ptr++ = c; |
goto test_skip; |
case TOK_ELSE: |
if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
error("#else without matching #if"); |
if (s1->ifdef_stack_ptr[-1] & 2) |
error("#else after #else"); |
c = (s1->ifdef_stack_ptr[-1] ^= 3); |
goto test_skip; |
case TOK_ELIF: |
if (s1->ifdef_stack_ptr == s1->ifdef_stack) |
error("#elif without matching #if"); |
c = s1->ifdef_stack_ptr[-1]; |
if (c > 1) |
error("#elif after #else"); |
/* last #if/#elif expression was true: we skip */ |
if (c == 1) |
goto skip; |
c = expr_preprocess(); |
s1->ifdef_stack_ptr[-1] = c; |
test_skip: |
if (!(c & 1)) { |
skip: |
preprocess_skip(); |
is_bof = 0; |
goto redo; |
} |
break; |
case TOK_ENDIF: |
if (s1->ifdef_stack_ptr <= file->ifdef_stack_ptr) |
error("#endif without matching #if"); |
s1->ifdef_stack_ptr--; |
/* '#ifndef macro' was at the start of file. Now we check if |
an '#endif' is exactly at the end of file */ |
if (file->ifndef_macro && |
s1->ifdef_stack_ptr == file->ifdef_stack_ptr) { |
file->ifndef_macro_saved = file->ifndef_macro; |
/* need to set to zero to avoid false matches if another |
#ifndef at middle of file */ |
file->ifndef_macro = 0; |
while (tok != TOK_LINEFEED) |
next_nomacro(); |
tok_flags |= TOK_FLAG_ENDIF; |
goto the_end; |
} |
break; |
case TOK_LINE: |
next(); |
if (tok != TOK_CINT) |
error("#line"); |
file->line_num = tokc.i - 1; /* the line number will be incremented after */ |
next(); |
if (tok != TOK_LINEFEED) { |
if (tok != TOK_STR) |
error("#line"); |
pstrcpy(file->filename, sizeof(file->filename), |
(char *)tokc.cstr->data); |
} |
break; |
case TOK_ERROR: |
case TOK_WARNING: |
c = tok; |
ch = file->buf_ptr[0]; |
skip_spaces(); |
q = buf; |
while (ch != '\n' && ch != CH_EOF) { |
if ((q - buf) < sizeof(buf) - 1) |
*q++ = ch; |
minp(); |
} |
*q = '\0'; |
if (c == TOK_ERROR) |
error("#error %s", buf); |
else |
warning("#warning %s", buf); |
break; |
case TOK_PRAGMA: |
pragma_parse(s1); |
break; |
default: |
if (tok == TOK_LINEFEED || tok == '!' || tok == TOK_CINT) { |
/* '!' is ignored to allow C scripts. numbers are ignored |
to emulate cpp behaviour */ |
} else { |
if (!(saved_parse_flags & PARSE_FLAG_ASM_COMMENTS)) |
error("invalid preprocessing directive #%s", get_tok_str(tok, &tokc)); |
} |
break; |
} |
/* ignore other preprocess commands or #! for C scripts */ |
while (tok != TOK_LINEFEED) |
next_nomacro(); |
the_end: |
parse_flags = saved_parse_flags; |
} |
/* evaluate escape codes in a string. */ |
static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long) |
{ |
int c, n; |
const uint8_t *p; |
p = buf; |
for(;;) { |
c = *p; |
if (c == '\0') |
break; |
if (c == '\\') { |
p++; |
/* escape */ |
c = *p; |
switch(c) { |
case '0': case '1': case '2': case '3': |
case '4': case '5': case '6': case '7': |
/* at most three octal digits */ |
n = c - '0'; |
p++; |
c = *p; |
if (isoct(c)) { |
n = n * 8 + c - '0'; |
p++; |
c = *p; |
if (isoct(c)) { |
n = n * 8 + c - '0'; |
p++; |
} |
} |
c = n; |
goto add_char_nonext; |
case 'x': |
p++; |
n = 0; |
for(;;) { |
c = *p; |
if (c >= 'a' && c <= 'f') |
c = c - 'a' + 10; |
else if (c >= 'A' && c <= 'F') |
c = c - 'A' + 10; |
else if (isnum(c)) |
c = c - '0'; |
else |
break; |
n = n * 16 + c; |
p++; |
} |
c = n; |
goto add_char_nonext; |
case 'a': |
c = '\a'; |
break; |
case 'b': |
c = '\b'; |
break; |
case 'f': |
c = '\f'; |
break; |
case 'n': |
c = '\n'; |
break; |
case 'r': |
c = '\r'; |
break; |
case 't': |
c = '\t'; |
break; |
case 'v': |
c = '\v'; |
break; |
case 'e': |
if (!gnu_ext) |
goto invalid_escape; |
c = 27; |
break; |
case '\'': |
case '\"': |
case '\\': |
case '?': |
break; |
default: |
invalid_escape: |
if (c >= '!' && c <= '~') |
warning("unknown escape sequence: \'\\%c\'", c); |
else |
warning("unknown escape sequence: \'\\x%x\'", c); |
break; |
} |
} |
p++; |
add_char_nonext: |
if (!is_long) |
cstr_ccat(outstr, c); |
else |
cstr_wccat(outstr, c); |
} |
/* add a trailing '\0' */ |
if (!is_long) |
cstr_ccat(outstr, '\0'); |
else |
cstr_wccat(outstr, '\0'); |
} |
/* we use 64 bit numbers */ |
#define BN_SIZE 2 |
/* bn = (bn << shift) | or_val */ |
void bn_lshift(unsigned int *bn, int shift, int or_val) |
{ |
int i; |
unsigned int v; |
for(i=0;i<BN_SIZE;i++) { |
v = bn[i]; |
bn[i] = (v << shift) | or_val; |
or_val = v >> (32 - shift); |
} |
} |
void bn_zero(unsigned int *bn) |
{ |
int i; |
for(i=0;i<BN_SIZE;i++) { |
bn[i] = 0; |
} |
} |
/* parse number in null terminated string 'p' and return it in the |
current token */ |
void parse_number(const char *p) |
{ |
int b, t, shift, frac_bits, s, exp_val, ch; |
char *q; |
unsigned int bn[BN_SIZE]; |
double d; |
/* number */ |
q = token_buf; |
ch = *p++; |
t = ch; |
ch = *p++; |
*q++ = t; |
b = 10; |
if (t == '.') { |
goto float_frac_parse; |
} else if (t == '0') { |
if (ch == 'x' || ch == 'X') { |
q--; |
ch = *p++; |
b = 16; |
} else if (tcc_ext && (ch == 'b' || ch == 'B')) { |
q--; |
ch = *p++; |
b = 2; |
} |
} |
/* parse all digits. cannot check octal numbers at this stage |
because of floating point constants */ |
while (1) { |
if (ch >= 'a' && ch <= 'f') |
t = ch - 'a' + 10; |
else if (ch >= 'A' && ch <= 'F') |
t = ch - 'A' + 10; |
else if (isnum(ch)) |
t = ch - '0'; |
else |
break; |
if (t >= b) |
break; |
if (q >= token_buf + STRING_MAX_SIZE) { |
num_too_long: |
error("number too long"); |
} |
*q++ = ch; |
ch = *p++; |
} |
if (ch == '.' || |
((ch == 'e' || ch == 'E') && b == 10) || |
((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { |
if (b != 10) { |
/* NOTE: strtox should support that for hexa numbers, but |
non ISOC99 libcs do not support it, so we prefer to do |
it by hand */ |
/* hexadecimal or binary floats */ |
/* XXX: handle overflows */ |
*q = '\0'; |
if (b == 16) |
shift = 4; |
else |
shift = 2; |
bn_zero(bn); |
q = token_buf; |
while (1) { |
t = *q++; |
if (t == '\0') { |
break; |
} else if (t >= 'a') { |
t = t - 'a' + 10; |
} else if (t >= 'A') { |
t = t - 'A' + 10; |
} else { |
t = t - '0'; |
} |
bn_lshift(bn, shift, t); |
} |
frac_bits = 0; |
if (ch == '.') { |
ch = *p++; |
while (1) { |
t = ch; |
if (t >= 'a' && t <= 'f') { |
t = t - 'a' + 10; |
} else if (t >= 'A' && t <= 'F') { |
t = t - 'A' + 10; |
} else if (t >= '0' && t <= '9') { |
t = t - '0'; |
} else { |
break; |
} |
if (t >= b) |
error("invalid digit"); |
bn_lshift(bn, shift, t); |
frac_bits += shift; |
ch = *p++; |
} |
} |
if (ch != 'p' && ch != 'P') |
expect("exponent"); |
ch = *p++; |
s = 1; |
exp_val = 0; |
if (ch == '+') { |
ch = *p++; |
} else if (ch == '-') { |
s = -1; |
ch = *p++; |
} |
if (ch < '0' || ch > '9') |
expect("exponent digits"); |
while (ch >= '0' && ch <= '9') { |
exp_val = exp_val * 10 + ch - '0'; |
ch = *p++; |
} |
exp_val = exp_val * s; |
/* now we can generate the number */ |
/* XXX: should patch directly float number */ |
d = (double)bn[1] * 4294967296.0 + (double)bn[0]; |
d = ldexp(d, exp_val - frac_bits); |
t = toup(ch); |
if (t == 'F') { |
ch = *p++; |
tok = TOK_CFLOAT; |
/* float : should handle overflow */ |
tokc.f = (float)d; |
} else if (t == 'L') { |
ch = *p++; |
tok = TOK_CLDOUBLE; |
/* XXX: not large enough */ |
tokc.ld = (long double)d; |
} else { |
tok = TOK_CDOUBLE; |
tokc.d = d; |
} |
} else { |
/* decimal floats */ |
if (ch == '.') { |
if (q >= token_buf + STRING_MAX_SIZE) |
goto num_too_long; |
*q++ = ch; |
ch = *p++; |
float_frac_parse: |
while (ch >= '0' && ch <= '9') { |
if (q >= token_buf + STRING_MAX_SIZE) |
goto num_too_long; |
*q++ = ch; |
ch = *p++; |
} |
} |
if (ch == 'e' || ch == 'E') { |
if (q >= token_buf + STRING_MAX_SIZE) |
goto num_too_long; |
*q++ = ch; |
ch = *p++; |
if (ch == '-' || ch == '+') { |
if (q >= token_buf + STRING_MAX_SIZE) |
goto num_too_long; |
*q++ = ch; |
ch = *p++; |
} |
if (ch < '0' || ch > '9') |
expect("exponent digits"); |
while (ch >= '0' && ch <= '9') { |
if (q >= token_buf + STRING_MAX_SIZE) |
goto num_too_long; |
*q++ = ch; |
ch = *p++; |
} |
} |
*q = '\0'; |
t = toup(ch); |
//errno = 0; |
if (t == 'F') { |
ch = *p++; |
tok = TOK_CFLOAT; |
tokc.f = strtof(token_buf, NULL); |
} else if (t == 'L') { |
ch = *p++; |
tok = TOK_CLDOUBLE; |
tokc.ld = strtold(token_buf, NULL); |
} else { |
tok = TOK_CDOUBLE; |
tokc.d = strtod(token_buf, NULL); |
} |
} |
} else { |
unsigned long long n, n1; |
int lcount, ucount; |
/* integer number */ |
*q = '\0'; |
q = token_buf; |
if (b == 10 && *q == '0') { |
b = 8; |
q++; |
} |
n = 0; |
while(1) { |
t = *q++; |
/* no need for checks except for base 10 / 8 errors */ |
if (t == '\0') { |
break; |
} else if (t >= 'a') { |
t = t - 'a' + 10; |
} else if (t >= 'A') { |
t = t - 'A' + 10; |
} else { |
t = t - '0'; |
if (t >= b) |
error("invalid digit"); |
} |
n1 = n; |
n = n * b + t; |
/* detect overflow */ |
/* XXX: this test is not reliable */ |
if (n < n1) |
error("integer constant overflow"); |
} |
/* XXX: not exactly ANSI compliant */ |
if ((n & 0xffffffff00000000LL) != 0) { |
if ((n >> 63) != 0) |
tok = TOK_CULLONG; |
else |
tok = TOK_CLLONG; |
} else if (n > 0x7fffffff) { |
tok = TOK_CUINT; |
} else { |
tok = TOK_CINT; |
} |
lcount = 0; |
ucount = 0; |
for(;;) { |
t = toup(ch); |
if (t == 'L') { |
if (lcount >= 2) |
error("three 'l's in integer constant"); |
lcount++; |
if (lcount == 2) { |
if (tok == TOK_CINT) |
tok = TOK_CLLONG; |
else if (tok == TOK_CUINT) |
tok = TOK_CULLONG; |
} |
ch = *p++; |
} else if (t == 'U') { |
if (ucount >= 1) |
error("two 'u's in integer constant"); |
ucount++; |
if (tok == TOK_CINT) |
tok = TOK_CUINT; |
else if (tok == TOK_CLLONG) |
tok = TOK_CULLONG; |
ch = *p++; |
} else { |
break; |
} |
} |
if (tok == TOK_CINT || tok == TOK_CUINT) |
tokc.ui = n; |
else |
tokc.ull = n; |
} |
} |
#define PARSE2(c1, tok1, c2, tok2) \ |
case c1: \ |
PEEKC(c, p); \ |
if (c == c2) { \ |
p++; \ |
tok = tok2; \ |
} else { \ |
tok = tok1; \ |
} \ |
break; |
/* return next token without macro substitution */ |
static inline void next_nomacro1(void) |
{ |
int t, c, is_long; |
TokenSym *ts; |
uint8_t *p, *p1; |
unsigned int h; |
p = file->buf_ptr; |
redo_no_start: |
c = *p; |
switch(c) { |
case ' ': |
case '\t': |
case '\f': |
case '\v': |
case '\r': |
p++; |
goto redo_no_start; |
case '\\': |
/* first look if it is in fact an end of buffer */ |
if (p >= file->buf_end) { |
file->buf_ptr = p; |
handle_eob(); |
p = file->buf_ptr; |
if (p >= file->buf_end) |
goto parse_eof; |
else |
goto redo_no_start; |
} else { |
file->buf_ptr = p; |
ch = *p; |
handle_stray(); |
p = file->buf_ptr; |
goto redo_no_start; |
} |
parse_eof: |
{ |
TCCState *s1 = tcc_state; |
if (parse_flags & PARSE_FLAG_LINEFEED) { |
tok = TOK_LINEFEED; |
} else if (s1->include_stack_ptr == s1->include_stack || |
!(parse_flags & PARSE_FLAG_PREPROCESS)) { |
/* no include left : end of file. */ |
tok = TOK_EOF; |
} else { |
/* pop include file */ |
/* test if previous '#endif' was after a #ifdef at |
start of file */ |
if (tok_flags & TOK_FLAG_ENDIF) { |
#ifdef INC_DEBUG |
printf("#endif %s\n", get_tok_str(file->ifndef_macro_saved, NULL)); |
#endif |
add_cached_include(s1, file->inc_type, file->inc_filename, |
file->ifndef_macro_saved); |
} |
/* add end of include file debug info */ |
if (do_debug) { |
put_stabd(N_EINCL, 0, 0); |
} |
/* pop include stack */ |
tcc_close(file); |
s1->include_stack_ptr--; |
file = *s1->include_stack_ptr; |
p = file->buf_ptr; |
goto redo_no_start; |
} |
} |
break; |
case '\n': |
if (parse_flags & PARSE_FLAG_LINEFEED) { |
tok = TOK_LINEFEED; |
} else { |
file->line_num++; |
tok_flags |= TOK_FLAG_BOL; |
p++; |
goto redo_no_start; |
} |
break; |
case '#': |
/* XXX: simplify */ |
PEEKC(c, p); |
if ((tok_flags & TOK_FLAG_BOL) && |
(parse_flags & PARSE_FLAG_PREPROCESS)) { |
file->buf_ptr = p; |
preprocess(tok_flags & TOK_FLAG_BOF); |
p = file->buf_ptr; |
goto redo_no_start; |
} else { |
if (c == '#') { |
p++; |
tok = TOK_TWOSHARPS; |
} else { |
if (parse_flags & PARSE_FLAG_ASM_COMMENTS) { |
p = parse_line_comment(p - 1); |
goto redo_no_start; |
} else { |
tok = '#'; |
} |
} |
} |
break; |
case 'a': case 'b': case 'c': case 'd': |
case 'e': case 'f': case 'g': case 'h': |
case 'i': case 'j': case 'k': case 'l': |
case 'm': case 'n': case 'o': case 'p': |
case 'q': case 'r': case 's': case 't': |
case 'u': case 'v': case 'w': case 'x': |
case 'y': case 'z': |
case 'A': case 'B': case 'C': case 'D': |
case 'E': case 'F': case 'G': case 'H': |
case 'I': case 'J': case 'K': |
case 'M': case 'N': case 'O': case 'P': |
case 'Q': case 'R': case 'S': case 'T': |
case 'U': case 'V': case 'W': case 'X': |
case 'Y': case 'Z': |
case '_': |
parse_ident_fast: |
p1 = p; |
h = TOK_HASH_INIT; |
h = TOK_HASH_FUNC(h, c); |
p++; |
for(;;) { |
c = *p; |
if (!isidnum_table[c]) |
break; |
h = TOK_HASH_FUNC(h, c); |
p++; |
} |
if (c != '\\') { |
TokenSym **pts; |
int len; |
/* fast case : no stray found, so we have the full token |
and we have already hashed it */ |
len = p - p1; |
h &= (TOK_HASH_SIZE - 1); |
pts = &hash_ident[h]; |
for(;;) { |
ts = *pts; |
if (!ts) |
break; |
if (ts->len == len && !memcmp(ts->str, p1, len)) |
goto token_found; |
pts = &(ts->hash_next); |
} |
ts = tok_alloc_new(pts, p1, len); |
token_found: ; |
} else { |
/* slower case */ |
cstr_reset(&tokcstr); |
while (p1 < p) { |
cstr_ccat(&tokcstr, *p1); |
p1++; |
} |
p--; |
PEEKC(c, p); |
parse_ident_slow: |
while (isidnum_table[c]) { |
cstr_ccat(&tokcstr, c); |
PEEKC(c, p); |
} |
ts = tok_alloc(tokcstr.data, tokcstr.size); |
} |
tok = ts->tok; |
break; |
case 'L': |
t = p[1]; |
if (t != '\\' && t != '\'' && t != '\"') { |
/* fast case */ |
goto parse_ident_fast; |
} else { |
PEEKC(c, p); |
if (c == '\'' || c == '\"') { |
is_long = 1; |
goto str_const; |
} else { |
cstr_reset(&tokcstr); |
cstr_ccat(&tokcstr, 'L'); |
goto parse_ident_slow; |
} |
} |
break; |
case '0': case '1': case '2': case '3': |
case '4': case '5': case '6': case '7': |
case '8': case '9': |
cstr_reset(&tokcstr); |
/* after the first digit, accept digits, alpha, '.' or sign if |
prefixed by 'eEpP' */ |
parse_num: |
for(;;) { |
t = c; |
cstr_ccat(&tokcstr, c); |
PEEKC(c, p); |
if (!(isnum(c) || isid(c) || c == '.' || |
((c == '+' || c == '-') && |
(t == 'e' || t == 'E' || t == 'p' || t == 'P')))) |
break; |
} |
/* We add a trailing '\0' to ease parsing */ |
cstr_ccat(&tokcstr, '\0'); |
tokc.cstr = &tokcstr; |
tok = TOK_PPNUM; |
break; |
case '.': |
/* special dot handling because it can also start a number */ |
PEEKC(c, p); |
if (isnum(c)) { |
cstr_reset(&tokcstr); |
cstr_ccat(&tokcstr, '.'); |
goto parse_num; |
} else if (c == '.') { |
PEEKC(c, p); |
if (c != '.') |
expect("'.'"); |
PEEKC(c, p); |
tok = TOK_DOTS; |
} else { |
tok = '.'; |
} |
break; |
case '\'': |
case '\"': |
is_long = 0; |
str_const: |
{ |
CString str; |
int sep; |
sep = c; |
/* parse the string */ |
cstr_new(&str); |
p = parse_pp_string(p, sep, &str); |
cstr_ccat(&str, '\0'); |
/* eval the escape (should be done as TOK_PPNUM) */ |
cstr_reset(&tokcstr); |
parse_escape_string(&tokcstr, str.data, is_long); |
cstr_free(&str); |
if (sep == '\'') { |
int char_size; |
/* XXX: make it portable */ |
if (!is_long) |
char_size = 1; |
else |
char_size = sizeof(int); |
if (tokcstr.size <= char_size) |
error("empty character constant"); |
if (tokcstr.size > 2 * char_size) |
warning("multi-character character constant"); |
if (!is_long) { |
tokc.i = *(int8_t *)tokcstr.data; |
tok = TOK_CCHAR; |
} else { |
tokc.i = *(int *)tokcstr.data; |
tok = TOK_LCHAR; |
} |
} else { |
tokc.cstr = &tokcstr; |
if (!is_long) |
tok = TOK_STR; |
else |
tok = TOK_LSTR; |
} |
} |
break; |
case '<': |
PEEKC(c, p); |
if (c == '=') { |
p++; |
tok = TOK_LE; |
} else if (c == '<') { |
PEEKC(c, p); |
if (c == '=') { |
p++; |
tok = TOK_A_SHL; |
} else { |
tok = TOK_SHL; |
} |
} else { |
tok = TOK_LT; |
} |
break; |
case '>': |
PEEKC(c, p); |
if (c == '=') { |
p++; |
tok = TOK_GE; |
} else if (c == '>') { |
PEEKC(c, p); |
if (c == '=') { |
p++; |
tok = TOK_A_SAR; |
} else { |
tok = TOK_SAR; |
} |
} else { |
tok = TOK_GT; |
} |
break; |
case '&': |
PEEKC(c, p); |
if (c == '&') { |
p++; |
tok = TOK_LAND; |
} else if (c == '=') { |
p++; |
tok = TOK_A_AND; |
} else { |
tok = '&'; |
} |
break; |
case '|': |
PEEKC(c, p); |
if (c == '|') { |
p++; |
tok = TOK_LOR; |
} else if (c == '=') { |
p++; |
tok = TOK_A_OR; |
} else { |
tok = '|'; |
} |
break; |
case '+': |
PEEKC(c, p); |
if (c == '+') { |
p++; |
tok = TOK_INC; |
} else if (c == '=') { |
p++; |
tok = TOK_A_ADD; |
} else { |
tok = '+'; |
} |
break; |
case '-': |
PEEKC(c, p); |
if (c == '-') { |
p++; |
tok = TOK_DEC; |
} else if (c == '=') { |
p++; |
tok = TOK_A_SUB; |
} else if (c == '>') { |
p++; |
tok = TOK_ARROW; |
} else { |
tok = '-'; |
} |
break; |
PARSE2('!', '!', '=', TOK_NE) |
PARSE2('=', '=', '=', TOK_EQ) |
PARSE2('*', '*', '=', TOK_A_MUL) |
PARSE2('%', '%', '=', TOK_A_MOD) |
PARSE2('^', '^', '=', TOK_A_XOR) |
/* comments or operator */ |
case '/': |
PEEKC(c, p); |
if (c == '*') { |
p = parse_comment(p); |
goto redo_no_start; |
} else if (c == '/') { |
p = parse_line_comment(p); |
goto redo_no_start; |
} else if (c == '=') { |
p++; |
tok = TOK_A_DIV; |
} else { |
tok = '/'; |
} |
break; |
/* simple tokens */ |
case '(': |
case ')': |
case '[': |
case ']': |
case '{': |
case '}': |
case ',': |
case ';': |
case ':': |
case '?': |
case '~': |
case '$': /* only used in assembler */ |
case '@': /* dito */ |
tok = c; |
p++; |
break; |
default: |
error("unrecognized character \\x%02x", c); |
break; |
} |
file->buf_ptr = p; |
tok_flags = 0; |
#if defined(PARSE_DEBUG) |
printf("token = %s\n", get_tok_str(tok, &tokc)); |
#endif |
} |
/* return next token without macro substitution. Can read input from |
macro_ptr buffer */ |
static void next_nomacro(void) |
{ |
if (macro_ptr) { |
redo: |
tok = *macro_ptr; |
if (tok) { |
TOK_GET(tok, macro_ptr, tokc); |
if (tok == TOK_LINENUM) { |
file->line_num = tokc.i; |
goto redo; |
} |
} |
} else { |
next_nomacro1(); |
} |
} |
/* substitute args in macro_str and return allocated string */ |
static int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args) |
{ |
int *st, last_tok, t, notfirst; |
Sym *s; |
CValue cval; |
TokenString str; |
CString cstr; |
tok_str_new(&str); |
last_tok = 0; |
while(1) { |
TOK_GET(t, macro_str, cval); |
if (!t) |
break; |
if (t == '#') { |
/* stringize */ |
TOK_GET(t, macro_str, cval); |
if (!t) |
break; |
s = sym_find2(args, t); |
if (s) { |
cstr_new(&cstr); |
st = (int *)s->c; |
notfirst = 0; |
while (*st) { |
if (notfirst) |
cstr_ccat(&cstr, ' '); |
TOK_GET(t, st, cval); |
cstr_cat(&cstr, get_tok_str(t, &cval)); |
notfirst = 1; |
} |
cstr_ccat(&cstr, '\0'); |
#ifdef PP_DEBUG |
printf("stringize: %s\n", (char *)cstr.data); |
#endif |
/* add string */ |
cval.cstr = &cstr; |
tok_str_add2(&str, TOK_STR, &cval); |
cstr_free(&cstr); |
} else { |
tok_str_add2(&str, t, &cval); |
} |
} else if (t >= TOK_IDENT) { |
s = sym_find2(args, t); |
if (s) { |
st = (int *)s->c; |
/* if '##' is present before or after, no arg substitution */ |
if (*macro_str == TOK_TWOSHARPS || last_tok == TOK_TWOSHARPS) { |
/* special case for var arg macros : ## eats the |
',' if empty VA_ARGS variable. */ |
/* XXX: test of the ',' is not 100% |
reliable. should fix it to avoid security |
problems */ |
if (gnu_ext && s->type.t && |
last_tok == TOK_TWOSHARPS && |
str.len >= 2 && str.str[str.len - 2] == ',') { |
if (*st == 0) { |
/* suppress ',' '##' */ |
str.len -= 2; |
} else { |
/* suppress '##' and add variable */ |
str.len--; |
goto add_var; |
} |
} else { |
int t1; |
add_var: |
for(;;) { |
TOK_GET(t1, st, cval); |
if (!t1) |
break; |
tok_str_add2(&str, t1, &cval); |
} |
} |
} else { |
/* NOTE: the stream cannot be read when macro |
substituing an argument */ |
macro_subst(&str, nested_list, st, NULL); |
} |
} else { |
tok_str_add(&str, t); |
} |
} else { |
tok_str_add2(&str, t, &cval); |
} |
last_tok = t; |
} |
tok_str_add(&str, 0); |
return str.str; |
} |
static char const ab_month_name[12][4] = |
{ |
"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" |
}; |
/* do macro substitution of current token with macro 's' and add |
result to (tok_str,tok_len). 'nested_list' is the list of all |
macros we got inside to avoid recursing. Return non zero if no |
substitution needs to be done */ |
static int macro_subst_tok(TokenString *tok_str, |
Sym **nested_list, Sym *s, struct macro_level **can_read_stream) |
{ |
Sym *args, *sa, *sa1; |
int mstr_allocated, parlevel, *mstr, t, t1; |
TokenString str; |
char *cstrval; |
CValue cval; |
CString cstr; |
char buf[32]; |
/* if symbol is a macro, prepare substitution */ |
/* special macros */ |
if (tok == TOK___LINE__) { |
snprintf(buf, sizeof(buf), "%d", file->line_num); |
cstrval = buf; |
t1 = TOK_PPNUM; |
goto add_cstr1; |
} else if (tok == TOK___FILE__) { |
cstrval = file->filename; |
goto add_cstr; |
} else if (tok == TOK___DATE__ || tok == TOK___TIME__) { |
time_t ti; |
struct tm *tm; |
time(&ti); |
tm = localtime(&ti); |
if (tok == TOK___DATE__) { |
snprintf(buf, sizeof(buf), "%s %2d %d", |
ab_month_name[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); |
} else { |
snprintf(buf, sizeof(buf), "%02d:%02d:%02d", |
tm->tm_hour, tm->tm_min, tm->tm_sec); |
} |
cstrval = buf; |
add_cstr: |
t1 = TOK_STR; |
add_cstr1: |
cstr_new(&cstr); |
cstr_cat(&cstr, cstrval); |
cstr_ccat(&cstr, '\0'); |
cval.cstr = &cstr; |
tok_str_add2(tok_str, t1, &cval); |
cstr_free(&cstr); |
} else { |
mstr = (int *)s->c; |
mstr_allocated = 0; |
if (s->type.t == MACRO_FUNC) { |
/* NOTE: we do not use next_nomacro to avoid eating the |
next token. XXX: find better solution */ |
redo: |
if (macro_ptr) { |
t = *macro_ptr; |
if (t == 0 && can_read_stream) { |
/* end of macro stream: we must look at the token |
after in the file */ |
struct macro_level *ml = *can_read_stream; |
macro_ptr = NULL; |
if (ml) |
{ |
macro_ptr = ml->p; |
ml->p = NULL; |
*can_read_stream = ml -> prev; |
} |
goto redo; |
} |
} else { |
/* XXX: incorrect with comments */ |
ch = file->buf_ptr[0]; |
while (is_space(ch) || ch == '\n') |
cinp(); |
t = ch; |
} |
if (t != '(') /* no macro subst */ |
return -1; |
/* argument macro */ |
next_nomacro(); |
next_nomacro(); |
args = NULL; |
sa = s->next; |
/* NOTE: empty args are allowed, except if no args */ |
for(;;) { |
/* handle '()' case */ |
if (!args && !sa && tok == ')') |
break; |
if (!sa) |
error("macro '%s' used with too many args", |
get_tok_str(s->v, 0)); |
tok_str_new(&str); |
parlevel = 0; |
/* NOTE: non zero sa->t indicates VA_ARGS */ |
while ((parlevel > 0 || |
(tok != ')' && |
(tok != ',' || sa->type.t))) && |
tok != -1) { |
if (tok == '(') |
parlevel++; |
else if (tok == ')') |
parlevel--; |
tok_str_add2(&str, tok, &tokc); |
next_nomacro(); |
} |
tok_str_add(&str, 0); |
sym_push2(&args, sa->v & ~SYM_FIELD, sa->type.t, (int)str.str); |
sa = sa->next; |
if (tok == ')') { |
/* special case for gcc var args: add an empty |
var arg argument if it is omitted */ |
if (sa && sa->type.t && gnu_ext) |
continue; |
else |
break; |
} |
if (tok != ',') |
expect(","); |
next_nomacro(); |
} |
if (sa) { |
error("macro '%s' used with too few args", |
get_tok_str(s->v, 0)); |
} |
/* now subst each arg */ |
mstr = macro_arg_subst(nested_list, mstr, args); |
/* free memory */ |
sa = args; |
while (sa) { |
sa1 = sa->prev; |
tok_str_free((int *)sa->c); |
sym_free(sa); |
sa = sa1; |
} |
mstr_allocated = 1; |
} |
sym_push2(nested_list, s->v, 0, 0); |
macro_subst(tok_str, nested_list, mstr, can_read_stream); |
/* pop nested defined symbol */ |
sa1 = *nested_list; |
*nested_list = sa1->prev; |
sym_free(sa1); |
if (mstr_allocated) |
tok_str_free(mstr); |
} |
return 0; |
} |
/* handle the '##' operator. Return NULL if no '##' seen. Otherwise |
return the resulting string (which must be freed). */ |
static inline int *macro_twosharps(const int *macro_str) |
{ |
TokenSym *ts; |
const int *macro_ptr1, *start_macro_ptr, *ptr, *saved_macro_ptr; |
int t; |
const char *p1, *p2; |
CValue cval; |
TokenString macro_str1; |
CString cstr; |
start_macro_ptr = macro_str; |
/* we search the first '##' */ |
for(;;) { |
macro_ptr1 = macro_str; |
TOK_GET(t, macro_str, cval); |
/* nothing more to do if end of string */ |
if (t == 0) |
return NULL; |
if (*macro_str == TOK_TWOSHARPS) |
break; |
} |
/* we saw '##', so we need more processing to handle it */ |
cstr_new(&cstr); |
tok_str_new(¯o_str1); |
tok = t; |
tokc = cval; |
/* add all tokens seen so far */ |
for(ptr = start_macro_ptr; ptr < macro_ptr1;) { |
TOK_GET(t, ptr, cval); |
tok_str_add2(¯o_str1, t, &cval); |
} |
saved_macro_ptr = macro_ptr; |
/* XXX: get rid of the use of macro_ptr here */ |
macro_ptr = (int *)macro_str; |
for(;;) { |
while (*macro_ptr == TOK_TWOSHARPS) { |
macro_ptr++; |
macro_ptr1 = macro_ptr; |
t = *macro_ptr; |
if (t) { |
TOK_GET(t, macro_ptr, cval); |
/* We concatenate the two tokens if we have an |
identifier or a preprocessing number */ |
cstr_reset(&cstr); |
p1 = get_tok_str(tok, &tokc); |
cstr_cat(&cstr, p1); |
p2 = get_tok_str(t, &cval); |
cstr_cat(&cstr, p2); |
cstr_ccat(&cstr, '\0'); |
if ((tok >= TOK_IDENT || tok == TOK_PPNUM) && |
(t >= TOK_IDENT || t == TOK_PPNUM)) { |
if (tok == TOK_PPNUM) { |
/* if number, then create a number token */ |
/* NOTE: no need to allocate because |
tok_str_add2() does it */ |
tokc.cstr = &cstr; |
} else { |
/* if identifier, we must do a test to |
validate we have a correct identifier */ |
if (t == TOK_PPNUM) { |
const char *p; |
int c; |
p = p2; |
for(;;) { |
c = *p; |
if (c == '\0') |
break; |
p++; |
if (!isnum(c) && !isid(c)) |
goto error_pasting; |
} |
} |
ts = tok_alloc(cstr.data, strlen(cstr.data)); |
tok = ts->tok; /* modify current token */ |
} |
} else { |
const char *str = cstr.data; |
const unsigned char *q; |
/* we look for a valid token */ |
/* XXX: do more extensive checks */ |
if (!strcmp(str, ">>=")) { |
tok = TOK_A_SAR; |
} else if (!strcmp(str, "<<=")) { |
tok = TOK_A_SHL; |
} else if (strlen(str) == 2) { |
/* search in two bytes table */ |
q = tok_two_chars; |
for(;;) { |
if (!*q) |
goto error_pasting; |
if (q[0] == str[0] && q[1] == str[1]) |
break; |
q += 3; |
} |
tok = q[2]; |
} else { |
error_pasting: |
/* NOTE: because get_tok_str use a static buffer, |
we must save it */ |
cstr_reset(&cstr); |
p1 = get_tok_str(tok, &tokc); |
cstr_cat(&cstr, p1); |
cstr_ccat(&cstr, '\0'); |
p2 = get_tok_str(t, &cval); |
warning("pasting \"%s\" and \"%s\" does not give a valid preprocessing token", cstr.data, p2); |
/* cannot merge tokens: just add them separately */ |
tok_str_add2(¯o_str1, tok, &tokc); |
/* XXX: free associated memory ? */ |
tok = t; |
tokc = cval; |
} |
} |
} |
} |
tok_str_add2(¯o_str1, tok, &tokc); |
next_nomacro(); |
if (tok == 0) |
break; |
} |
macro_ptr = (int *)saved_macro_ptr; |
cstr_free(&cstr); |
tok_str_add(¯o_str1, 0); |
return macro_str1.str; |
} |
/* do macro substitution of macro_str and add result to |
(tok_str,tok_len). 'nested_list' is the list of all macros we got |
inside to avoid recursing. */ |
static void macro_subst(TokenString *tok_str, Sym **nested_list, |
const int *macro_str, struct macro_level ** can_read_stream) |
{ |
Sym *s; |
int *macro_str1; |
const int *ptr; |
int t, ret; |
CValue cval; |
struct macro_level ml; |
/* first scan for '##' operator handling */ |
ptr = macro_str; |
macro_str1 = macro_twosharps(ptr); |
if (macro_str1) |
ptr = macro_str1; |
while (1) { |
/* NOTE: ptr == NULL can only happen if tokens are read from |
file stream due to a macro function call */ |
if (ptr == NULL) |
break; |
TOK_GET(t, ptr, cval); |
if (t == 0) |
break; |
s = define_find(t); |
if (s != NULL) { |
/* if nested substitution, do nothing */ |
if (sym_find2(*nested_list, t)) |
goto no_subst; |
ml.p = macro_ptr; |
if (can_read_stream) |
ml.prev = *can_read_stream, *can_read_stream = &ml; |
macro_ptr = (int *)ptr; |
tok = t; |
ret = macro_subst_tok(tok_str, nested_list, s, can_read_stream); |
ptr = (int *)macro_ptr; |
macro_ptr = ml.p; |
if (can_read_stream && *can_read_stream == &ml) |
*can_read_stream = ml.prev; |
if (ret != 0) |
goto no_subst; |
} else { |
no_subst: |
tok_str_add2(tok_str, t, &cval); |
} |
} |
if (macro_str1) |
tok_str_free(macro_str1); |
} |
/* return next token with macro substitution */ |
static void next(void) |
{ |
Sym *nested_list, *s; |
TokenString str; |
struct macro_level *ml; |
redo: |
next_nomacro(); |
if (!macro_ptr) { |
/* if not reading from macro substituted string, then try |
to substitute macros */ |
if (tok >= TOK_IDENT && |
(parse_flags & PARSE_FLAG_PREPROCESS)) { |
s = define_find(tok); |
if (s) { |
/* we have a macro: we try to substitute */ |
tok_str_new(&str); |
nested_list = NULL; |
ml = NULL; |
if (macro_subst_tok(&str, &nested_list, s, &ml) == 0) { |
/* substitution done, NOTE: maybe empty */ |
tok_str_add(&str, 0); |
macro_ptr = str.str; |
macro_ptr_allocated = str.str; |
goto redo; |
} |
} |
} |
} else { |
if (tok == 0) { |
/* end of macro or end of unget buffer */ |
if (unget_buffer_enabled) { |
macro_ptr = unget_saved_macro_ptr; |
unget_buffer_enabled = 0; |
} else { |
/* end of macro string: free it */ |
tok_str_free(macro_ptr_allocated); |
macro_ptr = NULL; |
} |
goto redo; |
} |
} |
/* convert preprocessor tokens into C tokens */ |
if (tok == TOK_PPNUM && |
(parse_flags & PARSE_FLAG_TOK_NUM)) { |
parse_number((char *)tokc.cstr->data); |
} |
} |
/* push back current token and set current token to 'last_tok'. Only |
identifier case handled for labels. */ |
static inline void unget_tok(int last_tok) |
{ |
int i, n; |
int *q; |
unget_saved_macro_ptr = macro_ptr; |
unget_buffer_enabled = 1; |
q = unget_saved_buffer; |
macro_ptr = q; |
*q++ = tok; |
n = tok_ext_size(tok) - 1; |
for(i=0;i<n;i++) |
*q++ = tokc.tab[i]; |
*q = 0; /* end of token string */ |
tok = last_tok; |
} |
void swap(int *p, int *q) |
{ |
int t; |
t = *p; |
*p = *q; |
*q = t; |
} |
void vsetc(CType *type, int r, CValue *vc) |
{ |
int v; |
if (vtop >= vstack + (VSTACK_SIZE - 1)) |
error("memory full"); |
/* cannot let cpu flags if other instruction are generated. Also |
avoid leaving VT_JMP anywhere except on the top of the stack |
because it would complicate the code generator. */ |
if (vtop >= vstack) { |
v = vtop->r & VT_VALMASK; |
if (v == VT_CMP || (v & ~1) == VT_JMP) |
gv(RC_INT); |
} |
vtop++; |
vtop->type = *type; |
vtop->r = r; |
vtop->r2 = VT_CONST; |
vtop->c = *vc; |
} |
/* push integer constant */ |
void vpushi(int v) |
{ |
CValue cval; |
cval.i = v; |
vsetc(&int_type, VT_CONST, &cval); |
} |
/* Return a static symbol pointing to a section */ |
static Sym *get_sym_ref(CType *type, Section *sec, |
unsigned long offset, unsigned long size) |
{ |
int v; |
Sym *sym; |
v = anon_sym++; |
sym = global_identifier_push(v, type->t | VT_STATIC, 0); |
sym->type.ref = type->ref; |
sym->r = VT_CONST | VT_SYM; |
put_extern_sym(sym, sec, offset, size); |
return sym; |
} |
/* push a reference to a section offset by adding a dummy symbol */ |
static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) |
{ |
CValue cval; |
cval.ul = 0; |
vsetc(type, VT_CONST | VT_SYM, &cval); |
vtop->sym = get_sym_ref(type, sec, offset, size); |
} |
/* define a new external reference to a symbol 'v' of type 'u' */ |
static Sym *external_global_sym(int v, CType *type, int r) |
{ |
Sym *s; |
s = sym_find(v); |
if (!s) { |
/* push forward reference */ |
s = global_identifier_push(v, type->t | VT_EXTERN, 0); |
s->type.ref = type->ref; |
s->r = r | VT_CONST | VT_SYM; |
} |
return s; |
} |
/* define a new external reference to a symbol 'v' of type 'u' */ |
static Sym *external_sym(int v, CType *type, int r) |
{ |
Sym *s; |
s = sym_find(v); |
if (!s) { |
/* push forward reference */ |
s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); |
s->type.t |= VT_EXTERN; |
} else { |
if (!is_compatible_types(&s->type, type)) |
error("incompatible types for redefinition of '%s'", |
get_tok_str(v, NULL)); |
} |
return s; |
} |
/* push a reference to global symbol v */ |
static void vpush_global_sym(CType *type, int v) |
{ |
Sym *sym; |
CValue cval; |
sym = external_global_sym(v, type, 0); |
cval.ul = 0; |
vsetc(type, VT_CONST | VT_SYM, &cval); |
vtop->sym = sym; |
} |
void vset(CType *type, int r, int v) |
{ |
CValue cval; |
cval.i = v; |
vsetc(type, r, &cval); |
} |
void vseti(int r, int v) |
{ |
CType type; |
type.t = VT_INT; |
vset(&type, r, v); |
} |
void vswap(void) |
{ |
SValue tmp; |
tmp = vtop[0]; |
vtop[0] = vtop[-1]; |
vtop[-1] = tmp; |
} |
void vpushv(SValue *v) |
{ |
if (vtop >= vstack + (VSTACK_SIZE - 1)) |
error("memory full"); |
vtop++; |
*vtop = *v; |
} |
void vdup(void) |
{ |
vpushv(vtop); |
} |
/* save r to the memory stack, and mark it as being free */ |
void save_reg(int r) |
{ |
int l, saved, size, align; |
SValue *p, sv; |
CType *type; |
/* modify all stack values */ |
saved = 0; |
l = 0; |
for(p=vstack;p<=vtop;p++) { |
if ((p->r & VT_VALMASK) == r || |
(p->r2 & VT_VALMASK) == r) { |
/* must save value on stack if not already done */ |
if (!saved) { |
/* NOTE: must reload 'r' because r might be equal to r2 */ |
r = p->r & VT_VALMASK; |
/* store register in the stack */ |
type = &p->type; |
if ((p->r & VT_LVAL) || |
(!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) |
type = &int_type; |
size = type_size(type, &align); |
loc = (loc - size) & -align; |
sv.type.t = type->t; |
sv.r = VT_LOCAL | VT_LVAL; |
sv.c.ul = loc; |
store(r, &sv); |
#ifdef TCC_TARGET_I386 |
/* x86 specific: need to pop fp register ST0 if saved */ |
if (r == TREG_ST0) { |
o(0xd9dd); /* fstp %st(1) */ |
} |
#endif |
/* special long long case */ |
if ((type->t & VT_BTYPE) == VT_LLONG) { |
sv.c.ul += 4; |
store(p->r2, &sv); |
} |
l = loc; |
saved = 1; |
} |
/* mark that stack entry as being saved on the stack */ |
if (p->r & VT_LVAL) { |
/* also clear the bounded flag because the |
relocation address of the function was stored in |
p->c.ul */ |
p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; |
} else { |
p->r = lvalue_type(p->type.t) | VT_LOCAL; |
} |
p->r2 = VT_CONST; |
p->c.ul = l; |
} |
} |
} |
/* find a register of class 'rc2' with at most one reference on stack. |
* If none, call get_reg(rc) */ |
int get_reg_ex(int rc, int rc2) |
{ |
int r; |
SValue *p; |
for(r=0;r<NB_REGS;r++) { |
if (reg_classes[r] & rc2) { |
int n; |
n=0; |
for(p = vstack; p <= vtop; p++) { |
if ((p->r & VT_VALMASK) == r || |
(p->r2 & VT_VALMASK) == r) |
n++; |
} |
if (n <= 1) |
return r; |
} |
} |
return get_reg(rc); |
} |
/* find a free register of class 'rc'. If none, save one register */ |
int get_reg(int rc) |
{ |
int r; |
SValue *p; |
/* find a free register */ |
for(r=0;r<NB_REGS;r++) { |
if (reg_classes[r] & rc) { |
for(p=vstack;p<=vtop;p++) { |
if ((p->r & VT_VALMASK) == r || |
(p->r2 & VT_VALMASK) == r) |
goto notfound; |
} |
return r; |
} |
notfound: ; |
} |
/* no register left : free the first one on the stack (VERY |
IMPORTANT to start from the bottom to ensure that we don't |
spill registers used in gen_opi()) */ |
for(p=vstack;p<=vtop;p++) { |
r = p->r & VT_VALMASK; |
if (r < VT_CONST && (reg_classes[r] & rc)) |
goto save_found; |
/* also look at second register (if long long) */ |
r = p->r2 & VT_VALMASK; |
if (r < VT_CONST && (reg_classes[r] & rc)) { |
save_found: |
save_reg(r); |
return r; |
} |
} |
/* Should never comes here */ |
return -1; |
} |
/* save registers up to (vtop - n) stack entry */ |
void save_regs(int n) |
{ |
int r; |
SValue *p, *p1; |
p1 = vtop - n; |
for(p = vstack;p <= p1; p++) { |
r = p->r & VT_VALMASK; |
if (r < VT_CONST) { |
save_reg(r); |
} |
} |
} |
/* move register 's' to 'r', and flush previous value of r to memory |
if needed */ |
void move_reg(int r, int s) |
{ |
SValue sv; |
if (r != s) { |
save_reg(r); |
sv.type.t = VT_INT; |
sv.r = s; |
sv.c.ul = 0; |
load(r, &sv); |
} |
} |
/* get address of vtop (vtop MUST BE an lvalue) */ |
void gaddrof(void) |
{ |
vtop->r &= ~VT_LVAL; |
/* tricky: if saved lvalue, then we can go back to lvalue */ |
if ((vtop->r & VT_VALMASK) == VT_LLOCAL) |
vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; |
} |
#ifdef CONFIG_TCC_BCHECK |
" -b compile with built-in memory and bounds checker (implies -g)\n" |
/* generate lvalue bound code */ |
void gbound(void) |
{ |
int lval_type; |
CType type1; |
vtop->r &= ~VT_MUSTBOUND; |
/* if lvalue, then use checking code before dereferencing */ |
if (vtop->r & VT_LVAL) { |
/* if not VT_BOUNDED value, then make one */ |
if (!(vtop->r & VT_BOUNDED)) { |
lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); |
/* must save type because we must set it to int to get pointer */ |
type1 = vtop->type; |
vtop->type.t = VT_INT; |
gaddrof(); |
vpushi(0); |
gen_bounded_ptr_add(); |
vtop->r |= lval_type; |
vtop->type = type1; |
} |
/* then check for dereferencing */ |
gen_bounded_ptr_deref(); |
} |
} |
#endif |
#ifdef CONFIG_TCC_BACKTRACE |
" -bt N show N callers in stack traces\n" |
/* store vtop a register belonging to class 'rc'. lvalues are |
converted to values. Cannot be used if cannot be converted to |
register value (such as structures). */ |
int gv(int rc) |
{ |
int r, r2, rc2, bit_pos, bit_size, size, align, i; |
unsigned long long ll; |
/* NOTE: get_reg can modify vstack[] */ |
if (vtop->type.t & VT_BITFIELD) { |
bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
/* remove bit field info to avoid loops */ |
vtop->type.t &= ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
/* generate shifts */ |
vpushi(32 - (bit_pos + bit_size)); |
gen_op(TOK_SHL); |
vpushi(32 - bit_size); |
/* NOTE: transformed to SHR if unsigned */ |
gen_op(TOK_SAR); |
r = gv(rc); |
} else { |
if (is_float(vtop->type.t) && |
(vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
Sym *sym; |
int *ptr; |
unsigned long offset; |
/* XXX: unify with initializers handling ? */ |
/* CPUs usually cannot use float constants, so we store them |
generically in data segment */ |
size = type_size(&vtop->type, &align); |
offset = (data_section->data_offset + align - 1) & -align; |
data_section->data_offset = offset; |
/* XXX: not portable yet */ |
ptr = section_ptr_add(data_section, size); |
size = size >> 2; |
for(i=0;i<size;i++) |
ptr[i] = vtop->c.tab[i]; |
sym = get_sym_ref(&vtop->type, data_section, offset, size << 2); |
vtop->r |= VT_LVAL | VT_SYM; |
vtop->sym = sym; |
vtop->c.ul = 0; |
} |
#ifdef CONFIG_TCC_BCHECK |
if (vtop->r & VT_MUSTBOUND) |
gbound(); |
#endif |
"Misc options:\n" |
" -nostdinc do not use standard system include paths\n" |
" -nostdlib do not link with standard crt and libraries\n" |
" -Bdir use 'dir' as tcc internal library and include path\n" |
" -MD generate target dependencies for make\n" |
" -MF depfile put generated dependencies here\n" |
); |
r = vtop->r & VT_VALMASK; |
/* need to reload if: |
- constant |
- lvalue (need to dereference pointer) |
- already a register, but not in the right class */ |
if (r >= VT_CONST || |
(vtop->r & VT_LVAL) || |
!(reg_classes[r] & rc) || |
((vtop->type.t & VT_BTYPE) == VT_LLONG && |
!(reg_classes[vtop->r2] & rc))) { |
r = get_reg(rc); |
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
/* two register type load : expand to two words |
temporarily */ |
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
/* load constant */ |
ll = vtop->c.ull; |
vtop->c.ui = ll; /* first word */ |
load(r, vtop); |
vtop->r = r; /* save register value */ |
vpushi(ll >> 32); /* second word */ |
} else if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ |
(vtop->r & VT_LVAL)) { |
/* We do not want to modifier the long long |
pointer here, so the safest (and less |
efficient) is to save all the other registers |
in the stack. XXX: totally inefficient. */ |
save_regs(1); |
/* load from memory */ |
load(r, vtop); |
vdup(); |
vtop[-1].r = r; /* save register value */ |
/* increment pointer to get second word */ |
vtop->type.t = VT_INT; |
gaddrof(); |
vpushi(4); |
gen_op('+'); |
vtop->r |= VT_LVAL; |
} else { |
/* move registers */ |
load(r, vtop); |
vdup(); |
vtop[-1].r = r; /* save register value */ |
vtop->r = vtop[-1].r2; |
} |
/* allocate second register */ |
rc2 = RC_INT; |
if (rc == RC_IRET) |
rc2 = RC_LRET; |
r2 = get_reg(rc2); |
load(r2, vtop); |
vpop(); |
/* write second register */ |
vtop->r2 = r2; |
} else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { |
int t1, t; |
/* lvalue of scalar type : need to use lvalue type |
because of possible cast */ |
t = vtop->type.t; |
t1 = t; |
/* compute memory access type */ |
if (vtop->r & VT_LVAL_BYTE) |
t = VT_BYTE; |
else if (vtop->r & VT_LVAL_SHORT) |
t = VT_SHORT; |
if (vtop->r & VT_LVAL_UNSIGNED) |
t |= VT_UNSIGNED; |
vtop->type.t = t; |
load(r, vtop); |
/* restore wanted type */ |
vtop->type.t = t1; |
} else { |
/* one register type load */ |
load(r, vtop); |
} |
} |
vtop->r = r; |
#ifdef TCC_TARGET_C67 |
/* uses register pairs for doubles */ |
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
vtop->r2 = r+1; |
#endif |
} |
return r; |
} |
/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */ |
#if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) && !defined(TCC_TARGET_MEOS) |
#ifdef _WIN32 |
#include <process.h> |
static int execvp_win32(const char *prog, char **argv) |
/* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ |
void gv2(int rc1, int rc2) |
{ |
int ret = spawnvp(P_NOWAIT, prog, (const char *const*)argv); |
if (-1 == ret) |
return ret; |
cwait(&ret, ret, WAIT_CHILD); |
exit(ret); |
int v; |
/* generate more generic register first. But VT_JMP or VT_CMP |
values must be generated first in all cases to avoid possible |
reload errors */ |
v = vtop[0].r & VT_VALMASK; |
if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { |
vswap(); |
gv(rc1); |
vswap(); |
gv(rc2); |
/* test if reload is needed for first register */ |
if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { |
vswap(); |
gv(rc1); |
vswap(); |
} |
#define execvp execvp_win32 |
} else { |
gv(rc2); |
vswap(); |
gv(rc1); |
vswap(); |
/* test if reload is needed for first register */ |
if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { |
gv(rc2); |
} |
} |
} |
/* expand long long on stack in two int registers */ |
void lexpand(void) |
{ |
int u; |
u = vtop->type.t & VT_UNSIGNED; |
gv(RC_INT); |
vdup(); |
vtop[0].r = vtop[-1].r2; |
vtop[0].r2 = VT_CONST; |
vtop[-1].r2 = VT_CONST; |
vtop[0].type.t = VT_INT | u; |
vtop[-1].type.t = VT_INT | u; |
} |
#ifdef TCC_TARGET_ARM |
/* expand long long on stack */ |
void lexpand_nr(void) |
{ |
int u,v; |
u = vtop->type.t & VT_UNSIGNED; |
vdup(); |
vtop->r2 = VT_CONST; |
vtop->type.t = VT_INT | u; |
v=vtop[-1].r & (VT_VALMASK | VT_LVAL); |
if (v == VT_CONST) { |
vtop[-1].c.ui = vtop->c.ull; |
vtop->c.ui = vtop->c.ull >> 32; |
vtop->r = VT_CONST; |
} else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { |
vtop->c.ui += 4; |
vtop->r = vtop[-1].r; |
} else if (v > VT_CONST) { |
vtop--; |
lexpand(); |
} else |
vtop->r = vtop[-1].r2; |
vtop[-1].r2 = VT_CONST; |
vtop[-1].type.t = VT_INT | u; |
} |
#endif |
static void exec_other_tcc(TCCState *s, char **argv, const char *optarg) |
/* build a long long from two ints */ |
void lbuild(int t) |
{ |
char child_path[4096], *child_name; const char *target; |
switch (atoi(optarg)) { |
gv2(RC_INT, RC_INT); |
vtop[-1].r2 = vtop[0].r; |
vtop[-1].type.t = t; |
vpop(); |
} |
/* rotate n first stack elements to the bottom |
I1 ... In -> I2 ... In I1 [top is right] |
*/ |
void vrotb(int n) |
{ |
int i; |
SValue tmp; |
tmp = vtop[-n + 1]; |
for(i=-n+1;i!=0;i++) |
vtop[i] = vtop[i+1]; |
vtop[0] = tmp; |
} |
/* rotate n first stack elements to the top |
I1 ... In -> In I1 ... I(n-1) [top is right] |
*/ |
void vrott(int n) |
{ |
int i; |
SValue tmp; |
tmp = vtop[0]; |
for(i = 0;i < n - 1; i++) |
vtop[-i] = vtop[-i - 1]; |
vtop[-n + 1] = tmp; |
} |
#ifdef TCC_TARGET_ARM |
/* like vrott but in other direction |
In ... I1 -> I(n-1) ... I1 In [top is right] |
*/ |
void vnrott(int n) |
{ |
int i; |
SValue tmp; |
tmp = vtop[-n + 1]; |
for(i = n - 1; i > 0; i--) |
vtop[-i] = vtop[-i + 1]; |
vtop[0] = tmp; |
} |
#endif |
/* pop stack value */ |
void vpop(void) |
{ |
int v; |
v = vtop->r & VT_VALMASK; |
#ifdef TCC_TARGET_I386 |
case 32: break; |
case 64: target = "x86_64"; |
/* for x86, we need to pop the FP stack */ |
if (v == TREG_ST0 && !nocode_wanted) { |
o(0xd9dd); /* fstp %st(1) */ |
} else |
#endif |
if (v == VT_JMP || v == VT_JMPI) { |
/* need to put correct jump if && or || without test */ |
gsym(vtop->c.ul); |
} |
vtop--; |
} |
/* convert stack entry to register and duplicate its value in another |
register */ |
void gv_dup(void) |
{ |
int rc, t, r, r1; |
SValue sv; |
t = vtop->type.t; |
if ((t & VT_BTYPE) == VT_LLONG) { |
lexpand(); |
gv_dup(); |
vswap(); |
vrotb(3); |
gv_dup(); |
vrotb(4); |
/* stack: H L L1 H1 */ |
lbuild(t); |
vrotb(3); |
vrotb(3); |
vswap(); |
lbuild(t); |
vswap(); |
} else { |
/* duplicate value */ |
rc = RC_INT; |
sv.type.t = VT_INT; |
if (is_float(t)) { |
rc = RC_FLOAT; |
sv.type.t = t; |
} |
r = gv(rc); |
r1 = get_reg(rc); |
sv.r = r; |
sv.c.ul = 0; |
load(r1, &sv); /* move r to r1 */ |
vdup(); |
/* duplicates value */ |
vtop->r = r1; |
} |
} |
/* generate CPU independent (unsigned) long long operations */ |
void gen_opl(int op) |
{ |
int t, a, b, op1, c, i; |
int func; |
SValue tmp; |
switch(op) { |
case '/': |
case TOK_PDIV: |
func = TOK___divdi3; |
goto gen_func; |
case TOK_UDIV: |
func = TOK___udivdi3; |
goto gen_func; |
case '%': |
func = TOK___moddi3; |
goto gen_func; |
case TOK_UMOD: |
func = TOK___umoddi3; |
gen_func: |
/* call generic long long function */ |
vpush_global_sym(&func_old_type, func); |
vrott(3); |
gfunc_call(2); |
vpushi(0); |
vtop->r = REG_IRET; |
vtop->r2 = REG_LRET; |
break; |
case '^': |
case '&': |
case '|': |
case '*': |
case '+': |
case '-': |
t = vtop->type.t; |
vswap(); |
lexpand(); |
vrotb(3); |
lexpand(); |
/* stack: L1 H1 L2 H2 */ |
tmp = vtop[0]; |
vtop[0] = vtop[-3]; |
vtop[-3] = tmp; |
tmp = vtop[-2]; |
vtop[-2] = vtop[-3]; |
vtop[-3] = tmp; |
vswap(); |
/* stack: H1 H2 L1 L2 */ |
if (op == '*') { |
vpushv(vtop - 1); |
vpushv(vtop - 1); |
gen_op(TOK_UMULL); |
lexpand(); |
/* stack: H1 H2 L1 L2 ML MH */ |
for(i=0;i<4;i++) |
vrotb(6); |
/* stack: ML MH H1 H2 L1 L2 */ |
tmp = vtop[0]; |
vtop[0] = vtop[-2]; |
vtop[-2] = tmp; |
/* stack: ML MH H1 L2 H2 L1 */ |
gen_op('*'); |
vrotb(3); |
vrotb(3); |
gen_op('*'); |
/* stack: ML MH M1 M2 */ |
gen_op('+'); |
gen_op('+'); |
} else if (op == '+' || op == '-') { |
/* XXX: add non carry method too (for MIPS or alpha) */ |
if (op == '+') |
op1 = TOK_ADDC1; |
else |
op1 = TOK_SUBC1; |
gen_op(op1); |
/* stack: H1 H2 (L1 op L2) */ |
vrotb(3); |
vrotb(3); |
gen_op(op1 + 1); /* TOK_xxxC2 */ |
} else { |
gen_op(op); |
/* stack: H1 H2 (L1 op L2) */ |
vrotb(3); |
vrotb(3); |
/* stack: (L1 op L2) H1 H2 */ |
gen_op(op); |
/* stack: (L1 op L2) (H1 op H2) */ |
} |
/* stack: L H */ |
lbuild(t); |
break; |
case TOK_SAR: |
case TOK_SHR: |
case TOK_SHL: |
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
t = vtop[-1].type.t; |
vswap(); |
lexpand(); |
vrotb(3); |
/* stack: L H shift */ |
c = (int)vtop->c.i; |
/* constant: simpler */ |
/* NOTE: all comments are for SHL. the other cases are |
done by swaping words */ |
vpop(); |
if (op != TOK_SHL) |
vswap(); |
if (c >= 32) { |
/* stack: L H */ |
vpop(); |
if (c > 32) { |
vpushi(c - 32); |
gen_op(op); |
} |
if (op != TOK_SAR) { |
vpushi(0); |
} else { |
gv_dup(); |
vpushi(31); |
gen_op(TOK_SAR); |
} |
vswap(); |
} else { |
vswap(); |
gv_dup(); |
/* stack: H L L */ |
vpushi(c); |
gen_op(op); |
vswap(); |
vpushi(32 - c); |
if (op == TOK_SHL) |
gen_op(TOK_SHR); |
else |
gen_op(TOK_SHL); |
vrotb(3); |
/* stack: L L H */ |
vpushi(c); |
if (op == TOK_SHL) |
gen_op(TOK_SHL); |
else |
gen_op(TOK_SHR); |
gen_op('|'); |
} |
if (op != TOK_SHL) |
vswap(); |
lbuild(t); |
} else { |
/* XXX: should provide a faster fallback on x86 ? */ |
switch(op) { |
case TOK_SAR: |
func = TOK___sardi3; |
goto gen_func; |
case TOK_SHR: |
func = TOK___shrdi3; |
goto gen_func; |
case TOK_SHL: |
func = TOK___shldi3; |
goto gen_func; |
} |
} |
break; |
default: |
/* compare operations */ |
t = vtop->type.t; |
vswap(); |
lexpand(); |
vrotb(3); |
lexpand(); |
/* stack: L1 H1 L2 H2 */ |
tmp = vtop[-1]; |
vtop[-1] = vtop[-2]; |
vtop[-2] = tmp; |
/* stack: L1 L2 H1 H2 */ |
/* compare high */ |
op1 = op; |
/* when values are equal, we need to compare low words. since |
the jump is inverted, we invert the test too. */ |
if (op1 == TOK_LT) |
op1 = TOK_LE; |
else if (op1 == TOK_GT) |
op1 = TOK_GE; |
else if (op1 == TOK_ULT) |
op1 = TOK_ULE; |
else if (op1 == TOK_UGT) |
op1 = TOK_UGE; |
a = 0; |
b = 0; |
gen_op(op1); |
if (op1 != TOK_NE) { |
a = gtst(1, 0); |
} |
if (op != TOK_EQ) { |
/* generate non equal test */ |
/* XXX: NOT PORTABLE yet */ |
if (a == 0) { |
b = gtst(0, 0); |
} else { |
#if defined(TCC_TARGET_I386) |
b = psym(0x850f, 0); |
#elif defined(TCC_TARGET_ARM) |
b = ind; |
o(0x1A000000 | encbranch(ind, 0, 1)); |
#elif defined(TCC_TARGET_C67) |
error("not implemented"); |
#else |
case 64: break; |
case 32: target = "i386"; |
#error not supported |
#endif |
pstrcpy(child_path, sizeof child_path - 40, argv[0]); |
child_name = tcc_basename(child_path); |
strcpy(child_name, target); |
#ifdef TCC_TARGET_PE |
strcat(child_name, "-win32"); |
#elif defined TCC_TARGET_MEOS |
strcat(child_name, "-kos32"); |
} |
} |
/* compare low. Always unsigned */ |
op1 = op; |
if (op1 == TOK_LT) |
op1 = TOK_ULT; |
else if (op1 == TOK_LE) |
op1 = TOK_ULE; |
else if (op1 == TOK_GT) |
op1 = TOK_UGT; |
else if (op1 == TOK_GE) |
op1 = TOK_UGE; |
gen_op(op1); |
a = gtst(1, a); |
gsym(b); |
vseti(VT_JMPI, a); |
break; |
} |
} |
/* handle integer constant optimizations and various machine |
independent opt */ |
void gen_opic(int op) |
{ |
int fc, c1, c2, n; |
SValue *v1, *v2; |
v1 = vtop - 1; |
v2 = vtop; |
/* currently, we cannot do computations with forward symbols */ |
c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
if (c1 && c2) { |
fc = v2->c.i; |
switch(op) { |
case '+': v1->c.i += fc; break; |
case '-': v1->c.i -= fc; break; |
case '&': v1->c.i &= fc; break; |
case '^': v1->c.i ^= fc; break; |
case '|': v1->c.i |= fc; break; |
case '*': v1->c.i *= fc; break; |
case TOK_PDIV: |
case '/': |
case '%': |
case TOK_UDIV: |
case TOK_UMOD: |
/* if division by zero, generate explicit division */ |
if (fc == 0) { |
if (const_wanted) |
error("division by zero in constant"); |
goto general_case; |
} |
switch(op) { |
default: v1->c.i /= fc; break; |
case '%': v1->c.i %= fc; break; |
case TOK_UDIV: v1->c.i = (unsigned)v1->c.i / fc; break; |
case TOK_UMOD: v1->c.i = (unsigned)v1->c.i % fc; break; |
} |
break; |
case TOK_SHL: v1->c.i <<= fc; break; |
case TOK_SHR: v1->c.i = (unsigned)v1->c.i >> fc; break; |
case TOK_SAR: v1->c.i >>= fc; break; |
/* tests */ |
case TOK_ULT: v1->c.i = (unsigned)v1->c.i < (unsigned)fc; break; |
case TOK_UGE: v1->c.i = (unsigned)v1->c.i >= (unsigned)fc; break; |
case TOK_EQ: v1->c.i = v1->c.i == fc; break; |
case TOK_NE: v1->c.i = v1->c.i != fc; break; |
case TOK_ULE: v1->c.i = (unsigned)v1->c.i <= (unsigned)fc; break; |
case TOK_UGT: v1->c.i = (unsigned)v1->c.i > (unsigned)fc; break; |
case TOK_LT: v1->c.i = v1->c.i < fc; break; |
case TOK_GE: v1->c.i = v1->c.i >= fc; break; |
case TOK_LE: v1->c.i = v1->c.i <= fc; break; |
case TOK_GT: v1->c.i = v1->c.i > fc; break; |
/* logical */ |
case TOK_LAND: v1->c.i = v1->c.i && fc; break; |
case TOK_LOR: v1->c.i = v1->c.i || fc; break; |
default: |
goto general_case; |
} |
vtop--; |
} else { |
/* if commutative ops, put c2 as constant */ |
if (c1 && (op == '+' || op == '&' || op == '^' || |
op == '|' || op == '*')) { |
vswap(); |
swap(&c1, &c2); |
} |
fc = vtop->c.i; |
if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || |
op == TOK_PDIV) && |
fc == 1) || |
((op == '+' || op == '-' || op == '|' || op == '^' || |
op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && |
fc == 0) || |
(op == '&' && |
fc == -1))) { |
/* nothing to do */ |
vtop--; |
} else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { |
/* try to use shifts instead of muls or divs */ |
if (fc > 0 && (fc & (fc - 1)) == 0) { |
n = -1; |
while (fc) { |
fc >>= 1; |
n++; |
} |
vtop->c.i = n; |
if (op == '*') |
op = TOK_SHL; |
else if (op == TOK_PDIV) |
op = TOK_SAR; |
else |
op = TOK_SHR; |
} |
goto general_case; |
} else if (c2 && (op == '+' || op == '-') && |
(vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == |
(VT_CONST | VT_SYM)) { |
/* symbol + constant case */ |
if (op == '-') |
fc = -fc; |
vtop--; |
vtop->c.i += fc; |
} else { |
general_case: |
if (!nocode_wanted) { |
/* call low level op generator */ |
gen_opi(op); |
} else { |
vtop--; |
} |
} |
} |
} |
/* generate a floating point operation with constant propagation */ |
void gen_opif(int op) |
{ |
int c1, c2; |
SValue *v1, *v2; |
long double f1, f2; |
v1 = vtop - 1; |
v2 = vtop; |
/* currently, we cannot do computations with forward symbols */ |
c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
if (c1 && c2) { |
if (v1->type.t == VT_FLOAT) { |
f1 = v1->c.f; |
f2 = v2->c.f; |
} else if (v1->type.t == VT_DOUBLE) { |
f1 = v1->c.d; |
f2 = v2->c.d; |
} else { |
f1 = v1->c.ld; |
f2 = v2->c.ld; |
} |
/* NOTE: we only do constant propagation if finite number (not |
NaN or infinity) (ANSI spec) */ |
if (!ieee_finite(f1) || !ieee_finite(f2)) |
goto general_case; |
switch(op) { |
case '+': f1 += f2; break; |
case '-': f1 -= f2; break; |
case '*': f1 *= f2; break; |
case '/': |
if (f2 == 0.0) { |
if (const_wanted) |
error("division by zero in constant"); |
goto general_case; |
} |
f1 /= f2; |
break; |
/* XXX: also handles tests ? */ |
default: |
goto general_case; |
} |
/* XXX: overflow test ? */ |
if (v1->type.t == VT_FLOAT) { |
v1->c.f = f1; |
} else if (v1->type.t == VT_DOUBLE) { |
v1->c.d = f1; |
} else { |
v1->c.ld = f1; |
} |
vtop--; |
} else { |
general_case: |
if (!nocode_wanted) { |
gen_opf(op); |
} else { |
vtop--; |
} |
} |
} |
static int pointed_size(CType *type) |
{ |
int align; |
return type_size(pointed_type(type), &align); |
} |
static inline int is_null_pointer(SValue *p) |
{ |
if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
return 0; |
return ((p->type.t & VT_BTYPE) == VT_INT && p->c.i == 0) || |
((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0); |
} |
static inline int is_integer_btype(int bt) |
{ |
return (bt == VT_BYTE || bt == VT_SHORT || |
bt == VT_INT || bt == VT_LLONG); |
} |
/* check types for comparison or substraction of pointers */ |
static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) |
{ |
CType *type1, *type2, tmp_type1, tmp_type2; |
int bt1, bt2; |
/* null pointers are accepted for all comparisons as gcc */ |
if (is_null_pointer(p1) || is_null_pointer(p2)) |
return; |
type1 = &p1->type; |
type2 = &p2->type; |
bt1 = type1->t & VT_BTYPE; |
bt2 = type2->t & VT_BTYPE; |
/* accept comparison between pointer and integer with a warning */ |
if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { |
warning("comparison between pointer and integer"); |
return; |
} |
/* both must be pointers or implicit function pointers */ |
if (bt1 == VT_PTR) { |
type1 = pointed_type(type1); |
} else if (bt1 != VT_FUNC) |
goto invalid_operands; |
if (bt2 == VT_PTR) { |
type2 = pointed_type(type2); |
} else if (bt2 != VT_FUNC) { |
invalid_operands: |
error("invalid operands to binary %s", get_tok_str(op, NULL)); |
} |
if ((type1->t & VT_BTYPE) == VT_VOID || |
(type2->t & VT_BTYPE) == VT_VOID) |
return; |
tmp_type1 = *type1; |
tmp_type2 = *type2; |
tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
/* gcc-like error if '-' is used */ |
if (op == '-') |
goto invalid_operands; |
else |
warning("comparison of distinct pointer types lacks a cast"); |
} |
} |
/* generic gen_op: handles types problems */ |
void gen_op(int op) |
{ |
int u, t1, t2, bt1, bt2, t; |
CType type1; |
t1 = vtop[-1].type.t; |
t2 = vtop[0].type.t; |
bt1 = t1 & VT_BTYPE; |
bt2 = t2 & VT_BTYPE; |
if (bt1 == VT_PTR || bt2 == VT_PTR) { |
/* at least one operand is a pointer */ |
/* relationnal op: must be both pointers */ |
if (op >= TOK_ULT && op <= TOK_GT) { |
check_comparison_pointer_types(vtop - 1, vtop, op); |
/* pointers are handled are unsigned */ |
t = VT_INT | VT_UNSIGNED; |
goto std_op; |
} |
/* if both pointers, then it must be the '-' op */ |
if (bt1 == VT_PTR && bt2 == VT_PTR) { |
if (op != '-') |
error("cannot use pointers here"); |
check_comparison_pointer_types(vtop - 1, vtop, op); |
/* XXX: check that types are compatible */ |
u = pointed_size(&vtop[-1].type); |
gen_opic(op); |
/* set to integer type */ |
vtop->type.t = VT_INT; |
vpushi(u); |
gen_op(TOK_PDIV); |
} else { |
/* exactly one pointer : must be '+' or '-'. */ |
if (op != '-' && op != '+') |
error("cannot use pointers here"); |
/* Put pointer as first operand */ |
if (bt2 == VT_PTR) { |
vswap(); |
swap(&t1, &t2); |
} |
type1 = vtop[-1].type; |
/* XXX: cast to int ? (long long case) */ |
vpushi(pointed_size(&vtop[-1].type)); |
gen_op('*'); |
#ifdef CONFIG_TCC_BCHECK |
/* if evaluating constant expression, no code should be |
generated, so no bound check */ |
if (do_bounds_check && !const_wanted) { |
/* if bounded pointers, we generate a special code to |
test bounds */ |
if (op == '-') { |
vpushi(0); |
vswap(); |
gen_op('-'); |
} |
gen_bounded_ptr_add(); |
} else |
#endif |
strcat(child_name, "-tcc"); |
if (strcmp(argv[0], child_path)) { |
if (s->verbose > 0) |
printf("tcc: using '%s'\n", child_name), fflush(stdout); |
execvp(argv[0] = child_path, argv); |
{ |
gen_opic(op); |
} |
tcc_error("'%s' not found", child_name); |
case 0: /* ignore -march etc. */ |
/* put again type if gen_opic() swaped operands */ |
vtop->type = type1; |
} |
} else if (is_float(bt1) || is_float(bt2)) { |
/* compute bigger type and do implicit casts */ |
if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
t = VT_LDOUBLE; |
} else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
t = VT_DOUBLE; |
} else { |
t = VT_FLOAT; |
} |
/* floats can only be used for a few operations */ |
if (op != '+' && op != '-' && op != '*' && op != '/' && |
(op < TOK_ULT || op > TOK_GT)) |
error("invalid operands for binary operation"); |
goto std_op; |
} else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
/* cast to biggest op */ |
t = VT_LLONG; |
/* convert to unsigned if it does not fit in a long long */ |
if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
t |= VT_UNSIGNED; |
goto std_op; |
} else { |
/* integer operations */ |
t = VT_INT; |
/* convert to unsigned if it does not fit in an integer */ |
if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
t |= VT_UNSIGNED; |
std_op: |
/* XXX: currently, some unsigned operations are explicit, so |
we modify them here */ |
if (t & VT_UNSIGNED) { |
if (op == TOK_SAR) |
op = TOK_SHR; |
else if (op == '/') |
op = TOK_UDIV; |
else if (op == '%') |
op = TOK_UMOD; |
else if (op == TOK_LT) |
op = TOK_ULT; |
else if (op == TOK_GT) |
op = TOK_UGT; |
else if (op == TOK_LE) |
op = TOK_ULE; |
else if (op == TOK_GE) |
op = TOK_UGE; |
} |
vswap(); |
type1.t = t; |
gen_cast(&type1); |
vswap(); |
/* special case for shifts and long long: we keep the shift as |
an integer */ |
if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) |
type1.t = VT_INT; |
gen_cast(&type1); |
if (is_float(t)) |
gen_opif(op); |
else if ((t & VT_BTYPE) == VT_LLONG) |
gen_opl(op); |
else |
gen_opic(op); |
if (op >= TOK_ULT && op <= TOK_GT) { |
/* relationnal op: the result is an int */ |
vtop->type.t = VT_INT; |
} else { |
vtop->type.t = t; |
} |
} |
} |
/* generic itof for unsigned long long case */ |
void gen_cvt_itof1(int t) |
{ |
if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == |
(VT_LLONG | VT_UNSIGNED)) { |
if (t == VT_FLOAT) |
vpush_global_sym(&func_old_type, TOK___ulltof); |
else if (t == VT_DOUBLE) |
vpush_global_sym(&func_old_type, TOK___ulltod); |
else |
vpush_global_sym(&func_old_type, TOK___ulltold); |
vrott(2); |
gfunc_call(1); |
vpushi(0); |
vtop->r = REG_FRET; |
} else { |
gen_cvt_itof(t); |
} |
} |
/* generic ftoi for unsigned long long case */ |
void gen_cvt_ftoi1(int t) |
{ |
int st; |
if (t == (VT_LLONG | VT_UNSIGNED)) { |
/* not handled natively */ |
st = vtop->type.t & VT_BTYPE; |
if (st == VT_FLOAT) |
vpush_global_sym(&func_old_type, TOK___fixunssfdi); |
else if (st == VT_DOUBLE) |
vpush_global_sym(&func_old_type, TOK___fixunsdfdi); |
else |
vpush_global_sym(&func_old_type, TOK___fixunsxfdi); |
vrott(2); |
gfunc_call(1); |
vpushi(0); |
vtop->r = REG_IRET; |
vtop->r2 = REG_LRET; |
} else { |
gen_cvt_ftoi(t); |
} |
} |
/* force char or short cast */ |
void force_charshort_cast(int t) |
{ |
int bits, dbt; |
dbt = t & VT_BTYPE; |
/* XXX: add optimization if lvalue : just change type and offset */ |
if (dbt == VT_BYTE) |
bits = 8; |
else |
bits = 16; |
if (t & VT_UNSIGNED) { |
vpushi((1 << bits) - 1); |
gen_op('&'); |
} else { |
bits = 32 - bits; |
vpushi(bits); |
gen_op(TOK_SHL); |
vpushi(bits); |
gen_op(TOK_SAR); |
} |
} |
/* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ |
static void gen_cast(CType *type) |
{ |
int sbt, dbt, sf, df, c; |
/* special delayed cast for char/short */ |
/* XXX: in some cases (multiple cascaded casts), it may still |
be incorrect */ |
if (vtop->r & VT_MUSTCAST) { |
vtop->r &= ~VT_MUSTCAST; |
force_charshort_cast(vtop->type.t); |
} |
/* bitfields first get cast to ints */ |
if (vtop->type.t & VT_BITFIELD) { |
gv(RC_INT); |
} |
dbt = type->t & (VT_BTYPE | VT_UNSIGNED); |
sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); |
if (sbt != dbt && !nocode_wanted) { |
sf = is_float(sbt); |
df = is_float(dbt); |
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
if (sf && df) { |
/* convert from fp to fp */ |
if (c) { |
/* constant case: we can do it now */ |
/* XXX: in ISOC, cannot do it if error in convert */ |
if (dbt == VT_FLOAT && sbt == VT_DOUBLE) |
vtop->c.f = (float)vtop->c.d; |
else if (dbt == VT_FLOAT && sbt == VT_LDOUBLE) |
vtop->c.f = (float)vtop->c.ld; |
else if (dbt == VT_DOUBLE && sbt == VT_FLOAT) |
vtop->c.d = (double)vtop->c.f; |
else if (dbt == VT_DOUBLE && sbt == VT_LDOUBLE) |
vtop->c.d = (double)vtop->c.ld; |
else if (dbt == VT_LDOUBLE && sbt == VT_FLOAT) |
vtop->c.ld = (long double)vtop->c.f; |
else if (dbt == VT_LDOUBLE && sbt == VT_DOUBLE) |
vtop->c.ld = (long double)vtop->c.d; |
} else { |
/* non constant case: generate code */ |
gen_cvt_ftof(dbt); |
} |
} else if (df) { |
/* convert int to fp */ |
if (c) { |
switch(sbt) { |
case VT_LLONG | VT_UNSIGNED: |
case VT_LLONG: |
/* XXX: add const cases for long long */ |
goto do_itof; |
case VT_INT | VT_UNSIGNED: |
switch(dbt) { |
case VT_FLOAT: vtop->c.f = (float)vtop->c.ui; break; |
case VT_DOUBLE: vtop->c.d = (double)vtop->c.ui; break; |
case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.ui; break; |
} |
break; |
default: |
tcc_warning("unsupported option \"-m%s\"", optarg); |
switch(dbt) { |
case VT_FLOAT: vtop->c.f = (float)vtop->c.i; break; |
case VT_DOUBLE: vtop->c.d = (double)vtop->c.i; break; |
case VT_LDOUBLE: vtop->c.ld = (long double)vtop->c.i; break; |
} |
break; |
} |
} else { |
do_itof: |
#if !defined(TCC_TARGET_ARM) |
gen_cvt_itof1(dbt); |
#else |
#define exec_other_tcc(s, argv, optarg) |
gen_cvt_itof(dbt); |
#endif |
} |
} else if (sf) { |
/* convert fp to int */ |
/* we handle char/short/etc... with generic code */ |
if (dbt != (VT_INT | VT_UNSIGNED) && |
dbt != (VT_LLONG | VT_UNSIGNED) && |
dbt != VT_LLONG) |
dbt = VT_INT; |
if (c) { |
switch(dbt) { |
case VT_LLONG | VT_UNSIGNED: |
case VT_LLONG: |
/* XXX: add const cases for long long */ |
goto do_ftoi; |
case VT_INT | VT_UNSIGNED: |
switch(sbt) { |
case VT_FLOAT: vtop->c.ui = (unsigned int)vtop->c.d; break; |
case VT_DOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
case VT_LDOUBLE: vtop->c.ui = (unsigned int)vtop->c.d; break; |
} |
break; |
default: |
/* int case */ |
switch(sbt) { |
case VT_FLOAT: vtop->c.i = (int)vtop->c.d; break; |
case VT_DOUBLE: vtop->c.i = (int)vtop->c.d; break; |
case VT_LDOUBLE: vtop->c.i = (int)vtop->c.d; break; |
} |
break; |
} |
} else { |
do_ftoi: |
gen_cvt_ftoi1(dbt); |
} |
if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { |
/* additional cast for char/short/bool... */ |
vtop->type.t = dbt; |
gen_cast(type); |
} |
} else if ((dbt & VT_BTYPE) == VT_LLONG) { |
if ((sbt & VT_BTYPE) != VT_LLONG) { |
/* scalar to long long */ |
if (c) { |
if (sbt == (VT_INT | VT_UNSIGNED)) |
vtop->c.ll = vtop->c.ui; |
else |
vtop->c.ll = vtop->c.i; |
} else { |
/* machine independent conversion */ |
gv(RC_INT); |
/* generate high word */ |
if (sbt == (VT_INT | VT_UNSIGNED)) { |
vpushi(0); |
gv(RC_INT); |
} else { |
gv_dup(); |
vpushi(31); |
gen_op(TOK_SAR); |
} |
/* patch second register */ |
vtop[-1].r2 = vtop->r; |
vpop(); |
} |
} |
} else if (dbt == VT_BOOL) { |
/* scalar to bool */ |
vpushi(0); |
gen_op(TOK_NE); |
} else if ((dbt & VT_BTYPE) == VT_BYTE || |
(dbt & VT_BTYPE) == VT_SHORT) { |
force_charshort_cast(dbt); |
} else if ((dbt & VT_BTYPE) == VT_INT) { |
/* scalar to int */ |
if (sbt == VT_LLONG) { |
/* from long long: just take low order word */ |
lexpand(); |
vpop(); |
} |
/* if lvalue and single word type, nothing to do because |
the lvalue already contains the real type size (see |
VT_LVAL_xxx constants) */ |
} |
} |
vtop->type = *type; |
} |
static void gen_makedeps(TCCState *s, const char *target, const char *filename) |
/* return type size. Put alignment at 'a' */ |
static int type_size(CType *type, int *a) |
{ |
FILE *depout; |
char buf[1024], *ext; |
Sym *s; |
int bt; |
int size; |
bt = type->t & VT_BTYPE; |
if (bt == VT_STRUCT) { |
/* struct/union */ |
s = type->ref; |
*a = s->r; |
return s->c; |
} else if (bt == VT_PTR) { |
if (type->t & VT_ARRAY) { |
s = type->ref; |
size=type_size(&s->type, a) * s->c; |
return size;//type_size(&s->type, a) * s->c; |
} else { |
*a = PTR_SIZE; |
return PTR_SIZE; |
} |
} else if (bt == VT_LDOUBLE) { |
*a = LDOUBLE_ALIGN; |
return LDOUBLE_SIZE; |
} else if (bt == VT_DOUBLE || bt == VT_LLONG) { |
#ifdef TCC_TARGET_I386 |
*a = 4; |
#else |
*a = 8; |
#endif |
return 8; |
} else if (bt == VT_INT || bt == VT_ENUM || bt == VT_FLOAT) { |
*a = 4; |
return 4; |
} else if (bt == VT_SHORT) { |
*a = 2; |
return 2; |
} else { |
/* char, void, function, _Bool */ |
*a = 1; |
return 1; |
} |
} |
/* return the pointed type of t */ |
static inline CType *pointed_type(CType *type) |
{ |
return &type->ref->type; |
} |
/* modify type so that its it is a pointer to type. */ |
static void mk_pointer(CType *type) |
{ |
Sym *s; |
s = sym_push(SYM_FIELD, type, 0, -1); |
type->t = VT_PTR | (type->t & ~VT_TYPE); |
type->ref = s; |
} |
/* compare function types. OLD functions match any new functions */ |
static int is_compatible_func(CType *type1, CType *type2) |
{ |
Sym *s1, *s2; |
s1 = type1->ref; |
s2 = type2->ref; |
if (!is_compatible_types(&s1->type, &s2->type)) |
return 0; |
/* check func_call */ |
if (s1->r != s2->r) |
return 0; |
/* XXX: not complete */ |
if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) |
return 1; |
if (s1->c != s2->c) |
return 0; |
while (s1 != NULL) { |
if (s2 == NULL) |
return 0; |
if (!is_compatible_types(&s1->type, &s2->type)) |
return 0; |
s1 = s1->next; |
s2 = s2->next; |
} |
if (s2) |
return 0; |
return 1; |
} |
/* return true if type1 and type2 are exactly the same (including |
qualifiers). |
- enums are not checked as gcc __builtin_types_compatible_p () |
*/ |
static int is_compatible_types(CType *type1, CType *type2) |
{ |
int bt1, t1, t2; |
t1 = type1->t & VT_TYPE; |
t2 = type2->t & VT_TYPE; |
/* XXX: bitfields ? */ |
if (t1 != t2) |
return 0; |
/* test more complicated cases */ |
bt1 = t1 & VT_BTYPE; |
if (bt1 == VT_PTR) { |
type1 = pointed_type(type1); |
type2 = pointed_type(type2); |
return is_compatible_types(type1, type2); |
} else if (bt1 == VT_STRUCT) { |
return (type1->ref == type2->ref); |
} else if (bt1 == VT_FUNC) { |
return is_compatible_func(type1, type2); |
} else { |
return 1; |
} |
} |
/* print a type. If 'varstr' is not NULL, then the variable is also |
printed in the type */ |
/* XXX: union */ |
/* XXX: add array and function pointers */ |
void type_to_str(char *buf, int buf_size, |
CType *type, const char *varstr) |
{ |
int bt, v, t; |
Sym *s, *sa; |
char buf1[256]; |
const char *tstr; |
t = type->t & VT_TYPE; |
bt = t & VT_BTYPE; |
buf[0] = '\0'; |
if (t & VT_CONSTANT) |
pstrcat(buf, buf_size, "const "); |
if (t & VT_VOLATILE) |
pstrcat(buf, buf_size, "volatile "); |
if (t & VT_UNSIGNED) |
pstrcat(buf, buf_size, "unsigned "); |
switch(bt) { |
case VT_VOID: |
tstr = "void"; |
goto add_tstr; |
case VT_BOOL: |
tstr = "_Bool"; |
goto add_tstr; |
case VT_BYTE: |
tstr = "char"; |
goto add_tstr; |
case VT_SHORT: |
tstr = "short"; |
goto add_tstr; |
case VT_INT: |
tstr = "int"; |
goto add_tstr; |
case VT_LONG: |
tstr = "long"; |
goto add_tstr; |
case VT_LLONG: |
tstr = "long long"; |
goto add_tstr; |
case VT_FLOAT: |
tstr = "float"; |
goto add_tstr; |
case VT_DOUBLE: |
tstr = "double"; |
goto add_tstr; |
case VT_LDOUBLE: |
tstr = "long double"; |
add_tstr: |
pstrcat(buf, buf_size, tstr); |
break; |
case VT_ENUM: |
case VT_STRUCT: |
if (bt == VT_STRUCT) |
tstr = "struct "; |
else |
tstr = "enum "; |
pstrcat(buf, buf_size, tstr); |
v = type->ref->v & ~SYM_STRUCT; |
if (v >= SYM_FIRST_ANOM) |
pstrcat(buf, buf_size, "<anonymous>"); |
else |
pstrcat(buf, buf_size, get_tok_str(v, NULL)); |
break; |
case VT_FUNC: |
s = type->ref; |
type_to_str(buf, buf_size, &s->type, varstr); |
pstrcat(buf, buf_size, "("); |
sa = s->next; |
while (sa != NULL) { |
type_to_str(buf1, sizeof(buf1), &sa->type, NULL); |
pstrcat(buf, buf_size, buf1); |
sa = sa->next; |
if (sa) |
pstrcat(buf, buf_size, ", "); |
} |
pstrcat(buf, buf_size, ")"); |
goto no_var; |
case VT_PTR: |
s = type->ref; |
pstrcpy(buf1, sizeof(buf1), "*"); |
if (varstr) |
pstrcat(buf1, sizeof(buf1), varstr); |
type_to_str(buf, buf_size, &s->type, buf1); |
goto no_var; |
} |
if (varstr) { |
pstrcat(buf, buf_size, " "); |
pstrcat(buf, buf_size, varstr); |
} |
no_var: ; |
} |
/* verify type compatibility to store vtop in 'dt' type, and generate |
casts if needed. */ |
static void gen_assign_cast(CType *dt) |
{ |
CType *st, *type1, *type2, tmp_type1, tmp_type2; |
char buf1[256], buf2[256]; |
int dbt, sbt; |
st = &vtop->type; /* source type */ |
dbt = dt->t & VT_BTYPE; |
sbt = st->t & VT_BTYPE; |
if (dt->t & VT_CONSTANT) |
warning("assignment of read-only location"); |
switch(dbt) { |
case VT_PTR: |
/* special cases for pointers */ |
/* '0' can also be a pointer */ |
if (is_null_pointer(vtop)) |
goto type_ok; |
/* accept implicit pointer to integer cast with warning */ |
if (is_integer_btype(sbt)) { |
warning("assignment makes pointer from integer without a cast"); |
goto type_ok; |
} |
type1 = pointed_type(dt); |
/* a function is implicitely a function pointer */ |
if (sbt == VT_FUNC) { |
if ((type1->t & VT_BTYPE) != VT_VOID && |
!is_compatible_types(pointed_type(dt), st)) |
goto error; |
else |
goto type_ok; |
} |
if (sbt != VT_PTR) |
goto error; |
type2 = pointed_type(st); |
if ((type1->t & VT_BTYPE) == VT_VOID || |
(type2->t & VT_BTYPE) == VT_VOID) { |
/* void * can match anything */ |
} else { |
/* exact type match, except for unsigned */ |
tmp_type1 = *type1; |
tmp_type2 = *type2; |
tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
if (!is_compatible_types(&tmp_type1, &tmp_type2)) |
goto error; |
} |
/* check const and volatile */ |
if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) || |
(!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE))) |
warning("assignment discards qualifiers from pointer target type"); |
break; |
case VT_BYTE: |
case VT_SHORT: |
case VT_INT: |
case VT_LLONG: |
if (sbt == VT_PTR || sbt == VT_FUNC) { |
warning("assignment makes integer from pointer without a cast"); |
} |
/* XXX: more tests */ |
break; |
case VT_STRUCT: |
tmp_type1 = *dt; |
tmp_type2 = *st; |
tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
error: |
type_to_str(buf1, sizeof(buf1), st, NULL); |
type_to_str(buf2, sizeof(buf2), dt, NULL); |
error("cannot cast '%s' to '%s'", buf1, buf2); |
} |
break; |
} |
type_ok: |
gen_cast(dt); |
} |
/* store vtop in lvalue pushed on stack */ |
void vstore(void) |
{ |
int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; |
ft = vtop[-1].type.t; |
sbt = vtop->type.t & VT_BTYPE; |
dbt = ft & VT_BTYPE; |
if (((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || |
(sbt == VT_INT && dbt == VT_SHORT)) { |
/* optimize char/short casts */ |
delayed_cast = VT_MUSTCAST; |
vtop->type.t = ft & VT_TYPE; |
/* XXX: factorize */ |
if (ft & VT_CONSTANT) |
warning("assignment of read-only location"); |
} else { |
delayed_cast = 0; |
if (!(ft & VT_BITFIELD)) |
gen_assign_cast(&vtop[-1].type); |
} |
if (sbt == VT_STRUCT) { |
/* if structure, only generate pointer */ |
/* structure assignment : generate memcpy */ |
/* XXX: optimize if small size */ |
if (!nocode_wanted) { |
size = type_size(&vtop->type, &align); |
vpush_global_sym(&func_old_type, TOK_memcpy); |
/* destination */ |
vpushv(vtop - 2); |
vtop->type.t = VT_INT; |
gaddrof(); |
/* source */ |
vpushv(vtop - 2); |
vtop->type.t = VT_INT; |
gaddrof(); |
/* type size */ |
vpushi(size); |
gfunc_call(3); |
vswap(); |
vpop(); |
} else { |
vswap(); |
vpop(); |
} |
/* leave source on stack */ |
} else if (ft & VT_BITFIELD) { |
/* bitfield store handling */ |
bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f; |
bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
/* remove bit field info to avoid loops */ |
vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); |
/* duplicate destination */ |
vdup(); |
vtop[-1] = vtop[-2]; |
/* mask and shift source */ |
vpushi((1 << bit_size) - 1); |
gen_op('&'); |
vpushi(bit_pos); |
gen_op(TOK_SHL); |
/* load destination, mask and or with source */ |
vswap(); |
vpushi(~(((1 << bit_size) - 1) << bit_pos)); |
gen_op('&'); |
gen_op('|'); |
/* store result */ |
vstore(); |
} else { |
#ifdef CONFIG_TCC_BCHECK |
/* bound check case */ |
if (vtop[-1].r & VT_MUSTBOUND) { |
vswap(); |
gbound(); |
vswap(); |
} |
#endif |
if (!nocode_wanted) { |
rc = RC_INT; |
if (is_float(ft)) |
rc = RC_FLOAT; |
r = gv(rc); /* generate value */ |
/* if lvalue was saved on stack, must read it */ |
if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { |
SValue sv; |
t = get_reg(RC_INT); |
sv.type.t = VT_INT; |
sv.r = VT_LOCAL | VT_LVAL; |
sv.c.ul = vtop[-1].c.ul; |
load(t, &sv); |
vtop[-1].r = t | VT_LVAL; |
} |
store(r, vtop - 1); |
/* two word case handling : store second register at word + 4 */ |
if ((ft & VT_BTYPE) == VT_LLONG) { |
vswap(); |
/* convert to int to increment easily */ |
vtop->type.t = VT_INT; |
gaddrof(); |
vpushi(4); |
gen_op('+'); |
vtop->r |= VT_LVAL; |
vswap(); |
/* XXX: it works because r2 is spilled last ! */ |
store(vtop->r2, vtop - 1); |
} |
} |
vswap(); |
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
vtop->r |= delayed_cast; |
} |
} |
/* post defines POST/PRE add. c is the token ++ or -- */ |
void inc(int post, int c) |
{ |
test_lvalue(); |
vdup(); /* save lvalue */ |
if (post) { |
gv_dup(); /* duplicate value */ |
vrotb(3); |
vrotb(3); |
} |
/* add constant */ |
vpushi(c - TOK_MID); |
gen_op('+'); |
vstore(); /* store value */ |
if (post) |
vpop(); /* if post op, return saved value */ |
} |
/* Parse GNUC __attribute__ extension. Currently, the following |
extensions are recognized: |
- aligned(n) : set data/function alignment. |
- packed : force data alignment to 1 |
- section(x) : generate data/code in this section. |
- unused : currently ignored, but may be used someday. |
- regparm(n) : pass function parameters in registers (i386 only) |
*/ |
static void parse_attribute(AttributeDef *ad) |
{ |
int t, n; |
while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { |
next(); |
skip('('); |
skip('('); |
while (tok != ')') { |
if (tok < TOK_IDENT) |
expect("attribute name"); |
t = tok; |
next(); |
switch(t) { |
case TOK_SECTION1: |
case TOK_SECTION2: |
skip('('); |
if (tok != TOK_STR) |
expect("section name"); |
ad->section = find_section(tcc_state, (char *)tokc.cstr->data); |
next(); |
skip(')'); |
break; |
case TOK_ALIGNED1: |
case TOK_ALIGNED2: |
if (tok == '(') { |
next(); |
n = expr_const(); |
if (n <= 0 || (n & (n - 1)) != 0) |
error("alignment must be a positive power of two"); |
skip(')'); |
} else { |
n = MAX_ALIGN; |
} |
ad->aligned = n; |
break; |
case TOK_PACKED1: |
case TOK_PACKED2: |
ad->packed = 1; |
break; |
case TOK_UNUSED1: |
case TOK_UNUSED2: |
/* currently, no need to handle it because tcc does not |
track unused objects */ |
break; |
case TOK_NORETURN1: |
case TOK_NORETURN2: |
/* currently, no need to handle it because tcc does not |
track unused objects */ |
break; |
case TOK_CDECL1: |
case TOK_CDECL2: |
case TOK_CDECL3: |
ad->func_call = FUNC_CDECL; |
break; |
case TOK_STDCALL1: |
case TOK_STDCALL2: |
case TOK_STDCALL3: |
ad->func_call = FUNC_STDCALL; |
break; |
#ifdef TCC_TARGET_I386 |
case TOK_REGPARM1: |
case TOK_REGPARM2: |
skip('('); |
n = expr_const(); |
if (n > 3) |
n = 3; |
else if (n < 0) |
n = 0; |
if (n > 0) |
ad->func_call = FUNC_FASTCALL1 + n - 1; |
skip(')'); |
break; |
#endif |
case TOK_DLLEXPORT: |
ad->dllexport = 1; |
break; |
default: |
if (tcc_state->warn_unsupported) |
warning("'%s' attribute ignored", get_tok_str(t, NULL)); |
/* skip parameters */ |
/* XXX: skip parenthesis too */ |
if (tok == '(') { |
next(); |
while (tok != ')' && tok != -1) |
next(); |
next(); |
} |
break; |
} |
if (tok != ',') |
break; |
next(); |
} |
skip(')'); |
skip(')'); |
} |
} |
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ |
static void struct_decl(CType *type, int u) |
{ |
int a, v, size, align, maxalign, c, offset; |
int bit_size, bit_pos, bsize, bt, lbit_pos; |
Sym *s, *ss, **ps; |
AttributeDef ad; |
CType type1, btype; |
a = tok; /* save decl type */ |
next(); |
if (tok != '{') { |
v = tok; |
next(); |
/* struct already defined ? return it */ |
if (v < TOK_IDENT) |
expect("struct/union/enum name"); |
s = struct_find(v); |
if (s) { |
if (s->type.t != a) |
error("invalid type"); |
goto do_decl; |
} |
} else { |
v = anon_sym++; |
} |
type1.t = a; |
/* we put an undefined size for struct/union */ |
s = sym_push(v | SYM_STRUCT, &type1, 0, -1); |
s->r = 0; /* default alignment is zero as gcc */ |
/* put struct/union/enum name in type */ |
do_decl: |
type->t = u; |
type->ref = s; |
if (tok == '{') { |
next(); |
if (s->c != -1) |
error("struct/union/enum already defined"); |
/* cannot be empty */ |
c = 0; |
/* non empty enums are not allowed */ |
if (a == TOK_ENUM) { |
for(;;) { |
v = tok; |
if (v < TOK_UIDENT) |
expect("identifier"); |
next(); |
if (tok == '=') { |
next(); |
c = expr_const(); |
} |
/* enum symbols have static storage */ |
ss = sym_push(v, &int_type, VT_CONST, c); |
ss->type.t |= VT_STATIC; |
if (tok != ',') |
break; |
next(); |
c++; |
/* NOTE: we accept a trailing comma */ |
if (tok == '}') |
break; |
} |
skip('}'); |
} else { |
maxalign = 1; |
ps = &s->next; |
bit_pos = 0; |
offset = 0; |
while (tok != '}') { |
parse_btype(&btype, &ad); |
while (1) { |
bit_size = -1; |
v = 0; |
type1 = btype; |
if (tok != ':') { |
type_decl(&type1, &ad, &v, TYPE_DIRECT); |
if ((type1.t & VT_BTYPE) == VT_FUNC || |
(type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE))) |
error("invalid type for '%s'", |
get_tok_str(v, NULL)); |
} |
if (tok == ':') { |
next(); |
bit_size = expr_const(); |
/* XXX: handle v = 0 case for messages */ |
if (bit_size < 0) |
error("negative width in bit-field '%s'", |
get_tok_str(v, NULL)); |
if (v && bit_size == 0) |
error("zero width for bit-field '%s'", |
get_tok_str(v, NULL)); |
} |
size = type_size(&type1, &align); |
if (ad.aligned) { |
if (align < ad.aligned) |
align = ad.aligned; |
} else if (ad.packed) { |
align = 1; |
} else if (*tcc_state->pack_stack_ptr) { |
if (align > *tcc_state->pack_stack_ptr) |
align = *tcc_state->pack_stack_ptr; |
} |
lbit_pos = 0; |
if (bit_size >= 0) { |
bt = type1.t & VT_BTYPE; |
if (bt != VT_INT && |
bt != VT_BYTE && |
bt != VT_SHORT && |
bt != VT_BOOL && |
bt != VT_ENUM) |
error("bitfields must have scalar type"); |
bsize = size * 8; |
if (bit_size > bsize) { |
error("width of '%s' exceeds its type", |
get_tok_str(v, NULL)); |
} else if (bit_size == bsize) { |
/* no need for bit fields */ |
bit_pos = 0; |
} else if (bit_size == 0) { |
/* XXX: what to do if only padding in a |
structure ? */ |
/* zero size: means to pad */ |
if (bit_pos > 0) |
bit_pos = bsize; |
} else { |
/* we do not have enough room ? */ |
if ((bit_pos + bit_size) > bsize) |
bit_pos = 0; |
lbit_pos = bit_pos; |
/* XXX: handle LSB first */ |
type1.t |= VT_BITFIELD | |
(bit_pos << VT_STRUCT_SHIFT) | |
(bit_size << (VT_STRUCT_SHIFT + 6)); |
bit_pos += bit_size; |
} |
} else { |
bit_pos = 0; |
} |
if (v) { |
/* add new memory data only if starting |
bit field */ |
if (lbit_pos == 0) { |
if (a == TOK_STRUCT) { |
//17.09.2007 |
//c = (c + align - 1) & -align; |
offset = c; |
//c += size; |
if (size<=4) {c=c+size;} |
else |
{c=c+align;} |
} else { |
offset = 0; |
if (size > c) |
c = size; |
} |
if (align > maxalign) |
maxalign = align; |
} |
#if 0 |
printf("add field %s offset=%d", |
get_tok_str(v, NULL), offset); |
if (type1.t & VT_BITFIELD) { |
printf(" pos=%d size=%d", |
(type1.t >> VT_STRUCT_SHIFT) & 0x3f, |
(type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); |
} |
printf("\n"); |
#endif |
ss = sym_push(v | SYM_FIELD, &type1, 0, offset); |
*ps = ss; |
ps = &ss->next; |
} |
if (tok == ';' || tok == TOK_EOF) |
break; |
skip(','); |
} |
skip(';'); |
} |
skip('}'); |
/* store size and alignment */ |
s->c = (c + maxalign - 1) & -maxalign; |
s->r = maxalign; |
} |
} |
} |
/* return 0 if no type declaration. otherwise, return the basic type |
and skip it. |
*/ |
static int parse_btype(CType *type, AttributeDef *ad) |
{ |
int t, u, type_found, typespec_found; |
Sym *s; |
CType type1; |
memset(ad, 0, sizeof(AttributeDef)); |
type_found = 0; |
typespec_found = 0; |
t = 0; |
while(1) { |
switch(tok) { |
case TOK_EXTENSION: |
/* currently, we really ignore extension */ |
next(); |
continue; |
/* basic types */ |
case TOK_CHAR: |
u = VT_BYTE; |
basic_type: |
next(); |
basic_type1: |
if ((t & VT_BTYPE) != 0) |
error("too many basic types"); |
t |= u; |
typespec_found = 1; |
break; |
case TOK_VOID: |
u = VT_VOID; |
goto basic_type; |
case TOK_SHORT: |
u = VT_SHORT; |
goto basic_type; |
case TOK_INT: |
next(); |
typespec_found = 1; |
break; |
case TOK_LONG: |
next(); |
if ((t & VT_BTYPE) == VT_DOUBLE) { |
t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
} else if ((t & VT_BTYPE) == VT_LONG) { |
t = (t & ~VT_BTYPE) | VT_LLONG; |
} else { |
u = VT_LONG; |
goto basic_type1; |
} |
break; |
case TOK_BOOL: |
u = VT_BOOL; |
goto basic_type; |
case TOK_FLOAT: |
u = VT_FLOAT; |
goto basic_type; |
case TOK_DOUBLE: |
next(); |
if ((t & VT_BTYPE) == VT_LONG) { |
t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
} else { |
u = VT_DOUBLE; |
goto basic_type1; |
} |
break; |
case TOK_ENUM: |
struct_decl(&type1, VT_ENUM); |
basic_type2: |
u = type1.t; |
type->ref = type1.ref; |
goto basic_type1; |
case TOK_STRUCT: |
case TOK_UNION: |
struct_decl(&type1, VT_STRUCT); |
goto basic_type2; |
/* type modifiers */ |
case TOK_CONST1: |
case TOK_CONST2: |
case TOK_CONST3: |
t |= VT_CONSTANT; |
next(); |
break; |
case TOK_VOLATILE1: |
case TOK_VOLATILE2: |
case TOK_VOLATILE3: |
t |= VT_VOLATILE; |
next(); |
break; |
case TOK_SIGNED1: |
case TOK_SIGNED2: |
case TOK_SIGNED3: |
typespec_found = 1; |
t |= VT_SIGNED; |
next(); |
break; |
case TOK_REGISTER: |
case TOK_AUTO: |
case TOK_RESTRICT1: |
case TOK_RESTRICT2: |
case TOK_RESTRICT3: |
next(); |
break; |
case TOK_UNSIGNED: |
t |= VT_UNSIGNED; |
next(); |
typespec_found = 1; |
break; |
/* storage */ |
case TOK_EXTERN: |
t |= VT_EXTERN; |
next(); |
break; |
case TOK_STATIC: |
t |= VT_STATIC; |
next(); |
break; |
case TOK_TYPEDEF: |
t |= VT_TYPEDEF; |
next(); |
break; |
case TOK_INLINE1: |
case TOK_INLINE2: |
case TOK_INLINE3: |
t |= VT_INLINE; |
next(); |
break; |
/* GNUC attribute */ |
case TOK_ATTRIBUTE1: |
case TOK_ATTRIBUTE2: |
parse_attribute(ad); |
break; |
/* GNUC typeof */ |
case TOK_TYPEOF1: |
case TOK_TYPEOF2: |
case TOK_TYPEOF3: |
next(); |
parse_expr_type(&type1); |
goto basic_type2; |
default: |
if (typespec_found) |
goto the_end; |
s = sym_find(tok); |
if (!s || !(s->type.t & VT_TYPEDEF)) |
goto the_end; |
t |= (s->type.t & ~VT_TYPEDEF); |
type->ref = s->type.ref; |
next(); |
break; |
} |
type_found = 1; |
} |
the_end: |
if ((t & (VT_SIGNED|VT_UNSIGNED)) == (VT_SIGNED|VT_UNSIGNED)) |
error("signed and unsigned modifier"); |
if (tcc_state->char_is_unsigned) { |
if ((t & (VT_SIGNED|VT_UNSIGNED|VT_BTYPE)) == VT_BYTE) |
t |= VT_UNSIGNED; |
} |
t &= ~VT_SIGNED; |
/* long is never used as type */ |
if ((t & VT_BTYPE) == VT_LONG) |
t = (t & ~VT_BTYPE) | VT_INT; |
type->t = t; |
return type_found; |
} |
/* convert a function parameter type (array to pointer and function to |
function pointer) */ |
static inline void convert_parameter_type(CType *pt) |
{ |
/* remove const and volatile qualifiers (XXX: const could be used |
to indicate a const function parameter */ |
pt->t &= ~(VT_CONSTANT | VT_VOLATILE); |
/* array must be transformed to pointer according to ANSI C */ |
pt->t &= ~VT_ARRAY; |
if ((pt->t & VT_BTYPE) == VT_FUNC) { |
mk_pointer(pt); |
} |
} |
static void post_type(CType *type, AttributeDef *ad) |
{ |
int n, l, t1; |
Sym **plast, *s, *first; |
AttributeDef ad1; |
CType pt; |
if (tok == '(') { |
/* function declaration */ |
next(); |
l = 0; |
first = NULL; |
plast = &first; |
while (tok != ')') { |
/* read param name and compute offset */ |
if (l != FUNC_OLD) { |
if (!parse_btype(&pt, &ad1)) { |
if (l) { |
error("invalid type"); |
} else { |
l = FUNC_OLD; |
goto old_proto; |
} |
} |
l = FUNC_NEW; |
if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') |
break; |
type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); |
if ((pt.t & VT_BTYPE) == VT_VOID) |
error("parameter declared as void"); |
} else { |
old_proto: |
n = tok; |
pt.t = VT_INT; |
next(); |
} |
convert_parameter_type(&pt); |
s = sym_push(n | SYM_FIELD, &pt, 0, 0); |
*plast = s; |
plast = &s->next; |
if (tok == ',') { |
next(); |
if (l == FUNC_NEW && tok == TOK_DOTS) { |
l = FUNC_ELLIPSIS; |
next(); |
break; |
} |
} |
} |
/* if no parameters, then old type prototype */ |
if (l == 0) |
l = FUNC_OLD; |
skip(')'); |
t1 = type->t & VT_STORAGE; |
/* NOTE: const is ignored in returned type as it has a special |
meaning in gcc / C++ */ |
type->t &= ~(VT_STORAGE | VT_CONSTANT); |
post_type(type, ad); |
/* we push a anonymous symbol which will contain the function prototype */ |
s = sym_push(SYM_FIELD, type, ad->func_call, l); |
s->next = first; |
type->t = t1 | VT_FUNC; |
type->ref = s; |
} else if (tok == '[') { |
/* array definition */ |
next(); |
n = -1; |
if (tok != ']') { |
n = expr_const(); |
if (n < 0) |
error("invalid array size"); |
} |
skip(']'); |
/* parse next post type */ |
t1 = type->t & VT_STORAGE; |
type->t &= ~VT_STORAGE; |
post_type(type, ad); |
/* we push a anonymous symbol which will contain the array |
element type */ |
s = sym_push(SYM_FIELD, type, 0, n); |
type->t = t1 | VT_ARRAY | VT_PTR; |
type->ref = s; |
} |
} |
/* Parse a type declaration (except basic type), and return the type |
in 'type'. 'td' is a bitmask indicating which kind of type decl is |
expected. 'type' should contain the basic type. 'ad' is the |
attribute definition of the basic type. It can be modified by |
type_decl(). |
*/ |
static void type_decl(CType *type, AttributeDef *ad, int *v, int td) |
{ |
Sym *s; |
CType type1, *type2; |
int qualifiers; |
while (tok == '*') { |
qualifiers = 0; |
redo: |
next(); |
switch(tok) { |
case TOK_CONST1: |
case TOK_CONST2: |
case TOK_CONST3: |
qualifiers |= VT_CONSTANT; |
goto redo; |
case TOK_VOLATILE1: |
case TOK_VOLATILE2: |
case TOK_VOLATILE3: |
qualifiers |= VT_VOLATILE; |
goto redo; |
case TOK_RESTRICT1: |
case TOK_RESTRICT2: |
case TOK_RESTRICT3: |
goto redo; |
} |
mk_pointer(type); |
type->t |= qualifiers; |
} |
/* XXX: clarify attribute handling */ |
if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
parse_attribute(ad); |
/* recursive type */ |
/* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ |
type1.t = 0; /* XXX: same as int */ |
if (tok == '(') { |
next(); |
/* XXX: this is not correct to modify 'ad' at this point, but |
the syntax is not clear */ |
if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
parse_attribute(ad); |
type_decl(&type1, ad, v, td); |
skip(')'); |
} else { |
/* type identifier */ |
if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { |
*v = tok; |
next(); |
} else { |
if (!(td & TYPE_ABSTRACT)) |
expect("identifier"); |
*v = 0; |
} |
} |
post_type(type, ad); |
if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
parse_attribute(ad); |
if (!type1.t) |
return; |
/* append type at the end of type1 */ |
type2 = &type1; |
for(;;) { |
s = type2->ref; |
type2 = &s->type; |
if (!type2->t) { |
*type2 = *type; |
break; |
} |
} |
*type = type1; |
} |
/* compute the lvalue VT_LVAL_xxx needed to match type t. */ |
static int lvalue_type(int t) |
{ |
int bt, r; |
r = VT_LVAL; |
bt = t & VT_BTYPE; |
if (bt == VT_BYTE || bt == VT_BOOL) |
r |= VT_LVAL_BYTE; |
else if (bt == VT_SHORT) |
r |= VT_LVAL_SHORT; |
else |
return r; |
if (t & VT_UNSIGNED) |
r |= VT_LVAL_UNSIGNED; |
return r; |
} |
/* indirection with full error checking and bound check */ |
static void indir(void) |
{ |
if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
expect("pointer"); |
if ((vtop->r & VT_LVAL) && !nocode_wanted) |
gv(RC_INT); |
vtop->type = *pointed_type(&vtop->type); |
/* an array is never an lvalue */ |
if (!(vtop->type.t & VT_ARRAY)) { |
vtop->r |= lvalue_type(vtop->type.t); |
/* if bound checking, the referenced pointer must be checked */ |
if (do_bounds_check) |
vtop->r |= VT_MUSTBOUND; |
} |
} |
/* pass a parameter to a function and do type checking and casting */ |
static void gfunc_param_typed(Sym *func, Sym *arg) |
{ |
int func_type; |
CType type; |
func_type = func->c; |
if (func_type == FUNC_OLD || |
(func_type == FUNC_ELLIPSIS && arg == NULL)) { |
/* default casting : only need to convert float to double */ |
if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { |
type.t = VT_DOUBLE; |
gen_cast(&type); |
} |
} else if (arg == NULL) { |
error("too many arguments to function"); |
} else { |
type = arg->type; |
type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
gen_assign_cast(&type); |
} |
} |
/* parse an expression of the form '(type)' or '(expr)' and return its |
type */ |
static void parse_expr_type(CType *type) |
{ |
int n; |
AttributeDef ad; |
skip('('); |
if (parse_btype(type, &ad)) { |
type_decl(type, &ad, &n, TYPE_ABSTRACT); |
} else { |
expr_type(type); |
} |
skip(')'); |
} |
static void parse_type(CType *type) |
{ |
AttributeDef ad; |
int n; |
if (!parse_btype(type, &ad)) { |
expect("type"); |
} |
type_decl(type, &ad, &n, TYPE_ABSTRACT); |
} |
static void vpush_tokc(int t) |
{ |
CType type; |
type.t = t; |
vsetc(&type, VT_CONST, &tokc); |
} |
static void unary(void) |
{ |
int n, t, align, size, r; |
CType type; |
Sym *s; |
AttributeDef ad; |
/* XXX: GCC 2.95.3 does not generate a table although it should be |
better here */ |
tok_next: |
switch(tok) { |
case TOK_EXTENSION: |
next(); |
goto tok_next; |
case TOK_CINT: |
case TOK_CCHAR: |
case TOK_LCHAR: |
vpushi(tokc.i); |
next(); |
break; |
case TOK_CUINT: |
vpush_tokc(VT_INT | VT_UNSIGNED); |
next(); |
break; |
case TOK_CLLONG: |
vpush_tokc(VT_LLONG); |
next(); |
break; |
case TOK_CULLONG: |
vpush_tokc(VT_LLONG | VT_UNSIGNED); |
next(); |
break; |
case TOK_CFLOAT: |
vpush_tokc(VT_FLOAT); |
next(); |
break; |
case TOK_CDOUBLE: |
vpush_tokc(VT_DOUBLE); |
next(); |
break; |
case TOK_CLDOUBLE: |
vpush_tokc(VT_LDOUBLE); |
next(); |
break; |
case TOK___FUNCTION__: |
if (!gnu_ext) |
goto tok_identifier; |
/* fall thru */ |
case TOK___FUNC__: |
{ |
void *ptr; |
int len; |
/* special function name identifier */ |
len = strlen(funcname) + 1; |
/* generate char[len] type */ |
type.t = VT_BYTE; |
mk_pointer(&type); |
type.t |= VT_ARRAY; |
type.ref->c = len; |
vpush_ref(&type, data_section, data_section->data_offset, len); |
ptr = section_ptr_add(data_section, len); |
memcpy(ptr, funcname, len); |
next(); |
} |
break; |
case TOK_LSTR: |
t = VT_INT; |
goto str_init; |
case TOK_STR: |
/* string parsing */ |
t = VT_BYTE; |
str_init: |
if (tcc_state->warn_write_strings) |
t |= VT_CONSTANT; |
type.t = t; |
mk_pointer(&type); |
type.t |= VT_ARRAY; |
memset(&ad, 0, sizeof(AttributeDef)); |
decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); |
break; |
case '(': |
next(); |
/* cast ? */ |
if (parse_btype(&type, &ad)) { |
type_decl(&type, &ad, &n, TYPE_ABSTRACT); |
skip(')'); |
/* check ISOC99 compound literal */ |
if (tok == '{') { |
/* data is allocated locally by default */ |
if (global_expr) |
r = VT_CONST; |
else |
r = VT_LOCAL; |
/* all except arrays are lvalues */ |
if (!(type.t & VT_ARRAY)) |
r |= lvalue_type(type.t); |
memset(&ad, 0, sizeof(AttributeDef)); |
decl_initializer_alloc(&type, &ad, r, 1, 0, 0); |
} else { |
unary(); |
gen_cast(&type); |
} |
} else if (tok == '{') { |
/* save all registers */ |
save_regs(0); |
/* statement expression : we do not accept break/continue |
inside as GCC does */ |
block(NULL, NULL, NULL, NULL, 0, 1); |
skip(')'); |
} else { |
gexpr(); |
skip(')'); |
} |
break; |
case '*': |
next(); |
unary(); |
indir(); |
break; |
case '&': |
next(); |
unary(); |
/* functions names must be treated as function pointers, |
except for unary '&' and sizeof. Since we consider that |
functions are not lvalues, we only have to handle it |
there and in function calls. */ |
/* arrays can also be used although they are not lvalues */ |
if ((vtop->type.t & VT_BTYPE) != VT_FUNC && |
!(vtop->type.t & VT_ARRAY)) |
test_lvalue(); |
mk_pointer(&vtop->type); |
gaddrof(); |
break; |
case '!': |
next(); |
unary(); |
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) |
vtop->c.i = !vtop->c.i; |
else if ((vtop->r & VT_VALMASK) == VT_CMP) |
vtop->c.i = vtop->c.i ^ 1; |
else |
vseti(VT_JMP, gtst(1, 0)); |
break; |
case '~': |
next(); |
unary(); |
vpushi(-1); |
gen_op('^'); |
break; |
case '+': |
next(); |
/* in order to force cast, we add zero */ |
unary(); |
if ((vtop->type.t & VT_BTYPE) == VT_PTR) |
error("pointer not accepted for unary plus"); |
vpushi(0); |
gen_op('+'); |
break; |
case TOK_SIZEOF: |
case TOK_ALIGNOF1: |
case TOK_ALIGNOF2: |
t = tok; |
next(); |
if (tok == '(') { |
parse_expr_type(&type); |
} else { |
unary_type(&type); |
} |
size = type_size(&type, &align); |
if (t == TOK_SIZEOF) { |
if (size < 0) |
error("sizeof applied to an incomplete type"); |
vpushi(size); |
} else { |
vpushi(align); |
} |
break; |
case TOK_builtin_types_compatible_p: |
{ |
CType type1, type2; |
next(); |
skip('('); |
parse_type(&type1); |
skip(','); |
parse_type(&type2); |
skip(')'); |
type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
vpushi(is_compatible_types(&type1, &type2)); |
} |
break; |
case TOK_builtin_constant_p: |
{ |
int saved_nocode_wanted, res; |
next(); |
skip('('); |
saved_nocode_wanted = nocode_wanted; |
nocode_wanted = 1; |
gexpr(); |
res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
vpop(); |
nocode_wanted = saved_nocode_wanted; |
skip(')'); |
vpushi(res); |
} |
break; |
case TOK_INC: |
case TOK_DEC: |
t = tok; |
next(); |
unary(); |
inc(0, t); |
break; |
case '-': |
next(); |
vpushi(0); |
unary(); |
gen_op('-'); |
break; |
case TOK_LAND: |
if (!gnu_ext) |
goto tok_identifier; |
next(); |
/* allow to take the address of a label */ |
if (tok < TOK_UIDENT) |
expect("label identifier"); |
s = label_find(tok); |
if (!s) { |
s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
} else { |
if (s->r == LABEL_DECLARED) |
s->r = LABEL_FORWARD; |
} |
if (!s->type.t) { |
s->type.t = VT_VOID; |
mk_pointer(&s->type); |
s->type.t |= VT_STATIC; |
} |
vset(&s->type, VT_CONST | VT_SYM, 0); |
vtop->sym = s; |
next(); |
break; |
default: |
tok_identifier: |
t = tok; |
next(); |
if (t < TOK_UIDENT) |
expect("identifier"); |
s = sym_find(t); |
if (!s) { |
if (tok != '(') |
error("'%s' undeclared", get_tok_str(t, NULL)); |
/* for simple function calls, we tolerate undeclared |
external reference to int() function */ |
if (tcc_state->warn_implicit_function_declaration) |
warning("implicit declaration of function '%s'", |
get_tok_str(t, NULL)); |
s = external_global_sym(t, &func_old_type, 0); |
} |
if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == |
(VT_STATIC | VT_INLINE | VT_FUNC)) { |
/* if referencing an inline function, then we generate a |
symbol to it if not already done. It will have the |
effect to generate code for it at the end of the |
compilation unit. Inline function as always |
generated in the text section. */ |
if (!s->c) |
put_extern_sym(s, text_section, 0, 0); |
r = VT_SYM | VT_CONST; |
} else { |
r = s->r; |
} |
vset(&s->type, r, s->c); |
/* if forward reference, we must point to s */ |
if (vtop->r & VT_SYM) { |
vtop->sym = s; |
vtop->c.ul = 0; |
} |
break; |
} |
/* post operations */ |
while (1) { |
if (tok == TOK_INC || tok == TOK_DEC) { |
inc(1, tok); |
next(); |
} else if (tok == '.' || tok == TOK_ARROW) { |
/* field */ |
if (tok == TOK_ARROW) |
indir(); |
test_lvalue(); |
gaddrof(); |
next(); |
/* expect pointer on structure */ |
if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) |
expect("struct or union"); |
s = vtop->type.ref; |
/* find field */ |
tok |= SYM_FIELD; |
while ((s = s->next) != NULL) { |
if (s->v == tok) |
break; |
} |
if (!s) |
error("field not found"); |
/* add field offset to pointer */ |
vtop->type = char_pointer_type; /* change type to 'char *' */ |
vpushi(s->c); |
gen_op('+'); |
/* change type to field type, and set to lvalue */ |
vtop->type = s->type; |
/* an array is never an lvalue */ |
if (!(vtop->type.t & VT_ARRAY)) { |
vtop->r |= lvalue_type(vtop->type.t); |
/* if bound checking, the referenced pointer must be checked */ |
if (do_bounds_check) |
vtop->r |= VT_MUSTBOUND; |
} |
next(); |
} else if (tok == '[') { |
next(); |
gexpr(); |
gen_op('+'); |
indir(); |
skip(']'); |
} else if (tok == '(') { |
SValue ret; |
Sym *sa; |
int nb_args; |
/* function call */ |
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { |
/* pointer test (no array accepted) */ |
if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { |
vtop->type = *pointed_type(&vtop->type); |
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) |
goto error_func; |
} else { |
error_func: |
expect("function pointer"); |
} |
} else { |
vtop->r &= ~VT_LVAL; /* no lvalue */ |
} |
/* get return type */ |
s = vtop->type.ref; |
next(); |
sa = s->next; /* first parameter */ |
nb_args = 0; |
/* compute first implicit argument if a structure is returned */ |
if ((s->type.t & VT_BTYPE) == VT_STRUCT) { |
/* get some space for the returned structure */ |
size = type_size(&s->type, &align); |
loc = (loc - size) & -align; |
ret.type = s->type; |
ret.r = VT_LOCAL | VT_LVAL; |
/* pass it as 'int' to avoid structure arg passing |
problems */ |
vseti(VT_LOCAL, loc); |
ret.c = vtop->c; |
nb_args++; |
} else { |
ret.type = s->type; |
ret.r2 = VT_CONST; |
/* return in register */ |
if (is_float(ret.type.t)) { |
ret.r = REG_FRET; |
} else { |
if ((ret.type.t & VT_BTYPE) == VT_LLONG) |
ret.r2 = REG_LRET; |
ret.r = REG_IRET; |
} |
ret.c.i = 0; |
} |
if (tok != ')') { |
for(;;) { |
expr_eq(); |
gfunc_param_typed(s, sa); |
nb_args++; |
if (sa) |
sa = sa->next; |
if (tok == ')') |
break; |
skip(','); |
} |
} |
if (sa) |
error("too few arguments to function"); |
skip(')'); |
if (!nocode_wanted) { |
gfunc_call(nb_args); |
} else { |
vtop -= (nb_args + 1); |
} |
/* return value */ |
vsetc(&ret.type, ret.r, &ret.c); |
vtop->r2 = ret.r2; |
} else { |
break; |
} |
} |
} |
static void uneq(void) |
{ |
int t; |
unary(); |
if (tok == '=' || |
(tok >= TOK_A_MOD && tok <= TOK_A_DIV) || |
tok == TOK_A_XOR || tok == TOK_A_OR || |
tok == TOK_A_SHL || tok == TOK_A_SAR) { |
test_lvalue(); |
t = tok; |
next(); |
if (t == '=') { |
expr_eq(); |
} else { |
vdup(); |
expr_eq(); |
gen_op(t & 0x7f); |
} |
vstore(); |
} |
} |
static void expr_prod(void) |
{ |
int t; |
uneq(); |
while (tok == '*' || tok == '/' || tok == '%') { |
t = tok; |
next(); |
uneq(); |
gen_op(t); |
} |
} |
static void expr_sum(void) |
{ |
int t; |
expr_prod(); |
while (tok == '+' || tok == '-') { |
t = tok; |
next(); |
expr_prod(); |
gen_op(t); |
} |
} |
static void expr_shift(void) |
{ |
int t; |
expr_sum(); |
while (tok == TOK_SHL || tok == TOK_SAR) { |
t = tok; |
next(); |
expr_sum(); |
gen_op(t); |
} |
} |
static void expr_cmp(void) |
{ |
int t; |
expr_shift(); |
while ((tok >= TOK_ULE && tok <= TOK_GT) || |
tok == TOK_ULT || tok == TOK_UGE) { |
t = tok; |
next(); |
expr_shift(); |
gen_op(t); |
} |
} |
static void expr_cmpeq(void) |
{ |
int t; |
expr_cmp(); |
while (tok == TOK_EQ || tok == TOK_NE) { |
t = tok; |
next(); |
expr_cmp(); |
gen_op(t); |
} |
} |
static void expr_and(void) |
{ |
expr_cmpeq(); |
while (tok == '&') { |
next(); |
expr_cmpeq(); |
gen_op('&'); |
} |
} |
static void expr_xor(void) |
{ |
expr_and(); |
while (tok == '^') { |
next(); |
expr_and(); |
gen_op('^'); |
} |
} |
static void expr_or(void) |
{ |
expr_xor(); |
while (tok == '|') { |
next(); |
expr_xor(); |
gen_op('|'); |
} |
} |
/* XXX: fix this mess */ |
static void expr_land_const(void) |
{ |
expr_or(); |
while (tok == TOK_LAND) { |
next(); |
expr_or(); |
gen_op(TOK_LAND); |
} |
} |
/* XXX: fix this mess */ |
static void expr_lor_const(void) |
{ |
expr_land_const(); |
while (tok == TOK_LOR) { |
next(); |
expr_land_const(); |
gen_op(TOK_LOR); |
} |
} |
/* only used if non constant */ |
static void expr_land(void) |
{ |
int t; |
expr_or(); |
if (tok == TOK_LAND) { |
t = 0; |
for(;;) { |
t = gtst(1, t); |
if (tok != TOK_LAND) { |
vseti(VT_JMPI, t); |
break; |
} |
next(); |
expr_or(); |
} |
} |
} |
static void expr_lor(void) |
{ |
int t; |
expr_land(); |
if (tok == TOK_LOR) { |
t = 0; |
for(;;) { |
t = gtst(0, t); |
if (tok != TOK_LOR) { |
vseti(VT_JMP, t); |
break; |
} |
next(); |
expr_land(); |
} |
} |
} |
/* XXX: better constant handling */ |
static void expr_eq(void) |
{ |
int tt, u, r1, r2, rc, t1, t2, bt1, bt2; |
SValue sv; |
CType type, type1, type2; |
if (const_wanted) { |
int c1, c; |
expr_lor_const(); |
if (tok == '?') { |
c = vtop->c.i; |
vpop(); |
next(); |
if (tok == ':' && gnu_ext) { |
c1 = c; |
} else { |
gexpr(); |
c1 = vtop->c.i; |
vpop(); |
} |
skip(':'); |
expr_eq(); |
if (c) |
vtop->c.i = c1; |
} |
} else { |
expr_lor(); |
if (tok == '?') { |
next(); |
if (vtop != vstack) { |
/* needed to avoid having different registers saved in |
each branch */ |
if (is_float(vtop->type.t)) |
rc = RC_FLOAT; |
else |
rc = RC_INT; |
gv(rc); |
save_regs(1); |
} |
if (tok == ':' && gnu_ext) { |
gv_dup(); |
tt = gtst(1, 0); |
} else { |
tt = gtst(1, 0); |
gexpr(); |
} |
type1 = vtop->type; |
sv = *vtop; /* save value to handle it later */ |
vtop--; /* no vpop so that FP stack is not flushed */ |
skip(':'); |
u = gjmp(0); |
gsym(tt); |
expr_eq(); |
type2 = vtop->type; |
t1 = type1.t; |
bt1 = t1 & VT_BTYPE; |
t2 = type2.t; |
bt2 = t2 & VT_BTYPE; |
/* cast operands to correct type according to ISOC rules */ |
if (is_float(bt1) || is_float(bt2)) { |
if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
type.t = VT_LDOUBLE; |
} else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
type.t = VT_DOUBLE; |
} else { |
type.t = VT_FLOAT; |
} |
} else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
/* cast to biggest op */ |
type.t = VT_LLONG; |
/* convert to unsigned if it does not fit in a long long */ |
if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
type.t |= VT_UNSIGNED; |
} else if (bt1 == VT_PTR || bt2 == VT_PTR) { |
/* XXX: test pointer compatibility */ |
type = type1; |
} else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { |
/* XXX: test structure compatibility */ |
type = type1; |
} else if (bt1 == VT_VOID || bt2 == VT_VOID) { |
/* NOTE: as an extension, we accept void on only one side */ |
type.t = VT_VOID; |
} else { |
/* integer operations */ |
type.t = VT_INT; |
/* convert to unsigned if it does not fit in an integer */ |
if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
type.t |= VT_UNSIGNED; |
} |
/* now we convert second operand */ |
gen_cast(&type); |
rc = RC_INT; |
if (is_float(type.t)) { |
rc = RC_FLOAT; |
} else if ((type.t & VT_BTYPE) == VT_LLONG) { |
/* for long longs, we use fixed registers to avoid having |
to handle a complicated move */ |
rc = RC_IRET; |
} |
r2 = gv(rc); |
/* this is horrible, but we must also convert first |
operand */ |
tt = gjmp(0); |
gsym(u); |
/* put again first value and cast it */ |
*vtop = sv; |
gen_cast(&type); |
r1 = gv(rc); |
move_reg(r2, r1); |
vtop->r = r2; |
gsym(tt); |
} |
} |
} |
static void gexpr(void) |
{ |
while (1) { |
expr_eq(); |
if (tok != ',') |
break; |
vpop(); |
next(); |
} |
} |
/* parse an expression and return its type without any side effect. */ |
static void expr_type(CType *type) |
{ |
int saved_nocode_wanted; |
saved_nocode_wanted = nocode_wanted; |
nocode_wanted = 1; |
gexpr(); |
*type = vtop->type; |
vpop(); |
nocode_wanted = saved_nocode_wanted; |
} |
/* parse a unary expression and return its type without any side |
effect. */ |
static void unary_type(CType *type) |
{ |
int a; |
a = nocode_wanted; |
nocode_wanted = 1; |
unary(); |
*type = vtop->type; |
vpop(); |
nocode_wanted = a; |
} |
/* parse a constant expression and return value in vtop. */ |
static void expr_const1(void) |
{ |
int a; |
a = const_wanted; |
const_wanted = 1; |
expr_eq(); |
const_wanted = a; |
} |
/* parse an integer constant and return its value. */ |
static int expr_const(void) |
{ |
int c; |
expr_const1(); |
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
expect("constant expression"); |
c = vtop->c.i; |
vpop(); |
return c; |
} |
/* return the label token if current token is a label, otherwise |
return zero */ |
static int is_label(void) |
{ |
int last_tok; |
/* fast test first */ |
if (tok < TOK_UIDENT) |
return 0; |
/* no need to save tokc because tok is an identifier */ |
last_tok = tok; |
next(); |
if (tok == ':') { |
next(); |
return last_tok; |
} else { |
unget_tok(last_tok); |
return 0; |
} |
} |
static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
int case_reg, int is_expr) |
{ |
int a, b, c, d; |
Sym *s; |
/* generate line number info */ |
if (do_debug && |
(last_line_num != file->line_num || last_ind != ind)) { |
put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); |
last_ind = ind; |
last_line_num = file->line_num; |
} |
if (is_expr) { |
/* default return value is (void) */ |
vpushi(0); |
vtop->type.t = VT_VOID; |
} |
if (tok == TOK_IF) { |
/* if test */ |
next(); |
skip('('); |
gexpr(); |
skip(')'); |
a = gtst(1, 0); |
block(bsym, csym, case_sym, def_sym, case_reg, 0); |
c = tok; |
if (c == TOK_ELSE) { |
next(); |
d = gjmp(0); |
gsym(a); |
block(bsym, csym, case_sym, def_sym, case_reg, 0); |
gsym(d); /* patch else jmp */ |
} else |
gsym(a); |
} else if (tok == TOK_WHILE) { |
next(); |
d = ind; |
skip('('); |
gexpr(); |
skip(')'); |
a = gtst(1, 0); |
b = 0; |
block(&a, &b, case_sym, def_sym, case_reg, 0); |
gjmp_addr(d); |
gsym(a); |
gsym_addr(b, d); |
} else if (tok == '{') { |
Sym *llabel; |
next(); |
/* record local declaration stack position */ |
s = local_stack; |
llabel = local_label_stack; |
/* handle local labels declarations */ |
if (tok == TOK_LABEL) { |
next(); |
for(;;) { |
if (tok < TOK_UIDENT) |
expect("label identifier"); |
label_push(&local_label_stack, tok, LABEL_DECLARED); |
next(); |
if (tok == ',') { |
next(); |
} else { |
skip(';'); |
break; |
} |
} |
} |
while (tok != '}') { |
decl(VT_LOCAL); |
if (tok != '}') { |
if (is_expr) |
vpop(); |
block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
} |
} |
/* pop locally defined labels */ |
label_pop(&local_label_stack, llabel); |
/* pop locally defined symbols */ |
sym_pop(&local_stack, s); |
next(); |
} else if (tok == TOK_RETURN) { |
next(); |
if (tok != ';') { |
gexpr(); |
gen_assign_cast(&func_vt); |
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
CType type; |
/* if returning structure, must copy it to implicit |
first pointer arg location */ |
type = func_vt; |
mk_pointer(&type); |
vset(&type, VT_LOCAL | VT_LVAL, func_vc); |
indir(); |
vswap(); |
/* copy structure value to pointer */ |
vstore(); |
} else if (is_float(func_vt.t)) { |
gv(RC_FRET); |
} else { |
gv(RC_IRET); |
} |
vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
} |
skip(';'); |
rsym = gjmp(rsym); /* jmp */ |
} else if (tok == TOK_BREAK) { |
/* compute jump */ |
if (!bsym) |
error("cannot break"); |
*bsym = gjmp(*bsym); |
next(); |
skip(';'); |
} else if (tok == TOK_CONTINUE) { |
/* compute jump */ |
if (!csym) |
error("cannot continue"); |
*csym = gjmp(*csym); |
next(); |
skip(';'); |
} else if (tok == TOK_FOR) { |
int e; |
next(); |
skip('('); |
if (tok != ';') { |
gexpr(); |
vpop(); |
} |
skip(';'); |
d = ind; |
c = ind; |
a = 0; |
b = 0; |
if (tok != ';') { |
gexpr(); |
a = gtst(1, 0); |
} |
skip(';'); |
if (tok != ')') { |
e = gjmp(0); |
c = ind; |
gexpr(); |
vpop(); |
gjmp_addr(d); |
gsym(e); |
} |
skip(')'); |
block(&a, &b, case_sym, def_sym, case_reg, 0); |
gjmp_addr(c); |
gsym(a); |
gsym_addr(b, c); |
} else |
if (tok == TOK_DO) { |
next(); |
a = 0; |
b = 0; |
d = ind; |
block(&a, &b, case_sym, def_sym, case_reg, 0); |
skip(TOK_WHILE); |
skip('('); |
gsym(b); |
gexpr(); |
c = gtst(0, 0); |
gsym_addr(c, d); |
skip(')'); |
gsym(a); |
skip(';'); |
} else |
if (tok == TOK_SWITCH) { |
next(); |
skip('('); |
gexpr(); |
/* XXX: other types than integer */ |
case_reg = gv(RC_INT); |
vpop(); |
skip(')'); |
a = 0; |
b = gjmp(0); /* jump to first case */ |
c = 0; |
block(&a, csym, &b, &c, case_reg, 0); |
/* if no default, jmp after switch */ |
if (c == 0) |
c = ind; |
/* default label */ |
gsym_addr(b, c); |
/* break label */ |
gsym(a); |
} else |
if (tok == TOK_CASE) { |
int v1, v2; |
if (!case_sym) |
expect("switch"); |
next(); |
v1 = expr_const(); |
v2 = v1; |
if (gnu_ext && tok == TOK_DOTS) { |
next(); |
v2 = expr_const(); |
if (v2 < v1) |
warning("empty case range"); |
} |
/* since a case is like a label, we must skip it with a jmp */ |
b = gjmp(0); |
gsym(*case_sym); |
vseti(case_reg, 0); |
vpushi(v1); |
if (v1 == v2) { |
gen_op(TOK_EQ); |
*case_sym = gtst(1, 0); |
} else { |
gen_op(TOK_GE); |
*case_sym = gtst(1, 0); |
vseti(case_reg, 0); |
vpushi(v2); |
gen_op(TOK_LE); |
*case_sym = gtst(1, *case_sym); |
} |
gsym(b); |
skip(':'); |
is_expr = 0; |
goto block_after_label; |
} else |
if (tok == TOK_DEFAULT) { |
next(); |
skip(':'); |
if (!def_sym) |
expect("switch"); |
if (*def_sym) |
error("too many 'default'"); |
*def_sym = ind; |
is_expr = 0; |
goto block_after_label; |
} else |
if (tok == TOK_GOTO) { |
next(); |
if (tok == '*' && gnu_ext) { |
/* computed goto */ |
next(); |
gexpr(); |
if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
expect("pointer"); |
ggoto(); |
} else if (tok >= TOK_UIDENT) { |
s = label_find(tok); |
/* put forward definition if needed */ |
if (!s) { |
s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
} else { |
if (s->r == LABEL_DECLARED) |
s->r = LABEL_FORWARD; |
} |
/* label already defined */ |
if (s->r & LABEL_FORWARD) |
s->next = (void *)gjmp((long)s->next); |
else |
gjmp_addr((long)s->next); |
next(); |
} else { |
expect("label identifier"); |
} |
skip(';'); |
} else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { |
asm_instr(); |
} else { |
b = is_label(); |
if (b) { |
/* label case */ |
s = label_find(b); |
if (s) { |
if (s->r == LABEL_DEFINED) |
error("duplicate label '%s'", get_tok_str(s->v, NULL)); |
gsym((long)s->next); |
s->r = LABEL_DEFINED; |
} else { |
s = label_push(&global_label_stack, b, LABEL_DEFINED); |
} |
s->next = (void *)ind; |
/* we accept this, but it is a mistake */ |
block_after_label: |
if (tok == '}') { |
warning("deprecated use of label at end of compound statement"); |
} else { |
if (is_expr) |
vpop(); |
block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
} |
} else { |
/* expression case */ |
if (tok != ';') { |
if (is_expr) { |
vpop(); |
gexpr(); |
} else { |
gexpr(); |
vpop(); |
} |
} |
skip(';'); |
} |
} |
} |
/* t is the array or struct type. c is the array or struct |
address. cur_index/cur_field is the pointer to the current |
value. 'size_only' is true if only size info is needed (only used |
in arrays) */ |
static void decl_designator(CType *type, Section *sec, unsigned long c, |
int *cur_index, Sym **cur_field, |
int size_only) |
{ |
Sym *s, *f; |
int notfirst, index, index_last, align, l, nb_elems, elem_size; |
CType type1; |
notfirst = 0; |
elem_size = 0; |
nb_elems = 1; |
if (gnu_ext && (l = is_label()) != 0) |
goto struct_field; |
while (tok == '[' || tok == '.') { |
if (tok == '[') { |
if (!(type->t & VT_ARRAY)) |
expect("array type"); |
s = type->ref; |
next(); |
index = expr_const(); |
if (index < 0 || (s->c >= 0 && index >= s->c)) |
expect("invalid index"); |
if (tok == TOK_DOTS && gnu_ext) { |
next(); |
index_last = expr_const(); |
if (index_last < 0 || |
(s->c >= 0 && index_last >= s->c) || |
index_last < index) |
expect("invalid index"); |
} else { |
index_last = index; |
} |
skip(']'); |
if (!notfirst) |
*cur_index = index_last; |
type = pointed_type(type); |
elem_size = type_size(type, &align); |
c += index * elem_size; |
/* NOTE: we only support ranges for last designator */ |
nb_elems = index_last - index + 1; |
if (nb_elems != 1) { |
notfirst = 1; |
break; |
} |
} else { |
next(); |
l = tok; |
next(); |
struct_field: |
if ((type->t & VT_BTYPE) != VT_STRUCT) |
expect("struct/union type"); |
s = type->ref; |
l |= SYM_FIELD; |
f = s->next; |
while (f) { |
if (f->v == l) |
break; |
f = f->next; |
} |
if (!f) |
expect("field"); |
if (!notfirst) |
*cur_field = f; |
/* XXX: fix this mess by using explicit storage field */ |
type1 = f->type; |
type1.t |= (type->t & ~VT_TYPE); |
type = &type1; |
c += f->c; |
} |
notfirst = 1; |
} |
if (notfirst) { |
if (tok == '=') { |
next(); |
} else { |
if (!gnu_ext) |
expect("="); |
} |
} else { |
if (type->t & VT_ARRAY) { |
index = *cur_index; |
type = pointed_type(type); |
c += index * type_size(type, &align); |
} else { |
f = *cur_field; |
if (!f) |
error("too many field init"); |
/* XXX: fix this mess by using explicit storage field */ |
type1 = f->type; |
type1.t |= (type->t & ~VT_TYPE); |
type = &type1; |
c += f->c; |
} |
} |
decl_initializer(type, sec, c, 0, size_only); |
/* XXX: make it more general */ |
if (!size_only && nb_elems > 1) { |
unsigned long c_end; |
uint8_t *src, *dst; |
int i; |
if (!filename) { |
/* compute filename automatically |
* dir/file.o -> dir/file.d */ |
pstrcpy(buf, sizeof(buf), target); |
ext = tcc_fileextension(buf); |
pstrcpy(ext, sizeof(buf) - (ext-buf), ".d"); |
filename = buf; |
if (!sec) |
error("range init not supported yet for dynamic storage"); |
c_end = c + nb_elems * elem_size; |
if (c_end > sec->data_allocated) |
section_realloc(sec, c_end); |
src = sec->data + c; |
dst = src; |
for(i = 1; i < nb_elems; i++) { |
dst += elem_size; |
memcpy(dst, src, elem_size); |
} |
} |
} |
if (s->verbose) |
printf("<- %s\n", filename); |
#define EXPR_VAL 0 |
#define EXPR_CONST 1 |
#define EXPR_ANY 2 |
/* XXX return err codes instead of error() ? */ |
depout = fopen(filename, "w"); |
if (!depout) |
tcc_error("could not open '%s'", filename); |
/* store a value or an expression directly in global data or in local array */ |
static void init_putv(CType *type, Section *sec, unsigned long c, |
int v, int expr_type) |
{ |
int saved_global_expr, bt, bit_pos, bit_size; |
void *ptr; |
unsigned long long bit_mask; |
CType dtype; |
fprintf(depout, "%s : \\\n", target); |
for (i=0; i<s->nb_target_deps; ++i) |
fprintf(depout, " %s \\\n", s->target_deps[i]); |
fprintf(depout, "\n"); |
fclose(depout); |
switch(expr_type) { |
case EXPR_VAL: |
vpushi(v); |
break; |
case EXPR_CONST: |
/* compound literals must be allocated globally in this case */ |
saved_global_expr = global_expr; |
global_expr = 1; |
expr_const1(); |
global_expr = saved_global_expr; |
/* NOTE: symbols are accepted */ |
if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST) |
error("initializer element is not constant"); |
break; |
case EXPR_ANY: |
expr_eq(); |
break; |
} |
static char *default_outputfile(TCCState *s, const char *first_file) |
dtype = *type; |
dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
if (sec) { |
/* XXX: not portable */ |
/* XXX: generate error if incorrect relocation */ |
gen_assign_cast(&dtype); |
bt = type->t & VT_BTYPE; |
ptr = sec->data + c; |
/* XXX: make code faster ? */ |
if (!(type->t & VT_BITFIELD)) { |
bit_pos = 0; |
bit_size = 32; |
bit_mask = -1LL; |
} else { |
bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
bit_mask = (1LL << bit_size) - 1; |
} |
if ((vtop->r & VT_SYM) && |
(bt == VT_BYTE || |
bt == VT_SHORT || |
bt == VT_DOUBLE || |
bt == VT_LDOUBLE || |
bt == VT_LLONG || |
(bt == VT_INT && bit_size != 32))) |
error("initializer element is not computable at load time"); |
switch(bt) { |
case VT_BYTE: |
*(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
break; |
case VT_SHORT: |
*(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
break; |
case VT_DOUBLE: |
*(double *)ptr = vtop->c.d; |
break; |
case VT_LDOUBLE: |
*(long double *)ptr = vtop->c.ld; |
break; |
case VT_LLONG: |
*(long long *)ptr |= (vtop->c.ll & bit_mask) << bit_pos; |
break; |
default: |
if (vtop->r & VT_SYM) { |
greloc(sec, vtop->sym, c, R_DATA_32); |
} |
*(int *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
break; |
} |
vtop--; |
} else { |
vset(&dtype, VT_LOCAL, c); |
vswap(); |
vstore(); |
vpop(); |
} |
} |
/* put zeros for variable based init */ |
static void init_putz(CType *t, Section *sec, unsigned long c, int size) |
{ |
char buf[1024]; |
char *ext; |
const char *name = "a"; |
if (sec) { |
/* nothing to do because globals are already set to zero */ |
} else { |
vpush_global_sym(&func_old_type, TOK_memset); |
vseti(VT_LOCAL, c); |
vpushi(0); |
vpushi(size); |
gfunc_call(3); |
} |
} |
if (first_file && strcmp(first_file, "-")) |
name = tcc_basename(first_file); |
pstrcpy(buf, sizeof(buf), name); |
ext = tcc_fileextension(buf); |
/* 't' contains the type and storage info. 'c' is the offset of the |
object in section 'sec'. If 'sec' is NULL, it means stack based |
allocation. 'first' is true if array '{' must be read (multi |
dimension implicit array init handling). 'size_only' is true if |
size only evaluation is wanted (only for arrays). */ |
static void decl_initializer(CType *type, Section *sec, unsigned long c, |
int first, int size_only) |
{ |
int index, array_length, n, no_oblock, nb, parlevel, i; |
int size1, align1, expr_type; |
Sym *s, *f; |
CType *t1; |
if (type->t & VT_ARRAY) { |
s = type->ref; |
n = s->c; |
array_length = 0; |
t1 = pointed_type(type); |
size1 = type_size(t1, &align1); |
no_oblock = 1; |
if ((first && tok != TOK_LSTR && tok != TOK_STR) || |
tok == '{') { |
skip('{'); |
no_oblock = 0; |
} |
/* only parse strings here if correct type (otherwise: handle |
them as ((w)char *) expressions */ |
if ((tok == TOK_LSTR && |
(t1->t & VT_BTYPE) == VT_INT) || |
(tok == TOK_STR && |
(t1->t & VT_BTYPE) == VT_BYTE)) { |
while (tok == TOK_STR || tok == TOK_LSTR) { |
int cstr_len, ch; |
CString *cstr; |
cstr = tokc.cstr; |
/* compute maximum number of chars wanted */ |
if (tok == TOK_STR) |
cstr_len = cstr->size; |
else |
cstr_len = cstr->size / sizeof(int); |
cstr_len--; |
nb = cstr_len; |
if (n >= 0 && nb > (n - array_length)) |
nb = n - array_length; |
if (!size_only) { |
if (cstr_len > nb) |
warning("initializer-string for array is too long"); |
/* in order to go faster for common case (char |
string in global variable, we handle it |
specifically */ |
if (sec && tok == TOK_STR && size1 == 1) { |
memcpy(sec->data + c + array_length, cstr->data, nb); |
} else { |
for(i=0;i<nb;i++) { |
if (tok == TOK_STR) |
ch = ((unsigned char *)cstr->data)[i]; |
else |
ch = ((int *)cstr->data)[i]; |
init_putv(t1, sec, c + (array_length + i) * size1, |
ch, EXPR_VAL); |
} |
} |
} |
array_length += nb; |
next(); |
} |
/* only add trailing zero if enough storage (no |
warning in this case since it is standard) */ |
if (n < 0 || array_length < n) { |
if (!size_only) { |
init_putv(t1, sec, c + (array_length * size1), 0, EXPR_VAL); |
} |
array_length++; |
} |
} else { |
index = 0; |
while (tok != '}') { |
decl_designator(type, sec, c, &index, NULL, size_only); |
if (n >= 0 && index >= n) |
error("index too large"); |
/* must put zero in holes (note that doing it that way |
ensures that it even works with designators) */ |
if (!size_only && array_length < index) { |
init_putz(t1, sec, c + array_length * size1, |
(index - array_length) * size1); |
} |
index++; |
if (index > array_length) |
array_length = index; |
/* special test for multi dimensional arrays (may not |
be strictly correct if designators are used at the |
same time) */ |
if (index >= n && no_oblock) |
break; |
if (tok == '}') |
break; |
skip(','); |
} |
} |
if (!no_oblock) |
skip('}'); |
/* put zeros at the end */ |
if (!size_only && n >= 0 && array_length < n) { |
init_putz(t1, sec, c + array_length * size1, |
(n - array_length) * size1); |
} |
/* patch type size if needed */ |
if (n < 0) |
s->c = array_length; |
} else if ((type->t & VT_BTYPE) == VT_STRUCT && |
(sec || !first || tok == '{')) { |
int par_count; |
/* NOTE: the previous test is a specific case for automatic |
struct/union init */ |
/* XXX: union needs only one init */ |
/* XXX: this test is incorrect for local initializers |
beginning with ( without {. It would be much more difficult |
to do it correctly (ideally, the expression parser should |
be used in all cases) */ |
par_count = 0; |
if (tok == '(') { |
AttributeDef ad1; |
CType type1; |
next(); |
while (tok == '(') { |
par_count++; |
next(); |
} |
if (!parse_btype(&type1, &ad1)) |
expect("cast"); |
type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); |
#if 0 |
if (!is_assignable_types(type, &type1)) |
error("invalid type for cast"); |
#endif |
skip(')'); |
} |
no_oblock = 1; |
if (first || tok == '{') { |
skip('{'); |
no_oblock = 0; |
} |
s = type->ref; |
f = s->next; |
array_length = 0; |
index = 0; |
n = s->c; |
while (tok != '}') { |
decl_designator(type, sec, c, NULL, &f, size_only); |
index = f->c; |
if (!size_only && array_length < index) { |
init_putz(type, sec, c + array_length, |
index - array_length); |
} |
index = index + type_size(&f->type, &align1); |
if (index > array_length) |
array_length = index; |
f = f->next; |
if (no_oblock && f == NULL) |
break; |
if (tok == '}') |
break; |
skip(','); |
} |
/* put zeros at the end */ |
if (!size_only && array_length < n) { |
init_putz(type, sec, c + array_length, |
n - array_length); |
} |
if (!no_oblock) |
skip('}'); |
while (par_count) { |
skip(')'); |
par_count--; |
} |
} else if (tok == '{') { |
next(); |
decl_initializer(type, sec, c, first, size_only); |
skip('}'); |
} else if (size_only) { |
/* just skip expression */ |
parlevel = 0; |
while ((parlevel > 0 || (tok != '}' && tok != ',')) && |
tok != -1) { |
if (tok == '(') |
parlevel++; |
else if (tok == ')') |
parlevel--; |
next(); |
} |
} else { |
/* currently, we always use constant expression for globals |
(may change for scripting case) */ |
expr_type = EXPR_CONST; |
if (!sec) |
expr_type = EXPR_ANY; |
init_putv(type, sec, c, 0, expr_type); |
} |
} |
/* parse an initializer for type 't' if 'has_init' is non zero, and |
allocate space in local or global data space ('r' is either |
VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated |
variable 'v' of scope 'scope' is declared before initializers are |
parsed. If 'v' is zero, then a reference to the new object is put |
in the value stack. If 'has_init' is 2, a special parsing is done |
to handle string constants. */ |
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
int has_init, int v, int scope) |
{ |
int size, align, addr, data_offset; |
int level; |
ParseState saved_parse_state; |
TokenString init_str; |
Section *sec; |
size = type_size(type, &align); |
/* If unknown size, we must evaluate it before |
evaluating initializers because |
initializers can generate global data too |
(e.g. string pointers or ISOC99 compound |
literals). It also simplifies local |
initializers handling */ |
tok_str_new(&init_str); |
if (size < 0) { |
if (!has_init) |
error("unknown type size"); |
/* get all init string */ |
if (has_init == 2) { |
/* only get strings */ |
while (tok == TOK_STR || tok == TOK_LSTR) { |
tok_str_add_tok(&init_str); |
next(); |
} |
} else { |
level = 0; |
while (level > 0 || (tok != ',' && tok != ';')) { |
if (tok < 0) |
error("unexpected end of file in initializer"); |
tok_str_add_tok(&init_str); |
if (tok == '{') |
level++; |
else if (tok == '}') { |
if (level == 0) |
break; |
level--; |
} |
next(); |
} |
} |
tok_str_add(&init_str, -1); |
tok_str_add(&init_str, 0); |
/* compute size */ |
save_parse_state(&saved_parse_state); |
macro_ptr = init_str.str; |
next(); |
decl_initializer(type, NULL, 0, 1, 1); |
/* prepare second initializer parsing */ |
macro_ptr = init_str.str; |
next(); |
/* if still unknown size, error */ |
size = type_size(type, &align); |
if (size < 0) |
error("unknown type size"); |
} |
/* take into account specified alignment if bigger */ |
if (ad->aligned) { |
if (ad->aligned > align) |
align = ad->aligned; |
} else if (ad->packed) { |
align = 1; |
} |
if ((r & VT_VALMASK) == VT_LOCAL) { |
sec = NULL; |
if (do_bounds_check && (type->t & VT_ARRAY)) |
loc--; |
loc = (loc - size) & -align; |
addr = loc; |
/* handles bounds */ |
/* XXX: currently, since we do only one pass, we cannot track |
'&' operators, so we add only arrays */ |
if (do_bounds_check && (type->t & VT_ARRAY)) { |
unsigned long *bounds_ptr; |
/* add padding between regions */ |
loc--; |
/* then add local bound info */ |
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long)); |
bounds_ptr[0] = addr; |
bounds_ptr[1] = size; |
} |
if (v) { |
/* local variable */ |
sym_push(v, type, r, addr); |
} else { |
/* push local reference */ |
vset(type, r, addr); |
} |
} else { |
Sym *sym; |
sym = NULL; |
if (v && scope == VT_CONST) { |
/* see if the symbol was already defined */ |
sym = sym_find(v); |
if (sym) { |
if (!is_compatible_types(&sym->type, type)) |
error("incompatible types for redefinition of '%s'", |
get_tok_str(v, NULL)); |
if (sym->type.t & VT_EXTERN) { |
/* if the variable is extern, it was not allocated */ |
sym->type.t &= ~VT_EXTERN; |
/* set array size if it was ommited in extern |
declaration */ |
if ((sym->type.t & VT_ARRAY) && |
sym->type.ref->c < 0 && |
type->ref->c >= 0) |
sym->type.ref->c = type->ref->c; |
} else { |
/* we accept several definitions of the same |
global variable. this is tricky, because we |
must play with the SHN_COMMON type of the symbol */ |
/* XXX: should check if the variable was already |
initialized. It is incorrect to initialized it |
twice */ |
/* no init data, we won't add more to the symbol */ |
if (!has_init) |
goto no_alloc; |
} |
} |
} |
/* allocate symbol in corresponding section */ |
sec = ad->section; |
if (!sec) { |
if (has_init) |
sec = data_section; |
else if (tcc_state->nocommon) |
sec = bss_section; |
} |
if (sec) { |
data_offset = sec->data_offset; |
data_offset = (data_offset + align - 1) & -align; |
addr = data_offset; |
/* very important to increment global pointer at this time |
because initializers themselves can create new initializers */ |
data_offset += size; |
/* add padding if bound check */ |
if (do_bounds_check) |
data_offset++; |
sec->data_offset = data_offset; |
/* allocate section space to put the data */ |
if (sec->sh_type != SHT_NOBITS && |
data_offset > sec->data_allocated) |
section_realloc(sec, data_offset); |
/* align section if needed */ |
if (align > sec->sh_addralign) |
sec->sh_addralign = align; |
} else { |
addr = 0; /* avoid warning */ |
} |
if (v) { |
if (scope == VT_CONST) { |
if (!sym) |
goto do_def; |
} else { |
do_def: |
sym = sym_push(v, type, r | VT_SYM, 0); |
} |
/* update symbol definition */ |
if (sec) { |
put_extern_sym(sym, sec, addr, size); |
} else { |
Elf32_Sym *esym; |
/* put a common area */ |
put_extern_sym(sym, NULL, align, size); |
/* XXX: find a nicer way */ |
esym = &((Elf32_Sym *)symtab_section->data)[sym->c]; |
esym->st_shndx = SHN_COMMON; |
} |
} else { |
CValue cval; |
/* push global reference */ |
sym = get_sym_ref(type, sec, addr, size); |
cval.ul = 0; |
vsetc(type, VT_CONST | VT_SYM, &cval); |
vtop->sym = sym; |
} |
/* handles bounds now because the symbol must be defined |
before for the relocation */ |
if (do_bounds_check) { |
unsigned long *bounds_ptr; |
greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_32); |
/* then add global bound info */ |
bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(long)); |
bounds_ptr[0] = 0; /* relocated */ |
bounds_ptr[1] = size; |
} |
} |
if (has_init) { |
decl_initializer(type, sec, addr, 1, 0); |
/* restore parse state if needed */ |
if (init_str.str) { |
tok_str_free(init_str.str); |
restore_parse_state(&saved_parse_state); |
} |
} |
no_alloc: ; |
} |
void put_func_debug(Sym *sym) |
{ |
char buf[512]; |
/* stabs info */ |
/* XXX: we put here a dummy type */ |
snprintf(buf, sizeof(buf), "%s:%c1", |
funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); |
put_stabs_r(buf, N_FUN, 0, file->line_num, 0, |
cur_text_section, sym->c); |
last_ind = 0; |
last_line_num = 0; |
} |
/* parse an old style function declaration list */ |
/* XXX: check multiple parameter */ |
static void func_decl_list(Sym *func_sym) |
{ |
AttributeDef ad; |
int v; |
Sym *s; |
CType btype, type; |
/* parse each declaration */ |
while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF) { |
if (!parse_btype(&btype, &ad)) |
expect("declaration list"); |
if (((btype.t & VT_BTYPE) == VT_ENUM || |
(btype.t & VT_BTYPE) == VT_STRUCT) && |
tok == ';') { |
/* we accept no variable after */ |
} else { |
for(;;) { |
type = btype; |
type_decl(&type, &ad, &v, TYPE_DIRECT); |
/* find parameter in function parameter list */ |
s = func_sym->next; |
while (s != NULL) { |
if ((s->v & ~SYM_FIELD) == v) |
goto found; |
s = s->next; |
} |
error("declaration for parameter '%s' but no such parameter", |
get_tok_str(v, NULL)); |
found: |
/* check that no storage specifier except 'register' was given */ |
if (type.t & VT_STORAGE) |
error("storage class specified for '%s'", get_tok_str(v, NULL)); |
convert_parameter_type(&type); |
/* we can add the type (NOTE: it could be local to the function) */ |
s->type = type; |
/* accept other parameters */ |
if (tok == ',') |
next(); |
else |
break; |
} |
} |
skip(';'); |
} |
} |
/* parse a function defined by symbol 'sym' and generate its code in |
'cur_text_section' */ |
static void gen_function(Sym *sym) |
{ |
ind = cur_text_section->data_offset; |
/* NOTE: we patch the symbol size later */ |
put_extern_sym(sym, cur_text_section, ind, 0); |
funcname = get_tok_str(sym->v, NULL); |
func_ind = ind; |
/* put debug symbol */ |
if (do_debug) |
put_func_debug(sym); |
/* push a dummy symbol to enable local sym storage */ |
sym_push2(&local_stack, SYM_FIELD, 0, 0); |
gfunc_prolog(&sym->type); |
rsym = 0; |
block(NULL, NULL, NULL, NULL, 0, 0); |
gsym(rsym); |
gfunc_epilog(); |
cur_text_section->data_offset = ind; |
label_pop(&global_label_stack, NULL); |
sym_pop(&local_stack, NULL); /* reset local stack */ |
/* end of function */ |
/* patch symbol size */ |
((Elf32_Sym *)symtab_section->data)[sym->c].st_size = |
ind - func_ind; |
if (do_debug) { |
put_stabn(N_FUN, 0, 0, ind - func_ind); |
} |
funcname = ""; /* for safety */ |
func_vt.t = VT_VOID; /* for safety */ |
ind = 0; /* for safety */ |
} |
static void gen_inline_functions(void) |
{ |
Sym *sym; |
CType *type; |
int *str, inline_generated; |
/* iterate while inline function are referenced */ |
for(;;) { |
inline_generated = 0; |
for(sym = global_stack; sym != NULL; sym = sym->prev) { |
type = &sym->type; |
if (((type->t & VT_BTYPE) == VT_FUNC) && |
(type->t & (VT_STATIC | VT_INLINE)) == |
(VT_STATIC | VT_INLINE) && |
sym->c != 0) { |
/* the function was used: generate its code and |
convert it to a normal function */ |
str = (int *)sym->r; |
sym->r = VT_SYM | VT_CONST; |
type->t &= ~VT_INLINE; |
macro_ptr = str; |
next(); |
cur_text_section = text_section; |
gen_function(sym); |
macro_ptr = NULL; /* fail safe */ |
tok_str_free(str); |
inline_generated = 1; |
} |
} |
if (!inline_generated) |
break; |
} |
/* free all remaining inline function tokens */ |
for(sym = global_stack; sym != NULL; sym = sym->prev) { |
type = &sym->type; |
if (((type->t & VT_BTYPE) == VT_FUNC) && |
(type->t & (VT_STATIC | VT_INLINE)) == |
(VT_STATIC | VT_INLINE)) { |
str = (int *)sym->r; |
tok_str_free(str); |
sym->r = 0; /* fail safe */ |
} |
} |
} |
/* 'l' is VT_LOCAL or VT_CONST to define default storage type */ |
static void decl(int l) |
{ |
int v, has_init, r; |
CType type, btype; |
Sym *sym; |
AttributeDef ad; |
while (1) { |
if (!parse_btype(&btype, &ad)) { |
/* skip redundant ';' */ |
/* XXX: find more elegant solution */ |
if (tok == ';') { |
next(); |
continue; |
} |
if (l == VT_CONST && |
(tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { |
/* global asm block */ |
asm_global_instr(); |
continue; |
} |
/* special test for old K&R protos without explicit int |
type. Only accepted when defining global data */ |
if (l == VT_LOCAL || tok < TOK_DEFINE) |
break; |
btype.t = VT_INT; |
} |
if (((btype.t & VT_BTYPE) == VT_ENUM || |
(btype.t & VT_BTYPE) == VT_STRUCT) && |
tok == ';') { |
/* we accept no variable after */ |
next(); |
continue; |
} |
while (1) { /* iterate thru each declaration */ |
type = btype; |
type_decl(&type, &ad, &v, TYPE_DIRECT); |
#if 0 |
{ |
char buf[500]; |
type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL)); |
printf("type = '%s'\n", buf); |
} |
#endif |
if ((type.t & VT_BTYPE) == VT_FUNC) { |
/* if old style function prototype, we accept a |
declaration list */ |
sym = type.ref; |
if (sym->c == FUNC_OLD) |
func_decl_list(sym); |
} |
if (tok == '{') { |
if (l == VT_LOCAL) |
error("cannot use local functions"); |
if (!(type.t & VT_FUNC)) |
expect("function definition"); |
/* reject abstract declarators in function definition */ |
sym = type.ref; |
while ((sym = sym->next) != NULL) |
if (!(sym->v & ~SYM_FIELD)) |
expect("identifier"); |
/* XXX: cannot do better now: convert extern line to static inline */ |
if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) |
type.t = (type.t & ~VT_EXTERN) | VT_STATIC; |
sym = sym_find(v); |
if (sym) { |
if ((sym->type.t & VT_BTYPE) != VT_FUNC) |
goto func_error1; |
/* specific case: if not func_call defined, we put |
the one of the prototype */ |
/* XXX: should have default value */ |
if (sym->type.ref->r != FUNC_CDECL && |
type.ref->r == FUNC_CDECL) |
type.ref->r = sym->type.ref->r; |
if (!is_compatible_types(&sym->type, &type)) { |
func_error1: |
error("incompatible types for redefinition of '%s'", |
get_tok_str(v, NULL)); |
} |
/* if symbol is already defined, then put complete type */ |
sym->type = type; |
} else { |
/* put function symbol */ |
sym = global_identifier_push(v, type.t, 0); |
sym->type.ref = type.ref; |
} |
/* static inline functions are just recorded as a kind |
of macro. Their code will be emitted at the end of |
the compilation unit only if they are used */ |
if ((type.t & (VT_INLINE | VT_STATIC)) == |
(VT_INLINE | VT_STATIC)) { |
TokenString func_str; |
int block_level; |
tok_str_new(&func_str); |
block_level = 0; |
for(;;) { |
int t; |
if (tok == TOK_EOF) |
error("unexpected end of file"); |
tok_str_add_tok(&func_str); |
t = tok; |
next(); |
if (t == '{') { |
block_level++; |
} else if (t == '}') { |
block_level--; |
if (block_level == 0) |
break; |
} |
} |
tok_str_add(&func_str, -1); |
tok_str_add(&func_str, 0); |
sym->r = (int)func_str.str; |
} else { |
/* compute text section */ |
cur_text_section = ad.section; |
if (!cur_text_section) |
cur_text_section = text_section; |
sym->r = VT_SYM | VT_CONST; |
gen_function(sym); |
#ifdef TCC_TARGET_PE |
if (s->output_type == TCC_OUTPUT_DLL) |
strcpy(ext, ".dll"); |
if (ad.dllexport) { |
((Elf32_Sym *)symtab_section->data)[sym->c].st_other |= 1; |
} |
#endif |
} |
break; |
} else { |
if (btype.t & VT_TYPEDEF) { |
/* save typedefed type */ |
/* XXX: test storage specifiers ? */ |
sym = sym_push(v, &type, 0, 0); |
sym->type.t |= VT_TYPEDEF; |
} else if ((type.t & VT_BTYPE) == VT_FUNC) { |
/* external function definition */ |
/* specific case for func_call attribute */ |
if (ad.func_call) |
type.ref->r = ad.func_call; |
external_sym(v, &type, 0); |
} else { |
/* not lvalue if array */ |
r = 0; |
if (!(type.t & VT_ARRAY)) |
r |= lvalue_type(type.t); |
has_init = (tok == '='); |
if ((btype.t & VT_EXTERN) || |
((type.t & VT_ARRAY) && (type.t & VT_STATIC) && |
!has_init && l == VT_CONST && type.ref->c < 0)) { |
/* external variable */ |
/* NOTE: as GCC, uninitialized global static |
arrays of null size are considered as |
extern */ |
external_sym(v, &type, r); |
} else { |
if (type.t & VT_STATIC) |
r |= VT_CONST; |
else |
if (s->output_type == TCC_OUTPUT_EXE) |
strcpy(ext, ".exe"); |
r |= l; |
if (has_init) |
next(); |
decl_initializer_alloc(&type, &ad, r, |
has_init, v, l); |
} |
} |
if (tok != ',') { |
skip(';'); |
break; |
} |
next(); |
} |
} |
} |
} |
/* better than nothing, but needs extension to handle '-E' option |
correctly too */ |
static void preprocess_init(TCCState *s1) |
{ |
s1->include_stack_ptr = s1->include_stack; |
/* XXX: move that before to avoid having to initialize |
file->ifdef_stack_ptr ? */ |
s1->ifdef_stack_ptr = s1->ifdef_stack; |
file->ifdef_stack_ptr = s1->ifdef_stack_ptr; |
/* XXX: not ANSI compliant: bound checking says error */ |
vtop = vstack - 1; |
s1->pack_stack[0] = 0; |
s1->pack_stack_ptr = s1->pack_stack; |
} |
/* compile the C file opened in 'file'. Return non zero if errors. */ |
static int tcc_compile(TCCState *s1) |
{ |
Sym *define_start; |
char buf[512]; |
volatile int section_sym; |
#ifdef INC_DEBUG |
printf("%s: **** new file\n", file->filename); |
#endif |
preprocess_init(s1); |
funcname = ""; |
anon_sym = SYM_FIRST_ANOM; |
/* file info: full path + filename */ |
section_sym = 0; /* avoid warning */ |
if (do_debug) { |
section_sym = put_elf_sym(symtab_section, 0, 0, |
ELF32_ST_INFO(STB_LOCAL, STT_SECTION), 0, |
text_section->sh_num, NULL); |
getcwd(buf, sizeof(buf)); |
pstrcat(buf, sizeof(buf), "/"); |
put_stabs_r(buf, N_SO, 0, 0, |
text_section->data_offset, text_section, section_sym); |
put_stabs_r(file->filename, N_SO, 0, 0, |
text_section->data_offset, text_section, section_sym); |
} |
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL |
symbols can be safely used */ |
put_elf_sym(symtab_section, 0, 0, |
ELF32_ST_INFO(STB_LOCAL, STT_FILE), 0, |
SHN_ABS, file->filename); |
/* define some often used types */ |
int_type.t = VT_INT; |
char_pointer_type.t = VT_BYTE; |
mk_pointer(&char_pointer_type); |
func_old_type.t = VT_FUNC; |
func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD); |
#if 0 |
/* define 'void *alloca(unsigned int)' builtin function */ |
{ |
Sym *s1; |
p = anon_sym++; |
sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW); |
s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0); |
s1->next = NULL; |
sym->next = s1; |
sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0); |
} |
#endif |
define_start = define_stack; |
if (setjmp(s1->error_jmp_buf) == 0) { |
s1->nb_errors = 0; |
s1->error_set_jmp_enabled = 1; |
ch = file->buf_ptr[0]; |
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; |
parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM; |
next(); |
decl(VT_CONST); |
if (tok != TOK_EOF) |
expect("declaration"); |
/* end of translation unit info */ |
if (do_debug) { |
put_stabs_r(NULL, N_SO, 0, 0, |
text_section->data_offset, text_section, section_sym); |
} |
} |
s1->error_set_jmp_enabled = 0; |
/* reset define stack, but leave -Dsymbols (may be incorrect if |
they are undefined) */ |
free_defines(define_start); |
gen_inline_functions(); |
sym_pop(&global_stack, NULL); |
return s1->nb_errors != 0 ? -1 : 0; |
} |
#ifdef LIBTCC |
int tcc_compile_string(TCCState *s, const char *str) |
{ |
BufferedFile bf1, *bf = &bf1; |
int ret, len; |
char *buf; |
/* init file structure */ |
bf->fd = -1; |
/* XXX: avoid copying */ |
len = strlen(str); |
buf = tcc_malloc(len + 1); |
if (!buf) |
return -1; |
memcpy(buf, str, len); |
buf[len] = CH_EOB; |
bf->buf_ptr = buf; |
bf->buf_end = buf + len; |
pstrcpy(bf->filename, sizeof(bf->filename), "<string>"); |
bf->line_num = 1; |
file = bf; |
ret = tcc_compile(s); |
tcc_free(buf); |
/* currently, no need to close */ |
return ret; |
} |
#endif |
/* define a preprocessor symbol. A value can also be provided with the '=' operator */ |
void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) |
{ |
BufferedFile bf1, *bf = &bf1; |
pstrcpy(bf->buffer, IO_BUF_SIZE, sym); |
pstrcat(bf->buffer, IO_BUF_SIZE, " "); |
/* default value */ |
if (!value) |
value = "1"; |
pstrcat(bf->buffer, IO_BUF_SIZE, value); |
/* init file structure */ |
bf->fd = -1; |
bf->buf_ptr = bf->buffer; |
bf->buf_end = bf->buffer + strlen(bf->buffer); |
*bf->buf_end = CH_EOB; |
bf->filename[0] = '\0'; |
bf->line_num = 1; |
file = bf; |
s1->include_stack_ptr = s1->include_stack; |
/* parse with define parser */ |
ch = file->buf_ptr[0]; |
next_nomacro(); |
parse_define(); |
file = NULL; |
} |
/* undefine a preprocessor symbol */ |
void tcc_undefine_symbol(TCCState *s1, const char *sym) |
{ |
TokenSym *ts; |
Sym *s; |
ts = tok_alloc(sym, strlen(sym)); |
s = define_find(ts->tok); |
/* undefine symbol by putting an invalid name */ |
if (s) |
define_undef(s); |
} |
#ifdef CONFIG_TCC_ASM |
#ifdef TCC_TARGET_I386 |
#include "i386-asm.c" |
#endif |
#include "tccasm.c" |
#else |
static void asm_instr(void) |
{ |
error("inline asm() not supported"); |
} |
static void asm_global_instr(void) |
{ |
error("inline asm() not supported"); |
} |
#endif |
#include "tccelf.c" |
#ifdef TCC_TARGET_COFF |
#include "tcccoff.c" |
#endif |
#if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
#include "tccpe.c" |
#endif |
#ifdef TCC_TARGET_MEOS |
#include "tccmeos.c" |
#endif |
/* print the position in the source file of PC value 'pc' by reading |
the stabs debug information */ |
static void rt_printline(unsigned long wanted_pc) |
{ |
Stab_Sym *sym, *sym_end; |
char func_name[128], last_func_name[128]; |
unsigned long func_addr, last_pc, pc; |
const char *incl_files[INCLUDE_STACK_SIZE]; |
int incl_index, len, last_line_num, i; |
const char *str, *p; |
printf("0x%08lx:", wanted_pc); |
func_name[0] = '\0'; |
func_addr = 0; |
incl_index = 0; |
last_func_name[0] = '\0'; |
last_pc = 0xffffffff; |
last_line_num = 1; |
sym = (Stab_Sym *)stab_section->data + 1; |
sym_end = (Stab_Sym *)(stab_section->data + stab_section->data_offset); |
while (sym < sym_end) { |
switch(sym->n_type) { |
/* function start or end */ |
case N_FUN: |
if (sym->n_strx == 0) { |
/* we test if between last line and end of function */ |
pc = sym->n_value + func_addr; |
if (wanted_pc >= last_pc && wanted_pc < pc) |
goto found; |
func_name[0] = '\0'; |
func_addr = 0; |
} else { |
str = stabstr_section->data + sym->n_strx; |
p = strchr(str, ':'); |
if (!p) { |
pstrcpy(func_name, sizeof(func_name), str); |
} else { |
len = p - str; |
if (len > sizeof(func_name) - 1) |
len = sizeof(func_name) - 1; |
memcpy(func_name, str, len); |
func_name[len] = '\0'; |
} |
func_addr = sym->n_value; |
} |
break; |
/* line number info */ |
case N_SLINE: |
pc = sym->n_value + func_addr; |
if (wanted_pc >= last_pc && wanted_pc < pc) |
goto found; |
last_pc = pc; |
last_line_num = sym->n_desc; |
/* XXX: slow! */ |
strcpy(last_func_name, func_name); |
break; |
/* include files */ |
case N_BINCL: |
str = stabstr_section->data + sym->n_strx; |
add_incl: |
if (incl_index < INCLUDE_STACK_SIZE) { |
incl_files[incl_index++] = str; |
} |
break; |
case N_EINCL: |
if (incl_index > 1) |
incl_index--; |
break; |
case N_SO: |
if (sym->n_strx == 0) { |
incl_index = 0; /* end of translation unit */ |
} else { |
str = stabstr_section->data + sym->n_strx; |
/* do not add path */ |
len = strlen(str); |
if (len > 0 && str[len - 1] != '/') |
goto add_incl; |
} |
break; |
} |
sym++; |
} |
/* second pass: we try symtab symbols (no line number info) */ |
incl_index = 0; |
{ |
Elf32_Sym *sym, *sym_end; |
int type; |
sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); |
for(sym = (Elf32_Sym *)symtab_section->data + 1; |
sym < sym_end; |
sym++) { |
type = ELF32_ST_TYPE(sym->st_info); |
if (type == STT_FUNC) { |
if (wanted_pc >= sym->st_value && |
wanted_pc < sym->st_value + sym->st_size) { |
pstrcpy(last_func_name, sizeof(last_func_name), |
strtab_section->data + sym->st_name); |
goto found; |
} |
} |
} |
} |
/* did not find any info: */ |
printf(" ???\n"); |
return; |
found: |
if (last_func_name[0] != '\0') { |
printf(" %s()", last_func_name); |
} |
if (incl_index > 0) { |
printf(" (%s:%d", |
incl_files[incl_index - 1], last_line_num); |
for(i = incl_index - 2; i >= 0; i--) |
printf(", included from %s", incl_files[i]); |
printf(")"); |
} |
printf("\n"); |
} |
#if !defined(WIN32) && !defined(CONFIG_TCCBOOT) |
#ifdef __i386__ |
/* fix for glibc 2.1 */ |
#ifndef REG_EIP |
#define REG_EIP EIP |
#define REG_EBP EBP |
#endif |
/* return the PC at frame level 'level'. Return non zero if not found */ |
/* |
static int rt_get_caller_pc(unsigned long *paddr, |
ucontext_t *uc, int level) |
{ |
unsigned long fp; |
int i; |
if (level == 0) { |
#if defined(__FreeBSD__) |
*paddr = uc->uc_mcontext.mc_eip; |
#elif defined(__dietlibc__) |
*paddr = uc->uc_mcontext.eip; |
#else |
*paddr = uc->uc_mcontext.gregs[REG_EIP]; |
#endif |
return 0; |
} else { |
#if defined(__FreeBSD__) |
fp = uc->uc_mcontext.mc_ebp; |
#elif defined(__dietlibc__) |
fp = uc->uc_mcontext.ebp; |
#else |
fp = uc->uc_mcontext.gregs[REG_EBP]; |
#endif |
for(i=1;i<level;i++) { |
// XXX: check address validity with program info |
if (fp <= 0x1000 || fp >= 0xc0000000) |
return -1; |
fp = ((unsigned long *)fp)[0]; |
} |
*paddr = ((unsigned long *)fp)[1]; |
return 0; |
} |
} |
*/ |
#else |
#warning add arch specific rt_get_caller_pc() |
/* |
static int rt_get_caller_pc(unsigned long *paddr, |
ucontext_t *uc, int level) |
{ |
return -1; |
} |
*/ |
#endif |
/* emit a run time error at position 'pc' */ |
/* |
void rt_error(ucontext_t *uc, const char *fmt, ...) |
{ |
va_list ap; |
unsigned long pc; |
int i; |
va_start(ap, fmt); |
printf("Runtime error: "); |
//vfprintf(stderr, fmt, ap); |
printf("\n"); |
for(i=0;i<num_callers;i++) { |
if (rt_get_caller_pc(&pc, uc, i) < 0) |
break; |
if (i == 0) |
printf("at "); |
else |
printf("by "); |
rt_printline(pc); |
} |
exit(255); |
va_end(ap); |
} |
*/ |
/* signal handler for fatal errors */ |
/* |
static void sig_error(int signum, siginfo_t *siginf, void *puc) |
{ |
ucontext_t *uc = puc; |
switch(signum) { |
case SIGFPE: |
switch(siginf->si_code) { |
case FPE_INTDIV: |
case FPE_FLTDIV: |
rt_error(uc, "division by zero"); |
break; |
default: |
rt_error(uc, "floating point exception"); |
break; |
} |
break; |
case SIGBUS: |
case SIGSEGV: |
if (rt_bound_error_msg && *rt_bound_error_msg) |
rt_error(uc, *rt_bound_error_msg); |
else |
rt_error(uc, "dereferencing invalid pointer"); |
break; |
case SIGILL: |
rt_error(uc, "illegal instruction"); |
break; |
case SIGABRT: |
rt_error(uc, "abort() called"); |
break; |
default: |
rt_error(uc, "caught signal %d", signum); |
break; |
} |
exit(255); |
} |
*/ |
#endif |
if (( (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) || |
(s->output_type == TCC_OUTPUT_PREPROCESS) ) |
&& *ext) |
strcpy(ext, ".o"); |
/* do all relocations (needed before using tcc_get_symbol()) */ |
int tcc_relocate(TCCState *s1) |
{ |
Section *s; |
int i; |
s1->nb_errors = 0; |
#if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
pe_add_runtime(s1); |
#else |
tcc_add_runtime(s1); |
#endif |
relocate_common_syms(); |
tcc_add_linker_symbols(s1); |
build_got_entries(s1); |
/* compute relocation address : section are relocated in place. We |
also alloc the bss space */ |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[i]; |
if (s->sh_flags & SHF_ALLOC) { |
if (s->sh_type == SHT_NOBITS) |
s->data = tcc_mallocz(s->data_offset); |
s->sh_addr = (unsigned long)s->data; |
} |
} |
relocate_syms(s1, 1); |
if (s1->nb_errors != 0) |
return -1; |
/* relocate each section */ |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[i]; |
if (s->reloc) |
relocate_section(s1, s); |
} |
return 0; |
} |
/* launch the compiled program with the given arguments */ |
int tcc_run(TCCState *s1, int argc, char **argv) |
{ |
int (*prog_main)(int, char **); |
if (tcc_relocate(s1) < 0) |
return -1; |
prog_main = tcc_get_symbol_err(s1, "main"); |
if (do_debug) { |
#if defined(WIN32) || defined(CONFIG_TCCBOOT) |
error("debug mode currently not available for Windows"); |
#else |
//struct sigaction sigact; |
/* install TCC signal handlers to print debug info on fatal |
runtime errors */ |
//sigact.sa_flags = SA_SIGINFO | SA_RESETHAND; |
//sigact.sa_sigaction = sig_error; |
//sigemptyset(&sigact.sa_mask); |
//sigaction(SIGFPE, &sigact, NULL); |
//sigaction(SIGILL, &sigact, NULL); |
//sigaction(SIGSEGV, &sigact, NULL); |
//sigaction(SIGBUS, &sigact, NULL); |
//sigaction(SIGABRT, &sigact, NULL); |
#endif |
} |
#ifdef CONFIG_TCC_BCHECK |
if (do_bounds_check) { |
void (*bound_init)(void); |
/* set error function */ |
rt_bound_error_msg = (void *)tcc_get_symbol_err(s1, |
"__bound_error_msg"); |
/* XXX: use .init section so that it also work in binary ? */ |
bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init"); |
bound_init(); |
} |
#endif |
return (*prog_main)(argc, argv); |
} |
TCCState *tcc_new(void) |
{ |
const char *p, *r; |
TCCState *s; |
TokenSym *ts; |
int i, c; |
s = tcc_mallocz(sizeof(TCCState)); |
if (!s) |
return NULL; |
tcc_state = s; |
s->output_type = TCC_OUTPUT_MEMORY; |
/* init isid table */ |
for(i=0;i<256;i++) |
isidnum_table[i] = isid(i) || isnum(i); |
/* add all tokens */ |
table_ident = NULL; |
memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *)); |
tok_ident = TOK_IDENT; |
p = tcc_keywords; |
while (*p) { |
r = p; |
for(;;) { |
c = *r++; |
if (c == '\0') |
break; |
} |
ts = tok_alloc(p, r - p - 1); |
p = r; |
} |
/* we add dummy defines for some special macros to speed up tests |
and to have working defined() */ |
define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL); |
define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL); |
define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL); |
define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL); |
/* standard defines */ |
tcc_define_symbol(s, "__STDC__", NULL); |
#if defined(TCC_TARGET_I386) |
tcc_define_symbol(s, "__i386__", NULL); |
#endif |
#if defined(TCC_TARGET_ARM) |
tcc_define_symbol(s, "__ARM_ARCH_4__", NULL); |
tcc_define_symbol(s, "__arm_elf__", NULL); |
tcc_define_symbol(s, "__arm_elf", NULL); |
tcc_define_symbol(s, "arm_elf", NULL); |
tcc_define_symbol(s, "__arm__", NULL); |
tcc_define_symbol(s, "__arm", NULL); |
tcc_define_symbol(s, "arm", NULL); |
tcc_define_symbol(s, "__APCS_32__", NULL); |
#endif |
#if defined(linux) |
tcc_define_symbol(s, "__linux__", NULL); |
tcc_define_symbol(s, "linux", NULL); |
#endif |
/* tiny C specific defines */ |
tcc_define_symbol(s, "__TINYC__", NULL); |
/* tiny C & gcc defines */ |
tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned int"); |
tcc_define_symbol(s, "__PTRDIFF_TYPE__", "int"); |
tcc_define_symbol(s, "__WCHAR_TYPE__", "int"); |
/* default library paths */ |
#ifdef TCC_TARGET_PE |
{ |
char buf[1024]; |
snprintf(buf, sizeof(buf), "%s/lib", tcc_lib_path); |
tcc_add_library_path(s, buf); |
} |
#else |
#ifdef TCC_TARGET_MEOS |
tcc_add_library_path(s, ".//lib"); |
#else |
tcc_add_library_path(s, "/usr/local/lib"); |
tcc_add_library_path(s, "/usr/lib"); |
tcc_add_library_path(s, "/lib"); |
#endif |
#endif |
/* no section zero */ |
dynarray_add((void ***)&s->sections, &s->nb_sections, NULL); |
/* create standard sections */ |
text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); |
/* symbols are always generated for linking stage */ |
symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0, |
".strtab", |
".hashtab", SHF_PRIVATE); |
strtab_section = symtab_section->link; |
/* private symbol table for dynamic symbols */ |
s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE, |
".dynstrtab", |
".dynhashtab", SHF_PRIVATE); |
s->alacarte_link = 1; |
#ifdef CHAR_IS_UNSIGNED |
s->char_is_unsigned = 1; |
#endif |
#if defined(TCC_TARGET_PE) && 0 |
/* XXX: currently the PE linker is not ready to support that */ |
s->leading_underscore = 1; |
#endif |
return s; |
} |
void tcc_delete(TCCState *s1) |
{ |
int i, n; |
/* free -D defines */ |
free_defines(NULL); |
/* free tokens */ |
n = tok_ident - TOK_IDENT; |
for(i = 0; i < n; i++) |
tcc_free(table_ident[i]); |
tcc_free(table_ident); |
/* free all sections */ |
free_section(symtab_section->hash); |
free_section(s1->dynsymtab_section->hash); |
free_section(s1->dynsymtab_section->link); |
free_section(s1->dynsymtab_section); |
for(i = 1; i < s1->nb_sections; i++) |
free_section(s1->sections[i]); |
tcc_free(s1->sections); |
/* free loaded dlls array */ |
for(i = 0; i < s1->nb_loaded_dlls; i++) |
tcc_free(s1->loaded_dlls[i]); |
tcc_free(s1->loaded_dlls); |
/* library paths */ |
for(i = 0; i < s1->nb_library_paths; i++) |
tcc_free(s1->library_paths[i]); |
tcc_free(s1->library_paths); |
/* cached includes */ |
for(i = 0; i < s1->nb_cached_includes; i++) |
tcc_free(s1->cached_includes[i]); |
tcc_free(s1->cached_includes); |
for(i = 0; i < s1->nb_include_paths; i++) |
tcc_free(s1->include_paths[i]); |
tcc_free(s1->include_paths); |
for(i = 0; i < s1->nb_sysinclude_paths; i++) |
tcc_free(s1->sysinclude_paths[i]); |
tcc_free(s1->sysinclude_paths); |
tcc_free(s1); |
} |
int tcc_add_include_path(TCCState *s1, const char *pathname) |
{ |
char *pathname1; |
pathname1 = tcc_strdup(pathname); |
dynarray_add((void ***)&s1->include_paths, &s1->nb_include_paths, pathname1); |
return 0; |
} |
int tcc_add_sysinclude_path(TCCState *s1, const char *pathname) |
{ |
char *pathname1; |
pathname1 = tcc_strdup(pathname); |
dynarray_add((void ***)&s1->sysinclude_paths, &s1->nb_sysinclude_paths, pathname1); |
return 0; |
} |
static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) |
{ |
const char *ext, *filename1; |
Elf32_Ehdr ehdr; |
int fd, ret; |
BufferedFile *saved_file; |
/* find source file type with extension */ |
filename1 = strrchr(filename, '/'); |
if (filename1) |
filename1++; |
else |
strcpy(buf, "a.out"); |
filename1 = filename; |
ext = strrchr(filename1, '.'); |
if (ext) |
ext++; |
return tcc_strdup(buf); |
/* open the file */ |
saved_file = file; |
file = tcc_open(s1, filename); |
if (!file) { |
if (flags & AFF_PRINT_ERROR) { |
error_noabort("file '%s' not found", filename); |
} |
ret = -1; |
goto fail1; |
} |
if (!ext || !strcmp(ext, "c")) { |
/* C file assumed */ |
ret = tcc_compile(s1); |
} else |
#ifdef CONFIG_TCC_ASM |
if (!strcmp(ext, "S")) { |
/* preprocessed assembler */ |
ret = tcc_assemble(s1, 1); |
} else if (!strcmp(ext, "s")) { |
/* non preprocessed assembler */ |
ret = tcc_assemble(s1, 0); |
} else |
#endif |
#ifdef TCC_TARGET_PE |
if (!strcmp(ext, "def")) { |
ret = pe_load_def_file(s1, fdopen(file->fd, "rb")); |
} else |
#endif |
{ |
fd = file->fd; |
/* assume executable format: auto guess file type */ |
ret = read(fd, &ehdr, sizeof(ehdr)); |
lseek(fd, 0, SEEK_SET); |
if (ret <= 0) { |
error_noabort("could not read header"); |
goto fail; |
} else if (ret != sizeof(ehdr)) { |
goto try_load_script; |
} |
if (ehdr.e_ident[0] == ELFMAG0 && |
ehdr.e_ident[1] == ELFMAG1 && |
ehdr.e_ident[2] == ELFMAG2 && |
ehdr.e_ident[3] == ELFMAG3) { |
file->line_num = 0; /* do not display line number if error */ |
if (ehdr.e_type == ET_REL) { |
ret = tcc_load_object_file(s1, fd, 0); |
} else if (ehdr.e_type == ET_DYN) { |
if (s1->output_type == TCC_OUTPUT_MEMORY) { |
#if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
ret = -1; |
#else |
void *h; |
h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); |
if (h) |
ret = 0; |
else |
ret = -1; |
#endif |
} else { |
ret = tcc_load_dll(s1, fd, filename, |
(flags & AFF_REFERENCED_DLL) != 0); |
} |
} else { |
error_noabort("unrecognized ELF file"); |
goto fail; |
} |
} else if (memcmp((char *)&ehdr, ARMAG, 8) == 0) { |
file->line_num = 0; /* do not display line number if error */ |
ret = tcc_load_archive(s1, fd); |
} else |
#ifdef TCC_TARGET_COFF |
if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) { |
ret = tcc_load_coff(s1, fd); |
} else |
#endif |
{ |
/* as GNU ld, consider it is an ld script if not recognized */ |
try_load_script: |
ret = tcc_load_ldscript(s1); |
if (ret < 0) { |
error_noabort("unrecognized file type"); |
goto fail; |
} |
} |
} |
the_end: |
tcc_close(file); |
fail1: |
file = saved_file; |
return ret; |
fail: |
ret = -1; |
goto the_end; |
} |
int tcc_add_file(TCCState *s, const char *filename) |
{ |
return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR); |
} |
int tcc_add_library_path(TCCState *s, const char *pathname) |
{ |
char *pathname1; |
pathname1 = tcc_strdup(pathname); |
dynarray_add((void ***)&s->library_paths, &s->nb_library_paths, pathname1); |
return 0; |
} |
/* find and load a dll. Return non zero if not found */ |
/* XXX: add '-rpath' option support ? */ |
static int tcc_add_dll(TCCState *s, const char *filename, int flags) |
{ |
char buf[1024]; |
int i; |
for(i = 0; i < s->nb_library_paths; i++) { |
snprintf(buf, sizeof(buf), "%s/%s", |
s->library_paths[i], filename); |
if (tcc_add_file_internal(s, buf, flags) == 0) |
return 0; |
} |
return -1; |
} |
/* the library name is the same as the argument of the '-l' option */ |
int tcc_add_library(TCCState *s, const char *libraryname) |
{ |
char buf[1024]; |
int i; |
/* first we look for the dynamic library if not static linking */ |
if (!s->static_link) { |
#ifdef TCC_TARGET_PE |
snprintf(buf, sizeof(buf), "%s.def", libraryname); |
#else |
snprintf(buf, sizeof(buf), "lib%s.so", libraryname); |
#endif |
if (tcc_add_dll(s, buf, 0) == 0) |
return 0; |
} |
/* then we look for the static library */ |
for(i = 0; i < s->nb_library_paths; i++) { |
snprintf(buf, sizeof(buf), "%s/lib%s.a", |
s->library_paths[i], libraryname); |
if (tcc_add_file_internal(s, buf, 0) == 0) |
return 0; |
} |
return -1; |
} |
int tcc_add_symbol(TCCState *s, const char *name, unsigned long val) |
{ |
add_elf_sym(symtab_section, val, 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
SHN_ABS, name); |
return 0; |
} |
int tcc_set_output_type(TCCState *s, int output_type) |
{ |
s->output_type = output_type; |
if (!s->nostdinc) { |
char buf[1024]; |
/* default include paths */ |
/* XXX: reverse order needed if -isystem support */ |
#if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
tcc_add_sysinclude_path(s, "/usr/local/include"); |
tcc_add_sysinclude_path(s, "/usr/include"); |
#endif |
#if defined(TCC_TARGET_MEOS) |
tcc_add_sysinclude_path(s, ".//include"); |
#endif |
snprintf(buf, sizeof(buf), "%s/include", tcc_lib_path); |
tcc_add_sysinclude_path(s, buf); |
#ifdef TCC_TARGET_PE |
snprintf(buf, sizeof(buf), "%s/include/winapi", tcc_lib_path); |
tcc_add_sysinclude_path(s, buf); |
#endif |
} |
/* if bound checking, then add corresponding sections */ |
#ifdef CONFIG_TCC_BCHECK |
if (do_bounds_check) { |
/* define symbol */ |
tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL); |
/* create bounds sections */ |
bounds_section = new_section(s, ".bounds", |
SHT_PROGBITS, SHF_ALLOC); |
lbounds_section = new_section(s, ".lbounds", |
SHT_PROGBITS, SHF_ALLOC); |
} |
#endif |
if (s->char_is_unsigned) { |
tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL); |
} |
/* add debug sections */ |
if (do_debug) { |
/* stab symbols */ |
stab_section = new_section(s, ".stab", SHT_PROGBITS, 0); |
stab_section->sh_entsize = sizeof(Stab_Sym); |
stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0); |
put_elf_str(stabstr_section, ""); |
stab_section->link = stabstr_section; |
/* put first entry */ |
put_stabs("", 0, 0, 0, 0); |
} |
/* add libc crt1/crti objects */ |
#if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && |
!s->nostdlib) { |
if (output_type != TCC_OUTPUT_DLL) |
tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o"); |
tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o"); |
} |
#endif |
#if defined(TCC_TARGET_MEOS) |
if (s->output_type != TCC_OUTPUT_OBJ) |
tcc_add_file(s,".//start.o"); |
#endif |
return 0; |
} |
#define WD_ALL 0x0001 /* warning is activated when using -Wall */ |
#define FD_INVERT 0x0002 /* invert value before storing */ |
typedef struct FlagDef { |
uint16_t offset; |
uint16_t flags; |
const char *name; |
} FlagDef; |
static const FlagDef warning_defs[] = { |
{ offsetof(TCCState, warn_unsupported), 0, "unsupported" }, |
{ offsetof(TCCState, warn_write_strings), 0, "write-strings" }, |
{ offsetof(TCCState, warn_error), 0, "error" }, |
{ offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, |
"implicit-function-declaration" }, |
}; |
static int set_flag(TCCState *s, const FlagDef *flags, int nb_flags, |
const char *name, int value) |
{ |
int i; |
const FlagDef *p; |
const char *r; |
r = name; |
if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') { |
r += 3; |
value = !value; |
} |
for(i = 0, p = flags; i < nb_flags; i++, p++) { |
if (!strcmp(r, p->name)) |
goto found; |
} |
return -1; |
found: |
if (p->flags & FD_INVERT) |
value = !value; |
*(int *)((uint8_t *)s + p->offset) = value; |
return 0; |
} |
/* set/reset a warning */ |
int tcc_set_warning(TCCState *s, const char *warning_name, int value) |
{ |
int i; |
const FlagDef *p; |
if (!strcmp(warning_name, "all")) { |
for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) { |
if (p->flags & WD_ALL) |
*(int *)((uint8_t *)s + p->offset) = 1; |
} |
return 0; |
} else { |
return set_flag(s, warning_defs, countof(warning_defs), |
warning_name, value); |
} |
} |
static const FlagDef flag_defs[] = { |
{ offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, |
{ offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, |
{ offsetof(TCCState, nocommon), FD_INVERT, "common" }, |
{ offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, |
}; |
/* set/reset a flag */ |
int tcc_set_flag(TCCState *s, const char *flag_name, int value) |
{ |
return set_flag(s, flag_defs, countof(flag_defs), |
flag_name, value); |
} |
#if !defined(LIBTCC) |
/* extract the basename of a file */ |
static const char *tcc_basename(const char *name) |
{ |
const char *p; |
p = strrchr(name, '/'); |
#ifdef WIN32 |
if (!p) |
p = strrchr(name, '\\'); |
#endif |
if (!p) |
p = name; |
else |
p++; |
return p; |
} |
static int64_t getclock_us(void) |
{ |
#ifdef _WIN32 |
LARGE_INTEGER frequency, t1; |
QueryPerformanceFrequency(&frequency); |
QueryPerformanceCounter(&t1); |
return t1.QuadPart * 1000000LL / frequency.QuadPart; |
#ifdef WIN32 |
struct _timeb tb; |
_ftime(&tb); |
return (tb.time * 1000LL + tb.millitm) * 1000LL; |
#else |
struct timeval tv; |
gettimeofday(&tv, NULL); |
252,116 → 10233,525 |
#endif |
} |
int main(int argc, char **argv) |
void help(void) |
{ |
TCCState *s; |
int ret, optind, i; |
int64_t start_time = 0; |
printf("tcc version " TCC_VERSION " - Tiny C Compiler - Copyright (C) 2001-2005 Fabrice Bellard\n" |
"usage: tcc [-v] [-c] [-o outfile] [-Bdir] [-bench] [-Idir] [-Dsym[=val]] [-Usym]\n" |
" [-Wwarn] [-g] [-b] [-bt N] [-Ldir] [-llib] [-shared] [-static]\n" |
" [infile1 infile2...] [-run infile args...]\n" |
"\n" |
"General options:\n" |
" -v display current version\n" |
" -c compile only - generate an object file\n" |
" -o outfile set output filename\n" |
" -Bdir set tcc internal library path\n" |
" -bench output compilation statistics\n" |
" -run run compiled source\n" |
" -fflag set or reset (with 'no-' prefix) 'flag' (see man page)\n" |
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see man page)\n" |
" -w disable all warnings\n" |
"Preprocessor options:\n" |
" -Idir add include path 'dir'\n" |
" -Dsym[=val] define 'sym' with value 'val'\n" |
" -Usym undefine 'sym'\n" |
"Linker options:\n" |
" -Ldir add library path 'dir'\n" |
" -llib link with dynamic or static library 'lib'\n" |
" -shared generate a shared library\n" |
" -static static linking\n" |
" -rdynamic export all global symbols to dynamic linker\n" |
" -r relocatable output\n" |
"Debugger options:\n" |
" -g generate runtime debug info\n" |
" -bt N show N callers in stack traces\n" |
); |
} |
s = tcc_new(); |
#define TCC_OPTION_HAS_ARG 0x0001 |
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ |
optind = tcc_parse_args(s, argc - 1, argv + 1); |
typedef struct TCCOption { |
const char *name; |
uint16_t index; |
uint16_t flags; |
} TCCOption; |
if (s->do_bench) |
start_time = getclock_us(); |
enum { |
TCC_OPTION_HELP, |
TCC_OPTION_I, |
TCC_OPTION_D, |
TCC_OPTION_U, |
TCC_OPTION_L, |
TCC_OPTION_B, |
TCC_OPTION_l, |
TCC_OPTION_bench, |
TCC_OPTION_bt, |
TCC_OPTION_b, |
TCC_OPTION_g, |
TCC_OPTION_c, |
TCC_OPTION_static, |
TCC_OPTION_shared, |
TCC_OPTION_o, |
TCC_OPTION_r, |
TCC_OPTION_Wl, |
TCC_OPTION_W, |
TCC_OPTION_O, |
TCC_OPTION_m, |
TCC_OPTION_f, |
TCC_OPTION_nostdinc, |
TCC_OPTION_nostdlib, |
TCC_OPTION_print_search_dirs, |
TCC_OPTION_rdynamic, |
TCC_OPTION_run, |
TCC_OPTION_v, |
TCC_OPTION_w, |
TCC_OPTION_pipe, |
}; |
tcc_set_environment(s); |
static const TCCOption tcc_options[] = { |
{ "h", TCC_OPTION_HELP, 0 }, |
{ "?", TCC_OPTION_HELP, 0 }, |
{ "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, |
{ "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, |
{ "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, |
{ "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, |
{ "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, |
{ "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
{ "bench", TCC_OPTION_bench, 0 }, |
{ "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG }, |
#ifdef CONFIG_TCC_BCHECK |
{ "b", TCC_OPTION_b, 0 }, |
#endif |
{ "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
{ "c", TCC_OPTION_c, 0 }, |
{ "static", TCC_OPTION_static, 0 }, |
{ "shared", TCC_OPTION_shared, 0 }, |
{ "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, |
{ "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
{ "rdynamic", TCC_OPTION_rdynamic, 0 }, |
{ "r", TCC_OPTION_r, 0 }, |
{ "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
{ "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
{ "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
{ "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG }, |
{ "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, |
{ "nostdinc", TCC_OPTION_nostdinc, 0 }, |
{ "nostdlib", TCC_OPTION_nostdlib, 0 }, |
{ "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, |
{ "v", TCC_OPTION_v, 0 }, |
{ "w", TCC_OPTION_w, 0 }, |
{ "pipe", TCC_OPTION_pipe, 0}, |
{ NULL }, |
}; |
if (optind == 0) { |
/* convert 'str' into an array of space separated strings */ |
static int expand_args(char ***pargv, const char *str) |
{ |
const char *s1; |
char **argv, *arg; |
int argc, len; |
argc = 0; |
argv = NULL; |
for(;;) { |
while (is_space(*str)) |
str++; |
if (*str == '\0') |
break; |
s1 = str; |
while (*str != '\0' && !is_space(*str)) |
str++; |
len = str - s1; |
arg = tcc_malloc(len + 1); |
memcpy(arg, s1, len); |
arg[len] = '\0'; |
dynarray_add((void ***)&argv, &argc, arg); |
} |
*pargv = argv; |
return argc; |
} |
static char **files; |
static int nb_files, nb_libraries; |
static int multiple_files; |
static int print_search_dirs; |
static int output_type; |
static int reloc_output; |
static const char *outfile; |
int parse_args(TCCState *s, int argc, char **argv) |
{ |
int optind; |
int i; |
const TCCOption *popt; |
const char *optarg, *p1, *r1; |
char *r; |
/* |
printf("\n%d\n",argc); |
for(i=0;i<argc;i++) |
{ |
printf("\n parameter %d = %s",i+1,argv[i]); |
} |
printf("\n"); |
*/ |
optind = 0; |
while (1) { |
if (optind >= argc) { |
if (nb_files == 0 && !print_search_dirs) |
goto show_help; |
else |
break; |
} |
r = argv[optind++]; |
if (r[0] != '-') { |
/* add a new file */ |
dynarray_add((void ***)&files, &nb_files, r); |
if (!multiple_files) { |
optind--; |
/* argv[0] will be this file */ |
break; |
} |
} else { |
/* find option in table (match only the first chars */ |
popt = tcc_options; |
for(;;) { |
p1 = popt->name; |
if (p1 == NULL) |
printf("\n invalid option -- '%s'", r); |
r1 = r + 1; |
for(;;) { |
if (*p1 == '\0') |
goto option_found; |
if (*r1 != *p1) |
break; |
p1++; |
r1++; |
} |
popt++; |
} |
option_found: |
if (popt->flags & TCC_OPTION_HAS_ARG) { |
if (*r1 != '\0' || (popt->flags & TCC_OPTION_NOSEP)) { |
optarg = r1; |
} else { |
if (optind >= argc) |
printf("\n argument to '%s' is missing", r); |
optarg = argv[optind++]; |
} |
} else { |
if (*r1 != '\0') |
goto show_help; |
optarg = NULL; |
} |
switch(popt->index) { |
case TCC_OPTION_HELP: |
show_help: |
help(); |
return 1; |
exit(1); |
case TCC_OPTION_I: |
if (tcc_add_include_path(s, optarg) < 0) |
printf("\n too many include paths"); |
break; |
case TCC_OPTION_D: |
{ |
char *sym, *value; |
sym = (char *)optarg; |
value = strchr(sym, '='); |
if (value) { |
*value = '\0'; |
value++; |
} |
tcc_define_symbol(s, sym, value); |
} |
break; |
case TCC_OPTION_U: |
tcc_undefine_symbol(s, optarg); |
break; |
case TCC_OPTION_L: |
tcc_add_library_path(s, optarg); |
break; |
case TCC_OPTION_B: |
/* set tcc utilities path (mainly for tcc development) */ |
tcc_lib_path = optarg; |
break; |
case TCC_OPTION_l: |
dynarray_add((void ***)&files, &nb_files, r); |
nb_libraries++; |
break; |
case TCC_OPTION_bench: |
do_bench = 1; |
break; |
case TCC_OPTION_bt: |
num_callers = atoi(optarg); |
break; |
#ifdef CONFIG_TCC_BCHECK |
case TCC_OPTION_b: |
do_bounds_check = 1; |
do_debug = 1; |
break; |
#endif |
case TCC_OPTION_g: |
do_debug = 1; |
break; |
case TCC_OPTION_c: |
multiple_files = 1; |
output_type = TCC_OUTPUT_OBJ; |
break; |
case TCC_OPTION_static: |
s->static_link = 1; |
break; |
case TCC_OPTION_shared: |
output_type = TCC_OUTPUT_DLL; |
break; |
case TCC_OPTION_o: |
multiple_files = 1; |
outfile = optarg; |
break; |
case TCC_OPTION_r: |
/* generate a .o merging several output files */ |
reloc_output = 1; |
output_type = TCC_OUTPUT_OBJ; |
break; |
case TCC_OPTION_nostdinc: |
s->nostdinc = 1; |
break; |
case TCC_OPTION_nostdlib: |
s->nostdlib = 1; |
break; |
case TCC_OPTION_print_search_dirs: |
print_search_dirs = 1; |
break; |
case TCC_OPTION_run: |
{ |
int argc1; |
char **argv1; |
argc1 = expand_args(&argv1, optarg); |
if (argc1 > 0) { |
parse_args(s, argc1, argv1); |
} |
multiple_files = 0; |
output_type = TCC_OUTPUT_MEMORY; |
} |
break; |
case TCC_OPTION_v: |
printf("tcc version %s\n", TCC_VERSION); |
exit(0); |
case TCC_OPTION_f: |
if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported) |
goto unsupported_option; |
break; |
case TCC_OPTION_W: |
if (tcc_set_warning(s, optarg, 1) < 0 && |
s->warn_unsupported) |
goto unsupported_option; |
break; |
case TCC_OPTION_w: |
s->warn_none = 1; |
break; |
case TCC_OPTION_rdynamic: |
s->rdynamic = 1; |
break; |
case TCC_OPTION_Wl: |
{ |
const char *p; |
if (strstart(optarg, "-Ttext,", &p)) { |
s->text_addr = strtoul(p, NULL, 16); |
s->has_text_addr = 1; |
} else if (strstart(optarg, "--oformat,", &p)) { |
if (strstart(p, "elf32-", NULL)) { |
s->output_format = TCC_OUTPUT_FORMAT_ELF; |
} else if (!strcmp(p, "binary")) { |
s->output_format = TCC_OUTPUT_FORMAT_BINARY; |
} else |
#ifdef TCC_TARGET_COFF |
if (!strcmp(p, "coff")) { |
s->output_format = TCC_OUTPUT_FORMAT_COFF; |
} else |
#endif |
{ |
printf("\n target %s not found", p); |
} |
} else { |
printf("\n unsupported linker option '%s'", optarg); |
} |
} |
break; |
default: |
if (s->warn_unsupported) { |
unsupported_option: |
warning("unsupported option '%s'", r); |
printf("\n unsupported option '%s'", r); |
} |
break; |
} |
} |
} |
return optind; |
} |
if (s->option_m) |
exec_other_tcc(s, argv, s->option_m); |
int main(int argc, char **argv) |
{ |
int i; |
TCCState *s; |
int nb_objfiles, ret, optind; |
char objfilename[1024]; |
int64_t start_time = 0; |
int bug; |
if (s->verbose) |
display_info(s, 0); |
printf("\nTinyC compiler started.\n "); |
#ifdef WIN32 |
/* on win32, we suppose the lib and includes are at the location |
of 'tcc.exe' */ |
{ |
static char path[1024]; |
char *p, *d; |
if (s->print_search_dirs || (s->verbose == 2 && optind == 1)) { |
tcc_set_output_type(s, TCC_OUTPUT_MEMORY); |
display_info(s, 1); |
return 0; |
GetModuleFileNameA(NULL, path, sizeof path); |
p = d = strlwr(path); |
while (*d) |
{ |
if (*d == '\\') *d = '/', p = d; |
++d; |
} |
*p = '\0'; |
tcc_lib_path = path; |
} |
#endif |
if (s->verbose && optind == 1) |
s = tcc_new(); |
output_type = TCC_OUTPUT_EXE; |
outfile = NULL; |
multiple_files = 1; |
files = NULL; |
nb_files = 0; |
nb_libraries = 0; |
reloc_output = 0; |
print_search_dirs = 0; |
printf("TinyC initializated.\n"); |
bug=argc; |
if (bug==0) {bug==1;} |
optind = parse_args(s, bug - 1, argv + 1) + 1; |
printf("\n Arguments parsed.\n"); |
if (print_search_dirs) { |
/* enough for Linux kernel */ |
printf("install: %s/\n", tcc_lib_path); |
return 0; |
} |
if (s->nb_files == 0) |
tcc_error("no input files\n"); |
nb_objfiles = nb_files - nb_libraries; |
/* check -c consistency : only single file handled. XXX: checks file type */ |
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) { |
if (s->nb_libraries != 0) |
tcc_error("cannot specify libraries with -c"); |
/* if outfile provided without other options, we output an |
executable */ |
if (outfile && output_type == TCC_OUTPUT_MEMORY) |
output_type = TCC_OUTPUT_EXE; |
/* check -c |
consistency : only single file handled. XXX: checks file type */ |
if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
/* accepts only a single input file */ |
if ((s->nb_files != 1) && s->outfile) { |
tcc_error("cannot specify multiple files with -c and -o"); |
if (nb_objfiles != 1) |
printf("\n cannot specify multiple files with -c"); |
if (nb_libraries != 0) |
printf("\n cannot specify libraries with -c"); |
} |
if (output_type != TCC_OUTPUT_MEMORY) { |
if (!outfile) { |
/* compute default outfile name */ |
pstrcpy(objfilename, sizeof(objfilename) - 1, |
/* strip path */ |
tcc_basename(files[0])); |
#ifdef TCC_TARGET_PE |
pe_guess_outfile(objfilename, output_type); |
#else |
if (output_type == TCC_OUTPUT_OBJ && !reloc_output) { |
char *ext = strrchr(objfilename, '.'); |
if (!ext) |
goto default_outfile; |
/* add .o extension */ |
strcpy(ext + 1, "o"); |
} else { |
default_outfile: |
pstrcpy(objfilename, sizeof(objfilename), "a.out"); |
} |
#endif |
outfile = objfilename; |
} |
} |
tcc_set_output_type(s, s->output_type); |
if (do_bench) { |
start_time = getclock_us(); |
} |
tcc_set_output_type(s, output_type); |
/* compile or add each files or library */ |
for(i = ret = 0; i < s->nb_files && ret == 0; i++) { |
int filetype = *(unsigned char *)s->files[i]; |
const char *filename = s->files[i] + 1; |
if (filename[0] == '-' && filename[1] == 'l') { |
if (tcc_add_library(s, filename + 2) < 0) { |
/* don't fail on -lm as it's harmless to skip math lib */ |
if (strcmp(filename + 2, "m")) { |
tcc_error_noabort("cannot find library 'lib%s'", filename + 2); |
ret = 1; |
} |
} |
for(i = 0;i < nb_files; i++) { |
const char *filename; |
filename = files[i]; |
if (filename[0] == '-') { |
if (tcc_add_library(s, filename + 2) < 0) |
error("cannot find %s", filename); |
} else { |
if (1 == s->verbose) |
printf("-> %s\n", filename); |
if (!s->outfile) |
s->outfile = default_outputfile(s, filename); |
if (tcc_add_file(s, filename, filetype) < 0) |
if (tcc_add_file(s, filename) < 0) { |
ret = 1; |
else |
if (s->output_type == TCC_OUTPUT_OBJ) { |
ret = !!tcc_output_file(s, s->outfile); |
if (s->gen_deps && !ret) |
gen_makedeps(s, s->outfile, s->deps_outfile); |
if (!ret) { |
if ((i+1) < s->nb_files) { |
tcc_delete(s); |
s = tcc_new(); |
tcc_parse_args(s, argc - 1, argv + 1); |
tcc_set_environment(s); |
if (s->output_type != TCC_OUTPUT_OBJ) |
tcc_error("internal error"); |
tcc_set_output_type(s, s->output_type); |
goto the_end; |
} |
} |
} |
/* free all files */ |
tcc_free(files); |
if (do_bench) { |
double total_time; |
total_time = (double)(getclock_us() - start_time) / 1000000.0; |
if (total_time < 0.001) |
total_time = 0.001; |
if (total_bytes < 1) |
total_bytes = 1; |
printf("%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n", |
tok_ident - TOK_IDENT, total_lines, total_bytes, |
total_time, (int)(total_lines / total_time), |
total_bytes / total_time / 1000000.0); |
} |
} |
if (0 == ret) { |
if (s->output_type == TCC_OUTPUT_MEMORY) { |
#ifdef TCC_IS_NATIVE |
ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind); |
ret = tcc_run(s, argc - optind, argv + optind); |
} else |
#ifdef TCC_TARGET_PE |
if (s->output_type != TCC_OUTPUT_OBJ) { |
ret = tcc_output_pe(s, outfile); |
} else |
#else |
tcc_error_noabort("-run is not available in a cross compiler"); |
ret = 1; |
#ifdef TCC_TARGET_MEOS |
if (s->output_type != TCC_OUTPUT_OBJ) { |
ret = tcc_output_me(s, outfile); |
} else |
#endif |
} else |
if (s->output_type == TCC_OUTPUT_EXE || |
s->output_type == TCC_OUTPUT_DLL) |
#endif |
{ |
ret = !!tcc_output_file(s, s->outfile); |
if (s->gen_deps && !ret) |
gen_makedeps(s, s->outfile, s->deps_outfile); |
tcc_output_file(s, outfile); |
ret = 0; |
} |
the_end: |
/* XXX: cannot do it with bound checking because of the malloc hooks */ |
if (!do_bounds_check) |
tcc_delete(s); |
#ifdef MEM_DEBUG |
if (do_bench) { |
printf("memory: %d bytes, max = %d bytes\n", mem_cur_size, mem_max_size); |
} |
if (s->do_bench) |
tcc_print_stats(s, getclock_us() - start_time); |
tcc_delete(s); |
#endif |
printf("\n TinyC finished work\n"); |
return ret; |
} |
#endif |
/programs/develop/ktcc/trunk/source/tccelf.c |
---|
18,15 → 18,7 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
*/ |
#include "tcc.h" |
/* Define this to get some debug output during relocation processing. */ |
#undef DEBUG_RELOC |
/* XXX: avoid static variable */ |
static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */ |
ST_FUNC int put_elf_str(Section *s, const char *sym) |
static int put_elf_str(Section *s, const char *sym) |
{ |
int offset, len; |
char *ptr; |
57,12 → 49,12 |
/* NOTE: we do factorize the hash table code to go faster */ |
static void rebuild_hash(Section *s, unsigned int nb_buckets) |
{ |
ElfW(Sym) *sym; |
Elf32_Sym *sym; |
int *ptr, *hash, nb_syms, sym_index, h; |
unsigned char *strtab; |
char *strtab; |
strtab = s->link->data; |
nb_syms = s->data_offset / sizeof(ElfW(Sym)); |
nb_syms = s->data_offset / sizeof(Elf32_Sym); |
s->hash->data_offset = 0; |
ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); |
73,9 → 65,9 |
memset(hash, 0, (nb_buckets + 1) * sizeof(int)); |
ptr += nb_buckets + 1; |
sym = (ElfW(Sym) *)s->data + 1; |
sym = (Elf32_Sym *)s->data + 1; |
for(sym_index = 1; sym_index < nb_syms; sym_index++) { |
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
h = elf_hash(strtab + sym->st_name) % nb_buckets; |
*ptr = hash[h]; |
hash[h] = sym_index; |
88,15 → 80,16 |
} |
/* return the symbol number */ |
ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, |
static int put_elf_sym(Section *s, |
unsigned long value, unsigned long size, |
int info, int other, int shndx, const char *name) |
{ |
int name_offset, sym_index; |
int nbuckets, h; |
ElfW(Sym) *sym; |
Elf32_Sym *sym; |
Section *hs; |
sym = section_ptr_add(s, sizeof(ElfW(Sym))); |
sym = section_ptr_add(s, sizeof(Elf32_Sym)); |
if (name) |
name_offset = put_elf_str(s->link, name); |
else |
108,7 → 101,7 |
sym->st_info = info; |
sym->st_other = other; |
sym->st_shndx = shndx; |
sym_index = sym - (ElfW(Sym) *)s->data; |
sym_index = sym - (Elf32_Sym *)s->data; |
hs = s->hash; |
if (hs) { |
int *ptr, *base; |
115,10 → 108,10 |
ptr = section_ptr_add(hs, sizeof(int)); |
base = (int *)hs->data; |
/* only add global or weak symbols */ |
if (ELFW(ST_BIND)(info) != STB_LOCAL) { |
if (ELF32_ST_BIND(info) != STB_LOCAL) { |
/* add another hashing entry */ |
nbuckets = base[0]; |
h = elf_hash((unsigned char *) name) % nbuckets; |
h = elf_hash(name) % nbuckets; |
*ptr = base[2 + h]; |
base[2 + h] = sym_index; |
base[1]++; |
137,9 → 130,9 |
/* find global ELF symbol 'name' and return its index. Return 0 if not |
found. */ |
ST_FUNC int find_elf_sym(Section *s, const char *name) |
static int find_elf_sym(Section *s, const char *name) |
{ |
ElfW(Sym) *sym; |
Elf32_Sym *sym; |
Section *hs; |
int nbuckets, sym_index, h; |
const char *name1; |
148,11 → 141,11 |
if (!hs) |
return 0; |
nbuckets = ((int *)hs->data)[0]; |
h = elf_hash((unsigned char *) name) % nbuckets; |
h = elf_hash(name) % nbuckets; |
sym_index = ((int *)hs->data)[2 + h]; |
while (sym_index != 0) { |
sym = &((ElfW(Sym) *)s->data)[sym_index]; |
name1 = (char *) s->link->data + sym->st_name; |
sym = &((Elf32_Sym *)s->data)[sym_index]; |
name1 = s->link->data + sym->st_name; |
if (!strcmp(name, name1)) |
return sym_index; |
sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; |
160,48 → 153,38 |
return 0; |
} |
/* return elf symbol value, signal error if 'err' is nonzero */ |
ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err) |
/* return elf symbol value or error */ |
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name) |
{ |
int sym_index; |
ElfW(Sym) *sym; |
Elf32_Sym *sym; |
sym_index = find_elf_sym(s->symtab, name); |
sym = &((ElfW(Sym) *)s->symtab->data)[sym_index]; |
if (!sym_index || sym->st_shndx == SHN_UNDEF) { |
if (err) |
tcc_error("%s not defined", name); |
sym_index = find_elf_sym(symtab_section, name); |
if (!sym_index) |
return -1; |
sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
*pval = sym->st_value; |
return 0; |
} |
return sym->st_value; |
} |
/* return elf symbol value */ |
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name) |
void *tcc_get_symbol_err(TCCState *s, const char *name) |
{ |
return (void*)(uintptr_t)get_elf_sym_addr(s, name, 0); |
unsigned long val; |
if (tcc_get_symbol(s, &val, name) < 0) |
error("%s not defined", name); |
return (void *)val; |
} |
#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE || defined TCC_TARGET_MEOS |
/* return elf symbol value or error */ |
ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name) |
{ |
return (void*)(uintptr_t)get_elf_sym_addr(s, name, 1); |
} |
#endif |
/* add an elf symbol : check if it is already defined and patch |
it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ |
ST_FUNC int add_elf_sym(Section *s, addr_t value, unsigned long size, |
static int add_elf_sym(Section *s, unsigned long value, unsigned long size, |
int info, int other, int sh_num, const char *name) |
{ |
ElfW(Sym) *esym; |
Elf32_Sym *esym; |
int sym_bind, sym_index, sym_type, esym_bind; |
unsigned char sym_vis, esym_vis, new_vis; |
sym_bind = ELFW(ST_BIND)(info); |
sym_type = ELFW(ST_TYPE)(info); |
sym_vis = ELFW(ST_VISIBILITY)(other); |
sym_bind = ELF32_ST_BIND(info); |
sym_type = ELF32_ST_TYPE(info); |
if (sym_bind != STB_LOCAL) { |
/* we search global or weak symbols */ |
208,22 → 191,9 |
sym_index = find_elf_sym(s, name); |
if (!sym_index) |
goto do_def; |
esym = &((ElfW(Sym) *)s->data)[sym_index]; |
esym = &((Elf32_Sym *)s->data)[sym_index]; |
if (esym->st_shndx != SHN_UNDEF) { |
esym_bind = ELFW(ST_BIND)(esym->st_info); |
/* propagate the most constraining visibility */ |
/* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */ |
esym_vis = ELFW(ST_VISIBILITY)(esym->st_other); |
if (esym_vis == STV_DEFAULT) { |
new_vis = sym_vis; |
} else if (sym_vis == STV_DEFAULT) { |
new_vis = esym_vis; |
} else { |
new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis; |
} |
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) |
| new_vis; |
other = esym->st_other; /* in case we have to patch esym */ |
esym_bind = ELF32_ST_BIND(esym->st_info); |
if (sh_num == SHN_UNDEF) { |
/* ignore adding of undefined symbol if the |
corresponding symbol is already defined */ |
232,29 → 202,19 |
goto do_patch; |
} else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { |
/* weak is ignored if already global */ |
} else if (sym_bind == STB_WEAK && esym_bind == STB_WEAK) { |
/* keep first-found weak definition, ignore subsequents */ |
} else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { |
/* ignore hidden symbols after */ |
} else if (esym->st_shndx == SHN_COMMON |
&& (sh_num < SHN_LORESERVE || sh_num == SHN_COMMON)) { |
/* gr: Happens with 'tcc ... -static tcctest.c' on e.g. Ubuntu 6.01 |
No idea if this is the correct solution ... */ |
goto do_patch; |
} else if (s == tcc_state->dynsymtab_section) { |
/* we accept that two DLL define the same symbol */ |
} else { |
#if 0 |
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", |
sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis); |
printf("new_bind=%d new_shndx=%d last_bind=%d old_shndx=%d\n", |
sym_bind, sh_num, esym_bind, esym->st_shndx); |
#endif |
tcc_error_noabort("'%s' defined twice... may be -fcommon is needed?", name); |
/* NOTE: we accept that two DLL define the same symbol */ |
if (s != tcc_state->dynsymtab_section) |
error_noabort("'%s' defined twice", name); |
} |
} else { |
do_patch: |
esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); |
esym->st_info = ELF32_ST_INFO(sym_bind, sym_type); |
esym->st_shndx = sh_num; |
new_undef_sym = 1; |
esym->st_value = value; |
esym->st_size = size; |
esym->st_other = other; |
262,7 → 222,7 |
} else { |
do_def: |
sym_index = put_elf_sym(s, value, size, |
ELFW(ST_INFO)(sym_bind, sym_type), other, |
ELF32_ST_INFO(sym_bind, sym_type), other, |
sh_num, name); |
} |
return sym_index; |
269,45 → 229,41 |
} |
/* put relocation */ |
ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, |
int type, int symbol, addr_t addend) |
static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, |
int type, int symbol) |
{ |
char buf[256]; |
Section *sr; |
ElfW_Rel *rel; |
Elf32_Rel *rel; |
sr = s->reloc; |
if (!sr) { |
/* if no relocation section, create it */ |
snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); |
snprintf(buf, sizeof(buf), ".rel%s", s->name); |
/* if the symtab is allocated, then we consider the relocation |
are also */ |
sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags); |
sr->sh_entsize = sizeof(ElfW_Rel); |
sr = new_section(tcc_state, buf, SHT_REL, symtab->sh_flags); |
sr->sh_entsize = sizeof(Elf32_Rel); |
sr->link = symtab; |
sr->sh_info = s->sh_num; |
s->reloc = sr; |
} |
rel = section_ptr_add(sr, sizeof(ElfW_Rel)); |
rel = section_ptr_add(sr, sizeof(Elf32_Rel)); |
rel->r_offset = offset; |
rel->r_info = ELFW(R_INFO)(symbol, type); |
#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
rel->r_addend = addend; |
#else |
if (addend) |
tcc_error("non-zero addend on REL architecture"); |
#endif |
rel->r_info = ELF32_R_INFO(symbol, type); |
} |
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, |
int type, int symbol) |
{ |
put_elf_reloca(symtab, s, offset, type, symbol, 0); |
} |
/* put stab debug information */ |
ST_FUNC void put_stabs(const char *str, int type, int other, int desc, |
typedef struct { |
unsigned long n_strx; /* index into string table of name */ |
unsigned char n_type; /* type of symbol */ |
unsigned char n_other; /* misc info (usually empty) */ |
unsigned short n_desc; /* description field */ |
unsigned long n_value; /* value of symbol */ |
} Stab_Sym; |
static void put_stabs(const char *str, int type, int other, int desc, |
unsigned long value) |
{ |
Stab_Sym *sym; |
324,31 → 280,25 |
sym->n_value = value; |
} |
ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, |
static void put_stabs_r(const char *str, int type, int other, int desc, |
unsigned long value, Section *sec, int sym_index) |
{ |
put_stabs(str, type, other, desc, value); |
put_elf_reloc(symtab_section, stab_section, |
stab_section->data_offset - sizeof(unsigned int), |
stab_section->data_offset - sizeof(unsigned long), |
R_DATA_32, sym_index); |
} |
ST_FUNC void put_stabn(int type, int other, int desc, int value) |
static void put_stabn(int type, int other, int desc, int value) |
{ |
put_stabs(NULL, type, other, desc, value); |
} |
ST_FUNC void put_stabd(int type, int other, int desc) |
static void put_stabd(int type, int other, int desc) |
{ |
put_stabs(NULL, type, other, desc, 0); |
} |
/* Browse each elem of type <type> in section <sec> starting at elem <startoff> |
using variable <elem> */ |
#define for_each_elem(sec, startoff, elem, type) \ |
for (elem = (type *) sec->data + startoff; \ |
elem < (type *) (sec->data + sec->data_offset); elem++) |
/* In an ELF file symbol table, the local symbols must appear below |
the global and weak ones. Since TCC cannot sort it while generating |
the code, we must do it after. All the relocation tables are also |
356,22 → 306,22 |
static void sort_syms(TCCState *s1, Section *s) |
{ |
int *old_to_new_syms; |
ElfW(Sym) *new_syms; |
Elf32_Sym *new_syms; |
int nb_syms, i; |
ElfW(Sym) *p, *q; |
ElfW_Rel *rel; |
Elf32_Sym *p, *q; |
Elf32_Rel *rel, *rel_end; |
Section *sr; |
int type, sym_index; |
nb_syms = s->data_offset / sizeof(ElfW(Sym)); |
new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); |
nb_syms = s->data_offset / sizeof(Elf32_Sym); |
new_syms = tcc_malloc(nb_syms * sizeof(Elf32_Sym)); |
old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); |
/* first pass for local symbols */ |
p = (ElfW(Sym) *)s->data; |
p = (Elf32_Sym *)s->data; |
q = new_syms; |
for(i = 0; i < nb_syms; i++) { |
if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) { |
if (ELF32_ST_BIND(p->st_info) == STB_LOCAL) { |
old_to_new_syms[i] = q - new_syms; |
*q++ = *p; |
} |
381,9 → 331,9 |
s->sh_info = q - new_syms; |
/* then second pass for non local symbols */ |
p = (ElfW(Sym) *)s->data; |
p = (Elf32_Sym *)s->data; |
for(i = 0; i < nb_syms; i++) { |
if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) { |
if (ELF32_ST_BIND(p->st_info) != STB_LOCAL) { |
old_to_new_syms[i] = q - new_syms; |
*q++ = *p; |
} |
391,18 → 341,21 |
} |
/* we copy the new symbols to the old */ |
memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym))); |
memcpy(s->data, new_syms, nb_syms * sizeof(Elf32_Sym)); |
tcc_free(new_syms); |
/* now we modify all the relocations */ |
for(i = 1; i < s1->nb_sections; i++) { |
sr = s1->sections[i]; |
if (sr->sh_type == SHT_RELX && sr->link == s) { |
for_each_elem(sr, 0, rel, ElfW_Rel) { |
sym_index = ELFW(R_SYM)(rel->r_info); |
type = ELFW(R_TYPE)(rel->r_info); |
if (sr->sh_type == SHT_REL && sr->link == s) { |
rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); |
for(rel = (Elf32_Rel *)sr->data; |
rel < rel_end; |
rel++) { |
sym_index = ELF32_R_SYM(rel->r_info); |
type = ELF32_R_TYPE(rel->r_info); |
sym_index = old_to_new_syms[sym_index]; |
rel->r_info = ELFW(R_INFO)(sym_index, type); |
rel->r_info = ELF32_R_INFO(sym_index, type); |
} |
} |
} |
411,12 → 364,15 |
} |
/* relocate common symbols in the .bss section */ |
ST_FUNC void relocate_common_syms(void) |
static void relocate_common_syms(void) |
{ |
ElfW(Sym) *sym; |
Elf32_Sym *sym, *sym_end; |
unsigned long offset, align; |
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); |
for(sym = (Elf32_Sym *)symtab_section->data + 1; |
sym < sym_end; |
sym++) { |
if (sym->st_shndx == SHN_COMMON) { |
/* align symbol */ |
align = sym->st_value; |
432,35 → 388,32 |
/* relocate symbol table, resolve undefined symbols if do_resolve is |
true and output error if undefined symbol. */ |
ST_FUNC void relocate_syms(TCCState *s1, int do_resolve) |
static void relocate_syms(TCCState *s1, int do_resolve) |
{ |
ElfW(Sym) *sym, *esym; |
Elf32_Sym *sym, *esym, *sym_end; |
int sym_bind, sh_num, sym_index; |
const char *name; |
unsigned long addr; |
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); |
for(sym = (Elf32_Sym *)symtab_section->data + 1; |
sym < sym_end; |
sym++) { |
sh_num = sym->st_shndx; |
if (sh_num == SHN_UNDEF) { |
name = (char *) strtab_section->data + sym->st_name; |
/* Use ld.so to resolve symbol for us (for tcc -run) */ |
name = strtab_section->data + sym->st_name; |
if (do_resolve) { |
#if defined TCC_IS_NATIVE && !defined _WIN32 |
void *addr; |
name = (char *) symtab_section->link->data + sym->st_name; |
addr = resolve_sym(s1, name); |
name = symtab_section->link->data + sym->st_name; |
addr = (unsigned long)resolve_sym(s1, name, ELF32_ST_TYPE(sym->st_info)); |
if (addr) { |
sym->st_value = (addr_t)addr; |
#ifdef DEBUG_RELOC |
printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value); |
#endif |
sym->st_value = addr; |
goto found; |
} |
#endif |
} else if (s1->dynsym) { |
/* if dynamic symbol exist, then use it */ |
sym_index = find_elf_sym(s1->dynsym, name); |
if (sym_index) { |
esym = &((ElfW(Sym) *)s1->dynsym->data)[sym_index]; |
esym = &((Elf32_Sym *)s1->dynsym->data)[sym_index]; |
sym->st_value = esym->st_value; |
goto found; |
} |
471,11 → 424,11 |
goto found; |
/* only weak symbols are accepted to be undefined. Their |
value is zero */ |
sym_bind = ELFW(ST_BIND)(sym->st_info); |
sym_bind = ELF32_ST_BIND(sym->st_info); |
if (sym_bind == STB_WEAK) { |
sym->st_value = 0; |
} else { |
tcc_error_noabort("undefined symbol '%s'", name); |
error_noabort("undefined symbol '%s'", name); |
} |
} else if (sh_num < SHN_LORESERVE) { |
/* add section base */ |
485,31 → 438,31 |
} |
} |
/* relocate a given section (CPU dependent) by applying the relocations |
in the associated relocation section */ |
ST_FUNC void relocate_section(TCCState *s1, Section *s) |
/* relocate a given section (CPU dependent) */ |
static void relocate_section(TCCState *s1, Section *s) |
{ |
Section *sr = s->reloc; |
ElfW_Rel *rel; |
ElfW(Sym) *sym; |
Section *sr; |
Elf32_Rel *rel, *rel_end, *qrel; |
Elf32_Sym *sym; |
int type, sym_index; |
unsigned char *ptr; |
addr_t val, addr; |
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 |
ElfW_Rel *qrel = (ElfW_Rel *) sr->data; /* ptr to next reloc entry reused */ |
unsigned long val, addr; |
#if defined(TCC_TARGET_I386) |
int esym_index; |
#endif |
for_each_elem(sr, 0, rel, ElfW_Rel) { |
sr = s->reloc; |
rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); |
qrel = (Elf32_Rel *)sr->data; |
for(rel = qrel; |
rel < rel_end; |
rel++) { |
ptr = s->data + rel->r_offset; |
sym_index = ELFW(R_SYM)(rel->r_info); |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
sym_index = ELF32_R_SYM(rel->r_info); |
sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
val = sym->st_value; |
#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
val += rel->r_addend; |
#endif |
type = ELFW(R_TYPE)(rel->r_info); |
type = ELF32_R_TYPE(rel->r_info); |
addr = s->sh_addr + rel->r_offset; |
/* CPU specific */ |
520,15 → 473,15 |
esym_index = s1->symtab_to_dynsym[sym_index]; |
qrel->r_offset = rel->r_offset; |
if (esym_index) { |
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32); |
qrel->r_info = ELF32_R_INFO(esym_index, R_386_32); |
qrel++; |
break; |
} else { |
qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE); |
qrel->r_info = ELF32_R_INFO(0, R_386_RELATIVE); |
qrel++; |
} |
} |
write32le(ptr, read32le(ptr) + val); |
*(int *)ptr += val; |
break; |
case R_386_PC32: |
if (s1->output_type == TCC_OUTPUT_DLL) { |
536,332 → 489,64 |
esym_index = s1->symtab_to_dynsym[sym_index]; |
if (esym_index) { |
qrel->r_offset = rel->r_offset; |
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32); |
qrel->r_info = ELF32_R_INFO(esym_index, R_386_PC32); |
qrel++; |
break; |
} |
} |
write32le(ptr, read32le(ptr) + val - addr); |
*(int *)ptr += val - addr; |
break; |
case R_386_PLT32: |
write32le(ptr, read32le(ptr) + val - addr); |
*(int *)ptr += val - addr; |
break; |
case R_386_GLOB_DAT: |
case R_386_JMP_SLOT: |
write32le(ptr, val); |
*(int *)ptr = val; |
break; |
case R_386_GOTPC: |
write32le(ptr, read32le(ptr) + s1->got->sh_addr - addr); |
*(int *)ptr += s1->got->sh_addr - addr; |
break; |
case R_386_GOTOFF: |
write32le(ptr, read32le(ptr) + val - s1->got->sh_addr); |
*(int *)ptr += val - s1->got->sh_addr; |
break; |
case R_386_GOT32: |
case R_386_GOT32X: |
/* we load the got offset */ |
write32le(ptr, read32le(ptr) + s1->sym_attrs[sym_index].got_offset); |
*(int *)ptr += s1->got_offsets[sym_index]; |
break; |
case R_386_16: |
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { |
output_file: |
tcc_error("can only produce 16-bit binary files"); |
} |
write16le(ptr, read16le(ptr) + val); |
break; |
case R_386_PC16: |
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) |
goto output_file; |
write16le(ptr, read16le(ptr) + val - addr); |
break; |
case R_386_RELATIVE: |
/* do nothing */ |
break; |
case R_386_COPY: |
/* This reloction must copy initialized data from the library |
to the program .bss segment. Currently made like for ARM |
(to remove noise of defaukt case). Is this true? |
*/ |
break; |
default: |
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n", |
type, (unsigned)addr, ptr, (unsigned)val); |
break; |
#elif defined(TCC_TARGET_ARM) |
case R_ARM_PC24: |
case R_ARM_CALL: |
case R_ARM_JUMP24: |
case R_ARM_PLT32: |
{ |
int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko; |
int x; |
x = (*(int *) ptr) & 0xffffff; |
if (sym->st_shndx == SHN_UNDEF) |
val = s1->plt->sh_addr; |
#ifdef DEBUG_RELOC |
printf ("reloc %d: x=0x%x val=0x%x ", type, x, val); |
#endif |
(*(int *)ptr) &= 0xff000000; |
if (x & 0x800000) |
x -= 0x1000000; |
x <<= 2; |
blx_avail = (TCC_ARM_VERSION >= 5); |
is_thumb = val & 1; |
is_bl = (*(unsigned *) ptr) >> 24 == 0xeb; |
is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl)); |
x *= 4; |
x += val - addr; |
#ifdef DEBUG_RELOC |
printf (" newx=0x%x name=%s\n", x, |
(char *) symtab_section->link->data + sym->st_name); |
#endif |
h = x & 2; |
th_ko = (x & 3) && (!blx_avail || !is_call); |
if (th_ko || x >= 0x2000000 || x < -0x2000000) |
tcc_error("can't relocate value at %x,%d",addr, type); |
if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000) |
error("can't relocate value at %x",addr); |
x >>= 2; |
x &= 0xffffff; |
/* Only reached if blx is avail and it is a call */ |
if (is_thumb) { |
x |= h << 24; |
(*(int *)ptr) = 0xfa << 24; /* bl -> blx */ |
} |
(*(int *) ptr) |= x; |
} |
break; |
/* Since these relocations only concern Thumb-2 and blx instruction was |
introduced before Thumb-2, we can assume blx is available and not |
guard its use */ |
case R_ARM_THM_PC22: |
case R_ARM_THM_JUMP24: |
{ |
int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11; |
int to_thumb, is_call, to_plt, blx_bit = 1 << 12; |
Section *plt; |
/* weak reference */ |
if (sym->st_shndx == SHN_UNDEF && |
ELFW(ST_BIND)(sym->st_info) == STB_WEAK) |
break; |
/* Get initial offset */ |
hi = (*(uint16_t *)ptr); |
lo = (*(uint16_t *)(ptr+2)); |
s = (hi >> 10) & 1; |
j1 = (lo >> 13) & 1; |
j2 = (lo >> 11) & 1; |
i1 = (j1 ^ s) ^ 1; |
i2 = (j2 ^ s) ^ 1; |
imm10 = hi & 0x3ff; |
imm11 = lo & 0x7ff; |
x = (s << 24) | (i1 << 23) | (i2 << 22) | |
(imm10 << 12) | (imm11 << 1); |
if (x & 0x01000000) |
x -= 0x02000000; |
/* Relocation infos */ |
to_thumb = val & 1; |
plt = s1->plt; |
to_plt = (val >= plt->sh_addr) && |
(val < plt->sh_addr + plt->data_offset); |
is_call = (type == R_ARM_THM_PC22); |
/* Compute final offset */ |
if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */ |
x -= 4; |
x += val - addr; |
if (!to_thumb && is_call) { |
blx_bit = 0; /* bl -> blx */ |
x = (x + 3) & -4; /* Compute offset from aligned PC */ |
} |
/* Check that relocation is possible |
* offset must not be out of range |
* if target is to be entered in arm mode: |
- bit 1 must not set |
- instruction must be a call (bl) or a jump to PLT */ |
if (!to_thumb || x >= 0x1000000 || x < -0x1000000) |
if (to_thumb || (val & 2) || (!is_call && !to_plt)) |
tcc_error("can't relocate value at %x,%d",addr, type); |
/* Compute and store final offset */ |
s = (x >> 24) & 1; |
i1 = (x >> 23) & 1; |
i2 = (x >> 22) & 1; |
j1 = s ^ (i1 ^ 1); |
j2 = s ^ (i2 ^ 1); |
imm10 = (x >> 12) & 0x3ff; |
imm11 = (x >> 1) & 0x7ff; |
(*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) | |
(s << 10) | imm10); |
(*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) | |
(j1 << 13) | blx_bit | (j2 << 11) | |
imm11); |
} |
break; |
case R_ARM_MOVT_ABS: |
case R_ARM_MOVW_ABS_NC: |
{ |
int x, imm4, imm12; |
if (type == R_ARM_MOVT_ABS) |
val >>= 16; |
imm12 = val & 0xfff; |
imm4 = (val >> 12) & 0xf; |
x = (imm4 << 16) | imm12; |
if (type == R_ARM_THM_MOVT_ABS) |
*(int *)ptr |= x; |
else |
*(int *)ptr += x; |
} |
break; |
case R_ARM_THM_MOVT_ABS: |
case R_ARM_THM_MOVW_ABS_NC: |
{ |
int x, i, imm4, imm3, imm8; |
if (type == R_ARM_THM_MOVT_ABS) |
val >>= 16; |
imm8 = val & 0xff; |
imm3 = (val >> 8) & 0x7; |
i = (val >> 11) & 1; |
imm4 = (val >> 12) & 0xf; |
x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4; |
if (type == R_ARM_THM_MOVT_ABS) |
*(int *)ptr |= x; |
else |
*(int *)ptr += x; |
} |
break; |
case R_ARM_PREL31: |
{ |
int x; |
x = (*(int *)ptr) & 0x7fffffff; |
(*(int *)ptr) &= 0x80000000; |
x = (x * 2) / 2; |
x += val - addr; |
if((x^(x>>1))&0x40000000) |
tcc_error("can't relocate value at %x,%d",addr, type); |
(*(int *)ptr) |= x & 0x7fffffff; |
} |
case R_ARM_ABS32: |
*(int *)ptr += val; |
break; |
case R_ARM_REL32: |
*(int *)ptr += val - addr; |
break; |
case R_ARM_GOTPC: |
*(int *)ptr += s1->got->sh_addr - addr; |
break; |
case R_ARM_GOTOFF: |
*(int *)ptr += val - s1->got->sh_addr; |
break; |
case R_ARM_GOT32: |
/* we load the got offset */ |
*(int *)ptr += s1->sym_attrs[sym_index].got_offset; |
*(int *)ptr += s1->got_offsets[sym_index]; |
break; |
case R_ARM_COPY: |
break; |
case R_ARM_V4BX: |
/* trade Thumb support for ARMv4 support */ |
if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10) |
*(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */ |
break; |
case R_ARM_GLOB_DAT: |
case R_ARM_JUMP_SLOT: |
*(addr_t *)ptr = val; |
break; |
case R_ARM_NONE: |
/* Nothing to do. Normally used to indicate a dependency |
on a certain symbol (like for exception handling under EABI). */ |
break; |
default: |
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", |
type, (unsigned)addr, ptr, (unsigned)val); |
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n", |
type,addr,(unsigned int )ptr,val); |
break; |
#elif defined(TCC_TARGET_ARM64) |
case R_AARCH64_ABS64: |
write64le(ptr, val); |
break; |
case R_AARCH64_ABS32: |
write32le(ptr, val); |
break; |
case R_AARCH64_MOVW_UABS_G0_NC: |
write32le(ptr, ((read32le(ptr) & 0xffe0001f) | |
(val & 0xffff) << 5)); |
break; |
case R_AARCH64_MOVW_UABS_G1_NC: |
write32le(ptr, ((read32le(ptr) & 0xffe0001f) | |
(val >> 16 & 0xffff) << 5)); |
break; |
case R_AARCH64_MOVW_UABS_G2_NC: |
write32le(ptr, ((read32le(ptr) & 0xffe0001f) | |
(val >> 32 & 0xffff) << 5)); |
break; |
case R_AARCH64_MOVW_UABS_G3: |
write32le(ptr, ((read32le(ptr) & 0xffe0001f) | |
(val >> 48 & 0xffff) << 5)); |
break; |
case R_AARCH64_ADR_PREL_PG_HI21: { |
uint64_t off = (val >> 12) - (addr >> 12); |
if ((off + ((uint64_t)1 << 20)) >> 21) |
tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed"); |
write32le(ptr, ((read32le(ptr) & 0x9f00001f) | |
(off & 0x1ffffc) << 3 | (off & 3) << 29)); |
break; |
} |
case R_AARCH64_ADD_ABS_LO12_NC: |
write32le(ptr, ((read32le(ptr) & 0xffc003ff) | |
(val & 0xfff) << 10)); |
break; |
case R_AARCH64_JUMP26: |
case R_AARCH64_CALL26: |
/* This check must match the one in build_got_entries, testing |
if we really need a PLT slot. */ |
if (sym->st_shndx == SHN_UNDEF) |
/* We've put the PLT slot offset into r_addend when generating |
it, and that's what we must use as relocation value (adjusted |
by section offset of course). */ |
val = s1->plt->sh_addr + rel->r_addend; |
#ifdef DEBUG_RELOC |
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val, |
(char *) symtab_section->link->data + sym->st_name); |
#endif |
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) |
{ |
tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed (val=%lx, addr=%lx)", addr, val); |
} |
write32le(ptr, (0x14000000 | |
(uint32_t)(type == R_AARCH64_CALL26) << 31 | |
((val - addr) >> 2 & 0x3ffffff))); |
break; |
case R_AARCH64_ADR_GOT_PAGE: { |
uint64_t off = |
(((s1->got->sh_addr + |
s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12)); |
if ((off + ((uint64_t)1 << 20)) >> 21) |
tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed"); |
write32le(ptr, ((read32le(ptr) & 0x9f00001f) | |
(off & 0x1ffffc) << 3 | (off & 3) << 29)); |
break; |
} |
case R_AARCH64_LD64_GOT_LO12_NC: |
write32le(ptr, |
((read32le(ptr) & 0xfff803ff) | |
((s1->got->sh_addr + |
s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7)); |
break; |
case R_AARCH64_COPY: |
break; |
case R_AARCH64_GLOB_DAT: |
case R_AARCH64_JUMP_SLOT: |
/* They don't need addend */ |
#ifdef DEBUG_RELOC |
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, |
val - rel->r_addend, |
(char *) symtab_section->link->data + sym->st_name); |
#endif |
write64le(ptr, val - rel->r_addend); |
break; |
default: |
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", |
type, (unsigned)addr, ptr, (unsigned)val); |
break; |
#elif defined(TCC_TARGET_C67) |
case R_C60_32: |
*(int *)ptr += val; |
870,13 → 555,13 |
{ |
uint32_t orig; |
/* put the low 16 bits of the absolute address |
add to what is already there */ |
/* put the low 16 bits of the absolute address */ |
// add to what is already there |
orig = ((*(int *)(ptr )) >> 7) & 0xffff; |
orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; |
/* patch both at once - assumes always in pairs Low - High */ |
//patch both at once - assumes always in pairs Low - High |
*(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | (((val+orig) & 0xffff) << 7); |
*(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7); |
885,91 → 570,9 |
case R_C60HI16: |
break; |
default: |
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", |
type, (unsigned)addr, ptr, (unsigned)val); |
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n", |
type,addr,(unsigned int )ptr,val); |
break; |
#elif defined(TCC_TARGET_X86_64) |
case R_X86_64_64: |
if (s1->output_type == TCC_OUTPUT_DLL) { |
esym_index = s1->symtab_to_dynsym[sym_index]; |
qrel->r_offset = rel->r_offset; |
if (esym_index) { |
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64); |
qrel->r_addend = rel->r_addend; |
qrel++; |
break; |
} else { |
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); |
qrel->r_addend = read64le(ptr) + val; |
qrel++; |
} |
} |
write64le(ptr, read64le(ptr) + val); |
break; |
case R_X86_64_32: |
case R_X86_64_32S: |
if (s1->output_type == TCC_OUTPUT_DLL) { |
/* XXX: this logic may depend on TCC's codegen |
now TCC uses R_X86_64_32 even for a 64bit pointer */ |
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); |
/* Use sign extension! */ |
qrel->r_addend = (int)read32le(ptr) + val; |
qrel++; |
} |
write32le(ptr, read32le(ptr) + val); |
break; |
case R_X86_64_PC32: |
if (s1->output_type == TCC_OUTPUT_DLL) { |
/* DLL relocation */ |
esym_index = s1->symtab_to_dynsym[sym_index]; |
if (esym_index) { |
qrel->r_offset = rel->r_offset; |
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); |
/* Use sign extension! */ |
qrel->r_addend = (int)read32le(ptr); |
qrel++; |
break; |
} |
} |
goto plt32pc32; |
case R_X86_64_PLT32: |
/* We've put the PLT slot offset into r_addend when generating |
it, and that's what we must use as relocation value (adjusted |
by section offset of course). */ |
val = s1->plt->sh_addr + rel->r_addend; |
/* fallthrough. */ |
plt32pc32: |
{ |
long long diff; |
diff = (long long)val - addr; |
if (diff < -2147483648LL || diff > 2147483647LL) { |
tcc_error("internal error: relocation failed"); |
} |
write32le(ptr, read32le(ptr) + diff); |
} |
break; |
case R_X86_64_GLOB_DAT: |
case R_X86_64_JUMP_SLOT: |
/* They don't need addend */ |
write64le(ptr, val - rel->r_addend); |
break; |
case R_X86_64_GOTPCREL: |
case R_X86_64_GOTPCRELX: |
case R_X86_64_REX_GOTPCRELX: |
write32le(ptr, read32le(ptr) + |
(s1->got->sh_addr - addr + |
s1->sym_attrs[sym_index].got_offset - 4)); |
break; |
case R_X86_64_GOTTPOFF: |
write32le(ptr, read32le(ptr) + val - s1->got->sh_addr); |
break; |
case R_X86_64_GOT32: |
/* we load the got offset */ |
write32le(ptr, read32le(ptr) + s1->sym_attrs[sym_index].got_offset); |
break; |
#else |
#error unsupported processor |
#endif |
984,39 → 587,34 |
static void relocate_rel(TCCState *s1, Section *sr) |
{ |
Section *s; |
ElfW_Rel *rel; |
Elf32_Rel *rel, *rel_end; |
s = s1->sections[sr->sh_info]; |
for_each_elem(sr, 0, rel, ElfW_Rel) |
rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); |
for(rel = (Elf32_Rel *)sr->data; |
rel < rel_end; |
rel++) { |
rel->r_offset += s->sh_addr; |
} |
} |
/* count the number of dynamic relocations so that we can reserve |
their space */ |
static int prepare_dynamic_rel(TCCState *s1, Section *sr) |
{ |
ElfW_Rel *rel; |
Elf32_Rel *rel, *rel_end; |
int sym_index, esym_index, type, count; |
count = 0; |
for_each_elem(sr, 0, rel, ElfW_Rel) { |
sym_index = ELFW(R_SYM)(rel->r_info); |
type = ELFW(R_TYPE)(rel->r_info); |
rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); |
for(rel = (Elf32_Rel *)sr->data; rel < rel_end; rel++) { |
sym_index = ELF32_R_SYM(rel->r_info); |
type = ELF32_R_TYPE(rel->r_info); |
switch(type) { |
#if defined(TCC_TARGET_I386) |
case R_386_32: |
#elif defined(TCC_TARGET_X86_64) |
case R_X86_64_32: |
case R_X86_64_32S: |
case R_X86_64_64: |
#endif |
count++; |
break; |
#if defined(TCC_TARGET_I386) |
case R_386_PC32: |
#elif defined(TCC_TARGET_X86_64) |
case R_X86_64_PC32: |
#endif |
esym_index = s1->symtab_to_dynsym[sym_index]; |
if (esym_index) |
count++; |
1028,30 → 626,48 |
if (count) { |
/* allocate the section */ |
sr->sh_flags |= SHF_ALLOC; |
sr->sh_size = count * sizeof(ElfW_Rel); |
sr->sh_size = count * sizeof(Elf32_Rel); |
} |
return count; |
} |
static struct sym_attr *alloc_sym_attr(TCCState *s1, int index) |
static void put_got_offset(TCCState *s1, int index, unsigned long val) |
{ |
int n; |
struct sym_attr *tab; |
unsigned long *tab; |
if (index >= s1->nb_sym_attrs) { |
if (index >= s1->nb_got_offsets) { |
/* find immediately bigger power of 2 and reallocate array */ |
n = 1; |
while (index >= n) |
n *= 2; |
tab = tcc_realloc(s1->sym_attrs, n * sizeof(*s1->sym_attrs)); |
s1->sym_attrs = tab; |
memset(s1->sym_attrs + s1->nb_sym_attrs, 0, |
(n - s1->nb_sym_attrs) * sizeof(*s1->sym_attrs)); |
s1->nb_sym_attrs = n; |
tab = tcc_realloc(s1->got_offsets, n * sizeof(unsigned long)); |
if (!tab) |
error("memory full"); |
s1->got_offsets = tab; |
memset(s1->got_offsets + s1->nb_got_offsets, 0, |
(n - s1->nb_got_offsets) * sizeof(unsigned long)); |
s1->nb_got_offsets = n; |
} |
return &s1->sym_attrs[index]; |
s1->got_offsets[index] = val; |
} |
/* XXX: suppress that */ |
static void put32(unsigned char *p, uint32_t val) |
{ |
p[0] = val; |
p[1] = val >> 8; |
p[2] = val >> 16; |
p[3] = val >> 24; |
} |
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) |
static uint32_t get32(unsigned char *p) |
{ |
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); |
} |
#endif |
static void build_got(TCCState *s1) |
{ |
unsigned char *ptr; |
1059,97 → 675,53 |
/* if no got, then create it */ |
s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
s1->got->sh_entsize = 4; |
add_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), |
add_elf_sym(symtab_section, 0, 4, ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), |
0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); |
ptr = section_ptr_add(s1->got, 3 * PTR_SIZE); |
#if PTR_SIZE == 4 |
ptr = section_ptr_add(s1->got, 3 * sizeof(int)); |
/* keep space for _DYNAMIC pointer, if present */ |
write32le(ptr, 0); |
put32(ptr, 0); |
/* two dummy got entries */ |
write32le(ptr + 4, 0); |
write32le(ptr + 8, 0); |
#else |
/* keep space for _DYNAMIC pointer, if present */ |
write32le(ptr, 0); |
write32le(ptr + 4, 0); |
/* two dummy got entries */ |
write32le(ptr + 8, 0); |
write32le(ptr + 12, 0); |
write32le(ptr + 16, 0); |
write32le(ptr + 20, 0); |
#endif |
put32(ptr + 4, 0); |
put32(ptr + 8, 0); |
} |
/* put a got or plt entry corresponding to a symbol in symtab_section. 'size' |
and 'info' can be modifed if more precise info comes from the DLL. |
Returns offset of GOT or PLT slot. */ |
static unsigned long put_got_entry(TCCState *s1, |
/* put a got entry corresponding to a symbol in symtab_section. 'size' |
and 'info' can be modifed if more precise info comes from the DLL */ |
static void put_got_entry(TCCState *s1, |
int reloc_type, unsigned long size, int info, |
int sym_index) |
{ |
int index, need_plt_entry; |
int index; |
const char *name; |
ElfW(Sym) *sym; |
Elf32_Sym *sym; |
unsigned long offset; |
int *ptr; |
struct sym_attr *symattr; |
if (!s1->got) |
build_got(s1); |
need_plt_entry = |
#ifdef TCC_TARGET_X86_64 |
(reloc_type == R_X86_64_JUMP_SLOT); |
#elif defined(TCC_TARGET_I386) |
(reloc_type == R_386_JMP_SLOT); |
#elif defined(TCC_TARGET_ARM) |
(reloc_type == R_ARM_JUMP_SLOT); |
#elif defined(TCC_TARGET_ARM64) |
(reloc_type == R_AARCH64_JUMP_SLOT); |
#else |
0; |
#endif |
/* if a got entry already exists for that symbol, no need to add one */ |
if (sym_index < s1->nb_got_offsets && |
s1->got_offsets[sym_index] != 0) |
return; |
if (need_plt_entry && !s1->plt) { |
/* add PLT */ |
s1->plt = new_section(s1, ".plt", SHT_PROGBITS, |
SHF_ALLOC | SHF_EXECINSTR); |
s1->plt->sh_entsize = 4; |
} |
put_got_offset(s1, sym_index, s1->got->data_offset); |
/* If a got/plt entry already exists for that symbol, no need to add one */ |
if (sym_index < s1->nb_sym_attrs) { |
if (need_plt_entry && s1->sym_attrs[sym_index].plt_offset) |
return s1->sym_attrs[sym_index].plt_offset; |
else if (!need_plt_entry && s1->sym_attrs[sym_index].got_offset) |
return s1->sym_attrs[sym_index].got_offset; |
} |
symattr = alloc_sym_attr(s1, sym_index); |
/* Only store the GOT offset if it's not generated for the PLT entry. */ |
if (!need_plt_entry) |
symattr->got_offset = s1->got->data_offset; |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
name = (char *) symtab_section->link->data + sym->st_name; |
if (s1->dynsym) { |
sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
name = symtab_section->link->data + sym->st_name; |
offset = sym->st_value; |
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) |
if (need_plt_entry) { |
#ifdef TCC_TARGET_I386 |
if (reloc_type == R_386_JMP_SLOT) { |
Section *plt; |
uint8_t *p; |
int modrm; |
unsigned long relofs; |
#if defined(TCC_OUTPUT_DLL_WITH_PLT) |
modrm = 0x25; |
#else |
/* if we build a DLL, we add a %ebx offset */ |
if (s1->output_type == TCC_OUTPUT_DLL) |
modrm = 0xa3; |
else |
modrm = 0x25; |
#endif |
/* add a PLT entry */ |
plt = s1->plt; |
1156,47 → 728,36 |
if (plt->data_offset == 0) { |
/* first plt entry */ |
p = section_ptr_add(plt, 16); |
p[0] = 0xff; /* pushl got + PTR_SIZE */ |
p[0] = 0xff; /* pushl got + 4 */ |
p[1] = modrm + 0x10; |
write32le(p + 2, PTR_SIZE); |
p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */ |
put32(p + 2, 4); |
p[6] = 0xff; /* jmp *(got + 8) */ |
p[7] = modrm; |
write32le(p + 8, PTR_SIZE * 2); |
put32(p + 8, 8); |
} |
/* The PLT slot refers to the relocation entry it needs |
via offset. The reloc entry is created below, so its |
offset is the current data_offset. */ |
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; |
symattr->plt_offset = plt->data_offset; |
p = section_ptr_add(plt, 16); |
p[0] = 0xff; /* jmp *(got + x) */ |
p[1] = modrm; |
write32le(p + 2, s1->got->data_offset); |
put32(p + 2, s1->got->data_offset); |
p[6] = 0x68; /* push $xxx */ |
#ifdef TCC_TARGET_X86_64 |
/* On x86-64, the relocation is referred to by _index_. */ |
write32le(p + 7, relofs / sizeof (ElfW_Rel)); |
#else |
write32le(p + 7, relofs); |
#endif |
put32(p + 7, (plt->data_offset - 32) >> 1); |
p[11] = 0xe9; /* jmp plt_start */ |
write32le(p + 12, -(plt->data_offset)); |
put32(p + 12, -(plt->data_offset)); |
/* If this was an UNDEF symbol set the offset in the |
dynsymtab to the PLT slot, so that PC32 relocs to it |
can be resolved. */ |
if (sym->st_shndx == SHN_UNDEF) |
/* the symbol is modified so that it will be relocated to |
the PLT */ |
if (s1->output_type == TCC_OUTPUT_EXE) |
offset = plt->data_offset - 16; |
} |
#elif defined(TCC_TARGET_ARM) |
if (need_plt_entry) { |
if (reloc_type == R_ARM_JUMP_SLOT) { |
Section *plt; |
uint8_t *p; |
/* if we build a DLL, we add a %ebx offset */ |
if (s1->output_type == TCC_OUTPUT_DLL) |
tcc_error("DLLs unimplemented!"); |
error("DLLs unimplemented!"); |
/* add a PLT entry */ |
plt = s1->plt; |
1203,114 → 764,73 |
if (plt->data_offset == 0) { |
/* first plt entry */ |
p = section_ptr_add(plt, 16); |
write32le(p, 0xe52de004); /* push {lr} */ |
write32le(p+4, 0xe59fe010); /* ldr lr, [pc, #16] */ |
write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */ |
write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ |
put32(p , 0xe52de004); |
put32(p + 4, 0xe59fe010); |
put32(p + 8, 0xe08fe00e); |
put32(p + 12, 0xe5bef008); |
} |
symattr->plt_offset = plt->data_offset; |
if (symattr->plt_thumb_stub) { |
p = section_ptr_add(plt, 20); |
write32le(p, 0x4778); /* bx pc */ |
write32le(p+2, 0x46c0); /* nop */ |
p += 4; |
} else |
p = section_ptr_add(plt, 16); |
write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] ; GOT entry offset */ |
write32le(p+4, 0xe08fc00c); /* add ip, pc, ip ; addr of GOT entry */ |
write32le(p+8, 0xe59cf000); /* ldr pc, [ip] ; jump to GOT entry */ |
write32le(p+12, s1->got->data_offset); /* GOT entry off once patched */ |
put32(p , 0xe59fc004); |
put32(p+4, 0xe08fc00c); |
put32(p+8, 0xe59cf000); |
put32(p+12, s1->got->data_offset); |
/* the symbol is modified so that it will be relocated to |
the PLT */ |
if (sym->st_shndx == SHN_UNDEF) |
if (s1->output_type == TCC_OUTPUT_EXE) |
offset = plt->data_offset - 16; |
} |
#elif defined(TCC_TARGET_ARM64) |
if (need_plt_entry) { |
Section *plt; |
uint8_t *p; |
if (s1->output_type == TCC_OUTPUT_DLL) |
tcc_error("DLLs unimplemented!"); |
plt = s1->plt; |
if (plt->data_offset == 0) |
section_ptr_add(plt, 32); |
symattr->plt_offset = plt->data_offset; |
p = section_ptr_add(plt, 16); |
write32le(p, s1->got->data_offset); |
write32le(p + 4, (uint64_t)s1->got->data_offset >> 32); |
if (sym->st_shndx == SHN_UNDEF) |
offset = plt->data_offset - 16; |
} |
#elif defined(TCC_TARGET_C67) |
if (s1->dynsym) { |
tcc_error("C67 got not implemented"); |
} |
error("C67 got not implemented"); |
#else |
#error unsupported CPU |
#endif |
if (s1->dynsym) { |
/* XXX This might generate multiple syms for name. */ |
index = put_elf_sym(s1->dynsym, offset, |
size, info, 0, sym->st_shndx, name); |
/* Create the relocation (it's against the GOT for PLT |
and GOT relocs). */ |
/* put a got entry */ |
put_elf_reloc(s1->dynsym, s1->got, |
s1->got->data_offset, |
reloc_type, index); |
} else { |
/* Without .dynsym (i.e. static link or memory output) we |
still need relocs against the generated got, so as to fill |
the entries with the symbol values (determined later). */ |
put_elf_reloc(symtab_section, s1->got, |
s1->got->data_offset, |
reloc_type, sym_index); |
} |
/* And now create the GOT slot itself. */ |
ptr = section_ptr_add(s1->got, PTR_SIZE); |
ptr = section_ptr_add(s1->got, sizeof(int)); |
*ptr = 0; |
if (need_plt_entry) |
return symattr->plt_offset; |
else |
return symattr->got_offset; |
} |
/* build GOT and PLT entries */ |
ST_FUNC void build_got_entries(TCCState *s1) |
static void build_got_entries(TCCState *s1) |
{ |
Section *s; |
ElfW_Rel *rel; |
ElfW(Sym) *sym; |
Section *s, *symtab; |
Elf32_Rel *rel, *rel_end; |
Elf32_Sym *sym; |
int i, type, reloc_type, sym_index; |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[i]; |
if (s->sh_type != SHT_RELX) |
if (s->sh_type != SHT_REL) |
continue; |
/* no need to handle got relocations */ |
if (s->link != symtab_section) |
continue; |
for_each_elem(s, 0, rel, ElfW_Rel) { |
type = ELFW(R_TYPE)(rel->r_info); |
symtab = s->link; |
rel_end = (Elf32_Rel *)(s->data + s->data_offset); |
for(rel = (Elf32_Rel *)s->data; |
rel < rel_end; |
rel++) { |
type = ELF32_R_TYPE(rel->r_info); |
switch(type) { |
#if defined(TCC_TARGET_I386) |
case R_386_GOT32: |
case R_386_GOT32X: |
case R_386_GOTOFF: |
case R_386_GOTPC: |
case R_386_PLT32: |
if (!s1->got) |
build_got(s1); |
if (type == R_386_GOT32 || type == R_386_GOT32X || |
type == R_386_PLT32) { |
sym_index = ELFW(R_SYM)(rel->r_info); |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
if (type == R_386_GOT32 || type == R_386_PLT32) { |
sym_index = ELF32_R_SYM(rel->r_info); |
sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
/* look at the symbol got offset. If none, then add one */ |
if (type == R_386_GOT32 || type == R_386_GOT32X) |
if (type == R_386_GOT32) |
reloc_type = R_386_GLOB_DAT; |
else |
reloc_type = R_386_JMP_SLOT; |
1319,9 → 839,6 |
} |
break; |
#elif defined(TCC_TARGET_ARM) |
case R_ARM_PC24: |
case R_ARM_CALL: |
case R_ARM_JUMP24: |
case R_ARM_GOT32: |
case R_ARM_GOTOFF: |
case R_ARM_GOTPC: |
1328,95 → 845,16 |
case R_ARM_PLT32: |
if (!s1->got) |
build_got(s1); |
sym_index = ELFW(R_SYM)(rel->r_info); |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
if (type != R_ARM_GOTOFF && type != R_ARM_GOTPC |
&& sym->st_shndx == SHN_UNDEF) { |
unsigned long ofs; |
if (type == R_ARM_GOT32 || type == R_ARM_PLT32) { |
sym_index = ELF32_R_SYM(rel->r_info); |
sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
/* look at the symbol got offset. If none, then add one */ |
if (type == R_ARM_GOT32) |
reloc_type = R_ARM_GLOB_DAT; |
else |
reloc_type = R_ARM_JUMP_SLOT; |
ofs = put_got_entry(s1, reloc_type, sym->st_size, |
sym->st_info, sym_index); |
#ifdef DEBUG_RELOC |
printf ("maybegot: %s, %d, %d --> ofs=0x%x\n", |
(char *) symtab_section->link->data + sym->st_name, |
type, sym->st_shndx, ofs); |
#endif |
if (type != R_ARM_GOT32) { |
addr_t *ptr = (addr_t*)(s1->sections[s->sh_info]->data |
+ rel->r_offset); |
/* x must be signed! */ |
int x = *ptr & 0xffffff; |
x = (x << 8) >> 8; |
x <<= 2; |
x += ofs; |
x >>= 2; |
#ifdef DEBUG_RELOC |
printf ("insn=0x%x --> 0x%x (x==0x%x)\n", *ptr, |
(*ptr & 0xff000000) | x, x); |
#endif |
*ptr = (*ptr & 0xff000000) | x; |
} |
} |
break; |
case R_ARM_THM_JUMP24: |
sym_index = ELFW(R_SYM)(rel->r_info); |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
/* We are relocating a jump from thumb code to arm code */ |
if (sym->st_shndx != SHN_UNDEF && !(sym->st_value & 1)) { |
int index; |
uint8_t *p; |
char *name, buf[1024]; |
Section *text_section; |
name = (char *) symtab_section->link->data + sym->st_name; |
text_section = s1->sections[sym->st_shndx]; |
/* Modify reloc to target a thumb stub to switch to ARM */ |
snprintf(buf, sizeof(buf), "%s_from_thumb", name); |
index = put_elf_sym(symtab_section, |
text_section->data_offset + 1, |
sym->st_size, sym->st_info, 0, |
sym->st_shndx, buf); |
rel->r_info = ELFW(R_INFO)(index, type); |
/* Create a thumb stub fonction to switch to ARM mode */ |
put_elf_reloc(symtab_section, text_section, |
text_section->data_offset + 4, R_ARM_JUMP24, |
sym_index); |
p = section_ptr_add(text_section, 8); |
write32le(p, 0x4778); /* bx pc */ |
write32le(p+2, 0x46c0); /* nop */ |
write32le(p+4, 0xeafffffe); /* b $sym */ |
} |
#elif defined(TCC_TARGET_ARM64) |
//xx Other cases may be required here: |
case R_AARCH64_ADR_GOT_PAGE: |
case R_AARCH64_LD64_GOT_LO12_NC: |
if (!s1->got) |
build_got(s1); |
sym_index = ELFW(R_SYM)(rel->r_info); |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
reloc_type = R_AARCH64_GLOB_DAT; |
put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
sym_index); |
break; |
case R_AARCH64_JUMP26: |
case R_AARCH64_CALL26: |
if (!s1->got) |
build_got(s1); |
sym_index = ELFW(R_SYM)(rel->r_info); |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
if (sym->st_shndx == SHN_UNDEF) { |
unsigned long ofs; |
reloc_type = R_AARCH64_JUMP_SLOT; |
ofs = put_got_entry(s1, reloc_type, sym->st_size, |
sym->st_info, sym_index); |
/* We store the place of the generated PLT slot |
in our addend. */ |
rel->r_addend += ofs; |
} |
break; |
#elif defined(TCC_TARGET_C67) |
1427,8 → 865,8 |
if (!s1->got) |
build_got(s1); |
if (type == R_C60_GOT32 || type == R_C60_PLT32) { |
sym_index = ELFW(R_SYM)(rel->r_info); |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
sym_index = ELF32_R_SYM(rel->r_info); |
sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
/* look at the symbol got offset. If none, then add one */ |
if (type == R_C60_GOT32) |
reloc_type = R_C60_GLOB_DAT; |
1438,44 → 876,6 |
sym_index); |
} |
break; |
#elif defined(TCC_TARGET_X86_64) |
case R_X86_64_GOT32: |
case R_X86_64_GOTTPOFF: |
case R_X86_64_GOTPCREL: |
case R_X86_64_GOTPCRELX: |
case R_X86_64_REX_GOTPCRELX: |
case R_X86_64_PLT32: |
sym_index = ELFW(R_SYM)(rel->r_info); |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
if (type == R_X86_64_PLT32 && |
ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT) |
{ |
rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); |
break; |
} |
if (!s1->got) { |
build_got(s1); |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
} |
if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL || |
type == R_X86_64_GOTPCRELX || |
type == R_X86_64_REX_GOTPCRELX || |
type == R_X86_64_PLT32) { |
unsigned long ofs; |
/* look at the symbol got offset. If none, then add one */ |
if (type == R_X86_64_PLT32) |
reloc_type = R_X86_64_JUMP_SLOT; |
else |
reloc_type = R_X86_64_GLOB_DAT; |
ofs = put_got_entry(s1, reloc_type, sym->st_size, |
sym->st_info, sym_index); |
if (type == R_X86_64_PLT32) |
/* We store the place of the generated PLT slot |
in our addend. */ |
rel->r_addend += ofs; |
} |
break; |
#else |
#error unsupported CPU |
#endif |
1486,7 → 886,7 |
} |
} |
ST_FUNC Section *new_symtab(TCCState *s1, |
static Section *new_symtab(TCCState *s1, |
const char *symtab_name, int sh_type, int sh_flags, |
const char *strtab_name, |
const char *hash_name, int hash_sh_flags) |
1495,7 → 895,7 |
int *ptr, nb_buckets; |
symtab = new_section(s1, symtab_name, sh_type, sh_flags); |
symtab->sh_entsize = sizeof(ElfW(Sym)); |
symtab->sh_entsize = sizeof(Elf32_Sym); |
strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags); |
put_elf_str(strtab, ""); |
symtab->link = strtab; |
1516,10 → 916,10 |
} |
/* put dynamic tag */ |
static void put_dt(Section *dynamic, int dt, addr_t val) |
static void put_dt(Section *dynamic, int dt, unsigned long val) |
{ |
ElfW(Dyn) *dyn; |
dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn))); |
Elf32_Dyn *dyn; |
dyn = section_ptr_add(dynamic, sizeof(Elf32_Dyn)); |
dyn->d_tag = dt; |
dyn->d_un.d_val = val; |
} |
1544,108 → 944,59 |
add_elf_sym(symtab_section, |
0, 0, |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
s->sh_num, sym_start); |
add_elf_sym(symtab_section, |
end_offset, 0, |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
s->sh_num, sym_end); |
} |
static int tcc_add_support(TCCState *s1, const char *filename) |
/* add tcc runtime libraries */ |
static void tcc_add_runtime(TCCState *s1) |
{ |
char buf[1024]; |
snprintf(buf, sizeof(buf), "%s/%s/%s", s1->tcc_lib_path, |
/* an cpu specific path inside tcc_lib_path, mainly for keeping libtcc1.a */ |
#ifdef TCC_TARGET_I386 |
"i386" |
#endif |
#ifdef TCC_TARGET_X86_64 |
"x86-64" |
#endif |
#ifdef TCC_TARGET_ARM |
"arm" |
#endif |
#ifdef TCC_TARGET_ARM64 |
"arm64" |
#endif |
#ifdef TCC_TARGET_C67 |
"C67" |
#endif |
,filename); |
return tcc_add_file(s1, buf, TCC_FILETYPE_BINARY); |
} |
ST_FUNC void tcc_add_bcheck(TCCState *s1) |
{ |
#ifdef CONFIG_TCC_BCHECK |
addr_t *ptr; |
if (do_bounds_check) { |
unsigned long *ptr; |
Section *init_section; |
unsigned char *pinit; |
int sym_index; |
if (0 == s1->do_bounds_check) |
return; |
/* XXX: add an object file to do that */ |
ptr = section_ptr_add(bounds_section, sizeof(*ptr)); |
ptr = section_ptr_add(bounds_section, sizeof(unsigned long)); |
*ptr = 0; |
add_elf_sym(symtab_section, 0, 0, |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
bounds_section->sh_num, "__bounds_start"); |
/* add bound check code */ |
snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "bcheck.o"); |
tcc_add_file(s1, buf); |
#ifdef TCC_TARGET_I386 |
if (s1->output_type != TCC_OUTPUT_MEMORY) { |
/* add 'call __bound_init()' in .init section */ |
/* XXX not called on MSYS, reason is unknown. For this |
case a call to __bound_init is performed in bcheck.c |
when __bound_ptr_add, __bound_new_region, |
__bound_delete_region called */ |
int sym_index = find_elf_sym(symtab_section, "__bound_init"); |
if (sym_index) { |
Section *init_section = find_section(s1, ".init"); |
unsigned char *pinit = section_ptr_add(init_section, 5); |
init_section = find_section(s1, ".init"); |
pinit = section_ptr_add(init_section, 5); |
pinit[0] = 0xe8; |
write32le(pinit + 1, -4); |
put32(pinit + 1, -4); |
sym_index = find_elf_sym(symtab_section, "__bound_init"); |
put_elf_reloc(symtab_section, init_section, |
init_section->data_offset - 4, R_386_PC32, sym_index); |
} |
else |
tcc_warning("__bound_init not defined"); |
#endif |
} |
#endif |
} |
/* add tcc runtime libraries */ |
ST_FUNC void tcc_add_runtime(TCCState *s1) |
{ |
tcc_add_pragma_libs(s1); |
/* add libc */ |
if (!s1->nostdlib) { |
tcc_add_library(s1, "c"); |
#ifdef CONFIG_USE_LIBGCC |
if (!s1->static_link) { |
tcc_add_file(s1, TCC_LIBGCC, TCC_FILETYPE_BINARY); |
snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "libtcc1.a"); |
tcc_add_file(s1, buf); |
} |
#endif |
#if !defined(TCC_TARGET_MEOS) |
tcc_add_support(s1, "libtcc1.a"); |
#endif |
} |
/* tcc_add_bcheck tries to relocate a call to __bound_init in _init so |
libtcc1.a must be loaded before for __bound_init to be defined and |
crtn.o must be loaded after to not finalize _init too early. */ |
tcc_add_bcheck(s1); |
if (!s1->nostdlib) { |
/* add crt end if not memory output */ |
if (s1->output_type != TCC_OUTPUT_MEMORY) |
#if defined(TCC_TARGET_MEOS) |
; |
// tcc_add_crt(s1, "start.o"); |
#else |
tcc_add_crt(s1, "crtn.o"); |
#endif |
if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) { |
tcc_add_file(s1, CONFIG_TCC_CRT_PREFIX "/crtn.o"); |
} |
} |
1652,7 → 1003,7 |
/* add various standard linker symbols (must be done after the |
sections are filled (for example after allocating common |
symbols)) */ |
ST_FUNC void tcc_add_linker_symbols(TCCState *s1) |
static void tcc_add_linker_symbols(TCCState *s1) |
{ |
char buf[1024]; |
int i; |
1660,15 → 1011,15 |
add_elf_sym(symtab_section, |
text_section->data_offset, 0, |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
text_section->sh_num, "_etext"); |
add_elf_sym(symtab_section, |
data_section->data_offset, 0, |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
data_section->sh_num, "_edata"); |
add_elf_sym(symtab_section, |
bss_section->data_offset, 0, |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
bss_section->sh_num, "_end"); |
/* horrible new standard ldscript defines */ |
add_init_array_defines(s1, ".preinit_array"); |
1697,12 → 1048,12 |
snprintf(buf, sizeof(buf), "__start_%s", s->name); |
add_elf_sym(symtab_section, |
0, 0, |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
s->sh_num, buf); |
snprintf(buf, sizeof(buf), "__stop_%s", s->name); |
add_elf_sym(symtab_section, |
s->data_offset, 0, |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
s->sh_num, buf); |
} |
next_sec: ; |
1709,8 → 1060,15 |
} |
} |
/* name of ELF interpreter */ |
#ifdef __FreeBSD__ |
static char elf_interp[] = "/usr/libexec/ld-elf.so.1"; |
#else |
static char elf_interp[] = "/lib/ld-linux.so.2"; |
#endif |
static void tcc_output_binary(TCCState *s1, FILE *f, |
const int *sec_order) |
const int *section_order) |
{ |
Section *s; |
int i, offset, size; |
1717,7 → 1075,7 |
offset = 0; |
for(i=1;i<s1->nb_sections;i++) { |
s = s1->sections[sec_order[i]]; |
s = s1->sections[section_order[i]]; |
if (s->sh_type != SHT_NOBITS && |
(s->sh_flags & SHF_ALLOC)) { |
while (offset < s->sh_offset) { |
1731,139 → 1089,105 |
} |
} |
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
#define HAVE_PHDR 1 |
#define EXTRA_RELITEMS 14 |
/* move the relocation value from .dynsym to .got */ |
void patch_dynsym_undef(TCCState *s1, Section *s) |
/* output an ELF file */ |
/* XXX: suppress unneeded sections */ |
int tcc_output_file(TCCState *s1, const char *filename) |
{ |
uint32_t *gotd = (void *)s1->got->data; |
ElfW(Sym) *sym; |
Elf32_Ehdr ehdr; |
FILE *f; |
int fd, mode, ret; |
int *section_order; |
int shnum, i, phnum, file_offset, offset, size, j, tmp, sh_order_index, k; |
unsigned long addr; |
Section *strsec, *s; |
Elf32_Shdr shdr, *sh; |
Elf32_Phdr *phdr, *ph; |
Section *interp, *dynamic, *dynstr; |
unsigned long saved_dynamic_data_offset; |
Elf32_Sym *sym; |
int type, file_type; |
unsigned long rel_addr, rel_size; |
gotd += 3; /* dummy entries in .got */ |
/* relocate symbols in .dynsym */ |
for_each_elem(s, 1, sym, ElfW(Sym)) { |
if (sym->st_shndx == SHN_UNDEF) { |
*gotd++ = sym->st_value + 6; /* XXX 6 is magic ? */ |
sym->st_value = 0; |
file_type = s1->output_type; |
s1->nb_errors = 0; |
if (file_type != TCC_OUTPUT_OBJ) { |
tcc_add_runtime(s1); |
} |
} |
} |
#else |
#define HAVE_PHDR 1 |
#define EXTRA_RELITEMS 9 |
/* zero plt offsets of weak symbols in .dynsym */ |
void patch_dynsym_undef(TCCState *s1, Section *s) |
{ |
ElfW(Sym) *sym; |
phdr = NULL; |
section_order = NULL; |
interp = NULL; |
dynamic = NULL; |
dynstr = NULL; /* avoid warning */ |
saved_dynamic_data_offset = 0; /* avoid warning */ |
for_each_elem(s, 1, sym, ElfW(Sym)) |
if (sym->st_shndx == SHN_UNDEF && ELFW(ST_BIND)(sym->st_info) == STB_WEAK) |
sym->st_value = 0; |
} |
#endif |
if (file_type != TCC_OUTPUT_OBJ) { |
relocate_common_syms(); |
ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) |
{ |
int sym_index = ELFW(R_SYM) (rel->r_info); |
ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; |
unsigned long offset; |
tcc_add_linker_symbols(s1); |
if (sym_index >= s1->nb_sym_attrs) |
return; |
offset = s1->sym_attrs[sym_index].got_offset; |
section_reserve(s1->got, offset + PTR_SIZE); |
#ifdef TCC_TARGET_X86_64 |
/* only works for x86-64 */ |
write32le(s1->got->data + offset + 4, sym->st_value >> 32); |
#endif |
write32le(s1->got->data + offset, sym->st_value & 0xffffffff); |
if (!s1->static_link) { |
const char *name; |
int sym_index, index; |
Elf32_Sym *esym, *sym_end; |
if (file_type == TCC_OUTPUT_EXE) { |
char *ptr; |
/* add interpreter section only if executable */ |
interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); |
interp->sh_addralign = 1; |
ptr = section_ptr_add(interp, sizeof(elf_interp)); |
strcpy(ptr, elf_interp); |
} |
/* Perform relocation to GOT or PLT entries */ |
ST_FUNC void fill_got(TCCState *s1) |
{ |
Section *s; |
ElfW_Rel *rel; |
int i; |
/* add dynamic symbol table */ |
s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, |
".dynstr", |
".hash", SHF_ALLOC); |
dynstr = s1->dynsym->link; |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[i]; |
if (s->sh_type != SHT_RELX) |
continue; |
/* no need to handle got relocations */ |
if (s->link != symtab_section) |
continue; |
for_each_elem(s, 0, rel, ElfW_Rel) { |
switch (ELFW(R_TYPE) (rel->r_info)) { |
case R_X86_64_GOT32: |
case R_X86_64_GOTPCREL: |
case R_X86_64_GOTPCRELX: |
case R_X86_64_REX_GOTPCRELX: |
case R_X86_64_PLT32: |
fill_got_entry(s1, rel); |
break; |
} |
} |
} |
} |
/* add dynamic section */ |
dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, |
SHF_ALLOC | SHF_WRITE); |
dynamic->link = dynstr; |
dynamic->sh_entsize = sizeof(Elf32_Dyn); |
/* Bind symbols of executable: resolve undefined symbols from exported symbols |
in shared libraries and export non local defined symbols to shared libraries |
if -rdynamic switch was given on command line */ |
static void bind_exe_dynsyms(TCCState *s1) |
{ |
const char *name; |
int sym_index, index; |
ElfW(Sym) *sym, *esym; |
int type; |
/* add PLT */ |
s1->plt = new_section(s1, ".plt", SHT_PROGBITS, |
SHF_ALLOC | SHF_EXECINSTR); |
s1->plt->sh_entsize = 4; |
/* Resolve undefined symbols from dynamic symbols. When there is a match: |
- if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT |
- if STT_OBJECT symbol -> add it in .bss section with suitable reloc */ |
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
build_got(s1); |
/* scan for undefined symbols and see if they are in the |
dynamic symbols. If a symbol STT_FUNC is found, then we |
add it in the PLT. If a symbol STT_OBJECT is found, we |
add it in the .bss section with a suitable relocation */ |
sym_end = (Elf32_Sym *)(symtab_section->data + |
symtab_section->data_offset); |
if (file_type == TCC_OUTPUT_EXE) { |
for(sym = (Elf32_Sym *)symtab_section->data + 1; |
sym < sym_end; |
sym++) { |
if (sym->st_shndx == SHN_UNDEF) { |
name = (char *) symtab_section->link->data + sym->st_name; |
name = symtab_section->link->data + sym->st_name; |
sym_index = find_elf_sym(s1->dynsymtab_section, name); |
if (sym_index) { |
esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; |
type = ELFW(ST_TYPE)(esym->st_info); |
if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { |
/* Indirect functions shall have STT_FUNC type in executable |
* dynsym section. Indeed, a dlsym call following a lazy |
* resolution would pick the symbol value from the |
* executable dynsym entry which would contain the address |
* of the function wanted by the caller of dlsym instead of |
* the address of the function that would return that |
* address */ |
esym = &((Elf32_Sym *)s1->dynsymtab_section->data)[sym_index]; |
type = ELF32_ST_TYPE(esym->st_info); |
if (type == STT_FUNC) { |
put_got_entry(s1, R_JMP_SLOT, esym->st_size, |
ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), |
sym - (ElfW(Sym) *)symtab_section->data); |
esym->st_info, |
sym - (Elf32_Sym *)symtab_section->data); |
} else if (type == STT_OBJECT) { |
unsigned long offset; |
ElfW(Sym) *dynsym; |
offset = bss_section->data_offset; |
/* XXX: which alignment ? */ |
offset = (offset + 16 - 1) & -16; |
index = put_elf_sym(s1->dynsym, offset, esym->st_size, |
esym->st_info, 0, bss_section->sh_num, |
name); |
/* Ensure R_COPY works for weak symbol aliases */ |
if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { |
for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) { |
if ((dynsym->st_value == esym->st_value) |
&& (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) { |
char *dynname = (char *) s1->dynsymtab_section->link->data |
+ dynsym->st_name; |
put_elf_sym(s1->dynsym, offset, dynsym->st_size, |
dynsym->st_info, 0, |
bss_section->sh_num, dynname); |
break; |
} |
} |
} |
esym->st_info, 0, |
bss_section->sh_num, name); |
put_elf_reloc(s1->dynsym, bss_section, |
offset, R_COPY, index); |
offset += esym->st_size; |
1871,160 → 1195,131 |
} |
} else { |
/* STB_WEAK undefined symbols are accepted */ |
/* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ |
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || |
/* XXX: _fp_hw seems to be part of the ABI, so we ignore |
it */ |
if (ELF32_ST_BIND(sym->st_info) == STB_WEAK || |
!strcmp(name, "_fp_hw")) { |
} else { |
tcc_error_noabort("undefined symbol '%s'", name); |
error_noabort("undefined symbol '%s'", name); |
} |
} |
} else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
/* if -rdynamic option, then export all non local symbols */ |
name = (char *) symtab_section->link->data + sym->st_name; |
put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, |
0, sym->st_shndx, name); |
} else if (s1->rdynamic && |
ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
/* if -rdynamic option, then export all non |
local symbols */ |
name = symtab_section->link->data + sym->st_name; |
put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
sym->st_info, 0, |
sym->st_shndx, name); |
} |
} |
} |
/* Bind symbols of libraries: export non local symbols of executable that |
resolve undefined symbols of shared libraries */ |
static void bind_libs_dynsyms(TCCState *s1) |
{ |
const char *name; |
int sym_index; |
ElfW(Sym) *sym, *esym; |
if (s1->nb_errors) |
goto fail; |
/* now look at unresolved dynamic symbols and export |
corresponding symbol */ |
for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) { |
name = (char *) s1->dynsymtab_section->link->data + esym->st_name; |
sym_end = (Elf32_Sym *)(s1->dynsymtab_section->data + |
s1->dynsymtab_section->data_offset); |
for(esym = (Elf32_Sym *)s1->dynsymtab_section->data + 1; |
esym < sym_end; |
esym++) { |
if (esym->st_shndx == SHN_UNDEF) { |
name = s1->dynsymtab_section->link->data + esym->st_name; |
sym_index = find_elf_sym(symtab_section, name); |
if (sym_index) { |
/* XXX: avoid adding a symbol if already present because of |
-rdynamic ? */ |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
if (sym->st_shndx != SHN_UNDEF) |
/* XXX: avoid adding a symbol if already |
present because of -rdynamic ? */ |
sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
sym->st_info, 0, sym->st_shndx, name); |
} else if (esym->st_shndx == SHN_UNDEF) { |
sym->st_info, 0, |
sym->st_shndx, name); |
} else { |
if (ELF32_ST_BIND(esym->st_info) == STB_WEAK) { |
/* weak symbols can stay undefined */ |
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK) |
tcc_warning("undefined dynamic symbol '%s'", name); |
} else { |
warning("undefined dynamic symbol '%s'", name); |
} |
} |
} |
/* Export all non local symbols (for shared libraries) */ |
static void export_global_syms(TCCState *s1) |
{ |
int nb_syms, dynindex, index; |
const char *name; |
ElfW(Sym) *sym; |
nb_syms = symtab_section->data_offset / sizeof(ElfW(Sym)); |
} |
} else { |
int nb_syms; |
/* shared library case : we simply export all the global symbols */ |
nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym); |
s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); |
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
name = (char *) symtab_section->link->data + sym->st_name; |
dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
sym->st_info, 0, sym->st_shndx, name); |
index = sym - (ElfW(Sym) *) symtab_section->data; |
s1->symtab_to_dynsym[index] = dynindex; |
for(sym = (Elf32_Sym *)symtab_section->data + 1; |
sym < sym_end; |
sym++) { |
if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
name = symtab_section->link->data + sym->st_name; |
index = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
sym->st_info, 0, |
sym->st_shndx, name); |
s1->symtab_to_dynsym[sym - |
(Elf32_Sym *)symtab_section->data] = |
index; |
} |
} |
} |
/* relocate the PLT: compute addresses and offsets in the PLT now that final |
address for PLT and GOT are known (see fill_program_header) */ |
ST_FUNC void relocate_plt(TCCState *s1) |
{ |
uint8_t *p, *p_end; |
build_got_entries(s1); |
if (!s1->plt) |
return; |
/* add a list of needed dlls */ |
for(i = 0; i < s1->nb_loaded_dlls; i++) { |
DLLReference *dllref = s1->loaded_dlls[i]; |
if (dllref->level == 0) |
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); |
} |
/* XXX: currently, since we do not handle PIC code, we |
must relocate the readonly segments */ |
if (file_type == TCC_OUTPUT_DLL) |
put_dt(dynamic, DT_TEXTREL, 0); |
p = s1->plt->data; |
p_end = p + s1->plt->data_offset; |
if (p < p_end) { |
#if defined(TCC_TARGET_I386) |
write32le(p + 2, read32le(p + 2) + s1->got->sh_addr); |
write32le(p + 8, read32le(p + 8) + s1->got->sh_addr); |
p += 16; |
while (p < p_end) { |
write32le(p + 2, read32le(p + 2) + s1->got->sh_addr); |
p += 16; |
/* add necessary space for other entries */ |
saved_dynamic_data_offset = dynamic->data_offset; |
dynamic->data_offset += 8 * 9; |
} else { |
/* still need to build got entries in case of static link */ |
build_got_entries(s1); |
} |
#elif defined(TCC_TARGET_X86_64) |
int x = s1->got->sh_addr - s1->plt->sh_addr - 6; |
write32le(p + 2, read32le(p + 2) + x); |
write32le(p + 8, read32le(p + 8) + x - 6); |
p += 16; |
while (p < p_end) { |
write32le(p + 2, read32le(p + 2) + x + s1->plt->data - p); |
p += 16; |
} |
#elif defined(TCC_TARGET_ARM) |
int x; |
x=s1->got->sh_addr - s1->plt->sh_addr - 12; |
p += 16; |
while (p < p_end) { |
if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */ |
p += 4; |
write32le(p + 12, x + read32le(p + 12) + s1->plt->data - p); |
p += 16; |
} |
#elif defined(TCC_TARGET_ARM64) |
uint64_t plt = s1->plt->sh_addr; |
uint64_t got = s1->got->sh_addr; |
uint64_t off = (got >> 12) - (plt >> 12); |
if ((off + ((uint32_t)1 << 20)) >> 21) |
tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt); |
write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]! |
write32le(p + 4, (0x90000010 | // adrp x16,... |
(off & 0x1ffffc) << 3 | (off & 3) << 29)); |
write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...] |
(got & 0xff8) << 7)); |
write32le(p + 12, (0x91000210 | // add x16,x16,#... |
(got & 0xfff) << 10)); |
write32le(p + 16, 0xd61f0220); // br x17 |
write32le(p + 20, 0xd503201f); // nop |
write32le(p + 24, 0xd503201f); // nop |
write32le(p + 28, 0xd503201f); // nop |
p += 32; |
while (p < p_end) { |
uint64_t pc = plt + (p - s1->plt->data); |
uint64_t addr = got + read64le(p); |
uint64_t off = (addr >> 12) - (pc >> 12); |
if ((off + ((uint32_t)1 << 20)) >> 21) |
tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc); |
write32le(p, (0x90000010 | // adrp x16,... |
(off & 0x1ffffc) << 3 | (off & 3) << 29)); |
write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...] |
(addr & 0xff8) << 7)); |
write32le(p + 8, (0x91000210 | // add x16,x16,#... |
(addr & 0xfff) << 10)); |
write32le(p + 12, 0xd61f0220); // br x17 |
p += 16; |
} |
#elif defined(TCC_TARGET_C67) |
/* XXX: TODO */ |
#else |
#error unsupported CPU |
#endif |
} |
} |
/* Allocate strings for section names and decide if an unallocated section |
should be output. |
memset(&ehdr, 0, sizeof(ehdr)); |
NOTE: the strsec section comes last, so its size is also correct ! */ |
static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec) |
{ |
int i; |
Section *s; |
/* we add a section for symbols */ |
strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); |
put_elf_str(strsec, ""); |
/* Allocate strings for section names */ |
/* compute number of sections */ |
shnum = s1->nb_sections; |
/* this array is used to reorder sections in the output file */ |
section_order = tcc_malloc(sizeof(int) * shnum); |
section_order[0] = 0; |
sh_order_index = 1; |
/* compute number of program headers */ |
switch(file_type) { |
default: |
case TCC_OUTPUT_OBJ: |
phnum = 0; |
break; |
case TCC_OUTPUT_EXE: |
if (!s1->static_link) |
phnum = 4; |
else |
phnum = 2; |
break; |
case TCC_OUTPUT_DLL: |
phnum = 3; |
break; |
} |
/* allocate strings for section names and decide if an unallocated |
section should be output */ |
/* NOTE: the strsec section comes last, so its size is also |
correct ! */ |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[i]; |
s->sh_name = put_elf_str(strsec, s->name); |
2031,16 → 1326,11 |
/* when generating a DLL, we include relocations but we may |
patch them */ |
if (file_type == TCC_OUTPUT_DLL && |
s->sh_type == SHT_RELX && |
s->sh_type == SHT_REL && |
!(s->sh_flags & SHF_ALLOC)) { |
/* gr: avoid bogus relocs for empty (debug) sections */ |
if (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) |
prepare_dynamic_rel(s1, s); |
else if (s1->do_debug) |
s->sh_size = s->data_offset; |
} else if (s1->do_debug || |
} else if (do_debug || |
file_type == TCC_OUTPUT_OBJ || |
file_type == TCC_OUTPUT_EXE || |
(s->sh_flags & SHF_ALLOC) || |
i == (s1->nb_sections - 1)) { |
/* we output all sections if debug or object file */ |
2047,53 → 1337,26 |
s->sh_size = s->data_offset; |
} |
} |
} |
/* Info to be copied in dynamic section */ |
struct dyn_inf { |
Section *dynamic; |
Section *dynstr; |
unsigned long dyn_rel_off; |
addr_t rel_addr; |
addr_t rel_size; |
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
addr_t bss_addr; |
addr_t bss_size; |
#endif |
}; |
/* allocate program segment headers */ |
phdr = tcc_mallocz(phnum * sizeof(Elf32_Phdr)); |
/* Assign sections to segments and decide how are sections laid out when loaded |
in memory. This function also fills corresponding program headers. */ |
static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, |
Section *interp, Section* strsec, |
struct dyn_inf *dyninf, int *sec_order) |
{ |
int i, j, k, file_type, sh_order_index, file_offset; |
unsigned long s_align; |
long long tmp; |
addr_t addr; |
ElfW(Phdr) *ph; |
Section *s; |
file_type = s1->output_type; |
sh_order_index = 1; |
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); |
} else { |
file_offset = 0; |
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) |
file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); |
s_align = ELF_PAGE_SIZE; |
if (s1->section_align) |
s_align = s1->section_align; |
} |
if (phnum > 0) { |
/* compute section to program header mapping */ |
if (s1->has_text_addr) { |
int a_offset, p_offset; |
addr = s1->text_addr; |
/* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % |
ELF_PAGE_SIZE */ |
a_offset = (int) (addr & (s_align - 1)); |
p_offset = file_offset & (s_align - 1); |
a_offset = addr & (ELF_PAGE_SIZE - 1); |
p_offset = file_offset & (ELF_PAGE_SIZE - 1); |
if (a_offset < p_offset) |
a_offset += s_align; |
a_offset += ELF_PAGE_SIZE; |
file_offset += (a_offset - p_offset); |
} else { |
if (file_type == TCC_OUTPUT_DLL) |
2101,22 → 1364,18 |
else |
addr = ELF_START_ADDR; |
/* compute address after headers */ |
addr += (file_offset & (s_align - 1)); |
addr += (file_offset & (ELF_PAGE_SIZE - 1)); |
} |
/* dynamic relocation table information, for .dynamic section */ |
rel_size = 0; |
rel_addr = 0; |
/* leave one program header for the program interpreter */ |
ph = &phdr[0]; |
/* Leave one program headers for the program interpreter and one for |
the program header table itself if needed. These are done later as |
they require section layout to be done first. */ |
if (interp) |
ph += 1 + HAVE_PHDR; |
ph++; |
/* dynamic relocation table information, for .dynamic section */ |
dyninf->rel_addr = dyninf->rel_size = 0; |
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
dyninf->bss_addr = dyninf->bss_size = 0; |
#endif |
for(j = 0; j < 2; j++) { |
ph->p_type = PT_LOAD; |
if (j == 0) |
2123,12 → 1382,10 |
ph->p_flags = PF_R | PF_X; |
else |
ph->p_flags = PF_R | PF_W; |
ph->p_align = s_align; |
ph->p_align = ELF_PAGE_SIZE; |
/* Decide the layout of sections loaded in memory. This must |
be done before program headers are filled since they contain |
info about the layout. We do the following ordering: interp, |
symbol tables, relocations, progbits, nobits */ |
/* we do the following ordering: interp, symbol tables, |
relocations, progbits, nobits */ |
/* XXX: do faster and simpler sorting */ |
for(k = 0; k < 5; k++) { |
for(i = 1; i < s1->nb_sections; i++) { |
2151,7 → 1408,7 |
s->sh_type == SHT_HASH) { |
if (k != 1) |
continue; |
} else if (s->sh_type == SHT_RELX) { |
} else if (s->sh_type == SHT_REL) { |
if (k != 2) |
continue; |
} else if (s->sh_type == SHT_NOBITS) { |
2161,13 → 1418,13 |
if (k != 3) |
continue; |
} |
sec_order[sh_order_index++] = i; |
section_order[sh_order_index++] = i; |
/* section matches: we align it and add its size */ |
tmp = addr; |
addr = (addr + s->sh_addralign - 1) & |
~(s->sh_addralign - 1); |
file_offset += (int) ( addr - tmp ); |
file_offset += addr - tmp; |
s->sh_offset = file_offset; |
s->sh_addr = addr; |
2178,36 → 1435,16 |
ph->p_paddr = ph->p_vaddr; |
} |
/* update dynamic relocation infos */ |
if (s->sh_type == SHT_RELX) { |
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { |
dyninf->rel_addr = addr; |
dyninf->rel_size += s->sh_size; /* XXX only first rel. */ |
if (s->sh_type == SHT_REL) { |
if (rel_size == 0) |
rel_addr = addr; |
rel_size += s->sh_size; |
} |
if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) { |
dyninf->bss_addr = addr; |
dyninf->bss_size = s->sh_size; /* XXX only first rel. */ |
} |
#else |
if (dyninf->rel_size == 0) |
dyninf->rel_addr = addr; |
dyninf->rel_size += s->sh_size; |
#endif |
} |
addr += s->sh_size; |
if (s->sh_type != SHT_NOBITS) |
file_offset += s->sh_size; |
} |
} |
if (j == 0) { |
/* Make the first PT_LOAD segment include the program |
headers itself (and the ELF header as well), it'll |
come out with same memory use but will make various |
tools like binutils strip work better. */ |
ph->p_offset &= ~(ph->p_align - 1); |
ph->p_vaddr &= ~(ph->p_align - 1); |
ph->p_paddr &= ~(ph->p_align - 1); |
} |
ph->p_filesz = file_offset - ph->p_offset; |
ph->p_memsz = addr - ph->p_vaddr; |
ph++; |
2215,56 → 1452,20 |
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
/* if in the middle of a page, we duplicate the page in |
memory so that one copy is RX and the other is RW */ |
if ((addr & (s_align - 1)) != 0) |
addr += s_align; |
if ((addr & (ELF_PAGE_SIZE - 1)) != 0) |
addr += ELF_PAGE_SIZE; |
} else { |
addr = (addr + s_align - 1) & ~(s_align - 1); |
file_offset = (file_offset + s_align - 1) & ~(s_align - 1); |
addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1); |
file_offset = (file_offset + ELF_PAGE_SIZE - 1) & |
~(ELF_PAGE_SIZE - 1); |
} |
} |
} |
} |
/* all other sections come after */ |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[i]; |
if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) |
continue; |
sec_order[sh_order_index++] = i; |
file_offset = (file_offset + s->sh_addralign - 1) & |
~(s->sh_addralign - 1); |
s->sh_offset = file_offset; |
if (s->sh_type != SHT_NOBITS) |
file_offset += s->sh_size; |
} |
return file_offset; |
} |
static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, |
Section *dynamic) |
{ |
ElfW(Phdr) *ph; |
/* if interpreter, then add corresponding program header */ |
/* if interpreter, then add corresponing program header */ |
if (interp) { |
ph = &phdr[0]; |
if (HAVE_PHDR) |
{ |
int len = phnum * sizeof(ElfW(Phdr)); |
ph->p_type = PT_PHDR; |
ph->p_offset = sizeof(ElfW(Ehdr)); |
ph->p_vaddr = interp->sh_addr - len; |
ph->p_paddr = ph->p_vaddr; |
ph->p_filesz = ph->p_memsz = len; |
ph->p_flags = PF_R | PF_X; |
ph->p_align = 4; /* interp->sh_addralign; */ |
ph++; |
} |
ph->p_type = PT_INTERP; |
ph->p_offset = interp->sh_offset; |
ph->p_vaddr = interp->sh_addr; |
2275,8 → 1476,10 |
ph->p_align = interp->sh_addralign; |
} |
/* if dynamic section, then add corresponding program header */ |
/* if dynamic section, then add corresponing program header */ |
if (dynamic) { |
Elf32_Sym *sym_end; |
ph = &phdr[phnum - 1]; |
ph->p_type = PT_DYNAMIC; |
2287,71 → 1490,105 |
ph->p_memsz = dynamic->sh_size; |
ph->p_flags = PF_R | PF_W; |
ph->p_align = dynamic->sh_addralign; |
/* put GOT dynamic section address */ |
put32(s1->got->data, dynamic->sh_addr); |
/* relocate the PLT */ |
if (file_type == TCC_OUTPUT_EXE) { |
uint8_t *p, *p_end; |
p = s1->plt->data; |
p_end = p + s1->plt->data_offset; |
if (p < p_end) { |
#if defined(TCC_TARGET_I386) |
put32(p + 2, get32(p + 2) + s1->got->sh_addr); |
put32(p + 8, get32(p + 8) + s1->got->sh_addr); |
p += 16; |
while (p < p_end) { |
put32(p + 2, get32(p + 2) + s1->got->sh_addr); |
p += 16; |
} |
#elif defined(TCC_TARGET_ARM) |
int x; |
x=s1->got->sh_addr - s1->plt->sh_addr - 12; |
p +=16; |
while (p < p_end) { |
put32(p + 12, x + get32(p + 12) + s1->plt->data - p); |
p += 16; |
} |
#elif defined(TCC_TARGET_C67) |
/* XXX: TODO */ |
#else |
#error unsupported CPU |
#endif |
} |
} |
/* Fill the dynamic section with tags describing the address and size of |
sections */ |
static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) |
{ |
Section *dynamic; |
/* relocate symbols in .dynsym */ |
sym_end = (Elf32_Sym *)(s1->dynsym->data + s1->dynsym->data_offset); |
for(sym = (Elf32_Sym *)s1->dynsym->data + 1; |
sym < sym_end; |
sym++) { |
if (sym->st_shndx == SHN_UNDEF) { |
/* relocate to the PLT if the symbol corresponds |
to a PLT entry */ |
if (sym->st_value) |
sym->st_value += s1->plt->sh_addr; |
} else if (sym->st_shndx < SHN_LORESERVE) { |
/* do symbol relocation */ |
sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
} |
} |
dynamic = dyninf->dynamic; |
/* put dynamic section entries */ |
dynamic->data_offset = dyninf->dyn_rel_off; |
dynamic->data_offset = saved_dynamic_data_offset; |
put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); |
put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr); |
put_dt(dynamic, DT_STRTAB, dynstr->sh_addr); |
put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); |
put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); |
#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
put_dt(dynamic, DT_RELA, dyninf->rel_addr); |
put_dt(dynamic, DT_RELASZ, dyninf->rel_size); |
put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); |
#else |
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); |
put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); |
put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); |
put_dt(dynamic, DT_PLTREL, DT_REL); |
put_dt(dynamic, DT_REL, dyninf->bss_addr); |
put_dt(dynamic, DT_RELSZ, dyninf->bss_size); |
#else |
put_dt(dynamic, DT_REL, dyninf->rel_addr); |
put_dt(dynamic, DT_RELSZ, dyninf->rel_size); |
put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); |
#endif |
#endif |
if (s1->do_debug) |
put_dt(dynamic, DT_DEBUG, 0); |
put_dt(dynamic, DT_STRSZ, dynstr->data_offset); |
put_dt(dynamic, DT_SYMENT, sizeof(Elf32_Sym)); |
put_dt(dynamic, DT_REL, rel_addr); |
put_dt(dynamic, DT_RELSZ, rel_size); |
put_dt(dynamic, DT_RELENT, sizeof(Elf32_Rel)); |
put_dt(dynamic, DT_NULL, 0); |
} |
/* Relocate remaining sections and symbols (that is those not related to |
dynamic linking) */ |
static int final_sections_reloc(TCCState *s1) |
{ |
int i; |
Section *s; |
ehdr.e_phentsize = sizeof(Elf32_Phdr); |
ehdr.e_phnum = phnum; |
ehdr.e_phoff = sizeof(Elf32_Ehdr); |
} |
/* all other sections come after */ |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[i]; |
if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) |
continue; |
section_order[sh_order_index++] = i; |
file_offset = (file_offset + s->sh_addralign - 1) & |
~(s->sh_addralign - 1); |
s->sh_offset = file_offset; |
if (s->sh_type != SHT_NOBITS) |
file_offset += s->sh_size; |
} |
/* if building executable or DLL, then relocate each section |
except the GOT which is already relocated */ |
if (file_type != TCC_OUTPUT_OBJ) { |
relocate_syms(s1, 0); |
if (s1->nb_errors != 0) |
return -1; |
if (s1->nb_errors != 0) { |
fail: |
ret = -1; |
goto the_end; |
} |
/* relocate sections */ |
/* XXX: ignore sections with allocated relocations ? */ |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[i]; |
#ifdef TCC_TARGET_I386 |
if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr |
/* On X86 gdb 7.3 works in any case but gdb 6.6 will crash if SHF_ALLOC |
checking is removed */ |
#else |
if (s->reloc && s != s1->got) |
/* On X86_64 gdb 7.3 will crash if SHF_ALLOC checking is present */ |
#endif |
relocate_section(s1, s); |
} |
2360,34 → 1597,38 |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[i]; |
if ((s->sh_flags & SHF_ALLOC) && |
s->sh_type == SHT_RELX) { |
s->sh_type == SHT_REL) { |
relocate_rel(s1, s); |
} |
} |
return 0; |
/* get entry point address */ |
if (file_type == TCC_OUTPUT_EXE) |
ehdr.e_entry = (unsigned long)tcc_get_symbol_err(s1, "_start"); |
else |
ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ |
} |
/* Create an ELF file on disk. |
This function handle ELF specific layout requirements */ |
static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, |
int file_offset, int *sec_order) |
{ |
int i, shnum, offset, size, file_type; |
Section *s; |
ElfW(Ehdr) ehdr; |
ElfW(Shdr) shdr, *sh; |
/* write elf file */ |
if (file_type == TCC_OUTPUT_OBJ) |
mode = 0666; |
else |
mode = 0777; |
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
if (fd < 0) { |
error_noabort("could not write '%s'", filename); |
goto fail; |
} |
f = fdopen(fd, "wb"); |
file_type = s1->output_type; |
shnum = s1->nb_sections; |
#ifdef TCC_TARGET_COFF |
if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) { |
tcc_output_coff(s1, f); |
} else |
#endif |
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
sort_syms(s1, symtab_section); |
memset(&ehdr, 0, sizeof(ehdr)); |
if (phnum > 0) { |
ehdr.e_phentsize = sizeof(ElfW(Phdr)); |
ehdr.e_phnum = phnum; |
ehdr.e_phoff = sizeof(ElfW(Ehdr)); |
} |
/* align to 4 */ |
file_offset = (file_offset + 3) & -4; |
2396,35 → 1637,22 |
ehdr.e_ident[1] = ELFMAG1; |
ehdr.e_ident[2] = ELFMAG2; |
ehdr.e_ident[3] = ELFMAG3; |
ehdr.e_ident[4] = ELFCLASSW; |
ehdr.e_ident[4] = ELFCLASS32; |
ehdr.e_ident[5] = ELFDATA2LSB; |
ehdr.e_ident[6] = EV_CURRENT; |
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
#ifdef __FreeBSD__ |
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; |
#endif |
#ifdef TCC_TARGET_ARM |
#ifdef TCC_ARM_EABI |
ehdr.e_ident[EI_OSABI] = 0; |
ehdr.e_flags = EF_ARM_EABI_VER4; |
if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL) |
ehdr.e_flags |= EF_ARM_HASENTRY; |
if (s1->float_abi == ARM_HARD_FLOAT) |
ehdr.e_flags |= EF_ARM_VFP_FLOAT; |
else |
ehdr.e_flags |= EF_ARM_SOFT_FLOAT; |
#else |
ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; |
#endif |
#endif |
switch(file_type) { |
default: |
case TCC_OUTPUT_EXE: |
ehdr.e_type = ET_EXEC; |
ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1); |
break; |
case TCC_OUTPUT_DLL: |
ehdr.e_type = ET_DYN; |
ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ |
break; |
case TCC_OUTPUT_OBJ: |
ehdr.e_type = ET_REL; |
2433,27 → 1661,23 |
ehdr.e_machine = EM_TCC_TARGET; |
ehdr.e_version = EV_CURRENT; |
ehdr.e_shoff = file_offset; |
ehdr.e_ehsize = sizeof(ElfW(Ehdr)); |
ehdr.e_shentsize = sizeof(ElfW(Shdr)); |
ehdr.e_ehsize = sizeof(Elf32_Ehdr); |
ehdr.e_shentsize = sizeof(Elf32_Shdr); |
ehdr.e_shnum = shnum; |
ehdr.e_shstrndx = shnum - 1; |
fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); |
fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); |
offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); |
fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f); |
fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f); |
offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); |
sort_syms(s1, symtab_section); |
for(i = 1; i < s1->nb_sections; i++) { |
s = s1->sections[sec_order[i]]; |
s = s1->sections[section_order[i]]; |
if (s->sh_type != SHT_NOBITS) { |
if (s->sh_type == SHT_DYNSYM) |
patch_dynsym_undef(s1, s); |
while (offset < s->sh_offset) { |
fputc(0, f); |
offset++; |
} |
size = s->sh_size; |
if (size) |
fwrite(s->data, 1, size, f); |
offset += size; |
} |
2467,7 → 1691,7 |
for(i = 0; i < s1->nb_sections; i++) { |
sh = &shdr; |
memset(sh, 0, sizeof(ElfW(Shdr))); |
memset(sh, 0, sizeof(Elf32_Shdr)); |
s = s1->sections[i]; |
if (s) { |
sh->sh_name = s->sh_name; |
2482,269 → 1706,22 |
sh->sh_offset = s->sh_offset; |
sh->sh_size = s->sh_size; |
} |
fwrite(sh, 1, sizeof(ElfW(Shdr)), f); |
fwrite(sh, 1, sizeof(Elf32_Shdr), f); |
} |
} else { |
tcc_output_binary(s1, f, section_order); |
} |
/* Write an elf, coff or "binary" file */ |
static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, |
ElfW(Phdr) *phdr, int file_offset, int *sec_order) |
{ |
int fd, mode, file_type; |
FILE *f; |
file_type = s1->output_type; |
if (file_type == TCC_OUTPUT_OBJ) |
mode = 0666; |
else |
mode = 0777; |
unlink(filename); |
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
if (fd < 0) { |
tcc_error_noabort("could not write '%s'", filename); |
return -1; |
} |
f = fdopen(fd, "wb"); |
if (s1->verbose) |
printf("<- %s\n", filename); |
#ifdef TCC_TARGET_COFF |
if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) |
tcc_output_coff(s1, f); |
else |
#endif |
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) |
tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order); |
else |
tcc_output_binary(s1, f, sec_order); |
fclose(f); |
return 0; |
} |
/* Output an elf, coff or binary file */ |
/* XXX: suppress unneeded sections */ |
static int elf_output_file(TCCState *s1, const char *filename) |
{ |
int i, ret, phnum, shnum, file_type, file_offset, *sec_order; |
struct dyn_inf dyninf; |
ElfW(Phdr) *phdr; |
ElfW(Sym) *sym; |
Section *strsec, *interp, *dynamic, *dynstr; |
file_type = s1->output_type; |
s1->nb_errors = 0; |
/* if linking, also link in runtime libraries (libc, libgcc, etc.) */ |
if (file_type != TCC_OUTPUT_OBJ) { |
tcc_add_runtime(s1); |
} |
phdr = NULL; |
sec_order = NULL; |
interp = dynamic = dynstr = NULL; /* avoid warning */ |
dyninf.dyn_rel_off = 0; /* avoid warning */ |
if (file_type != TCC_OUTPUT_OBJ) { |
relocate_common_syms(); |
tcc_add_linker_symbols(s1); |
if (!s1->static_link) { |
if (file_type == TCC_OUTPUT_EXE) { |
char *ptr; |
/* allow override the dynamic loader */ |
const char *elfint = getenv("LD_SO"); |
if (elfint == NULL) |
elfint = DEFAULT_ELFINTERP(s1); |
/* add interpreter section only if executable */ |
interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); |
interp->sh_addralign = 1; |
ptr = section_ptr_add(interp, 1 + strlen(elfint)); |
strcpy(ptr, elfint); |
} |
/* add dynamic symbol table */ |
s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, |
".dynstr", |
".hash", SHF_ALLOC); |
dynstr = s1->dynsym->link; |
/* add dynamic section */ |
dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, |
SHF_ALLOC | SHF_WRITE); |
dynamic->link = dynstr; |
dynamic->sh_entsize = sizeof(ElfW(Dyn)); |
build_got(s1); |
if (file_type == TCC_OUTPUT_EXE) { |
bind_exe_dynsyms(s1); |
if (s1->nb_errors) { |
ret = -1; |
goto the_end; |
} |
bind_libs_dynsyms(s1); |
} else /* shared library case: simply export all global symbols */ |
export_global_syms(s1); |
build_got_entries(s1); |
/* add a list of needed dlls */ |
for(i = 0; i < s1->nb_loaded_dlls; i++) { |
DLLReference *dllref = s1->loaded_dlls[i]; |
if (dllref->level == 0) |
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); |
} |
if (s1->rpath) |
put_dt(dynamic, DT_RPATH, put_elf_str(dynstr, s1->rpath)); |
/* XXX: currently, since we do not handle PIC code, we |
must relocate the readonly segments */ |
if (file_type == TCC_OUTPUT_DLL) { |
if (s1->soname) |
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); |
put_dt(dynamic, DT_TEXTREL, 0); |
} |
if (s1->symbolic) |
put_dt(dynamic, DT_SYMBOLIC, 0); |
/* add necessary space for other entries */ |
dyninf.dyn_rel_off = dynamic->data_offset; |
dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS; |
} else { |
/* still need to build got entries in case of static link */ |
build_got_entries(s1); |
} |
} |
/* we add a section for symbols */ |
strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); |
put_elf_str(strsec, ""); |
/* compute number of sections */ |
shnum = s1->nb_sections; |
/* this array is used to reorder sections in the output file */ |
sec_order = tcc_malloc(sizeof(int) * shnum); |
sec_order[0] = 0; |
/* compute number of program headers */ |
switch(file_type) { |
default: |
case TCC_OUTPUT_OBJ: |
phnum = 0; |
break; |
case TCC_OUTPUT_EXE: |
if (!s1->static_link) |
phnum = 4 + HAVE_PHDR; |
else |
phnum = 2; |
break; |
case TCC_OUTPUT_DLL: |
phnum = 3; |
break; |
} |
/* Allocate strings for section names */ |
alloc_sec_names(s1, file_type, strsec); |
/* allocate program segment headers */ |
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); |
/* compute section to program header mapping */ |
file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf, |
sec_order); |
/* Fill remaining program header and finalize relocation related to dynamic |
linking. */ |
if (phnum > 0) { |
fill_unloadable_phdr(phdr, phnum, interp, dynamic); |
if (dynamic) { |
dyninf.dynamic = dynamic; |
dyninf.dynstr = dynstr; |
fill_dynamic(s1, &dyninf); |
/* put in GOT the dynamic section address and relocate PLT */ |
write32le(s1->got->data, dynamic->sh_addr); |
if (file_type == TCC_OUTPUT_EXE |
#if defined(TCC_OUTPUT_DLL_WITH_PLT) |
|| file_type == TCC_OUTPUT_DLL |
#endif |
) |
relocate_plt(s1); |
/* relocate symbols in .dynsym now that final addresses are known */ |
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { |
if (sym->st_shndx == SHN_UNDEF) { |
/* relocate to PLT if symbol corresponds to a PLT entry, |
but not if it's a weak symbol */ |
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) |
sym->st_value = 0; |
else if (sym->st_value) |
sym->st_value += s1->plt->sh_addr; |
} else if (sym->st_shndx < SHN_LORESERVE) { |
/* do symbol relocation */ |
sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
} |
} |
} |
} |
/* if building executable or DLL, then relocate each section |
except the GOT which is already relocated */ |
if (file_type != TCC_OUTPUT_OBJ) { |
ret = final_sections_reloc(s1); |
if (ret) |
goto the_end; |
} |
/* Perform relocation to GOT or PLT entries */ |
if (file_type == TCC_OUTPUT_EXE && s1->static_link) |
fill_got(s1); |
/* Create the ELF file with name 'filename' */ |
ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order); |
if (s1->do_strip) { |
int rc; |
const char *strip_cmd = "sstrip "; // super strip utility from ELFkickers |
const char *null_dev = " 2> /dev/null"; |
char buf[1050]; |
snprintf(buf, sizeof(buf), "%s%s%s", strip_cmd, filename, null_dev); |
rc = system(buf); |
if (rc) |
system(buf+1); // call a strip utility from binutils |
} |
ret = 0; |
the_end: |
tcc_free(s1->symtab_to_dynsym); |
tcc_free(sec_order); |
tcc_free(section_order); |
tcc_free(phdr); |
tcc_free(s1->sym_attrs); |
s1->sym_attrs = NULL; |
tcc_free(s1->got_offsets); |
return ret; |
} |
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) |
{ |
int ret; |
#ifdef TCC_TARGET_PE |
if (s->output_type != TCC_OUTPUT_OBJ) { |
ret = pe_output_file(s, filename); |
} else |
#elif defined TCC_TARGET_MEOS |
if (s->output_type != TCC_OUTPUT_OBJ) { |
ret = tcc_output_me(s, filename); |
} else |
#endif |
ret = elf_output_file(s, filename); |
return ret; |
} |
static void *load_data(int fd, unsigned long file_offset, unsigned long size) |
{ |
void *data; |
2764,25 → 1741,20 |
/* load an object file and merge it with current files */ |
/* XXX: handle correctly stab (debug) info */ |
ST_FUNC int tcc_load_object_file(TCCState *s1, |
static int tcc_load_object_file(TCCState *s1, |
int fd, unsigned long file_offset) |
{ |
ElfW(Ehdr) ehdr; |
ElfW(Shdr) *shdr, *sh; |
Elf32_Ehdr ehdr; |
Elf32_Shdr *shdr, *sh; |
int size, i, j, offset, offseti, nb_syms, sym_index, ret; |
unsigned char *strsec, *strtab; |
int *old_to_new_syms; |
char *sh_name, *name; |
SectionMergeInfo *sm_table, *sm; |
ElfW(Sym) *sym, *symtab; |
ElfW_Rel *rel; |
Elf32_Sym *sym, *symtab; |
Elf32_Rel *rel, *rel_end; |
Section *s; |
int stab_index; |
int stabstr_index; |
stab_index = stabstr_index = 0; |
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) |
goto fail1; |
if (ehdr.e_ident[0] != ELFMAG0 || |
2797,12 → 1769,12 |
if (ehdr.e_ident[5] != ELFDATA2LSB || |
ehdr.e_machine != EM_TCC_TARGET) { |
fail1: |
tcc_error_noabort("invalid object file"); |
error_noabort("invalid object file"); |
return -1; |
} |
/* read sections */ |
shdr = load_data(fd, file_offset + ehdr.e_shoff, |
sizeof(ElfW(Shdr)) * ehdr.e_shnum); |
sizeof(Elf32_Shdr) * ehdr.e_shnum); |
sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum); |
/* load section names */ |
2818,12 → 1790,12 |
sh = &shdr[i]; |
if (sh->sh_type == SHT_SYMTAB) { |
if (symtab) { |
tcc_error_noabort("object must contain only one symtab"); |
error_noabort("object must contain only one symtab"); |
fail: |
ret = -1; |
goto the_end; |
} |
nb_syms = sh->sh_size / sizeof(ElfW(Sym)); |
nb_syms = sh->sh_size / sizeof(Elf32_Sym); |
symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); |
sm_table[i].s = symtab_section; |
2840,19 → 1812,11 |
if (i == ehdr.e_shstrndx) |
continue; |
sh = &shdr[i]; |
sh_name = (char *) strsec + sh->sh_name; |
sh_name = strsec + sh->sh_name; |
/* ignore sections types we do not handle */ |
if (sh->sh_type != SHT_PROGBITS && |
sh->sh_type != SHT_RELX && |
#ifdef TCC_ARM_EABI |
sh->sh_type != SHT_ARM_EXIDX && |
#endif |
sh->sh_type != SHT_NOBITS && |
sh->sh_type != SHT_PREINIT_ARRAY && |
sh->sh_type != SHT_INIT_ARRAY && |
sh->sh_type != SHT_FINI_ARRAY && |
strcmp(sh_name, ".stabstr") |
) |
sh->sh_type != SHT_REL && |
sh->sh_type != SHT_NOBITS) |
continue; |
if (sh->sh_addralign < 1) |
sh->sh_addralign = 1; |
2882,28 → 1846,17 |
sm_table[i].new_section = 1; |
found: |
if (sh->sh_type != s->sh_type) { |
tcc_error_noabort("invalid section type"); |
error_noabort("invalid section type"); |
goto fail; |
} |
/* align start of section */ |
offset = s->data_offset; |
if (0 == strcmp(sh_name, ".stab")) { |
stab_index = i; |
goto no_align; |
} |
if (0 == strcmp(sh_name, ".stabstr")) { |
stabstr_index = i; |
goto no_align; |
} |
size = sh->sh_addralign - 1; |
offset = (offset + size) & ~size; |
if (sh->sh_addralign > s->sh_addralign) |
s->sh_addralign = sh->sh_addralign; |
s->data_offset = offset; |
no_align: |
sm_table[i].offset = offset; |
sm_table[i].s = s; |
/* concatenate sections */ |
2919,20 → 1872,9 |
next: ; |
} |
/* gr relocate stab strings */ |
if (stab_index && stabstr_index) { |
Stab_Sym *a, *b; |
unsigned o; |
s = sm_table[stab_index].s; |
a = (Stab_Sym *)(s->data + sm_table[stab_index].offset); |
b = (Stab_Sym *)(s->data + s->data_offset); |
o = sm_table[stabstr_index].offset; |
while (a < b) |
a->n_strx += o, a++; |
} |
/* second short pass to update sh_link and sh_info fields of new |
sections */ |
sm = sm_table; |
for(i = 1; i < ehdr.e_shnum; i++) { |
s = sm_table[i].s; |
if (!s || !sm_table[i].new_section) |
2940,13 → 1882,12 |
sh = &shdr[i]; |
if (sh->sh_link > 0) |
s->link = sm_table[sh->sh_link].s; |
if (sh->sh_type == SHT_RELX) { |
if (sh->sh_type == SHT_REL) { |
s->sh_info = sm_table[sh->sh_info].s->sh_num; |
/* update backward link */ |
s1->sections[s->sh_info]->reloc = s; |
} |
} |
sm = sm_table; |
/* resolve symbols */ |
old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int)); |
2960,8 → 1901,8 |
/* if a symbol is in a link once section, we use the |
already defined symbol. It is very important to get |
correct relocations */ |
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
name = (char *) strtab + sym->st_name; |
if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
name = strtab + sym->st_name; |
sym_index = find_elf_sym(symtab_section, name); |
if (sym_index) |
old_to_new_syms[i] = sym_index; |
2977,7 → 1918,7 |
sym->st_value += sm->offset; |
} |
/* add symbol */ |
name = (char *) strtab + sym->st_name; |
name = strtab + sym->st_name; |
sym_index = add_elf_sym(symtab_section, sym->st_value, sym->st_size, |
sym->st_info, sym->st_other, |
sym->st_shndx, name); |
2992,45 → 1933,30 |
sh = &shdr[i]; |
offset = sm_table[i].offset; |
switch(s->sh_type) { |
case SHT_RELX: |
case SHT_REL: |
/* take relocation offset information */ |
offseti = sm_table[sh->sh_info].offset; |
for_each_elem(s, (offset / sizeof(*rel)), rel, ElfW_Rel) { |
rel_end = (Elf32_Rel *)(s->data + s->data_offset); |
for(rel = (Elf32_Rel *)(s->data + offset); |
rel < rel_end; |
rel++) { |
int type; |
unsigned sym_index; |
/* convert symbol index */ |
type = ELFW(R_TYPE)(rel->r_info); |
sym_index = ELFW(R_SYM)(rel->r_info); |
type = ELF32_R_TYPE(rel->r_info); |
sym_index = ELF32_R_SYM(rel->r_info); |
/* NOTE: only one symtab assumed */ |
if (sym_index >= nb_syms) |
goto invalid_reloc; |
sym_index = old_to_new_syms[sym_index]; |
/* ignore link_once in rel section. */ |
if (!sym_index && !sm->link_once |
#ifdef TCC_TARGET_ARM |
&& type != R_ARM_V4BX |
#endif |
) { |
if (!sym_index) { |
invalid_reloc: |
tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x", |
i, strsec + sh->sh_name, rel->r_offset); |
error_noabort("Invalid relocation entry"); |
goto fail; |
} |
rel->r_info = ELFW(R_INFO)(sym_index, type); |
rel->r_info = ELF32_R_INFO(sym_index, type); |
/* offset the relocation offset */ |
rel->r_offset += offseti; |
#ifdef TCC_TARGET_ARM |
/* Jumps and branches from a Thumb code to a PLT entry need |
special handling since PLT entries are ARM code. |
Unconditional bl instructions referencing PLT entries are |
handled by converting these instructions into blx |
instructions. Other case of instructions referencing a PLT |
entry require to add a Thumb stub before the PLT entry to |
switch to ARM mode. We set bit plt_thumb_stub of the |
attribute of a symbol to indicate such a case. */ |
if (type == R_ARM_THM_JUMP24) |
alloc_sym_attr(s1, sym_index)->plt_thumb_stub = 1; |
#endif |
} |
break; |
default: |
3049,6 → 1975,8 |
return ret; |
} |
#define ARMAG "!<arch>\012" /* For COFF and a.out archives */ |
typedef struct ArchiveHeader { |
char ar_name[16]; /* name of this member */ |
char ar_date[12]; /* file mtime */ |
3071,7 → 1999,7 |
uint8_t *data; |
const char *ar_names, *p; |
const uint8_t *ar_index; |
ElfW(Sym) *sym; |
Elf32_Sym *sym; |
data = tcc_malloc(size); |
if (read(fd, data, size) != size) |
3078,7 → 2006,7 |
goto fail; |
nsyms = get_be32(data); |
ar_index = data + 4; |
ar_names = (char *) ar_index + nsyms * 4; |
ar_names = ar_index + nsyms * 4; |
do { |
bound = 0; |
3085,9 → 2013,12 |
for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { |
sym_index = find_elf_sym(symtab_section, p); |
if(sym_index) { |
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
if(sym->st_shndx == SHN_UNDEF) { |
off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader); |
#if 0 |
printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx); |
#endif |
++bound; |
lseek(fd, off, SEEK_SET); |
if(tcc_load_object_file(s1, fd, off) < 0) { |
3106,7 → 2037,7 |
} |
/* load a '.a' file */ |
ST_FUNC int tcc_load_archive(TCCState *s1, int fd) |
static int tcc_load_archive(TCCState *s1, int fd) |
{ |
ArchiveHeader hdr; |
char ar_size[11]; |
3123,7 → 2054,7 |
if (len == 0) |
break; |
if (len != sizeof(hdr)) { |
tcc_error_noabort("invalid archive"); |
error_noabort("invalid archive"); |
return -1; |
} |
memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size)); |
3135,6 → 2066,7 |
break; |
} |
ar_name[i + 1] = '\0'; |
// printf("name='%s' size=%d %s\n", ar_name, size, ar_size); |
file_offset = lseek(fd, 0, SEEK_CUR); |
/* align to even */ |
size = (size + 1) & ~1; |
3156,19 → 2088,18 |
return 0; |
} |
#if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL |
is referenced by the user (so it should be added as DT_NEEDED in |
the generated ELF file) */ |
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) |
static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) |
{ |
ElfW(Ehdr) ehdr; |
ElfW(Shdr) *shdr, *sh, *sh1; |
int i, j, nb_syms, nb_dts, sym_bind, ret; |
ElfW(Sym) *sym, *dynsym; |
ElfW(Dyn) *dt, *dynamic; |
Elf32_Ehdr ehdr; |
Elf32_Shdr *shdr, *sh, *sh1; |
int i, nb_syms, nb_dts, sym_bind, ret; |
Elf32_Sym *sym, *dynsym; |
Elf32_Dyn *dt, *dynamic; |
unsigned char *dynstr; |
const char *name, *soname; |
const char *name, *soname, *p; |
DLLReference *dllref; |
read(fd, &ehdr, sizeof(ehdr)); |
3176,12 → 2107,12 |
/* test CPU specific stuff */ |
if (ehdr.e_ident[5] != ELFDATA2LSB || |
ehdr.e_machine != EM_TCC_TARGET) { |
tcc_error_noabort("bad architecture"); |
error_noabort("bad architecture"); |
return -1; |
} |
/* read sections */ |
shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum); |
shdr = load_data(fd, ehdr.e_shoff, sizeof(Elf32_Shdr) * ehdr.e_shnum); |
/* load dynamic section and dynamic symbols */ |
nb_syms = 0; |
3192,11 → 2123,11 |
for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { |
switch(sh->sh_type) { |
case SHT_DYNAMIC: |
nb_dts = sh->sh_size / sizeof(ElfW(Dyn)); |
nb_dts = sh->sh_size / sizeof(Elf32_Dyn); |
dynamic = load_data(fd, sh->sh_offset, sh->sh_size); |
break; |
case SHT_DYNSYM: |
nb_syms = sh->sh_size / sizeof(ElfW(Sym)); |
nb_syms = sh->sh_size / sizeof(Elf32_Sym); |
dynsym = load_data(fd, sh->sh_offset, sh->sh_size); |
sh1 = &shdr[sh->sh_link]; |
dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); |
3207,11 → 2138,14 |
} |
/* compute the real library name */ |
soname = tcc_basename(filename); |
soname = filename; |
p = strrchr(soname, '/'); |
if (p) |
soname = p + 1; |
for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { |
if (dt->d_tag == DT_SONAME) { |
soname = (char *) dynstr + dt->d_un.d_val; |
soname = dynstr + dt->d_un.d_val; |
} |
} |
3227,8 → 2161,10 |
} |
} |
// printf("loading dll '%s'\n", soname); |
/* add the dll and its level */ |
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); |
dllref = tcc_malloc(sizeof(DLLReference) + strlen(soname)); |
dllref->level = level; |
strcpy(dllref->name, soname); |
dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
3235,10 → 2171,10 |
/* add dynamic symbols in dynsym_section */ |
for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { |
sym_bind = ELFW(ST_BIND)(sym->st_info); |
sym_bind = ELF32_ST_BIND(sym->st_info); |
if (sym_bind == STB_LOCAL) |
continue; |
name = (char *) dynstr + sym->st_name; |
name = dynstr + sym->st_name; |
add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, |
sym->st_info, sym->st_other, sym->st_shndx, name); |
} |
3247,14 → 2183,14 |
for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { |
switch(dt->d_tag) { |
case DT_NEEDED: |
name = (char *) dynstr + dt->d_un.d_val; |
for(j = 0; j < s1->nb_loaded_dlls; j++) { |
dllref = s1->loaded_dlls[j]; |
name = dynstr + dt->d_un.d_val; |
for(i = 0; i < s1->nb_loaded_dlls; i++) { |
dllref = s1->loaded_dlls[i]; |
if (!strcmp(name, dllref->name)) |
goto already_loaded; |
} |
if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { |
tcc_error_noabort("referenced dll '%s' not found", name); |
error_noabort("referenced dll '%s' not found", name); |
ret = -1; |
goto the_end; |
} |
3288,12 → 2224,12 |
case '\v': |
case '\r': |
case '\n': |
inp(); |
input(); |
goto redo; |
case '/': |
minp(); |
if (ch == '*') { |
file->buf_ptr = parse_comment(file->buf_ptr,0); |
file->buf_ptr = parse_comment(file->buf_ptr); |
ch = file->buf_ptr[0]; |
goto redo; |
} else { |
3302,66 → 2238,10 |
goto parse_name; |
} |
break; |
case 'a' ... 'z': |
case 'A' ... 'Z': |
case '_': |
case '\\': |
ch = handle_eob(); |
if (ch != '\\') |
goto redo; |
/* fall through */ |
/* case 'a' ... 'z': */ |
case 'a': |
case 'b': |
case 'c': |
case 'd': |
case 'e': |
case 'f': |
case 'g': |
case 'h': |
case 'i': |
case 'j': |
case 'k': |
case 'l': |
case 'm': |
case 'n': |
case 'o': |
case 'p': |
case 'q': |
case 'r': |
case 's': |
case 't': |
case 'u': |
case 'v': |
case 'w': |
case 'x': |
case 'y': |
case 'z': |
/* case 'A' ... 'z': */ |
case 'A': |
case 'B': |
case 'C': |
case 'D': |
case 'E': |
case 'F': |
case 'G': |
case 'H': |
case 'I': |
case 'J': |
case 'K': |
case 'L': |
case 'M': |
case 'N': |
case 'O': |
case 'P': |
case 'Q': |
case 'R': |
case 'S': |
case 'T': |
case 'U': |
case 'V': |
case 'W': |
case 'X': |
case 'Y': |
case 'Z': |
case '_': |
case '.': |
case '$': |
case '~': |
3386,125 → 2266,55 |
break; |
default: |
c = ch; |
inp(); |
input(); |
break; |
} |
#if 0 |
printf("tok=%c %d\n", c, c); |
if (c == LD_TOK_NAME) |
printf(" name=%s\n", name); |
#endif |
return c; |
} |
static int ld_add_file(TCCState *s1, const char filename[]) |
/* interpret a subset of GNU ldscripts to handle the dummy libc.so |
files */ |
static int tcc_load_ldscript(TCCState *s1) |
{ |
int ret; |
char cmd[64]; |
char filename[1024]; |
int t; |
ret = tcc_add_file_internal(s1, filename, 0, TCC_FILETYPE_BINARY); |
if (ret) |
ret = tcc_add_dll(s1, filename, 0); |
return ret; |
} |
static inline int new_undef_syms(void) |
{ |
int ret = 0; |
ret = new_undef_sym; |
new_undef_sym = 0; |
return ret; |
} |
static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) |
{ |
char filename[1024], libname[1024]; |
int t, group, nblibs = 0, ret = 0; |
char **libs = NULL; |
group = !strcmp(cmd, "GROUP"); |
if (!as_needed) |
new_undef_syms(); |
t = ld_next(s1, filename, sizeof(filename)); |
ch = file->buf_ptr[0]; |
ch = handle_eob(); |
for(;;) { |
t = ld_next(s1, cmd, sizeof(cmd)); |
if (t == LD_TOK_EOF) |
return 0; |
else if (t != LD_TOK_NAME) |
return -1; |
if (!strcmp(cmd, "INPUT") || |
!strcmp(cmd, "GROUP")) { |
t = ld_next(s1, cmd, sizeof(cmd)); |
if (t != '(') |
expect("("); |
t = ld_next(s1, filename, sizeof(filename)); |
for(;;) { |
libname[0] = '\0'; |
if (t == LD_TOK_EOF) { |
tcc_error_noabort("unexpected end of file"); |
ret = -1; |
goto lib_parse_error; |
error_noabort("unexpected end of file"); |
return -1; |
} else if (t == ')') { |
break; |
} else if (t == '-') { |
t = ld_next(s1, filename, sizeof(filename)); |
if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { |
tcc_error_noabort("library name expected"); |
ret = -1; |
goto lib_parse_error; |
} |
pstrcpy(libname, sizeof libname, &filename[1]); |
if (s1->static_link) { |
snprintf(filename, sizeof filename, "lib%s.a", libname); |
} else { |
snprintf(filename, sizeof filename, "lib%s.so", libname); |
} |
} else if (t != LD_TOK_NAME) { |
tcc_error_noabort("filename expected"); |
ret = -1; |
goto lib_parse_error; |
error_noabort("filename expected"); |
return -1; |
} |
if (!strcmp(filename, "AS_NEEDED")) { |
ret = ld_add_file_list(s1, cmd, 1); |
if (ret) |
goto lib_parse_error; |
} else { |
/* TODO: Implement AS_NEEDED support. Ignore it for now */ |
if (!as_needed) { |
ret = ld_add_file(s1, filename); |
if (ret) |
goto lib_parse_error; |
if (group) { |
/* Add the filename *and* the libname to avoid future conversions */ |
dynarray_add((void ***) &libs, &nblibs, tcc_strdup(filename)); |
if (libname[0] != '\0') |
dynarray_add((void ***) &libs, &nblibs, tcc_strdup(libname)); |
} |
} |
} |
tcc_add_file(s1, filename); |
t = ld_next(s1, filename, sizeof(filename)); |
if (t == ',') { |
t = ld_next(s1, filename, sizeof(filename)); |
} |
} |
if (group && !as_needed) { |
while (new_undef_syms()) { |
int i; |
for (i = 0; i < nblibs; i ++) |
ld_add_file(s1, libs[i]); |
} |
} |
lib_parse_error: |
dynarray_reset(&libs, &nblibs); |
return ret; |
} |
/* interpret a subset of GNU ldscripts to handle the dummy libc.so |
files */ |
ST_FUNC int tcc_load_ldscript(TCCState *s1) |
{ |
char cmd[64]; |
char filename[1024]; |
int t, ret; |
ch = handle_eob(); |
for(;;) { |
t = ld_next(s1, cmd, sizeof(cmd)); |
if (t == LD_TOK_EOF) |
return 0; |
else if (t != LD_TOK_NAME) |
return -1; |
if (!strcmp(cmd, "INPUT") || |
!strcmp(cmd, "GROUP")) { |
ret = ld_add_file_list(s1, cmd, 0); |
if (ret) |
return ret; |
} else if (!strcmp(cmd, "OUTPUT_FORMAT") || |
!strcmp(cmd, "TARGET")) { |
/* ignore some commands */ |
3514,7 → 2324,7 |
for(;;) { |
t = ld_next(s1, filename, sizeof(filename)); |
if (t == LD_TOK_EOF) { |
tcc_error_noabort("unexpected end of file"); |
error_noabort("unexpected end of file"); |
return -1; |
} else if (t == ')') { |
break; |
3526,4 → 2336,3 |
} |
return 0; |
} |
#endif /* !TCC_TARGET_PE */ |
/programs/develop/ktcc/trunk/source/tccmeos.c |
---|
96,12 → 96,7 |
Elf32_Sym* esym = ((Elf32_Sym *)symtab_section->data)+sym; |
int sect=esym->st_shndx; |
ss=findsection(me,sect); |
if (ss==0) |
{ |
const char *sym_name = strtab_section->data + esym->st_name; |
tcc_error_noabort("undefined symbol '%s'", sym_name); |
continue; |
} |
if (ss==0) continue; |
if (rel->r_offset>s->data_size) |
continue; |
if (type==R_386_PC32) |
183,15 → 178,6 |
me->header.memory_size=addr; |
build_reloc(me); |
} |
const char *tcc_get_symbol_name(int st_name) |
// return string by index from stringtable section |
{ |
const char *sym_name = strtab_section->data + st_name; |
return sym_name; |
} |
int tcc_find_symbol_me(me_info* me, const char *sym_name) |
{ |
int i; |
213,10 → 199,7 |
} |
} |
if (symtab==0 || strtab==0) |
{ |
tcc_error_noabort("undefined sections .symtab or .strtab on linking '%s'", sym_name); |
return 0; |
} |
Elf32_Sym* s,*se; |
char* name; |
s=(Elf32_Sym*)me->s1->sections[symtab]->data; |
230,10 → 213,8 |
} |
s++; |
} |
tcc_error_noabort("undefined symbol '%s'", sym_name); |
return 0; |
} |
const char* me_magic="MENUET01"; |
int tcc_output_me(TCCState* s1,const char *filename) |
{ |
265,26 → 246,3 |
fclose(f); |
return 0; |
} |
#ifndef _WIN32 |
static inline int get_current_folder(char* buf, int bufsize){ |
register int val; |
asm volatile ("int $0x40":"=a"(val):"a"(30), "b"(2), "c"(buf), "d"(bufsize)); |
return val; |
} |
char *getcwd(char *buf, size_t size) |
{ |
int rc = get_current_folder(buf, size); |
if (rc > size) |
{ |
errno = ERANGE; |
return 0; |
} |
else |
return buf; |
} |
#endif |
/programs/develop/ktcc/trunk/source/tccpe.c |
---|
1,7 → 1,7 |
/* |
* TCCPE.C - PE file output for the Tiny C Compiler |
* |
* Copyright (c) 2005-2007 grischka |
* Copyright (c) 2005 grischka |
* |
* This library is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
18,70 → 18,16 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
*/ |
#include "tcc.h" |
typedef unsigned char BYTE; |
typedef unsigned short WORD; |
typedef unsigned long DWORD; |
#define ST static |
#ifndef _WIN32 |
#define stricmp strcasecmp |
#define strnicmp strncasecmp |
#endif |
/* XXX: move that to TCC ? */ |
int verbose = 0; |
#ifndef MAX_PATH |
#define MAX_PATH 260 |
#endif |
#define PE_MERGE_DATA |
/* #define PE_PRINT_SECTIONS */ |
#ifdef TCC_TARGET_X86_64 |
# define ADDR3264 ULONGLONG |
# define REL_TYPE_DIRECT R_X86_64_64 |
# define R_XXX_THUNKFIX R_X86_64_PC32 |
# define R_XXX_RELATIVE R_X86_64_RELATIVE |
# define IMAGE_FILE_MACHINE 0x8664 |
# define RSRC_RELTYPE 3 |
#elif defined TCC_TARGET_ARM |
# define ADDR3264 DWORD |
# define REL_TYPE_DIRECT R_ARM_ABS32 |
# define R_XXX_THUNKFIX R_ARM_ABS32 |
# define R_XXX_RELATIVE R_ARM_RELATIVE |
# define IMAGE_FILE_MACHINE 0x01C0 |
# define RSRC_RELTYPE 7 /* ??? (not tested) */ |
#elif defined TCC_TARGET_I386 |
# define ADDR3264 DWORD |
# define REL_TYPE_DIRECT R_386_32 |
# define R_XXX_THUNKFIX R_386_32 |
# define R_XXX_RELATIVE R_386_RELATIVE |
# define IMAGE_FILE_MACHINE 0x014C |
# define RSRC_RELTYPE 7 /* DIR32NB */ |
#endif |
#ifdef _WIN32 |
void dbg_printf (const char *fmt, ...) |
{ |
char buffer[4000]; |
va_list arg; |
int x; |
va_start(arg, fmt); |
x = vsprintf (buffer, fmt, arg); |
strcpy(buffer+x, "\n"); |
OutputDebugString(buffer); |
} |
#endif |
/* ----------------------------------------------------------- */ |
#ifndef IMAGE_NT_SIGNATURE |
/* ----------------------------------------------------------- */ |
/* definitions below are from winnt.h */ |
typedef unsigned char BYTE; |
typedef unsigned short WORD; |
typedef unsigned int DWORD; |
typedef unsigned long long ULONGLONG; |
#pragma pack(push, 1) |
typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */ |
WORD e_magic; /* Magic number */ |
WORD e_cblp; /* Bytes on last page of file */ |
102,6 → 48,8 |
WORD e_oeminfo; /* OEM information; e_oemid specific */ |
WORD e_res2[10]; /* Reserved words */ |
DWORD e_lfanew; /* File address of new exe header */ |
BYTE e_code[0x40]; |
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; |
#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ |
136,11 → 84,10 |
DWORD SizeOfUninitializedData; |
DWORD AddressOfEntryPoint; |
DWORD BaseOfCode; |
#ifndef TCC_TARGET_X86_64 |
DWORD BaseOfData; |
#endif |
/* NT additional fields. */ |
ADDR3264 ImageBase; |
DWORD ImageBase; |
DWORD SectionAlignment; |
DWORD FileAlignment; |
WORD MajorOperatingSystemVersion; |
155,15 → 102,17 |
DWORD CheckSum; |
WORD Subsystem; |
WORD DllCharacteristics; |
ADDR3264 SizeOfStackReserve; |
ADDR3264 SizeOfStackCommit; |
ADDR3264 SizeOfHeapReserve; |
ADDR3264 SizeOfHeapCommit; |
DWORD SizeOfStackReserve; |
DWORD SizeOfStackCommit; |
DWORD SizeOfHeapReserve; |
DWORD SizeOfHeapCommit; |
DWORD LoaderFlags; |
DWORD NumberOfRvaAndSizes; |
IMAGE_DATA_DIRECTORY DataDirectory[16]; |
} IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_OPTIONAL_HEADER; |
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; |
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ |
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */ |
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /* Resource Directory */ |
202,31 → 151,7 |
#define IMAGE_SIZEOF_SECTION_HEADER 40 |
typedef struct _IMAGE_EXPORT_DIRECTORY { |
DWORD Characteristics; |
DWORD TimeDateStamp; |
WORD MajorVersion; |
WORD MinorVersion; |
DWORD Name; |
DWORD Base; |
DWORD NumberOfFunctions; |
DWORD NumberOfNames; |
DWORD AddressOfFunctions; |
DWORD AddressOfNames; |
DWORD AddressOfNameOrdinals; |
} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; |
typedef struct _IMAGE_IMPORT_DESCRIPTOR { |
union { |
DWORD Characteristics; |
DWORD OriginalFirstThunk; |
}; |
DWORD TimeDateStamp; |
DWORD ForwarderChain; |
DWORD Name; |
DWORD FirstThunk; |
} IMAGE_IMPORT_DESCRIPTOR; |
/* ----------------------------------------------------------- */ |
typedef struct _IMAGE_BASE_RELOCATION { |
DWORD VirtualAddress; |
DWORD SizeOfBlock; |
244,102 → 169,172 |
#define IMAGE_REL_BASED_SECTION 6 |
#define IMAGE_REL_BASED_REL32 7 |
#pragma pack(pop) |
/* ----------------------------------------------------------- */ |
/* ----------------------------------------------------------- */ |
#endif /* ndef IMAGE_NT_SIGNATURE */ |
/* ----------------------------------------------------------- */ |
#pragma pack(push, 1) |
IMAGE_DOS_HEADER pe_dos_hdr = { |
0x5A4D, /*WORD e_magic; Magic number */ |
0x0090, /*WORD e_cblp; Bytes on last page of file */ |
0x0003, /*WORD e_cp; Pages in file */ |
0x0000, /*WORD e_crlc; Relocations */ |
struct pe_header |
{ |
IMAGE_DOS_HEADER doshdr; |
BYTE dosstub[0x40]; |
DWORD nt_sig; |
IMAGE_FILE_HEADER filehdr; |
#ifdef TCC_TARGET_X86_64 |
IMAGE_OPTIONAL_HEADER64 opthdr; |
#else |
#ifdef _WIN64 |
IMAGE_OPTIONAL_HEADER32 opthdr; |
#else |
IMAGE_OPTIONAL_HEADER opthdr; |
#endif |
#endif |
0x0004, /*WORD e_cparhdr; Size of header in paragraphs */ |
0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */ |
0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */ |
0x0000, /*WORD e_ss; Initial (relative) SS value */ |
0x00B8, /*WORD e_sp; Initial SP value */ |
0x0000, /*WORD e_csum; Checksum */ |
0x0000, /*WORD e_ip; Initial IP value */ |
0x0000, /*WORD e_cs; Initial (relative) CS value */ |
0x0040, /*WORD e_lfarlc; File address of relocation table */ |
0x0000, /*WORD e_ovno; Overlay number */ |
{0, 0, 0, 0}, /*WORD e_res[4]; Reserved words */ |
0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */ |
0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */ |
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /*WORD e_res2[10]; Reserved words */ |
0x00000080, /*DWORD e_lfanew; File address of new exe header */ |
{ /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */ |
/*0040 */ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, |
0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, |
/*0050 */ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, |
0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, |
/*0060 */ 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, |
0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, |
/*0070 */ 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
/*0080 */ |
} |
}; |
struct pe_reloc_header { |
DWORD offset; |
DWORD size; |
DWORD pe_magic = IMAGE_NT_SIGNATURE; |
IMAGE_FILE_HEADER pe_file_hdr = { |
0x014C, /*WORD Machine; */ |
0x0003, /*WORD NumberOfSections; */ |
0x00000000, /*DWORD TimeDateStamp; */ |
0x00000000, /*DWORD PointerToSymbolTable; */ |
0x00000000, /*DWORD NumberOfSymbols; */ |
0x00E0, /*WORD SizeOfOptionalHeader; */ |
0x030F /*WORD Characteristics; */ |
}; |
struct pe_rsrc_header { |
struct _IMAGE_FILE_HEADER filehdr; |
struct _IMAGE_SECTION_HEADER sectionhdr; |
IMAGE_OPTIONAL_HEADER32 pe_opt_hdr = { |
/* Standard fields. */ |
0x010B, /*WORD Magic; */ |
0x06, /*BYTE MajorLinkerVersion; */ |
0x00, /*BYTE MinorLinkerVersion; */ |
0x00000000, /*DWORD SizeOfCode; */ |
0x00000000, /*DWORD SizeOfInitializedData; */ |
0x00000000, /*DWORD SizeOfUninitializedData; */ |
0x00000000, /*DWORD AddressOfEntryPoint; */ |
0x00000000, /*DWORD BaseOfCode; */ |
0x00000000, /*DWORD BaseOfData; */ |
/* NT additional fields. */ |
0x00400000, /*DWORD ImageBase; */ |
0x00001000, /*DWORD SectionAlignment; */ |
0x00000200, /*DWORD FileAlignment; */ |
0x0004, /*WORD MajorOperatingSystemVersion; */ |
0x0000, /*WORD MinorOperatingSystemVersion; */ |
0x0000, /*WORD MajorImageVersion; */ |
0x0000, /*WORD MinorImageVersion; */ |
0x0004, /*WORD MajorSubsystemVersion; */ |
0x0000, /*WORD MinorSubsystemVersion; */ |
0x00000000, /*DWORD Win32VersionValue; */ |
0x00000000, /*DWORD SizeOfImage; */ |
0x00000200, /*DWORD SizeOfHeaders; */ |
0x00000000, /*DWORD CheckSum; */ |
0x0002, /*WORD Subsystem; */ |
0x0000, /*WORD DllCharacteristics; */ |
0x00100000, /*DWORD SizeOfStackReserve; */ |
0x00001000, /*DWORD SizeOfStackCommit; */ |
0x00100000, /*DWORD SizeOfHeapReserve; */ |
0x00001000, /*DWORD SizeOfHeapCommit; */ |
0x00000000, /*DWORD LoaderFlags; */ |
0x00000010, /*DWORD NumberOfRvaAndSizes; */ |
/* IMAGE_DATA_DIRECTORY DataDirectory[16]; */ |
{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, |
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}} |
}; |
struct pe_rsrc_reloc { |
/*----------------------------------------------------------------------------*/ |
/*----------------------------------------------------------------------------*/ |
struct pe_import_header { |
DWORD first_entry; |
DWORD time_date; |
DWORD forwarder; |
DWORD lib_name_offset; |
DWORD first_thunk; |
}; |
struct pe_export_header { |
DWORD Characteristics; |
DWORD TimeDateStamp; |
DWORD Version; |
DWORD Name; |
DWORD Base; |
DWORD NumberOfFunctions; |
DWORD NumberOfNames; |
DWORD AddressOfFunctions; |
DWORD AddressOfNames; |
DWORD AddressOfNameOrdinals; |
}; |
struct pe_reloc_header { |
DWORD offset; |
DWORD size; |
WORD type; |
}; |
#pragma pack(pop) |
/* ------------------------------------------------------------- */ |
/* internal temporary structures */ |
/* |
#define IMAGE_SCN_CNT_CODE 0x00000020 |
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 |
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 |
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 |
#define IMAGE_SCN_MEM_SHARED 0x10000000 |
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 |
#define IMAGE_SCN_MEM_READ 0x40000000 |
#define IMAGE_SCN_MEM_WRITE 0x80000000 |
*/ |
ST const char *pe_sec_names[] = { |
".text", |
".data", |
".bss", |
".rsrc", |
".reloc", |
".stab", |
".stabstr" |
}; |
enum { |
sec_text = 0, |
sec_data , |
sec_bss , |
sec_idata , |
sec_pdata , |
sec_other , |
sec_rsrc , |
sec_reloc, |
sec_stab , |
sec_reloc , |
sec_last |
sec_stabstr, |
pe_sec_number |
}; |
static const DWORD pe_sec_flags[] = { |
ST DWORD pe_flags[] = { |
0x60000020, /* ".text" , */ |
0xC0000040, /* ".data" , */ |
0xC0000080, /* ".bss" , */ |
0x40000040, /* ".idata" , */ |
0x40000040, /* ".pdata" , */ |
0xE0000060, /* < other > , */ |
0x40000040, /* ".rsrc" , */ |
0x42000040, /* ".reloc", */ |
0x42000802, /* ".stab" , */ |
0x42000040, /* ".reloc" , */ |
0x42000802 /* ".stabstr", */ |
}; |
struct section_info { |
int cls, ord; |
char name[32]; |
struct section_info *next; |
int id; |
DWORD sh_addr; |
DWORD sh_size; |
DWORD sh_flags; |
unsigned char *data; |
DWORD data_size; |
IMAGE_SECTION_HEADER ish; |
}; |
struct import_symbol { |
int sym_index; |
int iat_index; |
int thk_offset; |
int offset; |
}; |
struct pe_import_info { |
349,13 → 344,9 |
}; |
struct pe_info { |
TCCState *s1; |
Section *reloc; |
Section *thunk; |
const char *filename; |
int type; |
DWORD sizeofheaders; |
ADDR3264 imagebase; |
DWORD imagebase; |
DWORD start_addr; |
DWORD imp_offs; |
DWORD imp_size; |
363,67 → 354,104 |
DWORD iat_size; |
DWORD exp_offs; |
DWORD exp_size; |
int subsystem; |
DWORD section_align; |
DWORD file_align; |
struct section_info *sec_info; |
struct section_info sh_info[pe_sec_number]; |
int sec_count; |
struct pe_import_info **imp_info; |
int imp_count; |
Section *reloc; |
Section *thunk; |
TCCState *s1; |
}; |
/* ------------------------------------------------------------- */ |
#define PE_MERGE_DATA |
// #define PE_PRINT_SECTIONS |
#ifndef MAX_PATH |
#define MAX_PATH 260 |
#endif |
void error_noabort(const char *, ...); |
ST char pe_type; |
#define PE_NUL 0 |
#define PE_DLL 1 |
#define PE_GUI 2 |
#define PE_EXE 3 |
#define PE_RUN 4 |
/* --------------------------------------------*/ |
static const char *pe_export_name(TCCState *s1, ElfW(Sym) *sym) |
ST int pe_find_import(TCCState * s1, const char *symbol, char *ret) |
{ |
const char *name = symtab_section->link->data + sym->st_name; |
if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & ST_PE_STDCALL)) |
return name + 1; |
return name; |
int sym_index = find_elf_sym(s1->dynsymtab_section, symbol); |
if (0 == sym_index) { |
/* Hm, maybe it's '_symbol' instead of 'symbol' or '__imp__symbol' */ |
char buffer[100]; |
if (0 == memcmp(symbol, "__imp__", 7)) |
symbol += 6; |
else |
buffer[0] = '_', strcpy(buffer + 1, symbol), symbol = buffer; |
sym_index = find_elf_sym(s1->dynsymtab_section, symbol); |
} |
if (ret) |
strcpy(ret, symbol); |
return sym_index; |
} |
static int pe_find_import(TCCState * s1, ElfW(Sym) *sym) |
#ifdef WIN32 |
ST void **pe_imp; |
ST int nb_pe_imp; |
void *resolve_sym(struct TCCState *s1, const char *symbol, int type) |
{ |
char buffer[200]; |
const char *s, *p; |
int sym_index = 0, n = 0; |
char buffer[100], *p = buffer; |
void *a = NULL; |
int sym_index = pe_find_import(s1, symbol, p); |
int dll_index; |
const char *dll_name; |
void *hm; |
do { |
s = pe_export_name(s1, sym); |
if (n) { |
/* second try: */ |
if (sym->st_other & ST_PE_STDCALL) { |
/* try w/0 stdcall deco (windows API convention) */ |
p = strrchr(s, '@'); |
if (!p || s[0] != '_') |
break; |
strcpy(buffer, s+1)[p-s-1] = 0; |
} else if (s[0] != '_') { /* try non-ansi function */ |
buffer[0] = '_', strcpy(buffer + 1, s); |
} else if (0 == memcmp(s, "__imp__", 7)) { /* mingw 2.0 */ |
strcpy(buffer, s + 6); |
} else if (0 == memcmp(s, "_imp___", 7)) { /* mingw 3.7 */ |
strcpy(buffer, s + 6); |
} else { |
break; |
if (sym_index) { |
dll_index = ((Elf32_Sym *) s1->dynsymtab_section->data)[sym_index]. |
st_other; |
dll_name = s1->loaded_dlls[dll_index]->name; |
hm = GetModuleHandleA(dll_name); |
if (NULL == hm) |
hm = LoadLibraryA(dll_name); |
if (hm) { |
a = GetProcAddress(hm, buffer); |
if (a && STT_OBJECT == type) { |
// need to return a pointer to the address for data objects |
dynarray_add(&pe_imp, &nb_pe_imp, a); |
a = &pe_imp[nb_pe_imp - 1]; |
} |
s = buffer; |
} |
sym_index = find_elf_sym(s1->dynsymtab_section, s); |
// printf("find (%d) %d %s\n", n, sym_index, s); |
} while (0 == sym_index && ++n < 2); |
return sym_index; |
} |
return a; |
} |
#endif |
#define for_sym_in_symtab(sym) \ |
for (sym = (Elf32_Sym *)symtab_section->data + 1; \ |
sym < (Elf32_Sym *)(symtab_section->data + \ |
symtab_section->data_offset); \ |
++sym) |
#define pe_set_datadir(dir,addr,size) \ |
pe_opt_hdr.DataDirectory[dir].VirtualAddress = addr, \ |
pe_opt_hdr.DataDirectory[dir].Size = size |
/*----------------------------------------------------------------------------*/ |
ST void dynarray_reset(void ***pp, int *n) |
{ |
int i; |
for (i = 0; i < *n; ++i) |
tcc_free((*pp)[i]); |
tcc_free(*pp); |
*pp = NULL; |
*n = 0; |
} |
static int dynarray_assoc(void **pp, int n, int key) |
ST int dynarray_assoc(void **pp, int n, int key) |
{ |
int i; |
for (i = 0; i < n; ++i, ++pp) |
433,216 → 461,103 |
} |
#if 0 |
ST_FN DWORD umin(DWORD a, DWORD b) |
ST DWORD umin(DWORD a, DWORD b) |
{ |
return a < b ? a : b; |
} |
#endif |
static DWORD umax(DWORD a, DWORD b) |
ST DWORD umax(DWORD a, DWORD b) |
{ |
return a < b ? b : a; |
} |
static DWORD pe_file_align(struct pe_info *pe, DWORD n) |
ST void pe_fpad(FILE * fp, DWORD new_pos) |
{ |
return (n + (pe->file_align - 1)) & ~(pe->file_align - 1); |
DWORD pos = ftell(fp); |
while (++pos <= new_pos) |
fputc(0, fp); |
} |
static DWORD pe_virtual_align(struct pe_info *pe, DWORD n) |
ST DWORD pe_file_align(DWORD n) |
{ |
return (n + (pe->section_align - 1)) & ~(pe->section_align - 1); |
return (n + (0x200 - 1)) & ~(0x200 - 1); |
} |
static void pe_align_section(Section *s, int a) |
ST DWORD pe_virtual_align(DWORD n) |
{ |
return (n + (0x1000 - 1)) & ~(0x1000 - 1); |
} |
ST void pe_align_section(Section * s, int a) |
{ |
int i = s->data_offset & (a-1); |
if (i) |
section_ptr_add(s, a - i); |
} |
static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD size) |
{ |
hdr->opthdr.DataDirectory[dir].VirtualAddress = addr; |
hdr->opthdr.DataDirectory[dir].Size = size; |
} |
static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum) |
{ |
if (psum) { |
DWORD sum = *psum; |
WORD *p = data; |
int i; |
for (i = len; i > 0; i -= 2) { |
sum += (i >= 2) ? *p++ : *(BYTE*)p; |
sum = (sum + (sum >> 16)) & 0xFFFF; |
} |
*psum = sum; |
} |
return len == fwrite(data, 1, len, fp) ? 0 : -1; |
} |
static void pe_fpad(FILE *fp, DWORD new_pos) |
{ |
DWORD pos = ftell(fp); |
while (++pos <= new_pos) |
fputc(0, fp); |
} |
/*----------------------------------------------------------------------------*/ |
static int pe_write(struct pe_info *pe) |
ST int pe_write_pe(struct pe_info *pe) |
{ |
static const struct pe_header pe_template = { |
{ |
/* IMAGE_DOS_HEADER doshdr */ |
0x5A4D, /*WORD e_magic; Magic number */ |
0x0090, /*WORD e_cblp; Bytes on last page of file */ |
0x0003, /*WORD e_cp; Pages in file */ |
0x0000, /*WORD e_crlc; Relocations */ |
0x0004, /*WORD e_cparhdr; Size of header in paragraphs */ |
0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */ |
0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */ |
0x0000, /*WORD e_ss; Initial (relative) SS value */ |
0x00B8, /*WORD e_sp; Initial SP value */ |
0x0000, /*WORD e_csum; Checksum */ |
0x0000, /*WORD e_ip; Initial IP value */ |
0x0000, /*WORD e_cs; Initial (relative) CS value */ |
0x0040, /*WORD e_lfarlc; File address of relocation table */ |
0x0000, /*WORD e_ovno; Overlay number */ |
{0,0,0,0}, /*WORD e_res[4]; Reserved words */ |
0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */ |
0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */ |
{0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10]; Reserved words */ |
0x00000080 /*DWORD e_lfanew; File address of new exe header */ |
},{ |
/* BYTE dosstub[0x40] */ |
/* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */ |
0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68, |
0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f, |
0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20, |
0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
}, |
0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */ |
{ |
/* IMAGE_FILE_HEADER filehdr */ |
IMAGE_FILE_MACHINE, /*WORD Machine; */ |
0x0003, /*WORD NumberOfSections; */ |
0x00000000, /*DWORD TimeDateStamp; */ |
0x00000000, /*DWORD PointerToSymbolTable; */ |
0x00000000, /*DWORD NumberOfSymbols; */ |
#if defined(TCC_TARGET_X86_64) |
0x00F0, /*WORD SizeOfOptionalHeader; */ |
0x022F /*WORD Characteristics; */ |
#define CHARACTERISTICS_DLL 0x222E |
#elif defined(TCC_TARGET_I386) |
0x00E0, /*WORD SizeOfOptionalHeader; */ |
0x030F /*WORD Characteristics; */ |
#define CHARACTERISTICS_DLL 0x230E |
#elif defined(TCC_TARGET_ARM) |
0x00E0, /*WORD SizeOfOptionalHeader; */ |
0x010F, /*WORD Characteristics; */ |
#define CHARACTERISTICS_DLL 0x230F |
#endif |
},{ |
/* IMAGE_OPTIONAL_HEADER opthdr */ |
/* Standard fields. */ |
#ifdef TCC_TARGET_X86_64 |
0x020B, /*WORD Magic; */ |
#else |
0x010B, /*WORD Magic; */ |
#endif |
0x06, /*BYTE MajorLinkerVersion; */ |
0x00, /*BYTE MinorLinkerVersion; */ |
0x00000000, /*DWORD SizeOfCode; */ |
0x00000000, /*DWORD SizeOfInitializedData; */ |
0x00000000, /*DWORD SizeOfUninitializedData; */ |
0x00000000, /*DWORD AddressOfEntryPoint; */ |
0x00000000, /*DWORD BaseOfCode; */ |
#ifndef TCC_TARGET_X86_64 |
0x00000000, /*DWORD BaseOfData; */ |
#endif |
/* NT additional fields. */ |
#if defined(TCC_TARGET_ARM) |
0x00100000, /*DWORD ImageBase; */ |
#else |
0x00400000, /*DWORD ImageBase; */ |
#endif |
0x00001000, /*DWORD SectionAlignment; */ |
0x00000200, /*DWORD FileAlignment; */ |
0x0004, /*WORD MajorOperatingSystemVersion; */ |
0x0000, /*WORD MinorOperatingSystemVersion; */ |
0x0000, /*WORD MajorImageVersion; */ |
0x0000, /*WORD MinorImageVersion; */ |
0x0004, /*WORD MajorSubsystemVersion; */ |
0x0000, /*WORD MinorSubsystemVersion; */ |
0x00000000, /*DWORD Win32VersionValue; */ |
0x00000000, /*DWORD SizeOfImage; */ |
0x00000200, /*DWORD SizeOfHeaders; */ |
0x00000000, /*DWORD CheckSum; */ |
0x0002, /*WORD Subsystem; */ |
0x0000, /*WORD DllCharacteristics; */ |
0x00100000, /*DWORD SizeOfStackReserve; */ |
0x00001000, /*DWORD SizeOfStackCommit; */ |
0x00100000, /*DWORD SizeOfHeapReserve; */ |
0x00001000, /*DWORD SizeOfHeapCommit; */ |
0x00000000, /*DWORD LoaderFlags; */ |
0x00000010, /*DWORD NumberOfRvaAndSizes; */ |
/* IMAGE_DATA_DIRECTORY DataDirectory[16]; */ |
{{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, |
{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} |
}}; |
struct pe_header pe_header = pe_template; |
int i; |
FILE *op; |
DWORD file_offset, sum; |
struct section_info *si; |
IMAGE_SECTION_HEADER *psh; |
DWORD file_offset; |
IMAGE_SECTION_HEADER ish[pe_sec_number], *psh; |
int sec_index = 0; |
op = fopen(pe->filename, "wb"); |
if (NULL == op) { |
tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); |
return -1; |
error_noabort("could not create file: %s", pe->filename); |
return 1; |
} |
pe->sizeofheaders = pe_file_align(pe, |
sizeof (struct pe_header) |
+ pe->sec_count * sizeof (IMAGE_SECTION_HEADER) |
memset(&ish, 0, sizeof ish); |
pe->sizeofheaders = pe_file_align(sizeof pe_dos_hdr |
+ sizeof pe_magic |
+ sizeof pe_file_hdr |
+ sizeof pe_opt_hdr |
+ |
pe->sec_count * |
sizeof(IMAGE_SECTION_HEADER) |
); |
file_offset = pe->sizeofheaders; |
pe_fpad(op, file_offset); |
if (2 == pe->s1->verbose) |
if (2 == verbose) |
printf("-------------------------------" |
"\n virt file size section" "\n"); |
for (i = 0; i < pe->sec_count; ++i) { |
DWORD addr, size; |
const char *sh_name; |
struct section_info *si = pe->sh_info + i; |
const char *sh_name = pe_sec_names[si->id]; |
unsigned long addr = si->sh_addr - pe->imagebase; |
unsigned long size = si->sh_size; |
si = pe->sec_info + i; |
sh_name = si->name; |
addr = si->sh_addr - pe->imagebase; |
size = si->sh_size; |
psh = &si->ish; |
if (2 == verbose) |
printf("%6lx %6lx %6lx %s\n", |
addr, file_offset, size, sh_name); |
if (2 == pe->s1->verbose) |
printf("%6x %6x %6x %s\n", |
(unsigned)addr, (unsigned)file_offset, (unsigned)size, sh_name); |
switch (si->cls) { |
switch (si->id) { |
case sec_text: |
pe_header.opthdr.BaseOfCode = addr; |
pe_header.opthdr.AddressOfEntryPoint = addr + pe->start_addr; |
pe_opt_hdr.BaseOfCode = addr; |
pe_opt_hdr.AddressOfEntryPoint = addr + pe->start_addr; |
break; |
case sec_data: |
#ifndef TCC_TARGET_X86_64 |
pe_header.opthdr.BaseOfData = addr; |
#endif |
pe_opt_hdr.BaseOfData = addr; |
if (pe->imp_size) { |
pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT, |
pe->imp_offs + addr, pe->imp_size); |
pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT, |
pe->iat_offs + addr, pe->iat_size); |
} |
if (pe->exp_size) { |
pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT, |
pe->exp_offs + addr, pe->exp_size); |
} |
break; |
case sec_bss: |
649,100 → 564,77 |
break; |
case sec_reloc: |
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); |
pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); |
break; |
case sec_rsrc: |
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); |
pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); |
break; |
case sec_pdata: |
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size); |
case sec_stab: |
break; |
case sec_stab: |
case sec_stabstr: |
break; |
} |
if (pe->thunk == pe->s1->sections[si->ord]) { |
if (pe->imp_size) { |
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT, |
pe->imp_offs + addr, pe->imp_size); |
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT, |
pe->iat_offs + addr, pe->iat_size); |
} |
if (pe->exp_size) { |
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT, |
pe->exp_offs + addr, pe->exp_size); |
} |
} |
psh = &ish[sec_index++]; |
strcpy((char *) psh->Name, sh_name); |
strncpy((char*)psh->Name, sh_name, sizeof psh->Name); |
psh->Characteristics = pe_sec_flags[si->cls]; |
psh->Characteristics = pe_flags[si->id]; |
psh->VirtualAddress = addr; |
psh->Misc.VirtualSize = size; |
pe_header.opthdr.SizeOfImage = |
umax(pe_virtual_align(pe, size + addr), pe_header.opthdr.SizeOfImage); |
pe_opt_hdr.SizeOfImage = |
umax(psh->VirtualAddress + psh->Misc.VirtualSize, |
pe_opt_hdr.SizeOfImage); |
if (si->data_size) { |
psh->PointerToRawData = file_offset; |
file_offset = pe_file_align(pe, file_offset + si->data_size); |
fwrite(si->data, 1, si->data_size, op); |
file_offset = pe_file_align(file_offset + si->data_size); |
psh->SizeOfRawData = file_offset - psh->PointerToRawData; |
pe_fpad(op, file_offset); |
} |
} |
//pe_header.filehdr.TimeDateStamp = time(NULL); |
pe_header.filehdr.NumberOfSections = pe->sec_count; |
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders; |
pe_header.opthdr.ImageBase = pe->imagebase; |
pe_header.opthdr.Subsystem = pe->subsystem; |
if (pe->s1->pe_stack_size) |
pe_header.opthdr.SizeOfStackReserve = pe->s1->pe_stack_size; |
if (PE_DLL == pe->type) |
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL; |
/*----------------------------------------------------- */ |
sum = 0; |
pe_fwrite(&pe_header, sizeof pe_header, op, &sum); |
for (i = 0; i < pe->sec_count; ++i) |
pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum); |
pe_fpad(op, pe->sizeofheaders); |
for (i = 0; i < pe->sec_count; ++i) { |
si = pe->sec_info + i; |
psh = &si->ish; |
if (si->data_size) { |
pe_fwrite(si->data, si->data_size, op, &sum); |
file_offset = psh->PointerToRawData + psh->SizeOfRawData; |
pe_fpad(op, file_offset); |
} |
} |
pe_file_hdr.NumberOfSections = sec_index; |
pe_opt_hdr.SizeOfHeaders = pe->sizeofheaders; |
pe_opt_hdr.ImageBase = pe->imagebase; |
if (PE_DLL == pe_type) |
pe_file_hdr.Characteristics = 0x230E; |
else if (PE_GUI != pe_type) |
pe_opt_hdr.Subsystem = 3; |
pe_header.opthdr.CheckSum = sum + file_offset; |
fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET); |
pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL); |
fseek(op, SEEK_SET, 0); |
fwrite(&pe_dos_hdr, 1, sizeof pe_dos_hdr, op); |
fwrite(&pe_magic, 1, sizeof pe_magic, op); |
fwrite(&pe_file_hdr, 1, sizeof pe_file_hdr, op); |
fwrite(&pe_opt_hdr, 1, sizeof pe_opt_hdr, op); |
for (i = 0; i < sec_index; ++i) |
fwrite(&ish[i], 1, sizeof(IMAGE_SECTION_HEADER), op); |
fclose (op); |
if (2 == pe->s1->verbose) |
if (2 == verbose) |
printf("-------------------------------\n"); |
if (pe->s1->verbose) |
printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset); |
if (verbose) |
printf("<-- %s (%lu bytes)\n", pe->filename, file_offset); |
return 0; |
} |
/*----------------------------------------------------------------------------*/ |
static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index) |
ST int pe_add_import(struct pe_info *pe, int sym_index, DWORD offset) |
{ |
int i; |
int dll_index; |
struct pe_import_info *p; |
struct import_symbol *s; |
ElfW(Sym) *isym; |
isym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; |
dll_index = isym->st_size; |
dll_index = |
((Elf32_Sym *) pe->s1->dynsymtab_section->data)[sym_index]. |
st_other; |
i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index); |
if (-1 != i) { |
p = pe->imp_info[i]; |
755,19 → 647,21 |
found_dll: |
i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index); |
if (-1 != i) |
return p->symbols[i]; |
goto found_sym; |
s = tcc_mallocz(sizeof *s); |
s->sym_index = sym_index; |
s->offset = offset; |
dynarray_add((void***)&p->symbols, &p->sym_count, s); |
s->sym_index = sym_index; |
return s; |
found_sym: |
return 1; |
} |
/*----------------------------------------------------------------------------*/ |
static void pe_build_imports(struct pe_info *pe) |
ST void pe_build_imports(struct pe_info *pe) |
{ |
int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i; |
DWORD rva_base = pe->thunk->sh_addr - pe->imagebase; |
DWORD voffset = pe->thunk->sh_addr - pe->imagebase; |
int ndlls = pe->imp_count; |
for (sym_cnt = i = 0; i < ndlls; ++i) |
779,217 → 673,161 |
pe_align_section(pe->thunk, 16); |
pe->imp_offs = dll_ptr = pe->thunk->data_offset; |
pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR); |
pe->imp_size = (ndlls + 1) * sizeof(struct pe_import_header); |
pe->iat_offs = dll_ptr + pe->imp_size; |
pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264); |
pe->iat_size = (sym_cnt + ndlls) * sizeof(DWORD); |
section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size); |
thk_ptr = pe->iat_offs; |
ent_ptr = pe->iat_offs + pe->iat_size; |
for (i = 0; i < pe->imp_count; ++i) { |
IMAGE_IMPORT_DESCRIPTOR *hdr; |
int k, n, dllindex; |
ADDR3264 v; |
struct pe_import_header *hdr; |
int k, n, v; |
struct pe_import_info *p = pe->imp_info[i]; |
const char *name; |
DLLReference *dllref; |
const char *name = pe->s1->loaded_dlls[p->dll_index]->name; |
dllindex = p->dll_index; |
if (dllindex) |
name = (dllref = pe->s1->loaded_dlls[dllindex-1])->name; |
else |
name = "", dllref = NULL; |
/* put the dll name into the import header */ |
if (0 == strncmp(name, "lib", 3)) |
name += 3; |
v = put_elf_str(pe->thunk, name); |
hdr = (IMAGE_IMPORT_DESCRIPTOR*)(pe->thunk->data + dll_ptr); |
hdr->FirstThunk = thk_ptr + rva_base; |
hdr->OriginalFirstThunk = ent_ptr + rva_base; |
hdr->Name = v + rva_base; |
hdr = (struct pe_import_header *) (pe->thunk->data + dll_ptr); |
hdr->first_thunk = thk_ptr + voffset; |
hdr->first_entry = ent_ptr + voffset; |
hdr->lib_name_offset = v + voffset; |
for (k = 0, n = p->sym_count; k <= n; ++k) { |
if (k < n) { |
int iat_index = p->symbols[k]->iat_index; |
DWORD offset = p->symbols[k]->offset; |
int sym_index = p->symbols[k]->sym_index; |
ElfW(Sym) *imp_sym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; |
ElfW(Sym) *org_sym = (ElfW(Sym) *)symtab_section->data + iat_index; |
const char *name = pe->s1->dynsymtab_section->link->data + imp_sym->st_name; |
int ordinal; |
Elf32_Sym *sym = |
(Elf32_Sym *) pe->s1->dynsymtab_section->data + |
sym_index; |
const char *name = |
pe->s1->dynsymtab_section->link->data + sym->st_name; |
org_sym->st_value = thk_ptr; |
org_sym->st_shndx = pe->thunk->sh_num; |
if (offset & 0x80000000) { /* ref to data */ |
Elf32_Sym *sym = |
&((Elf32_Sym *) symtab_section-> |
data)[offset & 0x7FFFFFFF]; |
sym->st_value = thk_ptr; |
sym->st_shndx = pe->thunk->sh_num; |
} else { /* ref to function */ |
if (dllref) |
v = 0, ordinal = imp_sym->st_value; /* ordinal from pe_load_def */ |
else |
ordinal = 0, v = imp_sym->st_value; /* address from tcc_add_symbol() */ |
char buffer[100]; |
sprintf(buffer, "IAT.%s", name); |
sym_index = |
put_elf_sym(symtab_section, thk_ptr, sizeof(DWORD), |
ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), |
0, pe->thunk->sh_num, buffer); |
#ifdef TCC_IS_NATIVE |
if (pe->type == PE_RUN) { |
if (dllref) { |
if ( !dllref->handle ) |
dllref->handle = LoadLibrary(dllref->name); |
v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(LPCSTR)NULL+ordinal:name); |
put_elf_reloc(symtab_section, text_section, offset, R_386_32, /*R_JMP_SLOT, */ |
sym_index); |
} |
if (!v) |
tcc_error_noabort("can't build symbol '%s'", name); |
} else |
#endif |
if (ordinal) { |
v = ordinal | (ADDR3264)1 << (sizeof(ADDR3264)*8 - 1); |
} else { |
v = pe->thunk->data_offset + rva_base; |
v = pe->thunk->data_offset + voffset; |
section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */ |
put_elf_str(pe->thunk, name); |
} |
} else { |
v = 0; /* last entry is zero */ |
v = 0; // last entry is zero |
} |
*(ADDR3264*)(pe->thunk->data+thk_ptr) = |
*(ADDR3264*)(pe->thunk->data+ent_ptr) = v; |
thk_ptr += sizeof (ADDR3264); |
ent_ptr += sizeof (ADDR3264); |
*(DWORD *) (pe->thunk->data + thk_ptr) = |
*(DWORD *) (pe->thunk->data + ent_ptr) = v; |
thk_ptr += sizeof(DWORD); |
ent_ptr += sizeof(DWORD); |
} |
dll_ptr += sizeof(IMAGE_IMPORT_DESCRIPTOR); |
dynarray_reset(&p->symbols, &p->sym_count); |
dll_ptr += sizeof(struct pe_import_header); |
dynarray_reset((void ***) &p->symbols, &p->sym_count); |
} |
dynarray_reset(&pe->imp_info, &pe->imp_count); |
dynarray_reset((void ***) &pe->imp_info, &pe->imp_count); |
} |
/* ------------------------------------------------------------- */ |
struct pe_sort_sym |
ST int sym_cmp(const void *va, const void *vb) |
{ |
int index; |
const char *name; |
}; |
static int sym_cmp(const void *va, const void *vb) |
{ |
const char *ca = (*(struct pe_sort_sym**)va)->name; |
const char *cb = (*(struct pe_sort_sym**)vb)->name; |
Elf32_Sym *sa = (Elf32_Sym *)symtab_section->data + *(int*)va; |
Elf32_Sym *sb = (Elf32_Sym *)symtab_section->data + *(int*)vb; |
const char *ca = symtab_section->link->data + sa->st_name; |
const char *cb = symtab_section->link->data + sb->st_name; |
return strcmp(ca, cb); |
} |
static void pe_build_exports(struct pe_info *pe) |
ST void pe_build_exports(struct pe_info *pe) |
{ |
ElfW(Sym) *sym; |
int sym_index, sym_end; |
DWORD rva_base, func_o, name_o, ord_o, str_o; |
IMAGE_EXPORT_DIRECTORY *hdr; |
int sym_count, ord; |
struct pe_sort_sym **sorted, *p; |
Elf32_Sym *sym; |
DWORD func_offset, voffset; |
struct pe_export_header *hdr; |
int sym_count, n, ord, *sorted; |
FILE *op; |
char buf[MAX_PATH]; |
const char *dllname; |
const char *name; |
voffset = pe->thunk->sh_addr - pe->imagebase; |
sym_count = 0, n = 1, sorted = NULL; |
rva_base = pe->thunk->sh_addr - pe->imagebase; |
sym_count = 0, sorted = NULL, op = NULL; |
sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); |
for (sym_index = 1; sym_index < sym_end; ++sym_index) { |
sym = (ElfW(Sym)*)symtab_section->data + sym_index; |
name = pe_export_name(pe->s1, sym); |
if ((sym->st_other & ST_PE_EXPORT) |
/* export only symbols from actually written sections */ |
&& pe->s1->sections[sym->st_shndx]->sh_addr) { |
p = tcc_malloc(sizeof *p); |
p->index = sym_index; |
p->name = name; |
dynarray_add((void***)&sorted, &sym_count, p); |
// for simplicity only functions are exported |
for_sym_in_symtab(sym) |
{ |
if ((sym->st_other & 1) |
&& sym->st_shndx == text_section->sh_num) |
dynarray_add((void***)&sorted, &sym_count, (void*)n); |
++n; |
} |
#if 0 |
if (sym->st_other & ST_PE_EXPORT) |
printf("export: %s\n", name); |
if (sym->st_other & ST_PE_STDCALL) |
printf("stdcall: %s\n", name); |
#endif |
} |
if (0 == sym_count) |
return; |
qsort (sorted, sym_count, sizeof *sorted, sym_cmp); |
qsort (sorted, sym_count, sizeof sorted[0], sym_cmp); |
pe_align_section(pe->thunk, 16); |
dllname = tcc_basename(pe->filename); |
pe->exp_offs = pe->thunk->data_offset; |
func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY); |
name_o = func_o + sym_count * sizeof (DWORD); |
ord_o = name_o + sym_count * sizeof (DWORD); |
str_o = ord_o + sym_count * sizeof(WORD); |
hdr = section_ptr_add(pe->thunk, |
sizeof(struct pe_export_header) + |
sym_count * (2 * sizeof(DWORD) + sizeof(WORD))); |
hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs); |
func_offset = pe->exp_offs + sizeof(struct pe_export_header); |
hdr->Characteristics = 0; |
hdr->Base = 1; |
hdr->NumberOfFunctions = sym_count; |
hdr->NumberOfNames = sym_count; |
hdr->AddressOfFunctions = func_o + rva_base; |
hdr->AddressOfNames = name_o + rva_base; |
hdr->AddressOfNameOrdinals = ord_o + rva_base; |
hdr->Name = str_o + rva_base; |
put_elf_str(pe->thunk, dllname); |
hdr->AddressOfFunctions = func_offset + voffset; |
hdr->AddressOfNames = hdr->AddressOfFunctions + sym_count * sizeof(DWORD); |
hdr->AddressOfNameOrdinals = hdr->AddressOfNames + sym_count * sizeof(DWORD); |
hdr->Name = pe->thunk->data_offset + voffset; |
put_elf_str(pe->thunk, tcc_basename(pe->filename)); |
#if 1 |
/* automatically write exports to <output-filename>.def */ |
pstrcpy(buf, sizeof buf, pe->filename); |
strcpy(tcc_fileextension(buf), ".def"); |
op = fopen(buf, "w"); |
if (NULL == op) { |
tcc_error_noabort("could not create '%s': %s", buf, strerror(errno)); |
} else { |
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname); |
if (pe->s1->verbose) |
printf("<- %s (%d symbols)\n", buf, sym_count); |
} |
#endif |
for (ord = 0; ord < sym_count; ++ord) |
{ |
p = sorted[ord], sym_index = p->index, name = p->name; |
/* insert actual address later in pe_relocate_rva */ |
put_elf_reloc(symtab_section, pe->thunk, |
func_o, R_XXX_RELATIVE, sym_index); |
*(DWORD*)(pe->thunk->data + name_o) |
= pe->thunk->data_offset + rva_base; |
*(WORD*)(pe->thunk->data + ord_o) |
= ord; |
char *name; DWORD *p, *pfunc, *pname; WORD *pord; |
sym = (Elf32_Sym *)symtab_section->data + sorted[ord]; |
name = symtab_section->link->data + sym->st_name; |
p = (DWORD*)(pe->thunk->data + func_offset); |
pfunc = p + ord; |
pname = p + sym_count + ord; |
pord = (WORD *)(p + 2*sym_count) + ord; |
*pfunc = sym->st_value + pe->s1->sections[sym->st_shndx]->sh_addr - pe->imagebase; |
*pname = pe->thunk->data_offset + voffset; |
*pord = ord; |
put_elf_str(pe->thunk, name); |
func_o += sizeof (DWORD); |
name_o += sizeof (DWORD); |
ord_o += sizeof (WORD); |
if (op) |
fprintf(op, "%s\n", name); |
/* printf("export: %s\n", name); */ |
} |
pe->exp_size = pe->thunk->data_offset - pe->exp_offs; |
dynarray_reset(&sorted, &sym_count); |
if (op) |
fclose(op); |
tcc_free(sorted); |
} |
/* ------------------------------------------------------------- */ |
static void pe_build_reloc (struct pe_info *pe) |
ST void pe_build_reloc(struct pe_info *pe, int *section_order, |
int section_count) |
{ |
DWORD offset, block_ptr, addr; |
int count, i; |
ElfW_Rel *rel, *rel_end; |
Elf32_Rel *rel, *rel_end; |
Section *s = NULL, *sr; |
offset = addr = block_ptr = count = i = 0; |
rel = rel_end = NULL; |
for(;;) { |
if (rel < rel_end) { |
int type = ELFW(R_TYPE)(rel->r_info); |
int type = ELF32_R_TYPE(rel->r_info); |
addr = rel->r_offset + s->sh_addr; |
++ rel; |
if (type != REL_TYPE_DIRECT) |
if (type != R_386_32) |
continue; |
if (count == 0) { /* new block */ |
block_ptr = pe->reloc->data_offset; |
1003,27 → 841,25 |
continue; |
} |
-- rel; |
} else if (i < pe->sec_count) { |
sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc; |
} else if (i < section_count) { |
sr = (s = pe->s1->sections[section_order[i++]])->reloc; |
if (sr) { |
rel = (ElfW_Rel *)sr->data; |
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
rel = (Elf32_Rel *) sr->data; |
rel_end = (Elf32_Rel *) (sr->data + sr->data_offset); |
} |
continue; |
} |
if (count) { |
/* store the last block and ready for a new one */ |
if (count) { /* store the last block and ready for a new one */ |
struct pe_reloc_header *hdr; |
if (count & 1) /* align for DWORDS */ |
section_ptr_add(pe->reloc, sizeof(WORD)), ++count; |
if (count & 1) |
section_ptr_add(pe->reloc, 2), ++count; |
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr); |
hdr -> offset = offset - pe->imagebase; |
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header); |
hdr->size = |
count * sizeof(WORD) + sizeof(struct pe_reloc_header); |
count = 0; |
} |
if (rel >= rel_end) |
break; |
} |
1030,104 → 866,48 |
} |
/* ------------------------------------------------------------- */ |
static int pe_section_class(Section *s) |
ST int pe_assign_addresses(struct pe_info *pe) |
{ |
int type, flags; |
const char *name; |
type = s->sh_type; |
flags = s->sh_flags; |
name = s->name; |
if (flags & SHF_ALLOC) { |
if (type == SHT_PROGBITS) { |
if (flags & SHF_EXECINSTR) |
return sec_text; |
if (flags & SHF_WRITE) |
return sec_data; |
if (0 == strcmp(name, ".rsrc")) |
return sec_rsrc; |
if (0 == strcmp(name, ".iedat")) |
return sec_idata; |
if (0 == strcmp(name, ".pdata")) |
return sec_pdata; |
return sec_other; |
} else if (type == SHT_NOBITS) { |
if (flags & SHF_WRITE) |
return sec_bss; |
} |
} else { |
if (0 == strcmp(name, ".reloc")) |
return sec_reloc; |
if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */ |
return sec_stab; |
} |
return -1; |
} |
static int pe_assign_addresses (struct pe_info *pe) |
{ |
int i, k, o, c; |
int i, k, n; |
DWORD addr; |
int *section_order; |
struct section_info *si; |
Section *s; |
int section_order[pe_sec_number]; |
struct section_info *si_data = NULL; |
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); |
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int)); |
for (o = k = 0 ; k < sec_last; ++k) { |
for (i = 1; i < pe->s1->nb_sections; ++i) { |
s = pe->s1->sections[i]; |
if (k == pe_section_class(s)) { |
// printf("%s %d\n", s->name, k); |
s->sh_addr = pe->imagebase; |
section_order[o++] = i; |
} |
} |
} |
pe->sec_info = tcc_mallocz(o * sizeof (struct section_info)); |
pe->imagebase = PE_DLL == pe_type ? 0x10000000 : 0x00400000; |
addr = pe->imagebase + 1; |
for (i = 0; i < o; ++i) |
{ |
k = section_order[i]; |
s = pe->s1->sections[k]; |
c = pe_section_class(s); |
si = &pe->sec_info[pe->sec_count]; |
if (PE_DLL == pe_type) |
pe->reloc = new_section(pe->s1, ".reloc", SHT_DYNAMIC, SHF_ALLOC); |
for (n = k = 0; n < pe_sec_number; ++n) { |
for (i = 1; i < pe->s1->nb_sections; ++i) { |
Section *s = pe->s1->sections[i]; |
if (0 == strcmp(s->name, pe_sec_names[n])) { |
struct section_info *si = &pe->sh_info[pe->sec_count]; |
#ifdef PE_MERGE_DATA |
if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) { |
if (n == sec_bss && si_data) { |
/* append .bss to .data */ |
s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1; |
s->sh_addr = addr = ((addr - 1) | 15) + 1; |
addr += s->data_offset; |
si[-1].sh_size = addr - si[-1].sh_addr; |
continue; |
} |
si_data->sh_size = addr - si_data->sh_addr; |
} else |
#endif |
if (c == sec_stab && 0 == pe->s1->do_debug) |
continue; |
{ |
si->sh_addr = s->sh_addr = addr = |
pe_virtual_align(addr); |
si->id = n; |
strcpy(si->name, s->name); |
si->cls = c; |
si->ord = k; |
si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr); |
si->sh_flags = s->sh_flags; |
if (c == sec_data && NULL == pe->thunk) |
if (n == sec_data) { |
pe->thunk = s; |
if (s == pe->thunk) { |
si_data = si; |
pe_build_imports(pe); |
pe_build_exports(pe); |
} else if (n == sec_reloc) { |
pe_build_reloc(pe, section_order, k); |
} |
if (c == sec_reloc) |
pe_build_reloc (pe); |
if (s->data_offset) |
{ |
if (s->sh_type != SHT_NOBITS) { |
if (s->data_offset) { |
if (n != sec_bss) { |
si->data = s->data; |
si->data_size = s->data_offset; |
} |
1136,168 → 916,55 |
si->sh_size = s->data_offset; |
++pe->sec_count; |
} |
// printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name); |
//printf("Section %08X %04X %s\n", si->sh_addr, si->data_size, s->name); |
} |
#if 0 |
for (i = 1; i < pe->s1->nb_sections; ++i) { |
Section *s = pe->s1->sections[i]; |
int type = s->sh_type; |
int flags = s->sh_flags; |
printf("section %-16s %-10s %5x %s,%s,%s\n", |
s->name, |
type == SHT_PROGBITS ? "progbits" : |
type == SHT_NOBITS ? "nobits" : |
type == SHT_SYMTAB ? "symtab" : |
type == SHT_STRTAB ? "strtab" : |
type == SHT_RELX ? "rel" : "???", |
s->data_offset, |
flags & SHF_ALLOC ? "alloc" : "", |
flags & SHF_WRITE ? "write" : "", |
flags & SHF_EXECINSTR ? "exec" : "" |
); |
section_order[k] = i, ++k; |
} |
pe->s1->verbose = 2; |
#endif |
tcc_free(section_order); |
return 0; |
} |
/* ------------------------------------------------------------- */ |
static void pe_relocate_rva (struct pe_info *pe, Section *s) |
{ |
Section *sr = s->reloc; |
ElfW_Rel *rel, *rel_end; |
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) { |
if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) { |
int sym_index = ELFW(R_SYM)(rel->r_info); |
DWORD addr = s->sh_addr; |
if (sym_index) { |
ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index; |
addr = sym->st_value; |
} |
// printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name); |
*(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase; |
} |
} |
} |
/*----------------------------------------------------------------------------*/ |
static int pe_isafunc(int sym_index) |
{ |
Section *sr = text_section->reloc; |
ElfW_Rel *rel, *rel_end; |
Elf32_Word info = ELF32_R_INFO(sym_index, R_386_PC32); |
if (!sr) |
return 0; |
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
for (rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) |
if (rel->r_info == info) |
return 1; |
return 0; |
} |
/*----------------------------------------------------------------------------*/ |
static int pe_check_symbols(struct pe_info *pe) |
ST int pe_check_symbols(struct pe_info *pe) |
{ |
ElfW(Sym) *sym; |
int sym_index, sym_end; |
Elf32_Sym *sym; |
int ret = 0; |
pe_align_section(text_section, 8); |
sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); |
for (sym_index = 1; sym_index < sym_end; ++sym_index) { |
sym = (ElfW(Sym) *)symtab_section->data + sym_index; |
for_sym_in_symtab(sym) { |
if (sym->st_shndx == SHN_UNDEF) { |
const char *name = symtab_section->link->data + sym->st_name; |
unsigned type = ELFW(ST_TYPE)(sym->st_info); |
int imp_sym = pe_find_import(pe->s1, sym); |
struct import_symbol *is; |
if (0 == imp_sym) |
goto not_found; |
if (type == STT_NOTYPE) { |
/* symbols from assembler have no type, find out which */ |
if (pe_isafunc(sym_index)) |
type = STT_FUNC; |
else |
type = STT_OBJECT; |
} |
is = pe_add_import(pe, imp_sym); |
const char *symbol = symtab_section->link->data + sym->st_name; |
unsigned type = ELF32_ST_TYPE(sym->st_info); |
int sym_index = pe_find_import(pe->s1, symbol, NULL); |
if (sym_index) { |
if (type == STT_FUNC) { |
unsigned long offset = is->thk_offset; |
if (offset) { |
/* got aliased symbol, like stricmp and _stricmp */ |
} else { |
char buffer[100]; |
WORD *p; |
offset = text_section->data_offset; |
unsigned long offset = text_section->data_offset; |
if (pe_add_import(pe, sym_index, offset + 2)) { |
/* add the 'jmp IAT[x]' instruction */ |
#ifdef TCC_TARGET_ARM |
p = section_ptr_add(text_section, 8+4); // room for code and address |
(*(DWORD*)(p)) = 0xE59FC000; // arm code ldr ip, [pc] ; PC+8+0 = 0001xxxx |
(*(DWORD*)(p+2)) = 0xE59CF000; // arm code ldr pc, [ip] |
#else |
p = section_ptr_add(text_section, 8); |
*p = 0x25FF; |
#ifdef TCC_TARGET_X86_64 |
*(DWORD*)(p+1) = (DWORD)-4; |
#endif |
#endif |
/* add a helper symbol, will be patched later in |
pe_build_imports */ |
sprintf(buffer, "IAT.%s", name); |
is->iat_index = put_elf_sym( |
symtab_section, 0, sizeof(DWORD), |
ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), |
0, SHN_UNDEF, buffer); |
#ifdef TCC_TARGET_ARM |
put_elf_reloc(symtab_section, text_section, |
offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position |
#else |
put_elf_reloc(symtab_section, text_section, |
offset + 2, R_XXX_THUNKFIX, is->iat_index); |
#endif |
is->thk_offset = offset; |
} |
/* tcc_realloc might have altered sym's address */ |
sym = (ElfW(Sym) *)symtab_section->data + sym_index; |
/* patch the original symbol */ |
*(WORD *) section_ptr_add(text_section, 8) = |
0x25FF; |
/* patch the symbol */ |
sym->st_shndx = text_section->sh_num; |
sym->st_value = offset; |
sym->st_shndx = text_section->sh_num; |
sym->st_other &= ~ST_PE_EXPORT; /* do not export */ |
continue; |
} |
if (type == STT_OBJECT) { /* data, ptr to that should be */ |
if (0 == is->iat_index) { |
/* original symbol will be patched later in pe_build_imports */ |
is->iat_index = sym_index; |
} else if (type == STT_OBJECT) { /* data, ptr to that should be */ |
if (pe_add_import(pe, sym_index, |
(sym - |
(Elf32_Sym *) symtab_section->data) | |
0x80000000)) |
continue; |
} |
} |
not_found: |
tcc_error_noabort("undefined symbol '%s'", name); |
ret = -1; |
} else if (pe->s1->rdynamic |
&& ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
error_noabort("undefined symbol '%s'", symbol); |
ret = 1; |
} else |
if (pe->s1->rdynamic |
&& ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
/* if -rdynamic option, then export all non local symbols */ |
sym->st_other |= ST_PE_EXPORT; |
sym->st_other |= 1; |
} |
} |
return ret; |
1305,9 → 972,8 |
/*----------------------------------------------------------------------------*/ |
#ifdef PE_PRINT_SECTIONS |
static void pe_print_section(FILE * f, Section * s) |
{ |
/* just if you'r curious */ |
ST void pe_print_section(FILE * f, Section * s) |
{ /* just if you'r curious */ |
BYTE *p, *e, b; |
int i, n, l, m; |
p = s->data; |
1319,66 → 985,21 |
fprintf(f, "\nlink \"%s\"", s->link->name); |
if (s->reloc) |
fprintf(f, "\nreloc \"%s\"", s->reloc->name); |
fprintf(f, "\nv_addr %08X", (unsigned)s->sh_addr); |
fprintf(f, "\ncontents %08X", (unsigned)l); |
fprintf(f, "\nv_addr %08X", s->sh_addr); |
fprintf(f, "\ncontents %08X", l); |
fprintf(f, "\n\n"); |
if (s->sh_type == SHT_NOBITS) |
return; |
if (0 == l) |
return; |
if (s->sh_type == SHT_SYMTAB) |
m = sizeof(ElfW(Sym)); |
else if (s->sh_type == SHT_RELX) |
m = sizeof(ElfW_Rel); |
m = sizeof(Elf32_Sym); |
if (s->sh_type == SHT_REL) |
m = sizeof(Elf32_Rel); |
else |
m = 16; |
fprintf(f, "%-8s", "offset"); |
for (i = 0; i < m; ++i) |
fprintf(f, " %02x", i); |
n = 56; |
if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_RELX) { |
const char *fields1[] = { |
"name", |
"value", |
"size", |
"bind", |
"type", |
"other", |
"shndx", |
NULL |
}; |
const char *fields2[] = { |
"offs", |
"type", |
"symb", |
NULL |
}; |
const char **p; |
if (s->sh_type == SHT_SYMTAB) |
p = fields1, n = 106; |
else |
p = fields2, n = 58; |
for (i = 0; p[i]; ++i) |
fprintf(f, "%6s", p[i]); |
fprintf(f, " symbol"); |
} |
fprintf(f, "\n"); |
for (i = 0; i < n; ++i) |
fprintf(f, "-"); |
fprintf(f, "\n"); |
for (i = 0; i < l;) |
{ |
for (i = 0; i < l;) { |
fprintf(f, "%08X", i); |
for (n = 0; n < m; ++n) { |
if (n + i < l) |
1388,28 → 1009,36 |
} |
if (s->sh_type == SHT_SYMTAB) { |
ElfW(Sym) *sym = (ElfW(Sym) *) (p + i); |
Elf32_Sym *sym = (Elf32_Sym *) (p + i); |
const char *name = s->link->data + sym->st_name; |
fprintf(f, " %04X %04X %04X %02X %02X %02X %04X \"%s\"", |
(unsigned)sym->st_name, |
(unsigned)sym->st_value, |
(unsigned)sym->st_size, |
(unsigned)ELFW(ST_BIND)(sym->st_info), |
(unsigned)ELFW(ST_TYPE)(sym->st_info), |
(unsigned)sym->st_other, |
(unsigned)sym->st_shndx, |
name); |
} else if (s->sh_type == SHT_RELX) { |
ElfW_Rel *rel = (ElfW_Rel *) (p + i); |
ElfW(Sym) *sym = |
(ElfW(Sym) *) s->link->data + ELFW(R_SYM)(rel->r_info); |
fprintf(f, |
" name:%04X" |
" value:%04X" |
" size:%04X" |
" bind:%02X" |
" type:%02X" |
" other:%02X" |
" shndx:%04X" |
" \"%s\"", |
sym->st_name, |
sym->st_value, |
sym->st_size, |
ELF32_ST_BIND(sym->st_info), |
ELF32_ST_TYPE(sym->st_info), |
sym->st_other, sym->st_shndx, name); |
} else if (s->sh_type == SHT_REL) { |
Elf32_Rel *rel = (Elf32_Rel *) (p + i); |
Elf32_Sym *sym = |
(Elf32_Sym *) s->link->data + ELF32_R_SYM(rel->r_info); |
const char *name = s->link->link->data + sym->st_name; |
fprintf(f, " %04X %02X %04X \"%s\"", |
(unsigned)rel->r_offset, |
(unsigned)ELFW(R_TYPE)(rel->r_info), |
(unsigned)ELFW(R_SYM)(rel->r_info), |
name); |
fprintf(f, |
" offset:%04X" |
" type:%02X" |
" symbol:%04X" |
" \"%s\"", |
rel->r_offset, |
ELF32_R_TYPE(rel->r_info), |
ELF32_R_SYM(rel->r_info), name); |
} else { |
fprintf(f, " "); |
for (n = 0; n < m; ++n) { |
1426,454 → 1055,190 |
} |
fprintf(f, "\n\n"); |
} |
static void pe_print_sections(TCCState *s1, const char *fname) |
{ |
Section *s; |
FILE *f; |
int i; |
f = fopen(fname, "w"); |
for (i = 1; i < s1->nb_sections; ++i) { |
s = s1->sections[i]; |
pe_print_section(f, s); |
} |
pe_print_section(f, s1->dynsymtab_section); |
fclose(f); |
} |
#endif |
/* ------------------------------------------------------------- */ |
/* helper function for load/store to insert one more indirection */ |
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2) |
static int pe_test_cmd(const char **pp, const char *cmd) |
{ |
Sym *sym; |
ElfW(Sym) *esym; |
int r2; |
const char *p; |
char *q, buf[16]; |
int ret; |
if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST)) |
return sv; |
sym = sv->sym; |
if ((sym->type.t & (VT_EXTERN|VT_STATIC)) != VT_EXTERN) |
return sv; |
if (!sym->c) |
put_extern_sym(sym, NULL, 0, 0); |
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; |
if (!(esym->st_other & ST_PE_IMPORT)) |
return sv; |
// printf("import %04x %04x %04x %s\n", sv->type.t, sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL)); |
memset(v2, 0, sizeof *v2); |
v2->type.t = VT_PTR; |
v2->r = VT_CONST | VT_SYM | VT_LVAL; |
v2->sym = sv->sym; |
r2 = get_reg(RC_INT); |
load(r2, v2); |
v2->r = r2; |
if ((uint32_t)sv->c.i) { |
vpushv(v2); |
vpushi(sv->c.i); |
gen_opi('+'); |
*v2 = *vtop--; |
p = *pp; |
q = buf; |
while (*p != '\0' && !is_space(*p)) { |
if ((q - buf) < sizeof(buf) - 1) |
*q++ = toup(*p); |
p++; |
} |
v2->type.t = sv->type.t; |
v2->r |= sv->r & VT_LVAL; |
return v2; |
} |
ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value) |
{ |
return add_elf_sym( |
s1->dynsymtab_section, |
value, |
dllindex, /* st_size */ |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), |
0, |
value ? SHN_ABS : SHN_UNDEF, |
name |
); |
} |
static int add_dllref(TCCState *s1, const char *dllname) |
{ |
DLLReference *dllref; |
int i; |
for (i = 0; i < s1->nb_loaded_dlls; ++i) |
if (0 == strcmp(s1->loaded_dlls[i]->name, dllname)) |
return i + 1; |
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); |
strcpy(dllref->name, dllname); |
dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
return s1->nb_loaded_dlls; |
} |
/* ------------------------------------------------------------- */ |
static int read_mem(int fd, unsigned offset, void *buffer, unsigned len) |
{ |
lseek(fd, offset, SEEK_SET); |
return len == read(fd, buffer, len); |
} |
/* ------------------------------------------------------------- |
* This is for compiled windows resources in 'coff' format |
* as generated by 'windres.exe -O coff ...'. |
*/ |
static int pe_load_res(TCCState *s1, int fd) |
{ |
struct pe_rsrc_header hdr; |
Section *rsrc_section; |
int i, ret = -1; |
BYTE *ptr; |
unsigned offs; |
if (!read_mem(fd, 0, &hdr, sizeof hdr)) |
goto quit; |
if (hdr.filehdr.Machine != IMAGE_FILE_MACHINE |
|| hdr.filehdr.NumberOfSections != 1 |
|| strcmp(hdr.sectionhdr.Name, ".rsrc") != 0) |
goto quit; |
rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC); |
ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData); |
offs = hdr.sectionhdr.PointerToRawData; |
if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData)) |
goto quit; |
offs = hdr.sectionhdr.PointerToRelocations; |
for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) |
{ |
struct pe_rsrc_reloc rel; |
if (!read_mem(fd, offs, &rel, sizeof rel)) |
goto quit; |
// printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type); |
if (rel.type != RSRC_RELTYPE) |
goto quit; |
put_elf_reloc(symtab_section, rsrc_section, |
rel.offset, R_XXX_RELATIVE, 0); |
offs += sizeof rel; |
} |
ret = 0; |
quit: |
*q = '\0'; |
ret = !strcmp(buf, cmd); |
*pp = p; |
return ret; |
} |
/* ------------------------------------------------------------- */ |
#ifndef TCC_TARGET_MEOS |
static int pe_load_def(TCCState *s1, int fd) |
int pe_load_def_file(TCCState * s1, FILE * fp) |
{ |
int state = 0, ret = -1, dllindex = 0, ord; |
char line[400], dllname[80], *p, *x; |
FILE *fp; |
DLLReference *dllref; |
int f = 0, sym_index; |
char *p, line[120], dllname[40]; |
while (fgets(line, sizeof line, fp)) { |
//p = strchr(line, 0); |
while (p > line && p[-1] <= ' ') |
--p; |
*p = 0; |
p = line; |
while (*p && *p <= ' ') |
++p; |
fp = fdopen(dup(fd), "rb"); |
while (fgets(line, sizeof line, fp)) |
{ |
p = trimfront(trimback(line, strchr(line, 0))); |
if (0 == *p || ';' == *p) |
continue; |
switch (state) { |
if (*p && ';' != *p) |
switch (f) { |
case 0: |
if (0 != strnicmp(p, "LIBRARY", 7)) |
goto quit; |
pstrcpy(dllname, sizeof dllname, trimfront(p+7)); |
++state; |
if (!pe_test_cmd((const char **)&p, "LIBRARY")) |
return -1; |
while (is_space(*p)) |
p++; |
pstrcpy(dllname, sizeof(dllname), p); |
++f; |
continue; |
case 1: |
if (0 != stricmp(p, "EXPORTS")) |
goto quit; |
++state; |
if (!pe_test_cmd((const char **)&p, "EXPORTS")) |
return -1; |
++f; |
continue; |
case 2: |
dllindex = add_dllref(s1, dllname); |
++state; |
/* fall through */ |
dllref = |
tcc_malloc(sizeof(DLLReference) + strlen(dllname)); |
strcpy(dllref->name, dllname); |
dllref->level = 0; |
dynarray_add((void ***) &s1->loaded_dlls, |
&s1->nb_loaded_dlls, dllref); |
++f; |
default: |
/* get ordinal and will store in sym->st_value */ |
ord = 0; |
x = strchr(p, ' '); |
if (x) { |
*x = 0, x = strrchr(x + 1, '@'); |
if (x) { |
char *d; |
ord = (int)strtol(x + 1, &d, 10); |
if (*d) |
ord = 0; |
} |
} |
pe_putimport(s1, dllindex, p, ord); |
/* tccpe needs to know from what dll it should import |
the sym */ |
sym_index = add_elf_sym(s1->dynsymtab_section, |
0, 0, ELF32_ST_INFO(STB_GLOBAL, |
STT_FUNC), |
s1->nb_loaded_dlls - 1, |
text_section->sh_num, p); |
continue; |
} |
} |
ret = 0; |
quit: |
fclose(fp); |
return ret; |
} |
#else |
static int pe_load_def(TCCState *s1, int fd) |
{ return 0; } |
#endif |
/* ------------------------------------------------------------- */ |
#define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY |
#include "win32/tools/tiny_impdef.c" |
static int pe_load_dll(TCCState *s1, const char *dllname, int fd) |
{ |
char *p, *q; |
int index; |
p = get_export_names(fd); |
if (!p) |
return -1; |
index = add_dllref(s1, dllname); |
for (q = p; *q; q += 1 + strlen(q)) |
pe_putimport(s1, index, q, 0); |
tcc_free(p); |
return 0; |
} |
/* ------------------------------------------------------------- */ |
ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) |
void pe_guess_outfile(char *objfilename, int output_type) |
{ |
int ret = -1; |
char buf[10]; |
if (0 == strcmp(tcc_fileextension(filename), ".def")) |
ret = pe_load_def(s1, fd); |
else if (pe_load_res(s1, fd) == 0) |
ret = 0; |
else if (read_mem(fd, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2)) |
ret = pe_load_dll(s1, tcc_basename(filename), fd); |
return ret; |
char *ext = strrchr(objfilename, '.'); |
if (NULL == ext) |
//ext = strchr(objfilename, 0); |
if (output_type == TCC_OUTPUT_DLL) |
strcpy(ext, ".dll"); |
else |
if (output_type == TCC_OUTPUT_EXE) |
strcpy(ext, ".exe"); |
else |
if (output_type == TCC_OUTPUT_OBJ && strcmp(ext, ".o")) |
strcpy(ext, ".o"); |
else |
error("no outputfile given"); |
} |
/* ------------------------------------------------------------- */ |
#ifdef TCC_TARGET_X86_64 |
static unsigned pe_add_uwwind_info(TCCState *s1) |
unsigned long pe_add_runtime(TCCState * s1) |
{ |
if (NULL == s1->uw_pdata) { |
s1->uw_pdata = find_section(tcc_state, ".pdata"); |
s1->uw_pdata->sh_addralign = 4; |
s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL); |
} |
if (0 == s1->uw_offs) { |
/* As our functions all have the same stackframe, we use one entry for all */ |
static const unsigned char uw_info[] = { |
0x01, // UBYTE: 3 Version , UBYTE: 5 Flags |
0x04, // UBYTE Size of prolog |
0x02, // UBYTE Count of unwind codes |
0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled) |
// USHORT * n Unwind codes array |
// 0x0b, 0x01, 0xff, 0xff, // stack size |
0x04, 0x03, // set frame ptr (mov rsp -> rbp) |
0x01, 0x50 // push reg (rbp) |
}; |
Section *s = text_section; |
unsigned char *p; |
section_ptr_add(s, -s->data_offset & 3); /* align */ |
s1->uw_offs = s->data_offset; |
p = section_ptr_add(s, sizeof uw_info); |
memcpy(p, uw_info, sizeof uw_info); |
} |
return s1->uw_offs; |
} |
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) |
{ |
TCCState *s1 = tcc_state; |
Section *pd; |
unsigned o, n, d; |
struct /* _RUNTIME_FUNCTION */ { |
DWORD BeginAddress; |
DWORD EndAddress; |
DWORD UnwindData; |
} *p; |
d = pe_add_uwwind_info(s1); |
pd = s1->uw_pdata; |
o = pd->data_offset; |
p = section_ptr_add(pd, sizeof *p); |
/* record this function */ |
p->BeginAddress = start; |
p->EndAddress = end; |
p->UnwindData = d; |
/* put relocations on it */ |
for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress) |
put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym); |
} |
#endif |
/* ------------------------------------------------------------- */ |
#ifdef TCC_TARGET_X86_64 |
#define PE_STDSYM(n,s) n |
#else |
#define PE_STDSYM(n,s) "_" n s |
#endif |
static void pe_add_runtime(TCCState *s1, struct pe_info *pe) |
{ |
const char *start_symbol; |
int pe_type = 0; |
unsigned long addr; |
if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16"))) |
if (find_elf_sym(symtab_section, "WinMain")) |
pe_type = PE_GUI; |
else |
if (TCC_OUTPUT_DLL == s1->output_type) { |
if (TCC_OUTPUT_DLL == s1->output_type) |
{ |
pe_type = PE_DLL; |
/* need this for 'tccelf.c:relocate_section()' */ |
// need this for 'tccelf.c:relocate_section()' |
s1->output_type = TCC_OUTPUT_EXE; |
} |
else |
pe_type = PE_EXE; |
start_symbol = |
TCC_OUTPUT_MEMORY == s1->output_type |
? PE_GUI == pe_type ? "__runwinmain" : "_main" |
: PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12") |
: PE_GUI == pe_type ? "__winstart" : "__start" |
; |
? PE_GUI == pe_type ? "_runwinmain" : NULL |
: PE_DLL == pe_type ? "_dllstart" |
: PE_GUI == pe_type ? "_winstart" : "_start"; |
if (!s1->leading_underscore || strchr(start_symbol, '@')) |
++start_symbol; |
/* grab the startup code from libtcc1 */ |
if (TCC_OUTPUT_MEMORY != s1->output_type || PE_GUI == pe_type) |
if (start_symbol) |
add_elf_sym(symtab_section, |
0, 0, |
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
SHN_UNDEF, start_symbol); |
tcc_add_pragma_libs(s1); |
if (0 == s1->nostdlib) { |
static const char *libs[] = { |
"tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL |
}; |
const char **pp, *p; |
for (pp = libs; 0 != (p = *pp); ++pp) { |
if (0 == *p) { |
if (PE_DLL != pe_type && PE_GUI != pe_type) |
break; |
} else if (tcc_add_library_err(s1, p) < 0) { |
break; |
tcc_add_library(s1, "tcc1"); |
tcc_add_library(s1, "msvcrt"); |
if (PE_DLL == pe_type || PE_GUI == pe_type) { |
tcc_add_library(s1, "kernel32"); |
tcc_add_library(s1, "user32"); |
tcc_add_library(s1, "gdi32"); |
} |
} |
} |
if (TCC_OUTPUT_MEMORY == s1->output_type) { |
pe_type = PE_RUN; |
#ifdef TCC_IS_NATIVE |
s1->runtime_main = start_symbol; |
#endif |
} else { |
pe->start_addr = (DWORD)(uintptr_t)tcc_get_symbol_err(s1, start_symbol); |
} |
addr = start_symbol ? |
(unsigned long) tcc_get_symbol_err(s1, start_symbol) : 0; |
pe->type = pe_type; |
if (s1->output_type == TCC_OUTPUT_MEMORY && addr) { |
/* for -run GUI's, put '_runwinmain' instead of 'main' */ |
add_elf_sym(symtab_section, |
addr, 0, |
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
text_section->sh_num, "main"); |
/* FreeConsole(); */ |
} |
return addr; |
} |
ST_FUNC int pe_output_file(TCCState * s1, const char *filename) |
int tcc_output_pe(TCCState * s1, const char *filename) |
{ |
int ret; |
struct pe_info pe; |
int i; |
memset(&pe, 0, sizeof pe); |
pe.filename = filename; |
pe.s1 = s1; |
pe.start_addr = pe_add_runtime(s1); |
pe_add_runtime(s1, &pe); |
tcc_add_bcheck(s1); |
relocate_common_syms(); /* assign bss adresses */ |
tcc_add_linker_symbols(s1); |
ret = pe_check_symbols(&pe); |
if (ret) |
; |
else if (filename) { |
if (PE_DLL == pe.type) { |
pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0); |
/* XXX: check if is correct for arm-pe target */ |
pe.imagebase = 0x10000000; |
} else { |
#if defined(TCC_TARGET_ARM) |
pe.imagebase = 0x00010000; |
#else |
pe.imagebase = 0x00400000; |
#endif |
} |
#if defined(TCC_TARGET_ARM) |
/* we use "console" subsystem by default */ |
pe.subsystem = 9; |
#else |
if (PE_DLL == pe.type || PE_GUI == pe.type) |
pe.subsystem = 2; |
else |
pe.subsystem = 3; |
#endif |
/* Allow override via -Wl,-subsystem=... option */ |
if (s1->pe_subsystem != 0) |
pe.subsystem = s1->pe_subsystem; |
/* set default file/section alignment */ |
if (pe.subsystem == 1) { |
pe.section_align = 0x20; |
pe.file_align = 0x20; |
} else { |
pe.section_align = 0x1000; |
pe.file_align = 0x200; |
} |
if (s1->section_align != 0) |
pe.section_align = s1->section_align; |
if (s1->pe_file_align != 0) |
pe.file_align = s1->pe_file_align; |
if ((pe.subsystem >= 10) && (pe.subsystem <= 12)) |
pe.imagebase = 0; |
if (s1->has_text_addr) |
pe.imagebase = s1->text_addr; |
if (0 == ret) { |
pe_assign_addresses(&pe); |
relocate_syms(s1, 0); |
for (i = 1; i < s1->nb_sections; ++i) { |
Section *s = s1->sections[i]; |
if (s->reloc) { |
if (s->reloc) |
relocate_section(s1, s); |
pe_relocate_rva(&pe, s); |
} |
ret = pe_write_pe(&pe); |
} |
if (s1->nb_errors) |
ret = -1; |
else |
ret = pe_write(&pe); |
tcc_free(pe.sec_info); |
} else { |
#ifdef TCC_IS_NATIVE |
pe.thunk = data_section; |
pe_build_imports(&pe); |
#endif |
#ifdef PE_PRINT_SECTIONS |
{ |
Section *s; |
FILE *f; |
f = fopen("tccpe.log", "wt"); |
for (i = 1; i < s1->nb_sections; ++i) { |
s = s1->sections[i]; |
pe_print_section(f, s); |
} |
#ifdef PE_PRINT_SECTIONS |
pe_print_sections(s1, "tcc.log"); |
pe_print_section(f, s1->dynsymtab_section); |
fclose(f); |
} |
#endif |
return ret; |
} |
/* ------------------------------------------------------------- */ |
/*----------------------------------------------------------------------------*/ |
/programs/develop/ktcc/trunk/source/tcctest.c |
---|
0,0 → 1,1990 |
/* |
* TCC auto test program |
*/ |
#include "config.h" |
#if GCC_MAJOR >= 3 |
/* Unfortunately, gcc version < 3 does not handle that! */ |
#define ALL_ISOC99 |
/* only gcc 3 handles _Bool correctly */ |
#define BOOL_ISOC99 |
/* gcc 2.95.3 does not handle correctly CR in strings or after strays */ |
#define CORRECT_CR_HANDLING |
#endif |
/* deprecated and no longer supported in gcc 3.3 */ |
//#define ACCEPT_CR_IN_STRINGS |
/* __VA_ARGS__ and __func__ support */ |
#define C99_MACROS |
/* test various include syntaxes */ |
#define TCCLIB_INC <tcclib.h> |
#define TCCLIB_INC1 <tcclib |
#define TCCLIB_INC2 h> |
#define TCCLIB_INC3 "tcclib" |
#include TCCLIB_INC |
#include TCCLIB_INC1.TCCLIB_INC2 |
#include TCCLIB_INC1.h> |
/* gcc 3.2 does not accept that (bug ?) */ |
//#include TCCLIB_INC3 ".h" |
#include <tcclib.h> |
#include "tcclib.h" |
void string_test(); |
void expr_test(); |
void macro_test(); |
void scope_test(); |
void forward_test(); |
void funcptr_test(); |
void loop_test(); |
void switch_test(); |
void goto_test(); |
void enum_test(); |
void typedef_test(); |
void struct_test(); |
void array_test(); |
void expr_ptr_test(); |
void bool_test(); |
void expr2_test(); |
void constant_expr_test(); |
void expr_cmp_test(); |
void char_short_test(); |
void init_test(void); |
void compound_literal_test(void); |
int kr_test(); |
void struct_assign_test(void); |
void cast_test(void); |
void bitfield_test(void); |
void c99_bool_test(void); |
void float_test(void); |
void longlong_test(void); |
void stdarg_test(void); |
void whitespace_test(void); |
void relocation_test(void); |
void old_style_function(void); |
void sizeof_test(void); |
void typeof_test(void); |
void local_label_test(void); |
void statement_expr_test(void); |
void asm_test(void); |
void builtin_test(void); |
int fib(int n); |
void num(int n); |
void forward_ref(void); |
int isid(int c); |
#define A 2 |
#define N 1234 + A |
#define pf printf |
#define M1(a, b) (a) + (b) |
#define str\ |
(s) # s |
#define glue(a, b) a ## b |
#define xglue(a, b) glue(a, b) |
#define HIGHLOW "hello" |
#define LOW LOW ", world" |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
#ifdef C99_MACROS |
#define dprintf(level,...) printf(__VA_ARGS__) |
#endif |
/* gcc vararg macros */ |
#define dprintf1(level, fmt, args...) printf(fmt, ## args) |
#define MACRO_NOARGS() |
#define AAA 3 |
#undef AAA |
#define AAA 4 |
#if 1 |
#define B3 1 |
#elif 1 |
#define B3 2 |
#elif 0 |
#define B3 3 |
#else |
#define B3 4 |
#endif |
#define __INT64_C(c) c ## LL |
#define INT64_MIN (-__INT64_C(9223372036854775807)-1) |
int qq(int x) |
{ |
return x + 40; |
} |
#define qq(x) x |
#define spin_lock(lock) do { } while (0) |
#define wq_spin_lock spin_lock |
#define TEST2() wq_spin_lock(a) |
void macro_test(void) |
{ |
printf("macro:\n"); |
pf("N=%d\n", N); |
printf("aaa=%d\n", AAA); |
printf("min=%d\n", min(1, min(2, -1))); |
printf("s1=%s\n", glue(HIGH, LOW)); |
printf("s2=%s\n", xglue(HIGH, LOW)); |
printf("s3=%s\n", str("c")); |
printf("s4=%s\n", str(a1)); |
printf("B3=%d\n", B3); |
#ifdef A |
printf("A defined\n"); |
#endif |
#ifdef B |
printf("B defined\n"); |
#endif |
#ifdef A |
printf("A defined\n"); |
#else |
printf("A not defined\n"); |
#endif |
#ifdef B |
printf("B defined\n"); |
#else |
printf("B not defined\n"); |
#endif |
#ifdef A |
printf("A defined\n"); |
#ifdef B |
printf("B1 defined\n"); |
#else |
printf("B1 not defined\n"); |
#endif |
#else |
printf("A not defined\n"); |
#ifdef B |
printf("B2 defined\n"); |
#else |
printf("B2 not defined\n"); |
#endif |
#endif |
#if 1+1 |
printf("test true1\n"); |
#endif |
#if 0 |
printf("test true2\n"); |
#endif |
#if 1-1 |
printf("test true3\n"); |
#endif |
#if defined(A) |
printf("test trueA\n"); |
#endif |
#if defined(B) |
printf("test trueB\n"); |
#endif |
#if 0 |
printf("test 0\n"); |
#elif 0 |
printf("test 1\n"); |
#elif 2 |
printf("test 2\n"); |
#else |
printf("test 3\n"); |
#endif |
MACRO_NOARGS(); |
#ifdef __LINE__ |
printf("__LINE__ defined\n"); |
#endif |
printf("__LINE__=%d __FILE__=%s\n", |
__LINE__, __FILE__); |
#line 200 |
printf("__LINE__=%d __FILE__=%s\n", |
__LINE__, __FILE__); |
#line 203 "test" |
printf("__LINE__=%d __FILE__=%s\n", |
__LINE__, __FILE__); |
#line 220 "tcctest.c" |
/* not strictly preprocessor, but we test it there */ |
#ifdef C99_MACROS |
printf("__func__ = %s\n", __func__); |
dprintf(1, "vaarg=%d\n", 1); |
#endif |
dprintf1(1, "vaarg1\n"); |
dprintf1(1, "vaarg1=%d\n", 2); |
dprintf1(1, "vaarg1=%d %d\n", 1, 2); |
/* gcc extension */ |
printf("func='%s'\n", __FUNCTION__); |
/* complicated macros in glibc */ |
printf("INT64_MIN=%Ld\n", INT64_MIN); |
{ |
int a; |
a = 1; |
glue(a+, +); |
printf("a=%d\n", a); |
glue(a <, <= 2); |
printf("a=%d\n", a); |
} |
/* macro function with argument outside the macro string */ |
#define MF_s MF_hello |
#define MF_hello(msg) printf("%s\n",msg) |
#define MF_t printf("tralala\n"); MF_hello |
MF_s("hi"); |
MF_t("hi"); |
/* test macro substituion inside args (should not eat stream) */ |
printf("qq=%d\n", qq(qq)(2)); |
/* test zero argument case. NOTE: gcc 2.95.x does not accept a |
null argument without a space. gcc 3.2 fixes that. */ |
#define qq1(x) 1 |
printf("qq1=%d\n", qq1( )); |
/* comment with stray handling *\ |
/ |
/* this is a valid *\/ comment */ |
/* this is a valid comment *\*/ |
// this is a valid\ |
comment |
/* test function macro substitution when the function name is |
substituted */ |
TEST2(); |
} |
int op(a,b) |
{ |
return a / b; |
} |
int ret(a) |
{ |
if (a == 2) |
return 1; |
if (a == 3) |
return 2; |
return 0; |
} |
void ps(const char *s) |
{ |
int c; |
while (1) { |
c = *s; |
if (c == 0) |
break; |
printf("%c", c); |
s++; |
} |
} |
const char foo1_string[] = "\ |
bar\n\ |
test\14\ |
1"; |
void string_test() |
{ |
int b; |
printf("string:\n"); |
printf("\141\1423\143\n");/* dezdez test */ |
printf("\x41\x42\x43\x3a\n"); |
printf("c=%c\n", 'r'); |
printf("wc=%C 0x%lx %C\n", L'a', L'\x1234', L'c'); |
printf("foo1_string='%s'\n", foo1_string); |
#if 0 |
printf("wstring=%S\n", L"abc"); |
printf("wstring=%S\n", L"abc" L"def" "ghi"); |
printf("'\\377'=%d '\\xff'=%d\n", '\377', '\xff'); |
printf("L'\\377'=%d L'\\xff'=%d\n", L'\377', L'\xff'); |
#endif |
ps("test\n"); |
b = 32; |
while ((b = b + 1) < 96) { |
printf("%c", b); |
} |
printf("\n"); |
printf("fib=%d\n", fib(33)); |
b = 262144; |
while (b != 0x80000000) { |
num(b); |
b = b * 2; |
} |
} |
void loop_test() |
{ |
int i; |
i = 0; |
while (i < 10) |
printf("%d", i++); |
printf("\n"); |
for(i = 0; i < 10;i++) |
printf("%d", i); |
printf("\n"); |
i = 0; |
do { |
printf("%d", i++); |
} while (i < 10); |
printf("\n"); |
/* break/continue tests */ |
i = 0; |
while (1) { |
if (i == 6) |
break; |
i++; |
if (i == 3) |
continue; |
printf("%d", i); |
} |
printf("\n"); |
/* break/continue tests */ |
i = 0; |
do { |
if (i == 6) |
break; |
i++; |
if (i == 3) |
continue; |
printf("%d", i); |
} while(1); |
printf("\n"); |
for(i = 0;i < 10;i++) { |
if (i == 3) |
continue; |
printf("%d", i); |
} |
printf("\n"); |
} |
void goto_test() |
{ |
int i; |
static void *label_table[3] = { &&label1, &&label2, &&label3 }; |
printf("goto:\n"); |
i = 0; |
s_loop: |
if (i >= 10) |
goto s_end; |
printf("%d", i); |
i++; |
goto s_loop; |
s_end: |
printf("\n"); |
/* we also test computed gotos (GCC extension) */ |
for(i=0;i<3;i++) { |
goto *label_table[i]; |
label1: |
printf("label1\n"); |
goto next; |
label2: |
printf("label2\n"); |
goto next; |
label3: |
printf("label3\n"); |
next: ; |
} |
} |
enum { |
E0, |
E1 = 2, |
E2 = 4, |
E3, |
E4, |
}; |
enum test { |
E5 = 1000, |
}; |
void enum_test() |
{ |
enum test b1; |
printf("enum:\n%d %d %d %d %d %d\n", |
E0, E1, E2, E3, E4, E5); |
b1 = 1; |
printf("b1=%d\n", b1); |
} |
typedef int *my_ptr; |
void typedef_test() |
{ |
my_ptr a; |
int b; |
a = &b; |
*a = 1234; |
printf("typedef:\n"); |
printf("a=%d\n", *a); |
} |
void forward_test() |
{ |
printf("forward:\n"); |
forward_ref(); |
forward_ref(); |
} |
void forward_ref(void) |
{ |
printf("forward ok\n"); |
} |
typedef struct struct1 { |
int f1; |
int f2, f3; |
union union1 { |
int v1; |
int v2; |
} u; |
char str[3]; |
} struct1; |
struct struct2 { |
int a; |
char b; |
}; |
union union2 { |
int w1; |
int w2; |
}; |
struct struct1 st1, st2; |
int main(int argc, char **argv) |
{ |
string_test(); |
expr_test(); |
macro_test(); |
scope_test(); |
forward_test(); |
funcptr_test(); |
loop_test(); |
switch_test(); |
goto_test(); |
enum_test(); |
typedef_test(); |
struct_test(); |
array_test(); |
expr_ptr_test(); |
bool_test(); |
expr2_test(); |
constant_expr_test(); |
expr_cmp_test(); |
char_short_test(); |
init_test(); |
compound_literal_test(); |
kr_test(); |
struct_assign_test(); |
cast_test(); |
bitfield_test(); |
c99_bool_test(); |
float_test(); |
longlong_test(); |
stdarg_test(); |
whitespace_test(); |
relocation_test(); |
old_style_function(); |
sizeof_test(); |
typeof_test(); |
statement_expr_test(); |
local_label_test(); |
asm_test(); |
builtin_test(); |
return 0; |
} |
int tab[3]; |
int tab2[3][2]; |
int g; |
void f1(g) |
{ |
printf("g1=%d\n", g); |
} |
void scope_test() |
{ |
printf("scope:\n"); |
g = 2; |
f1(1); |
printf("g2=%d\n", g); |
{ |
int g; |
g = 3; |
printf("g3=%d\n", g); |
{ |
int g; |
g = 4; |
printf("g4=%d\n", g); |
} |
} |
printf("g5=%d\n", g); |
} |
void array_test(int a[4]) |
{ |
int i, j; |
printf("array:\n"); |
printf("sizeof(a) = %d\n", sizeof(a)); |
printf("sizeof(\"a\") = %d\n", sizeof("a")); |
#ifdef C99_MACROS |
printf("sizeof(__func__) = %d\n", sizeof(__func__)); |
#endif |
printf("sizeof tab %d\n", sizeof(tab)); |
printf("sizeof tab2 %d\n", sizeof tab2); |
tab[0] = 1; |
tab[1] = 2; |
tab[2] = 3; |
printf("%d %d %d\n", tab[0], tab[1], tab[2]); |
for(i=0;i<3;i++) |
for(j=0;j<2;j++) |
tab2[i][j] = 10 * i + j; |
for(i=0;i<3*2;i++) { |
printf(" %3d", ((int *)tab2)[i]); |
} |
printf("\n"); |
} |
void expr_test() |
{ |
int a, b; |
a = 0; |
printf("%d\n", a += 1); |
printf("%d\n", a -= 2); |
printf("%d\n", a *= 31232132); |
printf("%d\n", a /= 4); |
printf("%d\n", a %= 20); |
printf("%d\n", a &= 6); |
printf("%d\n", a ^= 7); |
printf("%d\n", a |= 8); |
printf("%d\n", a >>= 3); |
printf("%d\n", a <<= 4); |
a = 22321; |
b = -22321; |
printf("%d\n", a + 1); |
printf("%d\n", a - 2); |
printf("%d\n", a * 312); |
printf("%d\n", a / 4); |
printf("%d\n", b / 4); |
printf("%d\n", (unsigned)b / 4); |
printf("%d\n", a % 20); |
printf("%d\n", b % 20); |
printf("%d\n", (unsigned)b % 20); |
printf("%d\n", a & 6); |
printf("%d\n", a ^ 7); |
printf("%d\n", a | 8); |
printf("%d\n", a >> 3); |
printf("%d\n", b >> 3); |
printf("%d\n", (unsigned)b >> 3); |
printf("%d\n", a << 4); |
printf("%d\n", ~a); |
printf("%d\n", -a); |
printf("%d\n", +a); |
printf("%d\n", 12 + 1); |
printf("%d\n", 12 - 2); |
printf("%d\n", 12 * 312); |
printf("%d\n", 12 / 4); |
printf("%d\n", 12 % 20); |
printf("%d\n", 12 & 6); |
printf("%d\n", 12 ^ 7); |
printf("%d\n", 12 | 8); |
printf("%d\n", 12 >> 2); |
printf("%d\n", 12 << 4); |
printf("%d\n", ~12); |
printf("%d\n", -12); |
printf("%d\n", +12); |
printf("%d %d %d %d\n", |
isid('a'), |
isid('g'), |
isid('T'), |
isid('(')); |
} |
int isid(int c) |
{ |
return (c >= 'a' & c <= 'z') | (c >= 'A' & c <= 'Z') | c == '_'; |
} |
/**********************/ |
int vstack[10], *vstack_ptr; |
void vpush(int vt, int vc) |
{ |
*vstack_ptr++ = vt; |
*vstack_ptr++ = vc; |
} |
void vpop(int *ft, int *fc) |
{ |
*fc = *--vstack_ptr; |
*ft = *--vstack_ptr; |
} |
void expr2_test() |
{ |
int a, b; |
printf("expr2:\n"); |
vstack_ptr = vstack; |
vpush(1432432, 2); |
vstack_ptr[-2] &= ~0xffffff80; |
vpop(&a, &b); |
printf("res= %d %d\n", a, b); |
} |
void constant_expr_test() |
{ |
int a; |
printf("constant_expr:\n"); |
a = 3; |
printf("%d\n", a * 16); |
printf("%d\n", a * 1); |
printf("%d\n", a + 0); |
} |
int tab4[10]; |
void expr_ptr_test() |
{ |
int *p, *q; |
printf("expr_ptr:\n"); |
p = tab4; |
q = tab4 + 10; |
printf("diff=%d\n", q - p); |
p++; |
printf("inc=%d\n", p - tab4); |
p--; |
printf("dec=%d\n", p - tab4); |
++p; |
printf("inc=%d\n", p - tab4); |
--p; |
printf("dec=%d\n", p - tab4); |
printf("add=%d\n", p + 3 - tab4); |
printf("add=%d\n", 3 + p - tab4); |
} |
void expr_cmp_test() |
{ |
int a, b; |
printf("constant_expr:\n"); |
a = -1; |
b = 1; |
printf("%d\n", a == a); |
printf("%d\n", a != a); |
printf("%d\n", a < b); |
printf("%d\n", a <= b); |
printf("%d\n", a <= a); |
printf("%d\n", b >= a); |
printf("%d\n", a >= a); |
printf("%d\n", b > a); |
printf("%d\n", (unsigned)a < b); |
printf("%d\n", (unsigned)a <= b); |
printf("%d\n", (unsigned)a <= a); |
printf("%d\n", (unsigned)b >= a); |
printf("%d\n", (unsigned)a >= a); |
printf("%d\n", (unsigned)b > a); |
} |
struct empty { |
}; |
struct aligntest1 { |
char a[10]; |
}; |
struct aligntest2 { |
int a; |
char b[10]; |
}; |
struct aligntest3 { |
double a, b; |
}; |
struct aligntest4 { |
double a[0]; |
}; |
void struct_test() |
{ |
struct1 *s; |
union union2 u; |
printf("struct:\n"); |
printf("sizes: %d %d %d %d\n", |
sizeof(struct struct1), |
sizeof(struct struct2), |
sizeof(union union1), |
sizeof(union union2)); |
st1.f1 = 1; |
st1.f2 = 2; |
st1.f3 = 3; |
printf("st1: %d %d %d\n", |
st1.f1, st1.f2, st1.f3); |
st1.u.v1 = 1; |
st1.u.v2 = 2; |
printf("union1: %d\n", st1.u.v1); |
u.w1 = 1; |
u.w2 = 2; |
printf("union2: %d\n", u.w1); |
s = &st2; |
s->f1 = 3; |
s->f2 = 2; |
s->f3 = 1; |
printf("st2: %d %d %d\n", |
s->f1, s->f2, s->f3); |
printf("str_addr=%x\n", (int)st1.str - (int)&st1.f1); |
/* align / size tests */ |
printf("aligntest1 sizeof=%d alignof=%d\n", |
sizeof(struct aligntest1), __alignof__(struct aligntest1)); |
printf("aligntest2 sizeof=%d alignof=%d\n", |
sizeof(struct aligntest2), __alignof__(struct aligntest2)); |
printf("aligntest3 sizeof=%d alignof=%d\n", |
sizeof(struct aligntest3), __alignof__(struct aligntest3)); |
printf("aligntest4 sizeof=%d alignof=%d\n", |
sizeof(struct aligntest4), __alignof__(struct aligntest4)); |
/* empty structures (GCC extension) */ |
printf("sizeof(struct empty) = %d\n", sizeof(struct empty)); |
printf("alignof(struct empty) = %d\n", __alignof__(struct empty)); |
} |
/* XXX: depend on endianness */ |
void char_short_test() |
{ |
int var1, var2; |
printf("char_short:\n"); |
var1 = 0x01020304; |
var2 = 0xfffefdfc; |
printf("s8=%d %d\n", |
*(char *)&var1, *(char *)&var2); |
printf("u8=%d %d\n", |
*(unsigned char *)&var1, *(unsigned char *)&var2); |
printf("s16=%d %d\n", |
*(short *)&var1, *(short *)&var2); |
printf("u16=%d %d\n", |
*(unsigned short *)&var1, *(unsigned short *)&var2); |
printf("s32=%d %d\n", |
*(int *)&var1, *(int *)&var2); |
printf("u32=%d %d\n", |
*(unsigned int *)&var1, *(unsigned int *)&var2); |
*(char *)&var1 = 0x08; |
printf("var1=%x\n", var1); |
*(short *)&var1 = 0x0809; |
printf("var1=%x\n", var1); |
*(int *)&var1 = 0x08090a0b; |
printf("var1=%x\n", var1); |
} |
/******************/ |
typedef struct Sym { |
int v; |
int t; |
int c; |
struct Sym *next; |
struct Sym *prev; |
} Sym; |
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') |
#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) |
static int toupper1(int a) |
{ |
return TOUPPER(a); |
} |
void bool_test() |
{ |
int *s, a, b, t, f, i; |
a = 0; |
s = (void*)0; |
printf("!s=%d\n", !s); |
if (!s || !s[0]) |
a = 1; |
printf("a=%d\n", a); |
printf("a=%d %d %d\n", 0 || 0, 0 || 1, 1 || 1); |
printf("a=%d %d %d\n", 0 && 0, 0 && 1, 1 && 1); |
printf("a=%d %d\n", 1 ? 1 : 0, 0 ? 1 : 0); |
#if 1 && 1 |
printf("a1\n"); |
#endif |
#if 1 || 0 |
printf("a2\n"); |
#endif |
#if 1 ? 0 : 1 |
printf("a3\n"); |
#endif |
#if 0 ? 0 : 1 |
printf("a4\n"); |
#endif |
a = 4; |
printf("b=%d\n", a + (0 ? 1 : a / 2)); |
/* test register spilling */ |
a = 10; |
b = 10; |
a = (a + b) * ((a < b) ? |
((b - a) * (a - b)): a + b); |
printf("a=%d\n", a); |
/* test complex || or && expressions */ |
t = 1; |
f = 0; |
a = 32; |
printf("exp=%d\n", f == (32 <= a && a <= 3)); |
printf("r=%d\n", (t || f) + (t && f)); |
/* test ? : cast */ |
{ |
int aspect_on; |
int aspect_native = 65536; |
double bfu_aspect = 1.0; |
int aspect; |
for(aspect_on = 0; aspect_on < 2; aspect_on++) { |
aspect=aspect_on?(aspect_native*bfu_aspect+0.5):65535UL; |
printf("aspect=%d\n", aspect); |
} |
} |
/* test ? : GCC extension */ |
{ |
static int v1 = 34 ? : -1; /* constant case */ |
static int v2 = 0 ? : -1; /* constant case */ |
int a = 30; |
printf("%d %d\n", v1, v2); |
printf("%d %d\n", a - 30 ? : a * 2, a + 1 ? : a * 2); |
} |
/* again complex expression */ |
for(i=0;i<256;i++) { |
if (toupper1 (i) != TOUPPER (i)) |
printf("error %d\n", i); |
} |
} |
/* GCC accepts that */ |
static int tab_reinit[]; |
static int tab_reinit[10]; |
//int cinit1; /* a global variable can be defined several times without error ! */ |
int cinit1; |
int cinit1; |
int cinit1 = 0; |
int *cinit2 = (int []){3, 2, 1}; |
void compound_literal_test(void) |
{ |
int *p, i; |
char *q, *q3; |
printf("compound_test:\n"); |
p = (int []){1, 2, 3}; |
for(i=0;i<3;i++) |
printf(" %d", p[i]); |
printf("\n"); |
for(i=0;i<3;i++) |
printf("%d", cinit2[i]); |
printf("\n"); |
q = "tralala1"; |
printf("q1=%s\n", q); |
q = (char *){ "tralala2" }; |
printf("q2=%s\n", q); |
q3 = (char *){ q }; |
printf("q3=%s\n", q3); |
q = (char []){ "tralala3" }; |
printf("q4=%s\n", q); |
#ifdef ALL_ISOC99 |
p = (int []){1, 2, cinit1 + 3}; |
for(i=0;i<3;i++) |
printf(" %d", p[i]); |
printf("\n"); |
for(i=0;i<3;i++) { |
p = (int []){1, 2, 4 + i}; |
printf("%d %d %d\n", |
p[0], |
p[1], |
p[2]); |
} |
#endif |
} |
/* K & R protos */ |
kr_func1(a, b) |
{ |
return a + b; |
} |
int kr_func2(a, b) |
{ |
return a + b; |
} |
kr_test() |
{ |
printf("kr_test:\n"); |
printf("func1=%d\n", kr_func1(3, 4)); |
printf("func2=%d\n", kr_func2(3, 4)); |
return 0; |
} |
void num(int n) |
{ |
char *tab, *p; |
tab = (char*)malloc(20); |
p = tab; |
while (1) { |
*p = 48 + (n % 10); |
p++; |
n = n / 10; |
if (n == 0) |
break; |
} |
while (p != tab) { |
p--; |
printf("%c", *p); |
} |
printf("\n"); |
} |
/* structure assignment tests */ |
struct structa1 { |
int f1; |
char f2; |
}; |
struct structa1 ssta1; |
void struct_assign_test1(struct structa1 s1, int t) |
{ |
printf("%d %d %d\n", s1.f1, s1.f2, t); |
} |
struct structa1 struct_assign_test2(struct structa1 s1, int t) |
{ |
s1.f1 += t; |
s1.f2 -= t; |
return s1; |
} |
void struct_assign_test(void) |
{ |
struct structa1 lsta1, lsta2; |
#if 0 |
printf("struct_assign_test:\n"); |
lsta1.f1 = 1; |
lsta1.f2 = 2; |
printf("%d %d\n", lsta1.f1, lsta1.f2); |
lsta2 = lsta1; |
printf("%d %d\n", lsta2.f1, lsta2.f2); |
#else |
lsta2.f1 = 1; |
lsta2.f2 = 2; |
#endif |
struct_assign_test1(lsta2, 3); |
printf("before call: %d %d\n", lsta2.f1, lsta2.f2); |
lsta2 = struct_assign_test2(lsta2, 4); |
printf("after call: %d %d\n", lsta2.f1, lsta2.f2); |
} |
/* casts to short/char */ |
void cast1(char a, short b, unsigned char c, unsigned short d) |
{ |
printf("%d %d %d %d\n", a, b, c, d); |
} |
char bcast; |
short scast; |
void cast_test() |
{ |
int a; |
char c; |
char tab[10]; |
printf("cast_test:\n"); |
a = 0xfffff; |
cast1(a, a, a, a); |
a = 0xffffe; |
printf("%d %d %d %d\n", |
(char)(a + 1), |
(short)(a + 1), |
(unsigned char)(a + 1), |
(unsigned short)(a + 1)); |
printf("%d %d %d %d\n", |
(char)0xfffff, |
(short)0xfffff, |
(unsigned char)0xfffff, |
(unsigned short)0xfffff); |
a = (bcast = 128) + 1; |
printf("%d\n", a); |
a = (scast = 65536) + 1; |
printf("%d\n", a); |
printf("sizeof(c) = %d, sizeof((int)c) = %d\n", sizeof(c), sizeof((int)c)); |
/* test implicit int casting for array accesses */ |
c = 0; |
tab[1] = 2; |
tab[c] = 1; |
printf("%d %d\n", tab[0], tab[1]); |
/* test implicit casting on some operators */ |
printf("sizeof(+(char)'a') = %d\n", sizeof(+(char)'a')); |
printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a')); |
printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a')); |
} |
/* initializers tests */ |
struct structinit1 { |
int f1; |
char f2; |
short f3; |
int farray[3]; |
}; |
int sinit1 = 2; |
int sinit2 = { 3 }; |
int sinit3[3] = { 1, 2, {{3}}, }; |
int sinit4[3][2] = { {1, 2}, {3, 4}, {5, 6} }; |
int sinit5[3][2] = { 1, 2, 3, 4, 5, 6 }; |
int sinit6[] = { 1, 2, 3 }; |
int sinit7[] = { [2] = 3, [0] = 1, 2 }; |
char sinit8[] = "hello" "trala"; |
struct structinit1 sinit9 = { 1, 2, 3 }; |
struct structinit1 sinit10 = { .f2 = 2, 3, .f1 = 1 }; |
struct structinit1 sinit11 = { .f2 = 2, 3, .f1 = 1, |
#ifdef ALL_ISOC99 |
.farray[0] = 10, |
.farray[1] = 11, |
.farray[2] = 12, |
#endif |
}; |
char *sinit12 = "hello world"; |
char *sinit13[] = { |
"test1", |
"test2", |
"test3", |
}; |
char sinit14[10] = { "abc" }; |
int sinit15[3] = { sizeof(sinit15), 1, 2 }; |
struct { int a[3], b; } sinit16[] = { { 1 }, 2 }; |
struct bar { |
char *s; |
int len; |
} sinit17[] = { |
"a1", 4, |
"a2", 1 |
}; |
int sinit18[10] = { |
[2 ... 5] = 20, |
2, |
[8] = 10, |
}; |
void init_test(void) |
{ |
int linit1 = 2; |
int linit2 = { 3 }; |
int linit4[3][2] = { {1, 2}, {3, 4}, {5, 6} }; |
int linit6[] = { 1, 2, 3 }; |
int i, j; |
char linit8[] = "hello" "trala"; |
int linit12[10] = { 1, 2 }; |
int linit13[10] = { 1, 2, [7] = 3, [3] = 4, }; |
char linit14[10] = "abc"; |
int linit15[10] = { linit1, linit1 + 1, [6] = linit1 + 2, }; |
struct linit16 { int a1, a2, a3, a4; } linit16 = { 1, .a3 = 2 }; |
int linit17 = sizeof(linit17); |
printf("init_test:\n"); |
printf("sinit1=%d\n", sinit1); |
printf("sinit2=%d\n", sinit2); |
printf("sinit3=%d %d %d %d\n", |
sizeof(sinit3), |
sinit3[0], |
sinit3[1], |
sinit3[2] |
); |
printf("sinit6=%d\n", sizeof(sinit6)); |
printf("sinit7=%d %d %d %d\n", |
sizeof(sinit7), |
sinit7[0], |
sinit7[1], |
sinit7[2] |
); |
printf("sinit8=%s\n", sinit8); |
printf("sinit9=%d %d %d\n", |
sinit9.f1, |
sinit9.f2, |
sinit9.f3 |
); |
printf("sinit10=%d %d %d\n", |
sinit10.f1, |
sinit10.f2, |
sinit10.f3 |
); |
printf("sinit11=%d %d %d %d %d %d\n", |
sinit11.f1, |
sinit11.f2, |
sinit11.f3, |
sinit11.farray[0], |
sinit11.farray[1], |
sinit11.farray[2] |
); |
for(i=0;i<3;i++) |
for(j=0;j<2;j++) |
printf("[%d][%d] = %d %d %d\n", |
i, j, sinit4[i][j], sinit5[i][j], linit4[i][j]); |
printf("linit1=%d\n", linit1); |
printf("linit2=%d\n", linit2); |
printf("linit6=%d\n", sizeof(linit6)); |
printf("linit8=%d %s\n", sizeof(linit8), linit8); |
printf("sinit12=%s\n", sinit12); |
printf("sinit13=%d %s %s %s\n", |
sizeof(sinit13), |
sinit13[0], |
sinit13[1], |
sinit13[2]); |
printf("sinit14=%s\n", sinit14); |
for(i=0;i<10;i++) printf(" %d", linit12[i]); |
printf("\n"); |
for(i=0;i<10;i++) printf(" %d", linit13[i]); |
printf("\n"); |
for(i=0;i<10;i++) printf(" %d", linit14[i]); |
printf("\n"); |
for(i=0;i<10;i++) printf(" %d", linit15[i]); |
printf("\n"); |
printf("%d %d %d %d\n", |
linit16.a1, |
linit16.a2, |
linit16.a3, |
linit16.a4); |
/* test that initialisation is done after variable declare */ |
printf("linit17=%d\n", linit17); |
printf("sinit15=%d\n", sinit15[0]); |
printf("sinit16=%d %d\n", sinit16[0].a[0], sinit16[1].a[0]); |
printf("sinit17=%s %d %s %d\n", |
sinit17[0].s, sinit17[0].len, |
sinit17[1].s, sinit17[1].len); |
for(i=0;i<10;i++) |
printf("%x ", sinit18[i]); |
printf("\n"); |
} |
void switch_test() |
{ |
int i; |
for(i=0;i<15;i++) { |
switch(i) { |
case 0: |
case 1: |
printf("a"); |
break; |
default: |
printf("%d", i); |
break; |
case 8 ... 12: |
printf("c"); |
break; |
case 3: |
printf("b"); |
break; |
} |
} |
printf("\n"); |
} |
/* ISOC99 _Bool type */ |
void c99_bool_test(void) |
{ |
#ifdef BOOL_ISOC99 |
int a; |
_Bool b; |
printf("bool_test:\n"); |
printf("sizeof(_Bool) = %d\n", sizeof(_Bool)); |
a = 3; |
printf("cast: %d %d %d\n", (_Bool)10, (_Bool)0, (_Bool)a); |
b = 3; |
printf("b = %d\n", b); |
b++; |
printf("b = %d\n", b); |
#endif |
} |
void bitfield_test(void) |
{ |
int a; |
struct sbf1 { |
int f1 : 3; |
int : 2; |
int f2 : 1; |
int : 0; |
int f3 : 5; |
int f4 : 7; |
unsigned int f5 : 7; |
} st1; |
printf("bitfield_test:"); |
printf("sizeof(st1) = %d\n", sizeof(st1)); |
st1.f1 = 3; |
st1.f2 = 1; |
st1.f3 = 15; |
a = 120; |
st1.f4 = a; |
st1.f5 = a; |
st1.f5++; |
printf("%d %d %d %d %d\n", |
st1.f1, st1.f2, st1.f3, st1.f4, st1.f5); |
st1.f1 = 7; |
if (st1.f1 == -1) |
printf("st1.f1 == -1\n"); |
else |
printf("st1.f1 != -1\n"); |
if (st1.f2 == -1) |
printf("st1.f2 == -1\n"); |
else |
printf("st1.f2 != -1\n"); |
} |
#define FTEST(prefix, type, fmt)\ |
void prefix ## cmp(type a, type b)\ |
{\ |
printf("%d %d %d %d %d %d\n",\ |
a == b,\ |
a != b,\ |
a < b,\ |
a > b,\ |
a >= b,\ |
a <= b);\ |
printf(fmt " " fmt " " fmt " " fmt " " fmt " " fmt " " fmt "\n",\ |
a,\ |
b,\ |
a + b,\ |
a - b,\ |
a * b,\ |
a / b,\ |
-a);\ |
printf(fmt "\n", ++a);\ |
printf(fmt "\n", a++);\ |
printf(fmt "\n", a);\ |
}\ |
void prefix ## fcast(type a)\ |
{\ |
float fa;\ |
double da;\ |
long double la;\ |
int ia;\ |
unsigned int ua;\ |
type b;\ |
fa = a;\ |
da = a;\ |
la = a;\ |
printf("ftof: %f %f %Lf\n", fa, da, la);\ |
ia = (int)a;\ |
ua = (unsigned int)a;\ |
printf("ftoi: %d %u\n", ia, ua);\ |
ia = -1234;\ |
ua = 0x81234500;\ |
b = ia;\ |
printf("itof: " fmt "\n", b);\ |
b = ua;\ |
printf("utof: " fmt "\n", b);\ |
}\ |
\ |
void prefix ## test(void)\ |
{\ |
printf("testing '%s'\n", #type);\ |
prefix ## cmp(1, 2.5);\ |
prefix ## cmp(2, 1.5);\ |
prefix ## cmp(1, 1);\ |
prefix ## fcast(234.6);\ |
prefix ## fcast(-2334.6);\ |
} |
FTEST(f, float, "%f") |
FTEST(d, double, "%f") |
FTEST(ld, long double, "%Lf") |
double ftab1[3] = { 1.2, 3.4, -5.6 }; |
void float_test(void) |
{ |
float fa, fb; |
double da, db; |
int a; |
unsigned int b; |
printf("float_test:\n"); |
printf("sizeof(float) = %d\n", sizeof(float)); |
printf("sizeof(double) = %d\n", sizeof(double)); |
printf("sizeof(long double) = %d\n", sizeof(long double)); |
ftest(); |
dtest(); |
ldtest(); |
printf("%f %f %f\n", ftab1[0], ftab1[1], ftab1[2]); |
printf("%f %f %f\n", 2.12, .5, 2.3e10); |
// printf("%f %f %f\n", 0x1234p12, 0x1e23.23p10, 0x12dp-10); |
da = 123; |
printf("da=%f\n", da); |
fa = 123; |
printf("fa=%f\n", fa); |
a = 4000000000; |
da = a; |
printf("da = %f\n", da); |
b = 4000000000; |
db = b; |
printf("db = %f\n", db); |
} |
int fib(int n) |
{ |
if (n <= 2) |
return 1; |
else |
return fib(n-1) + fib(n-2); |
} |
void funcptr_test() |
{ |
void (*func)(int); |
int a; |
struct { |
int dummy; |
void (*func)(int); |
} st1; |
printf("funcptr:\n"); |
func = # |
(*func)(12345); |
func = num; |
a = 1; |
a = 1; |
func(12345); |
/* more complicated pointer computation */ |
st1.func = num; |
st1.func(12346); |
printf("sizeof1 = %d\n", sizeof(funcptr_test)); |
printf("sizeof2 = %d\n", sizeof funcptr_test); |
printf("sizeof3 = %d\n", sizeof(&funcptr_test)); |
printf("sizeof4 = %d\n", sizeof &funcptr_test); |
} |
void lloptest(long long a, long long b) |
{ |
unsigned long long ua, ub; |
ua = a; |
ub = b; |
/* arith */ |
printf("arith: %Ld %Ld %Ld\n", |
a + b, |
a - b, |
a * b); |
if (b != 0) { |
printf("arith1: %Ld %Ld\n", |
a / b, |
a % b); |
} |
/* binary */ |
printf("bin: %Ld %Ld %Ld\n", |
a & b, |
a | b, |
a ^ b); |
/* tests */ |
printf("test: %d %d %d %d %d %d\n", |
a == b, |
a != b, |
a < b, |
a > b, |
a >= b, |
a <= b); |
printf("utest: %d %d %d %d %d %d\n", |
ua == ub, |
ua != ub, |
ua < ub, |
ua > ub, |
ua >= ub, |
ua <= ub); |
/* arith2 */ |
a++; |
b++; |
printf("arith2: %Ld %Ld\n", a, b); |
printf("arith2: %Ld %Ld\n", a++, b++); |
printf("arith2: %Ld %Ld\n", --a, --b); |
printf("arith2: %Ld %Ld\n", a, b); |
} |
void llshift(long long a, int b) |
{ |
printf("shift: %Ld %Ld %Ld\n", |
(unsigned long long)a >> b, |
a >> b, |
a << b); |
printf("shiftc: %Ld %Ld %Ld\n", |
(unsigned long long)a >> 3, |
a >> 3, |
a << 3); |
printf("shiftc: %Ld %Ld %Ld\n", |
(unsigned long long)a >> 35, |
a >> 35, |
a << 35); |
} |
void llfloat(void) |
{ |
float fa; |
double da; |
long double lda; |
long long la, lb, lc; |
unsigned long long ula, ulb, ulc; |
la = 0x12345678; |
ula = 0x72345678; |
la = (la << 20) | 0x12345; |
ula = ula << 33; |
printf("la=%Ld ula=%Lu\n", la, ula); |
fa = la; |
da = la; |
lda = la; |
printf("lltof: %f %f %Lf\n", fa, da, lda); |
la = fa; |
lb = da; |
lc = lda; |
printf("ftoll: %Ld %Ld %Ld\n", la, lb, lc); |
fa = ula; |
da = ula; |
lda = ula; |
printf("ulltof: %f %f %Lf\n", fa, da, lda); |
ula = fa; |
ulb = da; |
ulc = lda; |
printf("ftoull: %Lu %Lu %Lu\n", ula, ulb, ulc); |
} |
long long llfunc1(int a) |
{ |
return a * 2; |
} |
struct S { |
int id; |
char item; |
}; |
long long int value(struct S *v) |
{ |
return ((long long int)v->item); |
} |
void longlong_test(void) |
{ |
long long a, b, c; |
int ia; |
unsigned int ua; |
printf("longlong_test:\n"); |
printf("sizeof(long long) = %d\n", sizeof(long long)); |
ia = -1; |
ua = -2; |
a = ia; |
b = ua; |
printf("%Ld %Ld\n", a, b); |
printf("%Ld %Ld %Ld %Lx\n", |
(long long)1, |
(long long)-2, |
1LL, |
0x1234567812345679); |
a = llfunc1(-3); |
printf("%Ld\n", a); |
lloptest(1000, 23); |
lloptest(0xff, 0x1234); |
b = 0x72345678 << 10; |
lloptest(-3, b); |
llshift(0x123, 5); |
llshift(-23, 5); |
b = 0x72345678LL << 10; |
llshift(b, 47); |
llfloat(); |
#if 1 |
b = 0x12345678; |
a = -1; |
c = a + b; |
printf("%Lx\n", c); |
#endif |
/* long long reg spill test */ |
{ |
struct S a; |
a.item = 3; |
printf("%lld\n", value(&a)); |
} |
lloptest(0x80000000, 0); |
/* another long long spill test */ |
{ |
long long *p, v; |
v = 1; |
p = &v; |
p[0]++; |
printf("%lld\n", *p); |
} |
} |
void vprintf1(const char *fmt, ...) |
{ |
va_list ap; |
const char *p; |
int c, i; |
double d; |
long long ll; |
va_start(ap, fmt); |
p = fmt; |
for(;;) { |
c = *p; |
if (c == '\0') |
break; |
p++; |
if (c == '%') { |
c = *p; |
switch(c) { |
case '\0': |
goto the_end; |
case 'd': |
i = va_arg(ap, int); |
printf("%d", i); |
break; |
case 'f': |
d = va_arg(ap, double); |
printf("%f", d); |
break; |
case 'l': |
ll = va_arg(ap, long long); |
printf("%Ld", ll); |
break; |
} |
p++; |
} else { |
putchar(c); |
} |
} |
the_end: |
va_end(ap); |
} |
void stdarg_test(void) |
{ |
vprintf1("%d %d %d\n", 1, 2, 3); |
vprintf1("%f %d %f\n", 1.0, 2, 3.0); |
vprintf1("%l %l %d %f\n", 1234567891234LL, 987654321986LL, 3, 1234.0); |
} |
void whitespace_test(void) |
{ |
char *str; |
#if 1 |
pri\ |
ntf("whitspace:\n"); |
#endif |
pf("N=%d\n", 2); |
#ifdef CORRECT_CR_HANDLING |
pri\ |
ntf("aaa=%d\n", 3); |
#endif |
pri\ |
\ |
ntf("min=%d\n", 4); |
#ifdef ACCEPT_CR_IN_STRINGS |
printf("len1=%d\n", strlen(" |
")); |
#ifdef CORRECT_CR_HANDLING |
str = " |
"; |
printf("len1=%d str[0]=%d\n", strlen(str), str[0]); |
#endif |
printf("len1=%d\n", strlen(" |
a |
")); |
#endif /* ACCEPT_CR_IN_STRINGS */ |
} |
int reltab[3] = { 1, 2, 3 }; |
int *rel1 = &reltab[1]; |
int *rel2 = &reltab[2]; |
void relocation_test(void) |
{ |
printf("*rel1=%d\n", *rel1); |
printf("*rel2=%d\n", *rel2); |
} |
void old_style_f(a,b,c) |
int a, b; |
double c; |
{ |
printf("a=%d b=%d b=%f\n", a, b, c); |
} |
void decl_func1(int cmpfn()) |
{ |
printf("cmpfn=%lx\n", (long)cmpfn); |
} |
void decl_func2(cmpfn) |
int cmpfn(); |
{ |
printf("cmpfn=%lx\n", (long)cmpfn); |
} |
void old_style_function(void) |
{ |
old_style_f((void *)1, 2, 3.0); |
decl_func1(NULL); |
decl_func2(NULL); |
} |
void sizeof_test(void) |
{ |
int a; |
int **ptr; |
printf("sizeof(int) = %d\n", sizeof(int)); |
printf("sizeof(unsigned int) = %d\n", sizeof(unsigned int)); |
printf("sizeof(short) = %d\n", sizeof(short)); |
printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short)); |
printf("sizeof(char) = %d\n", sizeof(char)); |
printf("sizeof(unsigned char) = %d\n", sizeof(unsigned char)); |
printf("sizeof(func) = %d\n", sizeof sizeof_test()); |
a = 1; |
printf("sizeof(a++) = %d\n", sizeof a++); |
printf("a=%d\n", a); |
ptr = NULL; |
printf("sizeof(**ptr) = %d\n", sizeof (**ptr)); |
/* some alignof tests */ |
printf("__alignof__(int) = %d\n", __alignof__(int)); |
printf("__alignof__(unsigned int) = %d\n", __alignof__(unsigned int)); |
printf("__alignof__(short) = %d\n", __alignof__(short)); |
printf("__alignof__(unsigned short) = %d\n", __alignof__(unsigned short)); |
printf("__alignof__(char) = %d\n", __alignof__(char)); |
printf("__alignof__(unsigned char) = %d\n", __alignof__(unsigned char)); |
printf("__alignof__(func) = %d\n", __alignof__ sizeof_test()); |
} |
void typeof_test(void) |
{ |
double a; |
typeof(a) b; |
typeof(float) c; |
a = 1.5; |
b = 2.5; |
c = 3.5; |
printf("a=%f b=%f c=%f\n", a, b, c); |
} |
void statement_expr_test(void) |
{ |
int a, i; |
a = 0; |
for(i=0;i<10;i++) { |
a += 1 + |
( { int b, j; |
b = 0; |
for(j=0;j<5;j++) |
b += j; b; |
} ); |
} |
printf("a=%d\n", a); |
} |
void local_label_test(void) |
{ |
int a; |
goto l1; |
l2: |
a = 1 + ({ |
__label__ l1, l2, l3; |
goto l4; |
l5: |
printf("aa1\n"); |
goto l1; |
l2: |
printf("aa3\n"); |
goto l3; |
l1: |
printf("aa2\n"); |
goto l2; |
l3:; |
1; |
}); |
printf("a=%d\n", a); |
return; |
l1: |
printf("bb1\n"); |
goto l2; |
l4: |
printf("bb2\n"); |
goto l5; |
} |
/* inline assembler test */ |
#ifdef __i386__ |
/* from linux kernel */ |
static char * strncat1(char * dest,const char * src,size_t count) |
{ |
int d0, d1, d2, d3; |
__asm__ __volatile__( |
"repne\n\t" |
"scasb\n\t" |
"decl %1\n\t" |
"movl %8,%3\n" |
"1:\tdecl %3\n\t" |
"js 2f\n\t" |
"lodsb\n\t" |
"stosb\n\t" |
"testb %%al,%%al\n\t" |
"jne 1b\n" |
"2:\txorl %2,%2\n\t" |
"stosb" |
: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) |
: "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count) |
: "memory"); |
return dest; |
} |
static inline void * memcpy1(void * to, const void * from, size_t n) |
{ |
int d0, d1, d2; |
__asm__ __volatile__( |
"rep ; movsl\n\t" |
"testb $2,%b4\n\t" |
"je 1f\n\t" |
"movsw\n" |
"1:\ttestb $1,%b4\n\t" |
"je 2f\n\t" |
"movsb\n" |
"2:" |
: "=&c" (d0), "=&D" (d1), "=&S" (d2) |
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) |
: "memory"); |
return (to); |
} |
static __inline__ void sigaddset1(unsigned int *set, int _sig) |
{ |
__asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); |
} |
static __inline__ void sigdelset1(unsigned int *set, int _sig) |
{ |
asm("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc"); |
} |
static __inline__ __const__ unsigned int swab32(unsigned int x) |
{ |
__asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ |
"rorl $16,%0\n\t" /* swap words */ |
"xchgb %b0,%h0" /* swap higher bytes */ |
:"=q" (x) |
: "0" (x)); |
return x; |
} |
static __inline__ unsigned long long mul64(unsigned int a, unsigned int b) |
{ |
unsigned long long res; |
__asm__("mull %2" : "=A" (res) : "a" (a), "r" (b)); |
return res; |
} |
static __inline__ unsigned long long inc64(unsigned long long a) |
{ |
unsigned long long res; |
__asm__("addl $1, %%eax ; adcl $0, %%edx" : "=A" (res) : "A" (a)); |
return res; |
} |
unsigned int set; |
void asm_test(void) |
{ |
char buf[128]; |
unsigned int val; |
printf("inline asm:\n"); |
/* test the no operand case */ |
asm volatile ("xorl %eax, %eax"); |
memcpy1(buf, "hello", 6); |
strncat1(buf, " worldXXXXX", 3); |
printf("%s\n", buf); |
/* 'A' constraint test */ |
printf("mul64=0x%Lx\n", mul64(0x12345678, 0xabcd1234)); |
printf("inc64=0x%Lx\n", inc64(0x12345678ffffffff)); |
set = 0xff; |
sigdelset1(&set, 2); |
sigaddset1(&set, 16); |
/* NOTE: we test here if C labels are correctly restored after the |
asm statement */ |
goto label1; |
label2: |
__asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc"); |
printf("set=0x%x\n", set); |
val = 0x01020304; |
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val)); |
return; |
label1: |
goto label2; |
} |
#else |
void asm_test(void) |
{ |
} |
#endif |
#define COMPAT_TYPE(type1, type2) \ |
{\ |
printf("__builtin_types_compatible_p(%s, %s) = %d\n", #type1, #type2, \ |
__builtin_types_compatible_p (type1, type2));\ |
} |
int constant_p_var; |
void builtin_test(void) |
{ |
#if GCC_MAJOR >= 3 |
COMPAT_TYPE(int, int); |
COMPAT_TYPE(int, unsigned int); |
COMPAT_TYPE(int, char); |
COMPAT_TYPE(int, const int); |
COMPAT_TYPE(int, volatile int); |
COMPAT_TYPE(int *, int *); |
COMPAT_TYPE(int *, void *); |
COMPAT_TYPE(int *, const int *); |
COMPAT_TYPE(char *, unsigned char *); |
/* space is needed because tcc preprocessor introduces a space between each token */ |
COMPAT_TYPE(char * *, void *); |
#endif |
printf("res = %d\n", __builtin_constant_p(1)); |
printf("res = %d\n", __builtin_constant_p(1 + 2)); |
printf("res = %d\n", __builtin_constant_p(&constant_p_var)); |
printf("res = %d\n", __builtin_constant_p(constant_p_var)); |
} |
void const_func(const int a) |
{ |
} |
void const_warn_test(void) |
{ |
const_func(1); |
} |
/programs/develop/ktcc/trunk/source/VERSION |
---|
1,0 → 0,0 |
0.9.26 |
0.9.23 |
/programs/develop/ktcc/trunk/source/arm-gen.c |
---|
1,8 → 1,7 |
/* |
* ARMv4 code generator for TCC |
* |
* Copyright (c) 2003 Daniel Glöckner |
* Copyright (c) 2012 Thomas Preud'homme |
* Copyright (c) 2003 Daniel Glöckner |
* |
* Based on i386-gen.c by Fabrice Bellard |
* |
21,23 → 20,9 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
*/ |
#ifdef TARGET_DEFS_ONLY |
#if defined(TCC_ARM_EABI) && !defined(TCC_ARM_VFP) |
#error "Currently TinyCC only supports float computation with VFP instructions" |
#endif |
/* number of available registers */ |
#ifdef TCC_ARM_VFP |
#define NB_REGS 13 |
#else |
#define NB_REGS 9 |
#endif |
#ifndef TCC_ARM_VERSION |
# define TCC_ARM_VERSION 5 |
#endif |
/* a register can belong to several classes. The classes must be |
sorted from more general to more precise (see gv2() code which does |
assumptions on it). */ |
52,12 → 37,6 |
#define RC_F1 0x0100 |
#define RC_F2 0x0200 |
#define RC_F3 0x0400 |
#ifdef TCC_ARM_VFP |
#define RC_F4 0x0800 |
#define RC_F5 0x1000 |
#define RC_F6 0x2000 |
#define RC_F7 0x4000 |
#endif |
#define RC_IRET RC_R0 /* function return: integer register */ |
#define RC_LRET RC_R1 /* function return: second integer register */ |
#define RC_FRET RC_F0 /* function return: float register */ |
73,55 → 52,46 |
TREG_F1, |
TREG_F2, |
TREG_F3, |
#ifdef TCC_ARM_VFP |
TREG_F4, |
TREG_F5, |
TREG_F6, |
TREG_F7, |
#endif |
}; |
#ifdef TCC_ARM_VFP |
#define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0) |
#endif |
int reg_classes[NB_REGS] = { |
/* r0 */ RC_INT | RC_R0, |
/* r1 */ RC_INT | RC_R1, |
/* r2 */ RC_INT | RC_R2, |
/* r3 */ RC_INT | RC_R3, |
/* r12 */ RC_INT | RC_R12, |
/* f0 */ RC_FLOAT | RC_F0, |
/* f1 */ RC_FLOAT | RC_F1, |
/* f2 */ RC_FLOAT | RC_F2, |
/* f3 */ RC_FLOAT | RC_F3, |
}; |
static int two2mask(int a,int b) { |
return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT); |
} |
static int regmask(int r) { |
return reg_classes[r]&~(RC_INT|RC_FLOAT); |
} |
/* return registers for function */ |
#define REG_IRET TREG_R0 /* single word int return register */ |
#define REG_LRET TREG_R1 /* second word return register (for long long) */ |
#define REG_FRET TREG_F0 /* float return register */ |
#ifdef TCC_ARM_EABI |
#define TOK___divdi3 TOK___aeabi_ldivmod |
#define TOK___moddi3 TOK___aeabi_ldivmod |
#define TOK___udivdi3 TOK___aeabi_uldivmod |
#define TOK___umoddi3 TOK___aeabi_uldivmod |
#endif |
/* defined if function parameters must be evaluated in reverse order */ |
#define INVERT_FUNC_PARAMS |
/* defined if structures are passed as pointers. Otherwise structures |
are directly pushed on stack. */ |
/* #define FUNC_STRUCT_PARAM_AS_PTR */ |
//#define FUNC_STRUCT_PARAM_AS_PTR |
/* pointer size, in bytes */ |
#define PTR_SIZE 4 |
/* long double size and alignment, in bytes */ |
#ifdef TCC_ARM_VFP |
#define LDOUBLE_SIZE 8 |
#endif |
#ifndef LDOUBLE_SIZE |
#define LDOUBLE_SIZE 8 |
#endif |
#ifdef TCC_ARM_EABI |
#define LDOUBLE_ALIGN 8 |
#else |
#define LDOUBLE_ALIGN 4 |
#endif |
/* maximum alignment (for aligned attribute support) */ |
#define MAX_ALIGN 8 |
134,7 → 104,6 |
/* relocation type for 32 bit data relocation */ |
#define R_DATA_32 R_ARM_ABS32 |
#define R_DATA_PTR R_ARM_ABS32 |
#define R_JMP_SLOT R_ARM_JUMP_SLOT |
#define R_COPY R_ARM_COPY |
141,100 → 110,17 |
#define ELF_START_ADDR 0x00008000 |
#define ELF_PAGE_SIZE 0x1000 |
enum float_abi { |
ARM_SOFTFP_FLOAT, |
ARM_HARD_FLOAT, |
}; |
/******************************************************/ |
#else /* ! TARGET_DEFS_ONLY */ |
/******************************************************/ |
#include "tcc.h" |
static unsigned long func_sub_sp_offset,last_itod_magic; |
enum float_abi float_abi; |
ST_DATA const int reg_classes[NB_REGS] = { |
/* r0 */ RC_INT | RC_R0, |
/* r1 */ RC_INT | RC_R1, |
/* r2 */ RC_INT | RC_R2, |
/* r3 */ RC_INT | RC_R3, |
/* r12 */ RC_INT | RC_R12, |
/* f0 */ RC_FLOAT | RC_F0, |
/* f1 */ RC_FLOAT | RC_F1, |
/* f2 */ RC_FLOAT | RC_F2, |
/* f3 */ RC_FLOAT | RC_F3, |
#ifdef TCC_ARM_VFP |
/* d4/s8 */ RC_FLOAT | RC_F4, |
/* d5/s10 */ RC_FLOAT | RC_F5, |
/* d6/s12 */ RC_FLOAT | RC_F6, |
/* d7/s14 */ RC_FLOAT | RC_F7, |
#endif |
}; |
static int func_sub_sp_offset, last_itod_magic; |
static int leaffunc; |
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) |
static CType float_type, double_type, func_float_type, func_double_type; |
ST_FUNC void arm_init(struct TCCState *s) |
void o(unsigned long i) |
{ |
float_type.t = VT_FLOAT; |
double_type.t = VT_DOUBLE; |
func_float_type.t = VT_FUNC; |
func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD); |
func_double_type.t = VT_FUNC; |
func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD); |
float_abi = s->float_abi; |
#ifndef TCC_ARM_HARDFLOAT |
tcc_warning("soft float ABI currently not supported: default to softfp"); |
#endif |
} |
#else |
#define func_float_type func_old_type |
#define func_double_type func_old_type |
#define func_ldouble_type func_old_type |
ST_FUNC void arm_init(struct TCCState *s) |
{ |
#if !defined (TCC_ARM_VFP) |
tcc_warning("Support for FPA is deprecated and will be removed in next" |
" release"); |
#endif |
#if !defined (TCC_ARM_EABI) |
tcc_warning("Support for OABI is deprecated and will be removed in next" |
" release"); |
#endif |
} |
#endif |
static int two2mask(int a,int b) { |
return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT); |
} |
static int regmask(int r) { |
return reg_classes[r]&~(RC_INT|RC_FLOAT); |
} |
/******************************************************/ |
#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP) |
char *default_elfinterp(struct TCCState *s) |
{ |
if (s->float_abi == ARM_HARD_FLOAT) |
return "/lib/ld-linux-armhf.so.3"; |
else |
return "/lib/ld-linux.so.3"; |
} |
#endif |
void o(uint32_t i) |
{ |
/* this is a good place to start adding big-endian support*/ |
int ind1; |
ind1 = ind + 4; |
if (!cur_text_section) |
tcc_error("compiler error! This happens f.ex. if the compiler\n" |
error("compiler error! This happens f.ex. if the compiler\n" |
"can't evaluate constant expressions outside of a function."); |
if (ind1 > cur_text_section->data_allocated) |
section_realloc(cur_text_section, ind1); |
247,10 → 133,10 |
cur_text_section->data[ind++] = i; |
} |
static uint32_t stuff_const(uint32_t op, uint32_t c) |
static unsigned long stuff_const(unsigned long op,unsigned long c) |
{ |
int try_neg=0; |
uint32_t nc = 0, negop = 0; |
unsigned long nc = 0,negop = 0; |
switch(op&0x1F00000) |
{ |
284,7 → 170,7 |
break; |
} |
do { |
uint32_t m; |
unsigned long m; |
int i; |
if(c<256) /* catch undefined <<32 */ |
return op|c; |
301,13 → 187,13 |
//only add,sub |
void stuff_const_harder(uint32_t op, uint32_t v) { |
uint32_t x; |
void stuff_const_harder(unsigned long op,unsigned long v) { |
unsigned long x; |
x=stuff_const(op,v); |
if(x) |
o(x); |
else { |
uint32_t a[16], nv, no, o2, n2; |
unsigned long a[16],nv,no,o2,n2; |
int i,j,k; |
a[0]=0xff; |
o2=(op&0xfff0ffff)|((op&0xf000)<<4);; |
314,7 → 200,7 |
for(i=1;i<16;i++) |
a[i]=(a[i-1]>>2)|(a[i-1]<<30); |
for(i=0;i<12;i++) |
for(j=i<4?i+12:15;j>=i+4;j--) |
for(j=i+4;i<13+i;i++) |
if((v&(a[i]|a[j]))==v) { |
o(stuff_const(op,v&a[i])); |
o(stuff_const(o2,v&a[j])); |
324,7 → 210,7 |
n2=o2^0xC00000; |
nv=-v; |
for(i=0;i<12;i++) |
for(j=i<4?i+12:15;j>=i+4;j--) |
for(j=i+4;i<13+i;i++) |
if((nv&(a[i]|a[j]))==nv) { |
o(stuff_const(no,nv&a[i])); |
o(stuff_const(n2,nv&a[j])); |
331,8 → 217,8 |
return; |
} |
for(i=0;i<8;i++) |
for(j=i+4;j<12;j++) |
for(k=i<4?i+12:15;k>=j+4;k--) |
for(j=i+4;i<12;i++) |
for(k=j+4;k<13+i;i++) |
if((v&(a[i]|a[j]|a[k]))==v) { |
o(stuff_const(op,v&a[i])); |
o(stuff_const(o2,v&a[j])); |
342,8 → 228,8 |
no=op^0xC00000; |
nv=-v; |
for(i=0;i<8;i++) |
for(j=i+4;j<12;j++) |
for(k=i<4?i+12:15;k>=j+4;k--) |
for(j=i+4;i<12;i++) |
for(k=j+4;k<13+i;i++) |
if((nv&(a[i]|a[j]|a[k]))==nv) { |
o(stuff_const(no,nv&a[i])); |
o(stuff_const(n2,nv&a[j])); |
357,13 → 243,13 |
} |
} |
ST_FUNC uint32_t encbranch(int pos, int addr, int fail) |
unsigned long encbranch(int pos,int addr,int fail) |
{ |
addr-=pos+8; |
addr/=4; |
if(addr>=0x1000000 || addr<-0x1000000) { |
if(fail) |
tcc_error("FIXME: function bigger than 32MB"); |
error("FIXME: function bigger than 32MB"); |
return 0; |
} |
return 0x0A000000|(addr&0xffffff); |
372,7 → 258,7 |
int decbranch(int pos) |
{ |
int x; |
x=*(uint32_t *)(cur_text_section->data + pos); |
x=*(int *)(cur_text_section->data + pos); |
x&=0x00ffffff; |
if(x&0x800000) |
x-=0x1000000; |
382,10 → 268,10 |
/* output a symbol and patch all calls to it */ |
void gsym_addr(int t, int a) |
{ |
uint32_t *x; |
unsigned long *x; |
int lt; |
while(t) { |
x=(uint32_t *)(cur_text_section->data + t); |
x=(unsigned long *)(cur_text_section->data + t); |
t=decbranch(lt=t); |
if(a==lt+4) |
*x=0xE1A00000; // nop |
401,35 → 287,26 |
gsym_addr(t, ind); |
} |
#ifdef TCC_ARM_VFP |
static uint32_t vfpr(int r) |
static unsigned long fpr(int r) |
{ |
if(r<TREG_F0 || r>TREG_F7) |
tcc_error("compiler error! register %i is no vfp register",r); |
return r-5; |
} |
#else |
static uint32_t fpr(int r) |
{ |
if(r<TREG_F0 || r>TREG_F3) |
tcc_error("compiler error! register %i is no fpa register",r); |
error("compiler error! register %i is no fp register\n",r); |
return r-5; |
} |
#endif |
static uint32_t intr(int r) |
static unsigned long intr(int r) |
{ |
if(r==4) |
return 12; |
if((r<0 || r>4) && r!=14) |
tcc_error("compiler error! register %i is no int register",r); |
error("compiler error! register %i is no int register\n",r); |
return r; |
} |
static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift) |
static void calcaddr(unsigned long *base,int *off,int *sgn,int maxoff,unsigned shift) |
{ |
if(*off>maxoff || *off&((1<<shift)-1)) { |
uint32_t x, y; |
unsigned long x,y; |
x=0xE280E000; |
if(*sgn) |
x=0xE240E000; |
453,37 → 330,33 |
} |
} |
static uint32_t mapcc(int cc) |
static unsigned long mapcc(int cc) |
{ |
switch(cc) |
{ |
case TOK_ULT: |
return 0x30000000; /* CC/LO */ |
return 0x30000000; |
case TOK_UGE: |
return 0x20000000; /* CS/HS */ |
return 0x20000000; |
case TOK_EQ: |
return 0x00000000; /* EQ */ |
return 0x00000000; |
case TOK_NE: |
return 0x10000000; /* NE */ |
return 0x10000000; |
case TOK_ULE: |
return 0x90000000; /* LS */ |
return 0x90000000; |
case TOK_UGT: |
return 0x80000000; /* HI */ |
case TOK_Nset: |
return 0x40000000; /* MI */ |
case TOK_Nclear: |
return 0x50000000; /* PL */ |
return 0x80000000; |
case TOK_LT: |
return 0xB0000000; /* LT */ |
return 0xB0000000; |
case TOK_GE: |
return 0xA0000000; /* GE */ |
return 0xA0000000; |
case TOK_LE: |
return 0xD0000000; /* LE */ |
return 0xD0000000; |
case TOK_GT: |
return 0xC0000000; /* GT */ |
return 0xC0000000; |
} |
tcc_error("unexpected condition code"); |
return 0xE0000000; /* AL */ |
error("unexpected condition code"); |
return 0xE0000000; |
} |
static int negcc(int cc) |
502,10 → 375,6 |
return TOK_UGT; |
case TOK_UGT: |
return TOK_ULE; |
case TOK_Nset: |
return TOK_Nclear; |
case TOK_Nclear: |
return TOK_Nset; |
case TOK_LT: |
return TOK_GE; |
case TOK_GE: |
515,7 → 384,7 |
case TOK_GT: |
return TOK_LE; |
} |
tcc_error("unexpected condition code"); |
error("unexpected condition code"); |
return TOK_NE; |
} |
523,12 → 392,12 |
void load(int r, SValue *sv) |
{ |
int v, ft, fc, fr, sign; |
uint32_t op; |
unsigned long op; |
SValue v1; |
fr = sv->r; |
ft = sv->type.t; |
fc = sv->c.i; |
fc = sv->c.ul; |
if(fc>=0) |
sign=0; |
539,11 → 408,11 |
v = fr & VT_VALMASK; |
if (fr & VT_LVAL) { |
uint32_t base = 0xB; // fp |
unsigned long base=0xB; // fp |
if(v == VT_LLOCAL) { |
v1.type.t = VT_PTR; |
v1.r = VT_LOCAL | VT_LVAL; |
v1.c.i = sv->c.i; |
v1.c.ul = sv->c.ul; |
load(base=14 /* lr */, &v1); |
fc=sign=0; |
v=VT_LOCAL; |
550,7 → 419,7 |
} else if(v == VT_CONST) { |
v1.type.t = VT_PTR; |
v1.r = fr&~VT_LVAL; |
v1.c.i = sv->c.i; |
v1.c.ul = sv->c.ul; |
v1.sym=sv->sym; |
load(base=14, &v1); |
fc=sign=0; |
563,14 → 432,6 |
if(v == VT_LOCAL) { |
if(is_float(ft)) { |
calcaddr(&base,&fc,&sign,1020,2); |
#ifdef TCC_ARM_VFP |
op=0xED100A00; /* flds */ |
if(!sign) |
op|=0x800000; |
if ((ft & VT_BTYPE) != VT_FLOAT) |
op|=0x100; /* flds -> fldd */ |
o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); |
#else |
op=0xED100100; |
if(!sign) |
op|=0x800000; |
584,9 → 445,7 |
op|=0x400000; |
#endif |
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
#endif |
} else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE |
|| (ft & VT_BTYPE) == VT_SHORT) { |
} else if((ft & VT_TYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_SHORT) { |
calcaddr(&base,&fc,&sign,255,0); |
op=0xE1500090; |
if ((ft & VT_BTYPE) == VT_SHORT) |
601,7 → 460,7 |
op=0xE5100000; |
if(!sign) |
op|=0x800000; |
if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) |
if ((ft & VT_BTYPE) == VT_BYTE) |
op|=0x400000; |
o(op|(intr(r)<<12)|fc|(base<<16)); |
} |
609,31 → 468,31 |
} |
} else { |
if (v == VT_CONST) { |
op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.i); |
op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul); |
if (fr & VT_SYM || !op) { |
o(0xE59F0000|(intr(r)<<12)); |
o(0xEA000000); |
if(fr & VT_SYM) |
greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); |
o(sv->c.i); |
o(sv->c.ul); |
} else |
o(op); |
return; |
} else if (v == VT_LOCAL) { |
op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.i); |
op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul); |
if (fr & VT_SYM || !op) { |
o(0xE59F0000|(intr(r)<<12)); |
o(0xEA000000); |
if(fr & VT_SYM) // needed ? |
greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); |
o(sv->c.i); |
o(sv->c.ul); |
o(0xE08B0000|(intr(r)<<12)|intr(r)); |
} else |
o(op); |
return; |
} else if(v == VT_CMP) { |
o(mapcc(sv->c.i)|0x3A00001|(intr(r)<<12)); |
o(mapcc(negcc(sv->c.i))|0x3A00000|(intr(r)<<12)); |
o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12)); |
o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12)); |
return; |
} else if (v == VT_JMP || v == VT_JMPI) { |
int t; |
640,22 → 499,18 |
t = v & 1; |
o(0xE3A00000|(intr(r)<<12)|t); |
o(0xEA000000); |
gsym(sv->c.i); |
gsym(sv->c.ul); |
o(0xE3A00000|(intr(r)<<12)|(t^1)); |
return; |
} else if (v < VT_CONST) { |
if(is_float(ft)) |
#ifdef TCC_ARM_VFP |
o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */ |
#else |
o(0xEE008180|(fpr(r)<<12)|fpr(v)); |
#endif |
else |
o(0xE1A00000|(intr(r)<<12)|intr(v)); |
return; |
} |
} |
tcc_error("load unimplemented!"); |
error("load unimplemented!"); |
} |
/* store register 'r' in lvalue 'v' */ |
663,11 → 518,11 |
{ |
SValue v1; |
int v, ft, fc, fr, sign; |
uint32_t op; |
unsigned long op; |
fr = sv->r; |
ft = sv->type.t; |
fc = sv->c.i; |
fc = sv->c.ul; |
if(fc>=0) |
sign=0; |
678,7 → 533,7 |
v = fr & VT_VALMASK; |
if (fr & VT_LVAL || fr == VT_LOCAL) { |
uint32_t base = 0xb; |
unsigned long base=0xb; |
if(v < VT_CONST) { |
base=intr(v); |
v=VT_LOCAL; |
686,7 → 541,7 |
} else if(v == VT_CONST) { |
v1.type.t = ft; |
v1.r = fr&~VT_LVAL; |
v1.c.i = sv->c.i; |
v1.c.ul = sv->c.ul; |
v1.sym=sv->sym; |
load(base=14, &v1); |
fc=sign=0; |
695,14 → 550,6 |
if(v == VT_LOCAL) { |
if(is_float(ft)) { |
calcaddr(&base,&fc,&sign,1020,2); |
#ifdef TCC_ARM_VFP |
op=0xED000A00; /* fsts */ |
if(!sign) |
op|=0x800000; |
if ((ft & VT_BTYPE) != VT_FLOAT) |
op|=0x100; /* fsts -> fstd */ |
o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); |
#else |
op=0xED000100; |
if(!sign) |
op|=0x800000; |
716,7 → 563,6 |
op|=0x400000; |
#endif |
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
#endif |
return; |
} else if((ft & VT_BTYPE) == VT_SHORT) { |
calcaddr(&base,&fc,&sign,255,0); |
729,7 → 575,7 |
op=0xE5000000; |
if(!sign) |
op|=0x800000; |
if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) |
if ((ft & VT_BTYPE) == VT_BYTE) |
op|=0x400000; |
o(op|(intr(r)<<12)|fc|(base<<16)); |
} |
736,7 → 582,7 |
return; |
} |
} |
tcc_error("store unimplemented"); |
error("store unimplemented"); |
} |
static void gadd_sp(int val) |
749,9 → 595,9 |
{ |
int r; |
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
uint32_t x; |
unsigned long x; |
/* constant case */ |
x=encbranch(ind,ind+vtop->c.i,0); |
x=encbranch(ind,ind+vtop->c.ul,0); |
if(x) { |
if (vtop->r & VT_SYM) { |
/* relocation case */ |
765,7 → 611,7 |
o(0xE51FF004); // ldr pc,[pc,#-4] |
if (vtop->r & VT_SYM) |
greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32); |
o(vtop->c.i); |
o(vtop->c.ul); |
} |
} else { |
/* otherwise, indirect call */ |
776,345 → 622,62 |
} |
} |
/* Return whether a structure is an homogeneous float aggregate or not. |
The answer is true if all the elements of the structure are of the same |
primitive float type and there is less than 4 elements. |
type: the type corresponding to the structure to be tested */ |
static int is_hgen_float_aggr(CType *type) |
/* Generate function call. The function address is pushed first, then |
all the parameters in call order. This functions pops all the |
parameters and the function address. */ |
void gfunc_call(int nb_args) |
{ |
if ((type->t & VT_BTYPE) == VT_STRUCT) { |
struct Sym *ref; |
int btype, nb_fields = 0; |
int size, align, r, args_size, i; |
Sym *func_sym; |
signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}}; |
int todo=0xf, keep, plan2[4]={0,0,0,0}; |
ref = type->ref->next; |
btype = ref->type.t & VT_BTYPE; |
if (btype == VT_FLOAT || btype == VT_DOUBLE) { |
for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++); |
return !ref && nb_fields <= 4; |
} |
} |
return 0; |
} |
struct avail_regs { |
signed char avail[3]; /* 3 holes max with only float and double alignments */ |
int first_hole; /* first available hole */ |
int last_hole; /* last available hole (none if equal to first_hole) */ |
int first_free_reg; /* next free register in the sequence, hole excluded */ |
}; |
#define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 } |
/* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC |
param) according to the rules described in the procedure call standard for |
the ARM architecture (AAPCS). If found, the registers are assigned to this |
VFP CPRC parameter. Registers are allocated in sequence unless a hole exists |
and the parameter is a single float. |
avregs: opaque structure to keep track of available VFP co-processor regs |
align: alignment contraints for the param, as returned by type_size() |
size: size of the parameter, as returned by type_size() */ |
int assign_vfpreg(struct avail_regs *avregs, int align, int size) |
{ |
int first_reg = 0; |
if (avregs->first_free_reg == -1) |
return -1; |
if (align >> 3) { /* double alignment */ |
first_reg = avregs->first_free_reg; |
/* alignment contraint not respected so use next reg and record hole */ |
if (first_reg & 1) |
avregs->avail[avregs->last_hole++] = first_reg++; |
} else { /* no special alignment (float or array of float) */ |
/* if single float and a hole is available, assign the param to it */ |
if (size == 4 && avregs->first_hole != avregs->last_hole) |
return avregs->avail[avregs->first_hole++]; |
else |
first_reg = avregs->first_free_reg; |
} |
if (first_reg + size / 4 <= 16) { |
avregs->first_free_reg = first_reg + size / 4; |
return first_reg; |
} |
avregs->first_free_reg = -1; |
return -1; |
} |
/* Returns whether all params need to be passed in core registers or not. |
This is the case for function part of the runtime ABI. */ |
int floats_in_core_regs(SValue *sval) |
{ |
if (!sval->sym) |
return 0; |
switch (sval->sym->v) { |
case TOK___floatundisf: |
case TOK___floatundidf: |
case TOK___fixunssfdi: |
case TOK___fixunsdfdi: |
#ifndef TCC_ARM_VFP |
case TOK___fixunsxfdi: |
#endif |
case TOK___floatdisf: |
case TOK___floatdidf: |
case TOK___fixsfdi: |
case TOK___fixdfdi: |
return 1; |
default: |
return 0; |
} |
} |
/* Return the number of registers needed to return the struct, or 0 if |
returning via struct pointer. */ |
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) { |
#ifdef TCC_ARM_EABI |
int size, align; |
size = type_size(vt, &align); |
if (float_abi == ARM_HARD_FLOAT && !variadic && |
(is_float(vt->t) || is_hgen_float_aggr(vt))) { |
*ret_align = 8; |
*regsize = 8; |
ret->ref = NULL; |
ret->t = VT_DOUBLE; |
return (size + 7) >> 3; |
} else if (size <= 4) { |
*ret_align = 4; |
*regsize = 4; |
ret->ref = NULL; |
ret->t = VT_INT; |
return 1; |
} else |
return 0; |
#else |
return 0; |
#endif |
} |
/* Parameters are classified according to how they are copied to their final |
destination for the function call. Because the copying is performed class |
after class according to the order in the union below, it is important that |
some constraints about the order of the members of this union are respected: |
- CORE_STRUCT_CLASS must come after STACK_CLASS; |
- CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and |
VFP_STRUCT_CLASS; |
- VFP_STRUCT_CLASS must come after VFP_CLASS. |
See the comment for the main loop in copy_params() for the reason. */ |
enum reg_class { |
STACK_CLASS = 0, |
CORE_STRUCT_CLASS, |
VFP_CLASS, |
VFP_STRUCT_CLASS, |
CORE_CLASS, |
NB_CLASSES |
}; |
struct param_plan { |
int start; /* first reg or addr used depending on the class */ |
int end; /* last reg used or next free addr depending on the class */ |
SValue *sval; /* pointer to SValue on the value stack */ |
struct param_plan *prev; /* previous element in this class */ |
}; |
struct plan { |
struct param_plan *pplans; /* array of all the param plans */ |
struct param_plan *clsplans[NB_CLASSES]; /* per class lists of param plans */ |
}; |
#define add_param_plan(plan,pplan,class) \ |
do { \ |
pplan.prev = plan->clsplans[class]; \ |
plan->pplans[plan ## _nb] = pplan; \ |
plan->clsplans[class] = &plan->pplans[plan ## _nb++]; \ |
} while(0) |
/* Assign parameters to registers and stack with alignment according to the |
rules in the procedure call standard for the ARM architecture (AAPCS). |
The overall assignment is recorded in an array of per parameter structures |
called parameter plans. The parameter plans are also further organized in a |
number of linked lists, one per class of parameter (see the comment for the |
definition of union reg_class). |
nb_args: number of parameters of the function for which a call is generated |
float_abi: float ABI in use for this function call |
plan: the structure where the overall assignment is recorded |
todo: a bitmap that record which core registers hold a parameter |
Returns the amount of stack space needed for parameter passing |
Note: this function allocated an array in plan->pplans with tcc_malloc. It |
is the responsibility of the caller to free this array once used (ie not |
before copy_params). */ |
static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo) |
{ |
int i, size, align; |
int ncrn /* next core register number */, nsaa /* next stacked argument address*/; |
int plan_nb = 0; |
struct param_plan pplan; |
struct avail_regs avregs = AVAIL_REGS_INITIALIZER; |
ncrn = nsaa = 0; |
*todo = 0; |
plan->pplans = tcc_malloc(nb_args * sizeof(*plan->pplans)); |
memset(plan->clsplans, 0, sizeof(plan->clsplans)); |
for(i = nb_args; i-- ;) { |
int j, start_vfpreg = 0; |
CType type = vtop[-i].type; |
type.t &= ~VT_ARRAY; |
size = type_size(&type, &align); |
r = vtop->r & VT_VALMASK; |
if (r == VT_CMP || (r & ~1) == VT_JMP) |
gv(RC_INT); |
args_size = 0; |
for(i = nb_args ; i-- && args_size < 16 ;) { |
if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) { |
size = type_size(&vtop[-i].type, &align); |
size = (size + 3) & ~3; |
align = (align + 3) & ~3; |
switch(vtop[-i].type.t & VT_BTYPE) { |
case VT_STRUCT: |
case VT_FLOAT: |
case VT_DOUBLE: |
case VT_LDOUBLE: |
if (float_abi == ARM_HARD_FLOAT) { |
int is_hfa = 0; /* Homogeneous float aggregate */ |
if (is_float(vtop[-i].type.t) |
|| (is_hfa = is_hgen_float_aggr(&vtop[-i].type))) { |
int end_vfpreg; |
start_vfpreg = assign_vfpreg(&avregs, align, size); |
end_vfpreg = start_vfpreg + ((size - 1) >> 2); |
if (start_vfpreg >= 0) { |
pplan = (struct param_plan) {start_vfpreg, end_vfpreg, &vtop[-i]}; |
if (is_hfa) |
add_param_plan(plan, pplan, VFP_STRUCT_CLASS); |
else |
add_param_plan(plan, pplan, VFP_CLASS); |
continue; |
} else |
break; |
args_size += size; |
} else if ((vtop[-i].type.t & VT_BTYPE) == VT_FLOAT) |
args_size += 4; |
else if ((vtop[-i].type.t & VT_BTYPE) == VT_DOUBLE) |
args_size += 8; |
else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) |
args_size += LDOUBLE_SIZE; |
else { |
plan[nb_args-1-i][0]=args_size/4; |
args_size += 4; |
if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) { |
plan[nb_args-1-i][1]=args_size/4; |
args_size += 4; |
} |
} |
ncrn = (ncrn + (align-1)/4) & ~((align/4) - 1); |
if (ncrn + size/4 <= 4 || (ncrn < 4 && start_vfpreg != -1)) { |
/* The parameter is allocated both in core register and on stack. As |
* such, it can be of either class: it would either be the last of |
* CORE_STRUCT_CLASS or the first of STACK_CLASS. */ |
for (j = ncrn; j < 4 && j < ncrn + size / 4; j++) |
*todo|=(1<<j); |
pplan = (struct param_plan) {ncrn, j, &vtop[-i]}; |
add_param_plan(plan, pplan, CORE_STRUCT_CLASS); |
ncrn += size/4; |
if (ncrn > 4) |
nsaa = (ncrn - 4) * 4; |
} else { |
ncrn = 4; |
break; |
} |
continue; |
default: |
if (ncrn < 4) { |
int is_long = (vtop[-i].type.t & VT_BTYPE) == VT_LLONG; |
if (is_long) { |
ncrn = (ncrn + 1) & -2; |
if (ncrn == 4) |
break; |
} |
pplan = (struct param_plan) {ncrn, ncrn, &vtop[-i]}; |
ncrn++; |
if (is_long) |
pplan.end = ncrn++; |
add_param_plan(plan, pplan, CORE_CLASS); |
continue; |
} |
} |
nsaa = (nsaa + (align - 1)) & ~(align - 1); |
pplan = (struct param_plan) {nsaa, nsaa + size, &vtop[-i]}; |
add_param_plan(plan, pplan, STACK_CLASS); |
nsaa += size; /* size already rounded up before */ |
} |
return nsaa; |
} |
#undef add_param_plan |
/* Copy parameters to their final destination (core reg, VFP reg or stack) for |
function call. |
nb_args: number of parameters the function take |
plan: the overall assignment plan for parameters |
todo: a bitmap indicating what core reg will hold a parameter |
Returns the number of SValue added by this function on the value stack */ |
static int copy_params(int nb_args, struct plan *plan, int todo) |
{ |
int size, align, r, i, nb_extra_sval = 0; |
struct param_plan *pplan; |
/* Several constraints require parameters to be copied in a specific order: |
- structures are copied to the stack before being loaded in a reg; |
- floats loaded to an odd numbered VFP reg are first copied to the |
preceding even numbered VFP reg and then moved to the next VFP reg. |
It is thus important that: |
- structures assigned to core regs must be copied after parameters |
assigned to the stack but before structures assigned to VFP regs because |
a structure can lie partly in core registers and partly on the stack; |
- parameters assigned to the stack and all structures be copied before |
parameters assigned to a core reg since copying a parameter to the stack |
require using a core reg; |
- parameters assigned to VFP regs be copied before structures assigned to |
VFP regs as the copy might use an even numbered VFP reg that already |
holds part of a structure. */ |
for(i = 0; i < NB_CLASSES; i++) { |
for(pplan = plan->clsplans[i]; pplan; pplan = pplan->prev) { |
vpushv(pplan->sval); |
pplan->sval->r = pplan->sval->r2 = VT_CONST; /* disable entry */ |
switch(i) { |
case STACK_CLASS: |
case CORE_STRUCT_CLASS: |
case VFP_STRUCT_CLASS: |
if ((pplan->sval->type.t & VT_BTYPE) == VT_STRUCT) { |
int padding = 0; |
size = type_size(&pplan->sval->type, &align); |
args_size = keep = 0; |
for(i = 0;i < nb_args; i++) { |
vnrott(keep+1); |
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { |
size = type_size(&vtop->type, &align); |
/* align to stack align size */ |
size = (size + 3) & ~3; |
if (i == STACK_CLASS && pplan->prev) |
padding = pplan->start - pplan->prev->end; |
size += padding; /* Add padding if any */ |
/* allocate the necessary size on stack */ |
gadd_sp(-size); |
/* generate structure store */ |
r = get_reg(RC_INT); |
o(0xE28D0000|(intr(r)<<12)|padding); /* add r, sp, padding */ |
o(0xE1A0000D|(intr(r)<<12)); |
vset(&vtop->type, r | VT_LVAL, 0); |
vswap(); |
vstore(); /* memcpy to current sp + potential padding */ |
/* Homogeneous float aggregate are loaded to VFP registers |
immediately since there is no way of loading data in multiple |
non consecutive VFP registers as what is done for other |
structures (see the use of todo). */ |
if (i == VFP_STRUCT_CLASS) { |
int first = pplan->start, nb = pplan->end - first + 1; |
/* vpop.32 {pplan->start, ..., pplan->end} */ |
o(0xECBD0A00|(first&1)<<22|(first>>1)<<12|nb); |
/* No need to write the register used to a SValue since VFP regs |
cannot be used for gcall_or_jmp */ |
} |
} else { |
if (is_float(pplan->sval->type.t)) { |
#ifdef TCC_ARM_VFP |
r = vfpr(gv(RC_FLOAT)) << 12; |
if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT) |
size = 4; |
else { |
size = 8; |
r |= 0x101; /* vpush.32 -> vpush.64 */ |
} |
o(0xED2D0A01 + r); /* vpush */ |
#else |
vstore(); |
vtop--; |
args_size += size; |
} else if (is_float(vtop->type.t)) { |
r = fpr(gv(RC_FLOAT)) << 12; |
if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT) |
if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) |
size = 4; |
else if ((pplan->sval->type.t & VT_BTYPE) == VT_DOUBLE) |
else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
size = 8; |
else |
size = LDOUBLE_SIZE; |
1124,238 → 687,122 |
else if(size == 8) |
r|=0x8000; |
o(0xED2D0100|r|(size>>2)); /* some kind of vpush for FPA */ |
#endif |
o(0xED2D0100|r|(size>>2)); |
vtop--; |
args_size += size; |
} else { |
int s; |
/* simple type (currently always same size) */ |
/* XXX: implicit cast ? */ |
size=4; |
if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) { |
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
lexpand_nr(); |
size = 8; |
r = gv(RC_INT); |
o(0xE52D0004|(intr(r)<<12)); /* push r */ |
s=RC_INT; |
if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) { |
s=regmask(plan[nb_args-i-1][1]); |
todo&=~(1<<plan[nb_args-i-1][1]); |
} |
if(s==RC_INT) { |
r = gv(s); |
o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
vtop--; |
} else { |
plan2[keep]=s; |
keep++; |
vswap(); |
} |
r = gv(RC_INT); |
o(0xE52D0004|(intr(r)<<12)); /* push r */ |
size = 8; |
} |
if (i == STACK_CLASS && pplan->prev) |
gadd_sp(pplan->prev->end - pplan->start); /* Add padding if any */ |
s=RC_INT; |
if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) { |
s=regmask(plan[nb_args-i-1][0]); |
todo&=~(1<<plan[nb_args-i-1][0]); |
} |
break; |
case VFP_CLASS: |
gv(regmask(TREG_F0 + (pplan->start >> 1))); |
if (pplan->start & 1) { /* Must be in upper part of double register */ |
o(0xEEF00A40|((pplan->start>>1)<<12)|(pplan->start>>1)); /* vmov.f32 s(n+1), sn */ |
vtop->r = VT_CONST; /* avoid being saved on stack by gv for next float */ |
} |
break; |
case CORE_CLASS: |
if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) { |
lexpand_nr(); |
gv(regmask(pplan->end)); |
pplan->sval->r2 = vtop->r; |
if(s==RC_INT) { |
r = gv(s); |
o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
vtop--; |
} else { |
plan2[keep]=s; |
keep++; |
} |
gv(regmask(pplan->start)); |
/* Mark register as used so that gcall_or_jmp use another one |
(regs >=4 are free as never used to pass parameters) */ |
pplan->sval->r = vtop->r; |
break; |
args_size += size; |
} |
vtop--; |
} |
for(i=keep;i--;) { |
gv(plan2[i]); |
vrott(keep); |
} |
/* Manually free remaining registers since next parameters are loaded |
* manually, without the help of gv(int). */ |
save_regs(nb_args); |
save_regs(keep); /* save used temporary registers */ |
keep++; |
if(args_size) { |
int n; |
n=args_size/4; |
if(n>4) |
n=4; |
todo&=((1<<n)-1); |
if(todo) { |
o(0xE8BD0000|todo); /* pop {todo} */ |
for(pplan = plan->clsplans[CORE_STRUCT_CLASS]; pplan; pplan = pplan->prev) { |
int r; |
pplan->sval->r = pplan->start; |
/* An SValue can only pin 2 registers at best (r and r2) but a structure |
can occupy more than 2 registers. Thus, we need to push on the value |
stack some fake parameter to have on SValue for each registers used |
by a structure (r2 is not used). */ |
for (r = pplan->start + 1; r <= pplan->end; r++) { |
if (todo & (1 << r)) { |
nb_extra_sval++; |
int i; |
o(0xE8BD0000|todo); |
for(i=0;i<4;i++) |
if(todo&(1<<i)) { |
vpushi(0); |
vtop->r = r; |
vtop->r=i; |
keep++; |
} |
} |
args_size-=n*4; |
} |
} |
return nb_extra_sval; |
} |
/* Generate function call. The function address is pushed first, then |
all the parameters in call order. This functions pops all the |
parameters and the function address. */ |
void gfunc_call(int nb_args) |
{ |
int r, args_size; |
int def_float_abi = float_abi; |
int todo; |
struct plan plan; |
#ifdef TCC_ARM_EABI |
int variadic; |
if (float_abi == ARM_HARD_FLOAT) { |
variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS); |
if (variadic || floats_in_core_regs(&vtop[-nb_args])) |
float_abi = ARM_SOFTFP_FLOAT; |
} |
#endif |
/* cannot let cpu flags if other instruction are generated. Also avoid leaving |
VT_JMP anywhere except on the top of the stack because it would complicate |
the code generator. */ |
r = vtop->r & VT_VALMASK; |
if (r == VT_CMP || (r & ~1) == VT_JMP) |
gv(RC_INT); |
args_size = assign_regs(nb_args, float_abi, &plan, &todo); |
#ifdef TCC_ARM_EABI |
if (args_size & 7) { /* Stack must be 8 byte aligned at fct call for EABI */ |
args_size = (args_size + 7) & ~7; |
o(0xE24DD004); /* sub sp, sp, #4 */ |
} |
#endif |
nb_args += copy_params(nb_args, &plan, todo); |
tcc_free(plan.pplans); |
/* Move fct SValue on top as required by gcall_or_jmp */ |
vrotb(nb_args + 1); |
vnrott(keep); |
func_sym = vtop->type.ref; |
gcall_or_jmp(0); |
if (args_size) |
gadd_sp(args_size); /* pop all parameters passed on the stack */ |
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) |
if(float_abi == ARM_SOFTFP_FLOAT && is_float(vtop->type.ref->type.t)) { |
if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) { |
o(0xEE000A10); /*vmov s0, r0 */ |
} else { |
o(0xEE000B10); /* vmov.32 d0[0], r0 */ |
o(0xEE201B10); /* vmov.32 d0[1], r1 */ |
gadd_sp(args_size); |
vtop-=keep; |
} |
} |
#endif |
vtop -= nb_args + 1; /* Pop all params and fct address from value stack */ |
leaffunc = 0; /* we are calling a function, so we aren't in a leaf function */ |
float_abi = def_float_abi; |
} |
/* generate function prolog of type 't' */ |
void gfunc_prolog(CType *func_type) |
{ |
Sym *sym,*sym2; |
int n, nf, size, align, rs, struct_ret = 0; |
int addr, pn, sn; /* pn=core, sn=stack */ |
CType ret_type; |
int n,addr,size,align; |
#ifdef TCC_ARM_EABI |
struct avail_regs avregs = AVAIL_REGS_INITIALIZER; |
#endif |
sym = func_type->ref; |
func_vt = sym->type; |
func_var = (func_type->ref->c == FUNC_ELLIPSIS); |
n = nf = 0; |
if ((func_vt.t & VT_BTYPE) == VT_STRUCT && |
!gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs)) |
{ |
n=0; |
addr=12; |
if((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
func_vc = addr; |
addr += 4; |
n++; |
struct_ret = 1; |
func_vc = 12; /* Offset from fp of the place to store the result */ |
} |
for(sym2 = sym->next; sym2 && (n < 4 || nf < 16); sym2 = sym2->next) { |
for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) { |
size = type_size(&sym2->type, &align); |
#ifdef TCC_ARM_EABI |
if (float_abi == ARM_HARD_FLOAT && !func_var && |
(is_float(sym2->type.t) || is_hgen_float_aggr(&sym2->type))) { |
int tmpnf = assign_vfpreg(&avregs, align, size); |
tmpnf += (size + 3) / 4; |
nf = (tmpnf > nf) ? tmpnf : nf; |
} else |
#endif |
if (n < 4) |
n += (size + 3) / 4; |
size = (size + 3) & ~3; |
n+=size/4; |
} |
o(0xE1A0C00D); /* mov ip,sp */ |
if (func_var) |
if(func_type->ref->c == FUNC_ELLIPSIS) |
n=4; |
if (n) { |
if(n>4) |
n=4; |
#ifdef TCC_ARM_EABI |
n=(n+1)&-2; |
#endif |
o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */ |
} |
if (nf) { |
if (nf>16) |
nf=16; |
nf=(nf+1)&-2; /* nf => HARDFLOAT => EABI */ |
o(0xED2D0A00|nf); /* save s0-s15 on stack if needed */ |
} |
o(0xE92D5800); /* save fp, ip, lr */ |
o(0xE1A0B00D); /* mov fp, sp */ |
func_sub_sp_offset = ind; |
o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */ |
#ifdef TCC_ARM_EABI |
if (float_abi == ARM_HARD_FLOAT) { |
func_vc += nf * 4; |
avregs = AVAIL_REGS_INITIALIZER; |
} |
#endif |
pn = struct_ret, sn = 0; |
o(0xE1A00000); /* nop, leave space for stack adjustment */ |
while ((sym = sym->next)) { |
CType *type; |
type = &sym->type; |
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); |
size = type_size(type, &align); |
size = (size + 3) >> 2; |
align = (align + 3) & ~3; |
#ifdef TCC_ARM_EABI |
if (float_abi == ARM_HARD_FLOAT && !func_var && (is_float(sym->type.t) |
|| is_hgen_float_aggr(&sym->type))) { |
int fpn = assign_vfpreg(&avregs, align, size << 2); |
if (fpn >= 0) |
addr = fpn * 4; |
else |
goto from_stack; |
} else |
#endif |
if (pn < 4) { |
#ifdef TCC_ARM_EABI |
pn = (pn + (align-1)/4) & -(align/4); |
#endif |
addr = (nf + pn) * 4; |
pn += size; |
if (!sn && pn > 4) |
sn = (pn - 4); |
} else { |
#ifdef TCC_ARM_EABI |
from_stack: |
sn = (sn + (align-1)/4) & -(align/4); |
#endif |
addr = (n + nf + sn) * 4; |
sn += size; |
size = (size + 3) & ~3; |
addr += size; |
} |
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), |
addr + 12); |
} |
last_itod_magic=0; |
leaffunc = 1; |
loc = 0; |
} |
1362,38 → 809,20 |
/* generate function epilog */ |
void gfunc_epilog(void) |
{ |
uint32_t x; |
int diff; |
/* Copy float return value to core register if base standard is used and |
float computation is made with VFP */ |
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) |
if ((float_abi == ARM_SOFTFP_FLOAT || func_var) && is_float(func_vt.t)) { |
if((func_vt.t & VT_BTYPE) == VT_FLOAT) |
o(0xEE100A10); /* fmrs r0, s0 */ |
else { |
o(0xEE100B10); /* fmrdl r0, d0 */ |
o(0xEE301B10); /* fmrdh r1, d0 */ |
} |
} |
#endif |
unsigned long x; |
o(0xE89BA800); /* restore fp, sp, pc */ |
diff = (-loc + 3) & -4; |
#ifdef TCC_ARM_EABI |
if(!leaffunc) |
diff = ((diff + 11) & -8) - 4; |
#endif |
if(diff > 0) { |
x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */ |
if(loc) { |
x=stuff_const(0xE24DD000, (-loc + 3) & -4); /* sub sp,sp,# */ |
if(x) |
*(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = x; |
*(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x; |
else { |
int addr; |
unsigned long addr; |
addr=ind; |
o(0xE59FC004); /* ldr ip,[pc+4] */ |
o(0xE04BD00C); /* sub sp,fp,ip */ |
o(0xE04DD00C); /* sub sp,sp,ip */ |
o(0xE1A0F00E); /* mov pc,lr */ |
o(diff); |
*(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1); |
o((-loc + 3) & -4); |
*(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1); |
} |
} |
} |
1417,7 → 846,7 |
int gtst(int inv, int t) |
{ |
int v, r; |
uint32_t op; |
unsigned long op; |
v = vtop->r & VT_VALMASK; |
r=ind; |
if (v == VT_CMP) { |
1430,7 → 859,7 |
if(!vtop->c.i) |
vtop->c.i=t; |
else { |
uint32_t *x; |
unsigned long *x; |
int p,lp; |
if(t) { |
p = vtop->c.i; |
1437,7 → 866,7 |
do { |
p = decbranch(lp=p); |
} while(p); |
x = (uint32_t *)(cur_text_section->data + lp); |
x = (unsigned long *)(cur_text_section->data + lp); |
*x &= 0xff000000; |
*x |= encbranch(lp,t,1); |
} |
1447,7 → 876,25 |
t = gjmp(t); |
gsym(vtop->c.i); |
} |
} else { |
if (is_float(vtop->type.t)) { |
r=gv(RC_FLOAT); |
o(0xEE90F118|fpr(r)<<16); |
vtop->r = VT_CMP; |
vtop->c.i = TOK_NE; |
return gtst(inv, t); |
} else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
/* constant jmp optimization */ |
if ((vtop->c.i != 0) != inv) |
t = gjmp(t); |
} else { |
v = gv(RC_INT); |
o(0xE3300000|(intr(v)<<16)); |
vtop->r = VT_CMP; |
vtop->c.i = TOK_NE; |
return gtst(inv, t); |
} |
} |
vtop--; |
return t; |
} |
1456,8 → 903,7 |
void gen_opi(int op) |
{ |
int c, func = 0; |
uint32_t opc = 0, r, fr; |
unsigned short retreg = REG_IRET; |
unsigned long opc = 0,r,fr; |
c=0; |
switch(op) { |
1526,21 → 972,11 |
c=3; |
break; |
case '%': |
#ifdef TCC_ARM_EABI |
func=TOK___aeabi_idivmod; |
retreg=REG_LRET; |
#else |
func=TOK___modsi3; |
#endif |
c=3; |
break; |
case TOK_UMOD: |
#ifdef TCC_ARM_EABI |
func=TOK___aeabi_uidivmod; |
retreg=REG_LRET; |
#else |
func=TOK___umodsi3; |
#endif |
c=3; |
break; |
case TOK_UMULL: |
1572,7 → 1008,7 |
vswap(); |
opc=0xE0000000|(opc<<20)|(c<<16); |
if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
uint32_t x; |
unsigned long x; |
x=stuff_const(opc|0x2000000,vtop->c.i); |
if(x) { |
r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); |
1615,121 → 1051,17 |
vrott(3); |
gfunc_call(2); |
vpushi(0); |
vtop->r = retreg; |
vtop->r = REG_IRET; |
break; |
default: |
tcc_error("gen_opi %i unimplemented!",op); |
error("gen_opi %i unimplemented!",op); |
} |
} |
#ifdef TCC_ARM_VFP |
static int is_zero(int i) |
static int is_fconst() |
{ |
if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
return 0; |
if (vtop[i].type.t == VT_FLOAT) |
return (vtop[i].c.f == 0.f); |
else if (vtop[i].type.t == VT_DOUBLE) |
return (vtop[i].c.d == 0.0); |
return (vtop[i].c.ld == 0.l); |
} |
/* generate a floating point operation 'v = t1 op t2' instruction. The |
* two operands are guaranted to have the same floating point type */ |
void gen_opf(int op) |
{ |
uint32_t x; |
int fneg=0,r; |
x=0xEE000A00|T2CPR(vtop->type.t); |
switch(op) { |
case '+': |
if(is_zero(-1)) |
vswap(); |
if(is_zero(0)) { |
vtop--; |
return; |
} |
x|=0x300000; |
break; |
case '-': |
x|=0x300040; |
if(is_zero(0)) { |
vtop--; |
return; |
} |
if(is_zero(-1)) { |
x|=0x810000; /* fsubX -> fnegX */ |
vswap(); |
vtop--; |
fneg=1; |
} |
break; |
case '*': |
x|=0x200000; |
break; |
case '/': |
x|=0x800000; |
break; |
default: |
if(op < TOK_ULT || op > TOK_GT) { |
tcc_error("unknown fp op %x!",op); |
return; |
} |
if(is_zero(-1)) { |
vswap(); |
switch(op) { |
case TOK_LT: op=TOK_GT; break; |
case TOK_GE: op=TOK_ULE; break; |
case TOK_LE: op=TOK_GE; break; |
case TOK_GT: op=TOK_ULT; break; |
} |
} |
x|=0xB40040; /* fcmpX */ |
if(op!=TOK_EQ && op!=TOK_NE) |
x|=0x80; /* fcmpX -> fcmpeX */ |
if(is_zero(0)) { |
vtop--; |
o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */ |
} else { |
x|=vfpr(gv(RC_FLOAT)); |
vswap(); |
o(x|(vfpr(gv(RC_FLOAT))<<12)); |
vtop--; |
} |
o(0xEEF1FA10); /* fmstat */ |
switch(op) { |
case TOK_LE: op=TOK_ULE; break; |
case TOK_LT: op=TOK_ULT; break; |
case TOK_UGE: op=TOK_GE; break; |
case TOK_UGT: op=TOK_GT; break; |
} |
vtop->r = VT_CMP; |
vtop->c.i = op; |
return; |
} |
r=gv(RC_FLOAT); |
x|=vfpr(r); |
r=regmask(r); |
if(!fneg) { |
int r2; |
vswap(); |
r2=gv(RC_FLOAT); |
x|=vfpr(r2)<<16; |
r|=regmask(r2); |
} |
vtop->r=get_reg_ex(RC_FLOAT,r); |
if(!fneg) |
vtop--; |
o(x|(vfpr(vtop->r)<<12)); |
} |
#else |
static uint32_t is_fconst() |
{ |
long double f; |
uint32_t r; |
int r; |
if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
return 0; |
if (vtop->type.t == VT_FLOAT) |
1768,7 → 1100,8 |
two operands are guaranted to have the same floating point type */ |
void gen_opf(int op) |
{ |
uint32_t x, r, r2, c1, c2; |
unsigned long x; |
int r,r2,c1,c2; |
//fputs("gen_opf\n",stderr); |
vswap(); |
c1 = is_fconst(); |
1860,21 → 1193,25 |
default: |
if(op >= TOK_ULT && op <= TOK_GT) { |
x|=0xd0f110; // cmfe |
/* bug (intention?) in Linux FPU emulator |
doesn't set carry if equal */ |
switch(op) { |
case TOK_ULT: |
case TOK_UGE: |
case TOK_ULE: |
case TOK_UGT: |
tcc_error("unsigned comparison on floats?"); |
fputs("unsigned comparision on floats?\n",stderr); |
break; |
case TOK_LT: |
op=TOK_Nset; |
op=TOK_ULT; |
break; |
case TOK_GE: |
op=TOK_UGE; |
break; |
case TOK_LE: |
op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */ |
op=TOK_ULE; |
break; |
case TOK_GT: |
op=TOK_UGT; |
break; |
case TOK_EQ: |
case TOK_NE: |
x&=~0x400000; // cmfe -> cmf |
1884,20 → 1221,26 |
c2=c1; |
vswap(); |
switch(op) { |
case TOK_Nset: |
op=TOK_GT; |
case TOK_ULT: |
op=TOK_UGT; |
break; |
case TOK_GE: |
case TOK_UGE: |
op=TOK_ULE; |
break; |
case TOK_ULE: |
op=TOK_GE; |
op=TOK_UGE; |
break; |
case TOK_GT: |
op=TOK_Nset; |
case TOK_UGT: |
op=TOK_ULT; |
break; |
} |
} |
// bug (intention?) in Linux FPU emulator |
// doesn't set carry if equal |
if(op==TOK_ULT) |
op=TOK_LT; |
else if(op==TOK_UGE) |
op=TOK_GE; |
vswap(); |
r=fpr(gv(RC_FLOAT)); |
vswap(); |
1911,7 → 1254,7 |
vtop[-1].r = VT_CMP; |
vtop[-1].c.i = op; |
} else { |
tcc_error("unknown fp op %x!",op); |
error("unknown fp op %x!\n",op); |
return; |
} |
} |
1927,35 → 1270,20 |
vtop--; |
o(x|(r<<16)|(c1<<12)|r2); |
} |
#endif |
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' |
and 'long long' cases. */ |
ST_FUNC void gen_cvt_itof1(int t) |
void gen_cvt_itof(int t) |
{ |
uint32_t r, r2; |
int bt; |
int r,r2,bt; |
bt=vtop->type.t & VT_BTYPE; |
if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) { |
#ifndef TCC_ARM_VFP |
uint32_t dsize = 0; |
#endif |
r=intr(gv(RC_INT)); |
#ifdef TCC_ARM_VFP |
r2=vfpr(vtop->r=get_reg(RC_FLOAT)); |
o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */ |
r2|=r2<<12; |
if(!(vtop->type.t & VT_UNSIGNED)) |
r2|=0x80; /* fuitoX -> fsituX */ |
o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/ |
#else |
r2=fpr(vtop->r=get_reg(RC_FLOAT)); |
if((t & VT_BTYPE) != VT_FLOAT) |
dsize=0x80; /* flts -> fltd */ |
o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */ |
o(0xEE000190|(r2<<16)|(r<<12)); |
if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) { |
uint32_t off = 0; |
o(0xE3500000|(r<<12)); /* cmp */ |
unsigned int off=0; |
o(0xE3500000|(r<<12)); |
r=fpr(get_reg(RC_FLOAT)); |
if(last_itod_magic) { |
off=ind+8-last_itod_magic; |
1963,44 → 1291,23 |
if(off>255) |
off=0; |
} |
o(0xBD1F0100|(r<<12)|off); /* ldflts */ |
o(0xBD1F8100|(r<<12)|off); |
if(!off) { |
o(0xEA000000); /* b */ |
o(0xEA000001); |
last_itod_magic=ind; |
o(0x4F800000); /* 4294967296.0f */ |
o(0x41F00000); |
o(0); |
} |
o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */ |
o(0xBE000180|(r2<<16)|(r2<<12)|r); |
} |
#endif |
return; |
} else if(bt == VT_LLONG) { |
int func; |
CType *func_type = 0; |
if((t & VT_BTYPE) == VT_FLOAT) { |
func_type = &func_float_type; |
if(vtop->type.t & VT_UNSIGNED) |
func=TOK___floatundisf; |
func=TOK___ulltold; |
else |
func=TOK___floatdisf; |
#if LDOUBLE_SIZE != 8 |
} else if((t & VT_BTYPE) == VT_LDOUBLE) { |
func_type = &func_ldouble_type; |
if(vtop->type.t & VT_UNSIGNED) |
func=TOK___floatundixf; |
else |
func=TOK___floatdixf; |
} else if((t & VT_BTYPE) == VT_DOUBLE) { |
#else |
} else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) { |
#endif |
func_type = &func_double_type; |
if(vtop->type.t & VT_UNSIGNED) |
func=TOK___floatundidf; |
else |
func=TOK___floatdidf; |
} |
if(func_type) { |
vpush_global_sym(func_type, func); |
func=TOK___slltold; |
vpush_global_sym(&func_old_type, func); |
vswap(); |
gfunc_call(1); |
vpushi(0); |
2007,38 → 1314,28 |
vtop->r=TREG_F0; |
return; |
} |
error("unimplemented gen_cvt_itof %x!",vtop->type.t); |
} |
tcc_error("unimplemented gen_cvt_itof %x!",vtop->type.t); |
} |
/* convert fp to int 't' type */ |
void gen_cvt_ftoi(int t) |
{ |
uint32_t r, r2; |
int u, func = 0; |
int r,r2,u,func=0; |
u=t&VT_UNSIGNED; |
t&=VT_BTYPE; |
r2=vtop->type.t & VT_BTYPE; |
if(t==VT_INT) { |
#ifdef TCC_ARM_VFP |
r=vfpr(gv(RC_FLOAT)); |
u=u?0:0x10000; |
o(0xEEBC0AC0|(r<<12)|r|T2CPR(r2)|u); /* ftoXizY */ |
r2=intr(vtop->r=get_reg(RC_INT)); |
o(0xEE100A10|(r<<16)|(r2<<12)); |
return; |
#else |
if(u) { |
if(r2 == VT_FLOAT) |
func=TOK___fixunssfsi; |
#if LDOUBLE_SIZE != 8 |
else if(r2 == VT_DOUBLE) |
func=TOK___fixunsdfsi; |
else if(r2 == VT_LDOUBLE) |
#if LDOUBLE_SIZE == 8 |
func=TOK___fixunsdfsi; |
#else |
func=TOK___fixunsxfsi; |
else if(r2 == VT_DOUBLE) |
#else |
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE) |
#endif |
func=TOK___fixunsdfsi; |
} else { |
r=fpr(gv(RC_FLOAT)); |
r2=intr(vtop->r=get_reg(RC_INT)); |
2045,18 → 1342,17 |
o(0xEE100170|(r2<<12)|r); |
return; |
} |
#endif |
} else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1 |
if(r2 == VT_FLOAT) |
func=TOK___fixsfdi; |
#if LDOUBLE_SIZE != 8 |
else if(r2 == VT_DOUBLE) |
func=TOK___fixdfdi; |
else if(r2 == VT_LDOUBLE) |
#if LDOUBLE_SIZE == 8 |
func=TOK___fixdfdi; |
#else |
func=TOK___fixxfdi; |
else if(r2 == VT_DOUBLE) |
#else |
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE) |
#endif |
func=TOK___fixdfdi; |
} |
if(func) { |
vpush_global_sym(&func_old_type, func); |
2068,21 → 1364,14 |
vtop->r = REG_IRET; |
return; |
} |
tcc_error("unimplemented gen_cvt_ftoi!"); |
error("unimplemented gen_cvt_ftoi!"); |
} |
/* convert from one floating point type to another */ |
void gen_cvt_ftof(int t) |
{ |
#ifdef TCC_ARM_VFP |
if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) { |
uint32_t r = vfpr(gv(RC_FLOAT)); |
o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t)); |
} |
#else |
/* all we have to do on i386 and FPA ARM is to put the float in a register */ |
/* all we have to do on i386 and ARM is to put the float in a register */ |
gv(RC_FLOAT); |
#endif |
} |
/* computed goto support */ |
2092,22 → 1381,6 |
vtop--; |
} |
/* Save the stack pointer onto the stack and return the location of its address */ |
ST_FUNC void gen_vla_sp_save(int addr) { |
tcc_error("variable length arrays unsupported for this target"); |
} |
/* Restore the SP from a location on the stack */ |
ST_FUNC void gen_vla_sp_restore(int addr) { |
tcc_error("variable length arrays unsupported for this target"); |
} |
/* Subtract from the stack pointer, and push the resulting value onto the stack */ |
ST_FUNC void gen_vla_alloc(CType *type, int align) { |
tcc_error("variable length arrays unsupported for this target"); |
} |
/* end of ARM code generator */ |
/*************************************************************/ |
#endif |
/*************************************************************/ |
/programs/develop/ktcc/trunk/source/bcheck.c |
---|
0,0 → 1,867 |
/* |
* Tiny C Memory and bounds checker |
* |
* Copyright (c) 2002 Fabrice Bellard |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
*/ |
#include <stdlib.h> |
#include <stdio.h> |
#include <stdarg.h> |
#include <string.h> |
#ifndef __FreeBSD__ |
#include <malloc.h> |
#endif |
//#define BOUND_DEBUG |
/* define so that bound array is static (faster, but use memory if |
bound checking not used) */ |
//#define BOUND_STATIC |
/* use malloc hooks. Currently the code cannot be reliable if no hooks */ |
#define CONFIG_TCC_MALLOC_HOOKS |
#define HAVE_MEMALIGN |
#if defined(__FreeBSD__) || defined(__dietlibc__) |
#warning Bound checking not fully supported on FreeBSD |
#undef CONFIG_TCC_MALLOC_HOOKS |
#undef HAVE_MEMALIGN |
#endif |
#define BOUND_T1_BITS 13 |
#define BOUND_T2_BITS 11 |
#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS) |
#define BOUND_T1_SIZE (1 << BOUND_T1_BITS) |
#define BOUND_T2_SIZE (1 << BOUND_T2_BITS) |
#define BOUND_T3_SIZE (1 << BOUND_T3_BITS) |
#define BOUND_E_BITS 4 |
#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS) |
#define BOUND_T23_SIZE (1 << BOUND_T23_BITS) |
/* this pointer is generated when bound check is incorrect */ |
#define INVALID_POINTER ((void *)(-2)) |
/* size of an empty region */ |
#define EMPTY_SIZE 0xffffffff |
/* size of an invalid region */ |
#define INVALID_SIZE 0 |
typedef struct BoundEntry { |
unsigned long start; |
unsigned long size; |
struct BoundEntry *next; |
unsigned long is_invalid; /* true if pointers outside region are invalid */ |
} BoundEntry; |
/* external interface */ |
void __bound_init(void); |
void __bound_new_region(void *p, unsigned long size); |
int __bound_delete_region(void *p); |
#define FASTCALL __attribute__((regparm(3))) |
void *__bound_malloc(size_t size, const void *caller); |
void *__bound_memalign(size_t size, size_t align, const void *caller); |
void __bound_free(void *ptr, const void *caller); |
void *__bound_realloc(void *ptr, size_t size, const void *caller); |
static void *libc_malloc(size_t size); |
static void libc_free(void *ptr); |
static void install_malloc_hooks(void); |
static void restore_malloc_hooks(void); |
#ifdef CONFIG_TCC_MALLOC_HOOKS |
static void *saved_malloc_hook; |
static void *saved_free_hook; |
static void *saved_realloc_hook; |
static void *saved_memalign_hook; |
#endif |
/* linker definitions */ |
extern char _end; |
/* TCC definitions */ |
extern char __bounds_start; /* start of static bounds table */ |
/* error message, just for TCC */ |
const char *__bound_error_msg; |
/* runtime error output */ |
extern void rt_error(unsigned long pc, const char *fmt, ...); |
#ifdef BOUND_STATIC |
static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */ |
#else |
static BoundEntry **__bound_t1; /* page table */ |
#endif |
static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */ |
static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */ |
static BoundEntry *__bound_find_region(BoundEntry *e1, void *p) |
{ |
unsigned long addr, tmp; |
BoundEntry *e; |
e = e1; |
while (e != NULL) { |
addr = (unsigned long)p; |
addr -= e->start; |
if (addr <= e->size) { |
/* put region at the head */ |
tmp = e1->start; |
e1->start = e->start; |
e->start = tmp; |
tmp = e1->size; |
e1->size = e->size; |
e->size = tmp; |
return e1; |
} |
e = e->next; |
} |
/* no entry found: return empty entry or invalid entry */ |
if (e1->is_invalid) |
return __bound_invalid_t2; |
else |
return __bound_empty_t2; |
} |
/* print a bound error message */ |
static void bound_error(const char *fmt, ...) |
{ |
__bound_error_msg = fmt; |
*(int *)0 = 0; /* force a runtime error */ |
} |
static void bound_alloc_error(void) |
{ |
bound_error("not enough memory for bound checking code"); |
} |
/* currently, tcc cannot compile that because we use GNUC extensions */ |
#if !defined(__TINYC__) |
/* return '(p + offset)' for pointer arithmetic (a pointer can reach |
the end of a region in this case */ |
void * FASTCALL __bound_ptr_add(void *p, int offset) |
{ |
unsigned long addr = (unsigned long)p; |
BoundEntry *e; |
#if defined(BOUND_DEBUG) |
printf("add: 0x%x %d\n", (int)p, offset); |
#endif |
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; |
e = (BoundEntry *)((char *)e + |
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & |
((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); |
addr -= e->start; |
if (addr > e->size) { |
e = __bound_find_region(e, p); |
addr = (unsigned long)p - e->start; |
} |
addr += offset; |
if (addr > e->size) |
return INVALID_POINTER; /* return an invalid pointer */ |
return p + offset; |
} |
/* return '(p + offset)' for pointer indirection (the resulting must |
be strictly inside the region */ |
#define BOUND_PTR_INDIR(dsize) \ |
void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \ |
{ \ |
unsigned long addr = (unsigned long)p; \ |
BoundEntry *e; \ |
\ |
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \ |
e = (BoundEntry *)((char *)e + \ |
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \ |
((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \ |
addr -= e->start; \ |
if (addr > e->size) { \ |
e = __bound_find_region(e, p); \ |
addr = (unsigned long)p - e->start; \ |
} \ |
addr += offset + dsize; \ |
if (addr > e->size) \ |
return INVALID_POINTER; /* return an invalid pointer */ \ |
return p + offset; \ |
} |
#ifdef __i386__ |
/* return the frame pointer of the caller */ |
#define GET_CALLER_FP(fp)\ |
{\ |
unsigned long *fp1;\ |
__asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp1));\ |
fp = fp1[0];\ |
} |
#else |
#error put code to extract the calling frame pointer |
#endif |
/* called when entering a function to add all the local regions */ |
void FASTCALL __bound_local_new(void *p1) |
{ |
unsigned long addr, size, fp, *p = p1; |
GET_CALLER_FP(fp); |
for(;;) { |
addr = p[0]; |
if (addr == 0) |
break; |
addr += fp; |
size = p[1]; |
p += 2; |
__bound_new_region((void *)addr, size); |
} |
} |
/* called when leaving a function to delete all the local regions */ |
void FASTCALL __bound_local_delete(void *p1) |
{ |
unsigned long addr, fp, *p = p1; |
GET_CALLER_FP(fp); |
for(;;) { |
addr = p[0]; |
if (addr == 0) |
break; |
addr += fp; |
p += 2; |
__bound_delete_region((void *)addr); |
} |
} |
#else |
void __bound_local_new(void *p) |
{ |
} |
void __bound_local_delete(void *p) |
{ |
} |
void *__bound_ptr_add(void *p, int offset) |
{ |
return p + offset; |
} |
#define BOUND_PTR_INDIR(dsize) \ |
void *__bound_ptr_indir ## dsize (void *p, int offset) \ |
{ \ |
return p + offset; \ |
} |
#endif |
BOUND_PTR_INDIR(1) |
BOUND_PTR_INDIR(2) |
BOUND_PTR_INDIR(4) |
BOUND_PTR_INDIR(8) |
BOUND_PTR_INDIR(12) |
BOUND_PTR_INDIR(16) |
static BoundEntry *__bound_new_page(void) |
{ |
BoundEntry *page; |
int i; |
page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE); |
if (!page) |
bound_alloc_error(); |
for(i=0;i<BOUND_T2_SIZE;i++) { |
/* put empty entries */ |
page[i].start = 0; |
page[i].size = EMPTY_SIZE; |
page[i].next = NULL; |
page[i].is_invalid = 0; |
} |
return page; |
} |
/* currently we use malloc(). Should use bound_new_page() */ |
static BoundEntry *bound_new_entry(void) |
{ |
BoundEntry *e; |
e = libc_malloc(sizeof(BoundEntry)); |
return e; |
} |
static void bound_free_entry(BoundEntry *e) |
{ |
libc_free(e); |
} |
static inline BoundEntry *get_page(int index) |
{ |
BoundEntry *page; |
page = __bound_t1[index]; |
if (page == __bound_empty_t2 || page == __bound_invalid_t2) { |
/* create a new page if necessary */ |
page = __bound_new_page(); |
__bound_t1[index] = page; |
} |
return page; |
} |
/* mark a region as being invalid (can only be used during init) */ |
static void mark_invalid(unsigned long addr, unsigned long size) |
{ |
unsigned long start, end; |
BoundEntry *page; |
int t1_start, t1_end, i, j, t2_start, t2_end; |
start = addr; |
end = addr + size; |
t2_start = (start + BOUND_T3_SIZE - 1) >> BOUND_T3_BITS; |
if (end != 0) |
t2_end = end >> BOUND_T3_BITS; |
else |
t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS); |
#if 0 |
printf("mark_invalid: start = %x %x\n", t2_start, t2_end); |
#endif |
/* first we handle full pages */ |
t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS; |
t1_end = t2_end >> BOUND_T2_BITS; |
i = t2_start & (BOUND_T2_SIZE - 1); |
j = t2_end & (BOUND_T2_SIZE - 1); |
if (t1_start == t1_end) { |
page = get_page(t2_start >> BOUND_T2_BITS); |
for(; i < j; i++) { |
page[i].size = INVALID_SIZE; |
page[i].is_invalid = 1; |
} |
} else { |
if (i > 0) { |
page = get_page(t2_start >> BOUND_T2_BITS); |
for(; i < BOUND_T2_SIZE; i++) { |
page[i].size = INVALID_SIZE; |
page[i].is_invalid = 1; |
} |
} |
for(i = t1_start; i < t1_end; i++) { |
__bound_t1[i] = __bound_invalid_t2; |
} |
if (j != 0) { |
page = get_page(t1_end); |
for(i = 0; i < j; i++) { |
page[i].size = INVALID_SIZE; |
page[i].is_invalid = 1; |
} |
} |
} |
} |
void __bound_init(void) |
{ |
int i; |
BoundEntry *page; |
unsigned long start, size; |
int *p; |
/* save malloc hooks and install bound check hooks */ |
install_malloc_hooks(); |
#ifndef BOUND_STATIC |
__bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *)); |
if (!__bound_t1) |
bound_alloc_error(); |
#endif |
__bound_empty_t2 = __bound_new_page(); |
for(i=0;i<BOUND_T1_SIZE;i++) { |
__bound_t1[i] = __bound_empty_t2; |
} |
page = __bound_new_page(); |
for(i=0;i<BOUND_T2_SIZE;i++) { |
/* put invalid entries */ |
page[i].start = 0; |
page[i].size = INVALID_SIZE; |
page[i].next = NULL; |
page[i].is_invalid = 1; |
} |
__bound_invalid_t2 = page; |
/* invalid pointer zone */ |
start = (unsigned long)INVALID_POINTER & ~(BOUND_T23_SIZE - 1); |
size = BOUND_T23_SIZE; |
mark_invalid(start, size); |
#if !defined(__TINYC__) && defined(CONFIG_TCC_MALLOC_HOOKS) |
/* malloc zone is also marked invalid. can only use that with |
hooks because all libs should use the same malloc. The solution |
would be to build a new malloc for tcc. */ |
start = (unsigned long)&_end; |
size = 128 * 0x100000; |
mark_invalid(start, size); |
#endif |
/* add all static bound check values */ |
p = (int *)&__bounds_start; |
while (p[0] != 0) { |
__bound_new_region((void *)p[0], p[1]); |
p += 2; |
} |
} |
static inline void add_region(BoundEntry *e, |
unsigned long start, unsigned long size) |
{ |
BoundEntry *e1; |
if (e->start == 0) { |
/* no region : add it */ |
e->start = start; |
e->size = size; |
} else { |
/* already regions in the list: add it at the head */ |
e1 = bound_new_entry(); |
e1->start = e->start; |
e1->size = e->size; |
e1->next = e->next; |
e->start = start; |
e->size = size; |
e->next = e1; |
} |
} |
/* create a new region. It should not already exist in the region list */ |
void __bound_new_region(void *p, unsigned long size) |
{ |
unsigned long start, end; |
BoundEntry *page, *e, *e2; |
int t1_start, t1_end, i, t2_start, t2_end; |
start = (unsigned long)p; |
end = start + size; |
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS); |
t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS); |
/* start */ |
page = get_page(t1_start); |
t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) & |
((BOUND_T2_SIZE - 1) << BOUND_E_BITS); |
t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) & |
((BOUND_T2_SIZE - 1) << BOUND_E_BITS); |
#ifdef BOUND_DEBUG |
printf("new %lx %lx %x %x %x %x\n", |
start, end, t1_start, t1_end, t2_start, t2_end); |
#endif |
e = (BoundEntry *)((char *)page + t2_start); |
add_region(e, start, size); |
if (t1_end == t1_start) { |
/* same ending page */ |
e2 = (BoundEntry *)((char *)page + t2_end); |
if (e2 > e) { |
e++; |
for(;e<e2;e++) { |
e->start = start; |
e->size = size; |
} |
add_region(e, start, size); |
} |
} else { |
/* mark until end of page */ |
e2 = page + BOUND_T2_SIZE; |
e++; |
for(;e<e2;e++) { |
e->start = start; |
e->size = size; |
} |
/* mark intermediate pages, if any */ |
for(i=t1_start+1;i<t1_end;i++) { |
page = get_page(i); |
e2 = page + BOUND_T2_SIZE; |
for(e=page;e<e2;e++) { |
e->start = start; |
e->size = size; |
} |
} |
/* last page */ |
page = get_page(t1_end); |
e2 = (BoundEntry *)((char *)page + t2_end); |
for(e=page;e<e2;e++) { |
e->start = start; |
e->size = size; |
} |
add_region(e, start, size); |
} |
} |
/* delete a region */ |
static inline void delete_region(BoundEntry *e, |
void *p, unsigned long empty_size) |
{ |
unsigned long addr; |
BoundEntry *e1; |
addr = (unsigned long)p; |
addr -= e->start; |
if (addr <= e->size) { |
/* region found is first one */ |
e1 = e->next; |
if (e1 == NULL) { |
/* no more region: mark it empty */ |
e->start = 0; |
e->size = empty_size; |
} else { |
/* copy next region in head */ |
e->start = e1->start; |
e->size = e1->size; |
e->next = e1->next; |
bound_free_entry(e1); |
} |
} else { |
/* find the matching region */ |
for(;;) { |
e1 = e; |
e = e->next; |
/* region not found: do nothing */ |
if (e == NULL) |
break; |
addr = (unsigned long)p - e->start; |
if (addr <= e->size) { |
/* found: remove entry */ |
e1->next = e->next; |
bound_free_entry(e); |
break; |
} |
} |
} |
} |
/* WARNING: 'p' must be the starting point of the region. */ |
/* return non zero if error */ |
int __bound_delete_region(void *p) |
{ |
unsigned long start, end, addr, size, empty_size; |
BoundEntry *page, *e, *e2; |
int t1_start, t1_end, t2_start, t2_end, i; |
start = (unsigned long)p; |
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS); |
t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) & |
((BOUND_T2_SIZE - 1) << BOUND_E_BITS); |
/* find region size */ |
page = __bound_t1[t1_start]; |
e = (BoundEntry *)((char *)page + t2_start); |
addr = start - e->start; |
if (addr > e->size) |
e = __bound_find_region(e, p); |
/* test if invalid region */ |
if (e->size == EMPTY_SIZE || (unsigned long)p != e->start) |
return -1; |
/* compute the size we put in invalid regions */ |
if (e->is_invalid) |
empty_size = INVALID_SIZE; |
else |
empty_size = EMPTY_SIZE; |
size = e->size; |
end = start + size; |
/* now we can free each entry */ |
t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS); |
t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) & |
((BOUND_T2_SIZE - 1) << BOUND_E_BITS); |
delete_region(e, p, empty_size); |
if (t1_end == t1_start) { |
/* same ending page */ |
e2 = (BoundEntry *)((char *)page + t2_end); |
if (e2 > e) { |
e++; |
for(;e<e2;e++) { |
e->start = 0; |
e->size = empty_size; |
} |
delete_region(e, p, empty_size); |
} |
} else { |
/* mark until end of page */ |
e2 = page + BOUND_T2_SIZE; |
e++; |
for(;e<e2;e++) { |
e->start = 0; |
e->size = empty_size; |
} |
/* mark intermediate pages, if any */ |
/* XXX: should free them */ |
for(i=t1_start+1;i<t1_end;i++) { |
page = get_page(i); |
e2 = page + BOUND_T2_SIZE; |
for(e=page;e<e2;e++) { |
e->start = 0; |
e->size = empty_size; |
} |
} |
/* last page */ |
page = get_page(t2_end); |
e2 = (BoundEntry *)((char *)page + t2_end); |
for(e=page;e<e2;e++) { |
e->start = 0; |
e->size = empty_size; |
} |
delete_region(e, p, empty_size); |
} |
return 0; |
} |
/* return the size of the region starting at p, or EMPTY_SIZE if non |
existant region. */ |
static unsigned long get_region_size(void *p) |
{ |
unsigned long addr = (unsigned long)p; |
BoundEntry *e; |
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; |
e = (BoundEntry *)((char *)e + |
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & |
((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); |
addr -= e->start; |
if (addr > e->size) |
e = __bound_find_region(e, p); |
if (e->start != (unsigned long)p) |
return EMPTY_SIZE; |
return e->size; |
} |
/* patched memory functions */ |
static void install_malloc_hooks(void) |
{ |
#ifdef CONFIG_TCC_MALLOC_HOOKS |
saved_malloc_hook = __malloc_hook; |
saved_free_hook = __free_hook; |
saved_realloc_hook = __realloc_hook; |
saved_memalign_hook = __memalign_hook; |
__malloc_hook = __bound_malloc; |
__free_hook = __bound_free; |
__realloc_hook = __bound_realloc; |
__memalign_hook = __bound_memalign; |
#endif |
} |
static void restore_malloc_hooks(void) |
{ |
#ifdef CONFIG_TCC_MALLOC_HOOKS |
__malloc_hook = saved_malloc_hook; |
__free_hook = saved_free_hook; |
__realloc_hook = saved_realloc_hook; |
__memalign_hook = saved_memalign_hook; |
#endif |
} |
static void *libc_malloc(size_t size) |
{ |
void *ptr; |
restore_malloc_hooks(); |
ptr = malloc(size); |
install_malloc_hooks(); |
return ptr; |
} |
static void libc_free(void *ptr) |
{ |
restore_malloc_hooks(); |
free(ptr); |
install_malloc_hooks(); |
} |
/* XXX: we should use a malloc which ensure that it is unlikely that |
two malloc'ed data have the same address if 'free' are made in |
between. */ |
void *__bound_malloc(size_t size, const void *caller) |
{ |
void *ptr; |
/* we allocate one more byte to ensure the regions will be |
separated by at least one byte. With the glibc malloc, it may |
be in fact not necessary */ |
ptr = libc_malloc(size + 1); |
if (!ptr) |
return NULL; |
__bound_new_region(ptr, size); |
return ptr; |
} |
void *__bound_memalign(size_t size, size_t align, const void *caller) |
{ |
void *ptr; |
restore_malloc_hooks(); |
#ifndef HAVE_MEMALIGN |
if (align > 4) { |
/* XXX: handle it ? */ |
ptr = NULL; |
} else { |
/* we suppose that malloc aligns to at least four bytes */ |
ptr = malloc(size + 1); |
} |
#else |
/* we allocate one more byte to ensure the regions will be |
separated by at least one byte. With the glibc malloc, it may |
be in fact not necessary */ |
ptr = memalign(size + 1, align); |
#endif |
install_malloc_hooks(); |
if (!ptr) |
return NULL; |
__bound_new_region(ptr, size); |
return ptr; |
} |
void __bound_free(void *ptr, const void *caller) |
{ |
if (ptr == NULL) |
return; |
if (__bound_delete_region(ptr) != 0) |
bound_error("freeing invalid region"); |
libc_free(ptr); |
} |
void *__bound_realloc(void *ptr, size_t size, const void *caller) |
{ |
void *ptr1; |
int old_size; |
if (size == 0) { |
__bound_free(ptr, caller); |
return NULL; |
} else { |
ptr1 = __bound_malloc(size, caller); |
if (ptr == NULL || ptr1 == NULL) |
return ptr1; |
old_size = get_region_size(ptr); |
if (old_size == EMPTY_SIZE) |
bound_error("realloc'ing invalid pointer"); |
memcpy(ptr1, ptr, old_size); |
__bound_free(ptr, caller); |
return ptr1; |
} |
} |
#ifndef CONFIG_TCC_MALLOC_HOOKS |
void *__bound_calloc(size_t nmemb, size_t size) |
{ |
void *ptr; |
size = size * nmemb; |
ptr = __bound_malloc(size, NULL); |
if (!ptr) |
return NULL; |
memset(ptr, 0, size); |
return ptr; |
} |
#endif |
#if 0 |
static void bound_dump(void) |
{ |
BoundEntry *page, *e; |
int i, j; |
printf("region dump:\n"); |
for(i=0;i<BOUND_T1_SIZE;i++) { |
page = __bound_t1[i]; |
for(j=0;j<BOUND_T2_SIZE;j++) { |
e = page + j; |
/* do not print invalid or empty entries */ |
if (e->size != EMPTY_SIZE && e->start != 0) { |
printf("%08x:", |
(i << (BOUND_T2_BITS + BOUND_T3_BITS)) + |
(j << BOUND_T3_BITS)); |
do { |
printf(" %08lx:%08lx", e->start, e->start + e->size); |
e = e->next; |
} while (e != NULL); |
printf("\n"); |
} |
} |
} |
} |
#endif |
/* some useful checked functions */ |
/* check that (p ... p + size - 1) lies inside 'p' region, if any */ |
static void __bound_check(const void *p, size_t size) |
{ |
if (size == 0) |
return; |
p = __bound_ptr_add((void *)p, size); |
if (p == INVALID_POINTER) |
bound_error("invalid pointer"); |
} |
void *__bound_memcpy(void *dst, const void *src, size_t size) |
{ |
__bound_check(dst, size); |
__bound_check(src, size); |
/* check also region overlap */ |
if (src >= dst && src < dst + size) |
bound_error("overlapping regions in memcpy()"); |
return memcpy(dst, src, size); |
} |
void *__bound_memmove(void *dst, const void *src, size_t size) |
{ |
__bound_check(dst, size); |
__bound_check(src, size); |
return memmove(dst, src, size); |
} |
void *__bound_memset(void *dst, int c, size_t size) |
{ |
__bound_check(dst, size); |
return memset(dst, c, size); |
} |
/* XXX: could be optimized */ |
int __bound_strlen(const char *s) |
{ |
const char *p; |
int len; |
len = 0; |
for(;;) { |
p = __bound_ptr_indir1((char *)s, len); |
if (p == INVALID_POINTER) |
bound_error("bad pointer in strlen()"); |
if (*p == '\0') |
break; |
len++; |
} |
return len; |
} |
char *__bound_strcpy(char *dst, const char *src) |
{ |
int len; |
len = __bound_strlen(src); |
return __bound_memcpy(dst, src, len + 1); |
} |
/programs/develop/ktcc/trunk/source/boundtest.c |
---|
0,0 → 1,214 |
#include <stdlib.h> |
#include <stdio.h> |
#define NB_ITS 1000000 |
//#define NB_ITS 1 |
#define TAB_SIZE 100 |
int tab[TAB_SIZE]; |
int ret_sum; |
char tab3[256]; |
int test1(void) |
{ |
int i, sum = 0; |
for(i=0;i<TAB_SIZE;i++) { |
sum += tab[i]; |
} |
return sum; |
} |
/* error */ |
int test2(void) |
{ |
int i, sum = 0; |
for(i=0;i<TAB_SIZE + 1;i++) { |
sum += tab[i]; |
} |
return sum; |
} |
/* actually, profiling test */ |
int test3(void) |
{ |
int sum; |
int i, it; |
sum = 0; |
for(it=0;it<NB_ITS;it++) { |
for(i=0;i<TAB_SIZE;i++) { |
sum += tab[i]; |
} |
} |
return sum; |
} |
/* ok */ |
int test4(void) |
{ |
int i, sum = 0; |
int *tab4; |
tab4 = malloc(20 * sizeof(int)); |
for(i=0;i<20;i++) { |
sum += tab4[i]; |
} |
free(tab4); |
return sum; |
} |
/* error */ |
int test5(void) |
{ |
int i, sum = 0; |
int *tab4; |
tab4 = malloc(20 * sizeof(int)); |
for(i=0;i<21;i++) { |
sum += tab4[i]; |
} |
free(tab4); |
return sum; |
} |
/* error */ |
/* XXX: currently: bug */ |
int test6(void) |
{ |
int i, sum = 0; |
int *tab4; |
tab4 = malloc(20 * sizeof(int)); |
free(tab4); |
for(i=0;i<21;i++) { |
sum += tab4[i]; |
} |
return sum; |
} |
/* error */ |
int test7(void) |
{ |
int i, sum = 0; |
int *p; |
for(i=0;i<TAB_SIZE + 1;i++) { |
p = &tab[i]; |
if (i == TAB_SIZE) |
printf("i=%d %x\n", i, p); |
sum += *p; |
} |
return sum; |
} |
/* ok */ |
int test8(void) |
{ |
int i, sum = 0; |
int tab[10]; |
for(i=0;i<10;i++) { |
sum += tab[i]; |
} |
return sum; |
} |
/* error */ |
int test9(void) |
{ |
int i, sum = 0; |
char tab[10]; |
for(i=0;i<11;i++) { |
sum += tab[i]; |
} |
return sum; |
} |
/* ok */ |
int test10(void) |
{ |
char tab[10]; |
char tab1[10]; |
memset(tab, 0, 10); |
memcpy(tab, tab1, 10); |
memmove(tab, tab1, 10); |
return 0; |
} |
/* error */ |
int test11(void) |
{ |
char tab[10]; |
memset(tab, 0, 11); |
return 0; |
} |
/* error */ |
int test12(void) |
{ |
void *ptr; |
ptr = malloc(10); |
free(ptr); |
free(ptr); |
return 0; |
} |
/* error */ |
int test13(void) |
{ |
char pad1 = 0; |
char tab[10]; |
char pad2 = 0; |
memset(tab, 'a', sizeof(tab)); |
return strlen(tab); |
} |
int (*table_test[])(void) = { |
test1, |
test1, |
test2, |
test3, |
test4, |
test5, |
test6, |
test7, |
test8, |
test9, |
test10, |
test11, |
test12, |
test13, |
}; |
int main(int argc, char **argv) |
{ |
int index; |
int (*ftest)(void); |
if (argc < 2) { |
printf("usage: boundtest n\n" |
"test TCC bound checking system\n" |
); |
exit(1); |
} |
index = 0; |
if (argc >= 2) |
index = atoi(argv[1]); |
/* well, we also use bounds on this ! */ |
ftest = table_test[index]; |
ftest(); |
return 0; |
} |
/* |
* without bound 0.77 s |
* with bounds 4.73 |
*/ |
/programs/develop/ktcc/trunk/source/c67-gen.c |
---|
18,10 → 18,8 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
*/ |
#ifdef TARGET_DEFS_ONLY |
//#define ASSEMBLY_LISTING_C67 |
/* #define ASSEMBLY_LISTING_C67 */ |
/* number of available registers */ |
#define NB_REGS 24 |
87,47 → 85,7 |
TREG_C67_B13, |
}; |
/* return registers for function */ |
#define REG_IRET TREG_C67_A4 /* single word int return register */ |
#define REG_LRET TREG_C67_A5 /* second word return register (for long long) */ |
#define REG_FRET TREG_C67_A4 /* float return register */ |
/* defined if function parameters must be evaluated in reverse order */ |
/* #define INVERT_FUNC_PARAMS */ |
/* defined if structures are passed as pointers. Otherwise structures |
are directly pushed on stack. */ |
/* #define FUNC_STRUCT_PARAM_AS_PTR */ |
/* pointer size, in bytes */ |
#define PTR_SIZE 4 |
/* long double size and alignment, in bytes */ |
#define LDOUBLE_SIZE 12 |
#define LDOUBLE_ALIGN 4 |
/* maximum alignment (for aligned attribute support) */ |
#define MAX_ALIGN 8 |
/******************************************************/ |
/* ELF defines */ |
#define EM_TCC_TARGET EM_C60 |
/* relocation type for 32 bit data relocation */ |
#define R_DATA_32 R_C60_32 |
#define R_DATA_PTR R_C60_32 |
#define R_JMP_SLOT R_C60_JMP_SLOT |
#define R_COPY R_C60_COPY |
#define ELF_START_ADDR 0x00000400 |
#define ELF_PAGE_SIZE 0x1000 |
/******************************************************/ |
#else /* ! TARGET_DEFS_ONLY */ |
/******************************************************/ |
#include "tcc.h" |
ST_DATA const int reg_classes[NB_REGS] = { |
int reg_classes[NB_REGS] = { |
/* eax */ RC_INT | RC_FLOAT | RC_EAX, |
// only allow even regs for floats (allow for doubles) |
/* ecx */ RC_INT | RC_ECX, |
156,6 → 114,18 |
/* B13 */ RC_C67_B11 |
}; |
/* return registers for function */ |
#define REG_IRET TREG_C67_A4 /* single word int return register */ |
#define REG_LRET TREG_C67_A5 /* second word return register (for long long) */ |
#define REG_FRET TREG_C67_A4 /* float return register */ |
#define ALWAYS_ASSERT(x) \ |
do {\ |
if (!(x))\ |
error("internal compiler error file at %s:%d", __FILE__, __LINE__);\ |
} while (0) |
// although tcc thinks it is passing parameters on the stack, |
// the C67 really passes up to the first 10 params in special |
// regs or regs pairs (for 64 bit params). So keep track of |
162,6 → 132,7 |
// the stack offsets so we can translate to the appropriate |
// reg (pair) |
#define NoCallArgsPassedOnStack 10 |
int NoOfCurFuncArgs; |
int TranslateStackToReg[NoCallArgsPassedOnStack]; |
168,24 → 139,42 |
int ParamLocOnStack[NoCallArgsPassedOnStack]; |
int TotalBytesPushedOnStack; |
#ifndef FALSE |
# define FALSE 0 |
# define TRUE 1 |
#endif |
/* defined if function parameters must be evaluated in reverse order */ |
#undef BOOL |
#define BOOL int |
//#define INVERT_FUNC_PARAMS |
#define ALWAYS_ASSERT(x) \ |
do {\ |
if (!(x))\ |
tcc_error("internal compiler error file at %s:%d", __FILE__, __LINE__);\ |
} while (0) |
/* defined if structures are passed as pointers. Otherwise structures |
are directly pushed on stack. */ |
//#define FUNC_STRUCT_PARAM_AS_PTR |
/* pointer size, in bytes */ |
#define PTR_SIZE 4 |
/* long double size and alignment, in bytes */ |
#define LDOUBLE_SIZE 12 |
#define LDOUBLE_ALIGN 4 |
/* maximum alignment (for aligned attribute support) */ |
#define MAX_ALIGN 8 |
/******************************************************/ |
/* ELF defines */ |
#define EM_TCC_TARGET EM_C60 |
/* relocation type for 32 bit data relocation */ |
#define R_DATA_32 R_C60_32 |
#define R_JMP_SLOT R_C60_JMP_SLOT |
#define R_COPY R_C60_COPY |
#define ELF_START_ADDR 0x00000400 |
#define ELF_PAGE_SIZE 0x1000 |
/******************************************************/ |
static unsigned long func_sub_sp_offset; |
static int func_ret_sub; |
static BOOL C67_invert_test; |
static int C67_compare_reg; |
193,6 → 182,7 |
FILE *f = NULL; |
#endif |
void C67_g(int c) |
{ |
int ind1; |
245,8 → 235,8 |
} |
// these are regs that tcc doesn't really know about, |
// but assign them unique values so the mapping routines |
// can distinguish them |
// but asign them unique values so the mapping routines |
// can distinquish them |
#define C67_A0 105 |
#define C67_SP 106 |
253,7 → 243,7 |
#define C67_B3 107 |
#define C67_FP 108 |
#define C67_B2 109 |
#define C67_CREG_ZERO -1 /* Special code for no condition reg test */ |
#define C67_CREG_ZERO -1 // Special code for no condition reg test |
int ConvertRegToRegClass(int r) |
1562,12 → 1552,12 |
void load(int r, SValue * sv) |
{ |
int v, t, ft, fc, fr, size = 0, element; |
BOOL Unsigned = FALSE; |
BOOL Unsigned = false; |
SValue v1; |
fr = sv->r; |
ft = sv->type.t; |
fc = sv->c.i; |
fc = sv->c.ul; |
v = fr & VT_VALMASK; |
if (fr & VT_LVAL) { |
1574,11 → 1564,11 |
if (v == VT_LLOCAL) { |
v1.type.t = VT_INT; |
v1.r = VT_LOCAL | VT_LVAL; |
v1.c.i = fc; |
v1.c.ul = fc; |
load(r, &v1); |
fr = r; |
} else if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
tcc_error("long double not supported"); |
error("long double not supported"); |
} else if ((ft & VT_TYPE) == VT_BYTE) { |
size = 1; |
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { |
1726,13 → 1716,13 |
int fr, bt, ft, fc, size, t, element; |
ft = v->type.t; |
fc = v->c.i; |
fc = v->c.ul; |
fr = v->r & VT_VALMASK; |
bt = ft & VT_BTYPE; |
/* XXX: incorrect if float reg to reg */ |
if (bt == VT_LDOUBLE) { |
tcc_error("long double not supported"); |
error("long double not supported"); |
} else { |
if (bt == VT_SHORT) |
size = 2; |
1879,13 → 1869,6 |
} |
} |
/* Return the number of registers needed to return the struct, or 0 if |
returning via struct pointer. */ |
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) { |
*ret_align = 1; // Never have to re-align return values for x86-64 |
return 0; |
} |
/* generate function call with address in (vtop->t, vtop->c) and free function |
context. Stack entry is popped */ |
void gfunc_call(int nb_args) |
1894,7 → 1877,7 |
int args_sizes[NoCallArgsPassedOnStack]; |
if (nb_args > NoCallArgsPassedOnStack) { |
tcc_error("more than 10 function params not currently supported"); |
error("more than 10 function params not currently supported"); |
// handle more than 10, put some on the stack |
} |
1901,6 → 1884,8 |
for (i = 0; i < nb_args; i++) { |
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { |
ALWAYS_ASSERT(FALSE); |
} else if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { |
ALWAYS_ASSERT(FALSE); |
} else { |
/* simple type (currently always same size) */ |
/* XXX: implicit cast ? */ |
1907,9 → 1892,9 |
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
tcc_error("long long not supported"); |
error("long long not supported"); |
} else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { |
tcc_error("long double not supported"); |
error("long double not supported"); |
} else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) { |
size = 8; |
} else { |
1969,7 → 1954,6 |
/* if the function returns a structure, then add an |
implicit pointer parameter */ |
func_vt = sym->type; |
func_var = (sym->c == FUNC_ELLIPSIS); |
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
func_vc = addr; |
addr += 4; |
1980,7 → 1964,7 |
/* define parameters */ |
while ((sym = sym->next) != NULL) { |
type = &sym->type; |
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr); |
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); |
size = type_size(type, &align); |
size = (size + 3) & ~3; |
2106,12 → 2090,13 |
/* && or || optimization */ |
if ((v & 1) == inv) { |
/* insert vtop->c jump list in t */ |
p = &vtop->c.i; |
// I guess the idea is to traverse to the |
// null at the end of the list and store t |
// there |
n = vtop->c.i; |
n = *p; |
while (n != 0) { |
p = (int *) (cur_text_section->data + n); |
2127,7 → 2112,38 |
t = gjmp(t); |
gsym(vtop->c.i); |
} |
} else { |
if (is_float(vtop->type.t)) { |
vpushi(0); |
gen_op(TOK_NE); |
} |
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
/* constant jmp optimization */ |
if ((vtop->c.i != 0) != inv) |
t = gjmp(t); |
} else { |
// I think we need to get the value on the stack |
// into a register, test it, and generate a branch |
// return the address of the branch, so it can be |
// later patched |
v = gv(RC_INT); // get value into a reg |
ind1 = ind; |
C67_MVKL(C67_A0, t); //r=reg to load, constant |
C67_MVKH(C67_A0, t); //r=reg to load, constant |
if (v != TREG_EAX && // check if not already in a conditional test reg |
v != TREG_EDX && v != TREG_ST0 && v != C67_B2) { |
C67_MV(v, C67_B2); |
v = C67_B2; |
} |
C67_IREG_B_REG(inv, v, C67_A0); // [!R] B.S2x A0 |
C67_NOP(5); |
t = ind1; //return where we need to patch |
ind1 = ind; |
} |
} |
vtop--; |
return t; |
} |
2162,34 → 2178,34 |
if (op == TOK_LT) { |
C67_CMPLT(r, fr, C67_B2); |
C67_invert_test = FALSE; |
C67_invert_test = false; |
} else if (op == TOK_GE) { |
C67_CMPLT(r, fr, C67_B2); |
C67_invert_test = TRUE; |
C67_invert_test = true; |
} else if (op == TOK_GT) { |
C67_CMPGT(r, fr, C67_B2); |
C67_invert_test = FALSE; |
C67_invert_test = false; |
} else if (op == TOK_LE) { |
C67_CMPGT(r, fr, C67_B2); |
C67_invert_test = TRUE; |
C67_invert_test = true; |
} else if (op == TOK_EQ) { |
C67_CMPEQ(r, fr, C67_B2); |
C67_invert_test = FALSE; |
C67_invert_test = false; |
} else if (op == TOK_NE) { |
C67_CMPEQ(r, fr, C67_B2); |
C67_invert_test = TRUE; |
C67_invert_test = true; |
} else if (op == TOK_ULT) { |
C67_CMPLTU(r, fr, C67_B2); |
C67_invert_test = FALSE; |
C67_invert_test = false; |
} else if (op == TOK_UGE) { |
C67_CMPLTU(r, fr, C67_B2); |
C67_invert_test = TRUE; |
C67_invert_test = true; |
} else if (op == TOK_UGT) { |
C67_CMPGTU(r, fr, C67_B2); |
C67_invert_test = FALSE; |
C67_invert_test = false; |
} else if (op == TOK_ULE) { |
C67_CMPGTU(r, fr, C67_B2); |
C67_invert_test = TRUE; |
C67_invert_test = true; |
} else if (op == '+') |
C67_ADD(fr, r); // ADD r,fr,r |
else if (op == '-') |
2303,13 → 2319,13 |
gv2(RC_FLOAT, RC_FLOAT); // make sure src2 is on b side |
ft = vtop->type.t; |
fc = vtop->c.i; |
fc = vtop->c.ul; |
r = vtop->r; |
fr = vtop[-1].r; |
if ((ft & VT_BTYPE) == VT_LDOUBLE) |
tcc_error("long doubles not supported"); |
error("long doubles not supported"); |
if (op >= TOK_ULT && op <= TOK_GT) { |
2324,7 → 2340,7 |
else |
C67_CMPLTSP(r, fr, C67_B2); |
C67_invert_test = FALSE; |
C67_invert_test = false; |
} else if (op == TOK_GE) { |
if ((ft & VT_BTYPE) == VT_DOUBLE) |
C67_CMPLTDP(r, fr, C67_B2); |
2331,7 → 2347,7 |
else |
C67_CMPLTSP(r, fr, C67_B2); |
C67_invert_test = TRUE; |
C67_invert_test = true; |
} else if (op == TOK_GT) { |
if ((ft & VT_BTYPE) == VT_DOUBLE) |
C67_CMPGTDP(r, fr, C67_B2); |
2338,7 → 2354,7 |
else |
C67_CMPGTSP(r, fr, C67_B2); |
C67_invert_test = FALSE; |
C67_invert_test = false; |
} else if (op == TOK_LE) { |
if ((ft & VT_BTYPE) == VT_DOUBLE) |
C67_CMPGTDP(r, fr, C67_B2); |
2345,7 → 2361,7 |
else |
C67_CMPGTSP(r, fr, C67_B2); |
C67_invert_test = TRUE; |
C67_invert_test = true; |
} else if (op == TOK_EQ) { |
if ((ft & VT_BTYPE) == VT_DOUBLE) |
C67_CMPEQDP(r, fr, C67_B2); |
2352,7 → 2368,7 |
else |
C67_CMPEQSP(r, fr, C67_B2); |
C67_invert_test = FALSE; |
C67_invert_test = false; |
} else if (op == TOK_NE) { |
if ((ft & VT_BTYPE) == VT_DOUBLE) |
C67_CMPEQDP(r, fr, C67_B2); |
2359,7 → 2375,7 |
else |
C67_CMPEQSP(r, fr, C67_B2); |
C67_invert_test = TRUE; |
C67_invert_test = true; |
} else { |
ALWAYS_ASSERT(FALSE); |
} |
2461,7 → 2477,7 |
r = vtop->r; |
if (t != VT_INT) |
tcc_error("long long not supported"); |
error("long long not supported"); |
else { |
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) { |
C67_DPTRUNC(r, r); |
2528,22 → 2544,5 |
vtop--; |
} |
/* Save the stack pointer onto the stack and return the location of its address */ |
ST_FUNC void gen_vla_sp_save(int addr) { |
tcc_error("variable length arrays unsupported for this target"); |
} |
/* Restore the SP from a location on the stack */ |
ST_FUNC void gen_vla_sp_restore(int addr) { |
tcc_error("variable length arrays unsupported for this target"); |
} |
/* Subtract from the stack pointer, and push the resulting value onto the stack */ |
ST_FUNC void gen_vla_alloc(CType *type, int align) { |
tcc_error("variable length arrays unsupported for this target"); |
} |
/* end of C67 code generator */ |
/* end of X86 code generator */ |
/*************************************************************/ |
#endif |
/*************************************************************/ |
/programs/develop/ktcc/trunk/source/coff.h |
---|
37,8 → 37,8 |
#define F_BYTE_ORDER (F_LITTLE | F_BIG) |
#define FILHDR struct filehdr |
/* #define FILHSZ sizeof(FILHDR) */ |
#define FILHSZ 22 /* above rounds to align on 4 bytes which causes problems */ |
//#define FILHSZ sizeof(FILHDR) |
#define FILHSZ 22 // above rounds to align on 4 bytes which causes problems |
#define COFF_C67_MAGIC 0x00c2 |
150,7 → 150,7 |
/*------------------------------------------------------------------------*/ |
/* Define constants for names of "special" sections */ |
/*------------------------------------------------------------------------*/ |
/* #define _TEXT ".text" */ |
//#define _TEXT ".text" |
#define _DATA ".data" |
#define _BSS ".bss" |
#define _CINIT ".cinit" |
/programs/develop/ktcc/trunk/source/elf.h |
---|
1,25 → 1,27 |
/* This file defines standard ELF types, structures, and macros. |
Copyright (C) 1995-2012 Free Software Foundation, Inc. |
Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ian Lance Taylor <ian@cygnus.com>. |
The GNU C Library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Lesser General Public |
License as published by the Free Software Foundation; either |
version 2.1 of the License, or (at your option) any later version. |
modify it under the terms of the GNU Library General Public License as |
published by the Free Software Foundation; either version 2 of the |
License, or (at your option) any later version. |
The GNU C Library is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
Lesser General Public License for more details. |
Library General Public License for more details. |
You should have received a copy of the GNU Lesser General Public |
License along with the GNU C Library; if not, see |
<http://www.gnu.org/licenses/>. */ |
You should have received a copy of the GNU Library General Public |
License along with the GNU C Library; see the file COPYING.LIB. If not, |
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
#ifndef _ELF_H |
#define _ELF_H 1 |
#ifndef _WIN32 |
#ifndef WIN32 |
#include <inttypes.h> |
#else |
#ifndef __int8_t_defined |
66,9 → 68,9 |
typedef uint16_t Elf32_Section; |
typedef uint16_t Elf64_Section; |
/* Type for version symbol information. */ |
typedef Elf32_Half Elf32_Versym; |
typedef Elf64_Half Elf64_Versym; |
/* Type of symbol indices. */ |
typedef uint32_t Elf32_Symndx; |
typedef uint64_t Elf64_Symndx; |
/* The ELF file header. This appears at the start of every ELF file. */ |
147,20 → 149,9 |
/* Value must be EV_CURRENT */ |
#define EI_OSABI 7 /* OS ABI identification */ |
#define ELFOSABI_NONE 0 /* UNIX System V ABI */ |
#define ELFOSABI_SYSV 0 /* Alias. */ |
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ |
#define ELFOSABI_HPUX 1 /* HP-UX */ |
#define ELFOSABI_NETBSD 2 /* NetBSD. */ |
#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ |
#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ |
#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ |
#define ELFOSABI_AIX 7 /* IBM AIX. */ |
#define ELFOSABI_IRIX 8 /* SGI Irix. */ |
#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ |
#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ |
#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ |
#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ |
#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ |
#define ELFOSABI_FREEBSD 9 /* Free BSD */ |
#define ELFOSABI_ARM 97 /* ARM */ |
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ |
176,10 → 167,8 |
#define ET_DYN 3 /* Shared object file */ |
#define ET_CORE 4 /* Core file */ |
#define ET_NUM 5 /* Number of defined types */ |
#define ET_LOOS 0xfe00 /* OS-specific range start */ |
#define ET_HIOS 0xfeff /* OS-specific range end */ |
#define ET_LOPROC 0xff00 /* Processor-specific range start */ |
#define ET_HIPROC 0xffff /* Processor-specific range end */ |
#define ET_LOPROC 0xff00 /* Processor-specific */ |
#define ET_HIPROC 0xffff /* Processor-specific */ |
/* Legal values for e_machine (architecture). */ |
189,23 → 178,24 |
#define EM_386 3 /* Intel 80386 */ |
#define EM_68K 4 /* Motorola m68k family */ |
#define EM_88K 5 /* Motorola m88k family */ |
#define EM_486 6 /* Intel 80486 */ |
#define EM_860 7 /* Intel 80860 */ |
#define EM_MIPS 8 /* MIPS R3000 big-endian */ |
#define EM_S370 9 /* IBM System/370 */ |
#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ |
#define EM_S370 9 /* Amdahl */ |
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ |
#define EM_RS6000 11 /* RS6000 */ |
#define EM_PARISC 15 /* HPPA */ |
#define EM_nCUBE 16 /* nCUBE */ |
#define EM_VPP500 17 /* Fujitsu VPP500 */ |
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ |
#define EM_960 19 /* Intel 80960 */ |
#define EM_PPC 20 /* PowerPC */ |
#define EM_PPC64 21 /* PowerPC 64-bit */ |
#define EM_S390 22 /* IBM S390 */ |
#define EM_V800 36 /* NEC V800 series */ |
#define EM_FR20 37 /* Fujitsu FR20 */ |
#define EM_RH32 38 /* TRW RH-32 */ |
#define EM_RCE 39 /* Motorola RCE */ |
#define EM_RH32 38 /* TRW RH32 */ |
#define EM_MMA 39 /* Fujitsu MMA */ |
#define EM_ARM 40 /* ARM */ |
#define EM_FAKE_ALPHA 41 /* Digital Alpha */ |
#define EM_SH 42 /* Hitachi SH */ |
220,51 → 210,8 |
#define EM_MIPS_X 51 /* Stanford MIPS-X */ |
#define EM_COLDFIRE 52 /* Motorola Coldfire */ |
#define EM_68HC12 53 /* Motorola M68HC12 */ |
#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ |
#define EM_PCP 55 /* Siemens PCP */ |
#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ |
#define EM_NDR1 57 /* Denso NDR1 microprocessor */ |
#define EM_STARCORE 58 /* Motorola Start*Core processor */ |
#define EM_ME16 59 /* Toyota ME16 processor */ |
#define EM_ST100 60 /* STMicroelectronic ST100 processor */ |
#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ |
#define EM_X86_64 62 /* AMD x86-64 architecture */ |
#define EM_PDSP 63 /* Sony DSP Processor */ |
#define EM_NUM 54 |
#define EM_FX66 66 /* Siemens FX66 microcontroller */ |
#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ |
#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ |
#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ |
#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ |
#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ |
#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ |
#define EM_SVX 73 /* Silicon Graphics SVx */ |
#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ |
#define EM_VAX 75 /* Digital VAX */ |
#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ |
#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ |
#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ |
#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ |
#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ |
#define EM_HUANY 81 /* Harvard University machine-independent object files */ |
#define EM_PRISM 82 /* SiTera Prism */ |
#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ |
#define EM_FR30 84 /* Fujitsu FR30 */ |
#define EM_D10V 85 /* Mitsubishi D10V */ |
#define EM_D30V 86 /* Mitsubishi D30V */ |
#define EM_V850 87 /* NEC v850 */ |
#define EM_M32R 88 /* Mitsubishi M32R */ |
#define EM_MN10300 89 /* Matsushita MN10300 */ |
#define EM_MN10200 90 /* Matsushita MN10200 */ |
#define EM_PJ 91 /* picoJava */ |
#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ |
#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ |
#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ |
#define EM_AARCH64 183 /* ARM AARCH64 */ |
#define EM_TILEPRO 188 /* Tilera TILEPro */ |
#define EM_TILEGX 191 /* Tilera TILE-Gx */ |
#define EM_NUM 192 |
/* If it is necessary to assign new unofficial EM_* values, please |
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the |
chances of collision with official or non-GNU unofficial values. */ |
313,16 → 260,9 |
#define SHN_UNDEF 0 /* Undefined section */ |
#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ |
#define SHN_LOPROC 0xff00 /* Start of processor-specific */ |
#define SHN_BEFORE 0xff00 /* Order section before all others |
(Solaris). */ |
#define SHN_AFTER 0xff01 /* Order section after all others |
(Solaris). */ |
#define SHN_HIPROC 0xff1f /* End of processor-specific */ |
#define SHN_LOOS 0xff20 /* Start of OS-specific */ |
#define SHN_HIOS 0xff3f /* End of OS-specific */ |
#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ |
#define SHN_COMMON 0xfff2 /* Associated symbol is common */ |
#define SHN_XINDEX 0xffff /* Index is in extra table. */ |
#define SHN_HIRESERVE 0xffff /* End of reserved indices */ |
/* Legal values for sh_type (section type). */ |
339,19 → 279,9 |
#define SHT_REL 9 /* Relocation entries, no addends */ |
#define SHT_SHLIB 10 /* Reserved */ |
#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ |
#define SHT_INIT_ARRAY 14 /* Array of constructors */ |
#define SHT_FINI_ARRAY 15 /* Array of destructors */ |
#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ |
#define SHT_GROUP 17 /* Section group */ |
#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ |
#define SHT_NUM 19 /* Number of defined types. */ |
#define SHT_LOOS 0x60000000 /* Start OS-specific. */ |
#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ |
#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ |
#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ |
#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ |
#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ |
#define SHT_SUNW_move 0x6ffffffa |
#define SHT_NUM 12 /* Number of defined types. */ |
#define SHT_LOOS 0x60000000 /* Start OS-specific */ |
#define SHT_LOSUNW 0x6ffffffb /* Sun-specific low bound. */ |
#define SHT_SUNW_COMDAT 0x6ffffffb |
#define SHT_SUNW_syminfo 0x6ffffffc |
#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ |
369,24 → 299,8 |
#define SHF_WRITE (1 << 0) /* Writable */ |
#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ |
#define SHF_EXECINSTR (1 << 2) /* Executable */ |
#define SHF_MERGE (1 << 4) /* Might be merged */ |
#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ |
#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ |
#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ |
#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling |
required */ |
#define SHF_GROUP (1 << 9) /* Section is member of a group. */ |
#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ |
#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ |
#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ |
#define SHF_ORDERED (1 << 30) /* Special ordering requirement |
(Solaris). */ |
#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless |
referenced or allocated (Solaris).*/ |
/* Section group handling. */ |
#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ |
/* Symbol table entry. */ |
typedef struct |
395,7 → 309,7 |
Elf32_Addr st_value; /* Symbol value */ |
Elf32_Word st_size; /* Symbol size */ |
unsigned char st_info; /* Symbol type and binding */ |
unsigned char st_other; /* Symbol visibility */ |
unsigned char st_other; /* No defined meaning, 0 */ |
Elf32_Section st_shndx; /* Section index */ |
} Elf32_Sym; |
403,7 → 317,7 |
{ |
Elf64_Word st_name; /* Symbol name (string tbl index) */ |
unsigned char st_info; /* Symbol type and binding */ |
unsigned char st_other; /* Symbol visibility */ |
unsigned char st_other; /* No defined meaning, 0 */ |
Elf64_Section st_shndx; /* Section index */ |
Elf64_Addr st_value; /* Symbol value */ |
Elf64_Xword st_size; /* Symbol size */ |
441,6 → 355,10 |
#define SYMINFO_NUM 2 |
/* Special section index. */ |
#define SHN_UNDEF 0 /* No section, undefined symbol. */ |
/* How to extract and insert information held in the st_info field. */ |
#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) |
459,7 → 377,6 |
#define STB_WEAK 2 /* Weak symbol */ |
#define STB_NUM 3 /* Number of defined types. */ |
#define STB_LOOS 10 /* Start of OS-specific */ |
#define STB_GNU_UNIQUE 10 /* Unique symbol. */ |
#define STB_HIOS 12 /* End of OS-specific */ |
#define STB_LOPROC 13 /* Start of processor-specific */ |
#define STB_HIPROC 15 /* End of processor-specific */ |
471,11 → 388,8 |
#define STT_FUNC 2 /* Symbol is a code object */ |
#define STT_SECTION 3 /* Symbol associated with a section */ |
#define STT_FILE 4 /* Symbol's name is file name */ |
#define STT_COMMON 5 /* Symbol is a common data object */ |
#define STT_TLS 6 /* Symbol is thread-local data object*/ |
#define STT_NUM 7 /* Number of defined types. */ |
#define STT_LOOS 10 /* Start of OS-specific */ |
#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ |
#define STT_NUM 5 /* Number of defined types. */ |
#define STT_LOOS 11 /* Start of OS-specific */ |
#define STT_HIOS 12 /* End of OS-specific */ |
#define STT_LOPROC 13 /* Start of processor-specific */ |
#define STT_HIPROC 15 /* End of processor-specific */ |
545,7 → 459,7 |
#define ELF64_R_SYM(i) ((i) >> 32) |
#define ELF64_R_TYPE(i) ((i) & 0xffffffff) |
#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) |
#define ELF64_R_INFO(sym,type) (((sym) << 32) + (type)) |
/* Program segment header. */ |
573,12 → 487,6 |
Elf64_Xword p_align; /* Segment alignment */ |
} Elf64_Phdr; |
/* Special value for e_phnum. This indicates that the real number of |
program headers is too large to fit into e_phnum. Instead the real |
value is in the field sh_info of section 0. */ |
#define PN_XNUM 0xffff |
/* Legal values for p_type (segment type). */ |
#define PT_NULL 0 /* Program header table entry unused */ |
588,16 → 496,8 |
#define PT_NOTE 4 /* Auxiliary information */ |
#define PT_SHLIB 5 /* Reserved */ |
#define PT_PHDR 6 /* Entry for header table itself */ |
#define PT_TLS 7 /* Thread-local storage segment */ |
#define PT_NUM 8 /* Number of defined types */ |
#define PT_NUM 7 /* Number of defined types. */ |
#define PT_LOOS 0x60000000 /* Start of OS-specific */ |
#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ |
#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ |
#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ |
#define PT_LOSUNW 0x6ffffffa |
#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ |
#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ |
#define PT_HISUNW 0x6fffffff |
#define PT_HIOS 0x6fffffff /* End of OS-specific */ |
#define PT_LOPROC 0x70000000 /* Start of processor-specific */ |
#define PT_HIPROC 0x7fffffff /* End of processor-specific */ |
607,7 → 507,6 |
#define PF_X (1 << 0) /* Segment is executable */ |
#define PF_W (1 << 1) /* Segment is writable */ |
#define PF_R (1 << 2) /* Segment is readable */ |
#define PF_MASKOS 0x0ff00000 /* OS-specific */ |
#define PF_MASKPROC 0xf0000000 /* Processor-specific */ |
/* Legal values for note segment descriptor types for core files. */ |
616,11 → 515,9 |
#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ |
#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ |
#define NT_PRXREG 4 /* Contains copy of prxregset struct */ |
#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ |
#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ |
#define NT_AUXV 6 /* Contains copy of auxv array */ |
#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ |
#define NT_ASRS 8 /* Contains copy of asrset struct */ |
#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ |
#define NT_PSINFO 13 /* Contains copy of psinfo struct */ |
#define NT_PRCRED 14 /* Contains copy of prcred struct */ |
627,26 → 524,6 |
#define NT_UTSNAME 15 /* Contains copy of utsname struct */ |
#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ |
#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ |
#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ |
#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ |
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ |
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ |
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ |
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ |
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ |
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ |
#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ |
#define NT_S390_TIMER 0x301 /* s390 timer register */ |
#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ |
#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ |
#define NT_S390_CTRS 0x304 /* s390 control registers */ |
#define NT_S390_PREFIX 0x305 /* s390 prefix register */ |
#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ |
#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ |
#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ |
#define NT_ARM_TLS 0x401 /* ARM TLS register */ |
#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ |
#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ |
/* Legal values for the note segment descriptor types for object files. */ |
692,7 → 569,7 |
#define DT_INIT 12 /* Address of init function */ |
#define DT_FINI 13 /* Address of termination function */ |
#define DT_SONAME 14 /* Name of shared object */ |
#define DT_RPATH 15 /* Library search path (deprecated) */ |
#define DT_RPATH 15 /* Library search path */ |
#define DT_SYMBOLIC 16 /* Start symbol search here */ |
#define DT_REL 17 /* Address of Rel relocs */ |
#define DT_RELSZ 18 /* Total size of Rel relocs */ |
706,14 → 583,9 |
#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ |
#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ |
#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ |
#define DT_RUNPATH 29 /* Library search path */ |
#define DT_FLAGS 30 /* Flags for the object being loaded */ |
#define DT_ENCODING 32 /* Start of encoded range */ |
#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ |
#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ |
#define DT_NUM 34 /* Number used */ |
#define DT_LOOS 0x6000000d /* Start of OS-specific */ |
#define DT_HIOS 0x6ffff000 /* End of OS-specific */ |
#define DT_NUM 29 /* Number used */ |
#define DT_LOOS 0x60000000 /* Start of OS-specific */ |
#define DT_HIOS 0x6fffffff /* End of OS-specific */ |
#define DT_LOPROC 0x70000000 /* Start of processor-specific */ |
#define DT_HIPROC 0x7fffffff /* End of processor-specific */ |
#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ |
722,21 → 594,11 |
Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's |
approach. */ |
#define DT_VALRNGLO 0x6ffffd00 |
#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ |
#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ |
#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ |
#define DT_CHECKSUM 0x6ffffdf8 |
#define DT_PLTPADSZ 0x6ffffdf9 |
#define DT_MOVEENT 0x6ffffdfa |
#define DT_MOVESZ 0x6ffffdfb |
#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ |
#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting |
the following DT_* entry. */ |
#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ |
#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ |
#define DT_VALRNGHI 0x6ffffdff |
#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ |
#define DT_VALNUM 12 |
/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the |
Dyn.d_un.d_ptr field of the Elf*_Dyn structure. |
744,28 → 606,13 |
If any adjustment is made to the ELF object after it has been |
built these entries will need to be adjusted. */ |
#define DT_ADDRRNGLO 0x6ffffe00 |
#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ |
#define DT_TLSDESC_PLT 0x6ffffef6 |
#define DT_TLSDESC_GOT 0x6ffffef7 |
#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ |
#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ |
#define DT_CONFIG 0x6ffffefa /* Configuration information. */ |
#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ |
#define DT_AUDIT 0x6ffffefc /* Object auditing. */ |
#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ |
#define DT_MOVETAB 0x6ffffefe /* Move table. */ |
#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ |
#define DT_SYMINFO 0x6ffffeff /* syminfo table */ |
#define DT_ADDRRNGHI 0x6ffffeff |
#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ |
#define DT_ADDRNUM 11 |
/* The versioning entry types. The next are defined as part of the |
GNU extension. */ |
#define DT_VERSYM 0x6ffffff0 |
#define DT_RELACOUNT 0x6ffffff9 |
#define DT_RELCOUNT 0x6ffffffa |
/* These were chosen by Sun. */ |
#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ |
#define DT_VERDEF 0x6ffffffc /* Address of version definition |
784,13 → 631,6 |
#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) |
#define DT_EXTRANUM 3 |
/* Values of `d_un.d_val' in the DT_FLAGS entry. */ |
#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ |
#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ |
#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ |
#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ |
#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ |
/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 |
entry in the dynamic section. */ |
#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ |
800,35 → 640,7 |
#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ |
#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ |
#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ |
#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ |
#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ |
#define DF_1_TRANS 0x00000200 |
#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ |
#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ |
#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ |
#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ |
#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ |
#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ |
#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ |
#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */ |
#define DF_1_IGNMULDEF 0x00040000 |
#define DF_1_NOKSYMS 0x00080000 |
#define DF_1_NOHDR 0x00100000 |
#define DF_1_EDITED 0x00200000 /* Object is modified after built. */ |
#define DF_1_NORELOC 0x00400000 |
#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */ |
#define DF_1_GLOBAUDIT 0x01000000 /* Global auditin required. */ |
#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */ |
/* Flags for the feature selection in DT_FEATURE_1. */ |
#define DTF_1_PARINIT 0x00000001 |
#define DTF_1_CONFEXP 0x00000002 |
/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ |
#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ |
#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not |
generally available. */ |
/* Version definition sections. */ |
typedef struct |
865,12 → 677,6 |
#define VER_FLG_BASE 0x1 /* Version definition of file itself */ |
#define VER_FLG_WEAK 0x2 /* Weak version identifier */ |
/* Versym symbol index values. */ |
#define VER_NDX_LOCAL 0 /* Symbol is local. */ |
#define VER_NDX_GLOBAL 1 /* Symbol is global. */ |
#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ |
#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ |
/* Auxialiary version information. */ |
typedef struct |
956,25 → 762,23 |
typedef struct |
{ |
uint32_t a_type; /* Entry type */ |
int a_type; /* Entry type */ |
union |
{ |
uint32_t a_val; /* Integer value */ |
/* We use to have pointer elements added here. We cannot do that, |
though, since it does not work when using 32-bit definitions |
on 64-bit platforms and vice versa. */ |
long int a_val; /* Integer value */ |
void *a_ptr; /* Pointer value */ |
void (*a_fcn) (void); /* Function pointer value */ |
} a_un; |
} Elf32_auxv_t; |
typedef struct |
{ |
uint64_t a_type; /* Entry type */ |
long int a_type; /* Entry type */ |
union |
{ |
uint64_t a_val; /* Integer value */ |
/* We use to have pointer elements added here. We cannot do that, |
though, since it does not work when using 32-bit definitions |
on 64-bit platforms and vice versa. */ |
long int a_val; /* Integer value */ |
void *a_ptr; /* Pointer value */ |
void (*a_fcn) (void); /* Function pointer value */ |
} a_un; |
} Elf64_auxv_t; |
995,7 → 799,6 |
#define AT_EUID 12 /* Effective uid */ |
#define AT_GID 13 /* Real gid */ |
#define AT_EGID 14 /* Effective gid */ |
#define AT_CLKTCK 17 /* Frequency of times() */ |
/* Some more special a_type values describing the hardware. */ |
#define AT_PLATFORM 15 /* String identifying platform. */ |
1004,37 → 807,9 |
/* This entry gives some information about the FPU initialization |
performed by the kernel. */ |
#define AT_FPUCW 18 /* Used FPU control word. */ |
#define AT_FPUCW 17 /* Used FPU control word. */ |
/* Cache block sizes. */ |
#define AT_DCACHEBSIZE 19 /* Data cache block size. */ |
#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ |
#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ |
/* A special ignored value for PPC, used by the kernel to control the |
interpretation of the AUXV. Must be > 16. */ |
#define AT_IGNOREPPC 22 /* Entry should be ignored. */ |
#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ |
#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ |
#define AT_RANDOM 25 /* Address of 16 random bytes. */ |
#define AT_EXECFN 31 /* Filename of executable. */ |
/* Pointer to the global system page used for system calls and other |
nice things. */ |
#define AT_SYSINFO 32 |
#define AT_SYSINFO_EHDR 33 |
/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains |
log2 of line size; mask those to get cache size. */ |
#define AT_L1I_CACHESHAPE 34 |
#define AT_L1D_CACHESHAPE 35 |
#define AT_L2_CACHESHAPE 36 |
#define AT_L3_CACHESHAPE 37 |
/* Note section contents. Each entry in the note section begins with |
a header of a fixed form. */ |
1075,66 → 850,17 |
word 2: minor version of the ABI |
word 3: subminor version of the ABI |
*/ |
#define NT_GNU_ABI_TAG 1 |
#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ |
#define ELF_NOTE_ABI 1 |
/* Known OSes. These values can appear in word 0 of an |
NT_GNU_ABI_TAG note section entry. */ |
/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI |
note section entry. */ |
#define ELF_NOTE_OS_LINUX 0 |
#define ELF_NOTE_OS_GNU 1 |
#define ELF_NOTE_OS_SOLARIS2 2 |
#define ELF_NOTE_OS_FREEBSD 3 |
/* Synthetic hwcap information. The descriptor begins with two words: |
word 0: number of entries |
word 1: bitmask of enabled entries |
Then follow variable-length entries, one byte followed by a |
'\0'-terminated hwcap name string. The byte gives the bit |
number to test if enabled, (1U << bit) & bitmask. */ |
#define NT_GNU_HWCAP 2 |
/* Build ID bits as generated by ld --build-id. |
The descriptor consists of any nonzero number of bytes. */ |
#define NT_GNU_BUILD_ID 3 |
/* Version note generated by GNU gold containing a version string. */ |
#define NT_GNU_GOLD_VERSION 4 |
/* Move records. */ |
typedef struct |
{ |
Elf32_Xword m_value; /* Symbol value. */ |
Elf32_Word m_info; /* Size and index. */ |
Elf32_Word m_poffset; /* Symbol offset. */ |
Elf32_Half m_repeat; /* Repeat count. */ |
Elf32_Half m_stride; /* Stride info. */ |
} Elf32_Move; |
typedef struct |
{ |
Elf64_Xword m_value; /* Symbol value. */ |
Elf64_Xword m_info; /* Size and index. */ |
Elf64_Xword m_poffset; /* Symbol offset. */ |
Elf64_Half m_repeat; /* Repeat count. */ |
Elf64_Half m_stride; /* Stride info. */ |
} Elf64_Move; |
/* Macro to construct move records. */ |
#define ELF32_M_SYM(info) ((info) >> 8) |
#define ELF32_M_SIZE(info) ((unsigned char) (info)) |
#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) |
#define ELF64_M_SYM(info) ELF32_M_SYM (info) |
#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) |
#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) |
/* Motorola 68k specific definitions. */ |
/* Values for Elf32_Ehdr.e_flags. */ |
#define EF_CPU32 0x00810000 |
/* m68k relocs. */ |
#define R_68K_NONE 0 /* No reloc */ |
1160,29 → 886,8 |
#define R_68K_GLOB_DAT 20 /* Create GOT entry */ |
#define R_68K_JMP_SLOT 21 /* Create PLT entry */ |
#define R_68K_RELATIVE 22 /* Adjust by program base */ |
#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ |
#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ |
#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ |
#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ |
#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ |
#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ |
#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ |
#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ |
#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ |
#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ |
#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ |
#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ |
#define R_68K_TLS_LE32 37 /* 32 bit offset relative to |
static TLS block */ |
#define R_68K_TLS_LE16 38 /* 16 bit offset relative to |
static TLS block */ |
#define R_68K_TLS_LE8 39 /* 8 bit offset relative to |
static TLS block */ |
#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ |
#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ |
#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ |
/* Keep this the last entry. */ |
#define R_68K_NUM 43 |
#define R_68K_NUM 23 |
/* Intel 80386 specific definitions. */ |
1199,63 → 904,11 |
#define R_386_RELATIVE 8 /* Adjust by program base */ |
#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ |
#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ |
#define R_386_32PLT 11 |
#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ |
#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS |
block offset */ |
#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block |
offset */ |
#define R_386_TLS_LE 17 /* Offset relative to static TLS |
block */ |
#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of |
general dynamic thread local data */ |
#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of |
local dynamic thread local data |
in LE code */ |
#define R_386_16 20 |
#define R_386_PC16 21 |
#define R_386_8 22 |
#define R_386_PC8 23 |
#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic |
thread local data */ |
#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ |
#define R_386_TLS_GD_CALL 26 /* Relocation for call to |
__tls_get_addr() */ |
#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ |
#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic |
thread local data in LE code */ |
#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ |
#define R_386_TLS_LDM_CALL 30 /* Relocation for call to |
__tls_get_addr() in LDM code */ |
#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ |
#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ |
#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS |
block offset */ |
#define R_386_TLS_LE_32 34 /* Negated offset relative to static |
TLS block */ |
#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ |
#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ |
#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ |
/* 38? */ |
#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ |
#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS |
descriptor for |
relaxation. */ |
#define R_386_TLS_DESC 41 /* TLS descriptor containing |
pointer to code and to |
argument, returning the TLS |
offset for the symbol. */ |
#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ |
#define R_386_GOT32X 43 /* 32 bit GOT entry, relaxable */ |
/* Keep this the last entry. */ |
#define R_386_NUM 44 |
#define R_386_NUM 11 |
/* SUN SPARC specific definitions. */ |
/* Legal values for ST_TYPE subfield of st_info (symbol type). */ |
#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ |
/* Values for Elf64_Ehdr.e_flags. */ |
#define EF_SPARCV9_MM 3 |
1262,12 → 915,9 |
#define EF_SPARCV9_TSO 0 |
#define EF_SPARCV9_PSO 1 |
#define EF_SPARCV9_RMO 2 |
#define EF_SPARC_LEDATA 0x800000 /* little endian data */ |
#define EF_SPARC_EXT_MASK 0xFFFF00 |
#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ |
#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ |
#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ |
#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ |
#define EF_SPARC_SUN_US1 0x000200 |
#define EF_SPARC_HAL_R1 0x000400 |
/* SPARC relocs. */ |
1307,7 → 957,7 |
#define R_SPARC_10 30 /* Direct 10 bit */ |
#define R_SPARC_11 31 /* Direct 11 bit */ |
#define R_SPARC_64 32 /* Direct 64 bit */ |
#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ |
#define R_SPARC_OLO10 33 /* ?? */ |
#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ |
#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ |
#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ |
1316,7 → 966,6 |
#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ |
#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ |
#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ |
#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ |
#define R_SPARC_7 43 /* Direct 7 bit */ |
#define R_SPARC_5 44 /* Direct 5 bit */ |
#define R_SPARC_6 45 /* Direct 6 bit */ |
1330,46 → 979,8 |
#define R_SPARC_REGISTER 53 /* Global register usage */ |
#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ |
#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ |
#define R_SPARC_TLS_GD_HI22 56 |
#define R_SPARC_TLS_GD_LO10 57 |
#define R_SPARC_TLS_GD_ADD 58 |
#define R_SPARC_TLS_GD_CALL 59 |
#define R_SPARC_TLS_LDM_HI22 60 |
#define R_SPARC_TLS_LDM_LO10 61 |
#define R_SPARC_TLS_LDM_ADD 62 |
#define R_SPARC_TLS_LDM_CALL 63 |
#define R_SPARC_TLS_LDO_HIX22 64 |
#define R_SPARC_TLS_LDO_LOX10 65 |
#define R_SPARC_TLS_LDO_ADD 66 |
#define R_SPARC_TLS_IE_HI22 67 |
#define R_SPARC_TLS_IE_LO10 68 |
#define R_SPARC_TLS_IE_LD 69 |
#define R_SPARC_TLS_IE_LDX 70 |
#define R_SPARC_TLS_IE_ADD 71 |
#define R_SPARC_TLS_LE_HIX22 72 |
#define R_SPARC_TLS_LE_LOX10 73 |
#define R_SPARC_TLS_DTPMOD32 74 |
#define R_SPARC_TLS_DTPMOD64 75 |
#define R_SPARC_TLS_DTPOFF32 76 |
#define R_SPARC_TLS_DTPOFF64 77 |
#define R_SPARC_TLS_TPOFF32 78 |
#define R_SPARC_TLS_TPOFF64 79 |
#define R_SPARC_GOTDATA_HIX22 80 |
#define R_SPARC_GOTDATA_LOX10 81 |
#define R_SPARC_GOTDATA_OP_HIX22 82 |
#define R_SPARC_GOTDATA_OP_LOX10 83 |
#define R_SPARC_GOTDATA_OP 84 |
#define R_SPARC_H34 85 |
#define R_SPARC_SIZE32 86 |
#define R_SPARC_SIZE64 87 |
#define R_SPARC_WDISP10 88 |
#define R_SPARC_JMP_IREL 248 |
#define R_SPARC_IRELATIVE 249 |
#define R_SPARC_GNU_VTINHERIT 250 |
#define R_SPARC_GNU_VTENTRY 251 |
#define R_SPARC_REV32 252 |
/* Keep this the last entry. */ |
#define R_SPARC_NUM 253 |
#define R_SPARC_NUM 56 |
/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ |
1376,6 → 987,14 |
#define DT_SPARC_REGISTER 0x70000001 |
#define DT_SPARC_NUM 2 |
/* Bits present in AT_HWCAP, primarily for Sparc32. */ |
#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */ |
#define HWCAP_SPARC_STBAR 2 |
#define HWCAP_SPARC_SWAP 4 |
#define HWCAP_SPARC_MULDIV 8 |
#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */ |
/* MIPS R3000 specific definitions. */ |
/* Legal values for e_flags field of Elf32_Ehdr. */ |
1396,8 → 1015,6 |
#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ |
#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ |
#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ |
#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ |
#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ |
/* The following are non-official names and should not be used. */ |
1406,8 → 1023,6 |
#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ |
#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ |
#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ |
#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ |
#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ |
/* Special section indices. */ |
1478,7 → 1093,6 |
#define STO_MIPS_INTERNAL 0x1 |
#define STO_MIPS_HIDDEN 0x2 |
#define STO_MIPS_PROTECTED 0x3 |
#define STO_MIPS_PLT 0x8 |
#define STO_MIPS_SC_ALIGN_UNUSED 0xff |
/* MIPS specific values for `st_info'. */ |
1611,24 → 1225,8 |
#define R_MIPS_PJUMP 35 |
#define R_MIPS_RELGOT 36 |
#define R_MIPS_JALR 37 |
#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ |
#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ |
#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ |
#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ |
#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ |
#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ |
#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ |
#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ |
#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ |
#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ |
#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ |
#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ |
#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ |
#define R_MIPS_GLOB_DAT 51 |
#define R_MIPS_COPY 126 |
#define R_MIPS_JUMP_SLOT 127 |
/* Keep this the last entry. */ |
#define R_MIPS_NUM 128 |
#define R_MIPS_NUM 38 |
/* Legal values for p_type field of Elf32_Phdr. */ |
1694,13 → 1292,7 |
#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ |
#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ |
#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ |
/* The address of .got.plt in an executable using the new non-PIC ABI. */ |
#define DT_MIPS_PLTGOT 0x70000032 |
/* The base of the PLT in an executable using the new non-PIC ABI if that |
PLT is writable. For a non-writable PLT, this is omitted or has a zero |
value. */ |
#define DT_MIPS_RWPLT 0x70000034 |
#define DT_MIPS_NUM 0x35 |
#define DT_MIPS_NUM 0x32 |
/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ |
1761,46 → 1353,38 |
/* Legal values for e_flags field of Elf32_Ehdr. */ |
#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ |
#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ |
#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ |
#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ |
#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch |
prediction. */ |
#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ |
#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ |
#define EF_PARISC_TRAPNL 1 /* Trap nil pointer dereference. */ |
#define EF_PARISC_EXT 2 /* Program uses arch. extensions. */ |
#define EF_PARISC_ARCH 0xffff0000 /* Architecture version. */ |
/* Defined values are: |
0x020b PA-RISC 1.0 big-endian |
0x0210 PA-RISC 1.1 big-endian |
0x028b PA-RISC 1.0 little-endian |
0x0290 PA-RISC 1.1 little-endian |
*/ |
/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ |
#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ |
#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ |
#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ |
/* Additional section indeces. */ |
#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared |
symbols in ANSI C. */ |
#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ |
/* Legal values for sh_type field of Elf32_Shdr. */ |
#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ |
#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ |
#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ |
#define SHT_PARISC_GOT 0x70000000 /* GOT for external data. */ |
#define SHT_PARISC_ARCH 0x70000001 /* Architecture extensions. */ |
#define SHT_PARISC_GLOBAL 0x70000002 /* Definition of $global$. */ |
#define SHT_PARISC_MILLI 0x70000003 /* Millicode routines. */ |
#define SHT_PARISC_UNWIND 0x70000004 /* Unwind information. */ |
#define SHT_PARISC_PLT 0x70000005 /* Procedure linkage table. */ |
#define SHT_PARISC_SDATA 0x70000006 /* Short initialized data. */ |
#define SHT_PARISC_SBSS 0x70000007 /* Short uninitialized data. */ |
#define SHT_PARISC_SYMEXTN 0x70000008 /* Argument/relocation info. */ |
#define SHT_PARISC_STUBS 0x70000009 /* Linker stubs. */ |
/* Legal values for sh_flags field of Elf32_Shdr. */ |
#define SHF_PARISC_GLOBAL 0x10000000 /* Section defines dp. */ |
#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ |
#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ |
#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ |
/* Legal values for ST_TYPE subfield of st_info (symbol type). */ |
#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ |
#define STT_HP_OPAQUE (STT_LOOS + 0x1) |
#define STT_HP_STUB (STT_LOOS + 0x2) |
/* HPPA relocs. */ |
#define R_PARISC_NONE 0 /* No reloc. */ |
1807,147 → 1391,27 |
#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ |
#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ |
#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ |
#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ |
#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ |
#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ |
#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ |
#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ |
#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ |
#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ |
#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ |
#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ |
#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ |
#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ |
#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ |
#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ |
#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ |
#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ |
#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ |
#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ |
#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ |
#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ |
#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ |
#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ |
#define R_PARISC_FPTR64 64 /* 64 bits function address. */ |
#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ |
#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ |
#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ |
#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ |
#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ |
#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ |
#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ |
#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ |
#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ |
#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ |
#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ |
#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ |
#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ |
#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ |
#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ |
#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ |
#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ |
#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ |
#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ |
#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ |
#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ |
#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ |
#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ |
#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ |
#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ |
#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ |
#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ |
#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ |
#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ |
#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ |
#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ |
#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ |
#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ |
#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ |
#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ |
#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ |
#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ |
#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ |
#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ |
#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ |
#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ |
#define R_PARISC_LORESERVE 128 |
#define R_PARISC_COPY 128 /* Copy relocation. */ |
#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ |
#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ |
#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ |
#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ |
#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ |
#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ |
#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ |
#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ |
#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ |
#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ |
#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ |
#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ |
#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ |
#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ |
#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ |
#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ |
#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ |
#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ |
#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ |
#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ |
#define R_PARISC_GNU_VTENTRY 232 |
#define R_PARISC_GNU_VTINHERIT 233 |
#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ |
#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ |
#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ |
#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ |
#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ |
#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ |
#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ |
#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ |
#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ |
#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ |
#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ |
#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ |
#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L |
#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R |
#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L |
#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R |
#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 |
#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 |
#define R_PARISC_HIRESERVE 255 |
#define R_PARISC_DIR14R 4 /* Right 14 bits of eff. address. */ |
#define R_PARISC_PCREL21L 5 /* PC-relative, left 21 bits. */ |
#define R_PARISC_PCREL14R 6 /* PC-relative, right 14 bits. */ |
#define R_PARISC_PCREL17C 7 /* Conditional PC-relative, ignore |
if displacement > 17bits. */ |
#define R_PARISC_PCREL17F 8 /* Conditional PC-relative, must |
fit in 17bits. */ |
#define R_PARISC_DPREL21L 9 /* DP-relative, left 21 bits. */ |
#define R_PARISC_DPREL14R 10 /* DP-relative, right 14 bits. */ |
#define R_PARISC_DPREL14F 11 /* DP-relative, must bit in 14 bits. */ |
#define R_PARISC_DLTREL21L 12 /* DLT-relative, left 21 bits. */ |
#define R_PARISC_DLTREL14R 13 /* DLT-relative, right 14 bits. */ |
#define R_PARISC_DLTREL14F 14 /* DLT-relative, must fit in 14 bits.*/ |
#define R_PARISC_DLTIND21L 15 /* DLT-relative indirect, left |
21 bits. */ |
#define R_PARISC_DLTIND14R 16 /* DLT-relative indirect, right |
14 bits. */ |
#define R_PARISC_DLTIND14F 17 /* DLT-relative indirect, must fit |
int 14 bits. */ |
#define R_PARISC_PLABEL32 18 /* Direct 32-bit reference to proc. */ |
/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ |
#define PT_HP_TLS (PT_LOOS + 0x0) |
#define PT_HP_CORE_NONE (PT_LOOS + 0x1) |
#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) |
#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) |
#define PT_HP_CORE_COMM (PT_LOOS + 0x4) |
#define PT_HP_CORE_PROC (PT_LOOS + 0x5) |
#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) |
#define PT_HP_CORE_STACK (PT_LOOS + 0x7) |
#define PT_HP_CORE_SHM (PT_LOOS + 0x8) |
#define PT_HP_CORE_MMF (PT_LOOS + 0x9) |
#define PT_HP_PARALLEL (PT_LOOS + 0x10) |
#define PT_HP_FASTBIND (PT_LOOS + 0x11) |
#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) |
#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) |
#define PT_HP_STACK (PT_LOOS + 0x14) |
#define PT_PARISC_ARCHEXT 0x70000000 |
#define PT_PARISC_UNWIND 0x70000001 |
/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ |
#define PF_PARISC_SBP 0x08000000 |
#define PF_HP_PAGE_SIZE 0x00100000 |
#define PF_HP_FAR_SHARED 0x00200000 |
#define PF_HP_NEAR_SHARED 0x00400000 |
#define PF_HP_CODE 0x01000000 |
#define PF_HP_MODIFY 0x02000000 |
#define PF_HP_LAZYSWAP 0x04000000 |
#define PF_HP_SBP 0x08000000 |
/* Alpha specific definitions. */ |
/* Legal values for e_flags field of Elf64_Ehdr. */ |
1983,52 → 1447,28 |
#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ |
#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ |
#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ |
#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ |
#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ |
#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ |
#define R_ALPHA_OP_PUSH 12 /* OP stack push */ |
#define R_ALPHA_OP_STORE 13 /* OP stack pop and store */ |
#define R_ALPHA_OP_PSUB 14 /* OP stack subtract */ |
#define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */ |
#define R_ALPHA_GPVALUE 16 |
#define R_ALPHA_GPRELHIGH 17 |
#define R_ALPHA_GPRELLOW 18 |
#define R_ALPHA_IMMED_GP_16 19 |
#define R_ALPHA_IMMED_GP_HI32 20 |
#define R_ALPHA_IMMED_SCN_HI32 21 |
#define R_ALPHA_IMMED_BR_HI32 22 |
#define R_ALPHA_IMMED_LO32 23 |
#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ |
#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ |
#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ |
#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ |
#define R_ALPHA_TLS_GD_HI 28 |
#define R_ALPHA_TLSGD 29 |
#define R_ALPHA_TLS_LDM 30 |
#define R_ALPHA_DTPMOD64 31 |
#define R_ALPHA_GOTDTPREL 32 |
#define R_ALPHA_DTPREL64 33 |
#define R_ALPHA_DTPRELHI 34 |
#define R_ALPHA_DTPRELLO 35 |
#define R_ALPHA_DTPREL16 36 |
#define R_ALPHA_GOTTPREL 37 |
#define R_ALPHA_TPREL64 38 |
#define R_ALPHA_TPRELHI 39 |
#define R_ALPHA_TPRELLO 40 |
#define R_ALPHA_TPREL16 41 |
/* Keep this the last entry. */ |
#define R_ALPHA_NUM 46 |
#define R_ALPHA_NUM 28 |
/* Magic values of the LITUSE relocation addend. */ |
#define LITUSE_ALPHA_ADDR 0 |
#define LITUSE_ALPHA_BASE 1 |
#define LITUSE_ALPHA_BYTOFF 2 |
#define LITUSE_ALPHA_JSR 3 |
#define LITUSE_ALPHA_TLS_GD 4 |
#define LITUSE_ALPHA_TLS_LDM 5 |
/* Legal values for d_tag of Elf64_Dyn. */ |
#define DT_ALPHA_PLTRO (DT_LOPROC + 0) |
#define DT_ALPHA_NUM 1 |
/* PowerPC specific declarations */ |
/* Values for Elf32/64_Ehdr.e_flags. */ |
#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ |
/* Cygnus local bits below */ |
#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ |
#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib |
flag */ |
/* PowerPC relocations defined by the ABIs */ |
#define R_PPC_NONE 0 |
#define R_PPC_ADDR32 1 /* 32bit absolute address */ |
2067,37 → 1507,9 |
#define R_PPC_SECTOFF_LO 34 |
#define R_PPC_SECTOFF_HI 35 |
#define R_PPC_SECTOFF_HA 36 |
/* Keep this the last entry. */ |
#define R_PPC_NUM 37 |
/* PowerPC relocations defined for the TLS access ABI. */ |
#define R_PPC_TLS 67 /* none (sym+add)@tls */ |
#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ |
#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ |
#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ |
#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ |
#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ |
#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ |
#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ |
#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ |
#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ |
#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ |
#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ |
#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ |
#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ |
#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ |
#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ |
#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ |
#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ |
#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ |
#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ |
#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ |
#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ |
#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ |
#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ |
#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ |
#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ |
#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ |
#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ |
/* The remaining relocs are from the Embedded ELF ABI, and are not |
in the SVR4 ELF ABI. */ |
#define R_PPC_EMB_NADDR32 101 |
2125,150 → 1537,11 |
#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ |
#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ |
/* GNU extension to support local ifunc. */ |
#define R_PPC_IRELATIVE 248 |
/* GNU relocs used in PIC code sequences. */ |
#define R_PPC_REL16 249 /* half16 (sym+add-.) */ |
#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ |
#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ |
#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ |
/* This is a phony reloc to handle any old fashioned TOC16 references |
that may still be in object files. */ |
#define R_PPC_TOC16 255 |
/* PowerPC specific values for the Dyn d_tag field. */ |
#define DT_PPC_GOT (DT_LOPROC + 0) |
#define DT_PPC_NUM 1 |
/* PowerPC64 relocations defined by the ABIs */ |
#define R_PPC64_NONE R_PPC_NONE |
#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ |
#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ |
#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ |
#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ |
#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ |
#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ |
#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ |
#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN |
#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN |
#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ |
#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ |
#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN |
#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN |
#define R_PPC64_GOT16 R_PPC_GOT16 |
#define R_PPC64_GOT16_LO R_PPC_GOT16_LO |
#define R_PPC64_GOT16_HI R_PPC_GOT16_HI |
#define R_PPC64_GOT16_HA R_PPC_GOT16_HA |
#define R_PPC64_COPY R_PPC_COPY |
#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT |
#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT |
#define R_PPC64_RELATIVE R_PPC_RELATIVE |
#define R_PPC64_UADDR32 R_PPC_UADDR32 |
#define R_PPC64_UADDR16 R_PPC_UADDR16 |
#define R_PPC64_REL32 R_PPC_REL32 |
#define R_PPC64_PLT32 R_PPC_PLT32 |
#define R_PPC64_PLTREL32 R_PPC_PLTREL32 |
#define R_PPC64_PLT16_LO R_PPC_PLT16_LO |
#define R_PPC64_PLT16_HI R_PPC_PLT16_HI |
#define R_PPC64_PLT16_HA R_PPC_PLT16_HA |
#define R_PPC64_SECTOFF R_PPC_SECTOFF |
#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO |
#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI |
#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA |
#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ |
#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ |
#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ |
#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ |
#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ |
#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ |
#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ |
#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ |
#define R_PPC64_PLT64 45 /* doubleword64 L + A */ |
#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ |
#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ |
#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ |
#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ |
#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ |
#define R_PPC64_TOC 51 /* doubleword64 .TOC */ |
#define R_PPC64_PLTGOT16 52 /* half16* M + A */ |
#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ |
#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ |
#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ |
#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ |
#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ |
#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ |
#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ |
#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ |
#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ |
#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ |
#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ |
#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ |
#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ |
#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ |
/* PowerPC64 relocations defined for the TLS access ABI. */ |
#define R_PPC64_TLS 67 /* none (sym+add)@tls */ |
#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ |
#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ |
#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ |
#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ |
#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ |
#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ |
#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ |
#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ |
#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ |
#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ |
#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ |
#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ |
#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ |
#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ |
#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ |
#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ |
#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ |
#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ |
#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ |
#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ |
#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ |
#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ |
#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ |
#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ |
#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ |
#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ |
#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ |
#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ |
#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ |
#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ |
#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ |
#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ |
#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ |
#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ |
#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ |
#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ |
#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ |
#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ |
#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ |
/* GNU extension to support local ifunc. */ |
#define R_PPC64_JMP_IREL 247 |
#define R_PPC64_IRELATIVE 248 |
#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ |
#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ |
#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ |
#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ |
/* PowerPC64 specific values for the Dyn d_tag field. */ |
#define DT_PPC64_GLINK (DT_LOPROC + 0) |
#define DT_PPC64_OPD (DT_LOPROC + 1) |
#define DT_PPC64_OPDSZ (DT_LOPROC + 2) |
#define DT_PPC64_NUM 3 |
/* ARM specific declarations */ |
/* Processor specific flags for the ELF header e_flags field. */ |
2278,188 → 1551,23 |
#define EF_ARM_APCS_26 0x08 |
#define EF_ARM_APCS_FLOAT 0x10 |
#define EF_ARM_PIC 0x20 |
#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ |
#define EF_ARM_NEW_ABI 0x80 |
#define EF_ARM_OLD_ABI 0x100 |
#define EF_ARM_SOFT_FLOAT 0x200 |
#define EF_ARM_VFP_FLOAT 0x400 |
#define EF_ARM_MAVERICK_FLOAT 0x800 |
#define EF_ALIGN8 0x40 /* 8-bit structure alignment is in use */ |
#define EF_NEW_ABI 0x80 |
#define EF_OLD_ABI 0x100 |
#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */ |
#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */ |
/* Additional symbol types for Thumb */ |
#define STT_ARM_TFUNC 0xd |
/* Other constants defined in the ARM ELF spec. version B-01. */ |
/* NB. These conflict with values defined above. */ |
#define EF_ARM_SYMSARESORTED 0x04 |
#define EF_ARM_DYNSYMSUSESEGIDX 0x08 |
#define EF_ARM_MAPSYMSFIRST 0x10 |
#define EF_ARM_EABIMASK 0XFF000000 |
/* Constants defined in AAELF. */ |
#define EF_ARM_BE8 0x00800000 |
#define EF_ARM_LE8 0x00400000 |
#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) |
#define EF_ARM_EABI_UNKNOWN 0x00000000 |
#define EF_ARM_EABI_VER1 0x01000000 |
#define EF_ARM_EABI_VER2 0x02000000 |
#define EF_ARM_EABI_VER3 0x03000000 |
#define EF_ARM_EABI_VER4 0x04000000 |
#define EF_ARM_EABI_VER5 0x05000000 |
/* Additional symbol types for Thumb. */ |
#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ |
#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ |
/* ARM-specific values for sh_flags */ |
#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ |
#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined |
in the input to a link step. */ |
in the input to a link step */ |
/* ARM-specific program header flags */ |
#define PF_ARM_SB 0x10000000 /* Segment contains the location |
addressed by the static base. */ |
#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ |
#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ |
addressed by the static base */ |
/* Processor specific values for the Phdr p_type field. */ |
#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ |
/* Processor specific values for the Shdr sh_type field. */ |
#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ |
#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ |
#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ |
/* AArch64 relocs. */ |
#define R_AARCH64_NONE 0 /* No relocation. */ |
#define R_AARCH64_ABS64 257 /* Direct 64 bit. */ |
#define R_AARCH64_ABS32 258 /* Direct 32 bit. */ |
#define R_AARCH64_ABS16 259 /* Direct 16-bit. */ |
#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */ |
#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */ |
#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */ |
#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */ |
#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */ |
#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */ |
#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */ |
#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */ |
#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */ |
#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */ |
#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */ |
#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */ |
#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */ |
#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */ |
#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */ |
#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */ |
#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */ |
#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */ |
#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */ |
#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */ |
#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */ |
#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */ |
#define R_AARCH64_CALL26 283 /* Likewise for CALL. */ |
#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */ |
#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */ |
#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */ |
#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */ |
#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */ |
#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */ |
#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */ |
#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */ |
#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */ |
#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */ |
#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */ |
#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */ |
#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */ |
#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */ |
#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */ |
#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */ |
#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */ |
#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */ |
#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */ |
#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */ |
#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */ |
#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */ |
#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */ |
#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */ |
#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */ |
#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */ |
#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */ |
#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */ |
#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */ |
#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */ |
#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */ |
#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */ |
#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */ |
#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */ |
#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */ |
#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */ |
#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */ |
#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */ |
#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */ |
#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */ |
#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */ |
#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */ |
#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */ |
#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */ |
#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */ |
#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */ |
#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */ |
#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */ |
#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */ |
#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */ |
#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */ |
#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */ |
#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */ |
#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */ |
#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */ |
#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */ |
#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */ |
#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */ |
#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */ |
#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */ |
#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */ |
#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */ |
#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */ |
#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */ |
#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */ |
#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */ |
#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */ |
#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */ |
#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */ |
#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */ |
#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */ |
#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */ |
#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */ |
#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */ |
#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */ |
#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */ |
#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */ |
#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */ |
#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */ |
#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */ |
#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */ |
#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */ |
#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */ |
#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */ |
#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */ |
#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */ |
#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */ |
#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ |
#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ |
#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ |
#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */ |
#define R_AARCH64_TLS_DTPMOD64 1028 /* Module number, 64 bit. */ |
#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ |
#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ |
#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ |
#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ |
/* ARM relocs. */ |
#define R_ARM_NONE 0 /* No reloc */ |
#define R_ARM_PC24 1 /* PC relative 26 bit branch */ |
#define R_ARM_ABS32 2 /* Direct 32 bit */ |
2473,14 → 1581,10 |
#define R_ARM_THM_PC22 10 |
#define R_ARM_THM_PC8 11 |
#define R_ARM_AMP_VCALL9 12 |
#define R_ARM_SWI24 13 /* Obsolete static relocation. */ |
#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ |
#define R_ARM_SWI24 13 |
#define R_ARM_THM_SWI8 14 |
#define R_ARM_XPC25 15 |
#define R_ARM_THM_XPC22 16 |
#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ |
#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ |
#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ |
#define R_ARM_COPY 20 /* Copy symbol at runtime */ |
#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ |
#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ |
2489,41 → 1593,10 |
#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ |
#define R_ARM_GOT32 26 /* 32 bit GOT entry */ |
#define R_ARM_PLT32 27 /* 32 bit PLT address */ |
#define R_ARM_CALL 28 |
#define R_ARM_JUMP24 29 |
#define R_ARM_THM_JUMP24 30 |
#define R_ARM_ALU_PCREL_7_0 32 |
#define R_ARM_ALU_PCREL_15_8 33 |
#define R_ARM_ALU_PCREL_23_15 34 |
#define R_ARM_LDR_SBREL_11_0 35 |
#define R_ARM_ALU_SBREL_19_12 36 |
#define R_ARM_ALU_SBREL_27_20 37 |
#define R_ARM_V4BX 40 |
#define R_ARM_PREL31 42 |
#define R_ARM_MOVW_ABS_NC 43 |
#define R_ARM_MOVT_ABS 44 |
#define R_ARM_THM_MOVW_ABS_NC 47 |
#define R_ARM_THM_MOVT_ABS 48 |
#define R_ARM_TLS_GOTDESC 90 |
#define R_ARM_TLS_CALL 91 |
#define R_ARM_TLS_DESCSEQ 92 |
#define R_ARM_THM_TLS_CALL 93 |
#define R_ARM_GNU_VTENTRY 100 |
#define R_ARM_GNU_VTINHERIT 101 |
#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ |
#define R_ARM_THM_PC9 103 /* thumb conditional branch */ |
#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic |
thread local data */ |
#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic |
thread local data */ |
#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS |
block */ |
#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of |
static TLS block offset */ |
#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static |
TLS block */ |
#define R_ARM_THM_TLS_DESCSEQ 129 |
#define R_ARM_IRELATIVE 160 |
#define R_ARM_RXPC25 249 |
#define R_ARM_RSBREL32 250 |
#define R_ARM_THM_RPC22 251 |
2535,7 → 1608,6 |
#define R_ARM_NUM 256 |
/* TMS320C67xx specific declarations */ |
/* XXX: no ELF standard yet*/ |
/* TMS320C67xx relocs. */ |
2549,685 → 1621,7 |
#define R_C60_GOTOFF 9 /* 32 bit offset to GOT */ |
#define R_C60_GOTPC 10 /* 32 bit PC relative offset to GOT */ |
#define R_C60HI16 0x55 /* high 16 bit MVKH embedded */ |
#define R_C60LO16 0x54 /* low 16 bit MVKL embedded */ |
#define R_C60HI16 0x55 // high 16 bit MVKH embedded |
#define R_C60LO16 0x54 // low 16 bit MVKL embedded |
/* IA-64 specific declarations. */ |
/* Processor specific flags for the Ehdr e_flags field. */ |
#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ |
#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ |
#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ |
/* Processor specific values for the Phdr p_type field. */ |
#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ |
#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ |
#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) |
#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) |
#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) |
/* Processor specific flags for the Phdr p_flags field. */ |
#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ |
/* Processor specific values for the Shdr sh_type field. */ |
#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ |
#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ |
/* Processor specific flags for the Shdr sh_flags field. */ |
#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ |
#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ |
/* Processor specific values for the Dyn d_tag field. */ |
#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) |
#define DT_IA_64_NUM 1 |
/* IA-64 relocations. */ |
#define R_IA64_NONE 0x00 /* none */ |
#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ |
#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ |
#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ |
#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ |
#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ |
#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ |
#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ |
#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ |
#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ |
#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ |
#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ |
#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ |
#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ |
#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ |
#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ |
#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ |
#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ |
#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ |
#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ |
#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ |
#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ |
#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ |
#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ |
#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ |
#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ |
#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ |
#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ |
#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ |
#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ |
#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ |
#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ |
#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ |
#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ |
#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ |
#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ |
#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ |
#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ |
#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ |
#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ |
#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ |
#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ |
#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ |
#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ |
#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ |
#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ |
#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ |
#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ |
#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ |
#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ |
#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ |
#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ |
#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ |
#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ |
#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ |
#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ |
#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ |
#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ |
#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ |
#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ |
#define R_IA64_COPY 0x84 /* copy relocation */ |
#define R_IA64_SUB 0x85 /* Addend and symbol difference */ |
#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ |
#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ |
#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ |
#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ |
#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ |
#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ |
#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ |
#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ |
#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ |
#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ |
#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ |
#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ |
#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ |
#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ |
#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ |
#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ |
#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ |
#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ |
#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ |
/* SH specific declarations */ |
/* Processor specific flags for the ELF header e_flags field. */ |
#define EF_SH_MACH_MASK 0x1f |
#define EF_SH_UNKNOWN 0x0 |
#define EF_SH1 0x1 |
#define EF_SH2 0x2 |
#define EF_SH3 0x3 |
#define EF_SH_DSP 0x4 |
#define EF_SH3_DSP 0x5 |
#define EF_SH4AL_DSP 0x6 |
#define EF_SH3E 0x8 |
#define EF_SH4 0x9 |
#define EF_SH2E 0xb |
#define EF_SH4A 0xc |
#define EF_SH2A 0xd |
#define EF_SH4_NOFPU 0x10 |
#define EF_SH4A_NOFPU 0x11 |
#define EF_SH4_NOMMU_NOFPU 0x12 |
#define EF_SH2A_NOFPU 0x13 |
#define EF_SH3_NOMMU 0x14 |
#define EF_SH2A_SH4_NOFPU 0x15 |
#define EF_SH2A_SH3_NOFPU 0x16 |
#define EF_SH2A_SH4 0x17 |
#define EF_SH2A_SH3E 0x18 |
/* SH relocs. */ |
#define R_SH_NONE 0 |
#define R_SH_DIR32 1 |
#define R_SH_REL32 2 |
#define R_SH_DIR8WPN 3 |
#define R_SH_IND12W 4 |
#define R_SH_DIR8WPL 5 |
#define R_SH_DIR8WPZ 6 |
#define R_SH_DIR8BP 7 |
#define R_SH_DIR8W 8 |
#define R_SH_DIR8L 9 |
#define R_SH_SWITCH16 25 |
#define R_SH_SWITCH32 26 |
#define R_SH_USES 27 |
#define R_SH_COUNT 28 |
#define R_SH_ALIGN 29 |
#define R_SH_CODE 30 |
#define R_SH_DATA 31 |
#define R_SH_LABEL 32 |
#define R_SH_SWITCH8 33 |
#define R_SH_GNU_VTINHERIT 34 |
#define R_SH_GNU_VTENTRY 35 |
#define R_SH_TLS_GD_32 144 |
#define R_SH_TLS_LD_32 145 |
#define R_SH_TLS_LDO_32 146 |
#define R_SH_TLS_IE_32 147 |
#define R_SH_TLS_LE_32 148 |
#define R_SH_TLS_DTPMOD32 149 |
#define R_SH_TLS_DTPOFF32 150 |
#define R_SH_TLS_TPOFF32 151 |
#define R_SH_GOT32 160 |
#define R_SH_PLT32 161 |
#define R_SH_COPY 162 |
#define R_SH_GLOB_DAT 163 |
#define R_SH_JMP_SLOT 164 |
#define R_SH_RELATIVE 165 |
#define R_SH_GOTOFF 166 |
#define R_SH_GOTPC 167 |
/* Keep this the last entry. */ |
#define R_SH_NUM 256 |
/* S/390 specific definitions. */ |
/* Valid values for the e_flags field. */ |
#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ |
/* Additional s390 relocs */ |
#define R_390_NONE 0 /* No reloc. */ |
#define R_390_8 1 /* Direct 8 bit. */ |
#define R_390_12 2 /* Direct 12 bit. */ |
#define R_390_16 3 /* Direct 16 bit. */ |
#define R_390_32 4 /* Direct 32 bit. */ |
#define R_390_PC32 5 /* PC relative 32 bit. */ |
#define R_390_GOT12 6 /* 12 bit GOT offset. */ |
#define R_390_GOT32 7 /* 32 bit GOT offset. */ |
#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ |
#define R_390_COPY 9 /* Copy symbol at runtime. */ |
#define R_390_GLOB_DAT 10 /* Create GOT entry. */ |
#define R_390_JMP_SLOT 11 /* Create PLT entry. */ |
#define R_390_RELATIVE 12 /* Adjust by program base. */ |
#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ |
#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ |
#define R_390_GOT16 15 /* 16 bit GOT offset. */ |
#define R_390_PC16 16 /* PC relative 16 bit. */ |
#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ |
#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ |
#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ |
#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ |
#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ |
#define R_390_64 22 /* Direct 64 bit. */ |
#define R_390_PC64 23 /* PC relative 64 bit. */ |
#define R_390_GOT64 24 /* 64 bit GOT offset. */ |
#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ |
#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ |
#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ |
#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ |
#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ |
#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ |
#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ |
#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ |
#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ |
#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ |
#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ |
#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ |
#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ |
#define R_390_TLS_GDCALL 38 /* Tag for function call in general |
dynamic TLS code. */ |
#define R_390_TLS_LDCALL 39 /* Tag for function call in local |
dynamic TLS code. */ |
#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic |
thread local data. */ |
#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic |
thread local data. */ |
#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS |
block offset. */ |
#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS |
block offset. */ |
#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS |
block offset. */ |
#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic |
thread local data in LE code. */ |
#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic |
thread local data in LE code. */ |
#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for |
negated static TLS block offset. */ |
#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for |
negated static TLS block offset. */ |
#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for |
negated static TLS block offset. */ |
#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to |
static TLS block. */ |
#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to |
static TLS block. */ |
#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS |
block. */ |
#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS |
block. */ |
#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ |
#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ |
#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS |
block. */ |
#define R_390_20 57 /* Direct 20 bit. */ |
#define R_390_GOT20 58 /* 20 bit GOT offset. */ |
#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ |
#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS |
block offset. */ |
#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ |
/* Keep this the last entry. */ |
#define R_390_NUM 62 |
/* CRIS relocations. */ |
#define R_CRIS_NONE 0 |
#define R_CRIS_8 1 |
#define R_CRIS_16 2 |
#define R_CRIS_32 3 |
#define R_CRIS_8_PCREL 4 |
#define R_CRIS_16_PCREL 5 |
#define R_CRIS_32_PCREL 6 |
#define R_CRIS_GNU_VTINHERIT 7 |
#define R_CRIS_GNU_VTENTRY 8 |
#define R_CRIS_COPY 9 |
#define R_CRIS_GLOB_DAT 10 |
#define R_CRIS_JUMP_SLOT 11 |
#define R_CRIS_RELATIVE 12 |
#define R_CRIS_16_GOT 13 |
#define R_CRIS_32_GOT 14 |
#define R_CRIS_16_GOTPLT 15 |
#define R_CRIS_32_GOTPLT 16 |
#define R_CRIS_32_GOTREL 17 |
#define R_CRIS_32_PLT_GOTREL 18 |
#define R_CRIS_32_PLT_PCREL 19 |
#define R_CRIS_NUM 20 |
/* AMD x86-64 relocations. */ |
#define R_X86_64_NONE 0 /* No reloc */ |
#define R_X86_64_64 1 /* Direct 64 bit */ |
#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ |
#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ |
#define R_X86_64_PLT32 4 /* 32 bit PLT address */ |
#define R_X86_64_COPY 5 /* Copy symbol at runtime */ |
#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ |
#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ |
#define R_X86_64_RELATIVE 8 /* Adjust by program base */ |
#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative |
offset to GOT */ |
#define R_X86_64_32 10 /* Direct 32 bit zero extended */ |
#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ |
#define R_X86_64_16 12 /* Direct 16 bit zero extended */ |
#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ |
#define R_X86_64_8 14 /* Direct 8 bit sign extended */ |
#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ |
#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ |
#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ |
#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ |
#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset |
to two GOT entries for GD symbol */ |
#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset |
to two GOT entries for LD symbol */ |
#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ |
#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset |
to GOT entry for IE symbol */ |
#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ |
#define R_X86_64_PC64 24 /* PC relative 64 bit */ |
#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ |
#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative |
offset to GOT */ |
#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ |
#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset |
to GOT entry */ |
#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ |
#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ |
#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset |
to PLT entry */ |
#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ |
#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ |
#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ |
#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS |
descriptor. */ |
#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ |
#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ |
#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ |
#define R_X86_64_GOTPCRELX 41 /* like GOTPCREL, but optionally with |
linker optimizations */ |
#define R_X86_64_REX_GOTPCRELX 42 /* like GOTPCRELX, but a REX prefix |
is present */ |
#define R_X86_64_NUM 39 |
/* AM33 relocations. */ |
#define R_MN10300_NONE 0 /* No reloc. */ |
#define R_MN10300_32 1 /* Direct 32 bit. */ |
#define R_MN10300_16 2 /* Direct 16 bit. */ |
#define R_MN10300_8 3 /* Direct 8 bit. */ |
#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ |
#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ |
#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ |
#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ |
#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ |
#define R_MN10300_24 9 /* Direct 24 bit. */ |
#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ |
#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ |
#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ |
#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ |
#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ |
#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ |
#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ |
#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ |
#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ |
#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ |
#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ |
#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ |
#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ |
#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ |
#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */ |
#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */ |
#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */ |
#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block |
offset. */ |
#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block |
offset. */ |
#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS |
block. */ |
#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */ |
#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */ |
#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */ |
#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed |
by linker relaxation. */ |
#define R_MN10300_ALIGN 34 /* Alignment requirement for linker |
relaxation. */ |
#define R_MN10300_NUM 35 |
/* M32R relocs. */ |
#define R_M32R_NONE 0 /* No reloc. */ |
#define R_M32R_16 1 /* Direct 16 bit. */ |
#define R_M32R_32 2 /* Direct 32 bit. */ |
#define R_M32R_24 3 /* Direct 24 bit. */ |
#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ |
#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ |
#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ |
#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ |
#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ |
#define R_M32R_LO16 9 /* Low 16 bit. */ |
#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ |
#define R_M32R_GNU_VTINHERIT 11 |
#define R_M32R_GNU_VTENTRY 12 |
/* M32R relocs use SHT_RELA. */ |
#define R_M32R_16_RELA 33 /* Direct 16 bit. */ |
#define R_M32R_32_RELA 34 /* Direct 32 bit. */ |
#define R_M32R_24_RELA 35 /* Direct 24 bit. */ |
#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ |
#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ |
#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ |
#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ |
#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ |
#define R_M32R_LO16_RELA 41 /* Low 16 bit */ |
#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ |
#define R_M32R_RELA_GNU_VTINHERIT 43 |
#define R_M32R_RELA_GNU_VTENTRY 44 |
#define R_M32R_REL32 45 /* PC relative 32 bit. */ |
#define R_M32R_GOT24 48 /* 24 bit GOT entry */ |
#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ |
#define R_M32R_COPY 50 /* Copy symbol at runtime */ |
#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ |
#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ |
#define R_M32R_RELATIVE 53 /* Adjust by program base */ |
#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ |
#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ |
#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned |
low */ |
#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed |
low */ |
#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ |
#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to |
GOT with unsigned low */ |
#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to |
GOT with signed low */ |
#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to |
GOT */ |
#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT |
with unsigned low */ |
#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT |
with signed low */ |
#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ |
#define R_M32R_NUM 256 /* Keep this the last entry. */ |
/* TILEPro relocations. */ |
#define R_TILEPRO_NONE 0 /* No reloc */ |
#define R_TILEPRO_32 1 /* Direct 32 bit */ |
#define R_TILEPRO_16 2 /* Direct 16 bit */ |
#define R_TILEPRO_8 3 /* Direct 8 bit */ |
#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ |
#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ |
#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ |
#define R_TILEPRO_LO16 7 /* Low 16 bit */ |
#define R_TILEPRO_HI16 8 /* High 16 bit */ |
#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ |
#define R_TILEPRO_COPY 10 /* Copy relocation */ |
#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ |
#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ |
#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ |
#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ |
#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ |
#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ |
#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ |
#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ |
#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ |
#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ |
#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ |
#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ |
#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ |
#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ |
#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ |
#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ |
#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ |
#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ |
#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ |
#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ |
#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ |
#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ |
#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ |
#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ |
#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ |
#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ |
#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ |
#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ |
#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ |
#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ |
#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ |
#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ |
#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ |
#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ |
#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ |
#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ |
#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ |
#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ |
#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ |
#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ |
#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ |
#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ |
#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ |
#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ |
#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ |
/* Relocs 56-59 are currently not defined. */ |
#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ |
#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ |
#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ |
#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ |
#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ |
#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ |
#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ |
#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ |
#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ |
#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ |
#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ |
#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ |
#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ |
#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ |
#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ |
#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ |
#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ |
#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ |
#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ |
#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ |
#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ |
#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ |
#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ |
#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ |
#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ |
#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ |
#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ |
#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ |
#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ |
#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ |
#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ |
#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ |
#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ |
#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ |
#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ |
#define R_TILEPRO_NUM 130 |
/* TILE-Gx relocations. */ |
#define R_TILEGX_NONE 0 /* No reloc */ |
#define R_TILEGX_64 1 /* Direct 64 bit */ |
#define R_TILEGX_32 2 /* Direct 32 bit */ |
#define R_TILEGX_16 3 /* Direct 16 bit */ |
#define R_TILEGX_8 4 /* Direct 8 bit */ |
#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ |
#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ |
#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ |
#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ |
#define R_TILEGX_HW0 9 /* hword 0 16-bit */ |
#define R_TILEGX_HW1 10 /* hword 1 16-bit */ |
#define R_TILEGX_HW2 11 /* hword 2 16-bit */ |
#define R_TILEGX_HW3 12 /* hword 3 16-bit */ |
#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ |
#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ |
#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ |
#define R_TILEGX_COPY 16 /* Copy relocation */ |
#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ |
#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ |
#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ |
#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ |
#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ |
#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ |
#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ |
#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ |
#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ |
#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ |
#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ |
#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ |
#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ |
#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ |
#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ |
#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ |
#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ |
#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ |
#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ |
#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ |
#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ |
#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ |
#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ |
#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ |
#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ |
#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ |
#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ |
#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ |
#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ |
#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ |
#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ |
#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ |
#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ |
#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ |
#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ |
#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ |
#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ |
#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ |
#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ |
#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ |
#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ |
#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ |
#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ |
#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ |
#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ |
#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ |
#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ |
#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ |
#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ |
#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */ |
#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */ |
#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */ |
#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */ |
#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */ |
#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */ |
#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ |
#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ |
#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ |
#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ |
#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */ |
#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */ |
#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ |
#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ |
#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ |
#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ |
#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ |
#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ |
#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ |
#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ |
#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ |
#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ |
#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ |
#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ |
/* Relocs 90-91 are currently not defined. */ |
#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ |
#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ |
#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */ |
#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */ |
#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */ |
#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */ |
#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */ |
#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */ |
#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ |
#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ |
#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ |
#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ |
/* Relocs 104-105 are currently not defined. */ |
#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ |
#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ |
#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ |
#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ |
#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ |
#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ |
#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ |
#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ |
#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ |
#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ |
#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ |
#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ |
#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ |
#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ |
#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ |
#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ |
#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ |
#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ |
#define R_TILEGX_NUM 130 |
#endif /* elf.h */ |
/programs/develop/ktcc/trunk/source/float.h |
---|
0,0 → 1,57 |
#ifndef _FLOAT_H_ |
#define _FLOAT_H_ |
#define FLT_RADIX 2 |
/* IEEE float */ |
#define FLT_MANT_DIG 24 |
#define FLT_DIG 6 |
#define FLT_ROUNDS 1 |
#define FLT_EPSILON 1.19209290e-07F |
#define FLT_MIN_EXP (-125) |
#define FLT_MIN 1.17549435e-38F |
#define FLT_MIN_10_EXP (-37) |
#define FLT_MAX_EXP 128 |
#define FLT_MAX 3.40282347e+38F |
#define FLT_MAX_10_EXP 38 |
/* IEEE double */ |
#define DBL_MANT_DIG 53 |
#define DBL_DIG 15 |
#define DBL_EPSILON 2.2204460492503131e-16 |
#define DBL_MIN_EXP (-1021) |
#define DBL_MIN 2.2250738585072014e-308 |
#define DBL_MIN_10_EXP (-307) |
#define DBL_MAX_EXP 1024 |
#define DBL_MAX 1.7976931348623157e+308 |
#define DBL_MAX_10_EXP 308 |
/* horrible intel long double */ |
#ifdef __i386__ |
#define LDBL_MANT_DIG 64 |
#define LDBL_DIG 18 |
#define LDBL_EPSILON 1.08420217248550443401e-19L |
#define LDBL_MIN_EXP (-16381) |
#define LDBL_MIN 3.36210314311209350626e-4932L |
#define LDBL_MIN_10_EXP (-4931) |
#define LDBL_MAX_EXP 16384 |
#define LDBL_MAX 1.18973149535723176502e+4932L |
#define LDBL_MAX_10_EXP 4932 |
#else |
/* same as IEEE double */ |
#define LDBL_MANT_DIG 53 |
#define LDBL_DIG 15 |
#define LDBL_EPSILON 2.2204460492503131e-16 |
#define LDBL_MIN_EXP (-1021) |
#define LDBL_MIN 2.2250738585072014e-308 |
#define LDBL_MIN_10_EXP (-307) |
#define LDBL_MAX_EXP 1024 |
#define LDBL_MAX 1.7976931348623157e+308 |
#define LDBL_MAX_10_EXP 308 |
#endif |
#endif /* _FLOAT_H_ */ |
/programs/develop/ktcc/trunk/source/i386-asm.c |
---|
2,7 → 2,6 |
* i386 specific functions for TCC assembler |
* |
* Copyright (c) 2001, 2002 Fabrice Bellard |
* Copyright (c) 2009 Frédéric Feret (x86_64 support) |
* |
* This library is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
19,18 → 18,14 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
*/ |
#include "tcc.h" |
/* #define NB_ASM_REGS 8 */ |
#define MAX_OPERANDS 3 |
#define NB_SAVED_REGS 3 |
#define TOK_ASM_first TOK_ASM_clc |
#define TOK_ASM_last TOK_ASM_emms |
#define TOK_ASM_alllast TOK_ASM_pxor |
typedef struct ASMInstr { |
uint16_t sym; |
uint16_t opcode; |
uint16_t instr_type; |
#define OPC_JMP 0x01 /* jmp operand */ |
#define OPC_B 0x02 /* only used with OPC_WL */ |
#define OPC_B 0x02 /* only used zith OPC_WL */ |
#define OPC_WL 0x04 /* accepts w, l or no suffix */ |
#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ |
#define OPC_REG 0x08 /* register is added to opcode */ |
42,58 → 37,47 |
#define OPC_ARITH 0x0200 /* arithmetic opcodes */ |
#define OPC_SHORTJMP 0x0400 /* short jmp operand */ |
#define OPC_FARITH 0x0800 /* FPU arithmetic opcodes */ |
#ifdef TCC_TARGET_X86_64 |
# define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */ |
# define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */ |
# define OPC_WLX OPC_WLQ |
#else |
# define OPC_WLX OPC_WL |
#endif |
#define OPC_GROUP_SHIFT 13 |
/* in order to compress the operand type, we use specific operands and |
we or only with EA */ |
enum { |
OPT_REG8=0, /* warning: value is hardcoded from TOK_ASM_xxx */ |
OPT_REG16, /* warning: value is hardcoded from TOK_ASM_xxx */ |
OPT_REG32, /* warning: value is hardcoded from TOK_ASM_xxx */ |
#ifdef TCC_TARGET_X86_64 |
OPT_REG64, /* warning: value is hardcoded from TOK_ASM_xxx */ |
#endif |
OPT_MMX, /* warning: value is hardcoded from TOK_ASM_xxx */ |
OPT_SSE, /* warning: value is hardcoded from TOK_ASM_xxx */ |
OPT_CR, /* warning: value is hardcoded from TOK_ASM_xxx */ |
OPT_TR, /* warning: value is hardcoded from TOK_ASM_xxx */ |
OPT_DB, /* warning: value is hardcoded from TOK_ASM_xxx */ |
OPT_SEG, |
OPT_ST, |
OPT_IM8, |
OPT_IM8S, |
OPT_IM16, |
OPT_IM32, |
#ifdef TCC_TARGET_X86_64 |
OPT_IM64, |
#endif |
OPT_EAX, /* %al, %ax, %eax or %rax register */ |
OPT_ST0, /* %st(0) register */ |
OPT_CL, /* %cl register */ |
OPT_DX, /* %dx register */ |
OPT_ADDR, /* OP_EA with only offset */ |
OPT_INDIR, /* *(expr) */ |
#define OPT_REG8 0 /* warning: value is hardcoded from TOK_ASM_xxx */ |
#define OPT_REG16 1 /* warning: value is hardcoded from TOK_ASM_xxx */ |
#define OPT_REG32 2 /* warning: value is hardcoded from TOK_ASM_xxx */ |
#define OPT_MMX 3 /* warning: value is hardcoded from TOK_ASM_xxx */ |
#define OPT_SSE 4 /* warning: value is hardcoded from TOK_ASM_xxx */ |
#define OPT_CR 5 /* warning: value is hardcoded from TOK_ASM_xxx */ |
#define OPT_TR 6 /* warning: value is hardcoded from TOK_ASM_xxx */ |
#define OPT_DB 7 /* warning: value is hardcoded from TOK_ASM_xxx */ |
#define OPT_SEG 8 |
#define OPT_ST 9 |
#define OPT_IM8 10 |
#define OPT_IM8S 11 |
#define OPT_IM16 12 |
#define OPT_IM32 13 |
#define OPT_EAX 14 /* %al, %ax or %eax register */ |
#define OPT_ST0 15 /* %st(0) register */ |
#define OPT_CL 16 /* %cl register */ |
#define OPT_DX 17 /* %dx register */ |
#define OPT_ADDR 18 /* OP_EA with only offset */ |
#define OPT_INDIR 19 /* *(expr) */ |
/* composite types */ |
OPT_COMPOSITE_FIRST, |
OPT_IM, /* IM8 | IM16 | IM32 | IM64 */ |
OPT_REG, /* REG8 | REG16 | REG32 | REG64 */ |
OPT_REGW, /* REG16 | REG32 | REG64 */ |
OPT_IMW, /* IM16 | IM32 | IM64 */ |
#ifdef TCC_TARGET_X86_64 |
OPT_IMNO64, /* IM16 | IM32 */ |
#endif |
#define OPT_COMPOSITE_FIRST 20 |
#define OPT_IM 20 /* IM8 | IM16 | IM32 */ |
#define OPT_REG 21 /* REG8 | REG16 | REG32 */ |
#define OPT_REGW 22 /* REG16 | REG32 */ |
#define OPT_IMW 23 /* IM16 | IM32 */ |
/* can be ored with any OPT_xxx */ |
OPT_EA = 0x80 |
}; |
#define OPT_EA 0x80 |
uint8_t nb_ops; |
uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */ |
} ASMInstr; |
typedef struct Operand { |
uint32_t type; |
#define OP_REG8 (1 << OPT_REG8) |
#define OP_REG16 (1 << OPT_REG16) |
#define OP_REG32 (1 << OPT_REG32) |
114,39 → 98,10 |
#define OP_DX (1 << OPT_DX) |
#define OP_ADDR (1 << OPT_ADDR) |
#define OP_INDIR (1 << OPT_INDIR) |
#ifdef TCC_TARGET_X86_64 |
# define OP_REG64 (1 << OPT_REG64) |
# define OP_IM64 (1 << OPT_IM64) |
#else |
# define OP_REG64 0 |
# define OP_IM64 0 |
#endif |
#define OP_EA 0x40000000 |
#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64) |
#ifdef TCC_TARGET_X86_64 |
# define OP_IM OP_IM64 |
# define TREG_XAX TREG_RAX |
# define TREG_XCX TREG_RCX |
# define TREG_XDX TREG_RDX |
#else |
#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32) |
# define OP_IM OP_IM32 |
# define TREG_XAX TREG_EAX |
# define TREG_XCX TREG_ECX |
# define TREG_XDX TREG_EDX |
#endif |
typedef struct ASMInstr { |
uint16_t sym; |
uint16_t opcode; |
uint16_t instr_type; |
uint8_t nb_ops; |
uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */ |
} ASMInstr; |
typedef struct Operand { |
uint32_t type; |
int8_t reg; /* register, -1 if none */ |
int8_t reg2; /* second register, -1 if none */ |
uint8_t shift; |
153,18 → 108,14 |
ExprValue e; |
} Operand; |
static const uint8_t reg_to_size[9] = { |
/* |
static const uint8_t reg_to_size[5] = { |
[OP_REG8] = 0, |
[OP_REG16] = 1, |
[OP_REG32] = 2, |
#ifdef TCC_TARGET_X86_64 |
[OP_REG64] = 3, |
#endif |
*/ |
0, 0, 1, 0, 2, 0, 0, 0, 3 |
}; |
#define WORD_PREFIX_OPCODE 0x66 |
#define NB_TEST_OPCODES 30 |
static const uint8_t test_bits[NB_TEST_OPCODES] = { |
200,15 → 151,6 |
0x0f, /* g */ |
}; |
static const uint8_t segment_prefixes[] = { |
0x26, /* es */ |
0x2e, /* cs */ |
0x36, /* ss */ |
0x3e, /* ds */ |
0x64, /* fs */ |
0x65 /* gs */ |
}; |
static const ASMInstr asm_instrs[] = { |
#define ALT(x) x |
#define DEF_ASM_OP0(name, opcode) |
216,11 → 158,8 |
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }}, |
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }}, |
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 3, { op0, op1, op2 }}, |
#ifdef TCC_TARGET_X86_64 |
# include "x86_64-asm.h" |
#else |
# include "i386-asm.h" |
#endif |
/* last operation */ |
{ 0, }, |
}; |
232,20 → 171,13 |
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) |
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) |
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) |
#ifdef TCC_TARGET_X86_64 |
# include "x86_64-asm.h" |
#else |
# include "i386-asm.h" |
#endif |
}; |
static inline int get_reg_shift(TCCState *s1) |
{ |
int shift, v; |
#ifdef I386_ASM_16 |
if (s1->seg_size == 16) |
tcc_error("invalid effective address"); |
#endif |
v = asm_int_expr(s1); |
switch(v) { |
case 1: |
270,26 → 202,19 |
static int asm_parse_reg(void) |
{ |
int reg = 0; |
int reg; |
if (tok != '%') |
goto error_32; |
next(); |
if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) { |
reg = tok - TOK_ASM_eax; |
#ifdef TCC_TARGET_X86_64 |
} else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) { |
reg = tok - TOK_ASM_rax; |
#endif |
#ifdef I386_ASM_16 |
} else if (tok >= TOK_ASM_ax && tok <= TOK_ASM_di) { |
reg = tok - TOK_ASM_ax; |
#endif |
next(); |
return reg; |
} else { |
error_32: |
expect("register"); |
expect("32 bit register"); |
return 0; |
} |
next(); |
return reg; |
} |
static void parse_operand(TCCState *s1, Operand *op) |
310,11 → 235,11 |
reg = tok - TOK_ASM_al; |
op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */ |
op->reg = reg & 7; |
if ((op->type & OP_REG) && op->reg == TREG_XAX) |
if ((op->type & OP_REG) && op->reg == TREG_EAX) |
op->type |= OP_EAX; |
else if (op->type == OP_REG8 && op->reg == TREG_XCX) |
else if (op->type == OP_REG8 && op->reg == TREG_ECX) |
op->type |= OP_CL; |
else if (op->type == OP_REG16 && op->reg == TREG_XDX) |
else if (op->type == OP_REG16 && op->reg == TREG_EDX) |
op->type |= OP_DX; |
} else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) { |
op->type = OP_DB; |
330,7 → 255,7 |
next(); |
if (tok != TOK_PPNUM) |
goto reg_error; |
p = tokc.str.data; |
p = tokc.cstr->data; |
reg = p[0] - '0'; |
if ((unsigned)reg >= 8 || p[1] != '\0') |
goto reg_error; |
343,7 → 268,7 |
goto no_skip; |
} else { |
reg_error: |
tcc_error("unknown register"); |
error("unknown register"); |
} |
next(); |
no_skip: ; |
351,7 → 276,7 |
/* constant value */ |
next(); |
asm_expr(s1, &e); |
op->type = OP_IM; |
op->type = OP_IM32; |
op->e.v = e.v; |
op->e.sym = e.sym; |
if (!op->e.sym) { |
361,10 → 286,6 |
op->type |= OP_IM8S; |
if (op->e.v == (uint16_t)op->e.v) |
op->type |= OP_IM16; |
#ifdef TCC_TARGET_X86_64 |
if (op->e.v == (uint32_t)op->e.v) |
op->type |= OP_IM32; |
#endif |
} |
} else { |
/* address(reg,reg2,shift) with all variants */ |
377,21 → 298,9 |
op->e.v = e.v; |
op->e.sym = e.sym; |
} else { |
next(); |
if (tok == '%') { |
unget_tok('('); |
op->e.v = 0; |
op->e.sym = NULL; |
} else { |
/* bracketed offset expression */ |
asm_expr(s1, &e); |
if (tok != ')') |
expect(")"); |
next(); |
op->e.v = e.v; |
op->e.sym = e.sym; |
} |
} |
if (tok == '(') { |
next(); |
if (tok != ',') { |
402,11 → 311,9 |
if (tok != ',') { |
op->reg2 = asm_parse_reg(); |
} |
if (tok == ',') { |
next(); |
skip(','); |
op->shift = get_reg_shift(s1); |
} |
} |
skip(')'); |
} |
if (op->reg == -1 && op->reg2 == -1) |
416,46 → 323,16 |
} |
/* XXX: unify with C code output ? */ |
ST_FUNC void gen_expr32(ExprValue *pe) |
static void gen_expr32(ExprValue *pe) |
{ |
gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); |
if (pe->sym) |
greloc(cur_text_section, pe->sym, ind, R_386_32); |
gen_le32(pe->v); |
} |
#ifdef TCC_TARGET_X86_64 |
static void gen_expr64(ExprValue *pe) |
{ |
gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v); |
} |
#endif |
/* XXX: unify with C code output ? */ |
static void gen_disp32(ExprValue *pe) |
{ |
Sym *sym = pe->sym; |
if (sym && sym->r == cur_text_section->sh_num) { |
/* same section: we can output an absolute value. Note |
that the TCC compiler behaves differently here because |
it always outputs a relocation to ease (future) code |
elimination in the linker */ |
gen_le32(pe->v + sym->jnext - ind - 4); |
} else { |
if (sym && sym->type.t == VT_VOID) { |
sym->type.t = VT_FUNC; |
sym->type.ref = NULL; |
} |
gen_addrpc32(VT_SYM, sym, pe->v); |
} |
} |
#ifdef I386_ASM_16 |
static void gen_expr16(ExprValue *pe) |
{ |
if (pe->sym) |
greloc(cur_text_section, pe->sym, ind, R_386_16); |
gen_le16(pe->v); |
} |
static void gen_disp16(ExprValue *pe) |
{ |
Sym *sym; |
sym = pe->sym; |
if (sym) { |
464,20 → 341,26 |
that the TCC compiler behaves differently here because |
it always outputs a relocation to ease (future) code |
elimination in the linker */ |
gen_le16(pe->v + sym->jnext - ind - 2); |
gen_le32(pe->v + (long)sym->next - ind - 4); |
} else { |
greloc(cur_text_section, sym, ind, R_386_PC16); |
gen_le16(pe->v - 2); |
greloc(cur_text_section, sym, ind, R_386_PC32); |
gen_le32(pe->v - 4); |
} |
} else { |
/* put an empty PC32 relocation */ |
put_elf_reloc(symtab_section, cur_text_section, |
ind, R_386_PC16, 0); |
gen_le16(pe->v - 2); |
ind, R_386_PC32, 0); |
gen_le32(pe->v - 4); |
} |
} |
#endif |
static void gen_le16(int v) |
{ |
g(v); |
g(v >> 8); |
} |
/* generate the modrm operand */ |
static inline void asm_modrm(int reg, Operand *op) |
{ |
487,16 → 370,8 |
g(0xc0 + (reg << 3) + op->reg); |
} else if (op->reg == -1 && op->reg2 == -1) { |
/* displacement only */ |
#ifdef I386_ASM_16 |
if (tcc_state->seg_size == 16) { |
g(0x06 + (reg << 3)); |
gen_expr16(&op->e); |
} else if (tcc_state->seg_size == 32) |
#endif |
{ |
g(0x05 + (reg << 3)); |
gen_expr32(&op->e); |
} |
} else { |
sib_reg1 = op->reg; |
/* fist compute displacement encoding */ |
514,9 → 389,6 |
reg1 = op->reg; |
if (op->reg2 != -1) |
reg1 = 4; |
#ifdef I386_ASM_16 |
if (tcc_state->seg_size == 32) { |
#endif |
g(mod + (reg << 3) + reg1); |
if (reg1 == 4) { |
/* add sib byte */ |
525,96 → 397,34 |
reg2 = 4; /* indicate no index */ |
g((op->shift << 6) + (reg2 << 3) + sib_reg1); |
} |
#ifdef I386_ASM_16 |
} else if (tcc_state->seg_size == 16) { |
/* edi = 7, esi = 6 --> di = 5, si = 4 */ |
if ((reg1 == 6) || (reg1 == 7)) { |
reg1 -= 2; |
/* ebx = 3 --> bx = 7 */ |
} else if (reg1 == 3) { |
reg1 = 7; |
/* o32 = 5 --> o16 = 6 */ |
} else if (reg1 == 5) { |
reg1 = 6; |
/* sib not valid in 16-bit mode */ |
} else if (reg1 == 4) { |
reg2 = op->reg2; |
/* bp + si + offset */ |
if ((sib_reg1 == 5) && (reg2 == 6)) { |
reg1 = 2; |
/* bp + di + offset */ |
} else if ((sib_reg1 == 5) && (reg2 == 7)) { |
reg1 = 3; |
/* bx + si + offset */ |
} else if ((sib_reg1 == 3) && (reg2 == 6)) { |
reg1 = 0; |
/* bx + di + offset */ |
} else if ((sib_reg1 == 3) && (reg2 == 7)) { |
reg1 = 1; |
} else { |
tcc_error("invalid effective address"); |
} |
if (op->e.v == 0) |
mod = 0; |
} else { |
tcc_error("invalid register"); |
} |
g(mod + (reg << 3) + reg1); |
} |
#endif |
/* add offset */ |
if (mod == 0x40) { |
g(op->e.v); |
} else if (mod == 0x80 || op->reg == -1) { |
#ifdef I386_ASM_16 |
if (tcc_state->seg_size == 16) |
gen_expr16(&op->e); |
else if (tcc_state->seg_size == 32) |
#endif |
gen_expr32(&op->e); |
} |
} |
} |
ST_FUNC void asm_opcode(TCCState *s1, int opcode) |
static void asm_opcode(TCCState *s1, int opcode) |
{ |
const ASMInstr *pa; |
int i, modrm_index, reg, v, op1, is_short_jmp, seg_prefix; |
int nb_ops, s; |
int i, modrm_index, reg, v, op1, is_short_jmp; |
int nb_ops, s, ss; |
Operand ops[MAX_OPERANDS], *pop; |
int op_type[3]; /* decoded op type */ |
#ifdef I386_ASM_16 |
static int a32 = 0, o32 = 0, addr32 = 0, data32 = 0; |
#endif |
/* force synthetic ';' after prefix instruction, so we can handle */ |
/* one-line things like "rep stosb" instead of only "rep\nstosb" */ |
if (opcode >= TOK_ASM_wait && opcode <= TOK_ASM_repnz) |
unget_tok(';'); |
/* get operands */ |
pop = ops; |
nb_ops = 0; |
seg_prefix = 0; |
for(;;) { |
if (tok == ';' || tok == TOK_LINEFEED) |
break; |
if (nb_ops >= MAX_OPERANDS) { |
tcc_error("incorrect number of operands"); |
error("incorrect number of operands"); |
} |
parse_operand(s1, pop); |
if (tok == ':') { |
if (pop->type != OP_SEG || seg_prefix) |
tcc_error("incorrect prefix"); |
seg_prefix = segment_prefixes[pop->reg]; |
next(); |
parse_operand(s1, pop); |
#ifndef I386_ASM_16 |
if (!(pop->type & OP_EA)) { |
tcc_error("segment prefix must be followed by memory reference"); |
} |
#endif |
} |
pop++; |
nb_ops++; |
if (tok != ',') |
634,22 → 444,23 |
if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) |
continue; |
} else if (pa->instr_type & OPC_ARITH) { |
if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX)) |
if (!(opcode >= pa->sym && opcode < pa->sym + 8 * 4)) |
continue; |
s = (opcode - pa->sym) % NBWLX; |
goto compute_size; |
} else if (pa->instr_type & OPC_SHIFT) { |
if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX)) |
if (!(opcode >= pa->sym && opcode < pa->sym + 7 * 4)) |
continue; |
s = (opcode - pa->sym) % NBWLX; |
goto compute_size; |
} else if (pa->instr_type & OPC_TEST) { |
if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) |
continue; |
} else if (pa->instr_type & OPC_B) { |
if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX)) |
if (!(opcode >= pa->sym && opcode <= pa->sym + 3)) |
continue; |
s = opcode - pa->sym; |
} else if (pa->instr_type & OPC_WLX) { |
if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) |
compute_size: |
s = (opcode - pa->sym) & 3; |
} else if (pa->instr_type & OPC_WL) { |
if (!(opcode >= pa->sym && opcode <= pa->sym + 2)) |
continue; |
s = opcode - pa->sym + 1; |
} else { |
665,22 → 476,17 |
op2 = op1 & 0x1f; |
switch(op2) { |
case OPT_IM: |
v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64; |
v = OP_IM8 | OP_IM16 | OP_IM32; |
break; |
case OPT_REG: |
v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64; |
v = OP_REG8 | OP_REG16 | OP_REG32; |
break; |
case OPT_REGW: |
v = OP_REG16 | OP_REG32 | OP_REG64; |
v = OP_REG16 | OP_REG32; |
break; |
case OPT_IMW: |
v = OP_IM16 | OP_IM32 | OP_IM64; |
break; |
#ifdef TCC_TARGET_X86_64 |
case OPT_IMNO64: |
v = OP_IM16 | OP_IM32; |
break; |
#endif |
default: |
v = 1 << op2; |
break; |
696,105 → 502,48 |
next: ; |
} |
if (pa->sym == 0) { |
if (opcode >= TOK_ASM_first && opcode <= TOK_ASM_last) { |
if (opcode >= TOK_ASM_pusha && opcode <= TOK_ASM_emms) { |
int b; |
b = op0_codes[opcode - TOK_ASM_first]; |
#ifdef I386_ASM_16 |
if (opcode == TOK_ASM_o32) { |
if (s1->seg_size == 32) |
tcc_error("incorrect prefix"); |
else |
o32 = data32 = 1; |
} else if (opcode == TOK_ASM_a32) { |
if (s1->seg_size == 32) |
tcc_error("incorrect prefix"); |
else |
a32 = addr32 = 1; |
} |
#endif |
b = op0_codes[opcode - TOK_ASM_pusha]; |
if (b & 0xff00) |
g(b >> 8); |
g(b); |
return; |
} else if (opcode <= TOK_ASM_alllast) { |
tcc_error("bad operand with opcode '%s'", |
get_tok_str(opcode, NULL)); |
} else { |
tcc_error("unknown opcode '%s'", |
error("unknown opcode '%s'", |
get_tok_str(opcode, NULL)); |
} |
} |
/* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */ |
if (s == NBWLX-1) { |
for(i = 0; s == NBWLX-1 && i < nb_ops; i++) { |
if (s == 3) { |
for(i = 0; s == 3 && i < nb_ops; i++) { |
if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX))) |
s = reg_to_size[ops[i].type & OP_REG]; |
} |
if (s == NBWLX-1) { |
if (s == 3) { |
if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && |
(ops[0].type & (OP_SEG | OP_IM8S | OP_IM32 | OP_IM64))) |
(ops[0].type & (OP_SEG | OP_IM8S | OP_IM32))) |
s = 2; |
else |
tcc_error("cannot infer opcode suffix"); |
error("cannot infer opcode suffix"); |
} |
} |
#ifdef I386_ASM_16 |
for(i = 0; i < nb_ops; i++) { |
if (ops[i].type & OP_REG32) { |
if (s1->seg_size == 16) |
o32 = 1; |
} else if (!(ops[i].type & OP_REG32)) { |
if (s1->seg_size == 32) |
o32 = 1; |
} |
} |
if (s == 1 || (pa->instr_type & OPC_D16)) { |
if (s1->seg_size == 32) |
o32 = 1; |
} else if (s == 2) { |
if (s1->seg_size == 16) { |
if (!(pa->instr_type & OPC_D16)) |
o32 = 1; |
} |
} |
/* generate a16/a32 prefix if needed */ |
if ((a32 == 1) && (addr32 == 0)) |
g(0x67); |
/* generate o16/o32 prefix if needed */ |
if ((o32 == 1) && (data32 == 0)) |
g(0x66); |
addr32 = data32 = 0; |
#else |
/* generate data16 prefix if needed */ |
ss = s; |
if (s == 1 || (pa->instr_type & OPC_D16)) |
g(0x66); |
#ifdef TCC_TARGET_X86_64 |
else if (s == 3) { |
/* generate REX prefix */ |
if ((opcode != TOK_ASM_push && opcode != TOK_ASM_pop) |
|| !(ops[0].type & OP_REG64)) |
g(0x48); |
} |
#endif |
#endif |
g(WORD_PREFIX_OPCODE); |
else if (s == 2) |
s = 1; |
/* now generates the operation */ |
if (pa->instr_type & OPC_FWAIT) |
g(0x9b); |
if (seg_prefix) |
g(seg_prefix); |
v = pa->opcode; |
if ((v == 0x69 || v == 0x6b) && nb_ops == 2) { |
if (v == 0x69 || v == 0x69) { |
/* kludge for imul $im, %reg */ |
nb_ops = 3; |
ops[2] = ops[1]; |
op_type[2] = op_type[1]; |
} else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) { |
v--; /* int $3 case */ |
nb_ops = 0; |
808,7 → 557,7 |
nb_ops = 0; |
} else if (v <= 0x05) { |
/* arith case */ |
v += ((opcode - TOK_ASM_addb) / NBWLX) << 3; |
v += ((opcode - TOK_ASM_addb) >> 2) << 3; |
} else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) { |
/* fpu arith case */ |
v += ((opcode - pa->sym) / 6) << 3; |
825,7 → 574,7 |
v += 7; |
} |
if (pa->instr_type & OPC_B) |
v += s >= 1; |
v += s; |
if (pa->instr_type & OPC_TEST) |
v += test_bits[opcode - pa->sym]; |
if (pa->instr_type & OPC_SHORTJMP) { |
838,7 → 587,7 |
goto no_short_jump; |
if (sym->r != cur_text_section->sh_num) |
goto no_short_jump; |
jmp_disp = ops[0].e.v + sym->jnext - ind - 2; |
jmp_disp = ops[0].e.v + (long)sym->next - ind - 2; |
if (jmp_disp == (int8_t)jmp_disp) { |
/* OK to generate jump */ |
is_short_jmp = 1; |
853,7 → 602,7 |
else |
v += 0x0f10; |
} else { |
tcc_error("invalid displacement"); |
error("invalid displacement"); |
} |
} |
} |
865,11 → 614,11 |
/* search which operand will used for modrm */ |
modrm_index = 0; |
if (pa->instr_type & OPC_SHIFT) { |
reg = (opcode - pa->sym) / NBWLX; |
reg = (opcode - pa->sym) >> 2; |
if (reg == 6) |
reg = 7; |
} else if (pa->instr_type & OPC_ARITH) { |
reg = (opcode - pa->sym) / NBWLX; |
reg = (opcode - pa->sym) >> 2; |
} else if (pa->instr_type & OPC_FARITH) { |
reg = (opcode - pa->sym) / 6; |
} else { |
887,7 → 636,7 |
goto modrm_found; |
} |
#ifdef ASM_DEBUG |
tcc_error("bad op table"); |
error("bad op table"); |
#endif |
modrm_found: |
modrm_index = i; |
906,35 → 655,26 |
} |
/* emit constants */ |
#ifndef TCC_TARGET_X86_64 |
if (pa->opcode == 0x9a || pa->opcode == 0xea) { |
/* ljmp or lcall kludge */ |
#ifdef I386_ASM_16 |
if (s1->seg_size == 16 && o32 == 0) |
gen_expr16(&ops[1].e); |
else |
#endif |
gen_expr32(&ops[1].e); |
if (ops[0].e.sym) |
tcc_error("cannot relocate"); |
error("cannot relocate"); |
gen_le16(ops[0].e.v); |
return; |
} |
#endif |
} else { |
for(i = 0;i < nb_ops; i++) { |
v = op_type[i]; |
if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) { |
if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM8S | OP_ADDR)) { |
/* if multiple sizes are given it means we must look |
at the op size */ |
if ((v | OP_IM8 | OP_IM64) == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64)) { |
if (s == 0) |
if (v == (OP_IM8 | OP_IM16 | OP_IM32) || |
v == (OP_IM16 | OP_IM32)) { |
if (ss == 0) |
v = OP_IM8; |
else if (s == 1) |
else if (ss == 1) |
v = OP_IM16; |
else if (s == 2 || (v & OP_IM64) == 0) |
else |
v = OP_IM32; |
else |
v = OP_IM64; |
} |
if (v & (OP_IM8 | OP_IM8S)) { |
if (ops[i].e.sym) |
941,61 → 681,29 |
goto error_relocate; |
g(ops[i].e.v); |
} else if (v & OP_IM16) { |
#ifdef I386_ASM_16 |
if (s1->seg_size == 16) |
gen_expr16(&ops[i].e); |
else |
#endif |
if (ops[i].e.sym) |
if (ops[i].e.sym) { |
error_relocate: |
tcc_error("cannot relocate"); |
else |
error("cannot relocate"); |
} |
gen_le16(ops[i].e.v); |
} else { |
if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { |
if (is_short_jmp) |
g(ops[i].e.v); |
#ifdef I386_ASM_16 |
else if (s1->seg_size == 16) |
gen_disp16(&ops[i].e); |
#endif |
else |
gen_disp32(&ops[i].e); |
} else { |
#ifdef I386_ASM_16 |
if (s1->seg_size == 16 && !((o32 == 1) && (v & OP_IM32))) |
gen_expr16(&ops[i].e); |
else |
#endif |
#ifdef TCC_TARGET_X86_64 |
if (v & OP_IM64) |
gen_expr64(&ops[i].e); |
else |
#endif |
gen_expr32(&ops[i].e); |
} |
} |
#ifdef I386_ASM_16 |
} else if (v & (OP_REG16 | OP_REG32)) { |
if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { |
/* jmp $r */ |
g(0xE0 + ops[i].reg); |
} |
#endif |
#ifdef TCC_TARGET_X86_64 |
} else if (v & (OP_REG32 | OP_REG64)) { |
if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { |
/* jmp $r */ |
g(0xE0 + ops[i].reg); |
} |
#endif |
} |
} |
#ifdef I386_ASM_16 |
a32 = o32 = 0; |
#endif |
} |
#define NB_SAVED_REGS 3 |
#define NB_ASM_REGS 8 |
/* return the constraint priority (we allocate first the lowest |
numbered constraints) */ |
static inline int constraint_priority(const char *str) |
1036,7 → 744,7 |
pr = 4; |
break; |
default: |
tcc_error("unknown constraint '%c'", c); |
error("unknown constraint '%c'", c); |
pr = 0; |
} |
if (pr > priority) |
1057,7 → 765,7 |
#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask) |
ST_FUNC void asm_compute_constraints(ASMOperand *operands, |
static void asm_compute_constraints(ASMOperand *operands, |
int nb_operands, int nb_outputs, |
const uint8_t *clobber_regs, |
int *pout_reg) |
1087,11 → 795,11 |
/* this is a reference to another constraint */ |
k = find_constraint(operands, nb_operands, str, NULL); |
if ((unsigned)k >= i || i < nb_outputs) |
tcc_error("invalid reference in constraint %d ('%s')", |
error("invalid reference in constraint %d ('%s')", |
i, str); |
op->ref_index = k; |
if (operands[k].input_index >= 0) |
tcc_error("cannot reference twice the same operand"); |
error("cannot reference twice the same operand"); |
operands[k].input_index = i; |
op->priority = 5; |
} else { |
1151,30 → 859,30 |
/* FALL THRU */ |
case '&': |
if (j >= nb_outputs) |
tcc_error("'%c' modifier can only be applied to outputs", c); |
error("'%c' modifier can only be applied to outputs", c); |
reg_mask = REG_IN_MASK | REG_OUT_MASK; |
goto try_next; |
case 'A': |
/* allocate both eax and edx */ |
if (is_reg_allocated(TREG_XAX) || |
is_reg_allocated(TREG_XDX)) |
if (is_reg_allocated(TREG_EAX) || |
is_reg_allocated(TREG_EDX)) |
goto try_next; |
op->is_llong = 1; |
op->reg = TREG_XAX; |
regs_allocated[TREG_XAX] |= reg_mask; |
regs_allocated[TREG_XDX] |= reg_mask; |
op->reg = TREG_EAX; |
regs_allocated[TREG_EAX] |= reg_mask; |
regs_allocated[TREG_EDX] |= reg_mask; |
break; |
case 'a': |
reg = TREG_XAX; |
reg = TREG_EAX; |
goto alloc_reg; |
case 'b': |
reg = 3; |
goto alloc_reg; |
case 'c': |
reg = TREG_XCX; |
reg = TREG_ECX; |
goto alloc_reg; |
case 'd': |
reg = TREG_XDX; |
reg = TREG_EDX; |
goto alloc_reg; |
case 'S': |
reg = 6; |
1242,7 → 950,7 |
} |
break; |
default: |
tcc_error("asm constraint %d ('%s') could not be satisfied", |
error("asm constraint %d ('%s') could not be satisfied", |
j, op->constraint); |
break; |
} |
1265,7 → 973,7 |
if (!(regs_allocated[reg] & REG_OUT_MASK)) |
goto reg_found2; |
} |
tcc_error("could not find free output register for reloading"); |
error("could not find free output register for reloading"); |
reg_found2: |
*pout_reg = reg; |
break; |
1289,7 → 997,7 |
#endif |
} |
ST_FUNC void subst_asm_operand(CString *add_str, |
static void subst_asm_operand(CString *add_str, |
SValue *sv, int modifier) |
{ |
int r, reg, size, val; |
1300,8 → 1008,8 |
if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n') |
cstr_ccat(add_str, '$'); |
if (r & VT_SYM) { |
cstr_cat(add_str, get_tok_str(sv->sym->v, NULL), -1); |
if ((uint32_t)sv->c.i != 0) { |
cstr_cat(add_str, get_tok_str(sv->sym->v, NULL)); |
if (sv->c.i != 0) { |
cstr_ccat(add_str, '+'); |
} else { |
return; |
1310,23 → 1018,23 |
val = sv->c.i; |
if (modifier == 'n') |
val = -val; |
snprintf(buf, sizeof(buf), "%d", (int)sv->c.i); |
cstr_cat(add_str, buf, -1); |
snprintf(buf, sizeof(buf), "%d", sv->c.i); |
cstr_cat(add_str, buf); |
} else if ((r & VT_VALMASK) == VT_LOCAL) { |
snprintf(buf, sizeof(buf), "%d(%%ebp)", (int)sv->c.i); |
cstr_cat(add_str, buf, -1); |
snprintf(buf, sizeof(buf), "%d(%%ebp)", sv->c.i); |
cstr_cat(add_str, buf); |
} else if (r & VT_LVAL) { |
reg = r & VT_VALMASK; |
if (reg >= VT_CONST) |
tcc_error("internal compiler error"); |
error("internal compiler error"); |
snprintf(buf, sizeof(buf), "(%%%s)", |
get_tok_str(TOK_ASM_eax + reg, NULL)); |
cstr_cat(add_str, buf, -1); |
cstr_cat(add_str, buf); |
} else { |
/* register case */ |
reg = r & VT_VALMASK; |
if (reg >= VT_CONST) |
tcc_error("internal compiler error"); |
error("internal compiler error"); |
/* choose register operand size */ |
if ((sv->type.t & VT_BTYPE) == VT_BYTE) |
1333,10 → 1041,6 |
size = 1; |
else if ((sv->type.t & VT_BTYPE) == VT_SHORT) |
size = 2; |
#ifdef TCC_TARGET_X86_64 |
else if ((sv->type.t & VT_BTYPE) == VT_LLONG) |
size = 8; |
#endif |
else |
size = 4; |
if (size == 1 && reg >= 4) |
1344,18 → 1048,14 |
if (modifier == 'b') { |
if (reg >= 4) |
tcc_error("cannot use byte register"); |
error("cannot use byte register"); |
size = 1; |
} else if (modifier == 'h') { |
if (reg >= 4) |
tcc_error("cannot use byte register"); |
error("cannot use byte register"); |
size = -1; |
} else if (modifier == 'w') { |
size = 2; |
#ifdef TCC_TARGET_X86_64 |
} else if (modifier == 'q') { |
size = 8; |
#endif |
} |
switch(size) { |
1371,19 → 1071,14 |
default: |
reg = TOK_ASM_eax + reg; |
break; |
#ifdef TCC_TARGET_X86_64 |
case 8: |
reg = TOK_ASM_rax + reg; |
break; |
#endif |
} |
snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL)); |
cstr_cat(add_str, buf, -1); |
cstr_cat(add_str, buf); |
} |
} |
/* generate prolog and epilog code for asm statement */ |
ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, |
/* generate prolog and epilog code for asm statment */ |
static void asm_gen_code(ASMOperand *operands, int nb_operands, |
int nb_outputs, int is_output, |
uint8_t *clobber_regs, |
int out_reg) |
1404,14 → 1099,9 |
/* generate reg save code */ |
for(i = 0; i < NB_SAVED_REGS; i++) { |
reg = reg_saved[i]; |
if (regs_allocated[reg]) { |
#ifdef I386_ASM_16 |
if (tcc_state->seg_size == 16) |
g(0x66); |
#endif |
if (regs_allocated[reg]) |
g(0x50 + reg); |
} |
} |
/* generate load code */ |
for(i = 0; i < nb_operands; i++) { |
1431,8 → 1121,8 |
if (op->is_llong) { |
SValue sv; |
sv = *op->vt; |
sv.c.i += 4; |
load(TREG_XDX, &sv); |
sv.c.ul += 4; |
load(TREG_EDX, &sv); |
} |
} |
} |
1457,8 → 1147,8 |
if (op->is_llong) { |
SValue sv; |
sv = *op->vt; |
sv.c.i += 4; |
store(TREG_XDX, &sv); |
sv.c.ul += 4; |
store(TREG_EDX, &sv); |
} |
} |
} |
1466,18 → 1156,13 |
/* generate reg restore code */ |
for(i = NB_SAVED_REGS - 1; i >= 0; i--) { |
reg = reg_saved[i]; |
if (regs_allocated[reg]) { |
#ifdef I386_ASM_16 |
if (tcc_state->seg_size == 16) |
g(0x66); |
#endif |
if (regs_allocated[reg]) |
g(0x58 + reg); |
} |
} |
} |
} |
ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) |
static void asm_clobber(uint8_t *clobber_regs, const char *str) |
{ |
int reg; |
TokenSym *ts; |
1491,12 → 1176,8 |
reg -= TOK_ASM_eax; |
} else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) { |
reg -= TOK_ASM_ax; |
#ifdef TCC_TARGET_X86_64 |
} else if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) { |
reg -= TOK_ASM_rax; |
#endif |
} else { |
tcc_error("invalid clobber register '%s'", str); |
error("invalid clobber register '%s'", str); |
} |
clobber_regs[reg] = 1; |
} |
/programs/develop/ktcc/trunk/source/i386-asm.h |
---|
1,4 → 1,6 |
DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */ |
DEF_ASM_OP0(pusha, 0x60) /* must be first OP0 */ |
DEF_ASM_OP0(popa, 0x61) |
DEF_ASM_OP0(clc, 0xf8) |
DEF_ASM_OP0(cld, 0xfc) |
DEF_ASM_OP0(cli, 0xfa) |
DEF_ASM_OP0(clts, 0x0f06) |
5,8 → 7,6 |
DEF_ASM_OP0(cmc, 0xf5) |
DEF_ASM_OP0(lahf, 0x9f) |
DEF_ASM_OP0(sahf, 0x9e) |
DEF_ASM_OP0(pusha, 0x60) |
DEF_ASM_OP0(popa, 0x61) |
DEF_ASM_OP0(pushfl, 0x9c) |
DEF_ASM_OP0(popfl, 0x9d) |
DEF_ASM_OP0(pushf, 0x9c) |
33,8 → 33,8 |
DEF_ASM_OP0(iret, 0xcf) |
DEF_ASM_OP0(rsm, 0x0faa) |
DEF_ASM_OP0(hlt, 0xf4) |
DEF_ASM_OP0(wait, 0x9b) |
DEF_ASM_OP0(nop, 0x90) |
DEF_ASM_OP0(pause, 0xf390) |
DEF_ASM_OP0(xlat, 0xd7) |
/* strings */ |
74,17 → 74,10 |
ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA)) |
/* prefixes */ |
DEF_ASM_OP0(wait, 0x9b) |
DEF_ASM_OP0(fwait, 0x9b) |
#ifdef I386_ASM_16 |
DEF_ASM_OP0(a32, 0x67) |
DEF_ASM_OP0(o32, 0x66) |
#else |
DEF_ASM_OP0(aword, 0x67) |
DEF_ASM_OP0(addr16, 0x67) |
ALT(DEF_ASM_OP0(word, 0x66)) |
DEF_ASM_OP0(word, 0x66) |
DEF_ASM_OP0(data16, 0x66) |
#endif |
DEF_ASM_OP0(lock, 0xf0) |
DEF_ASM_OP0(rep, 0xf3) |
DEF_ASM_OP0(repe, 0xf3) |
208,9 → 201,6 |
ALT(DEF_ASM_OP1(call, 0xe8, 0, OPC_JMP, OPT_ADDR)) |
ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR)) |
ALT(DEF_ASM_OP1(jmp, 0xeb, 0, OPC_SHORTJMP | OPC_JMP, OPT_ADDR)) |
#ifdef I386_ASM_16 |
ALT(DEF_ASM_OP1(jmp, 0xff, 0, OPC_JMP | OPC_WL, OPT_REGW)) |
#endif |
ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32)) |
ALT(DEF_ASM_OP1(lcall, 0xff, 3, 0, OPT_EA)) |
219,12 → 209,9 |
ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8)) |
ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) |
ALT(DEF_ASM_OP1(setob, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) |
DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8) |
DEF_ASM_OP0(leave, 0xc9) |
DEF_ASM_OP0(ret, 0xc3) |
DEF_ASM_OP0(retl,0xc3) |
ALT(DEF_ASM_OP1(retl,0xc2, 0, 0, OPT_IM16)) |
ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16)) |
DEF_ASM_OP0(lret, 0xcb) |
ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16)) |
243,8 → 230,6 |
ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST)) |
ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) |
ALT(DEF_ASM_OP2(fadd, 0xdcc0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) |
ALT(DEF_ASM_OP2(fmul, 0xdcc8, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) |
ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH)) |
ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST)) |
ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) |
287,6 → 272,7 |
DEF_ASM_OP0(fninit, 0xdbe3) |
DEF_ASM_OP0(fnclex, 0xdbe2) |
DEF_ASM_OP0(fnop, 0xd9d0) |
DEF_ASM_OP0(fwait, 0x9b) |
/* fp load */ |
DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST) |
364,11 → 350,6 |
DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA) |
DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA) |
#ifdef I386_ASM_16 |
/* 386 */ |
DEF_ASM_OP0(loadall386, 0x0f07) |
#endif |
/* 486 */ |
DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 ) |
ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA )) |
383,15 → 364,7 |
/* pentium pro */ |
ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32)) |
#ifdef I386_ASM_16 |
ALT(DEF_ASM_OP2(cmovno, 0x0f41, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32)) |
ALT(DEF_ASM_OP2(cmovc, 0x0f42, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32)) |
ALT(DEF_ASM_OP2(cmovnc, 0x0f43, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32)) |
ALT(DEF_ASM_OP2(cmovz, 0x0f44, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32)) |
ALT(DEF_ASM_OP2(cmovnz, 0x0f45, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32)) |
ALT(DEF_ASM_OP2(cmovna, 0x0f46, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32)) |
ALT(DEF_ASM_OP2(cmova, 0x0f47, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32)) |
#endif |
DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 ) |
DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 ) |
DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 ) |
408,7 → 381,6 |
/* mmx */ |
DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */ |
DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMX ) |
ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_REG32 )) |
DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) |
466,32 → 438,6 |
DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) |
DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) |
/* sse */ |
DEF_ASM_OP2(movups, 0x0f10, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) |
ALT(DEF_ASM_OP2(movups, 0x0f11, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) |
DEF_ASM_OP2(movaps, 0x0f28, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) |
ALT(DEF_ASM_OP2(movaps, 0x0f29, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) |
DEF_ASM_OP2(movhps, 0x0f16, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) |
ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) |
DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE ) |
DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) |
DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) |
DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(mulps, 0x0f59, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(pavgb, 0x0fe0, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(pavgw, 0x0fe3, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(pmaxsw, 0x0fee, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) |
DEF_ASM_OP2(pmaxub, 0x0fde, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) |
DEF_ASM_OP2(pminsw, 0x0fea, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) |
DEF_ASM_OP2(pminub, 0x0fda, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) |
DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) |
#undef ALT |
#undef DEF_ASM_OP0 |
#undef DEF_ASM_OP0L |
/programs/develop/ktcc/trunk/source/i386-gen.c |
---|
18,11 → 18,8 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
*/ |
#ifdef TARGET_DEFS_ONLY |
/* number of available registers */ |
#define NB_REGS 4 |
#define NB_ASM_REGS 8 |
/* a register can belong to several classes. The classes must be |
sorted from more general to more precise (see gv2() code which does |
43,9 → 40,15 |
TREG_ECX, |
TREG_EDX, |
TREG_ST0, |
TREG_ESP = 4 |
}; |
int reg_classes[NB_REGS] = { |
/* eax */ RC_INT | RC_EAX, |
/* ecx */ RC_INT | RC_ECX, |
/* edx */ RC_INT | RC_EDX, |
/* st0 */ RC_FLOAT | RC_ST0, |
}; |
/* return registers for function */ |
#define REG_IRET TREG_EAX /* single word int return register */ |
#define REG_LRET TREG_EDX /* second word return register (for long long) */ |
56,7 → 59,7 |
/* defined if structures are passed as pointers. Otherwise structures |
are directly pushed on stack. */ |
/* #define FUNC_STRUCT_PARAM_AS_PTR */ |
//#define FUNC_STRUCT_PARAM_AS_PTR |
/* pointer size, in bytes */ |
#define PTR_SIZE 4 |
67,9 → 70,6 |
/* maximum alignment (for aligned attribute support) */ |
#define MAX_ALIGN 8 |
#define psym oad |
/******************************************************/ |
/* ELF defines */ |
77,7 → 77,6 |
/* relocation type for 32 bit data relocation */ |
#define R_DATA_32 R_386_32 |
#define R_DATA_PTR R_386_32 |
#define R_JMP_SLOT R_386_JMP_SLOT |
#define R_COPY R_386_COPY |
85,25 → 84,13 |
#define ELF_PAGE_SIZE 0x1000 |
/******************************************************/ |
#else /* ! TARGET_DEFS_ONLY */ |
/******************************************************/ |
#include "tcc.h" |
ST_DATA const int reg_classes[NB_REGS] = { |
/* eax */ RC_INT | RC_EAX, |
/* ecx */ RC_INT | RC_ECX, |
/* edx */ RC_INT | RC_EDX, |
/* st0 */ RC_FLOAT | RC_ST0, |
}; |
static unsigned long func_sub_sp_offset; |
static unsigned long func_bound_offset; |
static int func_ret_sub; |
#ifdef CONFIG_TCC_BCHECK |
static addr_t func_bound_offset; |
#endif |
/* XXX: make it faster ? */ |
ST_FUNC void g(int c) |
void g(int c) |
{ |
int ind1; |
ind1 = ind + 1; |
113,7 → 100,7 |
ind = ind1; |
} |
ST_FUNC void o(unsigned int c) |
void o(unsigned int c) |
{ |
while (c) { |
g(c); |
121,14 → 108,8 |
} |
} |
ST_FUNC void gen_le16(int v) |
void gen_le32(int c) |
{ |
g(v); |
g(v >> 8); |
} |
ST_FUNC void gen_le32(int c) |
{ |
g(c); |
g(c >> 8); |
g(c >> 16); |
136,17 → 117,18 |
} |
/* output a symbol and patch all calls to it */ |
ST_FUNC void gsym_addr(int t, int a) |
void gsym_addr(int t, int a) |
{ |
int n, *ptr; |
while (t) { |
unsigned char *ptr = cur_text_section->data + t; |
uint32_t n = read32le(ptr); /* next value */ |
write32le(ptr, a - t - 4); |
ptr = (int *)(cur_text_section->data + t); |
n = *ptr; /* next value */ |
*ptr = a - t - 4; |
t = n; |
} |
} |
ST_FUNC void gsym(int t) |
void gsym(int t) |
{ |
gsym_addr(t, ind); |
} |
156,7 → 138,7 |
#define psym oad |
/* instruction + 4 bytes data. Return the address of the data */ |
ST_FUNC int oad(int c, int s) |
static int oad(int c, int s) |
{ |
int ind1; |
164,7 → 146,7 |
ind1 = ind + 4; |
if (ind1 > cur_text_section->data_allocated) |
section_realloc(cur_text_section, ind1); |
write32le(cur_text_section->data + ind, s); |
*(int *)(cur_text_section->data + ind) = s; |
s = ind; |
ind = ind1; |
return s; |
171,7 → 153,7 |
} |
/* output constant with relocation if 'r & VT_SYM' is true */ |
ST_FUNC void gen_addr32(int r, Sym *sym, int c) |
static void gen_addr32(int r, Sym *sym, int c) |
{ |
if (r & VT_SYM) |
greloc(cur_text_section, sym, ind, R_386_32); |
178,13 → 160,6 |
gen_le32(c); |
} |
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c) |
{ |
if (r & VT_SYM) |
greloc(cur_text_section, sym, ind, R_386_PC32); |
gen_le32(c - 4); |
} |
/* generate a modrm reference. 'op_reg' contains the addtionnal 3 |
opcode bits */ |
static void gen_modrm(int op_reg, int r, Sym *sym, int c) |
208,33 → 183,25 |
} |
} |
/* load 'r' from value 'sv' */ |
ST_FUNC void load(int r, SValue *sv) |
void load(int r, SValue *sv) |
{ |
int v, t, ft, fc, fr; |
SValue v1; |
#ifdef TCC_TARGET_PE |
SValue v2; |
sv = pe_getimport(sv, &v2); |
#endif |
fr = sv->r; |
ft = sv->type.t; |
fc = sv->c.i; |
fc = sv->c.ul; |
ft &= ~(VT_VOLATILE | VT_CONSTANT); |
v = fr & VT_VALMASK; |
if (fr & VT_LVAL) { |
if (v == VT_LLOCAL) { |
v1.type.t = VT_INT; |
v1.r = VT_LOCAL | VT_LVAL; |
v1.c.i = fc; |
v1.c.ul = fc; |
load(r, &v1); |
fr = r; |
if (!(reg_classes[fr] & RC_INT)) |
fr = get_reg(RC_INT); |
load(fr, &v1); |
} |
if ((ft & VT_BTYPE) == VT_FLOAT) { |
o(0xd9); /* flds */ |
245,7 → 212,7 |
} else if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
o(0xdb); /* fldt */ |
r = 5; |
} else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { |
} else if ((ft & VT_TYPE) == VT_BYTE) { |
o(0xbe0f); /* movsbl */ |
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { |
o(0xb60f); /* movzbl */ |
262,13 → 229,8 |
o(0xb8 + r); /* mov $xx, r */ |
gen_addr32(fr, sv->sym, fc); |
} else if (v == VT_LOCAL) { |
if (fc) { |
o(0x8d); /* lea xxx(%ebp), r */ |
gen_modrm(r, VT_LOCAL, sv->sym, fc); |
} else { |
o(0x89); |
o(0xe8 + r); /* mov %ebp, r */ |
} |
} else if (v == VT_CMP) { |
oad(0xb8 + r, 0); /* mov $0, r */ |
o(0x0f); /* setxx %br */ |
288,19 → 250,13 |
} |
/* store register 'r' in lvalue 'v' */ |
ST_FUNC void store(int r, SValue *v) |
void store(int r, SValue *v) |
{ |
int fr, bt, ft, fc; |
#ifdef TCC_TARGET_PE |
SValue v2; |
v = pe_getimport(v, &v2); |
#endif |
ft = v->type.t; |
fc = v->c.i; |
fc = v->c.ul; |
fr = v->r & VT_VALMASK; |
ft &= ~(VT_VOLATILE | VT_CONSTANT); |
bt = ft & VT_BTYPE; |
/* XXX: incorrect if float reg to reg */ |
if (bt == VT_FLOAT) { |
340,15 → 296,6 |
} |
} |
static void gen_static_call(int v) |
{ |
Sym *sym; |
sym = external_global_sym(v, &func_old_type, 0); |
oad(0xe8, -4); |
greloc(cur_text_section, sym, ind-4, R_386_PC32); |
} |
/* 'is_jmp' is '1' if it is a jump */ |
static void gcall_or_jmp(int is_jmp) |
{ |
364,7 → 311,7 |
put_elf_reloc(symtab_section, cur_text_section, |
ind + 1, R_386_PC32, 0); |
} |
oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */ |
oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */ |
} else { |
/* otherwise, indirect call */ |
r = gv(RC_INT); |
374,39 → 321,11 |
} |
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX }; |
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX }; |
/* Return the number of registers needed to return the struct, or 0 if |
returning via struct pointer. */ |
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) |
{ |
#ifdef TCC_TARGET_PE |
int size, align; |
*ret_align = 1; // Never have to re-align return values for x86 |
*regsize = 4; |
size = type_size(vt, &align); |
if (size > 8) { |
return 0; |
} else if (size > 4) { |
ret->ref = NULL; |
ret->t = VT_LLONG; |
return 1; |
} else { |
ret->ref = NULL; |
ret->t = VT_INT; |
return 1; |
} |
#else |
*ret_align = 1; // Never have to re-align return values for x86 |
return 0; |
#endif |
} |
/* Generate function call. The function address is pushed first, then |
all the parameters in call order. This functions pops all the |
parameters and the function address. */ |
ST_FUNC void gfunc_call(int nb_args) |
void gfunc_call(int nb_args) |
{ |
int size, align, r, args_size, i, func_call; |
Sym *func_sym; |
460,34 → 379,21 |
} |
save_regs(0); /* save used temporary registers */ |
func_sym = vtop->type.ref; |
func_call = func_sym->a.func_call; |
func_call = func_sym->r; |
/* fast call case */ |
if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) || |
func_call == FUNC_FASTCALLW) { |
if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) { |
int fastcall_nb_regs; |
uint8_t *fastcall_regs_ptr; |
if (func_call == FUNC_FASTCALLW) { |
fastcall_regs_ptr = fastcallw_regs; |
fastcall_nb_regs = 2; |
} else { |
fastcall_regs_ptr = fastcall_regs; |
fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; |
} |
for(i = 0;i < fastcall_nb_regs; i++) { |
if (args_size <= 0) |
break; |
o(0x58 + fastcall_regs_ptr[i]); /* pop r */ |
o(0x58 + fastcall_regs[i]); /* pop r */ |
/* XXX: incorrect for struct/floats */ |
args_size -= 4; |
} |
} |
#ifndef TCC_TARGET_PE |
else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT) |
args_size -= 4; |
#endif |
gcall_or_jmp(0); |
if (args_size && func_call != FUNC_STDCALL) |
if (args_size && func_sym->r != FUNC_STDCALL) |
gadd_sp(args_size); |
vtop--; |
} |
499,29 → 405,21 |
#endif |
/* generate function prolog of type 't' */ |
ST_FUNC void gfunc_prolog(CType *func_type) |
void gfunc_prolog(CType *func_type) |
{ |
int addr, align, size, func_call, fastcall_nb_regs; |
int param_index, param_addr; |
uint8_t *fastcall_regs_ptr; |
Sym *sym; |
CType *type; |
sym = func_type->ref; |
func_call = sym->a.func_call; |
func_call = sym->r; |
addr = 8; |
loc = 0; |
func_vc = 0; |
if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) { |
fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; |
fastcall_regs_ptr = fastcall_regs; |
} else if (func_call == FUNC_FASTCALLW) { |
fastcall_nb_regs = 2; |
fastcall_regs_ptr = fastcallw_regs; |
} else { |
fastcall_nb_regs = 0; |
fastcall_regs_ptr = NULL; |
} |
param_index = 0; |
530,13 → 428,7 |
/* if the function returns a structure, then add an |
implicit pointer parameter */ |
func_vt = sym->type; |
func_var = (sym->c == FUNC_ELLIPSIS); |
#ifdef TCC_TARGET_PE |
size = type_size(&func_vt,&align); |
if (((func_vt.t & VT_BTYPE) == VT_STRUCT) && (size > 8)) { |
#else |
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
#endif |
/* XXX: fastcall case ? */ |
func_vc = addr; |
addr += 4; |
557,7 → 449,7 |
/* save FASTCALL register */ |
loc -= 4; |
o(0x89); /* movl */ |
gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc); |
gen_modrm(fastcall_regs[param_index], VT_LOCAL, NULL, loc); |
param_addr = loc; |
} else { |
param_addr = addr; |
564,7 → 456,7 |
addr += size; |
} |
sym_push(sym->v & ~SYM_FIELD, type, |
VT_LOCAL | lvalue_type(type->t), param_addr); |
VT_LOCAL | VT_LVAL, param_addr); |
param_index++; |
} |
func_ret_sub = 0; |
571,34 → 463,27 |
/* pascal type call ? */ |
if (func_call == FUNC_STDCALL) |
func_ret_sub = addr - 8; |
#ifndef TCC_TARGET_PE |
else if (func_vc) |
func_ret_sub = 4; |
#endif |
#ifdef CONFIG_TCC_BCHECK |
/* leave some room for bound checking code */ |
if (tcc_state->do_bounds_check) { |
if (do_bounds_check) { |
oad(0xb8, 0); /* lbound section pointer */ |
oad(0xb8, 0); /* call to function */ |
func_bound_offset = lbounds_section->data_offset; |
} |
#endif |
} |
/* generate function epilog */ |
ST_FUNC void gfunc_epilog(void) |
void gfunc_epilog(void) |
{ |
addr_t v, saved_ind; |
int v, saved_ind; |
#ifdef CONFIG_TCC_BCHECK |
if (tcc_state->do_bounds_check |
&& func_bound_offset != lbounds_section->data_offset) { |
addr_t saved_ind; |
addr_t *bounds_ptr; |
Sym *sym_data; |
if (do_bounds_check && func_bound_offset != lbounds_section->data_offset) { |
int saved_ind; |
int *bounds_ptr; |
Sym *sym, *sym_data; |
/* add end of table info */ |
bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); |
bounds_ptr = section_ptr_add(lbounds_section, sizeof(int)); |
*bounds_ptr = 0; |
/* generate bound local allocation */ |
saved_ind = ind; |
608,8 → 493,10 |
greloc(cur_text_section, sym_data, |
ind + 1, R_386_32); |
oad(0xb8, 0); /* mov %eax, xxx */ |
gen_static_call(TOK___bound_local_new); |
sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0); |
greloc(cur_text_section, sym, |
ind + 1, R_386_PC32); |
oad(0xe8, -4); |
ind = saved_ind; |
/* generate bound check local freeing */ |
o(0x5250); /* save returned value, if any */ |
616,8 → 503,10 |
greloc(cur_text_section, sym_data, |
ind + 1, R_386_32); |
oad(0xb8, 0); /* mov %eax, xxx */ |
gen_static_call(TOK___bound_local_delete); |
sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0); |
greloc(cur_text_section, sym, |
ind + 1, R_386_PC32); |
oad(0xe8, -4); |
o(0x585a); /* restore returned value, if any */ |
} |
#endif |
636,8 → 525,10 |
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; |
#ifdef TCC_TARGET_PE |
if (v >= 4096) { |
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); |
oad(0xb8, v); /* mov stacksize, %eax */ |
gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */ |
oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */ |
greloc(cur_text_section, sym, ind-4, R_386_PC32); |
} else |
#endif |
{ |
652,13 → 543,13 |
} |
/* generate a jump to a label */ |
ST_FUNC int gjmp(int t) |
int gjmp(int t) |
{ |
return psym(0xe9, t); |
} |
/* generate a jump to a fixed address */ |
ST_FUNC void gjmp_addr(int a) |
void gjmp_addr(int a) |
{ |
int r; |
r = a - ind - 2; |
671,9 → 562,11 |
} |
/* generate a test. set 'inv' to invert test. Stack entry is popped */ |
ST_FUNC int gtst(int inv, int t) |
int gtst(int inv, int t) |
{ |
int v = vtop->r & VT_VALMASK; |
int v, *p; |
v = vtop->r & VT_VALMASK; |
if (v == VT_CMP) { |
/* fast case : can jump directly since flags are set */ |
g(0x0f); |
682,24 → 575,38 |
/* && or || optimization */ |
if ((v & 1) == inv) { |
/* insert vtop->c jump list in t */ |
uint32_t n1, n = vtop->c.i; |
if (n) { |
while ((n1 = read32le(cur_text_section->data + n))) |
n = n1; |
write32le(cur_text_section->data + n, t); |
p = &vtop->c.i; |
while (*p != 0) |
p = (int *)(cur_text_section->data + *p); |
*p = t; |
t = vtop->c.i; |
} |
} else { |
t = gjmp(t); |
gsym(vtop->c.i); |
} |
} else { |
if (is_float(vtop->type.t)) { |
vpushi(0); |
gen_op(TOK_NE); |
} |
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
/* constant jmp optimization */ |
if ((vtop->c.i != 0) != inv) |
t = gjmp(t); |
} else { |
v = gv(RC_INT); |
o(0x85); |
o(0xc0 + v * 9); |
g(0x0f); |
t = psym(0x85 ^ inv, t); |
} |
} |
vtop--; |
return t; |
} |
/* generate an integer binary operation */ |
ST_FUNC void gen_opi(int op) |
void gen_opi(int op) |
{ |
int r, fr, opc, c; |
715,16 → 622,10 |
vswap(); |
c = vtop->c.i; |
if (c == (char)c) { |
/* generate inc and dec for smaller code */ |
if (c==1 && opc==0) { |
o (0x40 | r); // inc |
} else if (c==1 && opc==5) { |
o (0x48 | r); // dec |
} else { |
/* XXX: generate inc and dec for smaller code ? */ |
o(0x83); |
o(0xc0 | (opc << 3) | r); |
g(c); |
} |
} else { |
o(0x81); |
oad(0xc0 | (opc << 3) | r, c); |
839,7 → 740,7 |
/* generate a floating point operation 'v = t1 op t2' instruction. The |
two operands are guaranted to have the same floating point type */ |
/* XXX: need to use ST1 too */ |
ST_FUNC void gen_opf(int op) |
void gen_opf(int op) |
{ |
int a, ft, fc, swapped, r; |
876,10 → 777,7 |
swapped = 0; |
if (swapped) |
o(0xc9d9); /* fxch %st(1) */ |
if (op == TOK_EQ || op == TOK_NE) |
o(0xe9da); /* fucompp */ |
else |
o(0xd9de); /* fcompp */ |
o(0xe0df); /* fnstsw %ax */ |
if (op == TOK_EQ) { |
o(0x45e480); /* and $0x45, %ah */ |
925,7 → 823,7 |
break; |
} |
ft = vtop->type.t; |
fc = vtop->c.i; |
fc = vtop->c.ul; |
if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
o(0xde); /* fxxxp %st, %st(1) */ |
o(0xc1 + (a << 3)); |
937,7 → 835,7 |
r = get_reg(RC_INT); |
v1.type.t = VT_INT; |
v1.r = VT_LOCAL | VT_LVAL; |
v1.c.i = fc; |
v1.c.ul = fc; |
load(r, &v1); |
fc = 0; |
} |
954,7 → 852,7 |
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int' |
and 'long long' cases. */ |
ST_FUNC void gen_cvt_itof(int t) |
void gen_cvt_itof(int t) |
{ |
save_reg(TREG_ST0); |
gv(RC_INT); |
983,47 → 881,58 |
} |
/* convert fp to int 't' type */ |
ST_FUNC void gen_cvt_ftoi(int t) |
/* XXX: handle long long case */ |
void gen_cvt_ftoi(int t) |
{ |
#ifndef COMMIT_4ad186c5ef61_IS_FIXED |
/* a good version but it takes a more time to execute */ |
int r, r2, size; |
Sym *sym; |
CType ushort_type; |
ushort_type.t = VT_SHORT | VT_UNSIGNED; |
gv(RC_FLOAT); |
save_reg(TREG_EAX); |
save_reg(TREG_EDX); |
gen_static_call(TOK___tcc_cvt_ftol); |
vtop->r = TREG_EAX; /* mark reg as used */ |
if (t == VT_LLONG) |
vtop->r2 = TREG_EDX; |
#else |
/* a new version with a bug: t2a = 44100312 */ |
/* |
#include<stdio.h> |
int main() { |
int t1 = 176401255; |
float f = 0.25f; |
int t2a = (int)(t1 * f); // must be 44100313 |
int t2b = (int)(t1 * (float)0.25f); |
printf("t2a=%d t2b=%d \n",t2a,t2b); |
return 0; |
} |
*/ |
int bt = vtop->type.t & VT_BTYPE; |
if (bt == VT_FLOAT) |
vpush_global_sym(&func_old_type, TOK___fixsfdi); |
else if (bt == VT_LDOUBLE) |
vpush_global_sym(&func_old_type, TOK___fixxfdi); |
if (t != VT_INT) |
size = 8; |
else |
vpush_global_sym(&func_old_type, TOK___fixdfdi); |
vswap(); |
gfunc_call(1); |
vpushi(0); |
vtop->r = REG_IRET; |
vtop->r2 = REG_LRET; |
#endif |
size = 4; |
o(0x2dd9); /* ldcw xxx */ |
sym = external_global_sym(TOK___tcc_int_fpu_control, |
&ushort_type, VT_LVAL); |
greloc(cur_text_section, sym, |
ind, R_386_32); |
gen_le32(0); |
oad(0xec81, size); /* sub $xxx, %esp */ |
if (size == 4) |
o(0x1cdb); /* fistpl */ |
else |
o(0x3cdf); /* fistpll */ |
o(0x24); |
o(0x2dd9); /* ldcw xxx */ |
sym = external_global_sym(TOK___tcc_fpu_control, |
&ushort_type, VT_LVAL); |
greloc(cur_text_section, sym, |
ind, R_386_32); |
gen_le32(0); |
r = get_reg(RC_INT); |
o(0x58 + r); /* pop r */ |
if (size == 8) { |
if (t == VT_LLONG) { |
vtop->r = r; /* mark reg as used */ |
r2 = get_reg(RC_INT); |
o(0x58 + r2); /* pop r2 */ |
vtop->r2 = r2; |
} else { |
o(0x04c483); /* add $4, %esp */ |
} |
} |
vtop->r = r; |
} |
/* convert from one floating point type to another */ |
ST_FUNC void gen_cvt_ftof(int t) |
void gen_cvt_ftof(int t) |
{ |
/* all we have to do on i386 is to put the float in a register */ |
gv(RC_FLOAT); |
1030,7 → 939,7 |
} |
/* computed goto support */ |
ST_FUNC void ggoto(void) |
void ggoto(void) |
{ |
gcall_or_jmp(1); |
vtop--; |
1040,8 → 949,10 |
#ifdef CONFIG_TCC_BCHECK |
/* generate a bounded pointer addition */ |
ST_FUNC void gen_bounded_ptr_add(void) |
void gen_bounded_ptr_add(void) |
{ |
Sym *sym; |
/* prepare fast i386 function call (args in eax and edx) */ |
gv2(RC_EAX, RC_EDX); |
/* save all temporary registers */ |
1048,19 → 959,22 |
vtop -= 2; |
save_regs(0); |
/* do a fast function call */ |
gen_static_call(TOK___bound_ptr_add); |
sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0); |
greloc(cur_text_section, sym, |
ind + 1, R_386_PC32); |
oad(0xe8, -4); |
/* returned pointer is in eax */ |
vtop++; |
vtop->r = TREG_EAX | VT_BOUNDED; |
/* address of bounding function call point */ |
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel)); |
vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel)); |
} |
/* patch pointer addition in vtop so that pointer dereferencing is |
also tested */ |
ST_FUNC void gen_bounded_ptr_deref(void) |
void gen_bounded_ptr_deref(void) |
{ |
addr_t func; |
int func; |
int size, align; |
Elf32_Rel *rel; |
Sym *sym; |
1083,7 → 997,7 |
case 12: func = TOK___bound_ptr_indir12; break; |
case 16: func = TOK___bound_ptr_indir16; break; |
default: |
tcc_error("unhandled size when dereferencing bounded pointer"); |
error("unhandled size when derefencing bounded pointer"); |
func = 0; |
break; |
} |
1090,7 → 1004,7 |
/* patch relocation */ |
/* XXX: find a better solution ? */ |
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i); |
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul); |
sym = external_global_sym(func, &func_old_type, 0); |
if (!sym->c) |
put_extern_sym(sym, NULL, 0, 0); |
1098,40 → 1012,6 |
} |
#endif |
/* Save the stack pointer onto the stack */ |
ST_FUNC void gen_vla_sp_save(int addr) { |
/* mov %esp,addr(%ebp)*/ |
o(0x89); |
gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr); |
} |
/* Restore the SP from a location on the stack */ |
ST_FUNC void gen_vla_sp_restore(int addr) { |
o(0x8b); |
gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr); |
} |
/* Subtract from the stack pointer, and push the resulting value onto the stack */ |
ST_FUNC void gen_vla_alloc(CType *type, int align) { |
#ifdef TCC_TARGET_PE |
/* alloca does more than just adjust %rsp on Windows */ |
vpush_global_sym(&func_old_type, TOK_alloca); |
vswap(); /* Move alloca ref past allocation size */ |
gfunc_call(1); |
#else |
int r; |
r = gv(RC_INT); /* allocation size */ |
/* sub r,%rsp */ |
o(0x2b); |
o(0xe0 | r); |
/* We align to 16 bytes rather than align */ |
/* and ~15, %esp */ |
o(0xf0e483); |
vpop(); |
#endif |
} |
/* end of X86 code generator */ |
/*************************************************************/ |
#endif |
/*************************************************************/ |
/programs/develop/ktcc/trunk/source/il-gen.c |
---|
3,19 → 3,19 |
* |
* Copyright (c) 2002 Fabrice Bellard |
* |
* This library is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* version 2 of the License, or (at your option) any later version. |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. |
* |
* This library is distributed in the hope that it will be useful, |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* Lesser General Public License for more details. |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU Lesser General Public |
* License along with this library; if not, write to the Free Software |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
*/ |
/* number of available registers */ |
41,7 → 41,7 |
REG_ST2, |
}; |
const int reg_classes[NB_REGS] = { |
int reg_classes[NB_REGS] = { |
/* ST0 */ RC_ST | RC_ST0, |
/* ST1 */ RC_ST | RC_ST1, |
/* ST2 */ RC_ST, |
53,11 → 53,11 |
#define REG_FRET REG_ST0 /* float return register */ |
/* defined if function parameters must be evaluated in reverse order */ |
/* #define INVERT_FUNC_PARAMS */ |
//#define INVERT_FUNC_PARAMS |
/* defined if structures are passed as pointers. Otherwise structures |
are directly pushed on stack. */ |
/* #define FUNC_STRUCT_PARAM_AS_PTR */ |
//#define FUNC_STRUCT_PARAM_AS_PTR |
/* pointer size, in bytes */ |
#define PTR_SIZE 4 |
193,7 → 193,7 |
pstrcat(buf, buf_size, tstr); |
break; |
case VT_STRUCT: |
tcc_error("structures not handled yet"); |
error("structures not handled yet"); |
break; |
case VT_FUNC: |
s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); |
387,7 → 387,7 |
void gfunc_param(GFuncContext *c) |
{ |
if ((vtop->t & VT_BTYPE) == VT_STRUCT) { |
tcc_error("structures passed as value not handled yet"); |
error("structures passed as value not handled yet"); |
} else { |
/* simply push on stack */ |
gv(RC_ST0); |
441,7 → 441,6 |
/* if the function returns a structure, then add an |
implicit pointer parameter */ |
func_vt = sym->t; |
func_var = (sym->c == FUNC_ELLIPSIS); |
if ((func_vt & VT_BTYPE) == VT_STRUCT) { |
func_vc = addr; |
addr++; |
450,7 → 449,7 |
while ((sym = sym->next) != NULL) { |
u = sym->t; |
sym_push(sym->v & ~SYM_FIELD, u, |
VT_LOCAL | lvalue_type(sym->type.t), addr); |
VT_LOCAL | VT_LVAL, addr); |
addr++; |
} |
} |
529,7 → 528,20 |
t = gjmp(t); |
gsym(vtop->c.i); |
} |
} else { |
if (is_float(vtop->t)) { |
vpushi(0); |
gen_op(TOK_NE); |
} |
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) { |
/* constant jmp optimization */ |
if ((vtop->c.i != 0) != inv) |
t = gjmp(t); |
} else { |
v = gv(RC_INT); |
t = out_opj(IL_OP_BRTRUE - inv, t); |
} |
} |
vtop--; |
return t; |
} |
/programs/develop/ktcc/trunk/source/libtcc.h |
---|
1,10 → 1,6 |
#ifndef LIBTCC_H |
#define LIBTCC_H |
#ifndef LIBTCCAPI |
# define LIBTCCAPI |
#endif |
#ifdef __cplusplus |
extern "C" { |
#endif |
14,88 → 10,85 |
typedef struct TCCState TCCState; |
/* create a new TCC compilation context */ |
LIBTCCAPI TCCState *tcc_new(void); |
TCCState *tcc_new(void); |
/* free a TCC compilation context */ |
LIBTCCAPI void tcc_delete(TCCState *s); |
void tcc_delete(TCCState *s); |
/* set CONFIG_TCCDIR at runtime */ |
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path); |
/* add debug information in the generated code */ |
void tcc_enable_debug(TCCState *s); |
/* set error/warning display callback */ |
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, |
void tcc_set_error_func(TCCState *s, void *error_opaque, |
void (*error_func)(void *opaque, const char *msg)); |
/* set options as from command line (multiple supported) */ |
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str); |
/* set/reset a warning */ |
int tcc_set_warning(TCCState *s, const char *warning_name, int value); |
/*****************************/ |
/* preprocessor */ |
/* add include path */ |
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname); |
int tcc_add_include_path(TCCState *s, const char *pathname); |
/* add in system include path */ |
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname); |
int tcc_add_sysinclude_path(TCCState *s, const char *pathname); |
/* define preprocessor symbol 'sym'. Can put optional value */ |
LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value); |
void tcc_define_symbol(TCCState *s, const char *sym, const char *value); |
/* undefine preprocess symbol 'sym' */ |
LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym); |
void tcc_undefine_symbol(TCCState *s, const char *sym); |
/*****************************/ |
/* compiling */ |
/* add a file (C file, dll, object, library, ld script). Return -1 if error. */ |
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename, int filetype); |
#define TCC_FILETYPE_BINARY 1 |
#define TCC_FILETYPE_C 2 |
#define TCC_FILETYPE_ASM 3 |
#define TCC_FILETYPE_ASM_PP 4 |
/* add a file (either a C file, dll, an object, a library or an ld |
script). Return -1 if error. */ |
int tcc_add_file(TCCState *s, const char *filename); |
/* compile a string containing a C source. Return -1 if error. */ |
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); |
/* compile a string containing a C source. Return non zero if |
error. */ |
int tcc_compile_string(TCCState *s, const char *buf); |
/*****************************/ |
/* linking commands */ |
/* set output type. MUST BE CALLED before any compilation */ |
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); |
#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */ |
#define TCC_OUTPUT_EXE 2 /* executable file */ |
#define TCC_OUTPUT_DLL 3 /* dynamic library */ |
#define TCC_OUTPUT_OBJ 4 /* object file */ |
#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */ |
#define TCC_OUTPUT_MEMORY 0 /* output will be ran in memory (no |
output file) (default) */ |
#define TCC_OUTPUT_EXE 1 /* executable file */ |
#define TCC_OUTPUT_DLL 2 /* dynamic library */ |
#define TCC_OUTPUT_OBJ 3 /* object file */ |
int tcc_set_output_type(TCCState *s, int output_type); |
#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */ |
#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */ |
#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */ |
/* equivalent to -Lpath option */ |
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); |
int tcc_add_library_path(TCCState *s, const char *pathname); |
/* the library name is the same as the argument of the '-l' option */ |
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname); |
int tcc_add_library(TCCState *s, const char *libraryname); |
/* add a symbol to the compiled program */ |
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val); |
int tcc_add_symbol(TCCState *s, const char *name, unsigned long val); |
/* output an executable, library or object file. DO NOT call |
tcc_relocate() before. */ |
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename); |
int tcc_output_file(TCCState *s, const char *filename); |
/* link and run main() function and return its value. DO NOT call |
tcc_relocate() before. */ |
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv); |
int tcc_run(TCCState *s, int argc, char **argv); |
/* do all relocations (needed before using tcc_get_symbol()) */ |
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr); |
/* possible values for 'ptr': |
- TCC_RELOCATE_AUTO : Allocate and manage memory internally |
- NULL : return required memory size for the step below |
- memory address : copy code to memory passed by the caller |
returns -1 if error. */ |
#define TCC_RELOCATE_AUTO (void*)1 |
/* do all relocations (needed before using tcc_get_symbol()). Return |
non zero if link error. */ |
int tcc_relocate(TCCState *s); |
/* return symbol value or NULL if not found */ |
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name); |
/* return symbol value. return 0 if OK, -1 if symbol not found */ |
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name); |
#ifdef __cplusplus |
} |
/programs/develop/ktcc/trunk/source/libtcc_test.c |
---|
0,0 → 1,65 |
/* |
* Simple Test program for libtcc |
* |
* libtcc can be useful to use tcc as a "backend" for a code generator. |
*/ |
#include <stdlib.h> |
#include <stdio.h> |
#include "libtcc.h" |
/* this function is called by the generated code */ |
int add(int a, int b) |
{ |
return a + b; |
} |
char my_program[] = |
"int fib(int n)\n" |
"{\n" |
" if (n <= 2)\n" |
" return 1;\n" |
" else\n" |
" return fib(n-1) + fib(n-2);\n" |
"}\n" |
"\n" |
"int foo(int n)\n" |
"{\n" |
" printf(\"Hello World!\\n\");\n" |
" printf(\"fib(%d) = %d\\n\", n, fib(n));\n" |
" printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n" |
" return 0;\n" |
"}\n"; |
int main(int argc, char **argv) |
{ |
TCCState *s; |
int (*func)(int); |
unsigned long val; |
s = tcc_new(); |
if (!s) { |
fprintf(stderr, "Could not create tcc state\n"); |
exit(1); |
} |
/* MUST BE CALLED before any compilation or file loading */ |
tcc_set_output_type(s, TCC_OUTPUT_MEMORY); |
tcc_compile_string(s, my_program); |
/* as a test, we add a symbol that the compiled program can be |
linked with. You can have a similar result by opening a dll |
with tcc_add_dll(() and using its symbols directly. */ |
tcc_add_symbol(s, "add", (unsigned long)&add); |
tcc_relocate(s); |
tcc_get_symbol(s, &val, "foo"); |
func = (void *)val; |
func(32); |
tcc_delete(s); |
return 0; |
} |
/programs/develop/ktcc/trunk/source/stdarg.h |
---|
0,0 → 1,15 |
#ifndef _STDARG_H |
#define _STDARG_H |
typedef char *va_list; |
/* only correct for i386 */ |
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3) |
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3))) |
#define va_end(ap) |
/* fix a buggy dependency on GCC in libio.h */ |
typedef va_list __gnuc_va_list; |
#define _VA_LIST_DEFINED |
#endif |
/programs/develop/ktcc/trunk/source/stdbool.h |
---|
0,0 → 1,10 |
#ifndef _STDBOOL_H |
#define _STDBOOL_H |
/* ISOC99 boolean */ |
#define bool _Bool |
#define true 1 |
#define false 0 |
#endif /* _STDBOOL_H */ |
/programs/develop/ktcc/trunk/source/stddef.h |
---|
0,0 → 1,21 |
#ifndef _STDDEF_H |
#define _STDDEF_H |
#define NULL ((void *)0) |
typedef __SIZE_TYPE__ size_t; |
typedef __WCHAR_TYPE__ wchar_t; |
typedef __PTRDIFF_TYPE__ ptrdiff_t; |
#define offsetof(type, field) ((size_t) &((type *)0)->field) |
/* need to do that because of glibc 2.1 bug (should have a way to test |
presence of 'long long' without __GNUC__, or TCC should define |
__GNUC__ ? */ |
#if !defined(__int8_t_defined) && !defined(__dietlibc__) |
#define __int8_t_defined |
typedef char int8_t; |
typedef short int int16_t; |
typedef int int32_t; |
typedef long long int int64_t; |
#endif |
#endif |
/programs/develop/ktcc/trunk/source/tcc-doc.html |
---|
0,0 → 1,1809 |
<HTML> |
<HEAD> |
<!-- Created by texi2html 1.56k from tcc-doc.texi on 18 June 2005 --> |
<TITLE>Tiny C Compiler Reference Documentation</TITLE> |
</HEAD> |
<BODY> |
<H1>Tiny C Compiler Reference Documentation</H1> |
<P> |
<P><HR><P> |
<H1>Table of Contents</H1> |
<UL> |
<LI><A NAME="TOC1" HREF="tcc-doc.html#SEC1">1. Introduction</A> |
<LI><A NAME="TOC2" HREF="tcc-doc.html#SEC2">2. Command line invocation</A> |
<UL> |
<LI><A NAME="TOC3" HREF="tcc-doc.html#SEC3">2.1 Quick start</A> |
<LI><A NAME="TOC4" HREF="tcc-doc.html#SEC4">2.2 Option summary</A> |
</UL> |
<LI><A NAME="TOC5" HREF="tcc-doc.html#SEC5">3. C language support</A> |
<UL> |
<LI><A NAME="TOC6" HREF="tcc-doc.html#SEC6">3.1 ANSI C</A> |
<LI><A NAME="TOC7" HREF="tcc-doc.html#SEC7">3.2 ISOC99 extensions</A> |
<LI><A NAME="TOC8" HREF="tcc-doc.html#SEC8">3.3 GNU C extensions</A> |
<LI><A NAME="TOC9" HREF="tcc-doc.html#SEC9">3.4 TinyCC extensions</A> |
</UL> |
<LI><A NAME="TOC10" HREF="tcc-doc.html#SEC10">4. TinyCC Assembler</A> |
<UL> |
<LI><A NAME="TOC11" HREF="tcc-doc.html#SEC11">4.1 Syntax</A> |
<LI><A NAME="TOC12" HREF="tcc-doc.html#SEC12">4.2 Expressions</A> |
<LI><A NAME="TOC13" HREF="tcc-doc.html#SEC13">4.3 Labels</A> |
<LI><A NAME="TOC14" HREF="tcc-doc.html#SEC14">4.4 Directives</A> |
<LI><A NAME="TOC15" HREF="tcc-doc.html#SEC15">4.5 X86 Assembler</A> |
</UL> |
<LI><A NAME="TOC16" HREF="tcc-doc.html#SEC16">5. TinyCC Linker</A> |
<UL> |
<LI><A NAME="TOC17" HREF="tcc-doc.html#SEC17">5.1 ELF file generation</A> |
<LI><A NAME="TOC18" HREF="tcc-doc.html#SEC18">5.2 ELF file loader</A> |
<LI><A NAME="TOC19" HREF="tcc-doc.html#SEC19">5.3 PE-i386 file generation</A> |
<LI><A NAME="TOC20" HREF="tcc-doc.html#SEC20">5.4 GNU Linker Scripts</A> |
</UL> |
<LI><A NAME="TOC21" HREF="tcc-doc.html#SEC21">6. TinyCC Memory and Bound checks</A> |
<LI><A NAME="TOC22" HREF="tcc-doc.html#SEC22">7. The <CODE>libtcc</CODE> library</A> |
<LI><A NAME="TOC23" HREF="tcc-doc.html#SEC23">8. Developer's guide</A> |
<UL> |
<LI><A NAME="TOC24" HREF="tcc-doc.html#SEC24">8.1 File reading</A> |
<LI><A NAME="TOC25" HREF="tcc-doc.html#SEC25">8.2 Lexer</A> |
<LI><A NAME="TOC26" HREF="tcc-doc.html#SEC26">8.3 Parser</A> |
<LI><A NAME="TOC27" HREF="tcc-doc.html#SEC27">8.4 Types</A> |
<LI><A NAME="TOC28" HREF="tcc-doc.html#SEC28">8.5 Symbols</A> |
<LI><A NAME="TOC29" HREF="tcc-doc.html#SEC29">8.6 Sections</A> |
<LI><A NAME="TOC30" HREF="tcc-doc.html#SEC30">8.7 Code generation</A> |
<UL> |
<LI><A NAME="TOC31" HREF="tcc-doc.html#SEC31">8.7.1 Introduction</A> |
<LI><A NAME="TOC32" HREF="tcc-doc.html#SEC32">8.7.2 The value stack</A> |
<LI><A NAME="TOC33" HREF="tcc-doc.html#SEC33">8.7.3 Manipulating the value stack</A> |
<LI><A NAME="TOC34" HREF="tcc-doc.html#SEC34">8.7.4 CPU dependent code generation</A> |
</UL> |
<LI><A NAME="TOC35" HREF="tcc-doc.html#SEC35">8.8 Optimizations done</A> |
</UL> |
<LI><A NAME="TOC36" HREF="tcc-doc.html#SEC36">Concept Index</A> |
</UL> |
<P><HR><P> |
<H1><A NAME="SEC1" HREF="tcc-doc.html#TOC1">1. Introduction</A></H1> |
<P> |
TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C |
compilers, it is meant to be self-relying: you do not need an |
external assembler or linker because TCC does that for you. |
<P> |
TCC compiles so <EM>fast</EM> that even for big projects <CODE>Makefile</CODE>s may |
not be necessary. |
<P> |
TCC not only supports ANSI C, but also most of the new ISO C99 |
standard and many GNUC extensions including inline assembly. |
<P> |
TCC can also be used to make <EM>C scripts</EM>, i.e. pieces of C source |
that you run as a Perl or Python script. Compilation is so fast that |
your script will be as fast as if it was an executable. |
<P> |
TCC can also automatically generate memory and bound checks |
(see section <A HREF="tcc-doc.html#SEC21">6. TinyCC Memory and Bound checks</A>) while allowing all C pointers operations. TCC can do |
these checks even if non patched libraries are used. |
<P> |
With <CODE>libtcc</CODE>, you can use TCC as a backend for dynamic code |
generation (see section <A HREF="tcc-doc.html#SEC22">7. The <CODE>libtcc</CODE> library</A>). |
<P> |
TCC mainly supports the i386 target on Linux and Windows. There are alpha |
ports for the ARM (<CODE>arm-tcc</CODE>) and the TMS320C67xx targets |
(<CODE>c67-tcc</CODE>). More information about the ARM port is available at |
<A HREF="http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html">http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html</A>. |
<H1><A NAME="SEC2" HREF="tcc-doc.html#TOC2">2. Command line invocation</A></H1> |
<P> |
[This manual documents version 0.9.23 of the Tiny C Compiler] |
<H2><A NAME="SEC3" HREF="tcc-doc.html#TOC3">2.1 Quick start</A></H2> |
<PRE> |
usage: tcc [options] [<VAR>infile1</VAR> <VAR>infile2</VAR>...] [<SAMP>`-run'</SAMP> <VAR>infile</VAR> <VAR>args</VAR>...] |
</PRE> |
<P> |
TCC options are a very much like gcc options. The main difference is that TCC |
can also execute directly the resulting program and give it runtime |
arguments. |
<P> |
Here are some examples to understand the logic: |
<DL COMPACT> |
<DT><CODE><SAMP>`tcc -run a.c'</SAMP></CODE> |
<DD> |
Compile <TT>`a.c'</TT> and execute it directly |
<DT><CODE><SAMP>`tcc -run a.c arg1'</SAMP></CODE> |
<DD> |
Compile a.c and execute it directly. arg1 is given as first argument to |
the <CODE>main()</CODE> of a.c. |
<DT><CODE><SAMP>`tcc a.c -run b.c arg1'</SAMP></CODE> |
<DD> |
Compile <TT>`a.c'</TT> and <TT>`b.c'</TT>, link them together and execute them. arg1 is given |
as first argument to the <CODE>main()</CODE> of the resulting program. Because |
multiple C files are specified, <SAMP>`--'</SAMP> are necessary to clearly separate the |
program arguments from the TCC options. |
<DT><CODE><SAMP>`tcc -o myprog a.c b.c'</SAMP></CODE> |
<DD> |
Compile <TT>`a.c'</TT> and <TT>`b.c'</TT>, link them and generate the executable <TT>`myprog'</TT>. |
<DT><CODE><SAMP>`tcc -o myprog a.o b.o'</SAMP></CODE> |
<DD> |
link <TT>`a.o'</TT> and <TT>`b.o'</TT> together and generate the executable <TT>`myprog'</TT>. |
<DT><CODE><SAMP>`tcc -c a.c'</SAMP></CODE> |
<DD> |
Compile <TT>`a.c'</TT> and generate object file <TT>`a.o'</TT>. |
<DT><CODE><SAMP>`tcc -c asmfile.S'</SAMP></CODE> |
<DD> |
Preprocess with C preprocess and assemble <TT>`asmfile.S'</TT> and generate |
object file <TT>`asmfile.o'</TT>. |
<DT><CODE><SAMP>`tcc -c asmfile.s'</SAMP></CODE> |
<DD> |
Assemble (but not preprocess) <TT>`asmfile.s'</TT> and generate object file |
<TT>`asmfile.o'</TT>. |
<DT><CODE><SAMP>`tcc -r -o ab.o a.c b.c'</SAMP></CODE> |
<DD> |
Compile <TT>`a.c'</TT> and <TT>`b.c'</TT>, link them together and generate the object file <TT>`ab.o'</TT>. |
</DL> |
<P> |
Scripting: |
<P> |
TCC can be invoked from <EM>scripts</EM>, just as shell scripts. You just |
need to add <CODE>#!/usr/local/bin/tcc -run</CODE> at the start of your C source: |
<PRE> |
#!/usr/local/bin/tcc -run |
#include <stdio.h> |
int main() |
{ |
printf("Hello World\n"); |
return 0; |
} |
</PRE> |
<H2><A NAME="SEC4" HREF="tcc-doc.html#TOC4">2.2 Option summary</A></H2> |
<P> |
General Options: |
<DL COMPACT> |
<DT><SAMP>`-v'</SAMP> |
<DD> |
Display current TCC version. |
<DT><SAMP>`-c'</SAMP> |
<DD> |
Generate an object file (<SAMP>`-o'</SAMP> option must also be given). |
<DT><SAMP>`-o outfile'</SAMP> |
<DD> |
Put object file, executable, or dll into output file <TT>`outfile'</TT>. |
<DT><SAMP>`-Bdir'</SAMP> |
<DD> |
Set the path where the tcc internal libraries can be found (default is |
<TT>`PREFIX/lib/tcc'</TT>). |
<DT><SAMP>`-bench'</SAMP> |
<DD> |
Output compilation statistics. |
<DT><SAMP>`-run source [args...]'</SAMP> |
<DD> |
Compile file <VAR>source</VAR> and run it with the command line arguments |
<VAR>args</VAR>. In order to be able to give more than one argument to a |
script, several TCC options can be given <EM>after</EM> the |
<SAMP>`-run'</SAMP> option, separated by spaces. Example: |
<PRE> |
tcc "-run -L/usr/X11R6/lib -lX11" ex4.c |
</PRE> |
In a script, it gives the following header: |
<PRE> |
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11 |
#include <stdlib.h> |
int main(int argc, char **argv) |
{ |
... |
} |
</PRE> |
</DL> |
<P> |
Preprocessor options: |
<DL COMPACT> |
<DT><SAMP>`-Idir'</SAMP> |
<DD> |
Specify an additional include path. Include paths are searched in the |
order they are specified. |
System include paths are always searched after. The default system |
include paths are: <TT>`/usr/local/include'</TT>, <TT>`/usr/include'</TT> |
and <TT>`PREFIX/lib/tcc/include'</TT>. (<TT>`PREFIX'</TT> is usually |
<TT>`/usr'</TT> or <TT>`/usr/local'</TT>). |
<DT><SAMP>`-Dsym[=val]'</SAMP> |
<DD> |
Define preprocessor symbol <SAMP>`sym'</SAMP> to |
val. If val is not present, its value is <SAMP>`1'</SAMP>. Function-like macros can |
also be defined: <SAMP>`-DF(a)=a+1'</SAMP> |
<DT><SAMP>`-Usym'</SAMP> |
<DD> |
Undefine preprocessor symbol <SAMP>`sym'</SAMP>. |
</DL> |
<P> |
Compilation flags: |
<P> |
Note: each of the following warning options has a negative form beginning with |
<SAMP>`-fno-'</SAMP>. |
<DL COMPACT> |
<DT><SAMP>`-funsigned-char'</SAMP> |
<DD> |
Let the <CODE>char</CODE> type be unsigned. |
<DT><SAMP>`-fsigned-char'</SAMP> |
<DD> |
Let the <CODE>char</CODE> type be signed. |
<DT><SAMP>`-fno-common'</SAMP> |
<DD> |
Do not generate common symbols for uninitialized data. |
<DT><SAMP>`-fleading-underscore'</SAMP> |
<DD> |
Add a leading underscore at the beginning of each C symbol. |
</DL> |
<P> |
Warning options: |
<DL COMPACT> |
<DT><SAMP>`-w'</SAMP> |
<DD> |
Disable all warnings. |
</DL> |
<P> |
Note: each of the following warning options has a negative form beginning with |
<SAMP>`-Wno-'</SAMP>. |
<DL COMPACT> |
<DT><SAMP>`-Wimplicit-function-declaration'</SAMP> |
<DD> |
Warn about implicit function declaration. |
<DT><SAMP>`-Wunsupported'</SAMP> |
<DD> |
Warn about unsupported GCC features that are ignored by TCC. |
<DT><SAMP>`-Wwrite-strings'</SAMP> |
<DD> |
Make string constants be of type <CODE>const char *</CODE> instead of <CODE>char |
*</CODE>. |
<DT><SAMP>`-Werror'</SAMP> |
<DD> |
Abort compilation if warnings are issued. |
<DT><SAMP>`-Wall'</SAMP> |
<DD> |
Activate all warnings, except <SAMP>`-Werror'</SAMP>, <SAMP>`-Wunusupported'</SAMP> and |
<SAMP>`-Wwrite-strings'</SAMP>. |
</DL> |
<P> |
Linker options: |
<DL COMPACT> |
<DT><SAMP>`-Ldir'</SAMP> |
<DD> |
Specify an additional static library path for the <SAMP>`-l'</SAMP> option. The |
default library paths are <TT>`/usr/local/lib'</TT>, <TT>`/usr/lib'</TT> and <TT>`/lib'</TT>. |
<DT><SAMP>`-lxxx'</SAMP> |
<DD> |
Link your program with dynamic library libxxx.so or static library |
libxxx.a. The library is searched in the paths specified by the |
<SAMP>`-L'</SAMP> option. |
<DT><SAMP>`-shared'</SAMP> |
<DD> |
Generate a shared library instead of an executable (<SAMP>`-o'</SAMP> option |
must also be given). |
<DT><SAMP>`-static'</SAMP> |
<DD> |
Generate a statically linked executable (default is a shared linked |
executable) (<SAMP>`-o'</SAMP> option must also be given). |
<DT><SAMP>`-rdynamic'</SAMP> |
<DD> |
Export global symbols to the dynamic linker. It is useful when a library |
opened with <CODE>dlopen()</CODE> needs to access executable symbols. |
<DT><SAMP>`-r'</SAMP> |
<DD> |
Generate an object file combining all input files (<SAMP>`-o'</SAMP> option must |
also be given). |
<DT><SAMP>`-Wl,-Ttext,address'</SAMP> |
<DD> |
Set the start of the .text section to <VAR>address</VAR>. |
<DT><SAMP>`-Wl,--oformat,fmt'</SAMP> |
<DD> |
Use <VAR>fmt</VAR> as output format. The supported output formats are: |
<DL COMPACT> |
<DT><CODE>elf32-i386</CODE> |
<DD> |
ELF output format (default) |
<DT><CODE>binary</CODE> |
<DD> |
Binary image (only for executable output) |
<DT><CODE>coff</CODE> |
<DD> |
COFF output format (only for executable output for TMS320C67xx target) |
</DL> |
</DL> |
<P> |
Debugger options: |
<DL COMPACT> |
<DT><SAMP>`-g'</SAMP> |
<DD> |
Generate run time debug information so that you get clear run time |
error messages: <CODE> test.c:68: in function 'test5()': dereferencing |
invalid pointer</CODE> instead of the laconic <CODE>Segmentation |
fault</CODE>. |
<DT><SAMP>`-b'</SAMP> |
<DD> |
Generate additional support code to check |
memory allocations and array/pointer bounds. <SAMP>`-g'</SAMP> is implied. Note |
that the generated code is slower and bigger in this case. |
<DT><SAMP>`-bt N'</SAMP> |
<DD> |
Display N callers in stack traces. This is useful with <SAMP>`-g'</SAMP> or |
<SAMP>`-b'</SAMP>. |
</DL> |
<P> |
Note: GCC options <SAMP>`-Ox'</SAMP>, <SAMP>`-fx'</SAMP> and <SAMP>`-mx'</SAMP> are |
ignored. |
<H1><A NAME="SEC5" HREF="tcc-doc.html#TOC5">3. C language support</A></H1> |
<H2><A NAME="SEC6" HREF="tcc-doc.html#TOC6">3.1 ANSI C</A></H2> |
<P> |
TCC implements all the ANSI C standard, including structure bit fields |
and floating point numbers (<CODE>long double</CODE>, <CODE>double</CODE>, and |
<CODE>float</CODE> fully supported). |
<H2><A NAME="SEC7" HREF="tcc-doc.html#TOC7">3.2 ISOC99 extensions</A></H2> |
<P> |
TCC implements many features of the new C standard: ISO C99. Currently |
missing items are: complex and imaginary numbers and variable length |
arrays. |
<P> |
Currently implemented ISOC99 features: |
<UL> |
<LI>64 bit <CODE>long long</CODE> types are fully supported. |
<LI>The boolean type <CODE>_Bool</CODE> is supported. |
<LI><CODE>__func__</CODE> is a string variable containing the current |
function name. |
<LI>Variadic macros: <CODE>__VA_ARGS__</CODE> can be used for |
function-like macros: |
<PRE> |
#define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__) |
</PRE> |
<CODE>dprintf</CODE> can then be used with a variable number of parameters. |
<LI>Declarations can appear anywhere in a block (as in C++). |
<LI>Array and struct/union elements can be initialized in any order by |
using designators: |
<PRE> |
struct { int x, y; } st[10] = { [0].x = 1, [0].y = 2 }; |
int tab[10] = { 1, 2, [5] = 5, [9] = 9}; |
</PRE> |
<LI>Compound initializers are supported: |
<PRE> |
int *p = (int []){ 1, 2, 3 }; |
</PRE> |
to initialize a pointer pointing to an initialized array. The same |
works for structures and strings. |
<LI>Hexadecimal floating point constants are supported: |
<PRE> |
double d = 0x1234p10; |
</PRE> |
is the same as writing |
<PRE> |
double d = 4771840.0; |
</PRE> |
<LI><CODE>inline</CODE> keyword is ignored. |
<LI><CODE>restrict</CODE> keyword is ignored. |
</UL> |
<H2><A NAME="SEC8" HREF="tcc-doc.html#TOC8">3.3 GNU C extensions</A></H2> |
<P> |
<A NAME="IDX1"></A> |
<A NAME="IDX2"></A> |
<A NAME="IDX3"></A> |
<A NAME="IDX4"></A> |
<A NAME="IDX5"></A> |
<A NAME="IDX6"></A> |
<A NAME="IDX7"></A> |
<P> |
TCC implements some GNU C extensions: |
<UL> |
<LI>array designators can be used without '=': |
<PRE> |
int a[10] = { [0] 1, [5] 2, 3, 4 }; |
</PRE> |
<LI>Structure field designators can be a label: |
<PRE> |
struct { int x, y; } st = { x: 1, y: 1}; |
</PRE> |
instead of |
<PRE> |
struct { int x, y; } st = { .x = 1, .y = 1}; |
</PRE> |
<LI><CODE>\e</CODE> is ASCII character 27. |
<LI>case ranges : ranges can be used in <CODE>case</CODE>s: |
<PRE> |
switch(a) { |
case 1 ... 9: |
printf("range 1 to 9\n"); |
break; |
default: |
printf("unexpected\n"); |
break; |
} |
</PRE> |
<LI>The keyword <CODE>__attribute__</CODE> is handled to specify variable or |
function attributes. The following attributes are supported: |
<UL> |
<LI><CODE>aligned(n)</CODE>: align a variable or a structure field to n bytes |
(must be a power of two). |
<LI><CODE>packed</CODE>: force alignment of a variable or a structure field to |
1. |
<LI><CODE>section(name)</CODE>: generate function or data in assembly section |
name (name is a string containing the section name) instead of the default |
section. |
<LI><CODE>unused</CODE>: specify that the variable or the function is unused. |
<LI><CODE>cdecl</CODE>: use standard C calling convention (default). |
<LI><CODE>stdcall</CODE>: use Pascal-like calling convention. |
<LI><CODE>regparm(n)</CODE>: use fast i386 calling convention. <VAR>n</VAR> must be |
between 1 and 3. The first <VAR>n</VAR> function parameters are respectively put in |
registers <CODE>%eax</CODE>, <CODE>%edx</CODE> and <CODE>%ecx</CODE>. |
</UL> |
Here are some examples: |
<PRE> |
int a __attribute__ ((aligned(8), section(".mysection"))); |
</PRE> |
align variable <CODE>a</CODE> to 8 bytes and put it in section <CODE>.mysection</CODE>. |
<PRE> |
int my_add(int a, int b) __attribute__ ((section(".mycodesection"))) |
{ |
return a + b; |
} |
</PRE> |
generate function <CODE>my_add</CODE> in section <CODE>.mycodesection</CODE>. |
<LI>GNU style variadic macros: |
<PRE> |
#define dprintf(fmt, args...) printf(fmt, ## args) |
dprintf("no arg\n"); |
dprintf("one arg %d\n", 1); |
</PRE> |
<LI><CODE>__FUNCTION__</CODE> is interpreted as C99 <CODE>__func__</CODE> |
(so it has not exactly the same semantics as string literal GNUC |
where it is a string literal). |
<LI>The <CODE>__alignof__</CODE> keyword can be used as <CODE>sizeof</CODE> |
to get the alignment of a type or an expression. |
<LI>The <CODE>typeof(x)</CODE> returns the type of <CODE>x</CODE>. |
<CODE>x</CODE> is an expression or a type. |
<LI>Computed gotos: <CODE>&&label</CODE> returns a pointer of type |
<CODE>void *</CODE> on the goto label <CODE>label</CODE>. <CODE>goto *expr</CODE> can be |
used to jump on the pointer resulting from <CODE>expr</CODE>. |
<LI>Inline assembly with asm instruction: |
<A NAME="IDX8"></A> |
<A NAME="IDX9"></A> |
<A NAME="IDX10"></A> |
<PRE> |
static inline void * my_memcpy(void * to, const void * from, size_t n) |
{ |
int d0, d1, d2; |
__asm__ __volatile__( |
"rep ; movsl\n\t" |
"testb $2,%b4\n\t" |
"je 1f\n\t" |
"movsw\n" |
"1:\ttestb $1,%b4\n\t" |
"je 2f\n\t" |
"movsb\n" |
"2:" |
: "=&c" (d0), "=&D" (d1), "=&S" (d2) |
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) |
: "memory"); |
return (to); |
} |
</PRE> |
<A NAME="IDX11"></A> |
TCC includes its own x86 inline assembler with a <CODE>gas</CODE>-like (GNU |
assembler) syntax. No intermediate files are generated. GCC 3.x named |
operands are supported. |
<LI><CODE>__builtin_types_compatible_p()</CODE> and <CODE>__builtin_constant_p()</CODE> |
are supported. |
<LI><CODE>#pragma pack</CODE> is supported for win32 compatibility. |
</UL> |
<H2><A NAME="SEC9" HREF="tcc-doc.html#TOC9">3.4 TinyCC extensions</A></H2> |
<UL> |
<LI><CODE>__TINYC__</CODE> is a predefined macro to <CODE>1</CODE> to |
indicate that you use TCC. |
<LI><CODE>#!</CODE> at the start of a line is ignored to allow scripting. |
<LI>Binary digits can be entered (<CODE>0b101</CODE> instead of |
<CODE>5</CODE>). |
<LI><CODE>__BOUNDS_CHECKING_ON</CODE> is defined if bound checking is activated. |
</UL> |
<H1><A NAME="SEC10" HREF="tcc-doc.html#TOC10">4. TinyCC Assembler</A></H1> |
<P> |
Since version 0.9.16, TinyCC integrates its own assembler. TinyCC |
assembler supports a gas-like syntax (GNU assembler). You can |
desactivate assembler support if you want a smaller TinyCC executable |
(the C compiler does not rely on the assembler). |
<P> |
TinyCC Assembler is used to handle files with <TT>`.S'</TT> (C |
preprocessed assembler) and <TT>`.s'</TT> extensions. It is also used to |
handle the GNU inline assembler with the <CODE>asm</CODE> keyword. |
<H2><A NAME="SEC11" HREF="tcc-doc.html#TOC11">4.1 Syntax</A></H2> |
<P> |
TinyCC Assembler supports most of the gas syntax. The tokens are the |
same as C. |
<UL> |
<LI>C and C++ comments are supported. |
<LI>Identifiers are the same as C, so you cannot use '.' or '$'. |
<LI>Only 32 bit integer numbers are supported. |
</UL> |
<H2><A NAME="SEC12" HREF="tcc-doc.html#TOC12">4.2 Expressions</A></H2> |
<UL> |
<LI>Integers in decimal, octal and hexa are supported. |
<LI>Unary operators: +, -, ~. |
<LI>Binary operators in decreasing priority order: |
<OL> |
<LI>*, /, % |
<LI>&, |, ^ |
<LI>+, - |
</OL> |
<LI>A value is either an absolute number or a label plus an offset. |
All operators accept absolute values except '+' and '-'. '+' or '-' can be |
used to add an offset to a label. '-' supports two labels only if they |
are the same or if they are both defined and in the same section. |
</UL> |
<H2><A NAME="SEC13" HREF="tcc-doc.html#TOC13">4.3 Labels</A></H2> |
<UL> |
<LI>All labels are considered as local, except undefined ones. |
<LI>Numeric labels can be used as local <CODE>gas</CODE>-like labels. |
They can be defined several times in the same source. Use 'b' |
(backward) or 'f' (forward) as suffix to reference them: |
<PRE> |
1: |
jmp 1b /* jump to '1' label before */ |
jmp 1f /* jump to '1' label after */ |
1: |
</PRE> |
</UL> |
<H2><A NAME="SEC14" HREF="tcc-doc.html#TOC14">4.4 Directives</A></H2> |
<P> |
<A NAME="IDX12"></A> |
<A NAME="IDX13"></A> |
<A NAME="IDX14"></A> |
<A NAME="IDX15"></A> |
<A NAME="IDX16"></A> |
<A NAME="IDX17"></A> |
<A NAME="IDX18"></A> |
<A NAME="IDX19"></A> |
<A NAME="IDX20"></A> |
<A NAME="IDX21"></A> |
<A NAME="IDX22"></A> |
<A NAME="IDX23"></A> |
<A NAME="IDX24"></A> |
<A NAME="IDX25"></A> |
<A NAME="IDX26"></A> |
<A NAME="IDX27"></A> |
<A NAME="IDX28"></A> |
<A NAME="IDX29"></A> |
<A NAME="IDX30"></A> |
<A NAME="IDX31"></A> |
<A NAME="IDX32"></A> |
<A NAME="IDX33"></A> |
<A NAME="IDX34"></A> |
<P> |
All directives are preceeded by a '.'. The following directives are |
supported: |
<UL> |
<LI>.align n[,value] |
<LI>.skip n[,value] |
<LI>.space n[,value] |
<LI>.byte value1[,...] |
<LI>.word value1[,...] |
<LI>.short value1[,...] |
<LI>.int value1[,...] |
<LI>.long value1[,...] |
<LI>.quad immediate_value1[,...] |
<LI>.globl symbol |
<LI>.global symbol |
<LI>.section section |
<LI>.text |
<LI>.data |
<LI>.bss |
<LI>.fill repeat[,size[,value]] |
<LI>.org n |
<LI>.previous |
<LI>.string string[,...] |
<LI>.asciz string[,...] |
<LI>.ascii string[,...] |
</UL> |
<H2><A NAME="SEC15" HREF="tcc-doc.html#TOC15">4.5 X86 Assembler</A></H2> |
<P> |
<A NAME="IDX35"></A> |
<P> |
All X86 opcodes are supported. Only ATT syntax is supported (source |
then destination operand order). If no size suffix is given, TinyCC |
tries to guess it from the operand sizes. |
<P> |
Currently, MMX opcodes are supported but not SSE ones. |
<H1><A NAME="SEC16" HREF="tcc-doc.html#TOC16">5. TinyCC Linker</A></H1> |
<P> |
<A NAME="IDX36"></A> |
<H2><A NAME="SEC17" HREF="tcc-doc.html#TOC17">5.1 ELF file generation</A></H2> |
<P> |
<A NAME="IDX37"></A> |
<P> |
TCC can directly output relocatable ELF files (object files), |
executable ELF files and dynamic ELF libraries without relying on an |
external linker. |
<P> |
Dynamic ELF libraries can be output but the C compiler does not generate |
position independent code (PIC). It means that the dynamic library |
code generated by TCC cannot be factorized among processes yet. |
<P> |
TCC linker eliminates unreferenced object code in libraries. A single pass is |
done on the object and library list, so the order in which object files and |
libraries are specified is important (same constraint as GNU ld). No grouping |
options (<SAMP>`--start-group'</SAMP> and <SAMP>`--end-group'</SAMP>) are supported. |
<H2><A NAME="SEC18" HREF="tcc-doc.html#TOC18">5.2 ELF file loader</A></H2> |
<P> |
TCC can load ELF object files, archives (.a files) and dynamic |
libraries (.so). |
<H2><A NAME="SEC19" HREF="tcc-doc.html#TOC19">5.3 PE-i386 file generation</A></H2> |
<P> |
<A NAME="IDX38"></A> |
<P> |
TCC for Windows supports the native Win32 executable file format (PE-i386). It |
generates both EXE and DLL files. DLL symbols can be imported thru DEF files |
generated with the <CODE>tiny_impdef</CODE> tool. |
<P> |
Currently TCC for Windows cannot generate nor read PE object files, so ELF |
object files are used for that purpose. It can be a problem if |
interoperability with MSVC is needed. Moreover, no leading underscore is |
currently generated in the ELF symbols. |
<H2><A NAME="SEC20" HREF="tcc-doc.html#TOC20">5.4 GNU Linker Scripts</A></H2> |
<P> |
<A NAME="IDX39"></A> |
<A NAME="IDX40"></A> |
<A NAME="IDX41"></A> |
<A NAME="IDX42"></A> |
<A NAME="IDX43"></A> |
<A NAME="IDX44"></A> |
<P> |
Because on many Linux systems some dynamic libraries (such as |
<TT>`/usr/lib/libc.so'</TT>) are in fact GNU ld link scripts (horrible!), |
the TCC linker also supports a subset of GNU ld scripts. |
<P> |
The <CODE>GROUP</CODE> and <CODE>FILE</CODE> commands are supported. <CODE>OUTPUT_FORMAT</CODE> |
and <CODE>TARGET</CODE> are ignored. |
<P> |
Example from <TT>`/usr/lib/libc.so'</TT>: |
<PRE> |
/* GNU ld script |
Use the shared library, but some functions are only in |
the static library, so try that secondarily. */ |
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a ) |
</PRE> |
<H1><A NAME="SEC21" HREF="tcc-doc.html#TOC21">6. TinyCC Memory and Bound checks</A></H1> |
<P> |
<A NAME="IDX45"></A> |
<A NAME="IDX46"></A> |
<P> |
This feature is activated with the <SAMP>`-b'</SAMP> (see section <A HREF="tcc-doc.html#SEC2">2. Command line invocation</A>). |
<P> |
Note that pointer size is <EM>unchanged</EM> and that code generated |
with bound checks is <EM>fully compatible</EM> with unchecked |
code. When a pointer comes from unchecked code, it is assumed to be |
valid. Even very obscure C code with casts should work correctly. |
<P> |
For more information about the ideas behind this method, see |
<A HREF="http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html">http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html</A>. |
<P> |
Here are some examples of caught errors: |
<DL COMPACT> |
<DT>Invalid range with standard string function: |
<DD> |
<PRE> |
{ |
char tab[10]; |
memset(tab, 0, 11); |
} |
</PRE> |
<DT>Out of bounds-error in global or local arrays: |
<DD> |
<PRE> |
{ |
int tab[10]; |
for(i=0;i<11;i++) { |
sum += tab[i]; |
} |
} |
</PRE> |
<DT>Out of bounds-error in malloc'ed data: |
<DD> |
<PRE> |
{ |
int *tab; |
tab = malloc(20 * sizeof(int)); |
for(i=0;i<21;i++) { |
sum += tab4[i]; |
} |
free(tab); |
} |
</PRE> |
<DT>Access of freed memory: |
<DD> |
<PRE> |
{ |
int *tab; |
tab = malloc(20 * sizeof(int)); |
free(tab); |
for(i=0;i<20;i++) { |
sum += tab4[i]; |
} |
} |
</PRE> |
<DT>Double free: |
<DD> |
<PRE> |
{ |
int *tab; |
tab = malloc(20 * sizeof(int)); |
free(tab); |
free(tab); |
} |
</PRE> |
</DL> |
<H1><A NAME="SEC22" HREF="tcc-doc.html#TOC22">7. The <CODE>libtcc</CODE> library</A></H1> |
<P> |
The <CODE>libtcc</CODE> library enables you to use TCC as a backend for |
dynamic code generation. |
<P> |
Read the <TT>`libtcc.h'</TT> to have an overview of the API. Read |
<TT>`libtcc_test.c'</TT> to have a very simple example. |
<P> |
The idea consists in giving a C string containing the program you want |
to compile directly to <CODE>libtcc</CODE>. Then you can access to any global |
symbol (function or variable) defined. |
<H1><A NAME="SEC23" HREF="tcc-doc.html#TOC23">8. Developer's guide</A></H1> |
<P> |
This chapter gives some hints to understand how TCC works. You can skip |
it if you do not intend to modify the TCC code. |
<H2><A NAME="SEC24" HREF="tcc-doc.html#TOC24">8.1 File reading</A></H2> |
<P> |
The <CODE>BufferedFile</CODE> structure contains the context needed to read a |
file, including the current line number. <CODE>tcc_open()</CODE> opens a new |
file and <CODE>tcc_close()</CODE> closes it. <CODE>inp()</CODE> returns the next |
character. |
<H2><A NAME="SEC25" HREF="tcc-doc.html#TOC25">8.2 Lexer</A></H2> |
<P> |
<CODE>next()</CODE> reads the next token in the current |
file. <CODE>next_nomacro()</CODE> reads the next token without macro |
expansion. |
<P> |
<CODE>tok</CODE> contains the current token (see <CODE>TOK_xxx</CODE>) |
constants. Identifiers and keywords are also keywords. <CODE>tokc</CODE> |
contains additional infos about the token (for example a constant value |
if number or string token). |
<H2><A NAME="SEC26" HREF="tcc-doc.html#TOC26">8.3 Parser</A></H2> |
<P> |
The parser is hardcoded (yacc is not necessary). It does only one pass, |
except: |
<UL> |
<LI>For initialized arrays with unknown size, a first pass |
is done to count the number of elements. |
<LI>For architectures where arguments are evaluated in |
reverse order, a first pass is done to reverse the argument order. |
</UL> |
<H2><A NAME="SEC27" HREF="tcc-doc.html#TOC27">8.4 Types</A></H2> |
<P> |
The types are stored in a single 'int' variable. It was choosen in the |
first stages of development when tcc was much simpler. Now, it may not |
be the best solution. |
<PRE> |
#define VT_INT 0 /* integer type */ |
#define VT_BYTE 1 /* signed byte type */ |
#define VT_SHORT 2 /* short type */ |
#define VT_VOID 3 /* void type */ |
#define VT_PTR 4 /* pointer */ |
#define VT_ENUM 5 /* enum definition */ |
#define VT_FUNC 6 /* function type */ |
#define VT_STRUCT 7 /* struct/union definition */ |
#define VT_FLOAT 8 /* IEEE float */ |
#define VT_DOUBLE 9 /* IEEE double */ |
#define VT_LDOUBLE 10 /* IEEE long double */ |
#define VT_BOOL 11 /* ISOC99 boolean type */ |
#define VT_LLONG 12 /* 64 bit integer */ |
#define VT_LONG 13 /* long integer (NEVER USED as type, only |
during parsing) */ |
#define VT_BTYPE 0x000f /* mask for basic type */ |
#define VT_UNSIGNED 0x0010 /* unsigned type */ |
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */ |
#define VT_BITFIELD 0x0040 /* bitfield modifier */ |
#define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */ |
</PRE> |
<P> |
When a reference to another type is needed (for pointers, functions and |
structures), the <CODE>32 - VT_STRUCT_SHIFT</CODE> high order bits are used to |
store an identifier reference. |
<P> |
The <CODE>VT_UNSIGNED</CODE> flag can be set for chars, shorts, ints and long |
longs. |
<P> |
Arrays are considered as pointers <CODE>VT_PTR</CODE> with the flag |
<CODE>VT_ARRAY</CODE> set. |
<P> |
The <CODE>VT_BITFIELD</CODE> flag can be set for chars, shorts, ints and long |
longs. If it is set, then the bitfield position is stored from bits |
VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored |
from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11. |
<P> |
<CODE>VT_LONG</CODE> is never used except during parsing. |
<P> |
During parsing, the storage of an object is also stored in the type |
integer: |
<PRE> |
#define VT_EXTERN 0x00000080 /* extern definition */ |
#define VT_STATIC 0x00000100 /* static variable */ |
#define VT_TYPEDEF 0x00000200 /* typedef definition */ |
</PRE> |
<H2><A NAME="SEC28" HREF="tcc-doc.html#TOC28">8.5 Symbols</A></H2> |
<P> |
All symbols are stored in hashed symbol stacks. Each symbol stack |
contains <CODE>Sym</CODE> structures. |
<P> |
<CODE>Sym.v</CODE> contains the symbol name (remember |
an idenfier is also a token, so a string is never necessary to store |
it). <CODE>Sym.t</CODE> gives the type of the symbol. <CODE>Sym.r</CODE> is usually |
the register in which the corresponding variable is stored. <CODE>Sym.c</CODE> is |
usually a constant associated to the symbol. |
<P> |
Four main symbol stacks are defined: |
<DL COMPACT> |
<DT><CODE>define_stack</CODE> |
<DD> |
for the macros (<CODE>#define</CODE>s). |
<DT><CODE>global_stack</CODE> |
<DD> |
for the global variables, functions and types. |
<DT><CODE>local_stack</CODE> |
<DD> |
for the local variables, functions and types. |
<DT><CODE>global_label_stack</CODE> |
<DD> |
for the local labels (for <CODE>goto</CODE>). |
<DT><CODE>label_stack</CODE> |
<DD> |
for GCC block local labels (see the <CODE>__label__</CODE> keyword). |
</DL> |
<P> |
<CODE>sym_push()</CODE> is used to add a new symbol in the local symbol |
stack. If no local symbol stack is active, it is added in the global |
symbol stack. |
<P> |
<CODE>sym_pop(st,b)</CODE> pops symbols from the symbol stack <VAR>st</VAR> until |
the symbol <VAR>b</VAR> is on the top of stack. If <VAR>b</VAR> is NULL, the stack |
is emptied. |
<P> |
<CODE>sym_find(v)</CODE> return the symbol associated to the identifier |
<VAR>v</VAR>. The local stack is searched first from top to bottom, then the |
global stack. |
<H2><A NAME="SEC29" HREF="tcc-doc.html#TOC29">8.6 Sections</A></H2> |
<P> |
The generated code and datas are written in sections. The structure |
<CODE>Section</CODE> contains all the necessary information for a given |
section. <CODE>new_section()</CODE> creates a new section. ELF file semantics |
is assumed for each section. |
<P> |
The following sections are predefined: |
<DL COMPACT> |
<DT><CODE>text_section</CODE> |
<DD> |
is the section containing the generated code. <VAR>ind</VAR> contains the |
current position in the code section. |
<DT><CODE>data_section</CODE> |
<DD> |
contains initialized data |
<DT><CODE>bss_section</CODE> |
<DD> |
contains uninitialized data |
<DT><CODE>bounds_section</CODE> |
<DD> |
<DT><CODE>lbounds_section</CODE> |
<DD> |
are used when bound checking is activated |
<DT><CODE>stab_section</CODE> |
<DD> |
<DT><CODE>stabstr_section</CODE> |
<DD> |
are used when debugging is actived to store debug information |
<DT><CODE>symtab_section</CODE> |
<DD> |
<DT><CODE>strtab_section</CODE> |
<DD> |
contain the exported symbols (currently only used for debugging). |
</DL> |
<H2><A NAME="SEC30" HREF="tcc-doc.html#TOC30">8.7 Code generation</A></H2> |
<P> |
<A NAME="IDX47"></A> |
<H3><A NAME="SEC31" HREF="tcc-doc.html#TOC31">8.7.1 Introduction</A></H3> |
<P> |
The TCC code generator directly generates linked binary code in one |
pass. It is rather unusual these days (see gcc for example which |
generates text assembly), but it can be very fast and surprisingly |
little complicated. |
<P> |
The TCC code generator is register based. Optimization is only done at |
the expression level. No intermediate representation of expression is |
kept except the current values stored in the <EM>value stack</EM>. |
<P> |
On x86, three temporary registers are used. When more registers are |
needed, one register is spilled into a new temporary variable on the stack. |
<H3><A NAME="SEC32" HREF="tcc-doc.html#TOC32">8.7.2 The value stack</A></H3> |
<P> |
<A NAME="IDX48"></A> |
<P> |
When an expression is parsed, its value is pushed on the value stack |
(<VAR>vstack</VAR>). The top of the value stack is <VAR>vtop</VAR>. Each value |
stack entry is the structure <CODE>SValue</CODE>. |
<P> |
<CODE>SValue.t</CODE> is the type. <CODE>SValue.r</CODE> indicates how the value is |
currently stored in the generated code. It is usually a CPU register |
index (<CODE>REG_xxx</CODE> constants), but additional values and flags are |
defined: |
<PRE> |
#define VT_CONST 0x00f0 |
#define VT_LLOCAL 0x00f1 |
#define VT_LOCAL 0x00f2 |
#define VT_CMP 0x00f3 |
#define VT_JMP 0x00f4 |
#define VT_JMPI 0x00f5 |
#define VT_LVAL 0x0100 |
#define VT_SYM 0x0200 |
#define VT_MUSTCAST 0x0400 |
#define VT_MUSTBOUND 0x0800 |
#define VT_BOUNDED 0x8000 |
#define VT_LVAL_BYTE 0x1000 |
#define VT_LVAL_SHORT 0x2000 |
#define VT_LVAL_UNSIGNED 0x4000 |
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) |
</PRE> |
<DL COMPACT> |
<DT><CODE>VT_CONST</CODE> |
<DD> |
indicates that the value is a constant. It is stored in the union |
<CODE>SValue.c</CODE>, depending on its type. |
<DT><CODE>VT_LOCAL</CODE> |
<DD> |
indicates a local variable pointer at offset <CODE>SValue.c.i</CODE> in the |
stack. |
<DT><CODE>VT_CMP</CODE> |
<DD> |
indicates that the value is actually stored in the CPU flags (i.e. the |
value is the consequence of a test). The value is either 0 or 1. The |
actual CPU flags used is indicated in <CODE>SValue.c.i</CODE>. |
If any code is generated which destroys the CPU flags, this value MUST be |
put in a normal register. |
<DT><CODE>VT_JMP</CODE> |
<DD> |
<DT><CODE>VT_JMPI</CODE> |
<DD> |
indicates that the value is the consequence of a conditional jump. For VT_JMP, |
it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted. |
These values are used to compile the <CODE>||</CODE> and <CODE>&&</CODE> logical |
operators. |
If any code is generated, this value MUST be put in a normal |
register. Otherwise, the generated code won't be executed if the jump is |
taken. |
<DT><CODE>VT_LVAL</CODE> |
<DD> |
is a flag indicating that the value is actually an lvalue (left value of |
an assignment). It means that the value stored is actually a pointer to |
the wanted value. |
Understanding the use <CODE>VT_LVAL</CODE> is very important if you want to |
understand how TCC works. |
<DT><CODE>VT_LVAL_BYTE</CODE> |
<DD> |
<DT><CODE>VT_LVAL_SHORT</CODE> |
<DD> |
<DT><CODE>VT_LVAL_UNSIGNED</CODE> |
<DD> |
if the lvalue has an integer type, then these flags give its real |
type. The type alone is not enough in case of cast optimisations. |
<DT><CODE>VT_LLOCAL</CODE> |
<DD> |
is a saved lvalue on the stack. <CODE>VT_LLOCAL</CODE> should be eliminated |
ASAP because its semantics are rather complicated. |
<DT><CODE>VT_MUSTCAST</CODE> |
<DD> |
indicates that a cast to the value type must be performed if the value |
is used (lazy casting). |
<DT><CODE>VT_SYM</CODE> |
<DD> |
indicates that the symbol <CODE>SValue.sym</CODE> must be added to the constant. |
<DT><CODE>VT_MUSTBOUND</CODE> |
<DD> |
<DT><CODE>VT_BOUNDED</CODE> |
<DD> |
are only used for optional bound checking. |
</DL> |
<H3><A NAME="SEC33" HREF="tcc-doc.html#TOC33">8.7.3 Manipulating the value stack</A></H3> |
<P> |
<A NAME="IDX49"></A> |
<P> |
<CODE>vsetc()</CODE> and <CODE>vset()</CODE> pushes a new value on the value |
stack. If the previous <VAR>vtop</VAR> was stored in a very unsafe place(for |
example in the CPU flags), then some code is generated to put the |
previous <VAR>vtop</VAR> in a safe storage. |
<P> |
<CODE>vpop()</CODE> pops <VAR>vtop</VAR>. In some cases, it also generates cleanup |
code (for example if stacked floating point registers are used as on |
x86). |
<P> |
The <CODE>gv(rc)</CODE> function generates code to evaluate <VAR>vtop</VAR> (the |
top value of the stack) into registers. <VAR>rc</VAR> selects in which |
register class the value should be put. <CODE>gv()</CODE> is the <EM>most |
important function</EM> of the code generator. |
<P> |
<CODE>gv2()</CODE> is the same as <CODE>gv()</CODE> but for the top two stack |
entries. |
<H3><A NAME="SEC34" HREF="tcc-doc.html#TOC34">8.7.4 CPU dependent code generation</A></H3> |
<P> |
<A NAME="IDX50"></A> |
See the <TT>`i386-gen.c'</TT> file to have an example. |
<DL COMPACT> |
<DT><CODE>load()</CODE> |
<DD> |
must generate the code needed to load a stack value into a register. |
<DT><CODE>store()</CODE> |
<DD> |
must generate the code needed to store a register into a stack value |
lvalue. |
<DT><CODE>gfunc_start()</CODE> |
<DD> |
<DT><CODE>gfunc_param()</CODE> |
<DD> |
<DT><CODE>gfunc_call()</CODE> |
<DD> |
should generate a function call |
<DT><CODE>gfunc_prolog()</CODE> |
<DD> |
<DT><CODE>gfunc_epilog()</CODE> |
<DD> |
should generate a function prolog/epilog. |
<DT><CODE>gen_opi(op)</CODE> |
<DD> |
must generate the binary integer operation <VAR>op</VAR> on the two top |
entries of the stack which are guaranted to contain integer types. |
The result value should be put on the stack. |
<DT><CODE>gen_opf(op)</CODE> |
<DD> |
same as <CODE>gen_opi()</CODE> for floating point operations. The two top |
entries of the stack are guaranted to contain floating point values of |
same types. |
<DT><CODE>gen_cvt_itof()</CODE> |
<DD> |
integer to floating point conversion. |
<DT><CODE>gen_cvt_ftoi()</CODE> |
<DD> |
floating point to integer conversion. |
<DT><CODE>gen_cvt_ftof()</CODE> |
<DD> |
floating point to floating point of different size conversion. |
<DT><CODE>gen_bounded_ptr_add()</CODE> |
<DD> |
<DT><CODE>gen_bounded_ptr_deref()</CODE> |
<DD> |
are only used for bounds checking. |
</DL> |
<H2><A NAME="SEC35" HREF="tcc-doc.html#TOC35">8.8 Optimizations done</A></H2> |
<P> |
<A NAME="IDX51"></A> |
<A NAME="IDX52"></A> |
<A NAME="IDX53"></A> |
<A NAME="IDX54"></A> |
<A NAME="IDX55"></A> |
<A NAME="IDX56"></A> |
<A NAME="IDX57"></A> |
Constant propagation is done for all operations. Multiplications and |
divisions are optimized to shifts when appropriate. Comparison |
operators are optimized by maintaining a special cache for the |
processor flags. &&, || and ! are optimized by maintaining a special |
'jump target' value. No other jump optimization is currently performed |
because it would require to store the code in a more abstract fashion. |
<H1><A NAME="SEC36" HREF="tcc-doc.html#TOC36">Concept Index</A></H1> |
<P> |
Jump to: |
<A HREF="#cindex__">_</A> |
- |
<A HREF="#cindex_a">a</A> |
- |
<A HREF="#cindex_b">b</A> |
- |
<A HREF="#cindex_c">c</A> |
- |
<A HREF="#cindex_d">d</A> |
- |
<A HREF="#cindex_e">e</A> |
- |
<A HREF="#cindex_f">f</A> |
- |
<A HREF="#cindex_g">g</A> |
- |
<A HREF="#cindex_i">i</A> |
- |
<A HREF="#cindex_j">j</A> |
- |
<A HREF="#cindex_l">l</A> |
- |
<A HREF="#cindex_m">m</A> |
- |
<A HREF="#cindex_o">o</A> |
- |
<A HREF="#cindex_p">p</A> |
- |
<A HREF="#cindex_q">q</A> |
- |
<A HREF="#cindex_r">r</A> |
- |
<A HREF="#cindex_s">s</A> |
- |
<A HREF="#cindex_t">t</A> |
- |
<A HREF="#cindex_u">u</A> |
- |
<A HREF="#cindex_v">v</A> |
- |
<A HREF="#cindex_w">w</A> |
<P> |
<H2><A NAME="cindex__">_</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX10">__asm__</A> |
</DIR> |
<H2><A NAME="cindex_a">a</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX14">align directive</A> |
<LI><A HREF="tcc-doc.html#IDX1">aligned attribute</A> |
<LI><A HREF="tcc-doc.html#IDX34">ascii directive</A> |
<LI><A HREF="tcc-doc.html#IDX33">asciz directive</A> |
<LI><A HREF="tcc-doc.html#IDX35">assembler</A> |
<LI><A HREF="tcc-doc.html#IDX12">assembler directives</A> |
<LI><A HREF="tcc-doc.html#IDX9">assembly, inline</A> |
</DIR> |
<H2><A NAME="cindex_b">b</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX45">bound checks</A> |
<LI><A HREF="tcc-doc.html#IDX28">bss directive</A> |
<LI><A HREF="tcc-doc.html#IDX17">byte directive</A> |
</DIR> |
<H2><A NAME="cindex_c">c</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX55">caching processor flags</A> |
<LI><A HREF="tcc-doc.html#IDX5">cdecl attribute</A> |
<LI><A HREF="tcc-doc.html#IDX47">code generation</A> |
<LI><A HREF="tcc-doc.html#IDX54">comparison operators</A> |
<LI><A HREF="tcc-doc.html#IDX52">constant propagation</A> |
<LI><A HREF="tcc-doc.html#IDX50">CPU dependent</A> |
</DIR> |
<H2><A NAME="cindex_d">d</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX27">data directive</A> |
<LI><A HREF="tcc-doc.html#IDX13">directives, assembler</A> |
</DIR> |
<H2><A NAME="cindex_e">e</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX37">ELF</A> |
</DIR> |
<H2><A NAME="cindex_f">f</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX42">FILE, linker command</A> |
<LI><A HREF="tcc-doc.html#IDX29">fill directive</A> |
<LI><A HREF="tcc-doc.html#IDX56">flags, caching</A> |
</DIR> |
<H2><A NAME="cindex_g">g</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX11">gas</A> |
<LI><A HREF="tcc-doc.html#IDX24">global directive</A> |
<LI><A HREF="tcc-doc.html#IDX23">globl directive</A> |
<LI><A HREF="tcc-doc.html#IDX41">GROUP, linker command</A> |
</DIR> |
<H2><A NAME="cindex_i">i</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX8">inline assembly</A> |
<LI><A HREF="tcc-doc.html#IDX20">int directive</A> |
</DIR> |
<H2><A NAME="cindex_j">j</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX57">jump optimization</A> |
</DIR> |
<H2><A NAME="cindex_l">l</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX36">linker</A> |
<LI><A HREF="tcc-doc.html#IDX40">linker scripts</A> |
<LI><A HREF="tcc-doc.html#IDX21">long directive</A> |
</DIR> |
<H2><A NAME="cindex_m">m</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX46">memory checks</A> |
</DIR> |
<H2><A NAME="cindex_o">o</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX51">optimizations</A> |
<LI><A HREF="tcc-doc.html#IDX30">org directive</A> |
<LI><A HREF="tcc-doc.html#IDX43">OUTPUT_FORMAT, linker command</A> |
</DIR> |
<H2><A NAME="cindex_p">p</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX2">packed attribute</A> |
<LI><A HREF="tcc-doc.html#IDX38">PE-i386</A> |
<LI><A HREF="tcc-doc.html#IDX31">previous directive</A> |
</DIR> |
<H2><A NAME="cindex_q">q</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX22">quad directive</A> |
</DIR> |
<H2><A NAME="cindex_r">r</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX7">regparm attribute</A> |
</DIR> |
<H2><A NAME="cindex_s">s</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX39">scripts, linker</A> |
<LI><A HREF="tcc-doc.html#IDX3">section attribute</A> |
<LI><A HREF="tcc-doc.html#IDX25">section directive</A> |
<LI><A HREF="tcc-doc.html#IDX19">short directive</A> |
<LI><A HREF="tcc-doc.html#IDX15">skip directive</A> |
<LI><A HREF="tcc-doc.html#IDX16">space directive</A> |
<LI><A HREF="tcc-doc.html#IDX6">stdcall attribute</A> |
<LI><A HREF="tcc-doc.html#IDX53">strength reduction</A> |
<LI><A HREF="tcc-doc.html#IDX32">string directive</A> |
</DIR> |
<H2><A NAME="cindex_t">t</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX44">TARGET, linker command</A> |
<LI><A HREF="tcc-doc.html#IDX26">text directive</A> |
</DIR> |
<H2><A NAME="cindex_u">u</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX4">unused attribute</A> |
</DIR> |
<H2><A NAME="cindex_v">v</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX49">value stack</A> |
<LI><A HREF="tcc-doc.html#IDX48">value stack, introduction</A> |
</DIR> |
<H2><A NAME="cindex_w">w</A></H2> |
<DIR> |
<LI><A HREF="tcc-doc.html#IDX18">word directive</A> |
</DIR> |
<P><HR><P> |
This document was generated on 18 June 2005 using |
<A HREF="http://wwwinfo.cern.ch/dis/texi2html/">texi2html</A> 1.56k. |
</BODY> |
</HTML> |
/programs/develop/ktcc/trunk/source/tccasm.c |
---|
18,10 → 18,7 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
*/ |
#include "tcc.h" |
#ifdef CONFIG_TCC_ASM |
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) |
static int asm_get_local_label_name(TCCState *s1, unsigned int n) |
{ |
char buf[64]; |
TokenSym *ts; |
31,9 → 28,7 |
return ts->tok; |
} |
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); |
static int tcc_assemble_internal(TCCState *s1, int do_preprocess); |
static Sym sym_dot; |
static void asm_expr(TCCState *s1, ExprValue *pe); |
/* We do not use the C expression parser to handle symbols. Maybe the |
C expression parser could be tweaked to do so. */ |
46,7 → 41,7 |
switch(tok) { |
case TOK_PPNUM: |
p = tokc.str.data; |
p = tokc.cstr->data; |
n = strtoul(p, (char **)&p, 0); |
if (*p == 'b' || *p == 'f') { |
/* backward or forward label */ |
57,7 → 52,7 |
if (sym && sym->r == 0) |
sym = sym->prev_tok; |
if (!sym) |
tcc_error("local label '%d' not found backward", n); |
error("local label '%d' not found backward", n); |
} else { |
/* forward */ |
if (!sym || sym->r) { |
72,7 → 67,7 |
pe->v = n; |
pe->sym = NULL; |
} else { |
tcc_error("invalid number syntax"); |
error("invalid number syntax"); |
} |
next(); |
break; |
86,7 → 81,7 |
next(); |
asm_expr_unary(s1, pe); |
if (pe->sym) |
tcc_error("invalid operation with label"); |
error("invalid operation with label"); |
if (op == '-') |
pe->v = -pe->v; |
else |
103,14 → 98,6 |
asm_expr(s1, pe); |
skip(')'); |
break; |
case '.': |
pe->v = 0; |
pe->sym = &sym_dot; |
sym_dot.type.t = VT_VOID | VT_STATIC; |
sym_dot.r = cur_text_section->sh_num; |
sym_dot.jnext = ind; |
next(); |
break; |
default: |
if (tok >= TOK_IDENT) { |
/* label case : if the label was not found, add one */ |
122,7 → 109,7 |
} |
if (sym->r == SHN_ABS) { |
/* if absolute symbol, no need to put a symbol value */ |
pe->v = sym->jnext; |
pe->v = (long)sym->next; |
pe->sym = NULL; |
} else { |
pe->v = 0; |
130,7 → 117,7 |
} |
next(); |
} else { |
tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); |
error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); |
} |
break; |
} |
150,7 → 137,7 |
next(); |
asm_expr_unary(s1, &e2); |
if (pe->sym || e2.sym) |
tcc_error("invalid operation with label"); |
error("invalid operation with label"); |
switch(op) { |
case '*': |
pe->v *= e2.v; |
158,7 → 145,7 |
case '/': |
if (e2.v == 0) { |
div_error: |
tcc_error("division by zero"); |
error("division by zero"); |
} |
pe->v /= e2.v; |
break; |
191,7 → 178,7 |
next(); |
asm_expr_prod(s1, &e2); |
if (pe->sym || e2.sym) |
tcc_error("invalid operation with label"); |
error("invalid operation with label"); |
switch(op) { |
case '&': |
pe->v &= e2.v; |
238,25 → 225,25 |
/* OK */ |
} else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) { |
/* we also accept defined symbols in the same section */ |
pe->v += pe->sym->jnext - e2.sym->jnext; |
pe->v += (long)pe->sym->next - (long)e2.sym->next; |
} else { |
goto cannot_relocate; |
} |
pe->sym = NULL; /* same symbols can be subtracted to NULL */ |
pe->sym = NULL; /* same symbols can be substracted to NULL */ |
} else { |
cannot_relocate: |
tcc_error("invalid operation with label"); |
error("invalid operation with label"); |
} |
} |
} |
} |
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe) |
static void asm_expr(TCCState *s1, ExprValue *pe) |
{ |
asm_expr_sum(s1, pe); |
} |
ST_FUNC int asm_int_expr(TCCState *s1) |
static int asm_int_expr(TCCState *s1) |
{ |
ExprValue e; |
asm_expr(s1, &e); |
277,7 → 264,7 |
if (sym->r) { |
/* the label is already defined */ |
if (!is_local) { |
tcc_error("assembler label '%s' already defined", |
error("assembler label '%s' already defined", |
get_tok_str(label, NULL)); |
} else { |
/* redefinition of local labels is possible */ |
290,7 → 277,7 |
sym->type.t = VT_STATIC | VT_VOID; |
} |
sym->r = sh_num; |
sym->jnext = value; |
sym->next = (void *)value; |
} |
static void asm_new_label(TCCState *s1, int label, int is_local) |
311,7 → 298,7 |
sec = SECTION_ABS; |
else |
sec = st->sections[s->r]; |
put_extern_sym2(s, sec, s->jnext, 0, 0); |
put_extern_sym2(s, sec, (long)s->next, 0, 0); |
} |
/* remove label */ |
table_ident[s->v - TOK_IDENT]->sym_label = NULL; |
341,25 → 328,18 |
uint8_t *ptr; |
/* assembler directive */ |
next(); |
sec = cur_text_section; |
switch(tok) { |
case TOK_ASMDIR_align: |
case TOK_ASMDIR_p2align: |
case TOK_ASMDIR_skip: |
case TOK_ASMDIR_space: |
case TOK_ASM_align: |
case TOK_ASM_skip: |
case TOK_ASM_space: |
tok1 = tok; |
next(); |
n = asm_int_expr(s1); |
if (tok1 == TOK_ASMDIR_p2align) |
{ |
if (n < 0 || n > 30) |
tcc_error("invalid p2align, must be between 0 and 30"); |
n = 1 << n; |
tok1 = TOK_ASMDIR_align; |
} |
if (tok1 == TOK_ASMDIR_align) { |
if (tok1 == TOK_ASM_align) { |
if (n < 0 || (n & (n-1)) != 0) |
tcc_error("alignment must be a positive power of two"); |
error("alignment must be a positive power of two"); |
offset = (ind + n - 1) & -n; |
size = offset - ind; |
/* the section must have a compatible alignment */ |
381,16 → 361,16 |
} |
ind += size; |
break; |
case TOK_ASMDIR_quad: |
case TOK_ASM_quad: |
next(); |
for(;;) { |
uint64_t vl; |
const char *p; |
p = tokc.str.data; |
p = tokc.cstr->data; |
if (tok != TOK_PPNUM) { |
error_constant: |
tcc_error("64 bit constant"); |
error("64 bit constant"); |
} |
vl = strtoll(p, (char **)&p, 0); |
if (*p != '\0') |
408,15 → 388,15 |
next(); |
} |
break; |
case TOK_ASMDIR_byte: |
case TOK_ASM_byte: |
size = 1; |
goto asm_data; |
case TOK_ASMDIR_word: |
case TOK_ASMDIR_short: |
case TOK_ASM_word: |
case TOK_SHORT: |
size = 2; |
goto asm_data; |
case TOK_ASMDIR_long: |
case TOK_ASMDIR_int: |
case TOK_LONG: |
case TOK_INT: |
size = 4; |
asm_data: |
next(); |
442,7 → 422,7 |
next(); |
} |
break; |
case TOK_ASMDIR_fill: |
case TOK_ASM_fill: |
{ |
int repeat, size, val, i, j; |
uint8_t repeat_buf[8]; |
449,7 → 429,7 |
next(); |
repeat = asm_int_expr(s1); |
if (repeat < 0) { |
tcc_error("repeat < 0; .fill ignored"); |
error("repeat < 0; .fill ignored"); |
break; |
} |
size = 1; |
458,7 → 438,7 |
next(); |
size = asm_int_expr(s1); |
if (size < 0) { |
tcc_error("size < 0; .fill ignored"); |
error("size < 0; .fill ignored"); |
break; |
} |
if (size > 8) |
484,52 → 464,22 |
} |
} |
break; |
case TOK_ASMDIR_rept: |
case TOK_ASM_org: |
{ |
int repeat; |
TokenString init_str; |
ParseState saved_parse_state = {0}; |
next(); |
repeat = asm_int_expr(s1); |
tok_str_new(&init_str); |
next(); |
while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) { |
tok_str_add_tok(&init_str); |
next(); |
} |
if (tok == CH_EOF) tcc_error("we at end of file, .endr not found"); |
next(); |
tok_str_add(&init_str, -1); |
tok_str_add(&init_str, 0); |
save_parse_state(&saved_parse_state); |
begin_macro(&init_str, 0); |
while (repeat-- > 0) { |
tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS)); |
macro_ptr = init_str.str; |
} |
end_macro(); |
restore_parse_state(&saved_parse_state); |
break; |
} |
case TOK_ASMDIR_org: |
{ |
unsigned long n; |
next(); |
/* XXX: handle section symbols too */ |
n = asm_int_expr(s1); |
if (n < ind) |
tcc_error("attempt to .org backwards"); |
error("attempt to .org backwards"); |
v = 0; |
size = n - ind; |
goto zero_pad; |
} |
break; |
case TOK_ASMDIR_globl: |
case TOK_ASMDIR_global: |
case TOK_ASMDIR_weak: |
case TOK_ASMDIR_hidden: |
tok1 = tok; |
do { |
case TOK_ASM_globl: |
case TOK_ASM_global: |
{ |
Sym *sym; |
next(); |
538,18 → 488,13 |
sym = label_push(&s1->asm_labels, tok, 0); |
sym->type.t = VT_VOID; |
} |
if (tok1 != TOK_ASMDIR_hidden) |
sym->type.t &= ~VT_STATIC; |
if (tok1 == TOK_ASMDIR_weak) |
sym->type.t |= VT_WEAK; |
else if (tok1 == TOK_ASMDIR_hidden) |
sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT; |
next(); |
} while (tok == ','); |
} |
break; |
case TOK_ASMDIR_string: |
case TOK_ASMDIR_ascii: |
case TOK_ASMDIR_asciz: |
case TOK_ASM_string: |
case TOK_ASM_ascii: |
case TOK_ASM_asciz: |
{ |
const uint8_t *p; |
int i, size, t; |
559,9 → 504,9 |
for(;;) { |
if (tok != TOK_STR) |
expect("string constant"); |
p = tokc.str.data; |
size = tokc.str.size; |
if (t == TOK_ASMDIR_ascii && size > 0) |
p = tokc.cstr->data; |
size = tokc.cstr->size; |
if (t == TOK_ASM_ascii && size > 0) |
size--; |
for(i = 0; i < size; i++) |
g(p[i]); |
574,9 → 519,9 |
} |
} |
break; |
case TOK_ASMDIR_text: |
case TOK_ASMDIR_data: |
case TOK_ASMDIR_bss: |
case TOK_ASM_text: |
case TOK_ASM_data: |
case TOK_ASM_bss: |
{ |
char sname[64]; |
tok1 = tok; |
586,104 → 531,12 |
n = asm_int_expr(s1); |
next(); |
} |
if (n) |
sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n); |
else |
sprintf(sname, "%s", get_tok_str(tok1, NULL)); |
sprintf(sname, (n?".%s%d":".%s"), get_tok_str(tok1, NULL), n); |
use_section(s1, sname); |
} |
break; |
case TOK_ASMDIR_file: |
case TOK_SECTION1: |
{ |
char filename[512]; |
filename[0] = '\0'; |
next(); |
if (tok == TOK_STR) |
pstrcat(filename, sizeof(filename), tokc.str.data); |
else |
pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); |
if (s1->warn_unsupported) |
tcc_warning("ignoring .file %s", filename); |
next(); |
} |
break; |
case TOK_ASMDIR_ident: |
{ |
char ident[256]; |
ident[0] = '\0'; |
next(); |
if (tok == TOK_STR) |
pstrcat(ident, sizeof(ident), tokc.str.data); |
else |
pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); |
if (s1->warn_unsupported) |
tcc_warning("ignoring .ident %s", ident); |
next(); |
} |
break; |
case TOK_ASMDIR_size: |
{ |
Sym *sym; |
next(); |
sym = label_find(tok); |
if (!sym) { |
tcc_error("label not found: %s", get_tok_str(tok, NULL)); |
} |
/* XXX .size name,label2-label1 */ |
if (s1->warn_unsupported) |
tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL)); |
next(); |
skip(','); |
while (tok != '\n' && tok != CH_EOF) { |
next(); |
} |
} |
break; |
case TOK_ASMDIR_type: |
{ |
Sym *sym; |
const char *newtype; |
next(); |
sym = label_find(tok); |
if (!sym) { |
sym = label_push(&s1->asm_labels, tok, 0); |
sym->type.t = VT_VOID; |
} |
next(); |
skip(','); |
if (tok == TOK_STR) { |
newtype = tokc.str.data; |
} else { |
if (tok == '@' || tok == '%') |
next(); |
newtype = get_tok_str(tok, NULL); |
} |
if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { |
sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC; |
} |
else if (s1->warn_unsupported) |
tcc_warning("change type of '%s' from 0x%x to '%s' ignored", |
get_tok_str(sym->v, NULL), sym->type.t, newtype); |
next(); |
} |
break; |
case TOK_ASMDIR_section: |
{ |
char sname[256]; |
/* XXX: support more options */ |
691,7 → 544,7 |
sname[0] = '\0'; |
while (tok != ';' && tok != TOK_LINEFEED && tok != ',') { |
if (tok == TOK_STR) |
pstrcat(sname, sizeof(sname), tokc.str.data); |
pstrcat(sname, sizeof(sname), tokc.cstr->data); |
else |
pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL)); |
next(); |
702,50 → 555,24 |
if (tok != TOK_STR) |
expect("string constant"); |
next(); |
if (tok == ',') { |
next(); |
if (tok == '@' || tok == '%') |
next(); |
next(); |
} |
} |
last_text_section = cur_text_section; |
use_section(s1, sname); |
} |
break; |
case TOK_ASMDIR_previous: |
case TOK_ASM_previous: |
{ |
Section *sec; |
next(); |
if (!last_text_section) |
tcc_error("no previous section referenced"); |
error("no previous section referenced"); |
sec = cur_text_section; |
use_section1(s1, last_text_section); |
last_text_section = sec; |
} |
break; |
#ifdef TCC_TARGET_I386 |
case TOK_ASMDIR_code16: |
{ |
next(); |
s1->seg_size = 16; |
} |
break; |
case TOK_ASMDIR_code32: |
{ |
next(); |
s1->seg_size = 32; |
} |
break; |
#endif |
#ifdef TCC_TARGET_X86_64 |
/* added for compatibility with GAS */ |
case TOK_ASMDIR_code64: |
next(); |
break; |
#endif |
default: |
tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL)); |
error("unknown assembler directive '.%s'", get_tok_str(tok, NULL)); |
break; |
} |
} |
792,7 → 619,7 |
ch = file->buf_ptr[0]; |
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; |
parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR; |
parse_flags = PARSE_FLAG_ASM_COMMENTS; |
if (do_preprocess) |
parse_flags |= PARSE_FLAG_PREPROCESS; |
next(); |
805,12 → 632,12 |
/* horrible gas comment */ |
while (tok != TOK_LINEFEED) |
next(); |
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) { |
} else if (tok == '.') { |
asm_parse_directive(s1); |
} else if (tok == TOK_PPNUM) { |
const char *p; |
int n; |
p = tokc.str.data; |
p = tokc.cstr->data; |
n = strtoul(p, (char **)&p, 10); |
if (*p != '\0') |
expect("':'"); |
852,7 → 679,7 |
} |
/* Assemble the current file */ |
ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) |
static int tcc_assemble(TCCState *s1, int do_preprocess) |
{ |
Sym *define_start; |
int ret; |
865,12 → 692,6 |
define_start = define_stack; |
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL |
symbols can be safely used */ |
put_elf_sym(symtab_section, 0, 0, |
ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, |
SHN_ABS, file->filename); |
ret = tcc_assemble_internal(s1, do_preprocess); |
cur_text_section->data_offset = ind; |
888,27 → 709,37 |
end */ |
static void tcc_assemble_inline(TCCState *s1, char *str, int len) |
{ |
int saved_parse_flags; |
const int *saved_macro_ptr; |
BufferedFile *bf, *saved_file; |
int saved_parse_flags, *saved_macro_ptr; |
bf = tcc_malloc(sizeof(BufferedFile)); |
memset(bf, 0, sizeof(BufferedFile)); |
bf->fd = -1; |
bf->buf_ptr = str; |
bf->buf_end = str + len; |
str[len] = CH_EOB; |
/* same name as current file so that errors are correctly |
reported */ |
pstrcpy(bf->filename, sizeof(bf->filename), file->filename); |
bf->line_num = file->line_num; |
saved_file = file; |
file = bf; |
saved_parse_flags = parse_flags; |
saved_macro_ptr = macro_ptr; |
macro_ptr = NULL; |
tcc_open_bf(s1, ":asm:", len); |
memcpy(file->buffer, str, len); |
macro_ptr = NULL; |
tcc_assemble_internal(s1, 0); |
tcc_close(); |
parse_flags = saved_parse_flags; |
macro_ptr = saved_macro_ptr; |
file = saved_file; |
tcc_free(bf); |
} |
/* find a constraint by its number or id (gcc 3 extended |
syntax). return -1 if not found. Return in *pp in char after the |
constraint */ |
ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, |
static int find_constraint(ASMOperand *operands, int nb_operands, |
const char *name, const char **pp) |
{ |
int index; |
970,12 → 801,12 |
modifier = *str++; |
index = find_constraint(operands, nb_operands, str, &str); |
if (index < 0) |
tcc_error("invalid operand reference after %%"); |
error("invalid operand reference after %%"); |
op = &operands[index]; |
sv = *op->vt; |
if (op->reg >= 0) { |
sv.r = op->reg; |
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) |
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) |
sv.r |= VT_LVAL; |
} |
subst_asm_operand(out_str, &sv, modifier); |
999,7 → 830,7 |
nb_operands = *nb_operands_ptr; |
for(;;) { |
if (nb_operands >= MAX_ASM_OPERANDS) |
tcc_error("too many asm operands"); |
error("too many asm operands"); |
op = &operands[nb_operands++]; |
op->id = 0; |
if (tok == '[') { |
1012,8 → 843,8 |
} |
if (tok != TOK_STR) |
expect("string constant"); |
op->constraint = tcc_malloc(tokc.str.size); |
strcpy(op->constraint, tokc.str.data); |
op->constraint = tcc_malloc(tokc.cstr->size); |
strcpy(op->constraint, tokc.cstr->data); |
next(); |
skip('('); |
gexpr(); |
1043,12 → 874,27 |
} |
} |
static void parse_asm_str(CString *astr) |
{ |
skip('('); |
/* read the string */ |
if (tok != TOK_STR) |
expect("string constant"); |
cstr_new(astr); |
while (tok == TOK_STR) { |
/* XXX: add \0 handling too ? */ |
cstr_cat(astr, tokc.cstr->data); |
next(); |
} |
cstr_ccat(astr, '\0'); |
} |
/* parse the GCC asm() instruction */ |
ST_FUNC void asm_instr(void) |
static void asm_instr(void) |
{ |
CString astr, astr1; |
ASMOperand operands[MAX_ASM_OPERANDS]; |
int nb_outputs, nb_operands, i, must_subst, out_reg; |
int nb_inputs, nb_outputs, nb_operands, i, must_subst, out_reg; |
uint8_t clobber_regs[NB_ASM_REGS]; |
next(); |
1070,7 → 916,6 |
nb_outputs = nb_operands; |
if (tok == ':') { |
next(); |
if (tok != ')') { |
/* input args */ |
parse_asm_operands(operands, &nb_operands, 0); |
if (tok == ':') { |
1080,7 → 925,7 |
for(;;) { |
if (tok != TOK_STR) |
expect("string constant"); |
asm_clobber(clobber_regs, tokc.str.data); |
asm_clobber(clobber_regs, tokc.cstr->data); |
next(); |
if (tok == ',') { |
next(); |
1091,12 → 936,12 |
} |
} |
} |
} |
skip(')'); |
/* NOTE: we do not eat the ';' so that we can restore the current |
token after the assembler parsing */ |
if (tok != ';') |
expect("';'"); |
nb_inputs = nb_operands - nb_outputs; |
/* save all values in the memory */ |
save_regs(0); |
1144,7 → 989,7 |
cstr_free(&astr1); |
} |
ST_FUNC void asm_global_instr(void) |
static void asm_global_instr(void) |
{ |
CString astr; |
1172,4 → 1017,3 |
cstr_free(&astr); |
} |
#endif /* CONFIG_TCC_ASM */ |
/programs/develop/ktcc/trunk/source/tcccoff.c |
---|
18,9 → 18,8 |
* License along with this library; if not, write to the Free Software |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
*/ |
#include "coff.h" |
#include "tcc.h" |
#define MAXNSCNS 255 /* MAXIMUM NUMBER OF SECTIONS */ |
#define MAX_STR_TABLE 1000000 |
AOUTHDR o_filehdr; /* OPTIONAL (A.OUT) FILE HEADER */ |
38,7 → 37,7 |
int LastLineNo[MAX_FUNCS]; |
int FuncEntries[MAX_FUNCS]; |
int OutputTheSection(Section * sect); |
BOOL OutputTheSection(Section * sect); |
short int GetCoffFlags(const char *s); |
void SortSymbolTable(void); |
Section *FindSection(TCCState * s1, const char *sname); |
74,7 → 73,7 |
unsigned short dummy4; |
} AUXEF; |
ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f) |
int tcc_output_coff(TCCState *s1, FILE *f) |
{ |
Section *tcc_sect; |
SCNHDR *coff_sec; |
85,8 → 84,6 |
Section *stext, *sdata, *sbss; |
int i, NSectionsToOutput = 0; |
Coff_str_table = pCoff_str_table = NULL; |
stext = FindSection(s1, ".text"); |
sdata = FindSection(s1, ".data"); |
sbss = FindSection(s1, ".bss"); |
186,7 → 183,7 |
coff_sec->s_nlnno = 0; |
coff_sec->s_lnnoptr = 0; |
if (s1->do_debug && tcc_sect == stext) { |
if (do_debug && tcc_sect == stext) { |
// count how many line nos data |
// also find association between source file name and function |
314,7 → 311,7 |
file_hdr.f_symptr = file_pointer; /* file pointer to symtab */ |
if (s1->do_debug) |
if (do_debug) |
file_hdr.f_nsyms = coff_nb_syms; /* number of symtab entries */ |
else |
file_hdr.f_nsyms = 0; |
365,7 → 362,7 |
// group the symbols in order of filename, func1, func2, etc |
// finally global symbols |
if (s1->do_debug) |
if (do_debug) |
SortSymbolTable(); |
// write line no data |
374,7 → 371,7 |
coff_sec = §ion_header[i]; |
tcc_sect = s1->sections[i]; |
if (s1->do_debug && tcc_sect == stext) { |
if (do_debug && tcc_sect == stext) { |
// count how many line nos data |
502,7 → 499,7 |
} |
// write symbol table |
if (s1->do_debug) { |
if (do_debug) { |
int k; |
struct syment csym; |
AUXFUNC auxfunc; |
533,7 → 530,7 |
} else { |
if (pCoff_str_table - Coff_str_table + strlen(name) > |
MAX_STR_TABLE - 1) |
tcc_error("String table too large"); |
error("String table too large"); |
csym._n._n_n._n_zeroes = 0; |
csym._n._n_n._n_offset = |
563,7 → 560,11 |
} |
if (k >= nFuncs) { |
tcc_error("debug info can't find function: %s", name); |
char s[256]; |
sprintf(s, "debug info can't find function: %s", name); |
error(s); |
} |
// put a Function Name |
669,7 → 670,7 |
} |
} |
if (s1->do_debug) { |
if (do_debug) { |
// write string table |
// first write the size |
730,7 → 731,13 |
} |
if (k >= nFuncs) { |
tcc_error("debug (sort) info can't find function: %s", name2); |
char s[256]; |
sprintf(s, |
"debug (sort) info can't find function: %s", |
name2); |
error(s); |
} |
if (strcmp(AssociatedFile[k], name) == 0) { |
757,7 → 764,7 |
} |
if (n != nb_syms) |
tcc_error("Internal Compiler error, debug info"); |
error("Internal Compiler error, debug info"); |
// copy it all back |
814,14 → 821,14 |
return n; // total number of symbols |
} |
int OutputTheSection(Section * sect) |
BOOL OutputTheSection(Section * sect) |
{ |
const char *s = sect->name; |
if (!strcmp(s, ".text")) |
return 1; |
return true; |
else if (!strcmp(s, ".data")) |
return 1; |
return true; |
else |
return 0; |
} |
854,11 → 861,11 |
return s; |
} |
tcc_error("could not find section %s", sname); |
error("could not find section %s", sname); |
return 0; |
} |
ST_FUNC int tcc_load_coff(TCCState * s1, int fd) |
int tcc_load_coff(TCCState * s1, int fd) |
{ |
// tktk TokenSym *ts; |
872,28 → 879,28 |
f = fdopen(fd, "rb"); |
if (!f) { |
tcc_error("Unable to open .out file for input"); |
error("Unable to open .out file for input"); |
} |
if (fread(&file_hdr, FILHSZ, 1, f) != 1) |
tcc_error("error reading .out file for input"); |
error("error reading .out file for input"); |
if (fread(&o_filehdr, sizeof(o_filehdr), 1, f) != 1) |
tcc_error("error reading .out file for input"); |
error("error reading .out file for input"); |
// first read the string table |
if (fseek(f, file_hdr.f_symptr + file_hdr.f_nsyms * SYMESZ, SEEK_SET)) |
tcc_error("error reading .out file for input"); |
error("error reading .out file for input"); |
if (fread(&str_size, sizeof(int), 1, f) != 1) |
tcc_error("error reading .out file for input"); |
error("error reading .out file for input"); |
Coff_str_table = (char *) tcc_malloc(str_size); |
if (fread(Coff_str_table, str_size - 4, 1, f) != 1) |
tcc_error("error reading .out file for input"); |
error("error reading .out file for input"); |
// read/process all the symbols |
900,11 → 907,11 |
// seek back to symbols |
if (fseek(f, file_hdr.f_symptr, SEEK_SET)) |
tcc_error("error reading .out file for input"); |
error("error reading .out file for input"); |
for (i = 0; i < file_hdr.f_nsyms; i++) { |
if (fread(&csym, SYMESZ, 1, f) != 1) |
tcc_error("error reading .out file for input"); |
error("error reading .out file for input"); |
if (csym._n._n_n._n_zeroes == 0) { |
name = Coff_str_table + csym._n._n_n._n_offset - 4; |
933,13 → 940,13 |
if (name[0] == '_' && strcmp(name, "_main") != 0) |
name++; |
tcc_add_symbol(s1, name, (void*)(uintptr_t)csym.n_value); |
tcc_add_symbol(s1, name, csym.n_value); |
} |
// skip any aux records |
if (csym.n_numaux == 1) { |
if (fread(&csym, SYMESZ, 1, f) != 1) |
tcc_error("error reading .out file for input"); |
error("error reading .out file for input"); |
i++; |
} |
} |
/programs/develop/ktcc/trunk/source/tcclib.h |
---|
18,7 → 18,6 |
int atoi(const char *nptr); |
long int strtol(const char *nptr, char **endptr, int base); |
unsigned long int strtoul(const char *nptr, char **endptr, int base); |
void exit(int); |
/* stdio.h */ |
typedef struct __FILE FILE; |
39,7 → 38,6 |
char *gets(char *s); |
int ungetc(int c, FILE *stream); |
int fflush(FILE *stream); |
int putchar (int c); |
int printf(const char *format, ...); |
int fprintf(FILE *stream, const char *format, ...); |
65,7 → 63,6 |
void *memmove(void *dest, const void *src, size_t n); |
void *memset(void *s, int c, size_t n); |
char *strdup(const char *s); |
size_t strlen(const char *s); |
/* dlfcn.h */ |
#define RTLD_LAZY 0x001 |
/programs/develop/ktcc/trunk/source/tcctok.h |
---|
59,10 → 59,6 |
DEF(TOK_ASM2, "__asm") |
DEF(TOK_ASM3, "__asm__") |
#ifdef TCC_TARGET_ARM64 |
DEF(TOK_UINT128, "__uint128_t") |
#endif |
/*********************************************************************/ |
/* the following are not keywords. They are included to ease parsing */ |
/* preprocessor only */ |
89,11 → 85,6 |
/* special identifiers */ |
DEF(TOK___FUNC__, "__func__") |
/* special floating point values */ |
DEF(TOK___NAN__, "__nan__") |
DEF(TOK___SNAN__, "__snan__") |
DEF(TOK___INF__, "__inf__") |
/* attribute identifiers */ |
/* XXX: handle all tokens generically since speed is not critical */ |
DEF(TOK_SECTION1, "section") |
102,10 → 93,6 |
DEF(TOK_ALIGNED2, "__aligned__") |
DEF(TOK_PACKED1, "packed") |
DEF(TOK_PACKED2, "__packed__") |
DEF(TOK_WEAK1, "weak") |
DEF(TOK_WEAK2, "__weak__") |
DEF(TOK_ALIAS1, "alias") |
DEF(TOK_ALIAS2, "__alias__") |
DEF(TOK_UNUSED1, "unused") |
DEF(TOK_UNUSED2, "__unused__") |
DEF(TOK_CDECL1, "cdecl") |
114,118 → 101,46 |
DEF(TOK_STDCALL1, "stdcall") |
DEF(TOK_STDCALL2, "__stdcall") |
DEF(TOK_STDCALL3, "__stdcall__") |
DEF(TOK_FASTCALL1, "fastcall") |
DEF(TOK_FASTCALL2, "__fastcall") |
DEF(TOK_FASTCALL3, "__fastcall__") |
DEF(TOK_MODE, "__mode__") |
DEF(TOK_MODE_DI, "__DI__") |
DEF(TOK_MODE_HI, "__HI__") |
DEF(TOK_MODE_SI, "__SI__") |
DEF(TOK_DLLEXPORT, "dllexport") |
DEF(TOK_DLLIMPORT, "dllimport") |
DEF(TOK_NORETURN1, "noreturn") |
DEF(TOK_NORETURN2, "__noreturn__") |
DEF(TOK_VISIBILITY1, "visibility") |
DEF(TOK_VISIBILITY2, "__visibility__") |
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p") |
DEF(TOK_builtin_constant_p, "__builtin_constant_p") |
DEF(TOK_builtin_frame_address, "__builtin_frame_address") |
DEF(TOK_builtin_return_address, "__builtin_return_address") |
DEF(TOK_builtin_expect, "__builtin_expect") |
#ifdef TCC_TARGET_X86_64 |
#ifdef TCC_TARGET_PE |
DEF(TOK_builtin_va_start, "__builtin_va_start") |
#else |
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types") |
#endif |
#endif |
DEF(TOK_REGPARM1, "regparm") |
DEF(TOK_REGPARM2, "__regparm__") |
#ifdef TCC_TARGET_ARM64 |
DEF(TOK___va_start, "__va_start") |
DEF(TOK___va_arg, "__va_arg") |
#endif |
/* pragma */ |
DEF(TOK_pack, "pack") |
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) |
#if !defined(TCC_TARGET_I386) |
/* already defined for assembler */ |
DEF(TOK_ASM_push, "push") |
DEF(TOK_ASM_pop, "pop") |
#endif |
DEF(TOK_comment, "comment") |
DEF(TOK_lib, "lib") |
DEF(TOK_push_macro, "push_macro") |
DEF(TOK_pop_macro, "pop_macro") |
DEF(TOK_once, "once") |
/* builtin functions or variables */ |
#ifndef TCC_ARM_EABI |
DEF(TOK_memcpy, "memcpy") |
DEF(TOK_memmove, "memmove") |
DEF(TOK_memset, "memset") |
DEF(TOK_alloca, "alloca") |
DEF(TOK___divdi3, "__divdi3") |
DEF(TOK___moddi3, "__moddi3") |
DEF(TOK___udivdi3, "__udivdi3") |
DEF(TOK___umoddi3, "__umoddi3") |
DEF(TOK___ashrdi3, "__ashrdi3") |
DEF(TOK___lshrdi3, "__lshrdi3") |
DEF(TOK___ashldi3, "__ashldi3") |
DEF(TOK___floatundisf, "__floatundisf") |
DEF(TOK___floatundidf, "__floatundidf") |
# ifndef TCC_ARM_VFP |
DEF(TOK___floatundixf, "__floatundixf") |
DEF(TOK___fixunsxfdi, "__fixunsxfdi") |
# endif |
DEF(TOK___fixunssfdi, "__fixunssfdi") |
DEF(TOK___fixunsdfdi, "__fixunsdfdi") |
#endif |
#if defined TCC_TARGET_ARM |
# ifdef TCC_ARM_EABI |
DEF(TOK_memcpy, "__aeabi_memcpy") |
DEF(TOK_memcpy4, "__aeabi_memcpy4") |
DEF(TOK_memcpy8, "__aeabi_memcpy8") |
DEF(TOK_memmove, "__aeabi_memmove") |
DEF(TOK_memset, "__aeabi_memset") |
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod") |
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod") |
DEF(TOK___aeabi_idivmod, "__aeabi_idivmod") |
DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod") |
DEF(TOK___divsi3, "__aeabi_idiv") |
DEF(TOK___udivsi3, "__aeabi_uidiv") |
DEF(TOK___floatdisf, "__aeabi_l2f") |
DEF(TOK___floatdidf, "__aeabi_l2d") |
DEF(TOK___fixsfdi, "__aeabi_f2lz") |
DEF(TOK___fixdfdi, "__aeabi_d2lz") |
DEF(TOK___ashrdi3, "__aeabi_lasr") |
DEF(TOK___lshrdi3, "__aeabi_llsr") |
DEF(TOK___ashldi3, "__aeabi_llsl") |
DEF(TOK___floatundisf, "__aeabi_ul2f") |
DEF(TOK___floatundidf, "__aeabi_ul2d") |
DEF(TOK___fixunssfdi, "__aeabi_f2ulz") |
DEF(TOK___fixunsdfdi, "__aeabi_d2ulz") |
# else |
#if defined(TCC_TARGET_ARM) |
DEF(TOK___divsi3, "__divsi3") |
DEF(TOK___modsi3, "__modsi3") |
DEF(TOK___udivsi3, "__udivsi3") |
DEF(TOK___umodsi3, "__umodsi3") |
DEF(TOK___divsi3, "__divsi3") |
DEF(TOK___udivsi3, "__udivsi3") |
DEF(TOK___floatdisf, "__floatdisf") |
DEF(TOK___floatdidf, "__floatdidf") |
# ifndef TCC_ARM_VFP |
DEF(TOK___floatdixf, "__floatdixf") |
DEF(TOK___sardi3, "__ashrdi3") |
DEF(TOK___shrdi3, "__lshrdi3") |
DEF(TOK___shldi3, "__ashldi3") |
DEF(TOK___slltold, "__slltold") |
DEF(TOK___fixunssfsi, "__fixunssfsi") |
DEF(TOK___fixunsdfsi, "__fixunsdfsi") |
DEF(TOK___fixunsxfsi, "__fixunsxfsi") |
DEF(TOK___fixxfdi, "__fixxfdi") |
# endif |
DEF(TOK___fixsfdi, "__fixsfdi") |
DEF(TOK___fixdfdi, "__fixdfdi") |
# endif |
#endif |
#if defined TCC_TARGET_C67 |
DEF(TOK___fixxfdi, "__fixxfdi") |
#elif defined(TCC_TARGET_C67) |
DEF(TOK__divi, "_divi") |
DEF(TOK__divu, "_divu") |
DEF(TOK__divf, "_divf") |
232,50 → 147,24 |
DEF(TOK__divd, "_divd") |
DEF(TOK__remi, "_remi") |
DEF(TOK__remu, "_remu") |
DEF(TOK___sardi3, "__sardi3") |
DEF(TOK___shrdi3, "__shrdi3") |
DEF(TOK___shldi3, "__shldi3") |
#else |
/* XXX: same names on i386 ? */ |
DEF(TOK___sardi3, "__sardi3") |
DEF(TOK___shrdi3, "__shrdi3") |
DEF(TOK___shldi3, "__shldi3") |
#endif |
#if defined TCC_TARGET_I386 |
DEF(TOK___fixsfdi, "__fixsfdi") |
DEF(TOK___fixdfdi, "__fixdfdi") |
DEF(TOK___fixxfdi, "__fixxfdi") |
#ifndef COMMIT_4ad186c5ef61_IS_FIXED |
DEF(TOK___tcc_cvt_ftol, "__tcc_cvt_ftol") |
#endif |
#endif |
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 |
DEF(TOK_alloca, "alloca") |
#endif |
#if defined TCC_TARGET_PE |
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control") |
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control") |
DEF(TOK___ulltof, "__ulltof") |
DEF(TOK___ulltod, "__ulltod") |
DEF(TOK___ulltold, "__ulltold") |
DEF(TOK___fixunssfdi, "__fixunssfdi") |
DEF(TOK___fixunsdfdi, "__fixunsdfdi") |
DEF(TOK___fixunsxfdi, "__fixunsxfdi") |
DEF(TOK___chkstk, "__chkstk") |
#endif |
#ifdef TCC_TARGET_ARM64 |
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache") |
DEF(TOK___addtf3, "__addtf3") |
DEF(TOK___subtf3, "__subtf3") |
DEF(TOK___multf3, "__multf3") |
DEF(TOK___divtf3, "__divtf3") |
DEF(TOK___extendsftf2, "__extendsftf2") |
DEF(TOK___extenddftf2, "__extenddftf2") |
DEF(TOK___trunctfsf2, "__trunctfsf2") |
DEF(TOK___trunctfdf2, "__trunctfdf2") |
DEF(TOK___fixtfsi, "__fixtfsi") |
DEF(TOK___fixtfdi, "__fixtfdi") |
DEF(TOK___fixunstfsi, "__fixunstfsi") |
DEF(TOK___fixunstfdi, "__fixunstfdi") |
DEF(TOK___floatsitf, "__floatsitf") |
DEF(TOK___floatditf, "__floatditf") |
DEF(TOK___floatunsitf, "__floatunsitf") |
DEF(TOK___floatunditf, "__floatunditf") |
DEF(TOK___eqtf2, "__eqtf2") |
DEF(TOK___netf2, "__netf2") |
DEF(TOK___lttf2, "__lttf2") |
DEF(TOK___letf2, "__letf2") |
DEF(TOK___gttf2, "__gttf2") |
DEF(TOK___getf2, "__getf2") |
#endif |
/* bound checking symbols */ |
#ifdef CONFIG_TCC_BCHECK |
286,59 → 175,251 |
DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8") |
DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12") |
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16") |
DEF(TOK___bound_main_arg, "__bound_main_arg") |
DEF(TOK___bound_local_new, "__bound_local_new") |
DEF(TOK___bound_local_delete, "__bound_local_delete") |
DEF(TOK___bound_init, "__bound_init") |
# ifdef TCC_TARGET_PE |
DEF(TOK_malloc, "malloc") |
DEF(TOK_free, "free") |
DEF(TOK_realloc, "realloc") |
DEF(TOK_memalign, "memalign") |
DEF(TOK_calloc, "calloc") |
# endif |
DEF(TOK_memmove, "memmove") |
DEF(TOK_strlen, "strlen") |
DEF(TOK_strcpy, "strcpy") |
#endif |
/* Tiny Assembler */ |
DEF_ASMDIR(byte) /* must be first directive */ |
DEF_ASMDIR(word) |
DEF_ASMDIR(align) |
DEF_ASMDIR(p2align) |
DEF_ASMDIR(skip) |
DEF_ASMDIR(space) |
DEF_ASMDIR(string) |
DEF_ASMDIR(asciz) |
DEF_ASMDIR(ascii) |
DEF_ASMDIR(file) |
DEF_ASMDIR(globl) |
DEF_ASMDIR(global) |
DEF_ASMDIR(weak) |
DEF_ASMDIR(hidden) |
DEF_ASMDIR(ident) |
DEF_ASMDIR(size) |
DEF_ASMDIR(type) |
DEF_ASMDIR(text) |
DEF_ASMDIR(data) |
DEF_ASMDIR(bss) |
DEF_ASMDIR(previous) |
DEF_ASMDIR(fill) |
DEF_ASMDIR(rept) |
DEF_ASMDIR(endr) |
DEF_ASMDIR(org) |
DEF_ASMDIR(quad) |
#if defined(TCC_TARGET_I386) |
DEF_ASMDIR(code16) |
DEF_ASMDIR(code32) |
#elif defined(TCC_TARGET_X86_64) |
DEF_ASMDIR(code64) |
#endif |
DEF_ASMDIR(short) |
DEF_ASMDIR(long) |
DEF_ASMDIR(int) |
DEF_ASMDIR(section) /* must be last directive */ |
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 |
#include "i386-tok.h" |
DEF_ASM(byte) |
DEF_ASM(align) |
DEF_ASM(skip) |
DEF_ASM(space) |
DEF_ASM(string) |
DEF_ASM(asciz) |
DEF_ASM(ascii) |
DEF_ASM(globl) |
DEF_ASM(global) |
DEF_ASM(text) |
DEF_ASM(data) |
DEF_ASM(bss) |
DEF_ASM(previous) |
DEF_ASM(fill) |
DEF_ASM(org) |
DEF_ASM(quad) |
#ifdef TCC_TARGET_I386 |
/* WARNING: relative order of tokens is important. */ |
DEF_ASM(al) |
DEF_ASM(cl) |
DEF_ASM(dl) |
DEF_ASM(bl) |
DEF_ASM(ah) |
DEF_ASM(ch) |
DEF_ASM(dh) |
DEF_ASM(bh) |
DEF_ASM(ax) |
DEF_ASM(cx) |
DEF_ASM(dx) |
DEF_ASM(bx) |
DEF_ASM(sp) |
DEF_ASM(bp) |
DEF_ASM(si) |
DEF_ASM(di) |
DEF_ASM(eax) |
DEF_ASM(ecx) |
DEF_ASM(edx) |
DEF_ASM(ebx) |
DEF_ASM(esp) |
DEF_ASM(ebp) |
DEF_ASM(esi) |
DEF_ASM(edi) |
DEF_ASM(mm0) |
DEF_ASM(mm1) |
DEF_ASM(mm2) |
DEF_ASM(mm3) |
DEF_ASM(mm4) |
DEF_ASM(mm5) |
DEF_ASM(mm6) |
DEF_ASM(mm7) |
DEF_ASM(xmm0) |
DEF_ASM(xmm1) |
DEF_ASM(xmm2) |
DEF_ASM(xmm3) |
DEF_ASM(xmm4) |
DEF_ASM(xmm5) |
DEF_ASM(xmm6) |
DEF_ASM(xmm7) |
DEF_ASM(cr0) |
DEF_ASM(cr1) |
DEF_ASM(cr2) |
DEF_ASM(cr3) |
DEF_ASM(cr4) |
DEF_ASM(cr5) |
DEF_ASM(cr6) |
DEF_ASM(cr7) |
DEF_ASM(tr0) |
DEF_ASM(tr1) |
DEF_ASM(tr2) |
DEF_ASM(tr3) |
DEF_ASM(tr4) |
DEF_ASM(tr5) |
DEF_ASM(tr6) |
DEF_ASM(tr7) |
DEF_ASM(db0) |
DEF_ASM(db1) |
DEF_ASM(db2) |
DEF_ASM(db3) |
DEF_ASM(db4) |
DEF_ASM(db5) |
DEF_ASM(db6) |
DEF_ASM(db7) |
DEF_ASM(dr0) |
DEF_ASM(dr1) |
DEF_ASM(dr2) |
DEF_ASM(dr3) |
DEF_ASM(dr4) |
DEF_ASM(dr5) |
DEF_ASM(dr6) |
DEF_ASM(dr7) |
DEF_ASM(es) |
DEF_ASM(cs) |
DEF_ASM(ss) |
DEF_ASM(ds) |
DEF_ASM(fs) |
DEF_ASM(gs) |
DEF_ASM(st) |
DEF_BWL(mov) |
/* generic two operands */ |
DEF_BWL(add) |
DEF_BWL(or) |
DEF_BWL(adc) |
DEF_BWL(sbb) |
DEF_BWL(and) |
DEF_BWL(sub) |
DEF_BWL(xor) |
DEF_BWL(cmp) |
/* unary ops */ |
DEF_BWL(inc) |
DEF_BWL(dec) |
DEF_BWL(not) |
DEF_BWL(neg) |
DEF_BWL(mul) |
DEF_BWL(imul) |
DEF_BWL(div) |
DEF_BWL(idiv) |
DEF_BWL(xchg) |
DEF_BWL(test) |
/* shifts */ |
DEF_BWL(rol) |
DEF_BWL(ror) |
DEF_BWL(rcl) |
DEF_BWL(rcr) |
DEF_BWL(shl) |
DEF_BWL(shr) |
DEF_BWL(sar) |
DEF_ASM(shldw) |
DEF_ASM(shldl) |
DEF_ASM(shld) |
DEF_ASM(shrdw) |
DEF_ASM(shrdl) |
DEF_ASM(shrd) |
DEF_ASM(pushw) |
DEF_ASM(pushl) |
DEF_ASM(push) |
DEF_ASM(popw) |
DEF_ASM(popl) |
DEF_ASM(pop) |
DEF_BWL(in) |
DEF_BWL(out) |
DEF_WL(movzb) |
DEF_ASM(movzwl) |
DEF_ASM(movsbw) |
DEF_ASM(movsbl) |
DEF_ASM(movswl) |
DEF_WL(lea) |
DEF_ASM(les) |
DEF_ASM(lds) |
DEF_ASM(lss) |
DEF_ASM(lfs) |
DEF_ASM(lgs) |
DEF_ASM(call) |
DEF_ASM(jmp) |
DEF_ASM(lcall) |
DEF_ASM(ljmp) |
DEF_ASMTEST(j) |
DEF_ASMTEST(set) |
DEF_ASMTEST(cmov) |
DEF_WL(bsf) |
DEF_WL(bsr) |
DEF_WL(bt) |
DEF_WL(bts) |
DEF_WL(btr) |
DEF_WL(btc) |
DEF_WL(lsl) |
/* generic FP ops */ |
DEF_FP(add) |
DEF_FP(mul) |
DEF_ASM(fcom) |
DEF_ASM(fcom_1) /* non existant op, just to have a regular table */ |
DEF_FP1(com) |
DEF_FP(comp) |
DEF_FP(sub) |
DEF_FP(subr) |
DEF_FP(div) |
DEF_FP(divr) |
DEF_BWL(xadd) |
DEF_BWL(cmpxchg) |
/* string ops */ |
DEF_BWL(cmps) |
DEF_BWL(scmp) |
DEF_BWL(ins) |
DEF_BWL(outs) |
DEF_BWL(lods) |
DEF_BWL(slod) |
DEF_BWL(movs) |
DEF_BWL(smov) |
DEF_BWL(scas) |
DEF_BWL(ssca) |
DEF_BWL(stos) |
DEF_BWL(ssto) |
/* generic asm ops */ |
#define ALT(x) |
#define DEF_ASM_OP0(name, opcode) DEF_ASM(name) |
#define DEF_ASM_OP0L(name, opcode, group, instr_type) |
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) |
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) |
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) |
#include "i386-asm.h" |
#define ALT(x) |
#define DEF_ASM_OP0(name, opcode) |
#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name) |
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name) |
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name) |
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name) |
#include "i386-asm.h" |
#endif |
/programs/develop/ktcc/trunk/source/tiny_impdef.c |
---|
0,0 → 1,372 |
/* -------------------------------------------------------------- */ |
/* |
"tiny_impdef creates a .def file from a dll" |
"Usage: tiny_impdef [-p] <library.dll> [-o outputfile]" |
"Options:" |
" -p print to stdout" |
*/ |
#include <windows.h> |
#include <stdio.h> |
/* Offset to PE file signature */ |
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + \ |
((PIMAGE_DOS_HEADER)a)->e_lfanew)) |
/* MS-OS header identifies the NT PEFile signature dword; |
the PEFILE header exists just after that dword. */ |
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + \ |
((PIMAGE_DOS_HEADER)a)->e_lfanew + \ |
SIZE_OF_NT_SIGNATURE)) |
/* PE optional header is immediately after PEFile header. */ |
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \ |
((PIMAGE_DOS_HEADER)a)->e_lfanew + \ |
SIZE_OF_NT_SIGNATURE + \ |
sizeof (IMAGE_FILE_HEADER))) |
/* Section headers are immediately after PE optional header. */ |
#define SECHDROFFSET(a) ((LPVOID)((BYTE *)a + \ |
((PIMAGE_DOS_HEADER)a)->e_lfanew + \ |
SIZE_OF_NT_SIGNATURE + \ |
sizeof (IMAGE_FILE_HEADER) + \ |
sizeof (IMAGE_OPTIONAL_HEADER))) |
#define SIZE_OF_NT_SIGNATURE 4 |
/* -------------------------------------------------------------- */ |
int WINAPI NumOfSections ( |
LPVOID lpFile) |
{ |
/* Number of sections is indicated in file header. */ |
return (int) |
((PIMAGE_FILE_HEADER) |
PEFHDROFFSET(lpFile))->NumberOfSections; |
} |
/* -------------------------------------------------------------- */ |
LPVOID WINAPI ImageDirectoryOffset ( |
LPVOID lpFile, |
DWORD dwIMAGE_DIRECTORY) |
{ |
PIMAGE_OPTIONAL_HEADER poh; |
PIMAGE_SECTION_HEADER psh; |
int nSections = NumOfSections (lpFile); |
int i = 0; |
LPVOID VAImageDir; |
/* Retrieve offsets to optional and section headers. */ |
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile); |
psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile); |
/* Must be 0 thru (NumberOfRvaAndSizes-1). */ |
if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes) |
return NULL; |
/* Locate image directory's relative virtual address. */ |
VAImageDir = (LPVOID)poh->DataDirectory |
[dwIMAGE_DIRECTORY].VirtualAddress; |
/* Locate section containing image directory. */ |
while (i++<nSections) |
{ |
if (psh->VirtualAddress <= (DWORD)VAImageDir |
&& psh->VirtualAddress + psh->SizeOfRawData > (DWORD)VAImageDir) |
break; |
psh++; |
} |
if (i > nSections) |
return NULL; |
/* Return image import directory offset. */ |
return (LPVOID)(((int)lpFile + |
(int)VAImageDir - psh->VirtualAddress) + |
(int)psh->PointerToRawData); |
} |
/* -------------------------------------------------------------- */ |
BOOL WINAPI GetSectionHdrByName ( |
LPVOID lpFile, |
IMAGE_SECTION_HEADER *sh, |
char *szSection) |
{ |
PIMAGE_SECTION_HEADER psh; |
int nSections = NumOfSections (lpFile); |
int i; |
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != |
NULL) |
{ |
/* find the section by name */ |
for (i=0; i<nSections; i++) |
{ |
if (!strcmp (psh->Name, szSection)) |
{ |
/* copy data to header */ |
memcpy ((LPVOID)sh, |
(LPVOID)psh, |
sizeof (IMAGE_SECTION_HEADER)); |
return TRUE; |
} |
else |
psh++; |
} |
} |
return FALSE; |
} |
/* -------------------------------------------------------------- */ |
BOOL WINAPI GetSectionHdrByAddress ( |
LPVOID lpFile, |
IMAGE_SECTION_HEADER *sh, |
DWORD addr) |
{ |
PIMAGE_SECTION_HEADER psh; |
int nSections = NumOfSections (lpFile); |
int i; |
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != |
NULL) |
{ |
/* find the section by name */ |
for (i=0; i<nSections; i++) |
{ |
if (addr >= psh->VirtualAddress && addr < psh->VirtualAddress + psh->SizeOfRawData) |
{ |
/* copy data to header */ |
memcpy ((LPVOID)sh, |
(LPVOID)psh, |
sizeof (IMAGE_SECTION_HEADER)); |
return TRUE; |
} |
else |
psh++; |
} |
} |
return FALSE; |
} |
/* -------------------------------------------------------------- */ |
int WINAPI GetExportFunctionNames ( |
LPVOID lpFile, |
HANDLE hHeap, |
char **pszFunctions) |
{ |
IMAGE_SECTION_HEADER sh; |
PIMAGE_EXPORT_DIRECTORY ped; |
int *pNames, *pCnt; |
char *pSrc, *pDest; |
int i, nCnt; |
DWORD VAImageDir; |
PIMAGE_OPTIONAL_HEADER poh; |
char *pOffset; |
/* Get section header and pointer to data directory |
for .edata section. */ |
if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset |
(lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)) == NULL) |
return 0; |
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile); |
VAImageDir = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; |
if (FALSE == GetSectionHdrByAddress (lpFile, &sh, VAImageDir)) return 0; |
pOffset = (char *)lpFile + (sh.PointerToRawData - sh.VirtualAddress); |
pNames = (int *)(pOffset + (DWORD)ped->AddressOfNames); |
/* Figure out how much memory to allocate for all strings. */ |
nCnt = 1; |
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++) |
{ |
pSrc = (pOffset + *pCnt++); |
if (pSrc) nCnt += strlen(pSrc)+1; |
} |
/* Allocate memory off heap for function names. */ |
pDest = *pszFunctions = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt); |
/* Copy all strings to buffer. */ |
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++) |
{ |
pSrc = (pOffset + *pCnt++); |
if (pSrc) { strcpy(pDest, pSrc); pDest += strlen(pSrc)+1; } |
} |
*pDest = 0; |
return ped->NumberOfNames; |
} |
/* -------------------------------------------------------------- */ |
int main(int argc, char **argv) |
{ |
HANDLE hHeap; HANDLE hFile; HANDLE hMapObject; VOID *pMem; |
int nCnt, ret, argind, std; |
char *pNames; |
char infile[MAX_PATH]; |
char buffer[MAX_PATH]; |
char outfile[MAX_PATH]; |
char libname[80]; |
hHeap = NULL; |
hFile = NULL; |
hMapObject = NULL; |
pMem = NULL; |
infile[0] = 0; |
outfile[0] = 0; |
ret = 0; |
std = 0; |
for (argind = 1; argind < argc; ++argind) |
{ |
const char *a = argv[argind]; |
if ('-' == a[0]) |
{ |
if (0 == strcmp(a, "-p")) |
std = 1; |
else |
if (0 == strcmp(a, "-o")) |
{ |
if (++argind == argc) goto usage; |
strcpy(outfile, argv[argind]); |
} |
else |
goto usage; |
} |
else |
if (0 == infile[0]) |
strcpy(infile, a); |
else |
goto usage; |
} |
if (0 == infile[0]) |
{ |
usage: |
fprintf(stderr, |
"tiny_impdef creates a .def file from a dll\n" |
"Usage: tiny_impdef [-p] <library.dll> [-o outputfile]\n" |
"Options:\n" |
" -p print to stdout\n" |
); |
error: |
ret = 1; |
goto the_end; |
} |
if (SearchPath(NULL, infile, ".dll", sizeof buffer, buffer, NULL)) |
strcpy(infile, buffer); |
if (0 == outfile[0]) |
{ |
char *p; |
p = strrchr(strcpy(outfile, infile), '\\'); |
if (NULL == p) |
p = strrchr(outfile, '/'); |
if (p) strcpy(outfile, p+1); |
p = strrchr(outfile, '.'); |
if (NULL == p) p = strchr(outfile, 0); |
strcpy(p, ".def"); |
} |
hFile=CreateFile( |
infile, |
GENERIC_READ, |
FILE_SHARE_READ, |
NULL, |
OPEN_EXISTING, |
0, |
NULL |
); |
if (hFile == INVALID_HANDLE_VALUE) |
{ |
fprintf(stderr, "file not found: %s\n", infile); |
goto error; |
} |
if (!std) printf("--> %s\n", infile); |
hMapObject = CreateFileMapping( |
hFile, |
NULL, |
PAGE_READONLY, |
0, 0, |
NULL |
); |
if (NULL == hMapObject) |
{ |
fprintf(stderr, "could not create file mapping.\n"); |
goto error; |
} |
pMem = MapViewOfFile( |
hMapObject, // object to map view of |
FILE_MAP_READ, // read access |
0, // high offset: map from |
0, // low offset: beginning |
0); // default: map entire file |
if (NULL == pMem) |
{ |
fprintf(stderr, "could not map view of file.\n"); |
goto error; |
} |
hHeap = GetProcessHeap(); |
nCnt = GetExportFunctionNames(pMem, hHeap, &pNames); |
{ |
FILE *op; char *p; int n; |
if (!std) printf("<-- %s\n", outfile); |
if (std) |
op = stdout; |
else |
op = fopen(outfile, "wt"); |
if (NULL == op) |
{ |
fprintf(stderr, "could not create file: %s\n", outfile); |
goto error; |
} |
p = strrchr(infile, '\\'); |
if (NULL == p) |
p = strrchr(infile, '/'); |
if (NULL == p) p = infile; else ++p; |
fprintf(op, "LIBRARY %s\n\nEXPORTS", p); |
if (std) fprintf(op, " (%d)", nCnt); |
fprintf(op, "\n"); |
for (n = 0, p = pNames; n < nCnt; ++n) |
{ |
fprintf(op, "%s\n", p); |
while (*p++); |
} |
if (!std) fclose(op); |
} |
the_end: |
if (pMem) UnmapViewOfFile(pMem); |
if (hMapObject) CloseHandle(hMapObject); |
if (hFile) CloseHandle(hFile); |
return ret; |
} |
/* -------------------------------------------------------------- */ |
/programs/develop/ktcc/trunk/source/varargs.h |
---|
0,0 → 1,11 |
#ifndef _VARARGS_H |
#define _VARARGS_H |
#include <stdarg.h> |
#define va_dcl |
#define va_alist __va_alist |
#undef va_start |
#define va_start(ap) ap = __builtin_varargs_start |
#endif |
/programs/develop/ktcc/trunk/readme.txt |
---|
1,4 → 1,12 |
see |
source/readme.* |
source/changelog |
source/tcc-doc.info or .texi |
The main file of metcc is "tcc.c". It certainly can be compiled by MinGW Studio. |
In order to compile MenuetOS program you must have start.o, metcc.exe in the same |
directory. The command line should be of type "metcc.exe program.c melibc.a -oprogram". |
In order to compile "melibc.a" you should configure paths is compile.js and run it. |
------------------------------------------------------------------------------------ |
Äëÿ êîìïèëÿöèè melibc íåîáõîäèìî çàïóñòèòü ñêðèïò libc/make.cmd |
ïî óìîë÷àíèþ ñ÷èòàåòñÿ ÷òî â ïåðåìåííîé îêðóæåíèÿ PATH ó âàñ óêàçàí ïóòü ê ïàêåòó mingw32 |
è ê àññåìáëåðó fasm. |
------------------------------------------------------------------------------------ |
Äëÿ áîëåå ïîäðîáíûõ èíñòðóêöèé îáðàùàòåñü íà ôîðóì â òåìó |
http://meos.sysbin.com/viewtopic.php?t=565&highlight=metcc |
For more help go to link above |