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 *);
66 /* ------------------------------------------------------------- */
67 /* Do all relocations (needed before using tcc_get_symbol())
68 Returns -1 on error. */
70 LIBTCCAPI
int tcc_relocate(TCCState
*s1
, void *ptr
)
75 if (TCC_RELOCATE_AUTO
!= ptr
)
76 return tcc_relocate_ex(s1
, ptr
, 0);
78 size
= tcc_relocate_ex(s1
, NULL
, 0);
84 /* Using mmap instead of malloc */
86 char tmpfname
[] = "/tmp/.tccrunXXXXXX";
87 int fd
= mkstemp(tmpfname
);
91 size
= (size
+ (PAGESIZE
-1)) & ~(PAGESIZE
-1);
92 ptr
= mmap(NULL
, size
* 2, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
93 /* mmap RX memory at a fixed distance */
94 prx
= mmap((char*)ptr
+ size
, size
, PROT_READ
|PROT_EXEC
, MAP_SHARED
|MAP_FIXED
, fd
, 0);
95 if (ptr
== MAP_FAILED
|| prx
== MAP_FAILED
)
96 tcc_error("tccrun: could not map memory");
97 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, (void*)(addr_t
)(size
*2));
98 ptr_diff
= (char*)prx
- (char*)ptr
;
100 //printf("map %p %p %p\n", ptr, prx, (void*)ptr_diff);
103 ptr
= tcc_malloc(size
);
105 tcc_relocate_ex(s1
, ptr
, ptr_diff
); /* no more errors expected */
106 dynarray_add(&s1
->runtime_mem
, &s1
->nb_runtime_mem
, ptr
);
110 ST_FUNC
void tcc_run_free(TCCState
*s1
)
114 for (i
= 0; i
< s1
->nb_runtime_mem
; ++i
) {
116 unsigned size
= (unsigned)(addr_t
)s1
->runtime_mem
[i
++];
117 munmap(s1
->runtime_mem
[i
], size
);
120 win64_del_function_table(*(void**)s1
->runtime_mem
[i
]);
122 tcc_free(s1
->runtime_mem
[i
]);
125 tcc_free(s1
->runtime_mem
);
128 static void run_cdtors(TCCState
*s1
, const char *start
, const char *end
,
129 int argc
, char **argv
, char **envp
)
131 void **a
= (void **)get_sym_addr(s1
, start
, 0, 0);
132 void **b
= (void **)get_sym_addr(s1
, end
, 0, 0);
134 ((void(*)(int, char **, char **))*a
++)(argc
, argv
, envp
);
137 /* launch the compiled program with the given arguments */
138 LIBTCCAPI
int tcc_run(TCCState
*s1
, int argc
, char **argv
)
140 int (*prog_main
)(int, char **, char **), ret
;
141 #ifdef CONFIG_TCC_BACKTRACE
142 rt_context
*rc
= &g_rtctxt
;
145 #if defined(__APPLE__) || defined(__FreeBSD__)
147 #elif defined(__OpenBSD__) || defined(__NetBSD__)
148 extern char **environ
;
149 char **envp
= environ
;
151 char **envp
= environ
;
154 s1
->runtime_main
= s1
->nostdlib
? "_start" : "main";
155 if ((s1
->dflag
& 16) && (addr_t
)-1 == get_sym_addr(s1
, s1
->runtime_main
, 0, 1))
157 #ifdef CONFIG_TCC_BACKTRACE
159 tcc_add_symbol(s1
, "exit", rt_exit
);
161 if (tcc_relocate(s1
, TCC_RELOCATE_AUTO
) < 0)
163 prog_main
= (void*)get_sym_addr(s1
, s1
->runtime_main
, 1, 1);
165 #ifdef CONFIG_TCC_BACKTRACE
166 memset(rc
, 0, sizeof *rc
);
169 rc
->stab_sym
= (Stab_Sym
*)stab_section
->data
;
170 rc
->stab_sym_end
= (Stab_Sym
*)(stab_section
->data
+ stab_section
->data_offset
);
171 rc
->stab_str
= (char *)stab_section
->link
->data
;
172 rc
->esym_start
= (ElfW(Sym
) *)(symtab_section
->data
);
173 rc
->esym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
174 rc
->elf_str
= (char *)symtab_section
->link
->data
;
176 rc
->prog_base
= text_section
->sh_addr
& 0xffffffff00000000ULL
;
178 rc
->top_func
= tcc_get_symbol(s1
, "main");
179 rc
->num_callers
= s1
->rt_num_callers
;
181 if ((p
= tcc_get_symbol(s1
, "__rt_error")))
182 *(void**)p
= _rt_error
;
183 #ifdef CONFIG_TCC_BCHECK
184 if (s1
->do_bounds_check
) {
185 if ((p
= tcc_get_symbol(s1
, "__bound_init")))
186 ((void(*)(addr_t
, int))p
)(bounds_section
->sh_addr
, 1);
189 set_exception_handler();
193 errno
= 0; /* clean errno value */
196 /* These aren't C symbols, so don't need leading underscore handling. */
197 run_cdtors(s1
, "__init_array_start", "__init_array_end", argc
, argv
, envp
);
198 #ifdef CONFIG_TCC_BACKTRACE
199 if (!rc
->do_jmp
|| !(ret
= setjmp(rc
->jmp_buf)))
202 ret
= prog_main(argc
, argv
, envp
);
204 run_cdtors(s1
, "__fini_array_start", "__fini_array_end", 0, NULL
, NULL
);
205 if ((s1
->dflag
& 16) && ret
)
206 fprintf(s1
->ppfp
, "[returns %d]\n", ret
), fflush(s1
->ppfp
);
210 #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
211 /* To avoid that x86 processors would reload cached instructions
212 each time when data is written in the near, we need to make
213 sure that code and data do not share the same 64 byte unit */
214 #define RUN_SECTION_ALIGNMENT 63
216 #define RUN_SECTION_ALIGNMENT 0
219 /* relocate code. Return -1 on error, required size if ptr is NULL,
220 otherwise copy code into buffer passed by the caller */
221 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
, addr_t ptr_diff
)
224 unsigned offset
, length
, align
, max_align
, i
, k
, f
;
230 pe_output_file(s1
, NULL
);
233 resolve_common_syms(s1
);
234 build_got_entries(s1
);
240 offset
= max_align
= 0, mem
= (addr_t
)ptr
;
242 offset
+= sizeof (void*); /* space for function_table pointer */
244 for (k
= 0; k
< 2; ++k
) {
245 f
= 0, addr
= k
? mem
: mem
+ ptr_diff
;
246 for(i
= 1; i
< s1
->nb_sections
; i
++) {
248 if (0 == (s
->sh_flags
& SHF_ALLOC
))
250 if (k
!= !(s
->sh_flags
& SHF_EXECINSTR
))
252 align
= s
->sh_addralign
- 1;
253 if (++f
== 1 && align
< RUN_SECTION_ALIGNMENT
)
254 align
= RUN_SECTION_ALIGNMENT
;
255 if (max_align
< align
)
257 offset
+= -(addr
+ offset
) & align
;
258 s
->sh_addr
= mem
? addr
+ offset
: 0;
259 offset
+= s
->data_offset
;
262 printf("%-16s %p len %04x align %2d\n",
263 s
->name
, (void*)s
->sh_addr
, (unsigned)s
->data_offset
, align
+ 1);
268 /* relocate symbols */
269 relocate_syms(s1
, s1
->symtab
, !(s1
->nostdlib
));
274 return offset
+ max_align
;
277 s1
->pe_imagebase
= mem
;
280 /* relocate each section */
281 for(i
= 1; i
< s1
->nb_sections
; i
++) {
284 relocate_section(s1
, s
);
286 #if !defined(TCC_TARGET_PE) || defined(TCC_TARGET_MACHO)
290 for(i
= 1; i
< s1
->nb_sections
; i
++) {
292 if (0 == (s
->sh_flags
& SHF_ALLOC
))
294 length
= s
->data_offset
;
295 ptr
= (void*)s
->sh_addr
;
296 if (s
->sh_flags
& SHF_EXECINSTR
)
297 ptr
= (char*)((addr_t
)ptr
- ptr_diff
);
298 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
299 memset(ptr
, 0, length
);
301 memcpy(ptr
, s
->data
, length
);
302 /* mark executable sections as executable in memory */
303 if (s
->sh_flags
& SHF_EXECINSTR
)
304 set_pages_executable(s1
, (char*)((addr_t
)ptr
+ ptr_diff
), length
);
308 *(void**)mem
= win64_add_function_table(s1
);
314 /* ------------------------------------------------------------- */
315 /* allow to run code in memory */
317 static void set_pages_executable(TCCState
*s1
, void *ptr
, unsigned long length
)
320 unsigned long old_protect
;
321 VirtualProtect(ptr
, length
, PAGE_EXECUTE_READWRITE
, &old_protect
);
323 void __clear_cache(void *beginning
, void *end
);
324 # ifndef HAVE_SELINUX
326 start
= (addr_t
)ptr
& ~(PAGESIZE
- 1);
327 end
= (addr_t
)ptr
+ length
;
328 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
329 if (mprotect((void *)start
, end
- start
, PROT_READ
| PROT_WRITE
| PROT_EXEC
))
330 tcc_error("mprotect failed: did you mean to configure --with-selinux?");
332 /* XXX: BSD sometimes dump core with bad system call */
333 # if (defined(TCC_TARGET_ARM) && \
334 !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)) || \
335 defined(TCC_TARGET_ARM64)
336 __clear_cache(ptr
, (char *)ptr
+ length
);
342 static void *win64_add_function_table(TCCState
*s1
)
346 p
= (void*)s1
->uw_pdata
->sh_addr
;
348 (RUNTIME_FUNCTION
*)p
,
349 s1
->uw_pdata
->data_offset
/ sizeof (RUNTIME_FUNCTION
),
357 static void win64_del_function_table(void *p
)
360 RtlDeleteFunctionTable((RUNTIME_FUNCTION
*)p
);
364 #endif //ndef CONFIG_TCC_BACKTRACE_ONLY
365 /* ------------------------------------------------------------- */
366 #ifdef CONFIG_TCC_BACKTRACE
368 static int rt_vprintf(const char *fmt
, va_list ap
)
370 int ret
= vfprintf(stderr
, fmt
, ap
);
375 static int rt_printf(const char *fmt
, ...)
380 r
= rt_vprintf(fmt
, ap
);
385 #define INCLUDE_STACK_SIZE 32
387 /* print the position in the source file of PC value 'pc' by reading
388 the stabs debug information */
389 static addr_t
rt_printline (rt_context
*rc
, addr_t wanted_pc
,
390 const char *msg
, const char *skip
)
393 addr_t func_addr
, last_pc
, pc
;
394 const char *incl_files
[INCLUDE_STACK_SIZE
];
395 int incl_index
, last_incl_index
, len
, last_line_num
, i
;
404 last_pc
= (addr_t
)-1;
408 for (sym
= rc
->stab_sym
+ 1; sym
< rc
->stab_sym_end
; ++sym
) {
409 str
= rc
->stab_str
+ sym
->n_strx
;
412 switch(sym
->n_type
) {
420 if (sym
->n_strx
== 0) /* end of function */
424 /* Stab_Sym.n_value is only 32bits */
431 if (pc
>= wanted_pc
&& wanted_pc
>= last_pc
)
436 switch(sym
->n_type
) {
437 /* function start or end */
439 if (sym
->n_strx
== 0)
441 p
= strchr(str
, ':');
442 if (0 == p
|| (len
= p
- str
+ 1, len
> sizeof func_name
))
443 len
= sizeof func_name
;
444 pstrcpy(func_name
, len
, str
);
447 /* line number info */
450 last_line_num
= sym
->n_desc
;
451 last_incl_index
= incl_index
;
455 if (incl_index
< INCLUDE_STACK_SIZE
)
456 incl_files
[incl_index
++] = str
;
462 /* start/end of translation unit */
466 /* do not add path */
468 if (len
> 0 && str
[len
- 1] != '/')
469 incl_files
[incl_index
++] = str
;
474 last_pc
= (addr_t
)-1;
476 /* alternative file name (from #line or #include directives) */
479 incl_files
[incl_index
-1] = str
;
488 /* we try symtab symbols (no line number info) */
489 for (esym
= rc
->esym_start
+ 1; esym
< rc
->esym_end
; ++esym
) {
490 int type
= ELFW(ST_TYPE
)(esym
->st_info
);
491 if (type
== STT_FUNC
|| type
== STT_GNU_IFUNC
) {
492 if (wanted_pc
>= esym
->st_value
&&
493 wanted_pc
< esym
->st_value
+ esym
->st_size
) {
494 pstrcpy(func_name
, sizeof(func_name
),
495 rc
->elf_str
+ esym
->st_name
);
496 func_addr
= esym
->st_value
;
508 str
= incl_files
[--i
];
509 if (skip
[0] && strstr(str
, skip
))
511 rt_printf("%s:%d: ", str
, last_line_num
);
513 rt_printf("%08llx : ", (long long)wanted_pc
);
514 rt_printf("%s %s", msg
, func_name
[0] ? func_name
: "???");
517 rt_printf(" (included from ");
519 rt_printf("%s", incl_files
[i
]);
530 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
);
532 static int _rt_error(void *fp
, void *ip
, const char *fmt
, va_list ap
)
534 rt_context
*rc
= &g_rtctxt
;
537 int i
, level
, ret
, n
;
538 const char *a
, *b
, *msg
;
541 /* we're called from tcc_backtrace. */
546 /* we're called from signal/exception handler */
547 msg
= "RUNTIME ERROR: ";
551 /* If fmt is like "^file.c^..." then skip calls from 'file.c' */
552 if (fmt
[0] == '^' && (b
= strchr(a
= fmt
+ 1, fmt
[0]))) {
553 memcpy(skip
, a
, b
- a
), skip
[b
- a
] = 0;
557 n
= rc
->num_callers
? rc
->num_callers
: 6;
558 for (i
= level
= 0; level
< n
; i
++) {
559 ret
= rt_get_caller_pc(&pc
, rc
, i
);
562 pc
= rt_printline(rc
, pc
, level
? "by" : "at", skip
);
563 if (pc
== (addr_t
)-1)
570 } else if (ret
== -1)
573 if (ret
== -1 || (pc
== (addr_t
)rc
->top_func
&& pc
))
582 /* emit a run time error at position 'pc' */
583 static int rt_error(const char *fmt
, ...)
588 ret
= _rt_error(0, 0, fmt
, ap
);
593 static void rt_exit(int code
)
595 rt_context
*rc
= &g_rtctxt
;
597 longjmp(rc
->jmp_buf, code
? code
: 256);
601 /* ------------------------------------------------------------- */
606 # include <sys/ucontext.h>
609 # define ucontext_t CONTEXT
612 /* translate from ucontext_t* to internal rt_context * */
613 static void rt_getcontext(ucontext_t
*uc
, rt_context
*rc
)
623 #elif defined __i386__
624 # if defined(__APPLE__)
625 rc
->ip
= uc
->uc_mcontext
->__ss
.__eip
;
626 rc
->fp
= uc
->uc_mcontext
->__ss
.__ebp
;
627 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
628 rc
->ip
= uc
->uc_mcontext
.mc_eip
;
629 rc
->fp
= uc
->uc_mcontext
.mc_ebp
;
630 # elif defined(__dietlibc__)
631 rc
->ip
= uc
->uc_mcontext
.eip
;
632 rc
->fp
= uc
->uc_mcontext
.ebp
;
633 # elif defined(__NetBSD__)
634 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_EIP
];
635 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_EBP
];
636 # elif defined(__OpenBSD__)
639 # elif !defined REG_EIP && defined EIP /* fix for glibc 2.1 */
640 rc
->ip
= uc
->uc_mcontext
.gregs
[EIP
];
641 rc
->fp
= uc
->uc_mcontext
.gregs
[EBP
];
643 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_EIP
];
644 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
646 #elif defined(__x86_64__)
647 # if defined(__APPLE__)
648 rc
->ip
= uc
->uc_mcontext
->__ss
.__rip
;
649 rc
->fp
= uc
->uc_mcontext
->__ss
.__rbp
;
650 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
651 rc
->ip
= uc
->uc_mcontext
.mc_rip
;
652 rc
->fp
= uc
->uc_mcontext
.mc_rbp
;
653 # elif defined(__NetBSD__)
654 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_RIP
];
655 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_RBP
];
656 # elif defined(__OpenBSD__)
660 rc
->ip
= uc
->uc_mcontext
.gregs
[REG_RIP
];
661 rc
->fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
663 #elif defined(__arm__) && defined(__NetBSD__)
664 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
665 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
666 #elif defined(__arm__) && defined(__OpenBSD__)
669 #elif defined(__arm__) && defined(__FreeBSD__)
670 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
671 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
672 #elif defined(__arm__)
673 rc
->ip
= uc
->uc_mcontext
.arm_pc
;
674 rc
->fp
= uc
->uc_mcontext
.arm_fp
;
675 #elif defined(__aarch64__) && defined(__FreeBSD__)
676 rc
->ip
= uc
->uc_mcontext
.mc_gpregs
.gp_elr
; /* aka REG_PC */
677 rc
->fp
= uc
->uc_mcontext
.mc_gpregs
.gp_x
[29];
678 #elif defined(__aarch64__) && defined(__NetBSD__)
679 rc
->ip
= uc
->uc_mcontext
.__gregs
[_REG_PC
];
680 rc
->fp
= uc
->uc_mcontext
.__gregs
[_REG_FP
];
681 #elif defined(__aarch64__) && defined(__OpenBSD__)
683 rc
->fp
= uc
->sc_x
[29];
684 #elif defined(__aarch64__)
685 rc
->ip
= uc
->uc_mcontext
.pc
;
686 rc
->fp
= uc
->uc_mcontext
.regs
[29];
687 #elif defined(__riscv)
688 rc
->ip
= uc
->uc_mcontext
.__gregs
[REG_PC
];
689 rc
->fp
= uc
->uc_mcontext
.__gregs
[REG_S0
];
693 /* ------------------------------------------------------------- */
695 /* signal handler for fatal errors */
696 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
698 rt_context
*rc
= &g_rtctxt
;
699 rt_getcontext(puc
, rc
);
703 switch(siginf
->si_code
) {
706 rt_error("division by zero");
709 rt_error("floating point exception");
715 rt_error("invalid memory access");
718 rt_error("illegal instruction");
721 rt_error("abort() called");
724 rt_error("caught signal %d", signum
);
731 # define SA_SIGINFO 0x00000004u
734 /* Generate a stack backtrace when a CPU exception occurs. */
735 static void set_exception_handler(void)
737 struct sigaction sigact
;
738 /* install TCC signal handlers to print debug info on fatal
740 sigemptyset (&sigact
.sa_mask
);
741 sigact
.sa_flags
= SA_SIGINFO
| SA_RESETHAND
;
742 #if 0//def SIGSTKSZ // this causes signals not to work at all on some (older) linuxes
743 sigact
.sa_flags
|= SA_ONSTACK
;
745 sigact
.sa_sigaction
= sig_error
;
746 sigemptyset(&sigact
.sa_mask
);
747 sigaction(SIGFPE
, &sigact
, NULL
);
748 sigaction(SIGILL
, &sigact
, NULL
);
749 sigaction(SIGSEGV
, &sigact
, NULL
);
750 sigaction(SIGBUS
, &sigact
, NULL
);
751 sigaction(SIGABRT
, &sigact
, NULL
);
753 /* This allows stack overflow to be reported instead of a SEGV */
756 static unsigned char stack
[SIGSTKSZ
] __attribute__((aligned(16)));
759 ss
.ss_size
= SIGSTKSZ
;
761 sigaltstack(&ss
, NULL
);
768 /* signal handler for fatal errors */
769 static long __stdcall
cpu_exception_handler(EXCEPTION_POINTERS
*ex_info
)
771 rt_context
*rc
= &g_rtctxt
;
773 rt_getcontext(ex_info
->ContextRecord
, rc
);
775 switch (code
= ex_info
->ExceptionRecord
->ExceptionCode
) {
776 case EXCEPTION_ACCESS_VIOLATION
:
777 rt_error("invalid memory access");
779 case EXCEPTION_STACK_OVERFLOW
:
780 rt_error("stack overflow");
782 case EXCEPTION_INT_DIVIDE_BY_ZERO
:
783 rt_error("division by zero");
785 case EXCEPTION_BREAKPOINT
:
786 case EXCEPTION_SINGLE_STEP
:
787 rc
->ip
= *(addr_t
*)rc
->sp
;
788 rt_error("breakpoint/single-step exception:");
789 return EXCEPTION_CONTINUE_SEARCH
;
791 rt_error("caught exception %08x", code
);
796 return EXCEPTION_EXECUTE_HANDLER
;
799 /* Generate a stack backtrace when a CPU exception occurs. */
800 static void set_exception_handler(void)
802 SetUnhandledExceptionFilter(cpu_exception_handler
);
807 /* ------------------------------------------------------------- */
808 /* return the PC at frame level 'level'. Return negative if not found */
809 #if defined(__i386__) || defined(__x86_64__)
810 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
819 /* XXX: check address validity with program info */
822 fp
= ((addr_t
*)fp
)[0];
825 ip
= ((addr_t
*)fp
)[1];
833 #elif defined(__arm__)
834 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
836 /* XXX: only supports linux/bsd */
837 #if !defined(__linux__) && \
838 !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
846 fp
= ((addr_t
*)fp
)[0];
847 *paddr
= ((addr_t
*)fp
)[2];
853 #elif defined(__aarch64__)
854 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
859 addr_t
*fp
= (addr_t
*)rc
->fp
;
861 fp
= (addr_t
*)fp
[0];
867 #elif defined(__riscv)
868 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
873 addr_t
*fp
= (addr_t
*)rc
->fp
;
874 while (--level
&& fp
>= (addr_t
*)0x1000)
875 fp
= (addr_t
*)fp
[-2];
876 if (fp
< (addr_t
*)0x1000)
884 #warning add arch specific rt_get_caller_pc()
885 static int rt_get_caller_pc(addr_t
*paddr
, rt_context
*rc
, int level
)
891 #endif /* CONFIG_TCC_BACKTRACE */
892 /* ------------------------------------------------------------- */
893 #ifdef CONFIG_TCC_STATIC
895 /* dummy function for profiling */
896 ST_FUNC
void *dlopen(const char *filename
, int flag
)
901 ST_FUNC
void dlclose(void *p
)
905 ST_FUNC
const char *dlerror(void)
910 typedef struct TCCSyms
{
916 /* add the symbol you want here if no dynamic linking is done */
917 static TCCSyms tcc_syms
[] = {
918 #if !defined(CONFIG_TCCBOOT)
919 #define TCCSYM(a) { #a, &a, },
929 ST_FUNC
void *dlsym(void *handle
, const char *symbol
)
933 while (p
->str
!= NULL
) {
934 if (!strcmp(p
->str
, symbol
))
941 #endif /* CONFIG_TCC_STATIC */
942 #endif /* TCC_IS_NATIVE */
943 /* ------------------------------------------------------------- */