Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  *  TCCMEOS.C - KolibriOS/MenuetOS file output for the TinyC Compiler
  3.  *
  4.  *  Copyright (c) 2006 Andrey Khalyavin
  5.  *  Copyright (c) 2021-2022 Coldy (KX extension)
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  */
  21.  
  22. #include "tcc.h"
  23.  
  24. typedef struct {
  25.         char magic[8];
  26.         int version;
  27.         int entry_point;
  28.         int image_size;
  29.         int memory_size;
  30.         int stack;
  31.         int argv;
  32.         int path;
  33. } IMAGE_MEOS_FILE_HEADER,*PIMAGE_MEOS_FILE_HEADER;
  34. typedef struct _meos_section_info{
  35.         int sh_addr;
  36.         void* data;
  37.         int data_size;
  38.         int sec_num;
  39.         struct _meos_section_info* next;
  40. } meos_section_info;
  41. #ifdef TCC_TARGET_KX
  42. typedef struct {
  43.         void* data;
  44.         int       data_size;
  45. } kx_import_table;
  46. #endif
  47. typedef struct {
  48.         TCCState* s1;
  49.         IMAGE_MEOS_FILE_HEADER header;
  50.         meos_section_info* code_sections;
  51.         meos_section_info* data_sections;
  52. #ifdef TCC_TARGET_KX
  53.         kx_import_table* imp_table;
  54. #endif
  55.         meos_section_info* bss_sections;
  56. } me_info;
  57.  
  58. #ifdef TCC_TARGET_KX
  59.         void kx_init(me_info* me);
  60.         void kx_build_imports(me_info* me);
  61.         void kx_check_import_error(int reloc_type, const char* code_base, Elf32_Addr    offset, const char* symbol_name);
  62.         long kx_get_header_length(me_info* me);
  63.         void kx_write_header(me_info* me, FILE* f);
  64.         void kx_write_imports(me_info* me, FILE* f);
  65.         void kx_free(me_info* me);
  66. #endif
  67.  
  68. int tcc_output_dbgme(const char *filename, me_info* me);
  69.  
  70.  
  71. meos_section_info* findsection(me_info* me,int num)
  72. {
  73.         meos_section_info* si;
  74.         for(si=me->code_sections;si;si=si->next)
  75.         {
  76.                 if (si->sec_num==num)
  77.                         return si;
  78.         }
  79.         for (si=me->data_sections;si;si=si->next)
  80.         {
  81.                 if (si->sec_num==num)
  82.                         return si;
  83.         }
  84.         for (si=me->bss_sections;si;si=si->next)
  85.         {
  86.                 if (si->sec_num==num)
  87.                         return si;
  88.         }
  89.         return (meos_section_info*)0;
  90. }
  91.  
  92. void build_reloc(me_info* me)
  93. {
  94.         int flag;
  95.         Elf32_Rel *rel = 0, *rel_ = 0, *rel_end = 0;
  96.         Section *sr;
  97.         meos_section_info* s;
  98.         meos_section_info* ss;
  99.         s=me->code_sections;
  100.         rel=0;
  101.         rel_end=0;
  102.         flag=0;
  103.         for(;;)
  104.         {
  105.                 sr=me->s1->sections[s->sec_num]->reloc;
  106.                 if (sr)
  107.                 {
  108.                         rel = (Elf32_Rel *) sr->data;
  109.                         rel_end = (Elf32_Rel *) (sr->data + sr->data_offset);
  110.                 }
  111.                 rel_=rel;
  112.                 while (rel_<rel_end){
  113.                         rel=rel_;
  114.                         int type = ELF32_R_TYPE(rel->r_info);
  115.                         rel_=rel+1;
  116.                         if (type != R_386_PC32 && type != R_386_32) {
  117.                                 // gcc (and friends) object files is used?
  118.                                 tcc_error("unsupported relocation type %d", type);
  119.                                 continue;
  120.                         }
  121.                         int sym = ELF32_R_SYM(rel->r_info);
  122.                         if (sym>symtab_section->data_offset/sizeof(Elf32_Sym))
  123.                                 continue;
  124.                         Elf32_Sym* esym = ((Elf32_Sym *)symtab_section->data)+sym;
  125.                         int sect=esym->st_shndx;
  126.       int sh_addr;
  127.                         ss=findsection(me,sect);
  128.       const char* sym_name = strtab_section->data + esym->st_name;
  129.                         int sym_index;
  130.                         Elf32_Sym* dyn_sym;
  131.                         // Import has more less priority in relation to local symbols
  132.                         if (ss==0)
  133.                         {
  134. #ifdef TCC_TARGET_KX
  135.                                  sym_index = find_elf_sym(me->s1->dynsymtab_section, sym_name);
  136.                                 if (sym_index == 0) {
  137. #endif
  138.           tcc_error_noabort("undefined import symbol '%s'", sym_name);
  139.                                   continue;
  140. #ifdef TCC_TARGET_KX
  141.                         }
  142.                                 dyn_sym = &((ElfW(Sym) *)me->s1->dynsymtab_section->data)[sym_index];
  143.                                 sh_addr = dyn_sym->st_value;
  144.                                 if (sh_addr == 0) {
  145.                                         tcc_error_noabort("import symbol '%s' has zero value", sym_name);
  146.                                         continue;
  147.                                 }
  148.        
  149.         // Stop linking if incorrect import
  150.                                 kx_check_import_error(type, s->data, rel->r_offset, sym_name);
  151. #endif
  152.                         }
  153.                         else {
  154.       if (esym->st_shndx == SHN_UNDEF)
  155.                                 tcc_error("unresolved external symbol '%s'", sym_name);
  156.                                 sh_addr = ss->sh_addr;
  157.       }
  158.                         if (rel->r_offset>s->data_size)
  159.                                 continue;
  160.                         if (type==R_386_PC32)
  161.                                 *(int*)(rel->r_offset+s->data)+= sh_addr+esym->st_value-rel->r_offset-s->sh_addr;
  162.                         else if (type==R_386_32)
  163.                                 *(int*)(rel->r_offset+s->data)+= sh_addr+esym->st_value;
  164.                 }
  165.         rel=rel_;
  166.                 s=s->next;
  167.                 if (s==0) // what about multiple BSS sections ?
  168.                 {
  169.                         if (flag) break;
  170.                         s=me->data_sections;
  171.                         if (s==0) break;
  172.                         flag=1;
  173.                         continue;
  174.                 }
  175.         }
  176. }
  177.  
  178. void assign_addresses(me_info* me)
  179. {
  180.         int i;
  181.         meos_section_info* si;
  182.         for (i=1;i<me->s1->nb_sections;i++)
  183.         {
  184.                 Section* s=me->s1->sections[i];
  185.                 if (strcmp(".text",s->name)==0)
  186.                 {
  187.                         si=tcc_malloc(sizeof(meos_section_info));
  188.                         si->data=s->data;
  189.                         si->data_size=s->data_offset;
  190.                         si->next=me->code_sections;
  191.                         si->sec_num=i;
  192.                         me->code_sections=si;
  193.                         continue;
  194.                 }
  195.                 if (strcmp(".data",s->name)==0)
  196.                 {
  197.                         si=tcc_malloc(sizeof(meos_section_info));
  198.                         si->data=s->data;
  199.                         si->data_size=s->data_offset;
  200.                         si->next=me->data_sections;
  201.                         si->sec_num=i;
  202.                         me->data_sections=si;
  203.                         continue;
  204.                 }
  205.                 if (strcmp(".bss",s->name)==0)
  206.                 {
  207.                         si=tcc_malloc(sizeof(meos_section_info));
  208.                         si->data=s->data;
  209.                         si->data_size=s->data_offset;
  210.                         si->next=me->bss_sections;
  211.                         si->sec_num=i;
  212.                         me->bss_sections=si;
  213.                         continue;
  214.                 }
  215.         }
  216.         int addr;
  217.         addr=sizeof(IMAGE_MEOS_FILE_HEADER);
  218. #ifdef TCC_TARGET_KX
  219.         addr += kx_get_header_length(me);
  220. #endif
  221.         for (si=me->code_sections;si;si=si->next)
  222.         {
  223.                 si->sh_addr=addr;
  224.                 addr+=si->data_size;
  225.         }
  226.         for (si=me->data_sections;si;si=si->next)
  227.         {
  228.                 si->sh_addr=addr;
  229.                 addr+=si->data_size;
  230.         }
  231.         me->header.image_size=addr;
  232. #ifdef TCC_TARGET_KX
  233.         kx_build_imports(me);
  234.         addr = me->header.image_size;
  235. #endif
  236.         for (si=me->bss_sections;si;si=si->next)
  237.         {
  238.                 si->sh_addr=addr;
  239.                 addr+=si->data_size;
  240.         }
  241.         if (me->s1->pe_stack_size < 4096)
  242.         addr+=4096;
  243.     else
  244.         addr += me->s1->pe_stack_size;
  245.         addr=(addr+4)&(~3);
  246.         me->header.stack=addr;
  247.         me->header.memory_size=addr;
  248.         build_reloc(me);
  249. }
  250.  
  251.  
  252. const char *tcc_get_symbol_name(int st_name)
  253. // return string by index from stringtable section
  254. {
  255.         const char *sym_name = strtab_section->data + st_name;
  256.         return sym_name;
  257. }
  258.  
  259. int tcc_find_symbol_me(me_info* me, const char *sym_name, int* addr)
  260. {
  261.         int i, symtab = 0, strtab = 0;
  262.         *addr = 0;
  263.         for (i=1;i<me->s1->nb_sections;i++)
  264.         {
  265.                 Section* s;
  266.                 s=me->s1->sections[i];
  267.                 if (strcmp(s->name,".symtab")==0)
  268.                 {
  269.                         symtab=i;
  270.                 }
  271.                 if (strcmp(s->name,".strtab")==0)
  272.                 {
  273.                         strtab=i;
  274.                 }
  275.         }
  276.         if (symtab==0 || strtab==0)
  277.         {
  278.         tcc_error_noabort("undefined sections .symtab or .strtab on linking '%s'", sym_name);
  279.                 return 0;
  280.         }
  281.         Elf32_Sym* s,*se;
  282.         char* name;
  283.         s=(Elf32_Sym*)me->s1->sections[symtab]->data;
  284.         se=(Elf32_Sym*)(((void*)s)+me->s1->sections[symtab]->data_offset);
  285.         name=(char*)me->s1->sections[strtab]->data;
  286.         while (s<se)
  287.         {
  288.                 if (strcmp(name+s->st_name,sym_name)==0)
  289.                 {
  290.                         *addr = s->st_value+findsection(me,s->st_shndx)->sh_addr;
  291.                         return 1;
  292.                 }
  293.                 s++;
  294.         }
  295.     tcc_error_noabort("undefined symbol '%s'", sym_name);
  296.         return 0;
  297. }
  298.  
  299. const char* me_magic="MENUET01";
  300. int tcc_output_me(TCCState* s1,const char *filename)
  301. {
  302.         me_info me;
  303.     int i;
  304.     FILE* f;
  305.     //printf("%d\n",s1->nb_sections);
  306.         memset(&me,0,sizeof(me));
  307.         me.s1=s1;
  308.         tcc_add_runtime(s1);
  309. #ifdef TCC_TARGET_KX
  310.         kx_init(&me);
  311. #endif
  312.         relocate_common_syms();
  313.         assign_addresses(&me);
  314.    
  315.         if (s1->do_debug)
  316.                 tcc_output_dbgme(filename, &me);
  317.  
  318.         if (!tcc_find_symbol_me(&me, "start",  &me.header.entry_point) |
  319.             !tcc_find_symbol_me(&me, "__argv", &me.header.argv) |
  320.             !tcc_find_symbol_me(&me, "__path", &me.header.path)) {
  321.             exit(1);
  322.         }
  323.  
  324.         if((f=fopen(filename,"wb"))==NULL){
  325.                 tcc_error("could not create '%s': %s", filename, strerror(errno));
  326.         }
  327.  
  328.     for (i=0;i<8;i++)
  329.         me.header.magic[i]=me_magic[i];
  330.         fwrite(&me.header,1,sizeof(IMAGE_MEOS_FILE_HEADER),f);
  331. #ifdef TCC_TARGET_KX
  332.         kx_write_header(&me, f);
  333. #endif
  334.         meos_section_info* si;
  335.         for(si=me.code_sections;si;si=si->next)
  336.                 fwrite(si->data,1,si->data_size,f);
  337.         for (si=me.data_sections;si;si=si->next)
  338.                 fwrite(si->data,1,si->data_size,f);
  339. #ifdef TCC_TARGET_KX   
  340.         kx_write_imports(&me, f);
  341.         kx_free(&me);
  342. #else
  343.         if (!s1->nobss)
  344.         {
  345.                 for (si=me.bss_sections;si;si=si->next)
  346.                 {
  347.                 if (si->data == NULL)
  348.                         {
  349.         //              printf("\nError! BSS data is NULL! size:%i",(int)si->data_size);
  350.                         si->data = calloc(si->data_size, 1);
  351.                 }
  352.                         fwrite(si->data, 1, si->data_size, f);
  353.                 }
  354.         }
  355. /*
  356.     if (me.bss_sections) // Siemargl testin, what we lose
  357.     {
  358.         tcc_error_noabort("We lose .BSS section when linking KOS32 executable");
  359.     }
  360. */
  361. #endif
  362.         fclose(f);
  363.         return 0;
  364. }
  365.  
  366. #if !defined(_WIN32) && !defined(TCC_TARGET_MEOS_LINUX)
  367.  
  368. static inline int get_current_folder(char* buf, int bufsize){
  369.     register int val;
  370.     asm volatile ("int $0x40":"=a"(val):"a"(30), "b"(2), "c"(buf), "d"(bufsize));
  371.     return val;
  372. }
  373.  
  374.  
  375. char *getcwd(char *buf, size_t size)
  376. {
  377.         int rc = get_current_folder(buf, size);
  378.         if (rc > size)
  379.         {
  380.                 errno = ERANGE;
  381.                 return 0;
  382.         }
  383.         else
  384.                 return buf;
  385. }
  386.  
  387. #endif
  388.  
  389.  
  390. static FILE *src_file;
  391. static int next_src_line;
  392.  
  393. void close_source_file()
  394. {
  395.     if (src_file)
  396.         fclose(src_file);
  397.     src_file = NULL;
  398. }
  399.  
  400. void load_source_file(char *fname)
  401. {
  402.     close_source_file();
  403.     src_file = fopen(fname,"rt");
  404.         if (!src_file) return;
  405.         next_src_line = 1;
  406. }
  407.  
  408. int get_src_lines(char *buf, int sz, int start, int end)
  409. // 1 if read
  410. {
  411.     char line[255], *ch;
  412.     strcpy(buf, "");
  413.         if (!src_file) return 0;
  414.     while (next_src_line < start) // skip
  415.     {
  416.         ch = fgets(line, sizeof line, src_file);
  417.         if (!ch) return 0;
  418.         next_src_line++;
  419.     }
  420.     while (next_src_line <= end)
  421.     {
  422.         ch = fgets(line, sizeof line, src_file);
  423.         if (!ch) return 0;
  424.         next_src_line++;
  425.         strncat(buf, line, sz - strlen(buf) - 1);
  426.     }
  427.     // remove newlines
  428.     for (ch = buf; *ch; ch++)
  429.         if (strchr("\t\n\r", *ch)) *ch = ' ';
  430.  
  431.     return 1;
  432. }
  433.  
  434. int tcc_output_dbgme(const char *filename, me_info* me)
  435. // by Siemargl. Writes filename.dbg file for source code level debuggin with MTDBG
  436. // return 1 on error
  437. {
  438.         FILE    *fdbg;
  439.         char    fname[400],
  440.             buf[80]; // no more fits in mtdbg string
  441.  
  442.         strcpy(fname, filename);
  443.         strcat(fname, ".dbg");
  444.         fdbg = fopen(fname,"wt");
  445.         if (!fdbg) return 1;
  446.  
  447.         meos_section_info *si, *ss;
  448.     fputs(".text\n", fdbg); // just for mtbg
  449.  
  450.     // print symbol table with resolved addresses
  451.     Elf32_Sym* esym;
  452.     for (esym = (Elf32_Sym*)symtab_section->data; esym <= (Elf32_Sym*)(symtab_section->data + symtab_section->data_offset); esym++)
  453.     {
  454.         if (esym->st_info == 0 || esym->st_info == 4) continue;
  455.         int sect = esym->st_shndx;
  456.         ss = findsection(me, sect);
  457.         const char *sym_name = strtab_section->data + esym->st_name;
  458.         if (ss == 0)
  459.         {
  460.             fprintf(fdbg, "undefined symbol '%s' type(%d)\n", sym_name, esym->st_info);
  461.             continue;
  462.         }
  463.         fprintf(fdbg, "0x%X %s\n", ss->sh_addr + esym->st_value, sym_name); // removed type(%d)   esym->st_info
  464.     }
  465.  
  466.     fputs(".text source code links\n", fdbg); // just for mtbg
  467.     // print symbol table with resolved addresses
  468.     Stab_Sym *stab;
  469.     char    *str = "", *cur_file = "???", cur_fun[255];
  470.     int cur_line = 0, cur_fun_addr = 0, fun_flag = 0;
  471.     strcpy(cur_fun, "fn???");
  472.     for (stab = (Stab_Sym*)stab_section->data; stab <= (Stab_Sym*)(stab_section->data + stab_section->data_offset); stab++)
  473.     {
  474.         str = "";
  475.         switch(stab->n_type)
  476.         {
  477.         case 100:   // source file, or path
  478.             if (stab->n_strx)
  479.             {
  480.                 cur_file = stabstr_section->data + stab->n_strx;
  481.                 load_source_file(cur_file);
  482.             }
  483.             else
  484.                 cur_file = "???";
  485.             strcpy(cur_fun, "fn???");
  486.             cur_line = 0;
  487.             cur_fun_addr = 0;
  488.             fun_flag = 0;
  489.             break;
  490.         case 36:    // func
  491.             cur_fun_addr = 0;
  492.             if (stab->n_strx)
  493.             {
  494.                 strcpy(cur_fun, stabstr_section->data + stab->n_strx);
  495.                 str = strchr(cur_fun, ':');
  496.                 if (str) *str = '\0';
  497.                 tcc_find_symbol_me(me, cur_fun, &cur_fun_addr);
  498.                 cur_line = stab->n_desc;
  499.                 fun_flag = 1;
  500.                 //fprintf(fdbg, "0x%X %s() line(%d)\n", cur_fun_addr, cur_fun, cur_line); // commented as conflicted with direct address
  501.             }
  502.             else
  503.                 strcpy(cur_fun, "fn???");
  504.             break;
  505.         case 68:    // N_SLINE
  506.             if (stab->n_value == 0 ) continue;  // skip zero offset line
  507.             if (fun_flag) // skip string {, as duplicates address
  508.             {
  509.                 fun_flag = 0;
  510.                 continue;
  511.             }
  512.  
  513.             int line;
  514.             if (stab->n_desc > cur_line)
  515.                 line = cur_line + 1;
  516.             else
  517.                 line = cur_line;
  518.             //fprintf(fdbg, "0x%X LINES %d-%d \n", cur_fun_addr + stab->n_value, line,  stab->n_desc);
  519.             if (get_src_lines(buf, sizeof buf, line, stab->n_desc))
  520.                 fprintf(fdbg, "0x%X %s\n", cur_fun_addr + stab->n_value, buf);
  521.  
  522.             cur_line = stab->n_desc;
  523.             break;
  524.         default:
  525.             continue;
  526.         }
  527. /*
  528.         if (stab->n_strx)
  529.             str = stabstr_section->data + stab->n_strx;
  530.         fprintf(fdbg, "0x%X type(%d) str(%s) desc(%d)\n", stab->n_value, stab->n_type, str, stab->n_desc);
  531. */
  532.     }
  533.  
  534. /*        for(; si; si = si->next)
  535.         {
  536.             Section *sr;
  537.             Elf32_Rel *rel, *rel_end;
  538.             for(sr = me->s1->sections[si->sec_num]->reloc; sr; )
  539.             {
  540.                 for (rel = (Elf32_Rel *) sr->data, rel_end = (Elf32_Rel *) (sr->data + sr->data_offset); rel < rel_end; rel++)
  541.                 {
  542.                     int type = ELF32_R_TYPE(rel->r_info);
  543.                     if (type != R_386_PC32 && type != R_386_32)
  544.                         continue;
  545.                     int sym = ELF32_R_SYM(rel->r_info);
  546.                     if (sym > symtab_section->data_offset / sizeof(Elf32_Sym))
  547.                         continue;
  548.                     Elf32_Sym* esym = ((Elf32_Sym*)symtab_section->data) + sym;
  549.                     int sect = esym->st_shndx;
  550.                     ss = findsection(me, sect);
  551.                     const char *sym_name = strtab_section->data + esym->st_name;
  552.                     if (ss == 0)
  553.                     {
  554.                         fprintf(fdbg, "undefined symbol '%s'\n", sym_name);
  555.                         continue;
  556.                     }
  557.                     if (rel->r_offset > si->data_size) continue;
  558.                     fprintf(fdbg, "\t0x%X %s\n", ss->sh_addr + esym->st_value, sym_name);
  559.                 }
  560.             }
  561.         }
  562. */
  563.     close_source_file();
  564.         fclose(fdbg);
  565.         return 0;
  566. }
  567.