forked from KolibriOS/kolibrios
ktcc: added __attribute__((dllimport)) support
git-svn-id: svn://kolibrios.org@9782 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
3dddd1c687
commit
db785142be
@ -1,5 +1,5 @@
|
||||
|
||||
Версия расширения KX - 0.4.3
|
||||
Версия расширения KX - 0.4.6
|
||||
|
||||
Обзор новых возможностей
|
||||
|
||||
@ -19,9 +19,10 @@
|
||||
|
||||
+ Уменьшенный размер образа
|
||||
Поскольку загрузчик библиотек больше не нужно размещать в каждом
|
||||
приложении, это уменьшает размер образа. Больше не нужен слой C
|
||||
(C layer), все зависимые библиотеки загружаются, а также инициализируются
|
||||
автоматически. Также используется компактный формат таблицы импорта.
|
||||
приложении, это уменьшает размер образа. Больше не нужна фукнция вызова
|
||||
инициализации библиотек в C layer, все зависимые библиотеки загружаются,
|
||||
а также инициализируются автоматически. Кроме того используется компактные
|
||||
формат таблицы импорта, а также вызовы функций из динамических библиотек.
|
||||
|
||||
+ Обратная совместимость
|
||||
Если Вы по каким то причинам не хотите, либо пока не готовы использовать
|
||||
|
@ -1,3 +1,16 @@
|
||||
0.4.6
|
||||
+ Добавлена поддержка __attribute__((dllimport))
|
||||
Новый способ вызова импортов дополнительно уменьшает размер приложений
|
||||
+ Добавлена обработка ошибок линкера при неправильном использовании типов
|
||||
вызовов функций импорта, в том числе для сторонних объектных файлов
|
||||
В частности, вызов без префикса __attribute__((dllimport)) перед
|
||||
импортируемой функцией в файле заголовка вызывает останов линкера
|
||||
+ Добавлено отображение информации о номере версии расширения KX (опция -vv)
|
||||
|
||||
0.4.5
|
||||
+ Добавлено подключение %ktcc_root%/include через файл tcc.conf
|
||||
+
|
||||
+
|
||||
|
||||
0.4.4
|
||||
+ Исправлена ошибка при задании неиспользуемых библиотек
|
||||
|
@ -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
|
||||
|
||||
...
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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, ...);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user