1 /* Write coff objects
2 Copyright (C) 2003, 2004, 2005
3 Craig Franklin
4
5 This file is part of gputils.
6
7 gputils is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 gputils is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with gputils; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include "stdhdr.h"
23 #include "libgputils.h"
24
25 /* String table offsets are 16 bits so this coff has a limit on the
26 maximum string table size. */
27 #define MAX_STRING_TABLE 0xffff
28
29 /*------------------------------------------------------------------------------------------------*/
30
31 /* write the symbol or section name into the string table */
32
33 static unsigned int
_add_string(const char * Name,uint8_t * Table)34 _add_string(const char *Name, uint8_t *Table)
35 {
36 uint32_t nbytes;
37 uint32_t offset;
38 uint32_t sizeof_name;
39
40 assert(Name != NULL);
41
42 sizeof_name = strlen(Name) + 1;
43
44 /* read the number of bytes in the string table */
45 offset = nbytes = gp_getl32(&Table[0]);
46
47 /* check the length against the max string table size */
48 nbytes += sizeof_name;
49 assert(nbytes <= MAX_STRING_TABLE);
50
51 /* copy the string to the table */
52 memcpy(&Table[offset], Name, sizeof_name);
53
54 /* write the new byte count */
55 gp_putl32(&Table[0], nbytes);
56
57 return offset;
58 }
59
60 /*------------------------------------------------------------------------------------------------*/
61
62 static void
_add_name(const char * Name,uint8_t * Table,FILE * Fp)63 _add_name(const char *Name, uint8_t *Table, FILE *Fp)
64 {
65 uint32_t length;
66 uint32_t offset;
67
68 if (Name == NULL) {
69 return;
70 }
71
72 length = strlen(Name);
73
74 if (length <= COFF_SSYMBOL_NAME_MAX) {
75 /* The string will fit in the structure. */
76 if (length > 0) {
77 /* 'name' */
78 gp_fputvar(Name, length, Fp); /* symbol name if less then 8 characters */
79 }
80
81 if (length < COFF_SSYMBOL_NAME_MAX) {
82 gp_fputzero(COFF_SSYMBOL_NAME_MAX - length, Fp);
83 }
84 }
85 else {
86 offset = _add_string(Name, Table);
87
88 /* write zeros and offset */
89 /* 's_zeros' */
90 gp_fputl32(0, Fp); /* first four characters are 0 */
91 /* 's_offset' */
92 gp_fputl32(offset, Fp); /* pointer to the string table */
93 }
94 }
95
96 /*------------------------------------------------------------------------------------------------*/
97
98 /* write the file header */
99
100 static void
_write_file_header(const gp_object_t * Object,FILE * Fp)101 _write_file_header(const gp_object_t *Object, FILE *Fp)
102 {
103 /* 'f_magic' -- magic number */
104 gp_fputl16((Object->isnew ? MICROCHIP_MAGIC_v2 : MICROCHIP_MAGIC_v1), Fp);
105 /* 'f_nscns' -- number of sections */
106 gp_fputl16(Object->section_list.num_nodes, Fp);
107 /* 'f_timdat' -- time and date stamp */
108 gp_fputl32(Object->time, Fp);
109 /* 'f_symptr' -- file ptr to symtab */
110 gp_fputl32(Object->symbol_ptr, Fp);
111 /* 'f_nsyms' -- # symtab entries */
112 gp_fputl32(Object->num_symbols, Fp);
113 /* 'f_opthdr' -- sizeof(opt hdr) */
114 gp_fputl16((Object->isnew ? OPT_HDR_SIZ_v2: OPT_HDR_SIZ_v1), Fp);
115 /* 'f_flags' -- flags */
116 gp_fputl16(Object->flags, Fp);
117 }
118
119 /*------------------------------------------------------------------------------------------------*/
120
121 /* write the optional header */
122
123 static void
_write_optional_header(const gp_object_t * Object,FILE * Fp)124 _write_optional_header(const gp_object_t *Object, FILE *Fp)
125 {
126 uint32_t coff_type;
127
128 coff_type = gp_processor_coff_type(Object->processor);
129 /* make sure we catch unfinished processors */
130 assert(coff_type != 0);
131
132 /* write the data to file */
133 /* 'opt_magic' */
134 gp_fputl16(Object->isnew ? OPTMAGIC_v2 : OPTMAGIC_v1, Fp);
135
136 /* 'vstamp' -- version stamp of compiler */
137 if (Object->isnew) {
138 gp_fputl32(1, Fp);
139 }
140 else {
141 gp_fputl16(1, Fp);
142 }
143
144 /* 'proc_type' -- processor type */
145 gp_fputl32(coff_type, Fp);
146 /* 'rom_width_bits' -- ROM width bits */
147 gp_fputl32(gp_processor_rom_width(Object->class), Fp);
148 /* 'ram_width_bits' -- RAM width bits */
149 gp_fputl32(8, Fp);
150 }
151
152 /*------------------------------------------------------------------------------------------------*/
153
154 /* write the section header */
155
156 static void
_write_section_header(const gp_section_t * Section,unsigned int Org_to_byte_shift,uint8_t * Table,FILE * Fp)157 _write_section_header(const gp_section_t *Section, unsigned int Org_to_byte_shift, uint8_t *Table, FILE *Fp)
158 {
159 uint32_t section_address;
160
161 if (FlagsIsAllClr(Section->flags, STYP_ROM_AREA)) {
162 Org_to_byte_shift = 0;
163 }
164
165 section_address = gp_insn_from_byte(Org_to_byte_shift, Section->address);
166 _add_name(Section->name, Table, Fp);
167 /* 's_paddr' -- physical address */
168 gp_fputl32(section_address, Fp);
169 /* 's_vaddr' -- virtual address */
170 gp_fputl32(section_address, Fp);
171 /* 's_size' -- section size */
172 gp_fputl32(Section->size, Fp);
173 /* 's_scnptr' -- file ptr to raw data */
174 gp_fputl32(Section->data_ptr, Fp);
175 /* 's_relptr' -- file ptr to relocation */
176 gp_fputl32(Section->reloc_ptr, Fp);
177 /* 's_lnnoptr' -- file ptr to line numbers */
178 gp_fputl32(Section->lineno_ptr, Fp);
179 /* 's_nreloc' -- # reloc entries */
180 gp_fputl16(Section->relocation_list.num_nodes, Fp);
181 /* 's_nlnno' -- # line number entries */
182 gp_fputl16(Section->line_number_list.num_nodes, Fp);
183 /* 's_flags' -- Don't write internal section flags. */
184 gp_fputl32(Section->flags & ~(STYP_RELOC | STYP_BPACK), Fp);
185 }
186
187 /*------------------------------------------------------------------------------------------------*/
188
189 /* write the section data */
190
191 static void
_write_section_data(pic_processor_t Processor,const gp_section_t * Section,FILE * Fp)192 _write_section_data(pic_processor_t Processor, const gp_section_t *Section, FILE *Fp)
193 {
194 unsigned int org;
195 unsigned int end;
196 uint8_t byte;
197
198 org = Section->shadow_address;
199 end = org + Section->size;
200
201 #ifdef GPUTILS_DEBUG
202 printf("section \"%s\"\nsize= %li\ndata:\n", Section->name, Section->size);
203 gp_mem_i_print(Section->data, Processor);
204 #endif
205
206 for ( ; org < end; org++) {
207 gp_mem_b_assert_get(Section->data, org, &byte, NULL, NULL);
208 fputc(byte, Fp);
209 }
210 }
211
212 /*------------------------------------------------------------------------------------------------*/
213
214 /* write the section relocations */
215
216 static void
_write_relocations(const gp_section_t * Section,FILE * Fp)217 _write_relocations(const gp_section_t *Section, FILE *Fp)
218 {
219 gp_reloc_t *current;
220
221 current = Section->relocation_list.first;
222 while (current != NULL) {
223 /* 'r_vaddr' -- entry relative virtual address */
224 gp_fputl32(current->address, Fp);
225 /* 'r_symndx' -- index into symbol table */
226 gp_fputl32(current->symbol->number, Fp);
227 /* 'r_offset' -- offset to be added to address of symbol 'r_symndx' */
228 gp_fputl16(current->offset, Fp);
229 /* 'r_type' -- relocation type */
230 gp_fputl16(current->type, Fp);
231
232 current = current->next;
233 }
234 }
235
236 /*------------------------------------------------------------------------------------------------*/
237
238 /* write the section linenumbers */
239
240 static void
_write_linenumbers(const gp_section_t * Section,unsigned int Org_to_byte_shift,FILE * Fp)241 _write_linenumbers(const gp_section_t *Section, unsigned int Org_to_byte_shift, FILE *Fp)
242 {
243 gp_linenum_t *current;
244
245 if (FlagsIsAllClr(Section->flags, STYP_ROM_AREA)) {
246 Org_to_byte_shift = 0;
247 }
248
249 current = Section->line_number_list.first;
250 while (current != NULL) {
251 /* 'l_srcndx' -- symbol table index of associated source file */
252 gp_fputl32(current->symbol->number, Fp);
253 /* 'l_lnno' -- line number */
254 gp_fputl16(current->line_number, Fp);
255 /* 'l_paddr' -- address of code for this lineno */
256 gp_fputl32(gp_insn_from_byte(Org_to_byte_shift, current->address), Fp);
257 /* 'l_flags' -- bit flags for the line number */
258 gp_fputl16(0, Fp);
259 /* 'l_fcnndx' -- symbol table index of associated function, if there is one */
260 gp_fputl32(0, Fp);
261
262 current = current->next;
263 }
264 }
265
266 /*------------------------------------------------------------------------------------------------*/
267
268 /* write the auxiliary symbols */
269
270 static void
_write_aux_symbols(const gp_aux_t * Aux,uint8_t * Table,gp_boolean Isnew,FILE * Fp)271 _write_aux_symbols(const gp_aux_t *Aux, uint8_t *Table, gp_boolean Isnew, FILE *Fp)
272 {
273 unsigned int offset;
274
275 while (Aux != NULL) {
276 switch (Aux->type) {
277 case AUX_DIRECT: {
278 /* add the direct string to the string table */
279 offset = _add_string(Aux->_aux_symbol._aux_direct.string, Table);
280 /* 'x_command' */
281 gp_fputl32(Aux->_aux_symbol._aux_direct.command, Fp);
282 /* 'x_offset' */
283 gp_fputl32(offset, Fp);
284 /* _unused */
285 gp_fputzero(10, Fp);
286
287 if (Isnew) {
288 /* _unused */
289 gp_fputzero(2, Fp);
290 }
291 break;
292 }
293
294 case AUX_FILE: {
295 /* add the filename to the string table */
296 offset = _add_string(Aux->_aux_symbol._aux_file.filename, Table);
297 /* 'x_offset' */
298 gp_fputl32(offset, Fp);
299 /* 'x_incline' */
300 gp_fputl32(Aux->_aux_symbol._aux_file.line_number, Fp);
301 /* x_flags */
302 fputc(Aux->_aux_symbol._aux_file.flags, Fp);
303 /* _unused */
304 gp_fputzero(9, Fp);
305
306 if (Isnew) {
307 /* _unused */
308 gp_fputzero(2, Fp);
309 }
310 break;
311 }
312
313 case AUX_IDENT: {
314 /* add the ident string to the string table */
315 offset = _add_string(Aux->_aux_symbol._aux_ident.string, Table);
316 /* 'x_offset' */
317 gp_fputl32(offset, Fp);
318 /* _unused */
319 gp_fputzero(14, Fp);
320
321 if (Isnew) {
322 /* _unused */
323 gp_fputzero(2, Fp);
324 }
325 break;
326 }
327
328 case AUX_SECTION: {
329 /* write section auxiliary symbol */
330 /* 'x_scnlen' */
331 gp_fputl32(Aux->_aux_symbol._aux_scn.length, Fp);
332 /* 'x_nreloc' */
333 gp_fputl16(Aux->_aux_symbol._aux_scn.nreloc, Fp);
334 /* 'x_nlinno' */
335 gp_fputl16(Aux->_aux_symbol._aux_scn.nlineno, Fp);
336 /* _unused */
337 gp_fputzero(10, Fp);
338
339 if (Isnew) {
340 /* _unused */
341 gp_fputzero(2, Fp);
342 }
343 break;
344 }
345
346 default:
347 /* copy the data to the file */
348 gp_fputvar(&Aux->_aux_symbol.data[0], ((Isnew) ? SYMBOL_SIZE_v2 : SYMBOL_SIZE_v1), Fp);
349 }
350
351 Aux = Aux->next;
352 }
353 }
354
355 /*------------------------------------------------------------------------------------------------*/
356
357 /* write the symbol table */
358
359 static void
_write_symbols(const gp_object_t * Object,uint8_t * Table,FILE * Fp)360 _write_symbols(const gp_object_t *Object, uint8_t *Table, FILE *Fp)
361 {
362 gp_symbol_t *symbol;
363 gp_boolean isnew;
364
365 isnew = Object->isnew;
366 symbol = Object->symbol_list.first;
367 while (symbol != NULL) {
368 _add_name(symbol->name, Table, Fp);
369 /* 'value' */
370 gp_fputl32(symbol->value, Fp);
371
372 /* 'sec_num' */
373 if (symbol->section_number < N_SCNUM) {
374 gp_fputl16(symbol->section_number, Fp);
375 }
376 else {
377 gp_fputl16(symbol->section->number, Fp);
378 }
379
380 /* 'type' */
381 if (isnew) {
382 gp_fputl32((uint32_t)symbol->type | (symbol->derived_type << T_SHIFT_v2), Fp);
383 }
384 else {
385 gp_fputl16((uint16_t)symbol->type | (uint16_t)(symbol->derived_type << T_SHIFT_v1), Fp);
386 }
387
388 /* 'st_class' */
389 fputc(symbol->class, Fp);
390 /* 'num_auxsym' */
391 fputc(symbol->aux_list.num_nodes, Fp);
392
393 if (symbol->aux_list.num_nodes > 0) {
394 _write_aux_symbols(symbol->aux_list.first, Table, isnew, Fp);
395 }
396
397 symbol = symbol->next;
398 }
399 }
400
401 /*------------------------------------------------------------------------------------------------*/
402
403 /* update all the coff pointers */
404
405 static void
_update_pointers(gp_object_t * Object)406 _update_pointers(gp_object_t *Object)
407 {
408 unsigned int data_idx;
409 gp_section_t *section;
410 gp_symbol_t *symbol;
411 unsigned int section_number;
412 unsigned int symbol_number;
413
414 section_number = Object->section_list.num_nodes;
415 data_idx = (Object->isnew) ? (FILE_HDR_SIZ_v2 + OPT_HDR_SIZ_v2 + (SEC_HDR_SIZ_v2 * section_number)) :
416 (FILE_HDR_SIZ_v1 + OPT_HDR_SIZ_v1 + (SEC_HDR_SIZ_v1 * section_number));
417
418 section_number = N_SCNUM;
419
420 /* update the data pointers in the section headers */
421 section = Object->section_list.first;
422 while (section != NULL) {
423 section->number = section_number;
424 section_number++;
425 section->data_ptr = 0;
426
427 if (gp_coffgen_section_has_data(section)) {
428 section->data_ptr = data_idx;
429 data_idx += section->size;
430 }
431 section = section->next;
432 }
433
434 /* update the relocation pointers in the section headers */
435 section = Object->section_list.first;
436 while (section != NULL) {
437 section->reloc_ptr = 0;
438
439 if (section->relocation_list.num_nodes > 0) {
440 section->reloc_ptr = data_idx;
441 data_idx += (section->relocation_list.num_nodes * RELOC_SIZ);
442 }
443 section = section->next;
444 }
445
446 /* update the line number pointers in the section headers */
447 section = Object->section_list.first;
448 while (section != NULL) {
449 section->lineno_ptr = 0;
450
451 if (section->line_number_list.num_nodes > 0) {
452 section->lineno_ptr = data_idx;
453 data_idx += (section->line_number_list.num_nodes * LINENO_SIZ);
454 }
455 section = section->next;
456 }
457
458 /* update symbol table pointer */
459 Object->symbol_ptr = data_idx;
460
461 /* update the symbol numbers */
462 symbol_number = 0;
463 symbol = Object->symbol_list.first;
464 while (symbol != NULL) {
465 symbol->number = symbol_number;
466 symbol_number += 1 + symbol->aux_list.num_nodes;
467 symbol = symbol->next;
468 }
469 }
470
471 /*------------------------------------------------------------------------------------------------*/
472
473 /* write the coff file */
474
475 gp_boolean
gp_writeobj_write_coff(gp_object_t * Object,int Num_errors)476 gp_writeobj_write_coff(gp_object_t *Object, int Num_errors)
477 {
478 FILE *coff;
479 unsigned int org_to_byte_shift;
480 gp_section_t *section;
481 uint8_t table[MAX_STRING_TABLE]; /* string table */
482
483 if (Num_errors > 0) {
484 unlink(Object->filename);
485 return false;
486 }
487
488 coff = fopen(Object->filename, "wb");
489 if (coff == NULL) {
490 perror(Object->filename);
491 return false;
492 }
493
494 /* update file pointers in the coff */
495 _update_pointers(Object);
496
497 /* initialize the string table byte count */
498 gp_putl32(&table[0], 4);
499
500 /* write the data to the file */
501 _write_file_header(Object, coff);
502 _write_optional_header(Object, coff);
503
504 /* write section headers */
505 org_to_byte_shift = Object->class->org_to_byte_shift;
506 section = Object->section_list.first;
507 while (section != NULL) {
508 _write_section_header(section, org_to_byte_shift, &table[0], coff);
509 section = section->next;
510 }
511
512 /* write section data */
513 section = Object->section_list.first;
514 while (section != NULL) {
515 if (gp_coffgen_section_has_data(section)) {
516 _write_section_data(Object->processor, section, coff);
517 }
518 section = section->next;
519 }
520
521 /* write section relocations */
522 section = Object->section_list.first;
523 while (section != NULL) {
524 if (section->relocation_list.num_nodes > 0) {
525 _write_relocations(section, coff);
526 }
527 section = section->next;
528 }
529
530 /* write section line numbers */
531 section = Object->section_list.first;
532 while (section != NULL) {
533 if (section->line_number_list.num_nodes > 0) {
534 _write_linenumbers(section, org_to_byte_shift, coff);
535 }
536 section = section->next;
537 }
538
539 /* write symbols */
540 if (Object->num_symbols != 0) {
541 _write_symbols(Object, &table[0], coff);
542 }
543
544 /* write string table */
545 fwrite(&table[0], 1, gp_getl32(&table[0]), coff);
546
547 fclose(coff);
548 return true;
549 }
550