allow libtcc states to be used concurrently

This allows creation of TCCStates and operation with API
calls independently from each other, even from threads.

Frontend (option parsing/libtcc.c) and backend (linker/tccelf.c)
now depend only on the TCCState (s1) argument.

Compilation per se (tccpp.c, tccgen.c) is still using
globals for convenience.  There is only one entry point
to this section which is tcc_compile() which is protected
by a semaphore.

There are some hacks involved to avoid too many changes,
as well as some changes in order to avoid too many hacks ;)

The test libtcc_test_mt.c shows the feature.  Except this
new file the patch adds 87 lines overall.
mob
grischka 2019-12-11 00:37:18 +01:00
parent 6082dd62bb
commit 72729d8e36
29 changed files with 805 additions and 418 deletions

1
.gitignore vendored
View File

@ -50,6 +50,7 @@ tests/*.gcc
tests/*-cc*
tests/*-tcc*
tests/libtcc_test
tests/libtcc_test_mt
tests/asm-c-connect
tests/asm-c-connect-sep
tests/vla_test

View File

@ -31,7 +31,7 @@ ifdef CONFIG_WIN32
CFGWIN = -win
NATIVE_TARGET = $(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)
else
LIBS=-lm
LIBS=-lm -lpthread
ifneq ($(CONFIG_ldl),no)
LIBS+=-ldl
endif

View File

@ -16,7 +16,7 @@ ST_FUNC void gen_le32(int c);
/*************************************************************/
#else
/*************************************************************/
#define USING_GLOBALS
#include "tcc.h"
static void asm_error(void)

View File

@ -132,6 +132,7 @@ enum {
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
enum float_abi float_abi;

View File

@ -57,8 +57,6 @@ int code_reloc (int reloc_type)
case R_ARM_JUMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -97,8 +95,6 @@ int gotplt_entry_type (int reloc_type)
case R_ARM_GOT32:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -252,24 +248,24 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
int index;
uint8_t *p;
char *name, buf[1024];
Section *text_section;
Section *text;
name = (char *) symtab_section->link->data + sym->st_name;
text_section = s1->sections[sym->st_shndx];
text = 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,
text->data_offset + 1,
sym->st_size, sym->st_info, 0,
sym->st_shndx, buf);
to_thumb = 1;
val = text_section->data_offset + 1;
val = text->data_offset + 1;
rel->r_info = ELFW(R_INFO)(index, type);
/* Create a thumb stub function to switch to ARM mode */
put_elf_reloc(symtab_section, text_section,
text_section->data_offset + 4, R_ARM_JUMP24,
put_elf_reloc(symtab_section, text,
text->data_offset + 4, R_ARM_JUMP24,
sym_index);
p = section_ptr_add(text_section, 8);
p = section_ptr_add(text, 8);
write32le(p, 0x4778); /* bx pc */
write32le(p+2, 0x46c0); /* nop */
write32le(p+4, 0xeafffffe); /* b $sym */

View File

@ -43,6 +43,7 @@
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
#include <assert.h>

View File

@ -46,8 +46,6 @@ int code_reloc (int reloc_type)
case R_AARCH64_JUMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -79,8 +77,6 @@ int gotplt_entry_type (int reloc_type)
case R_AARCH64_LD64_GOT_LO12_NC:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}

View File

@ -111,6 +111,7 @@ enum {
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
ST_DATA const int reg_classes[NB_REGS] = {

View File

@ -39,8 +39,6 @@ int code_reloc (int reloc_type)
case R_C60_PLT32:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -64,8 +62,6 @@ int gotplt_entry_type (int reloc_type)
case R_C60_GOT32:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}

View File

@ -19,6 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define USING_GLOBALS
#include "tcc.h"
#define MAX_OPERANDS 3

View File

@ -74,6 +74,7 @@ enum {
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
/* define to 1/0 to [not] have EBX as 4th register */
@ -1030,7 +1031,8 @@ ST_FUNC void gen_cvt_ftoi(int t)
gfunc_call(1);
vpushi(0);
vtop->r = REG_IRET;
vtop->r2 = REG_LRET;
if ((t & VT_BTYPE) == VT_LLONG)
vtop->r2 = REG_LRET;
}
/* convert from one floating point type to another */

View File

@ -45,8 +45,6 @@ int code_reloc (int reloc_type)
case R_386_JMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -82,8 +80,6 @@ int gotplt_entry_type (int reloc_type)
case R_386_PLT32:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}

344
libtcc.c
View File

@ -18,25 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tcc.h"
/********************************************************/
/* global variables */
/* use GNU C extensions */
ST_DATA int gnu_ext = 1;
/* use TinyCC extensions */
ST_DATA int tcc_ext = 1;
/* XXX: get rid of this ASAP */
ST_DATA struct TCCState *tcc_state;
static int nb_states;
/********************************************************/
#if ONE_SOURCE
#if !defined ONE_SOURCE || ONE_SOURCE
#include "tccpp.c"
#include "tccgen.c"
#include "tccelf.c"
@ -74,17 +56,15 @@ static int nb_states;
#endif
#endif /* ONE_SOURCE */
#include "tcc.h"
/********************************************************/
#ifndef CONFIG_TCC_ASM
ST_FUNC void asm_instr(void)
{
tcc_error("inline asm() not supported");
}
ST_FUNC void asm_global_instr(void)
{
tcc_error("inline asm() not supported");
}
#endif
/* global variables */
/* XXX: get rid of this ASAP (or maybe not) */
ST_DATA struct TCCState *tcc_state;
static int nb_states;
/********************************************************/
#ifdef _WIN32
@ -130,6 +110,35 @@ BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
#endif
#endif
/********************************************************/
#ifndef CONFIG_TCC_SEMLOCK
#define WAIT_SEM()
#define POST_SEM()
#elif defined _WIN32
static int tcc_sem_init;
static CRITICAL_SECTION tcc_cr;
static void wait_sem(void)
{
if (!tcc_sem_init)
InitializeCriticalSection(&tcc_cr), tcc_sem_init = 1;
EnterCriticalSection(&tcc_cr);
}
#define WAIT_SEM() wait_sem()
#define POST_SEM() LeaveCriticalSection(&tcc_cr);
#else
#include <semaphore.h>
static int tcc_sem_init;
static sem_t tcc_sem;
static void wait_sem(void)
{
if (!tcc_sem_init)
sem_init(&tcc_sem, 0, 1), tcc_sem_init = 1;
while (sem_wait (&tcc_sem) < 0 && errno == EINTR);
}
#define WAIT_SEM() wait_sem()
#define POST_SEM() sem_post(&tcc_sem)
#endif
/********************************************************/
/* copy a string and truncate it. */
ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s)
@ -207,7 +216,7 @@ PUB_FUNC void *tcc_malloc(unsigned long size)
void *ptr;
ptr = malloc(size);
if (!ptr && size)
tcc_error("memory full (malloc)");
_tcc_error("memory full (malloc)");
return ptr;
}
@ -224,7 +233,7 @@ PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size)
void *ptr1;
ptr1 = realloc(ptr, size);
if (!ptr1 && size)
tcc_error("memory full (realloc)");
_tcc_error("memory full (realloc)");
return ptr1;
}
@ -293,7 +302,7 @@ PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line)
header = malloc(sizeof(mem_debug_header_t) + size);
if (!header)
tcc_error("memory full (malloc)");
_tcc_error("memory full (malloc)");
header->magic1 = MEM_DEBUG_MAGIC1;
header->magic2 = MEM_DEBUG_MAGIC2;
@ -353,7 +362,7 @@ PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file
mem_debug_chain_update = (header == mem_debug_chain);
header = realloc(header, sizeof(mem_debug_header_t) + size);
if (!header)
tcc_error("memory full (realloc)");
_tcc_error("memory full (realloc)");
header->size = size;
MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3;
if (header->next)
@ -474,10 +483,41 @@ static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
va_end(ap);
}
static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
#define ERROR_WARN 0
#define ERROR_NOABORT 1
#define ERROR_ERROR 2
PUB_FUNC void tcc_enter_state(TCCState *s1)
{
WAIT_SEM();
tcc_state = s1;
}
static void error1(int mode, const char *fmt, va_list ap)
{
char buf[2048];
BufferedFile **pf, *f;
TCCState *s1 = tcc_state;
/* 's1->error_set_jmp_enabled' means that we're called from
within the parser/generator and 'tcc_state' was already
set (i.e. not by the function above).
Otherwise, 's1 = NULL' means we're called because of severe
problems from tcc_malloc() which under normal conditions
should never happen. */
if (s1 && !s1->error_set_jmp_enabled) {
tcc_state = NULL;
POST_SEM();
}
if (mode == ERROR_WARN) {
if (s1->warn_none)
return;
if (s1->warn_error)
mode = ERROR_ERROR;
}
buf[0] = '\0';
/* use upper file if inline ":asm:" or token ":paste:" */
@ -497,15 +537,14 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
} else {
strcat_printf(buf, sizeof(buf), "tcc: ");
}
if (is_warning)
if (mode == ERROR_WARN)
strcat_printf(buf, sizeof(buf), "warning: ");
else
strcat_printf(buf, sizeof(buf), "error: ");
strcat_vprintf(buf, sizeof(buf), fmt, ap);
if (!s1->error_func) {
if (!s1 || !s1->error_func) {
/* default case: stderr */
if (s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
if (s1 && s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout)
/* print a newline during tcc -E */
printf("\n"), fflush(stdout);
fflush(stdout); /* flush -v output */
@ -514,8 +553,15 @@ static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
} else {
s1->error_func(s1->error_opaque, buf);
}
if (!is_warning || s1->warn_error)
s1->nb_errors++;
if (s1) {
if (mode != ERROR_WARN)
s1->nb_errors++;
if (mode != ERROR_ERROR)
return;
if (s1->error_set_jmp_enabled)
longjmp(s1->error_jmp_buf, 1);
}
exit(1);
}
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc error_func)
@ -535,43 +581,26 @@ LIBTCCAPI void *tcc_get_error_opaque(TCCState *s)
}
/* error without aborting current compilation */
PUB_FUNC void tcc_error_noabort(const char *fmt, ...)
PUB_FUNC void _tcc_error_noabort(const char *fmt, ...)
{
TCCState *s1 = tcc_state;
va_list ap;
va_start(ap, fmt);
error1(s1, 0, fmt, ap);
error1(ERROR_NOABORT, fmt, ap);
va_end(ap);
}
PUB_FUNC void tcc_error(const char *fmt, ...)
PUB_FUNC void _tcc_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);
}
for (;;) error1(ERROR_ERROR, fmt, ap);
}
PUB_FUNC void tcc_warning(const char *fmt, ...)
PUB_FUNC void _tcc_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);
error1(ERROR_WARN, fmt, ap);
va_end(ap);
}
@ -588,6 +617,9 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
bf->buf_end = bf->buffer + initlen;
bf->buf_end[0] = CH_EOB; /* put eob symbol */
pstrcpy(bf->filename, sizeof(bf->filename), filename);
#ifdef _WIN32
normalize_slashes(bf->filename);
#endif
bf->true_filename = bf->filename;
bf->line_num = 1;
bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
@ -610,7 +642,7 @@ ST_FUNC void tcc_close(void)
tcc_free(bf);
}
ST_FUNC int tcc_open(TCCState *s1, const char *filename)
static int _tcc_open(TCCState *s1, const char *filename)
{
int fd;
if (strcmp(filename, "-") == 0)
@ -620,30 +652,52 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3)
printf("%s %*s%s\n", fd < 0 ? "nf":"->",
(int)(s1->include_stack_ptr - s1->include_stack), "", filename);
if (fd < 0)
return -1;
tcc_open_bf(s1, filename, 0);
#ifdef _WIN32
normalize_slashes(file->filename);
#endif
file->fd = fd;
return fd;
}
/* compile the file opened in 'file'. Return non zero if errors. */
static int tcc_compile(TCCState *s1, int filetype)
ST_FUNC int tcc_open(TCCState *s1, const char *filename)
{
Sym *define_start;
int is_asm;
int fd = _tcc_open(s1, filename);
if (fd < 0)
return -1;
tcc_open_bf(s1, filename, 0);
file->fd = fd;
return 0;
}
define_start = define_stack;
is_asm = !!(filetype & (AFF_TYPE_ASM|AFF_TYPE_ASMPP));
/* compile the file opened in 'file'. Return non zero if errors. */
static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
{
tccelf_begin_file(s1);
if (setjmp(s1->error_jmp_buf) == 0) {
s1->nb_errors = 0;
s1->error_set_jmp_enabled = 1;
/* Here we enter the code section where we use the global variables for
parsing and code generation (tccpp.c, tccgen.c, <target>-gen.c).
Other threads need to wait until we're done.
Alternatively we could of course pass TCCState *s1 everwhere
except that it would look extremly ugly.
Alternatively we could use thread local storage for those global
variables, which may or may not have advantages */
WAIT_SEM();
tcc_state = s1;
if (setjmp(s1->error_jmp_buf) == 0) {
int is_asm;
s1->error_set_jmp_enabled = 1;
s1->nb_errors = 0;
if (fd == -1) {
int len = strlen(str);
tcc_open_bf(s1, "<string>", len);
memcpy(file->buffer, str, len);
} else {
tcc_open_bf(s1, str, 0);
file->fd = fd;
}
is_asm = !!(filetype & (AFF_TYPE_ASM|AFF_TYPE_ASMPP));
preprocess_start(s1, is_asm);
if (s1->output_type == TCC_OUTPUT_PREPROCESS) {
tcc_preprocess(s1);
@ -658,92 +712,49 @@ static int tcc_compile(TCCState *s1, int filetype)
}
}
s1->error_set_jmp_enabled = 0;
tccgen_finish(s1, 1);
preprocess_end(s1);
free_inline_functions(s1);
/* reset define stack, but keep -D and built-ins */
free_defines(define_start);
sym_pop(&global_stack, NULL, 0);
sym_pop(&local_stack, NULL, 0);
tccgen_finish(s1, 2);
tcc_state = NULL;
POST_SEM();
tccelf_end_file(s1);
return s1->nb_errors != 0 ? -1 : 0;
}
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
{
int len, ret;
len = strlen(str);
tcc_open_bf(s, "<string>", len);
memcpy(file->buffer, str, len);
ret = tcc_compile(s, s->filetype);
tcc_close();
return ret;
return tcc_compile(s, s->filetype, str, -1);
}
/* define a preprocessor symbol. A value can also be provided with the '=' operator */
LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
{
int len1, len2;
/* default value */
if (!value)
value = "1";
len1 = strlen(sym);
len2 = strlen(value);
/* init file structure */
tcc_open_bf(s1, "<define>", len1 + len2 + 1);
memcpy(file->buffer, sym, len1);
file->buffer[len1] = ' ';
memcpy(file->buffer + len1 + 1, value, len2);
/* parse with define parser */
next_nomacro();
parse_define();
tcc_close();
cstr_printf(&s1->cmdline_defs, "#define %s %s\n", sym, value);
}
/* undefine a preprocessor symbol */
LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym)
{
TokenSym *ts;
Sym *s;
ts = tok_alloc(sym, strlen(sym));
s = define_find(ts->tok);
if (s) {
define_undef(s);
tok_str_free_str(s->d);
s->d = NULL;
}
cstr_printf(&s1->cmdline_defs, "#undef %s\n", sym);
}
/* cleanup all static data used during compilation */
static void tcc_cleanup(void)
{
if (NULL == tcc_state)
return;
while (file)
tcc_close();
tccpp_delete(tcc_state);
tcc_state = NULL;
/* free sym_pools */
dynarray_reset(&sym_pools, &nb_sym_pools);
/* reset symbol stack */
sym_free_first = NULL;
}
LIBTCCAPI TCCState *tcc_new(void)
{
TCCState *s;
tcc_cleanup();
s = tcc_mallocz(sizeof(TCCState));
if (!s)
return NULL;
tcc_state = s;
++nb_states;
#undef gnu_ext
s->gnu_ext = 1;
s->tcc_ext = 1;
s->nocommon = 1;
s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/
s->cversion = 199901; /* default unless -std=c11 is supplied */
@ -760,21 +771,21 @@ LIBTCCAPI TCCState *tcc_new(void)
#if 0 /* def TCC_TARGET_PE */
s->leading_underscore = 1;
#endif
#ifdef CONFIG_TCC_BACKTRACE
s->rt_num_callers = 6;
#endif
s->ppfp = stdout;
/* might be used in error() before preprocess_start() */
s->include_stack_ptr = s->include_stack;
tccelf_new(s);
#ifdef _WIN32
tcc_set_lib_path_w32(s);
#else
tcc_set_lib_path(s, CONFIG_TCCDIR);
#endif
tccelf_new(s);
tccpp_new(s);
/* 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);
define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
{
/* define __TINYC__ 92X */
char buffer[32]; int a,b,c;
@ -916,8 +927,6 @@ LIBTCCAPI TCCState *tcc_new(void)
LIBTCCAPI void tcc_delete(TCCState *s1)
{
tcc_cleanup();
/* free sections */
tccelf_delete(s1);
@ -926,10 +935,8 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
dynarray_reset(&s1->crt_paths, &s1->nb_crt_paths);
/* free include paths */
dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes);
dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
dynarray_reset(&s1->cmd_include_files, &s1->nb_cmd_include_files);
tcc_free(s1->tcc_lib_path);
tcc_free(s1->soname);
@ -943,6 +950,8 @@ LIBTCCAPI void tcc_delete(TCCState *s1)
dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs);
dynarray_reset(&s1->argv, &s1->argc);
cstr_free(&s1->cmdline_defs);
cstr_free(&s1->cmdline_incl);
#ifdef TCC_IS_NATIVE
/* free runtime memory */
tcc_run_free(s1);
@ -1018,14 +1027,14 @@ LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
{
int ret;
int fd, ret;
/* open the file */
ret = tcc_open(s1, filename);
if (ret < 0) {
fd = _tcc_open(s1, filename);
if (fd < 0) {
if (flags & AFF_PRINT_ERROR)
tcc_error_noabort("file '%s' not found", filename);
return ret;
return -1;
}
/* update target deps */
@ -1034,9 +1043,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
if (flags & AFF_TYPE_BIN) {
ElfW(Ehdr) ehdr;
int fd, obj_type;
int obj_type;
fd = file->fd;
obj_type = tcc_object_type(fd, &ehdr);
lseek(fd, 0, SEEK_SET);
@ -1076,16 +1084,16 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
ret = pe_load_file(s1, filename, fd);
#else
/* as GNU ld, consider it is an ld script if not recognized */
ret = tcc_load_ldscript(s1);
ret = tcc_load_ldscript(s1, fd);
#endif
if (ret < 0)
tcc_error_noabort("unrecognized file type");
break;
}
close(fd);
} else {
ret = tcc_compile(s1, flags);
ret = tcc_compile(s1, flags, filename, fd);
}
tcc_close();
return ret;
}
@ -1141,10 +1149,10 @@ ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags)
}
#ifndef TCC_TARGET_PE
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename)
ST_FUNC int tcc_add_crt(TCCState *s1, const char *filename)
{
if (-1 == tcc_add_library_internal(s, "%s/%s",
filename, 0, s->crt_paths, s->nb_crt_paths))
if (-1 == tcc_add_library_internal(s1, "%s/%s",
filename, 0, s1->crt_paths, s1->nb_crt_paths))
tcc_error_noabort("file '%s' not found", filename);
return 0;
}
@ -1173,9 +1181,9 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
return -1;
}
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *libname)
PUB_FUNC int tcc_add_library_err(TCCState *s1, const char *libname)
{
int ret = tcc_add_library(s, libname);
int ret = tcc_add_library(s1, libname);
if (ret < 0)
tcc_error_noabort("library '%s' not found", libname);
return ret;
@ -1189,12 +1197,12 @@ ST_FUNC void tcc_add_pragma_libs(TCCState *s1)
tcc_add_library_err(s1, s1->pragma_libs[i]);
}
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val)
LIBTCCAPI int tcc_add_symbol(TCCState *s1, const char *name, const void *val)
{
#ifdef TCC_TARGET_PE
/* On x86_64 'val' might not be reachable with a 32bit offset.
So it is handled here as if it were in a DLL. */
pe_putimport(s, 0, name, (uintptr_t)val);
pe_putimport(s1, 0, name, (uintptr_t)val);
#else
set_elf_sym(symtab_section, (uintptr_t)val, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
@ -1346,6 +1354,7 @@ static void copy_linker_arg(char **pp, const char *s, int sep)
/* set linker options */
static int tcc_set_linker(TCCState *s, const char *option)
{
TCCState *s1 = s;
while (*option) {
const char *p = NULL;
@ -1663,6 +1672,7 @@ static int args_parser_make_argv(const char *r, int *argc, char ***argv)
static void args_parser_listfile(TCCState *s,
const char *filename, int optind, int *pargc, char ***pargv)
{
TCCState *s1 = s;
int fd, i;
size_t len;
char *p;
@ -1690,6 +1700,7 @@ static void args_parser_listfile(TCCState *s,
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
{
TCCState *s1 = s;
const TCCOption *popt;
const char *optarg, *r;
const char *run = NULL;
@ -1781,7 +1792,7 @@ reparse:
break;
#ifdef CONFIG_TCC_BACKTRACE
case TCC_OPTION_bt:
tcc_set_num_callers(atoi(optarg));
s->rt_num_callers = atoi(optarg);
break;
#endif
#ifdef CONFIG_TCC_BCHECK
@ -1909,8 +1920,7 @@ reparse:
tcc_add_sysinclude_path(s, optarg);
break;
case TCC_OPTION_include:
dynarray_add(&s->cmd_include_files,
&s->nb_cmd_include_files, tcc_strdup(optarg));
cstr_printf(&s->cmdline_defs, "#include \"%s\"\n", optarg);
break;
case TCC_OPTION_nostdinc:
s->nostdinc = 1;

View File

@ -28,6 +28,7 @@
#define CHAR_IS_UNSIGNED
#else
#define USING_GLOBALS
#include "tcc.h"
#include <assert.h>

View File

@ -53,7 +53,6 @@ int code_reloc (int reloc_type)
case R_RISCV_CALL_PLT:
return 1;
}
tcc_error ("Unknown relocation type in code_reloc: %d", reloc_type);
return -1;
}
@ -93,8 +92,6 @@ int gotplt_entry_type (int reloc_type)
case R_RISCV_GOT_HI20:
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}

8
tcc.c
View File

@ -250,7 +250,7 @@ static unsigned getclock_ms(void)
int main(int argc0, char **argv0)
{
TCCState *s;
TCCState *s, *s1;
int ret, opt, n = 0, t = 0;
unsigned start_time = 0;
const char *first_file;
@ -259,14 +259,14 @@ int main(int argc0, char **argv0)
redo:
argc = argc0, argv = argv0;
s = tcc_new();
s = s1 = tcc_new();
opt = tcc_parse_args(s, &argc, &argv, 1);
if ((n | t) == 0) {
if (opt == OPT_HELP)
return 0>fputs(help,stdout) || 0>fclose(stdout);
return fputs(help, stdout), 1;
if (opt == OPT_HELP2)
return 0>fputs(help2,stdout) || 0>fclose(stdout);
return fputs(help2, stdout), 1;
if (opt == OPT_M32 || opt == OPT_M64)
tcc_tool_cross(s, argv, opt); /* never returns */
if (s->verbose)

126
tcc.h
View File

@ -317,6 +317,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define ONE_SOURCE 1
#endif
/* support using libtcc from threads */
#define CONFIG_TCC_SEMLOCK
#if ONE_SOURCE
#define ST_INLN static inline
#define ST_FUNC static
@ -520,6 +523,7 @@ typedef struct Section {
unsigned long data_offset; /* current data offset */
unsigned char *data; /* section data */
unsigned long data_allocated; /* used for realloc() handling */
TCCState *s1;
int sh_name; /* elf section name (only used during output) */
int sh_num; /* elf section number */
int sh_type; /* elf section type */
@ -727,6 +731,11 @@ struct TCCState {
unsigned section_align; /* section alignment */
/* use GNU C extensions */
unsigned char gnu_ext;
/* use TinyCC extensions */
unsigned char tcc_ext;
char *init_symbol; /* symbols to call at load-time (not used currently) */
char *fini_symbol; /* symbols to call at unload-time (not used currently) */
@ -756,9 +765,10 @@ struct TCCState {
char **crt_paths;
int nb_crt_paths;
/* -include files */
char **cmd_include_files;
int nb_cmd_include_files;
/* -D / -U options */
CString cmdline_defs;
/* -include options */
CString cmdline_incl;
/* error handling */
void *error_opaque;
@ -815,6 +825,22 @@ struct TCCState {
Section *got;
Section *plt;
/* predefined sections */
Section *text_section, *data_section, *bss_section;
Section *common_section;
Section *cur_text_section; /* current section where function code is generated */
#ifdef CONFIG_TCC_BCHECK
/* bound check related sections */
Section *bounds_section; /* contains global data bound description */
Section *lbounds_section; /* contains local data bound description */
#endif
/* symbol sections */
Section *symtab_section;
/* debug sections */
Section *stab_section;
/* Is there a new undefined sym since last new_undef_sym() */
int new_undef_sym;
/* temporary dynamic symbol sections (for dll loading) */
Section *dynsymtab_section;
/* exported dynamic symbol section */
@ -857,7 +883,14 @@ struct TCCState {
const char *runtime_main;
void **runtime_mem;
int nb_runtime_mem;
#ifdef CONFIG_TCC_BACKTRACE
int rt_num_callers;
const char **rt_bound_error_msg;
void *rt_prog_main;
#endif
#endif
int fd, cc; /* used by tcc_load_ldscript */
/* used by main and tcc_parse_args only */
struct filespec **files; /* files seen on command line */
@ -1129,11 +1162,6 @@ enum tcc_token {
/* ------------ libtcc.c ------------ */
/* use GNU C extensions */
ST_DATA int gnu_ext;
/* use Tiny C extensions */
ST_DATA int tcc_ext;
/* XXX: get rid of this ASAP */
ST_DATA struct TCCState *tcc_state;
/* public functions currently used by the tcc main function */
@ -1168,9 +1196,9 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line);
#undef strdup
#define strdup(s) use_tcc_strdup(s)
PUB_FUNC void tcc_memcheck(void);
PUB_FUNC void tcc_error_noabort(const char *fmt, ...);
PUB_FUNC NORETURN void tcc_error(const char *fmt, ...);
PUB_FUNC void tcc_warning(const char *fmt, ...);
PUB_FUNC void _tcc_error_noabort(const char *fmt, ...);
PUB_FUNC NORETURN void _tcc_error(const char *fmt, ...);
PUB_FUNC void _tcc_warning(const char *fmt, ...);
/* other utilities */
ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data);
@ -1180,6 +1208,7 @@ ST_FUNC void cstr_cat(CString *cstr, const char *str, int len);
ST_FUNC void cstr_wccat(CString *cstr, int ch);
ST_FUNC void cstr_new(CString *cstr);
ST_FUNC void cstr_free(CString *cstr);
ST_FUNC int cstr_printf(CString *cs, const char *fmt, ...);
ST_FUNC void cstr_reset(CString *cstr);
ST_INLN void sym_free(Sym *sym);
@ -1327,9 +1356,6 @@ static inline int toup(int c) {
/* ------------ tccgen.c ------------ */
#define SYM_POOL_NB (8192 / sizeof(Sym))
ST_DATA Sym *sym_free_first;
ST_DATA void **sym_pools;
ST_DATA int nb_sym_pools;
ST_DATA Sym *global_stack;
ST_DATA Sym *local_stack;
@ -1358,7 +1384,7 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);
ST_FUNC void tcc_debug_line(TCCState *s1);
ST_FUNC int tccgen_compile(TCCState *s1);
ST_FUNC void free_inline_functions(TCCState *s);
ST_FUNC void tccgen_finish(TCCState *s1, int f);
ST_FUNC void check_vstack(void);
ST_INLN int is_float(int t);
@ -1427,29 +1453,14 @@ typedef struct {
unsigned int n_value; /* value of symbol */
} Stab_Sym;
ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
ST_DATA Section *common_section;
ST_DATA Section *cur_text_section; /* current section where function code is generated */
#ifdef CONFIG_TCC_ASM
ST_DATA Section *last_text_section; /* to handle .previous asm directive */
#endif
#ifdef CONFIG_TCC_BCHECK
/* bound check related sections */
ST_DATA Section *bounds_section; /* contains global data bound description */
ST_DATA Section *lbounds_section; /* contains local data bound description */
ST_FUNC void tccelf_bounds_new(TCCState *s);
#endif
/* symbol sections */
ST_DATA Section *symtab_section;
/* debug sections */
ST_DATA Section *stab_section, *stabstr_section;
ST_FUNC void tccelf_new(TCCState *s);
ST_FUNC void tccelf_delete(TCCState *s);
ST_FUNC void tccelf_stab_new(TCCState *s);
ST_FUNC void tccelf_begin_file(TCCState *s1);
ST_FUNC void tccelf_end_file(TCCState *s1);
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void tccelf_bounds_new(TCCState *s);
#endif
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
ST_FUNC size_t section_add(Section *sec, addr_t size, int align);
@ -1475,10 +1486,10 @@ ST_FUNC int find_elf_sym(Section *s, const char *name);
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol);
ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, addr_t addend);
ST_FUNC void put_stabs(const char *str, int type, int other, int desc, unsigned long value);
ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
ST_FUNC void put_stabn(int type, int other, int desc, int value);
ST_FUNC void put_stabd(int type, int other, int desc);
ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value);
ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value);
ST_FUNC void put_stabd(TCCState *s1, int type, int other, int desc);
ST_FUNC void resolve_common_syms(TCCState *s1);
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);
@ -1504,7 +1515,7 @@ ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
#ifndef TCC_TARGET_PE
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level);
ST_FUNC int tcc_load_ldscript(TCCState *s1);
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd);
ST_FUNC uint8_t *parse_comment(uint8_t *p);
ST_FUNC void minp(void);
ST_INLN void inp(void);
@ -1702,12 +1713,6 @@ ST_FUNC void dlclose(void *p);
ST_FUNC const char *dlerror(void);
ST_FUNC void *dlsym(void *handle, const char *symbol);
#endif
#ifdef CONFIG_TCC_BACKTRACE
ST_DATA int rt_num_callers;
ST_DATA const char **rt_bound_error_msg;
ST_DATA void *rt_prog_main;
ST_FUNC void tcc_set_num_callers(int n);
#endif
ST_FUNC void tcc_run_free(TCCState *s1);
#endif
@ -1728,5 +1733,38 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
#else
#define ST_DATA
#endif
/********************************************************/
#define text_section TCC_STATE_VAR(text_section)
#define data_section TCC_STATE_VAR(data_section)
#define bss_section TCC_STATE_VAR(bss_section)
#define common_section TCC_STATE_VAR(common_section)
#define cur_text_section TCC_STATE_VAR(cur_text_section)
#define bounds_section TCC_STATE_VAR(bounds_section)
#define lbounds_section TCC_STATE_VAR(lbounds_section)
#define symtab_section TCC_STATE_VAR(symtab_section)
#define stab_section TCC_STATE_VAR(stab_section)
#define stabstr_section stab_section->link
#define gnu_ext TCC_STATE_VAR(gnu_ext)
#define tcc_error_noabort TCC_SET_STATE(_tcc_error_noabort)
#define tcc_error TCC_SET_STATE(_tcc_error)
#define tcc_warning TCC_SET_STATE(_tcc_warning)
PUB_FUNC void tcc_enter_state(TCCState *s1);
/********************************************************/
#endif /* _TCC_H */
#undef TCC_STATE_VAR
#undef TCC_SET_STATE
#ifdef USING_GLOBALS
# define TCC_STATE_VAR(sym) tcc_state->sym
# define TCC_SET_STATE(fn) fn
# undef USING_GLOBALS
#else
# define TCC_STATE_VAR(sym) s1->sym
# define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn)
/* actually we could avoid the tcc_enter_state(s1) hack by using
__VA_ARGS__ except that some compiler doesn't support it. */
#endif

View File

@ -18,9 +18,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define USING_GLOBALS
#include "tcc.h"
#ifdef CONFIG_TCC_ASM
static Section *last_text_section; /* to handle .previous asm directive */
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
{
char buf[64];

View File

@ -40,12 +40,12 @@ int FuncEntries[MAX_FUNCS];
int OutputTheSection(Section * sect);
short int GetCoffFlags(const char *s);
void SortSymbolTable(void);
void SortSymbolTable(TCCState *s1);
Section *FindSection(TCCState * s1, const char *sname);
int C67_main_entry_point;
int FindCoffSymbolIndex(const char *func_name);
int FindCoffSymbolIndex(TCCState * s1, const char *func_name);
int nb_syms;
typedef struct {
@ -92,7 +92,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
sbss = FindSection(s1, ".bss");
nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym);
coff_nb_syms = FindCoffSymbolIndex("XXXXXXXXXX1");
coff_nb_syms = FindCoffSymbolIndex(s1, "XXXXXXXXXX1");
file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */
file_hdr.f_timdat = 0; /* time & date stamp */
@ -366,7 +366,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
// finally global symbols
if (s1->do_debug)
SortSymbolTable();
SortSymbolTable(s1);
// write line no data
@ -437,7 +437,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
// output a function begin
CoffLineNo.l_addr.l_symndx =
FindCoffSymbolIndex(func_name);
FindCoffSymbolIndex(s1, func_name);
CoffLineNo.l_lnno = 0;
fwrite(&CoffLineNo, 6, 1, f);
@ -690,7 +690,7 @@ ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
// group the symbols in order of filename, func1, func2, etc
// finally global symbols
void SortSymbolTable(void)
void SortSymbolTable(TCCState *s1)
{
int i, j, k, n = 0;
Elf32_Sym *p, *p2, *NewTable;
@ -770,7 +770,7 @@ void SortSymbolTable(void)
}
int FindCoffSymbolIndex(const char *func_name)
int FindCoffSymbolIndex(TCCState *s1, const char *func_name)
{
int i, n = 0;
Elf32_Sym *p;

132
tccelf.c
View File

@ -26,22 +26,6 @@
/********************************************************/
/* global variables */
ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
ST_DATA Section *common_section;
ST_DATA Section *cur_text_section; /* current section where function code is generated */
#ifdef CONFIG_TCC_ASM
ST_DATA Section *last_text_section; /* to handle .previous asm directive */
#endif
#ifdef CONFIG_TCC_BCHECK
/* bound check related sections */
ST_DATA Section *bounds_section; /* contains global data bound description */
ST_DATA Section *lbounds_section; /* contains local data bound description */
#endif
/* symbol sections */
ST_DATA Section *symtab_section;
/* debug sections */
ST_DATA Section *stab_section, *stabstr_section;
/* elf version information */
struct sym_version {
char *lib;
@ -58,9 +42,6 @@ struct sym_version {
#define versym_section s1->versym_section
#define verneed_section s1->verneed_section
/* XXX: avoid static variable */
static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
/* special flag to indicate that the section should not be linked to the other ones */
#define SHF_PRIVATE 0x80000000
/* section is dynsymtab_section */
@ -70,6 +51,7 @@ static int new_undef_sym = 0; /* Is there a new undefined sym since last new_und
ST_FUNC void tccelf_new(TCCState *s)
{
TCCState *s1 = s;
/* no section zero */
dynarray_add(&s->sections, &s->nb_sections, NULL);
@ -96,6 +78,7 @@ ST_FUNC void tccelf_new(TCCState *s)
#ifdef CONFIG_TCC_BCHECK
ST_FUNC void tccelf_bounds_new(TCCState *s)
{
TCCState *s1 = s;
/* create bounds sections */
bounds_section = new_section(s, ".bounds",
SHT_PROGBITS, SHF_ALLOC);
@ -106,13 +89,13 @@ ST_FUNC void tccelf_bounds_new(TCCState *s)
ST_FUNC void tccelf_stab_new(TCCState *s)
{
TCCState *s1 = s;
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;
stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, 0);
put_elf_str(stab_section->link, "");
/* put first entry */
put_stabs("", 0, 0, 0, 0);
put_stabs(s, "", 0, 0, 0, 0);
}
static void free_section(Section *s)
@ -220,6 +203,7 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh
Section *sec;
sec = tcc_mallocz(sizeof(Section) + strlen(name));
sec->s1 = s1;
strcpy(sec->name, name);
sec->sh_type = sh_type;
sec->sh_flags = sh_flags;
@ -492,13 +476,13 @@ ST_FUNC int find_elf_sym(Section *s, const char *name)
}
/* 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)
ST_FUNC addr_t get_elf_sym_addr(TCCState *s1, const char *name, int err)
{
int sym_index;
ElfW(Sym) *sym;
sym_index = find_elf_sym(s->symtab, name);
sym = &((ElfW(Sym) *)s->symtab->data)[sym_index];
sym_index = find_elf_sym(s1->symtab, name);
sym = &((ElfW(Sym) *)s1->symtab->data)[sym_index];
if (!sym_index || sym->st_shndx == SHN_UNDEF) {
if (err)
tcc_error("%s not defined", name);
@ -554,7 +538,7 @@ ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name)
#ifndef ELF_OBJ_ONLY
static void
version_add (TCCState *s)
version_add (TCCState *s1)
{
int i;
ElfW(Sym) *sym;
@ -563,7 +547,6 @@ version_add (TCCState *s)
int sym_index, end_sym, nb_versions = 2, nb_entries = 0;
ElfW(Half) *versym;
const char *name;
TCCState *s1 = s;
if (0 == nb_sym_versions)
return;
@ -574,14 +557,14 @@ version_add (TCCState *s)
verneed_section->link = s1->dynsym->link;
/* add needed symbols */
symtab = s->dynsym;
symtab = s1->dynsym;
end_sym = symtab->data_offset / sizeof (ElfSym);
versym = section_ptr_add(versym_section, end_sym * sizeof(ElfW(Half)));
for (sym_index = 0; sym_index < end_sym; ++sym_index) {
int dllindex, verndx;
sym = &((ElfW(Sym) *)symtab->data)[sym_index];
name = (char *) symtab->link->data + sym->st_name;
dllindex = find_elf_sym(s->dynsymtab_section, name);
dllindex = find_elf_sym(s1->dynsymtab_section, name);
verndx = (dllindex && dllindex < nb_sym_to_version)
? sym_to_version[dllindex] : -1;
if (verndx >= 0) {
@ -636,6 +619,7 @@ version_add (TCCState *s)
ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
int info, int other, int shndx, const char *name)
{
TCCState *s1 = s->s1;
ElfW(Sym) *esym;
int sym_bind, sym_index, sym_type, esym_bind;
unsigned char sym_vis, esym_vis, new_vis;
@ -705,7 +689,7 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
do_patch:
esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type);
esym->st_shndx = shndx;
new_undef_sym = 1;
s1->new_undef_sym = 1;
esym->st_value = value;
esym->st_size = size;
esym->st_other = other;
@ -723,6 +707,7 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
int type, int symbol, addr_t addend)
{
TCCState *s1 = s->s1;
char buf[256];
Section *sr;
ElfW_Rel *rel;
@ -733,7 +718,7 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
snprintf(buf, sizeof(buf), REL_SECTION_FMT, 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 = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags);
sr->sh_entsize = sizeof(ElfW_Rel);
sr->link = symtab;
sr->sh_info = s->sh_num;
@ -744,10 +729,9 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
rel->r_info = ELFW(R_INFO)(symbol, type);
#if SHT_RELX == SHT_RELA
rel->r_addend = addend;
#else
if (addend)
tcc_error("non-zero addend on REL architecture");
#endif
if (SHT_RELX != SHT_RELA && addend)
tcc_error("non-zero addend on REL architecture");
}
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
@ -795,14 +779,14 @@ ST_FUNC void squeeze_multi_relocs(Section *s, size_t oldrelocoffset)
/* put stab debug information */
ST_FUNC void put_stabs(const char *str, int type, int other, int desc,
ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc,
unsigned long value)
{
Stab_Sym *sym;
sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
if (str) {
sym->n_strx = put_elf_str(stabstr_section, str);
sym->n_strx = put_elf_str(stab_section->link, str);
} else {
sym->n_strx = 0;
}
@ -812,23 +796,23 @@ ST_FUNC void put_stabs(const char *str, int type, int other, int desc,
sym->n_value = value;
}
ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc,
ST_FUNC void put_stabs_r(TCCState *s1, 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_stabs(s1, str, type, other, desc, value);
put_elf_reloc(symtab_section, stab_section,
stab_section->data_offset - sizeof(unsigned int),
R_DATA_32, sym_index);
}
ST_FUNC void put_stabn(int type, int other, int desc, int value)
ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value)
{
put_stabs(NULL, type, other, desc, value);
put_stabs(s1, NULL, type, other, desc, value);
}
ST_FUNC void put_stabd(int type, int other, int desc)
ST_FUNC void put_stabd(TCCState *s1, int type, int other, int desc)
{
put_stabs(NULL, type, other, desc, 0);
put_stabs(s1, NULL, type, other, desc, 0);
}
ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc)
@ -1180,6 +1164,8 @@ ST_FUNC void build_got_entries(TCCState *s1)
for_each_elem(s, 0, rel, ElfW_Rel) {
type = ELFW(R_TYPE)(rel->r_info);
gotplt_entry = gotplt_entry_type(type);
if (gotplt_entry == -1)
tcc_error ("Unknown relocation type for got: %d", type);
sym_index = ELFW(R_SYM)(rel->r_info);
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
@ -1235,7 +1221,10 @@ ST_FUNC void build_got_entries(TCCState *s1)
continue;
}
#endif
if (code_reloc(type)) {
reloc_type = code_reloc(type);
if (reloc_type == -1)
tcc_error ("Unknown relocation type: %d", type);
else if (reloc_type != 0) {
jmp_slot:
reloc_type = R_JMP_SLOT;
} else
@ -3194,13 +3183,27 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
#define LD_TOK_NAME 256
#define LD_TOK_EOF (-1)
static int ld_inp(TCCState *s1)
{
char b;
if (s1->cc != -1) {
int c = s1->cc;
s1->cc = -1;
return c;
}
if (1 == read(s1->fd, &b, 1))
return b;
return CH_EOF;
}
/* return next ld script token */
static int ld_next(TCCState *s1, char *name, int name_size)
{
int c;
int c, d, ch;
char *q;
redo:
ch = ld_inp(s1);
switch(ch) {
case ' ':
case '\t':
@ -3208,13 +3211,15 @@ static int ld_next(TCCState *s1, char *name, int name_size)
case '\v':
case '\r':
case '\n':
inp();
goto redo;
case '/':
minp();
if (ch == '*') {
file->buf_ptr = parse_comment(file->buf_ptr);
ch = file->buf_ptr[0];
ch = ld_inp(s1);
if (ch == '*') { /* comment */
for (d = 0;; d = ch) {
ch = ld_inp(s1);
if (ch == CH_EOF || (ch == '/' && d == '*'))
break;
}
goto redo;
} else {
q = name;
@ -3223,10 +3228,6 @@ static int ld_next(TCCState *s1, char *name, int name_size)
}
break;
case '\\':
ch = handle_eob();
if (ch != '\\')
goto redo;
/* fall through */
/* case 'a' ... 'z': */
case 'a':
case 'b':
@ -3296,8 +3297,9 @@ static int ld_next(TCCState *s1, char *name, int name_size)
if ((q - name) < name_size - 1) {
*q++ = ch;
}
minp();
ch = ld_inp(s1);
}
s1->cc = ch;
*q = '\0';
c = LD_TOK_NAME;
break;
@ -3306,7 +3308,6 @@ static int ld_next(TCCState *s1, char *name, int name_size)
break;
default:
c = ch;
inp();
break;
}
return c;
@ -3323,14 +3324,6 @@ static int ld_add_file(TCCState *s1, const char filename[])
return tcc_add_dll(s1, filename, 0);
}
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];
@ -3339,7 +3332,7 @@ static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed)
group = !strcmp(cmd, "GROUP");
if (!as_needed)
new_undef_syms();
s1->new_undef_sym = 0;
t = ld_next(s1, filename, sizeof(filename));
if (t != '(')
expect("(");
@ -3394,9 +3387,9 @@ static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed)
}
}
if (group && !as_needed) {
while (new_undef_syms()) {
while (s1->new_undef_sym) {
int i;
s1->new_undef_sym = 0;
for (i = 0; i < nblibs; i ++)
ld_add_file(s1, libs[i]);
}
@ -3408,13 +3401,14 @@ lib_parse_error:
/* interpret a subset of GNU ldscripts to handle the dummy libc.so
files */
ST_FUNC int tcc_load_ldscript(TCCState *s1)
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd)
{
char cmd[64];
char filename[1024];
int t, ret;
ch = handle_eob();
s1->fd = fd;
s1->cc = -1;
for(;;) {
t = ld_next(s1, cmd, sizeof(cmd));
if (t == LD_TOK_EOF)

View File

@ -18,7 +18,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define USING_GLOBALS
#include "tcc.h"
/********************************************************/
/* global variables */
@ -29,16 +31,16 @@
*/
ST_DATA int rsym, anon_sym, ind, loc;
ST_DATA Sym *sym_free_first;
ST_DATA void **sym_pools;
ST_DATA int nb_sym_pools;
ST_DATA Sym *global_stack;
ST_DATA Sym *local_stack;
ST_DATA Sym *define_stack;
ST_DATA Sym *global_label_stack;
ST_DATA Sym *local_label_stack;
static Sym *sym_free_first;
static void **sym_pools;
static int nb_sym_pools;
static Sym *all_cleanups, *pending_gotos;
static int local_scope;
static int in_sizeof;
@ -106,6 +108,18 @@ static struct scope {
Sym *lstk, *llstk;
} *cur_scope, *loop_scope, *root_scope;
/********************************************************/
#ifndef CONFIG_TCC_ASM
ST_FUNC void asm_instr(void)
{
tcc_error("inline asm() not supported");
}
ST_FUNC void asm_global_instr(void)
{
tcc_error("inline asm() not supported");
}
#endif
/* ------------------------------------------------------------------------- */
static void gen_cast(CType *type);
@ -129,6 +143,7 @@ static void vpush64(int ty, unsigned long long v);
static void vpush(CType *type);
static int gvtst(int inv, int t);
static void gen_inline_functions(TCCState *s);
static void free_inline_functions(TCCState *s);
static void skip_or_save_block(TokenString **str);
static void gv_dup(void);
static int get_temp_local_var(int size,int align);
@ -200,9 +215,9 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
normalize_slashes(buf);
#endif
pstrcat(buf, sizeof(buf), "/");
put_stabs_r(buf, N_SO, 0, 0,
put_stabs_r(s1, buf, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
put_stabs_r(file->filename, N_SO, 0, 0,
put_stabs_r(s1, file->prev->filename, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
last_ind = 0;
last_line_num = 0;
@ -220,7 +235,7 @@ ST_FUNC void tcc_debug_end(TCCState *s1)
{
if (!s1->do_debug)
return;
put_stabs_r(NULL, N_SO, 0, 0,
put_stabs_r(s1, NULL, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
}
@ -231,7 +246,7 @@ ST_FUNC void tcc_debug_line(TCCState *s1)
if (!s1->do_debug)
return;
if ((last_line_num != file->line_num || last_ind != ind)) {
put_stabn(N_SLINE, 0, file->line_num, ind - func_ind);
put_stabn(s1, N_SLINE, 0, file->line_num, ind - func_ind);
last_ind = ind;
last_line_num = file->line_num;
}
@ -249,10 +264,10 @@ ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym)
/* 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,
put_stabs_r(s1, buf, N_FUN, 0, file->line_num, 0,
cur_text_section, sym->c);
/* //gr gdb wants a line at the function */
put_stabn(N_SLINE, 0, file->line_num, 0);
put_stabn(s1, N_SLINE, 0, file->line_num, 0);
last_ind = 0;
last_line_num = 0;
@ -263,7 +278,7 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size)
{
if (!s1->do_debug)
return;
put_stabn(N_FUN, 0, 0, size);
put_stabn(s1, N_FUN, 0, 0, size);
}
/* ------------------------------------------------------------------------- */
@ -316,6 +331,21 @@ ST_FUNC int tccgen_compile(TCCState *s1)
return 0;
}
ST_FUNC void tccgen_finish(TCCState *s1, int f)
{
if (f == 1) {
free_inline_functions(s1);
sym_pop(&global_stack, NULL, 0);
sym_pop(&local_stack, NULL, 0);
}
if (f == 2) {
/* free sym_pools */
dynarray_reset(&sym_pools, &nb_sym_pools);
sym_free_first = NULL;
}
}
/* ------------------------------------------------------------------------- */
ST_FUNC ElfSym *elfsym(Sym *s)
{
@ -7684,7 +7714,7 @@ static void gen_inline_functions(TCCState *s)
tcc_close();
}
ST_FUNC void free_inline_functions(TCCState *s)
static void free_inline_functions(TCCState *s)
{
int i;
/* free tokens of unused inline functions */

10
tccpe.c
View File

@ -602,6 +602,7 @@ static int pe_write(struct pe_info *pe)
DWORD file_offset, sum;
struct section_info *si;
IMAGE_SECTION_HEADER *psh;
TCCState *s1 = pe->s1;
op = fopen(pe->filename, "wb");
if (NULL == op) {
@ -784,6 +785,7 @@ static 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;
int ndlls = pe->imp_count;
TCCState *s1 = pe->s1;
for (sym_cnt = i = 0; i < ndlls; ++i)
sym_cnt += pe->imp_info[i]->sym_count;
@ -895,6 +897,7 @@ static void pe_build_exports(struct pe_info *pe)
IMAGE_EXPORT_DIRECTORY *hdr;
int sym_count, ord;
struct pe_sort_sym **sorted, *p;
TCCState *s1 = pe->s1;
FILE *op;
char buf[260];
@ -1195,7 +1198,7 @@ static int pe_assign_addresses (struct pe_info *pe)
/*----------------------------------------------------------------------------*/
static int pe_isafunc(int sym_index)
static int pe_isafunc(TCCState *s1, int sym_index)
{
Section *sr = text_section->reloc;
ElfW_Rel *rel, *rel_end;
@ -1215,6 +1218,7 @@ static int pe_check_symbols(struct pe_info *pe)
ElfW(Sym) *sym;
int sym_index, sym_end;
int ret = 0;
TCCState *s1 = pe->s1;
pe_align_section(text_section, 8);
@ -1234,7 +1238,7 @@ static int pe_check_symbols(struct pe_info *pe)
if (type == STT_NOTYPE) {
/* symbols from assembler have no type, find out which */
if (pe_isafunc(sym_index))
if (pe_isafunc(s1, sym_index))
type = STT_FUNC;
else
type = STT_OBJECT;
@ -1769,7 +1773,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
static unsigned pe_add_uwwind_info(TCCState *s1)
{
if (NULL == s1->uw_pdata) {
s1->uw_pdata = find_section(tcc_state, ".pdata");
s1->uw_pdata = find_section(s1, ".pdata");
s1->uw_pdata->sh_addralign = 4;
}
if (0 == s1->uw_sym)

101
tccpp.c
View File

@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define USING_GLOBALS
#include "tcc.h"
/********************************************************/
@ -54,7 +55,6 @@ static void tok_print(const char *msg, const int *str);
static struct TinyAlloc *toksym_alloc;
static struct TinyAlloc *tokstr_alloc;
static struct TinyAlloc *cstr_alloc;
static TokenString *macro_stack;
@ -331,7 +331,7 @@ static void cstr_realloc(CString *cstr, int new_size)
size = 8; /* no need to allocate a too small first string */
while (size < new_size)
size = size * 2;
cstr->data = tal_realloc(cstr_alloc, cstr->data, size);
cstr->data = tcc_realloc(cstr->data, size);
cstr->size_allocated = size;
}
@ -377,7 +377,7 @@ ST_FUNC void cstr_new(CString *cstr)
/* free string and reset it to NULL */
ST_FUNC void cstr_free(CString *cstr)
{
tal_free(cstr_alloc, cstr->data);
tcc_free(cstr->data);
cstr_new(cstr);
}
@ -387,6 +387,24 @@ ST_FUNC void cstr_reset(CString *cstr)
cstr->size = 0;
}
ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
{
va_list v;
int len, size;
va_start(v, fmt);
len = vsnprintf(NULL, 0, fmt, v);
va_end(v);
size = cstr->size + len + 1;
if (size > cstr->size_allocated)
cstr_realloc(cstr, size);
va_start(v, fmt);
vsnprintf((char*)cstr->data + cstr->size, size, fmt, v);
va_end(v);
cstr->size += len;
return len;
}
/* XXX: unicode ? */
static void add_char(CString *cstr, int c)
{
@ -1338,18 +1356,6 @@ ST_FUNC void free_defines(Sym *b)
define_undef(top);
sym_free(top);
}
/* restore remaining (-D or predefined) symbols if they were
#undef'd in the file */
while (b) {
int v = b->v;
if (v >= TOK_IDENT && v < tok_ident) {
Sym **d = &table_ident[v - TOK_IDENT]->sym_define;
if (!*d && b->d)
*d = b;
}
b = b->prev;
}
}
/* label lookup */
@ -1855,7 +1861,7 @@ ST_FUNC void preprocess(int is_bof)
}
/* add include file debug info */
if (s1->do_debug)
put_stabs(file->filename, N_BINCL, 0, 0, 0);
put_stabs(tcc_state, file->filename, N_BINCL, 0, 0, 0);
tok_flags |= TOK_FLAG_BOF | TOK_FLAG_BOL;
ch = file->buf_ptr[0];
goto the_end;
@ -1964,7 +1970,7 @@ include_done:
total_lines += file->line_num - n;
file->line_num = n;
if (s1->do_debug)
put_stabs(file->filename, N_BINCL, 0, 0, 0);
put_stabs(tcc_state, file->filename, N_BINCL, 0, 0, 0);
break;
case TOK_ERROR:
case TOK_WARNING:
@ -2278,7 +2284,7 @@ static void parse_number(const char *p)
q--;
ch = *p++;
b = 16;
} else if (tcc_ext && (ch == 'b' || ch == 'B')) {
} else if (tcc_state->tcc_ext && (ch == 'b' || ch == 'B')) {
q--;
ch = *p++;
b = 2;
@ -2622,7 +2628,7 @@ static inline void next_nomacro1(void)
/* add end of include file debug info */
if (tcc_state->do_debug) {
put_stabd(N_EINCL, 0, 0);
put_stabd(tcc_state, N_EINCL, 0, 0);
}
/* pop include stack */
tcc_close();
@ -3584,7 +3590,8 @@ ST_INLN void unget_tok(int last_tok)
ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
{
CString cstr;
int i;
tccpp_new(s1);
s1->include_stack_ptr = s1->include_stack;
s1->ifdef_stack_ptr = s1->ifdef_stack;
@ -3602,26 +3609,18 @@ ST_FUNC void preprocess_start(TCCState *s1, int is_asm)
set_idnum('.', is_asm ? IS_ID : 0);
cstr_new(&cstr);
cstr_cat(&cstr, "\"", -1);
cstr_cat(&cstr, file->filename, -1);
cstr_cat(&cstr, "\"", 0);
tcc_define_symbol(s1, "__BASE_FILE__", cstr.data);
cstr_reset(&cstr);
for (i = 0; i < s1->nb_cmd_include_files; i++) {
cstr_cat(&cstr, "#include \"", -1);
cstr_cat(&cstr, s1->cmd_include_files[i], -1);
cstr_cat(&cstr, "\"\n", -1);
}
if (cstr.size) {
*s1->include_stack_ptr++ = file;
tcc_open_bf(s1, "<command line>", cstr.size);
memcpy(file->buffer, cstr.data, cstr.size);
}
cstr_free(&cstr);
if (is_asm)
tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
cstr_printf(&cstr, "#define __ASSEMBLER__ 1\n");
cstr_printf(&cstr, "#define __BASE_FILE__ \"%s\"\n", file->filename);
if (s1->cmdline_defs.size)
cstr_cat(&cstr, s1->cmdline_defs.data, s1->cmdline_defs.size);
//printf("%s\n", (char*)s1->cmdline_defs.data);
if (s1->cmdline_incl.size)
cstr_cat(&cstr, s1->cmdline_incl.data, s1->cmdline_incl.size);
*s1->include_stack_ptr++ = file;
tcc_open_bf(s1, "<command line>", cstr.size);
memcpy(file->buffer, cstr.data, cstr.size);
cstr_free(&cstr);
parse_flags = is_asm ? PARSE_FLAG_ASM_FILE : 0;
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
@ -3633,6 +3632,11 @@ ST_FUNC void preprocess_end(TCCState *s1)
while (macro_stack)
end_macro();
macro_ptr = NULL;
while (file)
tcc_close();
tccpp_delete(s1);
}
ST_FUNC void tccpp_new(TCCState *s)
@ -3640,10 +3644,6 @@ ST_FUNC void tccpp_new(TCCState *s)
int i, c;
const char *p, *r;
/* might be used in error() before preprocess_start() */
s->include_stack_ptr = s->include_stack;
s->ppfp = stdout;
/* init isid table */
for(i = CH_EOF; i<128; i++)
set_idnum(i,
@ -3658,9 +3658,10 @@ ST_FUNC void tccpp_new(TCCState *s)
/* init allocators */
tal_new(&toksym_alloc, TOKSYM_TAL_LIMIT, TOKSYM_TAL_SIZE);
tal_new(&tokstr_alloc, TOKSTR_TAL_LIMIT, TOKSTR_TAL_SIZE);
tal_new(&cstr_alloc, CSTR_TAL_LIMIT, CSTR_TAL_SIZE);
memset(hash_ident, 0, TOK_HASH_SIZE * sizeof(TokenSym *));
memset(s->cached_includes_hash, 0, sizeof s->cached_includes_hash);
cstr_new(&cstr_buf);
cstr_realloc(&cstr_buf, STRING_MAX_SIZE);
tok_str_new(&tokstr_buf);
@ -3678,14 +3679,22 @@ ST_FUNC void tccpp_new(TCCState *s)
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);
define_push(TOK___COUNTER__, MACRO_OBJ, NULL, NULL);
}
ST_FUNC void tccpp_delete(TCCState *s)
{
int i, n;
/* free -D and compiler defines */
free_defines(NULL);
dynarray_reset(&s->cached_includes, &s->nb_cached_includes);
/* free tokens */
n = tok_ident - TOK_IDENT;
@ -3705,8 +3714,6 @@ ST_FUNC void tccpp_delete(TCCState *s)
toksym_alloc = NULL;
tal_delete(tokstr_alloc);
tokstr_alloc = NULL;
tal_delete(cstr_alloc);
cstr_alloc = NULL;
}
/* ------------------------------------------------------------------------- */

View File

@ -36,15 +36,29 @@
# else
# define ucontext_t CONTEXT
# endif
ST_DATA int rt_num_callers = 6;
ST_DATA const char **rt_bound_error_msg;
ST_DATA void *rt_prog_main;
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
static void rt_error(ucontext_t *uc, const char *fmt, ...);
static void set_exception_handler(void);
#ifdef _WIN32
static DWORD s1_for_run_idx;
void set_s1_for_run(TCCState *s)
{
if (!s1_for_run_idx)
s1_for_run_idx = TlsAlloc();
TlsSetValue(s1_for_run_idx, s);
}
#define get_s1_for_run() ((TCCState*)TlsGetValue(s1_for_run_idx))
#else
/* XXX: add tls support for linux */
static TCCState *s1_for_run;
#define set_s1_for_run(s) (s1_for_run = s)
#define get_s1_for_run() s1_for_run
#endif
#endif
static void set_pages_executable(void *ptr, unsigned long length);
static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length);
static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff);
#ifdef _WIN64
@ -110,6 +124,8 @@ ST_FUNC void tcc_run_free(TCCState *s1)
#endif
}
tcc_free(s1->runtime_mem);
if (get_s1_for_run() == s1)
set_s1_for_run(NULL);
}
/* launch the compiled program with the given arguments */
@ -127,7 +143,9 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
#ifdef CONFIG_TCC_BACKTRACE
if (s1->do_debug) {
set_exception_handler();
rt_prog_main = prog_main;
s1->rt_prog_main = prog_main;
/* set global state pointer for exception handlers*/
set_s1_for_run(s1);
}
#endif
@ -142,7 +160,7 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
int ret;
/* set error function */
rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
s1->rt_bound_error_msg = tcc_get_symbol_err(s1, "__bound_error_msg");
/* XXX: use .init section so that it also work in binary ? */
bound_init = tcc_get_symbol_err(s1, "__bound_init");
bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
@ -255,7 +273,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
memcpy(ptr, s->data, length);
/* mark executable sections as executable in memory */
if (s->sh_flags & SHF_EXECINSTR)
set_pages_executable((char*)ptr + ptr_diff, length);
set_pages_executable(s1, (char*)ptr + ptr_diff, length);
}
#ifdef _WIN64
@ -268,7 +286,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
/* ------------------------------------------------------------- */
/* allow to run code in memory */
static void set_pages_executable(void *ptr, unsigned long length)
static void set_pages_executable(TCCState *s1, void *ptr, unsigned long length)
{
#ifdef _WIN32
unsigned long old_protect;
@ -319,14 +337,9 @@ static void win64_del_function_table(void *p)
/* ------------------------------------------------------------- */
#ifdef CONFIG_TCC_BACKTRACE
ST_FUNC void tcc_set_num_callers(int n)
{
rt_num_callers = n;
}
/* print the position in the source file of PC value 'pc' by reading
the stabs debug information */
static addr_t rt_printline(addr_t wanted_pc, const char *msg)
static addr_t rt_printline(TCCState *s1, addr_t wanted_pc, const char *msg)
{
char func_name[128], last_func_name[128];
addr_t func_addr, last_pc, pc;
@ -341,7 +354,7 @@ static addr_t rt_printline(addr_t wanted_pc, const char *msg)
if (stab_section) {
stab_len = stab_section->data_offset;
stab_sym = (Stab_Sym *)stab_section->data;
stab_str = (char *) stabstr_section->data;
stab_str = (char *) stab_section->link->data;
}
func_name[0] = '\0';
@ -473,6 +486,7 @@ static void rt_error(ucontext_t *uc, const char *fmt, ...)
va_list ap;
addr_t pc;
int i;
TCCState *s1 = get_s1_for_run();
fprintf(stderr, "Runtime error: ");
va_start(ap, fmt);
@ -480,11 +494,14 @@ static void rt_error(ucontext_t *uc, const char *fmt, ...)
va_end(ap);
fprintf(stderr, "\n");
for(i=0;i<rt_num_callers;i++) {
if (!s1)
return;
for(i=0;i<s1->rt_num_callers;i++) {
if (rt_get_caller_pc(&pc, uc, i) < 0)
break;
pc = rt_printline(pc, i ? "by" : "at");
if (pc == (addr_t)rt_prog_main && pc)
pc = rt_printline(s1, pc, i ? "by" : "at");
if (pc == (addr_t)s1->rt_prog_main && pc)
break;
}
}
@ -496,6 +513,7 @@ static void rt_error(ucontext_t *uc, const char *fmt, ...)
static void sig_error(int signum, siginfo_t *siginf, void *puc)
{
ucontext_t *uc = puc;
TCCState *s1;
switch(signum) {
case SIGFPE:
@ -511,8 +529,9 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
break;
case SIGBUS:
case SIGSEGV:
if (rt_bound_error_msg && *rt_bound_error_msg)
rt_error(uc, *rt_bound_error_msg);
s1 = get_s1_for_run();
if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
rt_error(uc, *s1->rt_bound_error_msg);
else
rt_error(uc, "dereferencing invalid pointer");
break;
@ -728,10 +747,12 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
{
EXCEPTION_RECORD *er = ex_info->ExceptionRecord;
CONTEXT *uc = ex_info->ContextRecord;
TCCState *s1;
switch (er->ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION:
if (rt_bound_error_msg && *rt_bound_error_msg)
rt_error(uc, *rt_bound_error_msg);
s1 = get_s1_for_run();
if (s1 && s1->rt_bound_error_msg && *s1->rt_bound_error_msg)
rt_error(uc, *s1->rt_bound_error_msg);
else
rt_error(uc, "access violation");
break;

View File

@ -430,7 +430,7 @@ the_end:
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option)
ST_FUNC void tcc_tool_cross(TCCState *s1, char **argv, int option)
{
tcc_error("-m%d not implemented.", option);
}
@ -479,7 +479,7 @@ static int execvp_win32(const char *prog, char **argv)
#define execvp execvp_win32
#endif /* _WIN32 */
ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target)
ST_FUNC void tcc_tool_cross(TCCState *s1, char **argv, int target)
{
char program[4096];
char *a0 = argv[0];
@ -515,7 +515,7 @@ int _dowildcard = 1;
/* -------------------------------------------------------------- */
/* generate xxx.d file */
ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
ST_FUNC void gen_makedeps(TCCState *s1, const char *target, const char *filename)
{
FILE *depout;
char buf[1024];
@ -528,7 +528,7 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
filename = buf;
}
if (s->verbose)
if (s1->verbose)
printf("<- %s\n", filename);
/* XXX return err codes instead of error() ? */
@ -537,8 +537,8 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
tcc_error("could not open '%s'", filename);
fprintf(depout, "%s: \\\n", target);
for (i=0; i<s->nb_target_deps; ++i)
fprintf(depout, " %s \\\n", s->target_deps[i]);
for (i=0; i<s1->nb_target_deps; ++i)
fprintf(depout, " %s \\\n", s1->target_deps[i]);
fprintf(depout, "\n");
fclose(depout);
}

View File

@ -12,6 +12,7 @@ TESTS = \
hello-exe \
hello-run \
libtest \
libtest_mt \
test3 \
memtest \
dlltest \
@ -71,11 +72,11 @@ hello-run: ../examples/ex1.c
@echo ------------ $@ ------------
$(TCC) -run $< || $(DUMPTCC)
libtest: libtcc_test$(EXESUF)
libtes%: libtcc_tes%$(EXESUF)
@echo ------------ $@ ------------
./libtcc_test$(EXESUF) $(TCCFLAGS)
./libtcc_tes$*$(EXESUF) $(TCCFLAGS)
libtcc_test$(EXESUF): libtcc_test.c $(LIBTCC)
libtcc_tes%$(EXESUF): libtcc_tes%.c $(LIBTCC)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
%-dir:
@ -283,7 +284,7 @@ clean:
rm -f *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc *.gcc
rm -f *-cc *-gcc *-tcc *.exe hello libtcc_test vla_test tcctest[1234]
rm -f asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
rm -f ex? tcc_g weaktest.*.txt *.def
rm -f ex? tcc_g weaktest.*.txt *.def libtcc_test_mt
@$(MAKE) -C tests2 $@
@$(MAKE) -C pp $@

View File

@ -0,0 +1,292 @@
/*
* Multi-thread Test for libtcc
*/
#ifndef FIB
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libtcc.h"
#define M 20 /* number of states */
#define F(n) (n % 20 + 2) /* fib argument */
#ifdef _WIN32
#include <windows.h>
#define TF_TYPE(func, param) DWORD WINAPI func(void *param)
typedef TF_TYPE(ThreadFunc, x);
HANDLE hh[M];
void create_thread(ThreadFunc f, int n)
{
DWORD tid;
hh[n] = CreateThread(NULL, 0, f, (void*)(size_t)n, 0, &tid);
}
void wait_threads(int n)
{
WaitForMultipleObjects(n, hh, TRUE, INFINITE);
while (n)
CloseHandle(hh[--n]);
}
void sleep_ms(unsigned n)
{
Sleep(n);
}
#else
#include <pthread.h>
#define TF_TYPE(func, param) void* func(void *param)
typedef TF_TYPE(ThreadFunc, x);
pthread_t hh[M];
void create_thread(ThreadFunc f, int n)
{
pthread_create(&hh[n], NULL, f, (void*)(size_t)n);
}
void wait_threads(int n)
{
while (n)
pthread_join(hh[--n], NULL);
}
void sleep_ms(unsigned n)
{
usleep(n * 1000);
}
#endif
void handle_error(void *opaque, const char *msg)
{
fprintf(opaque, "%s\n", msg);
}
/* this function is called by the generated code */
int add(int a, int b)
{
return a + b;
}
#define _str(s) #s
#define str(s) _str(s)
/* as a trick, prepend #line directive for better error/warning messages */
#define PROG(lbl) \
char lbl[] = "#line " str(__LINE__) " " str(__FILE__) "\n\n"
PROG(my_program)
"#include <tcclib.h>\n" /* include the "Simple libc header for TCC" */
"int add(int a, int b);\n"
"int fib(int n)\n"
"{\n"
" if (n <= 2)\n"
" return 1;\n"
" else\n"
" return add(fib(n-1),fib(n-2));\n"
"}\n"
"\n"
"int foo(int n)\n"
"{\n"
" printf(\" %d\", fib(n));\n"
" return 0;\n"
"# warning is this the correct file:line...\n"
"}\n";
int g_argc; char **g_argv;
void parse_args(TCCState *s)
{
int i;
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
for (i = 1; i < g_argc; ++i) {
char *a = g_argv[i];
if (a[0] == '-') {
if (a[1] == 'B')
tcc_set_lib_path(s, a+2);
else if (a[1] == 'I')
tcc_add_include_path(s, a+2);
else if (a[1] == 'L')
tcc_add_library_path(s, a+2);
}
}
}
TCCState *new_state(int w)
{
TCCState *s = tcc_new();
if (!s) {
fprintf(stderr, __FILE__ ": could not create tcc state\n");
exit(1);
}
tcc_set_error_func(s, stdout, handle_error);
parse_args(s);
if (!w) tcc_set_options(s, "-w");
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
return s;
}
void *reloc_state(TCCState *s, const char *entry)
{
void *func;
tcc_add_symbol(s, "add", add);
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) {
fprintf(stderr, __FILE__ ": could not relocate tcc state.\n");
return NULL;
}
func = tcc_get_symbol(s, entry);
if (!func)
fprintf(stderr, __FILE__ ": could not get entry symbol.\n");
return func;
}
/* work with several states at the same time */
int state_test(void)
{
TCCState *s[M];
int (*func[M])(int);
int n;
for (n = 0; n < M + 4; ++n) {
unsigned a = n, b = n - 1, c = n - 2, d = n - 3, e = n - 4;
if (a < M)
s[a] = new_state(0);
if (b < M)
if (tcc_compile_string(s[b], my_program) == -1)
break;
if (c < M)
func[c] = reloc_state(s[c], "foo");
if (d < M && func[d])
func[d](F(d));
if (e < M)
tcc_delete(s[e]);
}
return 0;
}
/* simple compilation in threads */
TF_TYPE(thread_test_simple, vn)
{
TCCState *s;
int (*func)(int);
int ret;
int n = (size_t)vn;
s = new_state(0);
sleep_ms(1);
ret = tcc_compile_string(s, my_program);
sleep_ms(1);
if (ret >= 0) {
func = reloc_state(s, "foo");
if (func)
func(F(n));
}
tcc_delete(s);
return 0;
}
/* more complex compilation in threads */
TF_TYPE(thread_test_complex, vn)
{
TCCState *s;
int ret;
int n = (size_t)vn;
char *argv[30], b[10];
int argc = 0, i;
sprintf(b, "%d", F(n));
argv[argc++] = "../tcc.c";
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
#if 0
argv[argc++] = "-run";
argv[argc++] = "../tcc.c";
for (i = 1; i < g_argc; ++i) argv[argc++] = g_argv[i];
#endif
argv[argc++] = "-g";
argv[argc++] = "-DFIB";
argv[argc++] = "-run";
argv[argc++] = __FILE__;
argv[argc++] = b;
argv[argc] = NULL;
s = new_state(1);
sleep_ms(1);
ret = tcc_add_file(s, argv[0]);
sleep_ms(1);
if (ret >= 0)
tcc_run(s, argc, argv);
tcc_delete(s);
return 0;
}
void time_tcc(int n)
{
TCCState *s;
int ret;
while (--n >= 0) {
s = new_state(1);
ret = tcc_add_file(s, "../tcc.c");
tcc_delete(s);
if (ret < 0)
break;
}
}
static unsigned getclock_ms(void)
{
#ifdef _WIN32
return GetTickCount();
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000 + (tv.tv_usec+500)/1000;
#endif
}
int main(int argc, char **argv)
{
int n;
unsigned t;
g_argc = argc;
g_argv = argv;
#if 1
printf("----- libtest : mixed calls -------\n"), fflush(stdout);
t = getclock_ms();
state_test();
printf("\n(%u ms)\n", getclock_ms() - t);
#endif
#if 1
printf("----- libtest : threads ------------\n"), fflush(stdout);
t = getclock_ms();
for (n = 0; n < M; ++n)
create_thread(thread_test_simple, n);
wait_threads(n);
printf("\n(%u ms)\n", getclock_ms() - t);
#endif
#if 1
printf("----- libtest : tcc in threads -----\n"), fflush(stdout);
t = getclock_ms();
for (n = 0; n < M; ++n)
create_thread(thread_test_complex, n);
wait_threads(n);
printf("\n(%u ms)\n", getclock_ms() - t);
#endif
#if 1
printf("----- compilation of tcc -----------\n"), fflush(stdout);
t = getclock_ms();
time_tcc(10);
printf("(%u ms)\n", (getclock_ms() - t) / 10), fflush(stdout);
#endif
return 0;
}
#else
#include <tcclib.h>
int fib(n)
{
return (n <= 2) ? 1 : fib(n-1) + fib(n-2);
}
int main(int argc, char **argv)
{
printf(" %d", fib(atoi(argv[1]), 2));
return 0;
}
#endif

View File

@ -105,6 +105,7 @@ enum {
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
/******************************************************/
#define USING_GLOBALS
#include "tcc.h"
#include <assert.h>
@ -1024,7 +1025,7 @@ void gfunc_call(int nb_args)
if ((vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) {
/* need to add the "func_scratch" area after alloca */
o(0x48); func_alloca = oad(0x2d, func_alloca); /* sub $NN, %rax */
o(0x48); func_alloca = oad(0x05, func_alloca); /* sub $NN, %rax */
}
/* other compilers don't clear the upper bits when returning char/short */

View File

@ -52,8 +52,6 @@ int code_reloc (int reloc_type)
case R_X86_64_JUMP_SLOT:
return 1;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}
@ -95,7 +93,6 @@ int gotplt_entry_type (int reloc_type)
return ALWAYS_GOTPLT_ENTRY;
}
tcc_error ("Unknown relocation type: %d", reloc_type);
return -1;
}