2 * TCC - Tiny C Compiler - Support for -run switch
4 * Copyright (c) 2001-2004 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 /* only native compiler supports -run */
26 #ifdef CONFIG_TCC_BACKTRACE
27 typedef struct rt_context
29 /* --> tccelf.c:tcc_add_btstub wants those below in that order: */
30 Stab_Sym
*stab_sym
, *stab_sym_end
;
32 ElfW(Sym
) *esym_start
, *esym_end
;
36 struct rt_context
*next
;
45 static rt_context g_rtctxt
;
46 static void set_exception_handler(void);
47 static int _rt_error(void *fp
, void *ip
, const char *fmt
, va_list ap
);
48 static void rt_exit(int code
);
49 #endif /* CONFIG_TCC_BACKTRACE */
51 /* defined when included from lib/bt-exe.c */
52 #ifndef CONFIG_TCC_BACKTRACE_ONLY
55 # include <sys/mman.h>
58 static void set_pages_executable(TCCState
*s1
, void *ptr
, unsigned long length
);
59 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
);
62 static void *win64_add_function_table(TCCState
*s1
);
63 static void win64_del_function_table(void *);
67 # define PAGESIZE 4096
70 /* ------------------------------------------------------------- */
71 /* Do all relocations (needed before using tcc_get_symbol())
72 Returns -1 on error. */
74 LIBTCCAPI
int tcc_relocate(TCCState
*s1
, void *ptr
)
79 if (TCC_RELOCATE_AUTO
!= ptr
)
80 return tcc_relocate_ex(s1
, ptr
, 0);
82 size
= tcc_relocate_ex(s1
, NULL
, 0);
88 /* Using mmap instead of malloc */
90 char tmpfname
[] = "/tmp/.tccrunXXXXXX";
91 int fd
= mkstemp(tmpfname
);
95 size
= (size
+ (PAGESIZE
-1)) & ~(PAGESIZE
-1);
96 ptr
= mmap(NULL
, size
* 2, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
97 /* mmap RX memory at a fixed distance */
98 prx
= mmap((char*)ptr
+ size
, size
, PROT_READ
|PROT_EXEC
, MAP_SHARED
|MAP_FIXED
, fd
, 0);
99 if (ptr
== MAP_FAILED
|| prx
== MAP_FAILED
)
100 tcc_error("tccrun: could not map memory");
101 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, (void*)(addr_t
)(size
*2));
102 ptr_diff
= (char*)prx
- (char*)ptr
;
104 //printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff);
107 ptr
= tcc_malloc(size
);
109 tcc_relocate_ex(s1
, ptr
, ptr_diff
); /* no more errors expected */
110 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, ptr
);
114 ST_FUNC
void tcc_run_free(TCCState
*s1
)
118 for (i
= 0; i
< s1
->nb_runtime_mem
; ++i
) {
120 unsigned size
= (unsigned)(addr_t
)s1
->runtime_mem
[i
++];
121 munmap(s1
->runtime_mem
[i
], size
);
124 win64_del_function_table(*(void**)s1
->runtime_mem
[i
]);
126 tcc_free(s1
->runtime_mem
[i
]);
129 tcc_free(s1
->runtime_mem
);
132 static void run_cdtors(TCCState
*s1
, const char *start
, const char *end
,
133 int argc
, char **argv
, char **envp
)
135 void **a
= (void **)get_sym_addr(s1
, start
, 0, 0);
136 void **b
= (void **)get_sym_addr(s1
, end
, 0, 0);
138 ((void(*)(int, char **, char **))*a
++)(argc
, argv
, envp
);
141 /* launch the compiled program with the given arguments */
142 LIBTCCAPI
int tcc_run(TCCState
*s1
, int argc
, char **argv
)
144 int (*prog_main
)(int, char **, char **), ret
;
145 #ifdef CONFIG_TCC_BACKTRACE
146 rt_context
*rc
= &g_rtctxt
;
149 #if defined(__APPLE__) || defined(__FreeBSD__)
151 #elif defined(__OpenBSD__) || defined(__NetBSD__)
152 extern char **environ
;
153 char **envp
= environ
;
155 char **envp
= environ
;
158 s1
->runtime_main
= s1
->nostdlib
? "_start" : "main";
159 if ((s1
->dflag
& 16) && (addr_t
)-1 == get_sym_addr(s1
, s1
->runtime_main
, 0, 1))
161 #ifdef CONFIG_TCC_BACKTRACE
163 tcc_add_symbol(s1
, "exit", rt_exit
);
165 if (tcc_relocate(s1
, TCC_RELOCATE_AUTO
) < 0)
167 prog_main
= (void*)get_sym_addr(s1
, s1
->runtime_main
, 1, 1);
169 #ifdef CONFIG_TCC_BACKTRACE
170 memset(rc
, 0, sizeof *rc
);
173 rc
->stab_sym
= (Stab_Sym
*)stab_section
->data
;
174 rc
->stab_sym_end
= (Stab_Sym
*)(stab_section
->data
+ stab_section
->data_offset
);
175 rc
->stab_str
= (char *)stab_section
->link
->data
;
176 rc
->esym_start
= (ElfW(Sym
) *)(symtab_section
->data
);
177 rc
->esym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
178 rc
->elf_str
= (char *)symtab_section
->link
->data
;
180 rc
->prog_base
= text_section
->sh_addr
& 0xffffffff00000000ULL
;
182 rc
->top_func
= tcc_get_symbol(s1
, "main");
183 rc
->num_callers
= s1
->rt_num_callers
;
185 if ((p
= tcc_get_symbol(s1
, "__rt_error")))
186 *(void**)p
= _rt_error
;
187 #ifdef CONFIG_TCC_BCHECK
188 if (s1
->do_bounds_check
) {
189 if ((p
= tcc_get_symbol(s1
, "__bound_init")))
190 ((void(*)(void*, int))p
)(bounds_section
->data
, 1);
193 set_exception_handler();
197 errno
= 0; /* clean errno value */
200 /* These aren't C symbols, so don't need leading underscore handling. */
201 run_cdtors(s1
, "__init_array_start", "__init_array_end", argc
, argv
, envp
);
202 #ifdef CONFIG_TCC_BACKTRACE
203 if (!rc
->do_jmp
|| !(ret
= setjmp(rc
->jmp_buf)))
206 ret
= prog_main(argc
, argv
, envp
);
208 run_cdtors(s1
, "__fini_array_start", "__fini_array_end", 0, NULL
, NULL
);
209 if ((s1
->dflag
& 16) && ret
)
210 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
214 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
215 /* To avoid that x86 processors would reload cached instructions
216 each time when data is written in the near, we need to make
217 sure that code and data do not share the same 64 byte unit */
218 #define RUN_SECTION_ALIGNMENT 63
220 #define RUN_SECTION_ALIGNMENT 0
223 /* relocate code. Return -1 on error, required size if ptr is NULL,
224 otherwise copy code into buffer passed by the caller */
225 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
)
228 unsigned offset
, length
, align
, max_align
, i
, k
, f
;
234 pe_output_file(s1
, NULL
);
237 resolve_common_syms(s1
);
238 build_got_entries(s1
);
244 offset
= max_align
= 0, mem
= (addr_t
)ptr
;
246 offset
+= sizeof (void*); /* space for function_table pointer */
248 for (k
= 0; k
< 2; ++k
) {
249 f
= 0, addr
= k
? mem
: mem
+ ptr_diff
;
250 for(i
= 1; i
< s1
->nb_sections
; i
++) {
252 if (0 == (s
->sh_flags
& SHF_ALLOC
))
254 if (k
!= !(s
->sh_flags
& SHF_EXECINSTR
))
256 align
= s
->sh_addralign
- 1;
257 if (++f
== 1 && align
< RUN_SECTION_ALIGNMENT
)
258 align
= RUN_SECTION_ALIGNMENT
;
259 if (max_align
< align
)
261 offset
+= -(addr
+ offset
) & align
;
262 s
->sh_addr
= mem
? addr
+ offset
: 0;
263 offset
+= s
->data_offset
;
266 printf("%-16s %p len %04x align %2d\n",
267 s
->name
, (void*)s
->sh_addr
, (unsigned)s
->data_offset
, align
+ 1);
272 /* relocate symbols */
273 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
278 return offset
+ max_align
;
281 s1
->pe_imagebase
= mem
;
284 /* relocate each section */
285 for(i
= 1; i
< s1
->nb_sections
; i
++) {
288 relocate_section(s1
, s
);
290 #if !defined(TCC_TARGET_PE) || defined(TCC_TARGET_MACHO)
294 for(i
= 1; i
< s1
->nb_sections
; i
++) {
296 if (0 == (s
->sh_flags
& SHF_ALLOC
))
298 length
= s
->data_offset
;
299 ptr
= (void*)s
->sh_addr
;
300 if (s
->sh_flags
& SHF_EXECINSTR
)
301 ptr
= (char*)((addr_t
)ptr
- ptr_diff
);
302 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
303 memset(ptr
, 0, length
);
305 memcpy(ptr
, s
->data
, length
);
306 /* mark executable sections as executable in memory */
307 if (s
->sh_flags
& SHF_EXECINSTR
)
308 set_pages_executable(s1
, (char*)((addr_t
)ptr
+ ptr_diff
), length
);
312 *(void**)mem
= win64_add_function_table(s1
);
318 /* ------------------------------------------------------------- */
319 /* allow to run code in memory */
321 static void set_pages_executable(TCCState
*s1
, void *ptr
, unsigned long length
)
324 unsigned long old_protect
;
325 VirtualProtect(ptr
, length
, PAGE_EXECUTE_READWRITE
, &old_protect
);
327 void __clear_cache(void *beginning
, void *end
);
328 # ifndef HAVE_SELINUX
330 start
= (addr_t
)ptr
& ~(PAGESIZE
- 1);
331 end
= (addr_t
)ptr
+ length
;
332 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
333 if (mprotect((void *)start
, end
- start
, PROT_READ
| PROT_WRITE
| PROT_EXEC
))
334 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
336 # if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
337 __clear_cache(ptr
, (char *)ptr
+ length
);
343 static void *win64_add_function_table(TCCState
*s1
)
347 p
= (void*)s1
->uw_pdata
->sh_addr
;
349 (RUNTIME_FUNCTION
*)p
,
350 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
358 static void win64_del_function_table(void *p
)
361 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
365 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
366 /* ------------------------------------------------------------- */
367 #ifdef CONFIG_TCC_BACKTRACE
369 static int rt_vprintf(const char *fmt
, va_list ap
)
371 int ret
= vfprintf(stderr
, fmt
, ap
);
376 static int rt_printf(const char *fmt
, ...)
381 r
= rt_vprintf(fmt
, ap
);
386 #define INCLUDE_STACK_SIZE 32
388 /* print the position in the source file of PC value 'pc' by reading
389 the stabs debug information */
390 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
,
391 const char *msg
, const char *skip
)
394 addr_t func_addr
, last_pc
, pc
;
395 const char *incl_files
[INCLUDE_STACK_SIZE
];
396 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
405 last_pc
= (addr_t
)-1;
409 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
410 str
= rc
->stab_str
+ sym
->n_strx
;
413 switch(sym
->n_type
) {
421 if (sym
->n_strx
== 0) /* end of function */
425 /* Stab_Sym.n_value is only 32bits */
432 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
437 switch(sym
->n_type
) {
438 /* function start or end */
440 if (sym
->n_strx
== 0)
442 p
= strchr(str
, ':');
443 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
444 len
= sizeof func_name
;
445 pstrcpy(func_name
, len
, str
);
448 /* line number info */
451 last_line_num
= sym
->n_desc
;
452 last_incl_index
= incl_index
;
456 if (incl_index
< INCLUDE_STACK_SIZE
)
457 incl_files
[incl_index
++] = str
;
463 /* start/end of translation unit */
467 /* do not add path */
469 if (len
> 0 && str
[len
- 1] != '/')
470 incl_files
[incl_index
++] = str
;
475 last_pc
= (addr_t
)-1;
477 /* alternative file name (from #line or #include directives) */
480 incl_files
[incl_index
-1] = str
;
489 /* we try symtab symbols (no line number info) */
490 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
491 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
492 if (type
== STT_FUNC
|| type
== STT_GNU_IFUNC
) {
493 if (wanted_pc
>= esym
->st_value
&&
494 wanted_pc
< esym
->st_value
+ esym
->st_size
) {
495 pstrcpy(func_name
, sizeof(func_name
),
496 rc
->elf_str
+ esym
->st_name
);
497 func_addr
= esym
->st_value
;
509 str
= incl_files
[--i
];
510 if (skip
[0] && strstr(str
, skip
))
512 rt_printf("%s:%d: ", str
, last_line_num
);
514 rt_printf("%08llx : ", (long long)wanted_pc
);
515 rt_printf("%s %s", msg
, func_name
[0] ? func_name
: "???");
518 rt_printf(" (included from ");
520 rt_printf("%s", incl_files
[i
]);
531 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
);
533 static int _rt_error(void *fp
, void *ip
, const char *fmt
, va_list ap
)
535 rt_context
*rc
= &g_rtctxt
;
538 int i
, level
, ret
, n
;
539 const char *a
, *b
, *msg
;
542 /* we're called from tcc_backtrace. */
547 /* we're called from signal/exception handler */
548 msg
= "RUNTIME ERROR: ";
552 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
553 if (fmt
[0] == '^' && (b
= strchr(a
= fmt
+ 1, fmt
[0]))) {
554 memcpy(skip
, a
, b
- a
), skip
[b
- a
] = 0;
558 n
= rc
->num_callers
? rc
->num_callers
: 6;
559 for (i
= level
= 0; level
< n
; i
++) {
560 ret
= rt_get_caller_pc(&pc
, rc
, i
);
563 pc
= rt_printline(rc
, pc
, level
? "by" : "at", skip
);
564 if (pc
== (addr_t
)-1)
571 } else if (ret
== -1)
574 if (ret
== -1 || (pc
== (addr_t
)rc
->top_func
&& pc
))
583 /* emit a run time error at position 'pc' */
584 static int rt_error(const char *fmt
, ...)
589 ret
= _rt_error(0, 0, fmt
, ap
);
594 static void rt_exit(int code
)
596 rt_context
*rc
= &g_rtctxt
;
598 longjmp(rc
->jmp_buf, code
? code
: 256);
602 /* ------------------------------------------------------------- */
607 # include <sys/ucontext.h>
610 # define ucontext_t CONTEXT
613 /* translate from ucontext_t* to internal rt_context * */
614 static void rt_getcontext(ucontext_t
*uc
, rt_context
*rc
)
624 #elif defined __i386__
625 # if defined(__APPLE__)
626 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
627 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
628 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
629 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
630 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
631 # elif defined(__dietlibc__)
632 rc
->ip
= uc
->uc_mcontext
.eip
;
633 rc
->fp
= uc
->uc_mcontext
.ebp
;
634 # elif defined(__NetBSD__)
635 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
636 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
637 # elif defined(__OpenBSD__)
640 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
641 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
642 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
644 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
645 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
647 #elif defined(__x86_64__)
648 # if defined(__APPLE__)
649 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
650 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
651 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
652 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
653 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
654 # elif defined(__NetBSD__)
655 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
656 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
657 # elif defined(__OpenBSD__)
661 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
662 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
664 #elif defined(__arm__)
665 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
666 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
667 #elif defined(__aarch64__) && defined(__FreeBSD__)
668 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
669 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
670 #elif defined(__aarch64__) && defined(__NetBSD__)
671 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
672 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
673 #elif defined(__aarch64__)
674 rc
->ip
= uc
->uc_mcontext
.pc
;
675 rc
->fp
= uc
->uc_mcontext
.regs
[29];
676 #elif defined(__riscv)
677 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
678 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
682 /* ------------------------------------------------------------- */
684 /* signal handler for fatal errors */
685 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
687 rt_context
*rc
= &g_rtctxt
;
688 rt_getcontext(puc
, rc
);
692 switch(siginf
->si_code
) {
695 rt_error("division by zero");
698 rt_error("floating point exception");
704 rt_error("invalid memory access");
707 rt_error("illegal instruction");
710 rt_error("abort() called");
713 rt_error("caught signal %d", signum
);
720 # define SA_SIGINFO 0x00000004u
723 /* Generate a stack backtrace when a CPU exception occurs. */
724 static void set_exception_handler(void)
726 struct sigaction sigact
;
727 /* install TCC signal handlers to print debug info on fatal
729 sigact
.sa_flags
= SA_SIGINFO
| SA_RESETHAND
;
730 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
731 sigact
.sa_flags
|= SA_ONSTACK
;
733 sigact
.sa_sigaction
= sig_error
;
734 sigemptyset(&sigact
.sa_mask
);
735 sigaction(SIGFPE
, &sigact
, NULL
);
736 sigaction(SIGILL
, &sigact
, NULL
);
737 sigaction(SIGSEGV
, &sigact
, NULL
);
738 sigaction(SIGBUS
, &sigact
, NULL
);
739 sigaction(SIGABRT
, &sigact
, NULL
);
741 /* This allows stack overflow to be reported instead of a SEGV */
744 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
747 ss
.ss_size
= SIGSTKSZ
;
749 sigaltstack(&ss
, NULL
);
756 /* signal handler for fatal errors */
757 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
759 rt_context
*rc
= &g_rtctxt
;
761 rt_getcontext(ex_info
->ContextRecord
, rc
);
763 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
764 case EXCEPTION_ACCESS_VIOLATION
:
765 rt_error("invalid memory access");
767 case EXCEPTION_STACK_OVERFLOW
:
768 rt_error("stack overflow");
770 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
771 rt_error("division by zero");
773 case EXCEPTION_BREAKPOINT
:
774 case EXCEPTION_SINGLE_STEP
:
775 rc
->ip
= *(addr_t
*)rc
->sp
;
776 rt_error("breakpoint/single-step exception:");
777 return EXCEPTION_CONTINUE_SEARCH
;
779 rt_error("caught exception %08x", code
);
784 return EXCEPTION_EXECUTE_HANDLER
;
787 /* Generate a stack backtrace when a CPU exception occurs. */
788 static void set_exception_handler(void)
790 SetUnhandledExceptionFilter(cpu_exception_handler
);
795 /* ------------------------------------------------------------- */
796 /* return the PC at frame level 'level'. Return negative if not found */
797 #if defined(__i386__) || defined(__x86_64__)
798 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
807 /* XXX: check address validity with program info */
810 fp
= ((addr_t
*)fp
)[0];
813 ip
= ((addr_t
*)fp
)[1];
821 #elif defined(__arm__)
822 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
824 /* XXX: only supports linux */
825 #if !defined(__linux__)
833 fp
= ((addr_t
*)fp
)[0];
834 *paddr
= ((addr_t
*)fp
)[2];
840 #elif defined(__aarch64__)
841 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
846 addr_t
*fp
= (addr_t
*)rc
->fp
;
848 fp
= (addr_t
*)fp
[0];
854 #elif defined(__riscv)
855 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
860 addr_t
*fp
= (addr_t
*)rc
->fp
;
861 while (--level
&& fp
>= (addr_t
*)0x1000)
862 fp
= (addr_t
*)fp
[-2];
863 if (fp
< (addr_t
*)0x1000)
871 #warning add arch specific rt_get_caller_pc()
872 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
878 #endif /* CONFIG_TCC_BACKTRACE */
879 /* ------------------------------------------------------------- */
880 #ifdef CONFIG_TCC_STATIC
882 /* dummy function for profiling */
883 ST_FUNC
void *dlopen(const char *filename
, int flag
)
888 ST_FUNC
void dlclose(void *p
)
892 ST_FUNC
const char *dlerror(void)
897 typedef struct TCCSyms
{
903 /* add the symbol you want here if no dynamic linking is done */
904 static TCCSyms tcc_syms
[] = {
905 #if !defined(CONFIG_TCCBOOT)
906 #define TCCSYM(a) { #a, &a, },
916 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
920 while (p
->str
!= NULL
) {
921 if (!strcmp(p
->str
, symbol
))
928 #endif /* CONFIG_TCC_STATIC */
929 #endif /* TCC_IS_NATIVE */
930 /* ------------------------------------------------------------- */