* added compilers lcc and bcc (linux86)
[mascara-docs.git] / compilers / linux86-0.16.17 / ld / writex86.c
blobeaf4881797afd5591035108c493d44f247835811
1 /* writex86.c - write binary file for linker */
3 /* Copyright (C) 1994 Bruce Evans */
5 #include "syshead.h"
6 #include "x86_aout.h"
7 #ifndef MSDOS
8 #include "x86_cpm86.h"
9 #endif
10 #include "const.h"
11 #include "obj.h"
12 #include "type.h"
13 #include "globvar.h"
15 #define btextoffset (text_base_value)
16 #define bdataoffset (data_base_value)
17 #define page_size() ((bin_off_t)4096)
19 #ifndef ELF_SYMS
20 #define ELF_SYMS 0
21 #endif
23 #ifdef MSDOS
24 # define FILEHEADERLENGTH (headerless?0:A_MINHDR)
25 #else
26 # define FILEHEADERLENGTH (headerless?0:(cpm86?CPM86_HEADERLEN:A_MINHDR))
27 #endif
28 /* part of header not counted in offsets */
29 #define DPSEG 2
31 #define CM_MASK 0xC0
32 #define MODIFY_MASK 0x3F
33 #define S_MASK 0x04
34 #define OF_MASK 0x03
36 #define CM_SPECIAL 0
37 #define CM_ABSOLUTE 0x40
38 #define CM_OFFSET_RELOC 0x80
39 #define CM_SYMBOL_RELOC 0xC0
41 #define CM_EOT 0
42 #define CM_BYTE_SIZE 1
43 #define CM_WORD_SIZE 2
44 #define CM_LONG_SIZE 3
45 #define CM_1_SKIP 17
46 #define CM_2_SKIP 18
47 #define CM_4_SKIP 19
48 #define CM_0_SEG 32
50 #define ABS_TEXT_MAX 64
52 #define offsetof(struc, mem) ((int) &((struc *) 0)->mem)
53 #define memsizeof(struc, mem) sizeof(((struc *) 0)->mem)
55 PRIVATE bool_t bits32; /* nonzero for 32-bit executable */
56 PRIVATE bin_off_t combase[NSEG];/* bases of common parts of segments */
57 PRIVATE bin_off_t comsz[NSEG]; /* sizes of common parts of segments */
58 PRIVATE fastin_t curseg; /* current segment, 0 to $F */
59 PRIVATE bin_off_t edataoffset; /* end of data */
60 PRIVATE bin_off_t endoffset; /* end of bss */
61 PRIVATE bin_off_t etextoffset; /* end of text */
62 PRIVATE bin_off_t etextpadoff; /* end of padded text */
63 PRIVATE unsigned nsym; /* number of symbols written */
64 PRIVATE unsigned relocsize; /* current relocation size 1, 2 or 4 */
65 PRIVATE bin_off_t segadj[NSEG]; /* adjusts (file offset - seg offset) */
66 /* depends on zero init */
67 PRIVATE bin_off_t segbase[NSEG];/* bases of data parts of segments */
68 PRIVATE char segboundary[9] = "__seg0DH";
69 /* name of seg boundary __seg0DL to __segfCH */
70 PRIVATE bin_off_t segpos[NSEG]; /* segment positions for current module */
71 PRIVATE bin_off_t segsz[NSEG]; /* sizes of data parts of segments */
72 /* depends on zero init */
73 PRIVATE bool_t sepid; /* nonzero for separate I & D */
74 PRIVATE bool_t stripflag; /* nonzero to strip symbols */
75 PRIVATE bin_off_t spos; /* position in current seg */
76 PRIVATE bool_t uzp; /* nonzero for unmapped zero page */
77 PRIVATE bool_t xsym; /* extended symbol table */
79 FORWARD void linkmod P((struct modstruct *modptr));
80 FORWARD void padmod P((struct modstruct *modptr));
81 FORWARD void setsym P((char *name, bin_off_t value));
82 FORWARD void symres P((char *name));
83 FORWARD void setseg P((fastin_pt newseg));
84 FORWARD void skip P((unsigned countsize));
85 FORWARD void writeheader P((void));
86 #ifndef MSDOS
87 FORWARD void cpm86header P((void));
88 #endif
89 FORWARD void writenulls P((bin_off_t count));
91 EXTERN bool_t reloc_output;
93 /* write binary file */
95 PUBLIC void write_elks(outfilename, argsepid, argbits32, argstripflag, arguzp, argxsym)
96 char *outfilename;
97 bool_pt argsepid;
98 bool_pt argbits32;
99 bool_pt argstripflag;
100 bool_pt arguzp;
101 bool_pt argxsym;
103 char buf4[4];
104 char *cptr;
105 struct nlist extsym;
106 flags_t flags;
107 struct modstruct *modptr;
108 fastin_t seg;
109 unsigned sizecount;
110 bin_off_t tempoffset;
112 if( reloc_output )
113 #ifndef MSDOS
114 fatalerror("Output binformat not configured relocatable, use -N");
115 #else
116 fatalerror("Cannot use -r under MSDOS, sorry");
117 #endif
119 sepid = argsepid;
120 bits32 = argbits32;
121 stripflag = argstripflag;
122 uzp = arguzp;
123 xsym = argxsym;
124 if (uzp)
126 if (btextoffset == 0)
127 btextoffset = page_size();
128 if (bdataoffset == 0 && sepid)
129 bdataoffset = page_size();
132 /* reserve special symbols use curseg to pass parameter to symres() */
133 for (curseg = 0; curseg < NSEG; ++curseg)
135 segboundary[5] = hexdigit[curseg]; /* to __segX?H */
136 segboundary[6] = 'D';
137 symres(segboundary); /* __segXDH */
138 segboundary[7] = 'L';
139 symres(segboundary); /* __segXDL */
140 segboundary[6] = 'C';
141 symres(segboundary); /* __segXCL */
142 segboundary[7] = 'H';
143 symres(segboundary); /* __segXCH */
144 #ifndef DATASEGS
145 if( curseg > 3 )
147 segboundary[6] = 'S';
148 segboundary[7] = 'O';
149 symres(segboundary); /* __segXSO */
151 #endif
153 curseg = 3;
154 symres("__edata");
155 symres("__end");
156 symres("__heap_top");
157 curseg = 0; /* text seg, s.b. variable */
158 symres("__etext");
159 symres("__segoff");
161 /* calculate segment and common sizes (sum over loaded modules) */
162 /* use zero init of segsz[] */
163 /* also relocate symbols relative to starts of their segments */
164 for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
165 if (modptr->loadflag)
167 register struct symstruct **symparray;
168 register struct symstruct *symptr;
170 for (symparray = modptr->symparray;
171 (symptr = *symparray) != NUL_PTR; ++symparray)
172 if (symptr->modptr == modptr && !(symptr->flags & A_MASK))
174 if (!(symptr->flags & (I_MASK | SA_MASK)))
176 /* relocate by offset of module in segment later */
177 /* relocate by offset of segment in memory special */
178 /* symbols get relocated improperly */
179 symptr->value += segsz[symptr->flags & SEGM_MASK];
181 else if (symptr->value == 0)
183 undefined(symptr->name);
185 else
187 tempoffset = ld_roundup(symptr->value, 4, bin_off_t);
188 /* temp kludge quad alignment for 386 */
189 symptr->value = comsz[seg = symptr->flags & SEGM_MASK];
190 comsz[seg] += tempoffset;
191 if (!(symptr->flags & SA_MASK))
192 symptr->flags |= C_MASK;
195 for (seg = 0, cptr = modptr->segsize; seg < NSEG; ++seg)
197 segsz[seg] += cntooffset(cptr,
198 sizecount = segsizecount((unsigned) seg, modptr));
200 /* adjust sizes to even to get quad boundaries */
201 /* this should be specifiable dynamically */
202 segsz[seg] = ld_roundup(segsz[seg], 4, bin_off_t);
203 comsz[seg] = ld_roundup(comsz[seg], 4, bin_off_t);
204 cptr += sizecount;
208 /* calculate seg positions now their sizes are known */
210 #ifdef DATASEGS
211 * Assume seg 0 is text and rest are data
212 #else
213 * Assume seg 1..3 are data, Seg 0 is real text, seg 4+ are far text
214 #endif
216 segpos[0] = segbase[0] = spos = btextoffset;
217 combase[0] = segbase[0] + segsz[0];
218 segadj[1] = segadj[0] = -btextoffset;
219 etextpadoff = etextoffset = combase[0] + comsz[0];
220 if (sepid)
222 etextpadoff = ld_roundup(etextoffset, 0x10, bin_off_t);
223 segadj[1] += etextpadoff - bdataoffset;
225 else if (bdataoffset == 0)
226 bdataoffset = etextpadoff;
227 segpos[1] = segbase[1] = edataoffset = bdataoffset;
228 combase[1] = segbase[1] + segsz[1];
229 #ifndef DATASEGS
230 for (seg = 4; seg < NSEG; ++seg)
232 segpos[seg] = segbase[seg] = 0;
233 combase[seg] = segbase[seg] + segsz[seg];
234 segadj[seg] = etextpadoff;
236 etextpadoff += ld_roundup(segsz[seg] + comsz[seg], 0x10, bin_off_t);
237 segadj[1] += ld_roundup(segsz[seg] + comsz[seg], 0x10, bin_off_t);
239 for (seg = 2; seg < 4; ++seg)
240 #else
241 for (seg = 2; seg < NSEG; ++seg)
242 #endif
244 segpos[seg] = segbase[seg] = combase[seg - 1] + comsz[seg - 1];
245 #ifdef MC6809
246 if (seg == DPSEG)
248 /* temporarily have fixed DP seg */
249 /* adjust if nec so it only spans 1 page */
250 tempoffset = segsz[seg] + comsz[seg];
251 if (tempoffset > 0x100)
252 fatalerror("direct page segment too large");
253 if ((((segbase[seg] + tempoffset) ^ segbase[seg])
254 & ~(bin_off_t) 0xFF) != 0)
255 segpos[seg] = segbase[seg] = (segbase[seg] + 0xFF)
256 & ~(bin_off_t) 0xFF;
258 #endif
259 combase[seg] = segbase[seg] + segsz[seg];
260 segadj[seg] = segadj[seg - 1];
263 /* relocate symbols by offsets of segments in memory */
264 for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
265 if (modptr->loadflag)
267 register struct symstruct **symparray;
268 register struct symstruct *symptr;
270 for (symparray = modptr->symparray;
271 (symptr = *symparray) != NUL_PTR; ++symparray)
272 if (symptr->modptr == modptr && !(symptr->flags & A_MASK))
274 if (symptr->flags & (C_MASK | SA_MASK))
275 symptr->value += combase[symptr->flags & SEGM_MASK];
276 else
277 symptr->value += segbase[symptr->flags & SEGM_MASK];
281 /* adjust special symbols */
282 for (seg = 0; seg < NSEG; ++seg)
284 #ifdef DATASEGS
285 if (segsz[seg] != 0)
286 /* only count data of nonzero length */
287 #else
288 if (segsz[seg] != 0 && seg < 4)
289 #endif
290 edataoffset = segbase[seg] + segsz[seg];
291 segboundary[5] = hexdigit[seg]; /* to __segX?H */
292 segboundary[6] = 'D';
293 setsym(segboundary, (tempoffset = segbase[seg]) + segsz[seg]);
294 /* __segXDH */
295 segboundary[7] = 'L';
296 setsym(segboundary, tempoffset); /* __segXDL */
297 segboundary[6] = 'C';
298 setsym(segboundary, tempoffset = combase[seg]);
299 /* __segXCL */
300 segboundary[7] = 'H';
301 setsym(segboundary, tempoffset + comsz[seg]);
302 /* __segXCH */
303 #ifndef DATASEGS
304 if( seg > 3 )
306 segboundary[6] = 'S';
307 segboundary[7] = 'O';
308 setsym(segboundary, (bin_off_t)(segadj[seg]-segadj[0])/0x10);
309 /* __segXSO */
311 #endif
313 setsym("__etext", etextoffset);
314 setsym("__edata", edataoffset);
315 #ifdef DATASEGS
316 setsym("__end", endoffset = combase[NSEG - 1] + comsz[NSEG - 1]);
317 #else
318 setsym("__end", endoffset = combase[3] + comsz[3]);
319 #endif
320 setsym("__segoff", (bin_off_t)(segadj[1]-segadj[0])/0x10);
321 if( !bits32 )
323 if( etextoffset > 65536L )
324 fatalerror("text segment too large for 16bit");
325 if( endoffset > 65536L )
326 fatalerror("data segment too large for 16bit");
329 if( heap_top_value < 0x100 || endoffset > heap_top_value-0x100)
330 heap_top_value = endoffset + 0x8000;
331 if( heap_top_value > 0x10000 && !bits32 ) heap_top_value = 0x10000;
332 setsym("__heap_top", (bin_off_t)heap_top_value);
334 openout(outfilename);
335 #ifndef MSDOS
336 if (cpm86) cpm86header();
337 else
338 #endif
339 writeheader();
340 for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
341 if (modptr->loadflag)
343 linkmod(modptr);
344 padmod(modptr);
347 /* dump symbol table */
348 if (!stripflag)
350 seekout(FILEHEADERLENGTH
351 + (unsigned long) (etextpadoff - btextoffset)
352 + (unsigned long) (edataoffset - bdataoffset)
354 extsym.n_numaux = extsym.n_type = 0;
355 for (modptr = modfirst; modptr != NUL_PTR; modptr = modptr->modnext)
356 if (modptr->loadflag)
358 register struct symstruct **symparray;
359 register struct symstruct *symptr;
361 for (symparray = modptr->symparray;
362 (symptr = *symparray) != NUL_PTR; ++symparray)
363 if (symptr->modptr == modptr)
365 #if ELF_SYMS
366 if (symptr->name[0] == '_' && symptr->name[1] )
367 strncpy((char *) extsym.n_name, symptr->name+1,
368 sizeof extsym.n_name);
369 else
371 memcpy((char *) extsym.n_name, "$", 1);
372 strncpy((char *) extsym.n_name+1, symptr->name,
373 sizeof(extsym.n_name)-1);
375 #else
376 strncpy((char *) extsym.n_name, symptr->name,
377 sizeof extsym.n_name);
378 #endif
379 u4cn((char *) &extsym.n_value, (u4_t) symptr->value,
380 sizeof extsym.n_value);
381 if ((flags = symptr->flags) & A_MASK)
382 extsym.n_sclass = N_ABS;
383 else if (flags & (E_MASK | I_MASK))
384 extsym.n_sclass = C_EXT;
385 else
386 extsym.n_sclass = C_STAT;
387 if (!(flags & I_MASK) ||
388 flags & C_MASK)
389 switch (flags & (A_MASK | SEGM_MASK))
391 #ifdef DATASEGS
392 case 0:
393 #else
394 default:
395 #endif
396 extsym.n_sclass |= N_TEXT;
397 case A_MASK:
398 break;
399 #ifdef DATASEGS
400 default:
401 #else
402 case 1: case 2: case 3:
403 case A_MASK|1: case A_MASK|2: case A_MASK|3:
404 #endif
405 if (flags & (C_MASK | SA_MASK))
406 extsym.n_sclass |= N_BSS;
407 else
408 extsym.n_sclass |= N_DATA;
409 break;
411 writeout((char *) &extsym, sizeof extsym);
412 ++nsym;
413 #if !ELF_SYMS
414 if( xsym )
416 int i;
417 extsym.n_sclass = 0;
418 memset((void*)&extsym.n_value,0,
419 sizeof(extsym.n_value));
421 for(i=sizeof extsym.n_name; i<strlen(symptr->name);
422 i+=sizeof extsym.n_name)
424 strncpy((char *) extsym.n_name, symptr->name+i,
425 sizeof extsym.n_name);
426 writeout((char *) &extsym, sizeof extsym);
427 ++nsym;
430 #endif
433 seekout((unsigned long) offsetof(struct exec, a_syms));
434 u4cn(buf4, (u4_t) nsym * sizeof extsym,
435 memsizeof(struct exec, a_syms));
436 writeout(buf4, memsizeof(struct exec, a_syms));
438 closeout();
439 executable();
442 PRIVATE void linkmod(modptr)
443 struct modstruct *modptr;
445 char buf[ABS_TEXT_MAX];
446 int command;
447 unsigned char modify;
448 bin_off_t offset;
449 int symbolnum;
450 struct symstruct **symparray;
451 struct symstruct *symptr;
453 setseg(0);
454 relocsize = 2;
455 symparray = modptr->symparray;
456 openin(modptr->filename); /* does nothing if already open */
457 seekin(modptr->textoffset);
458 while (TRUE)
460 if ((command = readchar()) < 0)
461 prematureeof();
462 modify = command & MODIFY_MASK;
463 switch (command & CM_MASK)
465 case CM_SPECIAL:
466 switch (modify)
468 case CM_EOT:
469 segpos[curseg] = spos;
470 return;
471 case CM_BYTE_SIZE:
472 relocsize = 1;
473 break;
474 case CM_WORD_SIZE:
475 relocsize = 2;
476 break;
477 case CM_LONG_SIZE:
478 #ifdef LONG_OFFSETS
479 relocsize = 4;
480 break;
481 #else
482 fatalerror("relocation by long offsets not implemented");
483 #endif
484 case CM_1_SKIP:
485 skip(1);
486 break;
487 case CM_2_SKIP:
488 skip(2);
489 break;
490 case CM_4_SKIP:
491 skip(4);
492 break;
493 default:
494 if ((modify -= CM_0_SEG) >= NSEG)
495 inputerror("bad data in");
496 setseg(modify);
497 break;
499 break;
500 case CM_ABSOLUTE:
501 if (modify == 0)
502 modify = ABS_TEXT_MAX;
503 readin(buf, (unsigned) modify);
504 writeout(buf, (unsigned) modify);
505 spos += (int) modify;
506 break;
507 case CM_OFFSET_RELOC:
508 offset = readsize(relocsize);
509 if (modify & R_MASK)
511 #ifndef DATASEGS
512 int m = (modify & SEGM_MASK);
513 if( curseg != m && m != SEGM_MASK )
514 interseg(modptr->filename, modptr->archentry, (char*)0);
515 #endif
516 offset -= (spos + relocsize);
518 offtocn(buf, segbase[modify & SEGM_MASK] + offset, relocsize);
519 writeout(buf, relocsize);
520 spos += relocsize;
521 break;
522 case CM_SYMBOL_RELOC:
523 symptr = symparray[symbolnum = readconvsize((unsigned)
524 (modify & S_MASK ? 2 : 1))];
525 offset = readconvsize((unsigned) modify & OF_MASK);
526 if (modify & R_MASK)
528 #ifndef DATASEGS
529 int m = (symptr->flags & SEGM_MASK);
530 if( curseg != m && m != SEGM_MASK )
531 interseg(modptr->filename, modptr->archentry, symptr->name);
532 #endif
533 offset -= (spos + relocsize);
535 offset += symptr->value;
536 offtocn(buf, offset, relocsize);
537 writeout(buf, relocsize);
538 spos += relocsize;
543 PRIVATE void padmod(modptr)
544 struct modstruct *modptr;
546 bin_off_t count;
547 fastin_t seg;
548 bin_off_t size;
549 unsigned sizecount;
550 char *sizeptr;
552 for (seg = 0, sizeptr = modptr->segsize; seg < NSEG; ++seg)
554 size = cntooffset(sizeptr,
555 sizecount = segsizecount((unsigned) seg, modptr));
556 sizeptr += sizecount;
557 if ((count = segpos[seg] - segbase[seg]) != size)
558 size_error(seg, count, size);
560 /* pad to quad boundary */
561 /* not padding in-between common areas which sometimes get into file */
562 if ((size = ld_roundup(segpos[seg], 4, bin_off_t) - segpos[seg]) != 0)
564 setseg(seg);
565 writenulls(size);
566 segpos[seg] = spos;
568 segbase[seg] = segpos[seg];
572 PRIVATE void setsym(name, value)
573 char *name;
574 bin_off_t value;
576 struct symstruct *symptr;
578 if ((symptr = findsym(name)) != NUL_PTR)
579 symptr->value = value;
582 PRIVATE void symres(name)
583 register char *name;
585 register struct symstruct *symptr;
587 if ((symptr = findsym(name)) != NUL_PTR)
589 if ((symptr->flags & SEGM_MASK) == SEGM_MASK)
590 symptr->flags &= ~SEGM_MASK | curseg;
591 if (symptr->flags != (I_MASK | curseg) || symptr->value != 0)
592 reserved(name);
593 symptr->flags = E_MASK | curseg; /* show defined, not common */
597 /* set new segment */
599 PRIVATE void setseg(newseg)
600 fastin_pt newseg;
602 if (newseg != curseg)
604 segpos[curseg] = spos;
605 spos = segpos[curseg = newseg];
606 seekout(FILEHEADERLENGTH + (unsigned long) spos
607 + (unsigned long) segadj[curseg]);
611 PRIVATE void skip(countsize)
612 unsigned countsize;
614 writenulls((bin_off_t) readsize(countsize));
617 #ifndef MSDOS
618 PRIVATE void cpm86header()
620 struct cpm86_exec header;
621 memset(&header, 0, sizeof header);
623 if (sepid)
625 header.ce_group[0].cg_type = CG_CODE;
626 u2c2(header.ce_group[0].cg_len, (15 + etextpadoff) / 16);
627 u2c2(header.ce_group[0].cg_min, (15 + etextpadoff) / 16);
628 header.ce_group[1].cg_type = CG_DATA;
629 u2c2(header.ce_group[1].cg_len, (15 + edataoffset) / 16);
630 u2c2(header.ce_group[1].cg_min, (15 + endoffset ) / 16);
631 u2c2(header.ce_group[1].cg_max, 0x1000);
633 else
635 header.ce_group[0].cg_type = CG_CODE;
636 u2c2(header.ce_group[0].cg_len, (15 + edataoffset) / 16);
637 u2c2(header.ce_group[0].cg_min, (15 + endoffset ) / 16);
639 if( FILEHEADERLENGTH )
640 writeout((char *) &header, FILEHEADERLENGTH);
642 #endif
644 PRIVATE void writeheader()
646 struct exec header;
648 memset(&header, 0, sizeof header);
649 header.a_magic[0] = A_MAGIC0;
650 header.a_magic[1] = A_MAGIC1;
651 header.a_flags = sepid ? A_SEP : A_EXEC;
652 if (uzp)
653 header.a_flags |= A_UZP;
654 header.a_cpu = bits32 ? A_I80386 : A_I8086;
655 header.a_hdrlen = FILEHEADERLENGTH;
656 offtocn((char *) &header.a_text, etextpadoff - btextoffset,
657 sizeof header.a_text);
658 offtocn((char *) &header.a_data, edataoffset - bdataoffset,
659 sizeof header.a_data);
660 offtocn((char *) &header.a_bss, endoffset - edataoffset,
661 sizeof header.a_bss);
662 if (uzp)
663 offtocn((char *) &header.a_entry, page_size(),
664 sizeof header.a_entry);
666 offtocn((char *) &header.a_total, (bin_off_t) heap_top_value,
667 sizeof header.a_total);
668 if( FILEHEADERLENGTH )
669 writeout((char *) &header, FILEHEADERLENGTH);
672 PRIVATE void writenulls(count)
673 bin_off_t count;
675 long lcount = count;
676 spos += count;
677 #if 0
678 /* This will only work if we record the highest spos found an seek there
679 * at the end of the generation
682 seekout(FILEHEADERLENGTH + (unsigned long) spos
683 + (unsigned long) segadj[curseg]);
684 return;
686 #endif
687 if( lcount < 0 )
688 fatalerror("org command requires reverse seek");
689 while (count-- > 0)
690 writechar(0);