1 /* output_hunk.c AmigaOS hunk format output driver for vasm */
2 /* (c) in 2002-2017 by Frank Wille */
3 
4 #include "vasm.h"
5 #include "output_hunk.h"
6 #if defined(OUTHUNK) && (defined(VASM_CPU_M68K) || defined(VASM_CPU_PPC))
7 static char *copyright="vasm hunk format output module 2.9b (c) 2002-2017 Frank Wille";
8 int hunk_onlyglobal;
9 
10 static int databss;
11 static int kick1;
12 static int exthunk;
13 static int genlinedebug;
14 static int keep_empty_sects;
15 
16 static uint32_t sec_cnt;
17 static symbol **secsyms;
18 
19 
strlen32(char * s)20 static uint32_t strlen32(char *s)
21 /* calculate number of 32 bit words required for
22    a string without terminator */
23 {
24   return (strlen(s) + 3) >> 2;
25 }
26 
27 
fwname(FILE * f,char * name)28 static void fwname(FILE *f,char *name)
29 {
30   size_t n = strlen(name);
31 
32   fwdata(f,name,n);
33   fwalign(f,n,4);
34 }
35 
36 
fwmemflags(FILE * f,section * s,uint32_t data)37 static void fwmemflags(FILE *f,section *s,uint32_t data)
38 /* write memory attributes with data (section size or type) */
39 {
40   uint32_t mem = s->memattr;
41 
42   if ((mem & ~MEMF_PUBLIC) == 0) {
43     fw32(f,data,1);
44   }
45   else if ((mem & ~MEMF_PUBLIC) == MEMF_CHIP) {
46     fw32(f,HUNKF_CHIP|data,1);
47   }
48   else if ((mem & ~MEMF_PUBLIC) == MEMF_FAST) {
49     fw32(f,HUNKF_FAST|data,1);
50   }
51   else {
52     fw32(f,HUNKF_MEMTYPE|data,1);
53     fw32(f,mem,1);
54   }
55 }
56 
57 
fwnopalign(FILE * f,taddr n)58 static void fwnopalign(FILE *f,taddr n)
59 /* align a 68k code section with NOP instructions */
60 {
61   taddr i;
62 
63   n = balign(n,4);
64   if (n & 1)
65     ierror(0);
66   for (i=0; i<n; i+=2)
67     fw16(f,0x4e71,1);
68 }
69 
70 
dummy_section(void)71 static section *dummy_section(void)
72 {
73   return new_section(".text","acrx3",8);
74 }
75 
76 
scan_attr(section * sec)77 static uint32_t scan_attr(section *sec)
78 /* extract hunk-type from section attributes */
79 {
80   uint32_t type = 0;
81   char *p = sec->attr;
82 
83   if (*p != '\0') {
84     while (*p) {
85       switch (*p++) {
86 #if defined(VASM_CPU_PPC)
87         case 'c': type = HUNK_PPC_CODE; break;
88 #else
89         case 'c': type = HUNK_CODE; break;
90 #endif
91         case 'd': type = HUNK_DATA; break;
92         case 'u': type = HUNK_BSS; break;
93       }
94     }
95   }
96   else
97     type = HUNK_DATA;
98 
99   return type;
100 }
101 
102 
prepare_sections(section * first_sec,symbol * sym)103 static section *prepare_sections(section *first_sec,symbol *sym)
104 /* Remove empty sections.
105    Assign all symbol definitions to their respective section.
106    Make sure that every common-symbol is referenced, otherwise there
107    is no possibility to represent such a symbol in hunk format.
108    Additionally we have to guarantee that at least one section exists,
109    when there are any symbols.
110    Remember the total number of sections left in sec_cnt. */
111 {
112   section *sec,*first_nonbss;
113   symbol *nextsym;
114   rlist *rl;
115   atom *a;
116 
117   for (sec_cnt=0,sec=first_sec,first_nonbss=NULL; sec!=NULL; sec=sec->next) {
118     /* ignore empty sections without symbols, unless -keepempty was given */
119     if (keep_empty_sects || get_sec_size(sec)!=0 || (sec->flags&HAS_SYMBOLS)) {
120       sec->idx = sec_cnt++;
121     }
122     else {
123       sec->flags |= SEC_DELETED;
124       continue;
125     }
126 
127     /* determine first initialized section for common-symbol references */
128     if (first_nonbss==NULL && scan_attr(sec)!=HUNK_BSS)
129       first_nonbss = sec;
130 
131     /* flag all present common-symbol references from this section */
132     for (a=sec->first; a; a=a->next) {
133       if (a->type == DATA) {
134         for (rl=a->content.db->relocs; rl; rl=rl->next) {
135           if (rl->type==REL_ABS || rl->type==REL_PC) {
136             if (((nreloc *)rl->reloc)->size==32) {
137               symbol *s = ((nreloc *)rl->reloc)->sym;
138 
139               if (s->flags & COMMON)
140                 s->flags |= COMM_REFERENCED;
141             }
142           }
143         }
144       }
145     }
146   }
147 
148   /* Allocate symbol lists for all sections.
149      Get one more for a potential dummy section. */
150   secsyms = mycalloc((sec_cnt+1)*sizeof(symbol *));
151 
152   /* Assign all valid symbol definitions to their section symbol list.
153      Check for missing common-symbol references. */
154   while (sym != NULL) {
155     nextsym = sym->next;
156 
157     if (*sym->name != ' ') {  /* internal symbols will be ignored */
158       if ((sym->flags & COMMON) && !(sym->flags & COMM_REFERENCED)) {
159         /* create a dummy reference for each unreferenced common symbol */
160         dblock *db = new_dblock();
161         nreloc *r = new_nreloc();
162         rlist *rl = mymalloc(sizeof(rlist));
163 
164         db->size = 4;
165         db->data = mycalloc(db->size);
166         db->relocs = rl;
167         rl->next = NULL;
168         rl->type = REL_ABS;
169         rl->reloc = r;
170         r->size = 32;
171         r->sym = sym;
172         if (first_nonbss == NULL) {
173           first_nonbss = dummy_section();
174           if (first_sec == NULL)
175             first_sec = first_nonbss;
176           first_nonbss->idx = sec_cnt++;
177         }
178         add_atom(first_nonbss,new_data_atom(db,4));
179       }
180       else if (sym->flags & WEAK) {
181         /* weak symbols are not supported, make them global */
182         sym->flags &= ~WEAK;
183         sym->flags |= EXPORT;
184         output_error(10,sym->name);
185       }
186 
187       if (sym->type==LABSYM ||
188                (sym->type==EXPRESSION && (sym->flags&EXPORT))) {
189         if (sym->type == EXPRESSION) {
190           /* put absolute globals symbols into the first section */
191           if (first_sec == NULL) {
192             first_sec = first_nonbss = dummy_section();
193             first_sec->idx = sec_cnt++;
194           }
195           first_sec->flags |= HAS_SYMBOLS;
196           sym->sec = first_sec;
197         }
198         /* assign symbols to the section they are defined in */
199         sym->next = secsyms[sym->sec->idx];
200         secsyms[sym->sec->idx] = sym;
201       }
202     }
203 
204     sym = nextsym;
205   }
206   return first_sec;
207 }
208 
209 
file_size(section * sec)210 static utaddr file_size(section *sec)
211 /* determine a section's initialized data size, which occupies space in
212    the executable file */
213 {
214   utaddr pc=0,zpc=0,npc;
215   atom *a;
216 
217   for (a=sec->first; a; a=a->next) {
218     int zerodata = 1;
219     unsigned char *d;
220 
221     npc = pcalign(a,pc);
222     if (a->type == DATA) {
223       /* do we have relocations or non-zero data in this atom? */
224       if (a->content.db->relocs) {
225         zerodata = 0;
226       }
227       else {
228        	for (d=a->content.db->data;
229              d<a->content.db->data+a->content.db->size; d++) {
230           if (*d) {
231             zerodata = 0;
232             break;
233           }
234         }
235       }
236     }
237     else if (a->type == SPACE) {
238       /* do we have relocations or non-zero data in this atom? */
239       if (a->content.sb->relocs) {
240         zerodata = 0;
241       }
242       else {
243         for (d=a->content.sb->fill;
244              d<a->content.sb->fill+a->content.sb->size; d++) {
245           if (*d) {
246             zerodata = 0;
247             break;
248           }
249         }
250       }
251     }
252     pc = npc + atom_size(a,sec,npc);
253     if (!zerodata)
254       zpc = pc;
255   }
256   return zpc;
257 }
258 
259 
convert_reloc(rlist * rl,utaddr pc)260 static struct hunkreloc *convert_reloc(rlist *rl,utaddr pc)
261 {
262   nreloc *r = (nreloc *)rl->reloc;
263 
264   if (rl->type <= LAST_STANDARD_RELOC
265 #if defined(VASM_CPU_PPC)
266       || rl->type==REL_PPCEABI_SDA2
267 #endif
268      ) {
269     if (LOCREF(r->sym)) {
270       struct hunkreloc *hr;
271       uint32_t type;
272       uint32_t offs = pc + r->byteoffset;
273 
274       switch (rl->type) {
275         case REL_ABS:
276           if (r->size!=32 || r->bitoffset!=0 || r->mask!=-1)
277             return NULL;
278           type = HUNK_ABSRELOC32;
279           break;
280 
281         case REL_PC:
282           switch (r->size) {
283             case 8:
284               if (r->bitoffset!=0 || r->mask!=-1)
285                 return NULL;
286               type = HUNK_RELRELOC8;
287               break;
288 #if defined(VASM_CPU_PPC)
289             case 14:
290               if (r->bitoffset!=0 || r->mask!=0xfffc)
291                 return NULL;
292               type = HUNK_RELRELOC16;
293               break;
294 #endif
295             case 16:
296               if (r->bitoffset!=0 || r->mask!=-1)
297                 return NULL;
298               type = HUNK_RELRELOC16;
299               break;
300 #if defined(VASM_CPU_PPC)
301             case 24:
302               if (r->bitoffset!=6 || r->mask!=0x3fffffc)
303                 return NULL;
304               type = HUNK_RELRELOC26;
305               break;
306 #endif
307             case 32:
308               if (kick1 || r->bitoffset!=0 || r->mask!=-1)
309                 return NULL;
310               type = HUNK_RELRELOC32;
311               break;
312           }
313           break;
314 
315 #if defined(VASM_CPU_PPC)
316         case REL_PPCEABI_SDA2: /* treat as REL_SD for WarpOS/EHF */
317 #endif
318         case REL_SD:
319           if (r->size!=16 || r->bitoffset!=0 || r->mask!=-1)
320             return NULL;
321           type = HUNK_DREL16;
322           break;
323 
324         default:
325           return NULL;
326       }
327 
328       hr = mymalloc(sizeof(struct hunkreloc));
329       hr->hunk_id = type;
330       hr->hunk_offset = offs;
331       hr->hunk_index = r->sym->sec->idx;
332       return hr;
333     }
334   }
335 
336   return NULL;
337 }
338 
339 
convert_xref(rlist * rl,utaddr pc)340 static struct hunkxref *convert_xref(rlist *rl,utaddr pc)
341 {
342   nreloc *r = (nreloc *)rl->reloc;
343 
344   if (rl->type <= LAST_STANDARD_RELOC
345 #if defined(VASM_CPU_PPC)
346       || rl->type==REL_PPCEABI_SDA2
347 #endif
348      ) {
349     if (EXTREF(r->sym)) {
350       struct hunkxref *xref;
351       uint32_t type,size=0;
352       uint32_t offs = pc + r->byteoffset;
353       int com = (r->sym->flags & COMMON) != 0;
354 
355       switch (rl->type) {
356         case REL_ABS:
357           if (r->bitoffset!=0 || r->mask!=-1 || (com && r->size!=32))
358             return NULL;
359           switch (r->size) {
360             case 8:
361               type = kick1 ? EXT_RELREF8 : EXT_ABSREF8;
362               break;
363             case 16:
364               type = kick1 ? EXT_RELREF16 : EXT_ABSREF16;
365               break;
366             case 32:
367               if (com) {
368                 type = EXT_ABSCOMMON;
369                 size = get_sym_size(r->sym);
370               }
371               else
372                 type = EXT_ABSREF32;
373               break;
374           }
375           break;
376 
377         case REL_PC:
378           switch (r->size) {
379             case 8:
380               if (r->bitoffset!=0 || r->mask!=-1 || com)
381                 return NULL;
382               type = EXT_RELREF8;
383               break;
384 #if defined(VASM_CPU_PPC)
385             case 14:
386               if (r->bitoffset!=0 || r->mask!=0xfffc || com)
387                 return NULL;
388               type = EXT_RELREF16;
389               break;
390 #endif
391             case 16:
392               if (r->bitoffset!=0 || r->mask!=-1 || com)
393                 return NULL;
394               type = EXT_RELREF16;
395               break;
396 #if defined(VASM_CPU_PPC)
397             case 24:
398               if (r->bitoffset!=6 || r->mask!=0x3fffffc || com)
399                 return NULL;
400               type = EXT_RELREF26;
401               break;
402 #endif
403             case 32:
404               if (kick1 || r->bitoffset!=0 || r->mask!=-1)
405                 return NULL;
406               if (com) {
407                 type = EXT_RELCOMMON;
408                 size = get_sym_size(r->sym);
409               }
410               else
411                 type = EXT_RELREF32;
412               break;
413           }
414           break;
415 
416 #if defined(VASM_CPU_PPC)
417         case REL_PPCEABI_SDA2: /* treat as REL_SD for WarpOS/EHF */
418 #endif
419         case REL_SD:
420           if (r->size!=16 || r->bitoffset!=0 || r->mask!=-1)
421             return NULL;
422           type = EXT_DEXT16;
423           break;
424 
425         default:
426           return NULL;
427       }
428 
429       xref = mymalloc(sizeof(struct hunkxref));
430       xref->name = r->sym->name;
431       xref->type = type;
432       xref->size = size;
433       xref->offset = offs;
434       return xref;
435     }
436   }
437 
438   return NULL;
439 }
440 
441 
process_relocs(atom * a,struct list * reloclist,struct list * xreflist,section * sec,utaddr pc)442 static void process_relocs(atom *a,struct list *reloclist,
443                            struct list *xreflist,section *sec,utaddr pc)
444 /* convert an atom's rlist into relocations and xrefs */
445 {
446   rlist *rl;
447 
448   if (a->type == DATA)
449     rl = a->content.db->relocs;
450   else if (a->type == SPACE)
451     rl = a->content.sb->relocs;
452   else
453     return;
454 
455   if (rl == NULL)
456     return;
457 
458   do {
459     struct hunkreloc *hr = convert_reloc(rl,pc);
460 
461     if (hr!=NULL && (xreflist!=NULL || hr->hunk_id==HUNK_ABSRELOC32 ||
462                      hr->hunk_id==HUNK_RELRELOC32)) {
463       addtail(reloclist,&hr->n);       /* add new relocation */
464     }
465     else {
466       struct hunkxref *xref = convert_xref(rl,pc);
467 
468       if (xref) {
469         if (xreflist)
470           addtail(xreflist,&xref->n);  /* add new external reference */
471         else
472           output_atom_error(8,a,xref->name,sec->name,xref->offset,rl->type);
473       }
474       else
475         unsupp_reloc_error(rl);  /* reloc not supported */
476     }
477   }
478   while (rl = rl->next);
479 }
480 
481 
reloc_hunk(FILE * f,uint32_t type,int shrt,struct list * reloclist)482 static void reloc_hunk(FILE *f,uint32_t type,int shrt,struct list *reloclist)
483 /* write all section-offsets for one relocation type */
484 {
485   int bytes = 0;
486   uint32_t idx;
487 
488   for (idx=0; idx<sec_cnt; idx++) {
489     struct hunkreloc *r,*next;
490     uint32_t n;
491     int off16;
492 
493     for (r=(struct hunkreloc *)reloclist->first,n=0,off16=1;
494          r->n.next; r=(struct hunkreloc *)r->n.next) {
495       if (r->hunk_id==type && r->hunk_index==idx) {
496         n++;
497         if (r->hunk_offset >= 0x10000)
498           off16 = 0;
499       }
500     }
501     if (shrt && (n>=0x10000 || off16==0))
502       continue;  /* relocs for this hunk don't fit into 16-bit entries */
503     if (n > 0) {
504       if (bytes == 0) {
505         if (shrt && type==HUNK_ABSRELOC32)
506           fw32(f,HUNK_DREL32,1);  /* RELOC32SHORT is DREL32 for OS2.0 */
507         else
508           fw32(f,type,1);
509         bytes = 4;
510       }
511       if (shrt) {
512         fw16(f,n,1);
513         fw16(f,idx,1);
514         bytes += 4;
515       }
516       else {
517         fw32(f,n,1);
518         fw32(f,idx,1);
519         bytes += 8;
520       }
521       r = (struct hunkreloc *)reloclist->first;
522       while (next = (struct hunkreloc *)r->n.next) {
523         if (r->hunk_id==type && r->hunk_index==idx) {
524           if (shrt) {
525             fw16(f,r->hunk_offset,1);
526             bytes += 2;
527           }
528           else {
529             fw32(f,r->hunk_offset,1);
530             bytes += 4;
531           }
532           remnode(&r->n);
533           myfree(r);
534         }
535         r = next;
536       }
537     }
538   }
539   if (bytes) {
540     if (shrt) {
541       fw16(f,0,1);
542       fwalign(f,bytes+2,4);
543     }
544     else
545       fw32(f,0,1);
546   }
547 }
548 
549 
add_linedebug(struct list * ldblist,uint32_t line,uint32_t off)550 static void add_linedebug(struct list *ldblist,uint32_t line,uint32_t off)
551 {
552   struct hunkline *ldebug = mymalloc(sizeof(struct hunkline));
553 
554   ldebug->line = line;
555   ldebug->offset = off;
556   addtail(ldblist,&ldebug->n);
557 }
558 
559 
linedebug_hunk(FILE * f,struct list * ldblist,int num)560 static void linedebug_hunk(FILE *f,struct list *ldblist,int num)
561 {
562   if (num > 0) {
563     struct hunkline *hl;
564     uint32_t srcname_len = strlen32(getdebugname());
565 
566     fw32(f,HUNK_DEBUG,1);
567     fw32(f,srcname_len + num*2 + 3,1);
568     fw32(f,0,1);
569     fw32(f,0x4c494e45,1);  /* "LINE" */
570     fw32(f,srcname_len,1);
571     fwname(f,getdebugname());
572 
573     for (hl=(struct hunkline *)ldblist->first;
574          hl->n.next; hl=(struct hunkline *)hl->n.next) {
575       fw32(f,hl->line,1);
576       fw32(f,hl->offset,1);
577     }
578   }
579 }
580 
581 
extheader(FILE * f)582 static void extheader(FILE *f)
583 {
584   if (!exthunk) {
585     exthunk = 1;
586     fw32(f,HUNK_EXT,1);
587   }
588 }
589 
590 
exttrailer(FILE * f)591 static void exttrailer(FILE *f)
592 {
593   if (exthunk)
594     fw32(f,0,1);
595 }
596 
597 
ext_refs(FILE * f,struct list * xreflist)598 static void ext_refs(FILE *f,struct list *xreflist)
599 /* write all external references from a section into a HUNK_EXT hunk */
600 {
601   while (xreflist->first->next) {
602     struct hunkxref *x,*next;
603     uint32_t n,type,size;
604     char *name;
605 
606     extheader(f);
607     x = (struct hunkxref *)xreflist->first;
608     name = x->name;
609     type = x->type;
610     size = x->size;
611 
612     for (n=0,x=(struct hunkxref *)xreflist->first;
613          x->n.next; x=(struct hunkxref *)x->n.next) {
614       if (!strcmp(x->name,name) && x->type==type)
615         n++;
616     }
617     fw32(f,(type<<24) | strlen32(name),1);
618     fwname(f,name);
619     if (type==EXT_ABSCOMMON || type==EXT_RELCOMMON)
620       fw32(f,size,1);
621     fw32(f,n,1);
622 
623     x = (struct hunkxref *)xreflist->first;
624     while (next = (struct hunkxref *)x->n.next) {
625       if (!strcmp(x->name,name) && x->type==type) {
626         fw32(f,x->offset,1);
627         remnode(&x->n);
628         myfree(x);
629       }
630       x = next;
631     }
632   }
633 }
634 
635 
ext_defs(FILE * f,int symtype,int global,size_t idx,uint32_t xtype)636 static void ext_defs(FILE *f,int symtype,int global,size_t idx,
637                      uint32_t xtype)
638 {
639   int header = 0;
640   symbol *sym;
641 
642   for (sym=secsyms[idx]; sym; sym=sym->next) {
643     if (sym->type==symtype && (sym->flags&global)==global) {
644       if (!header) {
645         header = 1;
646         if (xtype == EXT_SYMB)
647           fw32(f,HUNK_SYMBOL,1);
648         else
649           extheader(f);
650       }
651       fw32(f,(xtype<<24) | strlen32(sym->name),1);
652       fwname(f,sym->name);
653       fw32(f,(uint32_t)get_sym_value(sym),1);
654     }
655   }
656   if (header && xtype==EXT_SYMB)
657     fw32(f,0,1);
658 }
659 
660 
write_object(FILE * f,section * sec,symbol * sym)661 static void write_object(FILE *f,section *sec,symbol *sym)
662 {
663   int wrotesec = 0;
664 
665   sec = prepare_sections(sec,sym);
666 
667   /* write header */
668   fw32(f,HUNK_UNIT,1);
669   fw32(f,strlen32(filename),1);
670   fwname(f,filename);
671 
672   if (sec) {
673     for (; sec; sec=sec->next) {
674       if (!(sec->flags & SEC_DELETED)) {
675         uint32_t type;
676         atom *a;
677         struct list reloclist,xreflist,linedblist;
678         int num_linedb = 0;
679 
680         wrotesec = 1;
681         initlist(&reloclist);
682         initlist(&xreflist);
683         initlist(&linedblist);
684 
685         /* section name */
686         if (strlen(sec->name)) {
687           fw32(f,HUNK_NAME,1);
688           fw32(f,strlen32(sec->name),1);
689           fwname(f,sec->name);
690         }
691 
692         /* section type */
693         if (!(type = scan_attr(sec))) {
694           output_error(3,sec->attr);  /* section attributes not suppported */
695           type = HUNK_DATA;  /* default */
696         }
697         fwmemflags(f,sec,type);
698         fw32(f,(get_sec_size(sec)+3)>>2,1);  /* size */
699 
700         if (type != HUNK_BSS) {
701           /* write contents */
702           utaddr pc=0,npc,i;
703 
704           for (a=sec->first; a; a=a->next) {
705             rlist *rl;
706 
707             npc = fwpcalign(f,a,sec,pc);
708 
709             if (genlinedebug && (a->type==DATA || a->type==SPACE)) {
710               add_linedebug(&linedblist,(uint32_t)a->line,npc);
711               ++num_linedb;
712             }
713 
714             if (a->type == DATA) {
715               fwdata(f,a->content.db->data,a->content.db->size);
716             }
717             else if (a->type == SPACE) {
718               fwsblock(f,a->content.sb);
719             }
720             else if (a->type == LINE && !genlinedebug) {
721               add_linedebug(&linedblist,(uint32_t)a->content.srcline,npc);
722               ++num_linedb;
723             }
724             process_relocs(a,&reloclist,&xreflist,sec,npc);
725 
726             pc = npc + atom_size(a,sec,npc);
727           }
728           if (type == HUNK_CODE && (pc&1) == 0)
729             fwnopalign(f,pc);
730           else
731             fwalign(f,pc,4);
732         }
733 
734         /* relocation hunks */
735         reloc_hunk(f,HUNK_ABSRELOC32,0,&reloclist);
736         reloc_hunk(f,HUNK_RELRELOC8,0,&reloclist);
737         reloc_hunk(f,HUNK_RELRELOC16,0,&reloclist);
738         reloc_hunk(f,HUNK_RELRELOC26,0,&reloclist);
739         reloc_hunk(f,HUNK_RELRELOC32,0,&reloclist);
740         reloc_hunk(f,HUNK_DREL16,0,&reloclist);
741 
742         /* external references and global definitions */
743         exthunk = 0;
744         ext_refs(f,&xreflist);
745         if (sec->idx == 0)  /* absolute definitions into first hunk */
746           ext_defs(f,EXPRESSION,EXPORT,0,EXT_ABS);
747         ext_defs(f,LABSYM,EXPORT,sec->idx,EXT_DEF);
748         exttrailer(f);
749 
750         if (!no_symbols) {
751           /* symbol table */
752           if (!hunk_onlyglobal)
753             ext_defs(f,LABSYM,0,sec->idx,EXT_SYMB);
754           /* line-debug */
755           linedebug_hunk(f,&linedblist,num_linedb);
756         }
757         fw32(f,HUNK_END,1);
758       }
759     }
760   }
761   if (!wrotesec) {
762     /* there was no section at all - dummy section size 0 */
763 #if defined(VASM_CPU_PPC)
764     fw32(f,HUNK_PPC_CODE,1);
765 #else
766     fw32(f,HUNK_CODE,1);
767 #endif
768     fw32(f,0,1);
769     fw32(f,HUNK_END,1);
770   }
771 }
772 
773 
write_exec(FILE * f,section * sec,symbol * sym)774 static void write_exec(FILE *f,section *sec,symbol *sym)
775 {
776   section *s;
777 
778   sec = prepare_sections(sec,sym);
779 
780   /* write header */
781   fw32(f,HUNK_HEADER,1);
782   fw32(f,0,1);
783 
784   if (sec_cnt) {
785     fw32(f,sec_cnt,1);    /* number of sections - no overlay support */
786     fw32(f,0,1);          /* first section index: 0 */
787     fw32(f,sec_cnt-1,1);  /* last section index: sec_cnt - 1 */
788 
789     /* write section sizes and memory flags */
790     for (s=sec; s; s=s->next) {
791       if (!(s->flags & SEC_DELETED))
792         fwmemflags(f,s,(get_sec_size(s)+3)>>2);
793     }
794 
795     /* section hunk loop */
796     for (; sec; sec=sec->next) {
797       if (!(sec->flags & SEC_DELETED)) {
798       	uint32_t type;
799         atom *a;
800         struct list reloclist,linedblist;
801         int num_linedb = 0;
802 
803         initlist(&reloclist);
804         initlist(&linedblist);
805 
806         /* write hunk-type and size */
807         if (!(type = scan_attr(sec))) {
808           output_error(3,sec->attr);  /* section attributes not suppported */
809           type = HUNK_DATA;  /* default */
810         }
811         fw32(f,type,1);
812 
813         if (type != HUNK_BSS) {
814           /* write contents */
815           utaddr pc,npc,size,i;
816 
817           size = databss ? file_size(sec) : get_sec_size(sec);
818           fw32(f,(size+3)>>2,1);
819           for (a=sec->first,pc=0; a!=NULL&&pc<size; a=a->next) {
820             rlist *rl;
821 
822             npc = fwpcalign(f,a,sec,pc);
823 
824             if (genlinedebug && (a->type==DATA || a->type==SPACE)) {
825               add_linedebug(&linedblist,(uint32_t)a->line,npc);
826               ++num_linedb;
827             }
828 
829             if (a->type == DATA) {
830               fwdata(f,a->content.db->data,a->content.db->size);
831             }
832             else if (a->type == SPACE) {
833               fwsblock(f,a->content.sb);
834             }
835             else if (a->type == LINE && !genlinedebug) {
836               add_linedebug(&linedblist,(uint32_t)a->content.srcline,npc);
837               ++num_linedb;
838             }
839             process_relocs(a,&reloclist,NULL,sec,npc);
840 
841             pc = npc + atom_size(a,sec,npc);
842           }
843           if (type == HUNK_CODE && (pc&1) == 0)
844             fwnopalign(f,pc);
845           else
846             fwalign(f,pc,4);
847         }
848         else /* HUNK_BSS */
849           fw32(f,(get_sec_size(sec)+3)>>2,1);
850 
851         if (!kick1)
852           reloc_hunk(f,HUNK_ABSRELOC32,1,&reloclist);
853         reloc_hunk(f,HUNK_ABSRELOC32,0,&reloclist);
854         if (!kick1)  /* RELRELOC32 works with short 16-bit offsets only! */
855           reloc_hunk(f,HUNK_RELRELOC32,1,&reloclist);
856 
857         if (!no_symbols) {
858           /* symbol table */
859           if (!hunk_onlyglobal)
860             ext_defs(f,LABSYM,0,sec->idx,EXT_SYMB);
861           /* line-debug */
862           linedebug_hunk(f,&linedblist,num_linedb);
863         }
864         fw32(f,HUNK_END,1);
865       }
866     }
867   }
868   else {
869     /* no sections: create single code hunk with size 0 */
870     fw32(f,1,1);
871     fw32(f,0,1);
872     fw32(f,0,1);
873     fw32(f,0,1);
874     fw32(f,HUNK_CODE,1);
875     fw32(f,0,1);
876     fw32(f,HUNK_END,1);
877   }
878 }
879 
880 
write_output(FILE * f,section * sec,symbol * sym)881 static void write_output(FILE *f,section *sec,symbol *sym)
882 {
883   if (exec_out)
884     write_exec(f,sec,sym);
885   else
886     write_object(f,sec,sym);
887 }
888 
889 
common_args(char * p)890 static int common_args(char *p)
891 {
892 #if defined(VASM_CPU_M68K)
893   if (!strcmp(p,"-kick1hunks")) {
894     kick1 = 1;
895     return 1;
896   }
897 #endif
898   if (!strcmp(p,"-linedebug")) {
899     genlinedebug = 1;
900     return 1;
901   }
902   if (!strcmp(p,"-keepempty")) {
903     keep_empty_sects = 1;
904     return 1;
905   }
906   return 0;
907 }
908 
909 
object_args(char * p)910 static int object_args(char *p)
911 {
912   return common_args(p);
913 }
914 
915 
exec_args(char * p)916 static int exec_args(char *p)
917 {
918   if (!strcmp(p,"-databss")) {
919     databss = 1;
920     return 1;
921   }
922   return common_args(p);
923 }
924 
925 
init_output_hunk(char ** cp,void (** wo)(FILE *,section *,symbol *),int (** oa)(char *))926 int init_output_hunk(char **cp,void (**wo)(FILE *,section *,symbol *),
927                      int (**oa)(char *))
928 {
929   *cp = copyright;
930   *wo = write_output;
931   *oa = exec_out ? exec_args : object_args;
932   return 1;
933 }
934 
935 #else
936 
init_output_hunk(char ** cp,void (** wo)(FILE *,section *,symbol *),int (** oa)(char *))937 int init_output_hunk(char **cp,void (**wo)(FILE *,section *,symbol *),
938                      int (**oa)(char *))
939 {
940   return 0;
941 }
942 #endif
943