From 664e46d057cf97b2cdf9b8e971ce67a410a274cc Mon Sep 17 00:00:00 2001 From: Coldy Date: Wed, 17 Nov 2021 18:44:24 +0000 Subject: [PATCH] Add KX extension to tcc (autoload w/import table support), phase 1 git-svn-id: svn://kolibrios.org@9284 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/ktcc/trunk/source/libtcc.c | 11 +- programs/develop/ktcc/trunk/source/tcc.c | 2 + programs/develop/ktcc/trunk/source/tcc.h | 8 + programs/develop/ktcc/trunk/source/tcckx.c | 272 +++++++++++++++++++ programs/develop/ktcc/trunk/source/tccmeos.c | 68 ++++- programs/develop/ktcc/trunk/source/tccpe.c | 6 +- 6 files changed, 360 insertions(+), 7 deletions(-) create mode 100644 programs/develop/ktcc/trunk/source/tcckx.c diff --git a/programs/develop/ktcc/trunk/source/libtcc.c b/programs/develop/ktcc/trunk/source/libtcc.c index bdb0b24a10..0e8db555b3 100644 --- a/programs/develop/ktcc/trunk/source/libtcc.c +++ b/programs/develop/ktcc/trunk/source/libtcc.c @@ -71,6 +71,9 @@ ST_DATA struct TCCState *tcc_state; #ifdef TCC_TARGET_MEOS #include "tccmeos.c" #endif +#ifdef TCC_TARGET_KX +#include "tcckx.c" +#endif #ifdef TCC_TARGET_MEOS_LINUX #include #endif @@ -1461,8 +1464,10 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags, } #endif -#if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) +#if defined (TCC_TARGET_PE) || (defined(TCC_TARGET_MEOS) && !defined(TCC_TARGET_KX)) ret = pe_load_file(s1, filename, fd); +#elif defined(TCC_TARGET_KX) + ret = pe_load_def(s1, fd); #else /* as GNU ld, consider it is an ld script if not recognized */ ret = tcc_load_ldscript(s1); @@ -2125,7 +2130,9 @@ static const TCCOption tcc_options[] = { { "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG }, { "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG }, { "stack", TCC_OPTION_stack, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP}, +#if defined(TCC_TARGET_MEOS) && !defined (TCC_TARGET_KX) { "nobss", TCC_OPTION_nobss, 0 }, +#endif { NULL, 0, 0 }, }; @@ -2458,9 +2465,11 @@ ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv) s->pe_stack_size = strtoul(optarg+1, NULL, 10); #endif break; +#if defined(TCC_TARGET_MEOS) && !defined (TCC_TARGET_KX) case TCC_OPTION_nobss: s->nobss = 1; break; +#endif default: if (s->warn_unsupported) { unsupported_option: diff --git a/programs/develop/ktcc/trunk/source/tcc.c b/programs/develop/ktcc/trunk/source/tcc.c index 18d2714687..3df048afca 100644 --- a/programs/develop/ktcc/trunk/source/tcc.c +++ b/programs/develop/ktcc/trunk/source/tcc.c @@ -128,8 +128,10 @@ static void help(void) " -Bdir use 'dir' as tcc internal library and include path\n" " -MD generate target dependencies for make\n" " -MF depfile put generated dependencies here\n" +#if defined(TCC_TARGET_MEOS) && !defined (TCC_TARGET_KX) "For KolibriOS only:\n" " -nobss do not emit BSS section into file\n" +#endif ); } diff --git a/programs/develop/ktcc/trunk/source/tcc.h b/programs/develop/ktcc/trunk/source/tcc.h index 28e96e5388..6f30943e82 100644 --- a/programs/develop/ktcc/trunk/source/tcc.h +++ b/programs/develop/ktcc/trunk/source/tcc.h @@ -43,6 +43,12 @@ #define TCC_ASSERT(ex) #endif +#ifdef TCC_TARGET_KX +#ifndef TCC_TARGET_MEOS +#define TCC_TARGET_MEOS +#endif +#endif + #ifndef _WIN32 # include # include @@ -871,7 +877,9 @@ struct TCCState { int do_bench; /* option -bench */ int gen_deps; /* option -MD */ char *deps_outfile; /* option -MF */ +#if defined(TCC_TARGET_MEOS) && !defined (TCC_TARGET_KX) int nobss; /* option -nobss, omit BSS section (KolibriOS-only) */ +#endif ParseArgsState *parse_args_state; }; diff --git a/programs/develop/ktcc/trunk/source/tcckx.c b/programs/develop/ktcc/trunk/source/tcckx.c new file mode 100644 index 0000000000..c3e0a187cb --- /dev/null +++ b/programs/develop/ktcc/trunk/source/tcckx.c @@ -0,0 +1,272 @@ +/* + * TCCKX.C - KolibriOS/KX file output for the TinyC Compiler + * + * Copyright (c) 2021 Coldy + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +typedef struct { + char magic[4]; + long flags; + long i_ptr; +} kx_header; + +static kx_header __kx_header = { 'K','X',0, 0, 0x40, 0 }; + + typedef struct LibraryEntry { + uint32_t ImportEntry; + uint32_t LibraryName; + }; + + /*union ImportEntry { + uint32_t ImportStr; + uint32_t ImportPrt; + };*/ + + //static char __kx_import_table_sym[] = "__i_ptr__"; + + void kx_build_imports(me_info* me) { + + ElfW(Sym) *sym; + int sym_index, sym_end; + sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); + CString *str_arr, *len_arr; + int nlib = 0; + int i; + + if (me->header.version != 2) + return; + + str_arr = tcc_malloc(sizeof(CString) * me->s1->nb_loaded_dlls); + if (str_arr == 0) { + return; + } + + len_arr = tcc_malloc(sizeof(CString)* me->s1->nb_loaded_dlls); + if (len_arr == 0) { + tcc_free(str_arr); + return; + } + + for (sym_index = 1; sym_index < sym_end; ++sym_index) { + sym = (ElfW(Sym) *)symtab_section->data + sym_index; + if (sym->st_shndx == SHN_UNDEF) { + const char *name = symtab_section->link->data + sym->st_name; + int dynsym_index = find_elf_sym(me->s1->dynsymtab_section, name); + + if (dynsym_index == 0) { + //if (strcmp(name, __kx_import_table_sym) != 0) { + tcc_error/*_noabort*/("undefined symbol '%s'", name); + //continue; // FIXME: stop compile! + //} + + //continue; + } + + // KOS support 32 bit only + Elf32_Sym* dyn_sym = &((ElfW(Sym) *)me->s1->dynsymtab_section->data)[dynsym_index]; + DLLReference **dllref = me->s1->loaded_dlls; + i = dyn_sym->st_size - 1; + // TCC store dll index in dyn_sym->st_size field + if (dllref[i]->level != -1) { + char* dll_name = dllref[i]->name; + char dll_len = strlen(dll_name) + 1; + + nlib++; + + cstr_new(&str_arr[i]); + cstr_new(&len_arr[i]); + + cstr_ccat(&len_arr[i], dll_len); + cstr_cat(&str_arr[i], dll_name, dll_len); + //Mark dll as already used + dllref[i]->level = -1; + } + + char name_len = strlen(name) + 1; + cstr_ccat(&len_arr[i], name_len); + cstr_cat(&str_arr[i], name, name_len); + + } + } + + /*if (len_arr[0].size == 0) + { + + //tcc_error(""); + return; + }*/ + + // Zero terminate of ptr (was BUG#3) + i = 0; + do { + + cstr_ccat(&len_arr[i], 0); + + i++; + + } while (i < nlib); + + kx_import_table* imp_sect; + + imp_sect = tcc_mallocz(sizeof(kx_import_table)); + imp_sect->data = tcc_mallocz(1024); // FIXME!!! + imp_sect->data_size = 0; + //imp_sect->sh_addr = me->header.image_size;// +1; + + long imp_data = imp_sect->data; //FIXME change to long for gcc compatible? + + // Strings + i = 0; + do { + memcpy(imp_data, str_arr[i].data, str_arr[i].size); + imp_data += str_arr[i].size; + imp_sect->data_size += str_arr[i].size; + + i++; + + } while (i < nlib); + + // Align pad (check algorithm!) + int align = 4 - (me->header.image_size + imp_sect->data_size) % 4; + imp_data += align; + imp_sect->data_size += align; + + /*add_elf_sym( + me->s1->dynsymtab_section, + me->header.image_size + imp_sect->data_size, + 0, ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), + 0, SHN_ABS, __kx_import_table_sym);*/ + __kx_header.i_ptr = me->header.image_size + imp_sect->data_size; + + struct LibraryEntry lib; + lib.ImportEntry = me->header.image_size + imp_sect->data_size + (nlib * 8) + 4; + lib.LibraryName = me->header.image_size + 0; + + // LibraryEntry + memcpy(imp_data, &lib, sizeof(struct LibraryEntry)); + + if (nlib > 1) { + int prev = 0; + i = 1; + do { + lib.ImportEntry += (len_arr[prev].size - 2) * 4 + 4; //TODO: check that +4 is correct + lib.LibraryName = me->header.image_size + str_arr[prev].size; + imp_data += sizeof(struct LibraryEntry); + imp_sect->data_size += sizeof(struct LibraryEntry); + memcpy(imp_data, &lib, sizeof(struct LibraryEntry)); + + prev++; + i++; + + } while (i < nlib); + } + + // End of LibraryEntry + imp_data += sizeof(struct LibraryEntry) + 4; + imp_sect->data_size += sizeof(struct LibraryEntry) + 4; + + char name_len; + long l, nl; + + l = me->header.image_size; + i = 0; + do { + char* len_data = len_arr[i].data; + + name_len = *len_data++; // Skip library name + nl = name_len; + + do { + const char *name = (const char *)str_arr[i].data + nl; + + add_elf_sym( + me->s1->dynsymtab_section, + me->header.image_size + imp_sect->data_size, + 0, ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), + 0, SHN_ABS, name); + + l += name_len; + memcpy(imp_data, &l, 4); + + imp_data += 4; + imp_sect->data_size += 4; + name_len = */*++*/len_data/*++*/; //(was BUG#3) + + nl = nl + name_len; + + } while (/*name_len*/*(++len_data) > 0); + + imp_data += 4; + imp_sect->data_size += 4; + + l += name_len; + i++; + + } while (i < nlib); + + me->header.image_size += imp_sect->data_size; + me->imp_table = imp_sect; + + tcc_free(str_arr); + tcc_free(len_arr); + + } + + + + void kx_init(me_info* me) { + ElfW(Sym) *sym; + int sym_index = 1, sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); + // Check that we have at last one import... + for (; sym_index < sym_end; ++sym_index) { + sym = (ElfW(Sym) *)symtab_section->data + sym_index; + if (sym->st_shndx == SHN_UNDEF) + break; + } + if ((sym_index < sym_end) && + // ... and user attached at last one *.def + (me->s1->nb_loaded_dlls)) + me->header.version = 2; + + //tcc_add_crt(me->s1, "start1.o"); + } + + long kx_get_header_length(me_info* me) { + if (me->header.version = 2) + return sizeof(kx_header); + + return 0; + } + + void kx_write_header(me_info* me, FILE* f) { + if (me->header.version = 2) + fwrite(&__kx_header, 1, sizeof(kx_header), f); + } + + void kx_write_imports(me_info* me, FILE* f) { + if (me->imp_table) + fwrite(me->imp_table->data, 1, me->imp_table->data_size, f); + + } + + void kx_free(me_info* me) { + kx_import_table* imp = me->imp_table; + if (imp){ + tcc_free(imp->data); + tcc_free(imp); + } + } \ No newline at end of file diff --git a/programs/develop/ktcc/trunk/source/tccmeos.c b/programs/develop/ktcc/trunk/source/tccmeos.c index 70283fd3c0..8cd6e4ba78 100644 --- a/programs/develop/ktcc/trunk/source/tccmeos.c +++ b/programs/develop/ktcc/trunk/source/tccmeos.c @@ -2,6 +2,7 @@ * TCCMEOS.C - KolibriOS/MenuetOS file output for the TinyC Compiler * * Copyright (c) 2006 Andrey Khalyavin + * Copyright (c) 2021 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 @@ -18,7 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef TCC_TARGET_KX int undef_sym_flag=0; +#endif typedef struct { char magic[8]; @@ -37,14 +40,32 @@ typedef struct _meos_section_info{ int sec_num; struct _meos_section_info* next; } meos_section_info; +#ifdef TCC_TARGET_KX +typedef struct { + void* data; + int data_size; +} kx_import_table; +#endif typedef struct { TCCState* s1; IMAGE_MEOS_FILE_HEADER header; meos_section_info* code_sections; meos_section_info* data_sections; +#ifdef TCC_TARGET_KX + kx_import_table* imp_table; +#endif meos_section_info* bss_sections; } me_info; +#ifdef TCC_TARGET_KX + void kx_init(me_info* me); + void kx_build_imports(me_info* me); + 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); + void kx_free(me_info* me); +#endif + int tcc_output_dbgme(const char *filename, me_info* me); @@ -100,20 +121,38 @@ void build_reloc(me_info* me) continue; Elf32_Sym* esym = ((Elf32_Sym *)symtab_section->data)+sym; int sect=esym->st_shndx; + int sh_addr; ss=findsection(me,sect); if (ss==0) { - const char *sym_name = strtab_section->data + esym->st_name; + 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; + if (sym_index == 0) { +#else undef_sym_flag=1; - tcc_error_noabort("undefined symbol '%s'", sym_name); +#endif + tcc_error_noabort("undefined 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); + continue; + } +#endif + } + else + 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)+=/*ss->*/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)+=/*ss->*/sh_addr+esym->st_value; } rel=rel_; s=s->next; @@ -168,6 +207,9 @@ void assign_addresses(me_info* me) } int addr; addr=sizeof(IMAGE_MEOS_FILE_HEADER); +#ifdef TCC_TARGET_KX + addr += kx_get_header_length(me); +#endif for (si=me->code_sections;si;si=si->next) { si->sh_addr=addr; @@ -179,6 +221,10 @@ void assign_addresses(me_info* me) addr+=si->data_size; } me->header.image_size=addr; +#ifdef TCC_TARGET_KX + kx_build_imports(me); + addr = me->header.image_size; +#endif for (si=me->bss_sections;si;si=si->next) { si->sh_addr=addr; @@ -253,12 +299,16 @@ int tcc_output_me(TCCState* s1,const char *filename) //printf("%d\n",s1->nb_sections); memset(&me,0,sizeof(me)); me.s1=s1; +#ifdef TCC_TARGET_KX + kx_init(&me); +#endif relocate_common_syms(); assign_addresses(&me); - +#ifndef TCC_TARGET_KX if(undef_sym_flag){ tcc_error("Linker error!"); } +#endif if (s1->do_debug) tcc_output_dbgme(filename, &me); @@ -274,11 +324,18 @@ int tcc_output_me(TCCState* s1,const char *filename) for (i=0;i<8;i++) me.header.magic[i]=me_magic[i]; fwrite(&me.header,1,sizeof(IMAGE_MEOS_FILE_HEADER),f); +#ifdef TCC_TARGET_KX + kx_write_header(&me, f); +#endif meos_section_info* si; for(si=me.code_sections;si;si=si->next) fwrite(si->data,1,si->data_size,f); for (si=me.data_sections;si;si=si->next) fwrite(si->data,1,si->data_size,f); +#ifdef TCC_TARGET_KX + kx_write_imports(&me, f); + kx_free(&me); +#else if (!s1->nobss) { for (si=me.bss_sections;si;si=si->next) @@ -297,6 +354,7 @@ int tcc_output_me(TCCState* s1,const char *filename) tcc_error_noabort("We lose .BSS section when linking KOS32 executable"); } */ +#endif fclose(f); return 0; } diff --git a/programs/develop/ktcc/trunk/source/tccpe.c b/programs/develop/ktcc/trunk/source/tccpe.c index c4f6c79dfb..0412d308ed 100644 --- a/programs/develop/ktcc/trunk/source/tccpe.c +++ b/programs/develop/ktcc/trunk/source/tccpe.c @@ -1564,14 +1564,18 @@ quit: } /* ------------------------------------------------------------- */ -#ifndef TCC_TARGET_MEOS +#if !defined(TCC_TARGET_MEOS) || defined (TCC_TARGET_KX) static int pe_load_def(TCCState *s1, int fd) { int state = 0, ret = -1, dllindex = 0, ord; char line[400], dllname[80], *p, *x; FILE *fp; +#ifdef TCC_TARGET_KX + fp = fopen(file->filename, "rb"); +#else fp = fdopen(dup(fd), "rb"); +#endif while (fgets(line, sizeof line, fp)) { p = trimfront(trimback(line, strchr(line, 0)));