Subversion Repositories Kolibri OS

Rev

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