Subversion Repositories Kolibri OS

Rev

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 )", 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   Output into \n");
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
}