Subversion Repositories Kolibri OS

Rev

Rev 9088 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <stdarg.h>
  2. #include <stddef.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <stdint.h>
  6. #include <assert.h>
  7. #include <string.h>
  8.  
  9. #define EPEP_INST
  10. #include "epep/epep.h"
  11.  
  12. const char *epep_errors[] = {
  13.         "EPEP_ERR_SUCCESS",
  14.         "EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID",
  15.         "EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID",
  16.         "EPEP_ERR_SYMBOL_INDEX_IS_INVALID",
  17.         "EPEP_ERR_NOT_AN_OBJECT",
  18.         "EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA",
  19.         "EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO",
  20.         "EPEP_ERR_OUTPUT_IS_NULL",
  21.         "EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION",
  22.         "EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND",
  23.         "EPEP_ERR_NO_BASE_RELOCATION_TABLE",
  24.         "EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END",
  25.         "EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET",
  26.         "EPEP_ERR_INVALID_SECTION_HEADER_OFFSET",
  27.         "EPEP_ERR_INVALID_SECTION_DATA_OFFSET",
  28.         "EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET",
  29.         "EPEP_ERR_INVALID_SYMBOL_OFFSET",
  30.         "EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET",
  31.         "EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET",
  32.         "EPEP_ERR_INVALID_LOOKUP_OFFSET",
  33.         "EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET",
  34.         "EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET",
  35.         "EPEP_ERR_INVALID_DLL_NAME_OFFSET",
  36.         "EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET",
  37.         "EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET",
  38.         "EPEP_ERR_INVALID_EXPORT_NAME_OFFSET",
  39.         "EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET",
  40.         "EPEP_ERR_INVALID_FORWARDER_OFFSET",
  41.         "EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET",
  42.         "EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET",
  43.         "EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET",
  44.         "EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET",
  45.         "EPEP_ERR_INVALID_LINENUMBER_OFFSET",
  46. };
  47.  
  48. typedef char *pchar;
  49.  
  50. typedef struct {
  51.         Epep epep;
  52.         char *name;
  53.         size_t *section_offsets;
  54. } CoffObject;
  55.  
  56. typedef struct {
  57.         size_t obj_id;
  58.         size_t sec_id;
  59. } ObjIdSecId;
  60.  
  61. typedef struct {
  62.         ObjIdSecId *source;
  63.         uint32_t characteristics;
  64.         size_t size;
  65.         size_t number_of_relocations;
  66. } SectionInfo;
  67.  
  68. typedef struct {
  69.         EpepCoffSymbol sym;
  70.         EpepCoffSymbol *auxes;
  71.         char *name;
  72.         size_t object_index;
  73.         size_t index;
  74. } Symbol;
  75.  
  76. #define CDICT_VAL_T SectionInfo
  77. #define CDICT_INST
  78. #include "cdict/cdict.h"
  79.  
  80. #define CDICT_VAL_T Symbol
  81. #define CDICT_INST
  82. #include "cdict/cdict.h"
  83.  
  84. typedef struct {
  85.         CoffObject *objects;
  86.         char **section_names_set;
  87.         CDict_CStr_SectionInfo info_per_section;
  88.         CDict_CStr_Symbol symtab;
  89.         char **sym_name_set;
  90.         size_t number_of_symbols;
  91. } ObjectIr;
  92.  
  93. #define CVEC_INST
  94. #define CVEC_TYPE CoffObject
  95. #include "cvec/cvec.h"
  96.  
  97. #define CVEC_INST
  98. #define CVEC_TYPE size_t
  99. #include "cvec/cvec.h"
  100.  
  101. #define CVEC_INST
  102. #define CVEC_TYPE pchar
  103. #include "cvec/cvec.h"
  104.  
  105. #define CVEC_INST
  106. #define CVEC_TYPE char
  107. #include "cvec/cvec.h"
  108.  
  109. #define CVEC_INST
  110. #define CVEC_TYPE ObjIdSecId
  111. #include "cvec/cvec.h"
  112.  
  113. #define CVEC_INST
  114. #define CVEC_TYPE EpepCoffSymbol
  115. #include "cvec/cvec.h"
  116.  
  117. #define ERROR_EPEP(epep) printf("Error: epep returned %u (%s) at "__FILE__":%u", \
  118.                                 (epep)->error_code, epep_errors[(epep)->error_code], __LINE__); exit(-1)
  119.  
  120. #define ERROR_CDICT(cdict) printf("Error: cdict returned %u at "__FILE__":%u", \
  121.                                   (cdict)->error_code, __LINE__); exit(-1);
  122.  
  123. static int emit_logs;
  124.  
  125. static void log_info(const char *fmt, ...) {
  126.         if (emit_logs) {
  127.                 va_list ap;
  128.                 va_start(ap, fmt);
  129.                 vprintf(fmt, ap);
  130.                 va_end(ap);
  131.         }
  132. }
  133.  
  134. static void fwrite8(FILE *f, uint8_t b) {
  135.         fputc(b, f);
  136. }
  137.  
  138. static void fwrite16(FILE *f, uint16_t w) {
  139.         fputc((w & 0x00ff) >> 0, f);
  140.         fputc((w & 0xff00) >> 8, f);
  141. }
  142.  
  143. static void fwrite32(FILE *f, uint32_t d) {
  144.         fputc((d & 0x000000ff) >> 0, f);
  145.         fputc((d & 0x0000ff00) >> 8, f);
  146.         fputc((d & 0x00ff0000) >> 16, f);
  147.         fputc((d & 0xff000000) >> 24, f);
  148. }
  149.  
  150. static size_t strtab_add(char **strtab, char *str) {
  151.         size_t res = cvec_char_size(strtab);
  152.  
  153.         for (char *p = str; *p; p++) {
  154.                 cvec_char_push_back(strtab, *p);
  155.         }
  156.         cvec_char_push_back(strtab, '\0');
  157.         return res + 4;
  158. }
  159.  
  160. static size_t get_section_number(char ***section_names_set, char *sec_name) {
  161.         for (size_t i = 0; i < cvec_pchar_size(section_names_set); i++) {
  162.                 char *it = cvec_pchar_at(section_names_set, i);
  163.                 if (!strcmp(it, sec_name)) {
  164.                         return i + 1;
  165.                 }
  166.         }
  167.         return 0;
  168. }
  169.  
  170. static void add_name_to_set(char *sym_name, char ***set) {
  171.         for (size_t i = 0; i < cvec_pchar_size(set); i++) {
  172.                 char *it = cvec_pchar_at(set, i);
  173.                 if (!strcmp(it, sym_name)) {
  174.                         return;
  175.                 }
  176.         }
  177.         cvec_pchar_push_back(set, sym_name);
  178. }
  179.  
  180. static void build(ObjectIr *ir, const char *outname) {
  181.         FILE *out = fopen(outname, "wb");
  182.         char *strtab = cvec_char_new(1024);
  183.         size_t size_of_sections = 0;
  184.         size_t number_of_relocations = 0;
  185.  
  186.         log_info("Calculating all sections size and relocations count... ");
  187.         for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
  188.                 char *name = ir->section_names_set[sec_i];
  189.  
  190.                 SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
  191.                 size_of_sections += si.size;
  192.                 number_of_relocations += si.number_of_relocations;
  193.         }
  194.         log_info("Done: %u & %u\n", size_of_sections, number_of_relocations);
  195.  
  196.         size_t fisrt_section_offset = 20 + 40 * cvec_pchar_size(&ir->section_names_set);
  197.         size_t offset_to_first_relocation = fisrt_section_offset + size_of_sections;
  198.         size_t offset_to_next_relocation = offset_to_first_relocation;
  199.         size_t next_section_offset = fisrt_section_offset;
  200.  
  201.         size_t PointerToSymbolTable = fisrt_section_offset + size_of_sections + number_of_relocations * 10;
  202.  
  203.         // COFF Header
  204.         log_info("Writing COFF header... ");
  205.         fwrite16(out, 0x14c);                                   // Machine
  206.         fwrite16(out, cvec_pchar_size(&ir->section_names_set)); // NumberOfSections
  207.         fwrite32(out, 0);                                       // TimeDataStamp
  208.         fwrite32(out, PointerToSymbolTable);                    // PointerToSymbolTable
  209.         fwrite32(out, ir->number_of_symbols);                   // NumberOfSymbols
  210.         fwrite16(out, 0);                                       // SizeOfOptionalHeader
  211.         fwrite16(out, 0);                                       // Characteristics
  212.         log_info("Done.\n");
  213.  
  214.         // Section Headers
  215.         log_info("Writing section headers {\n");
  216.         for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
  217.                 char *name = ir->section_names_set[sec_i];
  218.                 SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
  219.  
  220.                 // Name
  221.                 log_info(" Writing %s Section Header... ", name);
  222.                 if (strlen(name) <= 8) {
  223.                         for (size_t i = 0; i < 8; i++) {
  224.                                 size_t sl = strlen(name);
  225.                                 fwrite8(out, i < sl ? name[i] : '\0');
  226.                         }
  227.                 } else {
  228.                         fwrite8(out, '/');
  229.  
  230.                         size_t strtab_index = strtab_add(&strtab, name);
  231.                         char numstr[8] = { 0 };
  232.                         sprintf(numstr, "%lu", strtab_index);
  233.                         fwrite(numstr, 1, 7, out);
  234.                 }
  235.                 fwrite32(out, 0);                         // VirtualSize
  236.                 fwrite32(out, 0);                         // VirtualAddress
  237.                 fwrite32(out, si.size);                   // SizeOfRawData
  238.                 fwrite32(out, next_section_offset);       // PointerToRawData
  239.                 next_section_offset += si.size;
  240.                 fwrite32(out, offset_to_next_relocation); // PointerToRelocations
  241.                 offset_to_next_relocation += si.number_of_relocations * 10;
  242.                 fwrite32(out, 0);                         // PointerToLinenumbers
  243.                 fwrite16(out, si.number_of_relocations);  // NumberOfRelocations
  244.                 fwrite16(out, 0);                         // NumberOfLinenumbers
  245.                 fwrite32(out, si.characteristics);        // Characteristics
  246.                 log_info("Done.\n");
  247.         }
  248.         log_info("}\n");
  249.  
  250.         // Section data
  251.         log_info("Writing sections {\n");
  252.         for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
  253.                 char *name = ir->section_names_set[sec_i];
  254.                 SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
  255.  
  256.                 log_info(" Writing %s... ", name);
  257.                 for (size_t i = 0; i < cvec_ObjIdSecId_size(&si.source); i++) {
  258.                         ObjIdSecId id = cvec_ObjIdSecId_at(&si.source, i);
  259.                         CoffObject *object = &ir->objects[id.obj_id];
  260.                         Epep *epep = &object->epep;
  261.  
  262.                         EpepSectionHeader sh = { 0 };
  263.                         if (!epep_get_section_header_by_index(epep, &sh, id.sec_id)) {
  264.                                 ERROR_EPEP(epep);
  265.                         }
  266.  
  267.                         // If the section contains uninitialized data (BSS)
  268.                         // it should be filled by zeroes
  269.                         // Yes, current implementation emits BSS sections too
  270.                         // cause KOS has no idea they should be allocated automatically
  271.                         // cause FASM has no idea they should be generated without contents
  272.                         // cause Tomasz Grysztar didn't care
  273.                         char *buf = calloc(sh.SizeOfRawData, 1);
  274.  
  275.                         // Othervice it should be filled by its contents from source object
  276.                         if (!(sh.Characteristics & 0x00000080)) {
  277.                                 if (!epep_get_section_contents(epep, &sh, buf)) {
  278.                                         ERROR_EPEP(epep);
  279.                                 }
  280.                         }
  281.  
  282.                         fwrite(buf, 1, sh.SizeOfRawData, out);
  283.                 }
  284.                 log_info("Done.\n");
  285.         }
  286.         log_info("}\n");
  287.  
  288.         // COFF Relocations
  289.         char **undefined_symbols = cvec_pchar_new(8);
  290.  
  291.         log_info("Writing COFF Relocations {\n");
  292.         for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
  293.                 char *name = ir->section_names_set[sec_i];
  294.                 SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
  295.  
  296.                 log_info(" Writing relocations of %s {\n", name);
  297.                 for (size_t i = 0; i < cvec_ObjIdSecId_size(&si.source); i++) {
  298.                         ObjIdSecId id = cvec_ObjIdSecId_at(&si.source, i);
  299.                         CoffObject *object = &ir->objects[id.obj_id];
  300.                         Epep *epep = &object->epep;
  301.  
  302.                         size_t strtab_size = 0;
  303.                         if (!epep_get_string_table_size(epep, &strtab_size)) {
  304.                                 ERROR_EPEP(epep);
  305.                         }
  306.  
  307.                         char *obj_strtab = malloc(strtab_size);
  308.                         if (!epep_get_string_table(epep, obj_strtab)) {
  309.                                 ERROR_EPEP(epep);
  310.                         }
  311.  
  312.                         EpepSectionHeader sh = { 0 };
  313.                         if (!epep_get_section_header_by_index(epep, &sh, id.sec_id)) {
  314.                                 ERROR_EPEP(epep);
  315.                         }
  316.                         for (size_t rel_i = 0; rel_i < sh.NumberOfRelocations; rel_i++) {
  317.                                 EpepCoffRelocation rel = { 0 };
  318.  
  319.                                 if (!epep_get_section_relocation_by_index(epep, &sh, &rel, rel_i)) {
  320.                                         ERROR_EPEP(epep);
  321.                                 }
  322.                                 log_info("  { %02x, %02x, %02x }", rel.VirtualAddress, rel.SymbolTableIndex, rel.Type);
  323.                                 rel.VirtualAddress += object->section_offsets[sec_i];
  324.                                 {
  325.                                         size_t index = rel.SymbolTableIndex;
  326.                                         EpepCoffSymbol sym = { 0 };
  327.  
  328.                                         if (!epep_get_symbol_by_index(epep, &sym, index)) {
  329.                                                 ERROR_EPEP(epep);
  330.                                         }
  331.  
  332.                                         size_t name_max = 1024;
  333.                                         char name[name_max];
  334.  
  335.                                         if (sym.symbol.Zeroes == 0) {
  336.                                                 strcpy(name, &obj_strtab[sym.symbol.Offset]);
  337.                                         } else {
  338.                                                 memcpy(name, sym.symbol.ShortName, 8);
  339.                                                 name[8] = '\0';
  340.                                         }
  341.  
  342.                                         if (!strcmp(name, "_EXPORTS")) {
  343.                                                 strcpy(name, "EXPORTS");
  344.                                         }
  345.  
  346.                                         if (sym.symbol.StorageClass != 2) {
  347.                                                 sprintf(name, "%s@%s", name, object->name);
  348.                                         }
  349.  
  350.                                         Symbol old_sym = cdict_CStr_Symbol_get_v(&ir->symtab, name);
  351.  
  352.                                         if (old_sym.name == NULL) {
  353.                                                 add_name_to_set(strdup(name), &undefined_symbols);
  354.                                         }
  355.  
  356.                                         rel.SymbolTableIndex = old_sym.index;
  357.                                         log_info(" -> { %02x, %02x, %02x }: ", rel.VirtualAddress, rel.SymbolTableIndex, rel.Type);
  358.                                         log_info("New relocation of %s in %s\n", name, sh.Name);
  359.                                 }
  360.                                 fwrite(&rel, 1, 10, out);
  361.                         }
  362.                 }
  363.                 log_info(" }\n");
  364.         }
  365.         log_info("}\n");
  366.  
  367.         if (cvec_pchar_size(&undefined_symbols) > 0) {
  368.                 printf("Undefined symbols found, aborting\nUndefined:\n");
  369.                 for (int i = 0; i < cvec_pchar_size(&undefined_symbols); i++) {
  370.                         printf("%s\n", undefined_symbols[i]);
  371.                 }
  372.                 exit(-1);
  373.         }
  374.  
  375.         // Symbols Table
  376.         log_info("Writing symbols {\n");
  377.         for (size_t sym_i = 0; sym_i < cvec_pchar_size(&ir->sym_name_set); sym_i++) {
  378.                 char *name = ir->sym_name_set[sym_i];
  379.  
  380.                 Symbol sym = cdict_CStr_Symbol_get_v(&ir->symtab, name);
  381.  
  382.                 if (sym.sym.symbol.SectionNumber == 0xffff ||
  383.                         sym.sym.symbol.SectionNumber == 0xfffe ||
  384.                         (sym.sym.symbol.StorageClass != 2 &&  // Not an external symbol
  385.                          sym.sym.symbol.StorageClass != 3 &&  // Not a static symbol
  386.                          sym.sym.symbol.StorageClass != 6)) { // Not a label
  387.                         fwrite(&sym.sym.symbol, 1, 18, out);
  388.                 } else {
  389.                         size_t sec_name_max = 1024;
  390.                         char sec_name[sec_name_max];
  391.  
  392.                         size_t object_index = sym.object_index;
  393.                         CoffObject *object = &ir->objects[object_index];
  394.                         Epep *epep = &object->epep;
  395.                         size_t section_offset = object->section_offsets[sym.sym.symbol.SectionNumber - 1];
  396.  
  397.                         size_t strtab_size = 0;
  398.                         if (!epep_get_string_table_size(epep, &strtab_size)) {
  399.                                 ERROR_EPEP(epep);
  400.                         }
  401.  
  402.                         char *obj_strtab = malloc(strtab_size);
  403.                         if (!epep_get_string_table(epep, obj_strtab)) {
  404.                                 ERROR_EPEP(epep);
  405.                         }
  406.  
  407.                         EpepSectionHeader sh = { 0 };
  408.                         if (!epep_get_section_header_by_index(epep, &sh, sym.sym.symbol.SectionNumber - 1)) {
  409.                                 ERROR_EPEP(epep);
  410.                         }
  411.  
  412.                         if (sh.Name[0] == '/') {
  413.                                 strcpy(sec_name, &obj_strtab[atoi(&sh.Name[1])]);
  414.                         } else {
  415.                                 memcpy(sec_name, sh.Name, 8);
  416.                                 sec_name[8] = '\0';
  417.                         }
  418.  
  419.                         log_info("%s:\n", sym.name);
  420.                         log_info(" Section:      %s\n", sec_name);
  421.                         log_info(" StorageClass: %u\n", sym.sym.symbol.StorageClass);
  422.  
  423.                         sym.sym.symbol.SectionNumber = get_section_number(&ir->section_names_set, sec_name);
  424.  
  425.                         if (sym.sym.symbol.SectionNumber == 0) {
  426.                                 printf("Internal error: %s section is not found in output file", sec_name);
  427.                                 exit(-1);
  428.                         }
  429.  
  430.                         sym.sym.symbol.Value += section_offset;
  431.  
  432.                         if (strlen(sym.name) <= 8) {
  433.                                 memcpy(sym.sym.symbol.ShortName, sym.name, 8);
  434.                         } else {
  435.                                 sym.sym.symbol.Zeroes = 0;
  436.                                 sym.sym.symbol.Offset = strtab_add(&strtab, name);
  437.                         }
  438.  
  439.                         fwrite(&sym.sym.symbol, 1, 18, out);
  440.                 }
  441.                 for (size_t aux_i = 0; aux_i < sym.sym.symbol.NumberOfAuxSymbols; aux_i++) {
  442.                         fwrite(&sym.auxes[aux_i].symbol, 1, 18, out);
  443.                 }
  444.         }
  445.         log_info("}\n");
  446.  
  447.         // COFF String Table
  448.         log_info("Writing COFF String Table... ");
  449.         fwrite32(out, cvec_char_size(&strtab) + 4);
  450.         fwrite(strtab, 1, cvec_char_size(&strtab), out);
  451.         log_info("Done.\n");
  452. }
  453.  
  454. static ObjectIr parse_objects(int argc, char **argv) {
  455.         CoffObject *objects = cvec_CoffObject_new(128);
  456.         char **section_names_set = cvec_pchar_new(4);
  457.         char **sym_name_set = cvec_pchar_new(128);
  458.         size_t number_of_symbols = 0;
  459.  
  460.         for (int i = 1; i < argc; i++) {
  461.                 // If one arg is NULL, that means it was a parameter and was cleared
  462.                 // It's not a input file name
  463.                 if (argv[i] == NULL) {
  464.                         continue;
  465.                 }
  466.  
  467.                 log_info("Primary parsing of %s... ", argv[i]);
  468.  
  469.                 CoffObject object = { 0 };
  470.                 object.name = argv[i];
  471.                 object.section_offsets = cvec_size_t_new(128);
  472.                
  473.                 {
  474.                         FILE *fp = fopen(object.name, "rb");
  475.                         if (!fp) {
  476.                                 printf("Error: Can't open \"%s\"", object.name);
  477.                                 exit(-1);
  478.                         }
  479.  
  480.                         if (!epep_init(&object.epep, fp)) {
  481.                                 ERROR_EPEP(&object.epep);
  482.                         }
  483.                 }
  484.  
  485.                 cvec_CoffObject_push_back(&objects, object);
  486.  
  487.                 log_info("Done.\n");
  488.         }
  489.  
  490.         CDict_CStr_Symbol symtab;
  491.  
  492.         if (!cdict_CStr_Symbol_init(&symtab)) {
  493.                 ERROR_CDICT(&symtab);
  494.         }
  495.  
  496.         CDict_CStr_SectionInfo info_per_section;
  497.  
  498.         if (!cdict_CStr_SectionInfo_init(&info_per_section)) {
  499.                 ERROR_CDICT(&info_per_section);
  500.         }
  501.  
  502.         for (size_t i = 0; i < cvec_CoffObject_size(&objects); i++) {
  503.                 log_info("Secondary parsing of %s {\n", objects[i].name);
  504.  
  505.                 Epep *epep = &(objects[i].epep);
  506.  
  507.                 size_t strtab_size = 0;
  508.                 if (!epep_get_string_table_size(epep, &strtab_size)) {
  509.                         ERROR_EPEP(epep);
  510.                 }
  511.  
  512.                 char *strtab = malloc(strtab_size);
  513.                 if (!epep_get_string_table(epep, strtab)) {
  514.                         ERROR_EPEP(epep);
  515.                 }
  516.  
  517.                 // Fill symbols table
  518.                 log_info(" Symbols {\n");
  519.                 for (size_t sym_i = 0; sym_i < epep->coffFileHeader.NumberOfSymbols; sym_i++) {
  520.                         EpepCoffSymbol sym = { 0 };
  521.  
  522.                         if (!epep_get_symbol_by_index(epep, &sym, sym_i)) {
  523.                                 ERROR_EPEP(epep);
  524.                         }
  525.  
  526.                         size_t name_max = 1024;
  527.                         char name[name_max];
  528.  
  529.                         if (sym.symbol.Zeroes == 0) {
  530.                                 strcpy(name, &strtab[sym.symbol.Offset]);
  531.                         } else {
  532.                                 memcpy(name, sym.symbol.ShortName, 8);
  533.                                 name[8] = '\0';
  534.                         }
  535.  
  536.                         if (!strcmp(name, "_EXPORTS")) {
  537.                                 strcpy(name, "EXPORTS");
  538.                         }
  539.  
  540.                         if (sym.symbol.StorageClass != 2) {
  541.                                 sprintf(name, "%s@%s", name, objects[i].name);
  542.                         }
  543.  
  544.                         if (sym.symbol.StorageClass != 2 || sym.symbol.SectionNumber) {
  545.                                 if (memcmp(cdict_CStr_Symbol_get_v(&symtab, name).sym.symbol.ShortName, "\0\0\0\0\0\0\0\0", 8)) {
  546.                                         printf("Error: Redefinition of \"%s\"", name);
  547.                                         exit(-1);
  548.                                 }
  549.  
  550.                                 EpepCoffSymbol *auxes = cvec_EpepCoffSymbol_new(1);
  551.                                 size_t index = number_of_symbols;
  552.  
  553.                                 for (size_t aux_i = 0; aux_i < sym.symbol.NumberOfAuxSymbols; aux_i++) {
  554.                                         EpepCoffSymbol aux = { 0 };
  555.  
  556.                                         if (!epep_get_symbol_by_index(epep, &aux, sym_i + aux_i)) {
  557.                                                 ERROR_EPEP(epep);
  558.                                         }
  559.                                         cvec_EpepCoffSymbol_push_back(&auxes, aux);
  560.                                         number_of_symbols++;
  561.                                 }
  562.  
  563.                                 Symbol new_sym = { sym, auxes, strdup(name), i, index };
  564.                                 if (!cdict_CStr_Symbol_add_vv(&symtab, strdup(name), new_sym, CDICT_NO_CHECK)) {
  565.                                         ERROR_CDICT(&symtab);
  566.                                 }
  567.                                 number_of_symbols++;
  568.  
  569.                                 log_info("  Symbol #%u: %s (%u auxes, #%u)\n", sym_i, name, cvec_EpepCoffSymbol_size(&auxes), number_of_symbols - 1);
  570.  
  571.                                 add_name_to_set(strdup(name), &sym_name_set);
  572.                         }
  573.  
  574.                         sym_i += sym.symbol.NumberOfAuxSymbols;
  575.                 }
  576.                 log_info(" }\n");
  577.  
  578.                 // Set section offsets and fill unique section name set
  579.                 log_info(" Sections {\n");
  580.                 for (size_t sec_i = 0; sec_i < epep->coffFileHeader.NumberOfSections; sec_i++) {
  581.                         EpepSectionHeader sh = { 0 };
  582.  
  583.                         if (!epep_get_section_header_by_index(epep, &sh, sec_i)) {
  584.                                 ERROR_EPEP(epep);
  585.                         }
  586.  
  587.                         size_t name_max = 1024;
  588.                         char name[name_max];
  589.  
  590.                         if (sh.Name[0] == '/') {
  591.                                 strcpy(name, &strtab[atoi(&sh.Name[1])]);
  592.                         } else {
  593.                                 memcpy(name, sh.Name, 8);
  594.                                 name[8] = '\0';
  595.                         }
  596.  
  597.                         add_name_to_set(strdup(name), &section_names_set);
  598.  
  599.                         SectionInfo si = cdict_CStr_SectionInfo_get_v(&info_per_section, name);
  600.                         if (si.source == NULL) {
  601.                                 si.source = cvec_ObjIdSecId_new(32);
  602.                         }
  603.  
  604.                         size_t sec_offset = si.size;
  605.                         cvec_size_t_push_back(&objects[i].section_offsets, sec_offset);
  606.  
  607.                         si.size += sh.SizeOfRawData;
  608.                         si.characteristics |= sh.Characteristics;
  609.                         si.number_of_relocations += sh.NumberOfRelocations;
  610.                         cvec_ObjIdSecId_push_back(&si.source, (ObjIdSecId){ i, sec_i });
  611.                         cdict_CStr_SectionInfo_add_vv(&info_per_section, strdup(name), si, CDICT_REPLACE_EXIST);
  612.  
  613.                         log_info("  Section #%llu {\n", sec_i);
  614.                         log_info("   Name:                      %s\n", name);
  615.                         log_info("   Virtual Address:           %u\n", sh.VirtualAddress);
  616.                         log_info("   Characteristics:           %08x\n", sh.Characteristics);
  617.                         log_info("   Offset in the big section: %u\n", objects[i].section_offsets[sec_i]);
  618.                         log_info("  }\n");
  619.  
  620.                         if (sh.VirtualAddress != 0) {
  621.                                 printf("Warning: Handling of section with Virtual Address another that 0 is not implemented");
  622.                         }
  623.                 }
  624.                 log_info(" }\n");
  625.                 log_info("}\n");
  626.         }
  627.  
  628.         ObjectIr ir;
  629.         ir.objects = objects;
  630.         ir.section_names_set = section_names_set;
  631.         ir.info_per_section = info_per_section;
  632.         ir.symtab = symtab;
  633.         ir.sym_name_set = sym_name_set;
  634.         ir.number_of_symbols = number_of_symbols;
  635.         return ir;
  636. }
  637.  
  638. int arg_got_flag(int argc, char **argv, ...) {
  639.         char *arg_names[8];
  640.         int arg_name_c = 0;
  641.  
  642.         va_list ap;
  643.         va_start(ap, argv);
  644.         for (char *arg_name = va_arg(ap, char *); arg_name; arg_name = va_arg(ap, char *)) {
  645.                 if (arg_name_c >= 8) {
  646.                         printf("Internal error: Too many parameter aliases passed to %s", __func__);
  647.                         exit(-1);
  648.                 }
  649.                 arg_names[arg_name_c++] = arg_name;
  650.         }
  651.         va_end(ap);
  652.  
  653.         for (int i = 1; i < argc; i++) {
  654.                 // If an argumetns was handled already then it's NULL here
  655.                 if (argv[i] == NULL) {
  656.                         continue;
  657.                 }
  658.                 for (int arg_name_i = 0; arg_name_i < arg_name_c; arg_name_i++) {
  659.                         char *arg_name = arg_names[arg_name_i];
  660.                         if (!strcmp(argv[i], arg_name)) {
  661.                                 argv[i] = NULL; // Do not handle this argument as a input name
  662.                                 return i;
  663.                         }
  664.                 }
  665.         }
  666.         return 0;
  667. }
  668.  
  669. char *arg_got_param(int argc, char **argv, char *arg) {
  670.         int i = arg_got_flag(argc, argv, arg, 0);
  671.         if (i == 0) {
  672.                 return NULL;
  673.         }
  674.  
  675.         if (i + 1 >= argc) {
  676.                 printf("Warning: %s parameter expects a value (like %s <value>)", arg, arg);
  677.                 return NULL;
  678.         }
  679.         char *result = argv[i + 1];
  680.         argv[i + 1] = NULL;
  681.         return result;
  682. }
  683.  
  684. int usage(char *name, char *remark) {
  685.         if (remark) {
  686.                 printf("Error: %s\n\n", remark);
  687.         }
  688.         printf("Usage: %s [option]... [object file name]...\n", name);
  689.         printf("  Link multiple COFF files into one\n");
  690.         printf("\n");
  691.         printf("Options:\n");
  692.         printf("  -o <outname>  Output into <outname>\n");
  693.         printf("  -v, --verbose Emit information logs\n");
  694.         printf("  -h, --help    Output this help and exit\n");
  695.         return 0;
  696. }
  697.  
  698. int main(int argc, char **argv) {
  699.         if (arg_got_flag(argc, argv, "-h", "-help", "--help", 0)) {
  700.                 return usage(argv[0], NULL);
  701.         }
  702.  
  703.         const char *outname = arg_got_param(argc, argv, "-o");
  704.         if (outname == NULL) {
  705.                 outname = "a.out.obj";
  706.         }
  707.  
  708.         emit_logs = arg_got_flag(argc, argv, "-v", "-verbose", "--verbose", 0);
  709.  
  710.         // After handling arguments there only leaven unhandled ones
  711.         // They should be names if inputs. But if there's no input - exit
  712.         int input_file_count = 0;
  713.         for (int i = 1; i < argc; i++) {
  714.                 if (argv[i] != NULL) {
  715.                         input_file_count++;
  716.                 }
  717.         }
  718.         if (input_file_count == 0) {
  719.                 return usage(argv[0], "No input file names supplied");
  720.         }
  721.  
  722.         ObjectIr ir = parse_objects(argc, argv);
  723.         build(&ir, outname);
  724.         return 0;
  725. }
  726.