Rev 9220 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
9085 | Boppan | 1 | #include |
9220 | Boppan | 2 | #include |
8579 | Boppan | 3 | #include |
4 | #include |
||
5 | #include |
||
6 | #include |
||
7 | #include |
||
8 | |||
9 | #define EPEP_INST |
||
10 | #include "epep/epep.h" |
||
11 | |||
8948 | Boppan | 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", |
||
9927 | boppan | 46 | "EPEP_ERR_INVALID_NUMBER_OF_RELOCATIONS_FOR_EXTENDED", |
8948 | Boppan | 47 | }; |
48 | |||
9927 | boppan | 49 | static_assert(sizeof(epep_errors) / sizeof(epep_errors[0]) == EPEP_ERR_END, |
50 | "Each EPEP error should be stringified."); |
||
51 | |||
8579 | Boppan | 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; |
||
9927 | boppan | 70 | // Number of relocations is greater than 2^16 - 1 |
71 | int number_of_relocations_is_extended; |
||
8579 | Boppan | 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 | |||
8948 | Boppan | 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) |
||
8579 | Boppan | 125 | |
126 | #define ERROR_CDICT(cdict) printf("Error: cdict returned %u at "__FILE__":%u", \ |
||
127 | (cdict)->error_code, __LINE__); exit(-1); |
||
128 | |||
9084 | Boppan | 129 | static int emit_logs; |
130 | |||
9085 | Boppan | 131 | static void log_info(const char *fmt, ...) { |
9084 | Boppan | 132 | if (emit_logs) { |
133 | va_list ap; |
||
134 | va_start(ap, fmt); |
||
135 | vprintf(fmt, ap); |
||
136 | va_end(ap); |
||
137 | } |
||
138 | } |
||
139 | |||
8579 | Boppan | 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 | |||
9080 | Boppan | 186 | static void build(ObjectIr *ir, const char *outname) { |
187 | FILE *out = fopen(outname, "wb"); |
||
8579 | Boppan | 188 | char *strtab = cvec_char_new(1024); |
189 | size_t size_of_sections = 0; |
||
190 | size_t number_of_relocations = 0; |
||
191 | |||
9084 | Boppan | 192 | log_info("Calculating all sections size and relocations count... "); |
8579 | Boppan | 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 | } |
||
9084 | Boppan | 200 | log_info("Done: %u & %u\n", size_of_sections, number_of_relocations); |
8579 | Boppan | 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 |
||
9084 | Boppan | 210 | log_info("Writing COFF header... "); |
8579 | Boppan | 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 |
||
9084 | Boppan | 218 | log_info("Done.\n"); |
8579 | Boppan | 219 | |
220 | // Section Headers |
||
9084 | Boppan | 221 | log_info("Writing section headers {\n"); |
8579 | Boppan | 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 |
||
9084 | Boppan | 227 | log_info(" Writing %s Section Header... ", name); |
8579 | Boppan | 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 }; |
||
9220 | Boppan | 238 | sprintf(numstr, "%lu", strtab_index); |
8579 | Boppan | 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 |
||
9927 | boppan | 249 | // NumberOfRelocations |
250 | if (si.number_of_relocations_is_extended) { |
||
251 | fwrite16(out, 0xffff); |
||
252 | } else { |
||
253 | fwrite16(out, si.number_of_relocations); |
||
254 | } |
||
8579 | Boppan | 255 | fwrite16(out, 0); // NumberOfLinenumbers |
256 | fwrite32(out, si.characteristics); // Characteristics |
||
9084 | Boppan | 257 | log_info("Done.\n"); |
8579 | Boppan | 258 | } |
9084 | Boppan | 259 | log_info("}\n"); |
8579 | Boppan | 260 | |
261 | // Section data |
||
9084 | Boppan | 262 | log_info("Writing sections {\n"); |
8579 | Boppan | 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 | |||
9084 | Boppan | 267 | log_info(" Writing %s... ", name); |
8579 | Boppan | 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 | } |
||
8618 | Boppan | 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 | } |
||
8579 | Boppan | 291 | } |
8618 | Boppan | 292 | |
8579 | Boppan | 293 | fwrite(buf, 1, sh.SizeOfRawData, out); |
294 | } |
||
9084 | Boppan | 295 | log_info("Done.\n"); |
8579 | Boppan | 296 | } |
9084 | Boppan | 297 | log_info("}\n"); |
8579 | Boppan | 298 | |
299 | // COFF Relocations |
||
8959 | Boppan | 300 | char **undefined_symbols = cvec_pchar_new(8); |
301 | |||
9084 | Boppan | 302 | log_info("Writing COFF Relocations {\n"); |
8579 | Boppan | 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 | |||
9084 | Boppan | 307 | log_info(" Writing relocations of %s {\n", name); |
9927 | boppan | 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 | } |
||
8579 | Boppan | 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 | } |
||
9927 | boppan | 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++) { |
||
8579 | Boppan | 338 | EpepCoffRelocation rel = { 0 }; |
339 | |||
9927 | boppan | 340 | if (!epep_get_section_relocation_by_index_x(epep, &sh, &rel, rel_i, extended)) { |
8579 | Boppan | 341 | ERROR_EPEP(epep); |
342 | } |
||
9084 | Boppan | 343 | log_info(" { %02x, %02x, %02x }", rel.VirtualAddress, rel.SymbolTableIndex, rel.Type); |
8579 | Boppan | 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) { |
||
8959 | Boppan | 374 | add_name_to_set(strdup(name), &undefined_symbols); |
8579 | Boppan | 375 | } |
376 | |||
377 | rel.SymbolTableIndex = old_sym.index; |
||
9084 | Boppan | 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); |
||
8579 | Boppan | 380 | } |
381 | fwrite(&rel, 1, 10, out); |
||
382 | } |
||
383 | } |
||
9084 | Boppan | 384 | log_info(" }\n"); |
8579 | Boppan | 385 | } |
9084 | Boppan | 386 | log_info("}\n"); |
8579 | Boppan | 387 | |
8959 | Boppan | 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 | |||
8579 | Boppan | 396 | // Symbols Table |
9084 | Boppan | 397 | log_info("Writing symbols {\n"); |
8579 | Boppan | 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 || |
||
9075 | Boppan | 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 |
||
8579 | Boppan | 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 | |||
9084 | Boppan | 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); |
||
8579 | Boppan | 443 | |
444 | sym.sym.symbol.SectionNumber = get_section_number(&ir->section_names_set, sec_name); |
||
445 | |||
446 | if (sym.sym.symbol.SectionNumber == 0) { |
||
9085 | Boppan | 447 | printf("Internal error: %s section is not found in output file", sec_name); |
8579 | Boppan | 448 | exit(-1); |
449 | } |
||
450 | |||
451 | sym.sym.symbol.Value += section_offset; |
||
452 | |||
453 | if (strlen(sym.name) <= 8) { |
||
9075 | Boppan | 454 | memcpy(sym.sym.symbol.ShortName, sym.name, 8); |
8579 | Boppan | 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 | } |
||
9084 | Boppan | 466 | log_info("}\n"); |
8579 | Boppan | 467 | |
468 | // COFF String Table |
||
9084 | Boppan | 469 | log_info("Writing COFF String Table... "); |
9085 | Boppan | 470 | fwrite32(out, cvec_char_size(&strtab) + 4); |
471 | fwrite(strtab, 1, cvec_char_size(&strtab), out); |
||
9084 | Boppan | 472 | log_info("Done.\n"); |
8579 | Boppan | 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++) { |
||
9084 | Boppan | 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 | } |
||
8579 | Boppan | 487 | |
9084 | Boppan | 488 | log_info("Primary parsing of %s... ", argv[i]); |
489 | |||
8579 | Boppan | 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 | |||
9084 | Boppan | 508 | log_info("Done.\n"); |
8579 | Boppan | 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++) { |
||
9084 | Boppan | 524 | log_info("Secondary parsing of %s {\n", objects[i].name); |
8579 | Boppan | 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 |
||
9084 | Boppan | 539 | log_info(" Symbols {\n"); |
8579 | Boppan | 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 | |||
9084 | Boppan | 590 | log_info(" Symbol #%u: %s (%u auxes, #%u)\n", sym_i, name, cvec_EpepCoffSymbol_size(&auxes), number_of_symbols - 1); |
8579 | Boppan | 591 | |
592 | add_name_to_set(strdup(name), &sym_name_set); |
||
593 | } |
||
594 | |||
595 | sym_i += sym.symbol.NumberOfAuxSymbols; |
||
596 | } |
||
9084 | Boppan | 597 | log_info(" }\n"); |
8579 | Boppan | 598 | |
599 | // Set section offsets and fill unique section name set |
||
9084 | Boppan | 600 | log_info(" Sections {\n"); |
8579 | Boppan | 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), §ion_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 | |||
9927 | boppan | 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 | |||
8579 | Boppan | 634 | si.size += sh.SizeOfRawData; |
635 | si.characteristics |= sh.Characteristics; |
||
9927 | boppan | 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 | } |
||
8579 | Boppan | 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 | |||
9084 | Boppan | 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"); |
||
9075 | Boppan | 653 | |
654 | if (sh.VirtualAddress != 0) { |
||
9084 | Boppan | 655 | printf("Warning: Handling of section with Virtual Address another that 0 is not implemented"); |
9075 | Boppan | 656 | } |
8579 | Boppan | 657 | } |
9084 | Boppan | 658 | log_info(" }\n"); |
659 | log_info("}\n"); |
||
8579 | Boppan | 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 | |||
9084 | Boppan | 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++) { |
||
9088 | Boppan | 688 | // If an argumetns was handled already then it's NULL here |
689 | if (argv[i] == NULL) { |
||
690 | continue; |
||
691 | } |
||
9084 | Boppan | 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 |
||
9088 | Boppan | 696 | return i; |
9084 | Boppan | 697 | } |
698 | } |
||
699 | } |
||
700 | return 0; |
||
701 | } |
||
702 | |||
9088 | Boppan | 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 |
||
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 |
||
727 | printf(" -v, --verbose Emit information logs\n"); |
||
728 | printf(" -h, --help Output this help and exit\n"); |
||
729 | return 0; |
||
730 | } |
||
731 | |||
8579 | Boppan | 732 | int main(int argc, char **argv) { |
9088 | Boppan | 733 | if (arg_got_flag(argc, argv, "-h", "-help", "--help", 0)) { |
734 | return usage(argv[0], NULL); |
||
735 | } |
||
9080 | Boppan | 736 | |
9088 | Boppan | 737 | const char *outname = arg_got_param(argc, argv, "-o"); |
738 | if (outname == NULL) { |
||
739 | outname = "a.out.obj"; |
||
9080 | Boppan | 740 | } |
741 | |||
9084 | Boppan | 742 | emit_logs = arg_got_flag(argc, argv, "-v", "-verbose", "--verbose", 0); |
743 | |||
9088 | Boppan | 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 | |||
8579 | Boppan | 756 | ObjectIr ir = parse_objects(argc, argv); |
9080 | Boppan | 757 | build(&ir, outname); |
8620 | Boppan | 758 | return 0; |
8579 | Boppan | 759 | }>>>>>>>>>=>>>>>>>>>>=>>>>> |