1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 1996-2017 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34 /*
35 * outas86.c output routines for the Netwide Assembler to produce
36 * Linux as86 (bin86-0.3) object files
37 */
38
39 #include "compiler.h"
40
41 #include "nctype.h"
42
43 #include "nasm.h"
44 #include "nasmlib.h"
45 #include "error.h"
46 #include "saa.h"
47 #include "raa.h"
48 #include "outform.h"
49 #include "outlib.h"
50
51 #ifdef OF_AS86
52
53 struct Piece {
54 struct Piece *next;
55 int type; /* 0 = absolute, 1 = seg, 2 = sym */
56 int32_t offset; /* relative offset */
57 int number; /* symbol/segment number (4=bss) */
58 int32_t bytes; /* size of reloc or of absolute data */
59 bool relative; /* relative address? */
60 };
61
62 struct Symbol {
63 int32_t strpos; /* string table position of name */
64 int flags; /* symbol flags */
65 int segment; /* 4=bss at this point */
66 int32_t value; /* address, or COMMON variable size */
67 };
68
69 /*
70 * Section IDs - used in Piece.number and Symbol.segment.
71 */
72 #define SECT_TEXT 0 /* text section */
73 #define SECT_DATA 3 /* data section */
74 #define SECT_BSS 4 /* bss section */
75
76 /*
77 * Flags used in Symbol.flags.
78 */
79 #define SYM_ENTRY (1<<8)
80 #define SYM_EXPORT (1<<7)
81 #define SYM_IMPORT (1<<6)
82 #define SYM_ABSOLUTE (1<<4)
83
84 struct Section {
85 struct SAA *data;
86 uint32_t datalen, size, len;
87 int32_t index;
88 struct Piece *head, *last, **tail;
89 };
90
91 static struct Section stext, sdata;
92 static uint32_t bsslen;
93 static int32_t bssindex;
94
95 static struct SAA *syms;
96 static uint32_t nsyms;
97
98 static struct RAA *bsym;
99
100 static struct SAA *strs;
101 static size_t strslen;
102
103 static int as86_reloc_size;
104
105 static void as86_write(void);
106 static void as86_write_section(struct Section *, int);
107 static size_t as86_add_string(const char *name);
108 static void as86_sect_write(struct Section *, const uint8_t *,
109 uint32_t);
110
as86_init(void)111 static void as86_init(void)
112 {
113 stext.data = saa_init(1L);
114 stext.datalen = 0L;
115 stext.head = stext.last = NULL;
116 stext.tail = &stext.head;
117 sdata.data = saa_init(1L);
118 sdata.datalen = 0L;
119 sdata.head = sdata.last = NULL;
120 sdata.tail = &sdata.head;
121 bsslen =
122 stext.len = stext.datalen = stext.size =
123 sdata.len = sdata.datalen = sdata.size = 0;
124 stext.index = seg_alloc();
125 sdata.index = seg_alloc();
126 bssindex = seg_alloc();
127 syms = saa_init((int32_t)sizeof(struct Symbol));
128 nsyms = 0;
129 bsym = raa_init();
130 strs = saa_init(1L);
131 strslen = 0;
132
133 /* as86 module name = input file minus extension */
134 as86_add_string(filename_set_extension(inname, ""));
135 }
136
as86_cleanup(void)137 static void as86_cleanup(void)
138 {
139 struct Piece *p;
140
141 as86_write();
142 saa_free(stext.data);
143 while (stext.head) {
144 p = stext.head;
145 stext.head = stext.head->next;
146 nasm_free(p);
147 }
148 saa_free(sdata.data);
149 while (sdata.head) {
150 p = sdata.head;
151 sdata.head = sdata.head->next;
152 nasm_free(p);
153 }
154 saa_free(syms);
155 raa_free(bsym);
156 saa_free(strs);
157 }
158
as86_section_names(char * name,int * bits)159 static int32_t as86_section_names(char *name, int *bits)
160 {
161 /*
162 * Default is 16 bits.
163 */
164 if (!name) {
165 *bits = 16;
166 return stext.index;
167 }
168
169 if (!strcmp(name, ".text"))
170 return stext.index;
171 else if (!strcmp(name, ".data"))
172 return sdata.index;
173 else if (!strcmp(name, ".bss"))
174 return bssindex;
175 else
176 return NO_SEG;
177 }
178
as86_add_string(const char * name)179 static size_t as86_add_string(const char *name)
180 {
181 size_t pos = strslen;
182 size_t length = strlen(name);
183
184 saa_wbytes(strs, name, length + 1);
185 strslen += 1 + length;
186
187 return pos;
188 }
189
as86_deflabel(char * name,int32_t segment,int64_t offset,int is_global,char * special)190 static void as86_deflabel(char *name, int32_t segment, int64_t offset,
191 int is_global, char *special)
192 {
193 bool is_start = false;
194 struct Symbol *sym;
195
196 if (special)
197 nasm_nonfatal("as86 format does not support any"
198 " special symbol types");
199
200
201 if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
202 if (strcmp(name, "..start")) {
203 nasm_nonfatal("unrecognised special symbol `%s'", name);
204 return;
205 } else {
206 is_start = true;
207 }
208 }
209
210 sym = saa_wstruct(syms);
211
212 sym->strpos = as86_add_string(name);
213 sym->flags = 0;
214
215 if (is_start)
216 sym->flags = SYM_ENTRY;
217
218 if (segment == NO_SEG)
219 sym->flags |= SYM_ABSOLUTE, sym->segment = 0;
220 else if (segment == stext.index)
221 sym->segment = SECT_TEXT;
222 else if (segment == sdata.index)
223 sym->segment = SECT_DATA;
224 else if (segment == bssindex)
225 sym->segment = SECT_BSS;
226 else {
227 sym->flags |= SYM_IMPORT;
228 sym->segment = 15;
229 }
230
231 if (is_global == 2)
232 sym->segment = 3; /* already have IMPORT */
233
234 if (is_global && !(sym->flags & SYM_IMPORT))
235 sym->flags |= SYM_EXPORT;
236
237 sym->value = offset;
238
239 /*
240 * define the references from external-symbol segment numbers
241 * to these symbol records.
242 */
243 if (segment != NO_SEG && segment != stext.index &&
244 segment != sdata.index && segment != bssindex)
245 bsym = raa_write(bsym, segment, nsyms);
246
247 nsyms++;
248 }
249
as86_add_piece(struct Section * sect,int type,int32_t offset,int32_t segment,int32_t bytes,int relative)250 static void as86_add_piece(struct Section *sect, int type, int32_t offset,
251 int32_t segment, int32_t bytes, int relative)
252 {
253 struct Piece *p;
254
255 sect->len += bytes;
256
257 if (type == 0 && sect->last && sect->last->type == 0) {
258 sect->last->bytes += bytes;
259 return;
260 }
261
262 p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece));
263 sect->tail = &p->next;
264 p->next = NULL;
265
266 p->type = type;
267 p->offset = offset;
268 p->bytes = bytes;
269 p->relative = relative;
270
271 if (type == 1 && segment == stext.index)
272 p->number = SECT_TEXT;
273 else if (type == 1 && segment == sdata.index)
274 p->number = SECT_DATA;
275 else if (type == 1 && segment == bssindex)
276 p->number = SECT_BSS;
277 else if (type == 1)
278 p->number = raa_read(bsym, segment), p->type = 2;
279 }
280
as86_out(int32_t segto,const void * data,enum out_type type,uint64_t size,int32_t segment,int32_t wrt)281 static void as86_out(int32_t segto, const void *data,
282 enum out_type type, uint64_t size,
283 int32_t segment, int32_t wrt)
284 {
285 struct Section *s;
286 int32_t offset;
287 uint8_t mydata[4], *p;
288
289 if (wrt != NO_SEG) {
290 wrt = NO_SEG; /* continue to do _something_ */
291 nasm_nonfatal("WRT not supported by as86 output format");
292 }
293
294 if (segto == stext.index)
295 s = &stext;
296 else if (segto == sdata.index)
297 s = &sdata;
298 else if (segto == bssindex)
299 s = NULL;
300 else {
301 nasm_warn(WARN_OTHER, "attempt to assemble code in"
302 " segment %d: defaulting to `.text'", segto);
303 s = &stext;
304 }
305
306 if (!s && type != OUT_RESERVE) {
307 nasm_warn(WARN_OTHER, "attempt to initialize memory in the"
308 " BSS section: ignored");
309 bsslen += realsize(type, size);
310 return;
311 }
312
313 memset(mydata, 0, sizeof(mydata));
314
315 if (type == OUT_RESERVE) {
316 if (s) {
317 nasm_warn(WARN_ZEROING, "uninitialized space declared in"
318 " %s section: zeroing",
319 (segto == stext.index ? "code" : "data"));
320 as86_sect_write(s, NULL, size);
321 as86_add_piece(s, 0, 0L, 0L, size, 0);
322 } else
323 bsslen += size;
324 } else if (type == OUT_RAWDATA) {
325 as86_sect_write(s, data, size);
326 as86_add_piece(s, 0, 0L, 0L, size, 0);
327 } else if (type == OUT_ADDRESS) {
328 int asize = abs((int)size);
329 if (segment != NO_SEG) {
330 if (segment % 2) {
331 nasm_nonfatal("as86 format does not support"
332 " segment base references");
333 } else {
334 offset = *(int64_t *)data;
335 as86_add_piece(s, 1, offset, segment, asize, 0);
336 }
337 } else {
338 p = mydata;
339 WRITELONG(p, *(int64_t *)data);
340 as86_sect_write(s, data, asize);
341 as86_add_piece(s, 0, 0L, 0L, asize, 0);
342 }
343 } else if (type == OUT_REL2ADR) {
344 if (segment != NO_SEG) {
345 if (segment % 2) {
346 nasm_nonfatal("as86 format does not support"
347 " segment base references");
348 } else {
349 offset = *(int64_t *)data;
350 as86_add_piece(s, 1, offset - size + 2, segment, 2L,
351 1);
352 }
353 }
354 } else if (type == OUT_REL4ADR) {
355 if (segment != NO_SEG) {
356 if (segment % 2) {
357 nasm_nonfatal("as86 format does not support"
358 " segment base references");
359 } else {
360 offset = *(int64_t *)data;
361 as86_add_piece(s, 1, offset - size + 4, segment, 4L,
362 1);
363 }
364 }
365 }
366 }
367
as86_write(void)368 static void as86_write(void)
369 {
370 uint32_t i;
371 int32_t symlen, seglen, segsize;
372
373 /*
374 * First, go through the symbol records working out how big
375 * each will be. Also fix up BSS references at this time, and
376 * set the flags words up completely.
377 */
378 symlen = 0;
379 saa_rewind(syms);
380 for (i = 0; i < nsyms; i++) {
381 struct Symbol *sym = saa_rstruct(syms);
382 if (sym->segment == SECT_BSS)
383 sym->segment = SECT_DATA, sym->value += sdata.len;
384 sym->flags |= sym->segment;
385 if (sym->value == 0)
386 sym->flags |= 0 << 14, symlen += 4;
387 else if (sym->value >= 0 && sym->value <= 255)
388 sym->flags |= 1 << 14, symlen += 5;
389 else if (sym->value >= 0 && sym->value <= 65535L)
390 sym->flags |= 2 << 14, symlen += 6;
391 else
392 sym->flags |= 3 << 14, symlen += 8;
393 }
394
395 /*
396 * Now do the same for the segments, and get the segment size
397 * descriptor word at the same time.
398 */
399 seglen = segsize = 0;
400 if ((uint32_t)stext.len > 65535L)
401 segsize |= 0x03000000L, seglen += 4;
402 else
403 segsize |= 0x02000000L, seglen += 2;
404 if ((uint32_t)sdata.len > 65535L)
405 segsize |= 0xC0000000L, seglen += 4;
406 else
407 segsize |= 0x80000000L, seglen += 2;
408
409 /*
410 * Emit the as86 header.
411 */
412 fwriteint32_t(0x000186A3L, ofile);
413 fputc(0x2A, ofile);
414 fwriteint32_t(27 + symlen + seglen + strslen, ofile); /* header length */
415 fwriteint32_t(stext.len + sdata.len + bsslen, ofile);
416 fwriteint16_t(strslen, ofile);
417 fwriteint16_t(0, ofile); /* class = revision = 0 */
418 fwriteint32_t(0x55555555L, ofile); /* segment max sizes: always this */
419 fwriteint32_t(segsize, ofile); /* segment size descriptors */
420 if (segsize & 0x01000000L)
421 fwriteint32_t(stext.len, ofile);
422 else
423 fwriteint16_t(stext.len, ofile);
424 if (segsize & 0x40000000L)
425 fwriteint32_t(sdata.len + bsslen, ofile);
426 else
427 fwriteint16_t(sdata.len + bsslen, ofile);
428 fwriteint16_t(nsyms, ofile);
429
430 /*
431 * Write the symbol table.
432 */
433 saa_rewind(syms);
434 for (i = 0; i < nsyms; i++) {
435 struct Symbol *sym = saa_rstruct(syms);
436 fwriteint16_t(sym->strpos, ofile);
437 fwriteint16_t(sym->flags, ofile);
438 switch (sym->flags & (3 << 14)) {
439 case 0 << 14:
440 break;
441 case 1 << 14:
442 fputc(sym->value, ofile);
443 break;
444 case 2 << 14:
445 fwriteint16_t(sym->value, ofile);
446 break;
447 case 3 << 14:
448 fwriteint32_t(sym->value, ofile);
449 break;
450 }
451 }
452
453 /*
454 * Write out the string table.
455 */
456 saa_fpwrite(strs, ofile);
457
458 /*
459 * Write the program text.
460 */
461 as86_reloc_size = -1;
462 as86_write_section(&stext, SECT_TEXT);
463 as86_write_section(&sdata, SECT_DATA);
464 /*
465 * Append the BSS section to the .data section
466 */
467 if (bsslen > 65535L) {
468 fputc(0x13, ofile);
469 fwriteint32_t(bsslen, ofile);
470 } else if (bsslen > 255) {
471 fputc(0x12, ofile);
472 fwriteint16_t(bsslen, ofile);
473 } else if (bsslen) {
474 fputc(0x11, ofile);
475 fputc(bsslen, ofile);
476 }
477
478 fputc(0, ofile); /* termination */
479 }
480
as86_set_rsize(int size)481 static void as86_set_rsize(int size)
482 {
483 if (as86_reloc_size != size) {
484 switch (as86_reloc_size = size) {
485 case 1:
486 fputc(0x01, ofile);
487 break;
488 case 2:
489 fputc(0x02, ofile);
490 break;
491 case 4:
492 fputc(0x03, ofile);
493 break;
494 default:
495 nasm_panic("bizarre relocation size %d", size);
496 break;
497 }
498 }
499 }
500
as86_write_section(struct Section * sect,int index)501 static void as86_write_section(struct Section *sect, int index)
502 {
503 struct Piece *p;
504 uint32_t s;
505 int32_t length;
506
507 fputc(0x20 + index, ofile); /* select the right section */
508
509 saa_rewind(sect->data);
510
511 for (p = sect->head; p; p = p->next)
512 switch (p->type) {
513 case 0:
514 /*
515 * Absolute data. Emit it in chunks of at most 64
516 * bytes.
517 */
518 length = p->bytes;
519 do {
520 char buf[64];
521 int32_t tmplen = (length > 64 ? 64 : length);
522 fputc(0x40 | (tmplen & 0x3F), ofile);
523 saa_rnbytes(sect->data, buf, tmplen);
524 nasm_write(buf, tmplen, ofile);
525 length -= tmplen;
526 } while (length > 0);
527 break;
528 case 1:
529 /*
530 * A segment-type relocation. First fix up the BSS.
531 */
532 if (p->number == SECT_BSS)
533 p->number = SECT_DATA, p->offset += sdata.len;
534 as86_set_rsize(p->bytes);
535 fputc(0x80 | (p->relative ? 0x20 : 0) | p->number, ofile);
536 if (as86_reloc_size == 2)
537 fwriteint16_t(p->offset, ofile);
538 else
539 fwriteint32_t(p->offset, ofile);
540 break;
541 case 2:
542 /*
543 * A symbol-type relocation.
544 */
545 as86_set_rsize(p->bytes);
546 s = p->offset;
547 if (s > 65535L)
548 s = 3;
549 else if (s > 255)
550 s = 2;
551 else if (s > 0)
552 s = 1;
553 else
554 s = 0;
555 fputc(0xC0 |
556 (p->relative ? 0x20 : 0) |
557 (p->number > 255 ? 0x04 : 0) | s, ofile);
558 if (p->number > 255)
559 fwriteint16_t(p->number, ofile);
560 else
561 fputc(p->number, ofile);
562 switch (s) {
563 case 0:
564 break;
565 case 1:
566 fputc(p->offset, ofile);
567 break;
568 case 2:
569 fwriteint16_t(p->offset, ofile);
570 break;
571 case 3:
572 fwriteint32_t(p->offset, ofile);
573 break;
574 }
575 break;
576 }
577 }
578
as86_sect_write(struct Section * sect,const uint8_t * data,uint32_t len)579 static void as86_sect_write(struct Section *sect,
580 const uint8_t *data, uint32_t len)
581 {
582 saa_wbytes(sect->data, data, len);
583 sect->datalen += len;
584 }
585
586 extern macros_t as86_stdmac[];
587
588 const struct ofmt of_as86 = {
589 "as86 (bin86/dev86 toolchain)",
590 "as86",
591 ".o",
592 0,
593 32,
594 null_debug_arr,
595 &null_debug_form,
596 as86_stdmac,
597 as86_init,
598 null_reset,
599 nasm_do_legacy_output,
600 as86_out,
601 as86_deflabel,
602 as86_section_names,
603 NULL,
604 null_sectalign,
605 null_segbase,
606 null_directive,
607 as86_cleanup,
608 NULL /* pragma list */
609 };
610
611 #endif /* OF_AS86 */
612