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