ktcc: added __attribute__((dllimport)) support

git-svn-id: svn://kolibrios.org@9782 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Coldy 2022-04-24 17:28:28 +00:00
parent 3dddd1c687
commit db785142be
10 changed files with 148 additions and 58 deletions

View File

@ -1,5 +1,5 @@
Версия расширения KX - 0.4.3
Версия расширения KX - 0.4.6
Обзор новых возможностей
@ -19,9 +19,10 @@
+ Уменьшенный размер образа
Поскольку загрузчик библиотек больше не нужно размещать в каждом
приложении, это уменьшает размер образа. Больше не нужен слой C
(C layer), все зависимые библиотеки загружаются, а также инициализируются
автоматически. Также используется компактный формат таблицы импорта.
приложении, это уменьшает размер образа. Больше не нужна фукнция вызова
инициализации библиотек в C layer, все зависимые библиотеки загружаются,
а также инициализируются автоматически. Кроме того используется компактные
формат таблицы импорта, а также вызовы функций из динамических библиотек.
+ Обратная совместимость
Если Вы по каким то причинам не хотите, либо пока не готовы использовать

View File

@ -1,3 +1,16 @@
0.4.6
+ Добавлена поддержка __attribute__((dllimport))
Новый способ вызова импортов дополнительно уменьшает размер приложений
+ Добавлена обработка ошибок линкера при неправильном использовании типов
вызовов функций импорта, в том числе для сторонних объектных файлов
В частности, вызов без префикса __attribute__((dllimport)) перед
импортируемой функцией в файле заголовка вызывает останов линкера
+ Добавлено отображение информации о номере версии расширения KX (опция -vv)
0.4.5
+ Добавлено подключение %ktcc_root%/include через файл tcc.conf
+
+
0.4.4
+ Исправлена ошибка при задании неиспользуемых библиотек

View File

@ -1,16 +1,29 @@
Быстрый старт
Для использования новых возможностей предоставляемых расширением KX
необходимо использовать файл конфигурации tcc.conf в папке где расположен tcc
Этот файл перенастраивает директорию %ktcc_root%\ на %ktcc_root%\kx.
tcc используется как обычно (см. справку tcc). Расширение KX использользует
файлы определений символов (*.def) для динамических библиотек (файлы *.o,
не требуются, исключение - статические *.o, если они нужны для работы
программы).
В данной директории присутствует папка lib с файлами
*.def, crt.0 и libtcc.a
Примеры по сборке см. в директории /samples
Примечание:
ключ -nobss был удален, так как он не имеет смысла (ранее генерировавшаяся
bss секция заполнялась нулями и занимала ненужное место в файле, эта секция
не должна содержаться в образе и ядро инициализирует эту часть нялями
автоматически при загрузке)
В директории /lib поставляются файлы *.def (определение символов динамических
библиотек), crt0.o (поддержка кода С) и *libtcc.a (вспомогательная библиотека
tcc), а также некоторые статические библиотеки *.a. Кроме того, имеется
библиотека tiny.o для возможности линковки приложений без поддержки кода С,
в том числе объектных файлов созданные сторонними компиляторами.
Во избежание конфликтов бибилиотек с использованием возможностей
предоставляемых расширением KX рекомендуется использовать только одну
директорию с библиотеками. Если определено несколько директорий библиотек,
директорию с библиотеками [++, в которой не должно быть взаимоисключающих
библиотек]. Если определено несколько директорий библиотек,
в каждой из них не должно быть конфликтных библиотек. Например,
при таком подключении библиотеки
@ -22,14 +35,8 @@
работы приложения с расширением KX все динамические библиотеки должны быть
обработаны только с *.def
В остальном tcc используется как обычно (см. справку tcc)
Примечание:
ключ -nobss был удален, так как он не имеет смысла (ранее генерировавшаяся
bss секция заполнялась нулями и занимала ненужное место в файле, эта секция
не должна содержаться в образе и ядро инициализирует эту часть нялями
автоматически при загрузке)
Файлы определения символов
Расширение KX использует файлы определений символов (*.def). Файлы *.def
используют простой формат и могут создваться и редактироваться в любом
удобном текстовом редакторе. Структура файла *.def описана ниже.
@ -54,12 +61,37 @@
; все остальные символы библиотеки
Заголовочные файлы динамических библиотек
Для импотируемых функций поддерживается два способа их объявления:
- с префиксом атрибута импорта (рекомендуется для новых бибилиотек).
Данный способ дополнительно уменьшает размер приложения.
__attribute__((dllimport)) void foo(int);
- внешняя функция с вызовом по указателю (устаревший способ, используется
для совместимости с имеющимися на данный момент заголовками)
extern int (*foo)(const char*);
ВНИМАНИЕ:
объявление импортируемой функции с вызовом по указателю без спецификатора
extern является ошибкой, которую tcc не может отследить, так как данная
конструкция является правильной с точки зрения языка С
int (*foo)(const char*); => ошибка!!!
Объявление импортируемых функций без __attribute__((dllimport))
не поддерживается и будет генерировать ошибку линкера
void foo(int); => ошибка!!!, останов линкера.
Проверка поддержки расширения KX
Для проверки, что tcc поддерживает расширение KX:
1. в командной строке наберите
tcc -v
Строка ниже означает, что имеется поддерка расширения KX
tcc version 0.9.26 (i386 KolibriOS/KX extension)
tcc version 0.9.26 (i386 KolibriOS/KX extension 0.4.6)
2. В коде для условной компиляции используйте директивы препроцессора
проверки предопределенного макроса __KX__, например
@ -75,24 +107,3 @@
использовать новые преимущества. При использовании текущих
особенностей разделять код описанным в примере выше способом в
большинстве случаев не требуется.
Обеспечение совместимости
Если для обеспечения совместимости необходимо отделить код, чтобы его можно
было использовать как с расширением KX, так и без него, Вы можете определить
дополнительный макрос и таким образом разделять код на нужные участки,
например. Настоятельно рекомендуется использовать только код с поддержкой
расширения KX.
...
#ifdef _C_LAYER
// Код который выполняется без поддержки расширения KX
/ использующий старый метод загрузки
if(!kolibri_libimg_init()){ // Загружаем libimg.obj
notify_show("Libimg.obj not loaded!' -E");
exit(0);
}
#endif
...

View File

@ -353,6 +353,14 @@ static void gen_static_call(int v)
static void gcall_or_jmp(int is_jmp)
{
int r;
#ifdef TCC_TARGET_KX
if (vtop->type.t & VT_IMPORT) {
o(0x15ff);
greloc(cur_text_section, vtop->sym, ind, R_386_32);
gen_le32(0);
return;
}
#endif
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant case */
if (vtop->r & VT_SYM) {

View File

@ -660,7 +660,11 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
else
sh_num = section->sh_num;
if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
if (((sym->type.t & VT_BTYPE) == VT_FUNC
#ifdef TCC_TARGET_KX
) && ((vtop->type.t & VT_IMPORT) == 0
#endif
)) {
sym_type = STT_FUNC;
} else if ((sym->type.t & VT_BTYPE) == VT_VOID) {
sym_type = STT_NOTYPE;
@ -859,11 +863,14 @@ PUB_FUNC void tcc_error_noabort(const char *fmt, ...)
PUB_FUNC void tcc_error(const char *fmt, ...)
{
TCCState *s1 = tcc_state;
// { Edit by Coldy
if (fmt) {
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);

View File

@ -59,7 +59,8 @@ static void display_info(TCCState *s, int what)
#elif defined TCC_TARGET_MEOS
" KolibriOS"
#ifdef TCC_TARGET_KX
"/KX extension"
"/KX extension "
TCC_KX_VERSION_INFO
#endif
#else
" Linux"

View File

@ -1217,6 +1217,9 @@ PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line);
#define realloc(p, s) use_tcc_realloc(p, s)
#undef strdup
#define strdup(s) use_tcc_strdup(s)
// { Added by Coldy
#define tcc_abort() tcc_error(0)
// }
PUB_FUNC void tcc_memstats(int bench);
PUB_FUNC void tcc_error_noabort(const char *fmt, ...);
PUB_FUNC NORETURN void tcc_error(const char *fmt, ...);

View File

@ -6316,7 +6316,7 @@ static int decl0(int l, int is_for_loop_init)
if (ad.a.weak)
type.t |= VT_WEAK;
#ifdef TCC_TARGET_PE
#if defined(TCC_TARGET_PE) || defined(TCC_TARGET_KX)
if (ad.a.func_import)
type.t |= VT_IMPORT;
if (ad.a.func_export)

View File

@ -1,7 +1,7 @@
/*
* TCCKX.C - KolibriOS/KX file output for the TinyC Compiler
*
* Copyright (c) 2021 Coldy
* Copyright (c) 2021-2022 Coldy
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -18,6 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define TCC_KX_VERSION_INFO "0.4.6"
typedef struct {
char magic[4];
long flags;
@ -67,7 +69,7 @@ typedef struct {
if (dynsym_index == 0) {
//if (strcmp(name, __kx_import_table_sym) != 0) {
tcc_error/*_noabort*/("undefined symbol '%s'", name);
tcc_error/*_noabort*/("(kx) undefined symbol '%s'", name);
}
// KOS support 32 bit only
@ -315,6 +317,38 @@ typedef struct {
}
}
// This routine is called from build_reloc to check the code for incorrect import calls
void kx_check_import_error(int reloc_type, const char* code_base, Elf32_Addr offset, const char* symbol_name) {
unsigned char fError = 0;
char* p = (char*)(offset + code_base);
// Hook for "[extern] rtype foo([?])" declaration
if (((unsigned char)*((char*)(p-1))) == 0xe8){
// call m32
tcc_error_noabort("import symbol '%s' has direct call (not supported),\n\t use __attribute__((dllimport)) prefix", symbol_name);
fError = 1;
}
// Hook for MSVC "__declspec(dllimport) rtype(*foo)([?])"
/*if ((((unsigned char)*(p + 4)) == 0xff) &&
(((unsigned char)*(p + 5)) == 0x10)) {*/
if (*((uint16_t*)(p + 4)) == 0x10ff) {
/*
(mov eax [m32])
call dword[eax]
*/
tcc_error_noabort("import symbol '%s' has unsupported call type", symbol_name);
fError = 1;
}
if (reloc_type == R_386_PC32) {
tcc_error_noabort("incorrect relocation type for import symbol '%s'", symbol_name);
fError = 1;
}
if (fError)
tcc_abort();
}
#if /*!*/defined(_DEBUG)// && !defined(_WIN32)
#define kx_debug_output printf
#else

View File

@ -2,7 +2,7 @@
* TCCMEOS.C - KolibriOS/MenuetOS file output for the TinyC Compiler
*
* Copyright (c) 2006 Andrey Khalyavin
* Copyright (c) 2021 Coldy (KX extension)
* Copyright (c) 2021-2022 Coldy (KX extension)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -58,6 +58,7 @@ typedef struct {
#ifdef TCC_TARGET_KX
void kx_init(me_info* me);
void kx_build_imports(me_info* me);
void kx_check_import_error(int reloc_type, const char* code_base, Elf32_Addr offset, const char* symbol_name);
long kx_get_header_length(me_info* me);
void kx_write_header(me_info* me, FILE* f);
void kx_write_imports(me_info* me, FILE* f);
@ -112,8 +113,11 @@ void build_reloc(me_info* me)
rel=rel_;
int type = ELF32_R_TYPE(rel->r_info);
rel_=rel+1;
if (type != R_386_PC32 && type != R_386_32)
if (type != R_386_PC32 && type != R_386_32) {
// gcc (and friends) object files is used?
tcc_error("unsupported relocation type %d", type);
continue;
}
int sym = ELF32_R_SYM(rel->r_info);
if (sym>symtab_section->data_offset/sizeof(Elf32_Sym))
continue;
@ -121,34 +125,42 @@ void build_reloc(me_info* me)
int sect=esym->st_shndx;
int sh_addr;
ss=findsection(me,sect);
const char* sym_name = strtab_section->data + esym->st_name;
int sym_index;
Elf32_Sym* dyn_sym;
// Import has more less priority in relation to local symbols
if (ss==0)
{
const char *sym_name = strtab_section->data + esym->st_name;
#ifdef TCC_TARGET_KX
int sym_index = find_elf_sym(me->s1->dynsymtab_section, sym_name);
Elf32_Sym* dyn_sym;
sym_index = find_elf_sym(me->s1->dynsymtab_section, sym_name);
if (sym_index == 0) {
#endif
tcc_error_noabort("undefined symbol '%s'", sym_name);
continue;
tcc_error_noabort("undefined import symbol '%s'", sym_name);
continue;
#ifdef TCC_TARGET_KX
}
dyn_sym = &((ElfW(Sym) *)me->s1->dynsymtab_section->data)[sym_index];
sh_addr = dyn_sym->st_value;
if (sh_addr == 0) {
tcc_error_noabort("symbol '%s' has zero value", sym_name);
tcc_error_noabort("import symbol '%s' has zero value", sym_name);
continue;
}
// Stop linking if incorrect import
kx_check_import_error(type, s->data, rel->r_offset, sym_name);
#endif
}
else
else {
if (esym->st_shndx == SHN_UNDEF)
tcc_error("unresolved external symbol '%s'", sym_name);
sh_addr = ss->sh_addr;
}
if (rel->r_offset>s->data_size)
continue;
if (type==R_386_PC32)
*(int*)(rel->r_offset+s->data)+=/*ss->*/sh_addr+esym->st_value-rel->r_offset-s->sh_addr;
*(int*)(rel->r_offset+s->data)+= sh_addr+esym->st_value-rel->r_offset-s->sh_addr;
else if (type==R_386_32)
*(int*)(rel->r_offset+s->data)+=/*ss->*/sh_addr+esym->st_value;
*(int*)(rel->r_offset+s->data)+= sh_addr+esym->st_value;
}
rel=rel_;
s=s->next;