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