Subversion Repositories Kolibri OS

Rev

Rev 9558 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *  TCCKX.C - KolibriOS/KX file output for the TinyC Compiler
  3.  *
  4.  *  Copyright (c) 2021-2022 Coldy
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #define TCC_KX_VERSION_INFO             "0.4.6"
  22.  
  23. typedef struct {
  24.         char magic[4];
  25.         long flags;
  26.         long i_ptr;
  27. } kx_header;
  28.  
  29. static kx_header __kx_header = { 'K','X',0, 0, 0x40, 0 };
  30.  
  31. typedef struct {
  32.          uint32_t ImportEntry;
  33.          uint32_t LibraryName;
  34.  } LibraryEntry;
  35.  
  36.  /*union ImportEntry {
  37.  uint32_t ImportStr;
  38.  uint32_t ImportPrt;
  39. };*/
  40.  
  41.  //static char __kx_import_table_sym[] = "__i_ptr__";
  42.  
  43.  void kx_build_imports(me_info* me) {
  44.  
  45.          ElfW(Sym) *sym;
  46.          int sym_index, sym_end;
  47.          sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
  48.          DLLReference **dllref = me->s1->loaded_dlls;
  49.          CString *str_arr, *len_arr, *sym_arr;
  50.          char dll_len;
  51.          int dll_loaded = me->s1->nb_loaded_dlls;
  52.          int nlib = 0;
  53.          int i;
  54.  
  55.          if (me->header.version != 2)
  56.                  return;
  57.  
  58.          str_arr = tcc_malloc(sizeof(CString) * dll_loaded);
  59.  
  60.          len_arr = tcc_malloc(sizeof(CString)* dll_loaded);
  61.          
  62.          sym_arr = tcc_malloc(sizeof(CString)* dll_loaded);
  63.  
  64.          for (sym_index = 1; sym_index < sym_end; ++sym_index) {
  65.                  sym = (ElfW(Sym) *)symtab_section->data + sym_index;
  66.                  if (sym->st_shndx == SHN_UNDEF) {
  67.                          const char *name = symtab_section->link->data + sym->st_name;
  68.                          int dynsym_index = find_elf_sym(me->s1->dynsymtab_section, name);
  69.  
  70.                          if (dynsym_index == 0) {
  71.                                  //if (strcmp(name, __kx_import_table_sym) != 0) {
  72.                                          tcc_error/*_noabort*/("(kx) undefined symbol '%s'", name);
  73.                          }
  74.  
  75.                          // KOS support 32 bit only
  76.                          Elf32_Sym* dyn_sym = &((ElfW(Sym) *)me->s1->dynsymtab_section->data)[dynsym_index];
  77.                          char* dll_name;
  78.                          // TCC store dll index in dyn_sym->st_size field
  79.                          i = dyn_sym->st_size - 1;
  80.                          if (dllref[i]->level != -1) {
  81.                                  dll_name = dllref[i]->name;
  82.                                  dll_len = strlen(dll_name) + 1;
  83.  
  84.                                  nlib++;
  85.  
  86.                                  cstr_new(&str_arr[i]);
  87.                                  cstr_new(&len_arr[i]);
  88.                                  cstr_new(&sym_arr[i]);
  89.  
  90.                                  cstr_ccat(&len_arr[i], dll_len);
  91.                                  cstr_cat(&str_arr[i], dll_name, dll_len);
  92.                                  //Mark dll as already used
  93.                                  dllref[i]->level = -1;
  94.                          }
  95.                          
  96.                          cstr_wccat(&sym_arr[i], (int)name);
  97.  
  98.                          // Export defined with prefix?
  99.                          if (dyn_sym->st_value == -1){
  100.                                  name += (dll_len - 4); // skip prefix_
  101.                          }
  102.  
  103.                          char name_len = strlen(name) + 1;
  104.                          cstr_ccat(&len_arr[i], name_len);
  105.                          cstr_cat(&str_arr[i], name, name_len);
  106.  
  107.                  }
  108.          }
  109.  
  110.          /*if (len_arr[0].size == 0)
  111.          {
  112.  
  113.                  //tcc_error("");
  114.                  return;
  115.          }*/
  116.    
  117.          // Fixed BUG#15 (possible access to uninitialized due unused library)
  118.          // Exclude unused librarys
  119.          if (nlib < dll_loaded) {
  120.                  i = 0; int j, n = 0;
  121.                  do {
  122.  
  123.                          // Find unused library
  124.                          if (dllref[i]->level == 0) {
  125.                                  j = i + 1;
  126.                                  
  127.                                  while (j < dll_loaded) {
  128.                                          // Find first used library
  129.                                          if (dllref[j]->level == -1) {
  130.                                                  // Found, copy i from j
  131.                                                  str_arr[i] = str_arr[j];
  132.                                                  len_arr[i] = len_arr[j];
  133.                                                  sym_arr[i] = sym_arr[j];
  134.                                                  // Mark j as unused
  135.                                                  dllref[j]->level = 0;
  136.  
  137.                                                  if (++n == nlib)
  138.                                                          goto __done;
  139.  
  140.                                                  break;
  141.                                          }
  142.  
  143.                                          j++;
  144.  
  145.                                  }
  146.  
  147.                          }
  148.  
  149.                          i++;
  150.  
  151.                  } while (i < dll_loaded);
  152.  
  153.          }
  154.  
  155.  __done:
  156.  
  157.          // Zero terminate of ptr (was BUG#3)
  158.          i = 0;
  159.          do {
  160.  
  161.                  cstr_ccat(&len_arr[i], 0);
  162.  
  163.                  i++;
  164.  
  165.          } while (i < nlib);
  166.  
  167.          kx_import_table* imp_sect;
  168.  
  169.          imp_sect = tcc_mallocz(sizeof(kx_import_table));
  170.          imp_sect->data = tcc_mallocz(4096); // FIXME!!! I increased it to 4Kb, but steel need dynamicaly size
  171.          imp_sect->data_size = 0;
  172.          //imp_sect->sh_addr = me->header.image_size;// +1;
  173.          
  174.          long imp_data = (long)imp_sect->data; //FIXED changed to long for gcc compatible
  175.  
  176.          // Strings
  177.          i = 0;
  178.          do {
  179.                  memcpy((void*)imp_data, str_arr[i].data, str_arr[i].size);
  180.                  imp_data += str_arr[i].size;
  181.                  imp_sect->data_size += str_arr[i].size;
  182.  
  183.                  i++;
  184.  
  185.          } while (i < nlib);
  186.  
  187.          // Align pad (check algorithm!)
  188.          int align = 4 - (me->header.image_size + imp_sect->data_size) % 4;
  189.          align = align < 4 ? align : 0;
  190.          imp_data += align;
  191.          imp_sect->data_size += align;
  192.  
  193.          /*add_elf_sym(
  194.                  me->s1->dynsymtab_section,
  195.                  me->header.image_size + imp_sect->data_size,
  196.                  0, ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE),
  197.                  0, SHN_ABS, __kx_import_table_sym);*/
  198.          __kx_header.i_ptr = me->header.image_size + imp_sect->data_size;
  199.  
  200.          LibraryEntry lib;
  201.          lib.ImportEntry = me->header.image_size + imp_sect->data_size + (nlib * 8) + 4;
  202.          lib.LibraryName = me->header.image_size + 0;
  203.  
  204.          // LibraryEntry
  205.          memcpy((void*)imp_data, &lib, sizeof(LibraryEntry));
  206.  
  207.          if (nlib > 1) {
  208.                  int prev_sum = 0;
  209.                  int prev = 0;
  210.                  i = 1;
  211.                  do {
  212.                          lib.ImportEntry += (len_arr[prev].size - 2) * 4 + 4; //TODO: check that +4 is correct
  213.                          prev_sum += str_arr[prev].size;
  214.                          lib.LibraryName = me->header.image_size + prev_sum; // FIXED (was BUG#10)
  215.                          imp_data += sizeof(LibraryEntry);
  216.                          imp_sect->data_size += sizeof(LibraryEntry);
  217.                          memcpy((void*)imp_data, &lib, sizeof(LibraryEntry));
  218.  
  219.                          prev++;
  220.                          i++;
  221.  
  222.                  } while (i < nlib);
  223.          }
  224.  
  225.          // End of LibraryEntry
  226.          imp_data += sizeof(LibraryEntry) + 4;
  227.          imp_sect->data_size += sizeof(LibraryEntry) + 4;
  228.  
  229.          const char *sym_name;
  230.          char name_len;
  231.          long len_sum;
  232.  
  233.          len_sum = me->header.image_size;
  234.          i = 0;
  235.          do {
  236.                  char* len_data = len_arr[i].data;
  237.                  long* sym_data = sym_arr[i].data;
  238.  
  239.                  name_len = *len_data++; // Skip library name
  240.  
  241.                  do {
  242.                                                  
  243.                          memcpy(&sym_name, sym_data++, 4);
  244.                          
  245.                          add_elf_sym(
  246.                                  me->s1->dynsymtab_section,
  247.                                  me->header.image_size + imp_sect->data_size,
  248.                                  0, ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE),
  249.                                  0, SHN_ABS, sym_name);
  250.  
  251.                          len_sum += name_len;
  252.                          memcpy((void*)imp_data, &len_sum, 4);
  253.  
  254.                          imp_data += 4;
  255.                          imp_sect->data_size += 4;
  256.                          name_len = */*++*/len_data/*++*/;              //(was BUG#3)
  257.  
  258.                  } while (/*name_len*/*(++len_data) > 0);
  259.  
  260.                  imp_data += 4;
  261.                  imp_sect->data_size += 4;
  262.  
  263.                  len_sum += name_len;
  264.                  i++;
  265.  
  266.          } while (i < nlib);
  267.  
  268.          me->header.image_size += imp_sect->data_size;
  269.          me->imp_table = imp_sect;
  270.  
  271.          tcc_free(str_arr);
  272.          tcc_free(len_arr);
  273.          tcc_free(sym_arr);
  274.  
  275.  }
  276.  
  277.  
  278.  
  279.  void kx_init(me_info* me) {
  280.          ElfW(Sym) *sym;
  281.          int sym_index = 1, sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
  282.          // Check that we have at last one import...
  283.          for (; sym_index < sym_end; ++sym_index) {
  284.                  sym = (ElfW(Sym) *)symtab_section->data + sym_index;
  285.                  if (sym->st_shndx == SHN_UNDEF)
  286.                          break;
  287.          }
  288.          if ((sym_index < sym_end) &&
  289.                  // ... and user attached at least one *.def
  290.                  (me->s1->nb_loaded_dlls))
  291.                         me->header.version = 2;
  292.  }
  293.  
  294.  long kx_get_header_length(me_info* me) {
  295.          if (me->header.version == 2)
  296.                  return sizeof(kx_header);
  297.  
  298.          return 0;
  299.  }
  300.  
  301.  void kx_write_header(me_info* me, FILE* f) {
  302.          if (me->header.version == 2)
  303.                  fwrite(&__kx_header, 1, sizeof(kx_header), f);
  304.  }
  305.  
  306.  void kx_write_imports(me_info* me, FILE* f) {
  307.          if (me->imp_table)
  308.                  fwrite(me->imp_table->data, 1, me->imp_table->data_size, f);
  309.                  
  310.  }
  311.  
  312.  void kx_free(me_info* me) {
  313.          kx_import_table* imp = me->imp_table;
  314.          if (imp){
  315.                  tcc_free(imp->data);
  316.                  tcc_free(imp);
  317.         }
  318.  }
  319.  
  320.  // This routine is called from build_reloc to check the code for incorrect import calls
  321. void kx_check_import_error(int reloc_type, const char* code_base, Elf32_Addr offset, const char* symbol_name) {
  322.          
  323.         unsigned char fError = 0;
  324.         char* p = (char*)(offset + code_base);
  325.  
  326.         // Hook for "[extern] rtype foo([?])" declaration
  327.         if (((unsigned char)*((char*)(p-1))) == 0xe8){
  328.                 // call         m32
  329.                 tcc_error_noabort("import symbol '%s' has direct call (not supported),\n\t    use __attribute__((dllimport)) prefix", symbol_name);
  330.                 fError = 1;
  331.         }
  332.  
  333.         //      Hook for MSVC "__declspec(dllimport) rtype(*foo)([?])"
  334.         /*if ((((unsigned char)*(p + 4)) == 0xff) &&
  335.                 (((unsigned char)*(p + 5)) == 0x10)) {*/
  336.         if (*((uint16_t*)(p + 4)) == 0x10ff) {
  337.                 /*
  338.                    (mov         eax [m32])
  339.                         call    dword[eax]
  340.                 */
  341.                 tcc_error_noabort("import symbol '%s' has unsupported call type", symbol_name);
  342.                 fError = 1;
  343.         }
  344.         if (reloc_type == R_386_PC32) {
  345.                 tcc_error_noabort("incorrect relocation type for import symbol '%s'", symbol_name);
  346.                 fError = 1;
  347.         }
  348.         if (fError)
  349.                 tcc_abort();
  350. }
  351.  
  352. #if /*!*/defined(_DEBUG)// && !defined(_WIN32)
  353.  #define        kx_debug_output         printf
  354. #else
  355.  #define kx_debug_output(s,p)   ((void)0)
  356. #endif
  357.  
  358. /*
  359.         Calling once from tcc_set_lib_path_xxx
  360.         This function correct tcc_root if tcc_root/kx is a run directory,
  361.         otherwise do trim filename
  362. */
  363.  void kx_fix_root_directory(char *buf, size_t size) {
  364.          
  365.          int defult = 1;
  366.          char* tcc_conf = tcc_malloc(strlen(buf)+5);
  367.          strcpy(tcc_conf, buf);
  368.          char* base = tcc_basename(tcc_conf);
  369.          *base = 0;
  370.          base = tcc_basename(buf);
  371.          strcat(tcc_conf, "tcc.conf");
  372.          FILE* f = fopen(tcc_conf,"r");
  373.          if (f) {
  374.                  char line[100];
  375.                  while (fgets(line, sizeof line, f)){
  376.                          switch (*line)
  377.                                 case '#':
  378.                                 case '\n':
  379.                                         continue;
  380.                                         if ((strspn(line, "tcc_root") == 8) && line[8] == ' ') {
  381.  
  382.                                                 if (strcmp(line + 9, "kx") == 0) {
  383.                                                         strcpy(base, line + 9);
  384.                                                         defult = 0;
  385.                                                 }
  386.                                                 else
  387.                                                 {
  388.                                                         // Disallow change tcc_root with arbitrary path
  389.                                                         continue;
  390.                                                 }
  391.  
  392.                                         }
  393.                  }
  394.  
  395.                  fclose(f);
  396.          }
  397.          if (defult) {
  398.  
  399.                  *--base = 0;
  400.          }
  401.  
  402.          tcc_free(tcc_conf);
  403.          //kx_debug_output("tcc root = %s\n", buf);
  404.  }