Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
8579 Boppan 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 
5
#include 
6
#include 
7
#include 
8
#include 
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
			}
8618 Boppan 220
 
221
			// If the section contains uninitialized data (BSS)
222
			// it should be filled by zeroes
223
			// Yes, current implementation emits BSS sections too
224
			// cause KOS has no idea they should be allocated automatically
225
			// cause FASM has no idea they should be generated without contents
226
			// cause Tomasz Grysztar didn't care
227
			char *buf = calloc(sh.SizeOfRawData, 1);
228
 
229
			// Othervice it should be filled by its contents from source object
230
			if (!(sh.Characteristics & 0x00000080)) {
231
				if (!epep_get_section_contents(epep, &sh, buf)) {
232
					ERROR_EPEP(epep);
233
				}
8579 Boppan 234
			}
8618 Boppan 235
 
8579 Boppan 236
			fwrite(buf, 1, sh.SizeOfRawData, out);
237
		}
238
		printf("Done.\n");
239
	}
240
	printf("}\n");
241
 
242
	// COFF Relocations
243
	printf("Writing COFF Relocations {\n");
244
	for (size_t sec_i = 0; sec_i < cvec_pchar_size(&ir->section_names_set); sec_i++) {
245
		char *name = ir->section_names_set[sec_i];
246
		SectionInfo si = cdict_CStr_SectionInfo_get_v(&ir->info_per_section, name);
247
 
248
		printf(" Writing relocations of %s {\n", name);
249
		for (size_t i = 0; i < cvec_ObjIdSecId_size(&si.source); i++) {
250
			ObjIdSecId id = cvec_ObjIdSecId_at(&si.source, i);
251
			CoffObject *object = &ir->objects[id.obj_id];
252
			Epep *epep = &object->epep;
253
 
254
			size_t strtab_size = 0;
255
			if (!epep_get_string_table_size(epep, &strtab_size)) {
256
				ERROR_EPEP(epep);
257
			}
258
 
259
			char *obj_strtab = malloc(strtab_size);
260
			if (!epep_get_string_table(epep, obj_strtab)) {
261
				ERROR_EPEP(epep);
262
			}
263
 
264
			EpepSectionHeader sh = { 0 };
265
			if (!epep_get_section_header_by_index(epep, &sh, id.sec_id)) {
266
				ERROR_EPEP(epep);
267
			}
268
			for (size_t rel_i = 0; rel_i < sh.NumberOfRelocations; rel_i++) {
269
				EpepCoffRelocation rel = { 0 };
270
 
271
				if (!epep_get_section_relocation_by_index(epep, &sh, &rel, rel_i)) {
272
					ERROR_EPEP(epep);
273
				}
274
				printf("  { %02x, %02x, %02x }", rel.VirtualAddress, rel.SymbolTableIndex, rel.Type);
275
				rel.VirtualAddress += object->section_offsets[sec_i];
276
				{
277
					size_t index = rel.SymbolTableIndex;
278
					EpepCoffSymbol sym = { 0 };
279
 
280
					if (!epep_get_symbol_by_index(epep, &sym, index)) {
281
						ERROR_EPEP(epep);
282
					}
283
 
284
					size_t name_max = 1024;
285
					char name[name_max];
286
 
287
					if (sym.symbol.Zeroes == 0) {
288
						strcpy(name, &obj_strtab[sym.symbol.Offset]);
289
					} else {
290
						memcpy(name, sym.symbol.ShortName, 8);
291
						name[8] = '\0';
292
					}
293
 
294
					if (!strcmp(name, "_EXPORTS")) {
295
						strcpy(name, "EXPORTS");
296
					}
297
 
298
					if (sym.symbol.StorageClass != 2) {
299
						sprintf(name, "%s@%s", name, object->name);
300
					}
301
 
302
					Symbol old_sym = cdict_CStr_Symbol_get_v(&ir->symtab, name);
303
 
304
					if (old_sym.name == NULL) {
305
						printf("Internal error: Symbol of %s relocation not found", name);
306
						exit(-1);
307
					}
308
 
309
					rel.SymbolTableIndex = old_sym.index;
310
					printf(" -> { %02x, %02x, %02x }: ", rel.VirtualAddress, rel.SymbolTableIndex, rel.Type);
311
					printf("New relocation of %s in %s\n", name, sh.Name);
312
				}
313
				fwrite(&rel, 1, 10, out);
314
			}
315
		}
316
		printf(" }\n");
317
	}
318
	printf("}\n");
319
 
320
	// Symbols Table
321
	printf("Writing symbols {\n");
322
	for (size_t sym_i = 0; sym_i < cvec_pchar_size(&ir->sym_name_set); sym_i++) {
323
		char *name = ir->sym_name_set[sym_i];
324
 
325
		Symbol sym = cdict_CStr_Symbol_get_v(&ir->symtab, name);
326
 
327
		if (sym.sym.symbol.SectionNumber == 0xffff ||
328
			sym.sym.symbol.SectionNumber == 0xfffe ||
329
			(sym.sym.symbol.StorageClass != 2 && sym.sym.symbol.StorageClass != 3)) {
330
			fwrite(&sym.sym.symbol, 1, 18, out);
331
		} else {
332
			size_t sec_name_max = 1024;
333
			char sec_name[sec_name_max];
334
 
335
			size_t object_index = sym.object_index;
336
			CoffObject *object = &ir->objects[object_index];
337
			Epep *epep = &object->epep;
338
			size_t section_offset = object->section_offsets[sym.sym.symbol.SectionNumber - 1];
339
 
340
			size_t strtab_size = 0;
341
			if (!epep_get_string_table_size(epep, &strtab_size)) {
342
				ERROR_EPEP(epep);
343
			}
344
 
345
			char *obj_strtab = malloc(strtab_size);
346
			if (!epep_get_string_table(epep, obj_strtab)) {
347
				ERROR_EPEP(epep);
348
			}
349
 
350
			EpepSectionHeader sh = { 0 };
351
			if (!epep_get_section_header_by_index(epep, &sh, sym.sym.symbol.SectionNumber - 1)) {
352
				ERROR_EPEP(epep);
353
			}
354
 
355
			if (sh.Name[0] == '/') {
356
				strcpy(sec_name, &obj_strtab[atoi(&sh.Name[1])]);
357
			} else {
358
				memcpy(sec_name, sh.Name, 8);
359
				sec_name[8] = '\0';
360
			}
361
 
362
			printf("%s:\n", sym.name);
363
			printf(" Section:      %s\n", sec_name);
364
			printf(" StorageClass: %u\n", sym.sym.symbol.StorageClass);
365
 
366
			sym.sym.symbol.SectionNumber = get_section_number(&ir->section_names_set, sec_name);
367
 
368
			if (sym.sym.symbol.SectionNumber == 0) {
369
				printf("Internal error: %s section is not found in output file");
370
				exit(-1);
371
			}
372
 
373
			sym.sym.symbol.Value += section_offset;
374
 
375
			if (strlen(sym.name) <= 8) {
376
				strcpy(sym.sym.symbol.ShortName, sym.name);
377
			} else {
378
				sym.sym.symbol.Zeroes = 0;
379
				sym.sym.symbol.Offset = strtab_add(&strtab, name);
380
			}
381
 
382
			fwrite(&sym.sym.symbol, 1, 18, out);
383
		}
384
		for (size_t aux_i = 0; aux_i < sym.sym.symbol.NumberOfAuxSymbols; aux_i++) {
385
			fwrite(&sym.auxes[aux_i].symbol, 1, 18, out);
386
		}
387
	}
388
	printf("}\n");
389
 
390
	// COFF String Table
391
	printf("Writing COFF String Table... ");
392
	fwrite32(out, cvec_pchar_size(&strtab) + 4);
393
	fwrite(strtab, 1, cvec_pchar_size(&strtab), out);
394
	printf("Done.\n");
395
}
396
 
397
static ObjectIr parse_objects(int argc, char **argv) {
398
	CoffObject *objects = cvec_CoffObject_new(128);
399
	char **section_names_set = cvec_pchar_new(4);
400
	char **sym_name_set = cvec_pchar_new(128);
401
	size_t number_of_symbols = 0;
402
 
403
	for (int i = 1; i < argc; i++) {
404
		printf("Primary parsing of %s... ", argv[i]);
405
 
406
		CoffObject object = { 0 };
407
		object.name = argv[i];
408
		object.section_offsets = cvec_size_t_new(128);
409
 
410
		{
411
			FILE *fp = fopen(object.name, "rb");
412
			if (!fp) {
413
				printf("Error: Can't open \"%s\"", object.name);
414
				exit(-1);
415
			}
416
 
417
			if (!epep_init(&object.epep, fp)) {
418
				ERROR_EPEP(&object.epep);
419
			}
420
		}
421
 
422
		cvec_CoffObject_push_back(&objects, object);
423
 
424
		printf("Done.\n");
425
	}
426
 
427
	CDict_CStr_Symbol symtab;
428
 
429
	if (!cdict_CStr_Symbol_init(&symtab)) {
430
		ERROR_CDICT(&symtab);
431
	}
432
 
433
	CDict_CStr_SectionInfo info_per_section;
434
 
435
	if (!cdict_CStr_SectionInfo_init(&info_per_section)) {
436
		ERROR_CDICT(&info_per_section);
437
	}
438
 
439
	for (size_t i = 0; i < cvec_CoffObject_size(&objects); i++) {
440
		printf("Secondary parsing of %s {\n", objects[i].name);
441
 
442
		Epep *epep = &(objects[i].epep);
443
 
444
		size_t strtab_size = 0;
445
		if (!epep_get_string_table_size(epep, &strtab_size)) {
446
			ERROR_EPEP(epep);
447
		}
448
 
449
		char *strtab = malloc(strtab_size);
450
		if (!epep_get_string_table(epep, strtab)) {
451
			ERROR_EPEP(epep);
452
		}
453
 
454
		// Fill symbols table
455
		printf(" Symbols {\n");
456
		for (size_t sym_i = 0; sym_i < epep->coffFileHeader.NumberOfSymbols; sym_i++) {
457
			EpepCoffSymbol sym = { 0 };
458
 
459
			if (!epep_get_symbol_by_index(epep, &sym, sym_i)) {
460
				ERROR_EPEP(epep);
461
			}
462
 
463
			size_t name_max = 1024;
464
			char name[name_max];
465
 
466
			if (sym.symbol.Zeroes == 0) {
467
				strcpy(name, &strtab[sym.symbol.Offset]);
468
			} else {
469
				memcpy(name, sym.symbol.ShortName, 8);
470
				name[8] = '\0';
471
			}
472
 
473
			if (!strcmp(name, "_EXPORTS")) {
474
				strcpy(name, "EXPORTS");
475
			}
476
 
477
			if (sym.symbol.StorageClass != 2) {
478
				sprintf(name, "%s@%s", name, objects[i].name);
479
			}
480
 
481
			if (sym.symbol.StorageClass != 2 || sym.symbol.SectionNumber) {
482
				if (memcmp(cdict_CStr_Symbol_get_v(&symtab, name).sym.symbol.ShortName, "\0\0\0\0\0\0\0\0", 8)) {
483
					printf("Error: Redefinition of \"%s\"", name);
484
					exit(-1);
485
				}
486
 
487
				EpepCoffSymbol *auxes = cvec_EpepCoffSymbol_new(1);
488
				size_t index = number_of_symbols;
489
 
490
				for (size_t aux_i = 0; aux_i < sym.symbol.NumberOfAuxSymbols; aux_i++) {
491
					EpepCoffSymbol aux = { 0 };
492
 
493
					if (!epep_get_symbol_by_index(epep, &aux, sym_i + aux_i)) {
494
						ERROR_EPEP(epep);
495
					}
496
					cvec_EpepCoffSymbol_push_back(&auxes, aux);
497
					number_of_symbols++;
498
				}
499
 
500
				Symbol new_sym = { sym, auxes, strdup(name), i, index };
501
				if (!cdict_CStr_Symbol_add_vv(&symtab, strdup(name), new_sym, CDICT_NO_CHECK)) {
502
					ERROR_CDICT(&symtab);
503
				}
504
				number_of_symbols++;
505
 
506
				printf("  Symbol #%u: %s (%u auxes, #%u)\n", sym_i, name, cvec_EpepCoffSymbol_size(&auxes), number_of_symbols - 1);
507
 
508
				add_name_to_set(strdup(name), &sym_name_set);
509
			}
510
 
511
			sym_i += sym.symbol.NumberOfAuxSymbols;
512
		}
513
		printf(" }\n");
514
 
515
		// Set section offsets and fill unique section name set
516
		printf(" Sections {\n");
517
		for (size_t sec_i = 0; sec_i < epep->coffFileHeader.NumberOfSections; sec_i++) {
518
			EpepSectionHeader sh = { 0 };
519
 
520
			if (!epep_get_section_header_by_index(epep, &sh, sec_i)) {
521
				ERROR_EPEP(epep);
522
			}
523
 
524
			size_t name_max = 1024;
525
			char name[name_max];
526
 
527
			if (sh.Name[0] == '/') {
528
				strcpy(name, &strtab[atoi(&sh.Name[1])]);
529
			} else {
530
				memcpy(name, sh.Name, 8);
531
				name[8] = '\0';
532
			}
533
 
534
			add_name_to_set(strdup(name), §ion_names_set);
535
 
536
			SectionInfo si = cdict_CStr_SectionInfo_get_v(&info_per_section, name);
537
			if (si.source == NULL) {
538
				si.source = cvec_ObjIdSecId_new(32);
539
			}
540
 
541
			size_t sec_offset = si.size;
542
			cvec_size_t_push_back(&objects[i].section_offsets, sec_offset);
543
 
544
			si.size += sh.SizeOfRawData;
545
			si.characteristics |= sh.Characteristics;
546
			si.number_of_relocations += sh.NumberOfRelocations;
547
			cvec_ObjIdSecId_push_back(&si.source, (ObjIdSecId){ i, sec_i });
548
			cdict_CStr_SectionInfo_add_vv(&info_per_section, strdup(name), si, CDICT_REPLACE_EXIST);
549
 
550
			printf("  Section #%llu {\n", sec_i);
551
			printf("   Name:                      %s\n", name);
552
			printf("   Virtual Address:           %u\n", sh.VirtualAddress);
553
			printf("   Characteristics:           %08x\n", sh.Characteristics);
554
			printf("   Offset in the big section: %u\n", objects[i].section_offsets[sec_i]);
555
			printf("  }\n");
556
		}
557
		printf(" }\n");
558
		printf("}\n");
559
	}
560
 
561
	ObjectIr ir;
562
	ir.objects = objects;
563
	ir.section_names_set = section_names_set;
564
	ir.info_per_section = info_per_section;
565
	ir.symtab = symtab;
566
	ir.sym_name_set = sym_name_set;
567
	ir.number_of_symbols = number_of_symbols;
568
	return ir;
569
}
570
 
571
int main(int argc, char **argv) {
572
	ObjectIr ir = parse_objects(argc, argv);
573
	build(&ir);
8620 Boppan 574
	return 0;
8579 Boppan 575
}