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. tcc используется как обычно (см. справку tcc). Расширение KX использользует
файлы определений символов (*.def) для динамических библиотек (файлы *.o,
не требуются, исключение - статические *.o, если они нужны для работы
программы).
В данной директории присутствует папка lib с файлами Примеры по сборке см. в директории /samples
*.def, crt.0 и libtcc.a
Примечание:
ключ -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 описана ниже.
@ -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 Проверка поддержки расширения 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__, например
@ -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) 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
@ -18,6 +18,8 @@
* 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];
long flags; long flags;
@ -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
@ -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) #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;