static void aout_write_syms (void) { unsigned long i; saa_rewind (syms); for (i = 0; i < nsyms; i++) { struct Symbol *sym = saa_rstruct(syms); fwritelong (sym->strpos, aoutfp); fwritelong ((long)sym->type & ~SYM_WITH_SIZE, aoutfp); /* * Fix up the symbol value now we know the final section * sizes. */ if ((sym->type & SECT_MASK) == SECT_DATA) sym->value += stext.len; if ((sym->type & SECT_MASK) == SECT_BSS) sym->value += stext.len + sdata.len; fwritelong (sym->value, aoutfp); /* * Output a size record if necessary. */ if (sym->type & SYM_WITH_SIZE) { fwritelong(sym->strpos, aoutfp); fwritelong(0x0DL, aoutfp); /* special value: means size */ fwritelong(sym->size, aoutfp); i++; /* use up another of `nsyms' */ } } }
/* * a.out files have the curious property that all references to * things in the data or bss sections are done by addresses which * are actually relative to the start of the _text_ section, in the * _file_. (No relation to what happens after linking. No idea why * this should be so. It's very strange.) So we have to go through * the relocation table, _after_ the final size of each section is * known, and fix up the relocations pointed to. */ static void aout_fixup_relocs(struct Section *sect) { struct Reloc *r; saa_rewind (sect->data); for (r = sect->head; r; r = r->next) { unsigned char *p, *q, blk[4]; long l; saa_fread (sect->data, r->address, blk, (long)r->bytes); p = q = blk; l = *p++; if (r->bytes > 1) { l += ((long)*p++) << 8; if (r->bytes == 4) { l += ((long)*p++) << 16; l += ((long)*p++) << 24; } } if (r->symbol == -SECT_DATA) l += stext.len; else if (r->symbol == -SECT_BSS) l += stext.len + sdata.len; if (r->bytes == 4) WRITELONG(q, l); else if (r->bytes == 2) WRITESHORT(q, l); else *q++ = l & 0xFF; saa_fwrite (sect->data, r->address, blk, (long)r->bytes); } }
static void coff_write_symbols (void) { char filename[18]; int i; /* * The `.file' record, and the file name auxiliary record. */ coff_symbol (".file", 0L, 0L, -2, 0x67, 1); memset (filename, 0, 18); strncpy (filename, coff_infile, 18); fwrite (filename, 18, 1, coffp); /* * The section records, with their auxiliaries. */ memset (filename, 0, 18); /* useful zeroed buffer */ for (i=0; i<nsects; i++) { coff_symbol (sects[i]->name, 0L, 0L, i+1, 3, 1); fwritelong (sects[i]->len, coffp); fwriteshort (sects[i]->nrelocs, coffp); fwrite (filename, 12, 1, coffp); } /* * The absolute symbol, for relative-to-absolute relocations. */ coff_symbol (".absolut", 0L, 0L, -1, 3, 0); /* * The real symbols. */ saa_rewind (syms); for (i=0; i<nsyms; i++) { struct Symbol *sym = saa_rstruct (syms); coff_symbol (sym->strpos == -1 ? sym->name : NULL, sym->strpos, sym->value, sym->section, sym->is_global ? 2 : 3, 0); } }
static struct SAA *elf_build_symtab(long *len, long *local) { struct SAA *s = saa_init(1L); struct Symbol *sym; unsigned char entry[16], *p; int i; *len = *local = 0; /* * First, an all-zeros entry, required by the ELF spec. */ saa_wbytes(s, NULL, 16L); /* null symbol table entry */ *len += 16; (*local)++; /* * Next, an entry for the file name. */ p = entry; WRITELONG(p, 1); /* we know it's 1st thing in strtab */ WRITELONG(p, 0); /* no value */ WRITELONG(p, 0); /* no size either */ WRITESHORT(p, 4); /* type FILE */ WRITESHORT(p, SHN_ABS); saa_wbytes(s, entry, 16L); *len += 16; (*local)++; /* * Now some standard symbols defining the segments, for relocation * purposes. */ for (i = 1; i <= nsects + 1; i++) { p = entry; WRITELONG(p, 0); /* no symbol name */ WRITELONG(p, 0); /* offset zero */ WRITELONG(p, 0); /* size zero */ WRITESHORT(p, 3); /* local section-type thing */ WRITESHORT(p, (i == 1 ? SHN_ABS : i - 1)); /* the section id */ saa_wbytes(s, entry, 16L); *len += 16; (*local)++; } /* * Now the other local symbols. */ saa_rewind(syms); while ((sym = saa_rstruct(syms))) { if (sym->type & SYM_GLOBAL) continue; p = entry; WRITELONG(p, sym->strpos); WRITELONG(p, sym->value); WRITELONG(p, sym->size); WRITESHORT(p, sym->type); /* local non-typed thing */ WRITESHORT(p, sym->section); saa_wbytes(s, entry, 16L); *len += 16; (*local)++; } /* * Now the global symbols. */ saa_rewind(syms); while ((sym = saa_rstruct(syms))) { if (!(sym->type & SYM_GLOBAL)) continue; p = entry; WRITELONG(p, sym->strpos); WRITELONG(p, sym->value); WRITELONG(p, sym->size); WRITESHORT(p, sym->type); /* global non-typed thing */ WRITESHORT(p, sym->section); saa_wbytes(s, entry, 16L); *len += 16; } return s; }
static void as86_write_section(struct Section *sect, int index) { struct Piece *p; uint32_t s; int32_t length; fputc(0x20 + index, ofile); /* select the right section */ saa_rewind(sect->data); for (p = sect->head; p; p = p->next) switch (p->type) { case 0: /* * Absolute data. Emit it in chunks of at most 64 * bytes. */ length = p->bytes; do { char buf[64]; int32_t tmplen = (length > 64 ? 64 : length); fputc(0x40 | (tmplen & 0x3F), ofile); saa_rnbytes(sect->data, buf, tmplen); nasm_write(buf, tmplen, ofile); length -= tmplen; } while (length > 0); break; case 1: /* * A segment-type relocation. First fix up the BSS. */ if (p->number == SECT_BSS) p->number = SECT_DATA, p->offset += sdata.len; as86_set_rsize(p->bytes); fputc(0x80 | (p->relative ? 0x20 : 0) | p->number, ofile); if (as86_reloc_size == 2) fwriteint16_t(p->offset, ofile); else fwriteint32_t(p->offset, ofile); break; case 2: /* * A symbol-type relocation. */ as86_set_rsize(p->bytes); s = p->offset; if (s > 65535L) s = 3; else if (s > 255) s = 2; else if (s > 0) s = 1; else s = 0; fputc(0xC0 | (p->relative ? 0x20 : 0) | (p->number > 255 ? 0x04 : 0) | s, ofile); if (p->number > 255) fwriteint16_t(p->number, ofile); else fputc(p->number, ofile); switch (s) { case 0: break; case 1: fputc(p->offset, ofile); break; case 2: fwriteint16_t(p->offset, ofile); break; case 3: fwriteint32_t(p->offset, ofile); break; } break; } }
static void as86_write(void) { uint32_t i; int32_t symlen, seglen, segsize; /* * First, go through the symbol records working out how big * each will be. Also fix up BSS references at this time, and * set the flags words up completely. */ symlen = 0; saa_rewind(syms); for (i = 0; i < nsyms; i++) { struct Symbol *sym = saa_rstruct(syms); if (sym->segment == SECT_BSS) sym->segment = SECT_DATA, sym->value += sdata.len; sym->flags |= sym->segment; if (sym->value == 0) sym->flags |= 0 << 14, symlen += 4; else if (sym->value >= 0 && sym->value <= 255) sym->flags |= 1 << 14, symlen += 5; else if (sym->value >= 0 && sym->value <= 65535L) sym->flags |= 2 << 14, symlen += 6; else sym->flags |= 3 << 14, symlen += 8; } /* * Now do the same for the segments, and get the segment size * descriptor word at the same time. */ seglen = segsize = 0; if ((uint32_t)stext.len > 65535L) segsize |= 0x03000000L, seglen += 4; else segsize |= 0x02000000L, seglen += 2; if ((uint32_t)sdata.len > 65535L) segsize |= 0xC0000000L, seglen += 4; else segsize |= 0x80000000L, seglen += 2; /* * Emit the as86 header. */ fwriteint32_t(0x000186A3L, ofile); fputc(0x2A, ofile); fwriteint32_t(27 + symlen + seglen + strslen, ofile); /* header length */ fwriteint32_t(stext.len + sdata.len + bsslen, ofile); fwriteint16_t(strslen, ofile); fwriteint16_t(0, ofile); /* class = revision = 0 */ fwriteint32_t(0x55555555L, ofile); /* segment max sizes: always this */ fwriteint32_t(segsize, ofile); /* segment size descriptors */ if (segsize & 0x01000000L) fwriteint32_t(stext.len, ofile); else fwriteint16_t(stext.len, ofile); if (segsize & 0x40000000L) fwriteint32_t(sdata.len + bsslen, ofile); else fwriteint16_t(sdata.len + bsslen, ofile); fwriteint16_t(nsyms, ofile); /* * Write the symbol table. */ saa_rewind(syms); for (i = 0; i < nsyms; i++) { struct Symbol *sym = saa_rstruct(syms); fwriteint16_t(sym->strpos, ofile); fwriteint16_t(sym->flags, ofile); switch (sym->flags & (3 << 14)) { case 0 << 14: break; case 1 << 14: fputc(sym->value, ofile); break; case 2 << 14: fwriteint16_t(sym->value, ofile); break; case 3 << 14: fwriteint32_t(sym->value, ofile); break; } } /* * Write out the string table. */ saa_fpwrite(strs, ofile); /* * Write the program text. */ as86_reloc_size = -1; as86_write_section(&stext, SECT_TEXT); as86_write_section(&sdata, SECT_DATA); /* * Append the BSS section to the .data section */ if (bsslen > 65535L) { fputc(0x13, ofile); fwriteint32_t(bsslen, ofile); } else if (bsslen > 255) { fputc(0x12, ofile); fwriteint16_t(bsslen, ofile); } else if (bsslen) { fputc(0x11, ofile); fputc(bsslen, ofile); } fputc(0, ofile); /* termination */ }