2 * TCC - Tiny C Compiler
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
21 /* tccrun.c - support for tcc -run */
24 /********************************************************/
25 #ifdef CONFIG_TCC_STATIC
27 #define RTLD_LAZY 0x001
28 #define RTLD_NOW 0x002
29 #define RTLD_GLOBAL 0x100
30 #define RTLD_DEFAULT NULL
32 /* dummy function for profiling */
33 void *dlopen(const char *filename
, int flag
)
42 const char *dlerror(void)
47 typedef struct TCCSyms
{
52 #define TCCSYM(a) { #a, &a, },
54 /* add the symbol you want here if no dynamic linking is done */
55 static TCCSyms tcc_syms
[] = {
56 #if !defined(CONFIG_TCCBOOT)
65 void *resolve_sym(TCCState
*s1
, const char *symbol
)
69 while (p
->str
!= NULL
) {
70 if (!strcmp(p
->str
, symbol
))
78 #define dlclose FreeLibrary
83 void *resolve_sym(TCCState
*s1
, const char *sym
)
85 return dlsym(RTLD_DEFAULT
, sym
);
88 #endif /* defined CONFIG_TCC_STATIC */
90 /********************************************************/
92 #ifdef CONFIG_TCC_BACKTRACE
94 /* print the position in the source file of PC value 'pc' by reading
95 the stabs debug information */
96 static unsigned long rt_printline(unsigned long wanted_pc
)
98 Stab_Sym
*sym
, *sym_end
;
99 char func_name
[128], last_func_name
[128];
100 unsigned long func_addr
, last_pc
, pc
;
101 const char *incl_files
[INCLUDE_STACK_SIZE
];
102 int incl_index
, len
, last_line_num
, i
;
105 fprintf(stderr
, "0x%08lx:", wanted_pc
);
110 last_func_name
[0] = '\0';
111 last_pc
= 0xffffffff;
113 sym
= (Stab_Sym
*)stab_section
->data
+ 1;
114 sym_end
= (Stab_Sym
*)(stab_section
->data
+ stab_section
->data_offset
);
115 while (sym
< sym_end
) {
116 switch(sym
->n_type
) {
117 /* function start or end */
119 if (sym
->n_strx
== 0) {
120 /* we test if between last line and end of function */
121 pc
= sym
->n_value
+ func_addr
;
122 if (wanted_pc
>= last_pc
&& wanted_pc
< pc
)
127 str
= stabstr_section
->data
+ sym
->n_strx
;
128 p
= strchr(str
, ':');
130 pstrcpy(func_name
, sizeof(func_name
), str
);
133 if (len
> sizeof(func_name
) - 1)
134 len
= sizeof(func_name
) - 1;
135 memcpy(func_name
, str
, len
);
136 func_name
[len
] = '\0';
138 func_addr
= sym
->n_value
;
141 /* line number info */
143 pc
= sym
->n_value
+ func_addr
;
144 if (wanted_pc
>= last_pc
&& wanted_pc
< pc
)
147 last_line_num
= sym
->n_desc
;
149 strcpy(last_func_name
, func_name
);
153 str
= stabstr_section
->data
+ sym
->n_strx
;
155 if (incl_index
< INCLUDE_STACK_SIZE
) {
156 incl_files
[incl_index
++] = str
;
164 if (sym
->n_strx
== 0) {
165 incl_index
= 0; /* end of translation unit */
167 str
= stabstr_section
->data
+ sym
->n_strx
;
168 /* do not add path */
170 if (len
> 0 && str
[len
- 1] != '/')
178 /* second pass: we try symtab symbols (no line number info) */
181 ElfW(Sym
) *sym
, *sym_end
;
184 sym_end
= (ElfW(Sym
) *)(symtab_section
->data
+ symtab_section
->data_offset
);
185 for(sym
= (ElfW(Sym
) *)symtab_section
->data
+ 1;
188 type
= ELFW(ST_TYPE
)(sym
->st_info
);
189 if (type
== STT_FUNC
) {
190 if (wanted_pc
>= sym
->st_value
&&
191 wanted_pc
< sym
->st_value
+ sym
->st_size
) {
192 pstrcpy(last_func_name
, sizeof(last_func_name
),
193 strtab_section
->data
+ sym
->st_name
);
194 func_addr
= sym
->st_value
;
200 /* did not find any info: */
201 fprintf(stderr
, " ???\n");
204 if (last_func_name
[0] != '\0') {
205 fprintf(stderr
, " %s()", last_func_name
);
207 if (incl_index
> 0) {
208 fprintf(stderr
, " (%s:%d",
209 incl_files
[incl_index
- 1], last_line_num
);
210 for(i
= incl_index
- 2; i
>= 0; i
--)
211 fprintf(stderr
, ", included from %s", incl_files
[i
]);
212 fprintf(stderr
, ")");
214 fprintf(stderr
, "\n");
219 /* fix for glibc 2.1 */
225 /* return the PC at frame level 'level'. Return non zero if not found */
226 static int rt_get_caller_pc(unsigned long *paddr
,
227 ucontext_t
*uc
, int level
)
233 #if defined(__FreeBSD__)
234 *paddr
= uc
->uc_mcontext
.mc_eip
;
235 #elif defined(__dietlibc__)
236 *paddr
= uc
->uc_mcontext
.eip
;
238 *paddr
= uc
->uc_mcontext
.gregs
[REG_EIP
];
242 #if defined(__FreeBSD__)
243 fp
= uc
->uc_mcontext
.mc_ebp
;
244 #elif defined(__dietlibc__)
245 fp
= uc
->uc_mcontext
.ebp
;
247 fp
= uc
->uc_mcontext
.gregs
[REG_EBP
];
249 for(i
=1;i
<level
;i
++) {
250 /* XXX: check address validity with program info */
251 if (fp
<= 0x1000 || fp
>= 0xc0000000)
253 fp
= ((unsigned long *)fp
)[0];
255 *paddr
= ((unsigned long *)fp
)[1];
259 #elif defined(__x86_64__)
260 /* return the PC at frame level 'level'. Return non zero if not found */
261 static int rt_get_caller_pc(unsigned long *paddr
,
262 ucontext_t
*uc
, int level
)
268 /* XXX: only support linux */
269 #if defined(__FreeBSD__)
270 *paddr
= uc
->uc_mcontext
.mc_rip
;
272 *paddr
= uc
->uc_mcontext
.gregs
[REG_RIP
];
276 #if defined(__FreeBSD__)
277 fp
= uc
->uc_mcontext
.mc_rbp
;
279 fp
= uc
->uc_mcontext
.gregs
[REG_RBP
];
281 for(i
=1;i
<level
;i
++) {
282 /* XXX: check address validity with program info */
285 fp
= ((unsigned long *)fp
)[0];
287 *paddr
= ((unsigned long *)fp
)[1];
292 #warning add arch specific rt_get_caller_pc()
293 static int rt_get_caller_pc(unsigned long *paddr
,
294 ucontext_t
*uc
, int level
)
300 /* emit a run time error at position 'pc' */
301 void rt_error(ucontext_t
*uc
, const char *fmt
, ...)
308 fprintf(stderr
, "Runtime error: ");
309 vfprintf(stderr
, fmt
, ap
);
310 fprintf(stderr
, "\n");
311 for(i
=0;i
<num_callers
;i
++) {
312 if (rt_get_caller_pc(&pc
, uc
, i
) < 0)
315 fprintf(stderr
, "at ");
317 fprintf(stderr
, "by ");
318 pc
= rt_printline(pc
);
319 if (pc
== rt_prog_main
&& pc
)
326 /* signal handler for fatal errors */
327 static void sig_error(int signum
, siginfo_t
*siginf
, void *puc
)
329 ucontext_t
*uc
= puc
;
333 switch(siginf
->si_code
) {
336 rt_error(uc
, "division by zero");
339 rt_error(uc
, "floating point exception");
345 if (rt_bound_error_msg
&& *rt_bound_error_msg
)
346 rt_error(uc
, *rt_bound_error_msg
);
348 rt_error(uc
, "dereferencing invalid pointer");
351 rt_error(uc
, "illegal instruction");
354 rt_error(uc
, "abort() called");
357 rt_error(uc
, "caught signal %d", signum
);
363 #endif /* defined CONFIG_TCC_BACKTRACE */
365 /********************************************************/
367 void set_pages_executable(void *ptr
, unsigned long length
)
370 unsigned long old_protect
;
371 VirtualProtect(ptr
, length
, PAGE_EXECUTE_READWRITE
, &old_protect
);
373 unsigned long start
, end
;
374 start
= (unsigned long)ptr
& ~(PAGESIZE
- 1);
375 end
= (unsigned long)ptr
+ length
;
376 end
= (end
+ PAGESIZE
- 1) & ~(PAGESIZE
- 1);
377 mprotect((void *)start
, end
- start
, PROT_READ
| PROT_WRITE
| PROT_EXEC
);
381 /* relocate code. Return -1 on error, required size if ptr is NULL,
382 otherwise copy code into buffer passed by the caller */
383 static int tcc_relocate_ex(TCCState
*s1
, void *ptr
)
386 unsigned long offset
, length
;
390 if (0 == s1
->runtime_added
) {
391 s1
->runtime_added
= 1;
394 pe_output_file(s1
, NULL
);
397 relocate_common_syms();
398 tcc_add_linker_symbols(s1
);
399 build_got_entries(s1
);
405 offset
= 0, mem
= (uplong
)ptr
;
406 for(i
= 1; i
< s1
->nb_sections
; i
++) {
408 if (0 == (s
->sh_flags
& SHF_ALLOC
))
410 length
= s
->data_offset
;
411 s
->sh_addr
= mem
? (mem
+ offset
+ 15) & ~15 : 0;
412 offset
= (offset
+ length
+ 15) & ~15;
416 /* relocate symbols */
417 relocate_syms(s1
, 1);
421 #ifndef TCC_TARGET_PE
422 #ifdef TCC_TARGET_X86_64
423 s1
->runtime_plt_and_got_offset
= 0;
424 s1
->runtime_plt_and_got
= (char *)(mem
+ offset
);
425 /* double the size of the buffer for got and plt entries
426 XXX: calculate exact size for them? */
434 /* relocate each section */
435 for(i
= 1; i
< s1
->nb_sections
; i
++) {
438 relocate_section(s1
, s
);
441 for(i
= 1; i
< s1
->nb_sections
; i
++) {
443 if (0 == (s
->sh_flags
& SHF_ALLOC
))
445 length
= s
->data_offset
;
446 // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
447 ptr
= (void*)(uplong
)s
->sh_addr
;
448 if (NULL
== s
->data
|| s
->sh_type
== SHT_NOBITS
)
449 memset(ptr
, 0, length
);
451 memcpy(ptr
, s
->data
, length
);
452 /* mark executable sections as executable in memory */
453 if (s
->sh_flags
& SHF_EXECINSTR
)
454 set_pages_executable(ptr
, length
);
457 #ifndef TCC_TARGET_PE
458 #ifdef TCC_TARGET_X86_64
459 set_pages_executable(s1
->runtime_plt_and_got
,
460 s1
->runtime_plt_and_got_offset
);
466 /* Do all relocations (needed before using tcc_get_symbol())
467 Returns -1 on error. */
468 int tcc_relocate(TCCState
*s1
)
470 int ret
= tcc_relocate_ex(s1
, NULL
);
473 s1
->runtime_mem
= tcc_malloc(ret
);
474 return tcc_relocate_ex(s1
, s1
->runtime_mem
);
477 /* launch the compiled program with the given arguments */
478 int tcc_run(TCCState
*s1
, int argc
, char **argv
)
480 int (*prog_main
)(int, char **);
482 if (tcc_relocate(s1
) < 0)
485 prog_main
= tcc_get_symbol_err(s1
, "main");
488 #ifdef CONFIG_TCC_BACKTRACE
489 struct sigaction sigact
;
490 /* install TCC signal handlers to print debug info on fatal
492 sigact
.sa_flags
= SA_SIGINFO
| SA_RESETHAND
;
493 sigact
.sa_sigaction
= sig_error
;
494 sigemptyset(&sigact
.sa_mask
);
495 sigaction(SIGFPE
, &sigact
, NULL
);
496 sigaction(SIGILL
, &sigact
, NULL
);
497 sigaction(SIGSEGV
, &sigact
, NULL
);
498 sigaction(SIGBUS
, &sigact
, NULL
);
499 sigaction(SIGABRT
, &sigact
, NULL
);
501 error("debug mode not available");
505 #ifdef CONFIG_TCC_BCHECK
506 if (s1
->do_bounds_check
) {
507 void (*bound_init
)(void);
508 void (*bound_exit
)(void);
509 /* set error function */
510 rt_bound_error_msg
= tcc_get_symbol_err(s1
, "__bound_error_msg");
511 rt_prog_main
= (unsigned long)prog_main
;
512 /* XXX: use .init section so that it also work in binary ? */
513 bound_init
= tcc_get_symbol_err(s1
, "__bound_init");
514 bound_exit
= tcc_get_symbol_err(s1
, "__bound_exit");
516 ret
= (*prog_main
)(argc
, argv
);
520 return (*prog_main
)(argc
, argv
);
523 /********************************************************/