forked from KolibriOS/kolibrios
db785142be
git-svn-id: svn://kolibrios.org@9782 a494cfbc-eb01-0410-851d-a64ba20cac60
404 lines
10 KiB
C
404 lines
10 KiB
C
/*
|
|
* TCCKX.C - KolibriOS/KX file output for the TinyC Compiler
|
|
*
|
|
* 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
|
|
* 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
|
|
*/
|
|
|
|
#define TCC_KX_VERSION_INFO "0.4.6"
|
|
|
|
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 {
|
|
uint32_t ImportEntry;
|
|
uint32_t LibraryName;
|
|
} LibraryEntry;
|
|
|
|
/*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));
|
|
DLLReference **dllref = me->s1->loaded_dlls;
|
|
CString *str_arr, *len_arr, *sym_arr;
|
|
char dll_len;
|
|
int dll_loaded = me->s1->nb_loaded_dlls;
|
|
int nlib = 0;
|
|
int i;
|
|
|
|
if (me->header.version != 2)
|
|
return;
|
|
|
|
str_arr = tcc_malloc(sizeof(CString) * dll_loaded);
|
|
|
|
len_arr = tcc_malloc(sizeof(CString)* dll_loaded);
|
|
|
|
sym_arr = tcc_malloc(sizeof(CString)* dll_loaded);
|
|
|
|
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*/("(kx) undefined symbol '%s'", name);
|
|
}
|
|
|
|
// KOS support 32 bit only
|
|
Elf32_Sym* dyn_sym = &((ElfW(Sym) *)me->s1->dynsymtab_section->data)[dynsym_index];
|
|
char* dll_name;
|
|
// TCC store dll index in dyn_sym->st_size field
|
|
i = dyn_sym->st_size - 1;
|
|
if (dllref[i]->level != -1) {
|
|
dll_name = dllref[i]->name;
|
|
dll_len = strlen(dll_name) + 1;
|
|
|
|
nlib++;
|
|
|
|
cstr_new(&str_arr[i]);
|
|
cstr_new(&len_arr[i]);
|
|
cstr_new(&sym_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;
|
|
}
|
|
|
|
cstr_wccat(&sym_arr[i], (int)name);
|
|
|
|
// Export defined with prefix?
|
|
if (dyn_sym->st_value == -1){
|
|
name += (dll_len - 4); // skip prefix_
|
|
}
|
|
|
|
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;
|
|
}*/
|
|
|
|
// Fixed BUG#15 (possible access to uninitialized due unused library)
|
|
// Exclude unused librarys
|
|
if (nlib < dll_loaded) {
|
|
i = 0; int j, n = 0;
|
|
do {
|
|
|
|
// Find unused library
|
|
if (dllref[i]->level == 0) {
|
|
j = i + 1;
|
|
|
|
while (j < dll_loaded) {
|
|
// Find first used library
|
|
if (dllref[j]->level == -1) {
|
|
// Found, copy i from j
|
|
str_arr[i] = str_arr[j];
|
|
len_arr[i] = len_arr[j];
|
|
sym_arr[i] = sym_arr[j];
|
|
// Mark j as unused
|
|
dllref[j]->level = 0;
|
|
|
|
if (++n == nlib)
|
|
goto __done;
|
|
|
|
break;
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
} while (i < dll_loaded);
|
|
|
|
}
|
|
|
|
__done:
|
|
|
|
// 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(4096); // FIXME!!! I increased it to 4Kb, but steel need dynamicaly size
|
|
imp_sect->data_size = 0;
|
|
//imp_sect->sh_addr = me->header.image_size;// +1;
|
|
|
|
long imp_data = (long)imp_sect->data; //FIXED changed to long for gcc compatible
|
|
|
|
// Strings
|
|
i = 0;
|
|
do {
|
|
memcpy((void*)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;
|
|
align = align < 4 ? align : 0;
|
|
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;
|
|
|
|
LibraryEntry lib;
|
|
lib.ImportEntry = me->header.image_size + imp_sect->data_size + (nlib * 8) + 4;
|
|
lib.LibraryName = me->header.image_size + 0;
|
|
|
|
// LibraryEntry
|
|
memcpy((void*)imp_data, &lib, sizeof(LibraryEntry));
|
|
|
|
if (nlib > 1) {
|
|
int prev_sum = 0;
|
|
int prev = 0;
|
|
i = 1;
|
|
do {
|
|
lib.ImportEntry += (len_arr[prev].size - 2) * 4 + 4; //TODO: check that +4 is correct
|
|
prev_sum += str_arr[prev].size;
|
|
lib.LibraryName = me->header.image_size + prev_sum; // FIXED (was BUG#10)
|
|
imp_data += sizeof(LibraryEntry);
|
|
imp_sect->data_size += sizeof(LibraryEntry);
|
|
memcpy((void*)imp_data, &lib, sizeof(LibraryEntry));
|
|
|
|
prev++;
|
|
i++;
|
|
|
|
} while (i < nlib);
|
|
}
|
|
|
|
// End of LibraryEntry
|
|
imp_data += sizeof(LibraryEntry) + 4;
|
|
imp_sect->data_size += sizeof(LibraryEntry) + 4;
|
|
|
|
const char *sym_name;
|
|
char name_len;
|
|
long len_sum;
|
|
|
|
len_sum = me->header.image_size;
|
|
i = 0;
|
|
do {
|
|
char* len_data = len_arr[i].data;
|
|
long* sym_data = sym_arr[i].data;
|
|
|
|
name_len = *len_data++; // Skip library name
|
|
|
|
do {
|
|
|
|
memcpy(&sym_name, sym_data++, 4);
|
|
|
|
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, sym_name);
|
|
|
|
len_sum += name_len;
|
|
memcpy((void*)imp_data, &len_sum, 4);
|
|
|
|
imp_data += 4;
|
|
imp_sect->data_size += 4;
|
|
name_len = */*++*/len_data/*++*/; //(was BUG#3)
|
|
|
|
} while (/*name_len*/*(++len_data) > 0);
|
|
|
|
imp_data += 4;
|
|
imp_sect->data_size += 4;
|
|
|
|
len_sum += 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);
|
|
tcc_free(sym_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 least one *.def
|
|
(me->s1->nb_loaded_dlls))
|
|
me->header.version = 2;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
// 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
|
|
#define kx_debug_output(s,p) ((void)0)
|
|
#endif
|
|
|
|
/*
|
|
Calling once from tcc_set_lib_path_xxx
|
|
This function correct tcc_root if tcc_root/kx is a run directory,
|
|
otherwise do trim filename
|
|
*/
|
|
void kx_fix_root_directory(char *buf, size_t size) {
|
|
|
|
int defult = 1;
|
|
char* tcc_conf = tcc_malloc(strlen(buf)+5);
|
|
strcpy(tcc_conf, buf);
|
|
char* base = tcc_basename(tcc_conf);
|
|
*base = 0;
|
|
base = tcc_basename(buf);
|
|
strcat(tcc_conf, "tcc.conf");
|
|
FILE* f = fopen(tcc_conf,"r");
|
|
if (f) {
|
|
char line[100];
|
|
while (fgets(line, sizeof line, f)){
|
|
switch (*line)
|
|
case '#':
|
|
case '\n':
|
|
continue;
|
|
if ((strspn(line, "tcc_root") == 8) && line[8] == ' ') {
|
|
|
|
if (strcmp(line + 9, "kx") == 0) {
|
|
strcpy(base, line + 9);
|
|
defult = 0;
|
|
}
|
|
else
|
|
{
|
|
// Disallow change tcc_root with arbitrary path
|
|
continue;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
if (defult) {
|
|
|
|
*--base = 0;
|
|
}
|
|
|
|
tcc_free(tcc_conf);
|
|
//kx_debug_output("tcc root = %s\n", buf);
|
|
} |