mirror of
https://gitflic.ru/project/e2khome/lccrt.git
synced 2024-11-26 03:39:12 +01:00
1146 lines
29 KiB
C
1146 lines
29 KiB
C
/**
|
||
* Part of the Lccrt Project, under the Apache License v2.0
|
||
* See http://www.apache.org/licenses/LICENSE-2.0.txt for license information.
|
||
* SPDX-License-Identifier: Apache-2.0
|
||
*
|
||
* lccrt_ctx.c - реализация пользовательский интерфейс (динамической) компиляции.
|
||
*/
|
||
|
||
#define _GNU_SOURCE
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include <stdarg.h>
|
||
#include <assert.h>
|
||
#include <errno.h>
|
||
#include <ctype.h>
|
||
#include <limits.h>
|
||
#include <dlfcn.h>
|
||
#include <libgen.h>
|
||
#include <sys/syscall.h>
|
||
#include <unistd.h>
|
||
|
||
#include "lccrt_irv.h"
|
||
|
||
#define LCCRT_CTX_PLUGIN_MAX_NUMBER (256)
|
||
#define LCCRT_CTX_PLUGIN_TARGET_MAX_NUMBER (256)
|
||
#define LCCRT_CTX_PLUGIN_NAME_LENGTH (4096 - 1)
|
||
|
||
#define lccrt_ctx_error_plugin_sym( ctx, lname, sname) \
|
||
lccrt_ctx_error( ctx, 0, "Plugin library [%s] hasn't symbol [%s]\n", \
|
||
lname, sname)
|
||
|
||
lccrt_check_type_define( lccrt_type_t);
|
||
lccrt_check_type_define( lccrt_varinit_t);
|
||
lccrt_check_type_define( lccrt_var_t);
|
||
lccrt_check_type_define( lccrt_oper_t);
|
||
lccrt_check_type_define( lccrt_oper_iterator_t);
|
||
lccrt_check_type_define( lccrt_function_t);
|
||
lccrt_check_type_define( lccrt_function_jit_info_t);
|
||
lccrt_check_type_define( lccrt_module_t);
|
||
lccrt_check_type_define( lccrt_einfo_tydescr_t);
|
||
lccrt_check_type_define( lccrt_einfo_block_t);
|
||
lccrt_check_type_define( lccrt_einfo_link_t);
|
||
lccrt_check_type_define( lccrt_context_t);
|
||
lccrt_check_type_define( lccrt_plugin_t);
|
||
|
||
/**
|
||
* Данные стандартного менеджера вывода сообщений в файл.
|
||
*/
|
||
typedef struct
|
||
{
|
||
int8_t is_init; /* флаг инициализации структуры */
|
||
FILE *file; /* файл для печати сообщений */
|
||
pid_t pid; /* идентификатор родительского процесса */
|
||
} lccrt_dir_error_info_t;
|
||
|
||
static void *lccrt_std_alloc( void *pool, uint64_t size);
|
||
static void *lccrt_std_realloc( void *pool, void *ptr, uint64_t size);
|
||
static void lccrt_std_free( void *pool, void *ptr);
|
||
static void lccrt_std_error( void *data, int errid, const char *fmt, ...);
|
||
static void lccrt_dir_error( void *data, int errid, const char *fmt, ...);
|
||
static void lccrt_std_warning( void *data, int errid, const char *fmt, ...);
|
||
static void lccrt_dir_warning( void *data, int errid, const char *fmt, ...);
|
||
|
||
/**
|
||
* Стандартные менеджеры.
|
||
*/
|
||
lccrt_err_t lccrt_std_err = {0, &lccrt_std_error, &lccrt_std_warning};
|
||
lccrt_mem_t lccrt_std_mem = {0, &lccrt_std_alloc, &lccrt_std_realloc, &lccrt_std_free};
|
||
lccrt_err_t lccrt_dir_err = {0, &lccrt_dir_error, &lccrt_dir_warning};
|
||
|
||
/**
|
||
* Стандартный malloc.
|
||
*/
|
||
static void *
|
||
lccrt_std_alloc( void *pool, uint64_t size)
|
||
{
|
||
void *result = (void *)malloc( size);
|
||
|
||
return (result);
|
||
} /* lccrt_std_alloc */
|
||
|
||
/**
|
||
* Стандартный realloc.
|
||
*/
|
||
static void *
|
||
lccrt_std_realloc( void *pool, void *ptr, uint64_t size)
|
||
{
|
||
void *result = (void *)realloc( ptr, size);
|
||
|
||
return (result);
|
||
} /* lccrt_std_realloc */
|
||
|
||
/**
|
||
* Стандартный free.
|
||
*/
|
||
static void
|
||
lccrt_std_free( void *pool, void *ptr)
|
||
{
|
||
free( ptr);
|
||
|
||
return;
|
||
} /* lccrt_std_free */
|
||
|
||
/**
|
||
* Стандартная реакция на ошибку.
|
||
*/
|
||
static void
|
||
lccrt_std_error( void *data, int errid, const char *fmt, ...)
|
||
{
|
||
char str[256];
|
||
va_list ap;
|
||
|
||
va_start( ap, fmt);
|
||
vsnprintf( str, 255, fmt, ap);
|
||
va_end( ap);
|
||
|
||
perror( str);
|
||
if ( errid )
|
||
{
|
||
exit( errid);
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_std_error */
|
||
|
||
/**
|
||
* Стандартная реакция на предупреждение.
|
||
*/
|
||
static void
|
||
lccrt_std_warning( void *data, int errid, const char *fmt, ...)
|
||
{
|
||
char str[256];
|
||
va_list ap;
|
||
|
||
va_start( ap, fmt);
|
||
vsnprintf( str, 255, fmt, ap);
|
||
va_end( ap);
|
||
|
||
printf( "%s", str);
|
||
|
||
return;
|
||
} /* lccrt_std_warning */
|
||
|
||
/**
|
||
* Подготовка данных для вывода сообщений.
|
||
*/
|
||
static lccrt_dir_error_info_t *
|
||
lccrt_dir_error_init( void)
|
||
{
|
||
static __thread lccrt_dir_error_info_t ei = {0};
|
||
|
||
if ( !ei.is_init
|
||
|| (ei.pid != getpid()) )
|
||
{
|
||
char s[1024];
|
||
const char *dir_name = getenv( "LCCRT_ERRDIR");
|
||
|
||
ei.is_init = 1;
|
||
ei.pid = getpid();
|
||
if ( !dir_name
|
||
|| (dir_name[0] == 0) )
|
||
{
|
||
dir_name = ".";
|
||
}
|
||
|
||
snprintf( s, 1024, "mkdir -p -m a+rwx %s", dir_name);
|
||
system( s);
|
||
|
||
snprintf( s, 1024, "%s/lccrt.errlog.pid_%d.tid_%d.txt", dir_name, getpid(), (unsigned)syscall( SYS_gettid));
|
||
ei.file = fopen( s, "w");
|
||
}
|
||
|
||
return (&ei);
|
||
} /* lccrt_dir_error_init */
|
||
|
||
/**
|
||
* Стандартная реакция на ошибку.
|
||
*/
|
||
static void
|
||
lccrt_dir_error( void *data, int errid, const char *fmt, ...)
|
||
{
|
||
va_list ap;
|
||
lccrt_dir_error_info_t *ei = lccrt_dir_error_init();
|
||
|
||
va_start( ap, fmt);
|
||
vfprintf( ei->file, fmt, ap);
|
||
va_end( ap);
|
||
|
||
fflush( ei->file);
|
||
|
||
if ( errid )
|
||
{
|
||
exit( errid);
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_dir_error */
|
||
|
||
/**
|
||
* Стандартная реакция на предупреждение.
|
||
*/
|
||
static void
|
||
lccrt_dir_warning( void *data, int errid, const char *fmt, ...)
|
||
{
|
||
va_list ap;
|
||
lccrt_dir_error_info_t *ei = lccrt_dir_error_init();
|
||
|
||
va_start( ap, fmt);
|
||
vfprintf( ei->file, fmt, ap);
|
||
va_end( ap);
|
||
|
||
fflush( ei->file);
|
||
|
||
return;
|
||
} /* lccrt_dir_warning */
|
||
|
||
/**
|
||
* Чтение из файла строки.
|
||
*/
|
||
static void
|
||
lccrt_getline( FILE *f, int max_str_len, char *line)
|
||
{
|
||
int c;
|
||
int k = 0;
|
||
|
||
c = getc( f);
|
||
while ( (c != '\n')
|
||
&& (c != EOF)
|
||
&& isspace( c) )
|
||
{
|
||
c = getc( f);
|
||
}
|
||
|
||
while ( (c != '\n')
|
||
&& (c != EOF) )
|
||
{
|
||
if ( (k < max_str_len) )
|
||
{
|
||
line[k] = c;
|
||
++k;
|
||
}
|
||
|
||
c = getc( f);
|
||
}
|
||
|
||
line[k] = 0;
|
||
|
||
return;
|
||
} /* lccrt_getline */
|
||
|
||
/**
|
||
* Получить ссылку на метод.
|
||
*/
|
||
void *
|
||
lccrt_ctx_plugin_get_func( lccrt_plg_ptr p, int func_num)
|
||
{
|
||
void *r = 0;
|
||
|
||
lccrt_check_type_assert( p, lccrt_plugin_t);
|
||
if ( (0 <= func_num)
|
||
&& (func_num < p->num_funcs) )
|
||
{
|
||
r = p->funcs[func_num];
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_plugin_get_func */
|
||
|
||
/**
|
||
* Закрытие библиотеки с ассемблером.
|
||
*/
|
||
static void
|
||
lccrt_ctx_plugin_unload( lccrt_plugin_t *a)
|
||
{
|
||
int k;
|
||
lccrt_context_ptr ctx = a->ctx;
|
||
|
||
lccrt_check_type_assert( a, lccrt_plugin_t);
|
||
if ( a->lib )
|
||
{
|
||
dlclose( a->lib);
|
||
a->lib = 0;
|
||
}
|
||
|
||
if ( a->targs )
|
||
{
|
||
for ( k = 0; k < a->num_targs; ++k )
|
||
{
|
||
lccrt_ctx_free( ctx, a->targs[k]);
|
||
lccrt_ctx_free( ctx, a->lccrt_s[k]);
|
||
lccrt_ctx_free( ctx, a->include_s[k]);
|
||
}
|
||
|
||
lccrt_ctx_free( ctx, a->targs);
|
||
lccrt_ctx_free( ctx, a->lccrt_s);
|
||
lccrt_ctx_free( ctx, a->include_s);
|
||
a->targs = 0;
|
||
}
|
||
|
||
lccrt_ctx_free( ctx, a->lib_name);
|
||
lccrt_ctx_free( ctx, a->lccrt_ver);
|
||
lccrt_ctx_free( ctx, a->lccrt_s);
|
||
lccrt_ctx_free( ctx, a->include_s);
|
||
a->lib_name = 0;
|
||
a->lccrt_ver = 0;
|
||
a->lccrt_s = 0;
|
||
a->include_s = 0;
|
||
|
||
a->num_targs = 0;
|
||
a->num_funcs = 0;
|
||
lccrt_ctx_free( ctx, a->funcs);
|
||
a->funcs = 0;
|
||
|
||
return;
|
||
} /* lccrt_ctx_plugin_unload */
|
||
|
||
/**
|
||
* Открытие библиотеки с ассемблером.
|
||
*/
|
||
static int
|
||
lccrt_ctx_load_plugin_lib( lccrt_plugin_t *a, const char *lib_name)
|
||
{
|
||
int k;
|
||
int r = -1;
|
||
char *cur_name = 0;
|
||
lccrt_context_ptr ctx = a->ctx;
|
||
|
||
lccrt_check_type_assert( a, lccrt_plugin_t);
|
||
if ( a->lib )
|
||
{
|
||
lccrt_ctx_error( ctx, 0, "INTERNAL ERROR\n");
|
||
return (r);
|
||
}
|
||
|
||
if ( (lib_name[0] == '/') )
|
||
{
|
||
cur_name = lccrt_ctx_copy_str( ctx, lib_name);
|
||
} else
|
||
{
|
||
cur_name = lccrt_ctx_cat_strs( ctx, ctx->paths.plugins[a->type], "/");
|
||
cur_name = lccrt_ctx_catby_strs( ctx, cur_name, lib_name);
|
||
}
|
||
|
||
a->lib = dlopen( cur_name, RTLD_LAZY);
|
||
if ( !a->lib )
|
||
{
|
||
lccrt_ctx_error( ctx, 0, "Can't load plugin library [%s]\n", cur_name);
|
||
} else
|
||
{
|
||
const char **lname;
|
||
const char **lver;
|
||
const char *(*targs)[];
|
||
int is_asm = (a->type == LCCRT_PLUGIN_TYPE_ASM);
|
||
|
||
a->num_funcs = LCCRT_PLUGIN_ASM_FUNC_LAST;
|
||
a->funcs = lccrt_ctx_mallocn( ctx, void *, a->num_funcs);
|
||
if ( is_asm )
|
||
{
|
||
a->funcs[LCCRT_PLUGIN_ASM_FUNC_COMP] = dlsym( a->lib, LCCRT_ASM_SFUNC_COMPILE);
|
||
a->funcs[LCCRT_PLUGIN_ASM_FUNC_TOOL] = dlsym( a->lib, LCCRT_ASM_SFUNC_GETTOOL);
|
||
if ( !a->funcs[LCCRT_PLUGIN_ASM_FUNC_COMP] )
|
||
{
|
||
lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_ASM_SFUNC_COMPILE);
|
||
|
||
} else if ( !a->funcs[LCCRT_PLUGIN_ASM_FUNC_TOOL] )
|
||
{
|
||
lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_ASM_SFUNC_GETTOOL);
|
||
}
|
||
} else
|
||
{
|
||
lccrt_assert( 0);
|
||
}
|
||
|
||
lname = dlsym( a->lib, LCCRT_PLUGIN_LIBRARY_NAME_S);
|
||
lver = dlsym( a->lib, LCCRT_PLUGIN_LCCRT_VERSION_S);
|
||
targs = dlsym( a->lib, LCCRT_PLUGIN_TARGETS_S);
|
||
if ( !lname
|
||
|| !lname[0] )
|
||
{
|
||
lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_PLUGIN_LIBRARY_NAME_S);
|
||
|
||
} else if ( !lname[0][0] )
|
||
{
|
||
lccrt_ctx_error( ctx, 0, "Plugin library [%s] name [%s] is incorrect\n",
|
||
cur_name, lname[0]);
|
||
|
||
} else if ( !lver
|
||
|| !lver[0] )
|
||
{
|
||
lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_PLUGIN_LCCRT_VERSION_S);
|
||
|
||
} else if ( !targs )
|
||
{
|
||
lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_PLUGIN_TARGETS_S);
|
||
} else
|
||
{
|
||
if ( ctx->verbose.is_base )
|
||
{
|
||
fprintf( stderr, "LCCRT: plugin [%s] config:\n", lib_name);
|
||
}
|
||
|
||
a->lib_name = lccrt_ctx_copy_str( ctx, lname[0]);
|
||
a->lccrt_ver = lccrt_ctx_copy_str( ctx, lver[0]);
|
||
if ( ctx->verbose.is_base )
|
||
{
|
||
fprintf( stderr, " plugin self-name : %s\n", a->lib_name);
|
||
fprintf( stderr, " plugin's version of lccrt-library : %s\n", a->lccrt_ver);
|
||
}
|
||
|
||
a->num_targs = 0;
|
||
for ( k = 0; (*targs)[k]; ++k )
|
||
{
|
||
a->num_targs++;
|
||
}
|
||
|
||
if ( (0 < a->num_targs)
|
||
&& (a->num_targs < LCCRT_CTX_PLUGIN_TARGET_MAX_NUMBER) )
|
||
{
|
||
r = 0;
|
||
a->targs = lccrt_ctx_mallocn( ctx, const char *, a->num_targs);
|
||
a->lccrt_s = lccrt_ctx_mallocn( ctx, const char *, a->num_targs);
|
||
a->include_s = lccrt_ctx_mallocn( ctx, const char *, a->num_targs);
|
||
memset( a->targs, 0, a->num_targs*sizeof( a->lccrt_s[0]));
|
||
memset( a->lccrt_s, 0, a->num_targs*sizeof( a->lccrt_s[0]));
|
||
memset( a->include_s, 0, a->num_targs*sizeof( a->include_s[0]));
|
||
for ( k = 0; k < a->num_targs; ++k )
|
||
{
|
||
char buf[1024] = {0};
|
||
|
||
a->targs[k] = lccrt_ctx_copy_str( ctx, (*targs)[k]);
|
||
if ( ctx->verbose.is_base )
|
||
{
|
||
fprintf( stderr, " plugin's target (%d) : %s\n", k, a->targs[k]);
|
||
}
|
||
|
||
snprintf( buf, 1024, "%s/lib/%s", ctx->paths.home, a->targs[k]);
|
||
a->lccrt_s[k] = lccrt_ctx_copy_str( ctx, buf);
|
||
if ( ctx->verbose.is_base )
|
||
{
|
||
fprintf( stderr, " plugin's target system libraries path : %s\n", a->lccrt_s[k]);
|
||
}
|
||
|
||
snprintf( buf, 1024, "%s/include/%s", ctx->paths.home, a->targs[k]);
|
||
a->include_s[k] = lccrt_ctx_copy_str( ctx, buf);
|
||
if ( ctx->verbose.is_base )
|
||
{
|
||
fprintf( stderr, " plugin's target system include path : %s\n", a->include_s[k]);
|
||
}
|
||
|
||
if ( lccrt_str_eq( a->lib_name, "lccopt-e2k64") )
|
||
{
|
||
FILE *flib = 0;
|
||
|
||
snprintf( buf, 1024, "%s/liblccrt_s.a", a->lccrt_s[k]);
|
||
flib = fopen( buf, "r");
|
||
|
||
if ( !flib )
|
||
{
|
||
r = -1;
|
||
lccrt_ctx_error( ctx, 0, "Can't find system library [liblccrt_s.a] by path [%s]\n",
|
||
a->lccrt_s[k]);
|
||
break;
|
||
} else
|
||
{
|
||
fclose( flib);
|
||
}
|
||
}
|
||
}
|
||
} else
|
||
{
|
||
a->num_targs = 0;
|
||
lccrt_ctx_error( ctx, 0, "Plugin library [%s] number of targets [%d]\n",
|
||
cur_name, a->num_targs);
|
||
}
|
||
}
|
||
}
|
||
|
||
lccrt_ctx_free( ctx, cur_name);
|
||
if ( r )
|
||
{
|
||
lccrt_ctx_plugin_unload( a);
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_load_plugin_lib */
|
||
|
||
/**
|
||
* Поиск lccrt-home пути на основе пути к liblccrt.so (места расположения загруженной библиотеки).
|
||
*/
|
||
char *
|
||
lccrt_ctx_find_home_path( lccrt_ctx_ptr ctx)
|
||
{
|
||
Dl_info dli;
|
||
char *t = 0;
|
||
char *s = 0;
|
||
|
||
dladdr( &lccrt_ctx_find_home_path, &dli);
|
||
t = realpath( dli.dli_fname, 0);
|
||
if ( !t )
|
||
{
|
||
lccrt_ctx_error( ctx, 0, "Can't resolve real path of lccrt-library's location [%s]\n", dli.dli_fname);
|
||
}
|
||
|
||
s = dirname( t);
|
||
if ( !s )
|
||
{
|
||
lccrt_ctx_error( ctx, 0, "Can't resolve directory of lccrt-library's location [%s]\n", t);
|
||
}
|
||
|
||
s = lccrt_ctx_cat_strs( ctx, s, "/lccrt");
|
||
free( t);
|
||
|
||
return (s);
|
||
} /* lccrt_ctx_find_home_path */
|
||
|
||
/**
|
||
* Загрузка плагина.
|
||
*/
|
||
static int
|
||
lccrt_ctx_load_plugin( lccrt_ctx_ptr ctx, lccrt_plugin_type_t type, const char *env, const char *dir)
|
||
{
|
||
int k;
|
||
int r = 0;
|
||
char *f_name = 0;
|
||
FILE *f = 0;
|
||
int num_ps = 0;
|
||
lccrt_plugin_t ps[LCCRT_CTX_PLUGIN_MAX_NUMBER] = {0};
|
||
|
||
if ( getenv( env) )
|
||
{
|
||
ctx->paths.plugins[type] = lccrt_ctx_copy_str( ctx, getenv( env));
|
||
} else
|
||
{
|
||
ctx->paths.plugins[type] = lccrt_ctx_cat_strs( ctx, ctx->paths.plugin, "/");
|
||
ctx->paths.plugins[type] = lccrt_ctx_cat_strs( ctx, ctx->paths.plugins[type], dir);
|
||
}
|
||
|
||
f_name = lccrt_ctx_cat_strs( ctx, ctx->paths.plugins[type], "/plugin.conf");
|
||
f = fopen( f_name, "r");
|
||
if ( !f )
|
||
{
|
||
lccrt_ctx_error( ctx, 0, "Can't open plugin [%s] config file [%s]\n", dir, f_name);
|
||
lccrt_ctx_free( ctx, f_name);
|
||
r = -1;
|
||
} else
|
||
{
|
||
char name[LCCRT_CTX_PLUGIN_NAME_LENGTH + 1];
|
||
|
||
lccrt_ctx_free( ctx, f_name);
|
||
while ( !feof( f) )
|
||
{
|
||
lccrt_getline( f, LCCRT_CTX_PLUGIN_NAME_LENGTH, name);
|
||
if ( (name[0] == '#')
|
||
|| (name[0] == 0) )
|
||
{
|
||
/* Пропускаем текущую строчку. */
|
||
} else
|
||
{
|
||
if ( (num_ps < LCCRT_CTX_PLUGIN_MAX_NUMBER) )
|
||
{
|
||
int is_load = 0;
|
||
|
||
lccrt_check_type_init( ps + num_ps, lccrt_plugin_t);
|
||
ps[num_ps].ctx = ctx;
|
||
ps[num_ps].type = type;
|
||
if ( (lccrt_ctx_load_plugin_lib( ps + num_ps, name) == 0) )
|
||
{
|
||
is_load = 1;
|
||
num_ps++;
|
||
for ( k = 0; k < num_ps - 1; ++k )
|
||
{
|
||
if ( lccrt_str_eq( ps[k].lib_name, ps[num_ps-1].lib_name) )
|
||
{
|
||
is_load = 0;
|
||
lccrt_ctx_error( ctx, 0, "Duplicate plugin name [%s]\n",
|
||
ps[k].lib_name);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( !is_load )
|
||
{
|
||
lccrt_ctx_error( ctx, 0, "Can't load plugin [%s]\n", name);
|
||
for ( k = 0; k < num_ps; ++k )
|
||
{
|
||
lccrt_ctx_plugin_unload( ps + k);
|
||
}
|
||
|
||
lccrt_context_delete( ctx);
|
||
return (0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
fclose( f);
|
||
if ( (num_ps == 0) )
|
||
{
|
||
//lccrt_ctx_warning( ctx, 0, "The plugin [%s] set is empty\n", dir);
|
||
} else
|
||
{
|
||
ctx->num_plgs[type] = num_ps;
|
||
ctx->plgs[type] = lccrt_ctx_memdup( ctx, ps, num_ps * sizeof( ps[0]));
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_load_plugin */
|
||
|
||
/**
|
||
* Создание контекста (конструктор).
|
||
* ---------------------------------
|
||
* @param mem менеджер памяти (0 - менеджер по умолчанию)
|
||
* @param err менеджер сообщений об ошибках (0 - менеджер по умолчанию)
|
||
* @result новый контекст, созданный с помощью менеджера памяти
|
||
*
|
||
* @ingroup tyCtxFns
|
||
*/
|
||
lccrt_context_ptr
|
||
lccrt_context_new( lccrt_mem_ptr mem, lccrt_err_ptr err)
|
||
{
|
||
int k;
|
||
lccrt_context_ptr ctx = 0;
|
||
FILE *pc = 0;
|
||
|
||
if ( !mem )
|
||
{
|
||
mem = &lccrt_std_mem;
|
||
}
|
||
|
||
if ( !err )
|
||
{
|
||
err = &lccrt_std_err;
|
||
}
|
||
|
||
if ( getenv( "LCCRT_ERRDIR") )
|
||
{
|
||
err = &lccrt_dir_err;
|
||
}
|
||
|
||
ctx = (*mem->palloc)( mem->pool, sizeof( lccrt_context_t));
|
||
memset( ctx, 0, sizeof( lccrt_context_t));
|
||
lccrt_check_type_init( ctx, lccrt_context_t);
|
||
ctx->mem = *mem;
|
||
ctx->err = *err;
|
||
ctx->modules = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR);
|
||
ctx->module_max = 0;
|
||
|
||
if ( getenv( "LCCRT_HOME") )
|
||
{
|
||
ctx->paths.home = lccrt_ctx_copy_str( ctx, getenv( "LCCRT_HOME"));
|
||
} else
|
||
{
|
||
ctx->paths.home = lccrt_ctx_find_home_path( ctx);
|
||
}
|
||
|
||
if ( getenv( "LCCRT_HOME_PLUGIN") )
|
||
{
|
||
ctx->paths.plugin = lccrt_ctx_copy_str( ctx, getenv( "LCCRT_HOME_PLUGIN"));
|
||
} else
|
||
{
|
||
ctx->paths.plugin = lccrt_ctx_cat_strs( ctx, ctx->paths.home, "/plugin");
|
||
}
|
||
|
||
if ( getenv( "LCCRT_VERBOSE") )
|
||
{
|
||
ctx->verbose.is_base = atoi( getenv( "LCCRT_VERBOSE"));
|
||
}
|
||
|
||
lccrt_ctx_load_plugin( ctx, LCCRT_PLUGIN_TYPE_ASM, "LCCRT_PLUGIN_TYPE_ASM", "asm");
|
||
|
||
return (ctx);
|
||
} /* lccrt_context_new */
|
||
|
||
/**
|
||
* Удаление контекста (деструктор).
|
||
* --------------------------------
|
||
* @param ctx удаляемый контекст
|
||
*
|
||
* @ingroup tyCtxFns
|
||
*/
|
||
void
|
||
lccrt_context_delete( lccrt_context_ptr ctx)
|
||
{
|
||
lccrt_hash_entry_ptr he;
|
||
|
||
lccrt_check_type_assert( ctx, lccrt_context_t);
|
||
|
||
/* Удаляем все ранее созданные модули. */
|
||
while ( (he = lccrt_hash_first( ctx->modules)) )
|
||
{
|
||
lccrt_module_delete( (lccrt_module_ptr)lccrt_hash_get_key( he));
|
||
}
|
||
lccrt_hash_delete( ctx->modules);
|
||
|
||
lccrt_ctx_free( ctx, ctx->paths.home);
|
||
lccrt_ctx_free( ctx, ctx->paths.plugin);
|
||
lccrt_ctx_free( ctx, ctx->paths.plugins[LCCRT_PLUGIN_TYPE_ASM]);
|
||
|
||
lccrt_check_type_done( ctx, lccrt_context_t);
|
||
(*ctx->mem.pfree)( ctx->mem.pool, ctx);
|
||
|
||
return;
|
||
} /* lccrt_context_delete */
|
||
|
||
/**
|
||
* Прочитать свойство.
|
||
*/
|
||
int
|
||
lccrt_context_get_verbose_ir( lccrt_context_ptr ctx)
|
||
{
|
||
int r = ctx->verbose.is_ir;
|
||
|
||
lccrt_check_type_assert( ctx, lccrt_context_t);
|
||
|
||
return (r);
|
||
} /* lccrt_context_get_verbose_ir */
|
||
|
||
/**
|
||
* Установить свойство.
|
||
*/
|
||
void
|
||
lccrt_context_set_verbose_ir( lccrt_context_ptr ctx, int value)
|
||
{
|
||
lccrt_check_type_assert( ctx, lccrt_context_t);
|
||
ctx->verbose.is_ir = value;
|
||
|
||
return;
|
||
} /* lccrt_context_set_verbose_ir */
|
||
|
||
/**
|
||
* Поиск плагина.
|
||
*/
|
||
static lccrt_plugin_t *
|
||
lccrt_context_find_plugin( lccrt_context_ptr c, lccrt_plugin_type_t type, const char *plg_name, int is_assert)
|
||
{
|
||
int k;
|
||
lccrt_plugin_t *r = 0;
|
||
|
||
if ( plg_name )
|
||
{
|
||
for ( k = 0; k < c->num_plgs[type]; ++k )
|
||
{
|
||
if ( lccrt_str_eq( plg_name, c->plgs[type][k].lib_name) )
|
||
{
|
||
r = c->plgs[type] + k;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( !r
|
||
&& is_assert )
|
||
{
|
||
lccrt_ctx_error( c, 0, "No plugin with name [%s]\n", plg_name);
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_context_find_plugin */
|
||
|
||
/**
|
||
* Поиск плагина.
|
||
*/
|
||
static lccrt_plg_ptr
|
||
lccrt_context_find_plugin_for_arch( lccrt_context_ptr c, lccrt_plugin_type_t type, const char *arch)
|
||
{
|
||
int k, i;
|
||
lccrt_plg_ptr r = 0;
|
||
|
||
for ( k = 0; k < c->num_plgs[type] && !r; ++k )
|
||
{
|
||
lccrt_plg_ptr p = c->plgs[type] + k;
|
||
|
||
for ( i = 0; i < p->num_targs; ++i )
|
||
{
|
||
if ( lccrt_str_eq( arch, p->targs[i]) )
|
||
{
|
||
r = p;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( !r )
|
||
{
|
||
lccrt_ctx_error( c, 0, "No plugin for target [%s]\n", arch);
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_context_find_plugin_for_arch */
|
||
|
||
/**
|
||
* Получить ссылку на плагин.
|
||
*/
|
||
lccrt_plg_ptr
|
||
lccrt_context_get_plugin_asm( lccrt_ctx_ptr ctx, const char *plg_name)
|
||
{
|
||
lccrt_plg_ptr r = lccrt_context_find_plugin( ctx, LCCRT_PLUGIN_TYPE_ASM, plg_name, 1);
|
||
|
||
return (r);
|
||
} /* lccrt_context_get_plugin_asm */
|
||
|
||
/**
|
||
* Поиск ассемблера.
|
||
*/
|
||
static int
|
||
lccrt_context_find_target( lccrt_context_ptr c, lccrt_plugin_t *a, const char *targ, int is_assert)
|
||
{
|
||
int k;
|
||
int r = -1;
|
||
|
||
if ( a )
|
||
{
|
||
if ( targ )
|
||
{
|
||
for ( k = 0; k < a->num_targs; ++k )
|
||
{
|
||
if ( lccrt_str_eq( targ, a->targs[k]) )
|
||
{
|
||
r = k;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( (r < 0)
|
||
&& is_assert )
|
||
{
|
||
lccrt_ctx_error( c, 0, "In plugin [%s] no target [%s]\n", a->lib_name, targ);
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_context_find_target */
|
||
|
||
/**
|
||
* Компиляция модуля.
|
||
*/
|
||
int
|
||
lccrt_module_compile_asm( lccrt_module_ptr m, const char *asm_lib,
|
||
lccrt_asm_compile_config_t *cnf)
|
||
{
|
||
int k;
|
||
int r = -1;
|
||
lccrt_context_ptr c = lccrt_module_get_context( m);
|
||
lccrt_plugin_t *a = lccrt_context_get_plugin_asm( c, asm_lib);
|
||
|
||
if ( cnf->is_jit )
|
||
{
|
||
assert( 0);
|
||
}
|
||
|
||
if ( 0 )
|
||
{
|
||
lccrt_fs_ptr fs = lccrt_fs_new_file( c, stdout);
|
||
|
||
lccrt_asm_print_module( fs, m);
|
||
lccrt_fs_delete( fs);
|
||
}
|
||
|
||
if ( (lccrt_context_find_target( c, a, cnf->target, 1) >= 0) )
|
||
{
|
||
r = ((lccrt_asm_compile_t)a->funcs[LCCRT_PLUGIN_ASM_FUNC_COMP])( m, cnf);
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_module_compile_asm */
|
||
|
||
/**
|
||
* Получить значение утилиты.
|
||
*/
|
||
const char *
|
||
lccrt_context_get_toolchain( lccrt_ctx_ptr c, const char *asm_lib, const char *targ,
|
||
const char *tool_type, const char *tool_name)
|
||
{
|
||
const char *r = "";
|
||
lccrt_plugin_t *a = lccrt_context_get_plugin_asm( c, asm_lib);
|
||
int k = lccrt_context_find_target( c, a, targ, 1);
|
||
|
||
if ( (k >= 0) )
|
||
{
|
||
if ( lccrt_str_eq( tool_type, "lib_path")
|
||
&& lccrt_str_eq( tool_name, "lccrt_s") )
|
||
{
|
||
r = a->lccrt_s[k];
|
||
|
||
} else if ( lccrt_str_eq( tool_type, "include_path")
|
||
&& lccrt_str_eq( tool_name, "system") )
|
||
{
|
||
r = a->include_s[k];
|
||
} else
|
||
{
|
||
r = ((lccrt_asm_gettool_t)a->funcs[LCCRT_PLUGIN_ASM_FUNC_TOOL])( targ, tool_type, tool_name);
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_context_get_toolchain */
|
||
|
||
/**
|
||
* Получить значение поля.
|
||
*/
|
||
lccrt_err_t
|
||
lccrt_context_get_err_info( lccrt_ctx_ptr ctx)
|
||
{
|
||
lccrt_err_t r;
|
||
|
||
lccrt_check_type_assert( ctx, lccrt_context_t);
|
||
r = ctx->err;
|
||
|
||
return (r);
|
||
} /* lccrt_context_get_err_info */
|
||
|
||
/**
|
||
* Установить значение поля.
|
||
*/
|
||
lccrt_err_t
|
||
lccrt_context_set_err_info( lccrt_ctx_ptr ctx, lccrt_err_t err)
|
||
{
|
||
lccrt_err_t r;
|
||
|
||
lccrt_check_type_assert( ctx, lccrt_context_t);
|
||
r = ctx->err;
|
||
ctx->err = err;
|
||
|
||
return (r);
|
||
} /* lccrt_context_set_err_info */
|
||
|
||
/**
|
||
* Выделение участка памяти.
|
||
*/
|
||
void *
|
||
lccrt_ctx_malloc_func( lccrt_ctx_ptr ctx, uint64_t size)
|
||
{
|
||
void *r;
|
||
|
||
lccrt_check_type_assert( ctx, lccrt_context_t);
|
||
r = ctx->mem.palloc( &(ctx->mem), size);
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_malloc_func */
|
||
|
||
/**
|
||
* Выделение участка памяти.
|
||
*/
|
||
void *
|
||
lccrt_ctx_realloc_func( lccrt_ctx_ptr ctx, void *ptr, uint64_t size)
|
||
{
|
||
void *r;
|
||
|
||
lccrt_check_type_assert( ctx, lccrt_context_t);
|
||
r = ctx->mem.prealloc( &(ctx->mem), ptr, size);
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_realloc_func */
|
||
|
||
/**
|
||
* Освобождение участка памяти.
|
||
*/
|
||
void *
|
||
lccrt_ctx_free_func( lccrt_ctx_ptr ctx, void *ptr)
|
||
{
|
||
lccrt_check_type_assert( ctx, lccrt_context_t);
|
||
if ( ptr )
|
||
{
|
||
ctx->mem.pfree( &(ctx->mem), ptr);
|
||
}
|
||
|
||
return (0);
|
||
} /* lccrt_ctx_free_func */
|
||
|
||
/**
|
||
* Копирование участка памяти.
|
||
*/
|
||
void *
|
||
lccrt_ctx_memdup_func( lccrt_ctx_ptr ctx, void *ptr, uint64_t size)
|
||
{
|
||
void *r = 0;
|
||
|
||
lccrt_check_type_assert( ctx, lccrt_context_t);
|
||
if ( (size > 0) )
|
||
{
|
||
r = ctx->mem.palloc( &(ctx->mem), size);
|
||
if ( ptr )
|
||
{
|
||
memcpy( r, ptr, size);
|
||
} else
|
||
{
|
||
memset( r, 0, size);
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_memdup_func */
|
||
|
||
/**
|
||
* Копирование массива.
|
||
*/
|
||
void **
|
||
lccrt_ctx_copy_arr_func( lccrt_ctx_ptr ctx, void **ptr, uint64_t size, uint64_t len)
|
||
{
|
||
uint64_t k;
|
||
void **r = 0;
|
||
|
||
if ( (len > 0) )
|
||
{
|
||
r = lccrt_ctx_malloc_func( ctx, len * sizeof( r[0]));
|
||
for ( k = 0; k < len; ++k )
|
||
{
|
||
r[k] = lccrt_ctx_memdup_func( ctx, ptr[k], size);
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_copy_arr_func */
|
||
|
||
/**
|
||
* Копирование участка памяти.
|
||
*/
|
||
char *
|
||
lccrt_ctx_copy_str( lccrt_ctx_ptr ctx, const char *str)
|
||
{
|
||
void *r = 0;
|
||
|
||
if ( str )
|
||
{
|
||
r = (char *)lccrt_ctx_memdup_func( ctx, (void *)str, strlen( str) + 1);
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_copy_str */
|
||
|
||
/**
|
||
* Объединение строк.
|
||
*/
|
||
char *
|
||
lccrt_ctx_cat_strs( lccrt_ctx_ptr ctx, const char *str1, const char *str2)
|
||
{
|
||
char *r = 0;
|
||
int len1 = str1 ? strlen( str1) : 0;
|
||
int len2 = str2 ? strlen( str2) : 0;
|
||
|
||
r = lccrt_ctx_malloc_func( ctx, len1 + len2 + 1);
|
||
memcpy( r, str1, len1);
|
||
memcpy( r + len1, str2, len2);
|
||
r[len1 + len2] = 0;
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_cat_strs */
|
||
|
||
/**
|
||
* Объединение строк.
|
||
*/
|
||
char *
|
||
lccrt_ctx_catby_strs( lccrt_ctx_ptr ctx, const char *str1, const char *str2)
|
||
{
|
||
char *r = lccrt_ctx_cat_strs( ctx, str1, str2);
|
||
|
||
lccrt_ctx_free( ctx, str1);
|
||
|
||
return (r);
|
||
} /* lccrt_ctx_catby_strs */
|
||
|
||
/**
|
||
* Старт внешней программы с перенаправлением стандартного потока вывода
|
||
* на канальные файловые дескрипторы.
|
||
*/
|
||
int
|
||
lccrt_exec_with_fork( const char *path, /* первый аргумент execv */
|
||
char *argv[], /* второй аргумент execv */
|
||
pid_t *wpid,
|
||
int fds[2]) /* fds[0] - выходной декскриптор для внешней программы,
|
||
fds[1] - входной декскриптор для внешней программы */
|
||
{
|
||
pid_t pid;
|
||
int ifd[2] = {-1, -1};
|
||
int ofd[2] = {-1, -1};
|
||
int r = -1;
|
||
|
||
if ( wpid )
|
||
{
|
||
wpid[0] = -1;
|
||
}
|
||
|
||
if ( fds )
|
||
{
|
||
if ( (pipe( ifd) != 0) )
|
||
{
|
||
/* Не удалось создать канал. */
|
||
return (r);
|
||
}
|
||
|
||
if ( (pipe( ofd) != 0) )
|
||
{
|
||
/* Не удалось создать канал. */
|
||
return (r);
|
||
}
|
||
}
|
||
|
||
pid = fork();
|
||
if ( (pid < 0) )
|
||
{
|
||
/* Не удалось создать процесс. */
|
||
return (r);
|
||
}
|
||
|
||
if ( (pid == 0) )
|
||
{
|
||
/* Запускаем внешнюю программу. */
|
||
if ( fds )
|
||
{
|
||
close( ifd[1]);
|
||
dup2( ifd[0], STDIN_FILENO);
|
||
close( ifd[0]);
|
||
|
||
close( ofd[0]);
|
||
dup2( ofd[1], STDOUT_FILENO);
|
||
dup2( ofd[1], STDERR_FILENO);
|
||
close( ofd[1]);
|
||
}
|
||
|
||
execvp( path, argv);
|
||
} else
|
||
{
|
||
/* Возвращаем файловые дескрипторы с вводом и выводом внешней программы. */
|
||
r = 0;
|
||
if ( fds )
|
||
{
|
||
close( ifd[0]);
|
||
close( ofd[1]);
|
||
|
||
fds[0] = ofd[0];
|
||
fds[1] = ifd[1];
|
||
}
|
||
|
||
if ( wpid )
|
||
{
|
||
(*wpid) = pid;
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_exec_with_fork */
|