Subversion Repositories Kolibri OS

Rev

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

  1. // TODO: Substract section's RVA from external and static defined symbol's value
  2. // TODO: Substract section's RVA from relocations
  3.  
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <stdint.h>
  7. #include <assert.h>
  8. #include <string.h>
  9.  
  10. #define EPEP_INST
  11. #include "epep/epep.h"
  12.  
  13. typedef char *pchar;
  14.  
  15. typedef struct {
  16.         Epep epep;
  17.         char *name;
  18.         size_t *section_offsets;
  19. } CoffObject;
  20.  
  21. typedef struct {
  22.         size_t obj_id;
  23.         size_t sec_id;
  24. } ObjIdSecId;
  25.  
  26. typedef struct {
  27.         ObjIdSecId *source;
  28.         uint32_t characteristics;
  29.         size_t size;
  30.         size_t number_of_relocations;
  31. } SectionInfo;
  32.  
  33. typedef struct {
  34.         EpepCoffSymbol sym;
  35.         EpepCoffSymbol *auxes;
  36.         char *name;
  37.         size_t object_index;
  38.         size_t index;
  39. } Symbol;
  40.  
  41. #define CDICT_VAL_T SectionInfo
  42. #define CDICT_INST
  43. #include "cdict/cdict.h"
  44.  
  45. #define CDICT_VAL_T Symbol
  46. #define CDICT_INST
  47. #include "cdict/cdict.h"
  48.  
  49. typedef struct {
  50.         CoffObject *objects;
  51.         char **section_names_set;
  52.         CDict_CStr_SectionInfo info_per_section;
  53.         CDict_CStr_Symbol symtab;
  54.         char **sym_name_set;
  55.         size_t number_of_symbols;
  56. } ObjectIr;
  57.  
  58. #define CVEC_INST
  59. #define CVEC_TYPE CoffObject
  60. #include "cvec/cvec.h"
  61.  
  62. #define CVEC_INST
  63. #define CVEC_TYPE size_t
  64. #include "cvec/cvec.h"
  65.  
  66. #define CVEC_INST
  67. #define CVEC_TYPE pchar
  68. #include "cvec/cvec.h"
  69.  
  70. #define CVEC_INST
  71. #define CVEC_TYPE char
  72. #include "cvec/cvec.h"
  73.  
  74. #define CVEC_INST
  75. #define CVEC_TYPE ObjIdSecId
  76. #include "cvec/cvec.h"
  77.  
  78. #define CVEC_INST
  79. #define CVEC_TYPE EpepCoffSymbol
  80. #include "cvec/cvec.h"
  81.  
  82. #define ERROR_EPEP(epep) printf("Error: epep returned %u at "__FILE__":%u", \
  83.                                 (epep)->error_code, __LINE__); exit(-1)
  84.  
  85. #define ERROR_CDICT(cdict) printf("Error: cdict returned %u at "__FILE__":%u", \
  86.                                   (cdict)->error_code, __LINE__); exit(-1);
  87.  
  88. static void fwrite8(FILE *f, uint8_t b) {
  89.         fputc(b, f);
  90. }
  91.  
  92. static void fwrite16(FILE *f, uint16_t w) {
  93.         fputc((w & 0x00ff) >> 0, f);
  94.         fputc((w & 0xff00) >> 8, f);
  95. }
  96.  
  97. static void fwrite32(FILE *f, uint32_t d) {
  98.         fputc((d & 0x000000ff) >> 0, f);
  99.         fputc((d & 0x0000ff00) >> 8, f);
  100.         fputc((d & 0x00ff0000) >> 16, f);
  101.         fputc((d & 0xff000000) >> 24, f);
  102. }
  103.  
  104. static size_t strtab_add(char **strtab, char *str) {
  105.         size_t res = cvec_char_size(strtab);
  106.  
  107.         for (char *p = str; *p; p++) {
  108.                 cvec_char_push_back(strtab, *p);
  109.         }
  110.         cvec_char_push_back(strtab, '\0');
  111.         return res + 4;
  112. }
  113.  
  114. static size_t get_section_number(char ***section_names_set, char *sec_name) {
  115.         for (size_t i = 0; i < cvec_pchar_size(section_names_set); i++) {
  116.                 char *it = cvec_pchar_at(section_names_set, i);
  117.                 if (!strcmp(it, sec_name)) {
  118.                         return i + 1;
  119.                 }
  120.         }
  121.         return 0;
  122. }
  123.  
  124. static void add_name_to_set(char *sym_name, char ***set) {
  125.         for (size_t i = 0; i < cvec_pchar_size(set); i++) {
  126.                 char *it = cvec_pchar_at(set, i);
  127.                 if (!strcmp(it, sym_name)) {
  128.                         return;
  129.                 }
  130.         }
  131.         cvec_pchar_push_back(set, sym_name);
  132. }
  133.  
  134. static void build(ObjectIr *ir) {
  135.         FILE *out = fopen("a.out.obj", "wb");
  136.         char *strtab = cvec_char_new(1024);
  137.         size_t size_of_sections = 0;
  138.         size_t number_of_relocations = 0;
  139.  
  140.         printf("Calculating all sections size and relocations count... ");
  141.         for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
  142.                 char *name = ir->section_names_set[sec_i];
  143.  
  144.                 SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
  145.                 size_of_sections += si.size;
  146.                 number_of_relocations += si.number_of_relocations;
  147.         }
  148.         printf("Done: %u & %u\n", size_of_sections, number_of_relocations);
  149.  
  150.         size_t fisrt_section_offset = 20 + 40 * cvec_pchar_size(&ir->section_names_set);
  151.         size_t offset_to_first_relocation = fisrt_section_offset + size_of_sections;
  152.         size_t offset_to_next_relocation = offset_to_first_relocation;
  153.         size_t next_section_offset = fisrt_section_offset;
  154.  
  155.         size_t PointerToSymbolTable = fisrt_section_offset + size_of_sections + number_of_relocations * 10;
  156.  
  157.         // COFF Header
  158.         printf("Writing COFF header... ");
  159.         fwrite16(out, 0x14c);                                   // Machine
  160.         fwrite16(out, cvec_pchar_size(&ir->section_names_set)); // NumberOfSections
  161.         fwrite32(out, 0);                                       // TimeDataStamp
  162.         fwrite32(out, PointerToSymbolTable);                    // PointerToSymbolTable
  163.         fwrite32(out, ir->number_of_symbols);                   // NumberOfSymbols
  164.         fwrite16(out, 0);                                       // SizeOfOptionalHeader
  165.         fwrite16(out, 0);                                       // Characteristics
  166.         printf("Done.\n");
  167.  
  168.         // Section Headers
  169.         printf("Writing section headers {\n");
  170.         for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
  171.                 char *name = ir->section_names_set[sec_i];
  172.                 SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
  173.  
  174.                 // Name
  175.                 printf(" Writing %s Section Header... ", name);
  176.                 if (strlen(name) <= 8) {
  177.                         for (size_t i = 0; i < 8; i++) {
  178.                                 size_t sl = strlen(name);
  179.                                 fwrite8(out, i < sl ? name[i] : '\0');
  180.                         }
  181.                 } else {
  182.                         fwrite8(out, '/');
  183.  
  184.                         size_t strtab_index = strtab_add(&strtab, name);
  185.                         char numstr[8] = { 0 };
  186.                         sprintf(numstr, "%u", strtab_index);
  187.                         fwrite(numstr, 1, 7, out);
  188.                 }
  189.                 fwrite32(out, 0);                         // VirtualSize
  190.                 fwrite32(out, 0);                         // VirtualAddress
  191.                 fwrite32(out, si.size);                   // SizeOfRawData
  192.                 fwrite32(out, next_section_offset);       // PointerToRawData
  193.                 next_section_offset += si.size;
  194.                 fwrite32(out, offset_to_next_relocation); // PointerToRelocations
  195.                 offset_to_next_relocation += si.number_of_relocations * 10;
  196.                 fwrite32(out, 0);                         // PointerToLinenumbers
  197.                 fwrite16(out, si.number_of_relocations);  // NumberOfRelocations
  198.                 fwrite16(out, 0);                         // NumberOfLinenumbers
  199.                 fwrite32(out, si.characteristics);        // Characteristics
  200.                 printf("Done.\n");
  201.         }
  202.         printf("}\n");
  203.  
  204.         // Section data
  205.         printf("Writing sections {\n");
  206.         for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
  207.                 char *name = ir->section_names_set[sec_i];
  208.                 SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
  209.  
  210.                 printf(" Writing %s... ", name);
  211.                 for (size_t i = 0; i < cvec_ObjIdSecId_size(&si.source); i++) {
  212.                         ObjIdSecId id = cvec_ObjIdSecId_at(&si.source, i);
  213.                         CoffObject *object = &ir->objects[id.obj_id];
  214.                         Epep *epep = &object->epep;
  215.  
  216.                         EpepSectionHeader sh = { 0 };
  217.                         if (!epep_get_section_header_by_index(epep, &sh, id.sec_id)) {
  218.                                 ERROR_EPEP(epep);
  219.                         }
  220.                         char *buf = malloc(sh.SizeOfRawData);
  221.                         if (!epep_get_section_contents(epep, &sh, buf)) {
  222.                                 ERROR_EPEP(epep);
  223.                         }
  224.                         fwrite(buf, 1, sh.SizeOfRawData, out);
  225.                 }
  226.                 printf("Done.\n");
  227.         }
  228.         printf("}\n");
  229.  
  230.         // COFF Relocations
  231.         printf("Writing COFF Relocations {\n");
  232.         for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
  233.                 char *name = ir->section_names_set[sec_i];
  234.                 SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
  235.  
  236.                 printf(" Writing relocations of %s {\n", name);
  237.                 for (size_t i = 0; i < cvec_ObjIdSecId_size(&si.source); i++) {
  238.                         ObjIdSecId id = cvec_ObjIdSecId_at(&si.source, i);
  239.                         CoffObject *object = &ir->objects[id.obj_id];
  240.                         Epep *epep = &object->epep;
  241.  
  242.                         size_t strtab_size = 0;
  243.                         if (!epep_get_string_table_size(epep, &strtab_size)) {
  244.                                 ERROR_EPEP(epep);
  245.                         }
  246.  
  247.                         char *obj_strtab = malloc(strtab_size);
  248.                         if (!epep_get_string_table(epep, obj_strtab)) {
  249.                                 ERROR_EPEP(epep);
  250.                         }
  251.  
  252.                         EpepSectionHeader sh = { 0 };
  253.                         if (!epep_get_section_header_by_index(epep, &sh, id.sec_id)) {
  254.                                 ERROR_EPEP(epep);
  255.                         }
  256.                         for (size_t rel_i = 0; rel_i < sh.NumberOfRelocations; rel_i++) {
  257.                                 EpepCoffRelocation rel = { 0 };
  258.  
  259.                                 if (!epep_get_section_relocation_by_index(epep, &sh, &rel, rel_i)) {
  260.                                         ERROR_EPEP(epep);
  261.                                 }
  262.                                 printf("  { %02x, %02x, %02x }", rel.VirtualAddress, rel.SymbolTableIndex, rel.Type);
  263.                                 rel.VirtualAddress += object->section_offsets[sec_i];
  264.                                 {
  265.                                         size_t index = rel.SymbolTableIndex;
  266.                                         EpepCoffSymbol sym = { 0 };
  267.  
  268.                                         if (!epep_get_symbol_by_index(epep, &sym, index)) {
  269.                                                 ERROR_EPEP(epep);
  270.                                         }
  271.  
  272.                                         size_t name_max = 1024;
  273.                                         char name[name_max];
  274.  
  275.                                         if (sym.symbol.Zeroes == 0) {
  276.                                                 strcpy(name, &obj_strtab[sym.symbol.Offset]);
  277.                                         } else {
  278.                                                 memcpy(name, sym.symbol.ShortName, 8);
  279.                                                 name[8] = '\0';
  280.                                         }
  281.  
  282.                                         if (!strcmp(name, "_EXPORTS")) {
  283.                                                 strcpy(name, "EXPORTS");
  284.                                         }
  285.  
  286.                                         if (sym.symbol.StorageClass != 2) {
  287.                                                 sprintf(name, "%s@%s", name, object->name);
  288.                                         }
  289.  
  290.                                         Symbol old_sym = cdict_CStr_Symbol_get_v(&ir->symtab, name);
  291.  
  292.                                         if (old_sym.name == NULL) {
  293.                                                 printf("Internal error: Symbol of %s relocation not found", name);
  294.                                                 exit(-1);
  295.                                         }
  296.  
  297.                                         rel.SymbolTableIndex = old_sym.index;
  298.                                         printf(" -> { %02x, %02x, %02x }: ", rel.VirtualAddress, rel.SymbolTableIndex, rel.Type);
  299.                                         printf("New relocation of %s in %s\n", name, sh.Name);
  300.                                 }
  301.                                 fwrite(&rel, 1, 10, out);
  302.                         }
  303.                 }
  304.                 printf(" }\n");
  305.         }
  306.         printf("}\n");
  307.  
  308.         // Symbols Table
  309.         printf("Writing symbols {\n");
  310.         for (size_t sym_i = 0; sym_i < cvec_pchar_size(&ir->sym_name_set); sym_i++) {
  311.                 char *name = ir->sym_name_set[sym_i];
  312.  
  313.                 Symbol sym = cdict_CStr_Symbol_get_v(&ir->symtab, name);
  314.  
  315.                 if (sym.sym.symbol.SectionNumber == 0xffff ||
  316.                         sym.sym.symbol.SectionNumber == 0xfffe ||
  317.                         (sym.sym.symbol.StorageClass != 2 && sym.sym.symbol.StorageClass != 3)) {
  318.                         fwrite(&sym.sym.symbol, 1, 18, out);
  319.                 } else {
  320.                         size_t sec_name_max = 1024;
  321.                         char sec_name[sec_name_max];
  322.  
  323.                         size_t object_index = sym.object_index;
  324.                         CoffObject *object = &ir->objects[object_index];
  325.                         Epep *epep = &object->epep;
  326.                         size_t section_offset = object->section_offsets[sym.sym.symbol.SectionNumber - 1];
  327.  
  328.                         size_t strtab_size = 0;
  329.                         if (!epep_get_string_table_size(epep, &strtab_size)) {
  330.                                 ERROR_EPEP(epep);
  331.                         }
  332.  
  333.                         char *obj_strtab = malloc(strtab_size);
  334.                         if (!epep_get_string_table(epep, obj_strtab)) {
  335.                                 ERROR_EPEP(epep);
  336.                         }
  337.  
  338.                         EpepSectionHeader sh = { 0 };
  339.                         if (!epep_get_section_header_by_index(epep, &sh, sym.sym.symbol.SectionNumber - 1)) {
  340.                                 ERROR_EPEP(epep);
  341.                         }
  342.  
  343.                         if (sh.Name[0] == '/') {
  344.                                 strcpy(sec_name, &obj_strtab[atoi(&sh.Name[1])]);
  345.                         } else {
  346.                                 memcpy(sec_name, sh.Name, 8);
  347.                                 sec_name[8] = '\0';
  348.                         }
  349.  
  350.                         printf("%s:\n", sym.name);
  351.                         printf(" Section:      %s\n", sec_name);
  352.                         printf(" StorageClass: %u\n", sym.sym.symbol.StorageClass);
  353.  
  354.                         sym.sym.symbol.SectionNumber = get_section_number(&ir->section_names_set, sec_name);
  355.  
  356.                         if (sym.sym.symbol.SectionNumber == 0) {
  357.                                 printf("Internal error: %s section is not found in output file");
  358.                                 exit(-1);
  359.                         }
  360.  
  361.                         sym.sym.symbol.Value += section_offset;
  362.  
  363.                         if (strlen(sym.name) <= 8) {
  364.                                 strcpy(sym.sym.symbol.ShortName, sym.name);
  365.                         } else {
  366.                                 sym.sym.symbol.Zeroes = 0;
  367.                                 sym.sym.symbol.Offset = strtab_add(&strtab, name);
  368.                         }
  369.  
  370.                         fwrite(&sym.sym.symbol, 1, 18, out);
  371.                 }
  372.                 for (size_t aux_i = 0; aux_i < sym.sym.symbol.NumberOfAuxSymbols; aux_i++) {
  373.                         fwrite(&sym.auxes[aux_i].symbol, 1, 18, out);
  374.                 }
  375.         }
  376.         printf("}\n");
  377.  
  378.         // COFF String Table
  379.         printf("Writing COFF String Table... ");
  380.         fwrite32(out, cvec_pchar_size(&strtab) + 4);
  381.         fwrite(strtab, 1, cvec_pchar_size(&strtab), out);
  382.         printf("Done.\n");
  383. }
  384.  
  385. static ObjectIr parse_objects(int argc, char **argv) {
  386.         CoffObject *objects = cvec_CoffObject_new(128);
  387.         char **section_names_set = cvec_pchar_new(4);
  388.         char **sym_name_set = cvec_pchar_new(128);
  389.         size_t number_of_symbols = 0;
  390.  
  391.         for (int i = 1; i < argc; i++) {
  392.                 printf("Primary parsing of %s... ", argv[i]);
  393.  
  394.                 CoffObject object = { 0 };
  395.                 object.name = argv[i];
  396.                 object.section_offsets = cvec_size_t_new(128);
  397.                
  398.                 {
  399.                         FILE *fp = fopen(object.name, "rb");
  400.                         if (!fp) {
  401.                                 printf("Error: Can't open \"%s\"", object.name);
  402.                                 exit(-1);
  403.                         }
  404.  
  405.                         if (!epep_init(&object.epep, fp)) {
  406.                                 ERROR_EPEP(&object.epep);
  407.                         }
  408.                 }
  409.  
  410.                 cvec_CoffObject_push_back(&objects, object);
  411.  
  412.                 printf("Done.\n");
  413.         }
  414.  
  415.         CDict_CStr_Symbol symtab;
  416.  
  417.         if (!cdict_CStr_Symbol_init(&symtab)) {
  418.                 ERROR_CDICT(&symtab);
  419.         }
  420.  
  421.         CDict_CStr_SectionInfo info_per_section;
  422.  
  423.         if (!cdict_CStr_SectionInfo_init(&info_per_section)) {
  424.                 ERROR_CDICT(&info_per_section);
  425.         }
  426.  
  427.         for (size_t i = 0; i < cvec_CoffObject_size(&objects); i++) {
  428.                 printf("Secondary parsing of %s {\n", objects[i].name);
  429.  
  430.                 Epep *epep = &(objects[i].epep);
  431.  
  432.                 size_t strtab_size = 0;
  433.                 if (!epep_get_string_table_size(epep, &strtab_size)) {
  434.                         ERROR_EPEP(epep);
  435.                 }
  436.  
  437.                 char *strtab = malloc(strtab_size);
  438.                 if (!epep_get_string_table(epep, strtab)) {
  439.                         ERROR_EPEP(epep);
  440.                 }
  441.  
  442.                 // Fill symbols table
  443.                 printf(" Symbols {\n");
  444.                 for (size_t sym_i = 0; sym_i < epep->coffFileHeader.NumberOfSymbols; sym_i++) {
  445.                         EpepCoffSymbol sym = { 0 };
  446.  
  447.                         if (!epep_get_symbol_by_index(epep, &sym, sym_i)) {
  448.                                 ERROR_EPEP(epep);
  449.                         }
  450.  
  451.                         size_t name_max = 1024;
  452.                         char name[name_max];
  453.  
  454.                         if (sym.symbol.Zeroes == 0) {
  455.                                 strcpy(name, &strtab[sym.symbol.Offset]);
  456.                         } else {
  457.                                 memcpy(name, sym.symbol.ShortName, 8);
  458.                                 name[8] = '\0';
  459.                         }
  460.  
  461.                         if (!strcmp(name, "_EXPORTS")) {
  462.                                 strcpy(name, "EXPORTS");
  463.                         }
  464.  
  465.                         if (sym.symbol.StorageClass != 2) {
  466.                                 sprintf(name, "%s@%s", name, objects[i].name);
  467.                         }
  468.  
  469.                         if (sym.symbol.StorageClass != 2 || sym.symbol.SectionNumber) {
  470.                                 if (memcmp(cdict_CStr_Symbol_get_v(&symtab, name).sym.symbol.ShortName, "\0\0\0\0\0\0\0\0", 8)) {
  471.                                         printf("Error: Redefinition of \"%s\"", name);
  472.                                         exit(-1);
  473.                                 }
  474.  
  475.                                 EpepCoffSymbol *auxes = cvec_EpepCoffSymbol_new(1);
  476.                                 size_t index = number_of_symbols;
  477.  
  478.                                 for (size_t aux_i = 0; aux_i < sym.symbol.NumberOfAuxSymbols; aux_i++) {
  479.                                         EpepCoffSymbol aux = { 0 };
  480.  
  481.                                         if (!epep_get_symbol_by_index(epep, &aux, sym_i + aux_i)) {
  482.                                                 ERROR_EPEP(epep);
  483.                                         }
  484.                                         cvec_EpepCoffSymbol_push_back(&auxes, aux);
  485.                                         number_of_symbols++;
  486.                                 }
  487.  
  488.                                 Symbol new_sym = { sym, auxes, strdup(name), i, index };
  489.                                 if (!cdict_CStr_Symbol_add_vv(&symtab, strdup(name), new_sym, CDICT_NO_CHECK)) {
  490.                                         ERROR_CDICT(&symtab);
  491.                                 }
  492.                                 number_of_symbols++;
  493.  
  494.                                 printf("  Symbol #%u: %s (%u auxes, #%u)\n", sym_i, name, cvec_EpepCoffSymbol_size(&auxes), number_of_symbols - 1);
  495.  
  496.                                 add_name_to_set(strdup(name), &sym_name_set);
  497.                         }
  498.  
  499.                         sym_i += sym.symbol.NumberOfAuxSymbols;
  500.                 }
  501.                 printf(" }\n");
  502.  
  503.                 // Set section offsets and fill unique section name set
  504.                 printf(" Sections {\n");
  505.                 for (size_t sec_i = 0; sec_i < epep->coffFileHeader.NumberOfSections; sec_i++) {
  506.                         EpepSectionHeader sh = { 0 };
  507.  
  508.                         if (!epep_get_section_header_by_index(epep, &sh, sec_i)) {
  509.                                 ERROR_EPEP(epep);
  510.                         }
  511.  
  512.                         size_t name_max = 1024;
  513.                         char name[name_max];
  514.  
  515.                         if (sh.Name[0] == '/') {
  516.                                 strcpy(name, &strtab[atoi(&sh.Name[1])]);
  517.                         } else {
  518.                                 memcpy(name, sh.Name, 8);
  519.                                 name[8] = '\0';
  520.                         }
  521.  
  522.                         add_name_to_set(strdup(name), &section_names_set);
  523.  
  524.                         SectionInfo si = cdict_CStr_SectionInfo_get_v(&info_per_section, name);
  525.                         if (si.source == NULL) {
  526.                                 si.source = cvec_ObjIdSecId_new(32);
  527.                         }
  528.  
  529.                         size_t sec_offset = si.size;
  530.                         cvec_size_t_push_back(&objects[i].section_offsets, sec_offset);
  531.  
  532.                         si.size += sh.SizeOfRawData;
  533.                         si.characteristics |= sh.Characteristics;
  534.                         si.number_of_relocations += sh.NumberOfRelocations;
  535.                         cvec_ObjIdSecId_push_back(&si.source, (ObjIdSecId){ i, sec_i });
  536.                         cdict_CStr_SectionInfo_add_vv(&info_per_section, strdup(name), si, CDICT_REPLACE_EXIST);
  537.  
  538.                         printf("  Section #%llu {\n", sec_i);
  539.                         printf("   Name:                      %s\n", name);
  540.                         printf("   Virtual Address:           %u\n", sh.VirtualAddress);
  541.                         printf("   Characteristics:           %08x\n", sh.Characteristics);
  542.                         printf("   Offset in the big section: %u\n", objects[i].section_offsets[sec_i]);
  543.                         printf("  }\n");
  544.                 }
  545.                 printf(" }\n");
  546.                 printf("}\n");
  547.         }
  548.  
  549.         ObjectIr ir;
  550.         ir.objects = objects;
  551.         ir.section_names_set = section_names_set;
  552.         ir.info_per_section = info_per_section;
  553.         ir.symtab = symtab;
  554.         ir.sym_name_set = sym_name_set;
  555.         ir.number_of_symbols = number_of_symbols;
  556.         return ir;
  557. }
  558.  
  559. int main(int argc, char **argv) {
  560.         ObjectIr ir = parse_objects(argc, argv);
  561.         build(&ir);
  562. }
  563.