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 0.4.4
+ Исправлена ошибка при задании неиспользуемых библиотек + Исправлена ошибка при задании неиспользуемых библиотек

View File

@ -1,16 +1,29 @@
Быстрый старт Быстрый старт
Для использования новых возможностей предоставляемых расширением KX
необходимо использовать файл конфигурации tcc.conf в папке где расположен tcc
Этот файл перенастраивает директорию %ktcc_root%\ на %ktcc_root%\kx.
В данной директории присутствует папка lib с файлами tcc используется как обычно (см. справку tcc). Расширение KX использользует
*.def, crt.0 и libtcc.a файлы определений символов (*.def) для динамических библиотек (файлы *.o,
не требуются, исключение - статические *.o, если они нужны для работы
программы).
Примеры по сборке см. в директории /samples
Примечание:
ключ -nobss был удален, так как он не имеет смысла (ранее генерировавшаяся
bss секция заполнялась нулями и занимала ненужное место в файле, эта секция
не должна содержаться в образе и ядро инициализирует эту часть нялями
автоматически при загрузке)
В директории /lib поставляются файлы *.def (определение символов динамических
библиотек), crt0.o (поддержка кода С) и *libtcc.a (вспомогательная библиотека
tcc), а также некоторые статические библиотеки *.a. Кроме того, имеется
библиотека tiny.o для возможности линковки приложений без поддержки кода С,
в том числе объектных файлов созданные сторонними компиляторами.
Во избежание конфликтов бибилиотек с использованием возможностей Во избежание конфликтов бибилиотек с использованием возможностей
предоставляемых расширением KX рекомендуется использовать только одну предоставляемых расширением KX рекомендуется использовать только одну
директорию с библиотеками. Если определено несколько директорий библиотек, директорию с библиотеками [++, в которой не должно быть взаимоисключающих
библиотек]. Если определено несколько директорий библиотек,
в каждой из них не должно быть конфликтных библиотек. Например, в каждой из них не должно быть конфликтных библиотек. Например,
при таком подключении библиотеки при таком подключении библиотеки
@ -22,14 +35,8 @@
работы приложения с расширением KX все динамические библиотеки должны быть работы приложения с расширением KX все динамические библиотеки должны быть
обработаны только с *.def обработаны только с *.def
В остальном tcc используется как обычно (см. справку tcc)
Примечание:
ключ -nobss был удален, так как он не имеет смысла (ранее генерировавшаяся
bss секция заполнялась нулями и занимала ненужное место в файле, эта секция
не должна содержаться в образе и ядро инициализирует эту часть нялями
автоматически при загрузке)
Файлы определения символов Файлы определения символов
Расширение KX использует файлы определений символов (*.def). Файлы *.def Расширение KX использует файлы определений символов (*.def). Файлы *.def
используют простой формат и могут создваться и редактироваться в любом используют простой формат и могут создваться и редактироваться в любом
удобном текстовом редакторе. Структура файла *.def описана ниже. удобном текстовом редакторе. Структура файла *.def описана ниже.
@ -53,13 +60,38 @@
[libname_]entry2 [libname_]entry2
; все остальные символы библиотеки ; все остальные символы библиотеки
Заголовочные файлы динамических библиотек
Для импотируемых функций поддерживается два способа их объявления:
- с префиксом атрибута импорта (рекомендуется для новых бибилиотек).
Данный способ дополнительно уменьшает размер приложения.
__attribute__((dllimport)) void foo(int);
- внешняя функция с вызовом по указателю (устаревший способ, используется
для совместимости с имеющимися на данный момент заголовками)
extern int (*foo)(const char*);
ВНИМАНИЕ:
объявление импортируемой функции с вызовом по указателю без спецификатора
extern является ошибкой, которую tcc не может отследить, так как данная
конструкция является правильной с точки зрения языка С
int (*foo)(const char*); => ошибка!!!
Объявление импортируемых функций без __attribute__((dllimport))
не поддерживается и будет генерировать ошибку линкера
void foo(int); => ошибка!!!, останов линкера.
Проверка поддержки расширения KX Проверка поддержки расширения KX
Для проверки, что tcc поддерживает расширение KX: Для проверки, что tcc поддерживает расширение KX:
1. в командной строке наберите 1. в командной строке наберите
tcc -v tcc -v
Строка ниже означает, что имеется поддерка расширения KX Строка ниже означает, что имеется поддерка расширения KX
tcc version 0.9.26 (i386 KolibriOS/KX extension) tcc version 0.9.26 (i386 KolibriOS/KX extension 0.4.6)
2. В коде для условной компиляции используйте директивы препроцессора 2. В коде для условной компиляции используйте директивы препроцессора
проверки предопределенного макроса __KX__, например проверки предопределенного макроса __KX__, например
@ -74,25 +106,4 @@
определен всегда, даже если Вы по каким то причинам не желаете определен всегда, даже если Вы по каким то причинам не желаете
использовать новые преимущества. При использовании текущих использовать новые преимущества. При использовании текущих
особенностей разделять код описанным в примере выше способом в особенностей разделять код описанным в примере выше способом в
большинстве случаев не требуется. большинстве случаев не требуется.
Обеспечение совместимости
Если для обеспечения совместимости необходимо отделить код, чтобы его можно
было использовать как с расширением 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) static void gcall_or_jmp(int is_jmp)
{ {
int r; 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) { if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant case */ /* constant case */
if (vtop->r & VT_SYM) { if (vtop->r & VT_SYM) {

View File

@ -660,7 +660,11 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
else else
sh_num = section->sh_num; 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; sym_type = STT_FUNC;
} else if ((sym->type.t & VT_BTYPE) == VT_VOID) { } else if ((sym->type.t & VT_BTYPE) == VT_VOID) {
sym_type = STT_NOTYPE; 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, ...) PUB_FUNC void tcc_error(const char *fmt, ...)
{ {
TCCState *s1 = tcc_state; TCCState *s1 = tcc_state;
// { Edit by Coldy
if (fmt) {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
error1(s1, 0, fmt, ap); error1(s1, 0, fmt, ap);
va_end(ap); va_end(ap);
} // }
/* better than nothing: in some cases, we accept to handle errors */ /* better than nothing: in some cases, we accept to handle errors */
if (s1->error_set_jmp_enabled) { if (s1->error_set_jmp_enabled) {
longjmp(s1->error_jmp_buf, 1); 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 #elif defined TCC_TARGET_MEOS
" KolibriOS" " KolibriOS"
#ifdef TCC_TARGET_KX #ifdef TCC_TARGET_KX
"/KX extension" "/KX extension "
TCC_KX_VERSION_INFO
#endif #endif
#else #else
" Linux" " 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) #define realloc(p, s) use_tcc_realloc(p, s)
#undef strdup #undef strdup
#define strdup(s) use_tcc_strdup(s) #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_memstats(int bench);
PUB_FUNC void tcc_error_noabort(const char *fmt, ...); PUB_FUNC void tcc_error_noabort(const char *fmt, ...);
PUB_FUNC NORETURN void tcc_error(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) if (ad.a.weak)
type.t |= VT_WEAK; type.t |= VT_WEAK;
#ifdef TCC_TARGET_PE #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_KX)
if (ad.a.func_import) if (ad.a.func_import)
type.t |= VT_IMPORT; type.t |= VT_IMPORT;
if (ad.a.func_export) if (ad.a.func_export)

View File

@ -1,7 +1,7 @@
/* /*
* TCCKX.C - KolibriOS/KX file output for the TinyC Compiler * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -17,6 +17,8 @@
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#define TCC_KX_VERSION_INFO "0.4.6"
typedef struct { typedef struct {
char magic[4]; char magic[4];
@ -67,7 +69,7 @@ typedef struct {
if (dynsym_index == 0) { if (dynsym_index == 0) {
//if (strcmp(name, __kx_import_table_sym) != 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 // KOS support 32 bit only
@ -314,7 +316,39 @@ typedef struct {
tcc_free(imp); tcc_free(imp);
} }
} }
// 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) #if /*!*/defined(_DEBUG)// && !defined(_WIN32)
#define kx_debug_output printf #define kx_debug_output printf
#else #else

View File

@ -2,7 +2,7 @@
* TCCMEOS.C - KolibriOS/MenuetOS file output for the TinyC Compiler * TCCMEOS.C - KolibriOS/MenuetOS file output for the TinyC Compiler
* *
* Copyright (c) 2006 Andrey Khalyavin * 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -58,6 +58,7 @@ typedef struct {
#ifdef TCC_TARGET_KX #ifdef TCC_TARGET_KX
void kx_init(me_info* me); void kx_init(me_info* me);
void kx_build_imports(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); long kx_get_header_length(me_info* me);
void kx_write_header(me_info* me, FILE* f); void kx_write_header(me_info* me, FILE* f);
void kx_write_imports(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_; rel=rel_;
int type = ELF32_R_TYPE(rel->r_info); int type = ELF32_R_TYPE(rel->r_info);
rel_=rel+1; 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; continue;
}
int sym = ELF32_R_SYM(rel->r_info); int sym = ELF32_R_SYM(rel->r_info);
if (sym>symtab_section->data_offset/sizeof(Elf32_Sym)) if (sym>symtab_section->data_offset/sizeof(Elf32_Sym))
continue; continue;
@ -121,34 +125,42 @@ void build_reloc(me_info* me)
int sect=esym->st_shndx; int sect=esym->st_shndx;
int sh_addr; int sh_addr;
ss=findsection(me,sect); 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) if (ss==0)
{ {
const char *sym_name = strtab_section->data + esym->st_name;
#ifdef TCC_TARGET_KX #ifdef TCC_TARGET_KX
int sym_index = find_elf_sym(me->s1->dynsymtab_section, sym_name); sym_index = find_elf_sym(me->s1->dynsymtab_section, sym_name);
Elf32_Sym* dyn_sym;
if (sym_index == 0) { if (sym_index == 0) {
#endif #endif
tcc_error_noabort("undefined symbol '%s'", sym_name); tcc_error_noabort("undefined import symbol '%s'", sym_name);
continue; continue;
#ifdef TCC_TARGET_KX #ifdef TCC_TARGET_KX
} }
dyn_sym = &((ElfW(Sym) *)me->s1->dynsymtab_section->data)[sym_index]; dyn_sym = &((ElfW(Sym) *)me->s1->dynsymtab_section->data)[sym_index];
sh_addr = dyn_sym->st_value; sh_addr = dyn_sym->st_value;
if (sh_addr == 0) { 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; continue;
} }
// Stop linking if incorrect import
kx_check_import_error(type, s->data, rel->r_offset, sym_name);
#endif #endif
} }
else else {
if (esym->st_shndx == SHN_UNDEF)
tcc_error("unresolved external symbol '%s'", sym_name);
sh_addr = ss->sh_addr; sh_addr = ss->sh_addr;
}
if (rel->r_offset>s->data_size) if (rel->r_offset>s->data_size)
continue; continue;
if (type==R_386_PC32) 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) 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_; rel=rel_;
s=s->next; s=s->next;