From e2c80181b6a6338f0381fc9c44fae32d8b8a20fc Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sat, 15 Jan 2005 22:15:51 +0000 Subject: [PATCH] Apply Nindent to all .c and .h files --- assemble.c | 3289 +++++++++++---------- assemble.h | 10 +- disasm.c | 1653 ++++++----- disasm.h | 8 +- eval.c | 1627 +++++----- eval.h | 9 +- float.c | 809 ++--- float.h | 4 +- insns.h | 198 +- labels.c | 310 +- labels.h | 46 +- lcc/bind.c | 46 +- lcc/lin-aout.c | 50 +- lcc/lin-elf.c | 52 +- listing.c | 559 ++-- listing.h | 2 +- names.c | 2 +- nasm.c | 3402 ++++++++++----------- nasm.h | 289 +- nasmlib.c | 2259 +++++++------- nasmlib.h | 90 +- ndisasm.c | 663 +++-- outform.c | 54 +- outform.h | 20 +- output/outaout.c | 918 +++--- output/outas86.c | 1234 ++++---- output/outbin.c | 2751 ++++++++--------- output/outcoff.c | 817 ++--- output/outdbg.c | 501 ++-- output/outelf.c | 2997 +++++++++---------- output/outieee.c | 1624 +++++----- output/outobj.c | 5098 ++++++++++++++++---------------- output/outrdf.c | 1090 +++---- output/outrdf2.c | 1552 +++++----- parser.c | 1560 +++++----- parser.h | 8 +- preproc.c | 8684 ++++++++++++++++++++++++++---------------------------- preproc.h | 12 +- rdoff/collectn.c | 20 +- rdoff/collectn.h | 10 +- rdoff/hash.c | 188 +- rdoff/hash.h | 3 +- rdoff/ldrdf.c | 2625 +++++++++-------- rdoff/ldsegs.h | 15 +- rdoff/rdf2bin.c | 271 +- rdoff/rdf2ihx.c | 380 +-- rdoff/rdfdump.c | 615 ++-- rdoff/rdflib.c | 797 +++-- rdoff/rdfload.c | 365 +-- rdoff/rdfload.h | 14 +- rdoff/rdlar.c | 924 +++--- rdoff/rdlar.h | 60 +- rdoff/rdlib.c | 529 ++-- rdoff/rdlib.h | 51 +- rdoff/rdoff.c | 517 ++-- rdoff/rdoff.h | 183 +- rdoff/rdx.c | 35 +- rdoff/segtab.c | 282 +- rdoff/segtab.h | 4 +- rdoff/symtab.c | 257 +- rdoff/symtab.h | 16 +- sync.c | 84 +- test/aouttest.c | 10 +- test/cofftest.c | 10 +- test/elftest.c | 10 +- test/objlink.c | 7 +- 66 files changed, 26426 insertions(+), 26153 deletions(-) rewrite assemble.c (83%) rewrite disasm.c (84%) rewrite eval.c (71%) rewrite float.c (70%) rewrite insns.h (61%) rewrite labels.h (63%) rewrite lcc/bind.c (89%) rewrite listing.c (61%) rewrite nasm.c (78%) rewrite nasmlib.c (61%) rewrite ndisasm.c (78%) rewrite output/outas86.c (63%) rewrite output/outbin.c (86%) rewrite output/outdbg.c (63%) rewrite output/outelf.c (74%) rewrite output/outobj.c (63%) rewrite output/outrdf.c (78%) rewrite output/outrdf2.c (72%) rewrite parser.c (89%) rewrite preproc.c (69%) rewrite rdoff/hash.c (89%) rewrite rdoff/ldrdf.c (67%) rewrite rdoff/rdf2bin.c (70%) rewrite rdoff/rdf2ihx.c (89%) rewrite rdoff/rdfdump.c (80%) rewrite rdoff/rdflib.c (75%) rewrite rdoff/rdfload.c (63%) rewrite rdoff/rdlar.c (69%) rewrite rdoff/rdlar.h (61%) rewrite rdoff/rdlib.c (79%) rewrite rdoff/rdlib.h (61%) rewrite rdoff/segtab.c (65%) rewrite rdoff/symtab.c (67%) diff --git a/assemble.c b/assemble.c dissimilarity index 83% index 8a6bd0d2..3a610411 100644 --- a/assemble.c +++ b/assemble.c @@ -1,1526 +1,1763 @@ -/* assemble.c code generation for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * the actual codes (C syntax, i.e. octal): - * \0 - terminates the code. (Unless it's a literal of course.) - * \1, \2, \3 - that many literal bytes follow in the code stream - * \4, \6 - the POP/PUSH (respectively) codes for CS, DS, ES, SS - * (POP is never used for CS) depending on operand 0 - * \5, \7 - the second byte of POP/PUSH codes for FS, GS, depending - * on operand 0 - * \10, \11, \12 - a literal byte follows in the code stream, to be added - * to the register value of operand 0, 1 or 2 - * \17 - encodes the literal byte 0. (Some compilers don't take - * kindly to a zero byte in the _middle_ of a compile time - * string constant, so I had to put this hack in.) - * \14, \15, \16 - a signed byte immediate operand, from operand 0, 1 or 2 - * \20, \21, \22 - a byte immediate operand, from operand 0, 1 or 2 - * \24, \25, \26 - an unsigned byte immediate operand, from operand 0, 1 or 2 - * \30, \31, \32 - a word immediate operand, from operand 0, 1 or 2 - * \34, \35, \36 - select between \3[012] and \4[012] depending on 16/32 bit - * assembly mode or the operand-size override on the operand - * \37 - a word constant, from the _segment_ part of operand 0 - * \40, \41, \42 - a long immediate operand, from operand 0, 1 or 2 - * \44, \45, \46 - select between \3[012] and \4[012] depending on 16/32 bit - * assembly mode or the address-size override on the operand - * \50, \51, \52 - a byte relative operand, from operand 0, 1 or 2 - * \60, \61, \62 - a word relative operand, from operand 0, 1 or 2 - * \64, \65, \66 - select between \6[012] and \7[012] depending on 16/32 bit - * assembly mode or the operand-size override on the operand - * \70, \71, \72 - a long relative operand, from operand 0, 1 or 2 - * \1ab - a ModRM, calculated on EA in operand a, with the spare - * field the register value of operand b. - * \130,\131,\132 - an immediate word or signed byte for operand 0, 1, or 2 - * \133,\134,\135 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2 - * is a signed byte rather than a word. - * \140,\141,\142 - an immediate dword or signed byte for operand 0, 1, or 2 - * \143,\144,\145 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2 - * is a signed byte rather than a dword. - * \2ab - a ModRM, calculated on EA in operand a, with the spare - * field equal to digit b. - * \30x - might be an 0x67 byte, depending on the address size of - * the memory reference in operand x. - * \310 - indicates fixed 16-bit address size, i.e. optional 0x67. - * \311 - indicates fixed 32-bit address size, i.e. optional 0x67. - * \312 - (disassembler only) marker on LOOP, LOOPxx instructions. - * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66. - * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66. - * \322 - indicates that this instruction is only valid when the - * operand size is the default (instruction to disassembler, - * generates no code in the assembler) - * \330 - a literal byte follows in the code stream, to be added - * to the condition code value of the instruction. - * \331 - instruction not valid with REP prefix. Hint for - * disassembler only; for SSE instructions. - * \332 - disassemble a rep (0xF3 byte) prefix as repe not rep. - * \333 - REP prefix (0xF3 byte); for SSE instructions. Not encoded - * as a literal byte in order to aid the disassembler. - * \340 - reserve bytes of uninitialised storage. - * Operand 0 had better be a segmentless constant. - * \370,\371,\372 - match only if operand 0 meets byte jump criteria. - * 370 is used for Jcc, 371 is used for JMP. - * \373 - assemble 0x03 if bits==16, 0x05 if bits==32; - * used for conditional jump over longer jump - */ - -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "assemble.h" -#include "insns.h" -#include "preproc.h" - -extern struct itemplate *nasm_instructions[]; - -typedef struct { - int sib_present; /* is a SIB byte necessary? */ - int bytes; /* # of bytes of offset needed */ - int size; /* lazy - this is sib+bytes+1 */ - unsigned char modrm, sib; /* the bytes themselves */ -} ea; - -static unsigned long cpu; /* cpu level received from nasm.c */ -static efunc errfunc; -static struct ofmt *outfmt; -static ListGen *list; - -static long calcsize (long, long, int, insn *, const char *); -static void gencode (long, long, int, insn *, const char *, long); -static int regval (operand *o); -static int matches (struct itemplate *, insn *); -static ea * process_ea (operand *, ea *, int, int, int); -static int chsize (operand *, int); - -/* - * This routine wrappers the real output format's output routine, - * in order to pass a copy of the data off to the listing file - * generator at the same time. - */ -static void out (long offset, long segto, const void *data, unsigned long type, - long segment, long wrt) -{ - static long lineno = 0; /* static!!! */ - static char *lnfname = NULL; - - if ((type & OUT_TYPMASK) == OUT_ADDRESS) { - if (segment != NO_SEG || wrt != NO_SEG) { - /* - * This address is relocated. We must write it as - * OUT_ADDRESS, so there's no work to be done here. - */ - list->output (offset, data, type); - } - else { - unsigned char p[4], *q = p; - /* - * This is a non-relocated address, and we're going to - * convert it into RAWDATA format. - */ - if ((type & OUT_SIZMASK) == 4) { - WRITELONG (q, * (long *) data); - list->output (offset, p, OUT_RAWDATA+4); - } - else { - WRITESHORT (q, * (long *) data); - list->output (offset, p, OUT_RAWDATA+2); - } - } - } - else if ((type & OUT_TYPMASK) == OUT_RAWDATA) { - list->output (offset, data, type); - } - else if ((type & OUT_TYPMASK) == OUT_RESERVE) { - list->output (offset, NULL, type); - } - else if ((type & OUT_TYPMASK) == OUT_REL2ADR || - (type & OUT_TYPMASK) == OUT_REL4ADR) { - list->output (offset, data, type); - } - - /* - * this call to src_get determines when we call the - * debug-format-specific "linenum" function - * it updates lineno and lnfname to the current values - * returning 0 if "same as last time", -2 if lnfname - * changed, and the amount by which lineno changed, - * if it did. thus, these variables must be static - */ - - if (src_get(&lineno,&lnfname)) - { - outfmt->current_dfmt->linenum(lnfname,lineno,segto); - } - - outfmt->output (segto, data, type, segment, wrt); -} - -static int jmp_match (long segment, long offset, int bits, - insn *ins, const char *code) -{ long isize; - unsigned char c = code[0]; - - - if (c != 0370 && c != 0371) return 0; - if (ins->oprs[0].opflags & OPFLAG_FORWARD) { - if ((optimizing<0 || (ins->oprs[0].type & STRICT)) - && c==0370) return 1; - else return (pass0==0); /* match a forward reference */ - } - isize = calcsize (segment, offset, bits, ins, code); - if (ins->oprs[0].segment != segment) return 0; - isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */ - if (isize >= -128L && isize <= 127L) return 1; /* it is byte size */ - - return 0; -} - - -long assemble (long segment, long offset, int bits, unsigned long cp, - insn *instruction, struct ofmt *output, efunc error, - ListGen *listgen) -{ - struct itemplate *temp; - int j; - int size_prob; - long insn_end; - long itimes; - long start = offset; - long wsize = 0; /* size for DB etc. */ - - errfunc = error; /* to pass to other functions */ - cpu = cp; - outfmt = output; /* likewise */ - list = listgen; /* and again */ - - switch (instruction->opcode) - { - case -1: return 0; - case I_DB: wsize = 1; break; - case I_DW: wsize = 2; break; - case I_DD: wsize = 4; break; - case I_DQ: wsize = 8; break; - case I_DT: wsize = 10; break; - } - - if (wsize) { - extop * e; - long t = instruction->times; - if (t < 0) - errfunc(ERR_PANIC, "instruction->times < 0 (%ld) in assemble()",t); - - while (t--) /* repeat TIMES times */ - { - for (e = instruction->eops; e; e = e->next) - { - if (e->type == EOT_DB_NUMBER) - { - if (wsize == 1) { - if (e->segment != NO_SEG) - errfunc (ERR_NONFATAL, - "one-byte relocation attempted"); - else { - unsigned char out_byte = e->offset; - out (offset, segment, &out_byte, OUT_RAWDATA+1, - NO_SEG, NO_SEG); - } - } - else if (wsize > 5) { - errfunc (ERR_NONFATAL, "integer supplied to a D%c" - " instruction", wsize==8 ? 'Q' : 'T'); - } - else - out (offset, segment, &e->offset, - OUT_ADDRESS+wsize, e->segment, - e->wrt); - offset += wsize; - } - else if (e->type == EOT_DB_STRING) - { - int align; - - out (offset, segment, e->stringval, - OUT_RAWDATA+e->stringlen, NO_SEG, NO_SEG); - align = e->stringlen % wsize; - - if (align) { - align = wsize - align; - out (offset, segment, "\0\0\0\0\0\0\0\0", - OUT_RAWDATA+align, NO_SEG, NO_SEG); - } - offset += e->stringlen + align; - } - } - if (t > 0 && t == instruction->times-1) - { - /* - * Dummy call to list->output to give the offset to the - * listing module. - */ - list->output (offset, NULL, OUT_RAWDATA); - list->uplevel (LIST_TIMES); - } - } - if (instruction->times > 1) - list->downlevel (LIST_TIMES); - return offset - start; - } - - if (instruction->opcode == I_INCBIN) - { - static char fname[FILENAME_MAX]; - FILE * fp; - long len; - char *prefix = "", *combine; - char** pPrevPath = NULL; - - len = FILENAME_MAX-1; - if (len > instruction->eops->stringlen) - len = instruction->eops->stringlen; - strncpy (fname, instruction->eops->stringval, len); - fname[len] = '\0'; - - while (1) /* added by alexfru: 'incbin' uses include paths */ - { - combine = nasm_malloc(strlen(prefix) + len + 1); - strcpy(combine, prefix); - strcat(combine, fname); - - if ( (fp = fopen(combine, "rb")) != NULL) - { - nasm_free(combine); - break; - } - - nasm_free(combine); - pPrevPath = pp_get_include_path_ptr (pPrevPath); - if (pPrevPath == NULL) - break; - prefix = *pPrevPath; - } - - if (fp == NULL) - error (ERR_NONFATAL, "`incbin': unable to open file `%s'", fname); - else if (fseek(fp, 0L, SEEK_END) < 0) - error (ERR_NONFATAL, "`incbin': unable to seek on file `%s'", - fname); - else - { - static char buf[2048]; - long t = instruction->times; - long base = 0; - - len = ftell (fp); - if (instruction->eops->next) { - base = instruction->eops->next->offset; - len -= base; - if (instruction->eops->next->next && - len > instruction->eops->next->next->offset) - len = instruction->eops->next->next->offset; - } - /* - * Dummy call to list->output to give the offset to the - * listing module. - */ - list->output (offset, NULL, OUT_RAWDATA); - list->uplevel(LIST_INCBIN); - while (t--) - { - long l; - - fseek (fp, base, SEEK_SET); - l = len; - while (l > 0) { - long m = fread (buf, 1, (l>sizeof(buf)?sizeof(buf):l), - fp); - if (!m) { - /* - * This shouldn't happen unless the file - * actually changes while we are reading - * it. - */ - error (ERR_NONFATAL, "`incbin': unexpected EOF while" - " reading file `%s'", fname); - t=0; /* Try to exit cleanly */ - break; - } - out (offset, segment, buf, OUT_RAWDATA+m, - NO_SEG, NO_SEG); - l -= m; - } - } - list->downlevel(LIST_INCBIN); - if (instruction->times > 1) { - /* - * Dummy call to list->output to give the offset to the - * listing module. - */ - list->output (offset, NULL, OUT_RAWDATA); - list->uplevel(LIST_TIMES); - list->downlevel(LIST_TIMES); - } - fclose (fp); - return instruction->times * len; - } - return 0; /* if we're here, there's an error */ - } - - size_prob = FALSE; - temp = nasm_instructions[instruction->opcode]; - while (temp->opcode != -1) { - int m = matches (temp, instruction); - if (m == 99) - m += jmp_match(segment, offset, bits, instruction, temp->code); - - if (m == 100) /* matches! */ - { - const char *codes = temp->code; - long insn_size = calcsize(segment, offset, bits, - instruction, codes); - itimes = instruction->times; - if (insn_size < 0) /* shouldn't be, on pass two */ - error (ERR_PANIC, "errors made it through from pass one"); - else while (itimes--) { - for (j=0; jnprefix; j++) { - unsigned char c=0; - switch (instruction->prefixes[j]) { - case P_LOCK: - c = 0xF0; break; - case P_REPNE: case P_REPNZ: - c = 0xF2; break; - case P_REPE: case P_REPZ: case P_REP: - c = 0xF3; break; - case R_CS: c = 0x2E; break; - case R_DS: c = 0x3E; break; - case R_ES: c = 0x26; break; - case R_FS: c = 0x64; break; - case R_GS: c = 0x65; break; - case R_SS: c = 0x36; break; - case R_SEGR6: - case R_SEGR7: - error (ERR_NONFATAL, "segr6 and segr7 cannot be used as prefixes"); - break; - case P_A16: - if (bits != 16) - c = 0x67; - break; - case P_A32: - if (bits != 32) - c = 0x67; - break; - case P_O16: - if (bits != 16) - c = 0x66; - break; - case P_O32: - if (bits != 32) - c = 0x66; - break; - default: - error (ERR_PANIC, - "invalid instruction prefix"); - } - if (c != 0) { - out (offset, segment, &c, OUT_RAWDATA+1, - NO_SEG, NO_SEG); - offset++; - } - } - insn_end = offset + insn_size; - gencode (segment, offset, bits, instruction, codes, insn_end); - offset += insn_size; - if (itimes > 0 && itimes == instruction->times-1) { - /* - * Dummy call to list->output to give the offset to the - * listing module. - */ - list->output (offset, NULL, OUT_RAWDATA); - list->uplevel (LIST_TIMES); - } - } - if (instruction->times > 1) - list->downlevel (LIST_TIMES); - return offset - start; - } else if (m > 0 && m > size_prob) { - size_prob = m; - } - temp++; - } - - if (temp->opcode == -1) { /* didn't match any instruction */ - if (size_prob == 1) /* would have matched, but for size */ - error (ERR_NONFATAL, "operation size not specified"); - else if (size_prob == 2) - error (ERR_NONFATAL, "mismatch in operand sizes"); - else if (size_prob == 3) - error (ERR_NONFATAL, "no instruction for this cpu level"); - else - error (ERR_NONFATAL, - "invalid combination of opcode and operands"); - } - return 0; -} - -long insn_size (long segment, long offset, int bits, unsigned long cp, - insn *instruction, efunc error) -{ - struct itemplate *temp; - - errfunc = error; /* to pass to other functions */ - cpu = cp; - - if (instruction->opcode == -1) - return 0; - - if (instruction->opcode == I_DB || - instruction->opcode == I_DW || - instruction->opcode == I_DD || - instruction->opcode == I_DQ || - instruction->opcode == I_DT) - { - extop *e; - long isize, osize, wsize = 0; /* placate gcc */ - - isize = 0; - switch (instruction->opcode) - { - case I_DB: wsize = 1; break; - case I_DW: wsize = 2; break; - case I_DD: wsize = 4; break; - case I_DQ: wsize = 8; break; - case I_DT: wsize = 10; break; - } - - for (e = instruction->eops; e; e = e->next) - { - long align; - - osize = 0; - if (e->type == EOT_DB_NUMBER) - osize = 1; - else if (e->type == EOT_DB_STRING) - osize = e->stringlen; - - align = (-osize) % wsize; - if (align < 0) - align += wsize; - isize += osize + align; - } - return isize * instruction->times; - } - - if (instruction->opcode == I_INCBIN) - { - char fname[FILENAME_MAX]; - FILE * fp; - long len; - char *prefix = "", *combine; - char** pPrevPath = NULL; - - len = FILENAME_MAX-1; - if (len > instruction->eops->stringlen) - len = instruction->eops->stringlen; - strncpy (fname, instruction->eops->stringval, len); - fname[len] = '\0'; - - while (1) /* added by alexfru: 'incbin' uses include paths */ - { - combine = nasm_malloc(strlen(prefix) + len + 1); - strcpy(combine, prefix); - strcat(combine, fname); - - if ( (fp = fopen(combine, "rb")) != NULL) - { - nasm_free(combine); - break; - } - - nasm_free(combine); - pPrevPath = pp_get_include_path_ptr (pPrevPath); - if (pPrevPath == NULL) - break; - prefix = *pPrevPath; - } - - if (fp == NULL) - error (ERR_NONFATAL, "`incbin': unable to open file `%s'", fname); - else if (fseek(fp, 0L, SEEK_END) < 0) - error (ERR_NONFATAL, "`incbin': unable to seek on file `%s'", - fname); - else - { - len = ftell (fp); - fclose (fp); - if (instruction->eops->next) - { - len -= instruction->eops->next->offset; - if (instruction->eops->next->next && - len > instruction->eops->next->next->offset) - { - len = instruction->eops->next->next->offset; - } - } - return instruction->times * len; - } - return 0; /* if we're here, there's an error */ - } - - temp = nasm_instructions[instruction->opcode]; - while (temp->opcode != -1) { - int m = matches(temp, instruction); - if (m == 99) - m += jmp_match(segment, offset, bits, instruction, temp->code); - - if (m == 100) { - /* we've matched an instruction. */ - long isize; - const char * codes = temp->code; - int j; - - isize = calcsize(segment, offset, bits, instruction, codes); - if (isize < 0) - return -1; - for (j = 0; j < instruction->nprefix; j++) - { - if ((instruction->prefixes[j] != P_A16 && - instruction->prefixes[j] != P_O16 && bits==16) || - (instruction->prefixes[j] != P_A32 && - instruction->prefixes[j] != P_O32 && bits==32)) - { - isize++; - } - } - return isize * instruction->times; - } - temp++; - } - return -1; /* didn't match any instruction */ -} - - -/* check that opn[op] is a signed byte of size 16 or 32, - and return the signed value*/ -static int is_sbyte (insn *ins, int op, int size) -{ - signed long v; - int ret; - - ret = !(ins->forw_ref && ins->oprs[op].opflags ) && /* dead in the water on forward reference or External */ - optimizing>=0 && - !(ins->oprs[op].type & STRICT) && - ins->oprs[op].wrt==NO_SEG && ins->oprs[op].segment==NO_SEG; - - v = ins->oprs[op].offset; - if (size==16) v = (signed short)v; /* sign extend if 16 bits */ - - return ret && v>=-128L && v<=127L; -} - -static long calcsize (long segment, long offset, int bits, - insn *ins, const char *codes) -{ - long length = 0; - unsigned char c; - - (void) segment; /* Don't warn that this parameter is unused */ - (void) offset; /* Don't warn that this parameter is unused */ - - while (*codes) switch (c = *codes++) { - case 01: case 02: case 03: - codes += c, length += c; break; - case 04: case 05: case 06: case 07: - length++; break; - case 010: case 011: case 012: - codes++, length++; break; - case 017: - length++; break; - case 014: case 015: case 016: - length++; break; - case 020: case 021: case 022: - length++; break; - case 024: case 025: case 026: - length++; break; - case 030: case 031: case 032: - length += 2; break; - case 034: case 035: case 036: - if ( ins->oprs[c-034].type & (BITS16|BITS32) ) - length += (ins->oprs[c-034].type & BITS16) ? 2 : 4; - else - length += (bits == 16) ? 2 : 4; - break; - case 037: - length += 2; break; - case 040: case 041: case 042: - length += 4; break; - case 044: case 045: case 046: - length += ((ins->oprs[c-044].addr_size ? - ins->oprs[c-044].addr_size : bits) == 16 ? 2 : 4); break; - case 050: case 051: case 052: - length++; break; - case 060: case 061: case 062: - length += 2; break; - case 064: case 065: case 066: - if ( ins->oprs[c-064].type & (BITS16|BITS32) ) - length += (ins->oprs[c-064].type & BITS16) ? 2 : 4; - else - length += (bits == 16) ? 2 : 4; - break; - case 070: case 071: case 072: - length += 4; break; - case 0130: case 0131: case 0132: - length += is_sbyte(ins, c-0130, 16) ? 1 : 2; break; - case 0133: case 0134: case 0135: - codes+=2; length++; break; - case 0140: case 0141: case 0142: - length += is_sbyte(ins, c-0140, 32) ? 1 : 4; break; - case 0143: case 0144: case 0145: - codes+=2; length++; break; - case 0300: case 0301: case 0302: - length += chsize (&ins->oprs[c-0300], bits); - break; - case 0310: - length += (bits==32); - break; - case 0311: - length += (bits==16); - break; - case 0312: - break; - case 0320: - length += (bits==32); - break; - case 0321: - length += (bits==16); - break; - case 0322: - break; - case 0330: - codes++, length++; break; - case 0331: - case 0332: - break; - case 0333: - length++; break; - case 0340: case 0341: case 0342: - if (ins->oprs[0].segment != NO_SEG) - errfunc (ERR_NONFATAL, "attempt to reserve non-constant" - " quantity of BSS space"); - else - length += ins->oprs[0].offset << (c-0340); - break; - case 0370: case 0371: case 0372: - break; - case 0373: - length++; break; - default: /* can't do it by 'case' statements */ - if (c>=0100 && c<=0277) { /* it's an EA */ - ea ea_data; - if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, 0, - ins->forw_ref)) { - errfunc (ERR_NONFATAL, "invalid effective address"); - return -1; - } else - length += ea_data.size; - } else - errfunc (ERR_PANIC, "internal instruction table corrupt" - ": instruction code 0x%02X given", c); - } - return length; -} - -static void gencode (long segment, long offset, int bits, - insn *ins, const char *codes, long insn_end) -{ - static char condval[] = { /* conditional opcodes */ - 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2, - 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5, - 0x0, 0xA, 0xA, 0xB, 0x8, 0x4 - }; - unsigned char c; - unsigned char bytes[4]; - long data, size; - - while (*codes) - switch (c = *codes++) - { - case 01: case 02: case 03: - out (offset, segment, codes, OUT_RAWDATA+c, NO_SEG, NO_SEG); - codes += c; - offset += c; - break; - - case 04: case 06: - switch (ins->oprs[0].basereg) - { - case R_CS: - bytes[0] = 0x0E + (c == 0x04 ? 1 : 0); break; - case R_DS: - bytes[0] = 0x1E + (c == 0x04 ? 1 : 0); break; - case R_ES: - bytes[0] = 0x06 + (c == 0x04 ? 1 : 0); break; - case R_SS: - bytes[0] = 0x16 + (c == 0x04 ? 1 : 0); break; - default: - errfunc (ERR_PANIC, "bizarre 8086 segment register received"); - } - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset++; - break; - - case 05: case 07: - switch (ins->oprs[0].basereg) { - case R_FS: bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0); break; - case R_GS: bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0); break; - default: - errfunc (ERR_PANIC, "bizarre 386 segment register received"); - } - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset++; - break; - - case 010: case 011: case 012: - bytes[0] = *codes++ + regval(&ins->oprs[c-010]); - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - break; - - case 017: - bytes[0] = 0; - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - break; - - case 014: case 015: case 016: - if (ins->oprs[c-014].offset < -128 - || ins->oprs[c-014].offset > 127) - { - errfunc (ERR_WARNING, "signed byte value exceeds bounds"); - } - - if (ins->oprs[c-014].segment != NO_SEG) - { - data = ins->oprs[c-014].offset; - out (offset, segment, &data, OUT_ADDRESS+1, - ins->oprs[c-014].segment, ins->oprs[c-014].wrt); - } - else { - bytes[0] = ins->oprs[c-014].offset; - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - } - offset += 1; - break; - - case 020: case 021: case 022: - if (ins->oprs[c-020].offset < -256 - || ins->oprs[c-020].offset > 255) - { - errfunc (ERR_WARNING, "byte value exceeds bounds"); - } - if (ins->oprs[c-020].segment != NO_SEG) { - data = ins->oprs[c-020].offset; - out (offset, segment, &data, OUT_ADDRESS+1, - ins->oprs[c-020].segment, ins->oprs[c-020].wrt); - } - else { - bytes[0] = ins->oprs[c-020].offset; - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - } - offset += 1; - break; - - case 024: case 025: case 026: - if (ins->oprs[c-024].offset < 0 || ins->oprs[c-024].offset > 255) - errfunc (ERR_WARNING, "unsigned byte value exceeds bounds"); - if (ins->oprs[c-024].segment != NO_SEG) { - data = ins->oprs[c-024].offset; - out (offset, segment, &data, OUT_ADDRESS+1, - ins->oprs[c-024].segment, ins->oprs[c-024].wrt); - } - else { - bytes[0] = ins->oprs[c-024].offset; - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - } - offset += 1; - break; - - case 030: case 031: case 032: - if (ins->oprs[c-030].segment == NO_SEG && - ins->oprs[c-030].wrt == NO_SEG && - (ins->oprs[c-030].offset < -65536L || - ins->oprs[c-030].offset > 65535L)) - { - errfunc (ERR_WARNING, "word value exceeds bounds"); - } - data = ins->oprs[c-030].offset; - out (offset, segment, &data, OUT_ADDRESS+2, - ins->oprs[c-030].segment, ins->oprs[c-030].wrt); - offset += 2; - break; - - case 034: case 035: case 036: - if ( ins->oprs[c-034].type & (BITS16|BITS32) ) - size = (ins->oprs[c-034].type & BITS16) ? 2 : 4; - else - size = (bits == 16) ? 2 : 4; - data = ins->oprs[c-034].offset; - if (size==2 && (data < -65536L || data > 65535L)) - errfunc (ERR_WARNING, "word value exceeds bounds"); - out (offset, segment, &data, OUT_ADDRESS+size, - ins->oprs[c-034].segment, ins->oprs[c-034].wrt); - offset += size; - break; - - case 037: - if (ins->oprs[0].segment == NO_SEG) - errfunc (ERR_NONFATAL, "value referenced by FAR is not" - " relocatable"); - data = 0L; - out (offset, segment, &data, OUT_ADDRESS+2, - outfmt->segbase(1+ins->oprs[0].segment), - ins->oprs[0].wrt); - offset += 2; - break; - - case 040: case 041: case 042: - data = ins->oprs[c-040].offset; - out (offset, segment, &data, OUT_ADDRESS+4, - ins->oprs[c-040].segment, ins->oprs[c-040].wrt); - offset += 4; - break; - - case 044: case 045: case 046: - data = ins->oprs[c-044].offset; - size = ((ins->oprs[c-044].addr_size ? - ins->oprs[c-044].addr_size : bits) == 16 ? 2 : 4); - if (size==2 && (data < -65536L || data > 65535L)) - errfunc (ERR_WARNING, "word value exceeds bounds"); - out (offset, segment, &data, OUT_ADDRESS+size, - ins->oprs[c-044].segment, ins->oprs[c-044].wrt); - offset += size; - break; - - case 050: case 051: case 052: - if (ins->oprs[c-050].segment != segment) - errfunc (ERR_NONFATAL, "short relative jump outside segment"); - data = ins->oprs[c-050].offset - insn_end; - if (data > 127 || data < -128) - errfunc (ERR_NONFATAL, "short jump is out of range"); - bytes[0] = data; - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - break; - - case 060: case 061: case 062: - if (ins->oprs[c-060].segment != segment) { - data = ins->oprs[c-060].offset; - out (offset, segment, &data, OUT_REL2ADR+insn_end-offset, - ins->oprs[c-060].segment, ins->oprs[c-060].wrt); - } else { - data = ins->oprs[c-060].offset - insn_end; - out (offset, segment, &data, - OUT_ADDRESS+2, NO_SEG, NO_SEG); - } - offset += 2; - break; - - case 064: case 065: case 066: - if ( ins->oprs[c-064].type & (BITS16|BITS32) ) - size = (ins->oprs[c-064].type & BITS16) ? 2 : 4; - else - size = (bits == 16) ? 2 : 4; - if (ins->oprs[c-064].segment != segment) { - long reltype = (size == 2 ? OUT_REL2ADR : OUT_REL4ADR); - data = ins->oprs[c-064].offset; - out (offset, segment, &data, reltype+insn_end-offset, - ins->oprs[c-064].segment, ins->oprs[c-064].wrt); - } else { - data = ins->oprs[c-064].offset - insn_end; - out (offset, segment, &data, - OUT_ADDRESS+size, NO_SEG, NO_SEG); - } - offset += size; - break; - - case 070: case 071: case 072: - if (ins->oprs[c-070].segment != segment) { - data = ins->oprs[c-070].offset; - out (offset, segment, &data, OUT_REL4ADR+insn_end-offset, - ins->oprs[c-070].segment, ins->oprs[c-070].wrt); - } else { - data = ins->oprs[c-070].offset - insn_end; - out (offset, segment, &data, - OUT_ADDRESS+4, NO_SEG, NO_SEG); - } - offset += 4; - break; - - case 0130: case 0131: case 0132: - data = ins->oprs[c-0130].offset; - if (is_sbyte(ins, c-0130, 16)) { - bytes[0] = data; - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset++; - } else { - if (ins->oprs[c-0130].segment == NO_SEG && - ins->oprs[c-0130].wrt == NO_SEG && - (data < -65536L || data > 65535L)) { - errfunc (ERR_WARNING, "word value exceeds bounds"); - } - out (offset, segment, &data, OUT_ADDRESS+2, - ins->oprs[c-0130].segment, ins->oprs[c-0130].wrt); - offset += 2; - } - break; - - case 0133: case 0134: case 0135: - codes++; - bytes[0] = *codes++; - if (is_sbyte(ins, c-0133, 16)) bytes[0] |= 2; /* s-bit */ - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset++; - break; - - case 0140: case 0141: case 0142: - data = ins->oprs[c-0140].offset; - if (is_sbyte(ins, c-0140, 32)) { - bytes[0] = data; - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset++; - } else { - out (offset, segment, &data, OUT_ADDRESS+4, - ins->oprs[c-0140].segment, ins->oprs[c-0140].wrt); - offset += 4; - } - break; - - case 0143: case 0144: case 0145: - codes++; - bytes[0] = *codes++; - if (is_sbyte(ins, c-0143, 32)) bytes[0] |= 2; /* s-bit */ - out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset++; - break; - - case 0300: case 0301: case 0302: - if (chsize (&ins->oprs[c-0300], bits)) { - *bytes = 0x67; - out (offset, segment, bytes, - OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - } else - offset += 0; - break; - - case 0310: - if (bits==32) { - *bytes = 0x67; - out (offset, segment, bytes, - OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - } else - offset += 0; - break; - - case 0311: - if (bits==16) { - *bytes = 0x67; - out (offset, segment, bytes, - OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - } else - offset += 0; - break; - - case 0312: - break; - - case 0320: - if (bits==32) { - *bytes = 0x66; - out (offset, segment, bytes, - OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - } else - offset += 0; - break; - - case 0321: - if (bits==16) { - *bytes = 0x66; - out (offset, segment, bytes, - OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - } else - offset += 0; - break; - - case 0322: - break; - - case 0330: - *bytes = *codes++ ^ condval[ins->condition]; - out (offset, segment, bytes, - OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - break; - - case 0331: - case 0332: - break; - - case 0333: - *bytes = 0xF3; - out (offset, segment, bytes, - OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - break; - - case 0340: case 0341: case 0342: - if (ins->oprs[0].segment != NO_SEG) - errfunc (ERR_PANIC, "non-constant BSS size in pass two"); - else { - long size = ins->oprs[0].offset << (c-0340); - if (size > 0) - out (offset, segment, NULL, - OUT_RESERVE+size, NO_SEG, NO_SEG); - offset += size; - } - break; - - case 0370: case 0371: case 0372: - break; - - case 0373: - *bytes = bits==16 ? 3 : 5; - out (offset, segment, bytes, - OUT_RAWDATA+1, NO_SEG, NO_SEG); - offset += 1; - break; - - default: /* can't do it by 'case' statements */ - if (c>=0100 && c<=0277) { /* it's an EA */ - ea ea_data; - int rfield; - unsigned char *p; - long s; - - if (c<=0177) /* pick rfield from operand b */ - rfield = regval (&ins->oprs[c&7]); - else /* rfield is constant */ - rfield = c & 7; - - if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, rfield, - ins->forw_ref)) - { - errfunc (ERR_NONFATAL, "invalid effective address"); - } - - p = bytes; - *p++ = ea_data.modrm; - if (ea_data.sib_present) - *p++ = ea_data.sib; - - s = p-bytes; - out (offset, segment, bytes, OUT_RAWDATA + s, - NO_SEG, NO_SEG); - - switch (ea_data.bytes) { - case 0: - break; - case 1: - if (ins->oprs[(c>>3)&7].segment != NO_SEG) { - data = ins->oprs[(c>>3)&7].offset; - out (offset, segment, &data, OUT_ADDRESS+1, - ins->oprs[(c>>3)&7].segment, - ins->oprs[(c>>3)&7].wrt); - } else { - *bytes = ins->oprs[(c>>3)&7].offset; - out (offset, segment, bytes, OUT_RAWDATA+1, - NO_SEG, NO_SEG); - } - s++; - break; - case 2: - case 4: - data = ins->oprs[(c>>3)&7].offset; - out (offset, segment, &data, - OUT_ADDRESS+ea_data.bytes, - ins->oprs[(c>>3)&7].segment, ins->oprs[(c>>3)&7].wrt); - s += ea_data.bytes; - break; - } - offset += s; - } else - errfunc (ERR_PANIC, "internal instruction table corrupt" - ": instruction code 0x%02X given", c); - } -} - -#include "regvals.c" - -static int regval (operand *o) -{ - if ( o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT ) { - errfunc (ERR_PANIC, "invalid operand passed to regval()"); - } - return regvals[o->basereg]; -} - -static int matches (struct itemplate *itemp, insn *instruction) -{ - int i, size[3], asize, oprs, ret; - - ret = 100; - - /* - * Check the opcode - */ - if (itemp->opcode != instruction->opcode) return 0; - - /* - * Count the operands - */ - if (itemp->operands != instruction->operands) return 0; - - /* - * Check that no spurious colons or TOs are present - */ - for (i=0; ioperands; i++) - if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON|TO)) - return 0; - - /* - * Check that the operand flags all match up - */ - for (i=0; ioperands; i++) - if (itemp->opd[i] & ~instruction->oprs[i].type || - ((itemp->opd[i] & SIZE_MASK) && - ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) - { - if ((itemp->opd[i] & ~instruction->oprs[i].type & NON_SIZE) || - (instruction->oprs[i].type & SIZE_MASK)) - return 0; - else -/* ret = 1; */ - return 1; - } - - /* - * Check operand sizes - */ - if (itemp->flags & IF_ARMASK) { - size[0] = size[1] = size[2] = 0; - - switch (itemp->flags & IF_ARMASK) { - case IF_AR0: i = 0; break; - case IF_AR1: i = 1; break; - case IF_AR2: i = 2; break; - default: break; /* Shouldn't happen */ - } - if (itemp->flags & IF_SB) { - size[i] = BITS8; - } else if (itemp->flags & IF_SW) { - size[i] = BITS16; - } else if (itemp->flags & IF_SD) { - size[i] = BITS32; - } - } else { - asize = 0; - if (itemp->flags & IF_SB) { - asize = BITS8; - oprs = itemp->operands; - } else if (itemp->flags & IF_SW) { - asize = BITS16; - oprs = itemp->operands; - } else if (itemp->flags & IF_SD) { - asize = BITS32; - oprs = itemp->operands; - } - size[0] = size[1] = size[2] = asize; - } - - if (itemp->flags & (IF_SM | IF_SM2)) { - oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands); - asize = 0; - for (i=0; iopd[i] & SIZE_MASK) != 0) { - int j; - for (j=0; joperands; - } - - for (i=0; ioperands; i++) - if (!(itemp->opd[i] & SIZE_MASK) && - (instruction->oprs[i].type & SIZE_MASK & ~size[i])) -/* ret = 2; */ - return 2; - - /* - * Check template is okay at the set cpu level - */ - if ((itemp->flags & IF_PLEVEL) > cpu) return 3; - - /* - * Check if special handling needed for Jumps - */ - if ((unsigned char)(itemp->code[0]) >= 0370) return 99; - - return ret; -} - -static ea *process_ea (operand *input, ea *output, int addrbits, int rfield, - int forw_ref) -{ - if (!(REGISTER & ~input->type)) { /* it's a single register */ - static int regs[] = { - R_AL, R_CL, R_DL, R_BL, R_AH, R_CH, R_DH, R_BH, - R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI, - R_EAX, R_ECX, R_EDX, R_EBX, R_ESP, R_EBP, R_ESI, R_EDI, - R_MM0, R_MM1, R_MM2, R_MM3, R_MM4, R_MM5, R_MM6, R_MM7, - R_XMM0, R_XMM1, R_XMM2, R_XMM3, R_XMM4, R_XMM5, R_XMM6, R_XMM7 - }; - int i; - - for (i=0; ibasereg == regs[i]) break; - if (isib_present = FALSE;/* no SIB necessary */ - output->bytes = 0; /* no offset necessary either */ - output->modrm = 0xC0 | (rfield << 3) | (i & 7); - } - else - return NULL; - } else { /* it's a memory reference */ - if (input->basereg==-1 && (input->indexreg==-1 || input->scale==0)) { - /* it's a pure offset */ - if (input->addr_size) - addrbits = input->addr_size; - output->sib_present = FALSE; - output->bytes = (addrbits==32 ? 4 : 2); - output->modrm = (addrbits==32 ? 5 : 6) | (rfield << 3); - } - else { /* it's an indirection */ - int i=input->indexreg, b=input->basereg, s=input->scale; - long o=input->offset, seg=input->segment; - int hb=input->hintbase, ht=input->hinttype; - int t; - - if (s==0) i = -1; /* make this easy, at least */ - - if (i==R_EAX || i==R_EBX || i==R_ECX || i==R_EDX - || i==R_EBP || i==R_ESP || i==R_ESI || i==R_EDI - || b==R_EAX || b==R_EBX || b==R_ECX || b==R_EDX - || b==R_EBP || b==R_ESP || b==R_ESI || b==R_EDI) { - /* it must be a 32-bit memory reference. Firstly we have - * to check that all registers involved are type Exx. */ - if (i!=-1 && i!=R_EAX && i!=R_EBX && i!=R_ECX && i!=R_EDX - && i!=R_EBP && i!=R_ESP && i!=R_ESI && i!=R_EDI) - return NULL; - if (b!=-1 && b!=R_EAX && b!=R_EBX && b!=R_ECX && b!=R_EDX - && b!=R_EBP && b!=R_ESP && b!=R_ESI && b!=R_EDI) - return NULL; - - /* While we're here, ensure the user didn't specify WORD. */ - if (input->addr_size == 16) - return NULL; - - /* now reorganise base/index */ - if (s == 1 && b != i && b != -1 && i != -1 && - ((hb==b&&ht==EAH_NOTBASE) || (hb==i&&ht==EAH_MAKEBASE))) - t = b, b = i, i = t; /* swap if hints say so */ - if (b==i) /* convert EAX+2*EAX to 3*EAX */ - b = -1, s++; - if (b==-1 && s==1 && !(hb == i && ht == EAH_NOTBASE)) - b = i, i = -1; /* make single reg base, unless hint */ - if (((s==2 && i!=R_ESP && !(input->eaflags & EAF_TIMESTWO)) || - s==3 || s==5 || s==9) && b==-1) - b = i, s--; /* convert 3*EAX to EAX+2*EAX */ - if (i==-1 && b!=R_ESP && (input->eaflags & EAF_TIMESTWO)) - i = b, b = -1, s = 1; - /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */ - if (s==1 && i==R_ESP) /* swap ESP into base if scale is 1 */ - i = b, b = R_ESP; - if (i==R_ESP || (s!=1 && s!=2 && s!=4 && s!=8 && i!=-1)) - return NULL; /* wrong, for various reasons */ - - if (i==-1 && b!=R_ESP) {/* no SIB needed */ - int mod, rm; - switch(b) { - case R_EAX: rm = 0; break; - case R_ECX: rm = 1; break; - case R_EDX: rm = 2; break; - case R_EBX: rm = 3; break; - case R_EBP: rm = 5; break; - case R_ESI: rm = 6; break; - case R_EDI: rm = 7; break; - case -1: rm = 5; break; - default: /* should never happen */ - return NULL; - } - if (b==-1 || (b!=R_EBP && o==0 && - seg==NO_SEG && !forw_ref && - !(input->eaflags & - (EAF_BYTEOFFS|EAF_WORDOFFS)))) - mod = 0; - else if (input->eaflags & EAF_BYTEOFFS || - (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref && - !(input->eaflags & EAF_WORDOFFS))) { - mod = 1; - } - else - mod = 2; - - output->sib_present = FALSE; - output->bytes = (b==-1 || mod==2 ? 4 : mod); - output->modrm = (mod<<6) | (rfield<<3) | rm; - } - else { /* we need a SIB */ - int mod, scale, index, base; - - switch (b) { - case R_EAX: base = 0; break; - case R_ECX: base = 1; break; - case R_EDX: base = 2; break; - case R_EBX: base = 3; break; - case R_ESP: base = 4; break; - case R_EBP: case -1: base = 5; break; - case R_ESI: base = 6; break; - case R_EDI: base = 7; break; - default: /* then what the smeg is it? */ - return NULL; /* panic */ - } - - switch (i) { - case R_EAX: index = 0; break; - case R_ECX: index = 1; break; - case R_EDX: index = 2; break; - case R_EBX: index = 3; break; - case -1: index = 4; break; - case R_EBP: index = 5; break; - case R_ESI: index = 6; break; - case R_EDI: index = 7; break; - default: /* then what the smeg is it? */ - return NULL; /* panic */ - } - - if (i==-1) s = 1; - switch (s) { - case 1: scale = 0; break; - case 2: scale = 1; break; - case 4: scale = 2; break; - case 8: scale = 3; break; - default: /* then what the smeg is it? */ - return NULL; /* panic */ - } - - if (b==-1 || (b!=R_EBP && o==0 && - seg==NO_SEG && !forw_ref && - !(input->eaflags & - (EAF_BYTEOFFS|EAF_WORDOFFS)))) - mod = 0; - else if (input->eaflags & EAF_BYTEOFFS || - (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref && - !(input->eaflags & EAF_WORDOFFS))) - mod = 1; - else - mod = 2; - - output->sib_present = TRUE; - output->bytes = (b==-1 || mod==2 ? 4 : mod); - output->modrm = (mod<<6) | (rfield<<3) | 4; - output->sib = (scale<<6) | (index<<3) | base; - } - } - else { /* it's 16-bit */ - int mod, rm; - - /* check all registers are BX, BP, SI or DI */ - if ((b!=-1 && b!=R_BP && b!=R_BX && b!=R_SI && b!=R_DI) || - (i!=-1 && i!=R_BP && i!=R_BX && i!=R_SI && i!=R_DI)) - return NULL; - - /* ensure the user didn't specify DWORD */ - if (input->addr_size == 32) - return NULL; - - if (s!=1 && i!=-1) return NULL;/* no can do, in 16-bit EA */ - if (b==-1 && i!=-1) { int tmp = b; b = i; i = tmp; } /* swap */ - if ((b==R_SI || b==R_DI) && i!=-1) - { int tmp = b; b = i; i = tmp; } - /* have BX/BP as base, SI/DI index */ - if (b==i) return NULL;/* shouldn't ever happen, in theory */ - if (i!=-1 && b!=-1 && - (i==R_BP || i==R_BX || b==R_SI || b==R_DI)) - return NULL; /* invalid combinations */ - if (b==-1) /* pure offset: handled above */ - return NULL; /* so if it gets to here, panic! */ - - rm = -1; - if (i!=-1) - switch (i*256 + b) { - case R_SI*256+R_BX: rm=0; break; - case R_DI*256+R_BX: rm=1; break; - case R_SI*256+R_BP: rm=2; break; - case R_DI*256+R_BP: rm=3; break; - } - else - switch (b) { - case R_SI: rm=4; break; - case R_DI: rm=5; break; - case R_BP: rm=6; break; - case R_BX: rm=7; break; - } - if (rm==-1) /* can't happen, in theory */ - return NULL; /* so panic if it does */ - - if (o==0 && seg==NO_SEG && !forw_ref && rm!=6 && - !(input->eaflags & (EAF_BYTEOFFS|EAF_WORDOFFS))) - mod = 0; - else if (input->eaflags & EAF_BYTEOFFS || - (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref && - !(input->eaflags & EAF_WORDOFFS))) - mod = 1; - else - mod = 2; - - output->sib_present = FALSE; /* no SIB - it's 16-bit */ - output->bytes = mod; /* bytes of offset needed */ - output->modrm = (mod<<6) | (rfield<<3) | rm; - } - } - } - output->size = 1 + output->sib_present + output->bytes; - return output; -} - -static int chsize (operand *input, int addrbits) -{ - if (!(MEMORY & ~input->type)) { - int i=input->indexreg, b=input->basereg; - - if (input->scale==0) i = -1; - - if (i == -1 && b == -1) /* pure offset */ - return (input->addr_size != 0 && input->addr_size != addrbits); - - if (i==R_EAX || i==R_EBX || i==R_ECX || i==R_EDX - || i==R_EBP || i==R_ESP || i==R_ESI || i==R_EDI - || b==R_EAX || b==R_EBX || b==R_ECX || b==R_EDX - || b==R_EBP || b==R_ESP || b==R_ESI || b==R_EDI) - return (addrbits==16); - else - return (addrbits==32); - } - else - return 0; -} +/* assemble.c code generation for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * the actual codes (C syntax, i.e. octal): + * \0 - terminates the code. (Unless it's a literal of course.) + * \1, \2, \3 - that many literal bytes follow in the code stream + * \4, \6 - the POP/PUSH (respectively) codes for CS, DS, ES, SS + * (POP is never used for CS) depending on operand 0 + * \5, \7 - the second byte of POP/PUSH codes for FS, GS, depending + * on operand 0 + * \10, \11, \12 - a literal byte follows in the code stream, to be added + * to the register value of operand 0, 1 or 2 + * \17 - encodes the literal byte 0. (Some compilers don't take + * kindly to a zero byte in the _middle_ of a compile time + * string constant, so I had to put this hack in.) + * \14, \15, \16 - a signed byte immediate operand, from operand 0, 1 or 2 + * \20, \21, \22 - a byte immediate operand, from operand 0, 1 or 2 + * \24, \25, \26 - an unsigned byte immediate operand, from operand 0, 1 or 2 + * \30, \31, \32 - a word immediate operand, from operand 0, 1 or 2 + * \34, \35, \36 - select between \3[012] and \4[012] depending on 16/32 bit + * assembly mode or the operand-size override on the operand + * \37 - a word constant, from the _segment_ part of operand 0 + * \40, \41, \42 - a long immediate operand, from operand 0, 1 or 2 + * \44, \45, \46 - select between \3[012] and \4[012] depending on 16/32 bit + * assembly mode or the address-size override on the operand + * \50, \51, \52 - a byte relative operand, from operand 0, 1 or 2 + * \60, \61, \62 - a word relative operand, from operand 0, 1 or 2 + * \64, \65, \66 - select between \6[012] and \7[012] depending on 16/32 bit + * assembly mode or the operand-size override on the operand + * \70, \71, \72 - a long relative operand, from operand 0, 1 or 2 + * \1ab - a ModRM, calculated on EA in operand a, with the spare + * field the register value of operand b. + * \130,\131,\132 - an immediate word or signed byte for operand 0, 1, or 2 + * \133,\134,\135 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2 + * is a signed byte rather than a word. + * \140,\141,\142 - an immediate dword or signed byte for operand 0, 1, or 2 + * \143,\144,\145 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2 + * is a signed byte rather than a dword. + * \2ab - a ModRM, calculated on EA in operand a, with the spare + * field equal to digit b. + * \30x - might be an 0x67 byte, depending on the address size of + * the memory reference in operand x. + * \310 - indicates fixed 16-bit address size, i.e. optional 0x67. + * \311 - indicates fixed 32-bit address size, i.e. optional 0x67. + * \312 - (disassembler only) marker on LOOP, LOOPxx instructions. + * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66. + * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66. + * \322 - indicates that this instruction is only valid when the + * operand size is the default (instruction to disassembler, + * generates no code in the assembler) + * \330 - a literal byte follows in the code stream, to be added + * to the condition code value of the instruction. + * \331 - instruction not valid with REP prefix. Hint for + * disassembler only; for SSE instructions. + * \332 - disassemble a rep (0xF3 byte) prefix as repe not rep. + * \333 - REP prefix (0xF3 byte); for SSE instructions. Not encoded + * as a literal byte in order to aid the disassembler. + * \340 - reserve bytes of uninitialised storage. + * Operand 0 had better be a segmentless constant. + * \370,\371,\372 - match only if operand 0 meets byte jump criteria. + * 370 is used for Jcc, 371 is used for JMP. + * \373 - assemble 0x03 if bits==16, 0x05 if bits==32; + * used for conditional jump over longer jump + */ + +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "assemble.h" +#include "insns.h" +#include "preproc.h" + +extern struct itemplate *nasm_instructions[]; + +typedef struct { + int sib_present; /* is a SIB byte necessary? */ + int bytes; /* # of bytes of offset needed */ + int size; /* lazy - this is sib+bytes+1 */ + unsigned char modrm, sib; /* the bytes themselves */ +} ea; + +static unsigned long cpu; /* cpu level received from nasm.c */ +static efunc errfunc; +static struct ofmt *outfmt; +static ListGen *list; + +static long calcsize(long, long, int, insn *, const char *); +static void gencode(long, long, int, insn *, const char *, long); +static int regval(operand * o); +static int matches(struct itemplate *, insn *); +static ea *process_ea(operand *, ea *, int, int, int); +static int chsize(operand *, int); + +/* + * This routine wrappers the real output format's output routine, + * in order to pass a copy of the data off to the listing file + * generator at the same time. + */ +static void out(long offset, long segto, const void *data, + unsigned long type, long segment, long wrt) +{ + static long lineno = 0; /* static!!! */ + static char *lnfname = NULL; + + if ((type & OUT_TYPMASK) == OUT_ADDRESS) { + if (segment != NO_SEG || wrt != NO_SEG) { + /* + * This address is relocated. We must write it as + * OUT_ADDRESS, so there's no work to be done here. + */ + list->output(offset, data, type); + } else { + unsigned char p[4], *q = p; + /* + * This is a non-relocated address, and we're going to + * convert it into RAWDATA format. + */ + if ((type & OUT_SIZMASK) == 4) { + WRITELONG(q, *(long *)data); + list->output(offset, p, OUT_RAWDATA + 4); + } else { + WRITESHORT(q, *(long *)data); + list->output(offset, p, OUT_RAWDATA + 2); + } + } + } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) { + list->output(offset, data, type); + } else if ((type & OUT_TYPMASK) == OUT_RESERVE) { + list->output(offset, NULL, type); + } else if ((type & OUT_TYPMASK) == OUT_REL2ADR || + (type & OUT_TYPMASK) == OUT_REL4ADR) { + list->output(offset, data, type); + } + + /* + * this call to src_get determines when we call the + * debug-format-specific "linenum" function + * it updates lineno and lnfname to the current values + * returning 0 if "same as last time", -2 if lnfname + * changed, and the amount by which lineno changed, + * if it did. thus, these variables must be static + */ + + if (src_get(&lineno, &lnfname)) { + outfmt->current_dfmt->linenum(lnfname, lineno, segto); + } + + outfmt->output(segto, data, type, segment, wrt); +} + +static int jmp_match(long segment, long offset, int bits, + insn * ins, const char *code) +{ + long isize; + unsigned char c = code[0]; + + if (c != 0370 && c != 0371) + return 0; + if (ins->oprs[0].opflags & OPFLAG_FORWARD) { + if ((optimizing < 0 || (ins->oprs[0].type & STRICT)) + && c == 0370) + return 1; + else + return (pass0 == 0); /* match a forward reference */ + } + isize = calcsize(segment, offset, bits, ins, code); + if (ins->oprs[0].segment != segment) + return 0; + isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */ + if (isize >= -128L && isize <= 127L) + return 1; /* it is byte size */ + + return 0; +} + +long assemble(long segment, long offset, int bits, unsigned long cp, + insn * instruction, struct ofmt *output, efunc error, + ListGen * listgen) +{ + struct itemplate *temp; + int j; + int size_prob; + long insn_end; + long itimes; + long start = offset; + long wsize = 0; /* size for DB etc. */ + + errfunc = error; /* to pass to other functions */ + cpu = cp; + outfmt = output; /* likewise */ + list = listgen; /* and again */ + + switch (instruction->opcode) { + case -1: + return 0; + case I_DB: + wsize = 1; + break; + case I_DW: + wsize = 2; + break; + case I_DD: + wsize = 4; + break; + case I_DQ: + wsize = 8; + break; + case I_DT: + wsize = 10; + break; + } + + if (wsize) { + extop *e; + long t = instruction->times; + if (t < 0) + errfunc(ERR_PANIC, + "instruction->times < 0 (%ld) in assemble()", t); + + while (t--) { /* repeat TIMES times */ + for (e = instruction->eops; e; e = e->next) { + if (e->type == EOT_DB_NUMBER) { + if (wsize == 1) { + if (e->segment != NO_SEG) + errfunc(ERR_NONFATAL, + "one-byte relocation attempted"); + else { + unsigned char out_byte = e->offset; + out(offset, segment, &out_byte, + OUT_RAWDATA + 1, NO_SEG, NO_SEG); + } + } else if (wsize > 5) { + errfunc(ERR_NONFATAL, "integer supplied to a D%c" + " instruction", wsize == 8 ? 'Q' : 'T'); + } else + out(offset, segment, &e->offset, + OUT_ADDRESS + wsize, e->segment, e->wrt); + offset += wsize; + } else if (e->type == EOT_DB_STRING) { + int align; + + out(offset, segment, e->stringval, + OUT_RAWDATA + e->stringlen, NO_SEG, NO_SEG); + align = e->stringlen % wsize; + + if (align) { + align = wsize - align; + out(offset, segment, "\0\0\0\0\0\0\0\0", + OUT_RAWDATA + align, NO_SEG, NO_SEG); + } + offset += e->stringlen + align; + } + } + if (t > 0 && t == instruction->times - 1) { + /* + * Dummy call to list->output to give the offset to the + * listing module. + */ + list->output(offset, NULL, OUT_RAWDATA); + list->uplevel(LIST_TIMES); + } + } + if (instruction->times > 1) + list->downlevel(LIST_TIMES); + return offset - start; + } + + if (instruction->opcode == I_INCBIN) { + static char fname[FILENAME_MAX]; + FILE *fp; + long len; + char *prefix = "", *combine; + char **pPrevPath = NULL; + + len = FILENAME_MAX - 1; + if (len > instruction->eops->stringlen) + len = instruction->eops->stringlen; + strncpy(fname, instruction->eops->stringval, len); + fname[len] = '\0'; + + while (1) { /* added by alexfru: 'incbin' uses include paths */ + combine = nasm_malloc(strlen(prefix) + len + 1); + strcpy(combine, prefix); + strcat(combine, fname); + + if ((fp = fopen(combine, "rb")) != NULL) { + nasm_free(combine); + break; + } + + nasm_free(combine); + pPrevPath = pp_get_include_path_ptr(pPrevPath); + if (pPrevPath == NULL) + break; + prefix = *pPrevPath; + } + + if (fp == NULL) + error(ERR_NONFATAL, "`incbin': unable to open file `%s'", + fname); + else if (fseek(fp, 0L, SEEK_END) < 0) + error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'", + fname); + else { + static char buf[2048]; + long t = instruction->times; + long base = 0; + + len = ftell(fp); + if (instruction->eops->next) { + base = instruction->eops->next->offset; + len -= base; + if (instruction->eops->next->next && + len > instruction->eops->next->next->offset) + len = instruction->eops->next->next->offset; + } + /* + * Dummy call to list->output to give the offset to the + * listing module. + */ + list->output(offset, NULL, OUT_RAWDATA); + list->uplevel(LIST_INCBIN); + while (t--) { + long l; + + fseek(fp, base, SEEK_SET); + l = len; + while (l > 0) { + long m = + fread(buf, 1, (l > sizeof(buf) ? sizeof(buf) : l), + fp); + if (!m) { + /* + * This shouldn't happen unless the file + * actually changes while we are reading + * it. + */ + error(ERR_NONFATAL, + "`incbin': unexpected EOF while" + " reading file `%s'", fname); + t = 0; /* Try to exit cleanly */ + break; + } + out(offset, segment, buf, OUT_RAWDATA + m, + NO_SEG, NO_SEG); + l -= m; + } + } + list->downlevel(LIST_INCBIN); + if (instruction->times > 1) { + /* + * Dummy call to list->output to give the offset to the + * listing module. + */ + list->output(offset, NULL, OUT_RAWDATA); + list->uplevel(LIST_TIMES); + list->downlevel(LIST_TIMES); + } + fclose(fp); + return instruction->times * len; + } + return 0; /* if we're here, there's an error */ + } + + size_prob = FALSE; + temp = nasm_instructions[instruction->opcode]; + while (temp->opcode != -1) { + int m = matches(temp, instruction); + if (m == 99) + m += jmp_match(segment, offset, bits, instruction, temp->code); + + if (m == 100) { /* matches! */ + const char *codes = temp->code; + long insn_size = calcsize(segment, offset, bits, + instruction, codes); + itimes = instruction->times; + if (insn_size < 0) /* shouldn't be, on pass two */ + error(ERR_PANIC, "errors made it through from pass one"); + else + while (itimes--) { + for (j = 0; j < instruction->nprefix; j++) { + unsigned char c = 0; + switch (instruction->prefixes[j]) { + case P_LOCK: + c = 0xF0; + break; + case P_REPNE: + case P_REPNZ: + c = 0xF2; + break; + case P_REPE: + case P_REPZ: + case P_REP: + c = 0xF3; + break; + case R_CS: + c = 0x2E; + break; + case R_DS: + c = 0x3E; + break; + case R_ES: + c = 0x26; + break; + case R_FS: + c = 0x64; + break; + case R_GS: + c = 0x65; + break; + case R_SS: + c = 0x36; + break; + case R_SEGR6: + case R_SEGR7: + error(ERR_NONFATAL, + "segr6 and segr7 cannot be used as prefixes"); + break; + case P_A16: + if (bits != 16) + c = 0x67; + break; + case P_A32: + if (bits != 32) + c = 0x67; + break; + case P_O16: + if (bits != 16) + c = 0x66; + break; + case P_O32: + if (bits != 32) + c = 0x66; + break; + default: + error(ERR_PANIC, "invalid instruction prefix"); + } + if (c != 0) { + out(offset, segment, &c, OUT_RAWDATA + 1, + NO_SEG, NO_SEG); + offset++; + } + } + insn_end = offset + insn_size; + gencode(segment, offset, bits, instruction, codes, + insn_end); + offset += insn_size; + if (itimes > 0 && itimes == instruction->times - 1) { + /* + * Dummy call to list->output to give the offset to the + * listing module. + */ + list->output(offset, NULL, OUT_RAWDATA); + list->uplevel(LIST_TIMES); + } + } + if (instruction->times > 1) + list->downlevel(LIST_TIMES); + return offset - start; + } else if (m > 0 && m > size_prob) { + size_prob = m; + } + temp++; + } + + if (temp->opcode == -1) { /* didn't match any instruction */ + if (size_prob == 1) /* would have matched, but for size */ + error(ERR_NONFATAL, "operation size not specified"); + else if (size_prob == 2) + error(ERR_NONFATAL, "mismatch in operand sizes"); + else if (size_prob == 3) + error(ERR_NONFATAL, "no instruction for this cpu level"); + else + error(ERR_NONFATAL, + "invalid combination of opcode and operands"); + } + return 0; +} + +long insn_size(long segment, long offset, int bits, unsigned long cp, + insn * instruction, efunc error) +{ + struct itemplate *temp; + + errfunc = error; /* to pass to other functions */ + cpu = cp; + + if (instruction->opcode == -1) + return 0; + + if (instruction->opcode == I_DB || + instruction->opcode == I_DW || + instruction->opcode == I_DD || + instruction->opcode == I_DQ || instruction->opcode == I_DT) { + extop *e; + long isize, osize, wsize = 0; /* placate gcc */ + + isize = 0; + switch (instruction->opcode) { + case I_DB: + wsize = 1; + break; + case I_DW: + wsize = 2; + break; + case I_DD: + wsize = 4; + break; + case I_DQ: + wsize = 8; + break; + case I_DT: + wsize = 10; + break; + } + + for (e = instruction->eops; e; e = e->next) { + long align; + + osize = 0; + if (e->type == EOT_DB_NUMBER) + osize = 1; + else if (e->type == EOT_DB_STRING) + osize = e->stringlen; + + align = (-osize) % wsize; + if (align < 0) + align += wsize; + isize += osize + align; + } + return isize * instruction->times; + } + + if (instruction->opcode == I_INCBIN) { + char fname[FILENAME_MAX]; + FILE *fp; + long len; + char *prefix = "", *combine; + char **pPrevPath = NULL; + + len = FILENAME_MAX - 1; + if (len > instruction->eops->stringlen) + len = instruction->eops->stringlen; + strncpy(fname, instruction->eops->stringval, len); + fname[len] = '\0'; + + while (1) { /* added by alexfru: 'incbin' uses include paths */ + combine = nasm_malloc(strlen(prefix) + len + 1); + strcpy(combine, prefix); + strcat(combine, fname); + + if ((fp = fopen(combine, "rb")) != NULL) { + nasm_free(combine); + break; + } + + nasm_free(combine); + pPrevPath = pp_get_include_path_ptr(pPrevPath); + if (pPrevPath == NULL) + break; + prefix = *pPrevPath; + } + + if (fp == NULL) + error(ERR_NONFATAL, "`incbin': unable to open file `%s'", + fname); + else if (fseek(fp, 0L, SEEK_END) < 0) + error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'", + fname); + else { + len = ftell(fp); + fclose(fp); + if (instruction->eops->next) { + len -= instruction->eops->next->offset; + if (instruction->eops->next->next && + len > instruction->eops->next->next->offset) { + len = instruction->eops->next->next->offset; + } + } + return instruction->times * len; + } + return 0; /* if we're here, there's an error */ + } + + temp = nasm_instructions[instruction->opcode]; + while (temp->opcode != -1) { + int m = matches(temp, instruction); + if (m == 99) + m += jmp_match(segment, offset, bits, instruction, temp->code); + + if (m == 100) { + /* we've matched an instruction. */ + long isize; + const char *codes = temp->code; + int j; + + isize = calcsize(segment, offset, bits, instruction, codes); + if (isize < 0) + return -1; + for (j = 0; j < instruction->nprefix; j++) { + if ((instruction->prefixes[j] != P_A16 && + instruction->prefixes[j] != P_O16 && bits == 16) || + (instruction->prefixes[j] != P_A32 && + instruction->prefixes[j] != P_O32 && bits == 32)) { + isize++; + } + } + return isize * instruction->times; + } + temp++; + } + return -1; /* didn't match any instruction */ +} + +/* check that opn[op] is a signed byte of size 16 or 32, + and return the signed value*/ +static int is_sbyte(insn * ins, int op, int size) +{ + signed long v; + int ret; + + ret = !(ins->forw_ref && ins->oprs[op].opflags) && /* dead in the water on forward reference or External */ + optimizing >= 0 && + !(ins->oprs[op].type & STRICT) && + ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG; + + v = ins->oprs[op].offset; + if (size == 16) + v = (signed short)v; /* sign extend if 16 bits */ + + return ret && v >= -128L && v <= 127L; +} + +static long calcsize(long segment, long offset, int bits, + insn * ins, const char *codes) +{ + long length = 0; + unsigned char c; + + (void)segment; /* Don't warn that this parameter is unused */ + (void)offset; /* Don't warn that this parameter is unused */ + + while (*codes) + switch (c = *codes++) { + case 01: + case 02: + case 03: + codes += c, length += c; + break; + case 04: + case 05: + case 06: + case 07: + length++; + break; + case 010: + case 011: + case 012: + codes++, length++; + break; + case 017: + length++; + break; + case 014: + case 015: + case 016: + length++; + break; + case 020: + case 021: + case 022: + length++; + break; + case 024: + case 025: + case 026: + length++; + break; + case 030: + case 031: + case 032: + length += 2; + break; + case 034: + case 035: + case 036: + if (ins->oprs[c - 034].type & (BITS16 | BITS32)) + length += (ins->oprs[c - 034].type & BITS16) ? 2 : 4; + else + length += (bits == 16) ? 2 : 4; + break; + case 037: + length += 2; + break; + case 040: + case 041: + case 042: + length += 4; + break; + case 044: + case 045: + case 046: + length += ((ins->oprs[c - 044].addr_size ? + ins->oprs[c - 044].addr_size : bits) == + 16 ? 2 : 4); + break; + case 050: + case 051: + case 052: + length++; + break; + case 060: + case 061: + case 062: + length += 2; + break; + case 064: + case 065: + case 066: + if (ins->oprs[c - 064].type & (BITS16 | BITS32)) + length += (ins->oprs[c - 064].type & BITS16) ? 2 : 4; + else + length += (bits == 16) ? 2 : 4; + break; + case 070: + case 071: + case 072: + length += 4; + break; + case 0130: + case 0131: + case 0132: + length += is_sbyte(ins, c - 0130, 16) ? 1 : 2; + break; + case 0133: + case 0134: + case 0135: + codes += 2; + length++; + break; + case 0140: + case 0141: + case 0142: + length += is_sbyte(ins, c - 0140, 32) ? 1 : 4; + break; + case 0143: + case 0144: + case 0145: + codes += 2; + length++; + break; + case 0300: + case 0301: + case 0302: + length += chsize(&ins->oprs[c - 0300], bits); + break; + case 0310: + length += (bits == 32); + break; + case 0311: + length += (bits == 16); + break; + case 0312: + break; + case 0320: + length += (bits == 32); + break; + case 0321: + length += (bits == 16); + break; + case 0322: + break; + case 0330: + codes++, length++; + break; + case 0331: + case 0332: + break; + case 0333: + length++; + break; + case 0340: + case 0341: + case 0342: + if (ins->oprs[0].segment != NO_SEG) + errfunc(ERR_NONFATAL, "attempt to reserve non-constant" + " quantity of BSS space"); + else + length += ins->oprs[0].offset << (c - 0340); + break; + case 0370: + case 0371: + case 0372: + break; + case 0373: + length++; + break; + default: /* can't do it by 'case' statements */ + if (c >= 0100 && c <= 0277) { /* it's an EA */ + ea ea_data; + if (!process_ea + (&ins->oprs[(c >> 3) & 7], &ea_data, bits, 0, + ins->forw_ref)) { + errfunc(ERR_NONFATAL, "invalid effective address"); + return -1; + } else + length += ea_data.size; + } else + errfunc(ERR_PANIC, "internal instruction table corrupt" + ": instruction code 0x%02X given", c); + } + return length; +} + +static void gencode(long segment, long offset, int bits, + insn * ins, const char *codes, long insn_end) +{ + static char condval[] = { /* conditional opcodes */ + 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2, + 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5, + 0x0, 0xA, 0xA, 0xB, 0x8, 0x4 + }; + unsigned char c; + unsigned char bytes[4]; + long data, size; + + while (*codes) + switch (c = *codes++) { + case 01: + case 02: + case 03: + out(offset, segment, codes, OUT_RAWDATA + c, NO_SEG, NO_SEG); + codes += c; + offset += c; + break; + + case 04: + case 06: + switch (ins->oprs[0].basereg) { + case R_CS: + bytes[0] = 0x0E + (c == 0x04 ? 1 : 0); + break; + case R_DS: + bytes[0] = 0x1E + (c == 0x04 ? 1 : 0); + break; + case R_ES: + bytes[0] = 0x06 + (c == 0x04 ? 1 : 0); + break; + case R_SS: + bytes[0] = 0x16 + (c == 0x04 ? 1 : 0); + break; + default: + errfunc(ERR_PANIC, + "bizarre 8086 segment register received"); + } + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset++; + break; + + case 05: + case 07: + switch (ins->oprs[0].basereg) { + case R_FS: + bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0); + break; + case R_GS: + bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0); + break; + default: + errfunc(ERR_PANIC, + "bizarre 386 segment register received"); + } + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset++; + break; + + case 010: + case 011: + case 012: + bytes[0] = *codes++ + regval(&ins->oprs[c - 010]); + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + break; + + case 017: + bytes[0] = 0; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + break; + + case 014: + case 015: + case 016: + if (ins->oprs[c - 014].offset < -128 + || ins->oprs[c - 014].offset > 127) { + errfunc(ERR_WARNING, "signed byte value exceeds bounds"); + } + + if (ins->oprs[c - 014].segment != NO_SEG) { + data = ins->oprs[c - 014].offset; + out(offset, segment, &data, OUT_ADDRESS + 1, + ins->oprs[c - 014].segment, ins->oprs[c - 014].wrt); + } else { + bytes[0] = ins->oprs[c - 014].offset; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, + NO_SEG); + } + offset += 1; + break; + + case 020: + case 021: + case 022: + if (ins->oprs[c - 020].offset < -256 + || ins->oprs[c - 020].offset > 255) { + errfunc(ERR_WARNING, "byte value exceeds bounds"); + } + if (ins->oprs[c - 020].segment != NO_SEG) { + data = ins->oprs[c - 020].offset; + out(offset, segment, &data, OUT_ADDRESS + 1, + ins->oprs[c - 020].segment, ins->oprs[c - 020].wrt); + } else { + bytes[0] = ins->oprs[c - 020].offset; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, + NO_SEG); + } + offset += 1; + break; + + case 024: + case 025: + case 026: + if (ins->oprs[c - 024].offset < 0 + || ins->oprs[c - 024].offset > 255) + errfunc(ERR_WARNING, "unsigned byte value exceeds bounds"); + if (ins->oprs[c - 024].segment != NO_SEG) { + data = ins->oprs[c - 024].offset; + out(offset, segment, &data, OUT_ADDRESS + 1, + ins->oprs[c - 024].segment, ins->oprs[c - 024].wrt); + } else { + bytes[0] = ins->oprs[c - 024].offset; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, + NO_SEG); + } + offset += 1; + break; + + case 030: + case 031: + case 032: + if (ins->oprs[c - 030].segment == NO_SEG && + ins->oprs[c - 030].wrt == NO_SEG && + (ins->oprs[c - 030].offset < -65536L || + ins->oprs[c - 030].offset > 65535L)) { + errfunc(ERR_WARNING, "word value exceeds bounds"); + } + data = ins->oprs[c - 030].offset; + out(offset, segment, &data, OUT_ADDRESS + 2, + ins->oprs[c - 030].segment, ins->oprs[c - 030].wrt); + offset += 2; + break; + + case 034: + case 035: + case 036: + if (ins->oprs[c - 034].type & (BITS16 | BITS32)) + size = (ins->oprs[c - 034].type & BITS16) ? 2 : 4; + else + size = (bits == 16) ? 2 : 4; + data = ins->oprs[c - 034].offset; + if (size == 2 && (data < -65536L || data > 65535L)) + errfunc(ERR_WARNING, "word value exceeds bounds"); + out(offset, segment, &data, OUT_ADDRESS + size, + ins->oprs[c - 034].segment, ins->oprs[c - 034].wrt); + offset += size; + break; + + case 037: + if (ins->oprs[0].segment == NO_SEG) + errfunc(ERR_NONFATAL, "value referenced by FAR is not" + " relocatable"); + data = 0L; + out(offset, segment, &data, OUT_ADDRESS + 2, + outfmt->segbase(1 + ins->oprs[0].segment), + ins->oprs[0].wrt); + offset += 2; + break; + + case 040: + case 041: + case 042: + data = ins->oprs[c - 040].offset; + out(offset, segment, &data, OUT_ADDRESS + 4, + ins->oprs[c - 040].segment, ins->oprs[c - 040].wrt); + offset += 4; + break; + + case 044: + case 045: + case 046: + data = ins->oprs[c - 044].offset; + size = ((ins->oprs[c - 044].addr_size ? + ins->oprs[c - 044].addr_size : bits) == 16 ? 2 : 4); + if (size == 2 && (data < -65536L || data > 65535L)) + errfunc(ERR_WARNING, "word value exceeds bounds"); + out(offset, segment, &data, OUT_ADDRESS + size, + ins->oprs[c - 044].segment, ins->oprs[c - 044].wrt); + offset += size; + break; + + case 050: + case 051: + case 052: + if (ins->oprs[c - 050].segment != segment) + errfunc(ERR_NONFATAL, + "short relative jump outside segment"); + data = ins->oprs[c - 050].offset - insn_end; + if (data > 127 || data < -128) + errfunc(ERR_NONFATAL, "short jump is out of range"); + bytes[0] = data; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + break; + + case 060: + case 061: + case 062: + if (ins->oprs[c - 060].segment != segment) { + data = ins->oprs[c - 060].offset; + out(offset, segment, &data, + OUT_REL2ADR + insn_end - offset, + ins->oprs[c - 060].segment, ins->oprs[c - 060].wrt); + } else { + data = ins->oprs[c - 060].offset - insn_end; + out(offset, segment, &data, + OUT_ADDRESS + 2, NO_SEG, NO_SEG); + } + offset += 2; + break; + + case 064: + case 065: + case 066: + if (ins->oprs[c - 064].type & (BITS16 | BITS32)) + size = (ins->oprs[c - 064].type & BITS16) ? 2 : 4; + else + size = (bits == 16) ? 2 : 4; + if (ins->oprs[c - 064].segment != segment) { + long reltype = (size == 2 ? OUT_REL2ADR : OUT_REL4ADR); + data = ins->oprs[c - 064].offset; + out(offset, segment, &data, reltype + insn_end - offset, + ins->oprs[c - 064].segment, ins->oprs[c - 064].wrt); + } else { + data = ins->oprs[c - 064].offset - insn_end; + out(offset, segment, &data, + OUT_ADDRESS + size, NO_SEG, NO_SEG); + } + offset += size; + break; + + case 070: + case 071: + case 072: + if (ins->oprs[c - 070].segment != segment) { + data = ins->oprs[c - 070].offset; + out(offset, segment, &data, + OUT_REL4ADR + insn_end - offset, + ins->oprs[c - 070].segment, ins->oprs[c - 070].wrt); + } else { + data = ins->oprs[c - 070].offset - insn_end; + out(offset, segment, &data, + OUT_ADDRESS + 4, NO_SEG, NO_SEG); + } + offset += 4; + break; + + case 0130: + case 0131: + case 0132: + data = ins->oprs[c - 0130].offset; + if (is_sbyte(ins, c - 0130, 16)) { + bytes[0] = data; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, + NO_SEG); + offset++; + } else { + if (ins->oprs[c - 0130].segment == NO_SEG && + ins->oprs[c - 0130].wrt == NO_SEG && + (data < -65536L || data > 65535L)) { + errfunc(ERR_WARNING, "word value exceeds bounds"); + } + out(offset, segment, &data, OUT_ADDRESS + 2, + ins->oprs[c - 0130].segment, ins->oprs[c - 0130].wrt); + offset += 2; + } + break; + + case 0133: + case 0134: + case 0135: + codes++; + bytes[0] = *codes++; + if (is_sbyte(ins, c - 0133, 16)) + bytes[0] |= 2; /* s-bit */ + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset++; + break; + + case 0140: + case 0141: + case 0142: + data = ins->oprs[c - 0140].offset; + if (is_sbyte(ins, c - 0140, 32)) { + bytes[0] = data; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, + NO_SEG); + offset++; + } else { + out(offset, segment, &data, OUT_ADDRESS + 4, + ins->oprs[c - 0140].segment, ins->oprs[c - 0140].wrt); + offset += 4; + } + break; + + case 0143: + case 0144: + case 0145: + codes++; + bytes[0] = *codes++; + if (is_sbyte(ins, c - 0143, 32)) + bytes[0] |= 2; /* s-bit */ + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset++; + break; + + case 0300: + case 0301: + case 0302: + if (chsize(&ins->oprs[c - 0300], bits)) { + *bytes = 0x67; + out(offset, segment, bytes, + OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + } else + offset += 0; + break; + + case 0310: + if (bits == 32) { + *bytes = 0x67; + out(offset, segment, bytes, + OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + } else + offset += 0; + break; + + case 0311: + if (bits == 16) { + *bytes = 0x67; + out(offset, segment, bytes, + OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + } else + offset += 0; + break; + + case 0312: + break; + + case 0320: + if (bits == 32) { + *bytes = 0x66; + out(offset, segment, bytes, + OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + } else + offset += 0; + break; + + case 0321: + if (bits == 16) { + *bytes = 0x66; + out(offset, segment, bytes, + OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + } else + offset += 0; + break; + + case 0322: + break; + + case 0330: + *bytes = *codes++ ^ condval[ins->condition]; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + break; + + case 0331: + case 0332: + break; + + case 0333: + *bytes = 0xF3; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + break; + + case 0340: + case 0341: + case 0342: + if (ins->oprs[0].segment != NO_SEG) + errfunc(ERR_PANIC, "non-constant BSS size in pass two"); + else { + long size = ins->oprs[0].offset << (c - 0340); + if (size > 0) + out(offset, segment, NULL, + OUT_RESERVE + size, NO_SEG, NO_SEG); + offset += size; + } + break; + + case 0370: + case 0371: + case 0372: + break; + + case 0373: + *bytes = bits == 16 ? 3 : 5; + out(offset, segment, bytes, OUT_RAWDATA + 1, NO_SEG, NO_SEG); + offset += 1; + break; + + default: /* can't do it by 'case' statements */ + if (c >= 0100 && c <= 0277) { /* it's an EA */ + ea ea_data; + int rfield; + unsigned char *p; + long s; + + if (c <= 0177) /* pick rfield from operand b */ + rfield = regval(&ins->oprs[c & 7]); + else /* rfield is constant */ + rfield = c & 7; + + if (!process_ea + (&ins->oprs[(c >> 3) & 7], &ea_data, bits, rfield, + ins->forw_ref)) { + errfunc(ERR_NONFATAL, "invalid effective address"); + } + + p = bytes; + *p++ = ea_data.modrm; + if (ea_data.sib_present) + *p++ = ea_data.sib; + + s = p - bytes; + out(offset, segment, bytes, OUT_RAWDATA + s, + NO_SEG, NO_SEG); + + switch (ea_data.bytes) { + case 0: + break; + case 1: + if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) { + data = ins->oprs[(c >> 3) & 7].offset; + out(offset, segment, &data, OUT_ADDRESS + 1, + ins->oprs[(c >> 3) & 7].segment, + ins->oprs[(c >> 3) & 7].wrt); + } else { + *bytes = ins->oprs[(c >> 3) & 7].offset; + out(offset, segment, bytes, OUT_RAWDATA + 1, + NO_SEG, NO_SEG); + } + s++; + break; + case 2: + case 4: + data = ins->oprs[(c >> 3) & 7].offset; + out(offset, segment, &data, + OUT_ADDRESS + ea_data.bytes, + ins->oprs[(c >> 3) & 7].segment, + ins->oprs[(c >> 3) & 7].wrt); + s += ea_data.bytes; + break; + } + offset += s; + } else + errfunc(ERR_PANIC, "internal instruction table corrupt" + ": instruction code 0x%02X given", c); + } +} + +#include "regvals.c" + +static int regval(operand * o) +{ + if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) { + errfunc(ERR_PANIC, "invalid operand passed to regval()"); + } + return regvals[o->basereg]; +} + +static int matches(struct itemplate *itemp, insn * instruction) +{ + int i, size[3], asize, oprs, ret; + + ret = 100; + + /* + * Check the opcode + */ + if (itemp->opcode != instruction->opcode) + return 0; + + /* + * Count the operands + */ + if (itemp->operands != instruction->operands) + return 0; + + /* + * Check that no spurious colons or TOs are present + */ + for (i = 0; i < itemp->operands; i++) + if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO)) + return 0; + + /* + * Check that the operand flags all match up + */ + for (i = 0; i < itemp->operands; i++) + if (itemp->opd[i] & ~instruction->oprs[i].type || + ((itemp->opd[i] & SIZE_MASK) && + ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) { + if ((itemp->opd[i] & ~instruction->oprs[i].type & NON_SIZE) || + (instruction->oprs[i].type & SIZE_MASK)) + return 0; + else +/* ret = 1; */ + return 1; + } + + /* + * Check operand sizes + */ + if (itemp->flags & IF_ARMASK) { + size[0] = size[1] = size[2] = 0; + + switch (itemp->flags & IF_ARMASK) { + case IF_AR0: + i = 0; + break; + case IF_AR1: + i = 1; + break; + case IF_AR2: + i = 2; + break; + default: + break; /* Shouldn't happen */ + } + if (itemp->flags & IF_SB) { + size[i] = BITS8; + } else if (itemp->flags & IF_SW) { + size[i] = BITS16; + } else if (itemp->flags & IF_SD) { + size[i] = BITS32; + } + } else { + asize = 0; + if (itemp->flags & IF_SB) { + asize = BITS8; + oprs = itemp->operands; + } else if (itemp->flags & IF_SW) { + asize = BITS16; + oprs = itemp->operands; + } else if (itemp->flags & IF_SD) { + asize = BITS32; + oprs = itemp->operands; + } + size[0] = size[1] = size[2] = asize; + } + + if (itemp->flags & (IF_SM | IF_SM2)) { + oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands); + asize = 0; + for (i = 0; i < oprs; i++) { + if ((asize = itemp->opd[i] & SIZE_MASK) != 0) { + int j; + for (j = 0; j < oprs; j++) + size[j] = asize; + break; + } + } + } else { + oprs = itemp->operands; + } + + for (i = 0; i < itemp->operands; i++) + if (!(itemp->opd[i] & SIZE_MASK) && + (instruction->oprs[i].type & SIZE_MASK & ~size[i])) +/* ret = 2; */ + return 2; + + /* + * Check template is okay at the set cpu level + */ + if ((itemp->flags & IF_PLEVEL) > cpu) + return 3; + + /* + * Check if special handling needed for Jumps + */ + if ((unsigned char)(itemp->code[0]) >= 0370) + return 99; + + return ret; +} + +static ea *process_ea(operand * input, ea * output, int addrbits, + int rfield, int forw_ref) +{ + if (!(REGISTER & ~input->type)) { /* it's a single register */ + static int regs[] = { + R_AL, R_CL, R_DL, R_BL, R_AH, R_CH, R_DH, R_BH, + R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI, + R_EAX, R_ECX, R_EDX, R_EBX, R_ESP, R_EBP, R_ESI, R_EDI, + R_MM0, R_MM1, R_MM2, R_MM3, R_MM4, R_MM5, R_MM6, R_MM7, + R_XMM0, R_XMM1, R_XMM2, R_XMM3, R_XMM4, R_XMM5, R_XMM6, R_XMM7 + }; + int i; + + for (i = 0; i < elements(regs); i++) + if (input->basereg == regs[i]) + break; + if (i < elements(regs)) { + output->sib_present = FALSE; /* no SIB necessary */ + output->bytes = 0; /* no offset necessary either */ + output->modrm = 0xC0 | (rfield << 3) | (i & 7); + } else + return NULL; + } else { /* it's a memory reference */ + if (input->basereg == -1 + && (input->indexreg == -1 || input->scale == 0)) { + /* it's a pure offset */ + if (input->addr_size) + addrbits = input->addr_size; + output->sib_present = FALSE; + output->bytes = (addrbits == 32 ? 4 : 2); + output->modrm = (addrbits == 32 ? 5 : 6) | (rfield << 3); + } else { /* it's an indirection */ + int i = input->indexreg, b = input->basereg, s = input->scale; + long o = input->offset, seg = input->segment; + int hb = input->hintbase, ht = input->hinttype; + int t; + + if (s == 0) + i = -1; /* make this easy, at least */ + + if (i == R_EAX || i == R_EBX || i == R_ECX || i == R_EDX + || i == R_EBP || i == R_ESP || i == R_ESI || i == R_EDI + || b == R_EAX || b == R_EBX || b == R_ECX || b == R_EDX + || b == R_EBP || b == R_ESP || b == R_ESI || b == R_EDI) { + /* it must be a 32-bit memory reference. Firstly we have + * to check that all registers involved are type Exx. */ + if (i != -1 && i != R_EAX && i != R_EBX && i != R_ECX + && i != R_EDX && i != R_EBP && i != R_ESP && i != R_ESI + && i != R_EDI) + return NULL; + if (b != -1 && b != R_EAX && b != R_EBX && b != R_ECX + && b != R_EDX && b != R_EBP && b != R_ESP && b != R_ESI + && b != R_EDI) + return NULL; + + /* While we're here, ensure the user didn't specify WORD. */ + if (input->addr_size == 16) + return NULL; + + /* now reorganise base/index */ + if (s == 1 && b != i && b != -1 && i != -1 && + ((hb == b && ht == EAH_NOTBASE) + || (hb == i && ht == EAH_MAKEBASE))) + t = b, b = i, i = t; /* swap if hints say so */ + if (b == i) /* convert EAX+2*EAX to 3*EAX */ + b = -1, s++; + if (b == -1 && s == 1 && !(hb == i && ht == EAH_NOTBASE)) + b = i, i = -1; /* make single reg base, unless hint */ + if (((s == 2 && i != R_ESP + && !(input->eaflags & EAF_TIMESTWO)) || s == 3 + || s == 5 || s == 9) && b == -1) + b = i, s--; /* convert 3*EAX to EAX+2*EAX */ + if (i == -1 && b != R_ESP + && (input->eaflags & EAF_TIMESTWO)) + i = b, b = -1, s = 1; + /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */ + if (s == 1 && i == R_ESP) /* swap ESP into base if scale is 1 */ + i = b, b = R_ESP; + if (i == R_ESP + || (s != 1 && s != 2 && s != 4 && s != 8 && i != -1)) + return NULL; /* wrong, for various reasons */ + + if (i == -1 && b != R_ESP) { /* no SIB needed */ + int mod, rm; + switch (b) { + case R_EAX: + rm = 0; + break; + case R_ECX: + rm = 1; + break; + case R_EDX: + rm = 2; + break; + case R_EBX: + rm = 3; + break; + case R_EBP: + rm = 5; + break; + case R_ESI: + rm = 6; + break; + case R_EDI: + rm = 7; + break; + case -1: + rm = 5; + break; + default: /* should never happen */ + return NULL; + } + if (b == -1 || (b != R_EBP && o == 0 && + seg == NO_SEG && !forw_ref && + !(input->eaflags & + (EAF_BYTEOFFS | EAF_WORDOFFS)))) + mod = 0; + else if (input->eaflags & EAF_BYTEOFFS || + (o >= -128 && o <= 127 && seg == NO_SEG + && !forw_ref + && !(input->eaflags & EAF_WORDOFFS))) { + mod = 1; + } else + mod = 2; + + output->sib_present = FALSE; + output->bytes = (b == -1 || mod == 2 ? 4 : mod); + output->modrm = (mod << 6) | (rfield << 3) | rm; + } else { /* we need a SIB */ + int mod, scale, index, base; + + switch (b) { + case R_EAX: + base = 0; + break; + case R_ECX: + base = 1; + break; + case R_EDX: + base = 2; + break; + case R_EBX: + base = 3; + break; + case R_ESP: + base = 4; + break; + case R_EBP: + case -1: + base = 5; + break; + case R_ESI: + base = 6; + break; + case R_EDI: + base = 7; + break; + default: /* then what the smeg is it? */ + return NULL; /* panic */ + } + + switch (i) { + case R_EAX: + index = 0; + break; + case R_ECX: + index = 1; + break; + case R_EDX: + index = 2; + break; + case R_EBX: + index = 3; + break; + case -1: + index = 4; + break; + case R_EBP: + index = 5; + break; + case R_ESI: + index = 6; + break; + case R_EDI: + index = 7; + break; + default: /* then what the smeg is it? */ + return NULL; /* panic */ + } + + if (i == -1) + s = 1; + switch (s) { + case 1: + scale = 0; + break; + case 2: + scale = 1; + break; + case 4: + scale = 2; + break; + case 8: + scale = 3; + break; + default: /* then what the smeg is it? */ + return NULL; /* panic */ + } + + if (b == -1 || (b != R_EBP && o == 0 && + seg == NO_SEG && !forw_ref && + !(input->eaflags & + (EAF_BYTEOFFS | EAF_WORDOFFS)))) + mod = 0; + else if (input->eaflags & EAF_BYTEOFFS || + (o >= -128 && o <= 127 && seg == NO_SEG + && !forw_ref + && !(input->eaflags & EAF_WORDOFFS))) + mod = 1; + else + mod = 2; + + output->sib_present = TRUE; + output->bytes = (b == -1 || mod == 2 ? 4 : mod); + output->modrm = (mod << 6) | (rfield << 3) | 4; + output->sib = (scale << 6) | (index << 3) | base; + } + } else { /* it's 16-bit */ + int mod, rm; + + /* check all registers are BX, BP, SI or DI */ + if ((b != -1 && b != R_BP && b != R_BX && b != R_SI + && b != R_DI) || (i != -1 && i != R_BP && i != R_BX + && i != R_SI && i != R_DI)) + return NULL; + + /* ensure the user didn't specify DWORD */ + if (input->addr_size == 32) + return NULL; + + if (s != 1 && i != -1) + return NULL; /* no can do, in 16-bit EA */ + if (b == -1 && i != -1) { + int tmp = b; + b = i; + i = tmp; + } /* swap */ + if ((b == R_SI || b == R_DI) && i != -1) { + int tmp = b; + b = i; + i = tmp; + } + /* have BX/BP as base, SI/DI index */ + if (b == i) + return NULL; /* shouldn't ever happen, in theory */ + if (i != -1 && b != -1 && + (i == R_BP || i == R_BX || b == R_SI || b == R_DI)) + return NULL; /* invalid combinations */ + if (b == -1) /* pure offset: handled above */ + return NULL; /* so if it gets to here, panic! */ + + rm = -1; + if (i != -1) + switch (i * 256 + b) { + case R_SI * 256 + R_BX: + rm = 0; + break; + case R_DI * 256 + R_BX: + rm = 1; + break; + case R_SI * 256 + R_BP: + rm = 2; + break; + case R_DI * 256 + R_BP: + rm = 3; + break; + } else + switch (b) { + case R_SI: + rm = 4; + break; + case R_DI: + rm = 5; + break; + case R_BP: + rm = 6; + break; + case R_BX: + rm = 7; + break; + } + if (rm == -1) /* can't happen, in theory */ + return NULL; /* so panic if it does */ + + if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 && + !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS))) + mod = 0; + else if (input->eaflags & EAF_BYTEOFFS || + (o >= -128 && o <= 127 && seg == NO_SEG + && !forw_ref + && !(input->eaflags & EAF_WORDOFFS))) + mod = 1; + else + mod = 2; + + output->sib_present = FALSE; /* no SIB - it's 16-bit */ + output->bytes = mod; /* bytes of offset needed */ + output->modrm = (mod << 6) | (rfield << 3) | rm; + } + } + } + output->size = 1 + output->sib_present + output->bytes; + return output; +} + +static int chsize(operand * input, int addrbits) +{ + if (!(MEMORY & ~input->type)) { + int i = input->indexreg, b = input->basereg; + + if (input->scale == 0) + i = -1; + + if (i == -1 && b == -1) /* pure offset */ + return (input->addr_size != 0 && input->addr_size != addrbits); + + if (i == R_EAX || i == R_EBX || i == R_ECX || i == R_EDX + || i == R_EBP || i == R_ESP || i == R_ESI || i == R_EDI + || b == R_EAX || b == R_EBX || b == R_ECX || b == R_EDX + || b == R_EBP || b == R_ESP || b == R_ESI || b == R_EDI) + return (addrbits == 16); + else + return (addrbits == 32); + } else + return 0; +} diff --git a/assemble.h b/assemble.h index b08ceb13..9d55bc3b 100644 --- a/assemble.h +++ b/assemble.h @@ -9,10 +9,10 @@ #ifndef NASM_ASSEMBLE_H #define NASM_ASSEMBLE_H -long insn_size (long segment, long offset, int bits, unsigned long cpu, - insn *instruction, efunc error); -long assemble (long segment, long offset, int bits, unsigned long cpu, - insn *instruction, struct ofmt *output, efunc error, - ListGen *listgen); +long insn_size(long segment, long offset, int bits, unsigned long cpu, + insn * instruction, efunc error); +long assemble(long segment, long offset, int bits, unsigned long cpu, + insn * instruction, struct ofmt *output, efunc error, + ListGen * listgen); #endif diff --git a/disasm.c b/disasm.c dissimilarity index 84% index dd806d6f..534c7fea 100644 --- a/disasm.c +++ b/disasm.c @@ -1,755 +1,898 @@ -/* disasm.c where all the _work_ gets done in the Netwide Disassembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * initial version 27/iii/95 by Simon Tatham - */ - -#include -#include - -#include "nasm.h" -#include "disasm.h" -#include "sync.h" -#include "insns.h" - -#include "names.c" - -extern struct itemplate **itable[]; - -/* - * Flags that go into the `segment' field of `insn' structures - * during disassembly. - */ -#define SEG_RELATIVE 1 -#define SEG_32BIT 2 -#define SEG_RMREG 4 -#define SEG_DISP8 8 -#define SEG_DISP16 16 -#define SEG_DISP32 32 -#define SEG_NODISP 64 -#define SEG_SIGNED 128 - -static int whichreg(long regflags, int regval) -{ -#include "regdis.c" - - if (!(REG_AL & ~regflags)) - return R_AL; - if (!(REG_AX & ~regflags)) - return R_AX; - if (!(REG_EAX & ~regflags)) - return R_EAX; - if (!(REG_DL & ~regflags)) - return R_DL; - if (!(REG_DX & ~regflags)) - return R_DX; - if (!(REG_EDX & ~regflags)) - return R_EDX; - if (!(REG_CL & ~regflags)) - return R_CL; - if (!(REG_CX & ~regflags)) - return R_CX; - if (!(REG_ECX & ~regflags)) - return R_ECX; - if (!(FPU0 & ~regflags)) - return R_ST0; - if (!(REG_CS & ~regflags)) - return (regval == 1) ? R_CS : 0; - if (!(REG_DESS & ~regflags)) - return (regval == 0 || regval == 2 || regval == 3 ? sreg[regval] : 0); - if (!(REG_FSGS & ~regflags)) - return (regval == 4 || regval == 5 ? sreg[regval] : 0); - if (!(REG_SEG67 & ~regflags)) - return (regval == 6 || regval == 7 ? sreg[regval] : 0); - - /* All the entries below look up regval in an 8-entry array */ - if (regval < 0 || regval > 7) - return 0; - - if (!((REGMEM|BITS8) & ~regflags)) - return reg8[regval]; - if (!((REGMEM|BITS16) & ~regflags)) - return reg16[regval]; - if (!((REGMEM|BITS32) & ~regflags)) - return reg32[regval]; - if (!(REG_SREG & ~regflags)) - return sreg[regval]; - if (!(REG_CREG & ~regflags)) - return creg[regval]; - if (!(REG_DREG & ~regflags)) - return dreg[regval]; - if (!(REG_TREG & ~regflags)) - return treg[regval]; - if (!(FPUREG & ~regflags)) - return fpureg[regval]; - if (!(MMXREG & ~regflags)) - return mmxreg[regval]; - if (!(XMMREG & ~regflags)) - return xmmreg[regval]; - - return 0; -} - -static const char *whichcond(int condval) -{ - static int conds[] = { - C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A, - C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G - }; - return conditions[conds[condval]]; -} - -/* - * Process an effective address (ModRM) specification. - */ -static unsigned char *do_ea (unsigned char *data, int modrm, int asize, - int segsize, operand *op) -{ - int mod, rm, scale, index, base; - - mod = (modrm >> 6) & 03; - rm = modrm & 07; - - if (mod == 3) { /* pure register version */ - op->basereg = rm; - op->segment |= SEG_RMREG; - return data; - } - - op->addr_size = 0; - - if (asize == 16) { - /* - * specifies the displacement size (none, byte or - * word), and specifies the register combination. - * Exception: mod=0,rm=6 does not specify [BP] as one might - * expect, but instead specifies [disp16]. - */ - op->indexreg = op->basereg = -1; - op->scale = 1; /* always, in 16 bits */ - switch (rm) { - case 0: op->basereg = R_BX; op->indexreg = R_SI; break; - case 1: op->basereg = R_BX; op->indexreg = R_DI; break; - case 2: op->basereg = R_BP; op->indexreg = R_SI; break; - case 3: op->basereg = R_BP; op->indexreg = R_DI; break; - case 4: op->basereg = R_SI; break; - case 5: op->basereg = R_DI; break; - case 6: op->basereg = R_BP; break; - case 7: op->basereg = R_BX; break; - } - if (rm == 6 && mod == 0) { /* special case */ - op->basereg = -1; - if (segsize != 16) - op->addr_size = 16; - mod = 2; /* fake disp16 */ - } - switch (mod) { - case 0: - op->segment |= SEG_NODISP; - break; - case 1: - op->segment |= SEG_DISP8; - op->offset = (signed char) *data++; - break; - case 2: - op->segment |= SEG_DISP16; - op->offset = *data++; - op->offset |= ((unsigned) *data++) << 8; - break; - } - return data; - } else { - /* - * Once again, specifies displacement size (this time - * none, byte or *dword*), while specifies the base - * register. Again, [EBP] is missing, replaced by a pure - * disp32 (this time that's mod=0,rm=*5*). However, rm=4 - * indicates not a single base register, but instead the - * presence of a SIB byte... - */ - op->indexreg = -1; - switch (rm) { - case 0: op->basereg = R_EAX; break; - case 1: op->basereg = R_ECX; break; - case 2: op->basereg = R_EDX; break; - case 3: op->basereg = R_EBX; break; - case 5: op->basereg = R_EBP; break; - case 6: op->basereg = R_ESI; break; - case 7: op->basereg = R_EDI; break; - } - if (rm == 5 && mod == 0) { - op->basereg = -1; - if (segsize != 32) - op->addr_size = 32; - mod = 2; /* fake disp32 */ - } - if (rm == 4) { /* process SIB */ - scale = (*data >> 6) & 03; - index = (*data >> 3) & 07; - base = *data & 07; - data++; - - op->scale = 1 << scale; - switch (index) { - case 0: op->indexreg = R_EAX; break; - case 1: op->indexreg = R_ECX; break; - case 2: op->indexreg = R_EDX; break; - case 3: op->indexreg = R_EBX; break; - case 4: op->indexreg = -1; break; - case 5: op->indexreg = R_EBP; break; - case 6: op->indexreg = R_ESI; break; - case 7: op->indexreg = R_EDI; break; - } - - switch (base) { - case 0: op->basereg = R_EAX; break; - case 1: op->basereg = R_ECX; break; - case 2: op->basereg = R_EDX; break; - case 3: op->basereg = R_EBX; break; - case 4: op->basereg = R_ESP; break; - case 6: op->basereg = R_ESI; break; - case 7: op->basereg = R_EDI; break; - case 5: - if (mod == 0) { - mod = 2; - op->basereg = -1; - } else - op->basereg = R_EBP; - break; - } - } - switch (mod) { - case 0: - op->segment |= SEG_NODISP; - break; - case 1: - op->segment |= SEG_DISP8; - op->offset = (signed char) *data++; - break; - case 2: - op->segment |= SEG_DISP32; - op->offset = *data++; - op->offset |= ((unsigned) *data++) << 8; - op->offset |= ((long) *data++) << 16; - op->offset |= ((long) *data++) << 24; - break; - } - return data; - } -} - -/* - * Determine whether the instruction template in t corresponds to the data - * stream in data. Return the number of bytes matched if so. - */ -static int matches (struct itemplate *t, unsigned char *data, int asize, - int osize, int segsize, int rep, insn *ins) -{ - unsigned char * r = (unsigned char *)(t->code); - unsigned char * origdata = data; - int a_used = FALSE, o_used = FALSE; - int drep = 0; - - if ( rep == 0xF2 ) - drep = P_REPNE; - else if ( rep == 0xF3 ) - drep = P_REP; - - while (*r) - { - int c = *r++; - if (c >= 01 && c <= 03) { - while (c--) - if (*r++ != *data++) - return FALSE; - } - if (c == 04) { - switch (*data++) { - case 0x07: ins->oprs[0].basereg = 0; break; - case 0x17: ins->oprs[0].basereg = 2; break; - case 0x1F: ins->oprs[0].basereg = 3; break; - default: return FALSE; - } - } - if (c == 05) { - switch (*data++) { - case 0xA1: ins->oprs[0].basereg = 4; break; - case 0xA9: ins->oprs[0].basereg = 5; break; - default: return FALSE; - } - } - if (c == 06) { - switch (*data++) { - case 0x06: ins->oprs[0].basereg = 0; break; - case 0x0E: ins->oprs[0].basereg = 1; break; - case 0x16: ins->oprs[0].basereg = 2; break; - case 0x1E: ins->oprs[0].basereg = 3; break; - default: return FALSE; - } - } - if (c == 07) { - switch (*data++) { - case 0xA0: ins->oprs[0].basereg = 4; break; - case 0xA8: ins->oprs[0].basereg = 5; break; - default: return FALSE; - } - } - if (c >= 010 && c <= 012) { - int t = *r++, d = *data++; - if (d < t || d > t+7) - return FALSE; - else { - ins->oprs[c-010].basereg = d-t; - ins->oprs[c-010].segment |= SEG_RMREG; - } - } - if (c == 017) - if (*data++) - return FALSE; - if (c >= 014 && c <= 016) { - ins->oprs[c-014].offset = (signed char) *data++; - ins->oprs[c-014].segment |= SEG_SIGNED; - } - if (c >= 020 && c <= 022) - ins->oprs[c-020].offset = *data++; - if (c >= 024 && c <= 026) - ins->oprs[c-024].offset = *data++; - if (c >= 030 && c <= 032) { - ins->oprs[c-030].offset = *data++; - ins->oprs[c-030].offset |= (((unsigned) *data++) << 8); - } - if (c >= 034 && c <= 036) { - ins->oprs[c-034].offset = *data++; - ins->oprs[c-034].offset |= (((unsigned) *data++) << 8); - if (osize == 32) { - ins->oprs[c-034].offset |= (((long) *data++) << 16); - ins->oprs[c-034].offset |= (((long) *data++) << 24); - } - if (segsize != asize) - ins->oprs[c-034].addr_size = asize; - } - if (c >= 040 && c <= 042) { - ins->oprs[c-040].offset = *data++; - ins->oprs[c-040].offset |= (((unsigned) *data++) << 8); - ins->oprs[c-040].offset |= (((long) *data++) << 16); - ins->oprs[c-040].offset |= (((long) *data++) << 24); - } - if (c >= 044 && c <= 046) { - ins->oprs[c-044].offset = *data++; - ins->oprs[c-044].offset |= (((unsigned) *data++) << 8); - if (asize == 32) { - ins->oprs[c-044].offset |= (((long) *data++) << 16); - ins->oprs[c-044].offset |= (((long) *data++) << 24); - } - if (segsize != asize) - ins->oprs[c-044].addr_size = asize; - } - if (c >= 050 && c <= 052) { - ins->oprs[c-050].offset = (signed char) *data++; - ins->oprs[c-050].segment |= SEG_RELATIVE; - } - if (c >= 060 && c <= 062) { - ins->oprs[c-060].offset = *data++; - ins->oprs[c-060].offset |= (((unsigned) *data++) << 8); - ins->oprs[c-060].segment |= SEG_RELATIVE; - ins->oprs[c-060].segment &= ~SEG_32BIT; - } - if (c >= 064 && c <= 066) { - ins->oprs[c-064].offset = *data++; - ins->oprs[c-064].offset |= (((unsigned) *data++) << 8); - if (osize == 32) { - ins->oprs[c-064].offset |= (((long) *data++) << 16); - ins->oprs[c-064].offset |= (((long) *data++) << 24); - ins->oprs[c-064].segment |= SEG_32BIT; - } else - ins->oprs[c-064].segment &= ~SEG_32BIT; - ins->oprs[c-064].segment |= SEG_RELATIVE; - if (segsize != osize) { - ins->oprs[c-064].type = - (ins->oprs[c-064].type & NON_SIZE) - | ((osize == 16) ? BITS16 : BITS32); - } - } - if (c >= 070 && c <= 072) { - ins->oprs[c-070].offset = *data++; - ins->oprs[c-070].offset |= (((unsigned) *data++) << 8); - ins->oprs[c-070].offset |= (((long) *data++) << 16); - ins->oprs[c-070].offset |= (((long) *data++) << 24); - ins->oprs[c-070].segment |= SEG_32BIT | SEG_RELATIVE; - } - if (c >= 0100 && c < 0130) { - int modrm = *data++; - ins->oprs[c & 07].basereg = (modrm >> 3) & 07; - ins->oprs[c & 07].segment |= SEG_RMREG; - data = do_ea (data, modrm, asize, segsize, - &ins->oprs[(c >> 3) & 07]); - } - if (c >= 0130 && c <= 0132) { - ins->oprs[c-0130].offset = *data++; - ins->oprs[c-0130].offset |= (((unsigned) *data++) << 8); - } - if (c >= 0140 && c <= 0142) { - ins->oprs[c-0140].offset = *data++; - ins->oprs[c-0140].offset |= (((unsigned) *data++) << 8); - ins->oprs[c-0140].offset |= (((long) *data++) << 16); - ins->oprs[c-0140].offset |= (((long) *data++) << 24); - } - if (c >= 0200 && c <= 0277) { - int modrm = *data++; - if (((modrm >> 3) & 07) != (c & 07)) - return FALSE; /* spare field doesn't match up */ - data = do_ea (data, modrm, asize, segsize, - &ins->oprs[(c >> 3) & 07]); - } - if (c >= 0300 && c <= 0302) { - if (asize) - ins->oprs[c-0300].segment |= SEG_32BIT; - else - ins->oprs[c-0300].segment &= ~SEG_32BIT; - a_used = TRUE; - } - if (c == 0310) { - if (asize == 32) - return FALSE; - else - a_used = TRUE; - } - if (c == 0311) { - if (asize == 16) - return FALSE; - else - a_used = TRUE; - } - if (c == 0312) { - if (asize != segsize) - return FALSE; - else - a_used = TRUE; - } - if (c == 0320) { - if (osize == 32) - return FALSE; - else - o_used = TRUE; - } - if (c == 0321) { - if (osize == 16) - return FALSE; - else - o_used = TRUE; - } - if (c == 0322) { - if (osize != segsize) - return FALSE; - else - o_used = TRUE; - } - if (c == 0330) { - int t = *r++, d = *data++; - if (d < t || d > t+15) - return FALSE; - else - ins->condition = d - t; - } - if (c == 0331) { - if ( rep ) - return FALSE; - } - if (c == 0332) { - if (drep == P_REP) - drep = P_REPE; - } - if (c == 0333) { - if ( rep != 0xF3 ) - return FALSE; - drep = 0; - } - } - - /* - * Check for unused rep or a/o prefixes. - */ - ins->nprefix = 0; - if (drep) - ins->prefixes[ins->nprefix++] = drep; - if (!a_used && asize != segsize) - ins->prefixes[ins->nprefix++] = (asize == 16 ? P_A16 : P_A32); - if (!o_used && osize != segsize) - ins->prefixes[ins->nprefix++] = (osize == 16 ? P_O16 : P_O32); - - return data - origdata; -} - -long disasm (unsigned char *data, char *output, int outbufsize, int segsize, - long offset, int autosync, unsigned long prefer) -{ - struct itemplate **p, **best_p; - int length, best_length = 0; - char *segover; - int rep, lock, asize, osize, i, slen, colon; - unsigned char *origdata; - int works; - insn tmp_ins, ins; - unsigned long goodness, best; - - /* - * Scan for prefixes. - */ - asize = osize = segsize; - segover = NULL; - rep = lock = 0; - origdata = data; - for (;;) { - if (*data == 0xF3 || *data == 0xF2) - rep = *data++; - else if (*data == 0xF0) - lock = *data++; - else if (*data == 0x2E || *data == 0x36 || *data == 0x3E || - *data == 0x26 || *data == 0x64 || *data == 0x65) { - switch (*data++) { - case 0x2E: segover = "cs"; break; - case 0x36: segover = "ss"; break; - case 0x3E: segover = "ds"; break; - case 0x26: segover = "es"; break; - case 0x64: segover = "fs"; break; - case 0x65: segover = "gs"; break; - } - } else if (*data == 0x66) - osize = 48 - segsize, data++; - else if (*data == 0x67) - asize = 48 - segsize, data++; - else - break; - } - - tmp_ins.oprs[0].segment = tmp_ins.oprs[1].segment = - tmp_ins.oprs[2].segment = - tmp_ins.oprs[0].addr_size = tmp_ins.oprs[1].addr_size = - tmp_ins.oprs[2].addr_size = (segsize == 16 ? 0 : SEG_32BIT); - tmp_ins.condition = -1; - best = ~0UL; /* Worst possible */ - best_p = NULL; - for (p = itable[*data]; *p; p++) { - if ( (length = matches(*p, data, asize, osize, - segsize, rep, &tmp_ins)) ) { - works = TRUE; - /* - * Final check to make sure the types of r/m match up. - */ - for (i = 0; i < (*p)->operands; i++) { - if ( - /* If it's a mem-only EA but we have a register, die. */ - ((tmp_ins.oprs[i].segment & SEG_RMREG) && - !(MEMORY & ~(*p)->opd[i])) || - - /* If it's a reg-only EA but we have a memory ref, die. */ - (!(tmp_ins.oprs[i].segment & SEG_RMREG) && - !(REGNORM & ~(*p)->opd[i]) && - !((*p)->opd[i] & REG_SMASK)) || - - /* Register type mismatch (eg FS vs REG_DESS): die. */ - ((((*p)->opd[i] & (REGISTER | FPUREG)) || - (tmp_ins.oprs[i].segment & SEG_RMREG)) && - !whichreg ((*p)->opd[i], tmp_ins.oprs[i].basereg))) { - works = FALSE; - break; - } - } - - if (works) { - goodness = ((*p)->flags & IF_PFMASK) ^ prefer; - if ( goodness < best ) { - /* This is the best one found so far */ - best = goodness; - best_p = p; - best_length = length; - ins = tmp_ins; - } - } - } - } - - if (!best_p) - return 0; /* no instruction was matched */ - - /* Pick the best match */ - p = best_p; - length = best_length; - - slen = 0; - - /* TODO: snprintf returns the value that the string would have if - * the buffer were long enough, and not the actual length of - * the returned string, so each instance of using the return - * value of snprintf should actually be checked to assure that - * the return value is "sane." Maybe a macro wrapper could - * be used for that purpose. - */ - if (lock) - slen += snprintf(output+slen, outbufsize-slen, "lock "); - for (i = 0; i < ins.nprefix; i++) - switch (ins.prefixes[i]) { - case P_REP: slen += snprintf(output+slen, outbufsize-slen, "rep "); break; - case P_REPE: slen += snprintf(output+slen, outbufsize-slen, "repe "); break; - case P_REPNE: slen += snprintf(output+slen, outbufsize-slen, "repne "); break; - case P_A16: slen += snprintf(output+slen, outbufsize-slen, "a16 "); break; - case P_A32: slen += snprintf(output+slen, outbufsize-slen, "a32 "); break; - case P_O16: slen += snprintf(output+slen, outbufsize-slen, "o16 "); break; - case P_O32: slen += snprintf(output+slen, outbufsize-slen, "o32 "); break; - } - - for (i = 0; i < elements(ico); i++) - if ((*p)->opcode == ico[i]) { - slen += snprintf(output+slen, outbufsize-slen, "%s%s", icn[i], - whichcond(ins.condition)); - break; - } - if (i >= elements(ico)) - slen += snprintf(output+slen, outbufsize-slen, "%s", insn_names[(*p)->opcode]); - colon = FALSE; - length += data - origdata; /* fix up for prefixes */ - for (i=0; i<(*p)->operands; i++) { - output[slen++] = (colon ? ':' : i==0 ? ' ' : ','); - - if (ins.oprs[i].segment & SEG_RELATIVE) { - ins.oprs[i].offset += offset + length; - /* - * sort out wraparound - */ - if (!(ins.oprs[i].segment & SEG_32BIT)) - ins.oprs[i].offset &= 0xFFFF; - /* - * add sync marker, if autosync is on - */ - if (autosync) - add_sync (ins.oprs[i].offset, 0L); - } - - if ((*p)->opd[i] & COLON) - colon = TRUE; - else - colon = FALSE; - - if (((*p)->opd[i] & (REGISTER | FPUREG)) || - (ins.oprs[i].segment & SEG_RMREG)) - { - ins.oprs[i].basereg = whichreg ((*p)->opd[i], - ins.oprs[i].basereg); - if ( (*p)->opd[i] & TO ) - slen += snprintf(output+slen, outbufsize-slen, "to "); - slen += snprintf(output+slen, outbufsize-slen, "%s", - reg_names[ins.oprs[i].basereg-EXPR_REG_START]); - } else if (!(UNITY & ~(*p)->opd[i])) { - output[slen++] = '1'; - } else if ( (*p)->opd[i] & IMMEDIATE ) { - if ( (*p)->opd[i] & BITS8 ) { - slen += snprintf(output+slen, outbufsize-slen, "byte "); - if (ins.oprs[i].segment & SEG_SIGNED) { - if (ins.oprs[i].offset < 0) { - ins.oprs[i].offset *= -1; - output[slen++] = '-'; - } else - output[slen++] = '+'; - } - } else if ( (*p)->opd[i] & BITS16 ) { - slen += snprintf(output+slen, outbufsize-slen, "word "); - } else if ( (*p)->opd[i] & BITS32 ) { - slen += snprintf(output+slen, outbufsize-slen, "dword "); - } else if ( (*p)->opd[i] & NEAR ) { - slen += snprintf(output+slen, outbufsize-slen, "near "); - } else if ( (*p)->opd[i] & SHORT ) { - slen += snprintf(output+slen, outbufsize-slen, "short "); - } - slen += snprintf(output+slen, outbufsize-slen, "0x%lx", ins.oprs[i].offset); - } else if ( !(MEM_OFFS & ~(*p)->opd[i]) ) { - slen += snprintf(output+slen, outbufsize-slen, "[%s%s%s0x%lx]", - (segover ? segover : ""), - (segover ? ":" : ""), - (ins.oprs[i].addr_size == 32 ? "dword " : - ins.oprs[i].addr_size == 16 ? "word " : ""), - ins.oprs[i].offset); - segover = NULL; - } else if ( !(REGMEM & ~(*p)->opd[i]) ) { - int started = FALSE; - if ( (*p)->opd[i] & BITS8 ) - slen += snprintf(output+slen, outbufsize-slen, "byte "); - if ( (*p)->opd[i] & BITS16 ) - slen += snprintf(output+slen, outbufsize-slen, "word "); - if ( (*p)->opd[i] & BITS32 ) - slen += snprintf(output+slen, outbufsize-slen, "dword "); - if ( (*p)->opd[i] & BITS64 ) - slen += snprintf(output+slen, outbufsize-slen, "qword "); - if ( (*p)->opd[i] & BITS80 ) - slen += snprintf(output+slen, outbufsize-slen, "tword "); - if ( (*p)->opd[i] & FAR ) - slen += snprintf(output+slen, outbufsize-slen, "far "); - if ( (*p)->opd[i] & NEAR ) - slen += snprintf(output+slen, outbufsize-slen, "near "); - output[slen++] = '['; - if (ins.oprs[i].addr_size) - slen += snprintf(output+slen, outbufsize-slen, "%s", - (ins.oprs[i].addr_size == 32 ? "dword " : - ins.oprs[i].addr_size == 16 ? "word " : "")); - if (segover) { - slen += snprintf(output+slen, outbufsize-slen, "%s:", segover); - segover = NULL; - } - if (ins.oprs[i].basereg != -1) { - slen += snprintf(output+slen, outbufsize-slen, "%s", - reg_names[(ins.oprs[i].basereg - - EXPR_REG_START)]); - started = TRUE; - } - if (ins.oprs[i].indexreg != -1) { - if (started) - output[slen++] = '+'; - slen += snprintf(output+slen, outbufsize-slen, "%s", - reg_names[(ins.oprs[i].indexreg - - EXPR_REG_START)]); - if (ins.oprs[i].scale > 1) - slen += snprintf(output+slen, outbufsize-slen, "*%d", ins.oprs[i].scale); - started = TRUE; - } - if (ins.oprs[i].segment & SEG_DISP8) { - int sign = '+'; - if (ins.oprs[i].offset & 0x80) { - ins.oprs[i].offset = - (signed char) ins.oprs[i].offset; - sign = '-'; - } - slen += snprintf(output+slen, outbufsize-slen, "%c0x%lx", sign, - ins.oprs[i].offset); - } else if (ins.oprs[i].segment & SEG_DISP16) { - if (started) - output[slen++] = '+'; - slen += snprintf(output+slen, outbufsize-slen, "0x%lx", ins.oprs[i].offset); - } else if (ins.oprs[i].segment & SEG_DISP32) { - if (started) - output[slen++] = '+'; - slen += snprintf(output+slen, outbufsize-slen, "0x%lx", ins.oprs[i].offset); - } - output[slen++] = ']'; - } else { - slen += snprintf(output+slen, outbufsize-slen, "", i); - } - } - output[slen] = '\0'; - if (segover) { /* unused segment override */ - char *p = output; - int count = slen+1; - while (count--) - p[count+3] = p[count]; - strncpy (output, segover, 2); - output[2] = ' '; - } - return length; -} - -long eatbyte (unsigned char *data, char *output, int outbufsize) -{ - snprintf(output, outbufsize, "db 0x%02X", *data); - return 1; -} +/* disasm.c where all the _work_ gets done in the Netwide Disassembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 27/iii/95 by Simon Tatham + */ + +#include +#include + +#include "nasm.h" +#include "disasm.h" +#include "sync.h" +#include "insns.h" + +#include "names.c" + +extern struct itemplate **itable[]; + +/* + * Flags that go into the `segment' field of `insn' structures + * during disassembly. + */ +#define SEG_RELATIVE 1 +#define SEG_32BIT 2 +#define SEG_RMREG 4 +#define SEG_DISP8 8 +#define SEG_DISP16 16 +#define SEG_DISP32 32 +#define SEG_NODISP 64 +#define SEG_SIGNED 128 + +static int whichreg(long regflags, int regval) +{ +#include "regdis.c" + + if (!(REG_AL & ~regflags)) + return R_AL; + if (!(REG_AX & ~regflags)) + return R_AX; + if (!(REG_EAX & ~regflags)) + return R_EAX; + if (!(REG_DL & ~regflags)) + return R_DL; + if (!(REG_DX & ~regflags)) + return R_DX; + if (!(REG_EDX & ~regflags)) + return R_EDX; + if (!(REG_CL & ~regflags)) + return R_CL; + if (!(REG_CX & ~regflags)) + return R_CX; + if (!(REG_ECX & ~regflags)) + return R_ECX; + if (!(FPU0 & ~regflags)) + return R_ST0; + if (!(REG_CS & ~regflags)) + return (regval == 1) ? R_CS : 0; + if (!(REG_DESS & ~regflags)) + return (regval == 0 || regval == 2 + || regval == 3 ? sreg[regval] : 0); + if (!(REG_FSGS & ~regflags)) + return (regval == 4 || regval == 5 ? sreg[regval] : 0); + if (!(REG_SEG67 & ~regflags)) + return (regval == 6 || regval == 7 ? sreg[regval] : 0); + + /* All the entries below look up regval in an 8-entry array */ + if (regval < 0 || regval > 7) + return 0; + + if (!((REGMEM | BITS8) & ~regflags)) + return reg8[regval]; + if (!((REGMEM | BITS16) & ~regflags)) + return reg16[regval]; + if (!((REGMEM | BITS32) & ~regflags)) + return reg32[regval]; + if (!(REG_SREG & ~regflags)) + return sreg[regval]; + if (!(REG_CREG & ~regflags)) + return creg[regval]; + if (!(REG_DREG & ~regflags)) + return dreg[regval]; + if (!(REG_TREG & ~regflags)) + return treg[regval]; + if (!(FPUREG & ~regflags)) + return fpureg[regval]; + if (!(MMXREG & ~regflags)) + return mmxreg[regval]; + if (!(XMMREG & ~regflags)) + return xmmreg[regval]; + + return 0; +} + +static const char *whichcond(int condval) +{ + static int conds[] = { + C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A, + C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G + }; + return conditions[conds[condval]]; +} + +/* + * Process an effective address (ModRM) specification. + */ +static unsigned char *do_ea(unsigned char *data, int modrm, int asize, + int segsize, operand * op) +{ + int mod, rm, scale, index, base; + + mod = (modrm >> 6) & 03; + rm = modrm & 07; + + if (mod == 3) { /* pure register version */ + op->basereg = rm; + op->segment |= SEG_RMREG; + return data; + } + + op->addr_size = 0; + + if (asize == 16) { + /* + * specifies the displacement size (none, byte or + * word), and specifies the register combination. + * Exception: mod=0,rm=6 does not specify [BP] as one might + * expect, but instead specifies [disp16]. + */ + op->indexreg = op->basereg = -1; + op->scale = 1; /* always, in 16 bits */ + switch (rm) { + case 0: + op->basereg = R_BX; + op->indexreg = R_SI; + break; + case 1: + op->basereg = R_BX; + op->indexreg = R_DI; + break; + case 2: + op->basereg = R_BP; + op->indexreg = R_SI; + break; + case 3: + op->basereg = R_BP; + op->indexreg = R_DI; + break; + case 4: + op->basereg = R_SI; + break; + case 5: + op->basereg = R_DI; + break; + case 6: + op->basereg = R_BP; + break; + case 7: + op->basereg = R_BX; + break; + } + if (rm == 6 && mod == 0) { /* special case */ + op->basereg = -1; + if (segsize != 16) + op->addr_size = 16; + mod = 2; /* fake disp16 */ + } + switch (mod) { + case 0: + op->segment |= SEG_NODISP; + break; + case 1: + op->segment |= SEG_DISP8; + op->offset = (signed char)*data++; + break; + case 2: + op->segment |= SEG_DISP16; + op->offset = *data++; + op->offset |= ((unsigned)*data++) << 8; + break; + } + return data; + } else { + /* + * Once again, specifies displacement size (this time + * none, byte or *dword*), while specifies the base + * register. Again, [EBP] is missing, replaced by a pure + * disp32 (this time that's mod=0,rm=*5*). However, rm=4 + * indicates not a single base register, but instead the + * presence of a SIB byte... + */ + op->indexreg = -1; + switch (rm) { + case 0: + op->basereg = R_EAX; + break; + case 1: + op->basereg = R_ECX; + break; + case 2: + op->basereg = R_EDX; + break; + case 3: + op->basereg = R_EBX; + break; + case 5: + op->basereg = R_EBP; + break; + case 6: + op->basereg = R_ESI; + break; + case 7: + op->basereg = R_EDI; + break; + } + if (rm == 5 && mod == 0) { + op->basereg = -1; + if (segsize != 32) + op->addr_size = 32; + mod = 2; /* fake disp32 */ + } + if (rm == 4) { /* process SIB */ + scale = (*data >> 6) & 03; + index = (*data >> 3) & 07; + base = *data & 07; + data++; + + op->scale = 1 << scale; + switch (index) { + case 0: + op->indexreg = R_EAX; + break; + case 1: + op->indexreg = R_ECX; + break; + case 2: + op->indexreg = R_EDX; + break; + case 3: + op->indexreg = R_EBX; + break; + case 4: + op->indexreg = -1; + break; + case 5: + op->indexreg = R_EBP; + break; + case 6: + op->indexreg = R_ESI; + break; + case 7: + op->indexreg = R_EDI; + break; + } + + switch (base) { + case 0: + op->basereg = R_EAX; + break; + case 1: + op->basereg = R_ECX; + break; + case 2: + op->basereg = R_EDX; + break; + case 3: + op->basereg = R_EBX; + break; + case 4: + op->basereg = R_ESP; + break; + case 6: + op->basereg = R_ESI; + break; + case 7: + op->basereg = R_EDI; + break; + case 5: + if (mod == 0) { + mod = 2; + op->basereg = -1; + } else + op->basereg = R_EBP; + break; + } + } + switch (mod) { + case 0: + op->segment |= SEG_NODISP; + break; + case 1: + op->segment |= SEG_DISP8; + op->offset = (signed char)*data++; + break; + case 2: + op->segment |= SEG_DISP32; + op->offset = *data++; + op->offset |= ((unsigned)*data++) << 8; + op->offset |= ((long)*data++) << 16; + op->offset |= ((long)*data++) << 24; + break; + } + return data; + } +} + +/* + * Determine whether the instruction template in t corresponds to the data + * stream in data. Return the number of bytes matched if so. + */ +static int matches(struct itemplate *t, unsigned char *data, int asize, + int osize, int segsize, int rep, insn * ins) +{ + unsigned char *r = (unsigned char *)(t->code); + unsigned char *origdata = data; + int a_used = FALSE, o_used = FALSE; + int drep = 0; + + if (rep == 0xF2) + drep = P_REPNE; + else if (rep == 0xF3) + drep = P_REP; + + while (*r) { + int c = *r++; + if (c >= 01 && c <= 03) { + while (c--) + if (*r++ != *data++) + return FALSE; + } + if (c == 04) { + switch (*data++) { + case 0x07: + ins->oprs[0].basereg = 0; + break; + case 0x17: + ins->oprs[0].basereg = 2; + break; + case 0x1F: + ins->oprs[0].basereg = 3; + break; + default: + return FALSE; + } + } + if (c == 05) { + switch (*data++) { + case 0xA1: + ins->oprs[0].basereg = 4; + break; + case 0xA9: + ins->oprs[0].basereg = 5; + break; + default: + return FALSE; + } + } + if (c == 06) { + switch (*data++) { + case 0x06: + ins->oprs[0].basereg = 0; + break; + case 0x0E: + ins->oprs[0].basereg = 1; + break; + case 0x16: + ins->oprs[0].basereg = 2; + break; + case 0x1E: + ins->oprs[0].basereg = 3; + break; + default: + return FALSE; + } + } + if (c == 07) { + switch (*data++) { + case 0xA0: + ins->oprs[0].basereg = 4; + break; + case 0xA8: + ins->oprs[0].basereg = 5; + break; + default: + return FALSE; + } + } + if (c >= 010 && c <= 012) { + int t = *r++, d = *data++; + if (d < t || d > t + 7) + return FALSE; + else { + ins->oprs[c - 010].basereg = d - t; + ins->oprs[c - 010].segment |= SEG_RMREG; + } + } + if (c == 017) + if (*data++) + return FALSE; + if (c >= 014 && c <= 016) { + ins->oprs[c - 014].offset = (signed char)*data++; + ins->oprs[c - 014].segment |= SEG_SIGNED; + } + if (c >= 020 && c <= 022) + ins->oprs[c - 020].offset = *data++; + if (c >= 024 && c <= 026) + ins->oprs[c - 024].offset = *data++; + if (c >= 030 && c <= 032) { + ins->oprs[c - 030].offset = *data++; + ins->oprs[c - 030].offset |= (((unsigned)*data++) << 8); + } + if (c >= 034 && c <= 036) { + ins->oprs[c - 034].offset = *data++; + ins->oprs[c - 034].offset |= (((unsigned)*data++) << 8); + if (osize == 32) { + ins->oprs[c - 034].offset |= (((long)*data++) << 16); + ins->oprs[c - 034].offset |= (((long)*data++) << 24); + } + if (segsize != asize) + ins->oprs[c - 034].addr_size = asize; + } + if (c >= 040 && c <= 042) { + ins->oprs[c - 040].offset = *data++; + ins->oprs[c - 040].offset |= (((unsigned)*data++) << 8); + ins->oprs[c - 040].offset |= (((long)*data++) << 16); + ins->oprs[c - 040].offset |= (((long)*data++) << 24); + } + if (c >= 044 && c <= 046) { + ins->oprs[c - 044].offset = *data++; + ins->oprs[c - 044].offset |= (((unsigned)*data++) << 8); + if (asize == 32) { + ins->oprs[c - 044].offset |= (((long)*data++) << 16); + ins->oprs[c - 044].offset |= (((long)*data++) << 24); + } + if (segsize != asize) + ins->oprs[c - 044].addr_size = asize; + } + if (c >= 050 && c <= 052) { + ins->oprs[c - 050].offset = (signed char)*data++; + ins->oprs[c - 050].segment |= SEG_RELATIVE; + } + if (c >= 060 && c <= 062) { + ins->oprs[c - 060].offset = *data++; + ins->oprs[c - 060].offset |= (((unsigned)*data++) << 8); + ins->oprs[c - 060].segment |= SEG_RELATIVE; + ins->oprs[c - 060].segment &= ~SEG_32BIT; + } + if (c >= 064 && c <= 066) { + ins->oprs[c - 064].offset = *data++; + ins->oprs[c - 064].offset |= (((unsigned)*data++) << 8); + if (osize == 32) { + ins->oprs[c - 064].offset |= (((long)*data++) << 16); + ins->oprs[c - 064].offset |= (((long)*data++) << 24); + ins->oprs[c - 064].segment |= SEG_32BIT; + } else + ins->oprs[c - 064].segment &= ~SEG_32BIT; + ins->oprs[c - 064].segment |= SEG_RELATIVE; + if (segsize != osize) { + ins->oprs[c - 064].type = + (ins->oprs[c - 064].type & NON_SIZE) + | ((osize == 16) ? BITS16 : BITS32); + } + } + if (c >= 070 && c <= 072) { + ins->oprs[c - 070].offset = *data++; + ins->oprs[c - 070].offset |= (((unsigned)*data++) << 8); + ins->oprs[c - 070].offset |= (((long)*data++) << 16); + ins->oprs[c - 070].offset |= (((long)*data++) << 24); + ins->oprs[c - 070].segment |= SEG_32BIT | SEG_RELATIVE; + } + if (c >= 0100 && c < 0130) { + int modrm = *data++; + ins->oprs[c & 07].basereg = (modrm >> 3) & 07; + ins->oprs[c & 07].segment |= SEG_RMREG; + data = do_ea(data, modrm, asize, segsize, + &ins->oprs[(c >> 3) & 07]); + } + if (c >= 0130 && c <= 0132) { + ins->oprs[c - 0130].offset = *data++; + ins->oprs[c - 0130].offset |= (((unsigned)*data++) << 8); + } + if (c >= 0140 && c <= 0142) { + ins->oprs[c - 0140].offset = *data++; + ins->oprs[c - 0140].offset |= (((unsigned)*data++) << 8); + ins->oprs[c - 0140].offset |= (((long)*data++) << 16); + ins->oprs[c - 0140].offset |= (((long)*data++) << 24); + } + if (c >= 0200 && c <= 0277) { + int modrm = *data++; + if (((modrm >> 3) & 07) != (c & 07)) + return FALSE; /* spare field doesn't match up */ + data = do_ea(data, modrm, asize, segsize, + &ins->oprs[(c >> 3) & 07]); + } + if (c >= 0300 && c <= 0302) { + if (asize) + ins->oprs[c - 0300].segment |= SEG_32BIT; + else + ins->oprs[c - 0300].segment &= ~SEG_32BIT; + a_used = TRUE; + } + if (c == 0310) { + if (asize == 32) + return FALSE; + else + a_used = TRUE; + } + if (c == 0311) { + if (asize == 16) + return FALSE; + else + a_used = TRUE; + } + if (c == 0312) { + if (asize != segsize) + return FALSE; + else + a_used = TRUE; + } + if (c == 0320) { + if (osize == 32) + return FALSE; + else + o_used = TRUE; + } + if (c == 0321) { + if (osize == 16) + return FALSE; + else + o_used = TRUE; + } + if (c == 0322) { + if (osize != segsize) + return FALSE; + else + o_used = TRUE; + } + if (c == 0330) { + int t = *r++, d = *data++; + if (d < t || d > t + 15) + return FALSE; + else + ins->condition = d - t; + } + if (c == 0331) { + if (rep) + return FALSE; + } + if (c == 0332) { + if (drep == P_REP) + drep = P_REPE; + } + if (c == 0333) { + if (rep != 0xF3) + return FALSE; + drep = 0; + } + } + + /* + * Check for unused rep or a/o prefixes. + */ + ins->nprefix = 0; + if (drep) + ins->prefixes[ins->nprefix++] = drep; + if (!a_used && asize != segsize) + ins->prefixes[ins->nprefix++] = (asize == 16 ? P_A16 : P_A32); + if (!o_used && osize != segsize) + ins->prefixes[ins->nprefix++] = (osize == 16 ? P_O16 : P_O32); + + return data - origdata; +} + +long disasm(unsigned char *data, char *output, int outbufsize, int segsize, + long offset, int autosync, unsigned long prefer) +{ + struct itemplate **p, **best_p; + int length, best_length = 0; + char *segover; + int rep, lock, asize, osize, i, slen, colon; + unsigned char *origdata; + int works; + insn tmp_ins, ins; + unsigned long goodness, best; + + /* + * Scan for prefixes. + */ + asize = osize = segsize; + segover = NULL; + rep = lock = 0; + origdata = data; + for (;;) { + if (*data == 0xF3 || *data == 0xF2) + rep = *data++; + else if (*data == 0xF0) + lock = *data++; + else if (*data == 0x2E || *data == 0x36 || *data == 0x3E || + *data == 0x26 || *data == 0x64 || *data == 0x65) { + switch (*data++) { + case 0x2E: + segover = "cs"; + break; + case 0x36: + segover = "ss"; + break; + case 0x3E: + segover = "ds"; + break; + case 0x26: + segover = "es"; + break; + case 0x64: + segover = "fs"; + break; + case 0x65: + segover = "gs"; + break; + } + } else if (*data == 0x66) + osize = 48 - segsize, data++; + else if (*data == 0x67) + asize = 48 - segsize, data++; + else + break; + } + + tmp_ins.oprs[0].segment = tmp_ins.oprs[1].segment = + tmp_ins.oprs[2].segment = + tmp_ins.oprs[0].addr_size = tmp_ins.oprs[1].addr_size = + tmp_ins.oprs[2].addr_size = (segsize == 16 ? 0 : SEG_32BIT); + tmp_ins.condition = -1; + best = ~0UL; /* Worst possible */ + best_p = NULL; + for (p = itable[*data]; *p; p++) { + if ((length = matches(*p, data, asize, osize, + segsize, rep, &tmp_ins))) { + works = TRUE; + /* + * Final check to make sure the types of r/m match up. + */ + for (i = 0; i < (*p)->operands; i++) { + if ( + /* If it's a mem-only EA but we have a register, die. */ + ((tmp_ins.oprs[i].segment & SEG_RMREG) && + !(MEMORY & ~(*p)->opd[i])) || + /* If it's a reg-only EA but we have a memory ref, die. */ + (!(tmp_ins.oprs[i].segment & SEG_RMREG) && + !(REGNORM & ~(*p)->opd[i]) && + !((*p)->opd[i] & REG_SMASK)) || + /* Register type mismatch (eg FS vs REG_DESS): die. */ + ((((*p)->opd[i] & (REGISTER | FPUREG)) || + (tmp_ins.oprs[i].segment & SEG_RMREG)) && + !whichreg((*p)->opd[i], + tmp_ins.oprs[i].basereg))) { + works = FALSE; + break; + } + } + + if (works) { + goodness = ((*p)->flags & IF_PFMASK) ^ prefer; + if (goodness < best) { + /* This is the best one found so far */ + best = goodness; + best_p = p; + best_length = length; + ins = tmp_ins; + } + } + } + } + + if (!best_p) + return 0; /* no instruction was matched */ + + /* Pick the best match */ + p = best_p; + length = best_length; + + slen = 0; + + /* TODO: snprintf returns the value that the string would have if + * the buffer were long enough, and not the actual length of + * the returned string, so each instance of using the return + * value of snprintf should actually be checked to assure that + * the return value is "sane." Maybe a macro wrapper could + * be used for that purpose. + */ + if (lock) + slen += snprintf(output + slen, outbufsize - slen, "lock "); + for (i = 0; i < ins.nprefix; i++) + switch (ins.prefixes[i]) { + case P_REP: + slen += snprintf(output + slen, outbufsize - slen, "rep "); + break; + case P_REPE: + slen += snprintf(output + slen, outbufsize - slen, "repe "); + break; + case P_REPNE: + slen += snprintf(output + slen, outbufsize - slen, "repne "); + break; + case P_A16: + slen += snprintf(output + slen, outbufsize - slen, "a16 "); + break; + case P_A32: + slen += snprintf(output + slen, outbufsize - slen, "a32 "); + break; + case P_O16: + slen += snprintf(output + slen, outbufsize - slen, "o16 "); + break; + case P_O32: + slen += snprintf(output + slen, outbufsize - slen, "o32 "); + break; + } + + for (i = 0; i < elements(ico); i++) + if ((*p)->opcode == ico[i]) { + slen += + snprintf(output + slen, outbufsize - slen, "%s%s", icn[i], + whichcond(ins.condition)); + break; + } + if (i >= elements(ico)) + slen += + snprintf(output + slen, outbufsize - slen, "%s", + insn_names[(*p)->opcode]); + colon = FALSE; + length += data - origdata; /* fix up for prefixes */ + for (i = 0; i < (*p)->operands; i++) { + output[slen++] = (colon ? ':' : i == 0 ? ' ' : ','); + + if (ins.oprs[i].segment & SEG_RELATIVE) { + ins.oprs[i].offset += offset + length; + /* + * sort out wraparound + */ + if (!(ins.oprs[i].segment & SEG_32BIT)) + ins.oprs[i].offset &= 0xFFFF; + /* + * add sync marker, if autosync is on + */ + if (autosync) + add_sync(ins.oprs[i].offset, 0L); + } + + if ((*p)->opd[i] & COLON) + colon = TRUE; + else + colon = FALSE; + + if (((*p)->opd[i] & (REGISTER | FPUREG)) || + (ins.oprs[i].segment & SEG_RMREG)) { + ins.oprs[i].basereg = whichreg((*p)->opd[i], + ins.oprs[i].basereg); + if ((*p)->opd[i] & TO) + slen += snprintf(output + slen, outbufsize - slen, "to "); + slen += snprintf(output + slen, outbufsize - slen, "%s", + reg_names[ins.oprs[i].basereg - + EXPR_REG_START]); + } else if (!(UNITY & ~(*p)->opd[i])) { + output[slen++] = '1'; + } else if ((*p)->opd[i] & IMMEDIATE) { + if ((*p)->opd[i] & BITS8) { + slen += + snprintf(output + slen, outbufsize - slen, "byte "); + if (ins.oprs[i].segment & SEG_SIGNED) { + if (ins.oprs[i].offset < 0) { + ins.oprs[i].offset *= -1; + output[slen++] = '-'; + } else + output[slen++] = '+'; + } + } else if ((*p)->opd[i] & BITS16) { + slen += + snprintf(output + slen, outbufsize - slen, "word "); + } else if ((*p)->opd[i] & BITS32) { + slen += + snprintf(output + slen, outbufsize - slen, "dword "); + } else if ((*p)->opd[i] & NEAR) { + slen += + snprintf(output + slen, outbufsize - slen, "near "); + } else if ((*p)->opd[i] & SHORT) { + slen += + snprintf(output + slen, outbufsize - slen, "short "); + } + slen += + snprintf(output + slen, outbufsize - slen, "0x%lx", + ins.oprs[i].offset); + } else if (!(MEM_OFFS & ~(*p)->opd[i])) { + slen += + snprintf(output + slen, outbufsize - slen, "[%s%s%s0x%lx]", + (segover ? segover : ""), (segover ? ":" : ""), + (ins.oprs[i].addr_size == + 32 ? "dword " : ins.oprs[i].addr_size == + 16 ? "word " : ""), ins.oprs[i].offset); + segover = NULL; + } else if (!(REGMEM & ~(*p)->opd[i])) { + int started = FALSE; + if ((*p)->opd[i] & BITS8) + slen += + snprintf(output + slen, outbufsize - slen, "byte "); + if ((*p)->opd[i] & BITS16) + slen += + snprintf(output + slen, outbufsize - slen, "word "); + if ((*p)->opd[i] & BITS32) + slen += + snprintf(output + slen, outbufsize - slen, "dword "); + if ((*p)->opd[i] & BITS64) + slen += + snprintf(output + slen, outbufsize - slen, "qword "); + if ((*p)->opd[i] & BITS80) + slen += + snprintf(output + slen, outbufsize - slen, "tword "); + if ((*p)->opd[i] & FAR) + slen += snprintf(output + slen, outbufsize - slen, "far "); + if ((*p)->opd[i] & NEAR) + slen += + snprintf(output + slen, outbufsize - slen, "near "); + output[slen++] = '['; + if (ins.oprs[i].addr_size) + slen += snprintf(output + slen, outbufsize - slen, "%s", + (ins.oprs[i].addr_size == 32 ? "dword " : + ins.oprs[i].addr_size == + 16 ? "word " : "")); + if (segover) { + slen += + snprintf(output + slen, outbufsize - slen, "%s:", + segover); + segover = NULL; + } + if (ins.oprs[i].basereg != -1) { + slen += snprintf(output + slen, outbufsize - slen, "%s", + reg_names[(ins.oprs[i].basereg - + EXPR_REG_START)]); + started = TRUE; + } + if (ins.oprs[i].indexreg != -1) { + if (started) + output[slen++] = '+'; + slen += snprintf(output + slen, outbufsize - slen, "%s", + reg_names[(ins.oprs[i].indexreg - + EXPR_REG_START)]); + if (ins.oprs[i].scale > 1) + slen += + snprintf(output + slen, outbufsize - slen, "*%d", + ins.oprs[i].scale); + started = TRUE; + } + if (ins.oprs[i].segment & SEG_DISP8) { + int sign = '+'; + if (ins.oprs[i].offset & 0x80) { + ins.oprs[i].offset = -(signed char)ins.oprs[i].offset; + sign = '-'; + } + slen += + snprintf(output + slen, outbufsize - slen, "%c0x%lx", + sign, ins.oprs[i].offset); + } else if (ins.oprs[i].segment & SEG_DISP16) { + if (started) + output[slen++] = '+'; + slen += + snprintf(output + slen, outbufsize - slen, "0x%lx", + ins.oprs[i].offset); + } else if (ins.oprs[i].segment & SEG_DISP32) { + if (started) + output[slen++] = '+'; + slen += + snprintf(output + slen, outbufsize - slen, "0x%lx", + ins.oprs[i].offset); + } + output[slen++] = ']'; + } else { + slen += + snprintf(output + slen, outbufsize - slen, "", + i); + } + } + output[slen] = '\0'; + if (segover) { /* unused segment override */ + char *p = output; + int count = slen + 1; + while (count--) + p[count + 3] = p[count]; + strncpy(output, segover, 2); + output[2] = ' '; + } + return length; +} + +long eatbyte(unsigned char *data, char *output, int outbufsize) +{ + snprintf(output, outbufsize, "db 0x%02X", *data); + return 1; +} diff --git a/disasm.h b/disasm.h index 61337516..d447ad9d 100644 --- a/disasm.h +++ b/disasm.h @@ -9,10 +9,10 @@ #ifndef NASM_DISASM_H #define NASM_DISASM_H -#define INSN_MAX 32 /* one instruction can't be longer than this */ +#define INSN_MAX 32 /* one instruction can't be longer than this */ -long disasm (unsigned char *data, char *output, int outbufsize, int segsize, - long offset, int autosync, unsigned long prefer); -long eatbyte (unsigned char *data, char *output, int outbufsize); +long disasm(unsigned char *data, char *output, int outbufsize, int segsize, + long offset, int autosync, unsigned long prefer); +long eatbyte(unsigned char *data, char *output, int outbufsize); #endif diff --git a/eval.c b/eval.c dissimilarity index 71% index 28aca642..62bd8b29 100644 --- a/eval.c +++ b/eval.c @@ -1,825 +1,802 @@ -/* eval.c expression evaluator for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * initial version 27/iii/95 by Simon Tatham - */ - -#include -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "eval.h" -#include "labels.h" - -#define TEMPEXPRS_DELTA 128 -#define TEMPEXPR_DELTA 8 - -static scanner scan; /* Address of scanner routine */ -static efunc error; /* Address of error reporting routine */ -static lfunc labelfunc; /* Address of label routine */ - -static struct ofmt *outfmt; /* Structure of addresses of output routines */ - -static expr **tempexprs = NULL; -static int ntempexprs; -static int tempexprs_size = 0; - -static expr *tempexpr; -static int ntempexpr; -static int tempexpr_size; - -static struct tokenval *tokval; /* The current token */ -static int i; /* The t_type of tokval */ - -static void *scpriv; -static loc_t *location; /* Pointer to current line's segment,offset */ -static int *opflags; - -static struct eval_hints *hint; - -extern int in_abs_seg; /* ABSOLUTE segment flag */ -extern long abs_seg; /* ABSOLUTE segment */ -extern long abs_offset; /* ABSOLUTE segment offset */ - -/* - * Unimportant cleanup is done to avoid confusing people who are trying - * to debug real memory leaks - */ -void eval_cleanup(void) -{ - while (ntempexprs) - nasm_free (tempexprs[--ntempexprs]); - nasm_free (tempexprs); -} - -/* - * Construct a temporary expression. - */ -static void begintemp(void) -{ - tempexpr = NULL; - tempexpr_size = ntempexpr = 0; -} - -static void addtotemp(long type, long value) -{ - while (ntempexpr >= tempexpr_size) { - tempexpr_size += TEMPEXPR_DELTA; - tempexpr = nasm_realloc(tempexpr, - tempexpr_size*sizeof(*tempexpr)); - } - tempexpr[ntempexpr].type = type; - tempexpr[ntempexpr++].value = value; -} - -static expr *finishtemp(void) -{ - addtotemp (0L, 0L); /* terminate */ - while (ntempexprs >= tempexprs_size) { - tempexprs_size += TEMPEXPRS_DELTA; - tempexprs = nasm_realloc(tempexprs, - tempexprs_size*sizeof(*tempexprs)); - } - return tempexprs[ntempexprs++] = tempexpr; -} - -/* - * Add two vector datatypes. We have some bizarre behaviour on far- - * absolute segment types: we preserve them during addition _only_ - * if one of the segments is a truly pure scalar. - */ -static expr *add_vectors(expr *p, expr *q) -{ - int preserve; - - preserve = is_really_simple(p) || is_really_simple(q); - - begintemp(); - - while (p->type && q->type && - p->type < EXPR_SEGBASE+SEG_ABS && - q->type < EXPR_SEGBASE+SEG_ABS) - { - int lasttype; - - if (p->type > q->type) { - addtotemp(q->type, q->value); - lasttype = q++->type; - } else if (p->type < q->type) { - addtotemp(p->type, p->value); - lasttype = p++->type; - } else { /* *p and *q have same type */ - long sum = p->value + q->value; - if (sum) - addtotemp(p->type, sum); - lasttype = p->type; - p++, q++; - } - if (lasttype == EXPR_UNKNOWN) { - return finishtemp(); - } - } - while (p->type && - (preserve || p->type < EXPR_SEGBASE+SEG_ABS)) - { - addtotemp(p->type, p->value); - p++; - } - while (q->type && - (preserve || q->type < EXPR_SEGBASE+SEG_ABS)) - { - addtotemp(q->type, q->value); - q++; - } - - return finishtemp(); -} - -/* - * Multiply a vector by a scalar. Strip far-absolute segment part - * if present. - * - * Explicit treatment of UNKNOWN is not required in this routine, - * since it will silently do the Right Thing anyway. - * - * If `affect_hints' is set, we also change the hint type to - * NOTBASE if a MAKEBASE hint points at a register being - * multiplied. This allows [eax*1+ebx] to hint EBX rather than EAX - * as the base register. - */ -static expr *scalar_mult(expr *vect, long scalar, int affect_hints) -{ - expr *p = vect; - - while (p->type && p->type < EXPR_SEGBASE+SEG_ABS) { - p->value = scalar * (p->value); - if (hint && hint->type == EAH_MAKEBASE && - p->type == hint->base && affect_hints) - hint->type = EAH_NOTBASE; - p++; - } - p->type = 0; - - return vect; -} - -static expr *scalarvect (long scalar) -{ - begintemp(); - addtotemp(EXPR_SIMPLE, scalar); - return finishtemp(); -} - -static expr *unknown_expr (void) -{ - begintemp(); - addtotemp(EXPR_UNKNOWN, 1L); - return finishtemp(); -} - -/* - * The SEG operator: calculate the segment part of a relocatable - * value. Return NULL, as usual, if an error occurs. Report the - * error too. - */ -static expr *segment_part (expr *e) -{ - long seg; - - if (is_unknown(e)) - return unknown_expr(); - - if (!is_reloc(e)) { - error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value"); - return NULL; - } - - seg = reloc_seg(e); - if (seg == NO_SEG) { - error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value"); - return NULL; - } else if (seg & SEG_ABS) { - return scalarvect(seg & ~SEG_ABS); - } else if (seg & 1) { - error(ERR_NONFATAL, "SEG applied to something which" - " is already a segment base"); - return NULL; - } - else { - long base = outfmt->segbase(seg+1); - - begintemp(); - addtotemp((base == NO_SEG ? EXPR_UNKNOWN : EXPR_SEGBASE+base), 1L); - return finishtemp(); - } -} - -/* - * Recursive-descent parser. Called with a single boolean operand, - * which is TRUE if the evaluation is critical (i.e. unresolved - * symbols are an error condition). Must update the global `i' to - * reflect the token after the parsed string. May return NULL. - * - * evaluate() should report its own errors: on return it is assumed - * that if NULL has been returned, the error has already been - * reported. - */ - -/* - * Grammar parsed is: - * - * expr : bexpr [ WRT expr6 ] - * bexpr : rexp0 or expr0 depending on relative-mode setting - * rexp0 : rexp1 [ {||} rexp1...] - * rexp1 : rexp2 [ {^^} rexp2...] - * rexp2 : rexp3 [ {&&} rexp3...] - * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ] - * expr0 : expr1 [ {|} expr1...] - * expr1 : expr2 [ {^} expr2...] - * expr2 : expr3 [ {&} expr3...] - * expr3 : expr4 [ {<<,>>} expr4...] - * expr4 : expr5 [ {+,-} expr5...] - * expr5 : expr6 [ {*,/,%,//,%%} expr6...] - * expr6 : { ~,+,-,SEG } expr6 - * | (bexpr) - * | symbol - * | $ - * | number - */ - -static expr *rexp0(int), *rexp1(int), *rexp2(int), *rexp3(int); - -static expr *expr0(int), *expr1(int), *expr2(int), *expr3(int); -static expr *expr4(int), *expr5(int), *expr6(int); - -static expr *(*bexpr)(int); - -static expr *rexp0(int critical) -{ - expr *e, *f; - - e = rexp1(critical); - if (!e) - return NULL; - - while (i == TOKEN_DBL_OR) - { - i = scan(scpriv, tokval); - f = rexp1(critical); - if (!f) - return NULL; - if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) - { - error(ERR_NONFATAL, "`|' operator may only be applied to" - " scalar values"); - } - - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect ((long) (reloc_value(e) || reloc_value(f))); - } - return e; -} - -static expr *rexp1(int critical) -{ - expr *e, *f; - - e = rexp2(critical); - if (!e) - return NULL; - - while (i == TOKEN_DBL_XOR) - { - i = scan(scpriv, tokval); - f = rexp2(critical); - if (!f) - return NULL; - if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) - { - error(ERR_NONFATAL, "`^' operator may only be applied to" - " scalar values"); - } - - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect ((long) (!reloc_value(e) ^ !reloc_value(f))); - } - return e; -} - -static expr *rexp2(int critical) -{ - expr *e, *f; - - e = rexp3(critical); - if (!e) - return NULL; - while (i == TOKEN_DBL_AND) - { - i = scan(scpriv, tokval); - f = rexp3(critical); - if (!f) - return NULL; - if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) - { - error(ERR_NONFATAL, "`&' operator may only be applied to" - " scalar values"); - } - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect ((long) (reloc_value(e) && reloc_value(f))); - } - return e; -} - -static expr *rexp3(int critical) -{ - expr *e, *f; - long v; - - e = expr0(critical); - if (!e) - return NULL; - - while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || - i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) - { - int j = i; - i = scan(scpriv, tokval); - f = expr0(critical); - if (!f) - return NULL; - - e = add_vectors (e, scalar_mult(f, -1L, FALSE)); - - switch (j) - { - case TOKEN_EQ: case TOKEN_NE: - if (is_unknown(e)) - v = -1; /* means unknown */ - else if (!is_really_simple(e) || reloc_value(e) != 0) - v = (j == TOKEN_NE); /* unequal, so return TRUE if NE */ - else - v = (j == TOKEN_EQ); /* equal, so return TRUE if EQ */ - break; - default: - if (is_unknown(e)) - v = -1; /* means unknown */ - else if (!is_really_simple(e)) { - error(ERR_NONFATAL, "`%s': operands differ by a non-scalar", - (j == TOKEN_LE ? "<=" : j == TOKEN_LT ? "<" : - j == TOKEN_GE ? ">=" : ">")); - v = 0; /* must set it to _something_ */ - } else { - int vv = reloc_value(e); - if (vv == 0) - v = (j == TOKEN_LE || j == TOKEN_GE); - else if (vv > 0) - v = (j == TOKEN_GE || j == TOKEN_GT); - else /* vv < 0 */ - v = (j == TOKEN_LE || j == TOKEN_LT); - } - break; - } - - if (v == -1) - e = unknown_expr(); - else - e = scalarvect(v); - } - return e; -} - -static expr *expr0(int critical) -{ - expr *e, *f; - - e = expr1(critical); - if (!e) - return NULL; - - while (i == '|') - { - i = scan(scpriv, tokval); - f = expr1(critical); - if (!f) - return NULL; - if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) - { - error(ERR_NONFATAL, "`|' operator may only be applied to" - " scalar values"); - } - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect (reloc_value(e) | reloc_value(f)); - } - return e; -} - -static expr *expr1(int critical) -{ - expr *e, *f; - - e = expr2(critical); - if (!e) - return NULL; - - while (i == '^') { - i = scan(scpriv, tokval); - f = expr2(critical); - if (!f) - return NULL; - if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) - { - error(ERR_NONFATAL, "`^' operator may only be applied to" - " scalar values"); - } - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect (reloc_value(e) ^ reloc_value(f)); - } - return e; -} - -static expr *expr2(int critical) -{ - expr *e, *f; - - e = expr3(critical); - if (!e) - return NULL; - - while (i == '&') { - i = scan(scpriv, tokval); - f = expr3(critical); - if (!f) - return NULL; - if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) - { - error(ERR_NONFATAL, "`&' operator may only be applied to" - " scalar values"); - } - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect (reloc_value(e) & reloc_value(f)); - } - return e; -} - -static expr *expr3(int critical) -{ - expr *e, *f; - - e = expr4(critical); - if (!e) - return NULL; - - while (i == TOKEN_SHL || i == TOKEN_SHR) - { - int j = i; - i = scan(scpriv, tokval); - f = expr4(critical); - if (!f) - return NULL; - if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) - { - error(ERR_NONFATAL, "shift operator may only be applied to" - " scalar values"); - } else if (is_just_unknown(e) || is_just_unknown(f)) { - e = unknown_expr(); - } else switch (j) { - case TOKEN_SHL: - e = scalarvect (reloc_value(e) << reloc_value(f)); - break; - case TOKEN_SHR: - e = scalarvect (((unsigned long)reloc_value(e)) >> - reloc_value(f)); - break; - } - } - return e; -} - -static expr *expr4(int critical) -{ - expr *e, *f; - - e = expr5(critical); - if (!e) - return NULL; - while (i == '+' || i == '-') - { - int j = i; - i = scan(scpriv, tokval); - f = expr5(critical); - if (!f) - return NULL; - switch (j) { - case '+': - e = add_vectors (e, f); - break; - case '-': - e = add_vectors (e, scalar_mult(f, -1L, FALSE)); - break; - } - } - return e; -} - -static expr *expr5(int critical) -{ - expr *e, *f; - - e = expr6(critical); - if (!e) - return NULL; - while (i == '*' || i == '/' || i == '%' || - i == TOKEN_SDIV || i == TOKEN_SMOD) - { - int j = i; - i = scan(scpriv, tokval); - f = expr6(critical); - if (!f) - return NULL; - if (j != '*' && (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f)))) - { - error(ERR_NONFATAL, "division operator may only be applied to" - " scalar values"); - return NULL; - } - if (j != '*' && !is_unknown(f) && reloc_value(f) == 0) { - error(ERR_NONFATAL, "division by zero"); - return NULL; - } - switch (j) { - case '*': - if (is_simple(e)) - e = scalar_mult (f, reloc_value(e), TRUE); - else if (is_simple(f)) - e = scalar_mult (e, reloc_value(f), TRUE); - else if (is_just_unknown(e) && is_just_unknown(f)) - e = unknown_expr(); - else { - error(ERR_NONFATAL, "unable to multiply two " - "non-scalar objects"); - return NULL; - } - break; - case '/': - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect (((unsigned long)reloc_value(e)) / - ((unsigned long)reloc_value(f))); - break; - case '%': - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect (((unsigned long)reloc_value(e)) % - ((unsigned long)reloc_value(f))); - break; - case TOKEN_SDIV: - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect (((signed long)reloc_value(e)) / - ((signed long)reloc_value(f))); - break; - case TOKEN_SMOD: - if (is_just_unknown(e) || is_just_unknown(f)) - e = unknown_expr(); - else - e = scalarvect (((signed long)reloc_value(e)) % - ((signed long)reloc_value(f))); - break; - } - } - return e; -} - -static expr *expr6(int critical) -{ - long type; - expr *e; - long label_seg, label_ofs; - - if (i == '-') { - i = scan(scpriv, tokval); - e = expr6(critical); - if (!e) - return NULL; - return scalar_mult (e, -1L, FALSE); - } else if (i == '+') { - i = scan(scpriv, tokval); - return expr6(critical); - } else if (i == '~') { - i = scan(scpriv, tokval); - e = expr6(critical); - if (!e) - return NULL; - if (is_just_unknown(e)) - return unknown_expr(); - else if (!is_simple(e)) { - error(ERR_NONFATAL, "`~' operator may only be applied to" - " scalar values"); - return NULL; - } - return scalarvect(~reloc_value(e)); - } else if (i == TOKEN_SEG) { - i = scan(scpriv, tokval); - e = expr6(critical); - if (!e) - return NULL; - e = segment_part(e); - if (!e) - return NULL; - if (is_unknown(e) && critical) { - error(ERR_NONFATAL, "unable to determine segment base"); - return NULL; - } - return e; - } else if (i == '(') { - i = scan(scpriv, tokval); - e = bexpr(critical); - if (!e) - return NULL; - if (i != ')') { - error(ERR_NONFATAL, "expecting `)'"); - return NULL; - } - i = scan(scpriv, tokval); - return e; - } - else if (i == TOKEN_NUM || i == TOKEN_REG || i == TOKEN_ID || - i == TOKEN_HERE || i == TOKEN_BASE) - { - begintemp(); - switch (i) { - case TOKEN_NUM: - addtotemp(EXPR_SIMPLE, tokval->t_integer); - break; - case TOKEN_REG: - addtotemp(tokval->t_integer, 1L); - if (hint && hint->type == EAH_NOHINT) - hint->base = tokval->t_integer, hint->type = EAH_MAKEBASE; - break; - case TOKEN_ID: - case TOKEN_HERE: - case TOKEN_BASE: - /* - * If !location->known, this indicates that no - * symbol, Here or Base references are valid because we - * are in preprocess-only mode. - */ - if (!location->known) { - error(ERR_NONFATAL, - "%s not supported in preprocess-only mode", - (i == TOKEN_ID ? "symbol references" : - i == TOKEN_HERE ? "`$'" : "`$$'")); - addtotemp(EXPR_UNKNOWN, 1L); - break; - } - - type = EXPR_SIMPLE; /* might get overridden by UNKNOWN */ - if (i == TOKEN_BASE) - { - label_seg = in_abs_seg ? abs_seg : location->segment; - label_ofs = 0; - } else if (i == TOKEN_HERE) { - label_seg = in_abs_seg ? abs_seg : location->segment; - label_ofs = in_abs_seg ? abs_offset : location->offset; - } else { - if (!labelfunc(tokval->t_charptr,&label_seg,&label_ofs)) - { - if (critical == 2) { - error (ERR_NONFATAL, "symbol `%s' undefined", - tokval->t_charptr); - return NULL; - } else if (critical == 1) { - error (ERR_NONFATAL, - "symbol `%s' not defined before use", - tokval->t_charptr); - return NULL; - } else { - if (opflags) - *opflags |= 1; - type = EXPR_UNKNOWN; - label_seg = NO_SEG; - label_ofs = 1; - } - } - if (opflags && is_extern (tokval->t_charptr)) - *opflags |= OPFLAG_EXTERN; - } - addtotemp(type, label_ofs); - if (label_seg!=NO_SEG) - addtotemp(EXPR_SEGBASE + label_seg, 1L); - break; - } - i = scan(scpriv, tokval); - return finishtemp(); - } else { - error(ERR_NONFATAL, "expression syntax error"); - return NULL; - } -} - -void eval_global_info (struct ofmt *output, lfunc lookup_label, loc_t *locp) -{ - outfmt = output; - labelfunc = lookup_label; - location = locp; -} - -expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, - int *fwref, int critical, efunc report_error, - struct eval_hints *hints) -{ - expr *e; - expr *f = NULL; - - hint = hints; - if (hint) - hint->type = EAH_NOHINT; - - if (critical & CRITICAL) { - critical &= ~CRITICAL; - bexpr = rexp0; - } else - bexpr = expr0; - - scan = sc; - scpriv = scprivate; - tokval = tv; - error = report_error; - opflags = fwref; - - if (tokval->t_type == TOKEN_INVALID) - i = scan(scpriv, tokval); - else - i = tokval->t_type; - - while (ntempexprs) /* initialise temporary storage */ - nasm_free (tempexprs[--ntempexprs]); - - e = bexpr (critical); - if (!e) - return NULL; - - if (i == TOKEN_WRT) { - i = scan(scpriv, tokval); /* eat the WRT */ - f = expr6 (critical); - if (!f) - return NULL; - } - e = scalar_mult (e, 1L, FALSE); /* strip far-absolute segment part */ - if (f) { - expr *g; - if (is_just_unknown(f)) - g = unknown_expr(); - else { - long value; - begintemp(); - if (!is_reloc(f)) { - error(ERR_NONFATAL, "invalid right-hand operand to WRT"); - return NULL; - } - value = reloc_seg(f); - if (value == NO_SEG) - value = reloc_value(f) | SEG_ABS; - else if (!(value & SEG_ABS) && !(value % 2) && critical) - { - error(ERR_NONFATAL, "invalid right-hand operand to WRT"); - return NULL; - } - addtotemp(EXPR_WRT, value); - g = finishtemp(); - } - e = add_vectors (e, g); - } - return e; -} +/* eval.c expression evaluator for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 27/iii/95 by Simon Tatham + */ + +#include +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "eval.h" +#include "labels.h" + +#define TEMPEXPRS_DELTA 128 +#define TEMPEXPR_DELTA 8 + +static scanner scan; /* Address of scanner routine */ +static efunc error; /* Address of error reporting routine */ +static lfunc labelfunc; /* Address of label routine */ + +static struct ofmt *outfmt; /* Structure of addresses of output routines */ + +static expr **tempexprs = NULL; +static int ntempexprs; +static int tempexprs_size = 0; + +static expr *tempexpr; +static int ntempexpr; +static int tempexpr_size; + +static struct tokenval *tokval; /* The current token */ +static int i; /* The t_type of tokval */ + +static void *scpriv; +static loc_t *location; /* Pointer to current line's segment,offset */ +static int *opflags; + +static struct eval_hints *hint; + +extern int in_abs_seg; /* ABSOLUTE segment flag */ +extern long abs_seg; /* ABSOLUTE segment */ +extern long abs_offset; /* ABSOLUTE segment offset */ + +/* + * Unimportant cleanup is done to avoid confusing people who are trying + * to debug real memory leaks + */ +void eval_cleanup(void) +{ + while (ntempexprs) + nasm_free(tempexprs[--ntempexprs]); + nasm_free(tempexprs); +} + +/* + * Construct a temporary expression. + */ +static void begintemp(void) +{ + tempexpr = NULL; + tempexpr_size = ntempexpr = 0; +} + +static void addtotemp(long type, long value) +{ + while (ntempexpr >= tempexpr_size) { + tempexpr_size += TEMPEXPR_DELTA; + tempexpr = nasm_realloc(tempexpr, + tempexpr_size * sizeof(*tempexpr)); + } + tempexpr[ntempexpr].type = type; + tempexpr[ntempexpr++].value = value; +} + +static expr *finishtemp(void) +{ + addtotemp(0L, 0L); /* terminate */ + while (ntempexprs >= tempexprs_size) { + tempexprs_size += TEMPEXPRS_DELTA; + tempexprs = nasm_realloc(tempexprs, + tempexprs_size * sizeof(*tempexprs)); + } + return tempexprs[ntempexprs++] = tempexpr; +} + +/* + * Add two vector datatypes. We have some bizarre behaviour on far- + * absolute segment types: we preserve them during addition _only_ + * if one of the segments is a truly pure scalar. + */ +static expr *add_vectors(expr * p, expr * q) +{ + int preserve; + + preserve = is_really_simple(p) || is_really_simple(q); + + begintemp(); + + while (p->type && q->type && + p->type < EXPR_SEGBASE + SEG_ABS && + q->type < EXPR_SEGBASE + SEG_ABS) { + int lasttype; + + if (p->type > q->type) { + addtotemp(q->type, q->value); + lasttype = q++->type; + } else if (p->type < q->type) { + addtotemp(p->type, p->value); + lasttype = p++->type; + } else { /* *p and *q have same type */ + long sum = p->value + q->value; + if (sum) + addtotemp(p->type, sum); + lasttype = p->type; + p++, q++; + } + if (lasttype == EXPR_UNKNOWN) { + return finishtemp(); + } + } + while (p->type && (preserve || p->type < EXPR_SEGBASE + SEG_ABS)) { + addtotemp(p->type, p->value); + p++; + } + while (q->type && (preserve || q->type < EXPR_SEGBASE + SEG_ABS)) { + addtotemp(q->type, q->value); + q++; + } + + return finishtemp(); +} + +/* + * Multiply a vector by a scalar. Strip far-absolute segment part + * if present. + * + * Explicit treatment of UNKNOWN is not required in this routine, + * since it will silently do the Right Thing anyway. + * + * If `affect_hints' is set, we also change the hint type to + * NOTBASE if a MAKEBASE hint points at a register being + * multiplied. This allows [eax*1+ebx] to hint EBX rather than EAX + * as the base register. + */ +static expr *scalar_mult(expr * vect, long scalar, int affect_hints) +{ + expr *p = vect; + + while (p->type && p->type < EXPR_SEGBASE + SEG_ABS) { + p->value = scalar * (p->value); + if (hint && hint->type == EAH_MAKEBASE && + p->type == hint->base && affect_hints) + hint->type = EAH_NOTBASE; + p++; + } + p->type = 0; + + return vect; +} + +static expr *scalarvect(long scalar) +{ + begintemp(); + addtotemp(EXPR_SIMPLE, scalar); + return finishtemp(); +} + +static expr *unknown_expr(void) +{ + begintemp(); + addtotemp(EXPR_UNKNOWN, 1L); + return finishtemp(); +} + +/* + * The SEG operator: calculate the segment part of a relocatable + * value. Return NULL, as usual, if an error occurs. Report the + * error too. + */ +static expr *segment_part(expr * e) +{ + long seg; + + if (is_unknown(e)) + return unknown_expr(); + + if (!is_reloc(e)) { + error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value"); + return NULL; + } + + seg = reloc_seg(e); + if (seg == NO_SEG) { + error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value"); + return NULL; + } else if (seg & SEG_ABS) { + return scalarvect(seg & ~SEG_ABS); + } else if (seg & 1) { + error(ERR_NONFATAL, "SEG applied to something which" + " is already a segment base"); + return NULL; + } else { + long base = outfmt->segbase(seg + 1); + + begintemp(); + addtotemp((base == NO_SEG ? EXPR_UNKNOWN : EXPR_SEGBASE + base), + 1L); + return finishtemp(); + } +} + +/* + * Recursive-descent parser. Called with a single boolean operand, + * which is TRUE if the evaluation is critical (i.e. unresolved + * symbols are an error condition). Must update the global `i' to + * reflect the token after the parsed string. May return NULL. + * + * evaluate() should report its own errors: on return it is assumed + * that if NULL has been returned, the error has already been + * reported. + */ + +/* + * Grammar parsed is: + * + * expr : bexpr [ WRT expr6 ] + * bexpr : rexp0 or expr0 depending on relative-mode setting + * rexp0 : rexp1 [ {||} rexp1...] + * rexp1 : rexp2 [ {^^} rexp2...] + * rexp2 : rexp3 [ {&&} rexp3...] + * rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ] + * expr0 : expr1 [ {|} expr1...] + * expr1 : expr2 [ {^} expr2...] + * expr2 : expr3 [ {&} expr3...] + * expr3 : expr4 [ {<<,>>} expr4...] + * expr4 : expr5 [ {+,-} expr5...] + * expr5 : expr6 [ {*,/,%,//,%%} expr6...] + * expr6 : { ~,+,-,SEG } expr6 + * | (bexpr) + * | symbol + * | $ + * | number + */ + +static expr *rexp0(int), *rexp1(int), *rexp2(int), *rexp3(int); + +static expr *expr0(int), *expr1(int), *expr2(int), *expr3(int); +static expr *expr4(int), *expr5(int), *expr6(int); + +static expr *(*bexpr) (int); + +static expr *rexp0(int critical) +{ + expr *e, *f; + + e = rexp1(critical); + if (!e) + return NULL; + + while (i == TOKEN_DBL_OR) { + i = scan(scpriv, tokval); + f = rexp1(critical); + if (!f) + return NULL; + if (!(is_simple(e) || is_just_unknown(e)) || + !(is_simple(f) || is_just_unknown(f))) { + error(ERR_NONFATAL, "`|' operator may only be applied to" + " scalar values"); + } + + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect((long)(reloc_value(e) || reloc_value(f))); + } + return e; +} + +static expr *rexp1(int critical) +{ + expr *e, *f; + + e = rexp2(critical); + if (!e) + return NULL; + + while (i == TOKEN_DBL_XOR) { + i = scan(scpriv, tokval); + f = rexp2(critical); + if (!f) + return NULL; + if (!(is_simple(e) || is_just_unknown(e)) || + !(is_simple(f) || is_just_unknown(f))) { + error(ERR_NONFATAL, "`^' operator may only be applied to" + " scalar values"); + } + + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect((long)(!reloc_value(e) ^ !reloc_value(f))); + } + return e; +} + +static expr *rexp2(int critical) +{ + expr *e, *f; + + e = rexp3(critical); + if (!e) + return NULL; + while (i == TOKEN_DBL_AND) { + i = scan(scpriv, tokval); + f = rexp3(critical); + if (!f) + return NULL; + if (!(is_simple(e) || is_just_unknown(e)) || + !(is_simple(f) || is_just_unknown(f))) { + error(ERR_NONFATAL, "`&' operator may only be applied to" + " scalar values"); + } + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect((long)(reloc_value(e) && reloc_value(f))); + } + return e; +} + +static expr *rexp3(int critical) +{ + expr *e, *f; + long v; + + e = expr0(critical); + if (!e) + return NULL; + + while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || + i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) { + int j = i; + i = scan(scpriv, tokval); + f = expr0(critical); + if (!f) + return NULL; + + e = add_vectors(e, scalar_mult(f, -1L, FALSE)); + + switch (j) { + case TOKEN_EQ: + case TOKEN_NE: + if (is_unknown(e)) + v = -1; /* means unknown */ + else if (!is_really_simple(e) || reloc_value(e) != 0) + v = (j == TOKEN_NE); /* unequal, so return TRUE if NE */ + else + v = (j == TOKEN_EQ); /* equal, so return TRUE if EQ */ + break; + default: + if (is_unknown(e)) + v = -1; /* means unknown */ + else if (!is_really_simple(e)) { + error(ERR_NONFATAL, + "`%s': operands differ by a non-scalar", + (j == TOKEN_LE ? "<=" : j == TOKEN_LT ? "<" : j == + TOKEN_GE ? ">=" : ">")); + v = 0; /* must set it to _something_ */ + } else { + int vv = reloc_value(e); + if (vv == 0) + v = (j == TOKEN_LE || j == TOKEN_GE); + else if (vv > 0) + v = (j == TOKEN_GE || j == TOKEN_GT); + else /* vv < 0 */ + v = (j == TOKEN_LE || j == TOKEN_LT); + } + break; + } + + if (v == -1) + e = unknown_expr(); + else + e = scalarvect(v); + } + return e; +} + +static expr *expr0(int critical) +{ + expr *e, *f; + + e = expr1(critical); + if (!e) + return NULL; + + while (i == '|') { + i = scan(scpriv, tokval); + f = expr1(critical); + if (!f) + return NULL; + if (!(is_simple(e) || is_just_unknown(e)) || + !(is_simple(f) || is_just_unknown(f))) { + error(ERR_NONFATAL, "`|' operator may only be applied to" + " scalar values"); + } + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect(reloc_value(e) | reloc_value(f)); + } + return e; +} + +static expr *expr1(int critical) +{ + expr *e, *f; + + e = expr2(critical); + if (!e) + return NULL; + + while (i == '^') { + i = scan(scpriv, tokval); + f = expr2(critical); + if (!f) + return NULL; + if (!(is_simple(e) || is_just_unknown(e)) || + !(is_simple(f) || is_just_unknown(f))) { + error(ERR_NONFATAL, "`^' operator may only be applied to" + " scalar values"); + } + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect(reloc_value(e) ^ reloc_value(f)); + } + return e; +} + +static expr *expr2(int critical) +{ + expr *e, *f; + + e = expr3(critical); + if (!e) + return NULL; + + while (i == '&') { + i = scan(scpriv, tokval); + f = expr3(critical); + if (!f) + return NULL; + if (!(is_simple(e) || is_just_unknown(e)) || + !(is_simple(f) || is_just_unknown(f))) { + error(ERR_NONFATAL, "`&' operator may only be applied to" + " scalar values"); + } + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect(reloc_value(e) & reloc_value(f)); + } + return e; +} + +static expr *expr3(int critical) +{ + expr *e, *f; + + e = expr4(critical); + if (!e) + return NULL; + + while (i == TOKEN_SHL || i == TOKEN_SHR) { + int j = i; + i = scan(scpriv, tokval); + f = expr4(critical); + if (!f) + return NULL; + if (!(is_simple(e) || is_just_unknown(e)) || + !(is_simple(f) || is_just_unknown(f))) { + error(ERR_NONFATAL, "shift operator may only be applied to" + " scalar values"); + } else if (is_just_unknown(e) || is_just_unknown(f)) { + e = unknown_expr(); + } else + switch (j) { + case TOKEN_SHL: + e = scalarvect(reloc_value(e) << reloc_value(f)); + break; + case TOKEN_SHR: + e = scalarvect(((unsigned long)reloc_value(e)) >> + reloc_value(f)); + break; + } + } + return e; +} + +static expr *expr4(int critical) +{ + expr *e, *f; + + e = expr5(critical); + if (!e) + return NULL; + while (i == '+' || i == '-') { + int j = i; + i = scan(scpriv, tokval); + f = expr5(critical); + if (!f) + return NULL; + switch (j) { + case '+': + e = add_vectors(e, f); + break; + case '-': + e = add_vectors(e, scalar_mult(f, -1L, FALSE)); + break; + } + } + return e; +} + +static expr *expr5(int critical) +{ + expr *e, *f; + + e = expr6(critical); + if (!e) + return NULL; + while (i == '*' || i == '/' || i == '%' || + i == TOKEN_SDIV || i == TOKEN_SMOD) { + int j = i; + i = scan(scpriv, tokval); + f = expr6(critical); + if (!f) + return NULL; + if (j != '*' && (!(is_simple(e) || is_just_unknown(e)) || + !(is_simple(f) || is_just_unknown(f)))) { + error(ERR_NONFATAL, "division operator may only be applied to" + " scalar values"); + return NULL; + } + if (j != '*' && !is_unknown(f) && reloc_value(f) == 0) { + error(ERR_NONFATAL, "division by zero"); + return NULL; + } + switch (j) { + case '*': + if (is_simple(e)) + e = scalar_mult(f, reloc_value(e), TRUE); + else if (is_simple(f)) + e = scalar_mult(e, reloc_value(f), TRUE); + else if (is_just_unknown(e) && is_just_unknown(f)) + e = unknown_expr(); + else { + error(ERR_NONFATAL, "unable to multiply two " + "non-scalar objects"); + return NULL; + } + break; + case '/': + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect(((unsigned long)reloc_value(e)) / + ((unsigned long)reloc_value(f))); + break; + case '%': + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect(((unsigned long)reloc_value(e)) % + ((unsigned long)reloc_value(f))); + break; + case TOKEN_SDIV: + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect(((signed long)reloc_value(e)) / + ((signed long)reloc_value(f))); + break; + case TOKEN_SMOD: + if (is_just_unknown(e) || is_just_unknown(f)) + e = unknown_expr(); + else + e = scalarvect(((signed long)reloc_value(e)) % + ((signed long)reloc_value(f))); + break; + } + } + return e; +} + +static expr *expr6(int critical) +{ + long type; + expr *e; + long label_seg, label_ofs; + + if (i == '-') { + i = scan(scpriv, tokval); + e = expr6(critical); + if (!e) + return NULL; + return scalar_mult(e, -1L, FALSE); + } else if (i == '+') { + i = scan(scpriv, tokval); + return expr6(critical); + } else if (i == '~') { + i = scan(scpriv, tokval); + e = expr6(critical); + if (!e) + return NULL; + if (is_just_unknown(e)) + return unknown_expr(); + else if (!is_simple(e)) { + error(ERR_NONFATAL, "`~' operator may only be applied to" + " scalar values"); + return NULL; + } + return scalarvect(~reloc_value(e)); + } else if (i == TOKEN_SEG) { + i = scan(scpriv, tokval); + e = expr6(critical); + if (!e) + return NULL; + e = segment_part(e); + if (!e) + return NULL; + if (is_unknown(e) && critical) { + error(ERR_NONFATAL, "unable to determine segment base"); + return NULL; + } + return e; + } else if (i == '(') { + i = scan(scpriv, tokval); + e = bexpr(critical); + if (!e) + return NULL; + if (i != ')') { + error(ERR_NONFATAL, "expecting `)'"); + return NULL; + } + i = scan(scpriv, tokval); + return e; + } else if (i == TOKEN_NUM || i == TOKEN_REG || i == TOKEN_ID || + i == TOKEN_HERE || i == TOKEN_BASE) { + begintemp(); + switch (i) { + case TOKEN_NUM: + addtotemp(EXPR_SIMPLE, tokval->t_integer); + break; + case TOKEN_REG: + addtotemp(tokval->t_integer, 1L); + if (hint && hint->type == EAH_NOHINT) + hint->base = tokval->t_integer, hint->type = EAH_MAKEBASE; + break; + case TOKEN_ID: + case TOKEN_HERE: + case TOKEN_BASE: + /* + * If !location->known, this indicates that no + * symbol, Here or Base references are valid because we + * are in preprocess-only mode. + */ + if (!location->known) { + error(ERR_NONFATAL, + "%s not supported in preprocess-only mode", + (i == TOKEN_ID ? "symbol references" : + i == TOKEN_HERE ? "`$'" : "`$$'")); + addtotemp(EXPR_UNKNOWN, 1L); + break; + } + + type = EXPR_SIMPLE; /* might get overridden by UNKNOWN */ + if (i == TOKEN_BASE) { + label_seg = in_abs_seg ? abs_seg : location->segment; + label_ofs = 0; + } else if (i == TOKEN_HERE) { + label_seg = in_abs_seg ? abs_seg : location->segment; + label_ofs = in_abs_seg ? abs_offset : location->offset; + } else { + if (!labelfunc(tokval->t_charptr, &label_seg, &label_ofs)) { + if (critical == 2) { + error(ERR_NONFATAL, "symbol `%s' undefined", + tokval->t_charptr); + return NULL; + } else if (critical == 1) { + error(ERR_NONFATAL, + "symbol `%s' not defined before use", + tokval->t_charptr); + return NULL; + } else { + if (opflags) + *opflags |= 1; + type = EXPR_UNKNOWN; + label_seg = NO_SEG; + label_ofs = 1; + } + } + if (opflags && is_extern(tokval->t_charptr)) + *opflags |= OPFLAG_EXTERN; + } + addtotemp(type, label_ofs); + if (label_seg != NO_SEG) + addtotemp(EXPR_SEGBASE + label_seg, 1L); + break; + } + i = scan(scpriv, tokval); + return finishtemp(); + } else { + error(ERR_NONFATAL, "expression syntax error"); + return NULL; + } +} + +void eval_global_info(struct ofmt *output, lfunc lookup_label, + loc_t * locp) +{ + outfmt = output; + labelfunc = lookup_label; + location = locp; +} + +expr *evaluate(scanner sc, void *scprivate, struct tokenval *tv, + int *fwref, int critical, efunc report_error, + struct eval_hints *hints) +{ + expr *e; + expr *f = NULL; + + hint = hints; + if (hint) + hint->type = EAH_NOHINT; + + if (critical & CRITICAL) { + critical &= ~CRITICAL; + bexpr = rexp0; + } else + bexpr = expr0; + + scan = sc; + scpriv = scprivate; + tokval = tv; + error = report_error; + opflags = fwref; + + if (tokval->t_type == TOKEN_INVALID) + i = scan(scpriv, tokval); + else + i = tokval->t_type; + + while (ntempexprs) /* initialise temporary storage */ + nasm_free(tempexprs[--ntempexprs]); + + e = bexpr(critical); + if (!e) + return NULL; + + if (i == TOKEN_WRT) { + i = scan(scpriv, tokval); /* eat the WRT */ + f = expr6(critical); + if (!f) + return NULL; + } + e = scalar_mult(e, 1L, FALSE); /* strip far-absolute segment part */ + if (f) { + expr *g; + if (is_just_unknown(f)) + g = unknown_expr(); + else { + long value; + begintemp(); + if (!is_reloc(f)) { + error(ERR_NONFATAL, "invalid right-hand operand to WRT"); + return NULL; + } + value = reloc_seg(f); + if (value == NO_SEG) + value = reloc_value(f) | SEG_ABS; + else if (!(value & SEG_ABS) && !(value % 2) && critical) { + error(ERR_NONFATAL, "invalid right-hand operand to WRT"); + return NULL; + } + addtotemp(EXPR_WRT, value); + g = finishtemp(); + } + e = add_vectors(e, g); + } + return e; +} diff --git a/eval.h b/eval.h index a933cbfd..1724e2fc 100644 --- a/eval.h +++ b/eval.h @@ -14,14 +14,15 @@ * providing segment-base details, and what function can be used to * look labels up. */ -void eval_global_info (struct ofmt *output, lfunc lookup_label, loc_t *locp); +void eval_global_info(struct ofmt *output, lfunc lookup_label, + loc_t * locp); /* * The evaluator itself. */ -expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, - int *fwref, int critical, efunc report_error, - struct eval_hints *hints); +expr *evaluate(scanner sc, void *scprivate, struct tokenval *tv, + int *fwref, int critical, efunc report_error, + struct eval_hints *hints); void eval_cleanup(void); diff --git a/float.c b/float.c dissimilarity index 70% index e7a5fcd5..75d68ef6 100644 --- a/float.c +++ b/float.c @@ -1,403 +1,406 @@ -/* float.c floating-point constant support for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * initial version 13/ix/96 by Simon Tatham - */ - -#include -#include -#include - -#include "nasm.h" - -#define TRUE 1 -#define FALSE 0 - -#define MANT_WORDS 6 /* 64 bits + 32 for accuracy == 96 */ -#define MANT_DIGITS 28 /* 29 digits don't fit in 96 bits */ - -/* - * guaranteed top bit of from is set - * => we only have to worry about _one_ bit shift to the left - */ - -static int ieee_multiply(unsigned short *to, unsigned short *from) -{ - unsigned long temp[MANT_WORDS*2]; - int i, j; - - for (i=0; i> 16; - temp[i+j+1] += n & 0xFFFF; - } - - for (i=MANT_WORDS*2; --i ;) { - temp[i-1] += temp[i] >> 16; - temp[i] &= 0xFFFF; - } - if (temp[0] & 0x8000) { - for (i=0; i= '0' && *string <= '9') { - if (*string == '0' && !started) { - if (seendot) - tenpwr--; - } else { - started = TRUE; - if (p < digits+sizeof(digits)) - *p++ = *string - '0'; - if (!seendot) - tenpwr++; - } - } else { - error (ERR_NONFATAL, - "floating-point constant: `%c' is invalid character", - *string); - return; - } - string++; - } - if (*string) { - string++; /* eat the E */ - tenpwr += atoi(string); - } - - /* - * At this point, the memory interval [digits,p) contains a - * series of decimal digits zzzzzzz such that our number X - * satisfies - * - * X = 0.zzzzzzz * 10^tenpwr - */ - - bit = 0x8000; - for (m=mant; m q && !p[-1]) - p--; - if (p <= q) - break; - for (r = p; r-- > q ;) { - int i; - - i = 2 * *r + carry; - if (i >= 10) - carry = 1, i -= 10; - else - carry = 0; - *r = i; - } - if (carry) - *m |= bit, started = TRUE; - if (started) { - if (bit == 1) - bit = 0x8000, m++; - else - bit >>= 1; - } else - twopwr--; - } - twopwr += tenpwr; - - /* - * At this point the `mant' array contains the first six - * fractional places of a base-2^16 real number, which when - * multiplied by 2^twopwr and 5^tenpwr gives X. So now we - * really do multiply by 5^tenpwr. - */ - - if (tenpwr < 0) { - for (m=mult; m 0) { - mult[0] = 0xA000; - for (m=mult+1; m>= 1; - } - - /* - * Conversion is done. The elements of `mant' contain the first - * fractional places of a base-2^16 real number in [0.5,1) - * which we can multiply by 2^twopwr to get X. Or, of course, - * it contains zero. - */ - *exponent = twopwr; -} - -/* - * Shift a mantissa to the right by i (i < 16) bits. - */ -static void ieee_shr(unsigned short *mant, int i) -{ - unsigned short n = 0, m; - int j; - - for (j=0; j> i) | n; - n = m; - } -} - -/* - * Round a mantissa off after i words. - */ -static int ieee_round(unsigned short *mant, int i) -{ - if (mant[i] & 0x8000) { - do { - ++mant[--i]; - mant[i] &= 0xFFFF; - } while (i > 0 && !mant[i]); - return !i && !mant[i]; - } - return 0; -} - -#define put(a,b) ( (*(a)=(b)), ((a)[1]=(b)>>8) ) - -static int to_double(char *str, long sign, unsigned char *result, - efunc error) -{ - unsigned short mant[MANT_WORDS]; - long exponent; - - sign = (sign < 0 ? 0x8000L : 0L); - - ieee_flconvert (str, mant, &exponent, error); - if (mant[0] & 0x8000) { - /* - * Non-zero. - */ - exponent--; - if (exponent >= -1022 && exponent <= 1024) { - /* - * Normalised. - */ - exponent += 1023; - ieee_shr(mant, 11); - ieee_round(mant, 4); - if (mant[0] & 0x20) /* did we scale up by one? */ - ieee_shr(mant, 1), exponent++; - mant[0] &= 0xF; /* remove leading one */ - put(result+6,(exponent << 4) | mant[0] | sign); - put(result+4,mant[1]); - put(result+2,mant[2]); - put(result+0,mant[3]); - } else if (exponent < -1022 && exponent >= -1074) { - /* - * Denormal. - */ - int shift = -(exponent+1011); - int sh = shift % 16, wds = shift / 16; - ieee_shr(mant, sh); - if (ieee_round(mant, 4-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) { - ieee_shr(mant, 1); - if (sh==0) - mant[0] |= 0x8000; - exponent++; - } - put(result+6,(wds == 0 ? mant[0] : 0) | sign); - put(result+4,(wds <= 1 ? mant[1-wds] : 0)); - put(result+2,(wds <= 2 ? mant[2-wds] : 0)); - put(result+0,(wds <= 3 ? mant[3-wds] : 0)); - } else { - if (exponent > 0) { - error(ERR_NONFATAL, "overflow in floating-point constant"); - return 0; - } else - memset (result, 0, 8); - } - } else { - /* - * Zero. - */ - memset (result, 0, 8); - } - return 1; /* success */ -} - -static int to_float(char *str, long sign, unsigned char *result, - efunc error) -{ - unsigned short mant[MANT_WORDS]; - long exponent; - - sign = (sign < 0 ? 0x8000L : 0L); - - ieee_flconvert (str, mant, &exponent, error); - if (mant[0] & 0x8000) { - /* - * Non-zero. - */ - exponent--; - if (exponent >= -126 && exponent <= 128) { - /* - * Normalised. - */ - exponent += 127; - ieee_shr(mant, 8); - ieee_round(mant, 2); - if (mant[0] & 0x100) /* did we scale up by one? */ - ieee_shr(mant, 1), exponent++; - mant[0] &= 0x7F; /* remove leading one */ - put(result+2,(exponent << 7) | mant[0] | sign); - put(result+0,mant[1]); - } else if (exponent < -126 && exponent >= -149) { - /* - * Denormal. - */ - int shift = -(exponent+118); - int sh = shift % 16, wds = shift / 16; - ieee_shr(mant, sh); - if (ieee_round(mant, 2-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) { - ieee_shr(mant, 1); - if (sh==0) - mant[0] |= 0x8000; - exponent++; - } - put(result+2,(wds == 0 ? mant[0] : 0) | sign); - put(result+0,(wds <= 1 ? mant[1-wds] : 0)); - } else { - if (exponent > 0) { - error(ERR_NONFATAL, "overflow in floating-point constant"); - return 0; - } else - memset (result, 0, 4); - } - } else { - memset (result, 0, 4); - } - return 1; -} - -static int to_ldoub(char *str, long sign, unsigned char *result, - efunc error) -{ - unsigned short mant[MANT_WORDS]; - long exponent; - - sign = (sign < 0 ? 0x8000L : 0L); - - ieee_flconvert (str, mant, &exponent, error); - if (mant[0] & 0x8000) { - /* - * Non-zero. - */ - exponent--; - if (exponent >= -16383 && exponent <= 16384) { - /* - * Normalised. - */ - exponent += 16383; - if (ieee_round(mant, 4)) /* did we scale up by one? */ - ieee_shr(mant, 1), mant[0] |= 0x8000, exponent++; - put(result+8,exponent | sign); - put(result+6,mant[0]); - put(result+4,mant[1]); - put(result+2,mant[2]); - put(result+0,mant[3]); - } else if (exponent < -16383 && exponent >= -16446) { - /* - * Denormal. - */ - int shift = -(exponent+16383); - int sh = shift % 16, wds = shift / 16; - ieee_shr(mant, sh); - if (ieee_round(mant, 4-wds) || (sh>0 && (mant[0]&(0x8000>>(sh-1))))) { - ieee_shr(mant, 1); - if (sh==0) - mant[0] |= 0x8000; - exponent++; - } - put(result+8,sign); - put(result+6,(wds == 0 ? mant[0] : 0)); - put(result+4,(wds <= 1 ? mant[1-wds] : 0)); - put(result+2,(wds <= 2 ? mant[2-wds] : 0)); - put(result+0,(wds <= 3 ? mant[3-wds] : 0)); - } else { - if (exponent > 0) { - error(ERR_NONFATAL, "overflow in floating-point constant"); - return 0; - } else - memset (result, 0, 10); - } - } else { - /* - * Zero. - */ - memset (result, 0, 10); - } - return 1; -} - -int float_const (char *number, long sign, unsigned char *result, int bytes, - efunc error) -{ - if (bytes == 4) - return to_float (number, sign, result, error); - else if (bytes == 8) - return to_double (number, sign, result, error); - else if (bytes == 10) - return to_ldoub (number, sign, result, error); - else { - error(ERR_PANIC, "strange value %d passed to float_const", bytes); - return 0; - } -} +/* float.c floating-point constant support for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 13/ix/96 by Simon Tatham + */ + +#include +#include +#include + +#include "nasm.h" + +#define TRUE 1 +#define FALSE 0 + +#define MANT_WORDS 6 /* 64 bits + 32 for accuracy == 96 */ +#define MANT_DIGITS 28 /* 29 digits don't fit in 96 bits */ + +/* + * guaranteed top bit of from is set + * => we only have to worry about _one_ bit shift to the left + */ + +static int ieee_multiply(unsigned short *to, unsigned short *from) +{ + unsigned long temp[MANT_WORDS * 2]; + int i, j; + + for (i = 0; i < MANT_WORDS * 2; i++) + temp[i] = 0; + + for (i = 0; i < MANT_WORDS; i++) + for (j = 0; j < MANT_WORDS; j++) { + unsigned long n; + n = (unsigned long)to[i] * (unsigned long)from[j]; + temp[i + j] += n >> 16; + temp[i + j + 1] += n & 0xFFFF; + } + + for (i = MANT_WORDS * 2; --i;) { + temp[i - 1] += temp[i] >> 16; + temp[i] &= 0xFFFF; + } + if (temp[0] & 0x8000) { + for (i = 0; i < MANT_WORDS; i++) + to[i] = temp[i] & 0xFFFF; + return 0; + } else { + for (i = 0; i < MANT_WORDS; i++) + to[i] = (temp[i] << 1) + !!(temp[i + 1] & 0x8000); + return -1; + } +} + +static void ieee_flconvert(char *string, unsigned short *mant, + long *exponent, efunc error) +{ + char digits[MANT_DIGITS]; + char *p, *q, *r; + unsigned short mult[MANT_WORDS], bit; + unsigned short *m; + long tenpwr, twopwr; + int extratwos, started, seendot; + + p = digits; + tenpwr = 0; + started = seendot = FALSE; + while (*string && *string != 'E' && *string != 'e') { + if (*string == '.') { + if (!seendot) + seendot = TRUE; + else { + error(ERR_NONFATAL, + "too many periods in floating-point constant"); + return; + } + } else if (*string >= '0' && *string <= '9') { + if (*string == '0' && !started) { + if (seendot) + tenpwr--; + } else { + started = TRUE; + if (p < digits + sizeof(digits)) + *p++ = *string - '0'; + if (!seendot) + tenpwr++; + } + } else { + error(ERR_NONFATAL, + "floating-point constant: `%c' is invalid character", + *string); + return; + } + string++; + } + if (*string) { + string++; /* eat the E */ + tenpwr += atoi(string); + } + + /* + * At this point, the memory interval [digits,p) contains a + * series of decimal digits zzzzzzz such that our number X + * satisfies + * + * X = 0.zzzzzzz * 10^tenpwr + */ + + bit = 0x8000; + for (m = mant; m < mant + MANT_WORDS; m++) + *m = 0; + m = mant; + q = digits; + started = FALSE; + twopwr = 0; + while (m < mant + MANT_WORDS) { + unsigned short carry = 0; + while (p > q && !p[-1]) + p--; + if (p <= q) + break; + for (r = p; r-- > q;) { + int i; + + i = 2 * *r + carry; + if (i >= 10) + carry = 1, i -= 10; + else + carry = 0; + *r = i; + } + if (carry) + *m |= bit, started = TRUE; + if (started) { + if (bit == 1) + bit = 0x8000, m++; + else + bit >>= 1; + } else + twopwr--; + } + twopwr += tenpwr; + + /* + * At this point the `mant' array contains the first six + * fractional places of a base-2^16 real number, which when + * multiplied by 2^twopwr and 5^tenpwr gives X. So now we + * really do multiply by 5^tenpwr. + */ + + if (tenpwr < 0) { + for (m = mult; m < mult + MANT_WORDS; m++) + *m = 0xCCCC; + extratwos = -2; + tenpwr = -tenpwr; + } else if (tenpwr > 0) { + mult[0] = 0xA000; + for (m = mult + 1; m < mult + MANT_WORDS; m++) + *m = 0; + extratwos = 3; + } else + extratwos = 0; + while (tenpwr) { + if (tenpwr & 1) + twopwr += extratwos + ieee_multiply(mant, mult); + extratwos = extratwos * 2 + ieee_multiply(mult, mult); + tenpwr >>= 1; + } + + /* + * Conversion is done. The elements of `mant' contain the first + * fractional places of a base-2^16 real number in [0.5,1) + * which we can multiply by 2^twopwr to get X. Or, of course, + * it contains zero. + */ + *exponent = twopwr; +} + +/* + * Shift a mantissa to the right by i (i < 16) bits. + */ +static void ieee_shr(unsigned short *mant, int i) +{ + unsigned short n = 0, m; + int j; + + for (j = 0; j < MANT_WORDS; j++) { + m = (mant[j] << (16 - i)) & 0xFFFF; + mant[j] = (mant[j] >> i) | n; + n = m; + } +} + +/* + * Round a mantissa off after i words. + */ +static int ieee_round(unsigned short *mant, int i) +{ + if (mant[i] & 0x8000) { + do { + ++mant[--i]; + mant[i] &= 0xFFFF; + } while (i > 0 && !mant[i]); + return !i && !mant[i]; + } + return 0; +} + +#define put(a,b) ( (*(a)=(b)), ((a)[1]=(b)>>8) ) + +static int to_double(char *str, long sign, unsigned char *result, + efunc error) +{ + unsigned short mant[MANT_WORDS]; + long exponent; + + sign = (sign < 0 ? 0x8000L : 0L); + + ieee_flconvert(str, mant, &exponent, error); + if (mant[0] & 0x8000) { + /* + * Non-zero. + */ + exponent--; + if (exponent >= -1022 && exponent <= 1024) { + /* + * Normalised. + */ + exponent += 1023; + ieee_shr(mant, 11); + ieee_round(mant, 4); + if (mant[0] & 0x20) /* did we scale up by one? */ + ieee_shr(mant, 1), exponent++; + mant[0] &= 0xF; /* remove leading one */ + put(result + 6, (exponent << 4) | mant[0] | sign); + put(result + 4, mant[1]); + put(result + 2, mant[2]); + put(result + 0, mant[3]); + } else if (exponent < -1022 && exponent >= -1074) { + /* + * Denormal. + */ + int shift = -(exponent + 1011); + int sh = shift % 16, wds = shift / 16; + ieee_shr(mant, sh); + if (ieee_round(mant, 4 - wds) + || (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) { + ieee_shr(mant, 1); + if (sh == 0) + mant[0] |= 0x8000; + exponent++; + } + put(result + 6, (wds == 0 ? mant[0] : 0) | sign); + put(result + 4, (wds <= 1 ? mant[1 - wds] : 0)); + put(result + 2, (wds <= 2 ? mant[2 - wds] : 0)); + put(result + 0, (wds <= 3 ? mant[3 - wds] : 0)); + } else { + if (exponent > 0) { + error(ERR_NONFATAL, "overflow in floating-point constant"); + return 0; + } else + memset(result, 0, 8); + } + } else { + /* + * Zero. + */ + memset(result, 0, 8); + } + return 1; /* success */ +} + +static int to_float(char *str, long sign, unsigned char *result, + efunc error) +{ + unsigned short mant[MANT_WORDS]; + long exponent; + + sign = (sign < 0 ? 0x8000L : 0L); + + ieee_flconvert(str, mant, &exponent, error); + if (mant[0] & 0x8000) { + /* + * Non-zero. + */ + exponent--; + if (exponent >= -126 && exponent <= 128) { + /* + * Normalised. + */ + exponent += 127; + ieee_shr(mant, 8); + ieee_round(mant, 2); + if (mant[0] & 0x100) /* did we scale up by one? */ + ieee_shr(mant, 1), exponent++; + mant[0] &= 0x7F; /* remove leading one */ + put(result + 2, (exponent << 7) | mant[0] | sign); + put(result + 0, mant[1]); + } else if (exponent < -126 && exponent >= -149) { + /* + * Denormal. + */ + int shift = -(exponent + 118); + int sh = shift % 16, wds = shift / 16; + ieee_shr(mant, sh); + if (ieee_round(mant, 2 - wds) + || (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) { + ieee_shr(mant, 1); + if (sh == 0) + mant[0] |= 0x8000; + exponent++; + } + put(result + 2, (wds == 0 ? mant[0] : 0) | sign); + put(result + 0, (wds <= 1 ? mant[1 - wds] : 0)); + } else { + if (exponent > 0) { + error(ERR_NONFATAL, "overflow in floating-point constant"); + return 0; + } else + memset(result, 0, 4); + } + } else { + memset(result, 0, 4); + } + return 1; +} + +static int to_ldoub(char *str, long sign, unsigned char *result, + efunc error) +{ + unsigned short mant[MANT_WORDS]; + long exponent; + + sign = (sign < 0 ? 0x8000L : 0L); + + ieee_flconvert(str, mant, &exponent, error); + if (mant[0] & 0x8000) { + /* + * Non-zero. + */ + exponent--; + if (exponent >= -16383 && exponent <= 16384) { + /* + * Normalised. + */ + exponent += 16383; + if (ieee_round(mant, 4)) /* did we scale up by one? */ + ieee_shr(mant, 1), mant[0] |= 0x8000, exponent++; + put(result + 8, exponent | sign); + put(result + 6, mant[0]); + put(result + 4, mant[1]); + put(result + 2, mant[2]); + put(result + 0, mant[3]); + } else if (exponent < -16383 && exponent >= -16446) { + /* + * Denormal. + */ + int shift = -(exponent + 16383); + int sh = shift % 16, wds = shift / 16; + ieee_shr(mant, sh); + if (ieee_round(mant, 4 - wds) + || (sh > 0 && (mant[0] & (0x8000 >> (sh - 1))))) { + ieee_shr(mant, 1); + if (sh == 0) + mant[0] |= 0x8000; + exponent++; + } + put(result + 8, sign); + put(result + 6, (wds == 0 ? mant[0] : 0)); + put(result + 4, (wds <= 1 ? mant[1 - wds] : 0)); + put(result + 2, (wds <= 2 ? mant[2 - wds] : 0)); + put(result + 0, (wds <= 3 ? mant[3 - wds] : 0)); + } else { + if (exponent > 0) { + error(ERR_NONFATAL, "overflow in floating-point constant"); + return 0; + } else + memset(result, 0, 10); + } + } else { + /* + * Zero. + */ + memset(result, 0, 10); + } + return 1; +} + +int float_const(char *number, long sign, unsigned char *result, int bytes, + efunc error) +{ + if (bytes == 4) + return to_float(number, sign, result, error); + else if (bytes == 8) + return to_double(number, sign, result, error); + else if (bytes == 10) + return to_ldoub(number, sign, result, error); + else { + error(ERR_PANIC, "strange value %d passed to float_const", bytes); + return 0; + } +} diff --git a/float.h b/float.h index cc01ec03..2f91633d 100644 --- a/float.h +++ b/float.h @@ -10,7 +10,7 @@ #ifndef NASM_FLOAT_H #define NASM_FLOAT_H -int float_const (char *number, long sign, unsigned char *result, int bytes, - efunc error); +int float_const(char *number, long sign, unsigned char *result, int bytes, + efunc error); #endif diff --git a/insns.h b/insns.h dissimilarity index 61% index e2f11453..92c23d02 100644 --- a/insns.h +++ b/insns.h @@ -1,99 +1,99 @@ -/* insns.h header file for insns.c - * $Id$ - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#ifndef NASM_INSNS_H -#define NASM_INSNS_H - -#include "insnsi.h" /* instruction opcode enum */ - -/* max length of any instruction, register name etc. */ -#if MAX_INSLEN > 9 /* MAX_INSLEN defined in insnsi.h */ -#define MAX_KEYWORD MAX_INSLEN -#else -#define MAX_KEYWORD 9 -#endif - -struct itemplate { - int opcode; /* the token, passed from "parser.c" */ - int operands; /* number of operands */ - long opd[3]; /* bit flags for operand types */ - const char *code; /* the code it assembles to */ - unsigned long flags; /* some flags */ -}; - -/* - * this define is used to signify the end of an itemplate - */ -#define ITEMPLATE_END {-1,-1,{-1,-1,-1},NULL,0} - -/* - * Instruction template flags. These specify which processor - * targets the instruction is eligible for, whether it is - * privileged or undocumented, and also specify extra error - * checking on the matching of the instruction. - * - * IF_SM stands for Size Match: any operand whose size is not - * explicitly specified by the template is `really' intended to be - * the same size as the first size-specified operand. - * Non-specification is tolerated in the input instruction, but - * _wrong_ specification is not. - * - * IF_SM2 invokes Size Match on only the first _two_ operands, for - * three-operand instructions such as SHLD: it implies that the - * first two operands must match in size, but that the third is - * required to be _unspecified_. - * - * IF_SB invokes Size Byte: operands with unspecified size in the - * template are really bytes, and so no non-byte specification in - * the input instruction will be tolerated. IF_SW similarly invokes - * Size Word, and IF_SD invokes Size Doubleword. - * - * (The default state if neither IF_SM nor IF_SM2 is specified is - * that any operand with unspecified size in the template is - * required to have unspecified size in the instruction too...) - */ - -#define IF_SM 0x00000001UL /* size match */ -#define IF_SM2 0x00000002UL /* size match first two operands */ -#define IF_SB 0x00000004UL /* unsized operands can't be non-byte */ -#define IF_SW 0x00000008UL /* unsized operands can't be non-word */ -#define IF_SD 0x00000010UL /* unsized operands can't be nondword */ -#define IF_AR0 0x00000020UL /* SB, SW, SD applies to argument 0 */ -#define IF_AR1 0x00000040UL /* SB, SW, SD applies to argument 1 */ -#define IF_AR2 0x00000060UL /* SB, SW, SD applies to argument 2 */ -#define IF_ARMASK 0x00000060UL /* mask for unsized argument spec */ -#define IF_PRIV 0x00000100UL /* it's a privileged instruction */ -#define IF_SMM 0x00000200UL /* it's only valid in SMM */ -#define IF_PROT 0x00000400UL /* it's protected mode only */ -#define IF_UNDOC 0x00001000UL /* it's an undocumented instruction */ -#define IF_FPU 0x00002000UL /* it's an FPU instruction */ -#define IF_MMX 0x00004000UL /* it's an MMX instruction */ -#define IF_3DNOW 0x00008000UL /* it's a 3DNow! instruction */ -#define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */ -#define IF_SSE2 0x00020000UL /* it's a SSE2 instruction */ -#define IF_SSE3 0x00040000UL /* it's a SSE3 (PNI) instruction */ -#define IF_PMASK 0xFF000000UL /* the mask for processor types */ -#define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */ - /* also the highest possible processor */ -#define IF_PFMASK 0xF001FF00UL /* the mask for disassembly "prefer" */ -#define IF_8086 0x00000000UL /* 8086 instruction */ -#define IF_186 0x01000000UL /* 186+ instruction */ -#define IF_286 0x02000000UL /* 286+ instruction */ -#define IF_386 0x03000000UL /* 386+ instruction */ -#define IF_486 0x04000000UL /* 486+ instruction */ -#define IF_PENT 0x05000000UL /* Pentium instruction */ -#define IF_P6 0x06000000UL /* P6 instruction */ -#define IF_KATMAI 0x07000000UL /* Katmai instructions */ -#define IF_WILLAMETTE 0x08000000UL /* Willamette instructions */ -#define IF_PRESCOTT 0x09000000UL /* Prescott instructions */ -#define IF_IA64 0x0F000000UL /* IA64 instructions */ -#define IF_CYRIX 0x10000000UL /* Cyrix-specific instruction */ -#define IF_AMD 0x20000000UL /* AMD-specific instruction */ - -#endif +/* insns.h header file for insns.c + * $Id$ + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef NASM_INSNS_H +#define NASM_INSNS_H + +#include "insnsi.h" /* instruction opcode enum */ + +/* max length of any instruction, register name etc. */ +#if MAX_INSLEN > 9 /* MAX_INSLEN defined in insnsi.h */ +#define MAX_KEYWORD MAX_INSLEN +#else +#define MAX_KEYWORD 9 +#endif + +struct itemplate { + int opcode; /* the token, passed from "parser.c" */ + int operands; /* number of operands */ + long opd[3]; /* bit flags for operand types */ + const char *code; /* the code it assembles to */ + unsigned long flags; /* some flags */ +}; + +/* + * this define is used to signify the end of an itemplate + */ +#define ITEMPLATE_END {-1,-1,{-1,-1,-1},NULL,0} + +/* + * Instruction template flags. These specify which processor + * targets the instruction is eligible for, whether it is + * privileged or undocumented, and also specify extra error + * checking on the matching of the instruction. + * + * IF_SM stands for Size Match: any operand whose size is not + * explicitly specified by the template is `really' intended to be + * the same size as the first size-specified operand. + * Non-specification is tolerated in the input instruction, but + * _wrong_ specification is not. + * + * IF_SM2 invokes Size Match on only the first _two_ operands, for + * three-operand instructions such as SHLD: it implies that the + * first two operands must match in size, but that the third is + * required to be _unspecified_. + * + * IF_SB invokes Size Byte: operands with unspecified size in the + * template are really bytes, and so no non-byte specification in + * the input instruction will be tolerated. IF_SW similarly invokes + * Size Word, and IF_SD invokes Size Doubleword. + * + * (The default state if neither IF_SM nor IF_SM2 is specified is + * that any operand with unspecified size in the template is + * required to have unspecified size in the instruction too...) + */ + +#define IF_SM 0x00000001UL /* size match */ +#define IF_SM2 0x00000002UL /* size match first two operands */ +#define IF_SB 0x00000004UL /* unsized operands can't be non-byte */ +#define IF_SW 0x00000008UL /* unsized operands can't be non-word */ +#define IF_SD 0x00000010UL /* unsized operands can't be nondword */ +#define IF_AR0 0x00000020UL /* SB, SW, SD applies to argument 0 */ +#define IF_AR1 0x00000040UL /* SB, SW, SD applies to argument 1 */ +#define IF_AR2 0x00000060UL /* SB, SW, SD applies to argument 2 */ +#define IF_ARMASK 0x00000060UL /* mask for unsized argument spec */ +#define IF_PRIV 0x00000100UL /* it's a privileged instruction */ +#define IF_SMM 0x00000200UL /* it's only valid in SMM */ +#define IF_PROT 0x00000400UL /* it's protected mode only */ +#define IF_UNDOC 0x00001000UL /* it's an undocumented instruction */ +#define IF_FPU 0x00002000UL /* it's an FPU instruction */ +#define IF_MMX 0x00004000UL /* it's an MMX instruction */ +#define IF_3DNOW 0x00008000UL /* it's a 3DNow! instruction */ +#define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */ +#define IF_SSE2 0x00020000UL /* it's a SSE2 instruction */ +#define IF_SSE3 0x00040000UL /* it's a SSE3 (PNI) instruction */ +#define IF_PMASK 0xFF000000UL /* the mask for processor types */ +#define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */ + /* also the highest possible processor */ +#define IF_PFMASK 0xF001FF00UL /* the mask for disassembly "prefer" */ +#define IF_8086 0x00000000UL /* 8086 instruction */ +#define IF_186 0x01000000UL /* 186+ instruction */ +#define IF_286 0x02000000UL /* 286+ instruction */ +#define IF_386 0x03000000UL /* 386+ instruction */ +#define IF_486 0x04000000UL /* 486+ instruction */ +#define IF_PENT 0x05000000UL /* Pentium instruction */ +#define IF_P6 0x06000000UL /* P6 instruction */ +#define IF_KATMAI 0x07000000UL /* Katmai instructions */ +#define IF_WILLAMETTE 0x08000000UL /* Willamette instructions */ +#define IF_PRESCOTT 0x09000000UL /* Prescott instructions */ +#define IF_IA64 0x0F000000UL /* IA64 instructions */ +#define IF_CYRIX 0x10000000UL /* Cyrix-specific instruction */ +#define IF_AMD 0x20000000UL /* AMD-specific instruction */ + +#endif diff --git a/labels.c b/labels.c index 833ad843..4d2c3470 100644 --- a/labels.c +++ b/labels.c @@ -29,17 +29,17 @@ ((c) == '.' || (c) == '@') : \ ((c) == '.')) -#define LABEL_BLOCK 32 /* no. of labels/block */ +#define LABEL_BLOCK 32 /* no. of labels/block */ #define LBLK_SIZE (LABEL_BLOCK*sizeof(union label)) -#define LABEL_HASHES 37 /* no. of hash table entries */ +#define LABEL_HASHES 37 /* no. of hash table entries */ -#define END_LIST -3 /* don't clash with NO_SEG! */ +#define END_LIST -3 /* don't clash with NO_SEG! */ #define END_BLOCK -2 #define BOGUS_VALUE -4 -#define PERMTS_SIZE 4096 /* size of text blocks */ +#define PERMTS_SIZE 4096 /* size of text blocks */ #if (PERMTS_SIZE > IDLEN_MAX) -#error "IPERMTS_SIZE must be less than or equal to IDLEN_MAX" +#error "IPERMTS_SIZE must be less than or equal to IDLEN_MAX" #endif /* values for label.defn.is_global */ @@ -53,7 +53,7 @@ #define GLOBAL_PLACEHOLDER (GLOBAL_BIT) #define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT) -union label { /* actual label structures */ +union label { /* actual label structures */ struct { long segment, offset; char *label, *special; @@ -65,35 +65,35 @@ union label { /* actual label structures */ } admin; }; -struct permts { /* permanent text storage */ - struct permts *next; /* for the linked list */ - int size, usage; /* size and used space in ... */ - char data[PERMTS_SIZE]; /* ... the data block itself */ +struct permts { /* permanent text storage */ + struct permts *next; /* for the linked list */ + int size, usage; /* size and used space in ... */ + char data[PERMTS_SIZE]; /* ... the data block itself */ }; -extern int global_offset_changed; /* defined in nasm.c */ +extern int global_offset_changed; /* defined in nasm.c */ -static union label *ltab[LABEL_HASHES];/* using a hash table */ -static union label *lfree[LABEL_HASHES];/* pointer into the above */ -static struct permts *perm_head; /* start of perm. text storage */ -static struct permts *perm_tail; /* end of perm. text storage */ +static union label *ltab[LABEL_HASHES]; /* using a hash table */ +static union label *lfree[LABEL_HASHES]; /* pointer into the above */ +static struct permts *perm_head; /* start of perm. text storage */ +static struct permts *perm_tail; /* end of perm. text storage */ -static void init_block (union label *blk); -static char *perm_copy (char *string1, char *string2); +static void init_block(union label *blk); +static char *perm_copy(char *string1, char *string2); static char *prevlabel; static int initialised = FALSE; -char lprefix[PREFIX_MAX] = {0}; -char lpostfix[PREFIX_MAX] = {0}; +char lprefix[PREFIX_MAX] = { 0 }; +char lpostfix[PREFIX_MAX] = { 0 }; /* * Internal routine: finds the `union label' corresponding to the * given label name. Creates a new one, if it isn't found, and if * `create' is TRUE. */ -static union label *find_label (char *label, int create) +static union label *find_label(char *label, int create) { int hash = 0; char *p, *prev; @@ -106,9 +106,11 @@ static union label *find_label (char *label, int create) prev = ""; prevlen = strlen(prev); p = prev; - while (*p) hash += *p++; + while (*p) + hash += *p++; p = label; - while (*p) hash += *p++; + while (*p) + hash += *p++; hash %= LABEL_HASHES; lptr = ltab[hash]; while (lptr->admin.movingon != END_LIST) { @@ -118,7 +120,7 @@ static union label *find_label (char *label, int create) break; } if (!strncmp(lptr->defn.label, prev, prevlen) && - !strcmp(lptr->defn.label+prevlen, label)) + !strcmp(lptr->defn.label + prevlen, label)) return lptr; lptr++; } @@ -127,123 +129,126 @@ static union label *find_label (char *label, int create) /* * must allocate a new block */ - lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE); + lfree[hash]->admin.next = + (union label *)nasm_malloc(LBLK_SIZE); lfree[hash] = lfree[hash]->admin.next; init_block(lfree[hash]); } lfree[hash]->admin.movingon = BOGUS_VALUE; - lfree[hash]->defn.label = perm_copy (prev, label); + lfree[hash]->defn.label = perm_copy(prev, label); lfree[hash]->defn.special = NULL; lfree[hash]->defn.is_global = NOT_DEFINED_YET; return lfree[hash]++; - } - else + } else return NULL; } -int lookup_label (char *label, long *segment, long *offset) +int lookup_label(char *label, long *segment, long *offset) { union label *lptr; if (!initialised) return 0; - lptr = find_label (label, 0); + lptr = find_label(label, 0); if (lptr && (lptr->defn.is_global & DEFINED_BIT)) { *segment = lptr->defn.segment; *offset = lptr->defn.offset; return 1; - } - else + } else return 0; } -int is_extern (char *label) +int is_extern(char *label) { union label *lptr; if (!initialised) return 0; - lptr = find_label (label, 0); + lptr = find_label(label, 0); if (lptr && (lptr->defn.is_global & EXTERN_BIT)) return 1; else return 0; } -void redefine_label (char *label, long segment, long offset, char *special, - int is_norm, int isextrn, struct ofmt *ofmt, efunc error) +void redefine_label(char *label, long segment, long offset, char *special, + int is_norm, int isextrn, struct ofmt *ofmt, + efunc error) { union label *lptr; int exi; - + /* This routine possibly ought to check for phase errors. Most assemblers * check for phase errors at this point. I don't know whether phase errors * are even possible, nor whether they are checked somewhere else */ - (void) segment; /* Don't warn that this parameter is unused */ - (void) special; /* Don't warn that this parameter is unused */ - (void) is_norm; /* Don't warn that this parameter is unused */ - (void) isextrn; /* Don't warn that this parameter is unused */ - (void) ofmt; /* Don't warn that this parameter is unused */ + (void)segment; /* Don't warn that this parameter is unused */ + (void)special; /* Don't warn that this parameter is unused */ + (void)is_norm; /* Don't warn that this parameter is unused */ + (void)isextrn; /* Don't warn that this parameter is unused */ + (void)ofmt; /* Don't warn that this parameter is unused */ #ifdef DEBUG #if DEBUG<3 if (!strncmp(label, "debugdump", 9)) #endif error(ERR_DEBUG, "redefine_label (%s, %ld, %08lx, %s, %d, %d)", - label, segment, offset, special, is_norm, isextrn); + label, segment, offset, special, is_norm, isextrn); #endif - lptr = find_label (label, 1); + lptr = find_label(label, 1); if (!lptr) - error (ERR_PANIC, "can't find label `%s' on pass two", label); - + error(ERR_PANIC, "can't find label `%s' on pass two", label); + if (!islocal(label)) { - if (!islocalchar(*label) && lptr->defn.is_norm) + if (!islocalchar(*label) && lptr->defn.is_norm) prevlabel = lptr->defn.label; } global_offset_changed |= (lptr->defn.offset != offset); lptr->defn.offset = offset; - -if (pass0 == 1) { - exi = !!(lptr->defn.is_global & GLOBAL_BIT); - if (exi) - { - char *xsymbol; - int slen; - slen = strlen(lprefix); - slen += strlen(lptr->defn.label); - slen += strlen(lpostfix); - slen++; /* room for that null char */ - xsymbol = nasm_malloc(slen); - snprintf(xsymbol,slen,"%s%s%s",lprefix,lptr->defn.label,lpostfix); - - ofmt->symdef (xsymbol, segment, offset, exi, - special ? special : lptr->defn.special); - ofmt->current_dfmt->debug_deflabel (xsymbol, segment, offset, exi, - special ? special : lptr->defn.special); + + if (pass0 == 1) { + exi = !!(lptr->defn.is_global & GLOBAL_BIT); + if (exi) { + char *xsymbol; + int slen; + slen = strlen(lprefix); + slen += strlen(lptr->defn.label); + slen += strlen(lpostfix); + slen++; /* room for that null char */ + xsymbol = nasm_malloc(slen); + snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label, + lpostfix); + + ofmt->symdef(xsymbol, segment, offset, exi, + special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset, + exi, + special ? special : lptr-> + defn.special); /** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/ + } else { + if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) != + EXTERN_BIT) { + ofmt->symdef(lptr->defn.label, segment, offset, exi, + special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel(label, segment, offset, + exi, + special ? special : + lptr->defn.special); + } + } } - else - { - if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) { - ofmt->symdef (lptr->defn.label, segment, offset, exi, - special ? special : lptr->defn.special); - ofmt->current_dfmt->debug_deflabel (label, segment, offset, exi, - special ? special : lptr->defn.special); - } - } -} /* if (pass0 == 1) */ - + /* if (pass0 == 1) */ } -void define_label (char *label, long segment, long offset, char *special, - int is_norm, int isextrn, struct ofmt *ofmt, efunc error) +void define_label(char *label, long segment, long offset, char *special, + int is_norm, int isextrn, struct ofmt *ofmt, efunc error) { union label *lptr; int exi; @@ -253,72 +258,75 @@ void define_label (char *label, long segment, long offset, char *special, if (!strncmp(label, "debugdump", 9)) #endif error(ERR_DEBUG, "define_label (%s, %ld, %08lx, %s, %d, %d)", - label, segment, offset, special, is_norm, isextrn); + label, segment, offset, special, is_norm, isextrn); #endif - lptr = find_label (label, 1); + lptr = find_label(label, 1); if (lptr->defn.is_global & DEFINED_BIT) { error(ERR_NONFATAL, "symbol `%s' redefined", label); return; } lptr->defn.is_global |= DEFINED_BIT; if (isextrn) - lptr->defn.is_global |= EXTERN_BIT; + lptr->defn.is_global |= EXTERN_BIT; - if (!islocalchar(label[0]) && is_norm) /* not local, but not special either */ - prevlabel = lptr->defn.label; + if (!islocalchar(label[0]) && is_norm) /* not local, but not special either */ + prevlabel = lptr->defn.label; else if (islocal(label) && !*prevlabel) { - error(ERR_NONFATAL, "attempt to define a local label before any" - " non-local labels"); - } + error(ERR_NONFATAL, "attempt to define a local label before any" + " non-local labels"); + } lptr->defn.segment = segment; lptr->defn.offset = offset; lptr->defn.is_norm = (!islocalchar(label[0]) && is_norm); -if (pass0 == 1 || (!is_norm && !isextrn && (segment&1))) { - exi = !!(lptr->defn.is_global & GLOBAL_BIT); - if (exi) - { - char *xsymbol; - int slen; - slen = strlen(lprefix); - slen += strlen(lptr->defn.label); - slen += strlen(lpostfix); - slen++; /* room for that null char */ - xsymbol = nasm_malloc(slen); - snprintf(xsymbol,slen,"%s%s%s",lprefix,lptr->defn.label,lpostfix); - - ofmt->symdef (xsymbol, segment, offset, exi, - special ? special : lptr->defn.special); - ofmt->current_dfmt->debug_deflabel (xsymbol, segment, offset, exi, - special ? special : lptr->defn.special); + if (pass0 == 1 || (!is_norm && !isextrn && (segment & 1))) { + exi = !!(lptr->defn.is_global & GLOBAL_BIT); + if (exi) { + char *xsymbol; + int slen; + slen = strlen(lprefix); + slen += strlen(lptr->defn.label); + slen += strlen(lpostfix); + slen++; /* room for that null char */ + xsymbol = nasm_malloc(slen); + snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label, + lpostfix); + + ofmt->symdef(xsymbol, segment, offset, exi, + special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset, + exi, + special ? special : lptr-> + defn.special); /** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/ - } - else - { - if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) { - ofmt->symdef (lptr->defn.label, segment, offset, exi, - special ? special : lptr->defn.special); - ofmt->current_dfmt->debug_deflabel (label, segment, offset, exi, - special ? special : lptr->defn.special); - } - } -} /* if (pass0 == 1) */ + } else { + if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) != + EXTERN_BIT) { + ofmt->symdef(lptr->defn.label, segment, offset, exi, + special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel(label, segment, offset, + exi, + special ? special : + lptr->defn.special); + } + } + } /* if (pass0 == 1) */ } -void define_common (char *label, long segment, long size, char *special, - struct ofmt *ofmt, efunc error) +void define_common(char *label, long segment, long size, char *special, + struct ofmt *ofmt, efunc error) { union label *lptr; - lptr = find_label (label, 1); + lptr = find_label(label, 1); if (lptr->defn.is_global & DEFINED_BIT) { error(ERR_NONFATAL, "symbol `%s' redefined", label); return; } lptr->defn.is_global |= DEFINED_BIT; - if (!islocalchar(label[0])) /* not local, but not special either */ + if (!islocalchar(label[0])) /* not local, but not special either */ prevlabel = lptr->defn.label; else error(ERR_NONFATAL, "attempt to define a local label as a " @@ -327,13 +335,14 @@ void define_common (char *label, long segment, long size, char *special, lptr->defn.segment = segment; lptr->defn.offset = 0; - ofmt->symdef (lptr->defn.label, segment, size, 2, - special ? special : lptr->defn.special); + ofmt->symdef(lptr->defn.label, segment, size, 2, + special ? special : lptr->defn.special); ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2, - special ? special : lptr->defn.special); + special ? special : lptr->defn. + special); } -void declare_as_global (char *label, char *special, efunc error) +void declare_as_global(char *label, char *special, efunc error) { union label *lptr; @@ -342,16 +351,16 @@ void declare_as_global (char *label, char *special, efunc error) " global", label); return; } - lptr = find_label (label, 1); + lptr = find_label(label, 1); switch (lptr->defn.is_global & TYPE_MASK) { - case NOT_DEFINED_YET: + case NOT_DEFINED_YET: lptr->defn.is_global = GLOBAL_PLACEHOLDER; lptr->defn.special = special ? perm_copy(special, "") : NULL; break; - case GLOBAL_PLACEHOLDER: /* already done: silently ignore */ - case GLOBAL_SYMBOL: + case GLOBAL_PLACEHOLDER: /* already done: silently ignore */ + case GLOBAL_SYMBOL: break; - case LOCAL_SYMBOL: + case LOCAL_SYMBOL: if (!lptr->defn.is_global & EXTERN_BIT) error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must" " appear before symbol definition", label); @@ -359,23 +368,23 @@ void declare_as_global (char *label, char *special, efunc error) } } -int init_labels (void) +int init_labels(void) { int i; - for (i=0; inext = NULL; perm_head->size = PERMTS_SIZE; @@ -388,21 +397,22 @@ int init_labels (void) return 0; } -void cleanup_labels (void) +void cleanup_labels(void) { int i; initialised = FALSE; - for (i=0; iadmin.movingon != END_BLOCK) lptr++; + while (lptr->admin.movingon != END_BLOCK) + lptr++; lptr = lptr->admin.next; - nasm_free (lhold); + nasm_free(lhold); lhold = lptr; } } @@ -410,35 +420,37 @@ void cleanup_labels (void) while (perm_head) { perm_tail = perm_head; perm_head = perm_head->next; - nasm_free (perm_tail); + nasm_free(perm_tail); } } -static void init_block (union label *blk) +static void init_block(union label *blk) { int j; - for (j=0; jsize - perm_tail->usage < len) { - perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts)); + perm_tail->next = + (struct permts *)nasm_malloc(sizeof(struct permts)); perm_tail = perm_tail->next; perm_tail->next = NULL; perm_tail->size = PERMTS_SIZE; perm_tail->usage = 0; } p = q = perm_tail->data + perm_tail->usage; - while ( (*q = *string1++) ) q++; - while ( (*q++ = *string2++) ) ; + while ((*q = *string1++)) + q++; + while ((*q++ = *string2++)) ; perm_tail->usage = q - perm_tail->data; return p; diff --git a/labels.h b/labels.h dissimilarity index 63% index 11c55194..eae66828 100644 --- a/labels.h +++ b/labels.h @@ -1,22 +1,24 @@ -/* labels.h header file for labels.c - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -extern char lprefix[PREFIX_MAX]; -extern char lpostfix[PREFIX_MAX]; - -int lookup_label (char *label, long *segment, long *offset); -int is_extern (char *label); -void define_label (char *label, long segment, long offset, char *special, - int is_norm, int isextrn, struct ofmt *ofmt, efunc error); -void redefine_label (char *label, long segment, long offset, char *special, - int is_norm, int isextrn, struct ofmt *ofmt, efunc error); -void define_common (char *label, long segment, long size, char *special, - struct ofmt *ofmt, efunc error); -void declare_as_global (char *label, char *special, efunc error); -int init_labels (void); -void cleanup_labels (void); +/* labels.h header file for labels.c + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +extern char lprefix[PREFIX_MAX]; +extern char lpostfix[PREFIX_MAX]; + +int lookup_label(char *label, long *segment, long *offset); +int is_extern(char *label); +void define_label(char *label, long segment, long offset, char *special, + int is_norm, int isextrn, struct ofmt *ofmt, + efunc error); +void redefine_label(char *label, long segment, long offset, char *special, + int is_norm, int isextrn, struct ofmt *ofmt, + efunc error); +void define_common(char *label, long segment, long size, char *special, + struct ofmt *ofmt, efunc error); +void declare_as_global(char *label, char *special, efunc error); +int init_labels(void); +void cleanup_labels(void); diff --git a/lcc/bind.c b/lcc/bind.c dissimilarity index 89% index b0c1f51f..286431d7 100644 --- a/lcc/bind.c +++ b/lcc/bind.c @@ -1,23 +1,23 @@ -#include "c.h" -extern Interface nullIR, symbolicIR; -extern Interface mipsebIR, mipselIR; -extern Interface sparcIR, solarisIR; -extern Interface x86IR, x86nasmIR; -Binding bindings[] = { - "symbolic", &symbolicIR, - "mips-irix", &mipsebIR, - "mips-ultrix", &mipselIR, - "sparc-sun", &sparcIR, - "sparc-solaris", &solarisIR, - "x86-dos", &x86IR, - "x86-nasm", &x86nasmIR, - "symbolic/irix", &symbolicIR, /* omit */ - "mips/irix", &mipsebIR, /* omit */ - "mips/ultrix", &mipselIR, /* omit */ - "sparc/sun", &sparcIR, /* omit */ - "sparc/solaris", &solarisIR, /* omit */ - "x86/dos", &x86IR, /* omit */ - "x86/nasm", &x86nasmIR, /* omit */ - "null", &nullIR, - NULL, NULL -}; +#include "c.h" +extern Interface nullIR, symbolicIR; +extern Interface mipsebIR, mipselIR; +extern Interface sparcIR, solarisIR; +extern Interface x86IR, x86nasmIR; +Binding bindings[] = { + "symbolic", &symbolicIR, + "mips-irix", &mipsebIR, + "mips-ultrix", &mipselIR, + "sparc-sun", &sparcIR, + "sparc-solaris", &solarisIR, + "x86-dos", &x86IR, + "x86-nasm", &x86nasmIR, + "symbolic/irix", &symbolicIR, /* omit */ + "mips/irix", &mipsebIR, /* omit */ + "mips/ultrix", &mipselIR, /* omit */ + "sparc/sun", &sparcIR, /* omit */ + "sparc/solaris", &solarisIR, /* omit */ + "x86/dos", &x86IR, /* omit */ + "x86/nasm", &x86nasmIR, /* omit */ + "null", &nullIR, + NULL, NULL +}; diff --git a/lcc/lin-aout.c b/lcc/lin-aout.c index e3f2a585..e4ac48f2 100644 --- a/lcc/lin-aout.c +++ b/lcc/lin-aout.c @@ -9,36 +9,40 @@ #define NASMPATH "/usr/local/bin/nasm" char *cpp[] = { LCCDIR "cpp", "-D__STDC__=1", - "-Di386", "-D__i386", "-D__i386__", - "-Dlinux", "-D__linux", "-D__linux__", - "-Dunix", "-D__unix", "-D__unix__", - "$1", "$2", "$3", 0 }; + "-Di386", "-D__i386", "-D__i386__", + "-Dlinux", "-D__linux", "-D__linux__", + "-Dunix", "-D__unix", "-D__unix__", + "$1", "$2", "$3", 0 +}; char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include", - "-I/usr/include", 0 }; + "-I/usr/include", 0 +}; char *com[] = { LCCDIR "rcc", "-target=x86/nasm", - "$1", "$2", "$3", 0 }; + "$1", "$2", "$3", 0 +}; char *as[] = { NASMPATH, "-a", "-faout", "-o", "$3", "$1", "$2", 0 }; char *ld[] = { "/usr/bin/ld", "-m", "i386linux", - "-L/usr/i486-linuxaout/lib", - "-o", "$3", "$1", - "/usr/i486-linuxaout/lib/crt0.o", - "$2", "", "-lc", 0 }; + "-L/usr/i486-linuxaout/lib", + "-o", "$3", "$1", + "/usr/i486-linuxaout/lib/crt0.o", + "$2", "", "-lc", 0 +}; static char *bbexit = LCCDIR "bbexit.o"; extern char *concat(char *, char *); extern int access(const char *, int); -int option(char *arg) { - if (strncmp(arg, "-lccdir=", 8) == 0) { - cpp[0] = concat(&arg[8], "/cpp"); - include[0] = concat("-I", concat(&arg[8], "/include")); - com[0] = concat(&arg[8], "/rcc"); - bbexit = concat(&arg[8], "/bbexit.o"); - } else if (strcmp(arg, "-g") == 0) - ; - else if (strcmp(arg, "-b") == 0 && access(bbexit, 4) == 0) - ld[9] = bbexit; - else - return 0; - return 1; +int option(char *arg) +{ + if (strncmp(arg, "-lccdir=", 8) == 0) { + cpp[0] = concat(&arg[8], "/cpp"); + include[0] = concat("-I", concat(&arg[8], "/include")); + com[0] = concat(&arg[8], "/rcc"); + bbexit = concat(&arg[8], "/bbexit.o"); + } else if (strcmp(arg, "-g") == 0) ; + else if (strcmp(arg, "-b") == 0 && access(bbexit, 4) == 0) + ld[9] = bbexit; + else + return 0; + return 1; } diff --git a/lcc/lin-elf.c b/lcc/lin-elf.c index 3af9fe8f..693309f9 100644 --- a/lcc/lin-elf.c +++ b/lcc/lin-elf.c @@ -9,37 +9,41 @@ #define NASMPATH "/usr/local/bin/nasm" char *cpp[] = { LCCDIR "cpp", "-D__STDC__=1", - "-D__ELF__", "-Di386", "-D__i386", "-D__i386__", - "-Dlinux", "-D__linux", "-D__linux__", - "$1", "$2", "$3", 0 }; + "-D__ELF__", "-Di386", "-D__i386", "-D__i386__", + "-Dlinux", "-D__linux", "-D__linux__", + "$1", "$2", "$3", 0 +}; char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include", - "-I/usr/include", 0 }; + "-I/usr/include", 0 +}; char *com[] = { LCCDIR "rcc", "-target=x86/nasm", - "$1", "$2", "$3", 0 }; + "$1", "$2", "$3", 0 +}; char *as[] = { NASMPATH, "-a", "-felf", "-o", "$3", "$1", "$2", 0 }; char *ld[] = { "/usr/bin/ld", "-m", "elf_i386", - "-dynamic-linker", "/lib/ld-linux.so.1", - "-L/usr/i486-linux/lib", - "-o", "$3", "$1", - "/usr/lib/crt1.o", "/usr/lib/crti.o", "/usr/lib/crtbegin.o", - "$2", "", - "-lc", "", "/usr/lib/crtend.o", "/usr/lib/crtn.o", 0 }; + "-dynamic-linker", "/lib/ld-linux.so.1", + "-L/usr/i486-linux/lib", + "-o", "$3", "$1", + "/usr/lib/crt1.o", "/usr/lib/crti.o", "/usr/lib/crtbegin.o", + "$2", "", + "-lc", "", "/usr/lib/crtend.o", "/usr/lib/crtn.o", 0 +}; static char *bbexit = LCCDIR "bbexit.o"; extern char *concat(char *, char *); extern int access(const char *, int); -int option(char *arg) { - if (strncmp(arg, "-lccdir=", 8) == 0) { - cpp[0] = concat(&arg[8], "/cpp"); - include[0] = concat("-I", concat(&arg[8], "/include")); - com[0] = concat(&arg[8], "/rcc"); - bbexit = concat(&arg[8], "/bbexit.o"); - } else if (strcmp(arg, "-g") == 0) - ; - else if (strcmp(arg, "-b") == 0 && access(bbexit, 4) == 0) - ld[13] = bbexit; - else - return 0; - return 1; +int option(char *arg) +{ + if (strncmp(arg, "-lccdir=", 8) == 0) { + cpp[0] = concat(&arg[8], "/cpp"); + include[0] = concat("-I", concat(&arg[8], "/include")); + com[0] = concat(&arg[8], "/rcc"); + bbexit = concat(&arg[8], "/bbexit.o"); + } else if (strcmp(arg, "-g") == 0) ; + else if (strcmp(arg, "-b") == 0 && access(bbexit, 4) == 0) + ld[13] = bbexit; + else + return 0; + return 1; } diff --git a/listing.c b/listing.c dissimilarity index 61% index 5deea2a5..1f5e961b 100644 --- a/listing.c +++ b/listing.c @@ -1,284 +1,275 @@ -/* listing.c listing file generator for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * initial version 2/vii/97 by Simon Tatham - */ - -#include -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "listing.h" - -#define LIST_MAX_LEN 216 /* something sensible */ -#define LIST_INDENT 40 -#define LIST_HEXBIT 18 - -typedef struct MacroInhibit MacroInhibit; - -static struct MacroInhibit { - MacroInhibit *next; - int level; - int inhibiting; -} *mistack; - -static char xdigit[] = "0123456789ABCDEF"; - -#define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]); - -static char listline[LIST_MAX_LEN]; -static int listlinep; - -static char listdata[2*LIST_INDENT]; /* we need less than that actually */ -static long listoffset; - -static long listlineno; - -static long listp; - -static int suppress; /* for INCBIN & TIMES special cases */ - -static int listlevel, listlevel_e; - -static FILE *listfp; - -static void list_emit (void) -{ - if (!listlinep && !listdata[0]) - return; - - fprintf(listfp, "%6ld ", ++listlineno); - - if (listdata[0]) - fprintf(listfp, "%08lX %-*s", listoffset, LIST_HEXBIT+1, listdata); - else - fprintf(listfp, "%*s", LIST_HEXBIT+10, ""); - - if (listlevel_e) - fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""), listlevel_e); - else if (listlinep) - fprintf(listfp, " "); - - if (listlinep) - fprintf(listfp, " %s", listline); - - fputc('\n', listfp); - listlinep = FALSE; - listdata[0] = '\0'; -} - -static void list_init (char *fname, efunc error) -{ - listfp = fopen (fname, "w"); - if (!listfp) { - error (ERR_NONFATAL, "unable to open listing file `%s'", fname); - return; - } - - *listline = '\0'; - listlineno = 0; - listp = TRUE; - listlevel = 0; - suppress = 0; - mistack = nasm_malloc(sizeof(MacroInhibit)); - mistack->next = NULL; - mistack->level = 0; - mistack->inhibiting = TRUE; -} - -static void list_cleanup (void) -{ - if (!listp) - return; - - while (mistack) { - MacroInhibit *temp = mistack; - mistack = temp->next; - nasm_free (temp); - } - - list_emit(); - fclose (listfp); -} - -static void list_out (long offset, char *str) -{ - if (strlen(listdata) + strlen(str) > LIST_HEXBIT) { - strcat(listdata, "-"); - list_emit(); - } - if (!listdata[0]) - listoffset = offset; - strcat(listdata, str); -} - -static void list_output (long offset, const void *data, unsigned long type) -{ - unsigned long typ, size; - - if (!listp || suppress || user_nolist) /* fbk - 9/2/00 */ - return; - - typ = type & OUT_TYPMASK; - size = type & OUT_SIZMASK; - - if (typ == OUT_RAWDATA) - { - unsigned char const *p = data; - char q[3]; - while (size--) - { - HEX (q, *p); - q[2] = '\0'; - list_out (offset++, q); - p++; - } - } - else if (typ == OUT_ADDRESS) - { - unsigned long d = *(long *)data; - char q[11]; - unsigned char p[4], *r = p; - if (size == 4) - { - q[0] = '['; q[9] = ']'; q[10] = '\0'; - WRITELONG (r, d); - HEX (q+1, p[0]); - HEX (q+3, p[1]); - HEX (q+5, p[2]); - HEX (q+7, p[3]); - list_out (offset, q); - } - else { - q[0] = '['; q[5] = ']'; q[6] = '\0'; - WRITESHORT (r, d); - HEX (q+1, p[0]); - HEX (q+3, p[1]); - list_out (offset, q); - } - } - else if (typ == OUT_REL2ADR) - { - unsigned long d = *(long *)data; - char q[11]; - unsigned char p[4], *r = p; - q[0] = '('; q[5] = ')'; q[6] = '\0'; - WRITESHORT (r, d); - HEX (q+1, p[0]); - HEX (q+3, p[1]); - list_out (offset, q); - } - else if (typ == OUT_REL4ADR) - { - unsigned long d = *(long *)data; - char q[11]; - unsigned char p[4], *r = p; - q[0] = '('; q[9] = ')'; q[10] = '\0'; - WRITELONG (r, d); - HEX (q+1, p[0]); - HEX (q+3, p[1]); - HEX (q+5, p[2]); - HEX (q+7, p[3]); - list_out (offset, q); - } - else if (typ == OUT_RESERVE) - { - char q[20]; - snprintf(q, sizeof(q), "", size); - list_out (offset, q); - } -} - -static void list_line (int type, char *line) -{ - if (!listp) - return; - if (user_nolist){ /* fbk - 9/2/00 */ - listlineno++; - return; - } - - if (mistack && mistack->inhibiting) - { - if (type == LIST_MACRO) - return; - else { /* pop the m i stack */ - MacroInhibit *temp = mistack; - mistack = temp->next; - nasm_free (temp); - } - } - list_emit(); - listlinep = TRUE; - strncpy (listline, line, LIST_MAX_LEN-1); - listline[LIST_MAX_LEN-1] = '\0'; - listlevel_e = listlevel; -} - -static void list_uplevel (int type) -{ - if (!listp) - return; - if (type == LIST_INCBIN || type == LIST_TIMES) - { - suppress |= (type == LIST_INCBIN ? 1 : 2); - list_out (listoffset, type == LIST_INCBIN ? "" : ""); - return; - } - - listlevel++; - - if (mistack && mistack->inhibiting && type == LIST_INCLUDE) - { - MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit)); - temp->next = mistack; - temp->level = listlevel; - temp->inhibiting = FALSE; - mistack = temp; - } - else if (type == LIST_MACRO_NOLIST) - { - MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit)); - temp->next = mistack; - temp->level = listlevel; - temp->inhibiting = TRUE; - mistack = temp; - } -} - -static void list_downlevel (int type) -{ - if (!listp) - return; - - if (type == LIST_INCBIN || type == LIST_TIMES) - { - suppress &= ~(type == LIST_INCBIN ? 1 : 2); - return; - } - - listlevel--; - while (mistack && mistack->level > listlevel) - { - MacroInhibit *temp = mistack; - mistack = temp->next; - nasm_free (temp); - } -} - -ListGen nasmlist = { - list_init, - list_cleanup, - list_output, - list_line, - list_uplevel, - list_downlevel -}; +/* listing.c listing file generator for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 2/vii/97 by Simon Tatham + */ + +#include +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "listing.h" + +#define LIST_MAX_LEN 216 /* something sensible */ +#define LIST_INDENT 40 +#define LIST_HEXBIT 18 + +typedef struct MacroInhibit MacroInhibit; + +static struct MacroInhibit { + MacroInhibit *next; + int level; + int inhibiting; +} *mistack; + +static char xdigit[] = "0123456789ABCDEF"; + +#define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]); + +static char listline[LIST_MAX_LEN]; +static int listlinep; + +static char listdata[2 * LIST_INDENT]; /* we need less than that actually */ +static long listoffset; + +static long listlineno; + +static long listp; + +static int suppress; /* for INCBIN & TIMES special cases */ + +static int listlevel, listlevel_e; + +static FILE *listfp; + +static void list_emit(void) +{ + if (!listlinep && !listdata[0]) + return; + + fprintf(listfp, "%6ld ", ++listlineno); + + if (listdata[0]) + fprintf(listfp, "%08lX %-*s", listoffset, LIST_HEXBIT + 1, + listdata); + else + fprintf(listfp, "%*s", LIST_HEXBIT + 10, ""); + + if (listlevel_e) + fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""), + listlevel_e); + else if (listlinep) + fprintf(listfp, " "); + + if (listlinep) + fprintf(listfp, " %s", listline); + + fputc('\n', listfp); + listlinep = FALSE; + listdata[0] = '\0'; +} + +static void list_init(char *fname, efunc error) +{ + listfp = fopen(fname, "w"); + if (!listfp) { + error(ERR_NONFATAL, "unable to open listing file `%s'", fname); + return; + } + + *listline = '\0'; + listlineno = 0; + listp = TRUE; + listlevel = 0; + suppress = 0; + mistack = nasm_malloc(sizeof(MacroInhibit)); + mistack->next = NULL; + mistack->level = 0; + mistack->inhibiting = TRUE; +} + +static void list_cleanup(void) +{ + if (!listp) + return; + + while (mistack) { + MacroInhibit *temp = mistack; + mistack = temp->next; + nasm_free(temp); + } + + list_emit(); + fclose(listfp); +} + +static void list_out(long offset, char *str) +{ + if (strlen(listdata) + strlen(str) > LIST_HEXBIT) { + strcat(listdata, "-"); + list_emit(); + } + if (!listdata[0]) + listoffset = offset; + strcat(listdata, str); +} + +static void list_output(long offset, const void *data, unsigned long type) +{ + unsigned long typ, size; + + if (!listp || suppress || user_nolist) /* fbk - 9/2/00 */ + return; + + typ = type & OUT_TYPMASK; + size = type & OUT_SIZMASK; + + if (typ == OUT_RAWDATA) { + unsigned char const *p = data; + char q[3]; + while (size--) { + HEX(q, *p); + q[2] = '\0'; + list_out(offset++, q); + p++; + } + } else if (typ == OUT_ADDRESS) { + unsigned long d = *(long *)data; + char q[11]; + unsigned char p[4], *r = p; + if (size == 4) { + q[0] = '['; + q[9] = ']'; + q[10] = '\0'; + WRITELONG(r, d); + HEX(q + 1, p[0]); + HEX(q + 3, p[1]); + HEX(q + 5, p[2]); + HEX(q + 7, p[3]); + list_out(offset, q); + } else { + q[0] = '['; + q[5] = ']'; + q[6] = '\0'; + WRITESHORT(r, d); + HEX(q + 1, p[0]); + HEX(q + 3, p[1]); + list_out(offset, q); + } + } else if (typ == OUT_REL2ADR) { + unsigned long d = *(long *)data; + char q[11]; + unsigned char p[4], *r = p; + q[0] = '('; + q[5] = ')'; + q[6] = '\0'; + WRITESHORT(r, d); + HEX(q + 1, p[0]); + HEX(q + 3, p[1]); + list_out(offset, q); + } else if (typ == OUT_REL4ADR) { + unsigned long d = *(long *)data; + char q[11]; + unsigned char p[4], *r = p; + q[0] = '('; + q[9] = ')'; + q[10] = '\0'; + WRITELONG(r, d); + HEX(q + 1, p[0]); + HEX(q + 3, p[1]); + HEX(q + 5, p[2]); + HEX(q + 7, p[3]); + list_out(offset, q); + } else if (typ == OUT_RESERVE) { + char q[20]; + snprintf(q, sizeof(q), "", size); + list_out(offset, q); + } +} + +static void list_line(int type, char *line) +{ + if (!listp) + return; + if (user_nolist) { /* fbk - 9/2/00 */ + listlineno++; + return; + } + + if (mistack && mistack->inhibiting) { + if (type == LIST_MACRO) + return; + else { /* pop the m i stack */ + MacroInhibit *temp = mistack; + mistack = temp->next; + nasm_free(temp); + } + } + list_emit(); + listlinep = TRUE; + strncpy(listline, line, LIST_MAX_LEN - 1); + listline[LIST_MAX_LEN - 1] = '\0'; + listlevel_e = listlevel; +} + +static void list_uplevel(int type) +{ + if (!listp) + return; + if (type == LIST_INCBIN || type == LIST_TIMES) { + suppress |= (type == LIST_INCBIN ? 1 : 2); + list_out(listoffset, type == LIST_INCBIN ? "" : ""); + return; + } + + listlevel++; + + if (mistack && mistack->inhibiting && type == LIST_INCLUDE) { + MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit)); + temp->next = mistack; + temp->level = listlevel; + temp->inhibiting = FALSE; + mistack = temp; + } else if (type == LIST_MACRO_NOLIST) { + MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit)); + temp->next = mistack; + temp->level = listlevel; + temp->inhibiting = TRUE; + mistack = temp; + } +} + +static void list_downlevel(int type) +{ + if (!listp) + return; + + if (type == LIST_INCBIN || type == LIST_TIMES) { + suppress &= ~(type == LIST_INCBIN ? 1 : 2); + return; + } + + listlevel--; + while (mistack && mistack->level > listlevel) { + MacroInhibit *temp = mistack; + mistack = temp->next; + nasm_free(temp); + } +} + +ListGen nasmlist = { + list_init, + list_cleanup, + list_output, + list_line, + list_uplevel, + list_downlevel +}; diff --git a/listing.h b/listing.h index 55db4f90..8baadb17 100644 --- a/listing.h +++ b/listing.h @@ -10,6 +10,6 @@ #define NASM_LISTING_H extern ListGen nasmlist; -extern int user_nolist; /* fbk - 9/1/00 */ +extern int user_nolist; /* fbk - 9/1/00 */ #endif diff --git a/names.c b/names.c index 97767b08..58721f47 100644 --- a/names.c +++ b/names.c @@ -7,7 +7,7 @@ * distributed in the NASM archive. */ -static const char *conditions[] = { /* condition code names */ +static const char *conditions[] = { /* condition code names */ "a", "ae", "b", "be", "c", "e", "g", "ge", "l", "le", "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", "np", "ns", "nz", "o", "p", "pe", "po", "s", "z" diff --git a/nasm.c b/nasm.c dissimilarity index 78% index 83eededd..21572868 100644 --- a/nasm.c +++ b/nasm.c @@ -1,1682 +1,1720 @@ -/* The Netwide Assembler main program module - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "insns.h" -#include "preproc.h" -#include "parser.h" -#include "eval.h" -#include "assemble.h" -#include "labels.h" -#include "outform.h" -#include "listing.h" - -struct forwrefinfo { /* info held on forward refs. */ - int lineno; - int operand; -}; - -static int get_bits (char *value); -static unsigned long get_cpu (char *cpu_str); -static void parse_cmdline (int, char **); -static void assemble_file (char *); -static int getkw (char **directive, char **value); -static void register_output_formats(void); -static void report_error_gnu (int severity, const char *fmt, ...); -static void report_error_vc (int severity, const char *fmt, ...); -static void report_error_common (int severity, const char *fmt, va_list args); -static int is_suppressed_warning (int severity); -static void usage(void); -static efunc report_error; - -static int using_debug_info, opt_verbose_info; -int tasm_compatible_mode = FALSE; -int pass0; - -static char inname[FILENAME_MAX]; -static char outname[FILENAME_MAX]; -static char listname[FILENAME_MAX]; -static int globallineno; /* for forward-reference tracking */ -/* static int pass = 0; */ -static struct ofmt *ofmt = NULL; - -static FILE *error_file; /* Where to write error messages */ - -static FILE *ofile = NULL; -int optimizing = -1; /* number of optimization passes to take */ -static int sb, cmd_sb = 16; /* by default */ -static unsigned long cmd_cpu = IF_PLEVEL; /* highest level by default */ -static unsigned long cpu = IF_PLEVEL; /* passed to insn_size & assemble.c */ -int global_offset_changed; /* referenced in labels.c */ - -static loc_t location; -int in_abs_seg; /* Flag we are in ABSOLUTE seg */ -long abs_seg; /* ABSOLUTE segment basis */ -long abs_offset; /* ABSOLUTE offset */ - -static struct RAA *offsets; - -static struct SAA *forwrefs; /* keep track of forward references */ -static struct forwrefinfo *forwref; - -static Preproc *preproc; -enum op_type { - op_normal, /* Preprocess and assemble */ - op_preprocess, /* Preprocess only */ - op_depend /* Generate dependencies */ -}; -static enum op_type operating_mode; - -/* - * Which of the suppressible warnings are suppressed. Entry zero - * doesn't do anything. Initial defaults are given here. - */ -static char suppressed[1+ERR_WARN_MAX] = { - 0, TRUE, TRUE, TRUE, FALSE, TRUE -}; - -/* - * The option names for the suppressible warnings. As before, entry - * zero does nothing. - */ -static const char *suppressed_names[1+ERR_WARN_MAX] = { - NULL, "macro-params", "macro-selfref", "orphan-labels", "number-overflow", - "gnu-elf-extensions" -}; - -/* - * The explanations for the suppressible warnings. As before, entry - * zero does nothing. - */ -static const char *suppressed_what[1+ERR_WARN_MAX] = { - NULL, - "macro calls with wrong no. of params", - "cyclic macro self-references", - "labels alone on lines without trailing `:'", - "numeric constants greater than 0xFFFFFFFF", - "using 8- or 16-bit relocation in ELF, a GNU extension" -}; - -/* - * This is a null preprocessor which just copies lines from input - * to output. It's used when someone explicitly requests that NASM - * not preprocess their source file. - */ - -static void no_pp_reset (char *, int, efunc, evalfunc, ListGen *); -static char *no_pp_getline (void); -static void no_pp_cleanup (int); -static Preproc no_pp = { - no_pp_reset, - no_pp_getline, - no_pp_cleanup -}; - -/* - * get/set current offset... - */ -#define GET_CURR_OFFS (in_abs_seg?abs_offset:\ - raa_read(offsets,location.segment)) -#define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\ - (void)(offsets=raa_write(offsets,location.segment,(x)))) - -static int want_usage; -static int terminate_after_phase; -int user_nolist = 0; /* fbk 9/2/00 */ - -static void nasm_fputs(const char *line, FILE *outfile) -{ - if (outfile) { - fputs(line, outfile); - fputc('\n', outfile); - } else - puts(line); -} - -int main(int argc, char **argv) -{ - pass0 = 1; - want_usage = terminate_after_phase = FALSE; - report_error = report_error_gnu; - - nasm_set_malloc_error (report_error); - offsets = raa_init(); - forwrefs = saa_init ((long)sizeof(struct forwrefinfo)); - - preproc = &nasmpp; - operating_mode = op_normal; - - error_file = stderr; - - seg_init(); - - register_output_formats(); - - parse_cmdline(argc, argv); - - if (terminate_after_phase) - { - if (want_usage) - usage(); - return 1; - } - - /* If debugging info is disabled, suppress any debug calls */ - if (!using_debug_info) - ofmt->current_dfmt = &null_debug_form; - - if (ofmt->stdmac) - pp_extra_stdmac (ofmt->stdmac); - parser_global_info (ofmt, &location); - eval_global_info (ofmt, lookup_label, &location); - - /* define some macros dependent of command-line */ - { - char temp [64]; - snprintf (temp, sizeof(temp), "__OUTPUT_FORMAT__=%s\n", ofmt->shortname); - pp_pre_define (temp); - } - - switch ( operating_mode ) { - case op_depend: - { - char *line; - preproc->reset (inname, 0, report_error, evaluate, &nasmlist); - if (outname[0] == '\0') - ofmt->filename (inname, outname, report_error); - ofile = NULL; - fprintf(stdout, "%s: %s", outname, inname); - while ( (line = preproc->getline()) ) - nasm_free (line); - preproc->cleanup(0); - putc('\n', stdout); - } - break; - - case op_preprocess: - { - char *line; - char *file_name = NULL; - long prior_linnum=0; - int lineinc=0; - - if (*outname) { - ofile = fopen(outname, "w"); - if (!ofile) - report_error (ERR_FATAL | ERR_NOFILE, - "unable to open output file `%s'", outname); - } else - ofile = NULL; - - location.known = FALSE; - -/* pass = 1; */ - preproc->reset (inname, 2, report_error, evaluate, &nasmlist); - while ( (line = preproc->getline()) ) { - /* - * We generate %line directives if needed for later programs - */ - long linnum = prior_linnum += lineinc; - int altline = src_get(&linnum, &file_name); - if (altline) { - if (altline==1 && lineinc==1) - nasm_fputs("", ofile); - else { - lineinc = (altline != -1 || lineinc!=1); - fprintf(ofile ? ofile : stdout, "%%line %ld+%d %s\n", - linnum, lineinc, file_name); - } - prior_linnum = linnum; - } - nasm_fputs(line, ofile); - nasm_free (line); - } - nasm_free(file_name); - preproc->cleanup(0); - if (ofile) - fclose(ofile); - if (ofile && terminate_after_phase) - remove(outname); - } - break; - - case op_normal: - { - /* - * We must call ofmt->filename _anyway_, even if the user - * has specified their own output file, because some - * formats (eg OBJ and COFF) use ofmt->filename to find out - * the name of the input file and then put that inside the - * file. - */ - ofmt->filename (inname, outname, report_error); - - ofile = fopen(outname, "wb"); - if (!ofile) { - report_error (ERR_FATAL | ERR_NOFILE, - "unable to open output file `%s'", outname); - } - - /* - * We must call init_labels() before ofmt->init() since - * some object formats will want to define labels in their - * init routines. (eg OS/2 defines the FLAT group) - */ - init_labels (); - - ofmt->init (ofile, report_error, define_label, evaluate); - - assemble_file (inname); - - if (!terminate_after_phase) { - ofmt->cleanup (using_debug_info); - cleanup_labels (); - } else { - /* - * We had an fclose on the output file here, but we - * actually do that in all the object file drivers as well, - * so we're leaving out the one here. - * fclose (ofile); - */ - remove(outname); - if (listname[0]) - remove(listname); - } - } - break; - } - - if (want_usage) - usage(); - - raa_free (offsets); - saa_free (forwrefs); - eval_cleanup (); - nasmlib_cleanup (); - - if (terminate_after_phase) - return 1; - else - return 0; -} - - -/* - * Get a parameter for a command line option. - * First arg must be in the form of e.g. -f... - */ -static char *get_param (char *p, char *q, int *advance) -{ - *advance = 0; - if (p[2]) /* the parameter's in the option */ - { - p += 2; - while (isspace(*p)) - p++; - return p; - } - if (q && q[0]) - { - *advance = 1; - return q; - } - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "option `-%c' requires an argument", - p[1]); - return NULL; -} - -struct textargs -{ - const char *label; - int value; -}; - -#define OPT_PREFIX 0 -#define OPT_POSTFIX 1 -struct textargs textopts[] = -{ - {"prefix",OPT_PREFIX}, - {"postfix",OPT_POSTFIX}, - {NULL,0} -}; - - -int stopoptions = 0; -static int process_arg (char *p, char *q) -{ - char *param; - int i, advance = 0; - - if (!p || !p[0]) - return 0; - - if (p[0]=='-' && ! stopoptions) - { - switch (p[1]) { - case 's': - error_file = stdout; - break; - case 'o': /* these parameters take values */ - case 'O': - case 'f': - case 'p': - case 'P': - case 'd': - case 'D': - case 'i': - case 'I': - case 'l': - case 'E': - case 'F': - case 'X': - case 'u': - case 'U': - if ( !(param = get_param (p, q, &advance)) ) - break; - if (p[1]=='o') { /* output file */ - strcpy (outname, param); - } else if (p[1]=='f') { /* output format */ - ofmt = ofmt_find(param); - if (!ofmt) { - report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE, - "unrecognised output format `%s' - " - "use -hf for a list", - param); - } - else - ofmt->current_dfmt = ofmt->debug_formats[0]; - } else if (p[1]=='O') { /* Optimization level */ - int opt; - opt = -99; - while (*param) { - if (isdigit(*param)) { - opt = atoi(param); - while(isdigit(*++param)) ; - if (opt<=0) optimizing = -1; /* 0.98 behaviour */ - else if (opt==1) optimizing = 0; /* Two passes, 0.98.09 behavior */ - else optimizing = opt; /* Multiple passes */ - } else { - if (*param == 'v' || *param == '+') { - ++param; - opt_verbose_info = TRUE; - opt = 0; - } else { /* garbage */ - opt = -99; - break; - } - } - } /* while (*param) */ - if (opt == -99) report_error(ERR_FATAL, - "command line optimization level must be 'v', 0..3 or "); - } else if (p[1]=='P' || p[1]=='p') { /* pre-include */ - pp_pre_include (param); - } else if (p[1]=='D' || p[1]=='d') { /* pre-define */ - pp_pre_define (param); - } else if (p[1]=='U' || p[1]=='u') { /* un-define */ - pp_pre_undefine (param); - } else if (p[1]=='I' || p[1]=='i') { /* include search path */ - pp_include_path (param); - } else if (p[1]=='l') { /* listing file */ - strcpy (listname, param); - } else if (p[1]=='E') { /* error messages file */ - error_file = fopen(param, "w"); - if ( !error_file ) { - error_file = stderr; /* Revert to default! */ - report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE, - "cannot open file `%s' for error messages", - param); - } - } else if (p[1] == 'F') { /* specify debug format */ - ofmt->current_dfmt = dfmt_find(ofmt, param); - if (!ofmt->current_dfmt) { - report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE, - "unrecognized debug format `%s' for" - " output format `%s'", - param, ofmt->shortname); - } - } else if (p[1] == 'X') { /* specify error reporting format */ - if (nasm_stricmp("vc", param) == 0) - report_error = report_error_vc; - else if (nasm_stricmp("gnu", param) == 0) - report_error = report_error_gnu; - else - report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE, - "unrecognized error reporting format `%s'", - param); - } - break; - case 'g': - using_debug_info = TRUE; - break; - case 'h': - printf("usage: nasm [-@ response file] [-o outfile] [-f format] " - "[-l listfile]\n" - " [options...] [--] filename\n" - " or nasm -r for version info (obsolete)\n" - " or nasm -v for version info (preferred)\n\n" - " -t assemble in SciTech TASM compatible mode\n" - " -g generate debug information in selected format.\n"); - printf(" -e preprocess only (writes output to stdout by default)\n" - " -a don't preprocess (assemble only)\n" - " -M generate Makefile dependencies on stdout\n\n" - " -E redirect error messages to file\n" - " -s redirect error messages to stdout\n\n" - " -F format select a debugging format\n\n" - " -I adds a pathname to the include file path\n"); - printf(" -O optimize branch offsets (-O0 disables, default)\n" - " -P pre-includes a file\n" - " -D[=] pre-defines a macro\n" - " -U undefines a macro\n" - " -X specifies error reporting format (gnu or vc)\n" - " -w+foo enables warnings about foo; -w-foo disables them\n" - "where foo can be:\n"); - for (i=1; i<=ERR_WARN_MAX; i++) - printf(" %-23s %s (default %s)\n", - suppressed_names[i], suppressed_what[i], - suppressed[i] ? "off" : "on"); - printf ("\nresponse files should contain command line parameters" - ", one per line.\n"); - if (p[2] == 'f') { - printf("\nvalid output formats for -f are" - " (`*' denotes default):\n"); - ofmt_list(ofmt, stdout); - } - else { - printf ("\nFor a list of valid output formats, use -hf.\n"); - printf ("For a list of debug formats, use -f
-y.\n"); - } - exit (0); /* never need usage message here */ - break; - case 'y': - printf("\nvalid debug formats for '%s' output format are" - " ('*' denotes default):\n", - ofmt->shortname); - dfmt_list(ofmt, stdout); - exit(0); - break; - case 't': - tasm_compatible_mode = TRUE; - break; - case 'r': - case 'v': - { - const char *nasm_version_string = - "NASM version " NASM_VER " compiled on " __DATE__ -#ifdef DEBUG - " with -DDEBUG" -#endif - ; - puts(nasm_version_string); - exit (0); /* never need usage message here */ - } - break; - case 'e': /* preprocess only */ - operating_mode = op_preprocess; - break; - case 'a': /* assemble only - don't preprocess */ - preproc = &no_pp; - break; - case 'w': - if (p[2] != '+' && p[2] != '-') { - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "invalid option to `-w'"); - } else { - for (i=1; i<=ERR_WARN_MAX; i++) - if (!nasm_stricmp(p+3, suppressed_names[i])) - break; - if (i <= ERR_WARN_MAX) - suppressed[i] = (p[2] == '-'); - else - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "invalid option to `-w'"); - } - break; - case 'M': - operating_mode = op_depend; - break; - - case '-': - { - int s; - - if (p[2]==0) { /* -- => stop processing options */ - stopoptions = 1; - break; - } - for(s=0; textopts[s].label; s++) - { - if(!nasm_stricmp(p+2, textopts[s].label)) - { - break; - } - } - - switch(s) - { - - case OPT_PREFIX: - case OPT_POSTFIX: - { - if (!q) - { - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "option `--%s' requires an argument", - p+2); - break; - } - else - { - advance = 1, param = q; - } - - if(s == OPT_PREFIX) - { - strncpy(lprefix,param,PREFIX_MAX-1); - lprefix[PREFIX_MAX-1]=0; - break; - } - if(s == OPT_POSTFIX) - { - strncpy(lpostfix,param,POSTFIX_MAX-1); - lpostfix[POSTFIX_MAX-1]=0; - break; - } - break; - } - default: - { - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "unrecognised option `--%s'", - p+2); - break; - } - } - break; - } - - default: - if (!ofmt->setinfo(GI_SWITCH,&p)) - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "unrecognised option `-%c'", - p[1]); - break; - } - } - else - { - if (*inname) { - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "more than one input file specified"); - } else - strcpy(inname, p); - } - - return advance; -} - -#define ARG_BUF_DELTA 128 - -static void process_respfile (FILE *rfile) -{ - char *buffer, *p, *q, *prevarg; - int bufsize, prevargsize; - - bufsize = prevargsize = ARG_BUF_DELTA; - buffer = nasm_malloc(ARG_BUF_DELTA); - prevarg = nasm_malloc(ARG_BUF_DELTA); - prevarg[0] = '\0'; - - while (1) { /* Loop to handle all lines in file */ - - p = buffer; - while (1) { /* Loop to handle long lines */ - q = fgets(p, bufsize-(p-buffer), rfile); - if (!q) - break; - p += strlen(p); - if (p > buffer && p[-1] == '\n') - break; - if (p-buffer > bufsize-10) { - int offset; - offset = p - buffer; - bufsize += ARG_BUF_DELTA; - buffer = nasm_realloc(buffer, bufsize); - p = buffer + offset; - } - } - - if (!q && p == buffer) { - if (prevarg[0]) - process_arg (prevarg, NULL); - nasm_free (buffer); - nasm_free (prevarg); - return; - } - - /* - * Play safe: remove CRs, LFs and any spurious ^Zs, if any of - * them are present at the end of the line. - */ - *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0'; - - while (p > buffer && isspace(p[-1])) - *--p = '\0'; - - p = buffer; - while (isspace(*p)) - p++; - - if (process_arg (prevarg, p)) - *p = '\0'; - - if (strlen(p) > prevargsize-10) { - prevargsize += ARG_BUF_DELTA; - prevarg = nasm_realloc(prevarg, prevargsize); - } - strcpy (prevarg, p); - } -} - -/* Function to process args from a string of args, rather than the - * argv array. Used by the environment variable and response file - * processing. - */ -static void process_args (char *args) { - char *p, *q, *arg, *prevarg; - char separator = ' '; - - p = args; - if (*p && *p != '-') - separator = *p++; - arg = NULL; - while (*p) { - q = p; - while (*p && *p != separator) p++; - while (*p == separator) *p++ = '\0'; - prevarg = arg; - arg = q; - if (process_arg (prevarg, arg)) - arg = NULL; - } - if (arg) - process_arg (arg, NULL); -} - -static void parse_cmdline(int argc, char **argv) -{ - FILE *rfile; - char *envreal, *envcopy=NULL, *p, *arg; - - *inname = *outname = *listname = '\0'; - - /* - * First, process the NASMENV environment variable. - */ - envreal = getenv("NASMENV"); - arg = NULL; - if (envreal) { - envcopy = nasm_strdup(envreal); - process_args(envcopy); - nasm_free (envcopy); - } - - /* - * Now process the actual command line. - */ - while (--argc) - { - int i; - argv++; - if (argv[0][0] == '@') { - /* We have a response file, so process this as a set of - * arguments like the environment variable. This allows us - * to have multiple arguments on a single line, which is - * different to the -@resp file processing below for regular - * NASM. - */ - char *str = malloc(2048); - FILE *f = fopen(&argv[0][1],"r"); - if (!str) { - printf("out of memory"); - exit(-1); - } - if (f) { - while (fgets(str,2048,f)) { - process_args(str); - } - fclose(f); - } - free(str); - argc--; - argv++; - } - if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') { - if ((p = get_param (argv[0], argc > 1 ? argv[1] : NULL, &i))) { - if ((rfile = fopen(p, "r"))) { - process_respfile (rfile); - fclose(rfile); - } else - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "unable to open response file `%s'", p); - } - } else - i = process_arg (argv[0], argc > 1 ? argv[1] : NULL); - argv += i, argc -= i; - } - - if (!*inname) - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "no input file specified"); -} - - -static void assemble_file (char *fname) -{ - char * directive, * value, * p, * q, * special, * line, debugid[80]; - insn output_ins; - int i, rn_error, validid; - long seg, offs; - struct tokenval tokval; - expr * e; - int pass, pass_max; - int pass_cnt = 0; /* count actual passes */ - - if (cmd_sb == 32 && cmd_cpu < IF_386) - report_error(ERR_FATAL, "command line: " - "32-bit segment size requires a higher cpu"); - - pass_max = (optimizing>0 ? optimizing : 0) + 2; /* passes 1, optimizing, then 2 */ - pass0 = !(optimizing>0); /* start at 1 if not optimizing */ - for (pass = 1; pass <= pass_max && pass0 <= 2; pass++) { - int pass1, pass2; - ldfunc def_label; - - pass1 = pass < pass_max ? 1 : 2; /* seq is 1, 1, 1,..., 1, 2 */ - pass2 = pass > 1 ? 2 : 1; /* seq is 1, 2, 2,..., 2, 2 */ - /* pass0 seq is 0, 0, 0,..., 1, 2 */ - - def_label = pass > 1 ? redefine_label : define_label; - - - sb = cmd_sb; /* set 'bits' to command line default */ - cpu = cmd_cpu; - if (pass0 == 2) { - if (*listname) - nasmlist.init(listname, report_error); - } - in_abs_seg = FALSE; - global_offset_changed = FALSE; /* set by redefine_label */ - location.segment = ofmt->section(NULL, pass2, &sb); - if (pass > 1) { - saa_rewind (forwrefs); - forwref = saa_rstruct (forwrefs); - raa_free (offsets); - offsets = raa_init(); - } - preproc->reset(fname, pass1, report_error, evaluate, &nasmlist); - globallineno = 0; - if (pass == 1) location.known = TRUE; - location.offset = offs = GET_CURR_OFFS; - - while ( (line = preproc->getline()) ) - { - globallineno++; - - /* here we parse our directives; this is not handled by the 'real' - * parser. */ - directive = line; - if ( (i = getkw (&directive, &value)) ) - { - switch (i) { - case 1: /* [SEGMENT n] */ - seg = ofmt->section (value, pass2, &sb); - if (seg == NO_SEG) { - report_error (pass1==1 ? ERR_NONFATAL : ERR_PANIC, - "segment name `%s' not recognised", - value); - } else { - in_abs_seg = FALSE; - location.segment = seg; - } - break; - case 2: /* [EXTERN label:special] */ - if (*value == '$') value++; /* skip initial $ if present */ - if (pass0 == 2) { - q = value; - while (*q && *q != ':') - q++; - if (*q == ':') { - *q++ = '\0'; - ofmt->symdef(value, 0L, 0L, 3, q); - } - } else if (pass == 1) { /* pass == 1 */ - q = value; - validid = TRUE; - if (!isidstart(*q)) - validid = FALSE; - while (*q && *q != ':') { - if (!isidchar(*q)) - validid = FALSE; - q++; - } - if (!validid) { - report_error (ERR_NONFATAL, - "identifier expected after EXTERN"); - break; - } - if (*q == ':') { - *q++ = '\0'; - special = q; - } else - special = NULL; - if (!is_extern(value)) { /* allow re-EXTERN to be ignored */ - int temp = pass0; - pass0 = 1; /* fake pass 1 in labels.c */ - declare_as_global (value, special, report_error); - define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE, - ofmt, report_error); - pass0 = temp; - } - } /* else pass0 == 1 */ - break; - case 3: /* [BITS bits] */ - sb = get_bits(value); - break; - case 4: /* [GLOBAL symbol:special] */ - if (*value == '$') value++; /* skip initial $ if present */ - if (pass0 == 2) { /* pass 2 */ - q = value; - while (*q && *q != ':') - q++; - if (*q == ':') { - *q++ = '\0'; - ofmt->symdef(value, 0L, 0L, 3, q); - } - } else if (pass2 == 1) { /* pass == 1 */ - q = value; - validid = TRUE; - if (!isidstart(*q)) - validid = FALSE; - while (*q && *q != ':') { - if (!isidchar(*q)) - validid = FALSE; - q++; - } - if (!validid) { - report_error (ERR_NONFATAL, - "identifier expected after GLOBAL"); - break; - } - if (*q == ':') { - *q++ = '\0'; - special = q; - } else - special = NULL; - declare_as_global (value, special, report_error); - } /* pass == 1 */ - break; - case 5: /* [COMMON symbol size:special] */ - if (*value == '$') value++; /* skip initial $ if present */ - if (pass0 == 1) { - p = value; - validid = TRUE; - if (!isidstart(*p)) - validid = FALSE; - while (*p && !isspace(*p)) { - if (!isidchar(*p)) - validid = FALSE; - p++; - } - if (!validid) { - report_error (ERR_NONFATAL, - "identifier expected after COMMON"); - break; - } - if (*p) { - long size; - - while (*p && isspace(*p)) - *p++ = '\0'; - q = p; - while (*q && *q != ':') - q++; - if (*q == ':') { - *q++ = '\0'; - special = q; - } else - special = NULL; - size = readnum (p, &rn_error); - if (rn_error) - report_error (ERR_NONFATAL, "invalid size specified" - " in COMMON declaration"); - else - define_common (value, seg_alloc(), size, - special, ofmt, report_error); - } else - report_error (ERR_NONFATAL, "no size specified in" - " COMMON declaration"); - } else if (pass0 == 2) { /* pass == 2 */ - q = value; - while (*q && *q != ':') { - if (isspace(*q)) - *q = '\0'; - q++; - } - if (*q == ':') { - *q++ = '\0'; - ofmt->symdef(value, 0L, 0L, 3, q); - } - } - break; - case 6: /* [ABSOLUTE address] */ - stdscan_reset(); - stdscan_bufptr = value; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, NULL, pass2, report_error, - NULL); - if (e) { - if (!is_reloc(e)) - report_error (pass0==1 ? ERR_NONFATAL : ERR_PANIC, - "cannot use non-relocatable expression as " - "ABSOLUTE address"); - else { - abs_seg = reloc_seg(e); - abs_offset = reloc_value(e); - } - } else - if (pass==1) abs_offset = 0x100;/* don't go near zero in case of / */ - else report_error (ERR_PANIC, "invalid ABSOLUTE address " - "in pass two"); - in_abs_seg = TRUE; - location.segment = NO_SEG; - break; - case 7: /* DEBUG */ - p = value; - q = debugid; - validid = TRUE; - if (!isidstart(*p)) - validid = FALSE; - while (*p && !isspace(*p)) { - if (!isidchar(*p)) - validid = FALSE; - *q++ = *p++; - } - *q++ = 0; - if (!validid) { - report_error (pass==1 ? ERR_NONFATAL : ERR_PANIC, - "identifier expected after DEBUG"); - break; - } - while (*p && isspace(*p)) p++; - if (pass==pass_max) ofmt->current_dfmt->debug_directive (debugid, p); - break; - case 8: /* [WARNING {+|-}warn-name] */ - if (pass1 == 1) { - while (*value && isspace(*value)) - value++; - - if (*value == '+' || *value == '-') { - validid = (*value == '-') ? TRUE : FALSE; - value++; - } else - validid = FALSE; - - for (i=1; i<=ERR_WARN_MAX; i++) - if (!nasm_stricmp(value, suppressed_names[i])) - break; - if (i <= ERR_WARN_MAX) - suppressed[i] = validid; - else - report_error (ERR_NONFATAL, "invalid warning id in WARNING directive"); - } - break; - case 9: /* cpu */ - cpu = get_cpu (value); - break; - case 10: /* fbk 9/2/00 */ /* [LIST {+|-}] */ - while (*value && isspace(*value)) - value++; - - if (*value == '+') { - user_nolist = 0; - } - else { - if (*value == '-') { - user_nolist = 1; - } - else { - report_error (ERR_NONFATAL, "invalid parameter to \"list\" directive"); - } - } - break; - default: - if (!ofmt->directive (directive, value, pass2)) - report_error (pass1==1 ? ERR_NONFATAL : ERR_PANIC, - "unrecognised directive [%s]", - directive); - } - } - else /* it isn't a directive */ - { - parse_line (pass1, line, &output_ins, - report_error, evaluate, - def_label); - - if (!(optimizing>0) && pass == 2) { - if (forwref != NULL && globallineno == forwref->lineno) { - output_ins.forw_ref = TRUE; - do { - output_ins.oprs[forwref->operand].opflags |= OPFLAG_FORWARD; - forwref = saa_rstruct (forwrefs); - } while (forwref != NULL && forwref->lineno == globallineno); - } else - output_ins.forw_ref = FALSE; - } - - - if (!(optimizing>0) && output_ins.forw_ref) - { - if (pass == 1) { - for(i = 0; i < output_ins.operands; i++) - { - if (output_ins.oprs[i].opflags & OPFLAG_FORWARD) - { - struct forwrefinfo *fwinf = - (struct forwrefinfo *)saa_wstruct(forwrefs); - fwinf->lineno = globallineno; - fwinf->operand = i; - } - } - } else { /* pass == 2 */ - /* - * Hack to prevent phase error in the code - * rol ax,x - * x equ 1 - * - * If the second operand is a forward reference, - * the UNITY property of the number 1 in that - * operand is cancelled. Otherwise the above - * sequence will cause a phase error. - * - * This hack means that the above code will - * generate 286+ code. - * - * The forward reference will mean that the - * operand will not have the UNITY property on - * the first pass, so the pass behaviours will - * be consistent. - */ - - if (output_ins.operands >= 2 && - (output_ins.oprs[1].opflags & OPFLAG_FORWARD)) - { - output_ins.oprs[1].type &= ~(ONENESS|BYTENESS); - } - - } /* pass == 2 */ - - } /* forw_ref */ - - - if (output_ins.opcode == I_EQU) { - if (pass1 == 1) - { - /* - * Special `..' EQUs get processed in pass two, - * except `..@' macro-processor EQUs which are done - * in the normal place. - */ - if (!output_ins.label) - report_error (ERR_NONFATAL, - "EQU not preceded by label"); - - else if (output_ins.label[0] != '.' || - output_ins.label[1] != '.' || - output_ins.label[2] == '@') - { - if (output_ins.operands == 1 && - (output_ins.oprs[0].type & IMMEDIATE) && - output_ins.oprs[0].wrt == NO_SEG) - { - int isext = output_ins.oprs[0].opflags & OPFLAG_EXTERN; - def_label (output_ins.label, - output_ins.oprs[0].segment, - output_ins.oprs[0].offset, - NULL, FALSE, isext, ofmt, report_error); - } - else if (output_ins.operands == 2 && - (output_ins.oprs[0].type & IMMEDIATE) && - (output_ins.oprs[0].type & COLON) && - output_ins.oprs[0].segment == NO_SEG && - output_ins.oprs[0].wrt == NO_SEG && - (output_ins.oprs[1].type & IMMEDIATE) && - output_ins.oprs[1].segment == NO_SEG && - output_ins.oprs[1].wrt == NO_SEG) - { - def_label (output_ins.label, - output_ins.oprs[0].offset | SEG_ABS, - output_ins.oprs[1].offset, - NULL, FALSE, FALSE, ofmt, report_error); - } - else - report_error(ERR_NONFATAL, "bad syntax for EQU"); - } - } else { /* pass == 2 */ - /* - * Special `..' EQUs get processed here, except - * `..@' macro processor EQUs which are done above. - */ - if (output_ins.label[0] == '.' && - output_ins.label[1] == '.' && - output_ins.label[2] != '@') - { - if (output_ins.operands == 1 && - (output_ins.oprs[0].type & IMMEDIATE)) { - define_label (output_ins.label, - output_ins.oprs[0].segment, - output_ins.oprs[0].offset, - NULL, FALSE, FALSE, ofmt, report_error); - } - else if (output_ins.operands == 2 && - (output_ins.oprs[0].type & IMMEDIATE) && - (output_ins.oprs[0].type & COLON) && - output_ins.oprs[0].segment == NO_SEG && - (output_ins.oprs[1].type & IMMEDIATE) && - output_ins.oprs[1].segment == NO_SEG) - { - define_label (output_ins.label, - output_ins.oprs[0].offset | SEG_ABS, - output_ins.oprs[1].offset, - NULL, FALSE, FALSE, ofmt, report_error); - } - else - report_error(ERR_NONFATAL, "bad syntax for EQU"); - } - } /* pass == 2 */ - } else { /* instruction isn't an EQU */ - - if (pass1 == 1) { - - long l = insn_size (location.segment, offs, sb, cpu, - &output_ins, report_error); - - /* if (using_debug_info) && output_ins.opcode != -1)*/ - if (using_debug_info) /* fbk 03/25/01 */ - - { - /* this is done here so we can do debug type info */ - long typeinfo = TYS_ELEMENTS(output_ins.operands); - switch (output_ins.opcode) { - case I_RESB: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE; - break; - case I_RESW: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD; - break; - case I_RESD: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD; - break; - case I_RESQ: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD; - break; - case I_REST: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE; - break; - case I_DB: - typeinfo |= TY_BYTE; - break; - case I_DW: - typeinfo |= TY_WORD; - break; - case I_DD: - if (output_ins.eops_float) - typeinfo |= TY_FLOAT; - else - typeinfo |= TY_DWORD; - break; - case I_DQ: - typeinfo |= TY_QWORD; - break; - case I_DT: - typeinfo |= TY_TBYTE; - break; - default: - typeinfo = TY_LABEL; - - } - - ofmt->current_dfmt->debug_typevalue(typeinfo); - - } - if (l != -1) { - offs += l; - SET_CURR_OFFS (offs); - } - /* - * else l == -1 => invalid instruction, which will be - * flagged as an error on pass 2 - */ - - } else { /* pass == 2 */ - offs += assemble (location.segment, offs, sb, cpu, - &output_ins, ofmt, report_error, &nasmlist); - SET_CURR_OFFS (offs); - - } - } /* not an EQU */ - cleanup_insn (&output_ins); - } - nasm_free (line); - location.offset = offs = GET_CURR_OFFS; - } /* end while (line = preproc->getline... */ - - if (pass1==2 && global_offset_changed) - report_error(ERR_NONFATAL, "phase error detected at end of assembly."); - - if (pass1 == 1) preproc->cleanup(1); - - if (pass1==1 && terminate_after_phase) { - fclose(ofile); - remove(outname); - if (want_usage) - usage(); - exit (1); - } - pass_cnt++; - if (pass>1 && !global_offset_changed) { - pass0++; - if (pass0==2) pass = pass_max - 1; - } else if (!(optimizing>0)) pass0++; - - } /* for (pass=1; pass<=2; pass++) */ - - preproc->cleanup(0); - nasmlist.cleanup(); -#if 1 - if (optimizing>0 && opt_verbose_info) /* -On and -Ov switches */ - fprintf(stdout, - "info:: assembly required 1+%d+1 passes\n", pass_cnt-2); -#endif -} /* exit from assemble_file (...) */ - - -static int getkw (char **directive, char **value) -{ - char *p, *q, *buf; - - buf = *directive; - - /* allow leading spaces or tabs */ - while (*buf==' ' || *buf=='\t') - buf++; - - if (*buf!='[') - return 0; - - p = buf; - - while (*p && *p != ']') p++; - - if (!*p) - return 0; - - q = p++; - - while (*p && *p != ';') { - if (!isspace(*p)) - return 0; - p++; - } - q[1] = '\0'; - - *directive = p = buf+1; - while (*buf && *buf!=' ' && *buf!=']' && *buf!='\t') - buf++; - if (*buf==']') { - *buf = '\0'; - *value = buf; - } else { - *buf++ = '\0'; - while (isspace(*buf)) buf++; /* beppu - skip leading whitespace */ - *value = buf; - while (*buf!=']') buf++; - *buf++ = '\0'; - } -#if 0 - for (q=p; *q; q++) - *q = tolower(*q); -#endif - if (!nasm_stricmp(p, "segment") || !nasm_stricmp(p, "section")) - return 1; - if (!nasm_stricmp(p, "extern")) - return 2; - if (!nasm_stricmp(p, "bits")) - return 3; - if (!nasm_stricmp(p, "global")) - return 4; - if (!nasm_stricmp(p, "common")) - return 5; - if (!nasm_stricmp(p, "absolute")) - return 6; - if (!nasm_stricmp(p, "debug")) - return 7; - if (!nasm_stricmp(p, "warning")) - return 8; - if (!nasm_stricmp(p, "cpu")) - return 9; - if (!nasm_stricmp(p, "list")) /* fbk 9/2/00 */ - return 10; - return -1; -} - -/** - * gnu style error reporting - * This function prints an error message to error_file in the - * style used by GNU. An example would be: - * file.asm:50: error: blah blah blah - * where file.asm is the name of the file, 50 is the line number on - * which the error occurs (or is detected) and "error:" is one of - * the possible optional diagnostics -- it can be "error" or "warning" - * or something else. Finally the line terminates with the actual - * error message. - * - * @param severity the severity of the warning or error - * @param fmt the printf style format string - */ -static void report_error_gnu (int severity, const char *fmt, ...) -{ - va_list ap; - - if (is_suppressed_warning(severity)) - return; - - if (severity & ERR_NOFILE) - fputs ("nasm: ", error_file); - else { - char * currentfile = NULL; - long lineno = 0; - src_get (&lineno, ¤tfile); - fprintf (error_file, "%s:%ld: ", currentfile, lineno); - nasm_free (currentfile); - } - va_start (ap, fmt); - report_error_common (severity, fmt, ap); - va_end (ap); -} - -/** - * MS style error reporting - * This function prints an error message to error_file in the - * style used by Visual C and some other Microsoft tools. An example - * would be: - * file.asm(50) : error: blah blah blah - * where file.asm is the name of the file, 50 is the line number on - * which the error occurs (or is detected) and "error:" is one of - * the possible optional diagnostics -- it can be "error" or "warning" - * or something else. Finally the line terminates with the actual - * error message. - * - * @param severity the severity of the warning or error - * @param fmt the printf style format string - */ -static void report_error_vc (int severity, const char *fmt, ...) -{ - va_list ap; - - if (is_suppressed_warning (severity)) - return; - - if (severity & ERR_NOFILE) - fputs ("nasm: ", error_file); - else { - char * currentfile = NULL; - long lineno = 0; - src_get (&lineno, ¤tfile); - fprintf (error_file, "%s(%ld) : ", currentfile, lineno); - nasm_free (currentfile); - } - va_start (ap, fmt); - report_error_common (severity, fmt, ap); - va_end (ap); -} - -/** - * check for supressed warning - * checks for suppressed warning or pass one only warning and we're - * not in pass 1 - * - * @param severity the severity of the warning or error - * @return true if we should abort error/warning printing - */ -static int is_suppressed_warning (int severity) -{ - /* - * See if it's a suppressed warning. - */ - return ((severity & ERR_MASK) == ERR_WARNING && - (severity & ERR_WARN_MASK) != 0 && - suppressed[ (severity & ERR_WARN_MASK) >> ERR_WARN_SHR ]) || - /* - * See if it's a pass-one only warning and we're not in pass one. - */ - ((severity & ERR_PASS1) && pass0 == 2); -} - -/** - * common error reporting - * This is the common back end of the error reporting schemes currently - * implemented. It prints the nature of the warning and then the - * specific error message to error_file and may or may not return. It - * doesn't return if the error severity is a "panic" or "debug" type. - * - * @param severity the severity of the warning or error - * @param fmt the printf style format string - */ -static void report_error_common (int severity, const char *fmt, va_list args) -{ - switch (severity & ERR_MASK) { - case ERR_WARNING: - fputs ("warning: ", error_file); break; - case ERR_NONFATAL: - fputs ("error: ", error_file); break; - case ERR_FATAL: - fputs ("fatal: ", error_file); break; - case ERR_PANIC: - fputs ("panic: ", error_file); break; - case ERR_DEBUG: - fputs("debug: ", error_file); break; - } - - vfprintf (error_file, fmt, args); - fputc ('\n', error_file); - - if (severity & ERR_USAGE) - want_usage = TRUE; - - switch (severity & ERR_MASK) { - case ERR_WARNING: case ERR_DEBUG: - /* no further action, by definition */ - break; - case ERR_NONFATAL: - /* hack enables listing(!) on errors */ - terminate_after_phase = TRUE; - break; - case ERR_FATAL: - if (ofile) { - fclose(ofile); - remove(outname); - } - if (want_usage) - usage(); - exit(1); /* instantly die */ - break; /* placate silly compilers */ - case ERR_PANIC: - fflush(NULL); -/* abort(); */ /* halt, catch fire, and dump core */ - exit(3); - break; - } -} - -static void usage(void) -{ - fputs("type `nasm -h' for help\n", error_file); -} - -static void register_output_formats(void) -{ - ofmt = ofmt_register (report_error); -} - -#define BUF_DELTA 512 - -static FILE *no_pp_fp; -static efunc no_pp_err; -static ListGen *no_pp_list; -static long no_pp_lineinc; - -static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval, - ListGen *listgen) -{ - src_set_fname(nasm_strdup(file)); - src_set_linnum(0); - no_pp_lineinc = 1; - no_pp_err = error; - no_pp_fp = fopen(file, "r"); - if (!no_pp_fp) - no_pp_err (ERR_FATAL | ERR_NOFILE, - "unable to open input file `%s'", file); - no_pp_list = listgen; - (void) pass; /* placate compilers */ - (void) eval; /* placate compilers */ -} - -static char *no_pp_getline (void) -{ - char *buffer, *p, *q; - int bufsize; - - bufsize = BUF_DELTA; - buffer = nasm_malloc(BUF_DELTA); - src_set_linnum(src_get_linnum() + no_pp_lineinc); - - while (1) { /* Loop to handle %line */ - - p = buffer; - while (1) { /* Loop to handle long lines */ - q = fgets(p, bufsize-(p-buffer), no_pp_fp); - if (!q) - break; - p += strlen(p); - if (p > buffer && p[-1] == '\n') - break; - if (p-buffer > bufsize-10) { - int offset; - offset = p - buffer; - bufsize += BUF_DELTA; - buffer = nasm_realloc(buffer, bufsize); - p = buffer + offset; - } - } - - if (!q && p == buffer) { - nasm_free (buffer); - return NULL; - } - - /* - * Play safe: remove CRs, LFs and any spurious ^Zs, if any of - * them are present at the end of the line. - */ - buffer[strcspn(buffer, "\r\n\032")] = '\0'; - - if (!strncmp(buffer, "%line", 5)) { - long ln; - int li; - char *nm = nasm_malloc(strlen(buffer)); - if (sscanf(buffer+5, "%ld+%d %s", &ln, &li, nm) == 3) { - nasm_free( src_set_fname(nm) ); - src_set_linnum(ln); - no_pp_lineinc = li; - continue; - } - nasm_free(nm); - } - break; - } - - no_pp_list->line (LIST_READ, buffer); - - return buffer; -} - -static void no_pp_cleanup (int pass) -{ - fclose(no_pp_fp); -} - -static unsigned long get_cpu (char *value) -{ - - if (!strcmp(value, "8086")) return IF_8086; - if (!strcmp(value, "186")) return IF_186; - if (!strcmp(value, "286")) return IF_286; - if (!strcmp(value, "386")) return IF_386; - if (!strcmp(value, "486")) return IF_486; - if (!strcmp(value, "586") || - !nasm_stricmp(value, "pentium") ) return IF_PENT; - if (!strcmp(value, "686") || - !nasm_stricmp(value, "ppro") || - !nasm_stricmp(value, "pentiumpro") || - !nasm_stricmp(value, "p2") ) return IF_P6; - if (!nasm_stricmp(value, "p3") || - !nasm_stricmp(value, "katmai") ) return IF_KATMAI; - if (!nasm_stricmp(value, "p4") || /* is this right? -- jrc */ - !nasm_stricmp(value, "willamette") ) return IF_WILLAMETTE; - if (!nasm_stricmp(value, "prescott") ) return IF_PRESCOTT; - if (!nasm_stricmp(value, "ia64") || - !nasm_stricmp(value, "ia-64") || - !nasm_stricmp(value, "itanium") || - !nasm_stricmp(value, "itanic") || - !nasm_stricmp(value, "merced") ) return IF_IA64; - - report_error (pass0<2 ? ERR_NONFATAL : ERR_FATAL, "unknown 'cpu' type"); - - return IF_PLEVEL; /* the maximum level */ -} - - -static int get_bits (char *value) -{ - int i; - - if ((i = atoi(value)) == 16) return i; /* set for a 16-bit segment */ - else if (i == 32) { - if (cpu < IF_386) { - report_error(ERR_NONFATAL, - "cannot specify 32-bit segment on processor below a 386"); - i = 16; - } - } else { - report_error(pass0<2 ? ERR_NONFATAL : ERR_FATAL, - "`%s' is not a valid segment size; must be 16 or 32", - value); - i = 16; - } - return i; -} - -/* end of nasm.c */ +/* The Netwide Assembler main program module + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "insns.h" +#include "preproc.h" +#include "parser.h" +#include "eval.h" +#include "assemble.h" +#include "labels.h" +#include "outform.h" +#include "listing.h" + +struct forwrefinfo { /* info held on forward refs. */ + int lineno; + int operand; +}; + +static int get_bits(char *value); +static unsigned long get_cpu(char *cpu_str); +static void parse_cmdline(int, char **); +static void assemble_file(char *); +static int getkw(char **directive, char **value); +static void register_output_formats(void); +static void report_error_gnu(int severity, const char *fmt, ...); +static void report_error_vc(int severity, const char *fmt, ...); +static void report_error_common(int severity, const char *fmt, + va_list args); +static int is_suppressed_warning(int severity); +static void usage(void); +static efunc report_error; + +static int using_debug_info, opt_verbose_info; +int tasm_compatible_mode = FALSE; +int pass0; + +static char inname[FILENAME_MAX]; +static char outname[FILENAME_MAX]; +static char listname[FILENAME_MAX]; +static int globallineno; /* for forward-reference tracking */ +/* static int pass = 0; */ +static struct ofmt *ofmt = NULL; + +static FILE *error_file; /* Where to write error messages */ + +static FILE *ofile = NULL; +int optimizing = -1; /* number of optimization passes to take */ +static int sb, cmd_sb = 16; /* by default */ +static unsigned long cmd_cpu = IF_PLEVEL; /* highest level by default */ +static unsigned long cpu = IF_PLEVEL; /* passed to insn_size & assemble.c */ +int global_offset_changed; /* referenced in labels.c */ + +static loc_t location; +int in_abs_seg; /* Flag we are in ABSOLUTE seg */ +long abs_seg; /* ABSOLUTE segment basis */ +long abs_offset; /* ABSOLUTE offset */ + +static struct RAA *offsets; + +static struct SAA *forwrefs; /* keep track of forward references */ +static struct forwrefinfo *forwref; + +static Preproc *preproc; +enum op_type { + op_normal, /* Preprocess and assemble */ + op_preprocess, /* Preprocess only */ + op_depend /* Generate dependencies */ +}; +static enum op_type operating_mode; + +/* + * Which of the suppressible warnings are suppressed. Entry zero + * doesn't do anything. Initial defaults are given here. + */ +static char suppressed[1 + ERR_WARN_MAX] = { + 0, TRUE, TRUE, TRUE, FALSE, TRUE +}; + +/* + * The option names for the suppressible warnings. As before, entry + * zero does nothing. + */ +static const char *suppressed_names[1 + ERR_WARN_MAX] = { + NULL, "macro-params", "macro-selfref", "orphan-labels", + "number-overflow", + "gnu-elf-extensions" +}; + +/* + * The explanations for the suppressible warnings. As before, entry + * zero does nothing. + */ +static const char *suppressed_what[1 + ERR_WARN_MAX] = { + NULL, + "macro calls with wrong no. of params", + "cyclic macro self-references", + "labels alone on lines without trailing `:'", + "numeric constants greater than 0xFFFFFFFF", + "using 8- or 16-bit relocation in ELF, a GNU extension" +}; + +/* + * This is a null preprocessor which just copies lines from input + * to output. It's used when someone explicitly requests that NASM + * not preprocess their source file. + */ + +static void no_pp_reset(char *, int, efunc, evalfunc, ListGen *); +static char *no_pp_getline(void); +static void no_pp_cleanup(int); +static Preproc no_pp = { + no_pp_reset, + no_pp_getline, + no_pp_cleanup +}; + +/* + * get/set current offset... + */ +#define GET_CURR_OFFS (in_abs_seg?abs_offset:\ + raa_read(offsets,location.segment)) +#define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\ + (void)(offsets=raa_write(offsets,location.segment,(x)))) + +static int want_usage; +static int terminate_after_phase; +int user_nolist = 0; /* fbk 9/2/00 */ + +static void nasm_fputs(const char *line, FILE * outfile) +{ + if (outfile) { + fputs(line, outfile); + fputc('\n', outfile); + } else + puts(line); +} + +int main(int argc, char **argv) +{ + pass0 = 1; + want_usage = terminate_after_phase = FALSE; + report_error = report_error_gnu; + + nasm_set_malloc_error(report_error); + offsets = raa_init(); + forwrefs = saa_init((long)sizeof(struct forwrefinfo)); + + preproc = &nasmpp; + operating_mode = op_normal; + + error_file = stderr; + + seg_init(); + + register_output_formats(); + + parse_cmdline(argc, argv); + + if (terminate_after_phase) { + if (want_usage) + usage(); + return 1; + } + + /* If debugging info is disabled, suppress any debug calls */ + if (!using_debug_info) + ofmt->current_dfmt = &null_debug_form; + + if (ofmt->stdmac) + pp_extra_stdmac(ofmt->stdmac); + parser_global_info(ofmt, &location); + eval_global_info(ofmt, lookup_label, &location); + + /* define some macros dependent of command-line */ + { + char temp[64]; + snprintf(temp, sizeof(temp), "__OUTPUT_FORMAT__=%s\n", + ofmt->shortname); + pp_pre_define(temp); + } + + switch (operating_mode) { + case op_depend: + { + char *line; + preproc->reset(inname, 0, report_error, evaluate, &nasmlist); + if (outname[0] == '\0') + ofmt->filename(inname, outname, report_error); + ofile = NULL; + fprintf(stdout, "%s: %s", outname, inname); + while ((line = preproc->getline())) + nasm_free(line); + preproc->cleanup(0); + putc('\n', stdout); + } + break; + + case op_preprocess: + { + char *line; + char *file_name = NULL; + long prior_linnum = 0; + int lineinc = 0; + + if (*outname) { + ofile = fopen(outname, "w"); + if (!ofile) + report_error(ERR_FATAL | ERR_NOFILE, + "unable to open output file `%s'", + outname); + } else + ofile = NULL; + + location.known = FALSE; + +/* pass = 1; */ + preproc->reset(inname, 2, report_error, evaluate, &nasmlist); + while ((line = preproc->getline())) { + /* + * We generate %line directives if needed for later programs + */ + long linnum = prior_linnum += lineinc; + int altline = src_get(&linnum, &file_name); + if (altline) { + if (altline == 1 && lineinc == 1) + nasm_fputs("", ofile); + else { + lineinc = (altline != -1 || lineinc != 1); + fprintf(ofile ? ofile : stdout, + "%%line %ld+%d %s\n", linnum, lineinc, + file_name); + } + prior_linnum = linnum; + } + nasm_fputs(line, ofile); + nasm_free(line); + } + nasm_free(file_name); + preproc->cleanup(0); + if (ofile) + fclose(ofile); + if (ofile && terminate_after_phase) + remove(outname); + } + break; + + case op_normal: + { + /* + * We must call ofmt->filename _anyway_, even if the user + * has specified their own output file, because some + * formats (eg OBJ and COFF) use ofmt->filename to find out + * the name of the input file and then put that inside the + * file. + */ + ofmt->filename(inname, outname, report_error); + + ofile = fopen(outname, "wb"); + if (!ofile) { + report_error(ERR_FATAL | ERR_NOFILE, + "unable to open output file `%s'", outname); + } + + /* + * We must call init_labels() before ofmt->init() since + * some object formats will want to define labels in their + * init routines. (eg OS/2 defines the FLAT group) + */ + init_labels(); + + ofmt->init(ofile, report_error, define_label, evaluate); + + assemble_file(inname); + + if (!terminate_after_phase) { + ofmt->cleanup(using_debug_info); + cleanup_labels(); + } else { + /* + * We had an fclose on the output file here, but we + * actually do that in all the object file drivers as well, + * so we're leaving out the one here. + * fclose (ofile); + */ + remove(outname); + if (listname[0]) + remove(listname); + } + } + break; + } + + if (want_usage) + usage(); + + raa_free(offsets); + saa_free(forwrefs); + eval_cleanup(); + nasmlib_cleanup(); + + if (terminate_after_phase) + return 1; + else + return 0; +} + +/* + * Get a parameter for a command line option. + * First arg must be in the form of e.g. -f... + */ +static char *get_param(char *p, char *q, int *advance) +{ + *advance = 0; + if (p[2]) { /* the parameter's in the option */ + p += 2; + while (isspace(*p)) + p++; + return p; + } + if (q && q[0]) { + *advance = 1; + return q; + } + report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "option `-%c' requires an argument", p[1]); + return NULL; +} + +struct textargs { + const char *label; + int value; +}; + +#define OPT_PREFIX 0 +#define OPT_POSTFIX 1 +struct textargs textopts[] = { + {"prefix", OPT_PREFIX}, + {"postfix", OPT_POSTFIX}, + {NULL, 0} +}; + +int stopoptions = 0; +static int process_arg(char *p, char *q) +{ + char *param; + int i, advance = 0; + + if (!p || !p[0]) + return 0; + + if (p[0] == '-' && !stopoptions) { + switch (p[1]) { + case 's': + error_file = stdout; + break; + case 'o': /* these parameters take values */ + case 'O': + case 'f': + case 'p': + case 'P': + case 'd': + case 'D': + case 'i': + case 'I': + case 'l': + case 'E': + case 'F': + case 'X': + case 'u': + case 'U': + if (!(param = get_param(p, q, &advance))) + break; + if (p[1] == 'o') { /* output file */ + strcpy(outname, param); + } else if (p[1] == 'f') { /* output format */ + ofmt = ofmt_find(param); + if (!ofmt) { + report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE, + "unrecognised output format `%s' - " + "use -hf for a list", param); + } else + ofmt->current_dfmt = ofmt->debug_formats[0]; + } else if (p[1] == 'O') { /* Optimization level */ + int opt; + opt = -99; + while (*param) { + if (isdigit(*param)) { + opt = atoi(param); + while (isdigit(*++param)) ; + if (opt <= 0) + optimizing = -1; /* 0.98 behaviour */ + else if (opt == 1) + optimizing = 0; /* Two passes, 0.98.09 behavior */ + else + optimizing = opt; /* Multiple passes */ + } else { + if (*param == 'v' || *param == '+') { + ++param; + opt_verbose_info = TRUE; + opt = 0; + } else { /* garbage */ + opt = -99; + break; + } + } + } /* while (*param) */ + if (opt == -99) + report_error(ERR_FATAL, + "command line optimization level must be 'v', 0..3 or "); + } else if (p[1] == 'P' || p[1] == 'p') { /* pre-include */ + pp_pre_include(param); + } else if (p[1] == 'D' || p[1] == 'd') { /* pre-define */ + pp_pre_define(param); + } else if (p[1] == 'U' || p[1] == 'u') { /* un-define */ + pp_pre_undefine(param); + } else if (p[1] == 'I' || p[1] == 'i') { /* include search path */ + pp_include_path(param); + } else if (p[1] == 'l') { /* listing file */ + strcpy(listname, param); + } else if (p[1] == 'E') { /* error messages file */ + error_file = fopen(param, "w"); + if (!error_file) { + error_file = stderr; /* Revert to default! */ + report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE, + "cannot open file `%s' for error messages", + param); + } + } else if (p[1] == 'F') { /* specify debug format */ + ofmt->current_dfmt = dfmt_find(ofmt, param); + if (!ofmt->current_dfmt) { + report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE, + "unrecognized debug format `%s' for" + " output format `%s'", + param, ofmt->shortname); + } + } else if (p[1] == 'X') { /* specify error reporting format */ + if (nasm_stricmp("vc", param) == 0) + report_error = report_error_vc; + else if (nasm_stricmp("gnu", param) == 0) + report_error = report_error_gnu; + else + report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE, + "unrecognized error reporting format `%s'", + param); + } + break; + case 'g': + using_debug_info = TRUE; + break; + case 'h': + printf + ("usage: nasm [-@ response file] [-o outfile] [-f format] " + "[-l listfile]\n" + " [options...] [--] filename\n" + " or nasm -r for version info (obsolete)\n" + " or nasm -v for version info (preferred)\n\n" + " -t assemble in SciTech TASM compatible mode\n" + " -g generate debug information in selected format.\n"); + printf + (" -e preprocess only (writes output to stdout by default)\n" + " -a don't preprocess (assemble only)\n" + " -M generate Makefile dependencies on stdout\n\n" + " -E redirect error messages to file\n" + " -s redirect error messages to stdout\n\n" + " -F format select a debugging format\n\n" + " -I adds a pathname to the include file path\n"); + printf + (" -O optimize branch offsets (-O0 disables, default)\n" + " -P pre-includes a file\n" + " -D[=] pre-defines a macro\n" + " -U undefines a macro\n" + " -X specifies error reporting format (gnu or vc)\n" + " -w+foo enables warnings about foo; -w-foo disables them\n" + "where foo can be:\n"); + for (i = 1; i <= ERR_WARN_MAX; i++) + printf(" %-23s %s (default %s)\n", + suppressed_names[i], suppressed_what[i], + suppressed[i] ? "off" : "on"); + printf + ("\nresponse files should contain command line parameters" + ", one per line.\n"); + if (p[2] == 'f') { + printf("\nvalid output formats for -f are" + " (`*' denotes default):\n"); + ofmt_list(ofmt, stdout); + } else { + printf("\nFor a list of valid output formats, use -hf.\n"); + printf("For a list of debug formats, use -f -y.\n"); + } + exit(0); /* never need usage message here */ + break; + case 'y': + printf("\nvalid debug formats for '%s' output format are" + " ('*' denotes default):\n", ofmt->shortname); + dfmt_list(ofmt, stdout); + exit(0); + break; + case 't': + tasm_compatible_mode = TRUE; + break; + case 'r': + case 'v': + { + const char *nasm_version_string = + "NASM version " NASM_VER " compiled on " __DATE__ +#ifdef DEBUG + " with -DDEBUG" +#endif + ; + puts(nasm_version_string); + exit(0); /* never need usage message here */ + } + break; + case 'e': /* preprocess only */ + operating_mode = op_preprocess; + break; + case 'a': /* assemble only - don't preprocess */ + preproc = &no_pp; + break; + case 'w': + if (p[2] != '+' && p[2] != '-') { + report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "invalid option to `-w'"); + } else { + for (i = 1; i <= ERR_WARN_MAX; i++) + if (!nasm_stricmp(p + 3, suppressed_names[i])) + break; + if (i <= ERR_WARN_MAX) + suppressed[i] = (p[2] == '-'); + else + report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "invalid option to `-w'"); + } + break; + case 'M': + operating_mode = op_depend; + break; + + case '-': + { + int s; + + if (p[2] == 0) { /* -- => stop processing options */ + stopoptions = 1; + break; + } + for (s = 0; textopts[s].label; s++) { + if (!nasm_stricmp(p + 2, textopts[s].label)) { + break; + } + } + + switch (s) { + + case OPT_PREFIX: + case OPT_POSTFIX: + { + if (!q) { + report_error(ERR_NONFATAL | ERR_NOFILE | + ERR_USAGE, + "option `--%s' requires an argument", + p + 2); + break; + } else { + advance = 1, param = q; + } + + if (s == OPT_PREFIX) { + strncpy(lprefix, param, PREFIX_MAX - 1); + lprefix[PREFIX_MAX - 1] = 0; + break; + } + if (s == OPT_POSTFIX) { + strncpy(lpostfix, param, POSTFIX_MAX - 1); + lpostfix[POSTFIX_MAX - 1] = 0; + break; + } + break; + } + default: + { + report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "unrecognised option `--%s'", p + 2); + break; + } + } + break; + } + + default: + if (!ofmt->setinfo(GI_SWITCH, &p)) + report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "unrecognised option `-%c'", p[1]); + break; + } + } else { + if (*inname) { + report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "more than one input file specified"); + } else + strcpy(inname, p); + } + + return advance; +} + +#define ARG_BUF_DELTA 128 + +static void process_respfile(FILE * rfile) +{ + char *buffer, *p, *q, *prevarg; + int bufsize, prevargsize; + + bufsize = prevargsize = ARG_BUF_DELTA; + buffer = nasm_malloc(ARG_BUF_DELTA); + prevarg = nasm_malloc(ARG_BUF_DELTA); + prevarg[0] = '\0'; + + while (1) { /* Loop to handle all lines in file */ + + p = buffer; + while (1) { /* Loop to handle long lines */ + q = fgets(p, bufsize - (p - buffer), rfile); + if (!q) + break; + p += strlen(p); + if (p > buffer && p[-1] == '\n') + break; + if (p - buffer > bufsize - 10) { + int offset; + offset = p - buffer; + bufsize += ARG_BUF_DELTA; + buffer = nasm_realloc(buffer, bufsize); + p = buffer + offset; + } + } + + if (!q && p == buffer) { + if (prevarg[0]) + process_arg(prevarg, NULL); + nasm_free(buffer); + nasm_free(prevarg); + return; + } + + /* + * Play safe: remove CRs, LFs and any spurious ^Zs, if any of + * them are present at the end of the line. + */ + *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0'; + + while (p > buffer && isspace(p[-1])) + *--p = '\0'; + + p = buffer; + while (isspace(*p)) + p++; + + if (process_arg(prevarg, p)) + *p = '\0'; + + if (strlen(p) > prevargsize - 10) { + prevargsize += ARG_BUF_DELTA; + prevarg = nasm_realloc(prevarg, prevargsize); + } + strcpy(prevarg, p); + } +} + +/* Function to process args from a string of args, rather than the + * argv array. Used by the environment variable and response file + * processing. + */ +static void process_args(char *args) +{ + char *p, *q, *arg, *prevarg; + char separator = ' '; + + p = args; + if (*p && *p != '-') + separator = *p++; + arg = NULL; + while (*p) { + q = p; + while (*p && *p != separator) + p++; + while (*p == separator) + *p++ = '\0'; + prevarg = arg; + arg = q; + if (process_arg(prevarg, arg)) + arg = NULL; + } + if (arg) + process_arg(arg, NULL); +} + +static void parse_cmdline(int argc, char **argv) +{ + FILE *rfile; + char *envreal, *envcopy = NULL, *p, *arg; + + *inname = *outname = *listname = '\0'; + + /* + * First, process the NASMENV environment variable. + */ + envreal = getenv("NASMENV"); + arg = NULL; + if (envreal) { + envcopy = nasm_strdup(envreal); + process_args(envcopy); + nasm_free(envcopy); + } + + /* + * Now process the actual command line. + */ + while (--argc) { + int i; + argv++; + if (argv[0][0] == '@') { + /* We have a response file, so process this as a set of + * arguments like the environment variable. This allows us + * to have multiple arguments on a single line, which is + * different to the -@resp file processing below for regular + * NASM. + */ + char *str = malloc(2048); + FILE *f = fopen(&argv[0][1], "r"); + if (!str) { + printf("out of memory"); + exit(-1); + } + if (f) { + while (fgets(str, 2048, f)) { + process_args(str); + } + fclose(f); + } + free(str); + argc--; + argv++; + } + if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') { + if ((p = get_param(argv[0], argc > 1 ? argv[1] : NULL, &i))) { + if ((rfile = fopen(p, "r"))) { + process_respfile(rfile); + fclose(rfile); + } else + report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "unable to open response file `%s'", p); + } + } else + i = process_arg(argv[0], argc > 1 ? argv[1] : NULL); + argv += i, argc -= i; + } + + if (!*inname) + report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "no input file specified"); +} + +static void assemble_file(char *fname) +{ + char *directive, *value, *p, *q, *special, *line, debugid[80]; + insn output_ins; + int i, rn_error, validid; + long seg, offs; + struct tokenval tokval; + expr *e; + int pass, pass_max; + int pass_cnt = 0; /* count actual passes */ + + if (cmd_sb == 32 && cmd_cpu < IF_386) + report_error(ERR_FATAL, "command line: " + "32-bit segment size requires a higher cpu"); + + pass_max = (optimizing > 0 ? optimizing : 0) + 2; /* passes 1, optimizing, then 2 */ + pass0 = !(optimizing > 0); /* start at 1 if not optimizing */ + for (pass = 1; pass <= pass_max && pass0 <= 2; pass++) { + int pass1, pass2; + ldfunc def_label; + + pass1 = pass < pass_max ? 1 : 2; /* seq is 1, 1, 1,..., 1, 2 */ + pass2 = pass > 1 ? 2 : 1; /* seq is 1, 2, 2,..., 2, 2 */ + /* pass0 seq is 0, 0, 0,..., 1, 2 */ + + def_label = pass > 1 ? redefine_label : define_label; + + sb = cmd_sb; /* set 'bits' to command line default */ + cpu = cmd_cpu; + if (pass0 == 2) { + if (*listname) + nasmlist.init(listname, report_error); + } + in_abs_seg = FALSE; + global_offset_changed = FALSE; /* set by redefine_label */ + location.segment = ofmt->section(NULL, pass2, &sb); + if (pass > 1) { + saa_rewind(forwrefs); + forwref = saa_rstruct(forwrefs); + raa_free(offsets); + offsets = raa_init(); + } + preproc->reset(fname, pass1, report_error, evaluate, &nasmlist); + globallineno = 0; + if (pass == 1) + location.known = TRUE; + location.offset = offs = GET_CURR_OFFS; + + while ((line = preproc->getline())) { + globallineno++; + + /* here we parse our directives; this is not handled by the 'real' + * parser. */ + directive = line; + if ((i = getkw(&directive, &value))) { + switch (i) { + case 1: /* [SEGMENT n] */ + seg = ofmt->section(value, pass2, &sb); + if (seg == NO_SEG) { + report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC, + "segment name `%s' not recognised", + value); + } else { + in_abs_seg = FALSE; + location.segment = seg; + } + break; + case 2: /* [EXTERN label:special] */ + if (*value == '$') + value++; /* skip initial $ if present */ + if (pass0 == 2) { + q = value; + while (*q && *q != ':') + q++; + if (*q == ':') { + *q++ = '\0'; + ofmt->symdef(value, 0L, 0L, 3, q); + } + } else if (pass == 1) { /* pass == 1 */ + q = value; + validid = TRUE; + if (!isidstart(*q)) + validid = FALSE; + while (*q && *q != ':') { + if (!isidchar(*q)) + validid = FALSE; + q++; + } + if (!validid) { + report_error(ERR_NONFATAL, + "identifier expected after EXTERN"); + break; + } + if (*q == ':') { + *q++ = '\0'; + special = q; + } else + special = NULL; + if (!is_extern(value)) { /* allow re-EXTERN to be ignored */ + int temp = pass0; + pass0 = 1; /* fake pass 1 in labels.c */ + declare_as_global(value, special, + report_error); + define_label(value, seg_alloc(), 0L, NULL, + FALSE, TRUE, ofmt, report_error); + pass0 = temp; + } + } /* else pass0 == 1 */ + break; + case 3: /* [BITS bits] */ + sb = get_bits(value); + break; + case 4: /* [GLOBAL symbol:special] */ + if (*value == '$') + value++; /* skip initial $ if present */ + if (pass0 == 2) { /* pass 2 */ + q = value; + while (*q && *q != ':') + q++; + if (*q == ':') { + *q++ = '\0'; + ofmt->symdef(value, 0L, 0L, 3, q); + } + } else if (pass2 == 1) { /* pass == 1 */ + q = value; + validid = TRUE; + if (!isidstart(*q)) + validid = FALSE; + while (*q && *q != ':') { + if (!isidchar(*q)) + validid = FALSE; + q++; + } + if (!validid) { + report_error(ERR_NONFATAL, + "identifier expected after GLOBAL"); + break; + } + if (*q == ':') { + *q++ = '\0'; + special = q; + } else + special = NULL; + declare_as_global(value, special, report_error); + } /* pass == 1 */ + break; + case 5: /* [COMMON symbol size:special] */ + if (*value == '$') + value++; /* skip initial $ if present */ + if (pass0 == 1) { + p = value; + validid = TRUE; + if (!isidstart(*p)) + validid = FALSE; + while (*p && !isspace(*p)) { + if (!isidchar(*p)) + validid = FALSE; + p++; + } + if (!validid) { + report_error(ERR_NONFATAL, + "identifier expected after COMMON"); + break; + } + if (*p) { + long size; + + while (*p && isspace(*p)) + *p++ = '\0'; + q = p; + while (*q && *q != ':') + q++; + if (*q == ':') { + *q++ = '\0'; + special = q; + } else + special = NULL; + size = readnum(p, &rn_error); + if (rn_error) + report_error(ERR_NONFATAL, + "invalid size specified" + " in COMMON declaration"); + else + define_common(value, seg_alloc(), size, + special, ofmt, report_error); + } else + report_error(ERR_NONFATAL, + "no size specified in" + " COMMON declaration"); + } else if (pass0 == 2) { /* pass == 2 */ + q = value; + while (*q && *q != ':') { + if (isspace(*q)) + *q = '\0'; + q++; + } + if (*q == ':') { + *q++ = '\0'; + ofmt->symdef(value, 0L, 0L, 3, q); + } + } + break; + case 6: /* [ABSOLUTE address] */ + stdscan_reset(); + stdscan_bufptr = value; + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, NULL, pass2, + report_error, NULL); + if (e) { + if (!is_reloc(e)) + report_error(pass0 == + 1 ? ERR_NONFATAL : ERR_PANIC, + "cannot use non-relocatable expression as " + "ABSOLUTE address"); + else { + abs_seg = reloc_seg(e); + abs_offset = reloc_value(e); + } + } else if (pass == 1) + abs_offset = 0x100; /* don't go near zero in case of / */ + else + report_error(ERR_PANIC, "invalid ABSOLUTE address " + "in pass two"); + in_abs_seg = TRUE; + location.segment = NO_SEG; + break; + case 7: /* DEBUG */ + p = value; + q = debugid; + validid = TRUE; + if (!isidstart(*p)) + validid = FALSE; + while (*p && !isspace(*p)) { + if (!isidchar(*p)) + validid = FALSE; + *q++ = *p++; + } + *q++ = 0; + if (!validid) { + report_error(pass == 1 ? ERR_NONFATAL : ERR_PANIC, + "identifier expected after DEBUG"); + break; + } + while (*p && isspace(*p)) + p++; + if (pass == pass_max) + ofmt->current_dfmt->debug_directive(debugid, p); + break; + case 8: /* [WARNING {+|-}warn-name] */ + if (pass1 == 1) { + while (*value && isspace(*value)) + value++; + + if (*value == '+' || *value == '-') { + validid = (*value == '-') ? TRUE : FALSE; + value++; + } else + validid = FALSE; + + for (i = 1; i <= ERR_WARN_MAX; i++) + if (!nasm_stricmp(value, suppressed_names[i])) + break; + if (i <= ERR_WARN_MAX) + suppressed[i] = validid; + else + report_error(ERR_NONFATAL, + "invalid warning id in WARNING directive"); + } + break; + case 9: /* cpu */ + cpu = get_cpu(value); + break; + case 10: /* fbk 9/2/00 *//* [LIST {+|-}] */ + while (*value && isspace(*value)) + value++; + + if (*value == '+') { + user_nolist = 0; + } else { + if (*value == '-') { + user_nolist = 1; + } else { + report_error(ERR_NONFATAL, + "invalid parameter to \"list\" directive"); + } + } + break; + default: + if (!ofmt->directive(directive, value, pass2)) + report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC, + "unrecognised directive [%s]", + directive); + } + } else { /* it isn't a directive */ + + parse_line(pass1, line, &output_ins, + report_error, evaluate, def_label); + + if (!(optimizing > 0) && pass == 2) { + if (forwref != NULL && globallineno == forwref->lineno) { + output_ins.forw_ref = TRUE; + do { + output_ins.oprs[forwref->operand].opflags |= + OPFLAG_FORWARD; + forwref = saa_rstruct(forwrefs); + } while (forwref != NULL + && forwref->lineno == globallineno); + } else + output_ins.forw_ref = FALSE; + } + + if (!(optimizing > 0) && output_ins.forw_ref) { + if (pass == 1) { + for (i = 0; i < output_ins.operands; i++) { + if (output_ins.oprs[i]. + opflags & OPFLAG_FORWARD) { + struct forwrefinfo *fwinf = + (struct forwrefinfo *) + saa_wstruct(forwrefs); + fwinf->lineno = globallineno; + fwinf->operand = i; + } + } + } else { /* pass == 2 */ + /* + * Hack to prevent phase error in the code + * rol ax,x + * x equ 1 + * + * If the second operand is a forward reference, + * the UNITY property of the number 1 in that + * operand is cancelled. Otherwise the above + * sequence will cause a phase error. + * + * This hack means that the above code will + * generate 286+ code. + * + * The forward reference will mean that the + * operand will not have the UNITY property on + * the first pass, so the pass behaviours will + * be consistent. + */ + + if (output_ins.operands >= 2 && + (output_ins.oprs[1].opflags & OPFLAG_FORWARD)) + { + output_ins.oprs[1].type &= + ~(ONENESS | BYTENESS); + } + + } /* pass == 2 */ + + } + + /* forw_ref */ + if (output_ins.opcode == I_EQU) { + if (pass1 == 1) { + /* + * Special `..' EQUs get processed in pass two, + * except `..@' macro-processor EQUs which are done + * in the normal place. + */ + if (!output_ins.label) + report_error(ERR_NONFATAL, + "EQU not preceded by label"); + + else if (output_ins.label[0] != '.' || + output_ins.label[1] != '.' || + output_ins.label[2] == '@') { + if (output_ins.operands == 1 && + (output_ins.oprs[0].type & IMMEDIATE) && + output_ins.oprs[0].wrt == NO_SEG) { + int isext = + output_ins.oprs[0]. + opflags & OPFLAG_EXTERN; + def_label(output_ins.label, + output_ins.oprs[0].segment, + output_ins.oprs[0].offset, NULL, + FALSE, isext, ofmt, + report_error); + } else if (output_ins.operands == 2 + && (output_ins.oprs[0]. + type & IMMEDIATE) + && (output_ins.oprs[0].type & COLON) + && output_ins.oprs[0].segment == + NO_SEG + && output_ins.oprs[0].wrt == NO_SEG + && (output_ins.oprs[1]. + type & IMMEDIATE) + && output_ins.oprs[1].segment == + NO_SEG + && output_ins.oprs[1].wrt == + NO_SEG) { + def_label(output_ins.label, + output_ins.oprs[0]. + offset | SEG_ABS, + output_ins.oprs[1].offset, NULL, + FALSE, FALSE, ofmt, + report_error); + } else + report_error(ERR_NONFATAL, + "bad syntax for EQU"); + } + } else { /* pass == 2 */ + /* + * Special `..' EQUs get processed here, except + * `..@' macro processor EQUs which are done above. + */ + if (output_ins.label[0] == '.' && + output_ins.label[1] == '.' && + output_ins.label[2] != '@') { + if (output_ins.operands == 1 && + (output_ins.oprs[0].type & IMMEDIATE)) { + define_label(output_ins.label, + output_ins.oprs[0].segment, + output_ins.oprs[0].offset, + NULL, FALSE, FALSE, ofmt, + report_error); + } else if (output_ins.operands == 2 + && (output_ins.oprs[0]. + type & IMMEDIATE) + && (output_ins.oprs[0].type & COLON) + && output_ins.oprs[0].segment == + NO_SEG + && (output_ins.oprs[1]. + type & IMMEDIATE) + && output_ins.oprs[1].segment == + NO_SEG) { + define_label(output_ins.label, + output_ins.oprs[0]. + offset | SEG_ABS, + output_ins.oprs[1].offset, + NULL, FALSE, FALSE, ofmt, + report_error); + } else + report_error(ERR_NONFATAL, + "bad syntax for EQU"); + } + } /* pass == 2 */ + } else { /* instruction isn't an EQU */ + + if (pass1 == 1) { + + long l = insn_size(location.segment, offs, sb, cpu, + &output_ins, report_error); + + /* if (using_debug_info) && output_ins.opcode != -1) */ + if (using_debug_info) + { /* fbk 03/25/01 */ + /* this is done here so we can do debug type info */ + long typeinfo = + TYS_ELEMENTS(output_ins.operands); + switch (output_ins.opcode) { + case I_RESB: + typeinfo = + TYS_ELEMENTS(output_ins.oprs[0]. + offset) | TY_BYTE; + break; + case I_RESW: + typeinfo = + TYS_ELEMENTS(output_ins.oprs[0]. + offset) | TY_WORD; + break; + case I_RESD: + typeinfo = + TYS_ELEMENTS(output_ins.oprs[0]. + offset) | TY_DWORD; + break; + case I_RESQ: + typeinfo = + TYS_ELEMENTS(output_ins.oprs[0]. + offset) | TY_QWORD; + break; + case I_REST: + typeinfo = + TYS_ELEMENTS(output_ins.oprs[0]. + offset) | TY_TBYTE; + break; + case I_DB: + typeinfo |= TY_BYTE; + break; + case I_DW: + typeinfo |= TY_WORD; + break; + case I_DD: + if (output_ins.eops_float) + typeinfo |= TY_FLOAT; + else + typeinfo |= TY_DWORD; + break; + case I_DQ: + typeinfo |= TY_QWORD; + break; + case I_DT: + typeinfo |= TY_TBYTE; + break; + default: + typeinfo = TY_LABEL; + + } + + ofmt->current_dfmt->debug_typevalue(typeinfo); + + } + if (l != -1) { + offs += l; + SET_CURR_OFFS(offs); + } + /* + * else l == -1 => invalid instruction, which will be + * flagged as an error on pass 2 + */ + + } else { /* pass == 2 */ + offs += assemble(location.segment, offs, sb, cpu, + &output_ins, ofmt, report_error, + &nasmlist); + SET_CURR_OFFS(offs); + + } + } /* not an EQU */ + cleanup_insn(&output_ins); + } + nasm_free(line); + location.offset = offs = GET_CURR_OFFS; + } /* end while (line = preproc->getline... */ + + if (pass1 == 2 && global_offset_changed) + report_error(ERR_NONFATAL, + "phase error detected at end of assembly."); + + if (pass1 == 1) + preproc->cleanup(1); + + if (pass1 == 1 && terminate_after_phase) { + fclose(ofile); + remove(outname); + if (want_usage) + usage(); + exit(1); + } + pass_cnt++; + if (pass > 1 && !global_offset_changed) { + pass0++; + if (pass0 == 2) + pass = pass_max - 1; + } else if (!(optimizing > 0)) + pass0++; + + } /* for (pass=1; pass<=2; pass++) */ + + preproc->cleanup(0); + nasmlist.cleanup(); +#if 1 + if (optimizing > 0 && opt_verbose_info) /* -On and -Ov switches */ + fprintf(stdout, + "info:: assembly required 1+%d+1 passes\n", pass_cnt - 2); +#endif +} /* exit from assemble_file (...) */ + +static int getkw(char **directive, char **value) +{ + char *p, *q, *buf; + + buf = *directive; + + /* allow leading spaces or tabs */ + while (*buf == ' ' || *buf == '\t') + buf++; + + if (*buf != '[') + return 0; + + p = buf; + + while (*p && *p != ']') + p++; + + if (!*p) + return 0; + + q = p++; + + while (*p && *p != ';') { + if (!isspace(*p)) + return 0; + p++; + } + q[1] = '\0'; + + *directive = p = buf + 1; + while (*buf && *buf != ' ' && *buf != ']' && *buf != '\t') + buf++; + if (*buf == ']') { + *buf = '\0'; + *value = buf; + } else { + *buf++ = '\0'; + while (isspace(*buf)) + buf++; /* beppu - skip leading whitespace */ + *value = buf; + while (*buf != ']') + buf++; + *buf++ = '\0'; + } +#if 0 + for (q = p; *q; q++) + *q = tolower(*q); +#endif + if (!nasm_stricmp(p, "segment") || !nasm_stricmp(p, "section")) + return 1; + if (!nasm_stricmp(p, "extern")) + return 2; + if (!nasm_stricmp(p, "bits")) + return 3; + if (!nasm_stricmp(p, "global")) + return 4; + if (!nasm_stricmp(p, "common")) + return 5; + if (!nasm_stricmp(p, "absolute")) + return 6; + if (!nasm_stricmp(p, "debug")) + return 7; + if (!nasm_stricmp(p, "warning")) + return 8; + if (!nasm_stricmp(p, "cpu")) + return 9; + if (!nasm_stricmp(p, "list")) /* fbk 9/2/00 */ + return 10; + return -1; +} + +/** + * gnu style error reporting + * This function prints an error message to error_file in the + * style used by GNU. An example would be: + * file.asm:50: error: blah blah blah + * where file.asm is the name of the file, 50 is the line number on + * which the error occurs (or is detected) and "error:" is one of + * the possible optional diagnostics -- it can be "error" or "warning" + * or something else. Finally the line terminates with the actual + * error message. + * + * @param severity the severity of the warning or error + * @param fmt the printf style format string + */ +static void report_error_gnu(int severity, const char *fmt, ...) +{ + va_list ap; + + if (is_suppressed_warning(severity)) + return; + + if (severity & ERR_NOFILE) + fputs("nasm: ", error_file); + else { + char *currentfile = NULL; + long lineno = 0; + src_get(&lineno, ¤tfile); + fprintf(error_file, "%s:%ld: ", currentfile, lineno); + nasm_free(currentfile); + } + va_start(ap, fmt); + report_error_common(severity, fmt, ap); + va_end(ap); +} + +/** + * MS style error reporting + * This function prints an error message to error_file in the + * style used by Visual C and some other Microsoft tools. An example + * would be: + * file.asm(50) : error: blah blah blah + * where file.asm is the name of the file, 50 is the line number on + * which the error occurs (or is detected) and "error:" is one of + * the possible optional diagnostics -- it can be "error" or "warning" + * or something else. Finally the line terminates with the actual + * error message. + * + * @param severity the severity of the warning or error + * @param fmt the printf style format string + */ +static void report_error_vc(int severity, const char *fmt, ...) +{ + va_list ap; + + if (is_suppressed_warning(severity)) + return; + + if (severity & ERR_NOFILE) + fputs("nasm: ", error_file); + else { + char *currentfile = NULL; + long lineno = 0; + src_get(&lineno, ¤tfile); + fprintf(error_file, "%s(%ld) : ", currentfile, lineno); + nasm_free(currentfile); + } + va_start(ap, fmt); + report_error_common(severity, fmt, ap); + va_end(ap); +} + +/** + * check for supressed warning + * checks for suppressed warning or pass one only warning and we're + * not in pass 1 + * + * @param severity the severity of the warning or error + * @return true if we should abort error/warning printing + */ +static int is_suppressed_warning(int severity) +{ + /* + * See if it's a suppressed warning. + */ + return ((severity & ERR_MASK) == ERR_WARNING && + (severity & ERR_WARN_MASK) != 0 && + suppressed[(severity & ERR_WARN_MASK) >> ERR_WARN_SHR]) || + /* + * See if it's a pass-one only warning and we're not in pass one. + */ + ((severity & ERR_PASS1) && pass0 == 2); +} + +/** + * common error reporting + * This is the common back end of the error reporting schemes currently + * implemented. It prints the nature of the warning and then the + * specific error message to error_file and may or may not return. It + * doesn't return if the error severity is a "panic" or "debug" type. + * + * @param severity the severity of the warning or error + * @param fmt the printf style format string + */ +static void report_error_common(int severity, const char *fmt, + va_list args) +{ + switch (severity & ERR_MASK) { + case ERR_WARNING: + fputs("warning: ", error_file); + break; + case ERR_NONFATAL: + fputs("error: ", error_file); + break; + case ERR_FATAL: + fputs("fatal: ", error_file); + break; + case ERR_PANIC: + fputs("panic: ", error_file); + break; + case ERR_DEBUG: + fputs("debug: ", error_file); + break; + } + + vfprintf(error_file, fmt, args); + fputc('\n', error_file); + + if (severity & ERR_USAGE) + want_usage = TRUE; + + switch (severity & ERR_MASK) { + case ERR_WARNING: + case ERR_DEBUG: + /* no further action, by definition */ + break; + case ERR_NONFATAL: + /* hack enables listing(!) on errors */ + terminate_after_phase = TRUE; + break; + case ERR_FATAL: + if (ofile) { + fclose(ofile); + remove(outname); + } + if (want_usage) + usage(); + exit(1); /* instantly die */ + break; /* placate silly compilers */ + case ERR_PANIC: + fflush(NULL); + /* abort(); *//* halt, catch fire, and dump core */ + exit(3); + break; + } +} + +static void usage(void) +{ + fputs("type `nasm -h' for help\n", error_file); +} + +static void register_output_formats(void) +{ + ofmt = ofmt_register(report_error); +} + +#define BUF_DELTA 512 + +static FILE *no_pp_fp; +static efunc no_pp_err; +static ListGen *no_pp_list; +static long no_pp_lineinc; + +static void no_pp_reset(char *file, int pass, efunc error, evalfunc eval, + ListGen * listgen) +{ + src_set_fname(nasm_strdup(file)); + src_set_linnum(0); + no_pp_lineinc = 1; + no_pp_err = error; + no_pp_fp = fopen(file, "r"); + if (!no_pp_fp) + no_pp_err(ERR_FATAL | ERR_NOFILE, + "unable to open input file `%s'", file); + no_pp_list = listgen; + (void)pass; /* placate compilers */ + (void)eval; /* placate compilers */ +} + +static char *no_pp_getline(void) +{ + char *buffer, *p, *q; + int bufsize; + + bufsize = BUF_DELTA; + buffer = nasm_malloc(BUF_DELTA); + src_set_linnum(src_get_linnum() + no_pp_lineinc); + + while (1) { /* Loop to handle %line */ + + p = buffer; + while (1) { /* Loop to handle long lines */ + q = fgets(p, bufsize - (p - buffer), no_pp_fp); + if (!q) + break; + p += strlen(p); + if (p > buffer && p[-1] == '\n') + break; + if (p - buffer > bufsize - 10) { + int offset; + offset = p - buffer; + bufsize += BUF_DELTA; + buffer = nasm_realloc(buffer, bufsize); + p = buffer + offset; + } + } + + if (!q && p == buffer) { + nasm_free(buffer); + return NULL; + } + + /* + * Play safe: remove CRs, LFs and any spurious ^Zs, if any of + * them are present at the end of the line. + */ + buffer[strcspn(buffer, "\r\n\032")] = '\0'; + + if (!strncmp(buffer, "%line", 5)) { + long ln; + int li; + char *nm = nasm_malloc(strlen(buffer)); + if (sscanf(buffer + 5, "%ld+%d %s", &ln, &li, nm) == 3) { + nasm_free(src_set_fname(nm)); + src_set_linnum(ln); + no_pp_lineinc = li; + continue; + } + nasm_free(nm); + } + break; + } + + no_pp_list->line(LIST_READ, buffer); + + return buffer; +} + +static void no_pp_cleanup(int pass) +{ + fclose(no_pp_fp); +} + +static unsigned long get_cpu(char *value) +{ + + if (!strcmp(value, "8086")) + return IF_8086; + if (!strcmp(value, "186")) + return IF_186; + if (!strcmp(value, "286")) + return IF_286; + if (!strcmp(value, "386")) + return IF_386; + if (!strcmp(value, "486")) + return IF_486; + if (!strcmp(value, "586") || !nasm_stricmp(value, "pentium")) + return IF_PENT; + if (!strcmp(value, "686") || + !nasm_stricmp(value, "ppro") || + !nasm_stricmp(value, "pentiumpro") || !nasm_stricmp(value, "p2")) + return IF_P6; + if (!nasm_stricmp(value, "p3") || !nasm_stricmp(value, "katmai")) + return IF_KATMAI; + if (!nasm_stricmp(value, "p4") || /* is this right? -- jrc */ + !nasm_stricmp(value, "willamette")) + return IF_WILLAMETTE; + if (!nasm_stricmp(value, "prescott")) + return IF_PRESCOTT; + if (!nasm_stricmp(value, "ia64") || + !nasm_stricmp(value, "ia-64") || + !nasm_stricmp(value, "itanium") || + !nasm_stricmp(value, "itanic") || !nasm_stricmp(value, "merced")) + return IF_IA64; + + report_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL, + "unknown 'cpu' type"); + + return IF_PLEVEL; /* the maximum level */ +} + +static int get_bits(char *value) +{ + int i; + + if ((i = atoi(value)) == 16) + return i; /* set for a 16-bit segment */ + else if (i == 32) { + if (cpu < IF_386) { + report_error(ERR_NONFATAL, + "cannot specify 32-bit segment on processor below a 386"); + i = 16; + } + } else { + report_error(pass0 < 2 ? ERR_NONFATAL : ERR_FATAL, + "`%s' is not a valid segment size; must be 16 or 32", + value); + i = 16; + } + return i; +} + +/* end of nasm.c */ diff --git a/nasm.h b/nasm.h index 3efb1e48..35f6d39c 100644 --- a/nasm.h +++ b/nasm.h @@ -12,21 +12,21 @@ #define NASM_NASM_H #include -#include "version.h" /* generated NASM version macros */ +#include "version.h" /* generated NASM version macros */ #ifndef NULL #define NULL 0 #endif #ifndef FALSE -#define FALSE 0 /* comes in handy */ +#define FALSE 0 /* comes in handy */ #endif #ifndef TRUE #define TRUE 1 #endif -#define NO_SEG -1L /* null segment value */ -#define SEG_ABS 0x40000000L /* mask for far-absolute segments */ +#define NO_SEG -1L /* null segment value */ +#define SEG_ABS 0x40000000L /* mask for far-absolute segments */ #ifndef FILENAME_MAX #define FILENAME_MAX 256 @@ -73,31 +73,31 @@ typedef void (*efunc) (int severity, const char *fmt, ...); * argument to an efunc. */ -#define ERR_DEBUG 0x00000008 /* put out debugging message */ -#define ERR_WARNING 0x00000000 /* warn only: no further action */ -#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ -#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ -#define ERR_PANIC 0x00000003 /* internal error: panic instantly - * and dump core for reference */ -#define ERR_MASK 0x0000000F /* mask off the above codes */ -#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ -#define ERR_USAGE 0x00000020 /* print a usage message */ -#define ERR_PASS1 0x00000040 /* only print this error on pass one */ +#define ERR_DEBUG 0x00000008 /* put out debugging message */ +#define ERR_WARNING 0x00000000 /* warn only: no further action */ +#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ +#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ +#define ERR_PANIC 0x00000003 /* internal error: panic instantly + * and dump core for reference */ +#define ERR_MASK 0x0000000F /* mask off the above codes */ +#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ +#define ERR_USAGE 0x00000020 /* print a usage message */ +#define ERR_PASS1 0x00000040 /* only print this error on pass one */ /* * These codes define specific types of suppressible warning. */ -#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ -#define ERR_WARN_SHR 8 /* how far to shift right */ +#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ +#define ERR_WARN_SHR 8 /* how far to shift right */ -#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ -#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ -#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and - * alone on line) */ -#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ +#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ +#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ +#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and + * alone on line) */ +#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ #define ERR_WARN_GNUELF 0x00000500 /* using GNU ELF extensions */ -#define ERR_WARN_MAX 5 /* the highest numbered one */ +#define ERR_WARN_MAX 5 /* the highest numbered one */ /* * ----------------------- @@ -116,9 +116,9 @@ typedef int (*lfunc) (char *label, long *segment, long *offset); * should affect the local-label system), or something odder like * an EQU or a segment-base symbol, which shouldn't. */ -typedef void (*ldfunc) (char *label, long segment, long offset, char *special, - int is_norm, int isextrn, struct ofmt *ofmt, - efunc error); +typedef void (*ldfunc) (char *label, long segment, long offset, + char *special, int is_norm, int isextrn, + struct ofmt * ofmt, efunc error); /* * List-file generators should look like this: @@ -193,33 +193,33 @@ struct tokenval { long t_integer, t_inttwo; char *t_charptr; }; -typedef int (*scanner) (void *private_data, struct tokenval *tv); +typedef int (*scanner) (void *private_data, struct tokenval * tv); /* * Token types returned by the scanner, in addition to ordinary * ASCII character values, and zero for end-of-string. */ -enum { /* token types, other than chars */ - TOKEN_INVALID = -1, /* a placeholder value */ - TOKEN_EOS = 0, /* end of string */ - TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */ - TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */ - TOKEN_ERRNUM, /* numeric constant with error in */ - TOKEN_HERE, TOKEN_BASE, /* $ and $$ */ - TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */ - TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ - TOKEN_SHL, TOKEN_SHR, /* << and >> */ - TOKEN_SDIV, TOKEN_SMOD, /* // and %% */ - TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */ - TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */ - TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */ - TOKEN_FLOAT /* floating-point constant */ +enum { /* token types, other than chars */ + TOKEN_INVALID = -1, /* a placeholder value */ + TOKEN_EOS = 0, /* end of string */ + TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */ + TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */ + TOKEN_ERRNUM, /* numeric constant with error in */ + TOKEN_HERE, TOKEN_BASE, /* $ and $$ */ + TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */ + TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ + TOKEN_SHL, TOKEN_SHR, /* << and >> */ + TOKEN_SDIV, TOKEN_SMOD, /* // and %% */ + TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */ + TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */ + TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */ + TOKEN_FLOAT /* floating-point constant */ }; typedef struct { long segment; long offset; - int known; + int known; } loc_t; /* @@ -235,8 +235,8 @@ typedef struct { * `value' field of zero is insignificant. */ typedef struct { - long type; /* a register, or EXPR_xxx */ - long value; /* must be >= 32 bits */ + long type; /* a register, or EXPR_xxx */ + long value; /* must be >= 32 bits */ } expr; /* @@ -274,9 +274,9 @@ struct eval_hints { * the base register in complex effective addresses. */ #define CRITICAL 0x100 -typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, - int *fwref, int critical, efunc error, - struct eval_hints *hints); +typedef expr *(*evalfunc) (scanner sc, void *scprivate, + struct tokenval * tv, int *fwref, int critical, + efunc error, struct eval_hints * hints); /* * Special values for expr->type. ASSUMPTION MADE HERE: the number @@ -286,7 +286,7 @@ typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, */ #define EXPR_REG_START 1 #define EXPR_REG_END 124 -#define EXPR_UNKNOWN 125L /* for forward references */ +#define EXPR_UNKNOWN 125L /* for forward references */ #define EXPR_SIMPLE 126L #define EXPR_WRT 127L #define EXPR_SEGBASE 128L @@ -371,71 +371,71 @@ enum { #define BITS8 0x00000001L #define BITS16 0x00000002L #define BITS32 0x00000004L -#define BITS64 0x00000008L /* FPU only */ -#define BITS80 0x00000010L /* FPU only */ -#define FAR 0x00000020L /* grotty: this means 16:16 or */ - /* 16:32, like in CALL/JMP */ +#define BITS64 0x00000008L /* FPU only */ +#define BITS80 0x00000010L /* FPU only */ +#define FAR 0x00000020L /* grotty: this means 16:16 or */ + /* 16:32, like in CALL/JMP */ #define NEAR 0x00000040L -#define SHORT 0x00000080L /* and this means what it says :) */ +#define SHORT 0x00000080L /* and this means what it says :) */ -#define SIZE_MASK 0x000000FFL /* all the size attributes */ +#define SIZE_MASK 0x000000FFL /* all the size attributes */ #define NON_SIZE (~SIZE_MASK) -#define TO 0x00000100L /* reverse effect in FADD, FSUB &c */ -#define COLON 0x00000200L /* operand is followed by a colon */ -#define STRICT 0x00000400L /* do not optimize this operand */ +#define TO 0x00000100L /* reverse effect in FADD, FSUB &c */ +#define COLON 0x00000200L /* operand is followed by a colon */ +#define STRICT 0x00000400L /* do not optimize this operand */ /* type of operand: memory reference, register, etc. */ #define MEMORY 0x00204000L -#define REGISTER 0x00001000L /* register number in 'basereg' */ +#define REGISTER 0x00001000L /* register number in 'basereg' */ #define IMMEDIATE 0x00002000L -#define REGMEM 0x00200000L /* for r/m, ie EA, operands */ -#define REGNORM 0x00201000L /* 'normal' reg, qualifies as EA */ +#define REGMEM 0x00200000L /* for r/m, ie EA, operands */ +#define REGNORM 0x00201000L /* 'normal' reg, qualifies as EA */ #define REG8 0x00201001L #define REG16 0x00201002L #define REG32 0x00201004L -#define MMXREG 0x00201008L /* MMX registers */ -#define XMMREG 0x00201010L /* XMM Katmai reg */ -#define FPUREG 0x01000000L /* floating point stack registers */ -#define FPU0 0x01000800L /* FPU stack register zero */ +#define MMXREG 0x00201008L /* MMX registers */ +#define XMMREG 0x00201010L /* XMM Katmai reg */ +#define FPUREG 0x01000000L /* floating point stack registers */ +#define FPU0 0x01000800L /* FPU stack register zero */ /* special register operands: these may be treated differently */ -#define REG_SMASK 0x00070000L /* a mask for the following */ -#define REG_ACCUM 0x00211000L /* accumulator: AL, AX or EAX */ -#define REG_AL 0x00211001L /* REG_ACCUM | BITSxx */ -#define REG_AX 0x00211002L /* ditto */ -#define REG_EAX 0x00211004L /* and again */ -#define REG_COUNT 0x00221000L /* counter: CL, CX or ECX */ -#define REG_CL 0x00221001L /* REG_COUNT | BITSxx */ -#define REG_CX 0x00221002L /* ditto */ -#define REG_ECX 0x00221004L /* another one */ +#define REG_SMASK 0x00070000L /* a mask for the following */ +#define REG_ACCUM 0x00211000L /* accumulator: AL, AX or EAX */ +#define REG_AL 0x00211001L /* REG_ACCUM | BITSxx */ +#define REG_AX 0x00211002L /* ditto */ +#define REG_EAX 0x00211004L /* and again */ +#define REG_COUNT 0x00221000L /* counter: CL, CX or ECX */ +#define REG_CL 0x00221001L /* REG_COUNT | BITSxx */ +#define REG_CX 0x00221002L /* ditto */ +#define REG_ECX 0x00221004L /* another one */ #define REG_DL 0x00241001L #define REG_DX 0x00241002L #define REG_EDX 0x00241004L -#define REG_SREG 0x00081002L /* any segment register */ -#define REG_CS 0x01081002L /* CS */ -#define REG_DESS 0x02081002L /* DS, ES, SS (non-CS 86 registers) */ -#define REG_FSGS 0x04081002L /* FS, GS (386 extended registers) */ -#define REG_SEG67 0x08081002L /* Non-implemented segment registers */ -#define REG_CDT 0x00101004L /* CRn, DRn and TRn */ -#define REG_CREG 0x08101004L /* CRn */ -#define REG_DREG 0x10101004L /* DRn */ -#define REG_TREG 0x20101004L /* TRn */ +#define REG_SREG 0x00081002L /* any segment register */ +#define REG_CS 0x01081002L /* CS */ +#define REG_DESS 0x02081002L /* DS, ES, SS (non-CS 86 registers) */ +#define REG_FSGS 0x04081002L /* FS, GS (386 extended registers) */ +#define REG_SEG67 0x08081002L /* Non-implemented segment registers */ +#define REG_CDT 0x00101004L /* CRn, DRn and TRn */ +#define REG_CREG 0x08101004L /* CRn */ +#define REG_DREG 0x10101004L /* DRn */ +#define REG_TREG 0x20101004L /* TRn */ /* special type of EA */ -#define MEM_OFFS 0x00604000L /* simple [address] offset */ +#define MEM_OFFS 0x00604000L /* simple [address] offset */ /* special type of immediate operand */ -#define ONENESS 0x00800000L /* so UNITY == IMMEDIATE | ONENESS */ -#define UNITY 0x00802000L /* for shift/rotate instructions */ -#define BYTENESS 0x40000000L /* so SBYTE == IMMEDIATE | BYTENESS */ -#define SBYTE 0x40002000L /* for op r16/32,immediate instrs. */ - +#define ONENESS 0x00800000L /* so UNITY == IMMEDIATE | ONENESS */ +#define UNITY 0x00802000L /* for shift/rotate instructions */ +#define BYTENESS 0x40000000L /* so SBYTE == IMMEDIATE | BYTENESS */ +#define SBYTE 0x40002000L /* for op r16/32,immediate instrs. */ + /* Register names automatically generated from regs.dat */ #include "regs.h" -enum { /* condition code names */ +enum { /* condition code names */ C_A, C_AE, C_B, C_BE, C_C, C_E, C_G, C_GE, C_L, C_LE, C_NA, C_NAE, C_NB, C_NBE, C_NC, C_NE, C_NG, C_NGE, C_NL, C_NLE, C_NO, C_NP, C_NS, C_NZ, C_O, C_P, C_PE, C_PO, C_S, C_Z @@ -446,68 +446,68 @@ enum { /* condition code names */ * prefixes, we must ensure the enumerations for prefixes and * register names do not overlap. */ -enum { /* instruction prefixes */ +enum { /* instruction prefixes */ PREFIX_ENUM_START = REG_ENUM_LIMIT, P_A16 = PREFIX_ENUM_START, P_A32, P_LOCK, P_O16, P_O32, P_REP, P_REPE, P_REPNE, P_REPNZ, P_REPZ, P_TIMES }; -enum { /* extended operand types */ +enum { /* extended operand types */ EOT_NOTHING, EOT_DB_STRING, EOT_DB_NUMBER }; -enum { /* special EA flags */ - EAF_BYTEOFFS = 1, /* force offset part to byte size */ - EAF_WORDOFFS = 2, /* force offset part to [d]word size */ - EAF_TIMESTWO = 4 /* really do EAX*2 not EAX+EAX */ +enum { /* special EA flags */ + EAF_BYTEOFFS = 1, /* force offset part to byte size */ + EAF_WORDOFFS = 2, /* force offset part to [d]word size */ + EAF_TIMESTWO = 4 /* really do EAX*2 not EAX+EAX */ }; -enum { /* values for `hinttype' */ - EAH_NOHINT = 0, /* no hint at all - our discretion */ - EAH_MAKEBASE = 1, /* try to make given reg the base */ - EAH_NOTBASE = 2 /* try _not_ to make reg the base */ +enum { /* values for `hinttype' */ + EAH_NOHINT = 0, /* no hint at all - our discretion */ + EAH_MAKEBASE = 1, /* try to make given reg the base */ + EAH_NOTBASE = 2 /* try _not_ to make reg the base */ }; -typedef struct { /* operand to an instruction */ - long type; /* type of operand */ - int addr_size; /* 0 means default; 16; 32 */ - int basereg, indexreg, scale; /* registers and scale involved */ - int hintbase, hinttype; /* hint as to real base register */ - long segment; /* immediate segment, if needed */ - long offset; /* any immediate number */ - long wrt; /* segment base it's relative to */ - int eaflags; /* special EA flags */ - int opflags; /* see OPFLAG_* defines below */ +typedef struct { /* operand to an instruction */ + long type; /* type of operand */ + int addr_size; /* 0 means default; 16; 32 */ + int basereg, indexreg, scale; /* registers and scale involved */ + int hintbase, hinttype; /* hint as to real base register */ + long segment; /* immediate segment, if needed */ + long offset; /* any immediate number */ + long wrt; /* segment base it's relative to */ + int eaflags; /* special EA flags */ + int opflags; /* see OPFLAG_* defines below */ } operand; -#define OPFLAG_FORWARD 1 /* operand is a forward reference */ -#define OPFLAG_EXTERN 2 /* operand is an external reference */ - -typedef struct extop { /* extended operand */ - struct extop *next; /* linked list */ - long type; /* defined above */ - char *stringval; /* if it's a string, then here it is */ - int stringlen; /* ... and here's how long it is */ - long segment; /* if it's a number/address, then... */ - long offset; /* ... it's given here ... */ - long wrt; /* ... and here */ +#define OPFLAG_FORWARD 1 /* operand is a forward reference */ +#define OPFLAG_EXTERN 2 /* operand is an external reference */ + +typedef struct extop { /* extended operand */ + struct extop *next; /* linked list */ + long type; /* defined above */ + char *stringval; /* if it's a string, then here it is */ + int stringlen; /* ... and here's how long it is */ + long segment; /* if it's a number/address, then... */ + long offset; /* ... it's given here ... */ + long wrt; /* ... and here */ } extop; #define MAXPREFIX 4 -typedef struct { /* an instruction itself */ - char *label; /* the label defined, or NULL */ - int prefixes[MAXPREFIX]; /* instruction prefixes, if any */ - int nprefix; /* number of entries in above */ - int opcode; /* the opcode - not just the string */ - int condition; /* the condition code, if Jcc/SETcc */ - int operands; /* how many operands? 0-3 - * (more if db et al) */ - operand oprs[3]; /* the operands, defined as above */ - extop *eops; /* extended operands */ - int eops_float; /* true if DD and floating */ - long times; /* repeat count (TIMES prefix) */ - int forw_ref; /* is there a forward reference? */ +typedef struct { /* an instruction itself */ + char *label; /* the label defined, or NULL */ + int prefixes[MAXPREFIX]; /* instruction prefixes, if any */ + int nprefix; /* number of entries in above */ + int opcode; /* the opcode - not just the string */ + int condition; /* the condition code, if Jcc/SETcc */ + int operands; /* how many operands? 0-3 + * (more if db et al) */ + operand oprs[3]; /* the operands, defined as above */ + extop *eops; /* extended operands */ + int eops_float; /* true if DD and floating */ + long times; /* repeat count (TIMES prefix) */ + int forw_ref; /* is there a forward reference? */ } insn; enum geninfo { GI_SWITCH }; @@ -567,7 +567,7 @@ struct ofmt { * to the label manager and expression evaluator if necessary. * It also gives it a chance to do other initialisation. */ - void (*init) (FILE *fp, efunc error, ldfunc ldef, evalfunc eval); + void (*init) (FILE * fp, efunc error, ldfunc ldef, evalfunc eval); /* * This procedure is called to pass generic information to the @@ -576,7 +576,7 @@ struct ofmt { * and the second parameter gives the value. This function returns * 1 if recognized, 0 if unrecognized */ - int (*setinfo)(enum geninfo type, char **string); + int (*setinfo) (enum geninfo type, char **string); /* * This procedure is called by assemble() to write actual @@ -588,7 +588,7 @@ struct ofmt { * usually the size as well: its contents are described below. */ void (*output) (long segto, const void *data, unsigned long type, - long segment, long wrt); + long segment, long wrt); /* * This procedure is called once for every symbol defined in @@ -619,7 +619,7 @@ struct ofmt { * be obvious to the output format from the other parameters. */ void (*symdef) (char *name, long segment, long offset, int is_global, - char *special); + char *special); /* * This procedure is called when the source code requests a @@ -734,7 +734,7 @@ struct ofmt { */ struct dfmt { - + /* * This is a short (one-liner) description of the type of * output generated by the driver. @@ -746,19 +746,18 @@ struct dfmt { */ const char *shortname; - /* * init - called initially to set up local pointer to object format, * void pointer to implementation defined data, file pointer (which * probably won't be used, but who knows?), and error function. */ - void (*init) (struct ofmt * of, void * id, FILE * fp, efunc error); + void (*init) (struct ofmt * of, void *id, FILE * fp, efunc error); /* * linenum - called any time there is output with a change of * line number or file. */ - void (*linenum) (const char * filename, long linenumber, long segto); + void (*linenum) (const char *filename, long linenumber, long segto); /* * debug_deflabel - called whenever a label is defined. Parameters @@ -766,8 +765,8 @@ struct dfmt { * would be called before the output format version. */ - void (*debug_deflabel) (char * name, long segment, long offset, - int is_global, char * special); + void (*debug_deflabel) (char *name, long segment, long offset, + int is_global, char *special); /* * debug_directive - called whenever a DEBUG directive other than 'LINE' * is encountered. 'directive' contains the first parameter to the @@ -776,7 +775,7 @@ struct dfmt { * function with 'directive' equal to "VAR" and 'params' equal to * "_somevar:int". */ - void (*debug_directive) (const char * directive, const char * params); + void (*debug_directive) (const char *directive, const char *params); /* * typevalue - called whenever the assembler wishes to register a type @@ -846,7 +845,7 @@ extern int tasm_compatible_mode; * 2 = pass 2 */ -extern int pass0; /* this is globally known */ +extern int pass0; /* this is globally known */ extern int optimizing; #endif diff --git a/nasmlib.c b/nasmlib.c dissimilarity index 61% index e63b573e..535ade93 100644 --- a/nasmlib.c +++ b/nasmlib.c @@ -1,1120 +1,1139 @@ -/* nasmlib.c library routines for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "insns.h" /* For MAX_KEYWORD */ - -static efunc nasm_malloc_error; - -#ifdef LOGALLOC -static FILE *logfp; -#endif - -void nasm_set_malloc_error (efunc error) -{ - nasm_malloc_error = error; -#ifdef LOGALLOC - logfp = fopen ("malloc.log", "w"); - setvbuf (logfp, NULL, _IOLBF, BUFSIZ); - fprintf (logfp, "null pointer is %p\n", NULL); -#endif -} - -#ifdef LOGALLOC -void *nasm_malloc_log (char *file, int line, size_t size) -#else -void *nasm_malloc (size_t size) -#endif -{ - void *p = malloc(size); - if (!p) - nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory"); -#ifdef LOGALLOC - else - fprintf(logfp, "%s %d malloc(%ld) returns %p\n", - file, line, (long)size, p); -#endif - return p; -} - -#ifdef LOGALLOC -void *nasm_realloc_log (char *file, int line, void *q, size_t size) -#else -void *nasm_realloc (void *q, size_t size) -#endif -{ - void *p = q ? realloc(q, size) : malloc(size); - if (!p) - nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory"); -#ifdef LOGALLOC - else if (q) - fprintf(logfp, "%s %d realloc(%p,%ld) returns %p\n", - file, line, q, (long)size, p); - else - fprintf(logfp, "%s %d malloc(%ld) returns %p\n", - file, line, (long)size, p); -#endif - return p; -} - -#ifdef LOGALLOC -void nasm_free_log (char *file, int line, void *q) -#else -void nasm_free (void *q) -#endif -{ - if (q) { - free (q); -#ifdef LOGALLOC - fprintf(logfp, "%s %d free(%p)\n", - file, line, q); -#endif - } -} - -#ifdef LOGALLOC -char *nasm_strdup_log (char *file, int line, const char *s) -#else -char *nasm_strdup (const char *s) -#endif -{ - char *p; - int size = strlen(s)+1; - - p = malloc(size); - if (!p) - nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory"); -#ifdef LOGALLOC - else - fprintf(logfp, "%s %d strdup(%ld) returns %p\n", - file, line, (long)size, p); -#endif - strcpy (p, s); - return p; -} - -#ifdef LOGALLOC -char *nasm_strndup_log (char *file, int line, char *s, size_t len) -#else -char *nasm_strndup (char *s, size_t len) -#endif -{ - char *p; - int size = len+1; - - p = malloc(size); - if (!p) - nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory"); -#ifdef LOGALLOC - else - fprintf(logfp, "%s %d strndup(%ld) returns %p\n", - file, line, (long)size, p); -#endif - strncpy (p, s, len); - p[len] = '\0'; - return p; -} - -#if !defined(stricmp) && !defined(strcasecmp) -int nasm_stricmp (const char *s1, const char *s2) -{ - while (*s1 && tolower(*s1) == tolower(*s2)) - s1++, s2++; - if (!*s1 && !*s2) - return 0; - else if (tolower(*s1) < tolower(*s2)) - return -1; - else - return 1; -} -#endif - -#if !defined(strnicmp) && !defined(strncasecmp) -int nasm_strnicmp (const char *s1, const char *s2, int n) -{ - while (n > 0 && *s1 && tolower(*s1) == tolower(*s2)) - s1++, s2++, n--; - if ((!*s1 && !*s2) || n==0) - return 0; - else if (tolower(*s1) < tolower(*s2)) - return -1; - else - return 1; -} -#endif - -#define lib_isnumchar(c) ( isalnum(c) || (c) == '$') -#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') - -long readnum (char *str, int *error) -{ - char *r = str, *q; - long radix; - unsigned long result, checklimit; - int digit, last; - int warn = FALSE; - int sign = 1; - - *error = FALSE; - - while (isspace(*r)) r++; /* find start of number */ - - /* - * If the number came from make_tok_num (as a result of an %assign), it - * might have a '-' built into it (rather than in a preceeding token). - */ - if (*r == '-') - { - r++; - sign = -1; - } - - q = r; - - while (lib_isnumchar(*q)) q++; /* find end of number */ - - /* - * If it begins 0x, 0X or $, or ends in H, it's in hex. if it - * ends in Q, it's octal. if it ends in B, it's binary. - * Otherwise, it's ordinary decimal. - */ - if (*r=='0' && (r[1]=='x' || r[1]=='X')) - radix = 16, r += 2; - else if (*r=='$') - radix = 16, r++; - else if (q[-1]=='H' || q[-1]=='h') - radix = 16 , q--; - else if (q[-1]=='Q' || q[-1]=='q' || q[-1]=='O' || q[-1]=='o') - radix = 8 , q--; - else if (q[-1]=='B' || q[-1]=='b') - radix = 2 , q--; - else - radix = 10; - - /* - * If this number has been found for us by something other than - * the ordinary scanners, then it might be malformed by having - * nothing between the prefix and the suffix. Check this case - * now. - */ - if (r >= q) { - *error = TRUE; - return 0; - } - - /* - * `checklimit' must be 2**32 / radix. We can't do that in - * 32-bit arithmetic, which we're (probably) using, so we - * cheat: since we know that all radices we use are even, we - * can divide 2**31 by radix/2 instead. - */ - checklimit = 0x80000000UL / (radix>>1); - - /* - * Calculate the highest allowable value for the last digit - * of a 32 bit constant... in radix 10, it is 6, otherwise it is 0 - */ - last = (radix == 10 ? 6 : 0); - - result = 0; - while (*r && r < q) { - if (*r<'0' || (*r>'9' && *r<'A') || (digit = numvalue(*r)) >= radix) - { - *error = TRUE; - return 0; - } - if (result > checklimit || - (result == checklimit && digit >= last)) - { - warn = TRUE; - } - - result = radix * result + digit; - r++; - } - - if (warn) - nasm_malloc_error (ERR_WARNING | ERR_PASS1 | ERR_WARN_NOV, - "numeric constant %s does not fit in 32 bits", - str); - - return result*sign; -} - -long readstrnum (char *str, int length, int *warn) -{ - long charconst = 0; - int i; - - *warn = FALSE; - - str += length; - for (i=0; i> 8) & 255), fp); -} - -void fwritelong (long data, FILE *fp) -{ - fputc ((int) (data & 255), fp); - fputc ((int) ((data >> 8) & 255), fp); - fputc ((int) ((data >> 16) & 255), fp); - fputc ((int) ((data >> 24) & 255), fp); -} - -void standard_extension (char *inname, char *outname, char *extension, - efunc error) -{ - char *p, *q; - - if (*outname) /* file name already exists, */ - return; /* so do nothing */ - q = inname; - p = outname; - while (*q) *p++ = *q++; /* copy, and find end of string */ - *p = '\0'; /* terminate it */ - while (p > outname && *--p != '.');/* find final period (or whatever) */ - if (*p != '.') while (*p) p++; /* go back to end if none found */ - if (!strcmp(p, extension)) { /* is the extension already there? */ - if (*extension) - error(ERR_WARNING | ERR_NOFILE, - "file name already ends in `%s': " - "output will be in `nasm.out'", - extension); - else - error(ERR_WARNING | ERR_NOFILE, - "file name already has no extension: " - "output will be in `nasm.out'"); - strcpy(outname, "nasm.out"); - } else - strcpy(p, extension); -} - -#define LEAFSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_LEAF)) -#define BRANCHSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_BRANCH)) - -#define LAYERSIZ(r) ( (r)->layers==0 ? RAA_BLKSIZE : RAA_LAYERSIZE ) - -static struct RAA *real_raa_init (int layers) -{ - struct RAA *r; - int i; - - if (layers == 0) { - r = nasm_malloc (LEAFSIZ); - r->layers = 0; - memset (r->u.l.data, 0, sizeof(r->u.l.data)); - r->stepsize = 1L; - } else { - r = nasm_malloc (BRANCHSIZ); - r->layers = layers; - for ( i = 0 ; i < RAA_LAYERSIZE ; i++ ) - r->u.b.data[i] = NULL; - r->stepsize = RAA_BLKSIZE; - while (--layers) - r->stepsize *= RAA_LAYERSIZE; - } - return r; -} - -struct RAA *raa_init (void) -{ - return real_raa_init (0); -} - -void raa_free (struct RAA *r) -{ - if (r->layers == 0) - nasm_free (r); - else { - struct RAA **p; - for (p = r->u.b.data; p - r->u.b.data < RAA_LAYERSIZE; p++) - if (*p) - raa_free (*p); - } -} - -long raa_read (struct RAA *r, long posn) -{ - if (posn >= r->stepsize * LAYERSIZ(r)) - return 0; /* Return 0 for undefined entries */ - while (r->layers > 0) { - ldiv_t l; - l = ldiv (posn, r->stepsize); - r = r->u.b.data[l.quot]; - posn = l.rem; - if (!r) - return 0; /* Return 0 for undefined entries */ - } - return r->u.l.data[posn]; -} - -struct RAA *raa_write (struct RAA *r, long posn, long value) -{ - struct RAA *result; - - if (posn < 0) - nasm_malloc_error (ERR_PANIC, "negative position in raa_write"); - - while (r->stepsize * LAYERSIZ(r) <= posn) { - /* - * Must add a layer. - */ - struct RAA *s; - int i; - - s = nasm_malloc (BRANCHSIZ); - for ( i = 0 ; i < RAA_LAYERSIZE ; i++ ) - s->u.b.data[i] = NULL; - s->layers = r->layers + 1; - s->stepsize = LAYERSIZ(r) * r->stepsize; - s->u.b.data[0] = r; - r = s; - } - - result = r; - - while (r->layers > 0) { - ldiv_t l; - struct RAA **s; - l = ldiv (posn, r->stepsize); - s = &r->u.b.data[l.quot]; - if (!*s) - *s = real_raa_init (r->layers - 1); - r = *s; - posn = l.rem; - } - - r->u.l.data[posn] = value; - - return result; -} - -#define SAA_MAXLEN 8192 - -struct SAA *saa_init (long elem_len) -{ - struct SAA *s; - - if (elem_len > SAA_MAXLEN) - nasm_malloc_error (ERR_PANIC | ERR_NOFILE, "SAA with huge elements"); - - s = nasm_malloc (sizeof(struct SAA)); - s->posn = s->start = 0L; - s->elem_len = elem_len; - s->length = SAA_MAXLEN - (SAA_MAXLEN % elem_len); - s->data = nasm_malloc (s->length); - s->next = NULL; - s->end = s; - - return s; -} - -void saa_free (struct SAA *s) -{ - struct SAA *t; - - while (s) { - t = s->next; - nasm_free (s->data); - nasm_free (s); - s = t; - } -} - -void *saa_wstruct (struct SAA *s) -{ - void *p; - - if (s->end->length - s->end->posn < s->elem_len) { - s->end->next = nasm_malloc (sizeof(struct SAA)); - s->end->next->start = s->end->start + s->end->posn; - s->end = s->end->next; - s->end->length = s->length; - s->end->next = NULL; - s->end->posn = 0L; - s->end->data = nasm_malloc (s->length); - } - - p = s->end->data + s->end->posn; - s->end->posn += s->elem_len; - return p; -} - -void saa_wbytes (struct SAA *s, const void *data, long len) -{ - const char *d = data; - - while (len > 0) { - long l = s->end->length - s->end->posn; - if (l > len) - l = len; - if (l > 0) { - if (d) { - memcpy (s->end->data + s->end->posn, d, l); - d += l; - } else - memset (s->end->data + s->end->posn, 0, l); - s->end->posn += l; - len -= l; - } - if (len > 0) { - s->end->next = nasm_malloc (sizeof(struct SAA)); - s->end->next->start = s->end->start + s->end->posn; - s->end = s->end->next; - s->end->length = s->length; - s->end->next = NULL; - s->end->posn = 0L; - s->end->data = nasm_malloc (s->length); - } - } -} - -void saa_rewind (struct SAA *s) -{ - s->rptr = s; - s->rpos = 0L; -} - -void *saa_rstruct (struct SAA *s) -{ - void *p; - - if (!s->rptr) - return NULL; - - if (s->rptr->posn - s->rpos < s->elem_len) { - s->rptr = s->rptr->next; - if (!s->rptr) - return NULL; /* end of array */ - s->rpos = 0L; - } - - p = s->rptr->data + s->rpos; - s->rpos += s->elem_len; - return p; -} - -void *saa_rbytes (struct SAA *s, long *len) -{ - void *p; - - if (!s->rptr) - return NULL; - - p = s->rptr->data + s->rpos; - *len = s->rptr->posn - s->rpos; - s->rptr = s->rptr->next; - s->rpos = 0L; - return p; -} - -void saa_rnbytes (struct SAA *s, void *data, long len) -{ - char *d = data; - - while (len > 0) { - long l; - - if (!s->rptr) - return; - - l = s->rptr->posn - s->rpos; - if (l > len) - l = len; - if (l > 0) { - memcpy (d, s->rptr->data + s->rpos, l); - d += l; - s->rpos += l; - len -= l; - } - if (len > 0) { - s->rptr = s->rptr->next; - s->rpos = 0L; - } - } -} - -void saa_fread (struct SAA *s, long posn, void *data, long len) -{ - struct SAA *p; - long pos; - char *cdata = data; - - if (!s->rptr || posn < s->rptr->start) - saa_rewind (s); - p = s->rptr; - while (posn >= p->start + p->posn) { - p = p->next; - if (!p) - return; /* what else can we do?! */ - } - - pos = posn - p->start; - while (len) { - long l = p->posn - pos; - if (l > len) - l = len; - memcpy (cdata, p->data+pos, l); - len -= l; - cdata += l; - p = p->next; - if (!p) - return; - pos = 0L; - } - s->rptr = p; -} - -void saa_fwrite (struct SAA *s, long posn, void *data, long len) -{ - struct SAA *p; - long pos; - char *cdata = data; - - if (!s->rptr || posn < s->rptr->start) - saa_rewind (s); - p = s->rptr; - while (posn >= p->start + p->posn) { - p = p->next; - if (!p) - return; /* what else can we do?! */ - } - - pos = posn - p->start; - while (len) { - long l = p->posn - pos; - if (l > len) - l = len; - memcpy (p->data+pos, cdata, l); - len -= l; - cdata += l; - p = p->next; - if (!p) - return; - pos = 0L; - } - s->rptr = p; -} - -void saa_fpwrite (struct SAA *s, FILE *fp) -{ - char *data; - long len; - - saa_rewind (s); - while ( (data = saa_rbytes (s, &len)) ) - fwrite (data, 1, len, fp); -} - -/* - * Register, instruction, condition-code and prefix keywords used - * by the scanner. - */ -#include "names.c" -static const char *special_names[] = { - "byte", "dword", "far", "long", "near", "nosplit", "qword", - "short", "strict", "to", "tword", "word" -}; -static const char *prefix_names[] = { - "a16", "a32", "lock", "o16", "o32", "rep", "repe", "repne", - "repnz", "repz", "times" -}; - - -/* - * Standard scanner routine used by parser.c and some output - * formats. It keeps a succession of temporary-storage strings in - * stdscan_tempstorage, which can be cleared using stdscan_reset. - */ -static char **stdscan_tempstorage = NULL; -static int stdscan_tempsize = 0, stdscan_templen = 0; -#define STDSCAN_TEMP_DELTA 256 - -static void stdscan_pop(void) -{ - nasm_free (stdscan_tempstorage[--stdscan_templen]); -} - -void stdscan_reset(void) -{ - while (stdscan_templen > 0) - stdscan_pop(); -} - -/* - * Unimportant cleanup is done to avoid confusing people who are trying - * to debug real memory leaks - */ -void nasmlib_cleanup (void) -{ - stdscan_reset(); - nasm_free (stdscan_tempstorage); -} - -static char *stdscan_copy(char *p, int len) -{ - char *text; - - text = nasm_malloc(len+1); - strncpy (text, p, len); - text[len] = '\0'; - - if (stdscan_templen >= stdscan_tempsize) { - stdscan_tempsize += STDSCAN_TEMP_DELTA; - stdscan_tempstorage = nasm_realloc(stdscan_tempstorage, - stdscan_tempsize*sizeof(char *)); - } - stdscan_tempstorage[stdscan_templen++] = text; - - return text; -} - -char *stdscan_bufptr = NULL; -int stdscan (void *private_data, struct tokenval *tv) -{ - char ourcopy[MAX_KEYWORD+1], *r, *s; - - (void) private_data; /* Don't warn that this parameter is unused */ - - while (isspace(*stdscan_bufptr)) stdscan_bufptr++; - if (!*stdscan_bufptr) - return tv->t_type = 0; - - /* we have a token; either an id, a number or a char */ - if (isidstart(*stdscan_bufptr) || - (*stdscan_bufptr == '$' && isidstart(stdscan_bufptr[1]))) { - /* now we've got an identifier */ - int i; - int is_sym = FALSE; - - if (*stdscan_bufptr == '$') { - is_sym = TRUE; - stdscan_bufptr++; - } - - r = stdscan_bufptr++; - /* read the entire buffer to advance the buffer pointer but... */ - while (isidchar(*stdscan_bufptr)) stdscan_bufptr++; - - /* ... copy only up to IDLEN_MAX-1 characters */ - tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r < IDLEN_MAX ? - stdscan_bufptr - r : IDLEN_MAX - 1); - - if (is_sym || stdscan_bufptr-r > MAX_KEYWORD) - return tv->t_type = TOKEN_ID;/* bypass all other checks */ - - for (s=tv->t_charptr, r=ourcopy; *s; s++) - *r++ = tolower (*s); - *r = '\0'; - /* right, so we have an identifier sitting in temp storage. now, - * is it actually a register or instruction name, or what? */ - if ((tv->t_integer=bsi(ourcopy, reg_names, - elements(reg_names)))>=0) { - tv->t_integer += EXPR_REG_START; - return tv->t_type = TOKEN_REG; - } else if ((tv->t_integer=bsi(ourcopy, insn_names, - elements(insn_names)))>=0) { - return tv->t_type = TOKEN_INSN; - } - for (i=0; it_integer = ico[i]; - if ((tv->t_inttwo=bsi(p, conditions, - elements(conditions)))>=0) - return tv->t_type = TOKEN_INSN; - } - if ((tv->t_integer=bsi(ourcopy, prefix_names, - elements(prefix_names)))>=0) { - tv->t_integer += PREFIX_ENUM_START; - return tv->t_type = TOKEN_PREFIX; - } - if ((tv->t_integer=bsi(ourcopy, special_names, - elements(special_names)))>=0) - return tv->t_type = TOKEN_SPECIAL; - if (!nasm_stricmp(ourcopy, "seg")) - return tv->t_type = TOKEN_SEG; - if (!nasm_stricmp(ourcopy, "wrt")) - return tv->t_type = TOKEN_WRT; - return tv->t_type = TOKEN_ID; - } else if (*stdscan_bufptr == '$' && !isnumchar(stdscan_bufptr[1])) { - /* - * It's a $ sign with no following hex number; this must - * mean it's a Here token ($), evaluating to the current - * assembly location, or a Base token ($$), evaluating to - * the base of the current segment. - */ - stdscan_bufptr++; - if (*stdscan_bufptr == '$') { - stdscan_bufptr++; - return tv->t_type = TOKEN_BASE; - } - return tv->t_type = TOKEN_HERE; - } else if (isnumstart(*stdscan_bufptr)) { /* now we've got a number */ - int rn_error; - - r = stdscan_bufptr++; - while (isnumchar(*stdscan_bufptr)) - stdscan_bufptr++; - - if (*stdscan_bufptr == '.') { - /* - * a floating point constant - */ - stdscan_bufptr++; - while (isnumchar(*stdscan_bufptr) || - ((stdscan_bufptr[-1] == 'e' || stdscan_bufptr[-1] == 'E') - && (*stdscan_bufptr == '-' || *stdscan_bufptr == '+')) ) - { - stdscan_bufptr++; - } - tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r); - return tv->t_type = TOKEN_FLOAT; - } - r = stdscan_copy(r, stdscan_bufptr - r); - tv->t_integer = readnum(r, &rn_error); - stdscan_pop(); - if (rn_error) - return tv->t_type = TOKEN_ERRNUM;/* some malformation occurred */ - tv->t_charptr = NULL; - return tv->t_type = TOKEN_NUM; - } else if (*stdscan_bufptr == '\'' || - *stdscan_bufptr == '"') {/* a char constant */ - char quote = *stdscan_bufptr++, *r; - int rn_warn; - r = tv->t_charptr = stdscan_bufptr; - while (*stdscan_bufptr && *stdscan_bufptr != quote) stdscan_bufptr++; - tv->t_inttwo = stdscan_bufptr - r; /* store full version */ - if (!*stdscan_bufptr) - return tv->t_type = TOKEN_ERRNUM; /* unmatched quotes */ - stdscan_bufptr++; /* skip over final quote */ - tv->t_integer = readstrnum(r, tv->t_inttwo, &rn_warn); - /* FIXME: rn_warn is not checked! */ - return tv->t_type = TOKEN_NUM; - } else if (*stdscan_bufptr == ';') { /* a comment has happened - stay */ - return tv->t_type = 0; - } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '>') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_SHR; - } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '<') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_SHL; - } else if (stdscan_bufptr[0] == '/' && stdscan_bufptr[1] == '/') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_SDIV; - } else if (stdscan_bufptr[0] == '%' && stdscan_bufptr[1] == '%') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_SMOD; - } else if (stdscan_bufptr[0] == '=' && stdscan_bufptr[1] == '=') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_EQ; - } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '>') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_NE; - } else if (stdscan_bufptr[0] == '!' && stdscan_bufptr[1] == '=') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_NE; - } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '=') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_LE; - } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '=') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_GE; - } else if (stdscan_bufptr[0] == '&' && stdscan_bufptr[1] == '&') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_DBL_AND; - } else if (stdscan_bufptr[0] == '^' && stdscan_bufptr[1] == '^') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_DBL_XOR; - } else if (stdscan_bufptr[0] == '|' && stdscan_bufptr[1] == '|') { - stdscan_bufptr += 2; - return tv->t_type = TOKEN_DBL_OR; - } else /* just an ordinary char */ - return tv->t_type = (unsigned char) (*stdscan_bufptr++); -} - -/* - * Return TRUE if the argument is a simple scalar. (Or a far- - * absolute, which counts.) - */ -int is_simple (expr *vect) -{ - while (vect->type && !vect->value) - vect++; - if (!vect->type) - return 1; - if (vect->type != EXPR_SIMPLE) - return 0; - do { - vect++; - } while (vect->type && !vect->value); - if (vect->type && vect->type < EXPR_SEGBASE+SEG_ABS) return 0; - return 1; -} - -/* - * Return TRUE if the argument is a simple scalar, _NOT_ a far- - * absolute. - */ -int is_really_simple (expr *vect) -{ - while (vect->type && !vect->value) - vect++; - if (!vect->type) - return 1; - if (vect->type != EXPR_SIMPLE) - return 0; - do { - vect++; - } while (vect->type && !vect->value); - if (vect->type) return 0; - return 1; -} - -/* - * Return TRUE if the argument is relocatable (i.e. a simple - * scalar, plus at most one segment-base, plus possibly a WRT). - */ -int is_reloc (expr *vect) -{ - while (vect->type && !vect->value) /* skip initial value-0 terms */ - vect++; - if (!vect->type) /* trivially return TRUE if nothing */ - return 1; /* is present apart from value-0s */ - if (vect->type < EXPR_SIMPLE) /* FALSE if a register is present */ - return 0; - if (vect->type == EXPR_SIMPLE) { /* skip over a pure number term... */ - do { - vect++; - } while (vect->type && !vect->value); - if (!vect->type) /* ...returning TRUE if that's all */ - return 1; - } - if (vect->type == EXPR_WRT) { /* skip over a WRT term... */ - do { - vect++; - } while (vect->type && !vect->value); - if (!vect->type) /* ...returning TRUE if that's all */ - return 1; - } - if (vect->value != 0 && vect->value != 1) - return 0; /* segment base multiplier non-unity */ - do { /* skip over _one_ seg-base term... */ - vect++; - } while (vect->type && !vect->value); - if (!vect->type) /* ...returning TRUE if that's all */ - return 1; - return 0; /* And return FALSE if there's more */ -} - -/* - * Return TRUE if the argument contains an `unknown' part. - */ -int is_unknown(expr *vect) -{ - while (vect->type && vect->type < EXPR_UNKNOWN) - vect++; - return (vect->type == EXPR_UNKNOWN); -} - -/* - * Return TRUE if the argument contains nothing but an `unknown' - * part. - */ -int is_just_unknown(expr *vect) -{ - while (vect->type && !vect->value) - vect++; - return (vect->type == EXPR_UNKNOWN); -} - -/* - * Return the scalar part of a relocatable vector. (Including - * simple scalar vectors - those qualify as relocatable.) - */ -long reloc_value (expr *vect) -{ - while (vect->type && !vect->value) - vect++; - if (!vect->type) return 0; - if (vect->type == EXPR_SIMPLE) - return vect->value; - else - return 0; -} - -/* - * Return the segment number of a relocatable vector, or NO_SEG for - * simple scalars. - */ -long reloc_seg (expr *vect) -{ - while (vect->type && (vect->type == EXPR_WRT || !vect->value)) - vect++; - if (vect->type == EXPR_SIMPLE) { - do { - vect++; - } while (vect->type && (vect->type == EXPR_WRT || !vect->value)); - } - if (!vect->type) - return NO_SEG; - else - return vect->type - EXPR_SEGBASE; -} - -/* - * Return the WRT segment number of a relocatable vector, or NO_SEG - * if no WRT part is present. - */ -long reloc_wrt (expr *vect) -{ - while (vect->type && vect->type < EXPR_WRT) - vect++; - if (vect->type == EXPR_WRT) { - return vect->value; - } else - return NO_SEG; -} - -/* - * Binary search. - */ -int bsi (char *string, const char **array, int size) -{ - int i = -1, j = size; /* always, i < index < j */ - while (j-i >= 2) { - int k = (i+j)/2; - int l = strcmp(string, array[k]); - if (l<0) /* it's in the first half */ - j = k; - else if (l>0) /* it's in the second half */ - i = k; - else /* we've got it :) */ - return k; - } - return -1; /* we haven't got it :( */ -} - -static char *file_name = NULL; -static long line_number = 0; - -char *src_set_fname(char *newname) -{ - char *oldname = file_name; - file_name = newname; - return oldname; -} - -long src_set_linnum(long newline) -{ - long oldline = line_number; - line_number = newline; - return oldline; -} - -long src_get_linnum(void) -{ - return line_number; -} - -int src_get(long *xline, char **xname) -{ - if (!file_name || !*xname || strcmp(*xname, file_name)) - { - nasm_free(*xname); - *xname = file_name ? nasm_strdup(file_name) : NULL; - *xline = line_number; - return -2; - } - if (*xline != line_number) - { - long tmp = line_number - *xline; - *xline = line_number; - return tmp; - } - return 0; -} - -void nasm_quote(char **str) -{ - int ln=strlen(*str); - char q=(*str)[0]; - char *p; - if (ln>1 && (*str)[ln-1]==q && (q=='"' || q=='\'')) - return; - q = '"'; - if (strchr(*str,q)) - q = '\''; - p = nasm_malloc(ln+3); - strcpy(p+1, *str); - nasm_free(*str); - p[ln+1] = p[0] = q; - p[ln+2] = 0; - *str = p; -} - -char *nasm_strcat(char *one, char *two) -{ - char *rslt; - int l1=strlen(one); - rslt = nasm_malloc(l1+strlen(two)+1); - strcpy(rslt, one); - strcpy(rslt+l1, two); - return rslt; -} - -void null_debug_init(struct ofmt *of, void *id, FILE *fp, efunc error ) {} -void null_debug_linenum(const char *filename, long linenumber, long segto) {} -void null_debug_deflabel(char *name, long segment, long offset, int is_global, char *special) {} -void null_debug_routine(const char *directive, const char *params) {} -void null_debug_typevalue(long type) {} -void null_debug_output(int type, void *param) {} -void null_debug_cleanup(void){} - -struct dfmt null_debug_form = { - "Null debug format", - "null", - null_debug_init, - null_debug_linenum, - null_debug_deflabel, - null_debug_routine, - null_debug_typevalue, - null_debug_output, - null_debug_cleanup -}; - -struct dfmt *null_debug_arr[2] = { &null_debug_form, NULL }; +/* nasmlib.c library routines for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "insns.h" /* For MAX_KEYWORD */ + +static efunc nasm_malloc_error; + +#ifdef LOGALLOC +static FILE *logfp; +#endif + +void nasm_set_malloc_error(efunc error) +{ + nasm_malloc_error = error; +#ifdef LOGALLOC + logfp = fopen("malloc.log", "w"); + setvbuf(logfp, NULL, _IOLBF, BUFSIZ); + fprintf(logfp, "null pointer is %p\n", NULL); +#endif +} + +#ifdef LOGALLOC +void *nasm_malloc_log(char *file, int line, size_t size) +#else +void *nasm_malloc(size_t size) +#endif +{ + void *p = malloc(size); + if (!p) + nasm_malloc_error(ERR_FATAL | ERR_NOFILE, "out of memory"); +#ifdef LOGALLOC + else + fprintf(logfp, "%s %d malloc(%ld) returns %p\n", + file, line, (long)size, p); +#endif + return p; +} + +#ifdef LOGALLOC +void *nasm_realloc_log(char *file, int line, void *q, size_t size) +#else +void *nasm_realloc(void *q, size_t size) +#endif +{ + void *p = q ? realloc(q, size) : malloc(size); + if (!p) + nasm_malloc_error(ERR_FATAL | ERR_NOFILE, "out of memory"); +#ifdef LOGALLOC + else if (q) + fprintf(logfp, "%s %d realloc(%p,%ld) returns %p\n", + file, line, q, (long)size, p); + else + fprintf(logfp, "%s %d malloc(%ld) returns %p\n", + file, line, (long)size, p); +#endif + return p; +} + +#ifdef LOGALLOC +void nasm_free_log(char *file, int line, void *q) +#else +void nasm_free(void *q) +#endif +{ + if (q) { + free(q); +#ifdef LOGALLOC + fprintf(logfp, "%s %d free(%p)\n", file, line, q); +#endif + } +} + +#ifdef LOGALLOC +char *nasm_strdup_log(char *file, int line, const char *s) +#else +char *nasm_strdup(const char *s) +#endif +{ + char *p; + int size = strlen(s) + 1; + + p = malloc(size); + if (!p) + nasm_malloc_error(ERR_FATAL | ERR_NOFILE, "out of memory"); +#ifdef LOGALLOC + else + fprintf(logfp, "%s %d strdup(%ld) returns %p\n", + file, line, (long)size, p); +#endif + strcpy(p, s); + return p; +} + +#ifdef LOGALLOC +char *nasm_strndup_log(char *file, int line, char *s, size_t len) +#else +char *nasm_strndup(char *s, size_t len) +#endif +{ + char *p; + int size = len + 1; + + p = malloc(size); + if (!p) + nasm_malloc_error(ERR_FATAL | ERR_NOFILE, "out of memory"); +#ifdef LOGALLOC + else + fprintf(logfp, "%s %d strndup(%ld) returns %p\n", + file, line, (long)size, p); +#endif + strncpy(p, s, len); + p[len] = '\0'; + return p; +} + +#if !defined(stricmp) && !defined(strcasecmp) +int nasm_stricmp(const char *s1, const char *s2) +{ + while (*s1 && tolower(*s1) == tolower(*s2)) + s1++, s2++; + if (!*s1 && !*s2) + return 0; + else if (tolower(*s1) < tolower(*s2)) + return -1; + else + return 1; +} +#endif + +#if !defined(strnicmp) && !defined(strncasecmp) +int nasm_strnicmp(const char *s1, const char *s2, int n) +{ + while (n > 0 && *s1 && tolower(*s1) == tolower(*s2)) + s1++, s2++, n--; + if ((!*s1 && !*s2) || n == 0) + return 0; + else if (tolower(*s1) < tolower(*s2)) + return -1; + else + return 1; +} +#endif + +#define lib_isnumchar(c) ( isalnum(c) || (c) == '$') +#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') + +long readnum(char *str, int *error) +{ + char *r = str, *q; + long radix; + unsigned long result, checklimit; + int digit, last; + int warn = FALSE; + int sign = 1; + + *error = FALSE; + + while (isspace(*r)) + r++; /* find start of number */ + + /* + * If the number came from make_tok_num (as a result of an %assign), it + * might have a '-' built into it (rather than in a preceeding token). + */ + if (*r == '-') { + r++; + sign = -1; + } + + q = r; + + while (lib_isnumchar(*q)) + q++; /* find end of number */ + + /* + * If it begins 0x, 0X or $, or ends in H, it's in hex. if it + * ends in Q, it's octal. if it ends in B, it's binary. + * Otherwise, it's ordinary decimal. + */ + if (*r == '0' && (r[1] == 'x' || r[1] == 'X')) + radix = 16, r += 2; + else if (*r == '$') + radix = 16, r++; + else if (q[-1] == 'H' || q[-1] == 'h') + radix = 16, q--; + else if (q[-1] == 'Q' || q[-1] == 'q' || q[-1] == 'O' || q[-1] == 'o') + radix = 8, q--; + else if (q[-1] == 'B' || q[-1] == 'b') + radix = 2, q--; + else + radix = 10; + + /* + * If this number has been found for us by something other than + * the ordinary scanners, then it might be malformed by having + * nothing between the prefix and the suffix. Check this case + * now. + */ + if (r >= q) { + *error = TRUE; + return 0; + } + + /* + * `checklimit' must be 2**32 / radix. We can't do that in + * 32-bit arithmetic, which we're (probably) using, so we + * cheat: since we know that all radices we use are even, we + * can divide 2**31 by radix/2 instead. + */ + checklimit = 0x80000000UL / (radix >> 1); + + /* + * Calculate the highest allowable value for the last digit + * of a 32 bit constant... in radix 10, it is 6, otherwise it is 0 + */ + last = (radix == 10 ? 6 : 0); + + result = 0; + while (*r && r < q) { + if (*r < '0' || (*r > '9' && *r < 'A') + || (digit = numvalue(*r)) >= radix) { + *error = TRUE; + return 0; + } + if (result > checklimit || (result == checklimit && digit >= last)) { + warn = TRUE; + } + + result = radix * result + digit; + r++; + } + + if (warn) + nasm_malloc_error(ERR_WARNING | ERR_PASS1 | ERR_WARN_NOV, + "numeric constant %s does not fit in 32 bits", + str); + + return result * sign; +} + +long readstrnum(char *str, int length, int *warn) +{ + long charconst = 0; + int i; + + *warn = FALSE; + + str += length; + for (i = 0; i < length; i++) { + if (charconst & 0xff000000UL) { + *warn = TRUE; + } + charconst = (charconst << 8) + (unsigned char)*--str; + } + return charconst; +} + +static long next_seg; + +void seg_init(void) +{ + next_seg = 0; +} + +long seg_alloc(void) +{ + return (next_seg += 2) - 2; +} + +void fwriteshort(int data, FILE * fp) +{ + fputc((int)(data & 255), fp); + fputc((int)((data >> 8) & 255), fp); +} + +void fwritelong(long data, FILE * fp) +{ + fputc((int)(data & 255), fp); + fputc((int)((data >> 8) & 255), fp); + fputc((int)((data >> 16) & 255), fp); + fputc((int)((data >> 24) & 255), fp); +} + +void standard_extension(char *inname, char *outname, char *extension, + efunc error) +{ + char *p, *q; + + if (*outname) /* file name already exists, */ + return; /* so do nothing */ + q = inname; + p = outname; + while (*q) + *p++ = *q++; /* copy, and find end of string */ + *p = '\0'; /* terminate it */ + while (p > outname && *--p != '.') ; /* find final period (or whatever) */ + if (*p != '.') + while (*p) + p++; /* go back to end if none found */ + if (!strcmp(p, extension)) { /* is the extension already there? */ + if (*extension) + error(ERR_WARNING | ERR_NOFILE, + "file name already ends in `%s': " + "output will be in `nasm.out'", extension); + else + error(ERR_WARNING | ERR_NOFILE, + "file name already has no extension: " + "output will be in `nasm.out'"); + strcpy(outname, "nasm.out"); + } else + strcpy(p, extension); +} + +#define LEAFSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_LEAF)) +#define BRANCHSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_BRANCH)) + +#define LAYERSIZ(r) ( (r)->layers==0 ? RAA_BLKSIZE : RAA_LAYERSIZE ) + +static struct RAA *real_raa_init(int layers) +{ + struct RAA *r; + int i; + + if (layers == 0) { + r = nasm_malloc(LEAFSIZ); + r->layers = 0; + memset(r->u.l.data, 0, sizeof(r->u.l.data)); + r->stepsize = 1L; + } else { + r = nasm_malloc(BRANCHSIZ); + r->layers = layers; + for (i = 0; i < RAA_LAYERSIZE; i++) + r->u.b.data[i] = NULL; + r->stepsize = RAA_BLKSIZE; + while (--layers) + r->stepsize *= RAA_LAYERSIZE; + } + return r; +} + +struct RAA *raa_init(void) +{ + return real_raa_init(0); +} + +void raa_free(struct RAA *r) +{ + if (r->layers == 0) + nasm_free(r); + else { + struct RAA **p; + for (p = r->u.b.data; p - r->u.b.data < RAA_LAYERSIZE; p++) + if (*p) + raa_free(*p); + } +} + +long raa_read(struct RAA *r, long posn) +{ + if (posn >= r->stepsize * LAYERSIZ(r)) + return 0; /* Return 0 for undefined entries */ + while (r->layers > 0) { + ldiv_t l; + l = ldiv(posn, r->stepsize); + r = r->u.b.data[l.quot]; + posn = l.rem; + if (!r) + return 0; /* Return 0 for undefined entries */ + } + return r->u.l.data[posn]; +} + +struct RAA *raa_write(struct RAA *r, long posn, long value) +{ + struct RAA *result; + + if (posn < 0) + nasm_malloc_error(ERR_PANIC, "negative position in raa_write"); + + while (r->stepsize * LAYERSIZ(r) <= posn) { + /* + * Must add a layer. + */ + struct RAA *s; + int i; + + s = nasm_malloc(BRANCHSIZ); + for (i = 0; i < RAA_LAYERSIZE; i++) + s->u.b.data[i] = NULL; + s->layers = r->layers + 1; + s->stepsize = LAYERSIZ(r) * r->stepsize; + s->u.b.data[0] = r; + r = s; + } + + result = r; + + while (r->layers > 0) { + ldiv_t l; + struct RAA **s; + l = ldiv(posn, r->stepsize); + s = &r->u.b.data[l.quot]; + if (!*s) + *s = real_raa_init(r->layers - 1); + r = *s; + posn = l.rem; + } + + r->u.l.data[posn] = value; + + return result; +} + +#define SAA_MAXLEN 8192 + +struct SAA *saa_init(long elem_len) +{ + struct SAA *s; + + if (elem_len > SAA_MAXLEN) + nasm_malloc_error(ERR_PANIC | ERR_NOFILE, + "SAA with huge elements"); + + s = nasm_malloc(sizeof(struct SAA)); + s->posn = s->start = 0L; + s->elem_len = elem_len; + s->length = SAA_MAXLEN - (SAA_MAXLEN % elem_len); + s->data = nasm_malloc(s->length); + s->next = NULL; + s->end = s; + + return s; +} + +void saa_free(struct SAA *s) +{ + struct SAA *t; + + while (s) { + t = s->next; + nasm_free(s->data); + nasm_free(s); + s = t; + } +} + +void *saa_wstruct(struct SAA *s) +{ + void *p; + + if (s->end->length - s->end->posn < s->elem_len) { + s->end->next = nasm_malloc(sizeof(struct SAA)); + s->end->next->start = s->end->start + s->end->posn; + s->end = s->end->next; + s->end->length = s->length; + s->end->next = NULL; + s->end->posn = 0L; + s->end->data = nasm_malloc(s->length); + } + + p = s->end->data + s->end->posn; + s->end->posn += s->elem_len; + return p; +} + +void saa_wbytes(struct SAA *s, const void *data, long len) +{ + const char *d = data; + + while (len > 0) { + long l = s->end->length - s->end->posn; + if (l > len) + l = len; + if (l > 0) { + if (d) { + memcpy(s->end->data + s->end->posn, d, l); + d += l; + } else + memset(s->end->data + s->end->posn, 0, l); + s->end->posn += l; + len -= l; + } + if (len > 0) { + s->end->next = nasm_malloc(sizeof(struct SAA)); + s->end->next->start = s->end->start + s->end->posn; + s->end = s->end->next; + s->end->length = s->length; + s->end->next = NULL; + s->end->posn = 0L; + s->end->data = nasm_malloc(s->length); + } + } +} + +void saa_rewind(struct SAA *s) +{ + s->rptr = s; + s->rpos = 0L; +} + +void *saa_rstruct(struct SAA *s) +{ + void *p; + + if (!s->rptr) + return NULL; + + if (s->rptr->posn - s->rpos < s->elem_len) { + s->rptr = s->rptr->next; + if (!s->rptr) + return NULL; /* end of array */ + s->rpos = 0L; + } + + p = s->rptr->data + s->rpos; + s->rpos += s->elem_len; + return p; +} + +void *saa_rbytes(struct SAA *s, long *len) +{ + void *p; + + if (!s->rptr) + return NULL; + + p = s->rptr->data + s->rpos; + *len = s->rptr->posn - s->rpos; + s->rptr = s->rptr->next; + s->rpos = 0L; + return p; +} + +void saa_rnbytes(struct SAA *s, void *data, long len) +{ + char *d = data; + + while (len > 0) { + long l; + + if (!s->rptr) + return; + + l = s->rptr->posn - s->rpos; + if (l > len) + l = len; + if (l > 0) { + memcpy(d, s->rptr->data + s->rpos, l); + d += l; + s->rpos += l; + len -= l; + } + if (len > 0) { + s->rptr = s->rptr->next; + s->rpos = 0L; + } + } +} + +void saa_fread(struct SAA *s, long posn, void *data, long len) +{ + struct SAA *p; + long pos; + char *cdata = data; + + if (!s->rptr || posn < s->rptr->start) + saa_rewind(s); + p = s->rptr; + while (posn >= p->start + p->posn) { + p = p->next; + if (!p) + return; /* what else can we do?! */ + } + + pos = posn - p->start; + while (len) { + long l = p->posn - pos; + if (l > len) + l = len; + memcpy(cdata, p->data + pos, l); + len -= l; + cdata += l; + p = p->next; + if (!p) + return; + pos = 0L; + } + s->rptr = p; +} + +void saa_fwrite(struct SAA *s, long posn, void *data, long len) +{ + struct SAA *p; + long pos; + char *cdata = data; + + if (!s->rptr || posn < s->rptr->start) + saa_rewind(s); + p = s->rptr; + while (posn >= p->start + p->posn) { + p = p->next; + if (!p) + return; /* what else can we do?! */ + } + + pos = posn - p->start; + while (len) { + long l = p->posn - pos; + if (l > len) + l = len; + memcpy(p->data + pos, cdata, l); + len -= l; + cdata += l; + p = p->next; + if (!p) + return; + pos = 0L; + } + s->rptr = p; +} + +void saa_fpwrite(struct SAA *s, FILE * fp) +{ + char *data; + long len; + + saa_rewind(s); + while ((data = saa_rbytes(s, &len))) + fwrite(data, 1, len, fp); +} + +/* + * Register, instruction, condition-code and prefix keywords used + * by the scanner. + */ +#include "names.c" +static const char *special_names[] = { + "byte", "dword", "far", "long", "near", "nosplit", "qword", + "short", "strict", "to", "tword", "word" +}; +static const char *prefix_names[] = { + "a16", "a32", "lock", "o16", "o32", "rep", "repe", "repne", + "repnz", "repz", "times" +}; + +/* + * Standard scanner routine used by parser.c and some output + * formats. It keeps a succession of temporary-storage strings in + * stdscan_tempstorage, which can be cleared using stdscan_reset. + */ +static char **stdscan_tempstorage = NULL; +static int stdscan_tempsize = 0, stdscan_templen = 0; +#define STDSCAN_TEMP_DELTA 256 + +static void stdscan_pop(void) +{ + nasm_free(stdscan_tempstorage[--stdscan_templen]); +} + +void stdscan_reset(void) +{ + while (stdscan_templen > 0) + stdscan_pop(); +} + +/* + * Unimportant cleanup is done to avoid confusing people who are trying + * to debug real memory leaks + */ +void nasmlib_cleanup(void) +{ + stdscan_reset(); + nasm_free(stdscan_tempstorage); +} + +static char *stdscan_copy(char *p, int len) +{ + char *text; + + text = nasm_malloc(len + 1); + strncpy(text, p, len); + text[len] = '\0'; + + if (stdscan_templen >= stdscan_tempsize) { + stdscan_tempsize += STDSCAN_TEMP_DELTA; + stdscan_tempstorage = nasm_realloc(stdscan_tempstorage, + stdscan_tempsize * + sizeof(char *)); + } + stdscan_tempstorage[stdscan_templen++] = text; + + return text; +} + +char *stdscan_bufptr = NULL; +int stdscan(void *private_data, struct tokenval *tv) +{ + char ourcopy[MAX_KEYWORD + 1], *r, *s; + + (void)private_data; /* Don't warn that this parameter is unused */ + + while (isspace(*stdscan_bufptr)) + stdscan_bufptr++; + if (!*stdscan_bufptr) + return tv->t_type = 0; + + /* we have a token; either an id, a number or a char */ + if (isidstart(*stdscan_bufptr) || + (*stdscan_bufptr == '$' && isidstart(stdscan_bufptr[1]))) { + /* now we've got an identifier */ + int i; + int is_sym = FALSE; + + if (*stdscan_bufptr == '$') { + is_sym = TRUE; + stdscan_bufptr++; + } + + r = stdscan_bufptr++; + /* read the entire buffer to advance the buffer pointer but... */ + while (isidchar(*stdscan_bufptr)) + stdscan_bufptr++; + + /* ... copy only up to IDLEN_MAX-1 characters */ + tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r < IDLEN_MAX ? + stdscan_bufptr - r : IDLEN_MAX - 1); + + if (is_sym || stdscan_bufptr - r > MAX_KEYWORD) + return tv->t_type = TOKEN_ID; /* bypass all other checks */ + + for (s = tv->t_charptr, r = ourcopy; *s; s++) + *r++ = tolower(*s); + *r = '\0'; + /* right, so we have an identifier sitting in temp storage. now, + * is it actually a register or instruction name, or what? */ + if ((tv->t_integer = bsi(ourcopy, reg_names, + elements(reg_names))) >= 0) { + tv->t_integer += EXPR_REG_START; + return tv->t_type = TOKEN_REG; + } else if ((tv->t_integer = bsi(ourcopy, insn_names, + elements(insn_names))) >= 0) { + return tv->t_type = TOKEN_INSN; + } + for (i = 0; i < elements(icn); i++) + if (!strncmp(ourcopy, icn[i], strlen(icn[i]))) { + char *p = ourcopy + strlen(icn[i]); + tv->t_integer = ico[i]; + if ((tv->t_inttwo = bsi(p, conditions, + elements(conditions))) >= 0) + return tv->t_type = TOKEN_INSN; + } + if ((tv->t_integer = bsi(ourcopy, prefix_names, + elements(prefix_names))) >= 0) { + tv->t_integer += PREFIX_ENUM_START; + return tv->t_type = TOKEN_PREFIX; + } + if ((tv->t_integer = bsi(ourcopy, special_names, + elements(special_names))) >= 0) + return tv->t_type = TOKEN_SPECIAL; + if (!nasm_stricmp(ourcopy, "seg")) + return tv->t_type = TOKEN_SEG; + if (!nasm_stricmp(ourcopy, "wrt")) + return tv->t_type = TOKEN_WRT; + return tv->t_type = TOKEN_ID; + } else if (*stdscan_bufptr == '$' && !isnumchar(stdscan_bufptr[1])) { + /* + * It's a $ sign with no following hex number; this must + * mean it's a Here token ($), evaluating to the current + * assembly location, or a Base token ($$), evaluating to + * the base of the current segment. + */ + stdscan_bufptr++; + if (*stdscan_bufptr == '$') { + stdscan_bufptr++; + return tv->t_type = TOKEN_BASE; + } + return tv->t_type = TOKEN_HERE; + } else if (isnumstart(*stdscan_bufptr)) { /* now we've got a number */ + int rn_error; + + r = stdscan_bufptr++; + while (isnumchar(*stdscan_bufptr)) + stdscan_bufptr++; + + if (*stdscan_bufptr == '.') { + /* + * a floating point constant + */ + stdscan_bufptr++; + while (isnumchar(*stdscan_bufptr) || + ((stdscan_bufptr[-1] == 'e' + || stdscan_bufptr[-1] == 'E') + && (*stdscan_bufptr == '-' || *stdscan_bufptr == '+'))) { + stdscan_bufptr++; + } + tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r); + return tv->t_type = TOKEN_FLOAT; + } + r = stdscan_copy(r, stdscan_bufptr - r); + tv->t_integer = readnum(r, &rn_error); + stdscan_pop(); + if (rn_error) + return tv->t_type = TOKEN_ERRNUM; /* some malformation occurred */ + tv->t_charptr = NULL; + return tv->t_type = TOKEN_NUM; + } else if (*stdscan_bufptr == '\'' || *stdscan_bufptr == '"') { /* a char constant */ + char quote = *stdscan_bufptr++, *r; + int rn_warn; + r = tv->t_charptr = stdscan_bufptr; + while (*stdscan_bufptr && *stdscan_bufptr != quote) + stdscan_bufptr++; + tv->t_inttwo = stdscan_bufptr - r; /* store full version */ + if (!*stdscan_bufptr) + return tv->t_type = TOKEN_ERRNUM; /* unmatched quotes */ + stdscan_bufptr++; /* skip over final quote */ + tv->t_integer = readstrnum(r, tv->t_inttwo, &rn_warn); + /* FIXME: rn_warn is not checked! */ + return tv->t_type = TOKEN_NUM; + } else if (*stdscan_bufptr == ';') { /* a comment has happened - stay */ + return tv->t_type = 0; + } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '>') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_SHR; + } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '<') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_SHL; + } else if (stdscan_bufptr[0] == '/' && stdscan_bufptr[1] == '/') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_SDIV; + } else if (stdscan_bufptr[0] == '%' && stdscan_bufptr[1] == '%') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_SMOD; + } else if (stdscan_bufptr[0] == '=' && stdscan_bufptr[1] == '=') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_EQ; + } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '>') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_NE; + } else if (stdscan_bufptr[0] == '!' && stdscan_bufptr[1] == '=') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_NE; + } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '=') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_LE; + } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '=') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_GE; + } else if (stdscan_bufptr[0] == '&' && stdscan_bufptr[1] == '&') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_DBL_AND; + } else if (stdscan_bufptr[0] == '^' && stdscan_bufptr[1] == '^') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_DBL_XOR; + } else if (stdscan_bufptr[0] == '|' && stdscan_bufptr[1] == '|') { + stdscan_bufptr += 2; + return tv->t_type = TOKEN_DBL_OR; + } else /* just an ordinary char */ + return tv->t_type = (unsigned char)(*stdscan_bufptr++); +} + +/* + * Return TRUE if the argument is a simple scalar. (Or a far- + * absolute, which counts.) + */ +int is_simple(expr * vect) +{ + while (vect->type && !vect->value) + vect++; + if (!vect->type) + return 1; + if (vect->type != EXPR_SIMPLE) + return 0; + do { + vect++; + } while (vect->type && !vect->value); + if (vect->type && vect->type < EXPR_SEGBASE + SEG_ABS) + return 0; + return 1; +} + +/* + * Return TRUE if the argument is a simple scalar, _NOT_ a far- + * absolute. + */ +int is_really_simple(expr * vect) +{ + while (vect->type && !vect->value) + vect++; + if (!vect->type) + return 1; + if (vect->type != EXPR_SIMPLE) + return 0; + do { + vect++; + } while (vect->type && !vect->value); + if (vect->type) + return 0; + return 1; +} + +/* + * Return TRUE if the argument is relocatable (i.e. a simple + * scalar, plus at most one segment-base, plus possibly a WRT). + */ +int is_reloc(expr * vect) +{ + while (vect->type && !vect->value) /* skip initial value-0 terms */ + vect++; + if (!vect->type) /* trivially return TRUE if nothing */ + return 1; /* is present apart from value-0s */ + if (vect->type < EXPR_SIMPLE) /* FALSE if a register is present */ + return 0; + if (vect->type == EXPR_SIMPLE) { /* skip over a pure number term... */ + do { + vect++; + } while (vect->type && !vect->value); + if (!vect->type) /* ...returning TRUE if that's all */ + return 1; + } + if (vect->type == EXPR_WRT) { /* skip over a WRT term... */ + do { + vect++; + } while (vect->type && !vect->value); + if (!vect->type) /* ...returning TRUE if that's all */ + return 1; + } + if (vect->value != 0 && vect->value != 1) + return 0; /* segment base multiplier non-unity */ + do { /* skip over _one_ seg-base term... */ + vect++; + } while (vect->type && !vect->value); + if (!vect->type) /* ...returning TRUE if that's all */ + return 1; + return 0; /* And return FALSE if there's more */ +} + +/* + * Return TRUE if the argument contains an `unknown' part. + */ +int is_unknown(expr * vect) +{ + while (vect->type && vect->type < EXPR_UNKNOWN) + vect++; + return (vect->type == EXPR_UNKNOWN); +} + +/* + * Return TRUE if the argument contains nothing but an `unknown' + * part. + */ +int is_just_unknown(expr * vect) +{ + while (vect->type && !vect->value) + vect++; + return (vect->type == EXPR_UNKNOWN); +} + +/* + * Return the scalar part of a relocatable vector. (Including + * simple scalar vectors - those qualify as relocatable.) + */ +long reloc_value(expr * vect) +{ + while (vect->type && !vect->value) + vect++; + if (!vect->type) + return 0; + if (vect->type == EXPR_SIMPLE) + return vect->value; + else + return 0; +} + +/* + * Return the segment number of a relocatable vector, or NO_SEG for + * simple scalars. + */ +long reloc_seg(expr * vect) +{ + while (vect->type && (vect->type == EXPR_WRT || !vect->value)) + vect++; + if (vect->type == EXPR_SIMPLE) { + do { + vect++; + } while (vect->type && (vect->type == EXPR_WRT || !vect->value)); + } + if (!vect->type) + return NO_SEG; + else + return vect->type - EXPR_SEGBASE; +} + +/* + * Return the WRT segment number of a relocatable vector, or NO_SEG + * if no WRT part is present. + */ +long reloc_wrt(expr * vect) +{ + while (vect->type && vect->type < EXPR_WRT) + vect++; + if (vect->type == EXPR_WRT) { + return vect->value; + } else + return NO_SEG; +} + +/* + * Binary search. + */ +int bsi(char *string, const char **array, int size) +{ + int i = -1, j = size; /* always, i < index < j */ + while (j - i >= 2) { + int k = (i + j) / 2; + int l = strcmp(string, array[k]); + if (l < 0) /* it's in the first half */ + j = k; + else if (l > 0) /* it's in the second half */ + i = k; + else /* we've got it :) */ + return k; + } + return -1; /* we haven't got it :( */ +} + +static char *file_name = NULL; +static long line_number = 0; + +char *src_set_fname(char *newname) +{ + char *oldname = file_name; + file_name = newname; + return oldname; +} + +long src_set_linnum(long newline) +{ + long oldline = line_number; + line_number = newline; + return oldline; +} + +long src_get_linnum(void) +{ + return line_number; +} + +int src_get(long *xline, char **xname) +{ + if (!file_name || !*xname || strcmp(*xname, file_name)) { + nasm_free(*xname); + *xname = file_name ? nasm_strdup(file_name) : NULL; + *xline = line_number; + return -2; + } + if (*xline != line_number) { + long tmp = line_number - *xline; + *xline = line_number; + return tmp; + } + return 0; +} + +void nasm_quote(char **str) +{ + int ln = strlen(*str); + char q = (*str)[0]; + char *p; + if (ln > 1 && (*str)[ln - 1] == q && (q == '"' || q == '\'')) + return; + q = '"'; + if (strchr(*str, q)) + q = '\''; + p = nasm_malloc(ln + 3); + strcpy(p + 1, *str); + nasm_free(*str); + p[ln + 1] = p[0] = q; + p[ln + 2] = 0; + *str = p; +} + +char *nasm_strcat(char *one, char *two) +{ + char *rslt; + int l1 = strlen(one); + rslt = nasm_malloc(l1 + strlen(two) + 1); + strcpy(rslt, one); + strcpy(rslt + l1, two); + return rslt; +} + +void null_debug_init(struct ofmt *of, void *id, FILE * fp, efunc error) +{ +} +void null_debug_linenum(const char *filename, long linenumber, long segto) +{ +} +void null_debug_deflabel(char *name, long segment, long offset, + int is_global, char *special) +{ +} +void null_debug_routine(const char *directive, const char *params) +{ +} +void null_debug_typevalue(long type) +{ +} +void null_debug_output(int type, void *param) +{ +} +void null_debug_cleanup(void) +{ +} + +struct dfmt null_debug_form = { + "Null debug format", + "null", + null_debug_init, + null_debug_linenum, + null_debug_deflabel, + null_debug_routine, + null_debug_typevalue, + null_debug_output, + null_debug_cleanup +}; + +struct dfmt *null_debug_arr[2] = { &null_debug_form, NULL }; diff --git a/nasmlib.h b/nasmlib.h index 4e4eda3f..ea1accbd 100644 --- a/nasmlib.h +++ b/nasmlib.h @@ -25,20 +25,20 @@ * passed a NULL pointer; nasm_free will do nothing if it is passed * a NULL pointer. */ -#ifdef NASM_NASM_H /* need efunc defined for this */ -void nasm_set_malloc_error (efunc); +#ifdef NASM_NASM_H /* need efunc defined for this */ +void nasm_set_malloc_error(efunc); #ifndef LOGALLOC -void *nasm_malloc (size_t); -void *nasm_realloc (void *, size_t); -void nasm_free (void *); -char *nasm_strdup (const char *); -char *nasm_strndup (char *, size_t); +void *nasm_malloc(size_t); +void *nasm_realloc(void *, size_t); +void nasm_free(void *); +char *nasm_strdup(const char *); +char *nasm_strndup(char *, size_t); #else -void *nasm_malloc_log (char *, int, size_t); -void *nasm_realloc_log (char *, int, void *, size_t); -void nasm_free_log (char *, int, void *); -char *nasm_strdup_log (char *, int, const char *); -char *nasm_strndup_log (char *, int, char *, size_t); +void *nasm_malloc_log(char *, int, size_t); +void *nasm_realloc_log(char *, int, void *, size_t); +void nasm_free_log(char *, int, void *); +char *nasm_strdup_log(char *, int, const char *); +char *nasm_strndup_log(char *, int, char *, size_t); #define nasm_malloc(x) nasm_malloc_log(__FILE__,__LINE__,x) #define nasm_realloc(x,y) nasm_realloc_log(__FILE__,__LINE__,x,y) #define nasm_free(x) nasm_free_log(__FILE__,__LINE__,x) @@ -58,7 +58,7 @@ char *nasm_strndup_log (char *, int, char *, size_t); #define nasm_stricmp strcasecmp #endif #else -int nasm_stricmp (const char *, const char *); +int nasm_stricmp(const char *, const char *); #endif #if defined(strnicmp) || defined(strncasecmp) @@ -68,7 +68,7 @@ int nasm_stricmp (const char *, const char *); #define nasm_strnicmp strncasecmp #endif #else -int nasm_strnicmp (const char *, const char *, int); +int nasm_strnicmp(const char *, const char *, int); #endif /* @@ -97,8 +97,8 @@ long seg_alloc(void); * function to add an extension to the name of the input file */ #ifdef NASM_NASM_H -void standard_extension (char *inname, char *outname, char *extension, - efunc error); +void standard_extension(char *inname, char *outname, char *extension, + efunc error); #endif /* @@ -129,8 +129,8 @@ void standard_extension (char *inname, char *outname, char *extension, /* * and routines to do the same thing to a file */ -void fwriteshort (int data, FILE *fp); -void fwritelong (long data, FILE *fp); +void fwriteshort(int data, FILE * fp); +void fwritelong(long data, FILE * fp); /* * Routines to manage a dynamic random access array of longs which @@ -138,8 +138,8 @@ void fwritelong (long data, FILE *fp); * chunk. */ -#define RAA_BLKSIZE 4096 /* this many longs allocated at once */ -#define RAA_LAYERSIZE 1024 /* this many _pointers_ allocated */ +#define RAA_BLKSIZE 4096 /* this many longs allocated at once */ +#define RAA_LAYERSIZE 1024 /* this many _pointers_ allocated */ typedef struct RAA RAA; typedef union RAA_UNION RAA_UNION; @@ -164,20 +164,19 @@ struct RAA { */ long stepsize; union RAA_UNION { - struct RAA_LEAF { - long data[RAA_BLKSIZE]; - } l; - struct RAA_BRANCH { - struct RAA *data[RAA_LAYERSIZE]; - } b; + struct RAA_LEAF { + long data[RAA_BLKSIZE]; + } l; + struct RAA_BRANCH { + struct RAA *data[RAA_LAYERSIZE]; + } b; } u; }; - -struct RAA *raa_init (void); -void raa_free (struct RAA *); -long raa_read (struct RAA *, long); -struct RAA *raa_write (struct RAA *r, long posn, long value); +struct RAA *raa_init(void); +void raa_free(struct RAA *); +long raa_read(struct RAA *, long); +struct RAA *raa_write(struct RAA *r, long posn, long value); /* * Routines to manage a dynamic sequential-access array, under the @@ -199,17 +198,17 @@ struct SAA { char *data; }; -struct SAA *saa_init (long elem_len); /* 1 == byte */ -void saa_free (struct SAA *); -void *saa_wstruct (struct SAA *); /* return a structure of elem_len */ -void saa_wbytes (struct SAA *, const void *, long); /* write arbitrary bytes */ -void saa_rewind (struct SAA *); /* for reading from beginning */ -void *saa_rstruct (struct SAA *); /* return NULL on EOA */ -void *saa_rbytes (struct SAA *, long *); /* return 0 on EOA */ -void saa_rnbytes (struct SAA *, void *, long); /* read a given no. of bytes */ -void saa_fread (struct SAA *s, long posn, void *p, long len); /* fixup */ -void saa_fwrite (struct SAA *s, long posn, void *p, long len); /* fixup */ -void saa_fpwrite (struct SAA *, FILE *); +struct SAA *saa_init(long elem_len); /* 1 == byte */ +void saa_free(struct SAA *); +void *saa_wstruct(struct SAA *); /* return a structure of elem_len */ +void saa_wbytes(struct SAA *, const void *, long); /* write arbitrary bytes */ +void saa_rewind(struct SAA *); /* for reading from beginning */ +void *saa_rstruct(struct SAA *); /* return NULL on EOA */ +void *saa_rbytes(struct SAA *, long *); /* return 0 on EOA */ +void saa_rnbytes(struct SAA *, void *, long); /* read a given no. of bytes */ +void saa_fread(struct SAA *s, long posn, void *p, long len); /* fixup */ +void saa_fwrite(struct SAA *s, long posn, void *p, long len); /* fixup */ +void saa_fpwrite(struct SAA *, FILE *); #ifdef NASM_NASM_H /* @@ -217,7 +216,7 @@ void saa_fpwrite (struct SAA *, FILE *); */ extern char *stdscan_bufptr; void stdscan_reset(void); -int stdscan (void *private_data, struct tokenval *tv); +int stdscan(void *private_data, struct tokenval *tv); #endif #ifdef NASM_NASM_H @@ -226,7 +225,7 @@ int stdscan (void *private_data, struct tokenval *tv); */ int is_reloc(expr *); int is_simple(expr *); -int is_really_simple (expr *); +int is_really_simple(expr *); int is_unknown(expr *); int is_just_unknown(expr *); long reloc_value(expr *); @@ -239,8 +238,7 @@ long reloc_wrt(expr *); * matching `string', or <0 if no match. `array' is taken to * contain `size' elements. */ -int bsi (char *string, const char **array, int size); - +int bsi(char *string, const char **array, int size); char *src_set_fname(char *newname); long src_set_linnum(long newline); diff --git a/ndisasm.c b/ndisasm.c dissimilarity index 78% index a167d870..06b3869b 100644 --- a/ndisasm.c +++ b/ndisasm.c @@ -1,321 +1,342 @@ -/* ndisasm.c the Netwide Disassembler main module - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include -#include -#include -#include -#include - -#include "insns.h" -#include "nasm.h" -#include "nasmlib.h" -#include "sync.h" -#include "disasm.h" - -#define BPL 8 /* bytes per line of hex dump */ - -static const char *help = -"usage: ndisasm [-a] [-i] [-h] [-r] [-u] [-b bits] [-o origin] [-s sync...]\n" -" [-e bytes] [-k start,bytes] [-p vendor] file\n" -" -a or -i activates auto (intelligent) sync\n" -" -u sets USE32 (32-bit mode)\n" -" -b 16 or -b 32 sets number of bits too\n" -" -h displays this text\n" -" -r or -v displays the version number\n" -" -e skips bytes of header\n" -" -k avoids disassembling bytes from position \n" -" -p selects the preferred vendor instruction set (intel, amd, cyrix, idt)\n"; - -static void output_ins (unsigned long, unsigned char *, int, char *); -static void skip (unsigned long dist, FILE *fp); - -int main(int argc, char **argv) -{ - unsigned char buffer[INSN_MAX * 2], *p, *q; - char outbuf[256]; - char *pname = *argv; - char *filename = NULL; - unsigned long nextsync, synclen, initskip = 0L; - int lenread; - long lendis; - int autosync = FALSE; - int bits = 16; - int eof = FALSE; - unsigned long prefer = 0; - int rn_error; - long offset; - FILE *fp; - - offset = 0; - init_sync(); - - while (--argc) { - char *v, *vv, *p = *++argv; - if (*p == '-' && p[1]) { - p++; - while (*p) switch (tolower(*p)) { - case 'a': /* auto or intelligent sync */ - case 'i': - autosync = TRUE; - p++; - break; - case 'h': - fprintf(stderr, help); - return 0; - case 'r': - case 'v': - fprintf(stderr, "NDISASM version %s compiled " __DATE__ "\n", NASM_VER); - return 0; - case 'u': /* USE32 */ - bits = 32; - p++; - break; - case 'b': /* bits */ - v = p[1] ? p+1 : --argc ? *++argv : NULL; - if (!v) { - fprintf(stderr, "%s: `-b' requires an argument\n", pname); - return 1; - } - if (!strcmp(v, "16")) - bits = 16; - else if (!strcmp(v, "32")) - bits = 32; - else { - fprintf(stderr, "%s: argument to `-b' should" - " be `16' or `32'\n", pname); - } - p = ""; /* force to next argument */ - break; - case 'o': /* origin */ - v = p[1] ? p+1 : --argc ? *++argv : NULL; - if (!v) { - fprintf(stderr, "%s: `-o' requires an argument\n", pname); - return 1; - } - offset = readnum (v, &rn_error); - if (rn_error) { - fprintf(stderr, "%s: `-o' requires a numeric argument\n", - pname); - return 1; - } - p = ""; /* force to next argument */ - break; - case 's': /* sync point */ - v = p[1] ? p+1 : --argc ? *++argv : NULL; - if (!v) { - fprintf(stderr, "%s: `-s' requires an argument\n", pname); - return 1; - } - add_sync (readnum (v, &rn_error), 0L); - if (rn_error) { - fprintf(stderr, "%s: `-s' requires a numeric argument\n", - pname); - return 1; - } - p = ""; /* force to next argument */ - break; - case 'e': /* skip a header */ - v = p[1] ? p+1 : --argc ? *++argv : NULL; - if (!v) { - fprintf(stderr, "%s: `-e' requires an argument\n", pname); - return 1; - } - initskip = readnum (v, &rn_error); - if (rn_error) { - fprintf(stderr, "%s: `-e' requires a numeric argument\n", - pname); - return 1; - } - p = ""; /* force to next argument */ - break; - case 'k': /* skip a region */ - v = p[1] ? p+1 : --argc ? *++argv : NULL; - if (!v) { - fprintf(stderr, "%s: `-k' requires an argument\n", pname); - return 1; - } - vv = strchr(v, ','); - if (!vv) { - fprintf(stderr, "%s: `-k' requires two numbers separated" - " by a comma\n", pname); - return 1; - } - *vv++ = '\0'; - nextsync = readnum (v, &rn_error); - if (rn_error) { - fprintf(stderr, "%s: `-k' requires numeric arguments\n", - pname); - return 1; - } - synclen = readnum (vv, &rn_error); - if (rn_error) { - fprintf(stderr, "%s: `-k' requires numeric arguments\n", - pname); - return 1; - } - add_sync (nextsync, synclen); - p = ""; /* force to next argument */ - break; - case 'p': /* preferred vendor */ - v = p[1] ? p+1 : --argc ? *++argv : NULL; - if (!v) { - fprintf(stderr, "%s: `-p' requires an argument\n", pname); - return 1; - } - if ( !strcmp(v, "intel") ) { - prefer = 0; /* Default */ - } else if ( !strcmp(v, "amd") ) { - prefer = IF_AMD|IF_3DNOW; - } else if ( !strcmp(v, "cyrix") ) { - prefer = IF_CYRIX|IF_3DNOW; - } else if ( !strcmp(v, "idt") || !strcmp(v, "centaur") || - !strcmp(v, "winchip") ) { - prefer = IF_3DNOW; - } else { - fprintf(stderr, "%s: unknown vendor `%s' specified with `-p'\n", pname, v); - return 1; - } - p = ""; /* force to next argument */ - break; - default: /*bf*/ - fprintf(stderr, "%s: unrecognised option `-%c'\n", - pname, *p); - return 1; - } - } else if (!filename) { - filename = p; - } else { - fprintf(stderr, "%s: more than one filename specified\n", pname); - return 1; - } - } - - if (!filename) { - fprintf(stderr, help, pname); - return 0; - } - - if (strcmp(filename, "-")) { - fp = fopen(filename, "rb"); - if (!fp) { - fprintf(stderr, "%s: unable to open `%s': %s\n", - pname, filename, strerror(errno)); - return 1; - } - } else - fp = stdin; - - if (initskip > 0) - skip (initskip, fp); - - /* - * This main loop is really horrible, and wants rewriting with - * an axe. It'll stay the way it is for a while though, until I - * find the energy... - */ - - p = q = buffer; - nextsync = next_sync (offset, &synclen); - do { - unsigned long to_read = buffer+sizeof(buffer)-p; - if (to_read > nextsync-offset-(p-q)) - to_read = nextsync-offset-(p-q); - if (to_read) { - lenread = fread (p, 1, to_read, fp); - if (lenread == 0) - eof = TRUE; /* help along systems with bad feof */ - } else - lenread = 0; - p += lenread; - if ((unsigned long)offset == nextsync) { - if (synclen) { - fprintf(stdout, "%08lX skipping 0x%lX bytes\n", offset, synclen); - offset += synclen; - skip (synclen, fp); - } - p = q = buffer; - nextsync = next_sync (offset, &synclen); - } - while (p > q && (p - q >= INSN_MAX || lenread == 0)) { - lendis = disasm (q, outbuf, sizeof(outbuf), bits, offset, autosync, prefer); - if (!lendis || lendis > (p - q) || - (unsigned long)lendis > nextsync-offset) - lendis = eatbyte (q, outbuf, sizeof(outbuf)); - output_ins (offset, q, lendis, outbuf); - q += lendis; - offset += lendis; - } - if (q >= buffer+INSN_MAX) { - unsigned char *r = buffer, *s = q; - int count = p - q; - while (count--) - *r++ = *s++; - p -= (q - buffer); - q = buffer; - } - } while (lenread > 0 || !(eof || feof(fp))); - - if (fp != stdin) - fclose (fp); - - return 0; -} - -static void output_ins (unsigned long offset, unsigned char *data, - int datalen, char *insn) -{ - int bytes; - fprintf(stdout, "%08lX ", offset); - - bytes = 0; - while (datalen > 0 && bytes < BPL) { - fprintf(stdout, "%02X", *data++); - bytes++; - datalen--; - } - - fprintf(stdout, "%*s%s\n", (BPL+1-bytes)*2, "", insn); - - while (datalen > 0) { - fprintf(stdout, " -"); - bytes = 0; - while (datalen > 0 && bytes < BPL) { - fprintf(stdout, "%02X", *data++); - bytes++; - datalen--; - } - fprintf(stdout, "\n"); - } -} - -/* - * Skip a certain amount of data in a file, either by seeking if - * possible, or if that fails then by reading and discarding. - */ -static void skip (unsigned long dist, FILE *fp) -{ - char buffer[256]; /* should fit on most stacks :-) */ - - /* - * Got to be careful with fseek: at least one fseek I've tried - * doesn't approve of SEEK_CUR. So I'll use SEEK_SET and - * ftell... horrible but apparently necessary. - */ - if (fseek (fp, dist+ftell(fp), SEEK_SET)) { - while (dist > 0) { - unsigned long len = (dist < sizeof(buffer) ? - dist : sizeof(buffer)); - if (fread (buffer, 1, len, fp) < len) { - perror("fread"); - exit(1); - } - dist -= len; - } - } -} +/* ndisasm.c the Netwide Disassembler main module + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include +#include + +#include "insns.h" +#include "nasm.h" +#include "nasmlib.h" +#include "sync.h" +#include "disasm.h" + +#define BPL 8 /* bytes per line of hex dump */ + +static const char *help = + "usage: ndisasm [-a] [-i] [-h] [-r] [-u] [-b bits] [-o origin] [-s sync...]\n" + " [-e bytes] [-k start,bytes] [-p vendor] file\n" + " -a or -i activates auto (intelligent) sync\n" + " -u sets USE32 (32-bit mode)\n" + " -b 16 or -b 32 sets number of bits too\n" + " -h displays this text\n" + " -r or -v displays the version number\n" + " -e skips bytes of header\n" + " -k avoids disassembling bytes from position \n" + " -p selects the preferred vendor instruction set (intel, amd, cyrix, idt)\n"; + +static void output_ins(unsigned long, unsigned char *, int, char *); +static void skip(unsigned long dist, FILE * fp); + +int main(int argc, char **argv) +{ + unsigned char buffer[INSN_MAX * 2], *p, *q; + char outbuf[256]; + char *pname = *argv; + char *filename = NULL; + unsigned long nextsync, synclen, initskip = 0L; + int lenread; + long lendis; + int autosync = FALSE; + int bits = 16; + int eof = FALSE; + unsigned long prefer = 0; + int rn_error; + long offset; + FILE *fp; + + offset = 0; + init_sync(); + + while (--argc) { + char *v, *vv, *p = *++argv; + if (*p == '-' && p[1]) { + p++; + while (*p) + switch (tolower(*p)) { + case 'a': /* auto or intelligent sync */ + case 'i': + autosync = TRUE; + p++; + break; + case 'h': + fprintf(stderr, help); + return 0; + case 'r': + case 'v': + fprintf(stderr, + "NDISASM version %s compiled " __DATE__ "\n", + NASM_VER); + return 0; + case 'u': /* USE32 */ + bits = 32; + p++; + break; + case 'b': /* bits */ + v = p[1] ? p + 1 : --argc ? *++argv : NULL; + if (!v) { + fprintf(stderr, "%s: `-b' requires an argument\n", + pname); + return 1; + } + if (!strcmp(v, "16")) + bits = 16; + else if (!strcmp(v, "32")) + bits = 32; + else { + fprintf(stderr, "%s: argument to `-b' should" + " be `16' or `32'\n", pname); + } + p = ""; /* force to next argument */ + break; + case 'o': /* origin */ + v = p[1] ? p + 1 : --argc ? *++argv : NULL; + if (!v) { + fprintf(stderr, "%s: `-o' requires an argument\n", + pname); + return 1; + } + offset = readnum(v, &rn_error); + if (rn_error) { + fprintf(stderr, + "%s: `-o' requires a numeric argument\n", + pname); + return 1; + } + p = ""; /* force to next argument */ + break; + case 's': /* sync point */ + v = p[1] ? p + 1 : --argc ? *++argv : NULL; + if (!v) { + fprintf(stderr, "%s: `-s' requires an argument\n", + pname); + return 1; + } + add_sync(readnum(v, &rn_error), 0L); + if (rn_error) { + fprintf(stderr, + "%s: `-s' requires a numeric argument\n", + pname); + return 1; + } + p = ""; /* force to next argument */ + break; + case 'e': /* skip a header */ + v = p[1] ? p + 1 : --argc ? *++argv : NULL; + if (!v) { + fprintf(stderr, "%s: `-e' requires an argument\n", + pname); + return 1; + } + initskip = readnum(v, &rn_error); + if (rn_error) { + fprintf(stderr, + "%s: `-e' requires a numeric argument\n", + pname); + return 1; + } + p = ""; /* force to next argument */ + break; + case 'k': /* skip a region */ + v = p[1] ? p + 1 : --argc ? *++argv : NULL; + if (!v) { + fprintf(stderr, "%s: `-k' requires an argument\n", + pname); + return 1; + } + vv = strchr(v, ','); + if (!vv) { + fprintf(stderr, + "%s: `-k' requires two numbers separated" + " by a comma\n", pname); + return 1; + } + *vv++ = '\0'; + nextsync = readnum(v, &rn_error); + if (rn_error) { + fprintf(stderr, + "%s: `-k' requires numeric arguments\n", + pname); + return 1; + } + synclen = readnum(vv, &rn_error); + if (rn_error) { + fprintf(stderr, + "%s: `-k' requires numeric arguments\n", + pname); + return 1; + } + add_sync(nextsync, synclen); + p = ""; /* force to next argument */ + break; + case 'p': /* preferred vendor */ + v = p[1] ? p + 1 : --argc ? *++argv : NULL; + if (!v) { + fprintf(stderr, "%s: `-p' requires an argument\n", + pname); + return 1; + } + if (!strcmp(v, "intel")) { + prefer = 0; /* Default */ + } else if (!strcmp(v, "amd")) { + prefer = IF_AMD | IF_3DNOW; + } else if (!strcmp(v, "cyrix")) { + prefer = IF_CYRIX | IF_3DNOW; + } else if (!strcmp(v, "idt") || !strcmp(v, "centaur") + || !strcmp(v, "winchip")) { + prefer = IF_3DNOW; + } else { + fprintf(stderr, + "%s: unknown vendor `%s' specified with `-p'\n", + pname, v); + return 1; + } + p = ""; /* force to next argument */ + break; + default: /*bf */ + fprintf(stderr, "%s: unrecognised option `-%c'\n", + pname, *p); + return 1; + } + } else if (!filename) { + filename = p; + } else { + fprintf(stderr, "%s: more than one filename specified\n", + pname); + return 1; + } + } + + if (!filename) { + fprintf(stderr, help, pname); + return 0; + } + + if (strcmp(filename, "-")) { + fp = fopen(filename, "rb"); + if (!fp) { + fprintf(stderr, "%s: unable to open `%s': %s\n", + pname, filename, strerror(errno)); + return 1; + } + } else + fp = stdin; + + if (initskip > 0) + skip(initskip, fp); + + /* + * This main loop is really horrible, and wants rewriting with + * an axe. It'll stay the way it is for a while though, until I + * find the energy... + */ + + p = q = buffer; + nextsync = next_sync(offset, &synclen); + do { + unsigned long to_read = buffer + sizeof(buffer) - p; + if (to_read > nextsync - offset - (p - q)) + to_read = nextsync - offset - (p - q); + if (to_read) { + lenread = fread(p, 1, to_read, fp); + if (lenread == 0) + eof = TRUE; /* help along systems with bad feof */ + } else + lenread = 0; + p += lenread; + if ((unsigned long)offset == nextsync) { + if (synclen) { + fprintf(stdout, "%08lX skipping 0x%lX bytes\n", offset, + synclen); + offset += synclen; + skip(synclen, fp); + } + p = q = buffer; + nextsync = next_sync(offset, &synclen); + } + while (p > q && (p - q >= INSN_MAX || lenread == 0)) { + lendis = + disasm(q, outbuf, sizeof(outbuf), bits, offset, autosync, + prefer); + if (!lendis || lendis > (p - q) + || (unsigned long)lendis > nextsync - offset) + lendis = eatbyte(q, outbuf, sizeof(outbuf)); + output_ins(offset, q, lendis, outbuf); + q += lendis; + offset += lendis; + } + if (q >= buffer + INSN_MAX) { + unsigned char *r = buffer, *s = q; + int count = p - q; + while (count--) + *r++ = *s++; + p -= (q - buffer); + q = buffer; + } + } while (lenread > 0 || !(eof || feof(fp))); + + if (fp != stdin) + fclose(fp); + + return 0; +} + +static void output_ins(unsigned long offset, unsigned char *data, + int datalen, char *insn) +{ + int bytes; + fprintf(stdout, "%08lX ", offset); + + bytes = 0; + while (datalen > 0 && bytes < BPL) { + fprintf(stdout, "%02X", *data++); + bytes++; + datalen--; + } + + fprintf(stdout, "%*s%s\n", (BPL + 1 - bytes) * 2, "", insn); + + while (datalen > 0) { + fprintf(stdout, " -"); + bytes = 0; + while (datalen > 0 && bytes < BPL) { + fprintf(stdout, "%02X", *data++); + bytes++; + datalen--; + } + fprintf(stdout, "\n"); + } +} + +/* + * Skip a certain amount of data in a file, either by seeking if + * possible, or if that fails then by reading and discarding. + */ +static void skip(unsigned long dist, FILE * fp) +{ + char buffer[256]; /* should fit on most stacks :-) */ + + /* + * Got to be careful with fseek: at least one fseek I've tried + * doesn't approve of SEEK_CUR. So I'll use SEEK_SET and + * ftell... horrible but apparently necessary. + */ + if (fseek(fp, dist + ftell(fp), SEEK_SET)) { + while (dist > 0) { + unsigned long len = (dist < sizeof(buffer) ? + dist : sizeof(buffer)); + if (fread(buffer, 1, len, fp) < len) { + perror("fread"); + exit(1); + } + dist -= len; + } + } +} diff --git a/outform.c b/outform.c index c8b95323..9216a8f9 100644 --- a/outform.c +++ b/outform.c @@ -17,54 +17,52 @@ static int ndrivers = 0; -struct ofmt *ofmt_find(char *name) /* find driver */ -{ +struct ofmt *ofmt_find(char *name) +{ /* find driver */ int i; - for (i=0; ishortname)) - return drivers[i]; + for (i = 0; i < ndrivers; i++) + if (!strcmp(name, drivers[i]->shortname)) + return drivers[i]; return NULL; } -struct dfmt *dfmt_find(struct ofmt *ofmt, char *name) /* find driver */ -{ +struct dfmt *dfmt_find(struct ofmt *ofmt, char *name) +{ /* find driver */ struct dfmt **dfmt = ofmt->debug_formats; while (*dfmt) { - if (!strcmp(name, (*dfmt)->shortname)) - return (*dfmt); - dfmt++; + if (!strcmp(name, (*dfmt)->shortname)) + return (*dfmt); + dfmt++; } return NULL; } -void ofmt_list(struct ofmt *deffmt, FILE *fp) +void ofmt_list(struct ofmt *deffmt, FILE * fp) { int i; - for (i=0; ishortname, - drivers[i]->fullname); + for (i = 0; i < ndrivers; i++) + fprintf(fp, " %c %-10s%s\n", + drivers[i] == deffmt ? '*' : ' ', + drivers[i]->shortname, drivers[i]->fullname); } -void dfmt_list(struct ofmt *ofmt, FILE *fp) +void dfmt_list(struct ofmt *ofmt, FILE * fp) { - struct dfmt ** drivers = ofmt->debug_formats; + struct dfmt **drivers = ofmt->debug_formats; while (*drivers) { - fprintf(fp, " %c %-10s%s\n", - drivers[0] == ofmt->current_dfmt ? '*' : ' ', - drivers[0]->shortname, - drivers[0]->fullname); - drivers++; + fprintf(fp, " %c %-10s%s\n", + drivers[0] == ofmt->current_dfmt ? '*' : ' ', + drivers[0]->shortname, drivers[0]->fullname); + drivers++; } } -struct ofmt *ofmt_register (efunc error) { - for (ndrivers=0; drivers[ndrivers] != NULL; ndrivers++); +struct ofmt *ofmt_register(efunc error) +{ + for (ndrivers = 0; drivers[ndrivers] != NULL; ndrivers++) ; - if (ndrivers==0) - { + if (ndrivers == 0) { error(ERR_PANIC | ERR_NOFILE, - "No output drivers given at compile time"); + "No output drivers given at compile time"); } return (&OF_DEFAULT); diff --git a/outform.h b/outform.h index 7da8e32c..28cab329 100644 --- a/outform.h +++ b/outform.h @@ -63,11 +63,11 @@ #ifndef OF_ONLY #ifndef OF_ALL -#define OF_ALL /* default is to have all formats */ +#define OF_ALL /* default is to have all formats */ #endif #endif -#ifdef OF_ALL /* set all formats on... */ +#ifdef OF_ALL /* set all formats on... */ #ifndef OF_BIN #define OF_BIN #endif @@ -98,7 +98,7 @@ #ifndef OF_IEEE #define OF_IEEE #endif -#endif /* OF_ALL */ +#endif /* OF_ALL */ /* turn on groups of formats specified.... */ #ifdef OF_DOS @@ -179,7 +179,7 @@ #define OF_DEFAULT of_bin #endif -#ifdef BUILD_DRIVERS_ARRAY /* only if included from outform.c */ +#ifdef BUILD_DRIVERS_ARRAY /* only if included from outform.c */ /* pull in the externs for the different formats, then make the *drivers * array based on the above defines */ @@ -196,7 +196,7 @@ extern struct ofmt of_rdf2; extern struct ofmt of_ieee; extern struct ofmt of_dbg; -struct ofmt *drivers[]={ +struct ofmt *drivers[] = { #ifdef OF_BIN &of_bin, #endif @@ -231,15 +231,15 @@ struct ofmt *drivers[]={ &of_dbg, #endif - NULL + NULL }; -#endif /* BUILD_DRIVERS_ARRAY */ +#endif /* BUILD_DRIVERS_ARRAY */ struct ofmt *ofmt_find(char *); struct dfmt *dfmt_find(struct ofmt *, char *); void ofmt_list(struct ofmt *, FILE *); -void dfmt_list(struct ofmt *ofmt, FILE *fp); -struct ofmt *ofmt_register (efunc error); +void dfmt_list(struct ofmt *ofmt, FILE * fp); +struct ofmt *ofmt_register(efunc error); -#endif /* NASM_OUTFORM_H */ +#endif /* NASM_OUTFORM_H */ diff --git a/output/outaout.c b/output/outaout.c index 24e2b581..dabfe1f9 100644 --- a/output/outaout.c +++ b/output/outaout.c @@ -28,41 +28,41 @@ struct Reloc { struct Reloc *next; - long address; /* relative to _start_ of section */ - long symbol; /* symbol number or -ve section id */ - int bytes; /* 2 or 4 */ - int reltype; /* see above */ + long address; /* relative to _start_ of section */ + long symbol; /* symbol number or -ve section id */ + int bytes; /* 2 or 4 */ + int reltype; /* see above */ }; struct Symbol { - long strpos; /* string table position of name */ - int type; /* symbol type - see flags below */ - long value; /* address, or COMMON variable size */ - long size; /* size for data or function exports */ - long segment; /* back-reference used by gsym_reloc */ - struct Symbol *next; /* list of globals in each section */ - struct Symbol *nextfwd; /* list of unresolved-size symbols */ - char *name; /* for unresolved-size symbols */ - long symnum; /* index into symbol table */ + long strpos; /* string table position of name */ + int type; /* symbol type - see flags below */ + long value; /* address, or COMMON variable size */ + long size; /* size for data or function exports */ + long segment; /* back-reference used by gsym_reloc */ + struct Symbol *next; /* list of globals in each section */ + struct Symbol *nextfwd; /* list of unresolved-size symbols */ + char *name; /* for unresolved-size symbols */ + long symnum; /* index into symbol table */ }; /* * Section IDs - used in Reloc.symbol when negative, and in * Symbol.type when positive. */ -#define SECT_ABS 2 /* absolute value */ -#define SECT_TEXT 4 /* text section */ -#define SECT_DATA 6 /* data section */ -#define SECT_BSS 8 /* bss section */ -#define SECT_MASK 0xE /* mask out any of the above */ +#define SECT_ABS 2 /* absolute value */ +#define SECT_TEXT 4 /* text section */ +#define SECT_DATA 6 /* data section */ +#define SECT_BSS 8 /* bss section */ +#define SECT_MASK 0xE /* mask out any of the above */ /* * More flags used in Symbol.type. */ -#define SYM_GLOBAL 1 /* it's a global symbol */ -#define SYM_DATA 0x100 /* used for shared libs */ -#define SYM_FUNCTION 0x200 /* used for shared libs */ -#define SYM_WITH_SIZE 0x4000 /* not output; internal only */ +#define SYM_GLOBAL 1 /* it's a global symbol */ +#define SYM_DATA 0x100 /* used for shared libs */ +#define SYM_FUNCTION 0x200 /* used for shared libs */ +#define SYM_WITH_SIZE 0x4000 /* not output; internal only */ /* * Bit more explanation of symbol types: SECT_xxx denotes a local @@ -103,7 +103,8 @@ static int is_pic; static void aout_write(void); static void aout_write_relocs(struct Reloc *); static void aout_write_syms(void); -static void aout_sect_write(struct Section *, const unsigned char *, unsigned long); +static void aout_sect_write(struct Section *, const unsigned char *, + unsigned long); static void aout_pad_sections(void); static void aout_fixup_relocs(struct Section *); @@ -116,14 +117,19 @@ static long aout_gotpc_sect, aout_gotoff_sect; static long aout_got_sect, aout_plt_sect; static long aout_sym_sect; -static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +static void aoutg_init(FILE * fp, efunc errfunc, ldfunc ldef, + evalfunc eval) { aoutfp = fp; error = errfunc; evaluate = eval; - (void) ldef; /* placate optimisers */ - stext.data = saa_init(1L); stext.head = NULL; stext.tail = &stext.head; - sdata.data = saa_init(1L); sdata.head = NULL; sdata.tail = &sdata.head; + (void)ldef; /* placate optimisers */ + stext.data = saa_init(1L); + stext.head = NULL; + stext.tail = &stext.head; + sdata.data = saa_init(1L); + sdata.head = NULL; + sdata.tail = &sdata.head; stext.len = stext.size = sdata.len = sdata.size = sbss.len = 0; stext.nrelocs = sdata.nrelocs = 0; stext.gsyms = sdata.gsyms = sbss.gsyms = NULL; @@ -141,13 +147,13 @@ static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) #ifdef OF_AOUT -static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +static void aout_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval) { bsd = FALSE; - aoutg_init (fp, errfunc, ldef, eval); + aoutg_init(fp, errfunc, ldef, eval); aout_gotpc_sect = aout_gotoff_sect = aout_got_sect = - aout_plt_sect = aout_sym_sect = NO_SEG; + aout_plt_sect = aout_sym_sect = NO_SEG; } #endif @@ -156,224 +162,233 @@ static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) extern struct ofmt of_aoutb; -static void aoutb_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +static void aoutb_init(FILE * fp, efunc errfunc, ldfunc ldef, + evalfunc eval) { bsd = TRUE; - aoutg_init (fp, errfunc, ldef, eval); + aoutg_init(fp, errfunc, ldef, eval); - is_pic = 0x00; /* may become 0x40 */ + is_pic = 0x00; /* may become 0x40 */ aout_gotpc_sect = seg_alloc(); - ldef("..gotpc", aout_gotpc_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error); + ldef("..gotpc", aout_gotpc_sect + 1, 0L, NULL, FALSE, FALSE, &of_aoutb, + error); aout_gotoff_sect = seg_alloc(); - ldef("..gotoff", aout_gotoff_sect+1, 0L,NULL,FALSE,FALSE,&of_aoutb,error); + ldef("..gotoff", aout_gotoff_sect + 1, 0L, NULL, FALSE, FALSE, + &of_aoutb, error); aout_got_sect = seg_alloc(); - ldef("..got", aout_got_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error); + ldef("..got", aout_got_sect + 1, 0L, NULL, FALSE, FALSE, &of_aoutb, + error); aout_plt_sect = seg_alloc(); - ldef("..plt", aout_plt_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error); + ldef("..plt", aout_plt_sect + 1, 0L, NULL, FALSE, FALSE, &of_aoutb, + error); aout_sym_sect = seg_alloc(); - ldef("..sym", aout_sym_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error); + ldef("..sym", aout_sym_sect + 1, 0L, NULL, FALSE, FALSE, &of_aoutb, + error); } #endif -static void aout_cleanup(int debuginfo) +static void aout_cleanup(int debuginfo) { struct Reloc *r; - (void) debuginfo; + (void)debuginfo; aout_pad_sections(); aout_fixup_relocs(&stext); aout_fixup_relocs(&sdata); aout_write(); - fclose (aoutfp); - saa_free (stext.data); + fclose(aoutfp); + saa_free(stext.data); while (stext.head) { - r = stext.head; - stext.head = stext.head->next; - nasm_free (r); + r = stext.head; + stext.head = stext.head->next; + nasm_free(r); } - saa_free (sdata.data); + saa_free(sdata.data); while (sdata.head) { - r = sdata.head; - sdata.head = sdata.head->next; - nasm_free (r); + r = sdata.head; + sdata.head = sdata.head->next; + nasm_free(r); } - saa_free (syms); - raa_free (bsym); - saa_free (strs); + saa_free(syms); + raa_free(bsym); + saa_free(strs); } -static long aout_section_names (char *name, int pass, int *bits) +static long aout_section_names(char *name, int pass, int *bits) { /* * Default to 32 bits. */ if (!name) - *bits = 32; + *bits = 32; if (!name) - return stext.index; + return stext.index; if (!strcmp(name, ".text")) - return stext.index; + return stext.index; else if (!strcmp(name, ".data")) - return sdata.index; + return sdata.index; else if (!strcmp(name, ".bss")) - return sbss.index; + return sbss.index; else - return NO_SEG; + return NO_SEG; } -static void aout_deflabel (char *name, long segment, long offset, - int is_global, char *special) +static void aout_deflabel(char *name, long segment, long offset, + int is_global, char *special) { - int pos = strslen+4; + int pos = strslen + 4; struct Symbol *sym; int special_used = FALSE; if (name[0] == '.' && name[1] == '.' && name[2] != '@') { - /* - * This is a NASM special symbol. We never allow it into - * the a.out symbol table, even if it's a valid one. If it - * _isn't_ a valid one, we should barf immediately. - */ - if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") && - strcmp(name, "..got") && strcmp(name, "..plt") && - strcmp(name, "..sym")) - error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); - return; + /* + * This is a NASM special symbol. We never allow it into + * the a.out symbol table, even if it's a valid one. If it + * _isn't_ a valid one, we should barf immediately. + */ + if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") && + strcmp(name, "..got") && strcmp(name, "..plt") && + strcmp(name, "..sym")) + error(ERR_NONFATAL, "unrecognised special symbol `%s'", name); + return; } if (is_global == 3) { - struct Symbol **s; - /* - * Fix up a forward-reference symbol size from the first - * pass. - */ - for (s = &fwds; *s; s = &(*s)->nextfwd) - if (!strcmp((*s)->name, name)) { - struct tokenval tokval; - expr *e; - char *p = special; - - while (*p && !isspace(*p)) p++; - while (*p && isspace(*p)) p++; - stdscan_reset(); - stdscan_bufptr = p; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); - if (e) { - if (!is_simple(e)) - error (ERR_NONFATAL, "cannot use relocatable" - " expression as symbol size"); - else - (*s)->size = reloc_value(e); - } - - /* - * Remove it from the list of unresolved sizes. - */ - nasm_free ((*s)->name); - *s = (*s)->nextfwd; - return; - } - return; /* it wasn't an important one */ + struct Symbol **s; + /* + * Fix up a forward-reference symbol size from the first + * pass. + */ + for (s = &fwds; *s; s = &(*s)->nextfwd) + if (!strcmp((*s)->name, name)) { + struct tokenval tokval; + expr *e; + char *p = special; + + while (*p && !isspace(*p)) + p++; + while (*p && isspace(*p)) + p++; + stdscan_reset(); + stdscan_bufptr = p; + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); + if (e) { + if (!is_simple(e)) + error(ERR_NONFATAL, "cannot use relocatable" + " expression as symbol size"); + else + (*s)->size = reloc_value(e); + } + + /* + * Remove it from the list of unresolved sizes. + */ + nasm_free((*s)->name); + *s = (*s)->nextfwd; + return; + } + return; /* it wasn't an important one */ } - saa_wbytes (strs, name, (long)(1+strlen(name))); - strslen += 1+strlen(name); + saa_wbytes(strs, name, (long)(1 + strlen(name))); + strslen += 1 + strlen(name); - sym = saa_wstruct (syms); + sym = saa_wstruct(syms); sym->strpos = pos; sym->type = is_global ? SYM_GLOBAL : 0; sym->segment = segment; if (segment == NO_SEG) - sym->type |= SECT_ABS; + sym->type |= SECT_ABS; else if (segment == stext.index) { - sym->type |= SECT_TEXT; - if (is_global) { - sym->next = stext.gsyms; - stext.gsyms = sym; - } else if (!stext.asym) - stext.asym = sym; + sym->type |= SECT_TEXT; + if (is_global) { + sym->next = stext.gsyms; + stext.gsyms = sym; + } else if (!stext.asym) + stext.asym = sym; } else if (segment == sdata.index) { - sym->type |= SECT_DATA; - if (is_global) { - sym->next = sdata.gsyms; - sdata.gsyms = sym; - } else if (!sdata.asym) - sdata.asym = sym; + sym->type |= SECT_DATA; + if (is_global) { + sym->next = sdata.gsyms; + sdata.gsyms = sym; + } else if (!sdata.asym) + sdata.asym = sym; } else if (segment == sbss.index) { - sym->type |= SECT_BSS; - if (is_global) { - sym->next = sbss.gsyms; - sbss.gsyms = sym; - } else if (!sbss.asym) - sbss.asym = sym; + sym->type |= SECT_BSS; + if (is_global) { + sym->next = sbss.gsyms; + sbss.gsyms = sym; + } else if (!sbss.asym) + sbss.asym = sym; } else - sym->type = SYM_GLOBAL; + sym->type = SYM_GLOBAL; if (is_global == 2) - sym->value = offset; + sym->value = offset; else - sym->value = (sym->type == SYM_GLOBAL ? 0 : offset); + sym->value = (sym->type == SYM_GLOBAL ? 0 : offset); if (is_global && sym->type != SYM_GLOBAL) { - /* - * Global symbol exported _from_ this module. We must check - * the special text for type information. - */ - - if (special) { - int n = strcspn(special, " "); - - if (!nasm_strnicmp(special, "function", n)) - sym->type |= SYM_FUNCTION; - else if (!nasm_strnicmp(special, "data", n) || - !nasm_strnicmp(special, "object", n)) - sym->type |= SYM_DATA; - else - error(ERR_NONFATAL, "unrecognised symbol type `%.*s'", - n, special); - if (special[n]) { - struct tokenval tokval; - expr *e; - int fwd = FALSE; - char *saveme=stdscan_bufptr; /* bugfix? fbk 8/10/00 */ - - if (!bsd) { - error(ERR_NONFATAL, "Linux a.out does not support" - " symbol size information"); - } else { - while (special[n] && isspace(special[n])) - n++; - /* - * We have a size expression; attempt to - * evaluate it. - */ - sym->type |= SYM_WITH_SIZE; - stdscan_reset(); - stdscan_bufptr = special+n; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error, NULL); - if (fwd) { - sym->nextfwd = fwds; - fwds = sym; - sym->name = nasm_strdup(name); - } else if (e) { - if (!is_simple(e)) - error (ERR_NONFATAL, "cannot use relocatable" - " expression as symbol size"); - else - sym->size = reloc_value(e); - } - } - stdscan_bufptr=saveme; /* bugfix? fbk 8/10/00 */ - } - special_used = TRUE; - } + /* + * Global symbol exported _from_ this module. We must check + * the special text for type information. + */ + + if (special) { + int n = strcspn(special, " "); + + if (!nasm_strnicmp(special, "function", n)) + sym->type |= SYM_FUNCTION; + else if (!nasm_strnicmp(special, "data", n) || + !nasm_strnicmp(special, "object", n)) + sym->type |= SYM_DATA; + else + error(ERR_NONFATAL, "unrecognised symbol type `%.*s'", + n, special); + if (special[n]) { + struct tokenval tokval; + expr *e; + int fwd = FALSE; + char *saveme = stdscan_bufptr; /* bugfix? fbk 8/10/00 */ + + if (!bsd) { + error(ERR_NONFATAL, "Linux a.out does not support" + " symbol size information"); + } else { + while (special[n] && isspace(special[n])) + n++; + /* + * We have a size expression; attempt to + * evaluate it. + */ + sym->type |= SYM_WITH_SIZE; + stdscan_reset(); + stdscan_bufptr = special + n; + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error, + NULL); + if (fwd) { + sym->nextfwd = fwds; + fwds = sym; + sym->name = nasm_strdup(name); + } else if (e) { + if (!is_simple(e)) + error(ERR_NONFATAL, "cannot use relocatable" + " expression as symbol size"); + else + sym->size = reloc_value(e); + } + } + stdscan_bufptr = saveme; /* bugfix? fbk 8/10/00 */ + } + special_used = TRUE; + } } /* @@ -381,20 +396,20 @@ static void aout_deflabel (char *name, long segment, long offset, * to these symbol records. */ if (segment != NO_SEG && segment != stext.index && - segment != sdata.index && segment != sbss.index) - bsym = raa_write (bsym, segment, nsyms); + segment != sdata.index && segment != sbss.index) + bsym = raa_write(bsym, segment, nsyms); sym->symnum = nsyms; nsyms++; if (sym->type & SYM_WITH_SIZE) - nsyms++; /* and another for the size */ + nsyms++; /* and another for the size */ if (special && !special_used) - error(ERR_NONFATAL, "no special symbol features supported here"); + error(ERR_NONFATAL, "no special symbol features supported here"); } -static void aout_add_reloc (struct Section *sect, long segment, - int reltype, int bytes) +static void aout_add_reloc(struct Section *sect, long segment, + int reltype, int bytes) { struct Reloc *r; @@ -404,13 +419,13 @@ static void aout_add_reloc (struct Section *sect, long segment, r->address = sect->len; r->symbol = (segment == NO_SEG ? -SECT_ABS : - segment == stext.index ? -SECT_TEXT : - segment == sdata.index ? -SECT_DATA : - segment == sbss.index ? -SECT_BSS : - raa_read(bsym, segment)); + segment == stext.index ? -SECT_TEXT : + segment == sdata.index ? -SECT_DATA : + segment == sbss.index ? -SECT_BSS : + raa_read(bsym, segment)); r->reltype = reltype; if (r->symbol >= 0) - r->reltype |= RELTYPE_SYMFLAG; + r->reltype |= RELTYPE_SYMFLAG; r->bytes = bytes; sect->nrelocs++; @@ -438,9 +453,9 @@ static void aout_add_reloc (struct Section *sect, long segment, * Inefficiency: we search, currently, using a linked list which * isn't even necessarily sorted. */ -static long aout_add_gsym_reloc (struct Section *sect, - long segment, long offset, - int type, int bytes, int exact) +static long aout_add_gsym_reloc(struct Section *sect, + long segment, long offset, + int type, int bytes, int exact) { struct Symbol *sym, *sm, *shead; struct Reloc *r; @@ -451,40 +466,40 @@ static long aout_add_gsym_reloc (struct Section *sect, */ shead = NULL; if (segment == stext.index) - shead = stext.gsyms; + shead = stext.gsyms; else if (segment == sdata.index) - shead = sdata.gsyms; + shead = sdata.gsyms; else if (segment == sbss.index) - shead = sbss.gsyms; + shead = sbss.gsyms; if (!shead) { - if (exact && offset != 0) - error (ERR_NONFATAL, "unable to find a suitable global symbol" - " for this reference"); - else - aout_add_reloc (sect, segment, type, bytes); - return offset; + if (exact && offset != 0) + error(ERR_NONFATAL, "unable to find a suitable global symbol" + " for this reference"); + else + aout_add_reloc(sect, segment, type, bytes); + return offset; } if (exact) { - /* - * Find a symbol pointing _exactly_ at this one. - */ - for (sym = shead; sym; sym = sym->next) - if (sym->value == offset) - break; + /* + * Find a symbol pointing _exactly_ at this one. + */ + for (sym = shead; sym; sym = sym->next) + if (sym->value == offset) + break; } else { - /* - * Find the nearest symbol below this one. - */ - sym = NULL; - for (sm = shead; sm; sm = sm->next) - if (sm->value <= offset && (!sym || sm->value > sym->value)) - sym = sm; + /* + * Find the nearest symbol below this one. + */ + sym = NULL; + for (sm = shead; sm; sm = sm->next) + if (sm->value <= offset && (!sym || sm->value > sym->value)) + sym = sm; } if (!sym && exact) { - error (ERR_NONFATAL, "unable to find a suitable global symbol" - " for this reference"); - return 0; + error(ERR_NONFATAL, "unable to find a suitable global symbol" + " for this reference"); + return 0; } r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); @@ -511,8 +526,8 @@ static long aout_add_gsym_reloc (struct Section *sect, * Return value is the adjusted value of `addr', having become an * offset from the `asym' symbol rather than the section. */ -static long aout_add_gotoff_reloc (struct Section *sect, long segment, - long offset, int bytes) +static long aout_add_gotoff_reloc(struct Section *sect, long segment, + long offset, int bytes) { struct Reloc *r; struct Symbol *asym; @@ -523,14 +538,14 @@ static long aout_add_gotoff_reloc (struct Section *sect, long segment, */ asym = NULL; if (segment == stext.index) - asym = stext.asym; + asym = stext.asym; else if (segment == sdata.index) - asym = sdata.asym; + asym = sdata.asym; else if (segment == sbss.index) - asym = sbss.asym; + asym = sbss.asym; if (!asym) - error (ERR_NONFATAL, "`..gotoff' relocations require a non-global" - " symbol in the section"); + error(ERR_NONFATAL, "`..gotoff' relocations require a non-global" + " symbol in the section"); r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); sect->tail = &r->next; @@ -546,8 +561,8 @@ static long aout_add_gotoff_reloc (struct Section *sect, long segment, return offset - asym->value; } -static void aout_out (long segto, const void *data, unsigned long type, - long segment, long wrt) +static void aout_out(long segto, const void *data, unsigned long type, + long segment, long wrt) { struct Section *s; long realbytes = type & OUT_SIZMASK; @@ -560,156 +575,161 @@ static void aout_out (long segto, const void *data, unsigned long type, * handle absolute-assembly (structure definitions) */ if (segto == NO_SEG) { - if (type != OUT_RESERVE) - error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" - " space"); - return; + if (type != OUT_RESERVE) + error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" + " space"); + return; } if (segto == stext.index) - s = &stext; + s = &stext; else if (segto == sdata.index) - s = &sdata; + s = &sdata; else if (segto == sbss.index) - s = NULL; + s = NULL; else { - error(ERR_WARNING, "attempt to assemble code in" - " segment %d: defaulting to `.text'", segto); - s = &stext; + error(ERR_WARNING, "attempt to assemble code in" + " segment %d: defaulting to `.text'", segto); + s = &stext; } if (!s && type != OUT_RESERVE) { - error(ERR_WARNING, "attempt to initialise memory in the" - " BSS section: ignored"); - if (type == OUT_REL2ADR) - realbytes = 2; - else if (type == OUT_REL4ADR) - realbytes = 4; - sbss.len += realbytes; - return; + error(ERR_WARNING, "attempt to initialise memory in the" + " BSS section: ignored"); + if (type == OUT_REL2ADR) + realbytes = 2; + else if (type == OUT_REL4ADR) + realbytes = 4; + sbss.len += realbytes; + return; } if (type == OUT_RESERVE) { - if (s) { - error(ERR_WARNING, "uninitialised space declared in" - " %s section: zeroing", - (segto == stext.index ? "code" : "data")); - aout_sect_write (s, NULL, realbytes); - } else - sbss.len += realbytes; + if (s) { + error(ERR_WARNING, "uninitialised space declared in" + " %s section: zeroing", + (segto == stext.index ? "code" : "data")); + aout_sect_write(s, NULL, realbytes); + } else + sbss.len += realbytes; } else if (type == OUT_RAWDATA) { - if (segment != NO_SEG) - error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); - aout_sect_write (s, data, realbytes); + if (segment != NO_SEG) + error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); + aout_sect_write(s, data, realbytes); } else if (type == OUT_ADDRESS) { - addr = *(long *)data; - if (segment != NO_SEG) { - if (segment % 2) { - error(ERR_NONFATAL, "a.out format does not support" - " segment base references"); - } else { - if (wrt == NO_SEG) { - aout_add_reloc (s, segment, RELTYPE_ABSOLUTE, realbytes); - } else if (!bsd) { - error (ERR_NONFATAL, "Linux a.out format does not support" - " any use of WRT"); - wrt = NO_SEG; /* we can at least _try_ to continue */ - } else if (wrt == aout_gotpc_sect+1) { - is_pic = 0x40; - aout_add_reloc (s, segment, RELTYPE_GOTPC, realbytes); - } else if (wrt == aout_gotoff_sect+1) { - is_pic = 0x40; - addr = aout_add_gotoff_reloc (s, segment, - addr, realbytes); - } else if (wrt == aout_got_sect+1) { - is_pic = 0x40; - addr = aout_add_gsym_reloc (s, segment, addr, RELTYPE_GOT, - realbytes, TRUE); - } else if (wrt == aout_sym_sect+1) { - addr = aout_add_gsym_reloc (s, segment, addr, - RELTYPE_ABSOLUTE, realbytes, - FALSE); - } else if (wrt == aout_plt_sect+1) { - is_pic = 0x40; - error(ERR_NONFATAL, "a.out format cannot produce non-PC-" - "relative PLT references"); - } else { - error (ERR_NONFATAL, "a.out format does not support this" - " use of WRT"); - wrt = NO_SEG; /* we can at least _try_ to continue */ - } - } - } - p = mydata; - if (realbytes == 2) - WRITESHORT (p, addr); - else - WRITELONG (p, addr); - aout_sect_write (s, mydata, realbytes); + addr = *(long *)data; + if (segment != NO_SEG) { + if (segment % 2) { + error(ERR_NONFATAL, "a.out format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + aout_add_reloc(s, segment, RELTYPE_ABSOLUTE, + realbytes); + } else if (!bsd) { + error(ERR_NONFATAL, + "Linux a.out format does not support" + " any use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } else if (wrt == aout_gotpc_sect + 1) { + is_pic = 0x40; + aout_add_reloc(s, segment, RELTYPE_GOTPC, realbytes); + } else if (wrt == aout_gotoff_sect + 1) { + is_pic = 0x40; + addr = aout_add_gotoff_reloc(s, segment, + addr, realbytes); + } else if (wrt == aout_got_sect + 1) { + is_pic = 0x40; + addr = + aout_add_gsym_reloc(s, segment, addr, RELTYPE_GOT, + realbytes, TRUE); + } else if (wrt == aout_sym_sect + 1) { + addr = aout_add_gsym_reloc(s, segment, addr, + RELTYPE_ABSOLUTE, realbytes, + FALSE); + } else if (wrt == aout_plt_sect + 1) { + is_pic = 0x40; + error(ERR_NONFATAL, + "a.out format cannot produce non-PC-" + "relative PLT references"); + } else { + error(ERR_NONFATAL, + "a.out format does not support this" + " use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } + } + } + p = mydata; + if (realbytes == 2) + WRITESHORT(p, addr); + else + WRITELONG(p, addr); + aout_sect_write(s, mydata, realbytes); } else if (type == OUT_REL2ADR) { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL2ADR"); - if (segment != NO_SEG && segment % 2) { - error(ERR_NONFATAL, "a.out format does not support" - " segment base references"); - } else { - if (wrt == NO_SEG) { - aout_add_reloc (s, segment, RELTYPE_RELATIVE, 2); - } else if (!bsd) { - error (ERR_NONFATAL, "Linux a.out format does not support" - " any use of WRT"); - wrt = NO_SEG; /* we can at least _try_ to continue */ - } else if (wrt == aout_plt_sect+1) { - is_pic = 0x40; - aout_add_reloc (s, segment, RELTYPE_PLT, 2); - } else if (wrt == aout_gotpc_sect+1 || - wrt == aout_gotoff_sect+1 || - wrt == aout_got_sect+1) { - error(ERR_NONFATAL, "a.out format cannot produce PC-" - "relative GOT references"); - } else { - error (ERR_NONFATAL, "a.out format does not support this" - " use of WRT"); - wrt = NO_SEG; /* we can at least _try_ to continue */ - } - } - p = mydata; - WRITESHORT (p, *(long*)data-(realbytes + s->len)); - aout_sect_write (s, mydata, 2L); + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL2ADR"); + if (segment != NO_SEG && segment % 2) { + error(ERR_NONFATAL, "a.out format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + aout_add_reloc(s, segment, RELTYPE_RELATIVE, 2); + } else if (!bsd) { + error(ERR_NONFATAL, "Linux a.out format does not support" + " any use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } else if (wrt == aout_plt_sect + 1) { + is_pic = 0x40; + aout_add_reloc(s, segment, RELTYPE_PLT, 2); + } else if (wrt == aout_gotpc_sect + 1 || + wrt == aout_gotoff_sect + 1 || + wrt == aout_got_sect + 1) { + error(ERR_NONFATAL, "a.out format cannot produce PC-" + "relative GOT references"); + } else { + error(ERR_NONFATAL, "a.out format does not support this" + " use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } + } + p = mydata; + WRITESHORT(p, *(long *)data - (realbytes + s->len)); + aout_sect_write(s, mydata, 2L); } else if (type == OUT_REL4ADR) { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL4ADR"); - if (segment != NO_SEG && segment % 2) { - error(ERR_NONFATAL, "a.out format does not support" - " segment base references"); - } else { - if (wrt == NO_SEG) { - aout_add_reloc (s, segment, RELTYPE_RELATIVE, 4); - } else if (!bsd) { - error (ERR_NONFATAL, "Linux a.out format does not support" - " any use of WRT"); - wrt = NO_SEG; /* we can at least _try_ to continue */ - } else if (wrt == aout_plt_sect+1) { - is_pic = 0x40; - aout_add_reloc (s, segment, RELTYPE_PLT, 4); - } else if (wrt == aout_gotpc_sect+1 || - wrt == aout_gotoff_sect+1 || - wrt == aout_got_sect+1) { - error(ERR_NONFATAL, "a.out format cannot produce PC-" - "relative GOT references"); - } else { - error (ERR_NONFATAL, "a.out format does not support this" - " use of WRT"); - wrt = NO_SEG; /* we can at least _try_ to continue */ - } - } - p = mydata; - WRITELONG (p, *(long*)data-(realbytes + s->len)); - aout_sect_write (s, mydata, 4L); + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL4ADR"); + if (segment != NO_SEG && segment % 2) { + error(ERR_NONFATAL, "a.out format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + aout_add_reloc(s, segment, RELTYPE_RELATIVE, 4); + } else if (!bsd) { + error(ERR_NONFATAL, "Linux a.out format does not support" + " any use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } else if (wrt == aout_plt_sect + 1) { + is_pic = 0x40; + aout_add_reloc(s, segment, RELTYPE_PLT, 4); + } else if (wrt == aout_gotpc_sect + 1 || + wrt == aout_gotoff_sect + 1 || + wrt == aout_got_sect + 1) { + error(ERR_NONFATAL, "a.out format cannot produce PC-" + "relative GOT references"); + } else { + error(ERR_NONFATAL, "a.out format does not support this" + " use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } + } + p = mydata; + WRITELONG(p, *(long *)data - (realbytes + s->len)); + aout_sect_write(s, mydata, 4L); } } -static void aout_pad_sections(void) +static void aout_pad_sections(void) { static unsigned char pad[] = { 0x90, 0x90, 0x90, 0x90 }; /* @@ -717,8 +737,8 @@ static void aout_pad_sections(void) * length is a multiple of four. (NOP == 0x90.) Also increase * the length of the BSS section similarly. */ - aout_sect_write (&stext, pad, (-(long)stext.len) & 3); - aout_sect_write (&sdata, pad, (-(long)sdata.len) & 3); + aout_sect_write(&stext, pad, (-(long)stext.len) & 3); + aout_sect_write(&sdata, pad, (-(long)sdata.len) & 3); sbss.len = (sbss.len + 3) & ~3; } @@ -731,148 +751,148 @@ static void aout_pad_sections(void) * 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) +static void aout_fixup_relocs(struct Section *sect) { struct Reloc *r; - saa_rewind (sect->data); + 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); + 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 aout_write(void) +static void aout_write(void) { /* * Emit the a.out header. */ /* OMAGIC, M_386 or MID_I386, no flags */ - fwritelong (bsd ? 0x07018600 | is_pic : 0x640107L, aoutfp); - fwritelong (stext.len, aoutfp); - fwritelong (sdata.len, aoutfp); - fwritelong (sbss.len, aoutfp); - fwritelong (nsyms * 12, aoutfp); /* length of symbol table */ - fwritelong (0L, aoutfp); /* object files have no entry point */ - fwritelong (stext.nrelocs * 8, aoutfp); /* size of text relocs */ - fwritelong (sdata.nrelocs * 8, aoutfp); /* size of data relocs */ + fwritelong(bsd ? 0x07018600 | is_pic : 0x640107L, aoutfp); + fwritelong(stext.len, aoutfp); + fwritelong(sdata.len, aoutfp); + fwritelong(sbss.len, aoutfp); + fwritelong(nsyms * 12, aoutfp); /* length of symbol table */ + fwritelong(0L, aoutfp); /* object files have no entry point */ + fwritelong(stext.nrelocs * 8, aoutfp); /* size of text relocs */ + fwritelong(sdata.nrelocs * 8, aoutfp); /* size of data relocs */ /* * Write out the code section and the data section. */ - saa_fpwrite (stext.data, aoutfp); - saa_fpwrite (sdata.data, aoutfp); + saa_fpwrite(stext.data, aoutfp); + saa_fpwrite(sdata.data, aoutfp); /* * Write out the relocations. */ - aout_write_relocs (stext.head); - aout_write_relocs (sdata.head); + aout_write_relocs(stext.head); + aout_write_relocs(sdata.head); /* * Write the symbol table. */ - aout_write_syms (); + aout_write_syms(); /* * And the string table. */ - fwritelong (strslen+4, aoutfp); /* length includes length count */ - saa_fpwrite (strs, aoutfp); + fwritelong(strslen + 4, aoutfp); /* length includes length count */ + saa_fpwrite(strs, aoutfp); } -static void aout_write_relocs (struct Reloc *r) +static void aout_write_relocs(struct Reloc *r) { while (r) { - unsigned long word2; + unsigned long word2; - fwritelong (r->address, aoutfp); + fwritelong(r->address, aoutfp); - if (r->symbol >= 0) - word2 = r->symbol; - else - word2 = -r->symbol; - word2 |= r->reltype << 24; - word2 |= (r->bytes == 1 ? 0 : - r->bytes == 2 ? 0x2000000L : 0x4000000L); - fwritelong (word2, aoutfp); + if (r->symbol >= 0) + word2 = r->symbol; + else + word2 = -r->symbol; + word2 |= r->reltype << 24; + word2 |= (r->bytes == 1 ? 0 : + r->bytes == 2 ? 0x2000000L : 0x4000000L); + fwritelong(word2, aoutfp); - r = r->next; + r = r->next; } } -static void aout_write_syms (void) +static void aout_write_syms(void) { unsigned long i; - saa_rewind (syms); + 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' */ - } + 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' */ + } } } -static void aout_sect_write (struct Section *sect, - const unsigned char *data, unsigned long len) +static void aout_sect_write(struct Section *sect, + const unsigned char *data, unsigned long len) { - saa_wbytes (sect->data, data, len); + saa_wbytes(sect->data, data, len); sect->len += len; } -static long aout_segbase (long segment) +static long aout_segbase(long segment) { return segment; } -static int aout_directive (char *directive, char *value, int pass) +static int aout_directive(char *directive, char *value, int pass) { return 0; } -static void aout_filename (char *inname, char *outname, efunc error) +static void aout_filename(char *inname, char *outname, efunc error) { - standard_extension (inname, outname, ".o", error); + standard_extension(inname, outname, ".o", error); } static const char *aout_stdmac[] = { @@ -886,7 +906,7 @@ static int aout_set_info(enum geninfo type, char **val) { return 0; } -#endif /* OF_AOUT || OF_AOUTB */ +#endif /* OF_AOUT || OF_AOUTB */ #ifdef OF_AOUT diff --git a/output/outas86.c b/output/outas86.c dissimilarity index 63% index fa1514c4..9a3d3662 100644 --- a/output/outas86.c +++ b/output/outas86.c @@ -1,605 +1,629 @@ -/* outas86.c output routines for the Netwide Assembler to produce - * Linux as86 (bin86-0.3) object files - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "outform.h" - -#ifdef OF_AS86 - -struct Piece { - struct Piece *next; - int type; /* 0 = absolute, 1 = seg, 2 = sym */ - long offset; /* relative offset */ - int number; /* symbol/segment number (4=bss) */ - long bytes; /* size of reloc or of absolute data */ - int relative; /* TRUE or FALSE */ -}; - -struct Symbol { - long strpos; /* string table position of name */ - int flags; /* symbol flags */ - int segment; /* 4=bss at this point */ - long value; /* address, or COMMON variable size */ -}; - -/* - * Section IDs - used in Piece.number and Symbol.segment. - */ -#define SECT_TEXT 0 /* text section */ -#define SECT_DATA 3 /* data section */ -#define SECT_BSS 4 /* bss section */ - -/* - * Flags used in Symbol.flags. - */ -#define SYM_ENTRY (1<<8) -#define SYM_EXPORT (1<<7) -#define SYM_IMPORT (1<<6) -#define SYM_ABSOLUTE (1<<4) - -struct Section { - struct SAA *data; - unsigned long datalen, size, len; - long index; - struct Piece *head, *last, **tail; -}; - -static char as86_module[FILENAME_MAX]; - -static struct Section stext, sdata; -static unsigned long bsslen; -static long bssindex; - -static struct SAA *syms; -static unsigned long nsyms; - -static struct RAA *bsym; - -static struct SAA *strs; -static unsigned long strslen; - -static int as86_reloc_size; - -static FILE *as86fp; -static efunc error; - -static void as86_write(void); -static void as86_write_section (struct Section *, int); -static int as86_add_string (char *name); -static void as86_sect_write(struct Section *, const unsigned char *, unsigned long); - -static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) -{ - as86fp = fp; - error = errfunc; - (void) ldef; /* placate optimisers */ - stext.data = saa_init(1L); stext.datalen = 0L; - stext.head = stext.last = NULL; - stext.tail = &stext.head; - sdata.data = saa_init(1L); sdata.datalen = 0L; - sdata.head = sdata.last = NULL; - sdata.tail = &sdata.head; - bsslen = - stext.len = stext.datalen = stext.size = - sdata.len = sdata.datalen = sdata.size = 0; - stext.index = seg_alloc(); - sdata.index = seg_alloc(); - bssindex = seg_alloc(); - syms = saa_init((long)sizeof(struct Symbol)); - nsyms = 0; - bsym = raa_init(); - strs = saa_init(1L); - strslen = 0; - - as86_add_string (as86_module); -} - -static void as86_cleanup(int debuginfo) -{ - struct Piece *p; - - (void) debuginfo; - - as86_write(); - fclose (as86fp); - saa_free (stext.data); - while (stext.head) { - p = stext.head; - stext.head = stext.head->next; - nasm_free (p); - } - saa_free (sdata.data); - while (sdata.head) { - p = sdata.head; - sdata.head = sdata.head->next; - nasm_free (p); - } - saa_free (syms); - raa_free (bsym); - saa_free (strs); -} - -static long as86_section_names (char *name, int pass, int *bits) -{ - /* - * Default is 16 bits. - */ - if (!name) - *bits = 16; - - if (!name) - return stext.index; - - if (!strcmp(name, ".text")) - return stext.index; - else if (!strcmp(name, ".data")) - return sdata.index; - else if (!strcmp(name, ".bss")) - return bssindex; - else - return NO_SEG; -} - -static int as86_add_string (char *name) -{ - int pos = strslen; - int length = strlen(name); - - saa_wbytes (strs, name, (long)(length+1)); - strslen += 1+length; - - return pos; -} - -static void as86_deflabel (char *name, long segment, long offset, - int is_global, char *special) -{ - struct Symbol *sym; - - if (special) - error (ERR_NONFATAL, "as86 format does not support any" - " special symbol types"); - - if (name[0] == '.' && name[1] == '.' && name[2] != '@') { - error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); - return; - } - - sym = saa_wstruct (syms); - - sym->strpos = as86_add_string (name); - sym->flags = 0; - if (segment == NO_SEG) - sym->flags |= SYM_ABSOLUTE, sym->segment = 0; - else if (segment == stext.index) - sym->segment = SECT_TEXT; - else if (segment == sdata.index) - sym->segment = SECT_DATA; - else if (segment == bssindex) - sym->segment = SECT_BSS; - else { - sym->flags |= SYM_IMPORT; - sym->segment = 15; - } - - if (is_global == 2) - sym->segment = 3; /* already have IMPORT */ - - if (is_global && !(sym->flags & SYM_IMPORT)) - sym->flags |= SYM_EXPORT; - - sym->value = offset; - - /* - * define the references from external-symbol segment numbers - * to these symbol records. - */ - if (segment != NO_SEG && segment != stext.index && - segment != sdata.index && segment != bssindex) - bsym = raa_write (bsym, segment, nsyms); - - nsyms++; -} - -static void as86_add_piece (struct Section *sect, int type, long offset, - long segment, long bytes, int relative) -{ - struct Piece *p; - - sect->len += bytes; - - if (type == 0 && sect->last && sect->last->type == 0) { - sect->last->bytes += bytes; - return; - } - - p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece)); - sect->tail = &p->next; - p->next = NULL; - - p->type = type; - p->offset = offset; - p->bytes = bytes; - p->relative = relative; - - if (type == 1 && segment == stext.index) - p->number = SECT_TEXT; - else if (type == 1 && segment == sdata.index) - p->number = SECT_DATA; - else if (type == 1 && segment == bssindex) - p->number = SECT_BSS; - else if (type == 1) - p->number = raa_read (bsym, segment), p->type = 2; -} - -static void as86_out (long segto, const void *data, unsigned long type, - long segment, long wrt) -{ - struct Section *s; - long realbytes = type & OUT_SIZMASK; - long offset; - unsigned char mydata[4], *p; - - if (wrt != NO_SEG) { - wrt = NO_SEG; /* continue to do _something_ */ - error (ERR_NONFATAL, "WRT not supported by as86 output format"); - } - - type &= OUT_TYPMASK; - - /* - * handle absolute-assembly (structure definitions) - */ - if (segto == NO_SEG) { - if (type != OUT_RESERVE) - error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" - " space"); - return; - } - - if (segto == stext.index) - s = &stext; - else if (segto == sdata.index) - s = &sdata; - else if (segto == bssindex) - s = NULL; - else { - error(ERR_WARNING, "attempt to assemble code in" - " segment %d: defaulting to `.text'", segto); - s = &stext; - } - - if (!s && type != OUT_RESERVE) { - error(ERR_WARNING, "attempt to initialise memory in the" - " BSS section: ignored"); - if (type == OUT_REL2ADR) - realbytes = 2; - else if (type == OUT_REL4ADR) - realbytes = 4; - bsslen += realbytes; - return; - } - - if (type == OUT_RESERVE) { - if (s) { - error(ERR_WARNING, "uninitialised space declared in" - " %s section: zeroing", - (segto == stext.index ? "code" : "data")); - as86_sect_write (s, NULL, realbytes); - as86_add_piece (s, 0, 0L, 0L, realbytes, 0); - } else - bsslen += realbytes; - } else if (type == OUT_RAWDATA) { - if (segment != NO_SEG) - error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); - as86_sect_write (s, data, realbytes); - as86_add_piece (s, 0, 0L, 0L, realbytes, 0); - } else if (type == OUT_ADDRESS) { - if (segment != NO_SEG) { - if (segment % 2) { - error(ERR_NONFATAL, "as86 format does not support" - " segment base references"); - } else{ - offset = * (long *) data; - as86_add_piece (s, 1, offset, segment, realbytes, 0); - } - } else { - p = mydata; - WRITELONG (p, * (long *) data); - as86_sect_write (s, data, realbytes); - as86_add_piece (s, 0, 0L, 0L, realbytes, 0); - } - } else if (type == OUT_REL2ADR) { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL2ADR"); - if (segment != NO_SEG) { - if (segment % 2) { - error(ERR_NONFATAL, "as86 format does not support" - " segment base references"); - } else { - offset = * (long *) data; - as86_add_piece (s, 1, offset-realbytes+2, segment, 2L, 1); - } - } - } else if (type == OUT_REL4ADR) { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL4ADR"); - if (segment != NO_SEG) { - if (segment % 2) { - error(ERR_NONFATAL, "as86 format does not support" - " segment base references"); - } else { - offset = * (long *) data; - as86_add_piece (s, 1, offset-realbytes+4, segment, 4L, 1); - } - } - } -} - -static void as86_write(void) -{ - unsigned long i; - long 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 ((unsigned long) stext.len > 65535L) - segsize |= 0x03000000L, seglen += 4; - else - segsize |= 0x02000000L, seglen += 2; - if ((unsigned long) sdata.len > 65535L) - segsize |= 0xC0000000L, seglen += 4; - else - segsize |= 0x80000000L, seglen += 2; - - /* - * Emit the as86 header. - */ - fwritelong (0x000186A3L, as86fp); - fputc (0x2A, as86fp); - fwritelong (27+symlen+seglen+strslen, as86fp); /* header length */ - fwritelong (stext.len+sdata.len+bsslen, as86fp); - fwriteshort (strslen, as86fp); - fwriteshort (0, as86fp); /* class = revision = 0 */ - fwritelong (0x55555555L, as86fp); /* segment max sizes: always this */ - fwritelong (segsize, as86fp); /* segment size descriptors */ - if (segsize & 0x01000000L) - fwritelong (stext.len, as86fp); - else - fwriteshort (stext.len, as86fp); - if (segsize & 0x40000000L) - fwritelong (sdata.len+bsslen, as86fp); - else - fwriteshort (sdata.len+bsslen, as86fp); - fwriteshort (nsyms, as86fp); - - /* - * Write the symbol table. - */ - saa_rewind (syms); - for (i = 0; i < nsyms; i++) { - struct Symbol *sym = saa_rstruct (syms); - fwriteshort (sym->strpos, as86fp); - fwriteshort (sym->flags, as86fp); - switch (sym->flags & (3<<14)) { - case 0<<14: break; - case 1<<14: fputc (sym->value, as86fp); break; - case 2<<14: fwriteshort (sym->value, as86fp); break; - case 3<<14: fwritelong (sym->value, as86fp); break; - } - } - - /* - * Write out the string table. - */ - saa_fpwrite (strs, as86fp); - - /* - * 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, as86fp); - fwritelong (bsslen, as86fp); - } - else if (bsslen > 255) { - fputc (0x12, as86fp); - fwriteshort (bsslen, as86fp); - } - else if (bsslen) { - fputc (0x11, as86fp); - fputc (bsslen, as86fp); - } - - fputc (0, as86fp); /* termination */ -} - -static void as86_set_rsize (int size) -{ - if (as86_reloc_size != size) { - switch (as86_reloc_size = size) { - case 1: fputc (0x01, as86fp); break; - case 2: fputc (0x02, as86fp); break; - case 4: fputc (0x03, as86fp); break; - default: error (ERR_PANIC, "bizarre relocation size %d", size); - } - } -} - -static void as86_write_section (struct Section *sect, int index) -{ - struct Piece *p; - unsigned long s; - long length; - - fputc (0x20+index, as86fp); /* 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]; - long tmplen = (length > 64 ? 64 : length); - fputc (0x40 | (tmplen & 0x3F), as86fp); - saa_rnbytes (sect->data, buf, tmplen); - fwrite (buf, 1, tmplen, as86fp); - 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, as86fp); - if (as86_reloc_size == 2) - fwriteshort (p->offset, as86fp); - else - fwritelong (p->offset, as86fp); - 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, as86fp); - if (p->number > 255) - fwriteshort (p->number, as86fp); - else - fputc (p->number, as86fp); - switch ((int)s) { - case 0: break; - case 1: fputc (p->offset, as86fp); break; - case 2: fwriteshort (p->offset, as86fp); break; - case 3: fwritelong (p->offset, as86fp); break; - } - break; - } -} - -static void as86_sect_write (struct Section *sect, - const unsigned char *data, unsigned long len) -{ - saa_wbytes (sect->data, data, len); - sect->datalen += len; -} - -static long as86_segbase (long segment) -{ - return segment; -} - -static int as86_directive (char *directive, char *value, int pass) -{ - return 0; -} - -static void as86_filename (char *inname, char *outname, efunc error) -{ - char *p; - - if ( (p = strrchr (inname, '.')) != NULL) { - strncpy (as86_module, inname, p-inname); - as86_module[p-inname] = '\0'; - } else - strcpy (as86_module, inname); - - standard_extension (inname, outname, ".o", error); -} - -static const char *as86_stdmac[] = { - "%define __SECT__ [section .text]", - "%macro __NASM_CDecl__ 1", - "%endmacro", - NULL -}; - -static int as86_set_info(enum geninfo type, char **val) -{ - return 0; -} -void as86_linenumber (char *name, long segment, long offset, int is_main, - int lineno) -{ -} -struct ofmt of_as86 = { - "Linux as86 (bin86 version 0.3) object files", - "as86", - NULL, - null_debug_arr, - &null_debug_form, - as86_stdmac, - as86_init, - as86_set_info, - as86_out, - as86_deflabel, - as86_section_names, - as86_segbase, - as86_directive, - as86_filename, - as86_cleanup -}; - -#endif /* OF_AS86 */ +/* outas86.c output routines for the Netwide Assembler to produce + * Linux as86 (bin86-0.3) object files + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "outform.h" + +#ifdef OF_AS86 + +struct Piece { + struct Piece *next; + int type; /* 0 = absolute, 1 = seg, 2 = sym */ + long offset; /* relative offset */ + int number; /* symbol/segment number (4=bss) */ + long bytes; /* size of reloc or of absolute data */ + int relative; /* TRUE or FALSE */ +}; + +struct Symbol { + long strpos; /* string table position of name */ + int flags; /* symbol flags */ + int segment; /* 4=bss at this point */ + long value; /* address, or COMMON variable size */ +}; + +/* + * Section IDs - used in Piece.number and Symbol.segment. + */ +#define SECT_TEXT 0 /* text section */ +#define SECT_DATA 3 /* data section */ +#define SECT_BSS 4 /* bss section */ + +/* + * Flags used in Symbol.flags. + */ +#define SYM_ENTRY (1<<8) +#define SYM_EXPORT (1<<7) +#define SYM_IMPORT (1<<6) +#define SYM_ABSOLUTE (1<<4) + +struct Section { + struct SAA *data; + unsigned long datalen, size, len; + long index; + struct Piece *head, *last, **tail; +}; + +static char as86_module[FILENAME_MAX]; + +static struct Section stext, sdata; +static unsigned long bsslen; +static long bssindex; + +static struct SAA *syms; +static unsigned long nsyms; + +static struct RAA *bsym; + +static struct SAA *strs; +static unsigned long strslen; + +static int as86_reloc_size; + +static FILE *as86fp; +static efunc error; + +static void as86_write(void); +static void as86_write_section(struct Section *, int); +static int as86_add_string(char *name); +static void as86_sect_write(struct Section *, const unsigned char *, + unsigned long); + +static void as86_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + as86fp = fp; + error = errfunc; + (void)ldef; /* placate optimisers */ + stext.data = saa_init(1L); + stext.datalen = 0L; + stext.head = stext.last = NULL; + stext.tail = &stext.head; + sdata.data = saa_init(1L); + sdata.datalen = 0L; + sdata.head = sdata.last = NULL; + sdata.tail = &sdata.head; + bsslen = + stext.len = stext.datalen = stext.size = + sdata.len = sdata.datalen = sdata.size = 0; + stext.index = seg_alloc(); + sdata.index = seg_alloc(); + bssindex = seg_alloc(); + syms = saa_init((long)sizeof(struct Symbol)); + nsyms = 0; + bsym = raa_init(); + strs = saa_init(1L); + strslen = 0; + + as86_add_string(as86_module); +} + +static void as86_cleanup(int debuginfo) +{ + struct Piece *p; + + (void)debuginfo; + + as86_write(); + fclose(as86fp); + saa_free(stext.data); + while (stext.head) { + p = stext.head; + stext.head = stext.head->next; + nasm_free(p); + } + saa_free(sdata.data); + while (sdata.head) { + p = sdata.head; + sdata.head = sdata.head->next; + nasm_free(p); + } + saa_free(syms); + raa_free(bsym); + saa_free(strs); +} + +static long as86_section_names(char *name, int pass, int *bits) +{ + /* + * Default is 16 bits. + */ + if (!name) + *bits = 16; + + if (!name) + return stext.index; + + if (!strcmp(name, ".text")) + return stext.index; + else if (!strcmp(name, ".data")) + return sdata.index; + else if (!strcmp(name, ".bss")) + return bssindex; + else + return NO_SEG; +} + +static int as86_add_string(char *name) +{ + int pos = strslen; + int length = strlen(name); + + saa_wbytes(strs, name, (long)(length + 1)); + strslen += 1 + length; + + return pos; +} + +static void as86_deflabel(char *name, long segment, long offset, + int is_global, char *special) +{ + struct Symbol *sym; + + if (special) + error(ERR_NONFATAL, "as86 format does not support any" + " special symbol types"); + + if (name[0] == '.' && name[1] == '.' && name[2] != '@') { + error(ERR_NONFATAL, "unrecognised special symbol `%s'", name); + return; + } + + sym = saa_wstruct(syms); + + sym->strpos = as86_add_string(name); + sym->flags = 0; + if (segment == NO_SEG) + sym->flags |= SYM_ABSOLUTE, sym->segment = 0; + else if (segment == stext.index) + sym->segment = SECT_TEXT; + else if (segment == sdata.index) + sym->segment = SECT_DATA; + else if (segment == bssindex) + sym->segment = SECT_BSS; + else { + sym->flags |= SYM_IMPORT; + sym->segment = 15; + } + + if (is_global == 2) + sym->segment = 3; /* already have IMPORT */ + + if (is_global && !(sym->flags & SYM_IMPORT)) + sym->flags |= SYM_EXPORT; + + sym->value = offset; + + /* + * define the references from external-symbol segment numbers + * to these symbol records. + */ + if (segment != NO_SEG && segment != stext.index && + segment != sdata.index && segment != bssindex) + bsym = raa_write(bsym, segment, nsyms); + + nsyms++; +} + +static void as86_add_piece(struct Section *sect, int type, long offset, + long segment, long bytes, int relative) +{ + struct Piece *p; + + sect->len += bytes; + + if (type == 0 && sect->last && sect->last->type == 0) { + sect->last->bytes += bytes; + return; + } + + p = sect->last = *sect->tail = nasm_malloc(sizeof(struct Piece)); + sect->tail = &p->next; + p->next = NULL; + + p->type = type; + p->offset = offset; + p->bytes = bytes; + p->relative = relative; + + if (type == 1 && segment == stext.index) + p->number = SECT_TEXT; + else if (type == 1 && segment == sdata.index) + p->number = SECT_DATA; + else if (type == 1 && segment == bssindex) + p->number = SECT_BSS; + else if (type == 1) + p->number = raa_read(bsym, segment), p->type = 2; +} + +static void as86_out(long segto, const void *data, unsigned long type, + long segment, long wrt) +{ + struct Section *s; + long realbytes = type & OUT_SIZMASK; + long offset; + unsigned char mydata[4], *p; + + if (wrt != NO_SEG) { + wrt = NO_SEG; /* continue to do _something_ */ + error(ERR_NONFATAL, "WRT not supported by as86 output format"); + } + + type &= OUT_TYPMASK; + + /* + * handle absolute-assembly (structure definitions) + */ + if (segto == NO_SEG) { + if (type != OUT_RESERVE) + error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" + " space"); + return; + } + + if (segto == stext.index) + s = &stext; + else if (segto == sdata.index) + s = &sdata; + else if (segto == bssindex) + s = NULL; + else { + error(ERR_WARNING, "attempt to assemble code in" + " segment %d: defaulting to `.text'", segto); + s = &stext; + } + + if (!s && type != OUT_RESERVE) { + error(ERR_WARNING, "attempt to initialise memory in the" + " BSS section: ignored"); + if (type == OUT_REL2ADR) + realbytes = 2; + else if (type == OUT_REL4ADR) + realbytes = 4; + bsslen += realbytes; + return; + } + + if (type == OUT_RESERVE) { + if (s) { + error(ERR_WARNING, "uninitialised space declared in" + " %s section: zeroing", + (segto == stext.index ? "code" : "data")); + as86_sect_write(s, NULL, realbytes); + as86_add_piece(s, 0, 0L, 0L, realbytes, 0); + } else + bsslen += realbytes; + } else if (type == OUT_RAWDATA) { + if (segment != NO_SEG) + error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); + as86_sect_write(s, data, realbytes); + as86_add_piece(s, 0, 0L, 0L, realbytes, 0); + } else if (type == OUT_ADDRESS) { + if (segment != NO_SEG) { + if (segment % 2) { + error(ERR_NONFATAL, "as86 format does not support" + " segment base references"); + } else { + offset = *(long *)data; + as86_add_piece(s, 1, offset, segment, realbytes, 0); + } + } else { + p = mydata; + WRITELONG(p, *(long *)data); + as86_sect_write(s, data, realbytes); + as86_add_piece(s, 0, 0L, 0L, realbytes, 0); + } + } else if (type == OUT_REL2ADR) { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL2ADR"); + if (segment != NO_SEG) { + if (segment % 2) { + error(ERR_NONFATAL, "as86 format does not support" + " segment base references"); + } else { + offset = *(long *)data; + as86_add_piece(s, 1, offset - realbytes + 2, segment, 2L, + 1); + } + } + } else if (type == OUT_REL4ADR) { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL4ADR"); + if (segment != NO_SEG) { + if (segment % 2) { + error(ERR_NONFATAL, "as86 format does not support" + " segment base references"); + } else { + offset = *(long *)data; + as86_add_piece(s, 1, offset - realbytes + 4, segment, 4L, + 1); + } + } + } +} + +static void as86_write(void) +{ + unsigned long i; + long 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 ((unsigned long)stext.len > 65535L) + segsize |= 0x03000000L, seglen += 4; + else + segsize |= 0x02000000L, seglen += 2; + if ((unsigned long)sdata.len > 65535L) + segsize |= 0xC0000000L, seglen += 4; + else + segsize |= 0x80000000L, seglen += 2; + + /* + * Emit the as86 header. + */ + fwritelong(0x000186A3L, as86fp); + fputc(0x2A, as86fp); + fwritelong(27 + symlen + seglen + strslen, as86fp); /* header length */ + fwritelong(stext.len + sdata.len + bsslen, as86fp); + fwriteshort(strslen, as86fp); + fwriteshort(0, as86fp); /* class = revision = 0 */ + fwritelong(0x55555555L, as86fp); /* segment max sizes: always this */ + fwritelong(segsize, as86fp); /* segment size descriptors */ + if (segsize & 0x01000000L) + fwritelong(stext.len, as86fp); + else + fwriteshort(stext.len, as86fp); + if (segsize & 0x40000000L) + fwritelong(sdata.len + bsslen, as86fp); + else + fwriteshort(sdata.len + bsslen, as86fp); + fwriteshort(nsyms, as86fp); + + /* + * Write the symbol table. + */ + saa_rewind(syms); + for (i = 0; i < nsyms; i++) { + struct Symbol *sym = saa_rstruct(syms); + fwriteshort(sym->strpos, as86fp); + fwriteshort(sym->flags, as86fp); + switch (sym->flags & (3 << 14)) { + case 0 << 14: + break; + case 1 << 14: + fputc(sym->value, as86fp); + break; + case 2 << 14: + fwriteshort(sym->value, as86fp); + break; + case 3 << 14: + fwritelong(sym->value, as86fp); + break; + } + } + + /* + * Write out the string table. + */ + saa_fpwrite(strs, as86fp); + + /* + * 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, as86fp); + fwritelong(bsslen, as86fp); + } else if (bsslen > 255) { + fputc(0x12, as86fp); + fwriteshort(bsslen, as86fp); + } else if (bsslen) { + fputc(0x11, as86fp); + fputc(bsslen, as86fp); + } + + fputc(0, as86fp); /* termination */ +} + +static void as86_set_rsize(int size) +{ + if (as86_reloc_size != size) { + switch (as86_reloc_size = size) { + case 1: + fputc(0x01, as86fp); + break; + case 2: + fputc(0x02, as86fp); + break; + case 4: + fputc(0x03, as86fp); + break; + default: + error(ERR_PANIC, "bizarre relocation size %d", size); + } + } +} + +static void as86_write_section(struct Section *sect, int index) +{ + struct Piece *p; + unsigned long s; + long length; + + fputc(0x20 + index, as86fp); /* 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]; + long tmplen = (length > 64 ? 64 : length); + fputc(0x40 | (tmplen & 0x3F), as86fp); + saa_rnbytes(sect->data, buf, tmplen); + fwrite(buf, 1, tmplen, as86fp); + 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, as86fp); + if (as86_reloc_size == 2) + fwriteshort(p->offset, as86fp); + else + fwritelong(p->offset, as86fp); + 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, as86fp); + if (p->number > 255) + fwriteshort(p->number, as86fp); + else + fputc(p->number, as86fp); + switch ((int)s) { + case 0: + break; + case 1: + fputc(p->offset, as86fp); + break; + case 2: + fwriteshort(p->offset, as86fp); + break; + case 3: + fwritelong(p->offset, as86fp); + break; + } + break; + } +} + +static void as86_sect_write(struct Section *sect, + const unsigned char *data, unsigned long len) +{ + saa_wbytes(sect->data, data, len); + sect->datalen += len; +} + +static long as86_segbase(long segment) +{ + return segment; +} + +static int as86_directive(char *directive, char *value, int pass) +{ + return 0; +} + +static void as86_filename(char *inname, char *outname, efunc error) +{ + char *p; + + if ((p = strrchr(inname, '.')) != NULL) { + strncpy(as86_module, inname, p - inname); + as86_module[p - inname] = '\0'; + } else + strcpy(as86_module, inname); + + standard_extension(inname, outname, ".o", error); +} + +static const char *as86_stdmac[] = { + "%define __SECT__ [section .text]", + "%macro __NASM_CDecl__ 1", + "%endmacro", + NULL +}; + +static int as86_set_info(enum geninfo type, char **val) +{ + return 0; +} +void as86_linenumber(char *name, long segment, long offset, int is_main, + int lineno) +{ +} +struct ofmt of_as86 = { + "Linux as86 (bin86 version 0.3) object files", + "as86", + NULL, + null_debug_arr, + &null_debug_form, + as86_stdmac, + as86_init, + as86_set_info, + as86_out, + as86_deflabel, + as86_section_names, + as86_segbase, + as86_directive, + as86_filename, + as86_cleanup +}; + +#endif /* OF_AS86 */ diff --git a/output/outbin.c b/output/outbin.c dissimilarity index 86% index 80be83cf..5cadff0d 100644 --- a/output/outbin.c +++ b/output/outbin.c @@ -1,1320 +1,1431 @@ -/* outbin.c output routines for the Netwide Assembler to produce - * flat-form binary files - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -/* This is the extended version of NASM's original binary output - * format. It is backward compatible with the original BIN format, - * and contains support for multiple sections and advanced section - * ordering. - * - * Feature summary: - * - * - Users can create an arbitrary number of sections; they are not - * limited to just ".text", ".data", and ".bss". - * - * - Sections can be either progbits or nobits type. - * - * - You can specify that they be aligned at a certian boundary - * following the previous section ("align="), or positioned at an - * arbitrary byte-granular location ("start="). - * - * - You can specify a "virtual" start address for a section, which - * will be used for the calculation for all address references - * with respect to that section ("vstart="). - * - * - The ORG directive, as well as the section/segment directive - * arguments ("align=", "start=", "vstart="), can take a critical - * expression as their value. For example: "align=(1 << 12)". - * - * - You can generate map files using the 'map' directive. - * - */ - -/* Uncomment the following define if you want sections to adapt - * their progbits/nobits state depending on what type of - * instructions are issued, rather than defaulting to progbits. - * Note that this behavior violates the specification. - -#define ABIN_SMART_ADAPT - -*/ - -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "labels.h" -#include "eval.h" -#include "outform.h" - -#ifdef OF_BIN - -struct ofmt *bin_get_ofmt(); /* Prototype goes here since no header file. */ - -static FILE *fp, *rf = NULL; -static efunc error; - -/* Section flags keep track of which attributes the user has defined. */ -#define START_DEFINED 0x001 -#define ALIGN_DEFINED 0x002 -#define FOLLOWS_DEFINED 0x004 -#define VSTART_DEFINED 0x008 -#define VALIGN_DEFINED 0x010 -#define VFOLLOWS_DEFINED 0x020 -#define TYPE_DEFINED 0x040 -#define TYPE_PROGBITS 0x080 -#define TYPE_NOBITS 0x100 - -/* This struct is used to keep track of symbols for map-file generation. */ -static struct bin_label -{ char * name; - struct bin_label *next; -} *no_seg_labels, **nsl_tail; - -static struct Section -{ char *name; - struct SAA * contents; - long length; /* section length in bytes */ - -/* Section attributes */ - int flags; /* see flag definitions above */ - unsigned long align; /* section alignment */ - unsigned long valign; /* notional section alignment */ - unsigned long start; /* section start address */ - unsigned long vstart; /* section virtual start address */ - char *follows; /* the section that this one will follow */ - char *vfollows; /* the section that this one will notionally follow */ - long start_index; /* NASM section id for non-relocated version */ - long vstart_index; /* the NASM section id */ - - struct bin_label *labels; /* linked-list of label handles for map output. */ - struct bin_label **labels_end; /* Holds address of end of labels list. */ - struct Section *ifollows; /* Points to previous section (implicit follows). */ - struct Section *next; /* This links sections with a defined start address. */ - -/* The extended bin format allows for sections to have a "virtual" - * start address. This is accomplished by creating two sections: - * one beginning at the Load Memory Address and the other beginning - * at the Virtual Memory Address. The LMA section is only used to - * define the section..start label, but there isn't - * any other good way for us to handle that label. - */ - -} *sections, *last_section; - -static struct Reloc { - struct Reloc *next; - long posn; - long bytes; - long secref; - long secrel; - struct Section *target; -} *relocs, **reloctail; - -extern char *stdscan_bufptr; -extern int lookup_label (char *label, long *segment, long *offset); - -static unsigned char format_mode; /* 0 = original bin, 1 = extended bin */ -static long current_section; /* only really needed if format_mode = 0 */ -static unsigned long origin; -static int origin_defined; - -/* Stuff we need for map-file generation. */ -#define MAP_ORIGIN 1 -#define MAP_SUMMARY 2 -#define MAP_SECTIONS 4 -#define MAP_SYMBOLS 8 -static int map_control = 0; -static char *infile, *outfile; - -static const char *bin_stdmac[] = { - "%define __SECT__ [section .text]", - "%imacro org 1+.nolist", - "[org %1]", - "%endmacro", - "%macro __NASM_CDecl__ 1", - "%endmacro", - NULL -}; - -static void add_reloc(struct Section *s, long bytes, long secref, long secrel) -{ struct Reloc *r; - - r = *reloctail = nasm_malloc(sizeof(struct Reloc)); - reloctail = &r->next; - r->next = NULL; - r->posn = s->length; - r->bytes = bytes; - r->secref = secref; - r->secrel = secrel; - r->target = s; -} - -static struct Section *find_section_by_name(const char *name) -{ struct Section *s; - - for (s = sections; s; s = s->next) - if (!strcmp(s->name,name)) break; - return s; -} - -static struct Section *find_section_by_index(long index) -{ struct Section *s; - - for (s = sections; s; s = s->next) - if ((index == s->vstart_index) || (index == s->start_index)) - break; - return s; -} - -static struct Section * create_section(char *name) -{ /* Create a new section. */ - last_section->next = nasm_malloc(sizeof(struct Section)); - last_section->next->ifollows = last_section; - last_section = last_section->next; - last_section->labels = NULL; - last_section->labels_end = &(last_section->labels); - - /* Initialize section attributes. */ - last_section->name = nasm_strdup(name); - last_section->contents = saa_init(1L); - last_section->follows = last_section->vfollows = 0; - last_section->length = 0; - last_section->flags = 0; - last_section->next = NULL; - - /* Register our sections with NASM. */ - last_section->vstart_index = seg_alloc(); - last_section->start_index = seg_alloc(); - return last_section; -} - -static void bin_cleanup (int debuginfo) -{ struct Section *g, **gp; - struct Section *gs = NULL, **gsp; - struct Section *s, **sp; - struct Section *nobits = NULL, **nt; - struct Section * last_progbits; - struct bin_label *l; - struct Reloc *r; - unsigned long pend; - int h; - -#ifdef DEBUG - fprintf(stdout, "bin_cleanup: Sections were initially referenced in this order:\n"); - for (h = 0, s = sections; s; h++, s = s->next) - fprintf(stdout, "%i. %s\n", h, s->name); -#endif - - /* Assembly has completed, so now we need to generate the output file. - * Step 1: Separate progbits and nobits sections into separate lists. - * Step 2: Sort the progbits sections into their output order. - * Step 3: Compute start addresses for all progbits sections. - * Step 4: Compute vstart addresses for all sections. - * Step 5: Apply relocations. - * Step 6: Write the sections' data to the output file. - * Step 7: Generate the map file. - * Step 8: Release all allocated memory. - */ - - /* To do: Smart section-type adaptation could leave some empty sections - * without a defined type (progbits/nobits). Won't fix now since this - * feature will be disabled. */ - - - /* Step 1: Split progbits and nobits sections into separate lists. */ - - nt = &nobits; - /* Move nobits sections into a separate list. Also pre-process nobits - * sections' attributes. */ - for (sp = §ions->next, s = sections->next; s; s = *sp) - { /* Skip progbits sections. */ - if (s->flags & TYPE_PROGBITS) - { sp = &s->next; continue; - } - /* Do some special pre-processing on nobits sections' attributes. */ - if (s->flags & (START_DEFINED | ALIGN_DEFINED | FOLLOWS_DEFINED)) - { /* Check for a mixture of real and virtual section attributes. */ - if (s->flags & (VSTART_DEFINED | VALIGN_DEFINED | VFOLLOWS_DEFINED)) - error(ERR_FATAL, "cannot mix real and virtual attributes" - " in nobits section (%s)", s->name); - /* Real and virtual attributes mean the same thing for nobits sections. */ - if (s->flags & START_DEFINED) - { s->vstart = s->start; s->flags |= VSTART_DEFINED; - } - if (s->flags & ALIGN_DEFINED) - { s->valign = s->align; s->flags |= VALIGN_DEFINED; - } - if (s->flags & FOLLOWS_DEFINED) - { s->vfollows = s->follows; s->flags |= VFOLLOWS_DEFINED; - s->flags &= ~FOLLOWS_DEFINED; - } - } - /* Every section must have a start address. */ - if (s->flags & VSTART_DEFINED) - { s->start = s->vstart; s->flags |= START_DEFINED; - } - /* Move the section into the nobits list. */ - *sp = s->next; s->next = NULL; - *nt = s; nt = &s->next; - } - - /* Step 2: Sort the progbits sections into their output order. */ - - /* In Step 2 we move around sections in groups. A group - * begins with a section (group leader) that has a user- - * defined start address or follows section. The remainder - * of the group is made up of the sections that implicitly - * follow the group leader (i.e., they were defined after - * the group leader and were not given an explicit start - * address or follows section by the user). */ - - /* For anyone attempting to read this code: - * g (group) points to a group of sections, the first one of which has - * a user-defined start address or follows section. - * gp (g previous) holds the location of the pointer to g. - * gs (g scan) is a temp variable that we use to scan to the end of the group. - * gsp (gs previous) holds the location of the pointer to gs. - * nt (nobits tail) points to the nobits section-list tail. - */ - - /* Link all 'follows' groups to their proper position. To do - * this we need to know three things: the start of the group - * to relocate (g), the section it is following (s), and the - * end of the group we're relocating (gs). */ - for (gp = §ions, g = sections; g; g = gs) - { /* Find the next follows group that is out of place (g). */ - if (!(g->flags & FOLLOWS_DEFINED)) - { while (g->next) - { if ((g->next->flags & FOLLOWS_DEFINED) && - strcmp(g->name, g->next->follows)) break; - g = g->next; - } - if (!g->next) break; - gp = &g->next; g = g->next; - } - /* Find the section that this group follows (s). */ - for (sp = §ions, s = sections; - s && strcmp(s->name, g->follows); - sp = &s->next, s = s->next); - if (!s) error(ERR_FATAL, "section %s follows an invalid or" - " unknown section (%s)", g->name, g->follows); - if (s->next && (s->next->flags & FOLLOWS_DEFINED) && - !strcmp(s->name, s->next->follows)) - error(ERR_FATAL, "sections %s and %s can't both follow" - " section %s", g->name, s->next->name, s->name); - /* Find the end of the current follows group (gs). */ - for (gsp = &g->next, gs = g->next; - gs && (gs != s) && !(gs->flags & START_DEFINED); - gsp = &gs->next, gs = gs->next) - { if (gs->next && (gs->next->flags & FOLLOWS_DEFINED) && - strcmp(gs->name, gs->next->follows)) - { gsp = &gs->next; gs = gs->next; break; - } - } - /* Re-link the group after its follows section. */ - *gsp = s->next; s->next = g; - *gp = gs; - } - - /* Link all 'start' groups to their proper position. Once - * again we need to know g, s, and gs (see above). The main - * difference is we already know g since we sort by moving - * groups from the 'unsorted' list into a 'sorted' list (g - * will always be the first section in the unsorted list). */ - for (g = sections, sections = NULL; g; g = gs) - { /* Find the section that we will insert this group before (s). */ - for (sp = §ions, s = sections; s; sp = &s->next, s = s->next) - if ((s->flags & START_DEFINED) && (g->start < s->start)) break; - /* Find the end of the group (gs). */ - for (gs = g->next, gsp = &g->next; - gs && !(gs->flags & START_DEFINED); - gsp = &gs->next, gs = gs->next); - /* Re-link the group before the target section. */ - *sp = g; *gsp = s; - } - - - /* Step 3: Compute start addresses for all progbits sections. */ - - /* Make sure we have an origin and a start address for the first section. */ - if (origin_defined) - switch (sections->flags & (START_DEFINED | ALIGN_DEFINED)) - { case START_DEFINED | ALIGN_DEFINED: - case START_DEFINED: - /* Make sure this section doesn't begin before the origin. */ - if (sections->start < origin) error(ERR_FATAL, "section %s begins" - " before program origin", sections->name); - break; - case ALIGN_DEFINED: - sections->start = ((origin + sections->align - 1) & - ~(sections->align - 1)); break; - case 0: - sections->start = origin; - } - else - { if (!(sections->flags & START_DEFINED)) - sections->start = 0; - origin = sections->start; - } - sections->flags |= START_DEFINED; - - /* Make sure each section has an explicit start address. If it - * doesn't, then compute one based its alignment and the end of - * the previous section. */ - for (pend = sections->start, g = s = sections; g; g = g->next) - { /* Find the next section that could cause an overlap situation - * (has a defined start address, and is not zero length). */ - if (g == s) - for (s = g->next; - s && ((s->length == 0) || !(s->flags & START_DEFINED)); - s = s->next); - /* Compute the start address of this section, if necessary. */ - if (!(g->flags & START_DEFINED)) - { /* Default to an alignment of 4 if unspecified. */ - if (!(g->flags & ALIGN_DEFINED)) - { g->align = 4; g->flags |= ALIGN_DEFINED; - } - /* Set the section start address. */ - g->start = (pend + g->align - 1) & ~(g->align - 1); - g->flags |= START_DEFINED; - } - /* Ugly special case for progbits sections' virtual attributes: - * If there is a defined valign, but no vstart and no vfollows, then - * we valign after the previous progbits section. This case doesn't - * really make much sense for progbits sections with a defined start - * address, but it is possible and we must do *something*. - * Not-so-ugly special case: - * If a progbits section has no virtual attributes, we set the - * vstart equal to the start address. */ - if (!(g->flags & (VSTART_DEFINED | VFOLLOWS_DEFINED))) - { if (g->flags & VALIGN_DEFINED) - g->vstart = (pend + g->valign - 1) & ~(g->valign - 1); - else g->vstart = g->start; - g->flags |= VSTART_DEFINED; - } - /* Ignore zero-length sections. */ - if (g->start < pend) continue; - /* Compute the span of this section. */ - pend = g->start + g->length; - /* Check for section overlap. */ - if (s) - { if (g->start > s->start) - error(ERR_FATAL, "sections %s ~ %s and %s overlap!", - gs->name, g->name, s->name); - if (pend > s->start) - error(ERR_FATAL, "sections %s and %s overlap!", - g->name, s->name); - } - /* Remember this section as the latest >0 length section. */ - gs = g; - } - - /* Step 4: Compute vstart addresses for all sections. */ - - /* Attach the nobits sections to the end of the progbits sections. */ - for (s = sections; s->next; s = s->next); s->next = nobits; - last_progbits = s; - /* Scan for sections that don't have a vstart address. If we find one we'll - * attempt to compute its vstart. If we can't compute the vstart, we leave - * it alone and come back to it in a subsequent scan. We continue scanning - * and re-scanning until we've gone one full cycle without computing any - * vstarts. */ - do - { /* Do one full scan of the sections list. */ - for (h = 0, g = sections; g; g = g->next) - { if (g->flags & VSTART_DEFINED) continue; - /* Find the section that this one virtually follows. */ - if (g->flags & VFOLLOWS_DEFINED) - { for (s = sections; s && strcmp(g->vfollows, s->name); s = s->next); - if (!s) error(ERR_FATAL, "section %s vfollows unknown section (%s)", - g->name, g->vfollows); - } - else if (g->ifollows != NULL) - for (s = sections; s && (s != g->ifollows); s = s->next); - /* The .bss section is the only one with ifollows = NULL. In this case we - * implicitly follow the last progbits section. */ - else s = last_progbits; - - /* If the section we're following has a vstart, we can proceed. */ - if (s->flags & VSTART_DEFINED) - { /* Default to virtual alignment of four. */ - if (!(g->flags & VALIGN_DEFINED)) - { g->valign = 4; g->flags |= VALIGN_DEFINED; - } - /* Compute the vstart address. */ - g->vstart = (s->vstart + s->length + g->valign - 1) & ~(g->valign - 1); - g->flags |= VSTART_DEFINED; h++; - /* Start and vstart mean the same thing for nobits sections. */ - if (g->flags & TYPE_NOBITS) g->start = g->vstart; - } - } - } while (h); - - /* Now check for any circular vfollows references, which will manifest - * themselves as sections without a defined vstart. */ - for (h = 0, s = sections; s; s = s->next) - { if (!(s->flags & VSTART_DEFINED)) - { /* Non-fatal errors after assembly has completed are generally a - * no-no, but we'll throw a fatal one eventually so it's ok. */ - error(ERR_NONFATAL, "cannot compute vstart for section %s", s->name); - h++; - } - } - if (h) error(ERR_FATAL, "circular vfollows path detected"); - -#ifdef DEBUG - fprintf(stdout, "bin_cleanup: Confirm final section order for output file:\n"); - for (h = 0, s = sections; s && (s->flags & TYPE_PROGBITS); h++, s = s->next) - fprintf(stdout, "%i. %s\n", h, s->name); -#endif - - - /* Step 5: Apply relocations. */ - - /* Prepare the sections for relocating. */ - for (s = sections; s; s = s->next) saa_rewind(s->contents); - /* Apply relocations. */ - for (r = relocs; r; r = r->next) - { unsigned char *p, *q, mydata[4]; - long l; - - saa_fread (r->target->contents, r->posn, mydata, r->bytes); - p = q = mydata; - l = *p++; - - if (r->bytes > 1) - { l += ((long)*p++) << 8; - if (r->bytes == 4) - { l += ((long)*p++) << 16; - l += ((long)*p++) << 24; - } - } - - s = find_section_by_index(r->secref); - if (s) - { if (r->secref == s->start_index) l += s->start; - else l += s->vstart; - } - s = find_section_by_index(r->secrel); - if (s) - { if (r->secrel == s->start_index) l -= s->start; - else l -= s->vstart; - } - - if (r->bytes == 4) WRITELONG(q, l); - else if (r->bytes == 2) WRITESHORT(q, l); - else *q++ = (unsigned char) (l & 0xFF); - saa_fwrite(r->target->contents, r->posn, mydata, r->bytes); - } - - - /* Step 6: Write the section data to the output file. */ - - /* Write the progbits sections to the output file. */ - for(pend = origin, s = sections; s && (s->flags & TYPE_PROGBITS); s = s->next) - { /* Skip zero-length sections. */ - if (s->length == 0) continue; - /* Pad the space between sections. */ - for (h = s->start - pend; h; h--) - fputc('\0', fp); - /* Write the section to the output file. */ - if (s->length > 0) saa_fpwrite(s->contents, fp); - pend = s->start + s->length; - } - /* Done writing the file, so close it. */ - fclose(fp); - - - /* Step 7: Generate the map file. */ - - if (map_control) - { const char *not_defined = { "not defined" }; - - /* Display input and output file names. */ - fprintf(rf, "\n- NASM Map file "); - for (h = 63; h; h--) fputc('-', rf); - fprintf(rf, "\n\nSource file: %s\nOutput file: %s\n\n", - infile, outfile); - - if (map_control & MAP_ORIGIN) - { /* Display program origin. */ - fprintf(rf, "-- Program origin "); - for (h = 61; h; h--) fputc('-', rf); - fprintf(rf, "\n\n%08lX\n\n", origin); - } - /* Display sections summary. */ - if (map_control & MAP_SUMMARY) - { fprintf(rf, "-- Sections (summary) "); - for (h = 57; h; h--) fputc('-', rf); - fprintf(rf, "\n\nVstart Start Stop " - "Length Class Name\n"); - for (s = sections; s; s = s->next) - { fprintf(rf, "%08lX %08lX %08lX %08lX ", - s->vstart, s->start, s->start + s->length, s->length); - if (s->flags & TYPE_PROGBITS) fprintf(rf, "progbits "); - else fprintf(rf, "nobits "); - fprintf(rf, "%s\n", s->name); - } - fprintf(rf, "\n"); - } - /* Display detailed section information. */ - if (map_control & MAP_SECTIONS) - { fprintf(rf, "-- Sections (detailed) "); - for (h = 56; h; h--) fputc('-', rf); - fprintf(rf, "\n\n"); - for (s = sections; s; s = s->next) - { fprintf(rf, "---- Section %s ", s->name); - for (h = 65 - strlen(s->name); h; h--) fputc('-', rf); - fprintf(rf, "\n\nclass: "); - if (s->flags & TYPE_PROGBITS) fprintf(rf, "progbits"); - else fprintf(rf, "nobits"); - fprintf(rf, "\nlength: %08lX\nstart: %08lX" - "\nalign: ", s->length, s->start); - if (s->flags & ALIGN_DEFINED) fprintf(rf, "%08lX", s->align); - else fprintf(rf, not_defined); - fprintf(rf, "\nfollows: "); - if (s->flags & FOLLOWS_DEFINED) fprintf(rf, "%s", s->follows); - else fprintf(rf, not_defined); - fprintf(rf, "\nvstart: %08lX\nvalign: ", s->vstart); - if (s->flags & VALIGN_DEFINED) fprintf(rf, "%08lX", s->valign); - else fprintf(rf, not_defined); - fprintf(rf, "\nvfollows: "); - if (s->flags & VFOLLOWS_DEFINED) fprintf(rf, "%s", s->vfollows); - else fprintf(rf, not_defined); - fprintf(rf, "\n\n"); - } - } - /* Display symbols information. */ - if (map_control & MAP_SYMBOLS) - { long segment, offset; - - fprintf(rf, "-- Symbols "); - for (h = 68; h; h--) fputc('-', rf); - fprintf(rf, "\n\n"); - if (no_seg_labels) - { fprintf(rf, "---- No Section "); - for (h = 63; h; h--) fputc('-', rf); - fprintf(rf, "\n\nValue Name\n"); - for (l = no_seg_labels; l; l = l->next) - { lookup_label(l->name, &segment, &offset); - fprintf(rf, "%08lX %s\n", offset, l->name); - } - fprintf(rf, "\n\n"); - } - for (s = sections; s; s = s->next) - { if (s->labels) - { fprintf(rf, "---- Section %s ", s->name); - for (h = 65 - strlen(s->name); h; h--) fputc('-', rf); - fprintf(rf, "\n\nReal Virtual Name\n"); - for (l = s->labels; l; l = l->next) - { lookup_label(l->name, &segment, &offset); - fprintf(rf, "%08lX %08lX %s\n", s->start + offset, - s->vstart + offset, l->name); - } - fprintf(rf, "\n"); - } - } - } - } - - /* Close the report file. */ - if (map_control && (rf != stdout) && (rf != stderr)) - fclose(rf); - - - /* Step 8: Release all allocated memory. */ - - /* Free sections, label pointer structs, etc.. */ - while (sections) - { s = sections; sections = s->next; - saa_free(s->contents); - nasm_free(s->name); - if (s->flags & FOLLOWS_DEFINED) nasm_free(s->follows); - if (s->flags & VFOLLOWS_DEFINED) nasm_free(s->vfollows); - while (s->labels) - { l = s->labels; s->labels = l->next; - nasm_free(l); - } - nasm_free(s); - } - - /* Free no-section labels. */ - while (no_seg_labels) - { l = no_seg_labels; no_seg_labels = l->next; - nasm_free(l); - } - - /* Free relocation structures. */ - while (relocs) - { r = relocs->next; - nasm_free(relocs); - relocs = r; - } -} - -static void bin_out (long segto, const void *data, unsigned long type, - long segment, long wrt) -{ unsigned char *p, mydata[4]; - struct Section *s; - long realbytes; - - if (wrt != NO_SEG) - { wrt = NO_SEG; /* continue to do _something_ */ - error (ERR_NONFATAL, - "WRT not supported by binary output format"); - } - - /* Handle absolute-assembly (structure definitions). */ - if (segto == NO_SEG) - { if ((type & OUT_TYPMASK) != OUT_RESERVE) - error (ERR_NONFATAL, "attempt to assemble code in" - " [ABSOLUTE] space"); - return; - } - - /* Find the segment we are targeting. */ - s = find_section_by_index(segto); - if (!s) - error (ERR_PANIC, "code directed to nonexistent segment?"); - - /* "Smart" section-type adaptation code. */ - if (!(s->flags & TYPE_DEFINED)) - { if ((type & OUT_TYPMASK) == OUT_RESERVE) - s->flags |= TYPE_DEFINED | TYPE_NOBITS; - else s->flags |= TYPE_DEFINED | TYPE_PROGBITS; - } - - if ((s->flags & TYPE_NOBITS) && ((type & OUT_TYPMASK) != OUT_RESERVE)) - error(ERR_WARNING, "attempt to initialise memory in a" - " nobits section: ignored"); - - if ((type & OUT_TYPMASK) == OUT_ADDRESS) - { if (segment != NO_SEG && !find_section_by_index(segment)) - { if (segment % 2) - error(ERR_NONFATAL, "binary output format does not support" - " segment base references"); - else - error(ERR_NONFATAL, "binary output format does not support" - " external references"); - segment = NO_SEG; - } - if (s->flags & TYPE_PROGBITS) - { if (segment != NO_SEG) - add_reloc(s, type & OUT_SIZMASK, segment, -1L); - p = mydata; - if ((type & OUT_SIZMASK) == 4) - WRITELONG(p, *(long *)data); - else - WRITESHORT(p, *(long *)data); - saa_wbytes(s->contents, mydata, type & OUT_SIZMASK); - } - s->length += type & OUT_SIZMASK; - } - else if ((type & OUT_TYPMASK) == OUT_RAWDATA) - { type &= OUT_SIZMASK; - if (s->flags & TYPE_PROGBITS) saa_wbytes(s->contents, data, type); - s->length += type; - } - else if ((type & OUT_TYPMASK) == OUT_RESERVE) - { type &= OUT_SIZMASK; - if (s->flags & TYPE_PROGBITS) - { error(ERR_WARNING, "uninitialised space declared in" - " %s section: zeroing", s->name); - saa_wbytes (s->contents, NULL, type); - } - s->length += type; - } - else if ((type & OUT_TYPMASK) == OUT_REL2ADR || - (type & OUT_TYPMASK) == OUT_REL4ADR) - { realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2); - if (segment != NO_SEG && !find_section_by_index(segment)) - { if (segment % 2) - error(ERR_NONFATAL, "binary output format does not support" - " segment base references"); - else - error(ERR_NONFATAL, "binary output format does not support" - " external references"); - segment = NO_SEG; - } - if (s->flags & TYPE_PROGBITS) - { add_reloc(s, realbytes, segment, segto); - p = mydata; - if (realbytes == 4) - WRITELONG(p, *(long*)data - realbytes - s->length); - else - WRITESHORT(p, *(long*)data - realbytes - s->length); - saa_wbytes(s->contents, mydata, realbytes); - } - s->length += realbytes; - } -} - -static void bin_deflabel (char *name, long segment, long offset, - int is_global, char *special) -{ (void) segment; /* Don't warn that this parameter is unused */ - (void) offset; /* Don't warn that this parameter is unused */ - - if (special) - error (ERR_NONFATAL, "binary format does not support any" - " special symbol types"); - else if (name[0] == '.' && name[1] == '.' && name[2] != '@') - error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); - else if (is_global == 2) - error (ERR_NONFATAL, "binary output format does not support common" - " variables"); - else - { struct Section *s; - struct bin_label ***ltp; - - /* Remember label definition so we can look it up later when - * creating the map file. */ - s = find_section_by_index(segment); - if (s) ltp = &(s->labels_end); - else ltp = &nsl_tail; - (**ltp) = nasm_malloc(sizeof(struct bin_label)); - (**ltp)->name = name; - (**ltp)->next = NULL; - *ltp = &((**ltp)->next); - } - -} - -/* These constants and the following function are used - * by bin_secname() to parse attribute assignments. */ - -enum { ATTRIB_START, ATTRIB_ALIGN, ATTRIB_FOLLOWS, - ATTRIB_VSTART, ATTRIB_VALIGN, ATTRIB_VFOLLOWS, - ATTRIB_NOBITS, ATTRIB_PROGBITS }; - -static int bin_read_attribute(char **line, int *attribute, unsigned long *value) -{ expr *e; - int attrib_name_size; - struct tokenval tokval; - char *exp; - - /* Skip whitespace. */ - while (**line && isspace(**line)) (*line)++; - if (!**line) return 0; - - /* Figure out what attribute we're reading. */ - if (!nasm_strnicmp(*line,"align=", 6)) - { *attribute = ATTRIB_ALIGN; - attrib_name_size = 6; - } - else if (format_mode) - { if (!nasm_strnicmp(*line,"start=", 6)) - { *attribute = ATTRIB_START; - attrib_name_size = 6; - } - else if (!nasm_strnicmp(*line,"follows=", 8)) - { *attribute = ATTRIB_FOLLOWS; - *line += 8; return 1; - } - else if (!nasm_strnicmp(*line,"vstart=", 7)) - { *attribute = ATTRIB_VSTART; - attrib_name_size = 7; - } - else if (!nasm_strnicmp(*line,"valign=", 7)) - { *attribute = ATTRIB_VALIGN; - attrib_name_size = 7; - } - else if (!nasm_strnicmp(*line,"vfollows=", 9)) - { *attribute = ATTRIB_VFOLLOWS; - *line += 9; return 1; - } - else if (!nasm_strnicmp(*line,"nobits", 6) && - (isspace((*line)[6]) || ((*line)[6] == '\0'))) - { *attribute = ATTRIB_NOBITS; - *line += 6; return 1; - } - else if (!nasm_strnicmp(*line,"progbits", 8) && - (isspace((*line)[8]) || ((*line)[8] == '\0'))) - { *attribute = ATTRIB_PROGBITS; - *line += 8; return 1; - } - else return 0; - } - else return 0; - - /* Find the end of the expression. */ - if ((*line)[attrib_name_size] != '(') - { - /* Single term (no parenthesis). */ - exp = *line += attrib_name_size; - while (**line && !isspace(**line)) (*line)++; - if (**line) - { **line = '\0'; (*line)++; - } - } - else - { char c; - int pcount = 1; - - /* Full expression (delimited by parenthesis) */ - exp = *line += attrib_name_size + 1; - while (1) - { (*line) += strcspn(*line, "()'\""); - if (**line == '(') - { ++(*line); ++pcount; - } - if (**line == ')') - { ++(*line); --pcount; - if (!pcount) break; - } - if ((**line == '"') || (**line == '\'')) - { c = **line; - while (**line) - { ++(*line); - if (**line == c) break; - } - if (!**line) - { error(ERR_NONFATAL, "invalid syntax in `section' directive"); - return -1; - } - ++(*line); - } - if (!**line) - { error(ERR_NONFATAL, "expecting `)'"); - return -1; - } - } - *(*line - 1) = '\0'; /* Terminate the expression. */ - } - - /* Check for no value given. */ - if (!*exp) - { error(ERR_WARNING, "No value given to attribute in" - " `section' directive"); - return -1; - } - - /* Read and evaluate the expression. */ - stdscan_reset(); - stdscan_bufptr = exp; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); - if (e) - { if (!is_really_simple(e)) - { error(ERR_NONFATAL, "section attribute value must be" - " a critical expression"); - return -1; - } - } - else - { error(ERR_NONFATAL, "Invalid attribute value" - " specified in `section' directive."); - return -1; - } - *value = (unsigned long) reloc_value(e); - return 1; -} - -static void bin_assign_attributes(struct Section *sec, char *astring) -{ int attribute, check; - unsigned long value; - char *p; - - while (1) - { /* Get the next attribute. */ - check = bin_read_attribute(&astring, &attribute, &value); - /* Skip bad attribute. */ - if (check == -1) continue; - /* Unknown section attribute, so skip it and warn the user. */ - if (!check) - { if (!*astring) break; /* End of line. */ - else - { p = astring; while (*astring && !isspace(*astring)) astring++; - if (*astring) - { *astring = '\0'; astring++; - } - error(ERR_WARNING, "ignoring unknown section attribute:" - " \"%s\"", p); - } - continue; - } - - switch (attribute) - { /* Handle nobits attribute. */ - case ATTRIB_NOBITS: - if ((sec->flags & TYPE_DEFINED) && (sec->flags & TYPE_PROGBITS)) - error(ERR_NONFATAL, "attempt to change section type" - " from progbits to nobits"); - else sec->flags |= TYPE_DEFINED | TYPE_NOBITS; - continue; - - /* Handle progbits attribute. */ - case ATTRIB_PROGBITS: - if ((sec->flags & TYPE_DEFINED) && (sec->flags & TYPE_NOBITS)) - error(ERR_NONFATAL, "attempt to change section type" - " from nobits to progbits"); - else sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; - continue; - - /* Handle align attribute. */ - case ATTRIB_ALIGN: - if (!format_mode && (!strcmp(sec->name, ".text"))) - error(ERR_NONFATAL, "cannot specify an alignment" - " to the .text section"); - else - { if (!value || ((value - 1) & value)) - error(ERR_NONFATAL, "argument to `align' is not a" - " power of two"); - else - { /* Alignment is already satisfied if the previous - * align value is greater. */ - if ((sec->flags & ALIGN_DEFINED) && (value < sec->align)) - value = sec->align; - - /* Don't allow a conflicting align value. */ - if ((sec->flags & START_DEFINED) && (sec->start & (value - 1))) - error(ERR_NONFATAL, "`align' value conflicts " - "with section start address"); - else - { sec->align = value; sec->flags |= ALIGN_DEFINED; - } - } - } - continue; - - /* Handle valign attribute. */ - case ATTRIB_VALIGN: - if (!value || ((value - 1) & value)) - error(ERR_NONFATAL, "argument to `valign' is not a" - " power of two"); - else - { /* Alignment is already satisfied if the previous - * align value is greater. */ - if ((sec->flags & VALIGN_DEFINED) && (value < sec->valign)) - value = sec->valign; - - /* Don't allow a conflicting valign value. */ - if ((sec->flags & VSTART_DEFINED) && (sec->vstart & (value - 1))) - error(ERR_NONFATAL, "`valign' value conflicts " - "with `vstart' address"); - else - { sec->valign = value; sec->flags |= VALIGN_DEFINED; - } - } - continue; - - /* Handle start attribute. */ - case ATTRIB_START: - if (sec->flags & FOLLOWS_DEFINED) - error(ERR_NONFATAL, "cannot combine `start' and `follows'" - " section attributes"); - else if (value < 0) - error(ERR_NONFATAL, "attempt to specify a negative" - " section start address"); - else if ((sec->flags & START_DEFINED) && (value != sec->start)) - error(ERR_NONFATAL, "section start address redefined"); - else - { sec->start = value; sec->flags |= START_DEFINED; - if (sec->flags & ALIGN_DEFINED) - { if (sec->start & (sec->align - 1)) - error (ERR_NONFATAL, "`start' address conflicts" - " with section alignment"); - sec->flags ^= ALIGN_DEFINED; - } - } - continue; - - /* Handle vstart attribute. */ - case ATTRIB_VSTART: - if (sec->flags & VFOLLOWS_DEFINED) - error(ERR_NONFATAL, "cannot combine `vstart' and `vfollows'" - " section attributes"); - else if ((sec->flags & VSTART_DEFINED) && (value != sec->vstart)) - error(ERR_NONFATAL, "section virtual start address" - " (vstart) redefined"); - else - { sec->vstart = value; sec->flags |= VSTART_DEFINED; - if (sec->flags & VALIGN_DEFINED) - { if (sec->vstart & (sec->valign - 1)) - error (ERR_NONFATAL, "`vstart' address conflicts" - " with `valign' value"); - sec->flags ^= VALIGN_DEFINED; - } - } - continue; - - /* Handle follows attribute. */ - case ATTRIB_FOLLOWS: - p = astring; astring += strcspn(astring, " \t"); - if (astring == p) - error(ERR_NONFATAL, "expecting section name for `follows'" - " attribute"); - else - { *(astring++) = '\0'; - if (sec->flags & START_DEFINED) - error(ERR_NONFATAL, "cannot combine `start' and `follows'" - " section attributes"); - sec->follows = nasm_strdup(p); - sec->flags |= FOLLOWS_DEFINED; - } - continue; - - /* Handle vfollows attribute. */ - case ATTRIB_VFOLLOWS: - if (sec->flags & VSTART_DEFINED) - error(ERR_NONFATAL, "cannot combine `vstart' and `vfollows'" - " section attributes"); - else - { p = astring; astring += strcspn(astring, " \t"); - if (astring == p) - error(ERR_NONFATAL, "expecting section name for `vfollows'" - " attribute"); - else - { *(astring++) = '\0'; - sec->vfollows = nasm_strdup(p); - sec->flags |= VFOLLOWS_DEFINED; - } - } - continue; - } - } -} - -static void bin_define_section_labels() -{ static int labels_defined = 0; - struct Section * sec; - char * label_name; - size_t base_len; - - if (labels_defined) return; - for (sec = sections; sec; sec = sec->next) - { base_len = strlen(sec->name) + 8; - label_name = nasm_malloc(base_len + 8); - strcpy(label_name, "section."); - strcpy(label_name + 8, sec->name); - - /* section..start */ - strcpy(label_name + base_len, ".start"); - define_label(label_name, sec->start_index, 0L, - NULL, 0, 0, bin_get_ofmt(), error); - - /* section..vstart */ - strcpy(label_name + base_len, ".vstart"); - define_label(label_name, sec->vstart_index, 0L, - NULL, 0, 0, bin_get_ofmt(), error); - - nasm_free(label_name); - } - labels_defined = 1; -} - -static long bin_secname(char *name, int pass, int *bits) -{ char *p; - struct Section *sec; - - /* bin_secname is called with *name = NULL at the start of each - * pass. Use this opportunity to establish the default section - * (default is BITS-16 ".text" segment). - */ - if (!name) - { /* Reset ORG and section attributes at the start of each pass. */ - origin_defined = 0; - for (sec = sections; sec; sec = sec->next) - sec->flags &= ~(START_DEFINED | VSTART_DEFINED | - ALIGN_DEFINED | VALIGN_DEFINED); - - /* Define section start and vstart labels. */ - if (format_mode && (pass != 1)) bin_define_section_labels(); - - /* Establish the default (.text) section. */ - *bits = 16; - sec = find_section_by_name(".text"); - sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; - current_section = sec->vstart_index; - return current_section; - } - - /* Attempt to find the requested section. If it does not - * exist, create it. */ - p = name; - while (*p && !isspace(*p)) p++; - if (*p) *p++ = '\0'; - sec = find_section_by_name(name); - if(!sec) - { sec = create_section(name); - if (!strcmp(name, ".data")) - sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; - else if (!strcmp(name, ".bss")) - { sec->flags |= TYPE_DEFINED | TYPE_NOBITS; - sec->ifollows = NULL; - } - else if (!format_mode) - { error(ERR_NONFATAL, "section name must be " - ".text, .data, or .bss"); - return current_section; - } - } - - /* Handle attribute assignments. */ - if (pass != 1) bin_assign_attributes(sec, p); - -#ifndef ABIN_SMART_ADAPT - /* The following line disables smart adaptation of - * PROGBITS/NOBITS section types (it forces sections to - * default to PROGBITS). */ - if ((pass != 1) && !(sec->flags & TYPE_DEFINED)) - sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; -#endif - - /* Set the current section and return. */ - current_section = sec->vstart_index; - return current_section; -} - -static int bin_directive (char *directive, char *args, int pass) -{ - /* Handle ORG directive */ - if (!nasm_stricmp(directive, "org")) - { struct tokenval tokval; - unsigned long value; - expr *e; - - stdscan_reset(); - stdscan_bufptr = args; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); - if (e) - { if (!is_really_simple(e)) - error(ERR_NONFATAL, "org value must be a critical" - " expression"); - else - { value = reloc_value(e); - /* Check for ORG redefinition. */ - if (origin_defined && (value != origin)) - error(ERR_NONFATAL, "program origin redefined"); - else - { origin = value; - origin_defined = 1; - } - } - } - else - error(ERR_NONFATAL, "No or invalid offset specified" - " in ORG directive."); - return 1; - } - - /* The 'map' directive allows the user to generate section - * and symbol information to stdout, stderr, or to a file. */ - else if (format_mode && !nasm_stricmp(directive, "map")) - { char *p; - - if (pass != 1) return 1; - args += strspn(args, " \t"); - while (*args) - { p = args; args += strcspn(args, " \t"); - if (*args != '\0') *(args++) = '\0'; - if (!nasm_stricmp(p, "all")) - map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS | MAP_SYMBOLS; - else if (!nasm_stricmp(p, "brief")) - map_control |= MAP_ORIGIN | MAP_SUMMARY; - else if (!nasm_stricmp(p, "sections")) - map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS; - else if (!nasm_stricmp(p, "segments")) - map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS; - else if (!nasm_stricmp(p, "symbols")) - map_control |= MAP_SYMBOLS; - else if (!rf) - { if (!nasm_stricmp(p, "stdout")) - rf = stdout; - else if (!nasm_stricmp(p, "stderr")) - rf = stderr; - else - { /* Must be a filename. */ - rf = fopen(p, "wt"); - if (!rf) - { error(ERR_WARNING, "unable to open map file `%s'", p); - map_control = 0; - return 1; - } - } - } - else error(ERR_WARNING, "map file already specified"); - } - if (map_control == 0) map_control |= MAP_ORIGIN | MAP_SUMMARY; - if (!rf) rf = stdout; - return 1; - } - return 0; -} - -static void bin_filename (char *inname, char *outname, efunc error) -{ standard_extension(inname, outname, "", error); - infile = inname; outfile = outname; -} - -static long bin_segbase (long segment) -{ return segment; -} - -static int bin_set_info(enum geninfo type, char **val) -{ return 0; -} - -static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) -{ fp = afp; - error = errfunc; - - (void) eval; /* Don't warn that this parameter is unused. */ - (void) ldef; /* Placate optimizers. */ - - relocs = NULL; - reloctail = &relocs; - origin_defined = 0; - no_seg_labels = NULL; - nsl_tail = &no_seg_labels; - format_mode = 1; /* Extended bin format - * (set this to zero for old bin format). */ - - /* Create default section (.text). */ - sections = last_section = nasm_malloc(sizeof(struct Section)); - last_section->next = NULL; - last_section->name = nasm_strdup(".text"); - last_section->contents = saa_init(1L); - last_section->follows = last_section->vfollows = 0; - last_section->ifollows = NULL; - last_section->length = 0; - last_section->flags = TYPE_DEFINED | TYPE_PROGBITS; - last_section->labels = NULL; - last_section->labels_end = &(last_section->labels); - last_section->start_index = seg_alloc(); - last_section->vstart_index = current_section = seg_alloc(); -} - -struct ofmt of_bin = { - "flat-form binary files (e.g. DOS .COM, .SYS)", - "bin", - NULL, - null_debug_arr, - &null_debug_form, - bin_stdmac, - bin_init, - bin_set_info, - bin_out, - bin_deflabel, - bin_secname, - bin_segbase, - bin_directive, - bin_filename, - bin_cleanup -}; - -/* This is needed for bin_define_section_labels() */ -struct ofmt *bin_get_ofmt() -{ return &of_bin; -} - -#endif /* #ifdef OF_BIN */ +/* outbin.c output routines for the Netwide Assembler to produce + * flat-form binary files + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +/* This is the extended version of NASM's original binary output + * format. It is backward compatible with the original BIN format, + * and contains support for multiple sections and advanced section + * ordering. + * + * Feature summary: + * + * - Users can create an arbitrary number of sections; they are not + * limited to just ".text", ".data", and ".bss". + * + * - Sections can be either progbits or nobits type. + * + * - You can specify that they be aligned at a certian boundary + * following the previous section ("align="), or positioned at an + * arbitrary byte-granular location ("start="). + * + * - You can specify a "virtual" start address for a section, which + * will be used for the calculation for all address references + * with respect to that section ("vstart="). + * + * - The ORG directive, as well as the section/segment directive + * arguments ("align=", "start=", "vstart="), can take a critical + * expression as their value. For example: "align=(1 << 12)". + * + * - You can generate map files using the 'map' directive. + * + */ + +/* Uncomment the following define if you want sections to adapt + * their progbits/nobits state depending on what type of + * instructions are issued, rather than defaulting to progbits. + * Note that this behavior violates the specification. + +#define ABIN_SMART_ADAPT + +*/ + +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "labels.h" +#include "eval.h" +#include "outform.h" + +#ifdef OF_BIN + +struct ofmt *bin_get_ofmt(); /* Prototype goes here since no header file. */ + +static FILE *fp, *rf = NULL; +static efunc error; + +/* Section flags keep track of which attributes the user has defined. */ +#define START_DEFINED 0x001 +#define ALIGN_DEFINED 0x002 +#define FOLLOWS_DEFINED 0x004 +#define VSTART_DEFINED 0x008 +#define VALIGN_DEFINED 0x010 +#define VFOLLOWS_DEFINED 0x020 +#define TYPE_DEFINED 0x040 +#define TYPE_PROGBITS 0x080 +#define TYPE_NOBITS 0x100 + +/* This struct is used to keep track of symbols for map-file generation. */ +static struct bin_label { + char *name; + struct bin_label *next; +} *no_seg_labels, **nsl_tail; + +static struct Section { + char *name; + struct SAA *contents; + long length; /* section length in bytes */ + +/* Section attributes */ + int flags; /* see flag definitions above */ + unsigned long align; /* section alignment */ + unsigned long valign; /* notional section alignment */ + unsigned long start; /* section start address */ + unsigned long vstart; /* section virtual start address */ + char *follows; /* the section that this one will follow */ + char *vfollows; /* the section that this one will notionally follow */ + long start_index; /* NASM section id for non-relocated version */ + long vstart_index; /* the NASM section id */ + + struct bin_label *labels; /* linked-list of label handles for map output. */ + struct bin_label **labels_end; /* Holds address of end of labels list. */ + struct Section *ifollows; /* Points to previous section (implicit follows). */ + struct Section *next; /* This links sections with a defined start address. */ + +/* The extended bin format allows for sections to have a "virtual" + * start address. This is accomplished by creating two sections: + * one beginning at the Load Memory Address and the other beginning + * at the Virtual Memory Address. The LMA section is only used to + * define the section..start label, but there isn't + * any other good way for us to handle that label. + */ + +} *sections, *last_section; + +static struct Reloc { + struct Reloc *next; + long posn; + long bytes; + long secref; + long secrel; + struct Section *target; +} *relocs, **reloctail; + +extern char *stdscan_bufptr; +extern int lookup_label(char *label, long *segment, long *offset); + +static unsigned char format_mode; /* 0 = original bin, 1 = extended bin */ +static long current_section; /* only really needed if format_mode = 0 */ +static unsigned long origin; +static int origin_defined; + +/* Stuff we need for map-file generation. */ +#define MAP_ORIGIN 1 +#define MAP_SUMMARY 2 +#define MAP_SECTIONS 4 +#define MAP_SYMBOLS 8 +static int map_control = 0; +static char *infile, *outfile; + +static const char *bin_stdmac[] = { + "%define __SECT__ [section .text]", + "%imacro org 1+.nolist", + "[org %1]", + "%endmacro", + "%macro __NASM_CDecl__ 1", + "%endmacro", + NULL +}; + +static void add_reloc(struct Section *s, long bytes, long secref, + long secrel) +{ + struct Reloc *r; + + r = *reloctail = nasm_malloc(sizeof(struct Reloc)); + reloctail = &r->next; + r->next = NULL; + r->posn = s->length; + r->bytes = bytes; + r->secref = secref; + r->secrel = secrel; + r->target = s; +} + +static struct Section *find_section_by_name(const char *name) +{ + struct Section *s; + + for (s = sections; s; s = s->next) + if (!strcmp(s->name, name)) + break; + return s; +} + +static struct Section *find_section_by_index(long index) +{ + struct Section *s; + + for (s = sections; s; s = s->next) + if ((index == s->vstart_index) || (index == s->start_index)) + break; + return s; +} + +static struct Section *create_section(char *name) +{ /* Create a new section. */ + last_section->next = nasm_malloc(sizeof(struct Section)); + last_section->next->ifollows = last_section; + last_section = last_section->next; + last_section->labels = NULL; + last_section->labels_end = &(last_section->labels); + + /* Initialize section attributes. */ + last_section->name = nasm_strdup(name); + last_section->contents = saa_init(1L); + last_section->follows = last_section->vfollows = 0; + last_section->length = 0; + last_section->flags = 0; + last_section->next = NULL; + + /* Register our sections with NASM. */ + last_section->vstart_index = seg_alloc(); + last_section->start_index = seg_alloc(); + return last_section; +} + +static void bin_cleanup(int debuginfo) +{ + struct Section *g, **gp; + struct Section *gs = NULL, **gsp; + struct Section *s, **sp; + struct Section *nobits = NULL, **nt; + struct Section *last_progbits; + struct bin_label *l; + struct Reloc *r; + unsigned long pend; + int h; + +#ifdef DEBUG + fprintf(stdout, + "bin_cleanup: Sections were initially referenced in this order:\n"); + for (h = 0, s = sections; s; h++, s = s->next) + fprintf(stdout, "%i. %s\n", h, s->name); +#endif + + /* Assembly has completed, so now we need to generate the output file. + * Step 1: Separate progbits and nobits sections into separate lists. + * Step 2: Sort the progbits sections into their output order. + * Step 3: Compute start addresses for all progbits sections. + * Step 4: Compute vstart addresses for all sections. + * Step 5: Apply relocations. + * Step 6: Write the sections' data to the output file. + * Step 7: Generate the map file. + * Step 8: Release all allocated memory. + */ + + /* To do: Smart section-type adaptation could leave some empty sections + * without a defined type (progbits/nobits). Won't fix now since this + * feature will be disabled. */ + + /* Step 1: Split progbits and nobits sections into separate lists. */ + + nt = &nobits; + /* Move nobits sections into a separate list. Also pre-process nobits + * sections' attributes. */ + for (sp = §ions->next, s = sections->next; s; s = *sp) { /* Skip progbits sections. */ + if (s->flags & TYPE_PROGBITS) { + sp = &s->next; + continue; + } + /* Do some special pre-processing on nobits sections' attributes. */ + if (s->flags & (START_DEFINED | ALIGN_DEFINED | FOLLOWS_DEFINED)) { /* Check for a mixture of real and virtual section attributes. */ + if (s-> + flags & (VSTART_DEFINED | VALIGN_DEFINED | + VFOLLOWS_DEFINED)) + error(ERR_FATAL, + "cannot mix real and virtual attributes" + " in nobits section (%s)", s->name); + /* Real and virtual attributes mean the same thing for nobits sections. */ + if (s->flags & START_DEFINED) { + s->vstart = s->start; + s->flags |= VSTART_DEFINED; + } + if (s->flags & ALIGN_DEFINED) { + s->valign = s->align; + s->flags |= VALIGN_DEFINED; + } + if (s->flags & FOLLOWS_DEFINED) { + s->vfollows = s->follows; + s->flags |= VFOLLOWS_DEFINED; + s->flags &= ~FOLLOWS_DEFINED; + } + } + /* Every section must have a start address. */ + if (s->flags & VSTART_DEFINED) { + s->start = s->vstart; + s->flags |= START_DEFINED; + } + /* Move the section into the nobits list. */ + *sp = s->next; + s->next = NULL; + *nt = s; + nt = &s->next; + } + + /* Step 2: Sort the progbits sections into their output order. */ + + /* In Step 2 we move around sections in groups. A group + * begins with a section (group leader) that has a user- + * defined start address or follows section. The remainder + * of the group is made up of the sections that implicitly + * follow the group leader (i.e., they were defined after + * the group leader and were not given an explicit start + * address or follows section by the user). */ + + /* For anyone attempting to read this code: + * g (group) points to a group of sections, the first one of which has + * a user-defined start address or follows section. + * gp (g previous) holds the location of the pointer to g. + * gs (g scan) is a temp variable that we use to scan to the end of the group. + * gsp (gs previous) holds the location of the pointer to gs. + * nt (nobits tail) points to the nobits section-list tail. + */ + + /* Link all 'follows' groups to their proper position. To do + * this we need to know three things: the start of the group + * to relocate (g), the section it is following (s), and the + * end of the group we're relocating (gs). */ + for (gp = §ions, g = sections; g; g = gs) { /* Find the next follows group that is out of place (g). */ + if (!(g->flags & FOLLOWS_DEFINED)) { + while (g->next) { + if ((g->next->flags & FOLLOWS_DEFINED) && + strcmp(g->name, g->next->follows)) + break; + g = g->next; + } + if (!g->next) + break; + gp = &g->next; + g = g->next; + } + /* Find the section that this group follows (s). */ + for (sp = §ions, s = sections; + s && strcmp(s->name, g->follows); + sp = &s->next, s = s->next) ; + if (!s) + error(ERR_FATAL, "section %s follows an invalid or" + " unknown section (%s)", g->name, g->follows); + if (s->next && (s->next->flags & FOLLOWS_DEFINED) && + !strcmp(s->name, s->next->follows)) + error(ERR_FATAL, "sections %s and %s can't both follow" + " section %s", g->name, s->next->name, s->name); + /* Find the end of the current follows group (gs). */ + for (gsp = &g->next, gs = g->next; + gs && (gs != s) && !(gs->flags & START_DEFINED); + gsp = &gs->next, gs = gs->next) { + if (gs->next && (gs->next->flags & FOLLOWS_DEFINED) && + strcmp(gs->name, gs->next->follows)) { + gsp = &gs->next; + gs = gs->next; + break; + } + } + /* Re-link the group after its follows section. */ + *gsp = s->next; + s->next = g; + *gp = gs; + } + + /* Link all 'start' groups to their proper position. Once + * again we need to know g, s, and gs (see above). The main + * difference is we already know g since we sort by moving + * groups from the 'unsorted' list into a 'sorted' list (g + * will always be the first section in the unsorted list). */ + for (g = sections, sections = NULL; g; g = gs) { /* Find the section that we will insert this group before (s). */ + for (sp = §ions, s = sections; s; sp = &s->next, s = s->next) + if ((s->flags & START_DEFINED) && (g->start < s->start)) + break; + /* Find the end of the group (gs). */ + for (gs = g->next, gsp = &g->next; + gs && !(gs->flags & START_DEFINED); + gsp = &gs->next, gs = gs->next) ; + /* Re-link the group before the target section. */ + *sp = g; + *gsp = s; + } + + /* Step 3: Compute start addresses for all progbits sections. */ + + /* Make sure we have an origin and a start address for the first section. */ + if (origin_defined) + switch (sections->flags & (START_DEFINED | ALIGN_DEFINED)) { + case START_DEFINED | ALIGN_DEFINED: + case START_DEFINED: + /* Make sure this section doesn't begin before the origin. */ + if (sections->start < origin) + error(ERR_FATAL, "section %s begins" + " before program origin", sections->name); + break; + case ALIGN_DEFINED: + sections->start = ((origin + sections->align - 1) & + ~(sections->align - 1)); + break; + case 0: + sections->start = origin; + } else { + if (!(sections->flags & START_DEFINED)) + sections->start = 0; + origin = sections->start; + } + sections->flags |= START_DEFINED; + + /* Make sure each section has an explicit start address. If it + * doesn't, then compute one based its alignment and the end of + * the previous section. */ + for (pend = sections->start, g = s = sections; g; g = g->next) { /* Find the next section that could cause an overlap situation + * (has a defined start address, and is not zero length). */ + if (g == s) + for (s = g->next; + s && ((s->length == 0) || !(s->flags & START_DEFINED)); + s = s->next) ; + /* Compute the start address of this section, if necessary. */ + if (!(g->flags & START_DEFINED)) { /* Default to an alignment of 4 if unspecified. */ + if (!(g->flags & ALIGN_DEFINED)) { + g->align = 4; + g->flags |= ALIGN_DEFINED; + } + /* Set the section start address. */ + g->start = (pend + g->align - 1) & ~(g->align - 1); + g->flags |= START_DEFINED; + } + /* Ugly special case for progbits sections' virtual attributes: + * If there is a defined valign, but no vstart and no vfollows, then + * we valign after the previous progbits section. This case doesn't + * really make much sense for progbits sections with a defined start + * address, but it is possible and we must do *something*. + * Not-so-ugly special case: + * If a progbits section has no virtual attributes, we set the + * vstart equal to the start address. */ + if (!(g->flags & (VSTART_DEFINED | VFOLLOWS_DEFINED))) { + if (g->flags & VALIGN_DEFINED) + g->vstart = (pend + g->valign - 1) & ~(g->valign - 1); + else + g->vstart = g->start; + g->flags |= VSTART_DEFINED; + } + /* Ignore zero-length sections. */ + if (g->start < pend) + continue; + /* Compute the span of this section. */ + pend = g->start + g->length; + /* Check for section overlap. */ + if (s) { + if (g->start > s->start) + error(ERR_FATAL, "sections %s ~ %s and %s overlap!", + gs->name, g->name, s->name); + if (pend > s->start) + error(ERR_FATAL, "sections %s and %s overlap!", + g->name, s->name); + } + /* Remember this section as the latest >0 length section. */ + gs = g; + } + + /* Step 4: Compute vstart addresses for all sections. */ + + /* Attach the nobits sections to the end of the progbits sections. */ + for (s = sections; s->next; s = s->next) ; + s->next = nobits; + last_progbits = s; + /* Scan for sections that don't have a vstart address. If we find one we'll + * attempt to compute its vstart. If we can't compute the vstart, we leave + * it alone and come back to it in a subsequent scan. We continue scanning + * and re-scanning until we've gone one full cycle without computing any + * vstarts. */ + do { /* Do one full scan of the sections list. */ + for (h = 0, g = sections; g; g = g->next) { + if (g->flags & VSTART_DEFINED) + continue; + /* Find the section that this one virtually follows. */ + if (g->flags & VFOLLOWS_DEFINED) { + for (s = sections; s && strcmp(g->vfollows, s->name); + s = s->next) ; + if (!s) + error(ERR_FATAL, + "section %s vfollows unknown section (%s)", + g->name, g->vfollows); + } else if (g->ifollows != NULL) + for (s = sections; s && (s != g->ifollows); s = s->next) ; + /* The .bss section is the only one with ifollows = NULL. In this case we + * implicitly follow the last progbits section. */ + else + s = last_progbits; + + /* If the section we're following has a vstart, we can proceed. */ + if (s->flags & VSTART_DEFINED) { /* Default to virtual alignment of four. */ + if (!(g->flags & VALIGN_DEFINED)) { + g->valign = 4; + g->flags |= VALIGN_DEFINED; + } + /* Compute the vstart address. */ + g->vstart = + (s->vstart + s->length + g->valign - 1) & ~(g->valign - + 1); + g->flags |= VSTART_DEFINED; + h++; + /* Start and vstart mean the same thing for nobits sections. */ + if (g->flags & TYPE_NOBITS) + g->start = g->vstart; + } + } + } while (h); + + /* Now check for any circular vfollows references, which will manifest + * themselves as sections without a defined vstart. */ + for (h = 0, s = sections; s; s = s->next) { + if (!(s->flags & VSTART_DEFINED)) { /* Non-fatal errors after assembly has completed are generally a + * no-no, but we'll throw a fatal one eventually so it's ok. */ + error(ERR_NONFATAL, "cannot compute vstart for section %s", + s->name); + h++; + } + } + if (h) + error(ERR_FATAL, "circular vfollows path detected"); + +#ifdef DEBUG + fprintf(stdout, + "bin_cleanup: Confirm final section order for output file:\n"); + for (h = 0, s = sections; s && (s->flags & TYPE_PROGBITS); + h++, s = s->next) + fprintf(stdout, "%i. %s\n", h, s->name); +#endif + + /* Step 5: Apply relocations. */ + + /* Prepare the sections for relocating. */ + for (s = sections; s; s = s->next) + saa_rewind(s->contents); + /* Apply relocations. */ + for (r = relocs; r; r = r->next) { + unsigned char *p, *q, mydata[4]; + long l; + + saa_fread(r->target->contents, r->posn, mydata, r->bytes); + p = q = mydata; + l = *p++; + + if (r->bytes > 1) { + l += ((long)*p++) << 8; + if (r->bytes == 4) { + l += ((long)*p++) << 16; + l += ((long)*p++) << 24; + } + } + + s = find_section_by_index(r->secref); + if (s) { + if (r->secref == s->start_index) + l += s->start; + else + l += s->vstart; + } + s = find_section_by_index(r->secrel); + if (s) { + if (r->secrel == s->start_index) + l -= s->start; + else + l -= s->vstart; + } + + if (r->bytes == 4) + WRITELONG(q, l); + else if (r->bytes == 2) + WRITESHORT(q, l); + else + *q++ = (unsigned char)(l & 0xFF); + saa_fwrite(r->target->contents, r->posn, mydata, r->bytes); + } + + /* Step 6: Write the section data to the output file. */ + + /* Write the progbits sections to the output file. */ + for (pend = origin, s = sections; s && (s->flags & TYPE_PROGBITS); s = s->next) { /* Skip zero-length sections. */ + if (s->length == 0) + continue; + /* Pad the space between sections. */ + for (h = s->start - pend; h; h--) + fputc('\0', fp); + /* Write the section to the output file. */ + if (s->length > 0) + saa_fpwrite(s->contents, fp); + pend = s->start + s->length; + } + /* Done writing the file, so close it. */ + fclose(fp); + + /* Step 7: Generate the map file. */ + + if (map_control) { + const char *not_defined = { "not defined" }; + + /* Display input and output file names. */ + fprintf(rf, "\n- NASM Map file "); + for (h = 63; h; h--) + fputc('-', rf); + fprintf(rf, "\n\nSource file: %s\nOutput file: %s\n\n", + infile, outfile); + + if (map_control & MAP_ORIGIN) { /* Display program origin. */ + fprintf(rf, "-- Program origin "); + for (h = 61; h; h--) + fputc('-', rf); + fprintf(rf, "\n\n%08lX\n\n", origin); + } + /* Display sections summary. */ + if (map_control & MAP_SUMMARY) { + fprintf(rf, "-- Sections (summary) "); + for (h = 57; h; h--) + fputc('-', rf); + fprintf(rf, "\n\nVstart Start Stop " + "Length Class Name\n"); + for (s = sections; s; s = s->next) { + fprintf(rf, "%08lX %08lX %08lX %08lX ", + s->vstart, s->start, s->start + s->length, + s->length); + if (s->flags & TYPE_PROGBITS) + fprintf(rf, "progbits "); + else + fprintf(rf, "nobits "); + fprintf(rf, "%s\n", s->name); + } + fprintf(rf, "\n"); + } + /* Display detailed section information. */ + if (map_control & MAP_SECTIONS) { + fprintf(rf, "-- Sections (detailed) "); + for (h = 56; h; h--) + fputc('-', rf); + fprintf(rf, "\n\n"); + for (s = sections; s; s = s->next) { + fprintf(rf, "---- Section %s ", s->name); + for (h = 65 - strlen(s->name); h; h--) + fputc('-', rf); + fprintf(rf, "\n\nclass: "); + if (s->flags & TYPE_PROGBITS) + fprintf(rf, "progbits"); + else + fprintf(rf, "nobits"); + fprintf(rf, "\nlength: %08lX\nstart: %08lX" + "\nalign: ", s->length, s->start); + if (s->flags & ALIGN_DEFINED) + fprintf(rf, "%08lX", s->align); + else + fprintf(rf, not_defined); + fprintf(rf, "\nfollows: "); + if (s->flags & FOLLOWS_DEFINED) + fprintf(rf, "%s", s->follows); + else + fprintf(rf, not_defined); + fprintf(rf, "\nvstart: %08lX\nvalign: ", s->vstart); + if (s->flags & VALIGN_DEFINED) + fprintf(rf, "%08lX", s->valign); + else + fprintf(rf, not_defined); + fprintf(rf, "\nvfollows: "); + if (s->flags & VFOLLOWS_DEFINED) + fprintf(rf, "%s", s->vfollows); + else + fprintf(rf, not_defined); + fprintf(rf, "\n\n"); + } + } + /* Display symbols information. */ + if (map_control & MAP_SYMBOLS) { + long segment, offset; + + fprintf(rf, "-- Symbols "); + for (h = 68; h; h--) + fputc('-', rf); + fprintf(rf, "\n\n"); + if (no_seg_labels) { + fprintf(rf, "---- No Section "); + for (h = 63; h; h--) + fputc('-', rf); + fprintf(rf, "\n\nValue Name\n"); + for (l = no_seg_labels; l; l = l->next) { + lookup_label(l->name, &segment, &offset); + fprintf(rf, "%08lX %s\n", offset, l->name); + } + fprintf(rf, "\n\n"); + } + for (s = sections; s; s = s->next) { + if (s->labels) { + fprintf(rf, "---- Section %s ", s->name); + for (h = 65 - strlen(s->name); h; h--) + fputc('-', rf); + fprintf(rf, "\n\nReal Virtual Name\n"); + for (l = s->labels; l; l = l->next) { + lookup_label(l->name, &segment, &offset); + fprintf(rf, "%08lX %08lX %s\n", + s->start + offset, s->vstart + offset, + l->name); + } + fprintf(rf, "\n"); + } + } + } + } + + /* Close the report file. */ + if (map_control && (rf != stdout) && (rf != stderr)) + fclose(rf); + + /* Step 8: Release all allocated memory. */ + + /* Free sections, label pointer structs, etc.. */ + while (sections) { + s = sections; + sections = s->next; + saa_free(s->contents); + nasm_free(s->name); + if (s->flags & FOLLOWS_DEFINED) + nasm_free(s->follows); + if (s->flags & VFOLLOWS_DEFINED) + nasm_free(s->vfollows); + while (s->labels) { + l = s->labels; + s->labels = l->next; + nasm_free(l); + } + nasm_free(s); + } + + /* Free no-section labels. */ + while (no_seg_labels) { + l = no_seg_labels; + no_seg_labels = l->next; + nasm_free(l); + } + + /* Free relocation structures. */ + while (relocs) { + r = relocs->next; + nasm_free(relocs); + relocs = r; + } +} + +static void bin_out(long segto, const void *data, unsigned long type, + long segment, long wrt) +{ + unsigned char *p, mydata[4]; + struct Section *s; + long realbytes; + + if (wrt != NO_SEG) { + wrt = NO_SEG; /* continue to do _something_ */ + error(ERR_NONFATAL, "WRT not supported by binary output format"); + } + + /* Handle absolute-assembly (structure definitions). */ + if (segto == NO_SEG) { + if ((type & OUT_TYPMASK) != OUT_RESERVE) + error(ERR_NONFATAL, "attempt to assemble code in" + " [ABSOLUTE] space"); + return; + } + + /* Find the segment we are targeting. */ + s = find_section_by_index(segto); + if (!s) + error(ERR_PANIC, "code directed to nonexistent segment?"); + + /* "Smart" section-type adaptation code. */ + if (!(s->flags & TYPE_DEFINED)) { + if ((type & OUT_TYPMASK) == OUT_RESERVE) + s->flags |= TYPE_DEFINED | TYPE_NOBITS; + else + s->flags |= TYPE_DEFINED | TYPE_PROGBITS; + } + + if ((s->flags & TYPE_NOBITS) && ((type & OUT_TYPMASK) != OUT_RESERVE)) + error(ERR_WARNING, "attempt to initialise memory in a" + " nobits section: ignored"); + + if ((type & OUT_TYPMASK) == OUT_ADDRESS) { + if (segment != NO_SEG && !find_section_by_index(segment)) { + if (segment % 2) + error(ERR_NONFATAL, "binary output format does not support" + " segment base references"); + else + error(ERR_NONFATAL, "binary output format does not support" + " external references"); + segment = NO_SEG; + } + if (s->flags & TYPE_PROGBITS) { + if (segment != NO_SEG) + add_reloc(s, type & OUT_SIZMASK, segment, -1L); + p = mydata; + if ((type & OUT_SIZMASK) == 4) + WRITELONG(p, *(long *)data); + else + WRITESHORT(p, *(long *)data); + saa_wbytes(s->contents, mydata, type & OUT_SIZMASK); + } + s->length += type & OUT_SIZMASK; + } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) { + type &= OUT_SIZMASK; + if (s->flags & TYPE_PROGBITS) + saa_wbytes(s->contents, data, type); + s->length += type; + } else if ((type & OUT_TYPMASK) == OUT_RESERVE) { + type &= OUT_SIZMASK; + if (s->flags & TYPE_PROGBITS) { + error(ERR_WARNING, "uninitialised space declared in" + " %s section: zeroing", s->name); + saa_wbytes(s->contents, NULL, type); + } + s->length += type; + } else if ((type & OUT_TYPMASK) == OUT_REL2ADR || + (type & OUT_TYPMASK) == OUT_REL4ADR) { + realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2); + if (segment != NO_SEG && !find_section_by_index(segment)) { + if (segment % 2) + error(ERR_NONFATAL, "binary output format does not support" + " segment base references"); + else + error(ERR_NONFATAL, "binary output format does not support" + " external references"); + segment = NO_SEG; + } + if (s->flags & TYPE_PROGBITS) { + add_reloc(s, realbytes, segment, segto); + p = mydata; + if (realbytes == 4) + WRITELONG(p, *(long *)data - realbytes - s->length); + else + WRITESHORT(p, *(long *)data - realbytes - s->length); + saa_wbytes(s->contents, mydata, realbytes); + } + s->length += realbytes; + } +} + +static void bin_deflabel(char *name, long segment, long offset, + int is_global, char *special) +{ + (void)segment; /* Don't warn that this parameter is unused */ + (void)offset; /* Don't warn that this parameter is unused */ + + if (special) + error(ERR_NONFATAL, "binary format does not support any" + " special symbol types"); + else if (name[0] == '.' && name[1] == '.' && name[2] != '@') + error(ERR_NONFATAL, "unrecognised special symbol `%s'", name); + else if (is_global == 2) + error(ERR_NONFATAL, "binary output format does not support common" + " variables"); + else { + struct Section *s; + struct bin_label ***ltp; + + /* Remember label definition so we can look it up later when + * creating the map file. */ + s = find_section_by_index(segment); + if (s) + ltp = &(s->labels_end); + else + ltp = &nsl_tail; + (**ltp) = nasm_malloc(sizeof(struct bin_label)); + (**ltp)->name = name; + (**ltp)->next = NULL; + *ltp = &((**ltp)->next); + } + +} + +/* These constants and the following function are used + * by bin_secname() to parse attribute assignments. */ + +enum { ATTRIB_START, ATTRIB_ALIGN, ATTRIB_FOLLOWS, + ATTRIB_VSTART, ATTRIB_VALIGN, ATTRIB_VFOLLOWS, + ATTRIB_NOBITS, ATTRIB_PROGBITS +}; + +static int bin_read_attribute(char **line, int *attribute, + unsigned long *value) +{ + expr *e; + int attrib_name_size; + struct tokenval tokval; + char *exp; + + /* Skip whitespace. */ + while (**line && isspace(**line)) + (*line)++; + if (!**line) + return 0; + + /* Figure out what attribute we're reading. */ + if (!nasm_strnicmp(*line, "align=", 6)) { + *attribute = ATTRIB_ALIGN; + attrib_name_size = 6; + } else if (format_mode) { + if (!nasm_strnicmp(*line, "start=", 6)) { + *attribute = ATTRIB_START; + attrib_name_size = 6; + } else if (!nasm_strnicmp(*line, "follows=", 8)) { + *attribute = ATTRIB_FOLLOWS; + *line += 8; + return 1; + } else if (!nasm_strnicmp(*line, "vstart=", 7)) { + *attribute = ATTRIB_VSTART; + attrib_name_size = 7; + } else if (!nasm_strnicmp(*line, "valign=", 7)) { + *attribute = ATTRIB_VALIGN; + attrib_name_size = 7; + } else if (!nasm_strnicmp(*line, "vfollows=", 9)) { + *attribute = ATTRIB_VFOLLOWS; + *line += 9; + return 1; + } else if (!nasm_strnicmp(*line, "nobits", 6) && + (isspace((*line)[6]) || ((*line)[6] == '\0'))) { + *attribute = ATTRIB_NOBITS; + *line += 6; + return 1; + } else if (!nasm_strnicmp(*line, "progbits", 8) && + (isspace((*line)[8]) || ((*line)[8] == '\0'))) { + *attribute = ATTRIB_PROGBITS; + *line += 8; + return 1; + } else + return 0; + } else + return 0; + + /* Find the end of the expression. */ + if ((*line)[attrib_name_size] != '(') { + /* Single term (no parenthesis). */ + exp = *line += attrib_name_size; + while (**line && !isspace(**line)) + (*line)++; + if (**line) { + **line = '\0'; + (*line)++; + } + } else { + char c; + int pcount = 1; + + /* Full expression (delimited by parenthesis) */ + exp = *line += attrib_name_size + 1; + while (1) { + (*line) += strcspn(*line, "()'\""); + if (**line == '(') { + ++(*line); + ++pcount; + } + if (**line == ')') { + ++(*line); + --pcount; + if (!pcount) + break; + } + if ((**line == '"') || (**line == '\'')) { + c = **line; + while (**line) { + ++(*line); + if (**line == c) + break; + } + if (!**line) { + error(ERR_NONFATAL, + "invalid syntax in `section' directive"); + return -1; + } + ++(*line); + } + if (!**line) { + error(ERR_NONFATAL, "expecting `)'"); + return -1; + } + } + *(*line - 1) = '\0'; /* Terminate the expression. */ + } + + /* Check for no value given. */ + if (!*exp) { + error(ERR_WARNING, "No value given to attribute in" + " `section' directive"); + return -1; + } + + /* Read and evaluate the expression. */ + stdscan_reset(); + stdscan_bufptr = exp; + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); + if (e) { + if (!is_really_simple(e)) { + error(ERR_NONFATAL, "section attribute value must be" + " a critical expression"); + return -1; + } + } else { + error(ERR_NONFATAL, "Invalid attribute value" + " specified in `section' directive."); + return -1; + } + *value = (unsigned long)reloc_value(e); + return 1; +} + +static void bin_assign_attributes(struct Section *sec, char *astring) +{ + int attribute, check; + unsigned long value; + char *p; + + while (1) { /* Get the next attribute. */ + check = bin_read_attribute(&astring, &attribute, &value); + /* Skip bad attribute. */ + if (check == -1) + continue; + /* Unknown section attribute, so skip it and warn the user. */ + if (!check) { + if (!*astring) + break; /* End of line. */ + else { + p = astring; + while (*astring && !isspace(*astring)) + astring++; + if (*astring) { + *astring = '\0'; + astring++; + } + error(ERR_WARNING, "ignoring unknown section attribute:" + " \"%s\"", p); + } + continue; + } + + switch (attribute) { /* Handle nobits attribute. */ + case ATTRIB_NOBITS: + if ((sec->flags & TYPE_DEFINED) + && (sec->flags & TYPE_PROGBITS)) + error(ERR_NONFATAL, + "attempt to change section type" + " from progbits to nobits"); + else + sec->flags |= TYPE_DEFINED | TYPE_NOBITS; + continue; + + /* Handle progbits attribute. */ + case ATTRIB_PROGBITS: + if ((sec->flags & TYPE_DEFINED) && (sec->flags & TYPE_NOBITS)) + error(ERR_NONFATAL, "attempt to change section type" + " from nobits to progbits"); + else + sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; + continue; + + /* Handle align attribute. */ + case ATTRIB_ALIGN: + if (!format_mode && (!strcmp(sec->name, ".text"))) + error(ERR_NONFATAL, "cannot specify an alignment" + " to the .text section"); + else { + if (!value || ((value - 1) & value)) + error(ERR_NONFATAL, "argument to `align' is not a" + " power of two"); + else { /* Alignment is already satisfied if the previous + * align value is greater. */ + if ((sec->flags & ALIGN_DEFINED) + && (value < sec->align)) + value = sec->align; + + /* Don't allow a conflicting align value. */ + if ((sec->flags & START_DEFINED) + && (sec->start & (value - 1))) + error(ERR_NONFATAL, + "`align' value conflicts " + "with section start address"); + else { + sec->align = value; + sec->flags |= ALIGN_DEFINED; + } + } + } + continue; + + /* Handle valign attribute. */ + case ATTRIB_VALIGN: + if (!value || ((value - 1) & value)) + error(ERR_NONFATAL, "argument to `valign' is not a" + " power of two"); + else { /* Alignment is already satisfied if the previous + * align value is greater. */ + if ((sec->flags & VALIGN_DEFINED) && (value < sec->valign)) + value = sec->valign; + + /* Don't allow a conflicting valign value. */ + if ((sec->flags & VSTART_DEFINED) + && (sec->vstart & (value - 1))) + error(ERR_NONFATAL, + "`valign' value conflicts " + "with `vstart' address"); + else { + sec->valign = value; + sec->flags |= VALIGN_DEFINED; + } + } + continue; + + /* Handle start attribute. */ + case ATTRIB_START: + if (sec->flags & FOLLOWS_DEFINED) + error(ERR_NONFATAL, "cannot combine `start' and `follows'" + " section attributes"); + else if (value < 0) + error(ERR_NONFATAL, "attempt to specify a negative" + " section start address"); + else if ((sec->flags & START_DEFINED) && (value != sec->start)) + error(ERR_NONFATAL, "section start address redefined"); + else { + sec->start = value; + sec->flags |= START_DEFINED; + if (sec->flags & ALIGN_DEFINED) { + if (sec->start & (sec->align - 1)) + error(ERR_NONFATAL, "`start' address conflicts" + " with section alignment"); + sec->flags ^= ALIGN_DEFINED; + } + } + continue; + + /* Handle vstart attribute. */ + case ATTRIB_VSTART: + if (sec->flags & VFOLLOWS_DEFINED) + error(ERR_NONFATAL, + "cannot combine `vstart' and `vfollows'" + " section attributes"); + else if ((sec->flags & VSTART_DEFINED) + && (value != sec->vstart)) + error(ERR_NONFATAL, + "section virtual start address" + " (vstart) redefined"); + else { + sec->vstart = value; + sec->flags |= VSTART_DEFINED; + if (sec->flags & VALIGN_DEFINED) { + if (sec->vstart & (sec->valign - 1)) + error(ERR_NONFATAL, "`vstart' address conflicts" + " with `valign' value"); + sec->flags ^= VALIGN_DEFINED; + } + } + continue; + + /* Handle follows attribute. */ + case ATTRIB_FOLLOWS: + p = astring; + astring += strcspn(astring, " \t"); + if (astring == p) + error(ERR_NONFATAL, "expecting section name for `follows'" + " attribute"); + else { + *(astring++) = '\0'; + if (sec->flags & START_DEFINED) + error(ERR_NONFATAL, + "cannot combine `start' and `follows'" + " section attributes"); + sec->follows = nasm_strdup(p); + sec->flags |= FOLLOWS_DEFINED; + } + continue; + + /* Handle vfollows attribute. */ + case ATTRIB_VFOLLOWS: + if (sec->flags & VSTART_DEFINED) + error(ERR_NONFATAL, + "cannot combine `vstart' and `vfollows'" + " section attributes"); + else { + p = astring; + astring += strcspn(astring, " \t"); + if (astring == p) + error(ERR_NONFATAL, + "expecting section name for `vfollows'" + " attribute"); + else { + *(astring++) = '\0'; + sec->vfollows = nasm_strdup(p); + sec->flags |= VFOLLOWS_DEFINED; + } + } + continue; + } + } +} + +static void bin_define_section_labels() +{ + static int labels_defined = 0; + struct Section *sec; + char *label_name; + size_t base_len; + + if (labels_defined) + return; + for (sec = sections; sec; sec = sec->next) { + base_len = strlen(sec->name) + 8; + label_name = nasm_malloc(base_len + 8); + strcpy(label_name, "section."); + strcpy(label_name + 8, sec->name); + + /* section..start */ + strcpy(label_name + base_len, ".start"); + define_label(label_name, sec->start_index, 0L, + NULL, 0, 0, bin_get_ofmt(), error); + + /* section..vstart */ + strcpy(label_name + base_len, ".vstart"); + define_label(label_name, sec->vstart_index, 0L, + NULL, 0, 0, bin_get_ofmt(), error); + + nasm_free(label_name); + } + labels_defined = 1; +} + +static long bin_secname(char *name, int pass, int *bits) +{ + char *p; + struct Section *sec; + + /* bin_secname is called with *name = NULL at the start of each + * pass. Use this opportunity to establish the default section + * (default is BITS-16 ".text" segment). + */ + if (!name) { /* Reset ORG and section attributes at the start of each pass. */ + origin_defined = 0; + for (sec = sections; sec; sec = sec->next) + sec->flags &= ~(START_DEFINED | VSTART_DEFINED | + ALIGN_DEFINED | VALIGN_DEFINED); + + /* Define section start and vstart labels. */ + if (format_mode && (pass != 1)) + bin_define_section_labels(); + + /* Establish the default (.text) section. */ + *bits = 16; + sec = find_section_by_name(".text"); + sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; + current_section = sec->vstart_index; + return current_section; + } + + /* Attempt to find the requested section. If it does not + * exist, create it. */ + p = name; + while (*p && !isspace(*p)) + p++; + if (*p) + *p++ = '\0'; + sec = find_section_by_name(name); + if (!sec) { + sec = create_section(name); + if (!strcmp(name, ".data")) + sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; + else if (!strcmp(name, ".bss")) { + sec->flags |= TYPE_DEFINED | TYPE_NOBITS; + sec->ifollows = NULL; + } else if (!format_mode) { + error(ERR_NONFATAL, "section name must be " + ".text, .data, or .bss"); + return current_section; + } + } + + /* Handle attribute assignments. */ + if (pass != 1) + bin_assign_attributes(sec, p); + +#ifndef ABIN_SMART_ADAPT + /* The following line disables smart adaptation of + * PROGBITS/NOBITS section types (it forces sections to + * default to PROGBITS). */ + if ((pass != 1) && !(sec->flags & TYPE_DEFINED)) + sec->flags |= TYPE_DEFINED | TYPE_PROGBITS; +#endif + + /* Set the current section and return. */ + current_section = sec->vstart_index; + return current_section; +} + +static int bin_directive(char *directive, char *args, int pass) +{ + /* Handle ORG directive */ + if (!nasm_stricmp(directive, "org")) { + struct tokenval tokval; + unsigned long value; + expr *e; + + stdscan_reset(); + stdscan_bufptr = args; + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); + if (e) { + if (!is_really_simple(e)) + error(ERR_NONFATAL, "org value must be a critical" + " expression"); + else { + value = reloc_value(e); + /* Check for ORG redefinition. */ + if (origin_defined && (value != origin)) + error(ERR_NONFATAL, "program origin redefined"); + else { + origin = value; + origin_defined = 1; + } + } + } else + error(ERR_NONFATAL, "No or invalid offset specified" + " in ORG directive."); + return 1; + } + + /* The 'map' directive allows the user to generate section + * and symbol information to stdout, stderr, or to a file. */ + else if (format_mode && !nasm_stricmp(directive, "map")) { + char *p; + + if (pass != 1) + return 1; + args += strspn(args, " \t"); + while (*args) { + p = args; + args += strcspn(args, " \t"); + if (*args != '\0') + *(args++) = '\0'; + if (!nasm_stricmp(p, "all")) + map_control |= + MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS | MAP_SYMBOLS; + else if (!nasm_stricmp(p, "brief")) + map_control |= MAP_ORIGIN | MAP_SUMMARY; + else if (!nasm_stricmp(p, "sections")) + map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS; + else if (!nasm_stricmp(p, "segments")) + map_control |= MAP_ORIGIN | MAP_SUMMARY | MAP_SECTIONS; + else if (!nasm_stricmp(p, "symbols")) + map_control |= MAP_SYMBOLS; + else if (!rf) { + if (!nasm_stricmp(p, "stdout")) + rf = stdout; + else if (!nasm_stricmp(p, "stderr")) + rf = stderr; + else { /* Must be a filename. */ + rf = fopen(p, "wt"); + if (!rf) { + error(ERR_WARNING, "unable to open map file `%s'", + p); + map_control = 0; + return 1; + } + } + } else + error(ERR_WARNING, "map file already specified"); + } + if (map_control == 0) + map_control |= MAP_ORIGIN | MAP_SUMMARY; + if (!rf) + rf = stdout; + return 1; + } + return 0; +} + +static void bin_filename(char *inname, char *outname, efunc error) +{ + standard_extension(inname, outname, "", error); + infile = inname; + outfile = outname; +} + +static long bin_segbase(long segment) +{ + return segment; +} + +static int bin_set_info(enum geninfo type, char **val) +{ + return 0; +} + +static void bin_init(FILE * afp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + fp = afp; + error = errfunc; + + (void)eval; /* Don't warn that this parameter is unused. */ + (void)ldef; /* Placate optimizers. */ + + relocs = NULL; + reloctail = &relocs; + origin_defined = 0; + no_seg_labels = NULL; + nsl_tail = &no_seg_labels; + format_mode = 1; /* Extended bin format + * (set this to zero for old bin format). */ + + /* Create default section (.text). */ + sections = last_section = nasm_malloc(sizeof(struct Section)); + last_section->next = NULL; + last_section->name = nasm_strdup(".text"); + last_section->contents = saa_init(1L); + last_section->follows = last_section->vfollows = 0; + last_section->ifollows = NULL; + last_section->length = 0; + last_section->flags = TYPE_DEFINED | TYPE_PROGBITS; + last_section->labels = NULL; + last_section->labels_end = &(last_section->labels); + last_section->start_index = seg_alloc(); + last_section->vstart_index = current_section = seg_alloc(); +} + +struct ofmt of_bin = { + "flat-form binary files (e.g. DOS .COM, .SYS)", + "bin", + NULL, + null_debug_arr, + &null_debug_form, + bin_stdmac, + bin_init, + bin_set_info, + bin_out, + bin_deflabel, + bin_secname, + bin_segbase, + bin_directive, + bin_filename, + bin_cleanup +}; + +/* This is needed for bin_define_section_labels() */ +struct ofmt *bin_get_ofmt() +{ + return &of_bin; +} + +#endif /* #ifdef OF_BIN */ diff --git a/output/outcoff.c b/output/outcoff.c index 856da58e..547f4db7 100644 --- a/output/outcoff.c +++ b/output/outcoff.c @@ -64,23 +64,23 @@ static int win32; struct Reloc { struct Reloc *next; - long address; /* relative to _start_ of section */ - long symbol; /* symbol number */ + long address; /* relative to _start_ of section */ + long symbol; /* symbol number */ enum { - SECT_SYMBOLS, - ABS_SYMBOL, - REAL_SYMBOLS - } symbase; /* relocation for symbol number :) */ - int relative; /* TRUE or FALSE */ + SECT_SYMBOLS, + ABS_SYMBOL, + REAL_SYMBOLS + } symbase; /* relocation for symbol number :) */ + int relative; /* TRUE or FALSE */ }; struct Symbol { char name[9]; - long strpos; /* string table position of name */ - int section; /* section number where it's defined - * - in COFF codes, not NASM codes */ - int is_global; /* is it a global symbol or not? */ - long value; /* address, or COMMON variable size */ + long strpos; /* string table position of name */ + int section; /* section number where it's defined + * - in COFF codes, not NASM codes */ + int is_global; /* is it a global symbol or not? */ + long value; /* address, or COMMON variable size */ }; static FILE *coffp; @@ -93,7 +93,7 @@ struct Section { int nrelocs; long index; struct Reloc *head, **tail; - unsigned long flags; /* section flags */ + unsigned long flags; /* section flags */ char name[9]; long pos, relpos; }; @@ -121,29 +121,30 @@ static struct SAA *strs; static unsigned long strslen; static void coff_gen_init(FILE *, efunc); -static void coff_sect_write (struct Section *, const unsigned char *, - unsigned long); -static void coff_write (void); -static void coff_section_header (char *, long, long, long, long, int, long); -static void coff_write_relocs (struct Section *); -static void coff_write_symbols (void); - -static void coff_win32_init(FILE *fp, efunc errfunc, - ldfunc ldef, evalfunc eval) +static void coff_sect_write(struct Section *, const unsigned char *, + unsigned long); +static void coff_write(void); +static void coff_section_header(char *, long, long, long, long, int, long); +static void coff_write_relocs(struct Section *); +static void coff_write_symbols(void); + +static void coff_win32_init(FILE * fp, efunc errfunc, + ldfunc ldef, evalfunc eval) { win32 = TRUE; - (void) ldef; /* placate optimisers */ + (void)ldef; /* placate optimisers */ coff_gen_init(fp, errfunc); } -static void coff_std_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +static void coff_std_init(FILE * fp, efunc errfunc, ldfunc ldef, + evalfunc eval) { win32 = FALSE; - (void) ldef; /* placate optimisers */ + (void)ldef; /* placate optimisers */ coff_gen_init(fp, errfunc); } -static void coff_gen_init(FILE *fp, efunc errfunc) +static void coff_gen_init(FILE * fp, efunc errfunc) { coffp = fp; @@ -159,62 +160,63 @@ static void coff_gen_init(FILE *fp, efunc errfunc) def_seg = seg_alloc(); } -static void coff_cleanup(int debuginfo) +static void coff_cleanup(int debuginfo) { struct Reloc *r; int i; - (void) debuginfo; + (void)debuginfo; coff_write(); - fclose (coffp); - for (i=0; idata) - saa_free (sects[i]->data); - while (sects[i]->head) { - r = sects[i]->head; - sects[i]->head = sects[i]->head->next; - nasm_free (r); - } - nasm_free (sects[i]); + fclose(coffp); + for (i = 0; i < nsects; i++) { + if (sects[i]->data) + saa_free(sects[i]->data); + while (sects[i]->head) { + r = sects[i]->head; + sects[i]->head = sects[i]->head->next; + nasm_free(r); + } + nasm_free(sects[i]); } - nasm_free (sects); - saa_free (syms); - raa_free (bsym); - raa_free (symval); - saa_free (strs); + nasm_free(sects); + saa_free(syms); + raa_free(bsym); + raa_free(symval); + saa_free(strs); } -static int coff_make_section (char *name, unsigned long flags) +static int coff_make_section(char *name, unsigned long flags) { struct Section *s; - s = nasm_malloc (sizeof(*s)); + s = nasm_malloc(sizeof(*s)); if (flags != BSS_FLAGS) - s->data = saa_init (1L); + s->data = saa_init(1L); else - s->data = NULL; + s->data = NULL; s->head = NULL; s->tail = &s->head; s->len = 0; s->nrelocs = 0; if (!strcmp(name, ".text")) - s->index = def_seg; + s->index = def_seg; else - s->index = seg_alloc(); - strncpy (s->name, name, 8); + s->index = seg_alloc(); + strncpy(s->name, name, 8); s->name[8] = '\0'; s->flags = flags; if (nsects >= sectlen) - sects = nasm_realloc (sects, (sectlen += SECT_DELTA)*sizeof(*sects)); + sects = + nasm_realloc(sects, (sectlen += SECT_DELTA) * sizeof(*sects)); sects[nsects++] = s; - return nsects-1; + return nsects - 1; } -static long coff_section_names (char *name, int pass, int *bits) +static long coff_section_names(char *name, int pass, int *bits) { char *p; unsigned long flags, align_and = ~0L, align_or = 0L; @@ -224,167 +226,175 @@ static long coff_section_names (char *name, int pass, int *bits) * Default is 32 bits. */ if (!name) - *bits = 32; + *bits = 32; if (!name) - return def_seg; + return def_seg; p = name; - while (*p && !isspace(*p)) p++; - if (*p) *p++ = '\0'; + while (*p && !isspace(*p)) + p++; + if (*p) + *p++ = '\0'; if (strlen(name) > 8) { - error (ERR_WARNING, "COFF section names limited to 8 characters:" - " truncating"); - name[8] = '\0'; + error(ERR_WARNING, "COFF section names limited to 8 characters:" + " truncating"); + name[8] = '\0'; } flags = 0; - while (*p && isspace(*p)) p++; + while (*p && isspace(*p)) + p++; while (*p) { - char *q = p; - while (*p && !isspace(*p)) p++; - if (*p) *p++ = '\0'; - while (*p && isspace(*p)) p++; - - if (!nasm_stricmp(q, "code") || !nasm_stricmp(q, "text")) { - flags = TEXT_FLAGS; - } else if (!nasm_stricmp(q, "data")) { - flags = DATA_FLAGS; - } else if (!nasm_stricmp(q, "rdata")) { - if (win32) - flags = RDATA_FLAGS; - else { - flags = DATA_FLAGS; /* gotta do something */ - error (ERR_NONFATAL, "standard COFF does not support" - " read-only data sections"); - } - } else if (!nasm_stricmp(q, "bss")) { - flags = BSS_FLAGS; - } else if (!nasm_stricmp(q, "info")) { - if (win32) - flags = INFO_FLAGS; - else { - flags = DATA_FLAGS; /* gotta do something */ - error (ERR_NONFATAL, "standard COFF does not support" - " informational sections"); - } - } else if (!nasm_strnicmp(q,"align=",6)) { - if (!win32) - error (ERR_NONFATAL, "standard COFF does not support" - " section alignment specification"); - else { - if (q[6+strspn(q+6,"0123456789")]) - error(ERR_NONFATAL, "argument to `align' is not numeric"); - else { - unsigned int align = atoi(q+6); - if (!align || ((align-1) & align)) - error(ERR_NONFATAL, "argument to `align' is not a" - " power of two"); - else if (align > 64) - error(ERR_NONFATAL, "Win32 cannot align sections" - " to better than 64-byte boundaries"); - else { - align_and = ~0x00F00000L; - align_or = (align == 1 ? 0x00100000L : - align == 2 ? 0x00200000L : - align == 4 ? 0x00300000L : - align == 8 ? 0x00400000L : - align == 16 ? 0x00500000L : - align == 32 ? 0x00600000L : 0x00700000L); - } - } - } - } + char *q = p; + while (*p && !isspace(*p)) + p++; + if (*p) + *p++ = '\0'; + while (*p && isspace(*p)) + p++; + + if (!nasm_stricmp(q, "code") || !nasm_stricmp(q, "text")) { + flags = TEXT_FLAGS; + } else if (!nasm_stricmp(q, "data")) { + flags = DATA_FLAGS; + } else if (!nasm_stricmp(q, "rdata")) { + if (win32) + flags = RDATA_FLAGS; + else { + flags = DATA_FLAGS; /* gotta do something */ + error(ERR_NONFATAL, "standard COFF does not support" + " read-only data sections"); + } + } else if (!nasm_stricmp(q, "bss")) { + flags = BSS_FLAGS; + } else if (!nasm_stricmp(q, "info")) { + if (win32) + flags = INFO_FLAGS; + else { + flags = DATA_FLAGS; /* gotta do something */ + error(ERR_NONFATAL, "standard COFF does not support" + " informational sections"); + } + } else if (!nasm_strnicmp(q, "align=", 6)) { + if (!win32) + error(ERR_NONFATAL, "standard COFF does not support" + " section alignment specification"); + else { + if (q[6 + strspn(q + 6, "0123456789")]) + error(ERR_NONFATAL, + "argument to `align' is not numeric"); + else { + unsigned int align = atoi(q + 6); + if (!align || ((align - 1) & align)) + error(ERR_NONFATAL, "argument to `align' is not a" + " power of two"); + else if (align > 64) + error(ERR_NONFATAL, "Win32 cannot align sections" + " to better than 64-byte boundaries"); + else { + align_and = ~0x00F00000L; + align_or = (align == 1 ? 0x00100000L : + align == 2 ? 0x00200000L : + align == 4 ? 0x00300000L : + align == 8 ? 0x00400000L : + align == 16 ? 0x00500000L : + align == + 32 ? 0x00600000L : 0x00700000L); + } + } + } + } } - for (i=0; iname)) - break; + for (i = 0; i < nsects; i++) + if (!strcmp(name, sects[i]->name)) + break; if (i == nsects) { - if (!flags) { - if (!strcmp(name, ".data")) - flags = DATA_FLAGS; - else if (!strcmp(name, ".rdata")) - flags = RDATA_FLAGS; - else if (!strcmp(name, ".bss")) - flags = BSS_FLAGS; - else - flags = TEXT_FLAGS; - } - i = coff_make_section (name, flags); - if (flags) - sects[i]->flags = flags; - sects[i]->flags &= align_and; - sects[i]->flags |= align_or; + if (!flags) { + if (!strcmp(name, ".data")) + flags = DATA_FLAGS; + else if (!strcmp(name, ".rdata")) + flags = RDATA_FLAGS; + else if (!strcmp(name, ".bss")) + flags = BSS_FLAGS; + else + flags = TEXT_FLAGS; + } + i = coff_make_section(name, flags); + if (flags) + sects[i]->flags = flags; + sects[i]->flags &= align_and; + sects[i]->flags |= align_or; } else if (pass == 1) { - if (flags) - error (ERR_WARNING, "section attributes ignored on" - " redeclaration of section `%s'", name); + if (flags) + error(ERR_WARNING, "section attributes ignored on" + " redeclaration of section `%s'", name); } return sects[i]->index; } -static void coff_deflabel (char *name, long segment, long offset, - int is_global, char *special) +static void coff_deflabel(char *name, long segment, long offset, + int is_global, char *special) { - int pos = strslen+4; + int pos = strslen + 4; struct Symbol *sym; if (special) - error (ERR_NONFATAL, "binary format does not support any" - " special symbol types"); + error(ERR_NONFATAL, "binary format does not support any" + " special symbol types"); if (name[0] == '.' && name[1] == '.' && name[2] != '@') { - error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); - return; + error(ERR_NONFATAL, "unrecognised special symbol `%s'", name); + return; } if (strlen(name) > 8) { - saa_wbytes (strs, name, (long)(1+strlen(name))); - strslen += 1+strlen(name); + saa_wbytes(strs, name, (long)(1 + strlen(name))); + strslen += 1 + strlen(name); } else - pos = -1; + pos = -1; - sym = saa_wstruct (syms); + sym = saa_wstruct(syms); sym->strpos = pos; if (pos == -1) - strcpy (sym->name, name); + strcpy(sym->name, name); sym->is_global = !!is_global; if (segment == NO_SEG) - sym->section = -1; /* absolute symbol */ + sym->section = -1; /* absolute symbol */ else { - int i; - sym->section = 0; - for (i=0; iindex) { - sym->section = i+1; - break; - } - if (!sym->section) - sym->is_global = TRUE; + int i; + sym->section = 0; + for (i = 0; i < nsects; i++) + if (segment == sects[i]->index) { + sym->section = i + 1; + break; + } + if (!sym->section) + sym->is_global = TRUE; } if (is_global == 2) - sym->value = offset; + sym->value = offset; else - sym->value = (sym->section == 0 ? 0 : offset); + sym->value = (sym->section == 0 ? 0 : offset); /* * define the references from external-symbol segment numbers * to these symbol records. */ if (sym->section == 0) - bsym = raa_write (bsym, segment, nsyms); + bsym = raa_write(bsym, segment, nsyms); if (segment != NO_SEG) - symval = raa_write (symval, segment, sym->section ? 0 : sym->value); + symval = raa_write(symval, segment, sym->section ? 0 : sym->value); nsyms++; } -static long coff_add_reloc (struct Section *sect, long segment, - int relative) +static long coff_add_reloc(struct Section *sect, long segment, + int relative) { struct Reloc *r; @@ -394,18 +404,18 @@ static long coff_add_reloc (struct Section *sect, long segment, r->address = sect->len; if (segment == NO_SEG) - r->symbol = 0, r->symbase = ABS_SYMBOL; + r->symbol = 0, r->symbase = ABS_SYMBOL; else { - int i; - r->symbase = REAL_SYMBOLS; - for (i=0; iindex) { - r->symbol = i*2; - r->symbase = SECT_SYMBOLS; - break; - } - if (r->symbase == REAL_SYMBOLS) - r->symbol = raa_read (bsym, segment); + int i; + r->symbase = REAL_SYMBOLS; + for (i = 0; i < nsects; i++) + if (segment == sects[i]->index) { + r->symbol = i * 2; + r->symbase = SECT_SYMBOLS; + break; + } + if (r->symbase == REAL_SYMBOLS) + r->symbol = raa_read(bsym, segment); } r->relative = relative; @@ -415,13 +425,13 @@ static long coff_add_reloc (struct Section *sect, long segment, * Return the fixup for standard COFF common variables. */ if (r->symbase == REAL_SYMBOLS && !win32) - return raa_read (symval, segment); + return raa_read(symval, segment); else - return 0; + return 0; } -static void coff_out (long segto, const void *data, unsigned long type, - long segment, long wrt) +static void coff_out(long segto, const void *data, unsigned long type, + long segment, long wrt) { struct Section *s; long realbytes = type & OUT_SIZMASK; @@ -429,8 +439,8 @@ static void coff_out (long segto, const void *data, unsigned long type, int i; if (wrt != NO_SEG) { - wrt = NO_SEG; /* continue to do _something_ */ - error (ERR_NONFATAL, "WRT not supported by COFF output formats"); + wrt = NO_SEG; /* continue to do _something_ */ + error(ERR_NONFATAL, "WRT not supported by COFF output formats"); } type &= OUT_TYPMASK; @@ -439,110 +449,110 @@ static void coff_out (long segto, const void *data, unsigned long type, * handle absolute-assembly (structure definitions) */ if (segto == NO_SEG) { - if (type != OUT_RESERVE) - error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" - " space"); - return; + if (type != OUT_RESERVE) + error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" + " space"); + return; } s = NULL; - for (i=0; iindex) { - s = sects[i]; - break; - } + for (i = 0; i < nsects; i++) + if (segto == sects[i]->index) { + s = sects[i]; + break; + } if (!s) { - int tempint; /* ignored */ - if (segto != coff_section_names (".text", 2, &tempint)) - error (ERR_PANIC, "strange segment conditions in COFF driver"); - else - s = sects[nsects-1]; + int tempint; /* ignored */ + if (segto != coff_section_names(".text", 2, &tempint)) + error(ERR_PANIC, "strange segment conditions in COFF driver"); + else + s = sects[nsects - 1]; } if (!s->data && type != OUT_RESERVE) { - error(ERR_WARNING, "attempt to initialise memory in" - " BSS section `%s': ignored", s->name); - if (type == OUT_REL2ADR) - realbytes = 2; - else if (type == OUT_REL4ADR) - realbytes = 4; - s->len += realbytes; - return; + error(ERR_WARNING, "attempt to initialise memory in" + " BSS section `%s': ignored", s->name); + if (type == OUT_REL2ADR) + realbytes = 2; + else if (type == OUT_REL4ADR) + realbytes = 4; + s->len += realbytes; + return; } if (type == OUT_RESERVE) { - if (s->data) { - error(ERR_WARNING, "uninitialised space declared in" - " non-BSS section `%s': zeroing", s->name); - coff_sect_write (s, NULL, realbytes); - } else - s->len += realbytes; + if (s->data) { + error(ERR_WARNING, "uninitialised space declared in" + " non-BSS section `%s': zeroing", s->name); + coff_sect_write(s, NULL, realbytes); + } else + s->len += realbytes; } else if (type == OUT_RAWDATA) { - if (segment != NO_SEG) - error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); - coff_sect_write (s, data, realbytes); + if (segment != NO_SEG) + error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); + coff_sect_write(s, data, realbytes); } else if (type == OUT_ADDRESS) { - if (realbytes != 4 && (segment != NO_SEG || wrt != NO_SEG)) - error(ERR_NONFATAL, "COFF format does not support non-32-bit" - " relocations"); - else { - long fix = 0; - if (segment != NO_SEG || wrt != NO_SEG) { - if (wrt != NO_SEG) { - error(ERR_NONFATAL, "COFF format does not support" - " WRT types"); - } else if (segment % 2) { - error(ERR_NONFATAL, "COFF format does not support" - " segment base references"); - } else - fix = coff_add_reloc (s, segment, FALSE); - } - p = mydata; - WRITELONG (p, *(long *)data + fix); - coff_sect_write (s, mydata, realbytes); - } + if (realbytes != 4 && (segment != NO_SEG || wrt != NO_SEG)) + error(ERR_NONFATAL, "COFF format does not support non-32-bit" + " relocations"); + else { + long fix = 0; + if (segment != NO_SEG || wrt != NO_SEG) { + if (wrt != NO_SEG) { + error(ERR_NONFATAL, "COFF format does not support" + " WRT types"); + } else if (segment % 2) { + error(ERR_NONFATAL, "COFF format does not support" + " segment base references"); + } else + fix = coff_add_reloc(s, segment, FALSE); + } + p = mydata; + WRITELONG(p, *(long *)data + fix); + coff_sect_write(s, mydata, realbytes); + } } else if (type == OUT_REL2ADR) { - error(ERR_NONFATAL, "COFF format does not support 16-bit" - " relocations"); + error(ERR_NONFATAL, "COFF format does not support 16-bit" + " relocations"); } else if (type == OUT_REL4ADR) { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL4ADR"); - else if (segment == NO_SEG && win32) - error(ERR_NONFATAL, "Win32 COFF does not correctly support" - " relative references to absolute addresses"); - else { - long fix = 0; - if (segment != NO_SEG && segment % 2) { - error(ERR_NONFATAL, "COFF format does not support" - " segment base references"); - } else - fix = coff_add_reloc (s, segment, TRUE); - p = mydata; - if (win32) { - WRITELONG (p, *(long*)data + 4 - realbytes + fix); - } else { - WRITELONG (p, *(long*)data-(realbytes + s->len) + fix); - } - coff_sect_write (s, mydata, 4L); - } + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL4ADR"); + else if (segment == NO_SEG && win32) + error(ERR_NONFATAL, "Win32 COFF does not correctly support" + " relative references to absolute addresses"); + else { + long fix = 0; + if (segment != NO_SEG && segment % 2) { + error(ERR_NONFATAL, "COFF format does not support" + " segment base references"); + } else + fix = coff_add_reloc(s, segment, TRUE); + p = mydata; + if (win32) { + WRITELONG(p, *(long *)data + 4 - realbytes + fix); + } else { + WRITELONG(p, *(long *)data - (realbytes + s->len) + fix); + } + coff_sect_write(s, mydata, 4L); + } } } -static void coff_sect_write (struct Section *sect, - const unsigned char *data, unsigned long len) +static void coff_sect_write(struct Section *sect, + const unsigned char *data, unsigned long len) { - saa_wbytes (sect->data, data, len); + saa_wbytes(sect->data, data, len); sect->len += len; } typedef struct tagString { - struct tagString *Next; - int len; - char *String; + struct tagString *Next; + int len; + char *String; } STRING; #define EXPORT_SECTION_NAME ".drectve" -#define EXPORT_SECTION_FLAGS INFO_FLAGS +#define EXPORT_SECTION_FLAGS INFO_FLAGS /* #define EXPORT_SECTION_NAME ".text" #define EXPORT_SECTION_FLAGS TEXT_FLAGS @@ -552,67 +562,65 @@ static STRING *Exports = NULL; static struct Section *directive_sec; void AddExport(char *name) { - STRING *rvp = Exports,*newS; - - newS = (STRING *)nasm_malloc(sizeof(STRING)); - newS->len = strlen(name); - newS->Next = NULL; - newS->String = (char*)nasm_malloc( newS->len + 1 ); - strcpy( newS->String, name ); - if (rvp == NULL) - { - int i; - for (i=0; iname)) - break; - if( i == nsects ) - directive_sec = sects[coff_make_section( EXPORT_SECTION_NAME, EXPORT_SECTION_FLAGS )]; - else - directive_sec = sects[i]; - Exports = newS; - } - else { - while (rvp->Next) { - if (!strcmp(rvp->String,name)) - return; - rvp = rvp->Next; - } - rvp->Next = newS; - } + STRING *rvp = Exports, *newS; + + newS = (STRING *) nasm_malloc(sizeof(STRING)); + newS->len = strlen(name); + newS->Next = NULL; + newS->String = (char *)nasm_malloc(newS->len + 1); + strcpy(newS->String, name); + if (rvp == NULL) { + int i; + for (i = 0; i < nsects; i++) + + if (!strcmp(EXPORT_SECTION_NAME, sects[i]->name)) + break; + if (i == nsects) + directive_sec = + sects[coff_make_section + (EXPORT_SECTION_NAME, EXPORT_SECTION_FLAGS)]; + else + directive_sec = sects[i]; + Exports = newS; + } else { + while (rvp->Next) { + if (!strcmp(rvp->String, name)) + return; + rvp = rvp->Next; + } + rvp->Next = newS; + } } void BuildExportTable(void) { - STRING *rvp = Exports, *next; - unsigned char buf[256]; - int len; - if (rvp == NULL) return; - while (rvp) { - len = sprintf( (char*)buf, "-export:%s ", rvp->String ); - coff_sect_write( directive_sec, buf, len ); - rvp = rvp->Next; - } - - next = Exports; - while( ( rvp = next ) ) - { - next = rvp->Next; - nasm_free( rvp->String ); - nasm_free( rvp ); - } - Exports = NULL; -} + STRING *rvp = Exports, *next; + unsigned char buf[256]; + int len; + if (rvp == NULL) + return; + while (rvp) { + len = sprintf((char *)buf, "-export:%s ", rvp->String); + coff_sect_write(directive_sec, buf, len); + rvp = rvp->Next; + } + next = Exports; + while ((rvp = next)) { + next = rvp->Next; + nasm_free(rvp->String); + nasm_free(rvp); + } + Exports = NULL; +} -static int coff_directives (char *directive, char *value, int pass) +static int coff_directives(char *directive, char *value, int pass) { if (!strcmp(directive, "export")) { char *q, *name; if (pass == 2) - return 1; /* ignore in pass two */ + return 1; /* ignore in pass two */ name = q = value; while (*q && !isspace(*q)) q++; @@ -626,140 +634,141 @@ static int coff_directives (char *directive, char *value, int pass) error(ERR_NONFATAL, "`export' directive requires export name"); return 1; } - if(*q) { + if (*q) { error(ERR_NONFATAL, "unrecognised export qualifier `%s'", q); return 1; } - AddExport( name ); + AddExport(name); return 1; } return 0; } -static void coff_write (void) +static void coff_write(void) { long pos, sympos, vsize; int i; - BuildExportTable(); /* fill in the .drectve section with -export's */ + BuildExportTable(); /* fill in the .drectve section with -export's */ /* * Work out how big the file will get. Calculate the start of * the `real' symbols at the same time. */ pos = 0x14 + 0x28 * nsects; - initsym = 3; /* two for the file, one absolute */ - for (i=0; idata) { - sects[i]->pos = pos; - pos += sects[i]->len; - sects[i]->relpos = pos; - pos += 10 * sects[i]->nrelocs; - } else - sects[i]->pos = sects[i]->relpos = 0L; - initsym += 2; /* two for each section */ + initsym = 3; /* two for the file, one absolute */ + for (i = 0; i < nsects; i++) { + if (sects[i]->data) { + sects[i]->pos = pos; + pos += sects[i]->len; + sects[i]->relpos = pos; + pos += 10 * sects[i]->nrelocs; + } else + sects[i]->pos = sects[i]->relpos = 0L; + initsym += 2; /* two for each section */ } sympos = pos; /* * Output the COFF header. */ - fwriteshort (0x14C, coffp); /* MACHINE_i386 */ - fwriteshort (nsects, coffp); /* number of sections */ - fwritelong (time(NULL), coffp); /* time stamp */ - fwritelong (sympos, coffp); - fwritelong (nsyms + initsym, coffp); - fwriteshort (0, coffp); /* no optional header */ + fwriteshort(0x14C, coffp); /* MACHINE_i386 */ + fwriteshort(nsects, coffp); /* number of sections */ + fwritelong(time(NULL), coffp); /* time stamp */ + fwritelong(sympos, coffp); + fwritelong(nsyms + initsym, coffp); + fwriteshort(0, coffp); /* no optional header */ /* Flags: 32-bit, no line numbers. Win32 doesn't even bother with them. */ - fwriteshort (win32 ? 0 : 0x104, coffp); + fwriteshort(win32 ? 0 : 0x104, coffp); /* * Output the section headers. */ vsize = 0L; - for (i=0; iname, vsize, sects[i]->len, - sects[i]->pos, sects[i]->relpos, - sects[i]->nrelocs, sects[i]->flags); - vsize += sects[i]->len; + for (i = 0; i < nsects; i++) { + coff_section_header(sects[i]->name, vsize, sects[i]->len, + sects[i]->pos, sects[i]->relpos, + sects[i]->nrelocs, sects[i]->flags); + vsize += sects[i]->len; } /* * Output the sections and their relocations. */ - for (i=0; idata) { - saa_fpwrite (sects[i]->data, coffp); - coff_write_relocs (sects[i]); - } + for (i = 0; i < nsects; i++) + if (sects[i]->data) { + saa_fpwrite(sects[i]->data, coffp); + coff_write_relocs(sects[i]); + } /* * Output the symbol and string tables. */ coff_write_symbols(); - fwritelong (strslen+4, coffp); /* length includes length count */ - saa_fpwrite (strs, coffp); + fwritelong(strslen + 4, coffp); /* length includes length count */ + saa_fpwrite(strs, coffp); } -static void coff_section_header (char *name, long vsize, - long datalen, long datapos, - long relpos, int nrelocs, long flags) +static void coff_section_header(char *name, long vsize, + long datalen, long datapos, + long relpos, int nrelocs, long flags) { char padname[8]; - memset (padname, 0, 8); - strncpy (padname, name, 8); - fwrite (padname, 8, 1, coffp); - fwritelong (vsize, coffp); - fwritelong (0L, coffp); /* RVA/offset - we ignore */ - fwritelong (datalen, coffp); - fwritelong (datapos, coffp); - fwritelong (relpos, coffp); - fwritelong (0L, coffp); /* no line numbers - we don't do 'em */ - fwriteshort (nrelocs, coffp); - fwriteshort (0, coffp); /* again, no line numbers */ - fwritelong (flags, coffp); + memset(padname, 0, 8); + strncpy(padname, name, 8); + fwrite(padname, 8, 1, coffp); + fwritelong(vsize, coffp); + fwritelong(0L, coffp); /* RVA/offset - we ignore */ + fwritelong(datalen, coffp); + fwritelong(datapos, coffp); + fwritelong(relpos, coffp); + fwritelong(0L, coffp); /* no line numbers - we don't do 'em */ + fwriteshort(nrelocs, coffp); + fwriteshort(0, coffp); /* again, no line numbers */ + fwritelong(flags, coffp); } -static void coff_write_relocs (struct Section *s) +static void coff_write_relocs(struct Section *s) { struct Reloc *r; for (r = s->head; r; r = r->next) { - fwritelong (r->address, coffp); - fwritelong (r->symbol + (r->symbase == REAL_SYMBOLS ? initsym : - r->symbase == ABS_SYMBOL ? initsym-1 : - r->symbase == SECT_SYMBOLS ? 2 : 0), coffp); - /* - * Strange: Microsoft's COFF documentation says 0x03 for an - * absolute relocation, but both Visual C++ and DJGPP agree - * that in fact it's 0x06. I'll use 0x06 until someone - * argues. - */ - fwriteshort (r->relative ? 0x14 : 0x06, coffp); + fwritelong(r->address, coffp); + fwritelong(r->symbol + (r->symbase == REAL_SYMBOLS ? initsym : + r->symbase == ABS_SYMBOL ? initsym - 1 : + r->symbase == SECT_SYMBOLS ? 2 : 0), + coffp); + /* + * Strange: Microsoft's COFF documentation says 0x03 for an + * absolute relocation, but both Visual C++ and DJGPP agree + * that in fact it's 0x06. I'll use 0x06 until someone + * argues. + */ + fwriteshort(r->relative ? 0x14 : 0x06, coffp); } } -static void coff_symbol (char *name, long strpos, long value, - int section, int type, int aux) +static void coff_symbol(char *name, long strpos, long value, + int section, int type, int aux) { char padname[8]; if (name) { - memset (padname, 0, 8); - strncpy (padname, name, 8); - fwrite (padname, 8, 1, coffp); + memset(padname, 0, 8); + strncpy(padname, name, 8); + fwrite(padname, 8, 1, coffp); } else { - fwritelong (0L, coffp); - fwritelong (strpos, coffp); + fwritelong(0L, coffp); + fwritelong(strpos, coffp); } - fwritelong (value, coffp); - fwriteshort (section, coffp); - fwriteshort (0, coffp); - fputc (type, coffp); - fputc (aux, coffp); + fwritelong(value, coffp); + fwriteshort(section, coffp); + fwriteshort(0, coffp); + fputc(type, coffp); + fputc(aux, coffp); } -static void coff_write_symbols (void) +static void coff_write_symbols(void) { char filename[18]; unsigned long i; @@ -767,55 +776,55 @@ static void coff_write_symbols (void) /* * 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); + 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 */ + 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); + 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); + coff_symbol(".absolut", 0L, 0L, -1, 3, 0); /* * The real symbols. */ - saa_rewind (syms); + 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); + 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 long coff_segbase (long segment) +static long coff_segbase(long segment) { return segment; } -static void coff_std_filename (char *inname, char *outname, efunc error) +static void coff_std_filename(char *inname, char *outname, efunc error) { strcpy(coff_infile, inname); - standard_extension (inname, outname, ".o", error); + standard_extension(inname, outname, ".o", error); } -static void coff_win32_filename (char *inname, char *outname, efunc error) +static void coff_win32_filename(char *inname, char *outname, efunc error) { strcpy(coff_infile, inname); - standard_extension (inname, outname, ".obj", error); + standard_extension(inname, outname, ".obj", error); } static const char *coff_stdmac[] = { @@ -832,7 +841,7 @@ static int coff_set_info(enum geninfo type, char **val) { return 0; } -#endif /* defined(OF_COFF) || defined(OF_WIN32) */ +#endif /* defined(OF_COFF) || defined(OF_WIN32) */ #ifdef OF_COFF diff --git a/output/outdbg.c b/output/outdbg.c dissimilarity index 63% index 723e372d..5000407b 100644 --- a/output/outdbg.c +++ b/output/outdbg.c @@ -1,249 +1,252 @@ -/* outdbg.c output routines for the Netwide Assembler to produce - * a debugging trace - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "outform.h" - -#ifdef OF_DBG - -struct Section { - struct Section *next; - long number; - char *name; -} *dbgsect; - -FILE *dbgf; -efunc dbgef; - -struct ofmt of_dbg; -static void dbg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) -{ - (void) eval; - - dbgf = fp; - dbgef = errfunc; - dbgsect = NULL; - (void) ldef; - fprintf(fp,"NASM Output format debug dump\n"); - of_dbg.current_dfmt->init(&of_dbg,0,fp,errfunc); - -} - -static void dbg_cleanup(int debuginfo) -{ - (void) debuginfo; - of_dbg.current_dfmt->cleanup(); - while (dbgsect) { - struct Section *tmp = dbgsect; - dbgsect = dbgsect->next; - nasm_free (tmp->name); - nasm_free (tmp); - } - fclose(dbgf); -} - -static long dbg_section_names (char *name, int pass, int *bits) -{ - int seg; - - /* - * We must have an initial default: let's make it 16. - */ - if (!name) - *bits = 16; - - if (!name) - fprintf(dbgf, "section_name on init: returning %d\n", - seg = seg_alloc()); - else { - int n = strcspn(name, " \t"); - char *sname = nasm_strndup(name, n); - struct Section *s; - - seg = NO_SEG; - for (s = dbgsect; s; s = s->next) - if (!strcmp(s->name, sname)) - seg = s->number; - - if (seg == NO_SEG) { - s = nasm_malloc(sizeof(*s)); - s->name = sname; - s->number = seg = seg_alloc(); - s->next = dbgsect; - dbgsect = s; - fprintf(dbgf, "section_name %s (pass %d): returning %d\n", - name, pass, seg); - } - } - return seg; -} - -static void dbg_deflabel (char *name, long segment, long offset, - int is_global, char *special) -{ - fprintf(dbgf,"deflabel %s := %08lx:%08lx %s (%d)%s%s\n", - name, segment, offset, - is_global == 2 ? "common" : is_global ? "global" : "local", - is_global, - special ? ": " : "", special); -} - -static void dbg_out (long segto, void *data, unsigned long type, - long segment, long wrt) -{ - long realbytes = type & OUT_SIZMASK; - long ldata; - int id; - - type &= OUT_TYPMASK; - - fprintf(dbgf,"out to %lx, len = %ld: ",segto,realbytes); - - switch(type) { - case OUT_RESERVE: - fprintf(dbgf,"reserved.\n"); break; - case OUT_RAWDATA: - fprintf(dbgf,"raw data = "); - while (realbytes--) { - id = *(unsigned char *)data; - data = (char *)data + 1; - fprintf(dbgf,"%02x ",id); - } - fprintf(dbgf,"\n"); break; - case OUT_ADDRESS: - ldata = 0; /* placate gcc */ - if (realbytes == 1) - ldata = *((char *)data); - else if (realbytes == 2) - ldata = *((short *)data); - else if (realbytes == 4) - ldata = *((long *)data); - fprintf(dbgf,"addr %08lx (seg %08lx, wrt %08lx)\n",ldata, - segment,wrt);break; - case OUT_REL2ADR: - fprintf(dbgf,"rel2adr %04x (seg %08lx)\n",(int)*(short *)data,segment); - break; - case OUT_REL4ADR: - fprintf(dbgf,"rel4adr %08lx (seg %08lx)\n",*(long *)data,segment); - break; - default: - fprintf(dbgf,"unknown\n"); - break; - } -} - -static long dbg_segbase(long segment) -{ - return segment; -} - -static int dbg_directive (char *directive, char *value, int pass) -{ - fprintf(dbgf, "directive [%s] value [%s] (pass %d)\n", - directive, value, pass); - return 1; -} - -static void dbg_filename (char *inname, char *outname, efunc error) -{ - standard_extension (inname, outname, ".dbg", error); -} - -static int dbg_set_info(enum geninfo type, char **val) -{ - (void) type; - (void) val; - return 0; -} -char *types[] = { - "unknown", "label", "byte","word","dword","float","qword","tbyte" -}; -void dbgdbg_init(struct ofmt * of, void * id, FILE * fp, efunc error) -{ - (void) of; - (void) id; - (void) fp; - (void) error; - fprintf(fp," With debug info\n"); -} -static void dbgdbg_cleanup(void) -{ -} - -static void dbgdbg_linnum (const char *lnfname, long lineno, long segto) -{ - fprintf(dbgf,"dbglinenum %s(%ld) := %08lx\n", - lnfname,lineno,segto); -} -static void dbgdbg_deflabel (char *name, long segment, - long offset, int is_global, char *special) -{ - fprintf(dbgf,"dbglabel %s := %08lx:%08lx %s (%d)%s%s\n", - name, - segment, offset, - is_global == 2 ? "common" : is_global ? "global" : "local", - is_global, - special ? ": " : "", special); -} -static void dbgdbg_define(const char *type, const char *params) -{ - fprintf(dbgf,"dbgdirective [%s] value [%s]\n",type, params); -} -static void dbgdbg_output (int output_type, void *param) -{ - (void) output_type; - (void) param; -} -static void dbgdbg_typevalue(long type) -{ - fprintf(dbgf,"new type: %s(%lX)\n", - types[TYM_TYPE(type) >> 3], TYM_ELEMENTS(type) ); -} -static struct dfmt debug_debug_form = { - "Trace of all info passed to debug stage", - "debug", - dbgdbg_init, - dbgdbg_linnum, - dbgdbg_deflabel, - dbgdbg_define, - dbgdbg_typevalue, - dbgdbg_output, - dbgdbg_cleanup, -}; - -static struct dfmt *debug_debug_arr[3] = { - &debug_debug_form, - &null_debug_form, - NULL -}; -struct ofmt of_dbg = { - "Trace of all info passed to output stage", - "dbg", - NULL, - debug_debug_arr, - &null_debug_form, - NULL, - dbg_init, - dbg_set_info, - dbg_out, - dbg_deflabel, - dbg_section_names, - dbg_segbase, - dbg_directive, - dbg_filename, - dbg_cleanup -}; - -#endif /* OF_DBG */ +/* outdbg.c output routines for the Netwide Assembler to produce + * a debugging trace + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "outform.h" + +#ifdef OF_DBG + +struct Section { + struct Section *next; + long number; + char *name; +} *dbgsect; + +FILE *dbgf; +efunc dbgef; + +struct ofmt of_dbg; +static void dbg_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + (void)eval; + + dbgf = fp; + dbgef = errfunc; + dbgsect = NULL; + (void)ldef; + fprintf(fp, "NASM Output format debug dump\n"); + of_dbg.current_dfmt->init(&of_dbg, 0, fp, errfunc); + +} + +static void dbg_cleanup(int debuginfo) +{ + (void)debuginfo; + of_dbg.current_dfmt->cleanup(); + while (dbgsect) { + struct Section *tmp = dbgsect; + dbgsect = dbgsect->next; + nasm_free(tmp->name); + nasm_free(tmp); + } + fclose(dbgf); +} + +static long dbg_section_names(char *name, int pass, int *bits) +{ + int seg; + + /* + * We must have an initial default: let's make it 16. + */ + if (!name) + *bits = 16; + + if (!name) + fprintf(dbgf, "section_name on init: returning %d\n", + seg = seg_alloc()); + else { + int n = strcspn(name, " \t"); + char *sname = nasm_strndup(name, n); + struct Section *s; + + seg = NO_SEG; + for (s = dbgsect; s; s = s->next) + if (!strcmp(s->name, sname)) + seg = s->number; + + if (seg == NO_SEG) { + s = nasm_malloc(sizeof(*s)); + s->name = sname; + s->number = seg = seg_alloc(); + s->next = dbgsect; + dbgsect = s; + fprintf(dbgf, "section_name %s (pass %d): returning %d\n", + name, pass, seg); + } + } + return seg; +} + +static void dbg_deflabel(char *name, long segment, long offset, + int is_global, char *special) +{ + fprintf(dbgf, "deflabel %s := %08lx:%08lx %s (%d)%s%s\n", + name, segment, offset, + is_global == 2 ? "common" : is_global ? "global" : "local", + is_global, special ? ": " : "", special); +} + +static void dbg_out(long segto, void *data, unsigned long type, + long segment, long wrt) +{ + long realbytes = type & OUT_SIZMASK; + long ldata; + int id; + + type &= OUT_TYPMASK; + + fprintf(dbgf, "out to %lx, len = %ld: ", segto, realbytes); + + switch (type) { + case OUT_RESERVE: + fprintf(dbgf, "reserved.\n"); + break; + case OUT_RAWDATA: + fprintf(dbgf, "raw data = "); + while (realbytes--) { + id = *(unsigned char *)data; + data = (char *)data + 1; + fprintf(dbgf, "%02x ", id); + } + fprintf(dbgf, "\n"); + break; + case OUT_ADDRESS: + ldata = 0; /* placate gcc */ + if (realbytes == 1) + ldata = *((char *)data); + else if (realbytes == 2) + ldata = *((short *)data); + else if (realbytes == 4) + ldata = *((long *)data); + fprintf(dbgf, "addr %08lx (seg %08lx, wrt %08lx)\n", ldata, + segment, wrt); + break; + case OUT_REL2ADR: + fprintf(dbgf, "rel2adr %04x (seg %08lx)\n", (int)*(short *)data, + segment); + break; + case OUT_REL4ADR: + fprintf(dbgf, "rel4adr %08lx (seg %08lx)\n", *(long *)data, + segment); + break; + default: + fprintf(dbgf, "unknown\n"); + break; + } +} + +static long dbg_segbase(long segment) +{ + return segment; +} + +static int dbg_directive(char *directive, char *value, int pass) +{ + fprintf(dbgf, "directive [%s] value [%s] (pass %d)\n", + directive, value, pass); + return 1; +} + +static void dbg_filename(char *inname, char *outname, efunc error) +{ + standard_extension(inname, outname, ".dbg", error); +} + +static int dbg_set_info(enum geninfo type, char **val) +{ + (void)type; + (void)val; + return 0; +} + +char *types[] = { + "unknown", "label", "byte", "word", "dword", "float", "qword", "tbyte" +}; +void dbgdbg_init(struct ofmt *of, void *id, FILE * fp, efunc error) +{ + (void)of; + (void)id; + (void)fp; + (void)error; + fprintf(fp, " With debug info\n"); +} +static void dbgdbg_cleanup(void) +{ +} + +static void dbgdbg_linnum(const char *lnfname, long lineno, long segto) +{ + fprintf(dbgf, "dbglinenum %s(%ld) := %08lx\n", lnfname, lineno, segto); +} +static void dbgdbg_deflabel(char *name, long segment, + long offset, int is_global, char *special) +{ + fprintf(dbgf, "dbglabel %s := %08lx:%08lx %s (%d)%s%s\n", + name, + segment, offset, + is_global == 2 ? "common" : is_global ? "global" : "local", + is_global, special ? ": " : "", special); +} +static void dbgdbg_define(const char *type, const char *params) +{ + fprintf(dbgf, "dbgdirective [%s] value [%s]\n", type, params); +} +static void dbgdbg_output(int output_type, void *param) +{ + (void)output_type; + (void)param; +} +static void dbgdbg_typevalue(long type) +{ + fprintf(dbgf, "new type: %s(%lX)\n", + types[TYM_TYPE(type) >> 3], TYM_ELEMENTS(type)); +} +static struct dfmt debug_debug_form = { + "Trace of all info passed to debug stage", + "debug", + dbgdbg_init, + dbgdbg_linnum, + dbgdbg_deflabel, + dbgdbg_define, + dbgdbg_typevalue, + dbgdbg_output, + dbgdbg_cleanup, +}; + +static struct dfmt *debug_debug_arr[3] = { + &debug_debug_form, + &null_debug_form, + NULL +}; +struct ofmt of_dbg = { + "Trace of all info passed to output stage", + "dbg", + NULL, + debug_debug_arr, + &null_debug_form, + NULL, + dbg_init, + dbg_set_info, + dbg_out, + dbg_deflabel, + dbg_section_names, + dbg_segbase, + dbg_directive, + dbg_filename, + dbg_cleanup +}; + +#endif /* OF_DBG */ diff --git a/output/outelf.c b/output/outelf.c dissimilarity index 74% index 16c25d10..35d0e343 100644 --- a/output/outelf.c +++ b/output/outelf.c @@ -1,1485 +1,1512 @@ -/* outelf.c output routines for the Netwide Assembler to produce - * ELF32 (i386 of course) object file format - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "outform.h" - -#ifdef OF_ELF - -/* - * Relocation types. - */ -enum reloc_type { - R_386_32 = 1, /* ordinary absolute relocation */ - R_386_PC32 = 2, /* PC-relative relocation */ - R_386_GOT32 = 3, /* an offset into GOT */ - R_386_PLT32 = 4, /* a PC-relative offset into PLT */ - R_386_COPY = 5, /* ??? */ - R_386_GLOB_DAT = 6, /* ??? */ - R_386_JUMP_SLOT = 7, /* ??? */ - R_386_RELATIVE = 8, /* ??? */ - R_386_GOTOFF = 9, /* an offset from GOT base */ - R_386_GOTPC = 10, /* a PC-relative offset _to_ GOT */ - /* These are GNU extensions, but useful */ - R_386_16 = 20, /* A 16-bit absolute relocation */ - R_386_PC16 = 21, /* A 16-bit PC-relative relocation */ - R_386_8 = 22, /* An 8-bit absolute relocation */ - R_386_PC8 = 23 /* An 8-bit PC-relative relocation */ -}; - -struct Reloc { - struct Reloc *next; - long address; /* relative to _start_ of section */ - long symbol; /* ELF symbol info thingy */ - int type; /* type of relocation */ -}; - -struct Symbol { - long strpos; /* string table position of name */ - long section; /* section ID of the symbol */ - int type; /* symbol type */ - long value; /* address, or COMMON variable align */ - long size; /* size of symbol */ - long globnum; /* symbol table offset if global */ - struct Symbol *next; /* list of globals in each section */ - struct Symbol *nextfwd; /* list of unresolved-size symbols */ - char *name; /* used temporarily if in above list */ -}; - -#define SHT_PROGBITS 1 -#define SHT_NOBITS 8 - -#define SHF_WRITE 1 -#define SHF_ALLOC 2 -#define SHF_EXECINSTR 4 - -struct Section { - struct SAA *data; - unsigned long len, size, nrelocs; - long index; - int type; /* SHT_PROGBITS or SHT_NOBITS */ - int align; /* alignment: power of two */ - unsigned long flags; /* section flags */ - char *name; - struct SAA *rel; - long rellen; - struct Reloc *head, **tail; - struct Symbol *gsyms; /* global symbols in section */ -}; - -#define SECT_DELTA 32 -static struct Section **sects; -static int nsects, sectlen; - -#define SHSTR_DELTA 256 -static char *shstrtab; -static int shstrtablen, shstrtabsize; - -static struct SAA *syms; -static unsigned long nlocals, nglobs; - -static long def_seg; - -static struct RAA *bsym; - -static struct SAA *strs; -static unsigned long strslen; - -static FILE *elffp; -static efunc error; -static evalfunc evaluate; - -static struct Symbol *fwds; - -static char elf_module[FILENAME_MAX]; - -extern struct ofmt of_elf; - -#define SHN_ABS 0xFFF1 -#define SHN_COMMON 0xFFF2 -#define SHN_UNDEF 0 - -#define SYM_SECTION 0x04 -#define SYM_GLOBAL 0x10 -#define SYM_DATA 0x01 -#define SYM_FUNCTION 0x02 - -#define GLOBAL_TEMP_BASE 16 /* bigger than any constant sym id */ - -#define SEG_ALIGN 16 /* alignment of sections in file */ -#define SEG_ALIGN_1 (SEG_ALIGN-1) - -static const char align_str[SEG_ALIGN] = ""; /* ANSI will pad this with 0s */ - -#define ELF_MAX_SECTIONS 16 /* really 10, but let's play safe */ -static struct ELF_SECTDATA { - void *data; - long len; - int is_saa; -} *elf_sects; -static int elf_nsect; -static long elf_foffs; - -static void elf_write(void); -static void elf_sect_write(struct Section *, const unsigned char *, unsigned long); -static void elf_section_header (int, int, int, void *, int, long, - int, int, int, int); -static void elf_write_sections (void); -static struct SAA *elf_build_symtab (long *, long *); -static struct SAA *elf_build_reltab (long *, struct Reloc *); -static void add_sectname (char *, char *); - - -/* this stuff is needed for the stabs debugging format */ -#define N_SO 0x64 /* ID for main source file */ -#define N_SOL 0x84 /* ID for sub-source file */ -#define N_BINCL 0x82 -#define N_EINCL 0xA2 -#define N_SLINE 0x44 -#define TY_STABSSYMLIN 0x40 /* ouch */ - -struct stabentry { - unsigned long n_strx; - unsigned char n_type; - unsigned char n_other; - unsigned short n_desc; - unsigned long n_value; -}; - -struct erel { - int offset,info; -}; - -struct symlininfo { - int offset; - int section; /* section index */ - char *name; /* shallow-copied pointer of section name */ -}; - -struct linelist { - struct symlininfo info; - int line; - char *filename; - struct linelist * next; - struct linelist * last; -}; - -static struct linelist *stabslines=0; -static int stabs_immcall=0; -static int currentline=0; -static int numlinestabs=0; -static char * stabs_filename=0; -static int symtabsection; -static unsigned char *stabbuf=0,*stabstrbuf=0,*stabrelbuf=0; -static int stablen,stabstrlen,stabrellen; - -static struct dfmt df_stabs; - -void stabs_init(struct ofmt *,void *,FILE *,efunc ); -void stabs_linenum(const char *filename,long linenumber,long); -void stabs_deflabel(char *,long ,long ,int ,char *); -void stabs_directive(const char *,const char *); -void stabs_typevalue(long ); -void stabs_output(int ,void *); -void stabs_generate(); -void stabs_cleanup(); - -/* end of stabs debugging stuff */ - - -/* - * Special section numbers which are used to define ELF special - * symbols, which can be used with WRT to provide PIC relocation - * types. - */ -static long elf_gotpc_sect, elf_gotoff_sect; -static long elf_got_sect, elf_plt_sect; -static long elf_sym_sect; - -static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) -{ - elffp = fp; - error = errfunc; - evaluate = eval; - (void) ldef; /* placate optimisers */ - sects = NULL; - nsects = sectlen = 0; - syms = saa_init((long)sizeof(struct Symbol)); - nlocals = nglobs = 0; - bsym = raa_init(); - strs = saa_init(1L); - saa_wbytes (strs, "\0", 1L); - saa_wbytes (strs, elf_module, (long)(strlen(elf_module)+1)); - strslen = 2+strlen(elf_module); - shstrtab = NULL; - shstrtablen = shstrtabsize = 0;; - add_sectname ("", ""); - - fwds = NULL; - - elf_gotpc_sect = seg_alloc(); - ldef("..gotpc", elf_gotpc_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); - elf_gotoff_sect = seg_alloc(); - ldef("..gotoff", elf_gotoff_sect+1, 0L, NULL, FALSE, FALSE,&of_elf,error); - elf_got_sect = seg_alloc(); - ldef("..got", elf_got_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); - elf_plt_sect = seg_alloc(); - ldef("..plt", elf_plt_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); - elf_sym_sect = seg_alloc(); - ldef("..sym", elf_sym_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error); - - def_seg = seg_alloc(); -} - -static void elf_cleanup(int debuginfo) -{ - struct Reloc *r; - int i; - - (void) debuginfo; - - elf_write(); - fclose (elffp); - for (i=0; itype != SHT_NOBITS) - saa_free (sects[i]->data); - if (sects[i]->head) - saa_free (sects[i]->rel); - while (sects[i]->head) { - r = sects[i]->head; - sects[i]->head = sects[i]->head->next; - nasm_free (r); - } - } - nasm_free (sects); - saa_free (syms); - raa_free (bsym); - saa_free (strs); - if (of_elf.current_dfmt) { - of_elf.current_dfmt->cleanup(); - } -} - -static void add_sectname (char *firsthalf, char *secondhalf) -{ - int len = strlen(firsthalf)+strlen(secondhalf); - while (shstrtablen + len + 1 > shstrtabsize) - shstrtab = nasm_realloc (shstrtab, (shstrtabsize += SHSTR_DELTA)); - strcpy (shstrtab+shstrtablen, firsthalf); - strcat (shstrtab+shstrtablen, secondhalf); - shstrtablen += len+1; -} - -static int elf_make_section (char *name, int type, int flags, int align) -{ - struct Section *s; - - s = nasm_malloc (sizeof(*s)); - - if (type != SHT_NOBITS) - s->data = saa_init (1L); - s->head = NULL; - s->tail = &s->head; - s->len = s->size = 0; - s->nrelocs = 0; - if (!strcmp(name, ".text")) - s->index = def_seg; - else - s->index = seg_alloc(); - add_sectname ("", name); - s->name = nasm_malloc (1+strlen(name)); - strcpy (s->name, name); - s->type = type; - s->flags = flags; - s->align = align; - s->gsyms = NULL; - - if (nsects >= sectlen) - sects = nasm_realloc (sects, (sectlen += SECT_DELTA)*sizeof(*sects)); - sects[nsects++] = s; - - return nsects-1; -} - -static long elf_section_names (char *name, int pass, int *bits) -{ - char *p; - int flags_and, flags_or, type, align, i; - - /* - * Default is 32 bits. - */ - if (!name) { - *bits = 32; - return def_seg; - } - - p = name; - while (*p && !isspace(*p)) p++; - if (*p) *p++ = '\0'; - flags_and = flags_or = type = align = 0; - - while (*p && isspace(*p)) p++; - while (*p) { - char *q = p; - while (*p && !isspace(*p)) p++; - if (*p) *p++ = '\0'; - while (*p && isspace(*p)) p++; - - if (!nasm_strnicmp(q, "align=", 6)) { - align = atoi(q+6); - if (align == 0) - align = 1; - if ( (align-1) & align ) { /* means it's not a power of two */ - error (ERR_NONFATAL, "section alignment %d is not" - " a power of two", align); - align = 1; - } - } else if (!nasm_stricmp(q, "alloc")) { - flags_and |= SHF_ALLOC; - flags_or |= SHF_ALLOC; - } else if (!nasm_stricmp(q, "noalloc")) { - flags_and |= SHF_ALLOC; - flags_or &= ~SHF_ALLOC; - } else if (!nasm_stricmp(q, "exec")) { - flags_and |= SHF_EXECINSTR; - flags_or |= SHF_EXECINSTR; - } else if (!nasm_stricmp(q, "noexec")) { - flags_and |= SHF_EXECINSTR; - flags_or &= ~SHF_EXECINSTR; - } else if (!nasm_stricmp(q, "write")) { - flags_and |= SHF_WRITE; - flags_or |= SHF_WRITE; - } else if (!nasm_stricmp(q, "nowrite")) { - flags_and |= SHF_WRITE; - flags_or &= ~SHF_WRITE; - } else if (!nasm_stricmp(q, "progbits")) { - type = SHT_PROGBITS; - } else if (!nasm_stricmp(q, "nobits")) { - type = SHT_NOBITS; - } - } - - if (!strcmp(name, ".comment") || - !strcmp(name, ".shstrtab") || - !strcmp(name, ".symtab") || - !strcmp(name, ".strtab")) { - error (ERR_NONFATAL, "attempt to redefine reserved section" - "name `%s'", name); - return NO_SEG; - } - - for (i=0; iname)) - break; - if (i == nsects) { - if (!strcmp(name, ".text")) - i = elf_make_section (name, SHT_PROGBITS, - SHF_ALLOC | SHF_EXECINSTR, 16); - else if (!strcmp(name, ".rodata")) - i = elf_make_section (name, SHT_PROGBITS, - SHF_ALLOC, 4); - else if (!strcmp(name, ".data")) - i = elf_make_section (name, SHT_PROGBITS, - SHF_ALLOC | SHF_WRITE, 4); - else if (!strcmp(name, ".bss")) - i = elf_make_section (name, SHT_NOBITS, - SHF_ALLOC | SHF_WRITE, 4); - else - i = elf_make_section (name, SHT_PROGBITS, SHF_ALLOC, 1); - if (type) - sects[i]->type = type; - if (align) - sects[i]->align = align; - sects[i]->flags &= ~flags_and; - sects[i]->flags |= flags_or; - } else if (pass == 1) { - if (type || align || flags_and) - error (ERR_WARNING, "section attributes ignored on" - " redeclaration of section `%s'", name); - } - - return sects[i]->index; -} - -static void elf_deflabel (char *name, long segment, long offset, - int is_global, char *special) -{ - int pos = strslen; - struct Symbol *sym; - int special_used = FALSE; - -#if defined(DEBUG) && DEBUG>2 -fprintf(stderr, " elf_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n", - name, segment, offset, is_global, special); -#endif - if (name[0] == '.' && name[1] == '.' && name[2] != '@') { - /* - * This is a NASM special symbol. We never allow it into - * the ELF symbol table, even if it's a valid one. If it - * _isn't_ a valid one, we should barf immediately. - */ - if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") && - strcmp(name, "..got") && strcmp(name, "..plt") && - strcmp(name, "..sym")) - error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); - return; - } - - if (is_global == 3) { - struct Symbol **s; - /* - * Fix up a forward-reference symbol size from the first - * pass. - */ - for (s = &fwds; *s; s = &(*s)->nextfwd) - if (!strcmp((*s)->name, name)) { - struct tokenval tokval; - expr *e; - char *p = special; - - while (*p && !isspace(*p)) p++; - while (*p && isspace(*p)) p++; - stdscan_reset(); - stdscan_bufptr = p; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); - if (e) { - if (!is_simple(e)) - error (ERR_NONFATAL, "cannot use relocatable" - " expression as symbol size"); - else - (*s)->size = reloc_value(e); - } - - /* - * Remove it from the list of unresolved sizes. - */ - nasm_free ((*s)->name); - *s = (*s)->nextfwd; - return; - } - return; /* it wasn't an important one */ - } - - saa_wbytes (strs, name, (long)(1+strlen(name))); - strslen += 1+strlen(name); - - sym = saa_wstruct (syms); - - sym->strpos = pos; - sym->type = is_global ? SYM_GLOBAL : 0; - sym->size = 0; - if (segment == NO_SEG) - sym->section = SHN_ABS; - else { - int i; - sym->section = SHN_UNDEF; - if (nsects == 0 && segment == def_seg) { - int tempint; - if (segment != elf_section_names (".text", 2, &tempint)) - error (ERR_PANIC, "strange segment conditions in ELF driver"); - sym->section = nsects; - } else { - for (i=0; iindex) { - sym->section = i+1; - break; - } - } - } - - if (is_global == 2) { - sym->size = offset; - sym->value = 0; - sym->section = SHN_COMMON; - /* - * We have a common variable. Check the special text to see - * if it's a valid number and power of two; if so, store it - * as the alignment for the common variable. - */ - if (special) { - int err; - sym->value = readnum (special, &err); - if (err) - error(ERR_NONFATAL, "alignment constraint `%s' is not a" - " valid number", special); - else if ( (sym->value | (sym->value-1)) != 2*sym->value - 1) - error(ERR_NONFATAL, "alignment constraint `%s' is not a" - " power of two", special); - } - special_used = TRUE; - } else - sym->value = (sym->section == SHN_UNDEF ? 0 : offset); - - if (sym->type == SYM_GLOBAL) { - /* - * There's a problem here that needs fixing. - * If sym->section == SHN_ABS, then the first line of the - * else section causes a core dump, because its a reference - * beyond the end of the section array. - * This behaviour is exhibited by this code: - * GLOBAL crash_nasm - * crash_nasm equ 0 - * - * I'm not sure how to procede, because I haven't got the - * first clue about how ELF works, so I don't know what to - * do with it. Furthermore, I'm not sure what the rest of this - * section of code does. Help? - * - * For now, I'll see if doing absolutely nothing with it will - * work... - */ - if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON) - { - bsym = raa_write (bsym, segment, nglobs); - } - else if (sym->section != SHN_ABS) - { - /* - * This is a global symbol; so we must add it to the linked - * list of global symbols in its section. We'll push it on - * the beginning of the list, because it doesn't matter - * much which end we put it on and it's easier like this. - * - * In addition, we check the special text for symbol - * type and size information. - */ - sym->next = sects[sym->section-1]->gsyms; - sects[sym->section-1]->gsyms = sym; - - if (special) { - int n = strcspn(special, " "); - - if (!nasm_strnicmp(special, "function", n)) - sym->type |= SYM_FUNCTION; - else if (!nasm_strnicmp(special, "data", n) || - !nasm_strnicmp(special, "object", n)) - sym->type |= SYM_DATA; - else - error(ERR_NONFATAL, "unrecognised symbol type `%.*s'", - n, special); - if (special[n]) { - struct tokenval tokval; - expr *e; - int fwd = FALSE; - char *saveme=stdscan_bufptr; /* bugfix? fbk 8/10/00 */ - - while (special[n] && isspace(special[n])) - n++; - /* - * We have a size expression; attempt to - * evaluate it. - */ - stdscan_reset(); - stdscan_bufptr = special+n; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error, NULL); - if (fwd) { - sym->nextfwd = fwds; - fwds = sym; - sym->name = nasm_strdup(name); - } else if (e) { - if (!is_simple(e)) - error (ERR_NONFATAL, "cannot use relocatable" - " expression as symbol size"); - else - sym->size = reloc_value(e); - } - stdscan_bufptr=saveme; /* bugfix? fbk 8/10/00 */ - } - special_used = TRUE; - } - } - sym->globnum = nglobs; - nglobs++; - } else - nlocals++; - - if (special && !special_used) - error(ERR_NONFATAL, "no special symbol features supported here"); -} - -static void elf_add_reloc (struct Section *sect, long segment, - int type) -{ - struct Reloc *r; - - r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); - sect->tail = &r->next; - r->next = NULL; - - r->address = sect->len; - if (segment == NO_SEG) - r->symbol = 2; - else { - int i; - r->symbol = 0; - for (i=0; iindex) - r->symbol = i+3; - if (!r->symbol) - r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment); - } - r->type = type; - - sect->nrelocs++; -} - -/* - * This routine deals with ..got and ..sym relocations: the more - * complicated kinds. In shared-library writing, some relocations - * with respect to global symbols must refer to the precise symbol - * rather than referring to an offset from the base of the section - * _containing_ the symbol. Such relocations call to this routine, - * which searches the symbol list for the symbol in question. - * - * R_386_GOT32 references require the _exact_ symbol address to be - * used; R_386_32 references can be at an offset from the symbol. - * The boolean argument `exact' tells us this. - * - * Return value is the adjusted value of `addr', having become an - * offset from the symbol rather than the section. Should always be - * zero when returning from an exact call. - * - * Limitation: if you define two symbols at the same place, - * confusion will occur. - * - * Inefficiency: we search, currently, using a linked list which - * isn't even necessarily sorted. - */ -static long elf_add_gsym_reloc (struct Section *sect, - long segment, long offset, - int type, int exact) -{ - struct Reloc *r; - struct Section *s; - struct Symbol *sym, *sm; - int i; - - /* - * First look up the segment/offset pair and find a global - * symbol corresponding to it. If it's not one of our segments, - * then it must be an external symbol, in which case we're fine - * doing a normal elf_add_reloc after first sanity-checking - * that the offset from the symbol is zero. - */ - s = NULL; - for (i=0; iindex) { - s = sects[i]; - break; - } - if (!s) { - if (exact && offset != 0) - error (ERR_NONFATAL, "unable to find a suitable global symbol" - " for this reference"); - else - elf_add_reloc (sect, segment, type); - return offset; - } - - if (exact) { - /* - * Find a symbol pointing _exactly_ at this one. - */ - for (sym = s->gsyms; sym; sym = sym->next) - if (sym->value == offset) - break; - } else { - /* - * Find the nearest symbol below this one. - */ - sym = NULL; - for (sm = s->gsyms; sm; sm = sm->next) - if (sm->value <= offset && (!sym || sm->value > sym->value)) - sym = sm; - } - if (!sym && exact) { - error (ERR_NONFATAL, "unable to find a suitable global symbol" - " for this reference"); - return 0; - } - - r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); - sect->tail = &r->next; - r->next = NULL; - - r->address = sect->len; - r->symbol = GLOBAL_TEMP_BASE + sym->globnum; - r->type = type; - - sect->nrelocs++; - - return offset - sym->value; -} - -static void elf_out (long segto, const void *data, unsigned long type, - long segment, long wrt) -{ - struct Section *s; - long realbytes = type & OUT_SIZMASK; - long addr; - unsigned char mydata[4], *p; - int i; - static struct symlininfo sinfo; - - type &= OUT_TYPMASK; - - /* - * handle absolute-assembly (structure definitions) - */ - if (segto == NO_SEG) { - if (type != OUT_RESERVE) - error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" - " space"); - return; - } - - s = NULL; - for (i=0; iindex) { - s = sects[i]; - break; - } - if (!s) { - int tempint; /* ignored */ - if (segto != elf_section_names (".text", 2, &tempint)) - error (ERR_PANIC, "strange segment conditions in ELF driver"); - else { - s = sects[nsects-1]; - i=nsects-1; - } - } - - /* again some stabs debugging stuff */ - if (of_elf.current_dfmt) { - sinfo.offset=s->len; - sinfo.section=i; - sinfo.name=s->name; - of_elf.current_dfmt->debug_output(TY_STABSSYMLIN,&sinfo); - } - /* end of debugging stuff */ - - if (s->type == SHT_NOBITS && type != OUT_RESERVE) { - error(ERR_WARNING, "attempt to initialise memory in" - " BSS section `%s': ignored", s->name); - if (type == OUT_REL2ADR) - realbytes = 2; - else if (type == OUT_REL4ADR) - realbytes = 4; - s->len += realbytes; - return; - } - - if (type == OUT_RESERVE) { - if (s->type == SHT_PROGBITS) { - error(ERR_WARNING, "uninitialised space declared in" - " non-BSS section `%s': zeroing", s->name); - elf_sect_write (s, NULL, realbytes); - } else - s->len += realbytes; - } else if (type == OUT_RAWDATA) { - if (segment != NO_SEG) - error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); - elf_sect_write (s, data, realbytes); - } else if (type == OUT_ADDRESS) { - int gnu16 = 0; - addr = *(long *)data; - if (segment != NO_SEG) { - if (segment % 2) { - error(ERR_NONFATAL, "ELF format does not support" - " segment base references"); - } else { - if (wrt == NO_SEG) { - if ( realbytes == 2 ) { - gnu16 = 1; - elf_add_reloc (s, segment, R_386_16); - } else { - elf_add_reloc (s, segment, R_386_32); - } - } else if (wrt == elf_gotpc_sect+1) { - /* - * The user will supply GOT relative to $$. ELF - * will let us have GOT relative to $. So we - * need to fix up the data item by $-$$. - */ - addr += s->len; - elf_add_reloc (s, segment, R_386_GOTPC); - } else if (wrt == elf_gotoff_sect+1) { - elf_add_reloc (s, segment, R_386_GOTOFF); - } else if (wrt == elf_got_sect+1) { - addr = elf_add_gsym_reloc (s, segment, addr, - R_386_GOT32, TRUE); - } else if (wrt == elf_sym_sect+1) { - if ( realbytes == 2 ) { - gnu16 = 1; - addr = elf_add_gsym_reloc (s, segment, addr, - R_386_16, FALSE); - } else { - addr = elf_add_gsym_reloc (s, segment, addr, - R_386_32, FALSE); - } - } else if (wrt == elf_plt_sect+1) { - error(ERR_NONFATAL, "ELF format cannot produce non-PC-" - "relative PLT references"); - } else { - error (ERR_NONFATAL, "ELF format does not support this" - " use of WRT"); - wrt = NO_SEG; /* we can at least _try_ to continue */ - } - } - } - p = mydata; - if (gnu16) { - error(ERR_WARNING|ERR_WARN_GNUELF, - "16-bit relocations in ELF is a GNU extension"); - WRITESHORT (p, addr); - } else { - if (realbytes != 4 && segment != NO_SEG) { - error (ERR_NONFATAL, "Unsupported non-32-bit ELF relocation"); - } - WRITELONG (p, addr); - } - elf_sect_write (s, mydata, realbytes); - } else if (type == OUT_REL2ADR) { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL2ADR"); - if (segment != NO_SEG && segment % 2) { - error(ERR_NONFATAL, "ELF format does not support" - " segment base references"); - } else { - if (wrt == NO_SEG) { - error (ERR_WARNING|ERR_WARN_GNUELF, - "16-bit relocations in ELF is a GNU extension"); - elf_add_reloc (s, segment, R_386_PC16); - } else { - error (ERR_NONFATAL, "Unsupported non-32-bit ELF relocation"); - } - } - p = mydata; - WRITESHORT (p, *(long*)data - realbytes); - elf_sect_write (s, mydata, 2L); - } else if (type == OUT_REL4ADR) { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL4ADR"); - if (segment != NO_SEG && segment % 2) { - error(ERR_NONFATAL, "ELF format does not support" - " segment base references"); - } else { - if (wrt == NO_SEG) { - elf_add_reloc (s, segment, R_386_PC32); - } else if (wrt == elf_plt_sect+1) { - elf_add_reloc (s, segment, R_386_PLT32); - } else if (wrt == elf_gotpc_sect+1 || - wrt == elf_gotoff_sect+1 || - wrt == elf_got_sect+1) { - error(ERR_NONFATAL, "ELF format cannot produce PC-" - "relative GOT references"); - } else { - error (ERR_NONFATAL, "ELF format does not support this" - " use of WRT"); - wrt = NO_SEG; /* we can at least _try_ to continue */ - } - } - p = mydata; - WRITELONG (p, *(long*)data - realbytes); - elf_sect_write (s, mydata, 4L); - } -} - -static void elf_write(void) -{ - int nsections, align; - int scount; - char *p; - int commlen; - char comment[64]; - int i; - - struct SAA *symtab; - long symtablen, symtablocal; - - /* - * Work out how many sections we will have. We have SHN_UNDEF, - * then the flexible user sections, then the four fixed - * sections `.comment', `.shstrtab', `.symtab' and `.strtab', - * then optionally relocation sections for the user sections. - */ - if (of_elf.current_dfmt == &df_stabs) - nsections=8; - else - nsections = 5; /* SHN_UNDEF and the fixed ones */ - - add_sectname ("", ".comment"); - add_sectname ("", ".shstrtab"); - add_sectname ("", ".symtab"); - add_sectname ("", ".strtab"); - for (i=0; ihead) { - nsections++; /* for its relocations */ - add_sectname (".rel", sects[i]->name); - } - } - - if (of_elf.current_dfmt == &df_stabs) { - /* in case the debug information is wanted, just add these three sections... */ - add_sectname("",".stab"); - add_sectname("",".stabstr"); - add_sectname(".rel",".stab"); - } - - /* - * Do the comment. - */ - *comment = '\0'; - commlen = 2+sprintf(comment+1, "The Netwide Assembler %s", NASM_VER); - - /* - * Output the ELF header. - */ - fwrite ("\177ELF\1\1\1\0\0\0\0\0\0\0\0\0", 16, 1, elffp); - fwriteshort (1, elffp); /* ET_REL relocatable file */ - fwriteshort (3, elffp); /* EM_386 processor ID */ - fwritelong (1L, elffp); /* EV_CURRENT file format version */ - fwritelong (0L, elffp); /* no entry point */ - fwritelong (0L, elffp); /* no program header table */ - fwritelong (0x40L, elffp); /* section headers straight after - * ELF header plus alignment */ - fwritelong (0L, elffp); /* 386 defines no special flags */ - fwriteshort (0x34, elffp); /* size of ELF header */ - fwriteshort (0, elffp); /* no program header table, again */ - fwriteshort (0, elffp); /* still no program header table */ - fwriteshort (0x28, elffp); /* size of section header */ - fwriteshort (nsections, elffp); /* number of sections */ - fwriteshort (nsects+2, elffp); /* string table section index for - * section header table */ - fwritelong (0L, elffp); /* align to 0x40 bytes */ - fwritelong (0L, elffp); - fwritelong (0L, elffp); - - /* - * Build the symbol table and relocation tables. - */ - symtab = elf_build_symtab (&symtablen, &symtablocal); - for (i=0; ihead) - sects[i]->rel = elf_build_reltab (§s[i]->rellen, - sects[i]->head); - - /* - * Now output the section header table. - */ - - elf_foffs = 0x40 + 0x28 * nsections; - align = ((elf_foffs+SEG_ALIGN_1) & ~SEG_ALIGN_1) - elf_foffs; - elf_foffs += align; - elf_nsect = 0; - elf_sects = nasm_malloc(sizeof(*elf_sects) * (2 * nsects + 10)); - - elf_section_header (0, 0, 0, NULL, FALSE, 0L, 0, 0, 0, 0); /* SHN_UNDEF */ - scount=1; /* needed for the stabs debugging to track the symtable section */ - p = shstrtab+1; - for (i=0; itype, sects[i]->flags, - (sects[i]->type == SHT_PROGBITS ? - sects[i]->data : NULL), TRUE, - sects[i]->len, 0, 0, sects[i]->align, 0); - p += strlen(p)+1; - scount++; /* dito */ - } - elf_section_header (p - shstrtab, 1, 0, comment, FALSE, - (long)commlen, 0, 0, 1, 0);/* .comment */ - scount++; /* dito */ - p += strlen(p)+1; - elf_section_header (p - shstrtab, 3, 0, shstrtab, FALSE, - (long)shstrtablen, 0, 0, 1, 0);/* .shstrtab */ - scount++; /* dito */ - p += strlen(p)+1; - elf_section_header (p - shstrtab, 2, 0, symtab, TRUE, - symtablen, nsects+4, symtablocal, 4, 16);/* .symtab */ - symtabsection = scount; /* now we got the symtab section index in the ELF file */ - p += strlen(p)+1; - elf_section_header (p - shstrtab, 3, 0, strs, TRUE, - strslen, 0, 0, 1, 0); /* .strtab */ - for (i=0; ihead) { - p += strlen(p)+1; - elf_section_header (p - shstrtab, 9, 0, sects[i]->rel, TRUE, - sects[i]->rellen, nsects+3, i+1, 4, 8); - } - if (of_elf.current_dfmt == &df_stabs) { - /* for debugging information, create the last three sections - which are the .stab , .stabstr and .rel.stab sections respectively */ - - /* this function call creates the stab sections in memory */ - stabs_generate(); - - if ((stabbuf)&&(stabstrbuf)&&(stabrelbuf)) { - p += strlen(p)+1; - elf_section_header(p-shstrtab,1,0,stabbuf,0,stablen,nsections-2,0,4,12); - - p += strlen(p)+1; - elf_section_header(p-shstrtab,3,0,stabstrbuf,0,stabstrlen,0,0,4,0); - - p += strlen(p)+1; - /* link -> symtable info -> section to refer to */ - elf_section_header(p-shstrtab,9,0,stabrelbuf,0,stabrellen,symtabsection,nsections-3,4,8); - } - } - fwrite (align_str, align, 1, elffp); - - /* - * Now output the sections. - */ - elf_write_sections(); - - nasm_free (elf_sects); - saa_free (symtab); -} - -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 struct SAA *elf_build_reltab (long *len, struct Reloc *r) { - struct SAA *s; - unsigned char *p, entry[8]; - - if (!r) - return NULL; - - s = saa_init(1L); - *len = 0; - - while (r) { - long sym = r->symbol; - - if (sym >= GLOBAL_TEMP_BASE) - sym += -GLOBAL_TEMP_BASE + (nsects+3) + nlocals; - - p = entry; - WRITELONG (p, r->address); - WRITELONG (p, (sym << 8) + r->type); - saa_wbytes (s, entry, 8L); - *len += 8; - - r = r->next; - } - - return s; -} - -static void elf_section_header (int name, int type, int flags, - void *data, int is_saa, long datalen, - int link, int info, int align, int eltsize) -{ - elf_sects[elf_nsect].data = data; - elf_sects[elf_nsect].len = datalen; - elf_sects[elf_nsect].is_saa = is_saa; - elf_nsect++; - - fwritelong ((long)name, elffp); - fwritelong ((long)type, elffp); - fwritelong ((long)flags, elffp); - fwritelong (0L, elffp); /* no address, ever, in object files */ - fwritelong (type == 0 ? 0L : elf_foffs, elffp); - fwritelong (datalen, elffp); - if (data) - elf_foffs += (datalen+SEG_ALIGN_1) & ~SEG_ALIGN_1; - fwritelong ((long)link, elffp); - fwritelong ((long)info, elffp); - fwritelong ((long)align, elffp); - fwritelong ((long)eltsize, elffp); -} - -static void elf_write_sections (void) -{ - int i; - for (i = 0; i < elf_nsect; i++) - if (elf_sects[i].data) { - long len = elf_sects[i].len; - long reallen = (len+SEG_ALIGN_1) & ~SEG_ALIGN_1; - long align = reallen - len; - if (elf_sects[i].is_saa) - saa_fpwrite (elf_sects[i].data, elffp); - else - fwrite (elf_sects[i].data, len, 1, elffp); - fwrite (align_str, align, 1, elffp); - } -} - -static void elf_sect_write (struct Section *sect, - const unsigned char *data, unsigned long len) -{ - saa_wbytes (sect->data, data, len); - sect->len += len; -} - -static long elf_segbase (long segment) -{ - return segment; -} - -static int elf_directive (char *directive, char *value, int pass) -{ - return 0; -} - -static void elf_filename (char *inname, char *outname, efunc error) -{ - strcpy(elf_module, inname); - standard_extension (inname, outname, ".o", error); -} - -static const char *elf_stdmac[] = { - "%define __SECT__ [section .text]", - "%macro __NASM_CDecl__ 1", - "%define $_%1 $%1", - "%endmacro", - NULL -}; -static int elf_set_info(enum geninfo type, char **val) -{ - return 0; -} - -static struct dfmt df_stabs = { - "ELF32 (i386) stabs debug format for Linux", - "stabs", - stabs_init, - stabs_linenum, - stabs_deflabel, - stabs_directive, - stabs_typevalue, - stabs_output, - stabs_cleanup -}; - -struct dfmt *elf_debugs_arr[2]={&df_stabs,NULL}; - -struct ofmt of_elf = { - "ELF32 (i386) object files (e.g. Linux)", - "elf", - NULL, - elf_debugs_arr, - &null_debug_form, - elf_stdmac, - elf_init, - elf_set_info, - elf_out, - elf_deflabel, - elf_section_names, - elf_segbase, - elf_directive, - elf_filename, - elf_cleanup -}; - -/* again, the stabs debugging stuff (code) */ - -void stabs_init(struct ofmt *of,void *id,FILE *fp,efunc error) -{ -} - -void stabs_linenum(const char *filename,long linenumber,long segto) -{ - if (!stabs_filename) { - stabs_filename = (char *)nasm_malloc(strlen(filename)+1); - strcpy(stabs_filename,filename); - } else { - if (strcmp(stabs_filename,filename)) { - /* yep, a memory leak...this program is one-shot anyway, so who cares... - in fact, this leak comes in quite handy to maintain a list of files - encountered so far in the symbol lines... */ - - /* why not nasm_free(stabs_filename); we're done with the old one */ - - stabs_filename = (char *)nasm_malloc(strlen(filename)+1); - strcpy(stabs_filename,filename); - } - } - stabs_immcall=1; - currentline=linenumber; -} - -void stabs_deflabel(char *name,long segment,long offset,int is_global,char *special) -{ -} - -void stabs_directive(const char *directive,const char *params) -{ -} - -void stabs_typevalue(long type) -{ -} - -void stabs_output(int type,void *param) -{ - struct symlininfo *s; - struct linelist *el; - if (type==TY_STABSSYMLIN) { - if (stabs_immcall) { - s=(struct symlininfo *)param; - if (strcmp( s->name,".text")) return; /* we are only interested in the text stuff */ - numlinestabs++; - el=(struct linelist *)nasm_malloc(sizeof(struct linelist)); - el->info.offset=s->offset; - el->info.section=s->section; - el->info.name=s->name; - el->line=currentline; - el->filename=stabs_filename; - el->next=0; - if (stabslines) { - stabslines->last->next=el; - stabslines->last=el; - } else { - stabslines=el; - stabslines->last=el; - } - } - } - stabs_immcall=0; -} - -#define WRITE_STAB(p,n_strx,n_type,n_other,n_desc,n_value) \ - do {\ - WRITELONG(p,n_strx); \ - WRITECHAR(p,n_type); \ - WRITECHAR(p,n_other); \ - WRITESHORT(p,n_desc); \ - WRITELONG(p,n_value); \ - } while (0) - -/* for creating the .stab , .stabstr and .rel.stab sections in memory */ - -void stabs_generate(void) -{ - int i,numfiles,strsize,numstabs=0,currfile,mainfileindex; - unsigned char *sbuf,*ssbuf,*rbuf,*sptr,*rptr; - char **allfiles; - int *fileidx; - - struct linelist *ptr; - - ptr=stabslines; - - allfiles = (char **)nasm_malloc(numlinestabs*sizeof(char *)); - for (i=0;ifilename; - numfiles++; - } else { - for (i=0;ifilename)) break; - } - if (i>=numfiles) { - allfiles[i]=ptr->filename; - numfiles++; - } - } - ptr=ptr->next; - } - strsize=1; - fileidx = (int *)nasm_malloc(numfiles*sizeof(int)); - for (i=0;iinfo.section+3)<<8)|R_386_32); - - numstabs++; - currfile=mainfileindex; - } - - while (ptr) { - if (strcmp(allfiles[currfile],ptr->filename)) { - /* oops file has changed... */ - for (i=0;ifilename)) break; - currfile=i; - WRITE_STAB(sptr,fileidx[currfile],N_SOL,0,0,ptr->info.offset); - numstabs++; - - /* relocation stuff */ - /* IS THIS SANE? WHAT DOES SECTION+3 MEAN HERE? */ - WRITELONG(rptr, (sptr-sbuf)-4); - WRITELONG(rptr, ((ptr->info.section+3)<<8)|R_386_32); - } - - WRITE_STAB(sptr,0,N_SLINE,0,ptr->line,ptr->info.offset); - numstabs++; - - /* relocation stuff */ - /* IS THIS SANE? WHAT DOES SECTION+3 MEAN HERE? */ - WRITELONG(rptr, (sptr-sbuf)-4); - WRITELONG(rptr, ((ptr->info.section+3)<<8)|R_386_32); - - ptr=ptr->next; - - } - - - ((struct stabentry *)sbuf)->n_desc=numstabs; - - nasm_free(allfiles); - nasm_free(fileidx); - - stablen = (sptr-sbuf); - stabrellen=(rptr-rbuf); - stabrelbuf= rbuf; - stabbuf = sbuf; - stabstrbuf = ssbuf; -} - -void stabs_cleanup() { - struct linelist *ptr,*del; - if (!stabslines) return; - ptr=stabslines; - while (ptr) { - del=ptr; - ptr=ptr->next; - nasm_free(del); - } - if (stabbuf) nasm_free(stabbuf); - if (stabrelbuf) nasm_free(stabrelbuf); - if (stabstrbuf) nasm_free(stabstrbuf); -} - -#endif /* OF_ELF */ +/* outelf.c output routines for the Netwide Assembler to produce + * ELF32 (i386 of course) object file format + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "outform.h" + +#ifdef OF_ELF + +/* + * Relocation types. + */ +enum reloc_type { + R_386_32 = 1, /* ordinary absolute relocation */ + R_386_PC32 = 2, /* PC-relative relocation */ + R_386_GOT32 = 3, /* an offset into GOT */ + R_386_PLT32 = 4, /* a PC-relative offset into PLT */ + R_386_COPY = 5, /* ??? */ + R_386_GLOB_DAT = 6, /* ??? */ + R_386_JUMP_SLOT = 7, /* ??? */ + R_386_RELATIVE = 8, /* ??? */ + R_386_GOTOFF = 9, /* an offset from GOT base */ + R_386_GOTPC = 10, /* a PC-relative offset _to_ GOT */ + /* These are GNU extensions, but useful */ + R_386_16 = 20, /* A 16-bit absolute relocation */ + R_386_PC16 = 21, /* A 16-bit PC-relative relocation */ + R_386_8 = 22, /* An 8-bit absolute relocation */ + R_386_PC8 = 23 /* An 8-bit PC-relative relocation */ +}; + +struct Reloc { + struct Reloc *next; + long address; /* relative to _start_ of section */ + long symbol; /* ELF symbol info thingy */ + int type; /* type of relocation */ +}; + +struct Symbol { + long strpos; /* string table position of name */ + long section; /* section ID of the symbol */ + int type; /* symbol type */ + long value; /* address, or COMMON variable align */ + long size; /* size of symbol */ + long globnum; /* symbol table offset if global */ + struct Symbol *next; /* list of globals in each section */ + struct Symbol *nextfwd; /* list of unresolved-size symbols */ + char *name; /* used temporarily if in above list */ +}; + +#define SHT_PROGBITS 1 +#define SHT_NOBITS 8 + +#define SHF_WRITE 1 +#define SHF_ALLOC 2 +#define SHF_EXECINSTR 4 + +struct Section { + struct SAA *data; + unsigned long len, size, nrelocs; + long index; + int type; /* SHT_PROGBITS or SHT_NOBITS */ + int align; /* alignment: power of two */ + unsigned long flags; /* section flags */ + char *name; + struct SAA *rel; + long rellen; + struct Reloc *head, **tail; + struct Symbol *gsyms; /* global symbols in section */ +}; + +#define SECT_DELTA 32 +static struct Section **sects; +static int nsects, sectlen; + +#define SHSTR_DELTA 256 +static char *shstrtab; +static int shstrtablen, shstrtabsize; + +static struct SAA *syms; +static unsigned long nlocals, nglobs; + +static long def_seg; + +static struct RAA *bsym; + +static struct SAA *strs; +static unsigned long strslen; + +static FILE *elffp; +static efunc error; +static evalfunc evaluate; + +static struct Symbol *fwds; + +static char elf_module[FILENAME_MAX]; + +extern struct ofmt of_elf; + +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 +#define SHN_UNDEF 0 + +#define SYM_SECTION 0x04 +#define SYM_GLOBAL 0x10 +#define SYM_DATA 0x01 +#define SYM_FUNCTION 0x02 + +#define GLOBAL_TEMP_BASE 16 /* bigger than any constant sym id */ + +#define SEG_ALIGN 16 /* alignment of sections in file */ +#define SEG_ALIGN_1 (SEG_ALIGN-1) + +static const char align_str[SEG_ALIGN] = ""; /* ANSI will pad this with 0s */ + +#define ELF_MAX_SECTIONS 16 /* really 10, but let's play safe */ +static struct ELF_SECTDATA { + void *data; + long len; + int is_saa; +} *elf_sects; +static int elf_nsect; +static long elf_foffs; + +static void elf_write(void); +static void elf_sect_write(struct Section *, const unsigned char *, + unsigned long); +static void elf_section_header(int, int, int, void *, int, long, int, int, + int, int); +static void elf_write_sections(void); +static struct SAA *elf_build_symtab(long *, long *); +static struct SAA *elf_build_reltab(long *, struct Reloc *); +static void add_sectname(char *, char *); + +/* this stuff is needed for the stabs debugging format */ +#define N_SO 0x64 /* ID for main source file */ +#define N_SOL 0x84 /* ID for sub-source file */ +#define N_BINCL 0x82 +#define N_EINCL 0xA2 +#define N_SLINE 0x44 +#define TY_STABSSYMLIN 0x40 /* ouch */ + +struct stabentry { + unsigned long n_strx; + unsigned char n_type; + unsigned char n_other; + unsigned short n_desc; + unsigned long n_value; +}; + +struct erel { + int offset, info; +}; + +struct symlininfo { + int offset; + int section; /* section index */ + char *name; /* shallow-copied pointer of section name */ +}; + +struct linelist { + struct symlininfo info; + int line; + char *filename; + struct linelist *next; + struct linelist *last; +}; + +static struct linelist *stabslines = 0; +static int stabs_immcall = 0; +static int currentline = 0; +static int numlinestabs = 0; +static char *stabs_filename = 0; +static int symtabsection; +static unsigned char *stabbuf = 0, *stabstrbuf = 0, *stabrelbuf = 0; +static int stablen, stabstrlen, stabrellen; + +static struct dfmt df_stabs; + +void stabs_init(struct ofmt *, void *, FILE *, efunc); +void stabs_linenum(const char *filename, long linenumber, long); +void stabs_deflabel(char *, long, long, int, char *); +void stabs_directive(const char *, const char *); +void stabs_typevalue(long); +void stabs_output(int, void *); +void stabs_generate(); +void stabs_cleanup(); + +/* end of stabs debugging stuff */ + +/* + * Special section numbers which are used to define ELF special + * symbols, which can be used with WRT to provide PIC relocation + * types. + */ +static long elf_gotpc_sect, elf_gotoff_sect; +static long elf_got_sect, elf_plt_sect; +static long elf_sym_sect; + +static void elf_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + elffp = fp; + error = errfunc; + evaluate = eval; + (void)ldef; /* placate optimisers */ + sects = NULL; + nsects = sectlen = 0; + syms = saa_init((long)sizeof(struct Symbol)); + nlocals = nglobs = 0; + bsym = raa_init(); + strs = saa_init(1L); + saa_wbytes(strs, "\0", 1L); + saa_wbytes(strs, elf_module, (long)(strlen(elf_module) + 1)); + strslen = 2 + strlen(elf_module); + shstrtab = NULL; + shstrtablen = shstrtabsize = 0;; + add_sectname("", ""); + + fwds = NULL; + + elf_gotpc_sect = seg_alloc(); + ldef("..gotpc", elf_gotpc_sect + 1, 0L, NULL, FALSE, FALSE, &of_elf, + error); + elf_gotoff_sect = seg_alloc(); + ldef("..gotoff", elf_gotoff_sect + 1, 0L, NULL, FALSE, FALSE, &of_elf, + error); + elf_got_sect = seg_alloc(); + ldef("..got", elf_got_sect + 1, 0L, NULL, FALSE, FALSE, &of_elf, + error); + elf_plt_sect = seg_alloc(); + ldef("..plt", elf_plt_sect + 1, 0L, NULL, FALSE, FALSE, &of_elf, + error); + elf_sym_sect = seg_alloc(); + ldef("..sym", elf_sym_sect + 1, 0L, NULL, FALSE, FALSE, &of_elf, + error); + + def_seg = seg_alloc(); +} + +static void elf_cleanup(int debuginfo) +{ + struct Reloc *r; + int i; + + (void)debuginfo; + + elf_write(); + fclose(elffp); + for (i = 0; i < nsects; i++) { + if (sects[i]->type != SHT_NOBITS) + saa_free(sects[i]->data); + if (sects[i]->head) + saa_free(sects[i]->rel); + while (sects[i]->head) { + r = sects[i]->head; + sects[i]->head = sects[i]->head->next; + nasm_free(r); + } + } + nasm_free(sects); + saa_free(syms); + raa_free(bsym); + saa_free(strs); + if (of_elf.current_dfmt) { + of_elf.current_dfmt->cleanup(); + } +} + +static void add_sectname(char *firsthalf, char *secondhalf) +{ + int len = strlen(firsthalf) + strlen(secondhalf); + while (shstrtablen + len + 1 > shstrtabsize) + shstrtab = nasm_realloc(shstrtab, (shstrtabsize += SHSTR_DELTA)); + strcpy(shstrtab + shstrtablen, firsthalf); + strcat(shstrtab + shstrtablen, secondhalf); + shstrtablen += len + 1; +} + +static int elf_make_section(char *name, int type, int flags, int align) +{ + struct Section *s; + + s = nasm_malloc(sizeof(*s)); + + if (type != SHT_NOBITS) + s->data = saa_init(1L); + s->head = NULL; + s->tail = &s->head; + s->len = s->size = 0; + s->nrelocs = 0; + if (!strcmp(name, ".text")) + s->index = def_seg; + else + s->index = seg_alloc(); + add_sectname("", name); + s->name = nasm_malloc(1 + strlen(name)); + strcpy(s->name, name); + s->type = type; + s->flags = flags; + s->align = align; + s->gsyms = NULL; + + if (nsects >= sectlen) + sects = + nasm_realloc(sects, (sectlen += SECT_DELTA) * sizeof(*sects)); + sects[nsects++] = s; + + return nsects - 1; +} + +static long elf_section_names(char *name, int pass, int *bits) +{ + char *p; + int flags_and, flags_or, type, align, i; + + /* + * Default is 32 bits. + */ + if (!name) { + *bits = 32; + return def_seg; + } + + p = name; + while (*p && !isspace(*p)) + p++; + if (*p) + *p++ = '\0'; + flags_and = flags_or = type = align = 0; + + while (*p && isspace(*p)) + p++; + while (*p) { + char *q = p; + while (*p && !isspace(*p)) + p++; + if (*p) + *p++ = '\0'; + while (*p && isspace(*p)) + p++; + + if (!nasm_strnicmp(q, "align=", 6)) { + align = atoi(q + 6); + if (align == 0) + align = 1; + if ((align - 1) & align) { /* means it's not a power of two */ + error(ERR_NONFATAL, "section alignment %d is not" + " a power of two", align); + align = 1; + } + } else if (!nasm_stricmp(q, "alloc")) { + flags_and |= SHF_ALLOC; + flags_or |= SHF_ALLOC; + } else if (!nasm_stricmp(q, "noalloc")) { + flags_and |= SHF_ALLOC; + flags_or &= ~SHF_ALLOC; + } else if (!nasm_stricmp(q, "exec")) { + flags_and |= SHF_EXECINSTR; + flags_or |= SHF_EXECINSTR; + } else if (!nasm_stricmp(q, "noexec")) { + flags_and |= SHF_EXECINSTR; + flags_or &= ~SHF_EXECINSTR; + } else if (!nasm_stricmp(q, "write")) { + flags_and |= SHF_WRITE; + flags_or |= SHF_WRITE; + } else if (!nasm_stricmp(q, "nowrite")) { + flags_and |= SHF_WRITE; + flags_or &= ~SHF_WRITE; + } else if (!nasm_stricmp(q, "progbits")) { + type = SHT_PROGBITS; + } else if (!nasm_stricmp(q, "nobits")) { + type = SHT_NOBITS; + } + } + + if (!strcmp(name, ".comment") || + !strcmp(name, ".shstrtab") || + !strcmp(name, ".symtab") || !strcmp(name, ".strtab")) { + error(ERR_NONFATAL, "attempt to redefine reserved section" + "name `%s'", name); + return NO_SEG; + } + + for (i = 0; i < nsects; i++) + if (!strcmp(name, sects[i]->name)) + break; + if (i == nsects) { + if (!strcmp(name, ".text")) + i = elf_make_section(name, SHT_PROGBITS, + SHF_ALLOC | SHF_EXECINSTR, 16); + else if (!strcmp(name, ".rodata")) + i = elf_make_section(name, SHT_PROGBITS, SHF_ALLOC, 4); + else if (!strcmp(name, ".data")) + i = elf_make_section(name, SHT_PROGBITS, + SHF_ALLOC | SHF_WRITE, 4); + else if (!strcmp(name, ".bss")) + i = elf_make_section(name, SHT_NOBITS, + SHF_ALLOC | SHF_WRITE, 4); + else + i = elf_make_section(name, SHT_PROGBITS, SHF_ALLOC, 1); + if (type) + sects[i]->type = type; + if (align) + sects[i]->align = align; + sects[i]->flags &= ~flags_and; + sects[i]->flags |= flags_or; + } else if (pass == 1) { + if (type || align || flags_and) + error(ERR_WARNING, "section attributes ignored on" + " redeclaration of section `%s'", name); + } + + return sects[i]->index; +} + +static void elf_deflabel(char *name, long segment, long offset, + int is_global, char *special) +{ + int pos = strslen; + struct Symbol *sym; + int special_used = FALSE; + +#if defined(DEBUG) && DEBUG>2 + fprintf(stderr, + " elf_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n", + name, segment, offset, is_global, special); +#endif + if (name[0] == '.' && name[1] == '.' && name[2] != '@') { + /* + * This is a NASM special symbol. We never allow it into + * the ELF symbol table, even if it's a valid one. If it + * _isn't_ a valid one, we should barf immediately. + */ + if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") && + strcmp(name, "..got") && strcmp(name, "..plt") && + strcmp(name, "..sym")) + error(ERR_NONFATAL, "unrecognised special symbol `%s'", name); + return; + } + + if (is_global == 3) { + struct Symbol **s; + /* + * Fix up a forward-reference symbol size from the first + * pass. + */ + for (s = &fwds; *s; s = &(*s)->nextfwd) + if (!strcmp((*s)->name, name)) { + struct tokenval tokval; + expr *e; + char *p = special; + + while (*p && !isspace(*p)) + p++; + while (*p && isspace(*p)) + p++; + stdscan_reset(); + stdscan_bufptr = p; + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); + if (e) { + if (!is_simple(e)) + error(ERR_NONFATAL, "cannot use relocatable" + " expression as symbol size"); + else + (*s)->size = reloc_value(e); + } + + /* + * Remove it from the list of unresolved sizes. + */ + nasm_free((*s)->name); + *s = (*s)->nextfwd; + return; + } + return; /* it wasn't an important one */ + } + + saa_wbytes(strs, name, (long)(1 + strlen(name))); + strslen += 1 + strlen(name); + + sym = saa_wstruct(syms); + + sym->strpos = pos; + sym->type = is_global ? SYM_GLOBAL : 0; + sym->size = 0; + if (segment == NO_SEG) + sym->section = SHN_ABS; + else { + int i; + sym->section = SHN_UNDEF; + if (nsects == 0 && segment == def_seg) { + int tempint; + if (segment != elf_section_names(".text", 2, &tempint)) + error(ERR_PANIC, + "strange segment conditions in ELF driver"); + sym->section = nsects; + } else { + for (i = 0; i < nsects; i++) + if (segment == sects[i]->index) { + sym->section = i + 1; + break; + } + } + } + + if (is_global == 2) { + sym->size = offset; + sym->value = 0; + sym->section = SHN_COMMON; + /* + * We have a common variable. Check the special text to see + * if it's a valid number and power of two; if so, store it + * as the alignment for the common variable. + */ + if (special) { + int err; + sym->value = readnum(special, &err); + if (err) + error(ERR_NONFATAL, "alignment constraint `%s' is not a" + " valid number", special); + else if ((sym->value | (sym->value - 1)) != 2 * sym->value - 1) + error(ERR_NONFATAL, "alignment constraint `%s' is not a" + " power of two", special); + } + special_used = TRUE; + } else + sym->value = (sym->section == SHN_UNDEF ? 0 : offset); + + if (sym->type == SYM_GLOBAL) { + /* + * There's a problem here that needs fixing. + * If sym->section == SHN_ABS, then the first line of the + * else section causes a core dump, because its a reference + * beyond the end of the section array. + * This behaviour is exhibited by this code: + * GLOBAL crash_nasm + * crash_nasm equ 0 + * + * I'm not sure how to procede, because I haven't got the + * first clue about how ELF works, so I don't know what to + * do with it. Furthermore, I'm not sure what the rest of this + * section of code does. Help? + * + * For now, I'll see if doing absolutely nothing with it will + * work... + */ + if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON) { + bsym = raa_write(bsym, segment, nglobs); + } else if (sym->section != SHN_ABS) { + /* + * This is a global symbol; so we must add it to the linked + * list of global symbols in its section. We'll push it on + * the beginning of the list, because it doesn't matter + * much which end we put it on and it's easier like this. + * + * In addition, we check the special text for symbol + * type and size information. + */ + sym->next = sects[sym->section - 1]->gsyms; + sects[sym->section - 1]->gsyms = sym; + + if (special) { + int n = strcspn(special, " "); + + if (!nasm_strnicmp(special, "function", n)) + sym->type |= SYM_FUNCTION; + else if (!nasm_strnicmp(special, "data", n) || + !nasm_strnicmp(special, "object", n)) + sym->type |= SYM_DATA; + else + error(ERR_NONFATAL, "unrecognised symbol type `%.*s'", + n, special); + if (special[n]) { + struct tokenval tokval; + expr *e; + int fwd = FALSE; + char *saveme = stdscan_bufptr; /* bugfix? fbk 8/10/00 */ + + while (special[n] && isspace(special[n])) + n++; + /* + * We have a size expression; attempt to + * evaluate it. + */ + stdscan_reset(); + stdscan_bufptr = special + n; + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error, + NULL); + if (fwd) { + sym->nextfwd = fwds; + fwds = sym; + sym->name = nasm_strdup(name); + } else if (e) { + if (!is_simple(e)) + error(ERR_NONFATAL, "cannot use relocatable" + " expression as symbol size"); + else + sym->size = reloc_value(e); + } + stdscan_bufptr = saveme; /* bugfix? fbk 8/10/00 */ + } + special_used = TRUE; + } + } + sym->globnum = nglobs; + nglobs++; + } else + nlocals++; + + if (special && !special_used) + error(ERR_NONFATAL, "no special symbol features supported here"); +} + +static void elf_add_reloc(struct Section *sect, long segment, int type) +{ + struct Reloc *r; + + r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); + sect->tail = &r->next; + r->next = NULL; + + r->address = sect->len; + if (segment == NO_SEG) + r->symbol = 2; + else { + int i; + r->symbol = 0; + for (i = 0; i < nsects; i++) + if (segment == sects[i]->index) + r->symbol = i + 3; + if (!r->symbol) + r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment); + } + r->type = type; + + sect->nrelocs++; +} + +/* + * This routine deals with ..got and ..sym relocations: the more + * complicated kinds. In shared-library writing, some relocations + * with respect to global symbols must refer to the precise symbol + * rather than referring to an offset from the base of the section + * _containing_ the symbol. Such relocations call to this routine, + * which searches the symbol list for the symbol in question. + * + * R_386_GOT32 references require the _exact_ symbol address to be + * used; R_386_32 references can be at an offset from the symbol. + * The boolean argument `exact' tells us this. + * + * Return value is the adjusted value of `addr', having become an + * offset from the symbol rather than the section. Should always be + * zero when returning from an exact call. + * + * Limitation: if you define two symbols at the same place, + * confusion will occur. + * + * Inefficiency: we search, currently, using a linked list which + * isn't even necessarily sorted. + */ +static long elf_add_gsym_reloc(struct Section *sect, + long segment, long offset, + int type, int exact) +{ + struct Reloc *r; + struct Section *s; + struct Symbol *sym, *sm; + int i; + + /* + * First look up the segment/offset pair and find a global + * symbol corresponding to it. If it's not one of our segments, + * then it must be an external symbol, in which case we're fine + * doing a normal elf_add_reloc after first sanity-checking + * that the offset from the symbol is zero. + */ + s = NULL; + for (i = 0; i < nsects; i++) + if (segment == sects[i]->index) { + s = sects[i]; + break; + } + if (!s) { + if (exact && offset != 0) + error(ERR_NONFATAL, "unable to find a suitable global symbol" + " for this reference"); + else + elf_add_reloc(sect, segment, type); + return offset; + } + + if (exact) { + /* + * Find a symbol pointing _exactly_ at this one. + */ + for (sym = s->gsyms; sym; sym = sym->next) + if (sym->value == offset) + break; + } else { + /* + * Find the nearest symbol below this one. + */ + sym = NULL; + for (sm = s->gsyms; sm; sm = sm->next) + if (sm->value <= offset && (!sym || sm->value > sym->value)) + sym = sm; + } + if (!sym && exact) { + error(ERR_NONFATAL, "unable to find a suitable global symbol" + " for this reference"); + return 0; + } + + r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); + sect->tail = &r->next; + r->next = NULL; + + r->address = sect->len; + r->symbol = GLOBAL_TEMP_BASE + sym->globnum; + r->type = type; + + sect->nrelocs++; + + return offset - sym->value; +} + +static void elf_out(long segto, const void *data, unsigned long type, + long segment, long wrt) +{ + struct Section *s; + long realbytes = type & OUT_SIZMASK; + long addr; + unsigned char mydata[4], *p; + int i; + static struct symlininfo sinfo; + + type &= OUT_TYPMASK; + + /* + * handle absolute-assembly (structure definitions) + */ + if (segto == NO_SEG) { + if (type != OUT_RESERVE) + error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" + " space"); + return; + } + + s = NULL; + for (i = 0; i < nsects; i++) + if (segto == sects[i]->index) { + s = sects[i]; + break; + } + if (!s) { + int tempint; /* ignored */ + if (segto != elf_section_names(".text", 2, &tempint)) + error(ERR_PANIC, "strange segment conditions in ELF driver"); + else { + s = sects[nsects - 1]; + i = nsects - 1; + } + } + + /* again some stabs debugging stuff */ + if (of_elf.current_dfmt) { + sinfo.offset = s->len; + sinfo.section = i; + sinfo.name = s->name; + of_elf.current_dfmt->debug_output(TY_STABSSYMLIN, &sinfo); + } + /* end of debugging stuff */ + + if (s->type == SHT_NOBITS && type != OUT_RESERVE) { + error(ERR_WARNING, "attempt to initialise memory in" + " BSS section `%s': ignored", s->name); + if (type == OUT_REL2ADR) + realbytes = 2; + else if (type == OUT_REL4ADR) + realbytes = 4; + s->len += realbytes; + return; + } + + if (type == OUT_RESERVE) { + if (s->type == SHT_PROGBITS) { + error(ERR_WARNING, "uninitialised space declared in" + " non-BSS section `%s': zeroing", s->name); + elf_sect_write(s, NULL, realbytes); + } else + s->len += realbytes; + } else if (type == OUT_RAWDATA) { + if (segment != NO_SEG) + error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); + elf_sect_write(s, data, realbytes); + } else if (type == OUT_ADDRESS) { + int gnu16 = 0; + addr = *(long *)data; + if (segment != NO_SEG) { + if (segment % 2) { + error(ERR_NONFATAL, "ELF format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + if (realbytes == 2) { + gnu16 = 1; + elf_add_reloc(s, segment, R_386_16); + } else { + elf_add_reloc(s, segment, R_386_32); + } + } else if (wrt == elf_gotpc_sect + 1) { + /* + * The user will supply GOT relative to $$. ELF + * will let us have GOT relative to $. So we + * need to fix up the data item by $-$$. + */ + addr += s->len; + elf_add_reloc(s, segment, R_386_GOTPC); + } else if (wrt == elf_gotoff_sect + 1) { + elf_add_reloc(s, segment, R_386_GOTOFF); + } else if (wrt == elf_got_sect + 1) { + addr = elf_add_gsym_reloc(s, segment, addr, + R_386_GOT32, TRUE); + } else if (wrt == elf_sym_sect + 1) { + if (realbytes == 2) { + gnu16 = 1; + addr = elf_add_gsym_reloc(s, segment, addr, + R_386_16, FALSE); + } else { + addr = elf_add_gsym_reloc(s, segment, addr, + R_386_32, FALSE); + } + } else if (wrt == elf_plt_sect + 1) { + error(ERR_NONFATAL, "ELF format cannot produce non-PC-" + "relative PLT references"); + } else { + error(ERR_NONFATAL, "ELF format does not support this" + " use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } + } + } + p = mydata; + if (gnu16) { + error(ERR_WARNING | ERR_WARN_GNUELF, + "16-bit relocations in ELF is a GNU extension"); + WRITESHORT(p, addr); + } else { + if (realbytes != 4 && segment != NO_SEG) { + error(ERR_NONFATAL, + "Unsupported non-32-bit ELF relocation"); + } + WRITELONG(p, addr); + } + elf_sect_write(s, mydata, realbytes); + } else if (type == OUT_REL2ADR) { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL2ADR"); + if (segment != NO_SEG && segment % 2) { + error(ERR_NONFATAL, "ELF format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + error(ERR_WARNING | ERR_WARN_GNUELF, + "16-bit relocations in ELF is a GNU extension"); + elf_add_reloc(s, segment, R_386_PC16); + } else { + error(ERR_NONFATAL, + "Unsupported non-32-bit ELF relocation"); + } + } + p = mydata; + WRITESHORT(p, *(long *)data - realbytes); + elf_sect_write(s, mydata, 2L); + } else if (type == OUT_REL4ADR) { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL4ADR"); + if (segment != NO_SEG && segment % 2) { + error(ERR_NONFATAL, "ELF format does not support" + " segment base references"); + } else { + if (wrt == NO_SEG) { + elf_add_reloc(s, segment, R_386_PC32); + } else if (wrt == elf_plt_sect + 1) { + elf_add_reloc(s, segment, R_386_PLT32); + } else if (wrt == elf_gotpc_sect + 1 || + wrt == elf_gotoff_sect + 1 || + wrt == elf_got_sect + 1) { + error(ERR_NONFATAL, "ELF format cannot produce PC-" + "relative GOT references"); + } else { + error(ERR_NONFATAL, "ELF format does not support this" + " use of WRT"); + wrt = NO_SEG; /* we can at least _try_ to continue */ + } + } + p = mydata; + WRITELONG(p, *(long *)data - realbytes); + elf_sect_write(s, mydata, 4L); + } +} + +static void elf_write(void) +{ + int nsections, align; + int scount; + char *p; + int commlen; + char comment[64]; + int i; + + struct SAA *symtab; + long symtablen, symtablocal; + + /* + * Work out how many sections we will have. We have SHN_UNDEF, + * then the flexible user sections, then the four fixed + * sections `.comment', `.shstrtab', `.symtab' and `.strtab', + * then optionally relocation sections for the user sections. + */ + if (of_elf.current_dfmt == &df_stabs) + nsections = 8; + else + nsections = 5; /* SHN_UNDEF and the fixed ones */ + + add_sectname("", ".comment"); + add_sectname("", ".shstrtab"); + add_sectname("", ".symtab"); + add_sectname("", ".strtab"); + for (i = 0; i < nsects; i++) { + nsections++; /* for the section itself */ + if (sects[i]->head) { + nsections++; /* for its relocations */ + add_sectname(".rel", sects[i]->name); + } + } + + if (of_elf.current_dfmt == &df_stabs) { + /* in case the debug information is wanted, just add these three sections... */ + add_sectname("", ".stab"); + add_sectname("", ".stabstr"); + add_sectname(".rel", ".stab"); + } + + /* + * Do the comment. + */ + *comment = '\0'; + commlen = + 2 + sprintf(comment + 1, "The Netwide Assembler %s", NASM_VER); + + /* + * Output the ELF header. + */ + fwrite("\177ELF\1\1\1\0\0\0\0\0\0\0\0\0", 16, 1, elffp); + fwriteshort(1, elffp); /* ET_REL relocatable file */ + fwriteshort(3, elffp); /* EM_386 processor ID */ + fwritelong(1L, elffp); /* EV_CURRENT file format version */ + fwritelong(0L, elffp); /* no entry point */ + fwritelong(0L, elffp); /* no program header table */ + fwritelong(0x40L, elffp); /* section headers straight after + * ELF header plus alignment */ + fwritelong(0L, elffp); /* 386 defines no special flags */ + fwriteshort(0x34, elffp); /* size of ELF header */ + fwriteshort(0, elffp); /* no program header table, again */ + fwriteshort(0, elffp); /* still no program header table */ + fwriteshort(0x28, elffp); /* size of section header */ + fwriteshort(nsections, elffp); /* number of sections */ + fwriteshort(nsects + 2, elffp); /* string table section index for + * section header table */ + fwritelong(0L, elffp); /* align to 0x40 bytes */ + fwritelong(0L, elffp); + fwritelong(0L, elffp); + + /* + * Build the symbol table and relocation tables. + */ + symtab = elf_build_symtab(&symtablen, &symtablocal); + for (i = 0; i < nsects; i++) + if (sects[i]->head) + sects[i]->rel = elf_build_reltab(§s[i]->rellen, + sects[i]->head); + + /* + * Now output the section header table. + */ + + elf_foffs = 0x40 + 0x28 * nsections; + align = ((elf_foffs + SEG_ALIGN_1) & ~SEG_ALIGN_1) - elf_foffs; + elf_foffs += align; + elf_nsect = 0; + elf_sects = nasm_malloc(sizeof(*elf_sects) * (2 * nsects + 10)); + + elf_section_header(0, 0, 0, NULL, FALSE, 0L, 0, 0, 0, 0); /* SHN_UNDEF */ + scount = 1; /* needed for the stabs debugging to track the symtable section */ + p = shstrtab + 1; + for (i = 0; i < nsects; i++) { + elf_section_header(p - shstrtab, sects[i]->type, sects[i]->flags, + (sects[i]->type == SHT_PROGBITS ? + sects[i]->data : NULL), TRUE, + sects[i]->len, 0, 0, sects[i]->align, 0); + p += strlen(p) + 1; + scount++; /* dito */ + } + elf_section_header(p - shstrtab, 1, 0, comment, FALSE, (long)commlen, 0, 0, 1, 0); /* .comment */ + scount++; /* dito */ + p += strlen(p) + 1; + elf_section_header(p - shstrtab, 3, 0, shstrtab, FALSE, (long)shstrtablen, 0, 0, 1, 0); /* .shstrtab */ + scount++; /* dito */ + p += strlen(p) + 1; + elf_section_header(p - shstrtab, 2, 0, symtab, TRUE, symtablen, nsects + 4, symtablocal, 4, 16); /* .symtab */ + symtabsection = scount; /* now we got the symtab section index in the ELF file */ + p += strlen(p) + 1; + elf_section_header(p - shstrtab, 3, 0, strs, TRUE, strslen, 0, 0, 1, 0); /* .strtab */ + for (i = 0; i < nsects; i++) + if (sects[i]->head) { + p += strlen(p) + 1; + elf_section_header(p - shstrtab, 9, 0, sects[i]->rel, TRUE, + sects[i]->rellen, nsects + 3, i + 1, 4, 8); + } + if (of_elf.current_dfmt == &df_stabs) { + /* for debugging information, create the last three sections + which are the .stab , .stabstr and .rel.stab sections respectively */ + + /* this function call creates the stab sections in memory */ + stabs_generate(); + + if ((stabbuf) && (stabstrbuf) && (stabrelbuf)) { + p += strlen(p) + 1; + elf_section_header(p - shstrtab, 1, 0, stabbuf, 0, stablen, + nsections - 2, 0, 4, 12); + + p += strlen(p) + 1; + elf_section_header(p - shstrtab, 3, 0, stabstrbuf, 0, + stabstrlen, 0, 0, 4, 0); + + p += strlen(p) + 1; + /* link -> symtable info -> section to refer to */ + elf_section_header(p - shstrtab, 9, 0, stabrelbuf, 0, + stabrellen, symtabsection, nsections - 3, 4, + 8); + } + } + fwrite(align_str, align, 1, elffp); + + /* + * Now output the sections. + */ + elf_write_sections(); + + nasm_free(elf_sects); + saa_free(symtab); +} + +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 struct SAA *elf_build_reltab(long *len, struct Reloc *r) +{ + struct SAA *s; + unsigned char *p, entry[8]; + + if (!r) + return NULL; + + s = saa_init(1L); + *len = 0; + + while (r) { + long sym = r->symbol; + + if (sym >= GLOBAL_TEMP_BASE) + sym += -GLOBAL_TEMP_BASE + (nsects + 3) + nlocals; + + p = entry; + WRITELONG(p, r->address); + WRITELONG(p, (sym << 8) + r->type); + saa_wbytes(s, entry, 8L); + *len += 8; + + r = r->next; + } + + return s; +} + +static void elf_section_header(int name, int type, int flags, + void *data, int is_saa, long datalen, + int link, int info, int align, int eltsize) +{ + elf_sects[elf_nsect].data = data; + elf_sects[elf_nsect].len = datalen; + elf_sects[elf_nsect].is_saa = is_saa; + elf_nsect++; + + fwritelong((long)name, elffp); + fwritelong((long)type, elffp); + fwritelong((long)flags, elffp); + fwritelong(0L, elffp); /* no address, ever, in object files */ + fwritelong(type == 0 ? 0L : elf_foffs, elffp); + fwritelong(datalen, elffp); + if (data) + elf_foffs += (datalen + SEG_ALIGN_1) & ~SEG_ALIGN_1; + fwritelong((long)link, elffp); + fwritelong((long)info, elffp); + fwritelong((long)align, elffp); + fwritelong((long)eltsize, elffp); +} + +static void elf_write_sections(void) +{ + int i; + for (i = 0; i < elf_nsect; i++) + if (elf_sects[i].data) { + long len = elf_sects[i].len; + long reallen = (len + SEG_ALIGN_1) & ~SEG_ALIGN_1; + long align = reallen - len; + if (elf_sects[i].is_saa) + saa_fpwrite(elf_sects[i].data, elffp); + else + fwrite(elf_sects[i].data, len, 1, elffp); + fwrite(align_str, align, 1, elffp); + } +} + +static void elf_sect_write(struct Section *sect, + const unsigned char *data, unsigned long len) +{ + saa_wbytes(sect->data, data, len); + sect->len += len; +} + +static long elf_segbase(long segment) +{ + return segment; +} + +static int elf_directive(char *directive, char *value, int pass) +{ + return 0; +} + +static void elf_filename(char *inname, char *outname, efunc error) +{ + strcpy(elf_module, inname); + standard_extension(inname, outname, ".o", error); +} + +static const char *elf_stdmac[] = { + "%define __SECT__ [section .text]", + "%macro __NASM_CDecl__ 1", + "%define $_%1 $%1", + "%endmacro", + NULL +}; +static int elf_set_info(enum geninfo type, char **val) +{ + return 0; +} + +static struct dfmt df_stabs = { + "ELF32 (i386) stabs debug format for Linux", + "stabs", + stabs_init, + stabs_linenum, + stabs_deflabel, + stabs_directive, + stabs_typevalue, + stabs_output, + stabs_cleanup +}; + +struct dfmt *elf_debugs_arr[2] = { &df_stabs, NULL }; + +struct ofmt of_elf = { + "ELF32 (i386) object files (e.g. Linux)", + "elf", + NULL, + elf_debugs_arr, + &null_debug_form, + elf_stdmac, + elf_init, + elf_set_info, + elf_out, + elf_deflabel, + elf_section_names, + elf_segbase, + elf_directive, + elf_filename, + elf_cleanup +}; + +/* again, the stabs debugging stuff (code) */ + +void stabs_init(struct ofmt *of, void *id, FILE * fp, efunc error) +{ +} + +void stabs_linenum(const char *filename, long linenumber, long segto) +{ + if (!stabs_filename) { + stabs_filename = (char *)nasm_malloc(strlen(filename) + 1); + strcpy(stabs_filename, filename); + } else { + if (strcmp(stabs_filename, filename)) { + /* yep, a memory leak...this program is one-shot anyway, so who cares... + in fact, this leak comes in quite handy to maintain a list of files + encountered so far in the symbol lines... */ + + /* why not nasm_free(stabs_filename); we're done with the old one */ + + stabs_filename = (char *)nasm_malloc(strlen(filename) + 1); + strcpy(stabs_filename, filename); + } + } + stabs_immcall = 1; + currentline = linenumber; +} + +void stabs_deflabel(char *name, long segment, long offset, int is_global, + char *special) +{ +} + +void stabs_directive(const char *directive, const char *params) +{ +} + +void stabs_typevalue(long type) +{ +} + +void stabs_output(int type, void *param) +{ + struct symlininfo *s; + struct linelist *el; + if (type == TY_STABSSYMLIN) { + if (stabs_immcall) { + s = (struct symlininfo *)param; + if (strcmp(s->name, ".text")) + return; /* we are only interested in the text stuff */ + numlinestabs++; + el = (struct linelist *)nasm_malloc(sizeof(struct linelist)); + el->info.offset = s->offset; + el->info.section = s->section; + el->info.name = s->name; + el->line = currentline; + el->filename = stabs_filename; + el->next = 0; + if (stabslines) { + stabslines->last->next = el; + stabslines->last = el; + } else { + stabslines = el; + stabslines->last = el; + } + } + } + stabs_immcall = 0; +} + +#define WRITE_STAB(p,n_strx,n_type,n_other,n_desc,n_value) \ + do {\ + WRITELONG(p,n_strx); \ + WRITECHAR(p,n_type); \ + WRITECHAR(p,n_other); \ + WRITESHORT(p,n_desc); \ + WRITELONG(p,n_value); \ + } while (0) + +/* for creating the .stab , .stabstr and .rel.stab sections in memory */ + +void stabs_generate(void) +{ + int i, numfiles, strsize, numstabs = 0, currfile, mainfileindex; + unsigned char *sbuf, *ssbuf, *rbuf, *sptr, *rptr; + char **allfiles; + int *fileidx; + + struct linelist *ptr; + + ptr = stabslines; + + allfiles = (char **)nasm_malloc(numlinestabs * sizeof(char *)); + for (i = 0; i < numlinestabs; i++) + allfiles[i] = 0; + numfiles = 0; + while (ptr) { + if (numfiles == 0) { + allfiles[0] = ptr->filename; + numfiles++; + } else { + for (i = 0; i < numfiles; i++) { + if (!strcmp(allfiles[i], ptr->filename)) + break; + } + if (i >= numfiles) { + allfiles[i] = ptr->filename; + numfiles++; + } + } + ptr = ptr->next; + } + strsize = 1; + fileidx = (int *)nasm_malloc(numfiles * sizeof(int)); + for (i = 0; i < numfiles; i++) { + fileidx[i] = strsize; + strsize += strlen(allfiles[i]) + 1; + } + mainfileindex = 0; + for (i = 0; i < numfiles; i++) { + if (!strcmp(allfiles[i], elf_module)) { + mainfileindex = i; + break; + } + } + + /* worst case size of the stab buffer would be: + the sourcefiles changes each line, which would mean 1 SOL, 1 SYMLIN per line + */ + sbuf = + (unsigned char *)nasm_malloc((numlinestabs * 2 + 3) * + sizeof(struct stabentry)); + + ssbuf = (unsigned char *)nasm_malloc(strsize); + + rbuf = (unsigned char *)nasm_malloc(numlinestabs * 8 * (2 + 3)); + rptr = rbuf; + + for (i = 0; i < numfiles; i++) { + strcpy((char *)ssbuf + fileidx[i], allfiles[i]); + } + ssbuf[0] = 0; + + stabstrlen = strsize; /* set global variable for length of stab strings */ + + sptr = sbuf; + /* this is the first stab, its strx points to the filename of the + the source-file, the n_desc field should be set to the number + of remaining stabs + */ + WRITE_STAB(sptr, fileidx[0], 0, 0, 0, strlen(allfiles[0] + 12)); + + ptr = stabslines; + numstabs = 0; + + if (ptr) { + /* this is the stab for the main source file */ + WRITE_STAB(sptr, fileidx[mainfileindex], N_SO, 0, 0, 0); + + /* relocation stuff */ + /* IS THIS SANE? WHAT DOES SECTION+3 MEAN HERE? */ + WRITELONG(rptr, (sptr - sbuf) - 4); + WRITELONG(rptr, ((ptr->info.section + 3) << 8) | R_386_32); + + numstabs++; + currfile = mainfileindex; + } + + while (ptr) { + if (strcmp(allfiles[currfile], ptr->filename)) { + /* oops file has changed... */ + for (i = 0; i < numfiles; i++) + if (!strcmp(allfiles[i], ptr->filename)) + break; + currfile = i; + WRITE_STAB(sptr, fileidx[currfile], N_SOL, 0, 0, + ptr->info.offset); + numstabs++; + + /* relocation stuff */ + /* IS THIS SANE? WHAT DOES SECTION+3 MEAN HERE? */ + WRITELONG(rptr, (sptr - sbuf) - 4); + WRITELONG(rptr, ((ptr->info.section + 3) << 8) | R_386_32); + } + + WRITE_STAB(sptr, 0, N_SLINE, 0, ptr->line, ptr->info.offset); + numstabs++; + + /* relocation stuff */ + /* IS THIS SANE? WHAT DOES SECTION+3 MEAN HERE? */ + WRITELONG(rptr, (sptr - sbuf) - 4); + WRITELONG(rptr, ((ptr->info.section + 3) << 8) | R_386_32); + + ptr = ptr->next; + + } + + ((struct stabentry *)sbuf)->n_desc = numstabs; + + nasm_free(allfiles); + nasm_free(fileidx); + + stablen = (sptr - sbuf); + stabrellen = (rptr - rbuf); + stabrelbuf = rbuf; + stabbuf = sbuf; + stabstrbuf = ssbuf; +} + +void stabs_cleanup() +{ + struct linelist *ptr, *del; + if (!stabslines) + return; + ptr = stabslines; + while (ptr) { + del = ptr; + ptr = ptr->next; + nasm_free(del); + } + if (stabbuf) + nasm_free(stabbuf); + if (stabrelbuf) + nasm_free(stabrelbuf); + if (stabstrbuf) + nasm_free(stabstrbuf); +} + +#endif /* OF_ELF */ diff --git a/output/outieee.c b/output/outieee.c index a8cb6cd8..7d723900 100644 --- a/output/outieee.c +++ b/output/outieee.c @@ -40,7 +40,7 @@ #include #include #include -#include /* Note: we need the ANSI version of stdarg.h */ +#include /* Note: we need the ANSI version of stdarg.h */ #include #include "nasm.h" @@ -60,9 +60,9 @@ static FILE *ofp; static int any_segs; static int arrindex; -#define HUNKSIZE 1024 /* Size of the data hunk */ +#define HUNKSIZE 1024 /* Size of the data hunk */ #define EXT_BLKSIZ 512 -#define LDPERLINE 32 /* bytes per line in output */ +#define LDPERLINE 32 /* bytes per line in output */ struct ieeeSection; @@ -89,9 +89,9 @@ static struct ieeePublic { struct ieeePublic *next; char *name; long offset; - long segment; /* only if it's far-absolute */ + long segment; /* only if it's far-absolute */ long index; - int type; /* for debug purposes */ + int type; /* for debug purposes */ } *fpubhead, **fpubtail, *last_defined; static struct ieeeExternal { @@ -109,20 +109,20 @@ static struct ExtBack { /* NOTE: the first segment MUST be the lineno segment */ static struct ieeeSection { - struct ieeeObjData *data,*datacurr; + struct ieeeObjData *data, *datacurr; struct ieeeSection *next; - struct ieeeFixupp *fptr, * flptr; - long index; /* the NASM segment id */ - long ieee_index; /* the OBJ-file segment index */ + struct ieeeFixupp *fptr, *flptr; + long index; /* the NASM segment id */ + long ieee_index; /* the OBJ-file segment index */ long currentpos; - long align; /* can be SEG_ABS + absolute addr */ + long align; /* can be SEG_ABS + absolute addr */ long startpos; enum { - CMB_PRIVATE = 0, - CMB_PUBLIC = 2, - CMB_COMMON = 6 + CMB_PRIVATE = 0, + CMB_PUBLIC = 2, + CMB_COMMON = 6 } combine; - long use32; /* is this segment 32-bit? */ + long use32; /* is this segment 32-bit? */ struct ieeePublic *pubhead, **pubtail, *lochead, **loctail; char *name; } *seghead, **segtail, *ieee_seg_needs_update; @@ -134,15 +134,15 @@ struct ieeeObjData { struct ieeeFixupp { struct ieeeFixupp *next; - enum { - FT_SEG = 0, - FT_REL = 1, - FT_OFS = 2, - FT_EXT = 3, - FT_WRT = 4, - FT_EXTREL = 5, - FT_EXTWRT = 6, - FT_EXTSEG = 7 + enum { + FT_SEG = 0, + FT_REL = 1, + FT_OFS = 2, + FT_EXT = 3, + FT_WRT = 4, + FT_EXTREL = 5, + FT_EXTWRT = 6, + FT_EXTSEG = 7 } ftype; short size; long id1; @@ -150,17 +150,17 @@ struct ieeeFixupp { long offset; long addend; }; - + static long ieee_entry_seg, ieee_entry_ofs; static int checksum; extern struct ofmt of_ieee; static void ieee_data_new(struct ieeeSection *); -static void ieee_write_fixup (long, long, struct ieeeSection *, - int, unsigned long, long); +static void ieee_write_fixup(long, long, struct ieeeSection *, + int, unsigned long, long); static void ieee_install_fixup(struct ieeeSection *, struct ieeeFixupp *); -static long ieee_segment (char *, int, int *); +static long ieee_segment(char *, int, int *); static void ieee_write_file(int debuginfo); static void ieee_write_byte(struct ieeeSection *, int); static void ieee_write_word(struct ieeeSection *, int); @@ -171,13 +171,12 @@ static long ieee_putld(long, long, unsigned char *); static long ieee_putlr(struct ieeeFixupp *); static void ieee_unqualified_name(char *, char *); - /* * pup init */ -static void ieee_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +static void ieee_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval) { - (void) eval; + (void)eval; ofp = fp; error = errfunc; deflabel = ldef; @@ -194,64 +193,67 @@ static void ieee_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) ieee_entry_seg = NO_SEG; ieee_uppercase = FALSE; checksum = 0; - of_ieee.current_dfmt->init (&of_ieee,NULL,fp,errfunc); + of_ieee.current_dfmt->init(&of_ieee, NULL, fp, errfunc); } static int ieee_set_info(enum geninfo type, char **val) { - (void) type; - (void) val; + (void)type; + (void)val; return 0; } + /* * Rundown */ -static void ieee_cleanup (int debuginfo) +static void ieee_cleanup(int debuginfo) { ieee_write_file(debuginfo); - of_ieee.current_dfmt->cleanup (); - fclose (ofp); + of_ieee.current_dfmt->cleanup(); + fclose(ofp); while (seghead) { - struct ieeeSection *segtmp = seghead; - seghead = seghead->next; - while (segtmp->pubhead) { - struct ieeePublic *pubtmp = segtmp->pubhead; - segtmp->pubhead = pubtmp->next; - nasm_free (pubtmp); - } - while (segtmp->fptr) { - struct ieeeFixupp *fixtmp = segtmp->fptr; - segtmp->fptr = fixtmp->next; - nasm_free(fixtmp); - } - while (segtmp->data) { - struct ieeeObjData *dattmp = segtmp->data; - segtmp->data = dattmp->next; - nasm_free(dattmp); - } - nasm_free (segtmp); + struct ieeeSection *segtmp = seghead; + seghead = seghead->next; + while (segtmp->pubhead) { + struct ieeePublic *pubtmp = segtmp->pubhead; + segtmp->pubhead = pubtmp->next; + nasm_free(pubtmp); + } + while (segtmp->fptr) { + struct ieeeFixupp *fixtmp = segtmp->fptr; + segtmp->fptr = fixtmp->next; + nasm_free(fixtmp); + } + while (segtmp->data) { + struct ieeeObjData *dattmp = segtmp->data; + segtmp->data = dattmp->next; + nasm_free(dattmp); + } + nasm_free(segtmp); } while (fpubhead) { - struct ieeePublic *pubtmp = fpubhead; - fpubhead = fpubhead->next; - nasm_free (pubtmp); + struct ieeePublic *pubtmp = fpubhead; + fpubhead = fpubhead->next; + nasm_free(pubtmp); } while (exthead) { - struct ieeeExternal *exttmp = exthead; - exthead = exthead->next; - nasm_free (exttmp); + struct ieeeExternal *exttmp = exthead; + exthead = exthead->next; + nasm_free(exttmp); } while (ebhead) { - struct ExtBack *ebtmp = ebhead; - ebhead = ebhead->next; - nasm_free (ebtmp); + struct ExtBack *ebtmp = ebhead; + ebhead = ebhead->next; + nasm_free(ebtmp); } } + /* * callback for labels */ -static void ieee_deflabel (char *name, long segment, - long offset, int is_global, char *special) { +static void ieee_deflabel(char *name, long segment, + long offset, int is_global, char *special) +{ /* * We have three cases: * @@ -279,56 +281,56 @@ static void ieee_deflabel (char *name, long segment, * unusual. */ if (name[0] == '.' && name[1] == '.') { - if (!strcmp(name, "..start")) { - ieee_entry_seg = segment; - ieee_entry_ofs = offset; - } - return; + if (!strcmp(name, "..start")) { + ieee_entry_seg = segment; + ieee_entry_ofs = offset; + } + return; } /* * Case (i): */ if (ieee_seg_needs_update) { - ieee_seg_needs_update->name = name; - return; - } + ieee_seg_needs_update->name = name; + return; + } if (segment < SEG_ABS && segment != NO_SEG && segment % 2) - return; + return; /* * case (ii) */ if (segment >= SEG_ABS) { - /* - * SEG_ABS subcase of (ii). - */ - if (is_global) { - struct ieeePublic *pub; - - pub = *fpubtail = nasm_malloc(sizeof(*pub)); - fpubtail = &pub->next; - pub->next = NULL; - pub->name = name; - pub->offset = offset; - pub->segment = segment & ~SEG_ABS; - } - return; + /* + * SEG_ABS subcase of (ii). + */ + if (is_global) { + struct ieeePublic *pub; + + pub = *fpubtail = nasm_malloc(sizeof(*pub)); + fpubtail = &pub->next; + pub->next = NULL; + pub->name = name; + pub->offset = offset; + pub->segment = segment & ~SEG_ABS; + } + return; } for (seg = seghead; seg && is_global; seg = seg->next) - if (seg->index == segment) { - struct ieeePublic *pub; - - last_defined = pub = *seg->pubtail = nasm_malloc(sizeof(*pub)); - seg->pubtail = &pub->next; - pub->next = NULL; - pub->name = name; - pub->offset = offset; - pub->index = seg->ieee_index; - pub->segment = -1; - return; - } + if (seg->index == segment) { + struct ieeePublic *pub; + + last_defined = pub = *seg->pubtail = nasm_malloc(sizeof(*pub)); + seg->pubtail = &pub->next; + pub->next = NULL; + pub->name = name; + pub->offset = offset; + pub->index = seg->ieee_index; + pub->segment = -1; + return; + } /* * Case (iii). @@ -339,36 +341,37 @@ static void ieee_deflabel (char *name, long segment, exttail = &ext->next; ext->name = name; if (is_global == 2) - ext->commonsize = offset; - else - ext->commonsize = 0; - i = segment/2; - eb = ebhead; - if (!eb) { - eb = *ebtail = nasm_malloc(sizeof(*eb)); - eb->next = NULL; - ebtail = &eb->next; + ext->commonsize = offset; + else + ext->commonsize = 0; + i = segment / 2; + eb = ebhead; + if (!eb) { + eb = *ebtail = nasm_malloc(sizeof(*eb)); + eb->next = NULL; + ebtail = &eb->next; + } + while (i > EXT_BLKSIZ) { + if (eb && eb->next) + eb = eb->next; + else { + eb = *ebtail = nasm_malloc(sizeof(*eb)); + eb->next = NULL; + ebtail = &eb->next; + } + i -= EXT_BLKSIZ; } - while (i > EXT_BLKSIZ) { - if (eb && eb->next) - eb = eb->next; - else { - eb = *ebtail = nasm_malloc(sizeof(*eb)); - eb->next = NULL; - ebtail = &eb->next; - } - i -= EXT_BLKSIZ; - } eb->index[i] = externals++; } - + } /* * Put data out */ -static void ieee_out (long segto, const void *data, unsigned long type, - long segment, long wrt) { +static void ieee_out(long segto, const void *data, unsigned long type, + long segment, long wrt) +{ unsigned long size, realtype; const unsigned char *ucdata; long ldata; @@ -378,10 +381,10 @@ static void ieee_out (long segto, const void *data, unsigned long type, * handle absolute-assembly (structure definitions) */ if (segto == NO_SEG) { - if ((type & OUT_TYPMASK) != OUT_RESERVE) - error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" - " space"); - return; + if ((type & OUT_TYPMASK) != OUT_RESERVE) + error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" + " space"); + return; } /* @@ -389,269 +392,266 @@ static void ieee_out (long segto, const void *data, unsigned long type, * segment. */ if (!any_segs) { - int tempint; /* ignored */ - if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint)) - error (ERR_PANIC, "strange segment conditions in IEEE driver"); + int tempint; /* ignored */ + if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint)) + error(ERR_PANIC, "strange segment conditions in IEEE driver"); } /* * Find the segment we are targetting. */ for (seg = seghead; seg; seg = seg->next) - if (seg->index == segto) - break; + if (seg->index == segto) + break; if (!seg) - error (ERR_PANIC, "code directed to nonexistent segment?"); + error(ERR_PANIC, "code directed to nonexistent segment?"); size = type & OUT_SIZMASK; realtype = type & OUT_TYPMASK; if (realtype == OUT_RAWDATA) { - ucdata = data; - while (size--) - ieee_write_byte(seg,*ucdata++); + ucdata = data; + while (size--) + ieee_write_byte(seg, *ucdata++); } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR || - realtype == OUT_REL4ADR) { - if (segment == NO_SEG && realtype != OUT_ADDRESS) - error(ERR_NONFATAL, "relative call to absolute address not" - " supported by IEEE format"); - ldata = *(long *)data; - if (realtype == OUT_REL2ADR) - ldata += (size-2); - if (realtype == OUT_REL4ADR) - ldata += (size-4); - ieee_write_fixup (segment, wrt, seg, size, realtype,ldata); - if (size == 2) - ieee_write_word (seg, ldata); - else - ieee_write_dword (seg, ldata); - } - else if (realtype == OUT_RESERVE) { - while (size--) - ieee_write_byte(seg,0); + realtype == OUT_REL4ADR) { + if (segment == NO_SEG && realtype != OUT_ADDRESS) + error(ERR_NONFATAL, "relative call to absolute address not" + " supported by IEEE format"); + ldata = *(long *)data; + if (realtype == OUT_REL2ADR) + ldata += (size - 2); + if (realtype == OUT_REL4ADR) + ldata += (size - 4); + ieee_write_fixup(segment, wrt, seg, size, realtype, ldata); + if (size == 2) + ieee_write_word(seg, ldata); + else + ieee_write_dword(seg, ldata); + } else if (realtype == OUT_RESERVE) { + while (size--) + ieee_write_byte(seg, 0); } } -static void ieee_data_new(struct ieeeSection *segto) { - +static void ieee_data_new(struct ieeeSection *segto) +{ + if (!segto->data) - segto->data = segto->datacurr = nasm_malloc(sizeof(*(segto->datacurr))); + segto->data = segto->datacurr = + nasm_malloc(sizeof(*(segto->datacurr))); else - segto->datacurr = segto->datacurr->next = nasm_malloc(sizeof(*(segto->datacurr))); + segto->datacurr = segto->datacurr->next = + nasm_malloc(sizeof(*(segto->datacurr))); segto->datacurr->next = NULL; } - /* * this routine is unalduterated bloatware. I usually don't do this * but I might as well see what it is like on a harmless program. * If anyone wants to optimize this is a good canditate! */ -static void ieee_write_fixup (long segment, long wrt, struct ieeeSection * segto, - int size, unsigned long realtype, long offset) { +static void ieee_write_fixup(long segment, long wrt, + struct ieeeSection *segto, int size, + unsigned long realtype, long offset) +{ struct ieeeSection *target; struct ieeeFixupp s; /* Don't put a fixup for things NASM can calculate */ if (wrt == NO_SEG && segment == NO_SEG) - return; + return; s.ftype = -1; /* if it is a WRT offset */ if (wrt != NO_SEG) { - s.ftype = FT_WRT; - s.addend = offset; - if (wrt >= SEG_ABS) - s.id1 = -(wrt-SEG_ABS); - else { - if (wrt %2 && realtype != OUT_REL2ADR && realtype != OUT_REL4ADR) { - wrt--; - - for (target = seghead; target; target = target->next) - if (target->index == wrt) - break; - if (target) { - s.id1 = target->ieee_index; - for (target = seghead; target; target = target->next) - if (target->index == segment) - break; - - if (target) - s.id2 = target->ieee_index; - else { - /* - * Now we assume the segment field is being used - * to hold an extern index - */ - long i = segment/2; - struct ExtBack *eb = ebhead; - while (i > EXT_BLKSIZ) { - if (eb) - eb = eb->next; - else - break; - i -= EXT_BLKSIZ; - } - /* if we have an extern decide the type and make a record - */ - if (eb) { - s.ftype = FT_EXTWRT; - s.addend = 0; - s.id2 = eb->index[i]; - } - else - error(ERR_NONFATAL, - "Source of WRT must be an offset"); - } - - } - else - error(ERR_PANIC, - "unrecognised WRT value in ieee_write_fixup"); - } - else - error(ERR_NONFATAL,"target of WRT must be a section "); - } - s.size = size; - ieee_install_fixup(segto,&s); - return; + s.ftype = FT_WRT; + s.addend = offset; + if (wrt >= SEG_ABS) + s.id1 = -(wrt - SEG_ABS); + else { + if (wrt % 2 && realtype != OUT_REL2ADR + && realtype != OUT_REL4ADR) { + wrt--; + + for (target = seghead; target; target = target->next) + if (target->index == wrt) + break; + if (target) { + s.id1 = target->ieee_index; + for (target = seghead; target; target = target->next) + if (target->index == segment) + break; + + if (target) + s.id2 = target->ieee_index; + else { + /* + * Now we assume the segment field is being used + * to hold an extern index + */ + long i = segment / 2; + struct ExtBack *eb = ebhead; + while (i > EXT_BLKSIZ) { + if (eb) + eb = eb->next; + else + break; + i -= EXT_BLKSIZ; + } + /* if we have an extern decide the type and make a record + */ + if (eb) { + s.ftype = FT_EXTWRT; + s.addend = 0; + s.id2 = eb->index[i]; + } else + error(ERR_NONFATAL, + "Source of WRT must be an offset"); + } + + } else + error(ERR_PANIC, + "unrecognised WRT value in ieee_write_fixup"); + } else + error(ERR_NONFATAL, "target of WRT must be a section "); + } + s.size = size; + ieee_install_fixup(segto, &s); + return; } /* Pure segment fixup ? */ if (segment != NO_SEG) { - s.ftype = FT_SEG; - s.id1 = 0; - if (segment >= SEG_ABS) { - /* absolute far segment fixup */ - s.id1 = -(segment -~SEG_ABS); - } - else if (segment % 2) { - /* fixup to named segment */ - /* look it up */ - for (target = seghead; target; target = target->next) - if (target->index == segment-1) - break; - if (target) - s.id1 = target->ieee_index; - else { - /* - * Now we assume the segment field is being used - * to hold an extern index - */ - long i = segment/2; - struct ExtBack *eb = ebhead; - while (i > EXT_BLKSIZ) { - if (eb) - eb = eb->next; - else - break; - i -= EXT_BLKSIZ; - } - /* if we have an extern decide the type and make a record - */ - if (eb) { - if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { - error(ERR_PANIC,"Segment of a rel not supported in ieee_write_fixup"); - } - else { - /* If we want the segment */ - s.ftype = FT_EXTSEG; - s.addend = 0; - s.id1 = eb->index[i]; - } - - } - else - /* If we get here the seg value doesn't make sense */ - error(ERR_PANIC, - "unrecognised segment value in ieee_write_fixup"); - } + s.ftype = FT_SEG; + s.id1 = 0; + if (segment >= SEG_ABS) { + /* absolute far segment fixup */ + s.id1 = -(segment - ~SEG_ABS); + } else if (segment % 2) { + /* fixup to named segment */ + /* look it up */ + for (target = seghead; target; target = target->next) + if (target->index == segment - 1) + break; + if (target) + s.id1 = target->ieee_index; + else { + /* + * Now we assume the segment field is being used + * to hold an extern index + */ + long i = segment / 2; + struct ExtBack *eb = ebhead; + while (i > EXT_BLKSIZ) { + if (eb) + eb = eb->next; + else + break; + i -= EXT_BLKSIZ; + } + /* if we have an extern decide the type and make a record + */ + if (eb) { + if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { + error(ERR_PANIC, + "Segment of a rel not supported in ieee_write_fixup"); + } else { + /* If we want the segment */ + s.ftype = FT_EXTSEG; + s.addend = 0; + s.id1 = eb->index[i]; + } + + } else + /* If we get here the seg value doesn't make sense */ + error(ERR_PANIC, + "unrecognised segment value in ieee_write_fixup"); + } } else { - /* Assume we are offsetting directly from a section - * So look up the target segment - */ - for (target = seghead; target; target = target->next) - if (target->index == segment) - break; - if (target) { - if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { - /* PC rel to a known offset */ - s.id1 = target->ieee_index; - s.ftype = FT_REL; - s.size = size; - s.addend = offset; - } - else { - /* We were offsetting from a seg */ - s.id1 = target->ieee_index; - s.ftype = FT_OFS; - s.size = size; - s.addend = offset; - } - } - else { - /* - * Now we assume the segment field is being used - * to hold an extern index - */ - long i = segment/2; - struct ExtBack *eb = ebhead; - while (i > EXT_BLKSIZ) { - if (eb) - eb = eb->next; - else - break; - i -= EXT_BLKSIZ; - } - /* if we have an extern decide the type and make a record - */ - if (eb) { - if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { - s.ftype = FT_EXTREL; - s.addend = 0; - s.id1 = eb->index[i]; - } - else { - /* else we want the external offset */ - s.ftype = FT_EXT; - s.addend = 0; - s.id1 = eb->index[i]; - } - - } - else - /* If we get here the seg value doesn't make sense */ - error(ERR_PANIC, - "unrecognised segment value in ieee_write_fixup"); - } - } - if (size != 2 && s.ftype == FT_SEG) - error(ERR_NONFATAL, "IEEE format can only handle 2-byte" - " segment base references"); - s.size = size; - ieee_install_fixup(segto,&s); - return; + /* Assume we are offsetting directly from a section + * So look up the target segment + */ + for (target = seghead; target; target = target->next) + if (target->index == segment) + break; + if (target) { + if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { + /* PC rel to a known offset */ + s.id1 = target->ieee_index; + s.ftype = FT_REL; + s.size = size; + s.addend = offset; + } else { + /* We were offsetting from a seg */ + s.id1 = target->ieee_index; + s.ftype = FT_OFS; + s.size = size; + s.addend = offset; + } + } else { + /* + * Now we assume the segment field is being used + * to hold an extern index + */ + long i = segment / 2; + struct ExtBack *eb = ebhead; + while (i > EXT_BLKSIZ) { + if (eb) + eb = eb->next; + else + break; + i -= EXT_BLKSIZ; + } + /* if we have an extern decide the type and make a record + */ + if (eb) { + if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { + s.ftype = FT_EXTREL; + s.addend = 0; + s.id1 = eb->index[i]; + } else { + /* else we want the external offset */ + s.ftype = FT_EXT; + s.addend = 0; + s.id1 = eb->index[i]; + } + + } else + /* If we get here the seg value doesn't make sense */ + error(ERR_PANIC, + "unrecognised segment value in ieee_write_fixup"); + } + } + if (size != 2 && s.ftype == FT_SEG) + error(ERR_NONFATAL, "IEEE format can only handle 2-byte" + " segment base references"); + s.size = size; + ieee_install_fixup(segto, &s); + return; } /* should never get here */ } -static void ieee_install_fixup(struct ieeeSection *seg, struct ieeeFixupp *fix) +static void ieee_install_fixup(struct ieeeSection *seg, + struct ieeeFixupp *fix) { struct ieeeFixupp *f; f = nasm_malloc(sizeof(struct ieeeFixupp)); - memcpy(f,fix,sizeof(struct ieeeFixupp)); + memcpy(f, fix, sizeof(struct ieeeFixupp)); f->offset = seg->currentpos; seg->currentpos += fix->size; f->next = NULL; if (seg->fptr) - seg->flptr = seg->flptr->next = f; + seg->flptr = seg->flptr->next = f; else - seg->fptr = seg->flptr = f; + seg->fptr = seg->flptr = f; } /* * segment registry */ -static long ieee_segment (char *name, int pass, int *bits) { +static long ieee_segment(char *name, int pass, int *bits) +{ /* * We call the label manager here to define a name for the new * segment, and when our _own_ label-definition stub gets @@ -660,163 +660,166 @@ static long ieee_segment (char *name, int pass, int *bits) { * by sponging off the label manager. */ if (!name) { - *bits = 16; - if (!any_segs) - return 0; - return seghead->index; + *bits = 16; + if (!any_segs) + return 0; + return seghead->index; } else { - struct ieeeSection *seg; - int ieee_idx, attrs, rn_error; - char *p; - - /* - * Look for segment attributes. - */ - attrs = 0; - while (*name == '.') - name++; /* hack, but a documented one */ - p = name; - while (*p && !isspace(*p)) - p++; - if (*p) { - *p++ = '\0'; - while (*p && isspace(*p)) - *p++ = '\0'; - } - while (*p) { - while (*p && !isspace(*p)) - p++; - if (*p) { - *p++ = '\0'; - while (*p && isspace(*p)) - *p++ = '\0'; - } - - attrs++; - } - - ieee_idx = 1; - for (seg = seghead; seg; seg = seg->next) { - ieee_idx++; - if (!strcmp(seg->name, name)) { - if (attrs > 0 && pass == 1) - error(ERR_WARNING, "segment attributes specified on" - " redeclaration of segment: ignoring"); - if (seg->use32) - *bits = 32; - else - *bits = 16; - return seg->index; - } - } - - *segtail = seg = nasm_malloc(sizeof(*seg)); - seg->next = NULL; - segtail = &seg->next; - seg->index = seg_alloc(); - seg->ieee_index = ieee_idx; - any_segs = TRUE; - seg->name = NULL; - seg->currentpos = 0; - seg->align = 1; /* default */ - seg->use32 = *bits == 32; /* default to user spec */ - seg->combine = CMB_PUBLIC; /* default */ - seg->pubhead = NULL; - seg->pubtail = &seg->pubhead; - seg->data = NULL; - seg->fptr = NULL; - seg->lochead = NULL; - seg->loctail = &seg->lochead; - - /* - * Process the segment attributes. - */ - p = name; - while (attrs--) { - p += strlen(p); - while (!*p) p++; - - /* - * `p' contains a segment attribute. - */ - if (!nasm_stricmp(p, "private")) - seg->combine = CMB_PRIVATE; - else if (!nasm_stricmp(p, "public")) - seg->combine = CMB_PUBLIC; - else if (!nasm_stricmp(p, "common")) - seg->combine = CMB_COMMON; - else if (!nasm_stricmp(p, "use16")) - seg->use32 = FALSE; - else if (!nasm_stricmp(p, "use32")) - seg->use32 = TRUE; - else if (!nasm_strnicmp(p, "align=", 6)) { - seg->align = readnum(p+6, &rn_error); - if (seg->align == 0) - seg->align = 1; - if (rn_error) { - seg->align = 1; - error (ERR_NONFATAL, "segment alignment should be" - " numeric"); - } - switch ((int) seg->align) { - case 1: /* BYTE */ - case 2: /* WORD */ - case 4: /* DWORD */ - case 16: /* PARA */ - case 256: /* PAGE */ - case 8: - case 32: - case 64: - case 128: - break; - default: - error(ERR_NONFATAL, "invalid alignment value %d", - seg->align); - seg->align = 1; - break; - } - } else if (!nasm_strnicmp(p, "absolute=", 9)) { - seg->align = SEG_ABS + readnum(p+9, &rn_error); - if (rn_error) - error (ERR_NONFATAL, "argument to `absolute' segment" - " attribute should be numeric"); - } - } - - ieee_seg_needs_update = seg; - if (seg->align >= SEG_ABS) - deflabel (name, NO_SEG, seg->align - SEG_ABS, - NULL, FALSE, FALSE, &of_ieee, error); - else - deflabel (name, seg->index+1, 0L, - NULL, FALSE, FALSE, &of_ieee, error); - ieee_seg_needs_update = NULL; - - if (seg->use32) - *bits = 32; - else - *bits = 16; - return seg->index; + struct ieeeSection *seg; + int ieee_idx, attrs, rn_error; + char *p; + + /* + * Look for segment attributes. + */ + attrs = 0; + while (*name == '.') + name++; /* hack, but a documented one */ + p = name; + while (*p && !isspace(*p)) + p++; + if (*p) { + *p++ = '\0'; + while (*p && isspace(*p)) + *p++ = '\0'; + } + while (*p) { + while (*p && !isspace(*p)) + p++; + if (*p) { + *p++ = '\0'; + while (*p && isspace(*p)) + *p++ = '\0'; + } + + attrs++; + } + + ieee_idx = 1; + for (seg = seghead; seg; seg = seg->next) { + ieee_idx++; + if (!strcmp(seg->name, name)) { + if (attrs > 0 && pass == 1) + error(ERR_WARNING, "segment attributes specified on" + " redeclaration of segment: ignoring"); + if (seg->use32) + *bits = 32; + else + *bits = 16; + return seg->index; + } + } + + *segtail = seg = nasm_malloc(sizeof(*seg)); + seg->next = NULL; + segtail = &seg->next; + seg->index = seg_alloc(); + seg->ieee_index = ieee_idx; + any_segs = TRUE; + seg->name = NULL; + seg->currentpos = 0; + seg->align = 1; /* default */ + seg->use32 = *bits == 32; /* default to user spec */ + seg->combine = CMB_PUBLIC; /* default */ + seg->pubhead = NULL; + seg->pubtail = &seg->pubhead; + seg->data = NULL; + seg->fptr = NULL; + seg->lochead = NULL; + seg->loctail = &seg->lochead; + + /* + * Process the segment attributes. + */ + p = name; + while (attrs--) { + p += strlen(p); + while (!*p) + p++; + + /* + * `p' contains a segment attribute. + */ + if (!nasm_stricmp(p, "private")) + seg->combine = CMB_PRIVATE; + else if (!nasm_stricmp(p, "public")) + seg->combine = CMB_PUBLIC; + else if (!nasm_stricmp(p, "common")) + seg->combine = CMB_COMMON; + else if (!nasm_stricmp(p, "use16")) + seg->use32 = FALSE; + else if (!nasm_stricmp(p, "use32")) + seg->use32 = TRUE; + else if (!nasm_strnicmp(p, "align=", 6)) { + seg->align = readnum(p + 6, &rn_error); + if (seg->align == 0) + seg->align = 1; + if (rn_error) { + seg->align = 1; + error(ERR_NONFATAL, "segment alignment should be" + " numeric"); + } + switch ((int)seg->align) { + case 1: /* BYTE */ + case 2: /* WORD */ + case 4: /* DWORD */ + case 16: /* PARA */ + case 256: /* PAGE */ + case 8: + case 32: + case 64: + case 128: + break; + default: + error(ERR_NONFATAL, "invalid alignment value %d", + seg->align); + seg->align = 1; + break; + } + } else if (!nasm_strnicmp(p, "absolute=", 9)) { + seg->align = SEG_ABS + readnum(p + 9, &rn_error); + if (rn_error) + error(ERR_NONFATAL, "argument to `absolute' segment" + " attribute should be numeric"); + } + } + + ieee_seg_needs_update = seg; + if (seg->align >= SEG_ABS) + deflabel(name, NO_SEG, seg->align - SEG_ABS, + NULL, FALSE, FALSE, &of_ieee, error); + else + deflabel(name, seg->index + 1, 0L, + NULL, FALSE, FALSE, &of_ieee, error); + ieee_seg_needs_update = NULL; + + if (seg->use32) + *bits = 32; + else + *bits = 16; + return seg->index; } } + /* * directives supported */ -static int ieee_directive (char *directive, char *value, int pass) +static int ieee_directive(char *directive, char *value, int pass) { - - (void) value; - (void) pass; + + (void)value; + (void)pass; if (!strcmp(directive, "uppercase")) { - ieee_uppercase = TRUE; - return 1; + ieee_uppercase = TRUE; + return 1; } return 0; } + /* * Return segment data */ -static long ieee_segbase (long segment) +static long ieee_segbase(long segment) { struct ieeeSection *seg; @@ -824,26 +827,29 @@ static long ieee_segbase (long segment) * Find the segment in our list. */ for (seg = seghead; seg; seg = seg->next) - if (seg->index == segment-1) - break; + if (seg->index == segment - 1) + break; if (!seg) - return segment; /* not one of ours - leave it alone */ + return segment; /* not one of ours - leave it alone */ if (seg->align >= SEG_ABS) - return seg->align; /* absolute segment */ + return seg->align; /* absolute segment */ - return segment; /* no special treatment */ + return segment; /* no special treatment */ } + /* * filename */ -static void ieee_filename (char *inname, char *outname, efunc error) { +static void ieee_filename(char *inname, char *outname, efunc error) +{ strcpy(ieee_infile, inname); - standard_extension (inname, outname, ".o", error); + standard_extension(inname, outname, ".o", error); } -static void ieee_write_file (int debuginfo) { +static void ieee_write_file(int debuginfo) +{ struct tm *thetime; time_t reltime; struct FileName *fn; @@ -859,12 +865,12 @@ static void ieee_write_file (int debuginfo) { /* * Write the module header */ - ieee_putascii("MBFNASM,%02X%s.\r\n",strlen(ieee_infile),ieee_infile); + ieee_putascii("MBFNASM,%02X%s.\r\n", strlen(ieee_infile), ieee_infile); /* * Write the NASM boast comment. */ - ieee_putascii("CO0,%02X%s.\r\n",strlen(boast),boast); + ieee_putascii("CO0,%02X%s.\r\n", strlen(boast), boast); /* * write processor-specific information @@ -876,16 +882,17 @@ static void ieee_write_file (int debuginfo) { */ time(&reltime); thetime = localtime(&reltime); - ieee_putascii("DT%04d%02d%02d%02d%02d%02d.\r\n", - 1900+thetime->tm_year,thetime->tm_mon+1,thetime->tm_mday, - thetime->tm_hour, thetime->tm_min, thetime->tm_sec); + ieee_putascii("DT%04d%02d%02d%02d%02d%02d.\r\n", + 1900 + thetime->tm_year, thetime->tm_mon + 1, + thetime->tm_mday, thetime->tm_hour, thetime->tm_min, + thetime->tm_sec); /* * if debugging, dump file names */ for (fn = fnhead; fn && debuginfo; fn = fn->next) { - ieee_putascii("C0105,%02X%s.\r\n",strlen(fn->name),fn->name); + ieee_putascii("C0105,%02X%s.\r\n", strlen(fn->name), fn->name); } - + ieee_putascii("CO101,07ENDHEAD.\r\n"); /* * the standard doesn't specify when to put checksums, @@ -897,48 +904,51 @@ static void ieee_write_file (int debuginfo) { * Write the section headers */ seg = seghead; - if (!debuginfo && !strcmp(seg->name,"??LINE")) - seg = seg->next; + if (!debuginfo && !strcmp(seg->name, "??LINE")) + seg = seg->next; while (seg) { - char buf[256]; - char attrib; - switch(seg->combine) { - case CMB_PUBLIC: - default: - attrib = 'C'; - break; - case CMB_PRIVATE: - attrib = 'S'; - break; - case CMB_COMMON: - attrib = 'M'; - break; - } - ieee_unqualified_name(buf,seg->name); - if (seg->align >= SEG_ABS) { - ieee_putascii("ST%X,A,%02X%s.\r\n",seg->ieee_index,strlen(buf), buf); - ieee_putascii("ASL%X,%lX.\r\n",seg->ieee_index, (seg->align - SEG_ABS)*16); - } - else { - ieee_putascii("ST%X,%c,%02X%s.\r\n",seg->ieee_index,attrib,strlen(buf), buf); - ieee_putascii("SA%X,%lX.\r\n",seg->ieee_index,seg->align); - ieee_putascii("ASS%X,%X.\r\n",seg->ieee_index, seg->currentpos); - } - seg = seg->next; + char buf[256]; + char attrib; + switch (seg->combine) { + case CMB_PUBLIC: + default: + attrib = 'C'; + break; + case CMB_PRIVATE: + attrib = 'S'; + break; + case CMB_COMMON: + attrib = 'M'; + break; + } + ieee_unqualified_name(buf, seg->name); + if (seg->align >= SEG_ABS) { + ieee_putascii("ST%X,A,%02X%s.\r\n", seg->ieee_index, + strlen(buf), buf); + ieee_putascii("ASL%X,%lX.\r\n", seg->ieee_index, + (seg->align - SEG_ABS) * 16); + } else { + ieee_putascii("ST%X,%c,%02X%s.\r\n", seg->ieee_index, attrib, + strlen(buf), buf); + ieee_putascii("SA%X,%lX.\r\n", seg->ieee_index, seg->align); + ieee_putascii("ASS%X,%X.\r\n", seg->ieee_index, + seg->currentpos); + } + seg = seg->next; } /* * write the start address if there is one */ if (ieee_entry_seg) { for (seg = seghead; seg; seg = seg->next) - if (seg->index == ieee_entry_seg) - break; - if (!seg) - error(ERR_PANIC,"Start address records are incorrect"); - else - ieee_putascii("ASG,R%X,%lX,+.\r\n",seg->ieee_index, ieee_entry_ofs); - } - + if (seg->index == ieee_entry_seg) + break; + if (!seg) + error(ERR_PANIC, "Start address records are incorrect"); + else + ieee_putascii("ASG,R%X,%lX,+.\r\n", seg->ieee_index, + ieee_entry_ofs); + } ieee_putcs(FALSE); /* @@ -947,39 +957,43 @@ static void ieee_write_file (int debuginfo) { i = 1; for (seg = seghead; seg; seg = seg->next) { for (pub = seg->pubhead; pub; pub = pub->next) { - char buf[256]; - ieee_unqualified_name(buf,pub->name); - ieee_putascii("NI%X,%02X%s.\r\n",i, strlen(buf), buf); - if (pub->segment == -1) - ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset); - else - ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset); - if (debuginfo) { - if (pub->type >= 0x100) - ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100); - else - ieee_putascii("ATI%X,%X.\r\n", i, pub->type); - } - i++; + char buf[256]; + ieee_unqualified_name(buf, pub->name); + ieee_putascii("NI%X,%02X%s.\r\n", i, strlen(buf), buf); + if (pub->segment == -1) + ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index, + pub->offset); + else + ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment * 16, + pub->offset); + if (debuginfo) { + if (pub->type >= 0x100) + ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100); + else + ieee_putascii("ATI%X,%X.\r\n", i, pub->type); + } + i++; } } pub = fpubhead; i = 1; while (pub) { - char buf[256]; - ieee_unqualified_name(buf,pub->name); - ieee_putascii("NI%X,%02X%s.\r\n",i, strlen(buf), buf); - if (pub->segment == -1) - ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset); - else - ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset); - if (debuginfo) { - if (pub->type >= 0x100) - ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100); - else - ieee_putascii("ATI%X,%X.\r\n", i, pub->type); - } - i++; + char buf[256]; + ieee_unqualified_name(buf, pub->name); + ieee_putascii("NI%X,%02X%s.\r\n", i, strlen(buf), buf); + if (pub->segment == -1) + ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index, + pub->offset); + else + ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment * 16, + pub->offset); + if (debuginfo) { + if (pub->type >= 0x100) + ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100); + else + ieee_putascii("ATI%X,%X.\r\n", i, pub->type); + } + i++; pub = pub->next; } /* @@ -988,9 +1002,9 @@ static void ieee_write_file (int debuginfo) { ext = exthead; i = 1; while (ext) { - char buf[256]; - ieee_unqualified_name(buf,ext->name); - ieee_putascii("NX%X,%02X%s.\r\n",i++, strlen(buf), buf); + char buf[256]; + ieee_unqualified_name(buf, ext->name); + ieee_putascii("NX%X,%02X%s.\r\n", i++, strlen(buf), buf); ext = ext->next; } ieee_putcs(FALSE); @@ -1006,7 +1020,8 @@ static void ieee_write_file (int debuginfo) { */ i = ARRAY_BOT; for (arr = arrhead; arr && debuginfo; arr = arr->next) { - ieee_putascii("TY%X,20,%X,%lX.\r\n",i++,arr->basetype,arr->size); + ieee_putascii("TY%X,20,%X,%lX.\r\n", i++, arr->basetype, + arr->size); } /* * now put locals @@ -1014,56 +1029,62 @@ static void ieee_write_file (int debuginfo) { i = 1; for (seg = seghead; seg && debuginfo; seg = seg->next) { for (loc = seg->lochead; loc; loc = loc->next) { - char buf[256]; - ieee_unqualified_name(buf,loc->name); - ieee_putascii("NN%X,%02X%s.\r\n",i, strlen(buf), buf); - if (loc->segment == -1) - ieee_putascii("ASN%X,R%X,%lX,+.\r\n", i, loc->index,loc->offset); - else - ieee_putascii("ASN%X,%lX,%lX,+.\r\n", i, loc->segment*16,loc->offset); - if (debuginfo) { - if (loc->type >= 0x100) - ieee_putascii("ATN%X,T%X.\r\n", i, loc->type - 0x100); - else - ieee_putascii("ATN%X,%X.\r\n", i, loc->type); - } - i++; + char buf[256]; + ieee_unqualified_name(buf, loc->name); + ieee_putascii("NN%X,%02X%s.\r\n", i, strlen(buf), buf); + if (loc->segment == -1) + ieee_putascii("ASN%X,R%X,%lX,+.\r\n", i, loc->index, + loc->offset); + else + ieee_putascii("ASN%X,%lX,%lX,+.\r\n", i, loc->segment * 16, + loc->offset); + if (debuginfo) { + if (loc->type >= 0x100) + ieee_putascii("ATN%X,T%X.\r\n", i, loc->type - 0x100); + else + ieee_putascii("ATN%X,%X.\r\n", i, loc->type); + } + i++; } } /* * put out section data; - */ + */ seg = seghead; - if (!debuginfo && !strcmp(seg->name,"??LINE")) - seg = seg->next; + if (!debuginfo && !strcmp(seg->name, "??LINE")) + seg = seg->next; while (seg) { - if (seg->currentpos) { - long size,org = 0; - data = seg->data; - ieee_putascii("SB%X.\r\n",seg->ieee_index); - fix = seg->fptr; - while (fix) { - size = HUNKSIZE - (org %HUNKSIZE); - size = size +org > seg->currentpos ? seg->currentpos-org : size; - size = fix->offset - org > size ? size : fix->offset-org; - org = ieee_putld(org,org+size,data->data); - if (org % HUNKSIZE == 0) - data = data->next; - if (org == fix->offset) { - org += ieee_putlr(fix); - fix = fix->next; - } - } - while (org < seg->currentpos && data) { - size = seg->currentpos-org > HUNKSIZE ? HUNKSIZE : seg->currentpos - org; - org = ieee_putld(org,org+size,data->data); - data = data->next; - } - ieee_putcs(FALSE); - - } - seg = seg->next; + if (seg->currentpos) { + long size, org = 0; + data = seg->data; + ieee_putascii("SB%X.\r\n", seg->ieee_index); + fix = seg->fptr; + while (fix) { + size = HUNKSIZE - (org % HUNKSIZE); + size = + size + org > + seg->currentpos ? seg->currentpos - org : size; + size = fix->offset - org > size ? size : fix->offset - org; + org = ieee_putld(org, org + size, data->data); + if (org % HUNKSIZE == 0) + data = data->next; + if (org == fix->offset) { + org += ieee_putlr(fix); + fix = fix->next; + } + } + while (org < seg->currentpos && data) { + size = + seg->currentpos - org > + HUNKSIZE ? HUNKSIZE : seg->currentpos - org; + org = ieee_putld(org, org + size, data->data); + data = data->next; + } + ieee_putcs(FALSE); + + } + seg = seg->next; } /* * module end record @@ -1071,82 +1092,84 @@ static void ieee_write_file (int debuginfo) { ieee_putascii("ME.\r\n"); } -static void ieee_write_byte(struct ieeeSection *seg, int data) { +static void ieee_write_byte(struct ieeeSection *seg, int data) +{ int temp; if (!(temp = seg->currentpos++ % HUNKSIZE)) - ieee_data_new(seg); + ieee_data_new(seg); seg->datacurr->data[temp] = data; } -static void ieee_write_word(struct ieeeSection *seg, int data) { +static void ieee_write_word(struct ieeeSection *seg, int data) +{ ieee_write_byte(seg, data & 0xFF); - ieee_write_byte(seg,(data >> 8) & 0xFF); + ieee_write_byte(seg, (data >> 8) & 0xFF); } -static void ieee_write_dword(struct ieeeSection *seg, long data) { +static void ieee_write_dword(struct ieeeSection *seg, long data) +{ ieee_write_byte(seg, data & 0xFF); - ieee_write_byte(seg,(data >> 8) & 0xFF); - ieee_write_byte(seg,(data >> 16) & 0xFF); - ieee_write_byte(seg,(data >> 24) & 0xFF); + ieee_write_byte(seg, (data >> 8) & 0xFF); + ieee_write_byte(seg, (data >> 16) & 0xFF); + ieee_write_byte(seg, (data >> 24) & 0xFF); } static void ieee_putascii(char *format, ...) { - char buffer[256]; - int i,l; - va_list ap; - - va_start(ap, format); - vsprintf(buffer, format, ap); - l = strlen(buffer); - for (i=0; i < l; i++) - if ((buffer[i] & 0xff) > 31) - checksum+=buffer[i]; - va_end(ap); - fprintf(ofp,buffer); + char buffer[256]; + int i, l; + va_list ap; + + va_start(ap, format); + vsprintf(buffer, format, ap); + l = strlen(buffer); + for (i = 0; i < l; i++) + if ((buffer[i] & 0xff) > 31) + checksum += buffer[i]; + va_end(ap); + fprintf(ofp, buffer); } /* * put out a checksum record */ static void ieee_putcs(int toclear) { - if (toclear) { - ieee_putascii("CS.\r\n"); - } - else { - checksum += 'C'; - checksum += 'S'; - ieee_putascii("CS%02X.\r\n",checksum & 127); - } - checksum = 0; + if (toclear) { + ieee_putascii("CS.\r\n"); + } else { + checksum += 'C'; + checksum += 'S'; + ieee_putascii("CS%02X.\r\n", checksum & 127); + } + checksum = 0; } static long ieee_putld(long start, long end, unsigned char *buf) { - long val; - if (start == end) - return(start); - val = start % HUNKSIZE; - /* fill up multiple lines */ - while (end - start >= LDPERLINE) { - int i; - ieee_putascii("LD"); - for (i=0; i < LDPERLINE; i++) { - ieee_putascii("%02X",buf[val++]); - start++; - } - ieee_putascii(".\r\n"); - } - /* if no partial lines */ - if (start == end) - return(start); - /* make a partial line */ - ieee_putascii("LD"); - while (start < end) { - ieee_putascii("%02X",buf[val++]); - start++; - } - ieee_putascii(".\r\n"); - return(start); + long val; + if (start == end) + return (start); + val = start % HUNKSIZE; + /* fill up multiple lines */ + while (end - start >= LDPERLINE) { + int i; + ieee_putascii("LD"); + for (i = 0; i < LDPERLINE; i++) { + ieee_putascii("%02X", buf[val++]); + start++; + } + ieee_putascii(".\r\n"); + } + /* if no partial lines */ + if (start == end) + return (start); + /* make a partial line */ + ieee_putascii("LD"); + while (start < end) { + ieee_putascii("%02X", buf[val++]); + start++; + } + ieee_putascii(".\r\n"); + return (start); } static long ieee_putlr(struct ieeeFixupp *p) { @@ -1165,74 +1188,78 @@ static long ieee_putlr(struct ieeeFixupp *p) * becomes an issue if real mode code is used. A pure 32-bit linker could * get away without defining the virtual mode... */ - char buf[40]; - long size=p->size; - switch(p->ftype) { - case FT_SEG: - if (p->id1 < 0) - sprintf(buf,"%lX",-p->id1); - else - sprintf(buf,"L%lX,10,/",p->id1); - break; - case FT_OFS: - sprintf(buf,"R%lX,%lX,+",p->id1,p->addend); - break; - case FT_REL: - sprintf(buf,"R%lX,%lX,+,P,-,%X,-",p->id1,p->addend,p->size); - break; - - case FT_WRT: - if (p->id2 < 0) - sprintf(buf,"R%lX,%lX,+,L%lX,+,%lX,-",p->id2,p->addend,p->id2,-p->id1*16); - else - sprintf(buf,"R%lX,%lX,+,L%lX,+,L%lX,-",p->id2,p->addend,p->id2,p->id1); - break; - case FT_EXT: - sprintf(buf,"X%lX",p->id1); - break; - case FT_EXTREL: - sprintf(buf,"X%lX,P,-,%lX,-",p->id1,size); - break; - case FT_EXTSEG: - /* We needed a non-ieee hack here. - * We introduce the Y variable, which is the low - * limit of the native segment the extern resides in - */ - sprintf(buf,"Y%lX,10,/",p->id1); - break; - case FT_EXTWRT: - if (p->id2 < 0) - sprintf(buf,"X%lX,Y%lX,+,%lX,-",p->id2,p->id2,-p->id1*16); - else - sprintf(buf,"X%lX,Y%lX,+,L%lX,-",p->id2,p->id2,p->id1); - break; - } - ieee_putascii("LR(%s,%lX).\r\n", buf, size); - - return(size); + char buf[40]; + long size = p->size; + switch (p->ftype) { + case FT_SEG: + if (p->id1 < 0) + sprintf(buf, "%lX", -p->id1); + else + sprintf(buf, "L%lX,10,/", p->id1); + break; + case FT_OFS: + sprintf(buf, "R%lX,%lX,+", p->id1, p->addend); + break; + case FT_REL: + sprintf(buf, "R%lX,%lX,+,P,-,%X,-", p->id1, p->addend, p->size); + break; + + case FT_WRT: + if (p->id2 < 0) + sprintf(buf, "R%lX,%lX,+,L%lX,+,%lX,-", p->id2, p->addend, + p->id2, -p->id1 * 16); + else + sprintf(buf, "R%lX,%lX,+,L%lX,+,L%lX,-", p->id2, p->addend, + p->id2, p->id1); + break; + case FT_EXT: + sprintf(buf, "X%lX", p->id1); + break; + case FT_EXTREL: + sprintf(buf, "X%lX,P,-,%lX,-", p->id1, size); + break; + case FT_EXTSEG: + /* We needed a non-ieee hack here. + * We introduce the Y variable, which is the low + * limit of the native segment the extern resides in + */ + sprintf(buf, "Y%lX,10,/", p->id1); + break; + case FT_EXTWRT: + if (p->id2 < 0) + sprintf(buf, "X%lX,Y%lX,+,%lX,-", p->id2, p->id2, + -p->id1 * 16); + else + sprintf(buf, "X%lX,Y%lX,+,L%lX,-", p->id2, p->id2, p->id1); + break; + } + ieee_putascii("LR(%s,%lX).\r\n", buf, size); + + return (size); } + /* Dump all segment data (text and fixups )*/ static void ieee_unqualified_name(char *dest, char *source) { if (ieee_uppercase) { - while (*source) - *dest++ = toupper(*source++); + while (*source) + *dest++ = toupper(*source++); *dest = 0; - } - else strcpy(dest,source); + } else + strcpy(dest, source); } -void dbgls_init(struct ofmt * of, void * id, FILE * fp, efunc error) +void dbgls_init(struct ofmt *of, void *id, FILE * fp, efunc error) { int tempint; - (void) of; - (void) id; - (void) fp; - (void) error; + (void)of; + (void)id; + (void)fp; + (void)error; fnhead = NULL; fntail = &fnhead; - arrindex = ARRAY_BOT ; + arrindex = ARRAY_BOT; arrhead = NULL; arrtail = &arrhead; ieee_segment("??LINE", 2, &tempint); @@ -1242,23 +1269,23 @@ static void dbgls_cleanup(void) { struct ieeeSection *segtmp; while (fnhead) { - struct FileName *fntemp = fnhead; - fnhead = fnhead->next; - nasm_free (fntemp->name); - nasm_free (fntemp); + struct FileName *fntemp = fnhead; + fnhead = fnhead->next; + nasm_free(fntemp->name); + nasm_free(fntemp); } for (segtmp = seghead; segtmp; segtmp = segtmp->next) { - while (segtmp->lochead) { - struct ieeePublic *loctmp = segtmp->lochead; - segtmp->lochead = loctmp->next; - nasm_free (loctmp->name); - nasm_free (loctmp); - } + while (segtmp->lochead) { + struct ieeePublic *loctmp = segtmp->lochead; + segtmp->lochead = loctmp->next; + nasm_free(loctmp->name); + nasm_free(loctmp); + } } while (arrhead) { - struct Array *arrtmp = arrhead; + struct Array *arrtmp = arrhead; arrhead = arrhead->next; - nasm_free (arrtmp); + nasm_free(arrtmp); } } @@ -1269,57 +1296,58 @@ static void dbgls_cleanup(void) * so, we have to make sure the ??LINE segment is avaialbe * as the first segment when this debug format is selected */ -static void dbgls_linnum (const char *lnfname, long lineno, long segto) +static void dbgls_linnum(const char *lnfname, long lineno, long segto) { struct FileName *fn; struct ieeeSection *seg; int i = 0; if (segto == NO_SEG) - return; + return; /* * If `any_segs' is still FALSE, we must define a default * segment. */ if (!any_segs) { - int tempint; /* ignored */ - if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint)) - error (ERR_PANIC, "strange segment conditions in OBJ driver"); + int tempint; /* ignored */ + if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint)) + error(ERR_PANIC, "strange segment conditions in OBJ driver"); } /* * Find the segment we are targetting. */ for (seg = seghead; seg; seg = seg->next) - if (seg->index == segto) - break; + if (seg->index == segto) + break; if (!seg) - error (ERR_PANIC, "lineno directed to nonexistent segment?"); + error(ERR_PANIC, "lineno directed to nonexistent segment?"); for (fn = fnhead; fn; fn = fn->next) { - if (!nasm_stricmp(lnfname,fn->name)) - break; + if (!nasm_stricmp(lnfname, fn->name)) + break; i++; } if (!fn) { - fn = nasm_malloc ( sizeof( *fn)); - fn->name = nasm_malloc ( strlen(lnfname) + 1) ; - fn->index = i; - strcpy (fn->name,lnfname); - fn->next = NULL; - *fntail = fn; - fntail = &fn->next; + fn = nasm_malloc(sizeof(*fn)); + fn->name = nasm_malloc(strlen(lnfname) + 1); + fn->index = i; + strcpy(fn->name, lnfname); + fn->next = NULL; + *fntail = fn; + fntail = &fn->next; } ieee_write_byte(seghead, fn->index); ieee_write_word(seghead, lineno); - ieee_write_fixup (segto, NO_SEG, seghead, 4, OUT_ADDRESS, seg->currentpos); + ieee_write_fixup(segto, NO_SEG, seghead, 4, OUT_ADDRESS, + seg->currentpos); } -static void dbgls_deflabel (char *name, long segment, - long offset, int is_global, char *special) +static void dbgls_deflabel(char *name, long segment, + long offset, int is_global, char *special) { struct ieeeSection *seg; - int used_special; /* have we used the special text? */ + int used_special; /* have we used the special text? */ /* Keep compiler from warning about special and used_special */ used_special = special ? FALSE : FALSE; @@ -1328,26 +1356,26 @@ static void dbgls_deflabel (char *name, long segment, * If it's a special-retry from pass two, discard it. */ if (is_global == 3) - return; + return; /* * First check for the double-period, signifying something * unusual. */ if (name[0] == '.' && name[1] == '.' && name[2] != '@') { - return; + return; } /* * Case (i): */ if (ieee_seg_needs_update) - return; + return; if (segment < SEG_ABS && segment != NO_SEG && segment % 2) - return; + return; if (segment >= SEG_ABS || segment == NO_SEG) { - return; + return; } /* @@ -1358,71 +1386,71 @@ static void dbgls_deflabel (char *name, long segment, */ for (seg = seghead; seg; seg = seg->next) - if (seg->index == segment) { - struct ieeePublic *loc; - /* - * Case (ii). Maybe MODPUB someday? - */ - if (!is_global) { - last_defined = loc = nasm_malloc (sizeof(*loc)); - *seg->loctail = loc; - seg->loctail = &loc->next; - loc->next = NULL; - loc->name = nasm_strdup(name); - loc->offset = offset; - loc->segment = -1; - loc->index = seg->ieee_index; - } - } + if (seg->index == segment) { + struct ieeePublic *loc; + /* + * Case (ii). Maybe MODPUB someday? + */ + if (!is_global) { + last_defined = loc = nasm_malloc(sizeof(*loc)); + *seg->loctail = loc; + seg->loctail = &loc->next; + loc->next = NULL; + loc->name = nasm_strdup(name); + loc->offset = offset; + loc->segment = -1; + loc->index = seg->ieee_index; + } + } } -static void dbgls_typevalue (long type) +static void dbgls_typevalue(long type) { int elem = TYM_ELEMENTS(type); type = TYM_TYPE(type); - if (! last_defined) - return; + if (!last_defined) + return; switch (type) { - case TY_BYTE: - last_defined->type = 1; /* unsigned char */ - break; - case TY_WORD: - last_defined->type = 3; /* unsigned word */ - break; - case TY_DWORD: - last_defined->type = 5; /* unsigned dword */ - break; - case TY_FLOAT: - last_defined->type = 9; /* float */ - break; - case TY_QWORD: - last_defined->type = 10; /* qword */ - break; - case TY_TBYTE: - last_defined->type = 11; /* TBYTE */ - break; - default: - last_defined->type = 0x10; /* near label */ - break; + case TY_BYTE: + last_defined->type = 1; /* unsigned char */ + break; + case TY_WORD: + last_defined->type = 3; /* unsigned word */ + break; + case TY_DWORD: + last_defined->type = 5; /* unsigned dword */ + break; + case TY_FLOAT: + last_defined->type = 9; /* float */ + break; + case TY_QWORD: + last_defined->type = 10; /* qword */ + break; + case TY_TBYTE: + last_defined->type = 11; /* TBYTE */ + break; + default: + last_defined->type = 0x10; /* near label */ + break; } - + if (elem > 1) { - struct Array *arrtmp = nasm_malloc (sizeof(*arrtmp)); + struct Array *arrtmp = nasm_malloc(sizeof(*arrtmp)); int vtype = last_defined->type; arrtmp->size = elem; arrtmp->basetype = vtype; arrtmp->next = NULL; last_defined->type = arrindex++ + 0x100; *arrtail = arrtmp; - arrtail = & (arrtmp->next); + arrtail = &(arrtmp->next); } last_defined = NULL; } -static void dbgls_output (int output_type, void *param) +static void dbgls_output(int output_type, void *param) { - (void) output_type; - (void) param; + (void)output_type; + (void)param; } static struct dfmt ladsoft_debug_form = { "LADsoft Debug Records", @@ -1436,9 +1464,9 @@ static struct dfmt ladsoft_debug_form = { dbgls_cleanup, }; static struct dfmt *ladsoft_debug_arr[3] = { - &ladsoft_debug_form, - &null_debug_form, - NULL + &ladsoft_debug_form, + &null_debug_form, + NULL }; struct ofmt of_ieee = { "IEEE-695 (LADsoft variant) object file format", @@ -1458,4 +1486,4 @@ struct ofmt of_ieee = { ieee_cleanup }; -#endif /* OF_IEEE */ +#endif /* OF_IEEE */ diff --git a/output/outobj.c b/output/outobj.c dissimilarity index 63% index 14b6cd9c..d1464fc0 100644 --- a/output/outobj.c +++ b/output/outobj.c @@ -1,2546 +1,2552 @@ -/* outobj.c output routines for the Netwide Assembler to produce - * .OBJ object files - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "outform.h" - -#ifdef OF_OBJ - -/* - * outobj.c is divided into two sections. The first section is low level - * routines for creating obj records; It has nearly zero NASM specific - * code. The second section is high level routines for processing calls and - * data structures from the rest of NASM into obj format. - * - * It should be easy (though not zero work) to lift the first section out for - * use as an obj file writer for some other assembler or compiler. - */ - -/* - * These routines are built around the ObjRecord data struture. An ObjRecord - * holds an object file record that may be under construction or complete. - * - * A major function of these routines is to support continuation of an obj - * record into the next record when the maximum record size is exceeded. The - * high level code does not need to worry about where the record breaks occur. - * It does need to do some minor extra steps to make the automatic continuation - * work. Those steps may be skipped for records where the high level knows no - * continuation could be required. - * - * 1) An ObjRecord is allocated and cleared by obj_new, or an existing ObjRecord - * is cleared by obj_clear. - * - * 2) The caller should fill in .type. - * - * 3) If the record is continuable and there is processing that must be done at - * the start of each record then the caller should fill in .ori with the - * address of the record initializer routine. - * - * 4) If the record is continuable and it should be saved (rather than emitted - * immediately) as each record is done, the caller should set .up to be a - * pointer to a location in which the caller keeps the master pointer to the - * ObjRecord. When the record is continued, the obj_bump routine will then - * allocate a new ObjRecord structure and update the master pointer. - * - * 5) If the .ori field was used then the caller should fill in the .parm with - * any data required by the initializer. - * - * 6) The caller uses the routines: obj_byte, obj_word, obj_rword, obj_dword, - * obj_x, obj_index, obj_value and obj_name to fill in the various kinds of - * data required for this record. - * - * 7) If the record is continuable, the caller should call obj_commit at each - * point where breaking the record is permitted. - * - * 8) To write out the record, the caller should call obj_emit2. If the - * caller has called obj_commit for all data written then he can get slightly - * faster code by calling obj_emit instead of obj_emit2. - * - * Most of these routines return an ObjRecord pointer. This will be the input - * pointer most of the time and will be the new location if the ObjRecord - * moved as a result of the call. The caller may ignore the return value in - * three cases: It is a "Never Reallocates" routine; or The caller knows - * continuation is not possible; or The caller uses the master pointer for the - * next operation. - */ - -#define RECORD_MAX (1024-3) /* maximal size of any record except type+reclen */ -#define OBJ_PARMS 3 /* maximum .parm used by any .ori routine */ - -#define FIX_08_LOW 0x8000 /* location type for various fixup subrecords */ -#define FIX_16_OFFSET 0x8400 -#define FIX_16_SELECTOR 0x8800 -#define FIX_32_POINTER 0x8C00 -#define FIX_08_HIGH 0x9000 -#define FIX_32_OFFSET 0xA400 -#define FIX_48_POINTER 0xAC00 - -enum RecordID { /* record ID codes */ - - THEADR = 0x80, /* module header */ - COMENT = 0x88, /* comment record */ - - LINNUM = 0x94, /* line number record */ - LNAMES = 0x96, /* list of names */ - - SEGDEF = 0x98, /* segment definition */ - GRPDEF = 0x9A, /* group definition */ - EXTDEF = 0x8C, /* external definition */ - PUBDEF = 0x90, /* public definition */ - COMDEF = 0xB0, /* common definition */ - - LEDATA = 0xA0, /* logical enumerated data */ - FIXUPP = 0x9C, /* fixups (relocations) */ - FIXU32 = 0x9D, /* 32-bit fixups (relocations) */ - - MODEND = 0x8A, /* module end */ - MODE32 = 0x8B /* module end for 32-bit objects */ -}; - -enum ComentID { /* ID codes for comment records */ - - dEXTENDED = 0xA1, /* tells that we are using translator-specific extensions */ - dLINKPASS = 0xA2, /* link pass 2 marker */ - dTYPEDEF = 0xE3, /* define a type */ - dSYM = 0xE6, /* symbol debug record */ - dFILNAME = 0xE8, /* file name record */ - dCOMPDEF = 0xEA /* compiler type info */ - -}; - -typedef struct ObjRecord ObjRecord; -typedef void ORI(ObjRecord *orp); - -struct ObjRecord { - ORI *ori; /* Initialization routine */ - int used; /* Current data size */ - int committed; /* Data size at last boundary */ - int x_size; /* (see obj_x) */ - unsigned int type; /* Record type */ - ObjRecord *child; /* Associated record below this one */ - ObjRecord **up; /* Master pointer to this ObjRecord */ - ObjRecord *back; /* Previous part of this record */ - unsigned long parm[OBJ_PARMS]; /* Parameters for ori routine */ - unsigned char buf[RECORD_MAX+3]; -}; - -static void obj_fwrite(ObjRecord *orp); -static void ori_ledata(ObjRecord *orp); -static void ori_pubdef(ObjRecord *orp); -static void ori_null(ObjRecord *orp); -static ObjRecord *obj_commit(ObjRecord *orp); - -static int obj_uppercase; /* Flag: all names in uppercase */ -static int obj_use32; /* Flag: at least one segment is 32-bit */ - -/* - * Clear an ObjRecord structure. (Never reallocates). - * To simplify reuse of ObjRecord's, .type, .ori and .parm are not cleared. - */ -static ObjRecord *obj_clear(ObjRecord *orp) -{ - orp->used = 0; - orp->committed = 0; - orp->x_size = 0; - orp->child = NULL; - orp->up = NULL; - orp->back = NULL; - return (orp); -} - -/* - * Emit an ObjRecord structure. (Never reallocates). - * The record is written out preceeded (recursively) by its previous part (if - * any) and followed (recursively) by its child (if any). - * The previous part and the child are freed. The main ObjRecord is cleared, - * not freed. - */ -static ObjRecord *obj_emit(ObjRecord *orp) -{ - if (orp->back) { - obj_emit(orp->back); - nasm_free(orp->back); - } - - if (orp->committed) - obj_fwrite(orp); - - if (orp->child) { - obj_emit(orp->child); - nasm_free(orp->child); - } - - return (obj_clear(orp)); -} - -/* - * Commit and Emit a record. (Never reallocates). - */ -static ObjRecord *obj_emit2(ObjRecord *orp) -{ - obj_commit(orp); - return (obj_emit(orp)); -} - -/* - * Allocate and clear a new ObjRecord; Also sets .ori to ori_null - */ -static ObjRecord *obj_new(void) -{ - ObjRecord *orp; - - orp = obj_clear( nasm_malloc(sizeof(ObjRecord)) ); - orp->ori = ori_null; - return (orp); -} - -/* - * Advance to the next record because the existing one is full or its x_size - * is incompatible. - * Any uncommited data is moved into the next record. - */ -static ObjRecord *obj_bump(ObjRecord *orp) -{ - ObjRecord *nxt; - int used = orp->used; - int committed = orp->committed; - - if (orp->up) { - *orp->up = nxt = obj_new(); - nxt->ori = orp->ori; - nxt->type = orp->type; - nxt->up = orp->up; - nxt->back = orp; - memcpy( nxt->parm, orp->parm, sizeof(orp->parm)); - } else - nxt = obj_emit(orp); - - used -= committed; - if (used) { - nxt->committed = 1; - nxt->ori (nxt); - nxt->committed = nxt->used; - memcpy( nxt->buf + nxt->committed, orp->buf + committed, used); - nxt->used = nxt->committed + used; - } - - return (nxt); -} - -/* - * Advance to the next record if necessary to allow the next field to fit. - */ -static ObjRecord *obj_check(ObjRecord *orp, int size) -{ - if (orp->used + size > RECORD_MAX) - orp = obj_bump(orp); - - if (!orp->committed) { - orp->committed = 1; - orp->ori (orp); - orp->committed = orp->used; - } - - return (orp); -} - -/* - * All data written so far is commited to the current record (won't be moved to - * the next record in case of continuation). - */ -static ObjRecord *obj_commit(ObjRecord *orp) -{ - orp->committed = orp->used; - return (orp); -} - -/* - * Write a byte - */ -static ObjRecord *obj_byte(ObjRecord *orp, unsigned char val) -{ - orp = obj_check(orp, 1); - orp->buf[orp->used] = val; - orp->used++; - return (orp); -} - -/* - * Write a word - */ -static ObjRecord *obj_word(ObjRecord *orp, unsigned int val) -{ - orp = obj_check(orp, 2); - orp->buf[orp->used] = val; - orp->buf[orp->used+1] = val >> 8; - orp->used += 2; - return (orp); -} - -/* - * Write a reversed word - */ -static ObjRecord *obj_rword(ObjRecord *orp, unsigned int val) -{ - orp = obj_check(orp, 2); - orp->buf[orp->used] = val >> 8; - orp->buf[orp->used+1] = val; - orp->used += 2; - return (orp); -} - -/* - * Write a dword - */ -static ObjRecord *obj_dword(ObjRecord *orp, unsigned long val) -{ - orp = obj_check(orp, 4); - orp->buf[orp->used] = val; - orp->buf[orp->used+1] = val >> 8; - orp->buf[orp->used+2] = val >> 16; - orp->buf[orp->used+3] = val >> 24; - orp->used += 4; - return (orp); -} - -/* - * All fields of "size x" in one obj record must be the same size (either 16 - * bits or 32 bits). There is a one bit flag in each record which specifies - * which. - * This routine is used to force the current record to have the desired - * x_size. x_size is normally automatic (using obj_x), so that this - * routine should be used outside obj_x, only to provide compatibility with - * linkers that have bugs in their processing of the size bit. - */ - -static ObjRecord *obj_force(ObjRecord *orp, int x) -{ - if (orp->x_size == (x^48)) - orp = obj_bump(orp); - orp->x_size = x; - return (orp); -} - -/* - * This routine writes a field of size x. The caller does not need to worry at - * all about whether 16-bits or 32-bits are required. - */ -static ObjRecord *obj_x(ObjRecord *orp, unsigned long val) -{ - if (orp->type & 1) - orp->x_size = 32; - if (val > 0xFFFF) - orp = obj_force(orp, 32); - if (orp->x_size == 32) - return (obj_dword(orp, val)); - orp->x_size = 16; - return (obj_word(orp, val)); -} - -/* - * Writes an index - */ -static ObjRecord *obj_index(ObjRecord *orp, unsigned int val) -{ - if (val < 128) - return ( obj_byte(orp, val) ); - return (obj_word(orp, (val>>8) | (val<<8) | 0x80)); -} - -/* - * Writes a variable length value - */ -static ObjRecord *obj_value(ObjRecord *orp, unsigned long val) -{ - if (val <= 128) - return ( obj_byte(orp, val) ); - if (val <= 0xFFFF) { - orp = obj_byte(orp, 129); - return ( obj_word(orp, val) ); - } - if (val <= 0xFFFFFF) - return ( obj_dword(orp, (val<<8) + 132 ) ); - orp = obj_byte(orp, 136); - return ( obj_dword(orp, val) ); -} - -/* - * Writes a counted string - */ -static ObjRecord *obj_name(ObjRecord *orp, char *name) -{ - int len = strlen(name); - unsigned char *ptr; - - orp = obj_check(orp, len+1); - ptr = orp->buf + orp->used; - *ptr++ = len; - orp->used += len+1; - if (obj_uppercase) - while (--len >= 0) { - *ptr++ = toupper(*name); - name++; - } else - memcpy(ptr, name, len); - return (orp); -} - -/* - * Initializer for an LEDATA record. - * parm[0] = offset - * parm[1] = segment index - * During the use of a LEDATA ObjRecord, parm[0] is constantly updated to - * represent the offset that would be required if the record were split at the - * last commit point. - * parm[2] is a copy of parm[0] as it was when the current record was initted. - */ -static void ori_ledata(ObjRecord *orp) -{ - obj_index (orp, orp->parm[1]); - orp->parm[2] = orp->parm[0]; - obj_x (orp, orp->parm[0]); -} - -/* - * Initializer for a PUBDEF record. - * parm[0] = group index - * parm[1] = segment index - * parm[2] = frame (only used when both indexes are zero) - */ -static void ori_pubdef(ObjRecord *orp) -{ - obj_index (orp, orp->parm[0]); - obj_index (orp, orp->parm[1]); - if ( !(orp->parm[0] | orp->parm[1]) ) - obj_word (orp, orp->parm[2]); -} - -/* - * Initializer for a LINNUM record. - * parm[0] = group index - * parm[1] = segment index - */ -static void ori_linnum(ObjRecord *orp) -{ - obj_index (orp, orp->parm[0]); - obj_index (orp, orp->parm[1]); -} -/* - * Initializer for a local vars record. - */ -static void ori_local(ObjRecord *orp) -{ - obj_byte (orp, 0x40); - obj_byte (orp, dSYM); -} - -/* - * Null initializer for records that continue without any header info - */ -static void ori_null(ObjRecord *orp) -{ - (void) orp; /* Do nothing */ -} - -/* - * This concludes the low level section of outobj.c - */ - -static char obj_infile[FILENAME_MAX]; - -static efunc error; -static evalfunc evaluate; -static ldfunc deflabel; -static FILE *ofp; -static long first_seg; -static int any_segs; -static int passtwo; -static int arrindex; - -#define GROUP_MAX 256 /* we won't _realistically_ have more - * than this many segs in a group */ -#define EXT_BLKSIZ 256 /* block size for externals list */ - -struct Segment; /* need to know these structs exist */ -struct Group; - -struct LineNumber { - struct LineNumber *next; - struct Segment *segment; - long offset; - long lineno; -}; - -static struct FileName { - struct FileName *next; - char *name; - struct LineNumber *lnhead, **lntail; - int index; -} *fnhead, **fntail; - -static struct Array { - struct Array *next; - unsigned size; - int basetype; -} *arrhead, **arrtail; - -#define ARRAYBOT 31 /* magic number for first array index */ - - -static struct Public { - struct Public *next; - char *name; - long offset; - long segment; /* only if it's far-absolute */ - int type; /* only for local debug syms */ -} *fpubhead, **fpubtail, *last_defined; - -static struct External { - struct External *next; - char *name; - long commonsize; - long commonelem; /* element size if FAR, else zero */ - int index; /* OBJ-file external index */ - enum { - DEFWRT_NONE, /* no unusual default-WRT */ - DEFWRT_STRING, /* a string we don't yet understand */ - DEFWRT_SEGMENT, /* a segment */ - DEFWRT_GROUP /* a group */ - } defwrt_type; - union { - char *string; - struct Segment *seg; - struct Group *grp; - } defwrt_ptr; - struct External *next_dws; /* next with DEFWRT_STRING */ -} *exthead, **exttail, *dws; - -static int externals; - -static struct ExtBack { - struct ExtBack *next; - struct External *exts[EXT_BLKSIZ]; -} *ebhead, **ebtail; - -static struct Segment { - struct Segment *next; - long index; /* the NASM segment id */ - long obj_index; /* the OBJ-file segment index */ - struct Group *grp; /* the group it belongs to */ - unsigned long currentpos; - long align; /* can be SEG_ABS + absolute addr */ - enum { - CMB_PRIVATE = 0, - CMB_PUBLIC = 2, - CMB_STACK = 5, - CMB_COMMON = 6 - } combine; - long use32; /* is this segment 32-bit? */ - struct Public *pubhead, **pubtail, *lochead, **loctail; - char *name; - char *segclass, *overlay; /* `class' is a C++ keyword :-) */ - ObjRecord *orp; -} *seghead, **segtail, *obj_seg_needs_update; - -static struct Group { - struct Group *next; - char *name; - long index; /* NASM segment id */ - long obj_index; /* OBJ-file group index */ - long nentries; /* number of elements... */ - long nindices; /* ...and number of index elts... */ - union { - long index; - char *name; - } segs[GROUP_MAX]; /* ...in this */ -} *grphead, **grptail, *obj_grp_needs_update; - -static struct ImpDef { - struct ImpDef *next; - char *extname; - char *libname; - unsigned int impindex; - char *impname; -} *imphead, **imptail; - -static struct ExpDef { - struct ExpDef *next; - char *intname; - char *extname; - unsigned int ordinal; - int flags; -} *exphead, **exptail; - -#define EXPDEF_FLAG_ORDINAL 0x80 -#define EXPDEF_FLAG_RESIDENT 0x40 -#define EXPDEF_FLAG_NODATA 0x20 -#define EXPDEF_MASK_PARMCNT 0x1F - -static long obj_entry_seg, obj_entry_ofs; - -struct ofmt of_obj; - -/* The current segment */ -static struct Segment *current_seg; - -static long obj_segment (char *, int, int *); -static void obj_write_file(int debuginfo); -static int obj_directive (char *, char *, int); - -static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) -{ - ofp = fp; - error = errfunc; - evaluate = eval; - deflabel = ldef; - first_seg = seg_alloc(); - any_segs = FALSE; - fpubhead = NULL; - fpubtail = &fpubhead; - exthead = NULL; - exttail = &exthead; - imphead = NULL; - imptail = &imphead; - exphead = NULL; - exptail = &exphead; - dws = NULL; - externals = 0; - ebhead = NULL; - ebtail = &ebhead; - seghead = obj_seg_needs_update = NULL; - segtail = &seghead; - grphead = obj_grp_needs_update = NULL; - grptail = &grphead; - obj_entry_seg = NO_SEG; - obj_uppercase = FALSE; - obj_use32 = FALSE; - passtwo = 0; - current_seg = NULL; - - of_obj.current_dfmt->init (&of_obj,NULL,fp,errfunc); -} - -static int obj_set_info(enum geninfo type, char **val) -{ - (void) type; - (void) val; - - return 0; -} -static void obj_cleanup (int debuginfo) -{ - obj_write_file(debuginfo); - of_obj.current_dfmt->cleanup(); - fclose (ofp); - while (seghead) { - struct Segment *segtmp = seghead; - seghead = seghead->next; - while (segtmp->pubhead) { - struct Public *pubtmp = segtmp->pubhead; - segtmp->pubhead = pubtmp->next; - nasm_free (pubtmp->name); - nasm_free (pubtmp); - } - nasm_free (segtmp->segclass); - nasm_free (segtmp->overlay); - nasm_free (segtmp); - } - while (fpubhead) { - struct Public *pubtmp = fpubhead; - fpubhead = fpubhead->next; - nasm_free (pubtmp->name); - nasm_free (pubtmp); - } - while (exthead) { - struct External *exttmp = exthead; - exthead = exthead->next; - nasm_free (exttmp); - } - while (imphead) { - struct ImpDef *imptmp = imphead; - imphead = imphead->next; - nasm_free (imptmp->extname); - nasm_free (imptmp->libname); - nasm_free (imptmp->impname); /* nasm_free won't mind if it's NULL */ - nasm_free (imptmp); - } - while (exphead) { - struct ExpDef *exptmp = exphead; - exphead = exphead->next; - nasm_free (exptmp->extname); - nasm_free (exptmp->intname); - nasm_free (exptmp); - } - while (ebhead) { - struct ExtBack *ebtmp = ebhead; - ebhead = ebhead->next; - nasm_free (ebtmp); - } - while (grphead) { - struct Group *grptmp = grphead; - grphead = grphead->next; - nasm_free (grptmp); - } -} - -static void obj_ext_set_defwrt (struct External *ext, char *id) -{ - struct Segment *seg; - struct Group *grp; - - for (seg = seghead; seg; seg = seg->next) - if (!strcmp(seg->name, id)) { - ext->defwrt_type = DEFWRT_SEGMENT; - ext->defwrt_ptr.seg = seg; - nasm_free (id); - return; - } - - for (grp = grphead; grp; grp = grp->next) - if (!strcmp(grp->name, id)) { - ext->defwrt_type = DEFWRT_GROUP; - ext->defwrt_ptr.grp = grp; - nasm_free (id); - return; - } - - ext->defwrt_type = DEFWRT_STRING; - ext->defwrt_ptr.string = id; - ext->next_dws = dws; - dws = ext; -} - -static void obj_deflabel (char *name, long segment, - long offset, int is_global, char *special) -{ - /* - * We have three cases: - * - * (i) `segment' is a segment-base. If so, set the name field - * for the segment or group structure it refers to, and then - * return. - * - * (ii) `segment' is one of our segments, or a SEG_ABS segment. - * Save the label position for later output of a PUBDEF record. - * (Or a MODPUB, if we work out how.) - * - * (iii) `segment' is not one of our segments. Save the label - * position for later output of an EXTDEF, and also store a - * back-reference so that we can map later references to this - * segment number to the external index. - */ - struct External *ext; - struct ExtBack *eb; - struct Segment *seg; - int i; - int used_special = FALSE; /* have we used the special text? */ - -#if defined(DEBUG) && DEBUG>2 -fprintf(stderr, " obj_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n", - name, segment, offset, is_global, special); -#endif - - /* - * If it's a special-retry from pass two, discard it. - */ - if (is_global == 3) - return; - - /* - * First check for the double-period, signifying something - * unusual. - */ - if (name[0] == '.' && name[1] == '.' && name[2] != '@') { - if (!strcmp(name, "..start")) { - obj_entry_seg = segment; - obj_entry_ofs = offset; - return; - } - error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); - } - - /* - * Case (i): - */ - if (obj_seg_needs_update) { - obj_seg_needs_update->name = name; - return; - } else if (obj_grp_needs_update) { - obj_grp_needs_update->name = name; - return; - } - if (segment < SEG_ABS && segment != NO_SEG && segment % 2) - return; - - if (segment >= SEG_ABS || segment == NO_SEG) { - /* - * SEG_ABS subcase of (ii). - */ - if (is_global) { - struct Public *pub; - - pub = *fpubtail = nasm_malloc(sizeof(*pub)); - fpubtail = &pub->next; - pub->next = NULL; - pub->name = nasm_strdup(name); - pub->offset = offset; - pub->segment = (segment == NO_SEG ? 0 : segment & ~SEG_ABS); - } - if (special) - error(ERR_NONFATAL, "OBJ supports no special symbol features" - " for this symbol type"); - return; - } - - /* - * If `any_segs' is still FALSE, we might need to define a - * default segment, if they're trying to declare a label in - * `first_seg'. - */ - if (!any_segs && segment == first_seg) { - int tempint; /* ignored */ - if (segment != obj_segment("__NASMDEFSEG", 2, &tempint)) - error (ERR_PANIC, "strange segment conditions in OBJ driver"); - } - - for (seg = seghead; seg && is_global; seg = seg->next) - if (seg->index == segment) { - struct Public *loc = nasm_malloc (sizeof(*loc)); - /* - * Case (ii). Maybe MODPUB someday? - */ - *seg->pubtail = loc; - seg->pubtail = &loc->next; - loc->next = NULL; - loc->name = nasm_strdup(name); - loc->offset = offset; - - if (special) - error(ERR_NONFATAL, "OBJ supports no special symbol features" - " for this symbol type"); - return; - } - - /* - * Case (iii). - */ - if (is_global) { - ext = *exttail = nasm_malloc(sizeof(*ext)); - ext->next = NULL; - exttail = &ext->next; - ext->name = name; - /* Place by default all externs into the current segment */ - ext->defwrt_type = DEFWRT_NONE; - -/* 28-Apr-2002 - John Coffman - The following code was introduced on 12-Aug-2000, and breaks fixups - on code passed thru the MSC 5.1 linker (3.66) and MSC 6.00A linker - (5.10). It was introduced after FIXUP32 was added, and may be needed - for 32-bit segments. The following will get 16-bit segments working - again, and maybe someone can correct the 'if' condition which is - actually needed. -*/ -#if 0 - if (current_seg) { -#else - if (current_seg && current_seg->use32) { - if (current_seg->grp) { - ext->defwrt_type = DEFWRT_GROUP; - ext->defwrt_ptr.grp = current_seg->grp; - } else { - ext->defwrt_type = DEFWRT_SEGMENT; - ext->defwrt_ptr.seg = current_seg; - } - } -#endif - - if (is_global == 2) { - ext->commonsize = offset; - ext->commonelem = 1; /* default FAR */ - } else - ext->commonsize = 0; - } - else - return; - - /* - * Now process the special text, if any, to find default-WRT - * specifications and common-variable element-size and near/far - * specifications. - */ - while (special && *special) { - used_special = TRUE; - - /* - * We might have a default-WRT specification. - */ - if (!nasm_strnicmp(special, "wrt", 3)) { - char *p; - int len; - special += 3; - special += strspn(special, " \t"); - p = nasm_strndup(special, len = strcspn(special, ":")); - obj_ext_set_defwrt (ext, p); - special += len; - if (*special && *special != ':') - error(ERR_NONFATAL, "`:' expected in special symbol" - " text for `%s'", ext->name); - else if (*special == ':') - special++; - } - - /* - * The NEAR or FAR keywords specify nearness or - * farness. FAR gives default element size 1. - */ - if (!nasm_strnicmp(special, "far", 3)) { - if (ext->commonsize) - ext->commonelem = 1; - else - error(ERR_NONFATAL, "`%s': `far' keyword may only be applied" - " to common variables\n", ext->name); - special += 3; - special += strspn(special, " \t"); - } else if (!nasm_strnicmp(special, "near", 4)) { - if (ext->commonsize) - ext->commonelem = 0; - else - error(ERR_NONFATAL, "`%s': `far' keyword may only be applied" - " to common variables\n", ext->name); - special += 4; - special += strspn(special, " \t"); - } - - /* - * If it's a common, and anything else remains on the line - * before a further colon, evaluate it as an expression and - * use that as the element size. Forward references aren't - * allowed. - */ - if (*special == ':') - special++; - else if (*special) { - if (ext->commonsize) { - expr *e; - struct tokenval tokval; - - stdscan_reset(); - stdscan_bufptr = special; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); - if (e) { - if (!is_simple(e)) - error (ERR_NONFATAL, "cannot use relocatable" - " expression as common-variable element size"); - else - ext->commonelem = reloc_value(e); - } - special = stdscan_bufptr; - } else { - error (ERR_NONFATAL, "`%s': element-size specifications only" - " apply to common variables", ext->name); - while (*special && *special != ':') - special++; - if (*special == ':') - special++; - } - } - } - - i = segment/2; - eb = ebhead; - if (!eb) { - eb = *ebtail = nasm_malloc(sizeof(*eb)); - eb->next = NULL; - ebtail = &eb->next; - } - while (i >= EXT_BLKSIZ) { - if (eb && eb->next) - eb = eb->next; - else { - eb = *ebtail = nasm_malloc(sizeof(*eb)); - eb->next = NULL; - ebtail = &eb->next; - } - i -= EXT_BLKSIZ; - } - eb->exts[i] = ext; - ext->index = ++externals; - - if (special && !used_special) - error(ERR_NONFATAL, "OBJ supports no special symbol features" - " for this symbol type"); -} - -/* forward declaration */ -static void obj_write_fixup (ObjRecord *orp, int bytes, - int segrel, long seg, long wrt, struct Segment *segto); - -static void obj_out (long segto, const void *data, unsigned long type, - long segment, long wrt) -{ - unsigned long size, realtype; - const unsigned char *ucdata; - long ldata; - struct Segment *seg; - ObjRecord *orp; - - /* - * handle absolute-assembly (structure definitions) - */ - if (segto == NO_SEG) { - if ((type & OUT_TYPMASK) != OUT_RESERVE) - error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" - " space"); - return; - } - - /* - * If `any_segs' is still FALSE, we must define a default - * segment. - */ - if (!any_segs) { - int tempint; /* ignored */ - if (segto != obj_segment("__NASMDEFSEG", 2, &tempint)) - error (ERR_PANIC, "strange segment conditions in OBJ driver"); - } - - /* - * Find the segment we are targetting. - */ - for (seg = seghead; seg; seg = seg->next) - if (seg->index == segto) - break; - if (!seg) - error (ERR_PANIC, "code directed to nonexistent segment?"); - - orp = seg->orp; - orp->parm[0] = seg->currentpos; - - size = type & OUT_SIZMASK; - realtype = type & OUT_TYPMASK; - if (realtype == OUT_RAWDATA) { - ucdata = data; - while (size > 0) { - unsigned int len; - orp = obj_check(seg->orp, 1); - len = RECORD_MAX - orp->used; - if (len > size) - len = size; - memcpy (orp->buf+orp->used, ucdata, len); - orp->committed = orp->used += len; - orp->parm[0] = seg->currentpos += len; - ucdata += len; - size -= len; - } - } - else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR || - realtype == OUT_REL4ADR) - { - int rsize; - - if (segment == NO_SEG && realtype != OUT_ADDRESS) - error(ERR_NONFATAL, "relative call to absolute address not" - " supported by OBJ format"); - if (segment >= SEG_ABS) - error(ERR_NONFATAL, "far-absolute relocations not supported" - " by OBJ format"); - ldata = *(long *)data; - if (realtype == OUT_REL2ADR) { - ldata += (size-2); - size = 2; - } - if (realtype == OUT_REL4ADR) { - ldata += (size-4); - size = 4; - } - if (size == 2) - orp = obj_word (orp, ldata); - else - orp = obj_dword (orp, ldata); - rsize = size; - if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) && - size == 4) { - /* - * This is a 4-byte segment-base relocation such as - * `MOV EAX,SEG foo'. OBJ format can't actually handle - * these, but if the constant term has the 16 low bits - * zero, we can just apply a 2-byte segment-base - * relocation to the low word instead. - */ - rsize = 2; - if (ldata & 0xFFFF) - error(ERR_NONFATAL, "OBJ format cannot handle complex" - " dword-size segment base references"); - } - if (segment != NO_SEG) - obj_write_fixup (orp, rsize, - (realtype == OUT_ADDRESS ? 0x4000 : 0), - segment, wrt, seg); - seg->currentpos += size; - } else if (realtype == OUT_RESERVE) { - if (orp->committed) - orp = obj_bump(orp); - seg->currentpos += size; - } - obj_commit(orp); -} - -static void obj_write_fixup (ObjRecord *orp, int bytes, - int segrel, long seg, long wrt, struct Segment *segto) -{ - unsigned locat; - int method; - int base; - long tidx, fidx; - struct Segment *s = NULL; - struct Group *g = NULL; - struct External *e = NULL; - ObjRecord *forp; - - if (bytes == 1) { - error(ERR_NONFATAL, "`obj' output driver does not support" - " one-byte relocations"); - return; - } - - forp = orp->child; - if (forp == NULL) { - orp->child = forp = obj_new(); - forp->up = &(orp->child); - /* We should choose between FIXUPP and FIXU32 record type */ - /* If we're targeting a 32-bit segment, use a FIXU32 record */ - if (segto->use32) - forp->type = FIXU32; - else - forp->type = FIXUPP; - } - - if (seg % 2) { - base = TRUE; - locat = FIX_16_SELECTOR; - seg--; - if (bytes != 2) - error(ERR_PANIC, "OBJ: 4-byte segment base fixup got" - " through sanity check"); - } - else { - base = FALSE; - locat = (bytes == 2) ? FIX_16_OFFSET : FIX_32_OFFSET; - if (!segrel) - /* - * There is a bug in tlink that makes it process self relative - * fixups incorrectly if the x_size doesn't match the location - * size. - */ - forp = obj_force(forp, bytes<<3); - } - - forp = obj_rword (forp, locat | segrel | (orp->parm[0]-orp->parm[2])); - - tidx = fidx = -1, method = 0; /* placate optimisers */ - - /* - * See if we can find the segment ID in our segment list. If - * so, we have a T4 (LSEG) target. - */ - for (s = seghead; s; s = s->next) - if (s->index == seg) - break; - if (s) - method = 4, tidx = s->obj_index; - else { - for (g = grphead; g; g = g->next) - if (g->index == seg) - break; - if (g) - method = 5, tidx = g->obj_index; - else { - long i = seg/2; - struct ExtBack *eb = ebhead; - while (i > EXT_BLKSIZ) { - if (eb) - eb = eb->next; - else - break; - i -= EXT_BLKSIZ; - } - if (eb) - method = 6, e = eb->exts[i], tidx = e->index; - else - error(ERR_PANIC, - "unrecognised segment value in obj_write_fixup"); - } - } - - /* - * If no WRT given, assume the natural default, which is method - * F5 unless: - * - * - we are doing an OFFSET fixup for a grouped segment, in - * which case we require F1 (group). - * - * - we are doing an OFFSET fixup for an external with a - * default WRT, in which case we must honour the default WRT. - */ - if (wrt == NO_SEG) { - if (!base && s && s->grp) - method |= 0x10, fidx = s->grp->obj_index; - else if (!base && e && e->defwrt_type != DEFWRT_NONE) { - if (e->defwrt_type == DEFWRT_SEGMENT) - method |= 0x00, fidx = e->defwrt_ptr.seg->obj_index; - else if (e->defwrt_type == DEFWRT_GROUP) - method |= 0x10, fidx = e->defwrt_ptr.grp->obj_index; - else { - error(ERR_NONFATAL, "default WRT specification for" - " external `%s' unresolved", e->name); - method |= 0x50, fidx = -1; /* got to do _something_ */ - } - } else - method |= 0x50, fidx = -1; - } else { - /* - * See if we can find the WRT-segment ID in our segment - * list. If so, we have a F0 (LSEG) frame. - */ - for (s = seghead; s; s = s->next) - if (s->index == wrt-1) - break; - if (s) - method |= 0x00, fidx = s->obj_index; - else { - for (g = grphead; g; g = g->next) - if (g->index == wrt-1) - break; - if (g) - method |= 0x10, fidx = g->obj_index; - else { - long i = wrt/2; - struct ExtBack *eb = ebhead; - while (i > EXT_BLKSIZ) { - if (eb) - eb = eb->next; - else - break; - i -= EXT_BLKSIZ; - } - if (eb) - method |= 0x20, fidx = eb->exts[i]->index; - else - error(ERR_PANIC, - "unrecognised WRT value in obj_write_fixup"); - } - } - } - - forp = obj_byte (forp, method); - if (fidx != -1) - forp = obj_index (forp, fidx); - forp = obj_index (forp, tidx); - obj_commit (forp); -} - -static long obj_segment (char *name, int pass, int *bits) -{ - /* - * We call the label manager here to define a name for the new - * segment, and when our _own_ label-definition stub gets - * called in return, it should register the new segment name - * using the pointer it gets passed. That way we save memory, - * by sponging off the label manager. - */ -#if defined(DEBUG) && DEBUG>=3 -fprintf(stderr," obj_segment: < %s >, pass=%d, *bits=%d\n", - name, pass, *bits); -#endif - if (!name) { - *bits = 16; - current_seg = NULL; - return first_seg; - } else { - struct Segment *seg; - struct Group *grp; - struct External **extp; - int obj_idx, i, attrs, rn_error; - char *p; - - /* - * Look for segment attributes. - */ - attrs = 0; - while (*name == '.') - name++; /* hack, but a documented one */ - p = name; - while (*p && !isspace(*p)) - p++; - if (*p) { - *p++ = '\0'; - while (*p && isspace(*p)) - *p++ = '\0'; - } - while (*p) { - while (*p && !isspace(*p)) - p++; - if (*p) { - *p++ = '\0'; - while (*p && isspace(*p)) - *p++ = '\0'; - } - - attrs++; - } - - obj_idx = 1; - for (seg = seghead; seg; seg = seg->next) { - obj_idx++; - if (!strcmp(seg->name, name)) { - if (attrs > 0 && pass == 1) - error(ERR_WARNING, "segment attributes specified on" - " redeclaration of segment: ignoring"); - if (seg->use32) - *bits = 32; - else - *bits = 16; - current_seg = seg; - return seg->index; - } - } - - *segtail = seg = nasm_malloc(sizeof(*seg)); - seg->next = NULL; - segtail = &seg->next; - seg->index = (any_segs ? seg_alloc() : first_seg); - seg->obj_index = obj_idx; - seg->grp = NULL; - any_segs = TRUE; - seg->name = NULL; - seg->currentpos = 0; - seg->align = 1; /* default */ - seg->use32 = FALSE; /* default */ - seg->combine = CMB_PUBLIC; /* default */ - seg->segclass = seg->overlay = NULL; - seg->pubhead = NULL; - seg->pubtail = &seg->pubhead; - seg->lochead = NULL; - seg->loctail = &seg->lochead; - seg->orp = obj_new(); - seg->orp->up = &(seg->orp); - seg->orp->ori = ori_ledata; - seg->orp->type = LEDATA; - seg->orp->parm[1] = obj_idx; - - /* - * Process the segment attributes. - */ - p = name; - while (attrs--) { - p += strlen(p); - while (!*p) p++; - - /* - * `p' contains a segment attribute. - */ - if (!nasm_stricmp(p, "private")) - seg->combine = CMB_PRIVATE; - else if (!nasm_stricmp(p, "public")) - seg->combine = CMB_PUBLIC; - else if (!nasm_stricmp(p, "common")) - seg->combine = CMB_COMMON; - else if (!nasm_stricmp(p, "stack")) - seg->combine = CMB_STACK; - else if (!nasm_stricmp(p, "use16")) - seg->use32 = FALSE; - else if (!nasm_stricmp(p, "use32")) - seg->use32 = TRUE; - else if (!nasm_stricmp(p, "flat")) { - /* - * This segment is an OS/2 FLAT segment. That means - * that its default group is group FLAT, even if - * the group FLAT does not explicitly _contain_ the - * segment. - * - * When we see this, we must create the group - * `FLAT', containing no segments, if it does not - * already exist; then we must set the default - * group of this segment to be the FLAT group. - */ - struct Group *grp; - for (grp = grphead; grp; grp = grp->next) - if (!strcmp(grp->name, "FLAT")) - break; - if (!grp) { - obj_directive ("group", "FLAT", 1); - for (grp = grphead; grp; grp = grp->next) - if (!strcmp(grp->name, "FLAT")) - break; - if (!grp) - error (ERR_PANIC, "failure to define FLAT?!"); - } - seg->grp = grp; - } else if (!nasm_strnicmp(p, "class=", 6)) - seg->segclass = nasm_strdup(p+6); - else if (!nasm_strnicmp(p, "overlay=", 8)) - seg->overlay = nasm_strdup(p+8); - else if (!nasm_strnicmp(p, "align=", 6)) { - seg->align = readnum(p+6, &rn_error); - if (rn_error) { - seg->align = 1; - error (ERR_NONFATAL, "segment alignment should be" - " numeric"); - } - switch ((int) seg->align) { - case 1: /* BYTE */ - case 2: /* WORD */ - case 4: /* DWORD */ - case 16: /* PARA */ - case 256: /* PAGE */ - case 4096: /* PharLap extension */ - break; - case 8: - error(ERR_WARNING, "OBJ format does not support alignment" - " of 8: rounding up to 16"); - seg->align = 16; - break; - case 32: - case 64: - case 128: - error(ERR_WARNING, "OBJ format does not support alignment" - " of %d: rounding up to 256", seg->align); - seg->align = 256; - break; - case 512: - case 1024: - case 2048: - error(ERR_WARNING, "OBJ format does not support alignment" - " of %d: rounding up to 4096", seg->align); - seg->align = 4096; - break; - default: - error(ERR_NONFATAL, "invalid alignment value %d", - seg->align); - seg->align = 1; - break; - } - } else if (!nasm_strnicmp(p, "absolute=", 9)) { - seg->align = SEG_ABS + readnum(p+9, &rn_error); - if (rn_error) - error (ERR_NONFATAL, "argument to `absolute' segment" - " attribute should be numeric"); - } - } - - /* We need to know whenever we have at least one 32-bit segment */ - obj_use32 |= seg->use32; - - obj_seg_needs_update = seg; - if (seg->align >= SEG_ABS) - deflabel (name, NO_SEG, seg->align - SEG_ABS, - NULL, FALSE, FALSE, &of_obj, error); - else - deflabel (name, seg->index+1, 0L, - NULL, FALSE, FALSE, &of_obj, error); - obj_seg_needs_update = NULL; - - /* - * See if this segment is defined in any groups. - */ - for (grp = grphead; grp; grp = grp->next) { - for (i = grp->nindices; i < grp->nentries; i++) { - if (!strcmp(grp->segs[i].name, seg->name)) { - nasm_free (grp->segs[i].name); - grp->segs[i] = grp->segs[grp->nindices]; - grp->segs[grp->nindices++].index = seg->obj_index; - if (seg->grp) - error(ERR_WARNING, "segment `%s' is already part of" - " a group: first one takes precedence", - seg->name); - else - seg->grp = grp; - } - } - } - - /* - * Walk through the list of externals with unresolved - * default-WRT clauses, and resolve any that point at this - * segment. - */ - extp = &dws; - while (*extp) { - if ((*extp)->defwrt_type == DEFWRT_STRING && - !strcmp((*extp)->defwrt_ptr.string, seg->name)) { - nasm_free((*extp)->defwrt_ptr.string); - (*extp)->defwrt_type = DEFWRT_SEGMENT; - (*extp)->defwrt_ptr.seg = seg; - *extp = (*extp)->next_dws; - } else - extp = &(*extp)->next_dws; - } - - if (seg->use32) - *bits = 32; - else - *bits = 16; - current_seg = seg; - return seg->index; - } -} - -static int obj_directive (char *directive, char *value, int pass) -{ - if (!strcmp(directive, "group")) { - char *p, *q, *v; - if (pass == 1) { - struct Group *grp; - struct Segment *seg; - struct External **extp; - int obj_idx; - - q = value; - while (*q == '.') - q++; /* hack, but a documented one */ - v = q; - while (*q && !isspace(*q)) - q++; - if (isspace(*q)) { - *q++ = '\0'; - while (*q && isspace(*q)) - q++; - } - /* - * Here we used to sanity-check the group directive to - * ensure nobody tried to declare a group containing no - * segments. However, OS/2 does this as standard - * practice, so the sanity check has been removed. - * - * if (!*q) { - * error(ERR_NONFATAL,"GROUP directive contains no segments"); - * return 1; - * } - */ - - obj_idx = 1; - for (grp = grphead; grp; grp = grp->next) { - obj_idx++; - if (!strcmp(grp->name, v)) { - error(ERR_NONFATAL, "group `%s' defined twice", v); - return 1; - } - } - - *grptail = grp = nasm_malloc(sizeof(*grp)); - grp->next = NULL; - grptail = &grp->next; - grp->index = seg_alloc(); - grp->obj_index = obj_idx; - grp->nindices = grp->nentries = 0; - grp->name = NULL; - - obj_grp_needs_update = grp; - deflabel (v, grp->index+1, 0L, - NULL, FALSE, FALSE, &of_obj, error); - obj_grp_needs_update = NULL; - - while (*q) { - p = q; - while (*q && !isspace(*q)) - q++; - if (isspace(*q)) { - *q++ = '\0'; - while (*q && isspace(*q)) - q++; - } - /* - * Now p contains a segment name. Find it. - */ - for (seg = seghead; seg; seg = seg->next) - if (!strcmp(seg->name, p)) - break; - if (seg) { - /* - * We have a segment index. Shift a name entry - * to the end of the array to make room. - */ - grp->segs[grp->nentries++] = grp->segs[grp->nindices]; - grp->segs[grp->nindices++].index = seg->obj_index; - if (seg->grp) - error(ERR_WARNING, "segment `%s' is already part of" - " a group: first one takes precedence", - seg->name); - else - seg->grp = grp; - } else { - /* - * We have an as-yet undefined segment. - * Remember its name, for later. - */ - grp->segs[grp->nentries++].name = nasm_strdup(p); - } - } - - /* - * Walk through the list of externals with unresolved - * default-WRT clauses, and resolve any that point at - * this group. - */ - extp = &dws; - while (*extp) { - if ((*extp)->defwrt_type == DEFWRT_STRING && - !strcmp((*extp)->defwrt_ptr.string, grp->name)) { - nasm_free((*extp)->defwrt_ptr.string); - (*extp)->defwrt_type = DEFWRT_GROUP; - (*extp)->defwrt_ptr.grp = grp; - *extp = (*extp)->next_dws; - } else - extp = &(*extp)->next_dws; - } - } - return 1; - } - if (!strcmp(directive, "uppercase")) { - obj_uppercase = TRUE; - return 1; - } - if (!strcmp(directive, "import")) { - char *q, *extname, *libname, *impname; - - if (pass == 2) - return 1; /* ignore in pass two */ - extname = q = value; - while (*q && !isspace(*q)) - q++; - if (isspace(*q)) { - *q++ = '\0'; - while (*q && isspace(*q)) - q++; - } - - libname = q; - while (*q && !isspace(*q)) - q++; - if (isspace(*q)) { - *q++ = '\0'; - while (*q && isspace(*q)) - q++; - } - - impname = q; - - if (!*extname || !*libname) - error(ERR_NONFATAL, "`import' directive requires symbol name" - " and library name"); - else { - struct ImpDef *imp; - int err = FALSE; - - imp = *imptail = nasm_malloc(sizeof(struct ImpDef)); - imptail = &imp->next; - imp->next = NULL; - imp->extname = nasm_strdup(extname); - imp->libname = nasm_strdup(libname); - imp->impindex = readnum(impname, &err); - if (!*impname || err) - imp->impname = nasm_strdup(impname); - else - imp->impname = NULL; - } - - return 1; - } - if (!strcmp(directive, "export")) { - char *q, *extname, *intname, *v; - struct ExpDef *export; - int flags = 0; - unsigned int ordinal = 0; - - if (pass == 2) - return 1; /* ignore in pass two */ - intname = q = value; - while (*q && !isspace(*q)) - q++; - if (isspace(*q)) { - *q++ = '\0'; - while (*q && isspace(*q)) - q++; - } - - extname = q; - while (*q && !isspace(*q)) - q++; - if (isspace(*q)) { - *q++ = '\0'; - while (*q && isspace(*q)) - q++; - } - - if (!*intname) { - error(ERR_NONFATAL, "`export' directive requires export name"); - return 1; - } - if (!*extname) { - extname = intname; - intname = ""; - } - while (*q) { - v = q; - while (*q && !isspace(*q)) - q++; - if (isspace(*q)) { - *q++ = '\0'; - while (*q && isspace(*q)) - q++; - } - if (!nasm_stricmp(v, "resident")) - flags |= EXPDEF_FLAG_RESIDENT; - else if (!nasm_stricmp(v, "nodata")) - flags |= EXPDEF_FLAG_NODATA; - else if (!nasm_strnicmp(v, "parm=", 5)) { - int err = FALSE; - flags |= EXPDEF_MASK_PARMCNT & readnum(v+5, &err); - if (err) { - error(ERR_NONFATAL, - "value `%s' for `parm' is non-numeric", v+5); - return 1; - } - } else { - int err = FALSE; - ordinal = readnum(v, &err); - if (err) { - error(ERR_NONFATAL, "unrecognised export qualifier `%s'", - v); - return 1; - } - flags |= EXPDEF_FLAG_ORDINAL; - } - } - - export = *exptail = nasm_malloc(sizeof(struct ExpDef)); - exptail = &export->next; - export->next = NULL; - export->extname = nasm_strdup(extname); - export->intname = nasm_strdup(intname); - export->ordinal = ordinal; - export->flags = flags; - - return 1; - } - return 0; -} - -static long obj_segbase (long segment) -{ - struct Segment *seg; - - /* - * Find the segment in our list. - */ - for (seg = seghead; seg; seg = seg->next) - if (seg->index == segment-1) - break; - - if (!seg) { - /* - * Might be an external with a default WRT. - */ - long i = segment/2; - struct ExtBack *eb = ebhead; - struct External *e; - - while (i > EXT_BLKSIZ) { - if (eb) - eb = eb->next; - else - break; - i -= EXT_BLKSIZ; - } - if (eb) { - e = eb->exts[i]; - if (e->defwrt_type == DEFWRT_NONE) - return segment; /* fine */ - else if (e->defwrt_type == DEFWRT_SEGMENT) - return e->defwrt_ptr.seg->index+1; - else if (e->defwrt_type == DEFWRT_GROUP) - return e->defwrt_ptr.grp->index+1; - else - return NO_SEG; /* can't tell what it is */ - } - - return segment; /* not one of ours - leave it alone */ - } - - if (seg->align >= SEG_ABS) - return seg->align; /* absolute segment */ - if (seg->grp) - return seg->grp->index+1; /* grouped segment */ - - return segment; /* no special treatment */ -} - -static void obj_filename (char *inname, char *outname, efunc lerror) -{ - strcpy(obj_infile, inname); - standard_extension (inname, outname, ".obj", lerror); -} - -static void obj_write_file (int debuginfo) -{ - struct Segment *seg, *entry_seg_ptr = 0; - struct FileName *fn; - struct LineNumber *ln; - struct Group *grp; - struct Public *pub, *loc; - struct External *ext; - struct ImpDef *imp; - struct ExpDef *export; - static char boast[] = "The Netwide Assembler " NASM_VER; - int lname_idx; - ObjRecord *orp; - - /* - * Write the THEADR module header. - */ - orp = obj_new(); - orp->type = THEADR; - obj_name (orp, obj_infile); - obj_emit2 (orp); - - /* - * Write the NASM boast comment. - */ - orp->type = COMENT; - obj_rword (orp, 0); /* comment type zero */ - obj_name (orp, boast); - obj_emit2 (orp); - - orp->type = COMENT; - /* - * Write the IMPDEF records, if any. - */ - for (imp = imphead; imp; imp = imp->next) { - obj_rword (orp, 0xA0); /* comment class A0 */ - obj_byte (orp, 1); /* subfunction 1: IMPDEF */ - if (imp->impname) - obj_byte (orp, 0); /* import by name */ - else - obj_byte (orp, 1); /* import by ordinal */ - obj_name (orp, imp->extname); - obj_name (orp, imp->libname); - if (imp->impname) - obj_name (orp, imp->impname); - else - obj_word (orp, imp->impindex); - obj_emit2 (orp); - } - - /* - * Write the EXPDEF records, if any. - */ - for (export = exphead; export; export = export->next) { - obj_rword (orp, 0xA0); /* comment class A0 */ - obj_byte (orp, 2); /* subfunction 2: EXPDEF */ - obj_byte (orp, export->flags); - obj_name (orp, export->extname); - obj_name (orp, export->intname); - if (export->flags & EXPDEF_FLAG_ORDINAL) - obj_word (orp, export->ordinal); - obj_emit2 (orp); - } - - /* we're using extended OMF if we put in debug info*/ - if (debuginfo) { - orp->type = COMENT; - obj_byte (orp, 0x40); - obj_byte (orp, dEXTENDED); - obj_emit2 (orp); - } - - /* - * Write the first LNAMES record, containing LNAME one, which - * is null. Also initialise the LNAME counter. - */ - orp->type = LNAMES; - obj_byte (orp, 0); - lname_idx = 1; - /* - * Write some LNAMES for the segment names - */ - for (seg = seghead; seg; seg = seg->next) { - orp = obj_name (orp, seg->name); - if (seg->segclass) - orp = obj_name (orp, seg->segclass); - if (seg->overlay) - orp = obj_name (orp, seg->overlay); - obj_commit (orp); - } - /* - * Write some LNAMES for the group names - */ - for (grp = grphead; grp; grp = grp->next) { - orp = obj_name (orp, grp->name); - obj_commit (orp); - } - obj_emit (orp); - - - /* - * Write the SEGDEF records. - */ - orp->type = SEGDEF; - for (seg = seghead; seg; seg = seg->next) { - int acbp; - unsigned long seglen = seg->currentpos; - - acbp = (seg->combine << 2); /* C field */ - - if (seg->use32) - acbp |= 0x01; /* P bit is Use32 flag */ - else if (seglen == 0x10000L) { - seglen = 0; /* This special case may be needed for old linkers */ - acbp |= 0x02; /* B bit */ - } - - - /* A field */ - if (seg->align >= SEG_ABS) - /* acbp |= 0x00 */; - else if (seg->align >= 4096) { - if (seg->align > 4096) - error(ERR_NONFATAL, "segment `%s' requires more alignment" - " than OBJ format supports", seg->name); - acbp |= 0xC0; /* PharLap extension */ - } else if (seg->align >= 256) { - acbp |= 0x80; - } else if (seg->align >= 16) { - acbp |= 0x60; - } else if (seg->align >= 4) { - acbp |= 0xA0; - } else if (seg->align >= 2) { - acbp |= 0x40; - } else - acbp |= 0x20; - - obj_byte (orp, acbp); - if (seg->align & SEG_ABS) { - obj_x (orp, seg->align - SEG_ABS); /* Frame */ - obj_byte (orp, 0); /* Offset */ - } - obj_x (orp, seglen); - obj_index (orp, ++lname_idx); - obj_index (orp, seg->segclass ? ++lname_idx : 1); - obj_index (orp, seg->overlay ? ++lname_idx : 1); - obj_emit2 (orp); - } - - /* - * Write the GRPDEF records. - */ - orp->type = GRPDEF; - for (grp = grphead; grp; grp = grp->next) { - int i; - - if (grp->nindices != grp->nentries) { - for (i = grp->nindices; i < grp->nentries; i++) { - error(ERR_NONFATAL, "group `%s' contains undefined segment" - " `%s'", grp->name, grp->segs[i].name); - nasm_free (grp->segs[i].name); - grp->segs[i].name = NULL; - } - } - obj_index (orp, ++lname_idx); - for (i = 0; i < grp->nindices; i++) { - obj_byte (orp, 0xFF); - obj_index (orp, grp->segs[i].index); - } - obj_emit2 (orp); - } - - /* - * Write the PUBDEF records: first the ones in the segments, - * then the far-absolutes. - */ - orp->type = PUBDEF; - orp->ori = ori_pubdef; - for (seg = seghead; seg; seg = seg->next) { - orp->parm[0] = seg->grp ? seg->grp->obj_index : 0; - orp->parm[1] = seg->obj_index; - for (pub = seg->pubhead; pub; pub = pub->next) { - orp = obj_name (orp, pub->name); - orp = obj_x (orp, pub->offset); - orp = obj_byte (orp, 0); /* type index */ - obj_commit (orp); - } - obj_emit (orp); - } - orp->parm[0] = 0; - orp->parm[1] = 0; - for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */ - if (orp->parm[2] != pub->segment) { - obj_emit (orp); - orp->parm[2] = pub->segment; - } - orp = obj_name (orp, pub->name); - orp = obj_x (orp, pub->offset); - orp = obj_byte (orp, 0); /* type index */ - obj_commit (orp); - } - obj_emit (orp); - - /* - * Write the EXTDEF and COMDEF records, in order. - */ - orp->ori = ori_null; - for (ext = exthead; ext; ext = ext->next) { - if (ext->commonsize == 0) { - if (orp->type != EXTDEF) { - obj_emit (orp); - orp->type = EXTDEF; - } - orp = obj_name (orp, ext->name); - orp = obj_index (orp, 0); - } else { - if (orp->type != COMDEF) { - obj_emit (orp); - orp->type = COMDEF; - } - orp = obj_name (orp, ext->name); - orp = obj_index (orp, 0); - if (ext->commonelem) { - orp = obj_byte (orp, 0x61);/* far communal */ - orp = obj_value (orp, (ext->commonsize / ext->commonelem)); - orp = obj_value (orp, ext->commonelem); - } else { - orp = obj_byte (orp, 0x62);/* near communal */ - orp = obj_value (orp, ext->commonsize); - } - } - obj_commit (orp); - } - obj_emit (orp); - - /* - * Write a COMENT record stating that the linker's first pass - * may stop processing at this point. Exception is if our - * MODEND record specifies a start point, in which case, - * according to some variants of the documentation, this COMENT - * should be omitted. So we'll omit it just in case. - * But, TASM puts it in all the time so if we are using - * TASM debug stuff we are putting it in - */ - if (debuginfo || obj_entry_seg == NO_SEG) { - orp->type = COMENT; - obj_byte (orp, 0x40); - obj_byte (orp, dLINKPASS); - obj_byte (orp, 1); - obj_emit2 (orp); - } - - /* - * 1) put out the compiler type - * 2) Put out the type info. The only type we are using is near label #19 - */ - if (debuginfo) { - int i; - struct Array *arrtmp = arrhead; - orp->type = COMENT; - obj_byte (orp, 0x40); - obj_byte (orp, dCOMPDEF); - obj_byte (orp, 4); - obj_byte (orp, 0); - obj_emit2 (orp); - - obj_byte (orp, 0x40); - obj_byte (orp, dTYPEDEF); - obj_word (orp, 0x18); /* type # for linking */ - obj_word (orp, 6); /* size of type */ - obj_byte (orp, 0x2a); /* absolute type for debugging */ - obj_emit2 (orp); - obj_byte (orp, 0x40); - obj_byte (orp, dTYPEDEF); - obj_word (orp, 0x19); /* type # for linking */ - obj_word (orp, 0); /* size of type */ - obj_byte (orp, 0x24); /* absolute type for debugging */ - obj_byte (orp, 0); /* near/far specifier */ - obj_emit2 (orp); - obj_byte (orp, 0x40); - obj_byte (orp, dTYPEDEF); - obj_word (orp, 0x1A); /* type # for linking */ - obj_word (orp, 0); /* size of type */ - obj_byte (orp, 0x24); /* absolute type for debugging */ - obj_byte (orp, 1); /* near/far specifier */ - obj_emit2 (orp); - obj_byte (orp, 0x40); - obj_byte (orp, dTYPEDEF); - obj_word (orp, 0x1b); /* type # for linking */ - obj_word (orp, 0); /* size of type */ - obj_byte (orp, 0x23); /* absolute type for debugging */ - obj_byte (orp, 0); - obj_byte (orp, 0); - obj_byte (orp, 0); - obj_emit2 (orp); - obj_byte (orp, 0x40); - obj_byte (orp, dTYPEDEF); - obj_word (orp, 0x1c); /* type # for linking */ - obj_word (orp, 0); /* size of type */ - obj_byte (orp, 0x23); /* absolute type for debugging */ - obj_byte (orp, 0); - obj_byte (orp, 4); - obj_byte (orp, 0); - obj_emit2 (orp); - obj_byte (orp, 0x40); - obj_byte (orp, dTYPEDEF); - obj_word (orp, 0x1d); /* type # for linking */ - obj_word (orp, 0); /* size of type */ - obj_byte (orp, 0x23); /* absolute type for debugging */ - obj_byte (orp, 0); - obj_byte (orp, 1); - obj_byte (orp, 0); - obj_emit2 (orp); - obj_byte (orp, 0x40); - obj_byte (orp, dTYPEDEF); - obj_word (orp, 0x1e); /* type # for linking */ - obj_word (orp, 0); /* size of type */ - obj_byte (orp, 0x23); /* absolute type for debugging */ - obj_byte (orp, 0); - obj_byte (orp, 5); - obj_byte (orp, 0); - obj_emit2 (orp); - - /* put out the array types */ - for (i= ARRAYBOT; i < arrindex; i++) { - obj_byte (orp, 0x40); - obj_byte (orp, dTYPEDEF); - obj_word (orp, i ); /* type # for linking */ - obj_word (orp, arrtmp->size); /* size of type */ - obj_byte (orp, 0x1A); /* absolute type for debugging (array)*/ - obj_byte (orp, arrtmp->basetype ); /* base type */ - obj_emit2 (orp); - arrtmp = arrtmp->next ; - } - } - /* - * write out line number info with a LINNUM record - * switch records when we switch segments, and output the - * file in a pseudo-TASM fashion. The record switch is naive; that - * is that one file may have many records for the same segment - * if there are lots of segment switches - */ - if (fnhead && debuginfo) { - seg = fnhead->lnhead->segment; - - for (fn = fnhead; fn; fn = fn->next) { - /* write out current file name */ - orp->type = COMENT; - orp->ori = ori_null; - obj_byte (orp, 0x40); - obj_byte (orp, dFILNAME); - obj_byte( orp,0); - obj_name( orp,fn->name); - obj_dword(orp, 0); - obj_emit2 (orp); - - /* write out line numbers this file */ - - orp->type = LINNUM; - orp->ori = ori_linnum; - for (ln = fn->lnhead; ln; ln = ln->next) { - if (seg != ln->segment) { - /* if we get here have to flush the buffer and start - * a new record for a new segment - */ - seg = ln->segment; - obj_emit ( orp ); - } - orp->parm[0] = seg->grp ? seg->grp->obj_index : 0; - orp->parm[1] = seg->obj_index; - orp = obj_word(orp, ln->lineno); - orp = obj_x(orp, ln->offset); - obj_commit (orp); - } - obj_emit (orp); - } - } - /* - * we are going to locate the entry point segment now - * rather than wait until the MODEND record, because, - * then we can output a special symbol to tell where the - * entry point is. - * - */ - if (obj_entry_seg != NO_SEG) { - for (seg = seghead; seg; seg = seg->next) { - if (seg->index == obj_entry_seg) { - entry_seg_ptr = seg; - break; - } - } - if (!seg) - error(ERR_NONFATAL, "entry point is not in this module"); - } - - /* - * get ready to put out symbol records - */ - orp->type = COMENT; - orp->ori = ori_local; - - /* - * put out a symbol for the entry point - * no dots in this symbol, because, borland does - * not (officially) support dots in label names - * and I don't know what various versions of TLINK will do - */ - if (debuginfo && obj_entry_seg != NO_SEG) { - orp = obj_name (orp,"start_of_program"); - orp = obj_word (orp,0x19); /* type: near label */ - orp = obj_index (orp, seg->grp ? seg->grp->obj_index : 0); - orp = obj_index (orp, seg->obj_index); - orp = obj_x (orp, obj_entry_ofs); - obj_commit (orp); - } - - /* - * put out the local labels - */ - for (seg = seghead; seg && debuginfo; seg = seg->next) { - /* labels this seg */ - for (loc = seg->lochead; loc; loc = loc->next) { - orp = obj_name (orp,loc->name); - orp = obj_word (orp, loc->type); - orp = obj_index (orp, seg->grp ? seg->grp->obj_index : 0); - orp = obj_index (orp, seg->obj_index); - orp = obj_x (orp,loc->offset); - obj_commit (orp); - } - } - if (orp->used) - obj_emit (orp); - - /* - * Write the LEDATA/FIXUPP pairs. - */ - for (seg = seghead; seg; seg = seg->next) { - obj_emit (seg->orp); - nasm_free (seg->orp); - } - - /* - * Write the MODEND module end marker. - */ - orp->type = obj_use32 ? MODE32 : MODEND; - orp->ori = ori_null; - if (entry_seg_ptr) { - orp->type = entry_seg_ptr->use32 ? MODE32 : MODEND; - obj_byte (orp, 0xC1); - seg = entry_seg_ptr; - if (seg->grp) { - obj_byte (orp, 0x10); - obj_index (orp, seg->grp->obj_index); - } else { - /* - * the below changed to prevent TLINK crashing. - * Previous more efficient version read: - * - * obj_byte (orp, 0x50); - */ - obj_byte (orp, 0x00); - obj_index (orp, seg->obj_index); - } - obj_index (orp, seg->obj_index); - obj_x (orp, obj_entry_ofs); - } else - obj_byte (orp, 0); - obj_emit2 (orp); - nasm_free (orp); -} - -void obj_fwrite(ObjRecord *orp) -{ - unsigned int cksum, len; - unsigned char *ptr; - - cksum = orp->type; - if (orp->x_size == 32) - cksum |= 1; - fputc (cksum, ofp); - len = orp->committed+1; - cksum += (len & 0xFF) + ((len>>8) & 0xFF); - fwriteshort (len, ofp); - fwrite (orp->buf, 1, len-1, ofp); - for (ptr=orp->buf; --len; ptr++) - cksum += *ptr; - fputc ( (-cksum) & 0xFF, ofp); -} - -static const char *obj_stdmac[] = { - "%define __SECT__ [section .text]", - "%imacro group 1+.nolist", - "[group %1]", - "%endmacro", - "%imacro uppercase 0+.nolist", - "[uppercase %1]", - "%endmacro", - "%imacro export 1+.nolist", - "[export %1]", - "%endmacro", - "%imacro import 1+.nolist", - "[import %1]", - "%endmacro", - "%macro __NASM_CDecl__ 1", - "%endmacro", - NULL -}; - -void dbgbi_init(struct ofmt * of, void * id, FILE * fp, efunc error) -{ - (void) of; - (void) id; - (void) fp; - (void) error; - - fnhead = NULL; - fntail = &fnhead; - arrindex = ARRAYBOT ; - arrhead = NULL; - arrtail = &arrhead; -} -static void dbgbi_cleanup(void) -{ - struct Segment *segtmp; - while (fnhead) { - struct FileName *fntemp = fnhead; - while (fnhead->lnhead) { - struct LineNumber *lntemp = fnhead->lnhead; - fnhead->lnhead = lntemp->next; - nasm_free( lntemp); - } - fnhead = fnhead->next; - nasm_free (fntemp->name); - nasm_free (fntemp); - } - for (segtmp=seghead; segtmp; segtmp=segtmp->next) { - while (segtmp->lochead) { - struct Public *loctmp = segtmp->lochead; - segtmp->lochead = loctmp->next; - nasm_free (loctmp->name); - nasm_free (loctmp); - } - } - while (arrhead) { - struct Array *arrtmp = arrhead; - arrhead = arrhead->next; - nasm_free (arrtmp); - } -} - -static void dbgbi_linnum (const char *lnfname, long lineno, long segto) -{ - struct FileName *fn; - struct LineNumber *ln; - struct Segment *seg; - - if (segto == NO_SEG) - return; - - /* - * If `any_segs' is still FALSE, we must define a default - * segment. - */ - if (!any_segs) { - int tempint; /* ignored */ - if (segto != obj_segment("__NASMDEFSEG", 2, &tempint)) - error (ERR_PANIC, "strange segment conditions in OBJ driver"); - } - - /* - * Find the segment we are targetting. - */ - for (seg = seghead; seg; seg = seg->next) - if (seg->index == segto) - break; - if (!seg) - error (ERR_PANIC, "lineno directed to nonexistent segment?"); - -/* for (fn = fnhead; fn; fn = fnhead->next) */ - for (fn = fnhead; fn; fn = fn->next) /* fbk - Austin Lunnen - John Fine*/ - if (!nasm_stricmp(lnfname,fn->name)) - break; - if (!fn) { - fn = nasm_malloc ( sizeof( *fn)); - fn->name = nasm_malloc ( strlen(lnfname) + 1) ; - strcpy (fn->name,lnfname); - fn->lnhead = NULL; - fn->lntail = & fn->lnhead; - fn->next = NULL; - *fntail = fn; - fntail = &fn->next; - } - ln = nasm_malloc ( sizeof( *ln)); - ln->segment = seg; - ln->offset = seg->currentpos; - ln->lineno = lineno; - ln->next = NULL; - *fn->lntail = ln; - fn->lntail = &ln->next; - -} -static void dbgbi_deflabel (char *name, long segment, - long offset, int is_global, char *special) -{ - struct Segment *seg; - - (void) special; - - /* - * If it's a special-retry from pass two, discard it. - */ - if (is_global == 3) - return; - - /* - * First check for the double-period, signifying something - * unusual. - */ - if (name[0] == '.' && name[1] == '.' && name[2] != '@') { - return; - } - - /* - * Case (i): - */ - if (obj_seg_needs_update) { - return; - } else if (obj_grp_needs_update) { - return; - } - if (segment < SEG_ABS && segment != NO_SEG && segment % 2) - return; - - if (segment >= SEG_ABS || segment == NO_SEG) { - return; - } - - /* - * If `any_segs' is still FALSE, we might need to define a - * default segment, if they're trying to declare a label in - * `first_seg'. But the label should exist due to a prior - * call to obj_deflabel so we can skip that. - */ - - for (seg = seghead; seg; seg = seg->next) - if (seg->index == segment) { - struct Public *loc = nasm_malloc (sizeof(*loc)); - /* - * Case (ii). Maybe MODPUB someday? - */ - last_defined = *seg->loctail = loc; - seg->loctail = &loc->next; - loc->next = NULL; - loc->name = nasm_strdup(name); - loc->offset = offset; - } -} -static void dbgbi_typevalue (long type) -{ - int vsize; - int elem = TYM_ELEMENTS(type); - type = TYM_TYPE(type); - - if (!last_defined) - return; - - switch (type) { - case TY_BYTE: - last_defined->type = 8; /* unsigned char */ - vsize = 1; - break; - case TY_WORD: - last_defined->type = 10; /* unsigned word */ - vsize = 2; - break; - case TY_DWORD: - last_defined->type = 12; /* unsigned dword */ - vsize = 4; - break; - case TY_FLOAT: - last_defined->type = 14; /* float */ - vsize = 4; - break; - case TY_QWORD: - last_defined->type = 15; /* qword */ - vsize = 8; - break; - case TY_TBYTE: - last_defined->type = 16; /* TBYTE */ - vsize = 10; - break; - default: - last_defined->type = 0x19; /*label */ - vsize = 0; - break; - } - - if (elem > 1) { - struct Array *arrtmp = nasm_malloc (sizeof(*arrtmp)); - int vtype = last_defined->type; - arrtmp->size = vsize * elem; - arrtmp->basetype = vtype; - arrtmp->next = NULL; - last_defined->type = arrindex++; - *arrtail = arrtmp; - arrtail = & (arrtmp->next); - } - last_defined = NULL; -} -static void dbgbi_output (int output_type, void *param) -{ - (void) output_type; - (void) param; -} -static struct dfmt borland_debug_form = { - "Borland Debug Records", - "borland", - dbgbi_init, - dbgbi_linnum, - dbgbi_deflabel, - null_debug_routine, - dbgbi_typevalue, - dbgbi_output, - dbgbi_cleanup, -}; - -static struct dfmt *borland_debug_arr[3] = { - &borland_debug_form, - &null_debug_form, - NULL -}; - -struct ofmt of_obj = { - "MS-DOS 16-bit/32-bit OMF object files", - "obj", - NULL, - borland_debug_arr, - &null_debug_form, - obj_stdmac, - obj_init, - obj_set_info, - obj_out, - obj_deflabel, - obj_segment, - obj_segbase, - obj_directive, - obj_filename, - obj_cleanup -}; -#endif /* OF_OBJ */ +/* outobj.c output routines for the Netwide Assembler to produce + * .OBJ object files + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "outform.h" + +#ifdef OF_OBJ + +/* + * outobj.c is divided into two sections. The first section is low level + * routines for creating obj records; It has nearly zero NASM specific + * code. The second section is high level routines for processing calls and + * data structures from the rest of NASM into obj format. + * + * It should be easy (though not zero work) to lift the first section out for + * use as an obj file writer for some other assembler or compiler. + */ + +/* + * These routines are built around the ObjRecord data struture. An ObjRecord + * holds an object file record that may be under construction or complete. + * + * A major function of these routines is to support continuation of an obj + * record into the next record when the maximum record size is exceeded. The + * high level code does not need to worry about where the record breaks occur. + * It does need to do some minor extra steps to make the automatic continuation + * work. Those steps may be skipped for records where the high level knows no + * continuation could be required. + * + * 1) An ObjRecord is allocated and cleared by obj_new, or an existing ObjRecord + * is cleared by obj_clear. + * + * 2) The caller should fill in .type. + * + * 3) If the record is continuable and there is processing that must be done at + * the start of each record then the caller should fill in .ori with the + * address of the record initializer routine. + * + * 4) If the record is continuable and it should be saved (rather than emitted + * immediately) as each record is done, the caller should set .up to be a + * pointer to a location in which the caller keeps the master pointer to the + * ObjRecord. When the record is continued, the obj_bump routine will then + * allocate a new ObjRecord structure and update the master pointer. + * + * 5) If the .ori field was used then the caller should fill in the .parm with + * any data required by the initializer. + * + * 6) The caller uses the routines: obj_byte, obj_word, obj_rword, obj_dword, + * obj_x, obj_index, obj_value and obj_name to fill in the various kinds of + * data required for this record. + * + * 7) If the record is continuable, the caller should call obj_commit at each + * point where breaking the record is permitted. + * + * 8) To write out the record, the caller should call obj_emit2. If the + * caller has called obj_commit for all data written then he can get slightly + * faster code by calling obj_emit instead of obj_emit2. + * + * Most of these routines return an ObjRecord pointer. This will be the input + * pointer most of the time and will be the new location if the ObjRecord + * moved as a result of the call. The caller may ignore the return value in + * three cases: It is a "Never Reallocates" routine; or The caller knows + * continuation is not possible; or The caller uses the master pointer for the + * next operation. + */ + +#define RECORD_MAX (1024-3) /* maximal size of any record except type+reclen */ +#define OBJ_PARMS 3 /* maximum .parm used by any .ori routine */ + +#define FIX_08_LOW 0x8000 /* location type for various fixup subrecords */ +#define FIX_16_OFFSET 0x8400 +#define FIX_16_SELECTOR 0x8800 +#define FIX_32_POINTER 0x8C00 +#define FIX_08_HIGH 0x9000 +#define FIX_32_OFFSET 0xA400 +#define FIX_48_POINTER 0xAC00 + +enum RecordID { /* record ID codes */ + + THEADR = 0x80, /* module header */ + COMENT = 0x88, /* comment record */ + + LINNUM = 0x94, /* line number record */ + LNAMES = 0x96, /* list of names */ + + SEGDEF = 0x98, /* segment definition */ + GRPDEF = 0x9A, /* group definition */ + EXTDEF = 0x8C, /* external definition */ + PUBDEF = 0x90, /* public definition */ + COMDEF = 0xB0, /* common definition */ + + LEDATA = 0xA0, /* logical enumerated data */ + FIXUPP = 0x9C, /* fixups (relocations) */ + FIXU32 = 0x9D, /* 32-bit fixups (relocations) */ + + MODEND = 0x8A, /* module end */ + MODE32 = 0x8B /* module end for 32-bit objects */ +}; + +enum ComentID { /* ID codes for comment records */ + + dEXTENDED = 0xA1, /* tells that we are using translator-specific extensions */ + dLINKPASS = 0xA2, /* link pass 2 marker */ + dTYPEDEF = 0xE3, /* define a type */ + dSYM = 0xE6, /* symbol debug record */ + dFILNAME = 0xE8, /* file name record */ + dCOMPDEF = 0xEA /* compiler type info */ +}; + +typedef struct ObjRecord ObjRecord; +typedef void ORI(ObjRecord * orp); + +struct ObjRecord { + ORI *ori; /* Initialization routine */ + int used; /* Current data size */ + int committed; /* Data size at last boundary */ + int x_size; /* (see obj_x) */ + unsigned int type; /* Record type */ + ObjRecord *child; /* Associated record below this one */ + ObjRecord **up; /* Master pointer to this ObjRecord */ + ObjRecord *back; /* Previous part of this record */ + unsigned long parm[OBJ_PARMS]; /* Parameters for ori routine */ + unsigned char buf[RECORD_MAX + 3]; +}; + +static void obj_fwrite(ObjRecord * orp); +static void ori_ledata(ObjRecord * orp); +static void ori_pubdef(ObjRecord * orp); +static void ori_null(ObjRecord * orp); +static ObjRecord *obj_commit(ObjRecord * orp); + +static int obj_uppercase; /* Flag: all names in uppercase */ +static int obj_use32; /* Flag: at least one segment is 32-bit */ + +/* + * Clear an ObjRecord structure. (Never reallocates). + * To simplify reuse of ObjRecord's, .type, .ori and .parm are not cleared. + */ +static ObjRecord *obj_clear(ObjRecord * orp) +{ + orp->used = 0; + orp->committed = 0; + orp->x_size = 0; + orp->child = NULL; + orp->up = NULL; + orp->back = NULL; + return (orp); +} + +/* + * Emit an ObjRecord structure. (Never reallocates). + * The record is written out preceeded (recursively) by its previous part (if + * any) and followed (recursively) by its child (if any). + * The previous part and the child are freed. The main ObjRecord is cleared, + * not freed. + */ +static ObjRecord *obj_emit(ObjRecord * orp) +{ + if (orp->back) { + obj_emit(orp->back); + nasm_free(orp->back); + } + + if (orp->committed) + obj_fwrite(orp); + + if (orp->child) { + obj_emit(orp->child); + nasm_free(orp->child); + } + + return (obj_clear(orp)); +} + +/* + * Commit and Emit a record. (Never reallocates). + */ +static ObjRecord *obj_emit2(ObjRecord * orp) +{ + obj_commit(orp); + return (obj_emit(orp)); +} + +/* + * Allocate and clear a new ObjRecord; Also sets .ori to ori_null + */ +static ObjRecord *obj_new(void) +{ + ObjRecord *orp; + + orp = obj_clear(nasm_malloc(sizeof(ObjRecord))); + orp->ori = ori_null; + return (orp); +} + +/* + * Advance to the next record because the existing one is full or its x_size + * is incompatible. + * Any uncommited data is moved into the next record. + */ +static ObjRecord *obj_bump(ObjRecord * orp) +{ + ObjRecord *nxt; + int used = orp->used; + int committed = orp->committed; + + if (orp->up) { + *orp->up = nxt = obj_new(); + nxt->ori = orp->ori; + nxt->type = orp->type; + nxt->up = orp->up; + nxt->back = orp; + memcpy(nxt->parm, orp->parm, sizeof(orp->parm)); + } else + nxt = obj_emit(orp); + + used -= committed; + if (used) { + nxt->committed = 1; + nxt->ori(nxt); + nxt->committed = nxt->used; + memcpy(nxt->buf + nxt->committed, orp->buf + committed, used); + nxt->used = nxt->committed + used; + } + + return (nxt); +} + +/* + * Advance to the next record if necessary to allow the next field to fit. + */ +static ObjRecord *obj_check(ObjRecord * orp, int size) +{ + if (orp->used + size > RECORD_MAX) + orp = obj_bump(orp); + + if (!orp->committed) { + orp->committed = 1; + orp->ori(orp); + orp->committed = orp->used; + } + + return (orp); +} + +/* + * All data written so far is commited to the current record (won't be moved to + * the next record in case of continuation). + */ +static ObjRecord *obj_commit(ObjRecord * orp) +{ + orp->committed = orp->used; + return (orp); +} + +/* + * Write a byte + */ +static ObjRecord *obj_byte(ObjRecord * orp, unsigned char val) +{ + orp = obj_check(orp, 1); + orp->buf[orp->used] = val; + orp->used++; + return (orp); +} + +/* + * Write a word + */ +static ObjRecord *obj_word(ObjRecord * orp, unsigned int val) +{ + orp = obj_check(orp, 2); + orp->buf[orp->used] = val; + orp->buf[orp->used + 1] = val >> 8; + orp->used += 2; + return (orp); +} + +/* + * Write a reversed word + */ +static ObjRecord *obj_rword(ObjRecord * orp, unsigned int val) +{ + orp = obj_check(orp, 2); + orp->buf[orp->used] = val >> 8; + orp->buf[orp->used + 1] = val; + orp->used += 2; + return (orp); +} + +/* + * Write a dword + */ +static ObjRecord *obj_dword(ObjRecord * orp, unsigned long val) +{ + orp = obj_check(orp, 4); + orp->buf[orp->used] = val; + orp->buf[orp->used + 1] = val >> 8; + orp->buf[orp->used + 2] = val >> 16; + orp->buf[orp->used + 3] = val >> 24; + orp->used += 4; + return (orp); +} + +/* + * All fields of "size x" in one obj record must be the same size (either 16 + * bits or 32 bits). There is a one bit flag in each record which specifies + * which. + * This routine is used to force the current record to have the desired + * x_size. x_size is normally automatic (using obj_x), so that this + * routine should be used outside obj_x, only to provide compatibility with + * linkers that have bugs in their processing of the size bit. + */ + +static ObjRecord *obj_force(ObjRecord * orp, int x) +{ + if (orp->x_size == (x ^ 48)) + orp = obj_bump(orp); + orp->x_size = x; + return (orp); +} + +/* + * This routine writes a field of size x. The caller does not need to worry at + * all about whether 16-bits or 32-bits are required. + */ +static ObjRecord *obj_x(ObjRecord * orp, unsigned long val) +{ + if (orp->type & 1) + orp->x_size = 32; + if (val > 0xFFFF) + orp = obj_force(orp, 32); + if (orp->x_size == 32) + return (obj_dword(orp, val)); + orp->x_size = 16; + return (obj_word(orp, val)); +} + +/* + * Writes an index + */ +static ObjRecord *obj_index(ObjRecord * orp, unsigned int val) +{ + if (val < 128) + return (obj_byte(orp, val)); + return (obj_word(orp, (val >> 8) | (val << 8) | 0x80)); +} + +/* + * Writes a variable length value + */ +static ObjRecord *obj_value(ObjRecord * orp, unsigned long val) +{ + if (val <= 128) + return (obj_byte(orp, val)); + if (val <= 0xFFFF) { + orp = obj_byte(orp, 129); + return (obj_word(orp, val)); + } + if (val <= 0xFFFFFF) + return (obj_dword(orp, (val << 8) + 132)); + orp = obj_byte(orp, 136); + return (obj_dword(orp, val)); +} + +/* + * Writes a counted string + */ +static ObjRecord *obj_name(ObjRecord * orp, char *name) +{ + int len = strlen(name); + unsigned char *ptr; + + orp = obj_check(orp, len + 1); + ptr = orp->buf + orp->used; + *ptr++ = len; + orp->used += len + 1; + if (obj_uppercase) + while (--len >= 0) { + *ptr++ = toupper(*name); + name++; + } else + memcpy(ptr, name, len); + return (orp); +} + +/* + * Initializer for an LEDATA record. + * parm[0] = offset + * parm[1] = segment index + * During the use of a LEDATA ObjRecord, parm[0] is constantly updated to + * represent the offset that would be required if the record were split at the + * last commit point. + * parm[2] is a copy of parm[0] as it was when the current record was initted. + */ +static void ori_ledata(ObjRecord * orp) +{ + obj_index(orp, orp->parm[1]); + orp->parm[2] = orp->parm[0]; + obj_x(orp, orp->parm[0]); +} + +/* + * Initializer for a PUBDEF record. + * parm[0] = group index + * parm[1] = segment index + * parm[2] = frame (only used when both indexes are zero) + */ +static void ori_pubdef(ObjRecord * orp) +{ + obj_index(orp, orp->parm[0]); + obj_index(orp, orp->parm[1]); + if (!(orp->parm[0] | orp->parm[1])) + obj_word(orp, orp->parm[2]); +} + +/* + * Initializer for a LINNUM record. + * parm[0] = group index + * parm[1] = segment index + */ +static void ori_linnum(ObjRecord * orp) +{ + obj_index(orp, orp->parm[0]); + obj_index(orp, orp->parm[1]); +} + +/* + * Initializer for a local vars record. + */ +static void ori_local(ObjRecord * orp) +{ + obj_byte(orp, 0x40); + obj_byte(orp, dSYM); +} + +/* + * Null initializer for records that continue without any header info + */ +static void ori_null(ObjRecord * orp) +{ + (void)orp; /* Do nothing */ +} + +/* + * This concludes the low level section of outobj.c + */ + +static char obj_infile[FILENAME_MAX]; + +static efunc error; +static evalfunc evaluate; +static ldfunc deflabel; +static FILE *ofp; +static long first_seg; +static int any_segs; +static int passtwo; +static int arrindex; + +#define GROUP_MAX 256 /* we won't _realistically_ have more + * than this many segs in a group */ +#define EXT_BLKSIZ 256 /* block size for externals list */ + +struct Segment; /* need to know these structs exist */ +struct Group; + +struct LineNumber { + struct LineNumber *next; + struct Segment *segment; + long offset; + long lineno; +}; + +static struct FileName { + struct FileName *next; + char *name; + struct LineNumber *lnhead, **lntail; + int index; +} *fnhead, **fntail; + +static struct Array { + struct Array *next; + unsigned size; + int basetype; +} *arrhead, **arrtail; + +#define ARRAYBOT 31 /* magic number for first array index */ + +static struct Public { + struct Public *next; + char *name; + long offset; + long segment; /* only if it's far-absolute */ + int type; /* only for local debug syms */ +} *fpubhead, **fpubtail, *last_defined; + +static struct External { + struct External *next; + char *name; + long commonsize; + long commonelem; /* element size if FAR, else zero */ + int index; /* OBJ-file external index */ + enum { + DEFWRT_NONE, /* no unusual default-WRT */ + DEFWRT_STRING, /* a string we don't yet understand */ + DEFWRT_SEGMENT, /* a segment */ + DEFWRT_GROUP /* a group */ + } defwrt_type; + union { + char *string; + struct Segment *seg; + struct Group *grp; + } defwrt_ptr; + struct External *next_dws; /* next with DEFWRT_STRING */ +} *exthead, **exttail, *dws; + +static int externals; + +static struct ExtBack { + struct ExtBack *next; + struct External *exts[EXT_BLKSIZ]; +} *ebhead, **ebtail; + +static struct Segment { + struct Segment *next; + long index; /* the NASM segment id */ + long obj_index; /* the OBJ-file segment index */ + struct Group *grp; /* the group it belongs to */ + unsigned long currentpos; + long align; /* can be SEG_ABS + absolute addr */ + enum { + CMB_PRIVATE = 0, + CMB_PUBLIC = 2, + CMB_STACK = 5, + CMB_COMMON = 6 + } combine; + long use32; /* is this segment 32-bit? */ + struct Public *pubhead, **pubtail, *lochead, **loctail; + char *name; + char *segclass, *overlay; /* `class' is a C++ keyword :-) */ + ObjRecord *orp; +} *seghead, **segtail, *obj_seg_needs_update; + +static struct Group { + struct Group *next; + char *name; + long index; /* NASM segment id */ + long obj_index; /* OBJ-file group index */ + long nentries; /* number of elements... */ + long nindices; /* ...and number of index elts... */ + union { + long index; + char *name; + } segs[GROUP_MAX]; /* ...in this */ +} *grphead, **grptail, *obj_grp_needs_update; + +static struct ImpDef { + struct ImpDef *next; + char *extname; + char *libname; + unsigned int impindex; + char *impname; +} *imphead, **imptail; + +static struct ExpDef { + struct ExpDef *next; + char *intname; + char *extname; + unsigned int ordinal; + int flags; +} *exphead, **exptail; + +#define EXPDEF_FLAG_ORDINAL 0x80 +#define EXPDEF_FLAG_RESIDENT 0x40 +#define EXPDEF_FLAG_NODATA 0x20 +#define EXPDEF_MASK_PARMCNT 0x1F + +static long obj_entry_seg, obj_entry_ofs; + +struct ofmt of_obj; + +/* The current segment */ +static struct Segment *current_seg; + +static long obj_segment(char *, int, int *); +static void obj_write_file(int debuginfo); +static int obj_directive(char *, char *, int); + +static void obj_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + ofp = fp; + error = errfunc; + evaluate = eval; + deflabel = ldef; + first_seg = seg_alloc(); + any_segs = FALSE; + fpubhead = NULL; + fpubtail = &fpubhead; + exthead = NULL; + exttail = &exthead; + imphead = NULL; + imptail = &imphead; + exphead = NULL; + exptail = &exphead; + dws = NULL; + externals = 0; + ebhead = NULL; + ebtail = &ebhead; + seghead = obj_seg_needs_update = NULL; + segtail = &seghead; + grphead = obj_grp_needs_update = NULL; + grptail = &grphead; + obj_entry_seg = NO_SEG; + obj_uppercase = FALSE; + obj_use32 = FALSE; + passtwo = 0; + current_seg = NULL; + + of_obj.current_dfmt->init(&of_obj, NULL, fp, errfunc); +} + +static int obj_set_info(enum geninfo type, char **val) +{ + (void)type; + (void)val; + + return 0; +} +static void obj_cleanup(int debuginfo) +{ + obj_write_file(debuginfo); + of_obj.current_dfmt->cleanup(); + fclose(ofp); + while (seghead) { + struct Segment *segtmp = seghead; + seghead = seghead->next; + while (segtmp->pubhead) { + struct Public *pubtmp = segtmp->pubhead; + segtmp->pubhead = pubtmp->next; + nasm_free(pubtmp->name); + nasm_free(pubtmp); + } + nasm_free(segtmp->segclass); + nasm_free(segtmp->overlay); + nasm_free(segtmp); + } + while (fpubhead) { + struct Public *pubtmp = fpubhead; + fpubhead = fpubhead->next; + nasm_free(pubtmp->name); + nasm_free(pubtmp); + } + while (exthead) { + struct External *exttmp = exthead; + exthead = exthead->next; + nasm_free(exttmp); + } + while (imphead) { + struct ImpDef *imptmp = imphead; + imphead = imphead->next; + nasm_free(imptmp->extname); + nasm_free(imptmp->libname); + nasm_free(imptmp->impname); /* nasm_free won't mind if it's NULL */ + nasm_free(imptmp); + } + while (exphead) { + struct ExpDef *exptmp = exphead; + exphead = exphead->next; + nasm_free(exptmp->extname); + nasm_free(exptmp->intname); + nasm_free(exptmp); + } + while (ebhead) { + struct ExtBack *ebtmp = ebhead; + ebhead = ebhead->next; + nasm_free(ebtmp); + } + while (grphead) { + struct Group *grptmp = grphead; + grphead = grphead->next; + nasm_free(grptmp); + } +} + +static void obj_ext_set_defwrt(struct External *ext, char *id) +{ + struct Segment *seg; + struct Group *grp; + + for (seg = seghead; seg; seg = seg->next) + if (!strcmp(seg->name, id)) { + ext->defwrt_type = DEFWRT_SEGMENT; + ext->defwrt_ptr.seg = seg; + nasm_free(id); + return; + } + + for (grp = grphead; grp; grp = grp->next) + if (!strcmp(grp->name, id)) { + ext->defwrt_type = DEFWRT_GROUP; + ext->defwrt_ptr.grp = grp; + nasm_free(id); + return; + } + + ext->defwrt_type = DEFWRT_STRING; + ext->defwrt_ptr.string = id; + ext->next_dws = dws; + dws = ext; +} + +static void obj_deflabel(char *name, long segment, + long offset, int is_global, char *special) +{ + /* + * We have three cases: + * + * (i) `segment' is a segment-base. If so, set the name field + * for the segment or group structure it refers to, and then + * return. + * + * (ii) `segment' is one of our segments, or a SEG_ABS segment. + * Save the label position for later output of a PUBDEF record. + * (Or a MODPUB, if we work out how.) + * + * (iii) `segment' is not one of our segments. Save the label + * position for later output of an EXTDEF, and also store a + * back-reference so that we can map later references to this + * segment number to the external index. + */ + struct External *ext; + struct ExtBack *eb; + struct Segment *seg; + int i; + int used_special = FALSE; /* have we used the special text? */ + +#if defined(DEBUG) && DEBUG>2 + fprintf(stderr, + " obj_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n", + name, segment, offset, is_global, special); +#endif + + /* + * If it's a special-retry from pass two, discard it. + */ + if (is_global == 3) + return; + + /* + * First check for the double-period, signifying something + * unusual. + */ + if (name[0] == '.' && name[1] == '.' && name[2] != '@') { + if (!strcmp(name, "..start")) { + obj_entry_seg = segment; + obj_entry_ofs = offset; + return; + } + error(ERR_NONFATAL, "unrecognised special symbol `%s'", name); + } + + /* + * Case (i): + */ + if (obj_seg_needs_update) { + obj_seg_needs_update->name = name; + return; + } else if (obj_grp_needs_update) { + obj_grp_needs_update->name = name; + return; + } + if (segment < SEG_ABS && segment != NO_SEG && segment % 2) + return; + + if (segment >= SEG_ABS || segment == NO_SEG) { + /* + * SEG_ABS subcase of (ii). + */ + if (is_global) { + struct Public *pub; + + pub = *fpubtail = nasm_malloc(sizeof(*pub)); + fpubtail = &pub->next; + pub->next = NULL; + pub->name = nasm_strdup(name); + pub->offset = offset; + pub->segment = (segment == NO_SEG ? 0 : segment & ~SEG_ABS); + } + if (special) + error(ERR_NONFATAL, "OBJ supports no special symbol features" + " for this symbol type"); + return; + } + + /* + * If `any_segs' is still FALSE, we might need to define a + * default segment, if they're trying to declare a label in + * `first_seg'. + */ + if (!any_segs && segment == first_seg) { + int tempint; /* ignored */ + if (segment != obj_segment("__NASMDEFSEG", 2, &tempint)) + error(ERR_PANIC, "strange segment conditions in OBJ driver"); + } + + for (seg = seghead; seg && is_global; seg = seg->next) + if (seg->index == segment) { + struct Public *loc = nasm_malloc(sizeof(*loc)); + /* + * Case (ii). Maybe MODPUB someday? + */ + *seg->pubtail = loc; + seg->pubtail = &loc->next; + loc->next = NULL; + loc->name = nasm_strdup(name); + loc->offset = offset; + + if (special) + error(ERR_NONFATAL, + "OBJ supports no special symbol features" + " for this symbol type"); + return; + } + + /* + * Case (iii). + */ + if (is_global) { + ext = *exttail = nasm_malloc(sizeof(*ext)); + ext->next = NULL; + exttail = &ext->next; + ext->name = name; + /* Place by default all externs into the current segment */ + ext->defwrt_type = DEFWRT_NONE; + +/* 28-Apr-2002 - John Coffman + The following code was introduced on 12-Aug-2000, and breaks fixups + on code passed thru the MSC 5.1 linker (3.66) and MSC 6.00A linker + (5.10). It was introduced after FIXUP32 was added, and may be needed + for 32-bit segments. The following will get 16-bit segments working + again, and maybe someone can correct the 'if' condition which is + actually needed. +*/ +#if 0 + if (current_seg) { +#else + if (current_seg && current_seg->use32) { + if (current_seg->grp) { + ext->defwrt_type = DEFWRT_GROUP; + ext->defwrt_ptr.grp = current_seg->grp; + } else { + ext->defwrt_type = DEFWRT_SEGMENT; + ext->defwrt_ptr.seg = current_seg; + } + } +#endif + + if (is_global == 2) { + ext->commonsize = offset; + ext->commonelem = 1; /* default FAR */ + } else + ext->commonsize = 0; + } else + return; + + /* + * Now process the special text, if any, to find default-WRT + * specifications and common-variable element-size and near/far + * specifications. + */ + while (special && *special) { + used_special = TRUE; + + /* + * We might have a default-WRT specification. + */ + if (!nasm_strnicmp(special, "wrt", 3)) { + char *p; + int len; + special += 3; + special += strspn(special, " \t"); + p = nasm_strndup(special, len = strcspn(special, ":")); + obj_ext_set_defwrt(ext, p); + special += len; + if (*special && *special != ':') + error(ERR_NONFATAL, "`:' expected in special symbol" + " text for `%s'", ext->name); + else if (*special == ':') + special++; + } + + /* + * The NEAR or FAR keywords specify nearness or + * farness. FAR gives default element size 1. + */ + if (!nasm_strnicmp(special, "far", 3)) { + if (ext->commonsize) + ext->commonelem = 1; + else + error(ERR_NONFATAL, + "`%s': `far' keyword may only be applied" + " to common variables\n", ext->name); + special += 3; + special += strspn(special, " \t"); + } else if (!nasm_strnicmp(special, "near", 4)) { + if (ext->commonsize) + ext->commonelem = 0; + else + error(ERR_NONFATAL, + "`%s': `far' keyword may only be applied" + " to common variables\n", ext->name); + special += 4; + special += strspn(special, " \t"); + } + + /* + * If it's a common, and anything else remains on the line + * before a further colon, evaluate it as an expression and + * use that as the element size. Forward references aren't + * allowed. + */ + if (*special == ':') + special++; + else if (*special) { + if (ext->commonsize) { + expr *e; + struct tokenval tokval; + + stdscan_reset(); + stdscan_bufptr = special; + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL); + if (e) { + if (!is_simple(e)) + error(ERR_NONFATAL, "cannot use relocatable" + " expression as common-variable element size"); + else + ext->commonelem = reloc_value(e); + } + special = stdscan_bufptr; + } else { + error(ERR_NONFATAL, + "`%s': element-size specifications only" + " apply to common variables", ext->name); + while (*special && *special != ':') + special++; + if (*special == ':') + special++; + } + } + } + + i = segment / 2; + eb = ebhead; + if (!eb) { + eb = *ebtail = nasm_malloc(sizeof(*eb)); + eb->next = NULL; + ebtail = &eb->next; + } + while (i >= EXT_BLKSIZ) { + if (eb && eb->next) + eb = eb->next; + else { + eb = *ebtail = nasm_malloc(sizeof(*eb)); + eb->next = NULL; + ebtail = &eb->next; + } + i -= EXT_BLKSIZ; + } + eb->exts[i] = ext; + ext->index = ++externals; + + if (special && !used_special) + error(ERR_NONFATAL, "OBJ supports no special symbol features" + " for this symbol type"); +} + +/* forward declaration */ +static void obj_write_fixup(ObjRecord * orp, int bytes, + int segrel, long seg, long wrt, + struct Segment *segto); + +static void obj_out(long segto, const void *data, unsigned long type, + long segment, long wrt) +{ + unsigned long size, realtype; + const unsigned char *ucdata; + long ldata; + struct Segment *seg; + ObjRecord *orp; + + /* + * handle absolute-assembly (structure definitions) + */ + if (segto == NO_SEG) { + if ((type & OUT_TYPMASK) != OUT_RESERVE) + error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" + " space"); + return; + } + + /* + * If `any_segs' is still FALSE, we must define a default + * segment. + */ + if (!any_segs) { + int tempint; /* ignored */ + if (segto != obj_segment("__NASMDEFSEG", 2, &tempint)) + error(ERR_PANIC, "strange segment conditions in OBJ driver"); + } + + /* + * Find the segment we are targetting. + */ + for (seg = seghead; seg; seg = seg->next) + if (seg->index == segto) + break; + if (!seg) + error(ERR_PANIC, "code directed to nonexistent segment?"); + + orp = seg->orp; + orp->parm[0] = seg->currentpos; + + size = type & OUT_SIZMASK; + realtype = type & OUT_TYPMASK; + if (realtype == OUT_RAWDATA) { + ucdata = data; + while (size > 0) { + unsigned int len; + orp = obj_check(seg->orp, 1); + len = RECORD_MAX - orp->used; + if (len > size) + len = size; + memcpy(orp->buf + orp->used, ucdata, len); + orp->committed = orp->used += len; + orp->parm[0] = seg->currentpos += len; + ucdata += len; + size -= len; + } + } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR || + realtype == OUT_REL4ADR) { + int rsize; + + if (segment == NO_SEG && realtype != OUT_ADDRESS) + error(ERR_NONFATAL, "relative call to absolute address not" + " supported by OBJ format"); + if (segment >= SEG_ABS) + error(ERR_NONFATAL, "far-absolute relocations not supported" + " by OBJ format"); + ldata = *(long *)data; + if (realtype == OUT_REL2ADR) { + ldata += (size - 2); + size = 2; + } + if (realtype == OUT_REL4ADR) { + ldata += (size - 4); + size = 4; + } + if (size == 2) + orp = obj_word(orp, ldata); + else + orp = obj_dword(orp, ldata); + rsize = size; + if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) && + size == 4) { + /* + * This is a 4-byte segment-base relocation such as + * `MOV EAX,SEG foo'. OBJ format can't actually handle + * these, but if the constant term has the 16 low bits + * zero, we can just apply a 2-byte segment-base + * relocation to the low word instead. + */ + rsize = 2; + if (ldata & 0xFFFF) + error(ERR_NONFATAL, "OBJ format cannot handle complex" + " dword-size segment base references"); + } + if (segment != NO_SEG) + obj_write_fixup(orp, rsize, + (realtype == OUT_ADDRESS ? 0x4000 : 0), + segment, wrt, seg); + seg->currentpos += size; + } else if (realtype == OUT_RESERVE) { + if (orp->committed) + orp = obj_bump(orp); + seg->currentpos += size; + } + obj_commit(orp); +} + +static void obj_write_fixup(ObjRecord * orp, int bytes, + int segrel, long seg, long wrt, + struct Segment *segto) +{ + unsigned locat; + int method; + int base; + long tidx, fidx; + struct Segment *s = NULL; + struct Group *g = NULL; + struct External *e = NULL; + ObjRecord *forp; + + if (bytes == 1) { + error(ERR_NONFATAL, "`obj' output driver does not support" + " one-byte relocations"); + return; + } + + forp = orp->child; + if (forp == NULL) { + orp->child = forp = obj_new(); + forp->up = &(orp->child); + /* We should choose between FIXUPP and FIXU32 record type */ + /* If we're targeting a 32-bit segment, use a FIXU32 record */ + if (segto->use32) + forp->type = FIXU32; + else + forp->type = FIXUPP; + } + + if (seg % 2) { + base = TRUE; + locat = FIX_16_SELECTOR; + seg--; + if (bytes != 2) + error(ERR_PANIC, "OBJ: 4-byte segment base fixup got" + " through sanity check"); + } else { + base = FALSE; + locat = (bytes == 2) ? FIX_16_OFFSET : FIX_32_OFFSET; + if (!segrel) + /* + * There is a bug in tlink that makes it process self relative + * fixups incorrectly if the x_size doesn't match the location + * size. + */ + forp = obj_force(forp, bytes << 3); + } + + forp = obj_rword(forp, locat | segrel | (orp->parm[0] - orp->parm[2])); + + tidx = fidx = -1, method = 0; /* placate optimisers */ + + /* + * See if we can find the segment ID in our segment list. If + * so, we have a T4 (LSEG) target. + */ + for (s = seghead; s; s = s->next) + if (s->index == seg) + break; + if (s) + method = 4, tidx = s->obj_index; + else { + for (g = grphead; g; g = g->next) + if (g->index == seg) + break; + if (g) + method = 5, tidx = g->obj_index; + else { + long i = seg / 2; + struct ExtBack *eb = ebhead; + while (i > EXT_BLKSIZ) { + if (eb) + eb = eb->next; + else + break; + i -= EXT_BLKSIZ; + } + if (eb) + method = 6, e = eb->exts[i], tidx = e->index; + else + error(ERR_PANIC, + "unrecognised segment value in obj_write_fixup"); + } + } + + /* + * If no WRT given, assume the natural default, which is method + * F5 unless: + * + * - we are doing an OFFSET fixup for a grouped segment, in + * which case we require F1 (group). + * + * - we are doing an OFFSET fixup for an external with a + * default WRT, in which case we must honour the default WRT. + */ + if (wrt == NO_SEG) { + if (!base && s && s->grp) + method |= 0x10, fidx = s->grp->obj_index; + else if (!base && e && e->defwrt_type != DEFWRT_NONE) { + if (e->defwrt_type == DEFWRT_SEGMENT) + method |= 0x00, fidx = e->defwrt_ptr.seg->obj_index; + else if (e->defwrt_type == DEFWRT_GROUP) + method |= 0x10, fidx = e->defwrt_ptr.grp->obj_index; + else { + error(ERR_NONFATAL, "default WRT specification for" + " external `%s' unresolved", e->name); + method |= 0x50, fidx = -1; /* got to do _something_ */ + } + } else + method |= 0x50, fidx = -1; + } else { + /* + * See if we can find the WRT-segment ID in our segment + * list. If so, we have a F0 (LSEG) frame. + */ + for (s = seghead; s; s = s->next) + if (s->index == wrt - 1) + break; + if (s) + method |= 0x00, fidx = s->obj_index; + else { + for (g = grphead; g; g = g->next) + if (g->index == wrt - 1) + break; + if (g) + method |= 0x10, fidx = g->obj_index; + else { + long i = wrt / 2; + struct ExtBack *eb = ebhead; + while (i > EXT_BLKSIZ) { + if (eb) + eb = eb->next; + else + break; + i -= EXT_BLKSIZ; + } + if (eb) + method |= 0x20, fidx = eb->exts[i]->index; + else + error(ERR_PANIC, + "unrecognised WRT value in obj_write_fixup"); + } + } + } + + forp = obj_byte(forp, method); + if (fidx != -1) + forp = obj_index(forp, fidx); + forp = obj_index(forp, tidx); + obj_commit(forp); +} + +static long obj_segment(char *name, int pass, int *bits) +{ + /* + * We call the label manager here to define a name for the new + * segment, and when our _own_ label-definition stub gets + * called in return, it should register the new segment name + * using the pointer it gets passed. That way we save memory, + * by sponging off the label manager. + */ +#if defined(DEBUG) && DEBUG>=3 + fprintf(stderr, " obj_segment: < %s >, pass=%d, *bits=%d\n", + name, pass, *bits); +#endif + if (!name) { + *bits = 16; + current_seg = NULL; + return first_seg; + } else { + struct Segment *seg; + struct Group *grp; + struct External **extp; + int obj_idx, i, attrs, rn_error; + char *p; + + /* + * Look for segment attributes. + */ + attrs = 0; + while (*name == '.') + name++; /* hack, but a documented one */ + p = name; + while (*p && !isspace(*p)) + p++; + if (*p) { + *p++ = '\0'; + while (*p && isspace(*p)) + *p++ = '\0'; + } + while (*p) { + while (*p && !isspace(*p)) + p++; + if (*p) { + *p++ = '\0'; + while (*p && isspace(*p)) + *p++ = '\0'; + } + + attrs++; + } + + obj_idx = 1; + for (seg = seghead; seg; seg = seg->next) { + obj_idx++; + if (!strcmp(seg->name, name)) { + if (attrs > 0 && pass == 1) + error(ERR_WARNING, "segment attributes specified on" + " redeclaration of segment: ignoring"); + if (seg->use32) + *bits = 32; + else + *bits = 16; + current_seg = seg; + return seg->index; + } + } + + *segtail = seg = nasm_malloc(sizeof(*seg)); + seg->next = NULL; + segtail = &seg->next; + seg->index = (any_segs ? seg_alloc() : first_seg); + seg->obj_index = obj_idx; + seg->grp = NULL; + any_segs = TRUE; + seg->name = NULL; + seg->currentpos = 0; + seg->align = 1; /* default */ + seg->use32 = FALSE; /* default */ + seg->combine = CMB_PUBLIC; /* default */ + seg->segclass = seg->overlay = NULL; + seg->pubhead = NULL; + seg->pubtail = &seg->pubhead; + seg->lochead = NULL; + seg->loctail = &seg->lochead; + seg->orp = obj_new(); + seg->orp->up = &(seg->orp); + seg->orp->ori = ori_ledata; + seg->orp->type = LEDATA; + seg->orp->parm[1] = obj_idx; + + /* + * Process the segment attributes. + */ + p = name; + while (attrs--) { + p += strlen(p); + while (!*p) + p++; + + /* + * `p' contains a segment attribute. + */ + if (!nasm_stricmp(p, "private")) + seg->combine = CMB_PRIVATE; + else if (!nasm_stricmp(p, "public")) + seg->combine = CMB_PUBLIC; + else if (!nasm_stricmp(p, "common")) + seg->combine = CMB_COMMON; + else if (!nasm_stricmp(p, "stack")) + seg->combine = CMB_STACK; + else if (!nasm_stricmp(p, "use16")) + seg->use32 = FALSE; + else if (!nasm_stricmp(p, "use32")) + seg->use32 = TRUE; + else if (!nasm_stricmp(p, "flat")) { + /* + * This segment is an OS/2 FLAT segment. That means + * that its default group is group FLAT, even if + * the group FLAT does not explicitly _contain_ the + * segment. + * + * When we see this, we must create the group + * `FLAT', containing no segments, if it does not + * already exist; then we must set the default + * group of this segment to be the FLAT group. + */ + struct Group *grp; + for (grp = grphead; grp; grp = grp->next) + if (!strcmp(grp->name, "FLAT")) + break; + if (!grp) { + obj_directive("group", "FLAT", 1); + for (grp = grphead; grp; grp = grp->next) + if (!strcmp(grp->name, "FLAT")) + break; + if (!grp) + error(ERR_PANIC, "failure to define FLAT?!"); + } + seg->grp = grp; + } else if (!nasm_strnicmp(p, "class=", 6)) + seg->segclass = nasm_strdup(p + 6); + else if (!nasm_strnicmp(p, "overlay=", 8)) + seg->overlay = nasm_strdup(p + 8); + else if (!nasm_strnicmp(p, "align=", 6)) { + seg->align = readnum(p + 6, &rn_error); + if (rn_error) { + seg->align = 1; + error(ERR_NONFATAL, "segment alignment should be" + " numeric"); + } + switch ((int)seg->align) { + case 1: /* BYTE */ + case 2: /* WORD */ + case 4: /* DWORD */ + case 16: /* PARA */ + case 256: /* PAGE */ + case 4096: /* PharLap extension */ + break; + case 8: + error(ERR_WARNING, + "OBJ format does not support alignment" + " of 8: rounding up to 16"); + seg->align = 16; + break; + case 32: + case 64: + case 128: + error(ERR_WARNING, + "OBJ format does not support alignment" + " of %d: rounding up to 256", seg->align); + seg->align = 256; + break; + case 512: + case 1024: + case 2048: + error(ERR_WARNING, + "OBJ format does not support alignment" + " of %d: rounding up to 4096", seg->align); + seg->align = 4096; + break; + default: + error(ERR_NONFATAL, "invalid alignment value %d", + seg->align); + seg->align = 1; + break; + } + } else if (!nasm_strnicmp(p, "absolute=", 9)) { + seg->align = SEG_ABS + readnum(p + 9, &rn_error); + if (rn_error) + error(ERR_NONFATAL, "argument to `absolute' segment" + " attribute should be numeric"); + } + } + + /* We need to know whenever we have at least one 32-bit segment */ + obj_use32 |= seg->use32; + + obj_seg_needs_update = seg; + if (seg->align >= SEG_ABS) + deflabel(name, NO_SEG, seg->align - SEG_ABS, + NULL, FALSE, FALSE, &of_obj, error); + else + deflabel(name, seg->index + 1, 0L, + NULL, FALSE, FALSE, &of_obj, error); + obj_seg_needs_update = NULL; + + /* + * See if this segment is defined in any groups. + */ + for (grp = grphead; grp; grp = grp->next) { + for (i = grp->nindices; i < grp->nentries; i++) { + if (!strcmp(grp->segs[i].name, seg->name)) { + nasm_free(grp->segs[i].name); + grp->segs[i] = grp->segs[grp->nindices]; + grp->segs[grp->nindices++].index = seg->obj_index; + if (seg->grp) + error(ERR_WARNING, + "segment `%s' is already part of" + " a group: first one takes precedence", + seg->name); + else + seg->grp = grp; + } + } + } + + /* + * Walk through the list of externals with unresolved + * default-WRT clauses, and resolve any that point at this + * segment. + */ + extp = &dws; + while (*extp) { + if ((*extp)->defwrt_type == DEFWRT_STRING && + !strcmp((*extp)->defwrt_ptr.string, seg->name)) { + nasm_free((*extp)->defwrt_ptr.string); + (*extp)->defwrt_type = DEFWRT_SEGMENT; + (*extp)->defwrt_ptr.seg = seg; + *extp = (*extp)->next_dws; + } else + extp = &(*extp)->next_dws; + } + + if (seg->use32) + *bits = 32; + else + *bits = 16; + current_seg = seg; + return seg->index; + } +} + +static int obj_directive(char *directive, char *value, int pass) +{ + if (!strcmp(directive, "group")) { + char *p, *q, *v; + if (pass == 1) { + struct Group *grp; + struct Segment *seg; + struct External **extp; + int obj_idx; + + q = value; + while (*q == '.') + q++; /* hack, but a documented one */ + v = q; + while (*q && !isspace(*q)) + q++; + if (isspace(*q)) { + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + } + /* + * Here we used to sanity-check the group directive to + * ensure nobody tried to declare a group containing no + * segments. However, OS/2 does this as standard + * practice, so the sanity check has been removed. + * + * if (!*q) { + * error(ERR_NONFATAL,"GROUP directive contains no segments"); + * return 1; + * } + */ + + obj_idx = 1; + for (grp = grphead; grp; grp = grp->next) { + obj_idx++; + if (!strcmp(grp->name, v)) { + error(ERR_NONFATAL, "group `%s' defined twice", v); + return 1; + } + } + + *grptail = grp = nasm_malloc(sizeof(*grp)); + grp->next = NULL; + grptail = &grp->next; + grp->index = seg_alloc(); + grp->obj_index = obj_idx; + grp->nindices = grp->nentries = 0; + grp->name = NULL; + + obj_grp_needs_update = grp; + deflabel(v, grp->index + 1, 0L, + NULL, FALSE, FALSE, &of_obj, error); + obj_grp_needs_update = NULL; + + while (*q) { + p = q; + while (*q && !isspace(*q)) + q++; + if (isspace(*q)) { + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + } + /* + * Now p contains a segment name. Find it. + */ + for (seg = seghead; seg; seg = seg->next) + if (!strcmp(seg->name, p)) + break; + if (seg) { + /* + * We have a segment index. Shift a name entry + * to the end of the array to make room. + */ + grp->segs[grp->nentries++] = grp->segs[grp->nindices]; + grp->segs[grp->nindices++].index = seg->obj_index; + if (seg->grp) + error(ERR_WARNING, + "segment `%s' is already part of" + " a group: first one takes precedence", + seg->name); + else + seg->grp = grp; + } else { + /* + * We have an as-yet undefined segment. + * Remember its name, for later. + */ + grp->segs[grp->nentries++].name = nasm_strdup(p); + } + } + + /* + * Walk through the list of externals with unresolved + * default-WRT clauses, and resolve any that point at + * this group. + */ + extp = &dws; + while (*extp) { + if ((*extp)->defwrt_type == DEFWRT_STRING && + !strcmp((*extp)->defwrt_ptr.string, grp->name)) { + nasm_free((*extp)->defwrt_ptr.string); + (*extp)->defwrt_type = DEFWRT_GROUP; + (*extp)->defwrt_ptr.grp = grp; + *extp = (*extp)->next_dws; + } else + extp = &(*extp)->next_dws; + } + } + return 1; + } + if (!strcmp(directive, "uppercase")) { + obj_uppercase = TRUE; + return 1; + } + if (!strcmp(directive, "import")) { + char *q, *extname, *libname, *impname; + + if (pass == 2) + return 1; /* ignore in pass two */ + extname = q = value; + while (*q && !isspace(*q)) + q++; + if (isspace(*q)) { + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + } + + libname = q; + while (*q && !isspace(*q)) + q++; + if (isspace(*q)) { + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + } + + impname = q; + + if (!*extname || !*libname) + error(ERR_NONFATAL, "`import' directive requires symbol name" + " and library name"); + else { + struct ImpDef *imp; + int err = FALSE; + + imp = *imptail = nasm_malloc(sizeof(struct ImpDef)); + imptail = &imp->next; + imp->next = NULL; + imp->extname = nasm_strdup(extname); + imp->libname = nasm_strdup(libname); + imp->impindex = readnum(impname, &err); + if (!*impname || err) + imp->impname = nasm_strdup(impname); + else + imp->impname = NULL; + } + + return 1; + } + if (!strcmp(directive, "export")) { + char *q, *extname, *intname, *v; + struct ExpDef *export; + int flags = 0; + unsigned int ordinal = 0; + + if (pass == 2) + return 1; /* ignore in pass two */ + intname = q = value; + while (*q && !isspace(*q)) + q++; + if (isspace(*q)) { + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + } + + extname = q; + while (*q && !isspace(*q)) + q++; + if (isspace(*q)) { + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + } + + if (!*intname) { + error(ERR_NONFATAL, "`export' directive requires export name"); + return 1; + } + if (!*extname) { + extname = intname; + intname = ""; + } + while (*q) { + v = q; + while (*q && !isspace(*q)) + q++; + if (isspace(*q)) { + *q++ = '\0'; + while (*q && isspace(*q)) + q++; + } + if (!nasm_stricmp(v, "resident")) + flags |= EXPDEF_FLAG_RESIDENT; + else if (!nasm_stricmp(v, "nodata")) + flags |= EXPDEF_FLAG_NODATA; + else if (!nasm_strnicmp(v, "parm=", 5)) { + int err = FALSE; + flags |= EXPDEF_MASK_PARMCNT & readnum(v + 5, &err); + if (err) { + error(ERR_NONFATAL, + "value `%s' for `parm' is non-numeric", v + 5); + return 1; + } + } else { + int err = FALSE; + ordinal = readnum(v, &err); + if (err) { + error(ERR_NONFATAL, + "unrecognised export qualifier `%s'", v); + return 1; + } + flags |= EXPDEF_FLAG_ORDINAL; + } + } + + export = *exptail = nasm_malloc(sizeof(struct ExpDef)); + exptail = &export->next; + export->next = NULL; + export->extname = nasm_strdup(extname); + export->intname = nasm_strdup(intname); + export->ordinal = ordinal; + export->flags = flags; + + return 1; + } + return 0; +} + +static long obj_segbase(long segment) +{ + struct Segment *seg; + + /* + * Find the segment in our list. + */ + for (seg = seghead; seg; seg = seg->next) + if (seg->index == segment - 1) + break; + + if (!seg) { + /* + * Might be an external with a default WRT. + */ + long i = segment / 2; + struct ExtBack *eb = ebhead; + struct External *e; + + while (i > EXT_BLKSIZ) { + if (eb) + eb = eb->next; + else + break; + i -= EXT_BLKSIZ; + } + if (eb) { + e = eb->exts[i]; + if (e->defwrt_type == DEFWRT_NONE) + return segment; /* fine */ + else if (e->defwrt_type == DEFWRT_SEGMENT) + return e->defwrt_ptr.seg->index + 1; + else if (e->defwrt_type == DEFWRT_GROUP) + return e->defwrt_ptr.grp->index + 1; + else + return NO_SEG; /* can't tell what it is */ + } + + return segment; /* not one of ours - leave it alone */ + } + + if (seg->align >= SEG_ABS) + return seg->align; /* absolute segment */ + if (seg->grp) + return seg->grp->index + 1; /* grouped segment */ + + return segment; /* no special treatment */ +} + +static void obj_filename(char *inname, char *outname, efunc lerror) +{ + strcpy(obj_infile, inname); + standard_extension(inname, outname, ".obj", lerror); +} + +static void obj_write_file(int debuginfo) +{ + struct Segment *seg, *entry_seg_ptr = 0; + struct FileName *fn; + struct LineNumber *ln; + struct Group *grp; + struct Public *pub, *loc; + struct External *ext; + struct ImpDef *imp; + struct ExpDef *export; + static char boast[] = "The Netwide Assembler " NASM_VER; + int lname_idx; + ObjRecord *orp; + + /* + * Write the THEADR module header. + */ + orp = obj_new(); + orp->type = THEADR; + obj_name(orp, obj_infile); + obj_emit2(orp); + + /* + * Write the NASM boast comment. + */ + orp->type = COMENT; + obj_rword(orp, 0); /* comment type zero */ + obj_name(orp, boast); + obj_emit2(orp); + + orp->type = COMENT; + /* + * Write the IMPDEF records, if any. + */ + for (imp = imphead; imp; imp = imp->next) { + obj_rword(orp, 0xA0); /* comment class A0 */ + obj_byte(orp, 1); /* subfunction 1: IMPDEF */ + if (imp->impname) + obj_byte(orp, 0); /* import by name */ + else + obj_byte(orp, 1); /* import by ordinal */ + obj_name(orp, imp->extname); + obj_name(orp, imp->libname); + if (imp->impname) + obj_name(orp, imp->impname); + else + obj_word(orp, imp->impindex); + obj_emit2(orp); + } + + /* + * Write the EXPDEF records, if any. + */ + for (export = exphead; export; export = export->next) { + obj_rword(orp, 0xA0); /* comment class A0 */ + obj_byte(orp, 2); /* subfunction 2: EXPDEF */ + obj_byte(orp, export->flags); + obj_name(orp, export->extname); + obj_name(orp, export->intname); + if (export->flags & EXPDEF_FLAG_ORDINAL) + obj_word(orp, export->ordinal); + obj_emit2(orp); + } + + /* we're using extended OMF if we put in debug info */ + if (debuginfo) { + orp->type = COMENT; + obj_byte(orp, 0x40); + obj_byte(orp, dEXTENDED); + obj_emit2(orp); + } + + /* + * Write the first LNAMES record, containing LNAME one, which + * is null. Also initialise the LNAME counter. + */ + orp->type = LNAMES; + obj_byte(orp, 0); + lname_idx = 1; + /* + * Write some LNAMES for the segment names + */ + for (seg = seghead; seg; seg = seg->next) { + orp = obj_name(orp, seg->name); + if (seg->segclass) + orp = obj_name(orp, seg->segclass); + if (seg->overlay) + orp = obj_name(orp, seg->overlay); + obj_commit(orp); + } + /* + * Write some LNAMES for the group names + */ + for (grp = grphead; grp; grp = grp->next) { + orp = obj_name(orp, grp->name); + obj_commit(orp); + } + obj_emit(orp); + + /* + * Write the SEGDEF records. + */ + orp->type = SEGDEF; + for (seg = seghead; seg; seg = seg->next) { + int acbp; + unsigned long seglen = seg->currentpos; + + acbp = (seg->combine << 2); /* C field */ + + if (seg->use32) + acbp |= 0x01; /* P bit is Use32 flag */ + else if (seglen == 0x10000L) { + seglen = 0; /* This special case may be needed for old linkers */ + acbp |= 0x02; /* B bit */ + } + + /* A field */ + if (seg->align >= SEG_ABS) + /* acbp |= 0x00 */ ; + else if (seg->align >= 4096) { + if (seg->align > 4096) + error(ERR_NONFATAL, "segment `%s' requires more alignment" + " than OBJ format supports", seg->name); + acbp |= 0xC0; /* PharLap extension */ + } else if (seg->align >= 256) { + acbp |= 0x80; + } else if (seg->align >= 16) { + acbp |= 0x60; + } else if (seg->align >= 4) { + acbp |= 0xA0; + } else if (seg->align >= 2) { + acbp |= 0x40; + } else + acbp |= 0x20; + + obj_byte(orp, acbp); + if (seg->align & SEG_ABS) { + obj_x(orp, seg->align - SEG_ABS); /* Frame */ + obj_byte(orp, 0); /* Offset */ + } + obj_x(orp, seglen); + obj_index(orp, ++lname_idx); + obj_index(orp, seg->segclass ? ++lname_idx : 1); + obj_index(orp, seg->overlay ? ++lname_idx : 1); + obj_emit2(orp); + } + + /* + * Write the GRPDEF records. + */ + orp->type = GRPDEF; + for (grp = grphead; grp; grp = grp->next) { + int i; + + if (grp->nindices != grp->nentries) { + for (i = grp->nindices; i < grp->nentries; i++) { + error(ERR_NONFATAL, "group `%s' contains undefined segment" + " `%s'", grp->name, grp->segs[i].name); + nasm_free(grp->segs[i].name); + grp->segs[i].name = NULL; + } + } + obj_index(orp, ++lname_idx); + for (i = 0; i < grp->nindices; i++) { + obj_byte(orp, 0xFF); + obj_index(orp, grp->segs[i].index); + } + obj_emit2(orp); + } + + /* + * Write the PUBDEF records: first the ones in the segments, + * then the far-absolutes. + */ + orp->type = PUBDEF; + orp->ori = ori_pubdef; + for (seg = seghead; seg; seg = seg->next) { + orp->parm[0] = seg->grp ? seg->grp->obj_index : 0; + orp->parm[1] = seg->obj_index; + for (pub = seg->pubhead; pub; pub = pub->next) { + orp = obj_name(orp, pub->name); + orp = obj_x(orp, pub->offset); + orp = obj_byte(orp, 0); /* type index */ + obj_commit(orp); + } + obj_emit(orp); + } + orp->parm[0] = 0; + orp->parm[1] = 0; + for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */ + if (orp->parm[2] != pub->segment) { + obj_emit(orp); + orp->parm[2] = pub->segment; + } + orp = obj_name(orp, pub->name); + orp = obj_x(orp, pub->offset); + orp = obj_byte(orp, 0); /* type index */ + obj_commit(orp); + } + obj_emit(orp); + + /* + * Write the EXTDEF and COMDEF records, in order. + */ + orp->ori = ori_null; + for (ext = exthead; ext; ext = ext->next) { + if (ext->commonsize == 0) { + if (orp->type != EXTDEF) { + obj_emit(orp); + orp->type = EXTDEF; + } + orp = obj_name(orp, ext->name); + orp = obj_index(orp, 0); + } else { + if (orp->type != COMDEF) { + obj_emit(orp); + orp->type = COMDEF; + } + orp = obj_name(orp, ext->name); + orp = obj_index(orp, 0); + if (ext->commonelem) { + orp = obj_byte(orp, 0x61); /* far communal */ + orp = obj_value(orp, (ext->commonsize / ext->commonelem)); + orp = obj_value(orp, ext->commonelem); + } else { + orp = obj_byte(orp, 0x62); /* near communal */ + orp = obj_value(orp, ext->commonsize); + } + } + obj_commit(orp); + } + obj_emit(orp); + + /* + * Write a COMENT record stating that the linker's first pass + * may stop processing at this point. Exception is if our + * MODEND record specifies a start point, in which case, + * according to some variants of the documentation, this COMENT + * should be omitted. So we'll omit it just in case. + * But, TASM puts it in all the time so if we are using + * TASM debug stuff we are putting it in + */ + if (debuginfo || obj_entry_seg == NO_SEG) { + orp->type = COMENT; + obj_byte(orp, 0x40); + obj_byte(orp, dLINKPASS); + obj_byte(orp, 1); + obj_emit2(orp); + } + + /* + * 1) put out the compiler type + * 2) Put out the type info. The only type we are using is near label #19 + */ + if (debuginfo) { + int i; + struct Array *arrtmp = arrhead; + orp->type = COMENT; + obj_byte(orp, 0x40); + obj_byte(orp, dCOMPDEF); + obj_byte(orp, 4); + obj_byte(orp, 0); + obj_emit2(orp); + + obj_byte(orp, 0x40); + obj_byte(orp, dTYPEDEF); + obj_word(orp, 0x18); /* type # for linking */ + obj_word(orp, 6); /* size of type */ + obj_byte(orp, 0x2a); /* absolute type for debugging */ + obj_emit2(orp); + obj_byte(orp, 0x40); + obj_byte(orp, dTYPEDEF); + obj_word(orp, 0x19); /* type # for linking */ + obj_word(orp, 0); /* size of type */ + obj_byte(orp, 0x24); /* absolute type for debugging */ + obj_byte(orp, 0); /* near/far specifier */ + obj_emit2(orp); + obj_byte(orp, 0x40); + obj_byte(orp, dTYPEDEF); + obj_word(orp, 0x1A); /* type # for linking */ + obj_word(orp, 0); /* size of type */ + obj_byte(orp, 0x24); /* absolute type for debugging */ + obj_byte(orp, 1); /* near/far specifier */ + obj_emit2(orp); + obj_byte(orp, 0x40); + obj_byte(orp, dTYPEDEF); + obj_word(orp, 0x1b); /* type # for linking */ + obj_word(orp, 0); /* size of type */ + obj_byte(orp, 0x23); /* absolute type for debugging */ + obj_byte(orp, 0); + obj_byte(orp, 0); + obj_byte(orp, 0); + obj_emit2(orp); + obj_byte(orp, 0x40); + obj_byte(orp, dTYPEDEF); + obj_word(orp, 0x1c); /* type # for linking */ + obj_word(orp, 0); /* size of type */ + obj_byte(orp, 0x23); /* absolute type for debugging */ + obj_byte(orp, 0); + obj_byte(orp, 4); + obj_byte(orp, 0); + obj_emit2(orp); + obj_byte(orp, 0x40); + obj_byte(orp, dTYPEDEF); + obj_word(orp, 0x1d); /* type # for linking */ + obj_word(orp, 0); /* size of type */ + obj_byte(orp, 0x23); /* absolute type for debugging */ + obj_byte(orp, 0); + obj_byte(orp, 1); + obj_byte(orp, 0); + obj_emit2(orp); + obj_byte(orp, 0x40); + obj_byte(orp, dTYPEDEF); + obj_word(orp, 0x1e); /* type # for linking */ + obj_word(orp, 0); /* size of type */ + obj_byte(orp, 0x23); /* absolute type for debugging */ + obj_byte(orp, 0); + obj_byte(orp, 5); + obj_byte(orp, 0); + obj_emit2(orp); + + /* put out the array types */ + for (i = ARRAYBOT; i < arrindex; i++) { + obj_byte(orp, 0x40); + obj_byte(orp, dTYPEDEF); + obj_word(orp, i); /* type # for linking */ + obj_word(orp, arrtmp->size); /* size of type */ + obj_byte(orp, 0x1A); /* absolute type for debugging (array) */ + obj_byte(orp, arrtmp->basetype); /* base type */ + obj_emit2(orp); + arrtmp = arrtmp->next; + } + } + /* + * write out line number info with a LINNUM record + * switch records when we switch segments, and output the + * file in a pseudo-TASM fashion. The record switch is naive; that + * is that one file may have many records for the same segment + * if there are lots of segment switches + */ + if (fnhead && debuginfo) { + seg = fnhead->lnhead->segment; + + for (fn = fnhead; fn; fn = fn->next) { + /* write out current file name */ + orp->type = COMENT; + orp->ori = ori_null; + obj_byte(orp, 0x40); + obj_byte(orp, dFILNAME); + obj_byte(orp, 0); + obj_name(orp, fn->name); + obj_dword(orp, 0); + obj_emit2(orp); + + /* write out line numbers this file */ + + orp->type = LINNUM; + orp->ori = ori_linnum; + for (ln = fn->lnhead; ln; ln = ln->next) { + if (seg != ln->segment) { + /* if we get here have to flush the buffer and start + * a new record for a new segment + */ + seg = ln->segment; + obj_emit(orp); + } + orp->parm[0] = seg->grp ? seg->grp->obj_index : 0; + orp->parm[1] = seg->obj_index; + orp = obj_word(orp, ln->lineno); + orp = obj_x(orp, ln->offset); + obj_commit(orp); + } + obj_emit(orp); + } + } + /* + * we are going to locate the entry point segment now + * rather than wait until the MODEND record, because, + * then we can output a special symbol to tell where the + * entry point is. + * + */ + if (obj_entry_seg != NO_SEG) { + for (seg = seghead; seg; seg = seg->next) { + if (seg->index == obj_entry_seg) { + entry_seg_ptr = seg; + break; + } + } + if (!seg) + error(ERR_NONFATAL, "entry point is not in this module"); + } + + /* + * get ready to put out symbol records + */ + orp->type = COMENT; + orp->ori = ori_local; + + /* + * put out a symbol for the entry point + * no dots in this symbol, because, borland does + * not (officially) support dots in label names + * and I don't know what various versions of TLINK will do + */ + if (debuginfo && obj_entry_seg != NO_SEG) { + orp = obj_name(orp, "start_of_program"); + orp = obj_word(orp, 0x19); /* type: near label */ + orp = obj_index(orp, seg->grp ? seg->grp->obj_index : 0); + orp = obj_index(orp, seg->obj_index); + orp = obj_x(orp, obj_entry_ofs); + obj_commit(orp); + } + + /* + * put out the local labels + */ + for (seg = seghead; seg && debuginfo; seg = seg->next) { + /* labels this seg */ + for (loc = seg->lochead; loc; loc = loc->next) { + orp = obj_name(orp, loc->name); + orp = obj_word(orp, loc->type); + orp = obj_index(orp, seg->grp ? seg->grp->obj_index : 0); + orp = obj_index(orp, seg->obj_index); + orp = obj_x(orp, loc->offset); + obj_commit(orp); + } + } + if (orp->used) + obj_emit(orp); + + /* + * Write the LEDATA/FIXUPP pairs. + */ + for (seg = seghead; seg; seg = seg->next) { + obj_emit(seg->orp); + nasm_free(seg->orp); + } + + /* + * Write the MODEND module end marker. + */ + orp->type = obj_use32 ? MODE32 : MODEND; + orp->ori = ori_null; + if (entry_seg_ptr) { + orp->type = entry_seg_ptr->use32 ? MODE32 : MODEND; + obj_byte(orp, 0xC1); + seg = entry_seg_ptr; + if (seg->grp) { + obj_byte(orp, 0x10); + obj_index(orp, seg->grp->obj_index); + } else { + /* + * the below changed to prevent TLINK crashing. + * Previous more efficient version read: + * + * obj_byte (orp, 0x50); + */ + obj_byte(orp, 0x00); + obj_index(orp, seg->obj_index); + } + obj_index(orp, seg->obj_index); + obj_x(orp, obj_entry_ofs); + } else + obj_byte(orp, 0); + obj_emit2(orp); + nasm_free(orp); +} + +void obj_fwrite(ObjRecord * orp) +{ + unsigned int cksum, len; + unsigned char *ptr; + + cksum = orp->type; + if (orp->x_size == 32) + cksum |= 1; + fputc(cksum, ofp); + len = orp->committed + 1; + cksum += (len & 0xFF) + ((len >> 8) & 0xFF); + fwriteshort(len, ofp); + fwrite(orp->buf, 1, len - 1, ofp); + for (ptr = orp->buf; --len; ptr++) + cksum += *ptr; + fputc((-cksum) & 0xFF, ofp); +} + +static const char *obj_stdmac[] = { + "%define __SECT__ [section .text]", + "%imacro group 1+.nolist", + "[group %1]", + "%endmacro", + "%imacro uppercase 0+.nolist", + "[uppercase %1]", + "%endmacro", + "%imacro export 1+.nolist", + "[export %1]", + "%endmacro", + "%imacro import 1+.nolist", + "[import %1]", + "%endmacro", + "%macro __NASM_CDecl__ 1", + "%endmacro", + NULL +}; + +void dbgbi_init(struct ofmt *of, void *id, FILE * fp, efunc error) +{ + (void)of; + (void)id; + (void)fp; + (void)error; + + fnhead = NULL; + fntail = &fnhead; + arrindex = ARRAYBOT; + arrhead = NULL; + arrtail = &arrhead; +} +static void dbgbi_cleanup(void) +{ + struct Segment *segtmp; + while (fnhead) { + struct FileName *fntemp = fnhead; + while (fnhead->lnhead) { + struct LineNumber *lntemp = fnhead->lnhead; + fnhead->lnhead = lntemp->next; + nasm_free(lntemp); + } + fnhead = fnhead->next; + nasm_free(fntemp->name); + nasm_free(fntemp); + } + for (segtmp = seghead; segtmp; segtmp = segtmp->next) { + while (segtmp->lochead) { + struct Public *loctmp = segtmp->lochead; + segtmp->lochead = loctmp->next; + nasm_free(loctmp->name); + nasm_free(loctmp); + } + } + while (arrhead) { + struct Array *arrtmp = arrhead; + arrhead = arrhead->next; + nasm_free(arrtmp); + } +} + +static void dbgbi_linnum(const char *lnfname, long lineno, long segto) +{ + struct FileName *fn; + struct LineNumber *ln; + struct Segment *seg; + + if (segto == NO_SEG) + return; + + /* + * If `any_segs' is still FALSE, we must define a default + * segment. + */ + if (!any_segs) { + int tempint; /* ignored */ + if (segto != obj_segment("__NASMDEFSEG", 2, &tempint)) + error(ERR_PANIC, "strange segment conditions in OBJ driver"); + } + + /* + * Find the segment we are targetting. + */ + for (seg = seghead; seg; seg = seg->next) + if (seg->index == segto) + break; + if (!seg) + error(ERR_PANIC, "lineno directed to nonexistent segment?"); + +/* for (fn = fnhead; fn; fn = fnhead->next) */ + for (fn = fnhead; fn; fn = fn->next) /* fbk - Austin Lunnen - John Fine */ + if (!nasm_stricmp(lnfname, fn->name)) + break; + if (!fn) { + fn = nasm_malloc(sizeof(*fn)); + fn->name = nasm_malloc(strlen(lnfname) + 1); + strcpy(fn->name, lnfname); + fn->lnhead = NULL; + fn->lntail = &fn->lnhead; + fn->next = NULL; + *fntail = fn; + fntail = &fn->next; + } + ln = nasm_malloc(sizeof(*ln)); + ln->segment = seg; + ln->offset = seg->currentpos; + ln->lineno = lineno; + ln->next = NULL; + *fn->lntail = ln; + fn->lntail = &ln->next; + +} +static void dbgbi_deflabel(char *name, long segment, + long offset, int is_global, char *special) +{ + struct Segment *seg; + + (void)special; + + /* + * If it's a special-retry from pass two, discard it. + */ + if (is_global == 3) + return; + + /* + * First check for the double-period, signifying something + * unusual. + */ + if (name[0] == '.' && name[1] == '.' && name[2] != '@') { + return; + } + + /* + * Case (i): + */ + if (obj_seg_needs_update) { + return; + } else if (obj_grp_needs_update) { + return; + } + if (segment < SEG_ABS && segment != NO_SEG && segment % 2) + return; + + if (segment >= SEG_ABS || segment == NO_SEG) { + return; + } + + /* + * If `any_segs' is still FALSE, we might need to define a + * default segment, if they're trying to declare a label in + * `first_seg'. But the label should exist due to a prior + * call to obj_deflabel so we can skip that. + */ + + for (seg = seghead; seg; seg = seg->next) + if (seg->index == segment) { + struct Public *loc = nasm_malloc(sizeof(*loc)); + /* + * Case (ii). Maybe MODPUB someday? + */ + last_defined = *seg->loctail = loc; + seg->loctail = &loc->next; + loc->next = NULL; + loc->name = nasm_strdup(name); + loc->offset = offset; + } +} +static void dbgbi_typevalue(long type) +{ + int vsize; + int elem = TYM_ELEMENTS(type); + type = TYM_TYPE(type); + + if (!last_defined) + return; + + switch (type) { + case TY_BYTE: + last_defined->type = 8; /* unsigned char */ + vsize = 1; + break; + case TY_WORD: + last_defined->type = 10; /* unsigned word */ + vsize = 2; + break; + case TY_DWORD: + last_defined->type = 12; /* unsigned dword */ + vsize = 4; + break; + case TY_FLOAT: + last_defined->type = 14; /* float */ + vsize = 4; + break; + case TY_QWORD: + last_defined->type = 15; /* qword */ + vsize = 8; + break; + case TY_TBYTE: + last_defined->type = 16; /* TBYTE */ + vsize = 10; + break; + default: + last_defined->type = 0x19; /*label */ + vsize = 0; + break; + } + + if (elem > 1) { + struct Array *arrtmp = nasm_malloc(sizeof(*arrtmp)); + int vtype = last_defined->type; + arrtmp->size = vsize * elem; + arrtmp->basetype = vtype; + arrtmp->next = NULL; + last_defined->type = arrindex++; + *arrtail = arrtmp; + arrtail = &(arrtmp->next); + } + last_defined = NULL; +} +static void dbgbi_output(int output_type, void *param) +{ + (void)output_type; + (void)param; +} +static struct dfmt borland_debug_form = { + "Borland Debug Records", + "borland", + dbgbi_init, + dbgbi_linnum, + dbgbi_deflabel, + null_debug_routine, + dbgbi_typevalue, + dbgbi_output, + dbgbi_cleanup, +}; + +static struct dfmt *borland_debug_arr[3] = { + &borland_debug_form, + &null_debug_form, + NULL +}; + +struct ofmt of_obj = { + "MS-DOS 16-bit/32-bit OMF object files", + "obj", + NULL, + borland_debug_arr, + &null_debug_form, + obj_stdmac, + obj_init, + obj_set_info, + obj_out, + obj_deflabel, + obj_segment, + obj_segbase, + obj_directive, + obj_filename, + obj_cleanup +}; +#endif /* OF_OBJ */ diff --git a/output/outrdf.c b/output/outrdf.c dissimilarity index 78% index d9989e52..dff7cad0 100644 --- a/output/outrdf.c +++ b/output/outrdf.c @@ -1,539 +1,551 @@ -/* outrdf.c output routines for the Netwide Assembler to produce - * RDOFF format object files (which are intended mainly - * for use in proprietary projects, as the code to load and - * execute them is very simple). They will also be used - * for device drivers and possibly some executable files - * in the MOSCOW operating system. See Rdoff.txt for - * details. - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "outform.h" - -/* VERBOSE_WARNINGS: define this to add some extra warnings... */ -#define VERBOSE_WARNINGS - -#ifdef OF_RDF - -typedef short int16; /* not sure if this will be required to be altered - at all... best to typedef it just in case */ - -static const char *RDOFFId = "RDOFF1"; /* written to start of RDOFF files */ - -/* the records that can be found in the RDOFF header */ - -/* Note that whenever a segment is referred to in the RDOFF file, its number - * is always half of the segment number that NASM uses to refer to it; this - * is because NASM only allocates even numbered segments, so as to not - * waste any of the 16 bits of segment number written to the file - this - * allows up to 65533 external labels to be defined; otherwise it would be - * 32764. */ - -struct RelocRec { - char type; /* must be 1 */ - char segment; /* only 0 for code, or 1 for data supported, - * but add 64 for relative refs (ie do not require - * reloc @ loadtime, only linkage) */ - long offset; /* from start of segment in which reference is loc'd */ - char length; /* 1 2 or 4 bytes */ - int16 refseg; /* segment to which reference refers to */ -}; - -struct ImportRec { - char type; /* must be 2 */ - int16 segment; /* segment number allocated to the label for reloc - * records - label is assumed to be at offset zero - * in this segment, so linker must fix up with offset - * of segment and of offset within segment */ - char label[33]; /* zero terminated... should be written to file until - * the zero, but not after it - max len = 32 chars */ -}; - -struct ExportRec { - char type; /* must be 3 */ - char segment; /* segment referred to (0/1) */ - long offset; /* offset within segment */ - char label[33]; /* zero terminated as above. max len = 32 chars */ -}; - -struct DLLRec { - char type; /* must be 4 */ - char libname[128]; /* name of library to link with at load time */ -}; - -struct BSSRec { - char type; /* must be 5 */ - long amount; /* number of bytes BSS to reserve */ -}; - -/* code for managing buffers needed to seperate code and data into individual - * sections until they are ready to be written to the file. - * We'd better hope that it all fits in memory else we're buggered... */ - -#define BUF_BLOCK_LEN 4088 /* selected to match page size (4096) - * on 80x86 machines for efficiency */ - -typedef struct memorybuffer { - int length; - char buffer[BUF_BLOCK_LEN]; - struct memorybuffer *next; -} memorybuffer; - -static memorybuffer * newmembuf(void){ - memorybuffer * t; - - t = nasm_malloc(sizeof(memorybuffer)); - - t->length = 0; - t->next = NULL; - return t; -} - -static void membufwrite(memorybuffer *b, void *data, int bytes) { - int16 w; - long l; - - if (b->next) { /* memory buffer full - use next buffer */ - membufwrite(b->next,data,bytes); - return; - } - if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN) - || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) { - - /* buffer full and no next allocated... allocate and initialise next - * buffer */ - - b->next = newmembuf(); - membufwrite(b->next,data,bytes); - return; - } - - switch(bytes) { - case -4: /* convert to little-endian */ - l = * (long *) data ; - b->buffer[b->length++] = l & 0xFF; - l >>= 8 ; - b->buffer[b->length++] = l & 0xFF; - l >>= 8 ; - b->buffer[b->length++] = l & 0xFF; - l >>= 8 ; - b->buffer[b->length++] = l & 0xFF; - break; - - case -2: - w = * (int16 *) data ; - b->buffer[b->length++] = w & 0xFF; - w >>= 8 ; - b->buffer[b->length++] = w & 0xFF; - break; - - default: - while(bytes--) { - b->buffer[b->length++] = *(* (unsigned char **) &data); - - (* (unsigned char **) &data)++ ; - } - break; - } -} - -static void membufdump(memorybuffer *b,FILE *fp) -{ - if (!b) return; - - fwrite (b->buffer, 1, b->length, fp); - - membufdump(b->next,fp); -} - -static int membuflength(memorybuffer *b) -{ - if (!b) return 0; - return b->length + membuflength(b->next); -} - -static void freemembuf(memorybuffer *b) -{ - if (!b) return; - freemembuf(b->next); - nasm_free(b); -} - -/*********************************************************************** - * Actual code to deal with RDOFF ouput format begins here... - */ - -/* global variables set during the initialisation phase */ - -static memorybuffer *seg[2]; /* seg 0 = code, seg 1 = data */ -static memorybuffer *header; /* relocation/import/export records */ - -static FILE *ofile; - -static efunc error; - -static int segtext,segdata,segbss; -static long bsslength; - -static void rdf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) -{ - ofile = fp; - error = errfunc; - seg[0] = newmembuf(); - seg[1] = newmembuf(); - header = newmembuf(); - segtext = seg_alloc(); - segdata = seg_alloc(); - segbss = seg_alloc(); - if (segtext != 0 || segdata != 2 || segbss != 4) - error(ERR_PANIC,"rdf segment numbers not allocated as expected (%d,%d,%d)", - segtext,segdata,segbss); - bsslength=0; -} - -static long rdf_section_names(char *name, int pass, int *bits) -{ - /* - * Default is 32 bits. - */ - if (!name) - *bits = 32; - - if (!name) return 0; - if (!strcmp(name, ".text")) return 0; - else if (!strcmp(name, ".data")) return 2; - else if (!strcmp(name, ".bss")) return 4; - else - return NO_SEG; -} - -static void write_reloc_rec(struct RelocRec *r) -{ - if (r->refseg != NO_SEG && (r->refseg & 1)) - error (ERR_NONFATAL, "RDF format does not support segment base" - " references"); - - r->refseg >>= 1; /* adjust segment nos to RDF rather than NASM */ - - membufwrite(header,&r->type,1); - membufwrite(header,&r->segment,1); - membufwrite(header,&r->offset,-4); - membufwrite(header,&r->length,1); - membufwrite(header,&r->refseg,-2); /* 9 bytes written */ -} - -static void write_export_rec(struct ExportRec *r) -{ - r->segment >>= 1; - - membufwrite(header,&r->type,1); - membufwrite(header,&r->segment,1); - membufwrite(header,&r->offset,-4); - membufwrite(header,r->label,strlen(r->label) + 1); -} - -static void write_import_rec(struct ImportRec *r) -{ - r->segment >>= 1; - - membufwrite(header,&r->type,1); - membufwrite(header,&r->segment,-2); - membufwrite(header,r->label,strlen(r->label) + 1); -} - -static void write_bss_rec(struct BSSRec *r) -{ - membufwrite(header,&r->type,1); - membufwrite(header,&r->amount,-4); -} - -static void write_dll_rec(struct DLLRec *r) -{ - membufwrite(header,&r->type,1); - membufwrite(header,r->libname,strlen(r->libname) + 1); -} - -static void rdf_deflabel(char *name, long segment, long offset, - int is_global, char *special) -{ - struct ExportRec r; - struct ImportRec ri; -#ifdef VERBOSE_WARNINGS - static int warned_common = 0; -#endif - - if (special) - error (ERR_NONFATAL, "RDOFF format does not support any" - " special symbol types"); - - if (name[0] == '.' && name[1] == '.' && name[2] != '@') { - error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); - return; - } - - if (is_global == 2) { -#ifdef VERBOSE_WARNINGS - if (!warned_common) { - error(ERR_WARNING,"common declarations not supported: using extern"); - warned_common = 1; - } -#endif - is_global = 1; - } - - if (segment > 4) { /* EXTERN declaration */ - ri.type = 2; - ri.segment = segment; - strncpy(ri.label,name,32); - ri.label[32] = 0; - write_import_rec(&ri); - } else if (is_global) { - r.type = 3; - r.segment = segment; - r.offset = offset; - strncpy(r.label,name,32); - r.label[32] = 0; - write_export_rec(&r); - } -} - -static void rdf_out (long segto, void *data, unsigned long type, - long segment, long wrt) -{ - long bytes = type & OUT_SIZMASK; - struct RelocRec rr; - unsigned char databuf[4],*pd; - - if (segto == NO_SEG) { - if ((type & OUT_TYPMASK) != OUT_RESERVE) - error (ERR_NONFATAL, "attempt to assemble code in ABSOLUTE space"); - return; - } - - segto >>= 1; /* convert NASM segment no to RDF number */ - - if (segto != 0 && segto != 1 && segto != 2) { - error(ERR_NONFATAL,"specified segment not supported by rdf output format"); - return; - } - - if (wrt != NO_SEG) { - wrt = NO_SEG; /* continue to do _something_ */ - error (ERR_NONFATAL, "WRT not supported by rdf output format"); - } - - type &= OUT_TYPMASK; - - if (segto == 2 && type != OUT_RESERVE) - { - error(ERR_NONFATAL, "BSS segments may not be initialised"); - - /* just reserve the space for now... */ - - if (type == OUT_REL2ADR) - bytes = 2; - else - bytes = 4; - type = OUT_RESERVE; - } - - if (type == OUT_RESERVE) { - if (segto == 2) /* BSS segment space reserverd */ - bsslength += bytes; - else - while (bytes --) - membufwrite(seg[segto],databuf,1); - } - else if (type == OUT_RAWDATA) { - if (segment != NO_SEG) - error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); - membufwrite(seg[segto],data,bytes); - } - else if (type == OUT_ADDRESS) { - - /* if segment == NO_SEG then we are writing an address of an - object within the same segment - do not produce reloc rec. */ - - if (segment != NO_SEG) - { - - /* it's an address, so we must write a relocation record */ - - rr.type = 1; /* type signature */ - rr.segment = segto; /* segment we're currently in */ - rr.offset = membuflength(seg[segto]); /* current offset */ - rr.length = bytes; /* length of reference */ - rr.refseg = segment; /* segment referred to */ - write_reloc_rec(&rr); - } - - pd = databuf; /* convert address to little-endian */ - if (bytes == 2) - WRITESHORT (pd, *(long *)data); - else - WRITELONG (pd, *(long *)data); - - membufwrite(seg[segto],databuf,bytes); - - } - else if (type == OUT_REL2ADR) - { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL2ADR"); - if (segment != NO_SEG && segment % 2) { - error(ERR_NONFATAL, "rdf format does not support segment base refs"); - } - - rr.type = 1; /* type signature */ - rr.segment = segto+64; /* segment we're currently in + rel flag */ - rr.offset = membuflength(seg[segto]); /* current offset */ - rr.length = 2; /* length of reference */ - rr.refseg = segment; /* segment referred to */ - write_reloc_rec(&rr); - - /* work out what to put in the code: offset of the end of this operand, - * subtracted from any data specified, so that loader can just add - * address of imported symbol onto it to get address relative to end of - * instruction: import_address + data(offset) - end_of_instrn */ - - rr.offset = *(long *)data -(rr.offset + bytes); - - membufwrite(seg[segto],&rr.offset,-2); - } - else if (type == OUT_REL4ADR) - { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL4ADR"); - if (segment != NO_SEG && segment % 2) { - error(ERR_NONFATAL, "rdf format does not support segment base refs"); - } - - rr.type = 1; /* type signature */ - rr.segment = segto+64; /* segment we're currently in + rel tag */ - rr.offset = membuflength(seg[segto]); /* current offset */ - rr.length = 4; /* length of reference */ - rr.refseg = segment; /* segment referred to */ - write_reloc_rec(&rr); - - rr.offset = *(long *)data -(rr.offset + bytes); - membufwrite(seg[segto],&rr.offset,-4); - } -} - -static void rdf_cleanup (int debuginfo) { - long l; - unsigned char b[4],*d; - struct BSSRec bs; - - (void) debuginfo; - - - /* should write imported & exported symbol declarations to header here */ - - /* generate the output file... */ - fwrite(RDOFFId,6,1,ofile); /* file type magic number */ - - if (bsslength != 0) /* reserve BSS */ - { - bs.type = 5; - bs.amount = bsslength; - write_bss_rec(&bs); - } - - l = membuflength(header);d=b; - WRITELONG(d,l); - - fwrite(b,4,1,ofile); /* write length of header */ - membufdump(header,ofile); /* dump header */ - - l = membuflength(seg[0]);d=b; /* code segment */ - WRITELONG(d,l); - - fwrite(b,4,1,ofile); - membufdump(seg[0],ofile); - - l = membuflength(seg[1]);d=b; /* data segment */ - WRITELONG(d,l); - - fwrite(b,4,1,ofile); - membufdump(seg[1],ofile); - - freemembuf(header); - freemembuf(seg[0]); - freemembuf(seg[1]); - fclose(ofile); -} - -static long rdf_segbase (long segment) { - return segment; -} - -static int rdf_directive (char *directive, char *value, int pass) { - struct DLLRec r; - - if (! strcmp(directive, "library")) { - if (pass == 1) { - r.type = 4; - strcpy(r.libname, value); - write_dll_rec(&r); - } - return 1; - } - - return 0; -} - -static void rdf_filename (char *inname, char *outname, efunc error) { - standard_extension(inname,outname,".rdf",error); -} - -static char *rdf_stdmac[] = { - "%define __SECT__ [section .text]", - "%imacro library 1+.nolist", - "[library %1]", - "%endmacro", - "%macro __NASM_CDecl__ 1", - "%endmacro", - NULL -}; - -static int rdf_set_info(enum geninfo type, char **val) -{ - return 0; -} - -struct ofmt of_rdf = { - "Relocatable Dynamic Object File Format v1.1", -#ifdef OF_RDF2 - "oldrdf", -#else - "rdf", -#endif - NULL, - null_debug_arr, - &null_debug_form, - rdf_stdmac, - rdf_init, - rdf_set_info, - rdf_out, - rdf_deflabel, - rdf_section_names, - rdf_segbase, - rdf_directive, - rdf_filename, - rdf_cleanup -}; - -#endif /* OF_RDF */ +/* outrdf.c output routines for the Netwide Assembler to produce + * RDOFF format object files (which are intended mainly + * for use in proprietary projects, as the code to load and + * execute them is very simple). They will also be used + * for device drivers and possibly some executable files + * in the MOSCOW operating system. See Rdoff.txt for + * details. + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "outform.h" + +/* VERBOSE_WARNINGS: define this to add some extra warnings... */ +#define VERBOSE_WARNINGS + +#ifdef OF_RDF + +typedef short int16; /* not sure if this will be required to be altered + at all... best to typedef it just in case */ + +static const char *RDOFFId = "RDOFF1"; /* written to start of RDOFF files */ + +/* the records that can be found in the RDOFF header */ + +/* Note that whenever a segment is referred to in the RDOFF file, its number + * is always half of the segment number that NASM uses to refer to it; this + * is because NASM only allocates even numbered segments, so as to not + * waste any of the 16 bits of segment number written to the file - this + * allows up to 65533 external labels to be defined; otherwise it would be + * 32764. */ + +struct RelocRec { + char type; /* must be 1 */ + char segment; /* only 0 for code, or 1 for data supported, + * but add 64 for relative refs (ie do not require + * reloc @ loadtime, only linkage) */ + long offset; /* from start of segment in which reference is loc'd */ + char length; /* 1 2 or 4 bytes */ + int16 refseg; /* segment to which reference refers to */ +}; + +struct ImportRec { + char type; /* must be 2 */ + int16 segment; /* segment number allocated to the label for reloc + * records - label is assumed to be at offset zero + * in this segment, so linker must fix up with offset + * of segment and of offset within segment */ + char label[33]; /* zero terminated... should be written to file until + * the zero, but not after it - max len = 32 chars */ +}; + +struct ExportRec { + char type; /* must be 3 */ + char segment; /* segment referred to (0/1) */ + long offset; /* offset within segment */ + char label[33]; /* zero terminated as above. max len = 32 chars */ +}; + +struct DLLRec { + char type; /* must be 4 */ + char libname[128]; /* name of library to link with at load time */ +}; + +struct BSSRec { + char type; /* must be 5 */ + long amount; /* number of bytes BSS to reserve */ +}; + +/* code for managing buffers needed to seperate code and data into individual + * sections until they are ready to be written to the file. + * We'd better hope that it all fits in memory else we're buggered... */ + +#define BUF_BLOCK_LEN 4088 /* selected to match page size (4096) + * on 80x86 machines for efficiency */ + +typedef struct memorybuffer { + int length; + char buffer[BUF_BLOCK_LEN]; + struct memorybuffer *next; +} memorybuffer; + +static memorybuffer *newmembuf(void) +{ + memorybuffer *t; + + t = nasm_malloc(sizeof(memorybuffer)); + + t->length = 0; + t->next = NULL; + return t; +} + +static void membufwrite(memorybuffer * b, void *data, int bytes) +{ + int16 w; + long l; + + if (b->next) { /* memory buffer full - use next buffer */ + membufwrite(b->next, data, bytes); + return; + } + if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN) + || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) { + + /* buffer full and no next allocated... allocate and initialise next + * buffer */ + + b->next = newmembuf(); + membufwrite(b->next, data, bytes); + return; + } + + switch (bytes) { + case -4: /* convert to little-endian */ + l = *(long *)data; + b->buffer[b->length++] = l & 0xFF; + l >>= 8; + b->buffer[b->length++] = l & 0xFF; + l >>= 8; + b->buffer[b->length++] = l & 0xFF; + l >>= 8; + b->buffer[b->length++] = l & 0xFF; + break; + + case -2: + w = *(int16 *) data; + b->buffer[b->length++] = w & 0xFF; + w >>= 8; + b->buffer[b->length++] = w & 0xFF; + break; + + default: + while (bytes--) { + b->buffer[b->length++] = *(*(unsigned char **)&data); + + (*(unsigned char **)&data)++; + } + break; + } +} + +static void membufdump(memorybuffer * b, FILE * fp) +{ + if (!b) + return; + + fwrite(b->buffer, 1, b->length, fp); + + membufdump(b->next, fp); +} + +static int membuflength(memorybuffer * b) +{ + if (!b) + return 0; + return b->length + membuflength(b->next); +} + +static void freemembuf(memorybuffer * b) +{ + if (!b) + return; + freemembuf(b->next); + nasm_free(b); +} + +/*********************************************************************** + * Actual code to deal with RDOFF ouput format begins here... + */ + +/* global variables set during the initialisation phase */ + +static memorybuffer *seg[2]; /* seg 0 = code, seg 1 = data */ +static memorybuffer *header; /* relocation/import/export records */ + +static FILE *ofile; + +static efunc error; + +static int segtext, segdata, segbss; +static long bsslength; + +static void rdf_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + ofile = fp; + error = errfunc; + seg[0] = newmembuf(); + seg[1] = newmembuf(); + header = newmembuf(); + segtext = seg_alloc(); + segdata = seg_alloc(); + segbss = seg_alloc(); + if (segtext != 0 || segdata != 2 || segbss != 4) + error(ERR_PANIC, + "rdf segment numbers not allocated as expected (%d,%d,%d)", + segtext, segdata, segbss); + bsslength = 0; +} + +static long rdf_section_names(char *name, int pass, int *bits) +{ + /* + * Default is 32 bits. + */ + if (!name) + *bits = 32; + + if (!name) + return 0; + if (!strcmp(name, ".text")) + return 0; + else if (!strcmp(name, ".data")) + return 2; + else if (!strcmp(name, ".bss")) + return 4; + else + return NO_SEG; +} + +static void write_reloc_rec(struct RelocRec *r) +{ + if (r->refseg != NO_SEG && (r->refseg & 1)) + error(ERR_NONFATAL, "RDF format does not support segment base" + " references"); + + r->refseg >>= 1; /* adjust segment nos to RDF rather than NASM */ + + membufwrite(header, &r->type, 1); + membufwrite(header, &r->segment, 1); + membufwrite(header, &r->offset, -4); + membufwrite(header, &r->length, 1); + membufwrite(header, &r->refseg, -2); /* 9 bytes written */ +} + +static void write_export_rec(struct ExportRec *r) +{ + r->segment >>= 1; + + membufwrite(header, &r->type, 1); + membufwrite(header, &r->segment, 1); + membufwrite(header, &r->offset, -4); + membufwrite(header, r->label, strlen(r->label) + 1); +} + +static void write_import_rec(struct ImportRec *r) +{ + r->segment >>= 1; + + membufwrite(header, &r->type, 1); + membufwrite(header, &r->segment, -2); + membufwrite(header, r->label, strlen(r->label) + 1); +} + +static void write_bss_rec(struct BSSRec *r) +{ + membufwrite(header, &r->type, 1); + membufwrite(header, &r->amount, -4); +} + +static void write_dll_rec(struct DLLRec *r) +{ + membufwrite(header, &r->type, 1); + membufwrite(header, r->libname, strlen(r->libname) + 1); +} + +static void rdf_deflabel(char *name, long segment, long offset, + int is_global, char *special) +{ + struct ExportRec r; + struct ImportRec ri; +#ifdef VERBOSE_WARNINGS + static int warned_common = 0; +#endif + + if (special) + error(ERR_NONFATAL, "RDOFF format does not support any" + " special symbol types"); + + if (name[0] == '.' && name[1] == '.' && name[2] != '@') { + error(ERR_NONFATAL, "unrecognised special symbol `%s'", name); + return; + } + + if (is_global == 2) { +#ifdef VERBOSE_WARNINGS + if (!warned_common) { + error(ERR_WARNING, + "common declarations not supported: using extern"); + warned_common = 1; + } +#endif + is_global = 1; + } + + if (segment > 4) { /* EXTERN declaration */ + ri.type = 2; + ri.segment = segment; + strncpy(ri.label, name, 32); + ri.label[32] = 0; + write_import_rec(&ri); + } else if (is_global) { + r.type = 3; + r.segment = segment; + r.offset = offset; + strncpy(r.label, name, 32); + r.label[32] = 0; + write_export_rec(&r); + } +} + +static void rdf_out(long segto, void *data, unsigned long type, + long segment, long wrt) +{ + long bytes = type & OUT_SIZMASK; + struct RelocRec rr; + unsigned char databuf[4], *pd; + + if (segto == NO_SEG) { + if ((type & OUT_TYPMASK) != OUT_RESERVE) + error(ERR_NONFATAL, + "attempt to assemble code in ABSOLUTE space"); + return; + } + + segto >>= 1; /* convert NASM segment no to RDF number */ + + if (segto != 0 && segto != 1 && segto != 2) { + error(ERR_NONFATAL, + "specified segment not supported by rdf output format"); + return; + } + + if (wrt != NO_SEG) { + wrt = NO_SEG; /* continue to do _something_ */ + error(ERR_NONFATAL, "WRT not supported by rdf output format"); + } + + type &= OUT_TYPMASK; + + if (segto == 2 && type != OUT_RESERVE) { + error(ERR_NONFATAL, "BSS segments may not be initialised"); + + /* just reserve the space for now... */ + + if (type == OUT_REL2ADR) + bytes = 2; + else + bytes = 4; + type = OUT_RESERVE; + } + + if (type == OUT_RESERVE) { + if (segto == 2) /* BSS segment space reserverd */ + bsslength += bytes; + else + while (bytes--) + membufwrite(seg[segto], databuf, 1); + } else if (type == OUT_RAWDATA) { + if (segment != NO_SEG) + error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); + membufwrite(seg[segto], data, bytes); + } else if (type == OUT_ADDRESS) { + + /* if segment == NO_SEG then we are writing an address of an + object within the same segment - do not produce reloc rec. */ + + if (segment != NO_SEG) { + + /* it's an address, so we must write a relocation record */ + + rr.type = 1; /* type signature */ + rr.segment = segto; /* segment we're currently in */ + rr.offset = membuflength(seg[segto]); /* current offset */ + rr.length = bytes; /* length of reference */ + rr.refseg = segment; /* segment referred to */ + write_reloc_rec(&rr); + } + + pd = databuf; /* convert address to little-endian */ + if (bytes == 2) + WRITESHORT(pd, *(long *)data); + else + WRITELONG(pd, *(long *)data); + + membufwrite(seg[segto], databuf, bytes); + + } else if (type == OUT_REL2ADR) { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL2ADR"); + if (segment != NO_SEG && segment % 2) { + error(ERR_NONFATAL, + "rdf format does not support segment base refs"); + } + + rr.type = 1; /* type signature */ + rr.segment = segto + 64; /* segment we're currently in + rel flag */ + rr.offset = membuflength(seg[segto]); /* current offset */ + rr.length = 2; /* length of reference */ + rr.refseg = segment; /* segment referred to */ + write_reloc_rec(&rr); + + /* work out what to put in the code: offset of the end of this operand, + * subtracted from any data specified, so that loader can just add + * address of imported symbol onto it to get address relative to end of + * instruction: import_address + data(offset) - end_of_instrn */ + + rr.offset = *(long *)data - (rr.offset + bytes); + + membufwrite(seg[segto], &rr.offset, -2); + } else if (type == OUT_REL4ADR) { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL4ADR"); + if (segment != NO_SEG && segment % 2) { + error(ERR_NONFATAL, + "rdf format does not support segment base refs"); + } + + rr.type = 1; /* type signature */ + rr.segment = segto + 64; /* segment we're currently in + rel tag */ + rr.offset = membuflength(seg[segto]); /* current offset */ + rr.length = 4; /* length of reference */ + rr.refseg = segment; /* segment referred to */ + write_reloc_rec(&rr); + + rr.offset = *(long *)data - (rr.offset + bytes); + membufwrite(seg[segto], &rr.offset, -4); + } +} + +static void rdf_cleanup(int debuginfo) +{ + long l; + unsigned char b[4], *d; + struct BSSRec bs; + + (void)debuginfo; + + /* should write imported & exported symbol declarations to header here */ + + /* generate the output file... */ + fwrite(RDOFFId, 6, 1, ofile); /* file type magic number */ + + if (bsslength != 0) { /* reserve BSS */ + bs.type = 5; + bs.amount = bsslength; + write_bss_rec(&bs); + } + + l = membuflength(header); + d = b; + WRITELONG(d, l); + + fwrite(b, 4, 1, ofile); /* write length of header */ + membufdump(header, ofile); /* dump header */ + + l = membuflength(seg[0]); + d = b; /* code segment */ + WRITELONG(d, l); + + fwrite(b, 4, 1, ofile); + membufdump(seg[0], ofile); + + l = membuflength(seg[1]); + d = b; /* data segment */ + WRITELONG(d, l); + + fwrite(b, 4, 1, ofile); + membufdump(seg[1], ofile); + + freemembuf(header); + freemembuf(seg[0]); + freemembuf(seg[1]); + fclose(ofile); +} + +static long rdf_segbase(long segment) +{ + return segment; +} + +static int rdf_directive(char *directive, char *value, int pass) +{ + struct DLLRec r; + + if (!strcmp(directive, "library")) { + if (pass == 1) { + r.type = 4; + strcpy(r.libname, value); + write_dll_rec(&r); + } + return 1; + } + + return 0; +} + +static void rdf_filename(char *inname, char *outname, efunc error) +{ + standard_extension(inname, outname, ".rdf", error); +} + +static char *rdf_stdmac[] = { + "%define __SECT__ [section .text]", + "%imacro library 1+.nolist", + "[library %1]", + "%endmacro", + "%macro __NASM_CDecl__ 1", + "%endmacro", + NULL +}; + +static int rdf_set_info(enum geninfo type, char **val) +{ + return 0; +} + +struct ofmt of_rdf = { + "Relocatable Dynamic Object File Format v1.1", +#ifdef OF_RDF2 + "oldrdf", +#else + "rdf", +#endif + NULL, + null_debug_arr, + &null_debug_form, + rdf_stdmac, + rdf_init, + rdf_set_info, + rdf_out, + rdf_deflabel, + rdf_section_names, + rdf_segbase, + rdf_directive, + rdf_filename, + rdf_cleanup +}; + +#endif /* OF_RDF */ diff --git a/output/outrdf2.c b/output/outrdf2.c dissimilarity index 72% index 6c7a1027..0baca45a 100644 --- a/output/outrdf2.c +++ b/output/outrdf2.c @@ -1,770 +1,782 @@ -/* - * outrdf2.c output routines for the Netwide Assembler to produce - * RDOFF version 2 format object files, which is used as a - * main binary format in the RadiOS (http://radios.sf.net). - * Originally Julian planned to use it in his MOSCOW - * operating system. - * - * The Netwide Assembler is copyright (C) 1996-1998 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" -#include "outform.h" - -/* VERBOSE_WARNINGS: define this to add some extra warnings... */ -#define VERBOSE_WARNINGS - -#ifdef OF_RDF2 - -#include "rdoff/rdoff.h" - -/* This signature is written to start of RDOFF files */ -static const char *RDOFF2Id = RDOFF2_SIGNATURE; - - -/* Note that whenever a segment is referred to in the RDOFF file, its number - * is always half of the segment number that NASM uses to refer to it; this - * is because NASM only allocates even numbered segments, so as to not - * waste any of the 16 bits of segment number written to the file - this - * allows up to 65533 external labels to be defined; otherwise it would be - * 32764. */ - -#define COUNT_SEGTYPES 9 - -static char * segmenttypes[COUNT_SEGTYPES] = { - "null", "text", "code", "data", - "comment", "lcomment", "pcomment", - "symdebug", "linedebug" -}; - -static int segmenttypenumbers[COUNT_SEGTYPES] = { - 0, 1, 1, 2, 3, 4, 5, 6, 7 -}; - -/* code for managing buffers needed to separate code and data into individual - * sections until they are ready to be written to the file. - * We'd better hope that it all fits in memory else we're buggered... */ - -#define BUF_BLOCK_LEN 4088 /* selected to match page size (4096) - * on 80x86 machines for efficiency */ - -/*********************************************************************** - * Actual code to deal with RDOFF2 ouput format begins here... - */ - -/* global variables set during the initialisation phase */ - -static struct SAA *seg[RDF_MAXSEGS]; /* seg 0 = code, seg 1 = data */ -static struct SAA *header; /* relocation/import/export records */ - -static FILE *ofile; - -static efunc error; - -static struct seginfo { - char *segname; - int segnumber; - uint16 segtype; - uint16 segreserved; - long seglength; -} segments[RDF_MAXSEGS]; - -static int nsegments; - -static long bsslength; -static long headerlength; - -static void rdf2_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) -{ - int segtext, segdata, segbss; - - /* set up the initial segments */ - segments[0].segname = ".text"; - segments[0].segnumber = 0; - segments[0].segtype = 1; - segments[0].segreserved = 0; - segments[0].seglength = 0; - - segments[1].segname = ".data"; - segments[1].segnumber = 1; - segments[1].segtype = 2; - segments[1].segreserved = 0; - segments[1].seglength = 0; - - segments[2].segname = ".bss"; - segments[2].segnumber = 2; - segments[2].segtype = 0xFFFF; /* reserved - should never be produced */ - segments[2].segreserved = 0; - segments[2].seglength = 0; - - nsegments = 3; - - ofile = fp; - error = errfunc; - - seg[0] = saa_init(1L); - seg[1] = saa_init(1L); - seg[2] = NULL; /* special case! */ - - header = saa_init(1L); - - segtext = seg_alloc(); - segdata = seg_alloc(); - segbss = seg_alloc(); - if (segtext != 0 || segdata != 2 || segbss != 4) - error(ERR_PANIC,"rdf segment numbers not allocated as expected (%d,%d,%d)", - segtext,segdata,segbss); - bsslength=0; - headerlength = 0; -} - -static long rdf2_section_names(char *name, int pass, int *bits) -{ - int i; - char * p, * q; - int code = -1; - int reserved = 0; - - /* - * Default is 32 bits, in the text segment. - */ - if (!name) { - *bits = 32; - return 0; - } - - /* look for segment type code following segment name */ - p = name; - while (*p && !isspace(*p)) p++; - if (*p) { /* we're now in whitespace */ - *p++ = '\0'; - while (*p && isspace(80)) *p++ = '\0'; - } - if (*p) { /* we're now in an attribute value */ - /* - * see if we have an optional ',number' following the type code - */ - if ((q = strchr(p, ','))) { - *q++ = '\0'; - - reserved = readnum(q, &i); - if (i) { - error(ERR_NONFATAL, "value following comma must be numeric"); - reserved = 0; - } - } - /* - * check it against the text strings in segmenttypes - */ - - for (i = 0; i < COUNT_SEGTYPES; i++) - if (!nasm_stricmp(p, segmenttypes[i])) { - code = segmenttypenumbers[i]; - break; - } - if (code == -1) { /* didn't find anything */ - code = readnum(p, &i); - if (i) { - error(ERR_NONFATAL, "unrecognised RDF segment type (%s)",p); - code = 3; - } - } - } - for (i = 0; i < nsegments; i++) { - if (!strcmp(name, segments[i].segname)) { - if (code != -1 || reserved != 0) - error(ERR_NONFATAL, "segment attributes specified on" - " redeclaration of segment"); - return segments[i].segnumber * 2; - } - } - - /* declaring a new segment! */ - - if (code == -1) { - error(ERR_NONFATAL, "new segment declared without type code"); - code = 3; - } - if (nsegments == RDF_MAXSEGS) { - error(ERR_FATAL, "reached compiled-in maximum segment limit (%d)", - RDF_MAXSEGS); - return NO_SEG; - } - - segments[nsegments].segname = nasm_strdup(name); - i = seg_alloc(); - if (i % 2 != 0) - error(ERR_PANIC, "seg_alloc() returned odd number"); - segments[nsegments].segnumber = i >> 1; - segments[nsegments].segtype = code; - segments[nsegments].segreserved = reserved; - segments[nsegments].seglength = 0; - - seg[nsegments] = saa_init(1L); - - return i; -} - - -/* - * Write relocation record - */ -static void write_reloc_rec(struct RelocRec *r) -{ - char buf[4],*b; - - if (r->refseg != (uint16)NO_SEG && (r->refseg & 1)) /* segment base ref */ - r->type = RDFREC_SEGRELOC; - - r->refseg >>= 1; /* adjust segment nos to RDF rather than NASM */ - - saa_wbytes(header,&r->type,1); - saa_wbytes(header,&r->reclen,1); - saa_wbytes(header,&r->segment,1); - b = buf; WRITELONG(b,r->offset); - saa_wbytes(header,buf,4); - saa_wbytes(header,&r->length,1); - b = buf; WRITESHORT(b,r->refseg); - saa_wbytes(header,buf,2); - headerlength += r->reclen + 2; -} - - -/* - * Write export record - */ -static void write_export_rec(struct ExportRec *r) -{ - char buf[4], *b; - - r->segment >>= 1; - - saa_wbytes(header, &r->type, 1); - saa_wbytes(header, &r->reclen, 1); - saa_wbytes(header, &r->flags, 1); - saa_wbytes(header, &r->segment, 1); - b = buf; WRITELONG(b, r->offset); - saa_wbytes(header, buf, 4); - saa_wbytes(header, r->label, strlen(r->label) + 1); - headerlength += r->reclen + 2; -} - -static void write_import_rec(struct ImportRec *r) -{ - char buf[4], *b; - - r->segment >>= 1; - - saa_wbytes(header, &r->type, 1); - saa_wbytes(header, &r->reclen, 1); - saa_wbytes(header, &r->flags, 1); - b = buf; WRITESHORT(b,r->segment); - saa_wbytes(header, buf, 2); - saa_wbytes(header, r->label, strlen(r->label) + 1); - headerlength += r->reclen + 2; -} - - -/* - * Write BSS record - */ -static void write_bss_rec(struct BSSRec *r) -{ - char buf[4], *b; - - saa_wbytes(header,&r->type,1); - saa_wbytes(header,&r->reclen,1); - b = buf; WRITELONG(b,r->amount); - saa_wbytes(header,buf,4); - headerlength += r->reclen + 2; -} - -/* - * Write common variable record - */ -static void write_common_rec(struct CommonRec *r) -{ - char buf[4], *b; - - r->segment >>= 1; - - saa_wbytes(header, &r->type, 1); - saa_wbytes(header, &r->reclen, 1); - b = buf; WRITESHORT(b,r->segment); - saa_wbytes(header, buf, 2); - b = buf; WRITELONG(b, r->size); - saa_wbytes(header,buf,4); - b = buf; WRITESHORT(b, r->align); - saa_wbytes(header, buf, 2); - saa_wbytes(header, r->label, strlen(r->label) + 1); - headerlength += r->reclen + 2; -} - -/* - * Write library record - */ -static void write_dll_rec(struct DLLRec *r) -{ - saa_wbytes(header,&r->type,1); - saa_wbytes(header,&r->reclen,1); - saa_wbytes(header, r->libname, strlen(r->libname) + 1); - headerlength += r->reclen + 2; -} - - -/* - * Write module name record - */ -static void write_modname_rec(struct ModRec *r) -{ - saa_wbytes(header,&r->type,1); - saa_wbytes(header,&r->reclen,1); - saa_wbytes(header, r->modname, strlen(r->modname) + 1); - headerlength += r->reclen + 2; -} - - -/* - * Handle export, import and common records. - */ -static void rdf2_deflabel(char *name, long segment, long offset, - int is_global, char *special) -{ - struct ExportRec r; - struct ImportRec ri; - struct CommonRec ci; - static int farsym = 0; - static int i; - byte symflags = 0; - int len; - - /* Check if the label length is OK */ - if ((len = strlen(name)) >= EXIM_LABEL_MAX) { - error(ERR_NONFATAL, "label size exceeds %d bytes", EXIM_LABEL_MAX); - return; - } - if (!len) { - error(ERR_NONFATAL, "zero-length label"); - return; - } - - if (is_global == 2) { - /* Common variable */ - ci.type = RDFREC_COMMON; - ci.size = offset; - ci.segment = segment; - strcpy(ci.label, name); - ci.reclen = 9 + len; - ci.align = 0; - - /* - * Check the special text to see if it's a valid number and power - * of two; if so, store it as the alignment for the common variable. - */ - if (special) { - int err; - ci.align = readnum(special, &err); - if (err) - error(ERR_NONFATAL, "alignment constraint `%s' is not a" - " valid number", special); - else if ( (ci.align | (ci.align-1)) != 2*ci.align - 1) - error(ERR_NONFATAL, "alignment constraint `%s' is not a" - " power of two", special); - } - write_common_rec(&ci); - } - - /* We don't care about local labels or fix-up hints */ - if (is_global != 1) return; - - if (special) { - while(*special == ' ' || *special == '\t') special++; - - if (!nasm_strnicmp(special, "export", 6)) { - special += 6; - symflags |= SYM_GLOBAL; - } else if (!nasm_strnicmp(special, "import", 6)) { - special += 6; - symflags |= SYM_IMPORT; - } - - if (*special) { - while (isspace(*special)) special++; - if (!nasm_stricmp(special, "far")) { - farsym = 1; - } else if (!nasm_stricmp(special, "near")) { - farsym = 0; - } else if (!nasm_stricmp(special, "proc") || - !nasm_stricmp(special, "function")) { - symflags |= SYM_FUNCTION; - } else if (!nasm_stricmp(special, "data") || - !nasm_stricmp(special, "object")) { - symflags |= SYM_DATA; - } else - error(ERR_NONFATAL, "unrecognised symbol type `%s'", special); - } - } - - if (name[0] == '.' && name[1] == '.' && name[2] != '@') { - error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); - return; - } - - for (i = 0; i < nsegments; i++) { - if (segments[i].segnumber == segment>>1) break; - } - - if (i >= nsegments) { /* EXTERN declaration */ - ri.type = farsym ? RDFREC_FARIMPORT : RDFREC_IMPORT; - if (symflags & SYM_GLOBAL) - error(ERR_NONFATAL, "symbol type conflict - EXTERN cannot be EXPORT"); - ri.flags = symflags; - ri.segment = segment; - strcpy(ri.label, name); - ri.reclen = 4 + len; - write_import_rec(&ri); - } else if (is_global) { - r.type = RDFREC_GLOBAL; /* GLOBAL declaration */ - if (symflags & SYM_IMPORT) - error(ERR_NONFATAL, "symbol type conflict - GLOBAL cannot be IMPORT"); - r.flags = symflags; - r.segment = segment; - r.offset = offset; - strcpy(r.label, name); - r.reclen = 7 + len; - write_export_rec(&r); - } -} - -static void membufwrite(int segment, const void * data, int bytes) -{ - int i; - char buf[4], * b; - - for (i = 0; i < nsegments; i++) { - if (segments[i].segnumber == segment) break; - } - if (i == nsegments) - error(ERR_PANIC, "can't find segment %d", segment); - - if (bytes < 0) { - b = buf; - if (bytes == -2) - WRITESHORT(b,*(short *)data); - else - WRITELONG(b,*(long *)data); - data = buf; - bytes = -bytes; - } - segments[i].seglength += bytes; - saa_wbytes(seg[i],data,bytes); -} - -static int getsegmentlength(int segment) -{ - int i; - for (i = 0; i < nsegments; i++) { - if (segments[i].segnumber == segment) break; - } - if (i == nsegments) - error(ERR_PANIC, "can't find segment %d", segment); - - return segments[i].seglength; -} - -static void rdf2_out (long segto, const void *data, unsigned long type, - long segment, long wrt) -{ - long bytes = type & OUT_SIZMASK; - struct RelocRec rr; - unsigned char databuf[4],*pd; - int seg; - - if (segto == NO_SEG) { - if ((type & OUT_TYPMASK) != OUT_RESERVE) - error (ERR_NONFATAL, "attempt to assemble code in ABSOLUTE space"); - return; - } - - segto >>= 1; /* convert NASM segment no to RDF number */ - - for (seg = 0; seg < nsegments; seg++) { - if (segments[seg].segnumber == segto) break; - } - if (seg >= nsegments) { - error(ERR_NONFATAL,"specified segment not supported by rdf output format"); - return; - } - - if (wrt != NO_SEG) { - wrt = NO_SEG; /* continue to do _something_ */ - error (ERR_NONFATAL, "WRT not supported by rdf output format"); - } - - type &= OUT_TYPMASK; - - if (segto == 2 && type != OUT_RESERVE) - { - error(ERR_NONFATAL, "BSS segments may not be initialised"); - - /* just reserve the space for now... */ - - if (type == OUT_REL2ADR) - bytes = 2; - else - bytes = 4; - type = OUT_RESERVE; - } - - if (type == OUT_RESERVE) { - if (segto == 2) /* BSS segment space reserverd */ - bsslength += bytes; - else - while (bytes --) - membufwrite(segto,databuf,1); - } - else if (type == OUT_RAWDATA) { - if (segment != NO_SEG) - error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); - - membufwrite(segto,data,bytes); - } - else if (type == OUT_ADDRESS) { - - /* if segment == NO_SEG then we are writing an address of an - object within the same segment - do not produce reloc rec. */ - - /* FIXME - is this behaviour sane? at first glance it doesn't - appear to be. Must test this thoroughly...! */ - - if (segment != NO_SEG) - { - /* it's an address, so we must write a relocation record */ - - rr.type = RDFREC_RELOC; /* type signature */ - rr.reclen = 8; - rr.segment = segto; /* segment we're currently in */ - rr.offset = getsegmentlength(segto); /* current offset */ - rr.length = bytes; /* length of reference */ - rr.refseg = segment; /* segment referred to */ - write_reloc_rec(&rr); - } - - pd = databuf; /* convert address to little-endian */ - if (bytes == 2) - WRITESHORT (pd, *(long *)data); - else - WRITELONG (pd, *(long *)data); - - membufwrite(segto,databuf,bytes); - - } - else if (type == OUT_REL2ADR) - { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL2ADR"); - - rr.reclen = 8; - rr.offset = getsegmentlength(segto); /* current offset */ - rr.length = 2; /* length of reference */ - rr.refseg = segment; /* segment referred to (will be >>1'd)*/ - - if (segment != NO_SEG && segment % 2) { - rr.type = RDFREC_SEGRELOC; - rr.segment = segto; /* memory base refs *aren't ever* relative! */ - write_reloc_rec(&rr); - - /* what do we put in the code? Simply the data. This should almost - * always be zero, unless someone's doing segment arithmetic... - */ - rr.offset = *(long *) data; - } - else - { - rr.type = RDFREC_RELOC; /* type signature */ - rr.segment = segto+64; /* segment we're currently in + rel flag */ - write_reloc_rec(&rr); - - /* work out what to put in the code: offset of the end of this operand, - * subtracted from any data specified, so that loader can just add - * address of imported symbol onto it to get address relative to end of - * instruction: import_address + data(offset) - end_of_instrn */ - - rr.offset = *(long *)data -(rr.offset + bytes); - } - - membufwrite(segto,&rr.offset,-2); - } - else if (type == OUT_REL4ADR) - { - if (segment == segto) - error(ERR_PANIC, "intra-segment OUT_REL4ADR"); - if (segment != NO_SEG && segment % 2) { - error(ERR_PANIC, "erm... 4 byte segment base ref?"); - } - - rr.type = RDFREC_RELOC; /* type signature */ - rr.segment = segto+64; /* segment we're currently in + rel tag */ - rr.offset = getsegmentlength(segto); /* current offset */ - rr.length = 4; /* length of reference */ - rr.refseg = segment; /* segment referred to */ - rr.reclen = 8; - write_reloc_rec(&rr); - - rr.offset = *(long *)data -(rr.offset + bytes); - - membufwrite(segto,&rr.offset,-4); - } -} - -static void rdf2_cleanup (int debuginfo) { - long l; - struct BSSRec bs; - int i; - - (void) debuginfo; - - /* should write imported & exported symbol declarations to header here */ - - /* generate the output file... */ - fwrite(RDOFF2Id,6,1,ofile); /* file type magic number */ - - if (bsslength != 0) { /* reserve BSS */ - bs.type = RDFREC_BSS; - bs.amount = bsslength; - bs.reclen = 4; - write_bss_rec(&bs); - } - - /* - * calculate overall length of the output object - */ - l = headerlength + 4; - - for (i = 0; i < nsegments; i++) { - if (i == 2) continue; /* skip BSS segment */ - l += 10 + segments[i].seglength; - } - l += 10; /* null segment */ - - fwritelong(l, ofile); - - fwritelong(headerlength, ofile); - saa_fpwrite(header,ofile); /* dump header */ - saa_free(header); - - for (i = 0; i < nsegments; i++) { - if (i == 2) continue; - - fwriteshort(segments[i].segtype, ofile); - fwriteshort(segments[i].segnumber, ofile); - fwriteshort(segments[i].segreserved, ofile); - fwritelong(segments[i].seglength, ofile); - - saa_fpwrite(seg[i], ofile); - saa_free(seg[i]); - } - - /* null segment - write 10 bytes of zero */ - fwritelong(0,ofile); - fwritelong(0,ofile); - fwriteshort(0,ofile); - - fclose(ofile); -} - -static long rdf2_segbase (long segment) { - return segment; -} - - -/* - * Handle RDOFF2 specific directives - */ -static int rdf2_directive (char *directive, char *value, int pass) -{ - int n; - - /* Check if the name length is OK */ - if ((n = strlen(value)) >= MODLIB_NAME_MAX) { - error(ERR_NONFATAL, "name size exceeds %d bytes", MODLIB_NAME_MAX); - return 0; - } - - if (! strcmp(directive, "library")) { - if (pass == 1) { - struct DLLRec r; - r.type = RDFREC_DLL; - r.reclen = n+1; - strcpy(r.libname, value); - write_dll_rec(&r); - } - return 1; - } - - if (! strcmp(directive, "module")) { - if (pass == 1) { - struct ModRec r; - r.type = RDFREC_MODNAME; - r.reclen = n+1; - strcpy(r.modname, value); - write_modname_rec(&r); - } - return 1; - } - - return 0; -} - -static void rdf2_filename (char *inname, char *outname, efunc error) { - standard_extension(inname,outname,".rdf",error); -} - -static const char *rdf2_stdmac[] = { - "%define __SECT__ [section .text]", - "%imacro library 1+.nolist", - "[library %1]", - "%endmacro", - "%imacro module 1+.nolist", - "[module %1]", - "%endmacro", - "%macro __NASM_CDecl__ 1", - "%endmacro", - NULL -}; - -static int rdf2_set_info(enum geninfo type, char **val) -{ - return 0; -} - - -struct ofmt of_rdf2 = { - "Relocatable Dynamic Object File Format v2.0", - "rdf", - NULL, - null_debug_arr, - &null_debug_form, - rdf2_stdmac, - rdf2_init, - rdf2_set_info, - rdf2_out, - rdf2_deflabel, - rdf2_section_names, - rdf2_segbase, - rdf2_directive, - rdf2_filename, - rdf2_cleanup -}; - -#endif /* OF_RDF2 */ +/* + * outrdf2.c output routines for the Netwide Assembler to produce + * RDOFF version 2 format object files, which is used as a + * main binary format in the RadiOS (http://radios.sf.net). + * Originally Julian planned to use it in his MOSCOW + * operating system. + * + * The Netwide Assembler is copyright (C) 1996-1998 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "outform.h" + +/* VERBOSE_WARNINGS: define this to add some extra warnings... */ +#define VERBOSE_WARNINGS + +#ifdef OF_RDF2 + +#include "rdoff/rdoff.h" + +/* This signature is written to start of RDOFF files */ +static const char *RDOFF2Id = RDOFF2_SIGNATURE; + +/* Note that whenever a segment is referred to in the RDOFF file, its number + * is always half of the segment number that NASM uses to refer to it; this + * is because NASM only allocates even numbered segments, so as to not + * waste any of the 16 bits of segment number written to the file - this + * allows up to 65533 external labels to be defined; otherwise it would be + * 32764. */ + +#define COUNT_SEGTYPES 9 + +static char *segmenttypes[COUNT_SEGTYPES] = { + "null", "text", "code", "data", + "comment", "lcomment", "pcomment", + "symdebug", "linedebug" +}; + +static int segmenttypenumbers[COUNT_SEGTYPES] = { + 0, 1, 1, 2, 3, 4, 5, 6, 7 +}; + +/* code for managing buffers needed to separate code and data into individual + * sections until they are ready to be written to the file. + * We'd better hope that it all fits in memory else we're buggered... */ + +#define BUF_BLOCK_LEN 4088 /* selected to match page size (4096) + * on 80x86 machines for efficiency */ + +/*********************************************************************** + * Actual code to deal with RDOFF2 ouput format begins here... + */ + +/* global variables set during the initialisation phase */ + +static struct SAA *seg[RDF_MAXSEGS]; /* seg 0 = code, seg 1 = data */ +static struct SAA *header; /* relocation/import/export records */ + +static FILE *ofile; + +static efunc error; + +static struct seginfo { + char *segname; + int segnumber; + uint16 segtype; + uint16 segreserved; + long seglength; +} segments[RDF_MAXSEGS]; + +static int nsegments; + +static long bsslength; +static long headerlength; + +static void rdf2_init(FILE * fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + int segtext, segdata, segbss; + + /* set up the initial segments */ + segments[0].segname = ".text"; + segments[0].segnumber = 0; + segments[0].segtype = 1; + segments[0].segreserved = 0; + segments[0].seglength = 0; + + segments[1].segname = ".data"; + segments[1].segnumber = 1; + segments[1].segtype = 2; + segments[1].segreserved = 0; + segments[1].seglength = 0; + + segments[2].segname = ".bss"; + segments[2].segnumber = 2; + segments[2].segtype = 0xFFFF; /* reserved - should never be produced */ + segments[2].segreserved = 0; + segments[2].seglength = 0; + + nsegments = 3; + + ofile = fp; + error = errfunc; + + seg[0] = saa_init(1L); + seg[1] = saa_init(1L); + seg[2] = NULL; /* special case! */ + + header = saa_init(1L); + + segtext = seg_alloc(); + segdata = seg_alloc(); + segbss = seg_alloc(); + if (segtext != 0 || segdata != 2 || segbss != 4) + error(ERR_PANIC, + "rdf segment numbers not allocated as expected (%d,%d,%d)", + segtext, segdata, segbss); + bsslength = 0; + headerlength = 0; +} + +static long rdf2_section_names(char *name, int pass, int *bits) +{ + int i; + char *p, *q; + int code = -1; + int reserved = 0; + + /* + * Default is 32 bits, in the text segment. + */ + if (!name) { + *bits = 32; + return 0; + } + + /* look for segment type code following segment name */ + p = name; + while (*p && !isspace(*p)) + p++; + if (*p) { /* we're now in whitespace */ + *p++ = '\0'; + while (*p && isspace(80)) + *p++ = '\0'; + } + if (*p) { /* we're now in an attribute value */ + /* + * see if we have an optional ',number' following the type code + */ + if ((q = strchr(p, ','))) { + *q++ = '\0'; + + reserved = readnum(q, &i); + if (i) { + error(ERR_NONFATAL, + "value following comma must be numeric"); + reserved = 0; + } + } + /* + * check it against the text strings in segmenttypes + */ + + for (i = 0; i < COUNT_SEGTYPES; i++) + if (!nasm_stricmp(p, segmenttypes[i])) { + code = segmenttypenumbers[i]; + break; + } + if (code == -1) { /* didn't find anything */ + code = readnum(p, &i); + if (i) { + error(ERR_NONFATAL, "unrecognised RDF segment type (%s)", + p); + code = 3; + } + } + } + for (i = 0; i < nsegments; i++) { + if (!strcmp(name, segments[i].segname)) { + if (code != -1 || reserved != 0) + error(ERR_NONFATAL, "segment attributes specified on" + " redeclaration of segment"); + return segments[i].segnumber * 2; + } + } + + /* declaring a new segment! */ + + if (code == -1) { + error(ERR_NONFATAL, "new segment declared without type code"); + code = 3; + } + if (nsegments == RDF_MAXSEGS) { + error(ERR_FATAL, "reached compiled-in maximum segment limit (%d)", + RDF_MAXSEGS); + return NO_SEG; + } + + segments[nsegments].segname = nasm_strdup(name); + i = seg_alloc(); + if (i % 2 != 0) + error(ERR_PANIC, "seg_alloc() returned odd number"); + segments[nsegments].segnumber = i >> 1; + segments[nsegments].segtype = code; + segments[nsegments].segreserved = reserved; + segments[nsegments].seglength = 0; + + seg[nsegments] = saa_init(1L); + + return i; +} + +/* + * Write relocation record + */ +static void write_reloc_rec(struct RelocRec *r) +{ + char buf[4], *b; + + if (r->refseg != (uint16) NO_SEG && (r->refseg & 1)) /* segment base ref */ + r->type = RDFREC_SEGRELOC; + + r->refseg >>= 1; /* adjust segment nos to RDF rather than NASM */ + + saa_wbytes(header, &r->type, 1); + saa_wbytes(header, &r->reclen, 1); + saa_wbytes(header, &r->segment, 1); + b = buf; + WRITELONG(b, r->offset); + saa_wbytes(header, buf, 4); + saa_wbytes(header, &r->length, 1); + b = buf; + WRITESHORT(b, r->refseg); + saa_wbytes(header, buf, 2); + headerlength += r->reclen + 2; +} + +/* + * Write export record + */ +static void write_export_rec(struct ExportRec *r) +{ + char buf[4], *b; + + r->segment >>= 1; + + saa_wbytes(header, &r->type, 1); + saa_wbytes(header, &r->reclen, 1); + saa_wbytes(header, &r->flags, 1); + saa_wbytes(header, &r->segment, 1); + b = buf; + WRITELONG(b, r->offset); + saa_wbytes(header, buf, 4); + saa_wbytes(header, r->label, strlen(r->label) + 1); + headerlength += r->reclen + 2; +} + +static void write_import_rec(struct ImportRec *r) +{ + char buf[4], *b; + + r->segment >>= 1; + + saa_wbytes(header, &r->type, 1); + saa_wbytes(header, &r->reclen, 1); + saa_wbytes(header, &r->flags, 1); + b = buf; + WRITESHORT(b, r->segment); + saa_wbytes(header, buf, 2); + saa_wbytes(header, r->label, strlen(r->label) + 1); + headerlength += r->reclen + 2; +} + +/* + * Write BSS record + */ +static void write_bss_rec(struct BSSRec *r) +{ + char buf[4], *b; + + saa_wbytes(header, &r->type, 1); + saa_wbytes(header, &r->reclen, 1); + b = buf; + WRITELONG(b, r->amount); + saa_wbytes(header, buf, 4); + headerlength += r->reclen + 2; +} + +/* + * Write common variable record + */ +static void write_common_rec(struct CommonRec *r) +{ + char buf[4], *b; + + r->segment >>= 1; + + saa_wbytes(header, &r->type, 1); + saa_wbytes(header, &r->reclen, 1); + b = buf; + WRITESHORT(b, r->segment); + saa_wbytes(header, buf, 2); + b = buf; + WRITELONG(b, r->size); + saa_wbytes(header, buf, 4); + b = buf; + WRITESHORT(b, r->align); + saa_wbytes(header, buf, 2); + saa_wbytes(header, r->label, strlen(r->label) + 1); + headerlength += r->reclen + 2; +} + +/* + * Write library record + */ +static void write_dll_rec(struct DLLRec *r) +{ + saa_wbytes(header, &r->type, 1); + saa_wbytes(header, &r->reclen, 1); + saa_wbytes(header, r->libname, strlen(r->libname) + 1); + headerlength += r->reclen + 2; +} + +/* + * Write module name record + */ +static void write_modname_rec(struct ModRec *r) +{ + saa_wbytes(header, &r->type, 1); + saa_wbytes(header, &r->reclen, 1); + saa_wbytes(header, r->modname, strlen(r->modname) + 1); + headerlength += r->reclen + 2; +} + +/* + * Handle export, import and common records. + */ +static void rdf2_deflabel(char *name, long segment, long offset, + int is_global, char *special) +{ + struct ExportRec r; + struct ImportRec ri; + struct CommonRec ci; + static int farsym = 0; + static int i; + byte symflags = 0; + int len; + + /* Check if the label length is OK */ + if ((len = strlen(name)) >= EXIM_LABEL_MAX) { + error(ERR_NONFATAL, "label size exceeds %d bytes", EXIM_LABEL_MAX); + return; + } + if (!len) { + error(ERR_NONFATAL, "zero-length label"); + return; + } + + if (is_global == 2) { + /* Common variable */ + ci.type = RDFREC_COMMON; + ci.size = offset; + ci.segment = segment; + strcpy(ci.label, name); + ci.reclen = 9 + len; + ci.align = 0; + + /* + * Check the special text to see if it's a valid number and power + * of two; if so, store it as the alignment for the common variable. + */ + if (special) { + int err; + ci.align = readnum(special, &err); + if (err) + error(ERR_NONFATAL, "alignment constraint `%s' is not a" + " valid number", special); + else if ((ci.align | (ci.align - 1)) != 2 * ci.align - 1) + error(ERR_NONFATAL, "alignment constraint `%s' is not a" + " power of two", special); + } + write_common_rec(&ci); + } + + /* We don't care about local labels or fix-up hints */ + if (is_global != 1) + return; + + if (special) { + while (*special == ' ' || *special == '\t') + special++; + + if (!nasm_strnicmp(special, "export", 6)) { + special += 6; + symflags |= SYM_GLOBAL; + } else if (!nasm_strnicmp(special, "import", 6)) { + special += 6; + symflags |= SYM_IMPORT; + } + + if (*special) { + while (isspace(*special)) + special++; + if (!nasm_stricmp(special, "far")) { + farsym = 1; + } else if (!nasm_stricmp(special, "near")) { + farsym = 0; + } else if (!nasm_stricmp(special, "proc") || + !nasm_stricmp(special, "function")) { + symflags |= SYM_FUNCTION; + } else if (!nasm_stricmp(special, "data") || + !nasm_stricmp(special, "object")) { + symflags |= SYM_DATA; + } else + error(ERR_NONFATAL, "unrecognised symbol type `%s'", + special); + } + } + + if (name[0] == '.' && name[1] == '.' && name[2] != '@') { + error(ERR_NONFATAL, "unrecognised special symbol `%s'", name); + return; + } + + for (i = 0; i < nsegments; i++) { + if (segments[i].segnumber == segment >> 1) + break; + } + + if (i >= nsegments) { /* EXTERN declaration */ + ri.type = farsym ? RDFREC_FARIMPORT : RDFREC_IMPORT; + if (symflags & SYM_GLOBAL) + error(ERR_NONFATAL, + "symbol type conflict - EXTERN cannot be EXPORT"); + ri.flags = symflags; + ri.segment = segment; + strcpy(ri.label, name); + ri.reclen = 4 + len; + write_import_rec(&ri); + } else if (is_global) { + r.type = RDFREC_GLOBAL; /* GLOBAL declaration */ + if (symflags & SYM_IMPORT) + error(ERR_NONFATAL, + "symbol type conflict - GLOBAL cannot be IMPORT"); + r.flags = symflags; + r.segment = segment; + r.offset = offset; + strcpy(r.label, name); + r.reclen = 7 + len; + write_export_rec(&r); + } +} + +static void membufwrite(int segment, const void *data, int bytes) +{ + int i; + char buf[4], *b; + + for (i = 0; i < nsegments; i++) { + if (segments[i].segnumber == segment) + break; + } + if (i == nsegments) + error(ERR_PANIC, "can't find segment %d", segment); + + if (bytes < 0) { + b = buf; + if (bytes == -2) + WRITESHORT(b, *(short *)data); + else + WRITELONG(b, *(long *)data); + data = buf; + bytes = -bytes; + } + segments[i].seglength += bytes; + saa_wbytes(seg[i], data, bytes); +} + +static int getsegmentlength(int segment) +{ + int i; + for (i = 0; i < nsegments; i++) { + if (segments[i].segnumber == segment) + break; + } + if (i == nsegments) + error(ERR_PANIC, "can't find segment %d", segment); + + return segments[i].seglength; +} + +static void rdf2_out(long segto, const void *data, unsigned long type, + long segment, long wrt) +{ + long bytes = type & OUT_SIZMASK; + struct RelocRec rr; + unsigned char databuf[4], *pd; + int seg; + + if (segto == NO_SEG) { + if ((type & OUT_TYPMASK) != OUT_RESERVE) + error(ERR_NONFATAL, + "attempt to assemble code in ABSOLUTE space"); + return; + } + + segto >>= 1; /* convert NASM segment no to RDF number */ + + for (seg = 0; seg < nsegments; seg++) { + if (segments[seg].segnumber == segto) + break; + } + if (seg >= nsegments) { + error(ERR_NONFATAL, + "specified segment not supported by rdf output format"); + return; + } + + if (wrt != NO_SEG) { + wrt = NO_SEG; /* continue to do _something_ */ + error(ERR_NONFATAL, "WRT not supported by rdf output format"); + } + + type &= OUT_TYPMASK; + + if (segto == 2 && type != OUT_RESERVE) { + error(ERR_NONFATAL, "BSS segments may not be initialised"); + + /* just reserve the space for now... */ + + if (type == OUT_REL2ADR) + bytes = 2; + else + bytes = 4; + type = OUT_RESERVE; + } + + if (type == OUT_RESERVE) { + if (segto == 2) /* BSS segment space reserverd */ + bsslength += bytes; + else + while (bytes--) + membufwrite(segto, databuf, 1); + } else if (type == OUT_RAWDATA) { + if (segment != NO_SEG) + error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); + + membufwrite(segto, data, bytes); + } else if (type == OUT_ADDRESS) { + + /* if segment == NO_SEG then we are writing an address of an + object within the same segment - do not produce reloc rec. */ + + /* FIXME - is this behaviour sane? at first glance it doesn't + appear to be. Must test this thoroughly...! */ + + if (segment != NO_SEG) { + /* it's an address, so we must write a relocation record */ + + rr.type = RDFREC_RELOC; /* type signature */ + rr.reclen = 8; + rr.segment = segto; /* segment we're currently in */ + rr.offset = getsegmentlength(segto); /* current offset */ + rr.length = bytes; /* length of reference */ + rr.refseg = segment; /* segment referred to */ + write_reloc_rec(&rr); + } + + pd = databuf; /* convert address to little-endian */ + if (bytes == 2) + WRITESHORT(pd, *(long *)data); + else + WRITELONG(pd, *(long *)data); + + membufwrite(segto, databuf, bytes); + + } else if (type == OUT_REL2ADR) { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL2ADR"); + + rr.reclen = 8; + rr.offset = getsegmentlength(segto); /* current offset */ + rr.length = 2; /* length of reference */ + rr.refseg = segment; /* segment referred to (will be >>1'd) */ + + if (segment != NO_SEG && segment % 2) { + rr.type = RDFREC_SEGRELOC; + rr.segment = segto; /* memory base refs *aren't ever* relative! */ + write_reloc_rec(&rr); + + /* what do we put in the code? Simply the data. This should almost + * always be zero, unless someone's doing segment arithmetic... + */ + rr.offset = *(long *)data; + } else { + rr.type = RDFREC_RELOC; /* type signature */ + rr.segment = segto + 64; /* segment we're currently in + rel flag */ + write_reloc_rec(&rr); + + /* work out what to put in the code: offset of the end of this operand, + * subtracted from any data specified, so that loader can just add + * address of imported symbol onto it to get address relative to end of + * instruction: import_address + data(offset) - end_of_instrn */ + + rr.offset = *(long *)data - (rr.offset + bytes); + } + + membufwrite(segto, &rr.offset, -2); + } else if (type == OUT_REL4ADR) { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL4ADR"); + if (segment != NO_SEG && segment % 2) { + error(ERR_PANIC, "erm... 4 byte segment base ref?"); + } + + rr.type = RDFREC_RELOC; /* type signature */ + rr.segment = segto + 64; /* segment we're currently in + rel tag */ + rr.offset = getsegmentlength(segto); /* current offset */ + rr.length = 4; /* length of reference */ + rr.refseg = segment; /* segment referred to */ + rr.reclen = 8; + write_reloc_rec(&rr); + + rr.offset = *(long *)data - (rr.offset + bytes); + + membufwrite(segto, &rr.offset, -4); + } +} + +static void rdf2_cleanup(int debuginfo) +{ + long l; + struct BSSRec bs; + int i; + + (void)debuginfo; + + /* should write imported & exported symbol declarations to header here */ + + /* generate the output file... */ + fwrite(RDOFF2Id, 6, 1, ofile); /* file type magic number */ + + if (bsslength != 0) { /* reserve BSS */ + bs.type = RDFREC_BSS; + bs.amount = bsslength; + bs.reclen = 4; + write_bss_rec(&bs); + } + + /* + * calculate overall length of the output object + */ + l = headerlength + 4; + + for (i = 0; i < nsegments; i++) { + if (i == 2) + continue; /* skip BSS segment */ + l += 10 + segments[i].seglength; + } + l += 10; /* null segment */ + + fwritelong(l, ofile); + + fwritelong(headerlength, ofile); + saa_fpwrite(header, ofile); /* dump header */ + saa_free(header); + + for (i = 0; i < nsegments; i++) { + if (i == 2) + continue; + + fwriteshort(segments[i].segtype, ofile); + fwriteshort(segments[i].segnumber, ofile); + fwriteshort(segments[i].segreserved, ofile); + fwritelong(segments[i].seglength, ofile); + + saa_fpwrite(seg[i], ofile); + saa_free(seg[i]); + } + + /* null segment - write 10 bytes of zero */ + fwritelong(0, ofile); + fwritelong(0, ofile); + fwriteshort(0, ofile); + + fclose(ofile); +} + +static long rdf2_segbase(long segment) +{ + return segment; +} + +/* + * Handle RDOFF2 specific directives + */ +static int rdf2_directive(char *directive, char *value, int pass) +{ + int n; + + /* Check if the name length is OK */ + if ((n = strlen(value)) >= MODLIB_NAME_MAX) { + error(ERR_NONFATAL, "name size exceeds %d bytes", MODLIB_NAME_MAX); + return 0; + } + + if (!strcmp(directive, "library")) { + if (pass == 1) { + struct DLLRec r; + r.type = RDFREC_DLL; + r.reclen = n + 1; + strcpy(r.libname, value); + write_dll_rec(&r); + } + return 1; + } + + if (!strcmp(directive, "module")) { + if (pass == 1) { + struct ModRec r; + r.type = RDFREC_MODNAME; + r.reclen = n + 1; + strcpy(r.modname, value); + write_modname_rec(&r); + } + return 1; + } + + return 0; +} + +static void rdf2_filename(char *inname, char *outname, efunc error) +{ + standard_extension(inname, outname, ".rdf", error); +} + +static const char *rdf2_stdmac[] = { + "%define __SECT__ [section .text]", + "%imacro library 1+.nolist", + "[library %1]", + "%endmacro", + "%imacro module 1+.nolist", + "[module %1]", + "%endmacro", + "%macro __NASM_CDecl__ 1", + "%endmacro", + NULL +}; + +static int rdf2_set_info(enum geninfo type, char **val) +{ + return 0; +} + +struct ofmt of_rdf2 = { + "Relocatable Dynamic Object File Format v2.0", + "rdf", + NULL, + null_debug_arr, + &null_debug_form, + rdf2_stdmac, + rdf2_init, + rdf2_set_info, + rdf2_out, + rdf2_deflabel, + rdf2_section_names, + rdf2_segbase, + rdf2_directive, + rdf2_filename, + rdf2_cleanup +}; + +#endif /* OF_RDF2 */ diff --git a/parser.c b/parser.c dissimilarity index 89% index b18277f8..fe779ef8 100644 --- a/parser.c +++ b/parser.c @@ -1,782 +1,778 @@ -/* parser.c source line parser for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * initial version 27/iii/95 by Simon Tatham - */ - -#include -#include -#include -#include -#include - -#include "nasm.h" -#include "insns.h" -#include "nasmlib.h" -#include "parser.h" -#include "float.h" - -extern int in_abs_seg; /* ABSOLUTE segment flag */ -extern long abs_seg; /* ABSOLUTE segment */ -extern long abs_offset; /* ABSOLUTE segment offset */ - -#include "regflags.c" /* List of register flags */ - -enum { /* special tokens */ - S_BYTE, S_DWORD, S_FAR, S_LONG, S_NEAR, S_NOSPLIT, S_QWORD, - S_SHORT, S_STRICT, S_TO, S_TWORD, S_WORD -}; - -static int is_comma_next (void); - -static int i; -static struct tokenval tokval; -static efunc error; -static struct ofmt *outfmt; /* Structure of addresses of output routines */ -static loc_t *location; /* Pointer to current line's segment,offset */ - -void parser_global_info (struct ofmt *output, loc_t *locp) -{ - outfmt = output; - location = locp; -} - -insn *parse_line (int pass, char *buffer, insn *result, - efunc errfunc, evalfunc evaluate, ldfunc ldef) -{ - int operand; - int critical; - struct eval_hints hints; - - result->forw_ref = FALSE; - error = errfunc; - - stdscan_reset(); - stdscan_bufptr = buffer; - i = stdscan(NULL, &tokval); - - result->label = NULL; /* Assume no label */ - result->eops = NULL; /* must do this, whatever happens */ - result->operands = 0; /* must initialise this */ - - if (i==0) { /* blank line - ignore */ - result->opcode = -1; /* and no instruction either */ - return result; - } - if (i != TOKEN_ID && i != TOKEN_INSN && i != TOKEN_PREFIX && - (i!=TOKEN_REG || (REG_SREG & ~reg_flags[tokval.t_integer]))) { - error (ERR_NONFATAL, "label or instruction expected" - " at start of line"); - result->opcode = -1; - return result; - } - - if (i == TOKEN_ID) { /* there's a label here */ - result->label = tokval.t_charptr; - i = stdscan(NULL, &tokval); - if (i == ':') { /* skip over the optional colon */ - i = stdscan(NULL, &tokval); - } else if (i == 0) { - error (ERR_WARNING|ERR_WARN_OL|ERR_PASS1, - "label alone on a line without a colon might be in error"); - } - if (i != TOKEN_INSN || tokval.t_integer != I_EQU) - { - /* - * FIXME: location->segment could be NO_SEG, in which case - * it is possible we should be passing 'abs_seg'. Look into this. - * Work out whether that is *really* what we should be doing. - * Generally fix things. I think this is right as it is, but - * am still not certain. - */ - ldef (result->label, in_abs_seg?abs_seg:location->segment, - location->offset, NULL, TRUE, FALSE, outfmt, errfunc); - } - } - - if (i==0) { - result->opcode = -1; /* this line contains just a label */ - return result; - } - - result->nprefix = 0; - result->times = 1L; - - while (i == TOKEN_PREFIX || - (i==TOKEN_REG && !(REG_SREG & ~reg_flags[tokval.t_integer]))) - { - /* - * Handle special case: the TIMES prefix. - */ - if (i == TOKEN_PREFIX && tokval.t_integer == P_TIMES) { - expr *value; - - i = stdscan(NULL, &tokval); - value = evaluate (stdscan, NULL, &tokval, NULL, pass0, error, NULL); - i = tokval.t_type; - if (!value) { /* but, error in evaluator */ - result->opcode = -1; /* unrecoverable parse error: */ - return result; /* ignore this instruction */ - } - if (!is_simple (value)) { - error (ERR_NONFATAL, - "non-constant argument supplied to TIMES"); - result->times = 1L; - } else { - result->times = value->value; - if (value->value < 0) { - error(ERR_NONFATAL, "TIMES value %d is negative", - value->value); - result->times = 0; - } - } - } else { - if (result->nprefix == MAXPREFIX) - error (ERR_NONFATAL, - "instruction has more than %d prefixes", MAXPREFIX); - else - result->prefixes[result->nprefix++] = tokval.t_integer; - i = stdscan(NULL, &tokval); - } - } - - if (i != TOKEN_INSN) { - if (result->nprefix > 0 && i == 0) { - /* - * Instruction prefixes are present, but no actual - * instruction. This is allowed: at this point we - * invent a notional instruction of RESB 0. - */ - result->opcode = I_RESB; - result->operands = 1; - result->oprs[0].type = IMMEDIATE; - result->oprs[0].offset = 0L; - result->oprs[0].segment = result->oprs[0].wrt = NO_SEG; - return result; - } else { - error (ERR_NONFATAL, "parser: instruction expected"); - result->opcode = -1; - return result; - } - } - - result->opcode = tokval.t_integer; - result->condition = tokval.t_inttwo; - - /* - * RESB, RESW and RESD cannot be satisfied with incorrectly - * evaluated operands, since the correct values _must_ be known - * on the first pass. Hence, even in pass one, we set the - * `critical' flag on calling evaluate(), so that it will bomb - * out on undefined symbols. Nasty, but there's nothing we can - * do about it. - * - * For the moment, EQU has the same difficulty, so we'll - * include that. - */ - if (result->opcode == I_RESB || - result->opcode == I_RESW || - result->opcode == I_RESD || - result->opcode == I_RESQ || - result->opcode == I_REST || - result->opcode == I_EQU || - result->opcode == I_INCBIN) /* fbk */ - { - critical = pass0; - } - else - critical = (pass==2 ? 2 : 0); - - if (result->opcode == I_DB || - result->opcode == I_DW || - result->opcode == I_DD || - result->opcode == I_DQ || - result->opcode == I_DT || - result->opcode == I_INCBIN) - { - extop *eop, **tail = &result->eops, **fixptr; - int oper_num = 0; - - result->eops_float = FALSE; - - /* - * Begin to read the DB/DW/DD/DQ/DT/INCBIN operands. - */ - while (1) { - i = stdscan(NULL, &tokval); - if (i == 0) - break; - fixptr = tail; - eop = *tail = nasm_malloc(sizeof(extop)); - tail = &eop->next; - eop->next = NULL; - eop->type = EOT_NOTHING; - oper_num++; - - if (i == TOKEN_NUM && tokval.t_charptr && is_comma_next()) { - eop->type = EOT_DB_STRING; - eop->stringval = tokval.t_charptr; - eop->stringlen = tokval.t_inttwo; - i = stdscan(NULL, &tokval); /* eat the comma */ - continue; - } - - if ((i == TOKEN_FLOAT && is_comma_next()) || i == '-') { - long sign = +1L; - - if (i == '-') { - char *save = stdscan_bufptr; - i = stdscan(NULL, &tokval); - sign = -1L; - if (i != TOKEN_FLOAT || !is_comma_next()) { - stdscan_bufptr = save; - i = tokval.t_type = '-'; - } - } - - if (i == TOKEN_FLOAT) { - eop->type = EOT_DB_STRING; - result->eops_float = TRUE; - if (result->opcode == I_DD) - eop->stringlen = 4; - else if (result->opcode == I_DQ) - eop->stringlen = 8; - else if (result->opcode == I_DT) - eop->stringlen = 10; - else { - error(ERR_NONFATAL, "floating-point constant" - " encountered in `D%c' instruction", - result->opcode == I_DW ? 'W' : 'B'); - /* - * fix suggested by Pedro Gimeno... original line - * was: - * eop->type = EOT_NOTHING; - */ - eop->stringlen = 0; - } - eop = nasm_realloc(eop, sizeof(extop)+eop->stringlen); - tail = &eop->next; - *fixptr = eop; - eop->stringval = (char *)eop + sizeof(extop); - if (eop->stringlen < 4 || - !float_const (tokval.t_charptr, sign, - (unsigned char *)eop->stringval, - eop->stringlen, error)) - eop->type = EOT_NOTHING; - i = stdscan(NULL, &tokval); /* eat the comma */ - continue; - } - } - - /* anything else */ - { - expr *value; - value = evaluate (stdscan, NULL, &tokval, NULL, - critical, error, NULL); - i = tokval.t_type; - if (!value) { /* error in evaluator */ - result->opcode = -1;/* unrecoverable parse error: */ - return result; /* ignore this instruction */ - } - if (is_unknown(value)) { - eop->type = EOT_DB_NUMBER; - eop->offset = 0; /* doesn't matter what we put */ - eop->segment = eop->wrt = NO_SEG; /* likewise */ - } else if (is_reloc(value)) { - eop->type = EOT_DB_NUMBER; - eop->offset = reloc_value(value); - eop->segment = reloc_seg(value); - eop->wrt = reloc_wrt(value); - } else { - error (ERR_NONFATAL, - "operand %d: expression is not simple" - " or relocatable", oper_num); - } - } - - /* - * We're about to call stdscan(), which will eat the - * comma that we're currently sitting on between - * arguments. However, we'd better check first that it - * _is_ a comma. - */ - if (i == 0) /* also could be EOL */ - break; - if (i != ',') { - error (ERR_NONFATAL, "comma expected after operand %d", - oper_num); - result->opcode = -1;/* unrecoverable parse error: */ - return result; /* ignore this instruction */ - } - } - - if (result->opcode == I_INCBIN) { - /* - * Correct syntax for INCBIN is that there should be - * one string operand, followed by one or two numeric - * operands. - */ - if (!result->eops || result->eops->type != EOT_DB_STRING) - error (ERR_NONFATAL, "`incbin' expects a file name"); - else if (result->eops->next && - result->eops->next->type != EOT_DB_NUMBER) - error (ERR_NONFATAL, "`incbin': second parameter is", - " non-numeric"); - else if (result->eops->next && result->eops->next->next && - result->eops->next->next->type != EOT_DB_NUMBER) - error (ERR_NONFATAL, "`incbin': third parameter is", - " non-numeric"); - else if (result->eops->next && result->eops->next->next && - result->eops->next->next->next) - error (ERR_NONFATAL, "`incbin': more than three parameters"); - else - return result; - /* - * If we reach here, one of the above errors happened. - * Throw the instruction away. - */ - result->opcode = -1; - return result; - } else /* DB ... */ - if (oper_num == 0) - error (ERR_WARNING|ERR_PASS1, - "no operand for data declaration"); - else - result->operands = oper_num; - - return result; - } - - /* right. Now we begin to parse the operands. There may be up to three - * of these, separated by commas, and terminated by a zero token. */ - - for (operand = 0; operand < 3; operand++) { - expr *value; /* used most of the time */ - int mref; /* is this going to be a memory ref? */ - int bracket; /* is it a [] mref, or a & mref? */ - int setsize = 0; - - result->oprs[operand].addr_size = 0;/* have to zero this whatever */ - result->oprs[operand].eaflags = 0; /* and this */ - result->oprs[operand].opflags = 0; - - i = stdscan(NULL, &tokval); - if (i == 0) break; /* end of operands: get out of here */ - result->oprs[operand].type = 0; /* so far, no override */ - while (i == TOKEN_SPECIAL) {/* size specifiers */ - switch ((int)tokval.t_integer) { - case S_BYTE: - if (!setsize) /* we want to use only the first */ - result->oprs[operand].type |= BITS8; - setsize = 1; - break; - case S_WORD: - if (!setsize) - result->oprs[operand].type |= BITS16; - setsize = 1; - break; - case S_DWORD: - case S_LONG: - if (!setsize) - result->oprs[operand].type |= BITS32; - setsize = 1; - break; - case S_QWORD: - if (!setsize) - result->oprs[operand].type |= BITS64; - setsize = 1; - break; - case S_TWORD: - if (!setsize) - result->oprs[operand].type |= BITS80; - setsize = 1; - break; - case S_TO: - result->oprs[operand].type |= TO; - break; - case S_STRICT: - result->oprs[operand].type |= STRICT; - break; - case S_FAR: - result->oprs[operand].type |= FAR; - break; - case S_NEAR: - result->oprs[operand].type |= NEAR; - break; - case S_SHORT: - result->oprs[operand].type |= SHORT; - break; - default: - error (ERR_NONFATAL, "invalid operand size specification"); - } - i = stdscan(NULL, &tokval); - } - - if (i == '[' || i == '&') { /* memory reference */ - mref = TRUE; - bracket = (i == '['); - i = stdscan(NULL, &tokval); - if (i == TOKEN_SPECIAL) { /* check for address size override */ - if (tasm_compatible_mode) { - switch ((int)tokval.t_integer) { - /* For TASM compatibility a size override inside the - * brackets changes the size of the operand, not the - * address type of the operand as it does in standard - * NASM syntax. Hence: - * - * mov eax,[DWORD val] - * - * is valid syntax in TASM compatibility mode. Note that - * you lose the ability to override the default address - * type for the instruction, but we never use anything - * but 32-bit flat model addressing in our code. - */ - case S_BYTE: - result->oprs[operand].type |= BITS8; - break; - case S_WORD: - result->oprs[operand].type |= BITS16; - break; - case S_DWORD: - case S_LONG: - result->oprs[operand].type |= BITS32; - break; - case S_QWORD: - result->oprs[operand].type |= BITS64; - break; - case S_TWORD: - result->oprs[operand].type |= BITS80; - break; - default: - error (ERR_NONFATAL, "invalid operand size specification"); - } - } else { - /* Standard NASM compatible syntax */ - switch ((int)tokval.t_integer) { - case S_NOSPLIT: - result->oprs[operand].eaflags |= EAF_TIMESTWO; - break; - case S_BYTE: - result->oprs[operand].eaflags |= EAF_BYTEOFFS; - break; - case S_WORD: - result->oprs[operand].addr_size = 16; - result->oprs[operand].eaflags |= EAF_WORDOFFS; - break; - case S_DWORD: - case S_LONG: - result->oprs[operand].addr_size = 32; - result->oprs[operand].eaflags |= EAF_WORDOFFS; - break; - default: - error (ERR_NONFATAL, "invalid size specification in" - " effective address"); - } - } - i = stdscan(NULL, &tokval); - } - } else { /* immediate operand, or register */ - mref = FALSE; - bracket = FALSE; /* placate optimisers */ - } - - if((result->oprs[operand].type & FAR) && !mref && - result->opcode != I_JMP && result->opcode != I_CALL) - { - error (ERR_NONFATAL, "invalid use of FAR operand specifier"); - } - - value = evaluate (stdscan, NULL, &tokval, - &result->oprs[operand].opflags, - critical, error, &hints); - i = tokval.t_type; - if (result->oprs[operand].opflags & OPFLAG_FORWARD) { - result->forw_ref = TRUE; - } - if (!value) { /* error in evaluator */ - result->opcode = -1; /* unrecoverable parse error: */ - return result; /* ignore this instruction */ - } - if (i == ':' && mref) { /* it was seg:offset */ - /* - * Process the segment override. - */ - if (value[1].type!=0 || value->value!=1 || - REG_SREG & ~reg_flags[value->type]) - error (ERR_NONFATAL, "invalid segment override"); - else if (result->nprefix == MAXPREFIX) - error (ERR_NONFATAL, - "instruction has more than %d prefixes", - MAXPREFIX); - else - result->prefixes[result->nprefix++] = value->type; - - i = stdscan(NULL, &tokval); /* then skip the colon */ - if (i == TOKEN_SPECIAL) { /* another check for size override */ - switch ((int)tokval.t_integer) { - case S_WORD: - result->oprs[operand].addr_size = 16; - break; - case S_DWORD: - case S_LONG: - result->oprs[operand].addr_size = 32; - break; - default: - error (ERR_NONFATAL, "invalid size specification in" - " effective address"); - } - i = stdscan(NULL, &tokval); - } - value = evaluate (stdscan, NULL, &tokval, - &result->oprs[operand].opflags, - critical, error, &hints); - i = tokval.t_type; - if (result->oprs[operand].opflags & OPFLAG_FORWARD) { - result->forw_ref = TRUE; - } - /* and get the offset */ - if (!value) { /* but, error in evaluator */ - result->opcode = -1; /* unrecoverable parse error: */ - return result; /* ignore this instruction */ - } - } - if (mref && bracket) { /* find ] at the end */ - if (i != ']') { - error (ERR_NONFATAL, "parser: expecting ]"); - do { /* error recovery again */ - i = stdscan(NULL, &tokval); - } while (i != 0 && i != ','); - } else /* we got the required ] */ - i = stdscan(NULL, &tokval); - } else { /* immediate operand */ - if (i != 0 && i != ',' && i != ':') { - error (ERR_NONFATAL, "comma or end of line expected"); - do { /* error recovery */ - i = stdscan(NULL, &tokval); - } while (i != 0 && i != ','); - } else if (i == ':') { - result->oprs[operand].type |= COLON; - } - } - - /* now convert the exprs returned from evaluate() into operand - * descriptions... */ - - if (mref) { /* it's a memory reference */ - expr *e = value; - int b, i, s; /* basereg, indexreg, scale */ - long o; /* offset */ - - b = i = -1, o = s = 0; - result->oprs[operand].hintbase = hints.base; - result->oprs[operand].hinttype = hints.type; - - if (e->type && e->type <= EXPR_REG_END) /* this bit's a register */ - { - if (e->value == 1) /* in fact it can be basereg */ - b = e->type; - else /* no, it has to be indexreg */ - i = e->type, s = e->value; - e++; - } - if (e->type && e->type <= EXPR_REG_END) /* it's a 2nd register */ - { - if (b != -1) /* If the first was the base, ... */ - i = e->type, s = e->value; /* second has to be indexreg */ - - else if (e->value != 1) /* If both want to be index */ - { - error(ERR_NONFATAL, "beroset-p-592-invalid effective address"); - result->opcode = -1; - return result; - } - else - b = e->type; - e++; - } - if (e->type != 0) { /* is there an offset? */ - if (e->type <= EXPR_REG_END) /* in fact, is there an error? */ - { - error (ERR_NONFATAL, "beroset-p-603-invalid effective address"); - result->opcode = -1; - return result; - } - else - { - if (e->type == EXPR_UNKNOWN) { - o = 0; /* doesn't matter what */ - result->oprs[operand].wrt = NO_SEG; /* nor this */ - result->oprs[operand].segment = NO_SEG; /* or this */ - while (e->type) e++; /* go to the end of the line */ - } - else - { - if (e->type == EXPR_SIMPLE) { - o = e->value; - e++; - } - if (e->type == EXPR_WRT) { - result->oprs[operand].wrt = e->value; - e++; - } else - result->oprs[operand].wrt = NO_SEG; - /* - * Look for a segment base type. - */ - if (e->type && e->type < EXPR_SEGBASE) { - error (ERR_NONFATAL, "beroset-p-630-invalid effective address"); - result->opcode = -1; - return result; - } - while (e->type && e->value == 0) - e++; - if (e->type && e->value != 1) { - error (ERR_NONFATAL, "beroset-p-637-invalid effective address"); - result->opcode = -1; - return result; - } - if (e->type) { - result->oprs[operand].segment = - e->type - EXPR_SEGBASE; - e++; - } else - result->oprs[operand].segment = NO_SEG; - while (e->type && e->value == 0) - e++; - if (e->type) { - error (ERR_NONFATAL, "beroset-p-650-invalid effective address"); - result->opcode = -1; - return result; - } - } - } - } else { - o = 0; - result->oprs[operand].wrt = NO_SEG; - result->oprs[operand].segment = NO_SEG; - } - - if (e->type != 0) { /* there'd better be nothing left! */ - error (ERR_NONFATAL, "beroset-p-663-invalid effective address"); - result->opcode = -1; - return result; - } - - result->oprs[operand].type |= MEMORY; - if (b==-1 && (i==-1 || s==0)) - result->oprs[operand].type |= MEM_OFFS; - result->oprs[operand].basereg = b; - result->oprs[operand].indexreg = i; - result->oprs[operand].scale = s; - result->oprs[operand].offset = o; - } - else /* it's not a memory reference */ - { - if (is_just_unknown(value)) { /* it's immediate but unknown */ - result->oprs[operand].type |= IMMEDIATE; - result->oprs[operand].offset = 0; /* don't care */ - result->oprs[operand].segment = NO_SEG; /* don't care again */ - result->oprs[operand].wrt = NO_SEG;/* still don't care */ - } - else if (is_reloc(value)) /* it's immediate */ - { - result->oprs[operand].type |= IMMEDIATE; - result->oprs[operand].offset = reloc_value(value); - result->oprs[operand].segment = reloc_seg(value); - result->oprs[operand].wrt = reloc_wrt(value); - if (is_simple(value)) { - if (reloc_value(value)==1) - result->oprs[operand].type |= UNITY; - if (optimizing>=0 && - !(result->oprs[operand].type & STRICT)) { - if (reloc_value(value) >= -128 && - reloc_value(value) <= 127) - result->oprs[operand].type |= SBYTE; - } - } - } - else /* it's a register */ - { - if (value->type>=EXPR_SIMPLE || value->value!=1) { - error (ERR_NONFATAL, "invalid operand type"); - result->opcode = -1; - return result; - } - - /* - * check that its only 1 register, not an expression... - */ - for (i = 1; value[i].type; i++) - if (value[i].value) { - error (ERR_NONFATAL, "invalid operand type"); - result->opcode = -1; - return result; - } - - /* clear overrides, except TO which applies to FPU regs */ - if (result->oprs[operand].type & ~TO) { - /* - * we want to produce a warning iff the specified size - * is different from the register size - */ - i = result->oprs[operand].type & SIZE_MASK; - } - else - i = 0; - - result->oprs[operand].type &= TO; - result->oprs[operand].type |= REGISTER; - result->oprs[operand].type |= reg_flags[value->type]; - result->oprs[operand].basereg = value->type; - - if (i && (result->oprs[operand].type & SIZE_MASK) != i) - error (ERR_WARNING|ERR_PASS1, - "register size specification ignored"); - } - } - } - - result->operands = operand; /* set operand count */ - - while (operand<3) /* clear remaining operands */ - result->oprs[operand++].type = 0; - - /* - * Transform RESW, RESD, RESQ, REST into RESB. - */ - switch (result->opcode) { - case I_RESW: result->opcode=I_RESB; result->oprs[0].offset*=2; break; - case I_RESD: result->opcode=I_RESB; result->oprs[0].offset*=4; break; - case I_RESQ: result->opcode=I_RESB; result->oprs[0].offset*=8; break; - case I_REST: result->opcode=I_RESB; result->oprs[0].offset*=10; break; - } - - return result; -} - -static int is_comma_next (void) -{ - char *p; - int i; - struct tokenval tv; - - p = stdscan_bufptr; - i = stdscan (NULL, &tv); - stdscan_bufptr = p; - return (i == ',' || i == ';' || !i); -} - -void cleanup_insn (insn *i) -{ - extop *e; - - while (i->eops) { - e = i->eops; - i->eops = i->eops->next; - nasm_free (e); - } -} +/* parser.c source line parser for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 27/iii/95 by Simon Tatham + */ + +#include +#include +#include +#include +#include + +#include "nasm.h" +#include "insns.h" +#include "nasmlib.h" +#include "parser.h" +#include "float.h" + +extern int in_abs_seg; /* ABSOLUTE segment flag */ +extern long abs_seg; /* ABSOLUTE segment */ +extern long abs_offset; /* ABSOLUTE segment offset */ + +#include "regflags.c" /* List of register flags */ + +enum { /* special tokens */ + S_BYTE, S_DWORD, S_FAR, S_LONG, S_NEAR, S_NOSPLIT, S_QWORD, + S_SHORT, S_STRICT, S_TO, S_TWORD, S_WORD +}; + +static int is_comma_next(void); + +static int i; +static struct tokenval tokval; +static efunc error; +static struct ofmt *outfmt; /* Structure of addresses of output routines */ +static loc_t *location; /* Pointer to current line's segment,offset */ + +void parser_global_info(struct ofmt *output, loc_t * locp) +{ + outfmt = output; + location = locp; +} + +insn *parse_line(int pass, char *buffer, insn * result, + efunc errfunc, evalfunc evaluate, ldfunc ldef) +{ + int operand; + int critical; + struct eval_hints hints; + + result->forw_ref = FALSE; + error = errfunc; + + stdscan_reset(); + stdscan_bufptr = buffer; + i = stdscan(NULL, &tokval); + + result->label = NULL; /* Assume no label */ + result->eops = NULL; /* must do this, whatever happens */ + result->operands = 0; /* must initialise this */ + + if (i == 0) { /* blank line - ignore */ + result->opcode = -1; /* and no instruction either */ + return result; + } + if (i != TOKEN_ID && i != TOKEN_INSN && i != TOKEN_PREFIX && + (i != TOKEN_REG || (REG_SREG & ~reg_flags[tokval.t_integer]))) { + error(ERR_NONFATAL, "label or instruction expected" + " at start of line"); + result->opcode = -1; + return result; + } + + if (i == TOKEN_ID) { /* there's a label here */ + result->label = tokval.t_charptr; + i = stdscan(NULL, &tokval); + if (i == ':') { /* skip over the optional colon */ + i = stdscan(NULL, &tokval); + } else if (i == 0) { + error(ERR_WARNING | ERR_WARN_OL | ERR_PASS1, + "label alone on a line without a colon might be in error"); + } + if (i != TOKEN_INSN || tokval.t_integer != I_EQU) { + /* + * FIXME: location->segment could be NO_SEG, in which case + * it is possible we should be passing 'abs_seg'. Look into this. + * Work out whether that is *really* what we should be doing. + * Generally fix things. I think this is right as it is, but + * am still not certain. + */ + ldef(result->label, in_abs_seg ? abs_seg : location->segment, + location->offset, NULL, TRUE, FALSE, outfmt, errfunc); + } + } + + if (i == 0) { + result->opcode = -1; /* this line contains just a label */ + return result; + } + + result->nprefix = 0; + result->times = 1L; + + while (i == TOKEN_PREFIX || + (i == TOKEN_REG && !(REG_SREG & ~reg_flags[tokval.t_integer]))) + { + /* + * Handle special case: the TIMES prefix. + */ + if (i == TOKEN_PREFIX && tokval.t_integer == P_TIMES) { + expr *value; + + i = stdscan(NULL, &tokval); + value = + evaluate(stdscan, NULL, &tokval, NULL, pass0, error, NULL); + i = tokval.t_type; + if (!value) { /* but, error in evaluator */ + result->opcode = -1; /* unrecoverable parse error: */ + return result; /* ignore this instruction */ + } + if (!is_simple(value)) { + error(ERR_NONFATAL, + "non-constant argument supplied to TIMES"); + result->times = 1L; + } else { + result->times = value->value; + if (value->value < 0) { + error(ERR_NONFATAL, "TIMES value %d is negative", + value->value); + result->times = 0; + } + } + } else { + if (result->nprefix == MAXPREFIX) + error(ERR_NONFATAL, + "instruction has more than %d prefixes", MAXPREFIX); + else + result->prefixes[result->nprefix++] = tokval.t_integer; + i = stdscan(NULL, &tokval); + } + } + + if (i != TOKEN_INSN) { + if (result->nprefix > 0 && i == 0) { + /* + * Instruction prefixes are present, but no actual + * instruction. This is allowed: at this point we + * invent a notional instruction of RESB 0. + */ + result->opcode = I_RESB; + result->operands = 1; + result->oprs[0].type = IMMEDIATE; + result->oprs[0].offset = 0L; + result->oprs[0].segment = result->oprs[0].wrt = NO_SEG; + return result; + } else { + error(ERR_NONFATAL, "parser: instruction expected"); + result->opcode = -1; + return result; + } + } + + result->opcode = tokval.t_integer; + result->condition = tokval.t_inttwo; + + /* + * RESB, RESW and RESD cannot be satisfied with incorrectly + * evaluated operands, since the correct values _must_ be known + * on the first pass. Hence, even in pass one, we set the + * `critical' flag on calling evaluate(), so that it will bomb + * out on undefined symbols. Nasty, but there's nothing we can + * do about it. + * + * For the moment, EQU has the same difficulty, so we'll + * include that. + */ + if (result->opcode == I_RESB || result->opcode == I_RESW || result->opcode == I_RESD || result->opcode == I_RESQ || result->opcode == I_REST || result->opcode == I_EQU || result->opcode == I_INCBIN) { /* fbk */ + critical = pass0; + } else + critical = (pass == 2 ? 2 : 0); + + if (result->opcode == I_DB || + result->opcode == I_DW || + result->opcode == I_DD || + result->opcode == I_DQ || + result->opcode == I_DT || result->opcode == I_INCBIN) { + extop *eop, **tail = &result->eops, **fixptr; + int oper_num = 0; + + result->eops_float = FALSE; + + /* + * Begin to read the DB/DW/DD/DQ/DT/INCBIN operands. + */ + while (1) { + i = stdscan(NULL, &tokval); + if (i == 0) + break; + fixptr = tail; + eop = *tail = nasm_malloc(sizeof(extop)); + tail = &eop->next; + eop->next = NULL; + eop->type = EOT_NOTHING; + oper_num++; + + if (i == TOKEN_NUM && tokval.t_charptr && is_comma_next()) { + eop->type = EOT_DB_STRING; + eop->stringval = tokval.t_charptr; + eop->stringlen = tokval.t_inttwo; + i = stdscan(NULL, &tokval); /* eat the comma */ + continue; + } + + if ((i == TOKEN_FLOAT && is_comma_next()) || i == '-') { + long sign = +1L; + + if (i == '-') { + char *save = stdscan_bufptr; + i = stdscan(NULL, &tokval); + sign = -1L; + if (i != TOKEN_FLOAT || !is_comma_next()) { + stdscan_bufptr = save; + i = tokval.t_type = '-'; + } + } + + if (i == TOKEN_FLOAT) { + eop->type = EOT_DB_STRING; + result->eops_float = TRUE; + if (result->opcode == I_DD) + eop->stringlen = 4; + else if (result->opcode == I_DQ) + eop->stringlen = 8; + else if (result->opcode == I_DT) + eop->stringlen = 10; + else { + error(ERR_NONFATAL, "floating-point constant" + " encountered in `D%c' instruction", + result->opcode == I_DW ? 'W' : 'B'); + /* + * fix suggested by Pedro Gimeno... original line + * was: + * eop->type = EOT_NOTHING; + */ + eop->stringlen = 0; + } + eop = + nasm_realloc(eop, sizeof(extop) + eop->stringlen); + tail = &eop->next; + *fixptr = eop; + eop->stringval = (char *)eop + sizeof(extop); + if (eop->stringlen < 4 || + !float_const(tokval.t_charptr, sign, + (unsigned char *)eop->stringval, + eop->stringlen, error)) + eop->type = EOT_NOTHING; + i = stdscan(NULL, &tokval); /* eat the comma */ + continue; + } + } + + /* anything else */ + { + expr *value; + value = evaluate(stdscan, NULL, &tokval, NULL, + critical, error, NULL); + i = tokval.t_type; + if (!value) { /* error in evaluator */ + result->opcode = -1; /* unrecoverable parse error: */ + return result; /* ignore this instruction */ + } + if (is_unknown(value)) { + eop->type = EOT_DB_NUMBER; + eop->offset = 0; /* doesn't matter what we put */ + eop->segment = eop->wrt = NO_SEG; /* likewise */ + } else if (is_reloc(value)) { + eop->type = EOT_DB_NUMBER; + eop->offset = reloc_value(value); + eop->segment = reloc_seg(value); + eop->wrt = reloc_wrt(value); + } else { + error(ERR_NONFATAL, + "operand %d: expression is not simple" + " or relocatable", oper_num); + } + } + + /* + * We're about to call stdscan(), which will eat the + * comma that we're currently sitting on between + * arguments. However, we'd better check first that it + * _is_ a comma. + */ + if (i == 0) /* also could be EOL */ + break; + if (i != ',') { + error(ERR_NONFATAL, "comma expected after operand %d", + oper_num); + result->opcode = -1; /* unrecoverable parse error: */ + return result; /* ignore this instruction */ + } + } + + if (result->opcode == I_INCBIN) { + /* + * Correct syntax for INCBIN is that there should be + * one string operand, followed by one or two numeric + * operands. + */ + if (!result->eops || result->eops->type != EOT_DB_STRING) + error(ERR_NONFATAL, "`incbin' expects a file name"); + else if (result->eops->next && + result->eops->next->type != EOT_DB_NUMBER) + error(ERR_NONFATAL, "`incbin': second parameter is", + " non-numeric"); + else if (result->eops->next && result->eops->next->next && + result->eops->next->next->type != EOT_DB_NUMBER) + error(ERR_NONFATAL, "`incbin': third parameter is", + " non-numeric"); + else if (result->eops->next && result->eops->next->next && + result->eops->next->next->next) + error(ERR_NONFATAL, + "`incbin': more than three parameters"); + else + return result; + /* + * If we reach here, one of the above errors happened. + * Throw the instruction away. + */ + result->opcode = -1; + return result; + } else /* DB ... */ if (oper_num == 0) + error(ERR_WARNING | ERR_PASS1, + "no operand for data declaration"); + else + result->operands = oper_num; + + return result; + } + + /* right. Now we begin to parse the operands. There may be up to three + * of these, separated by commas, and terminated by a zero token. */ + + for (operand = 0; operand < 3; operand++) { + expr *value; /* used most of the time */ + int mref; /* is this going to be a memory ref? */ + int bracket; /* is it a [] mref, or a & mref? */ + int setsize = 0; + + result->oprs[operand].addr_size = 0; /* have to zero this whatever */ + result->oprs[operand].eaflags = 0; /* and this */ + result->oprs[operand].opflags = 0; + + i = stdscan(NULL, &tokval); + if (i == 0) + break; /* end of operands: get out of here */ + result->oprs[operand].type = 0; /* so far, no override */ + while (i == TOKEN_SPECIAL) { /* size specifiers */ + switch ((int)tokval.t_integer) { + case S_BYTE: + if (!setsize) /* we want to use only the first */ + result->oprs[operand].type |= BITS8; + setsize = 1; + break; + case S_WORD: + if (!setsize) + result->oprs[operand].type |= BITS16; + setsize = 1; + break; + case S_DWORD: + case S_LONG: + if (!setsize) + result->oprs[operand].type |= BITS32; + setsize = 1; + break; + case S_QWORD: + if (!setsize) + result->oprs[operand].type |= BITS64; + setsize = 1; + break; + case S_TWORD: + if (!setsize) + result->oprs[operand].type |= BITS80; + setsize = 1; + break; + case S_TO: + result->oprs[operand].type |= TO; + break; + case S_STRICT: + result->oprs[operand].type |= STRICT; + break; + case S_FAR: + result->oprs[operand].type |= FAR; + break; + case S_NEAR: + result->oprs[operand].type |= NEAR; + break; + case S_SHORT: + result->oprs[operand].type |= SHORT; + break; + default: + error(ERR_NONFATAL, "invalid operand size specification"); + } + i = stdscan(NULL, &tokval); + } + + if (i == '[' || i == '&') { /* memory reference */ + mref = TRUE; + bracket = (i == '['); + i = stdscan(NULL, &tokval); + if (i == TOKEN_SPECIAL) { /* check for address size override */ + if (tasm_compatible_mode) { + switch ((int)tokval.t_integer) { + /* For TASM compatibility a size override inside the + * brackets changes the size of the operand, not the + * address type of the operand as it does in standard + * NASM syntax. Hence: + * + * mov eax,[DWORD val] + * + * is valid syntax in TASM compatibility mode. Note that + * you lose the ability to override the default address + * type for the instruction, but we never use anything + * but 32-bit flat model addressing in our code. + */ + case S_BYTE: + result->oprs[operand].type |= BITS8; + break; + case S_WORD: + result->oprs[operand].type |= BITS16; + break; + case S_DWORD: + case S_LONG: + result->oprs[operand].type |= BITS32; + break; + case S_QWORD: + result->oprs[operand].type |= BITS64; + break; + case S_TWORD: + result->oprs[operand].type |= BITS80; + break; + default: + error(ERR_NONFATAL, + "invalid operand size specification"); + } + } else { + /* Standard NASM compatible syntax */ + switch ((int)tokval.t_integer) { + case S_NOSPLIT: + result->oprs[operand].eaflags |= EAF_TIMESTWO; + break; + case S_BYTE: + result->oprs[operand].eaflags |= EAF_BYTEOFFS; + break; + case S_WORD: + result->oprs[operand].addr_size = 16; + result->oprs[operand].eaflags |= EAF_WORDOFFS; + break; + case S_DWORD: + case S_LONG: + result->oprs[operand].addr_size = 32; + result->oprs[operand].eaflags |= EAF_WORDOFFS; + break; + default: + error(ERR_NONFATAL, "invalid size specification in" + " effective address"); + } + } + i = stdscan(NULL, &tokval); + } + } else { /* immediate operand, or register */ + mref = FALSE; + bracket = FALSE; /* placate optimisers */ + } + + if ((result->oprs[operand].type & FAR) && !mref && + result->opcode != I_JMP && result->opcode != I_CALL) { + error(ERR_NONFATAL, "invalid use of FAR operand specifier"); + } + + value = evaluate(stdscan, NULL, &tokval, + &result->oprs[operand].opflags, + critical, error, &hints); + i = tokval.t_type; + if (result->oprs[operand].opflags & OPFLAG_FORWARD) { + result->forw_ref = TRUE; + } + if (!value) { /* error in evaluator */ + result->opcode = -1; /* unrecoverable parse error: */ + return result; /* ignore this instruction */ + } + if (i == ':' && mref) { /* it was seg:offset */ + /* + * Process the segment override. + */ + if (value[1].type != 0 || value->value != 1 || + REG_SREG & ~reg_flags[value->type]) + error(ERR_NONFATAL, "invalid segment override"); + else if (result->nprefix == MAXPREFIX) + error(ERR_NONFATAL, + "instruction has more than %d prefixes", MAXPREFIX); + else + result->prefixes[result->nprefix++] = value->type; + + i = stdscan(NULL, &tokval); /* then skip the colon */ + if (i == TOKEN_SPECIAL) { /* another check for size override */ + switch ((int)tokval.t_integer) { + case S_WORD: + result->oprs[operand].addr_size = 16; + break; + case S_DWORD: + case S_LONG: + result->oprs[operand].addr_size = 32; + break; + default: + error(ERR_NONFATAL, "invalid size specification in" + " effective address"); + } + i = stdscan(NULL, &tokval); + } + value = evaluate(stdscan, NULL, &tokval, + &result->oprs[operand].opflags, + critical, error, &hints); + i = tokval.t_type; + if (result->oprs[operand].opflags & OPFLAG_FORWARD) { + result->forw_ref = TRUE; + } + /* and get the offset */ + if (!value) { /* but, error in evaluator */ + result->opcode = -1; /* unrecoverable parse error: */ + return result; /* ignore this instruction */ + } + } + if (mref && bracket) { /* find ] at the end */ + if (i != ']') { + error(ERR_NONFATAL, "parser: expecting ]"); + do { /* error recovery again */ + i = stdscan(NULL, &tokval); + } while (i != 0 && i != ','); + } else /* we got the required ] */ + i = stdscan(NULL, &tokval); + } else { /* immediate operand */ + if (i != 0 && i != ',' && i != ':') { + error(ERR_NONFATAL, "comma or end of line expected"); + do { /* error recovery */ + i = stdscan(NULL, &tokval); + } while (i != 0 && i != ','); + } else if (i == ':') { + result->oprs[operand].type |= COLON; + } + } + + /* now convert the exprs returned from evaluate() into operand + * descriptions... */ + + if (mref) { /* it's a memory reference */ + expr *e = value; + int b, i, s; /* basereg, indexreg, scale */ + long o; /* offset */ + + b = i = -1, o = s = 0; + result->oprs[operand].hintbase = hints.base; + result->oprs[operand].hinttype = hints.type; + + if (e->type && e->type <= EXPR_REG_END) { /* this bit's a register */ + if (e->value == 1) /* in fact it can be basereg */ + b = e->type; + else /* no, it has to be indexreg */ + i = e->type, s = e->value; + e++; + } + if (e->type && e->type <= EXPR_REG_END) { /* it's a 2nd register */ + if (b != -1) /* If the first was the base, ... */ + i = e->type, s = e->value; /* second has to be indexreg */ + + else if (e->value != 1) { /* If both want to be index */ + error(ERR_NONFATAL, + "beroset-p-592-invalid effective address"); + result->opcode = -1; + return result; + } else + b = e->type; + e++; + } + if (e->type != 0) { /* is there an offset? */ + if (e->type <= EXPR_REG_END) { /* in fact, is there an error? */ + error(ERR_NONFATAL, + "beroset-p-603-invalid effective address"); + result->opcode = -1; + return result; + } else { + if (e->type == EXPR_UNKNOWN) { + o = 0; /* doesn't matter what */ + result->oprs[operand].wrt = NO_SEG; /* nor this */ + result->oprs[operand].segment = NO_SEG; /* or this */ + while (e->type) + e++; /* go to the end of the line */ + } else { + if (e->type == EXPR_SIMPLE) { + o = e->value; + e++; + } + if (e->type == EXPR_WRT) { + result->oprs[operand].wrt = e->value; + e++; + } else + result->oprs[operand].wrt = NO_SEG; + /* + * Look for a segment base type. + */ + if (e->type && e->type < EXPR_SEGBASE) { + error(ERR_NONFATAL, + "beroset-p-630-invalid effective address"); + result->opcode = -1; + return result; + } + while (e->type && e->value == 0) + e++; + if (e->type && e->value != 1) { + error(ERR_NONFATAL, + "beroset-p-637-invalid effective address"); + result->opcode = -1; + return result; + } + if (e->type) { + result->oprs[operand].segment = + e->type - EXPR_SEGBASE; + e++; + } else + result->oprs[operand].segment = NO_SEG; + while (e->type && e->value == 0) + e++; + if (e->type) { + error(ERR_NONFATAL, + "beroset-p-650-invalid effective address"); + result->opcode = -1; + return result; + } + } + } + } else { + o = 0; + result->oprs[operand].wrt = NO_SEG; + result->oprs[operand].segment = NO_SEG; + } + + if (e->type != 0) { /* there'd better be nothing left! */ + error(ERR_NONFATAL, + "beroset-p-663-invalid effective address"); + result->opcode = -1; + return result; + } + + result->oprs[operand].type |= MEMORY; + if (b == -1 && (i == -1 || s == 0)) + result->oprs[operand].type |= MEM_OFFS; + result->oprs[operand].basereg = b; + result->oprs[operand].indexreg = i; + result->oprs[operand].scale = s; + result->oprs[operand].offset = o; + } else { /* it's not a memory reference */ + + if (is_just_unknown(value)) { /* it's immediate but unknown */ + result->oprs[operand].type |= IMMEDIATE; + result->oprs[operand].offset = 0; /* don't care */ + result->oprs[operand].segment = NO_SEG; /* don't care again */ + result->oprs[operand].wrt = NO_SEG; /* still don't care */ + } else if (is_reloc(value)) { /* it's immediate */ + result->oprs[operand].type |= IMMEDIATE; + result->oprs[operand].offset = reloc_value(value); + result->oprs[operand].segment = reloc_seg(value); + result->oprs[operand].wrt = reloc_wrt(value); + if (is_simple(value)) { + if (reloc_value(value) == 1) + result->oprs[operand].type |= UNITY; + if (optimizing >= 0 && + !(result->oprs[operand].type & STRICT)) { + if (reloc_value(value) >= -128 && + reloc_value(value) <= 127) + result->oprs[operand].type |= SBYTE; + } + } + } else { /* it's a register */ + + if (value->type >= EXPR_SIMPLE || value->value != 1) { + error(ERR_NONFATAL, "invalid operand type"); + result->opcode = -1; + return result; + } + + /* + * check that its only 1 register, not an expression... + */ + for (i = 1; value[i].type; i++) + if (value[i].value) { + error(ERR_NONFATAL, "invalid operand type"); + result->opcode = -1; + return result; + } + + /* clear overrides, except TO which applies to FPU regs */ + if (result->oprs[operand].type & ~TO) { + /* + * we want to produce a warning iff the specified size + * is different from the register size + */ + i = result->oprs[operand].type & SIZE_MASK; + } else + i = 0; + + result->oprs[operand].type &= TO; + result->oprs[operand].type |= REGISTER; + result->oprs[operand].type |= reg_flags[value->type]; + result->oprs[operand].basereg = value->type; + + if (i && (result->oprs[operand].type & SIZE_MASK) != i) + error(ERR_WARNING | ERR_PASS1, + "register size specification ignored"); + } + } + } + + result->operands = operand; /* set operand count */ + + while (operand < 3) /* clear remaining operands */ + result->oprs[operand++].type = 0; + + /* + * Transform RESW, RESD, RESQ, REST into RESB. + */ + switch (result->opcode) { + case I_RESW: + result->opcode = I_RESB; + result->oprs[0].offset *= 2; + break; + case I_RESD: + result->opcode = I_RESB; + result->oprs[0].offset *= 4; + break; + case I_RESQ: + result->opcode = I_RESB; + result->oprs[0].offset *= 8; + break; + case I_REST: + result->opcode = I_RESB; + result->oprs[0].offset *= 10; + break; + } + + return result; +} + +static int is_comma_next(void) +{ + char *p; + int i; + struct tokenval tv; + + p = stdscan_bufptr; + i = stdscan(NULL, &tv); + stdscan_bufptr = p; + return (i == ',' || i == ';' || !i); +} + +void cleanup_insn(insn * i) +{ + extop *e; + + while (i->eops) { + e = i->eops; + i->eops = i->eops->next; + nasm_free(e); + } +} diff --git a/parser.h b/parser.h index bc2135de..7b3bfdc1 100644 --- a/parser.h +++ b/parser.h @@ -10,9 +10,9 @@ #ifndef NASM_PARSER_H #define NASM_PARSER_H -void parser_global_info (struct ofmt *output, loc_t *locp); -insn *parse_line (int pass, char *buffer, insn *result, - efunc error, evalfunc evaluate, ldfunc ldef); -void cleanup_insn (insn *instruction); +void parser_global_info(struct ofmt *output, loc_t * locp); +insn *parse_line(int pass, char *buffer, insn * result, + efunc error, evalfunc evaluate, ldfunc ldef); +void cleanup_insn(insn * instruction); #endif diff --git a/preproc.c b/preproc.c dissimilarity index 69% index dbcd88d6..90c83e4c 100644 --- a/preproc.c +++ b/preproc.c @@ -1,4561 +1,4123 @@ -/* -*- mode: c; c-file-style: "bsd" -*- */ -/* preproc.c macro preprocessor for the Netwide Assembler - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * initial version 18/iii/97 by Simon Tatham - */ - -/* Typical flow of text through preproc - * - * pp_getline gets tokenised lines, either - * - * from a macro expansion - * - * or - * { - * read_line gets raw text from stdmacpos, or predef, or current input file - * tokenise converts to tokens - * } - * - * expand_mmac_params is used to expand %1 etc., unless a macro is being - * defined or a false conditional is being processed - * (%0, %1, %+1, %-1, %%foo - * - * do_directive checks for directives - * - * expand_smacro is used to expand single line macros - * - * expand_mmacro is used to expand multi-line macros - * - * detoken is used to convert the line back to text - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "nasm.h" -#include "nasmlib.h" - -typedef struct SMacro SMacro; -typedef struct MMacro MMacro; -typedef struct Context Context; -typedef struct Token Token; -typedef struct Blocks Blocks; -typedef struct Line Line; -typedef struct Include Include; -typedef struct Cond Cond; -typedef struct IncPath IncPath; - -/* - * Store the definition of a single-line macro. - */ -struct SMacro -{ - SMacro *next; - char *name; - int casesense; - int nparam; - int in_progress; - Token *expansion; -}; - -/* - * Store the definition of a multi-line macro. This is also used to - * store the interiors of `%rep...%endrep' blocks, which are - * effectively self-re-invoking multi-line macros which simply - * don't have a name or bother to appear in the hash tables. %rep - * blocks are signified by having a NULL `name' field. - * - * In a MMacro describing a `%rep' block, the `in_progress' field - * isn't merely boolean, but gives the number of repeats left to - * run. - * - * The `next' field is used for storing MMacros in hash tables; the - * `next_active' field is for stacking them on istk entries. - * - * When a MMacro is being expanded, `params', `iline', `nparam', - * `paramlen', `rotate' and `unique' are local to the invocation. - */ -struct MMacro -{ - MMacro *next; - char *name; - int casesense; - int nparam_min, nparam_max; - int plus; /* is the last parameter greedy? */ - int nolist; /* is this macro listing-inhibited? */ - int in_progress; - Token *dlist; /* All defaults as one list */ - Token **defaults; /* Parameter default pointers */ - int ndefs; /* number of default parameters */ - Line *expansion; - - MMacro *next_active; - MMacro *rep_nest; /* used for nesting %rep */ - Token **params; /* actual parameters */ - Token *iline; /* invocation line */ - int nparam, rotate, *paramlen; - unsigned long unique; - int lineno; /* Current line number on expansion */ -}; - -/* - * The context stack is composed of a linked list of these. - */ -struct Context -{ - Context *next; - SMacro *localmac; - char *name; - unsigned long number; -}; - -/* - * This is the internal form which we break input lines up into. - * Typically stored in linked lists. - * - * Note that `type' serves a double meaning: TOK_SMAC_PARAM is not - * necessarily used as-is, but is intended to denote the number of - * the substituted parameter. So in the definition - * - * %define a(x,y) ( (x) & ~(y) ) - * - * the token representing `x' will have its type changed to - * TOK_SMAC_PARAM, but the one representing `y' will be - * TOK_SMAC_PARAM+1. - * - * TOK_INTERNAL_STRING is a dirty hack: it's a single string token - * which doesn't need quotes around it. Used in the pre-include - * mechanism as an alternative to trying to find a sensible type of - * quote to use on the filename we were passed. - */ -struct Token -{ - Token *next; - char *text; - SMacro *mac; /* associated macro for TOK_SMAC_END */ - int type; -}; -enum -{ - TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING, - TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_SMAC_PARAM, - TOK_INTERNAL_STRING -}; - -/* - * Multi-line macro definitions are stored as a linked list of - * these, which is essentially a container to allow several linked - * lists of Tokens. - * - * Note that in this module, linked lists are treated as stacks - * wherever possible. For this reason, Lines are _pushed_ on to the - * `expansion' field in MMacro structures, so that the linked list, - * if walked, would give the macro lines in reverse order; this - * means that we can walk the list when expanding a macro, and thus - * push the lines on to the `expansion' field in _istk_ in reverse - * order (so that when popped back off they are in the right - * order). It may seem cockeyed, and it relies on my design having - * an even number of steps in, but it works... - * - * Some of these structures, rather than being actual lines, are - * markers delimiting the end of the expansion of a given macro. - * This is for use in the cycle-tracking and %rep-handling code. - * Such structures have `finishes' non-NULL, and `first' NULL. All - * others have `finishes' NULL, but `first' may still be NULL if - * the line is blank. - */ -struct Line -{ - Line *next; - MMacro *finishes; - Token *first; -}; - -/* - * To handle an arbitrary level of file inclusion, we maintain a - * stack (ie linked list) of these things. - */ -struct Include -{ - Include *next; - FILE *fp; - Cond *conds; - Line *expansion; - char *fname; - int lineno, lineinc; - MMacro *mstk; /* stack of active macros/reps */ -}; - -/* - * Include search path. This is simply a list of strings which get - * prepended, in turn, to the name of an include file, in an - * attempt to find the file if it's not in the current directory. - */ -struct IncPath -{ - IncPath *next; - char *path; -}; - -/* - * Conditional assembly: we maintain a separate stack of these for - * each level of file inclusion. (The only reason we keep the - * stacks separate is to ensure that a stray `%endif' in a file - * included from within the true branch of a `%if' won't terminate - * it and cause confusion: instead, rightly, it'll cause an error.) - */ -struct Cond -{ - Cond *next; - int state; -}; -enum -{ - /* - * These states are for use just after %if or %elif: IF_TRUE - * means the condition has evaluated to truth so we are - * currently emitting, whereas IF_FALSE means we are not - * currently emitting but will start doing so if a %else comes - * up. In these states, all directives are admissible: %elif, - * %else and %endif. (And of course %if.) - */ - COND_IF_TRUE, COND_IF_FALSE, - /* - * These states come up after a %else: ELSE_TRUE means we're - * emitting, and ELSE_FALSE means we're not. In ELSE_* states, - * any %elif or %else will cause an error. - */ - COND_ELSE_TRUE, COND_ELSE_FALSE, - /* - * This state means that we're not emitting now, and also that - * nothing until %endif will be emitted at all. It's for use in - * two circumstances: (i) when we've had our moment of emission - * and have now started seeing %elifs, and (ii) when the - * condition construct in question is contained within a - * non-emitting branch of a larger condition construct. - */ - COND_NEVER -}; -#define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE ) - -/* - * These defines are used as the possible return values for do_directive - */ -#define NO_DIRECTIVE_FOUND 0 -#define DIRECTIVE_FOUND 1 - -/* - * Condition codes. Note that we use c_ prefix not C_ because C_ is - * used in nasm.h for the "real" condition codes. At _this_ level, - * we treat CXZ and ECXZ as condition codes, albeit non-invertible - * ones, so we need a different enum... - */ -static const char *conditions[] = { - "a", "ae", "b", "be", "c", "cxz", "e", "ecxz", "g", "ge", "l", "le", - "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", - "np", "ns", "nz", "o", "p", "pe", "po", "s", "z" -}; -enum -{ - c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE, - c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO, - c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_S, c_Z -}; -static int inverse_ccs[] = { - c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE, - c_A, c_AE, c_B, c_BE, c_C, c_E, c_G, c_GE, c_L, c_LE, c_O, c_P, c_S, - c_Z, c_NO, c_NP, c_PO, c_PE, c_NS, c_NZ -}; - -/* - * Directive names. - */ -static const char *directives[] = { - "%arg", - "%assign", "%clear", "%define", "%elif", "%elifctx", "%elifdef", - "%elifid", "%elifidn", "%elifidni", "%elifmacro", "%elifnctx", "%elifndef", - "%elifnid", "%elifnidn", "%elifnidni", "%elifnmacro", "%elifnnum", "%elifnstr", - "%elifnum", "%elifstr", "%else", "%endif", "%endm", "%endmacro", - "%endrep", "%error", "%exitrep", "%iassign", "%idefine", "%if", - "%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifmacro", "%ifnctx", - "%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnmacro", "%ifnnum", - "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", - "%ixdefine", "%line", - "%local", - "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", - "%stacksize", - "%strlen", "%substr", "%undef", "%xdefine" -}; -enum -{ - PP_ARG, - PP_ASSIGN, PP_CLEAR, PP_DEFINE, PP_ELIF, PP_ELIFCTX, PP_ELIFDEF, - PP_ELIFID, PP_ELIFIDN, PP_ELIFIDNI, PP_ELIFMACRO, PP_ELIFNCTX, PP_ELIFNDEF, - PP_ELIFNID, PP_ELIFNIDN, PP_ELIFNIDNI, PP_ELIFNMACRO, PP_ELIFNNUM, PP_ELIFNSTR, - PP_ELIFNUM, PP_ELIFSTR, PP_ELSE, PP_ENDIF, PP_ENDM, PP_ENDMACRO, - PP_ENDREP, PP_ERROR, PP_EXITREP, PP_IASSIGN, PP_IDEFINE, PP_IF, - PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFMACRO, PP_IFNCTX, - PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNMACRO, PP_IFNNUM, - PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, - PP_IXDEFINE, PP_LINE, - PP_LOCAL, - PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, - PP_STACKSIZE, - PP_STRLEN, PP_SUBSTR, PP_UNDEF, PP_XDEFINE -}; - -/* If this is a an IF, ELIF, ELSE or ENDIF keyword */ -static int is_condition(int arg) -{ - return ((arg >= PP_ELIF) && (arg <= PP_ENDIF)) || - ((arg >= PP_IF) && (arg <= PP_IFSTR)); -} - -/* For TASM compatibility we need to be able to recognise TASM compatible - * conditional compilation directives. Using the NASM pre-processor does - * not work, so we look for them specifically from the following list and - * then jam in the equivalent NASM directive into the input stream. - */ - -#ifndef MAX -# define MAX(a,b) ( ((a) > (b)) ? (a) : (b)) -#endif - -enum -{ - TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI, - TM_IFNDEF, TM_INCLUDE, TM_LOCAL -}; - -static const char *tasm_directives[] = { - "arg", "elif", "else", "endif", "if", "ifdef", "ifdifi", - "ifndef", "include", "local" -}; - -static int StackSize = 4; -static char *StackPointer = "ebp"; -static int ArgOffset = 8; -static int LocalOffset = 4; - - -static Context *cstk; -static Include *istk; -static IncPath *ipath = NULL; - -static efunc _error; /* Pointer to client-provided error reporting function */ -static evalfunc evaluate; - -static int pass; /* HACK: pass 0 = generate dependencies only */ - -static unsigned long unique; /* unique identifier numbers */ - -static Line *predef = NULL; - -static ListGen *list; - -/* - * The number of hash values we use for the macro lookup tables. - * FIXME: We should *really* be able to configure this at run time, - * or even have the hash table automatically expanding when necessary. - */ -#define NHASH 31 - -/* - * The current set of multi-line macros we have defined. - */ -static MMacro *mmacros[NHASH]; - -/* - * The current set of single-line macros we have defined. - */ -static SMacro *smacros[NHASH]; - -/* - * The multi-line macro we are currently defining, or the %rep - * block we are currently reading, if any. - */ -static MMacro *defining; - -/* - * The number of macro parameters to allocate space for at a time. - */ -#define PARAM_DELTA 16 - -/* - * The standard macro set: defined as `static char *stdmac[]'. Also - * gives our position in the macro set, when we're processing it. - */ -#include "macros.c" -static const char **stdmacpos; - -/* - * The extra standard macros that come from the object format, if - * any. - */ -static const char **extrastdmac = NULL; -int any_extrastdmac; - -/* - * Tokens are allocated in blocks to improve speed - */ -#define TOKEN_BLOCKSIZE 4096 -static Token *freeTokens = NULL; -struct Blocks { - Blocks *next; - void *chunk; -}; - -static Blocks blocks = { NULL, NULL }; - -/* - * Forward declarations. - */ -static Token *expand_mmac_params(Token * tline); -static Token *expand_smacro(Token * tline); -static Token *expand_id(Token * tline); -static Context *get_ctx(char *name, int all_contexts); -static void make_tok_num(Token * tok, long val); -static void error(int severity, const char *fmt, ...); -static void *new_Block(size_t size); -static void delete_Blocks(void); -static Token *new_Token(Token * next, int type, char *text, int txtlen); -static Token *delete_Token(Token * t); - -/* - * Macros for safe checking of token pointers, avoid *(NULL) - */ -#define tok_type_(x,t) ((x) && (x)->type == (t)) -#define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next -#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v))) -#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v)))) - -/* Handle TASM specific directives, which do not contain a % in - * front of them. We do it here because I could not find any other - * place to do it for the moment, and it is a hack (ideally it would - * be nice to be able to use the NASM pre-processor to do it). - */ -static char * -check_tasm_directive(char *line) -{ - int i, j, k, m, len; - char *p = line, *oldline, oldchar; - - /* Skip whitespace */ - while (isspace(*p) && *p != 0) - p++; - - /* Binary search for the directive name */ - i = -1; - j = elements(tasm_directives); - len = 0; - while (!isspace(p[len]) && p[len] != 0) - len++; - if (len) - { - oldchar = p[len]; - p[len] = 0; - while (j - i > 1) - { - k = (j + i) / 2; - m = nasm_stricmp(p, tasm_directives[k]); - if (m == 0) - { - /* We have found a directive, so jam a % in front of it - * so that NASM will then recognise it as one if it's own. - */ - p[len] = oldchar; - len = strlen(p); - oldline = line; - line = nasm_malloc(len + 2); - line[0] = '%'; - if (k == TM_IFDIFI) - { - /* NASM does not recognise IFDIFI, so we convert it to - * %ifdef BOGUS. This is not used in NASM comaptible - * code, but does need to parse for the TASM macro - * package. - */ - strcpy(line + 1, "ifdef BOGUS"); - } - else - { - memcpy(line + 1, p, len + 1); - } - nasm_free(oldline); - return line; - } - else if (m < 0) - { - j = k; - } - else - i = k; - } - p[len] = oldchar; - } - return line; -} - -/* - * The pre-preprocessing stage... This function translates line - * number indications as they emerge from GNU cpp (`# lineno "file" - * flags') into NASM preprocessor line number indications (`%line - * lineno file'). - */ -static char * -prepreproc(char *line) -{ - int lineno, fnlen; - char *fname, *oldline; - - if (line[0] == '#' && line[1] == ' ') - { - oldline = line; - fname = oldline + 2; - lineno = atoi(fname); - fname += strspn(fname, "0123456789 "); - if (*fname == '"') - fname++; - fnlen = strcspn(fname, "\""); - line = nasm_malloc(20 + fnlen); - snprintf(line, 20+fnlen,"%%line %d %.*s", lineno, fnlen, fname); - nasm_free(oldline); - } - if (tasm_compatible_mode) - return check_tasm_directive(line); - return line; -} - -/* - * The hash function for macro lookups. Note that due to some - * macros having case-insensitive names, the hash function must be - * invariant under case changes. We implement this by applying a - * perfectly normal hash function to the uppercase of the string. - */ -static int -hash(char *s) -{ - unsigned int h = 0; - int i = 0; - /* - * Powers of three, mod 31. - */ - static const int multipliers[] = { - 1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, - 30, 28, 22, 4, 12, 5, 15, 14, 11, 2, 6, 18, 23, 7, 21 - }; - - - while (*s) - { - h += multipliers[i] * (unsigned char) (toupper(*s)); - s++; - if (++i >= elements(multipliers)) - i = 0; - } - h %= NHASH; - return h; -} - -/* - * Free a linked list of tokens. - */ -static void -free_tlist(Token * list) -{ - while (list) - { - list = delete_Token(list); - } -} - -/* - * Free a linked list of lines. - */ -static void -free_llist(Line * list) -{ - Line *l; - while (list) - { - l = list; - list = list->next; - free_tlist(l->first); - nasm_free(l); - } -} - -/* - * Free an MMacro - */ -static void -free_mmacro(MMacro * m) -{ - nasm_free(m->name); - free_tlist(m->dlist); - nasm_free(m->defaults); - free_llist(m->expansion); - nasm_free(m); -} - -/* - * Pop the context stack. - */ -static void -ctx_pop(void) -{ - Context *c = cstk; - SMacro *smac, *s; - - cstk = cstk->next; - smac = c->localmac; - while (smac) - { - s = smac; - smac = smac->next; - nasm_free(s->name); - free_tlist(s->expansion); - nasm_free(s); - } - nasm_free(c->name); - nasm_free(c); -} - -#define BUF_DELTA 512 -/* - * Read a line from the top file in istk, handling multiple CR/LFs - * at the end of the line read, and handling spurious ^Zs. Will - * return lines from the standard macro set if this has not already - * been done. - */ -static char * -read_line(void) -{ - char *buffer, *p, *q; - int bufsize, continued_count; - - if (stdmacpos) - { - if (*stdmacpos) - { - char *ret = nasm_strdup(*stdmacpos++); - if (!*stdmacpos && any_extrastdmac) - { - stdmacpos = extrastdmac; - any_extrastdmac = FALSE; - return ret; - } - /* - * Nasty hack: here we push the contents of `predef' on - * to the top-level expansion stack, since this is the - * most convenient way to implement the pre-include and - * pre-define features. - */ - if (!*stdmacpos) - { - Line *pd, *l; - Token *head, **tail, *t; - - for (pd = predef; pd; pd = pd->next) - { - head = NULL; - tail = &head; - for (t = pd->first; t; t = t->next) - { - *tail = new_Token(NULL, t->type, t->text, 0); - tail = &(*tail)->next; - } - l = nasm_malloc(sizeof(Line)); - l->next = istk->expansion; - l->first = head; - l->finishes = FALSE; - istk->expansion = l; - } - } - return ret; - } - else - { - stdmacpos = NULL; - } - } - - bufsize = BUF_DELTA; - buffer = nasm_malloc(BUF_DELTA); - p = buffer; - continued_count = 0; - while (1) - { - q = fgets(p, bufsize - (p - buffer), istk->fp); - if (!q) - break; - p += strlen(p); - if (p > buffer && p[-1] == '\n') - { - /* Convert backslash-CRLF line continuation sequences into - nothing at all (for DOS and Windows) */ - if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) { - p -= 3; - *p = 0; - continued_count++; - } - /* Also convert backslash-LF line continuation sequences into - nothing at all (for Unix) */ - else if (((p - 1) > buffer) && (p[-2] == '\\')) { - p -= 2; - *p = 0; - continued_count++; - } - else { - break; - } - } - if (p - buffer > bufsize - 10) - { - long offset = p - buffer; - bufsize += BUF_DELTA; - buffer = nasm_realloc(buffer, bufsize); - p = buffer + offset; /* prevent stale-pointer problems */ - } - } - - if (!q && p == buffer) - { - nasm_free(buffer); - return NULL; - } - - src_set_linnum(src_get_linnum() + istk->lineinc + (continued_count * istk->lineinc)); - - /* - * Play safe: remove CRs as well as LFs, if any of either are - * present at the end of the line. - */ - while (--p >= buffer && (*p == '\n' || *p == '\r')) - *p = '\0'; - - /* - * Handle spurious ^Z, which may be inserted into source files - * by some file transfer utilities. - */ - buffer[strcspn(buffer, "\032")] = '\0'; - - list->line(LIST_READ, buffer); - - return buffer; -} - -/* - * Tokenise a line of text. This is a very simple process since we - * don't need to parse the value out of e.g. numeric tokens: we - * simply split one string into many. - */ -static Token * -tokenise(char *line) -{ - char *p = line; - int type; - Token *list = NULL; - Token *t, **tail = &list; - - while (*line) - { - p = line; - if (*p == '%') - { - p++; - if ( isdigit(*p) || - ((*p == '-' || *p == '+') && isdigit(p[1])) || - ((*p == '+') && (isspace(p[1]) || !p[1]))) - { - do - { - p++; - } - while (isdigit(*p)); - type = TOK_PREPROC_ID; - } - else if (*p == '{') - { - p++; - while (*p && *p != '}') - { - p[-1] = *p; - p++; - } - p[-1] = '\0'; - if (*p) - p++; - type = TOK_PREPROC_ID; - } - else if (isidchar(*p) || - ((*p == '!' || *p == '%' || *p == '$') && - isidchar(p[1]))) - { - do - { - p++; - } - while (isidchar(*p)); - type = TOK_PREPROC_ID; - } - else - { - type = TOK_OTHER; - if (*p == '%') - p++; - } - } - else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) - { - type = TOK_ID; - p++; - while (*p && isidchar(*p)) - p++; - } - else if (*p == '\'' || *p == '"') - { - /* - * A string token. - */ - char c = *p; - p++; - type = TOK_STRING; - while (*p && *p != c) - p++; - - if (*p) - { - p++; - } - else - { - error(ERR_WARNING, "unterminated string"); - /* Handling unterminated strings by UNV */ - /* type = -1; */ - } - } - else if (isnumstart(*p)) - { - /* - * A number token. - */ - type = TOK_NUMBER; - p++; - while (*p && isnumchar(*p)) - p++; - } - else if (isspace(*p)) - { - type = TOK_WHITESPACE; - p++; - while (*p && isspace(*p)) - p++; - /* - * Whitespace just before end-of-line is discarded by - * pretending it's a comment; whitespace just before a - * comment gets lumped into the comment. - */ - if (!*p || *p == ';') - { - type = TOK_COMMENT; - while (*p) - p++; - } - } - else if (*p == ';') - { - type = TOK_COMMENT; - while (*p) - p++; - } - else - { - /* - * Anything else is an operator of some kind. We check - * for all the double-character operators (>>, <<, //, - * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything - * else is a single-character operator. - */ - type = TOK_OTHER; - if ((p[0] == '>' && p[1] == '>') || - (p[0] == '<' && p[1] == '<') || - (p[0] == '/' && p[1] == '/') || - (p[0] == '<' && p[1] == '=') || - (p[0] == '>' && p[1] == '=') || - (p[0] == '=' && p[1] == '=') || - (p[0] == '!' && p[1] == '=') || - (p[0] == '<' && p[1] == '>') || - (p[0] == '&' && p[1] == '&') || - (p[0] == '|' && p[1] == '|') || - (p[0] == '^' && p[1] == '^')) - { - p++; - } - p++; - } - - /* Handling unterminated string by UNV */ - /*if (type == -1) - { - *tail = t = new_Token(NULL, TOK_STRING, line, p-line+1); - t->text[p-line] = *line; - tail = &t->next; - } - else*/ - if (type != TOK_COMMENT) - { - *tail = t = new_Token(NULL, type, line, p - line); - tail = &t->next; - } - line = p; - } - return list; -} - -/* - * this function allocates a new managed block of memory and - * returns a pointer to the block. The managed blocks are - * deleted only all at once by the delete_Blocks function. - */ -static void * -new_Block(size_t size) -{ - Blocks *b = &blocks; - - /* first, get to the end of the linked list */ - while (b->next) - b = b->next; - /* now allocate the requested chunk */ - b->chunk = nasm_malloc(size); - - /* now allocate a new block for the next request */ - b->next = nasm_malloc(sizeof(Blocks)); - /* and initialize the contents of the new block */ - b->next->next = NULL; - b->next->chunk = NULL; - return b->chunk; -} - -/* - * this function deletes all managed blocks of memory - */ -static void -delete_Blocks(void) -{ - Blocks *a,*b = &blocks; - - /* - * keep in mind that the first block, pointed to by blocks - * is a static and not dynamically allocated, so we don't - * free it. - */ - while (b) - { - if (b->chunk) - nasm_free(b->chunk); - a = b; - b = b->next; - if (a != &blocks) - nasm_free(a); - } -} - -/* - * this function creates a new Token and passes a pointer to it - * back to the caller. It sets the type and text elements, and - * also the mac and next elements to NULL. - */ -static Token * -new_Token(Token * next, int type, char *text, int txtlen) -{ - Token *t; - int i; - - if (freeTokens == NULL) - { - freeTokens = (Token *)new_Block(TOKEN_BLOCKSIZE * sizeof(Token)); - for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++) - freeTokens[i].next = &freeTokens[i + 1]; - freeTokens[i].next = NULL; - } - t = freeTokens; - freeTokens = t->next; - t->next = next; - t->mac = NULL; - t->type = type; - if (type == TOK_WHITESPACE || text == NULL) - { - t->text = NULL; - } - else - { - if (txtlen == 0) - txtlen = strlen(text); - t->text = nasm_malloc(1 + txtlen); - strncpy(t->text, text, txtlen); - t->text[txtlen] = '\0'; - } - return t; -} - -static Token * -delete_Token(Token * t) -{ - Token *next = t->next; - nasm_free(t->text); - t->next = freeTokens; - freeTokens = t; - return next; -} - -/* - * Convert a line of tokens back into text. - * If expand_locals is not zero, identifiers of the form "%$*xxx" - * will be transformed into ..@ctxnum.xxx - */ -static char * -detoken(Token * tlist, int expand_locals) -{ - Token *t; - int len; - char *line, *p; - - len = 0; - for (t = tlist; t; t = t->next) - { - if (t->type == TOK_PREPROC_ID && t->text[1] == '!') - { - char *p = getenv(t->text + 2); - nasm_free(t->text); - if (p) - t->text = nasm_strdup(p); - else - t->text = NULL; - } - /* Expand local macros here and not during preprocessing */ - if (expand_locals && - t->type == TOK_PREPROC_ID && t->text && - t->text[0] == '%' && t->text[1] == '$') - { - Context *ctx = get_ctx(t->text, FALSE); - if (ctx) - { - char buffer[40]; - char *p, *q = t->text + 2; - - q += strspn(q, "$"); - snprintf(buffer, sizeof(buffer), "..@%lu.", ctx->number); - p = nasm_strcat(buffer, q); - nasm_free(t->text); - t->text = p; - } - } - if (t->type == TOK_WHITESPACE) - { - len++; - } - else if (t->text) - { - len += strlen(t->text); - } - } - p = line = nasm_malloc(len + 1); - for (t = tlist; t; t = t->next) - { - if (t->type == TOK_WHITESPACE) - { - *p = ' '; - p++; - *p = '\0'; - } - else if (t->text) - { - strcpy(p, t->text); - p += strlen(p); - } - } - *p = '\0'; - return line; -} - -/* - * A scanner, suitable for use by the expression evaluator, which - * operates on a line of Tokens. Expects a pointer to a pointer to - * the first token in the line to be passed in as its private_data - * field. - */ -static int -ppscan(void *private_data, struct tokenval *tokval) -{ - Token **tlineptr = private_data; - Token *tline; - - do - { - tline = *tlineptr; - *tlineptr = tline ? tline->next : NULL; - } - while (tline && (tline->type == TOK_WHITESPACE || - tline->type == TOK_COMMENT)); - - if (!tline) - return tokval->t_type = TOKEN_EOS; - - if (tline->text[0] == '$' && !tline->text[1]) - return tokval->t_type = TOKEN_HERE; - if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2]) - return tokval->t_type = TOKEN_BASE; - - if (tline->type == TOK_ID) - { - tokval->t_charptr = tline->text; - if (tline->text[0] == '$') - { - tokval->t_charptr++; - return tokval->t_type = TOKEN_ID; - } - - /* - * This is the only special case we actually need to worry - * about in this restricted context. - */ - if (!nasm_stricmp(tline->text, "seg")) - return tokval->t_type = TOKEN_SEG; - - return tokval->t_type = TOKEN_ID; - } - - if (tline->type == TOK_NUMBER) - { - int rn_error; - - tokval->t_integer = readnum(tline->text, &rn_error); - if (rn_error) - return tokval->t_type = TOKEN_ERRNUM; - tokval->t_charptr = NULL; - return tokval->t_type = TOKEN_NUM; - } - - if (tline->type == TOK_STRING) - { - int rn_warn; - char q, *r; - int l; - - r = tline->text; - q = *r++; - l = strlen(r); - - if (l == 0 || r[l - 1] != q) - return tokval->t_type = TOKEN_ERRNUM; - tokval->t_integer = readstrnum(r, l - 1, &rn_warn); - if (rn_warn) - error(ERR_WARNING | ERR_PASS1, "character constant too long"); - tokval->t_charptr = NULL; - return tokval->t_type = TOKEN_NUM; - } - - if (tline->type == TOK_OTHER) - { - if (!strcmp(tline->text, "<<")) - return tokval->t_type = TOKEN_SHL; - if (!strcmp(tline->text, ">>")) - return tokval->t_type = TOKEN_SHR; - if (!strcmp(tline->text, "//")) - return tokval->t_type = TOKEN_SDIV; - if (!strcmp(tline->text, "%%")) - return tokval->t_type = TOKEN_SMOD; - if (!strcmp(tline->text, "==")) - return tokval->t_type = TOKEN_EQ; - if (!strcmp(tline->text, "<>")) - return tokval->t_type = TOKEN_NE; - if (!strcmp(tline->text, "!=")) - return tokval->t_type = TOKEN_NE; - if (!strcmp(tline->text, "<=")) - return tokval->t_type = TOKEN_LE; - if (!strcmp(tline->text, ">=")) - return tokval->t_type = TOKEN_GE; - if (!strcmp(tline->text, "&&")) - return tokval->t_type = TOKEN_DBL_AND; - if (!strcmp(tline->text, "^^")) - return tokval->t_type = TOKEN_DBL_XOR; - if (!strcmp(tline->text, "||")) - return tokval->t_type = TOKEN_DBL_OR; - } - - /* - * We have no other options: just return the first character of - * the token text. - */ - return tokval->t_type = tline->text[0]; -} - -/* - * Compare a string to the name of an existing macro; this is a - * simple wrapper which calls either strcmp or nasm_stricmp - * depending on the value of the `casesense' parameter. - */ -static int -mstrcmp(char *p, char *q, int casesense) -{ - return casesense ? strcmp(p, q) : nasm_stricmp(p, q); -} - -/* - * Return the Context structure associated with a %$ token. Return - * NULL, having _already_ reported an error condition, if the - * context stack isn't deep enough for the supplied number of $ - * signs. - * If all_contexts == TRUE, contexts that enclose current are - * also scanned for such smacro, until it is found; if not - - * only the context that directly results from the number of $'s - * in variable's name. - */ -static Context * -get_ctx(char *name, int all_contexts) -{ - Context *ctx; - SMacro *m; - int i; - - if (!name || name[0] != '%' || name[1] != '$') - return NULL; - - if (!cstk) - { - error(ERR_NONFATAL, "`%s': context stack is empty", name); - return NULL; - } - - for (i = strspn(name + 2, "$"), ctx = cstk; (i > 0) && ctx; i--) - { - ctx = ctx->next; -/* i--; Lino - 02/25/02 */ - } - if (!ctx) - { - error(ERR_NONFATAL, "`%s': context stack is only" - " %d level%s deep", name, i - 1, (i == 2 ? "" : "s")); - return NULL; - } - if (!all_contexts) - return ctx; - - do - { - /* Search for this smacro in found context */ - m = ctx->localmac; - while (m) - { - if (!mstrcmp(m->name, name, m->casesense)) - return ctx; - m = m->next; - } - ctx = ctx->next; - } - while (ctx); - return NULL; -} - -/* - * Open an include file. This routine must always return a valid - * file pointer if it returns - it's responsible for throwing an - * ERR_FATAL and bombing out completely if not. It should also try - * the include path one by one until it finds the file or reaches - * the end of the path. - */ -static FILE * -inc_fopen(char *file) -{ - FILE *fp; - char *prefix = "", *combine; - IncPath *ip = ipath; - static int namelen = 0; - int len = strlen(file); - - while (1) - { - combine = nasm_malloc(strlen(prefix) + len + 1); - strcpy(combine, prefix); - strcat(combine, file); - fp = fopen(combine, "r"); - if (pass == 0 && fp) - { - namelen += strlen(combine) + 1; - if (namelen > 62) - { - printf(" \\\n "); - namelen = 2; - } - printf(" %s", combine); - } - nasm_free(combine); - if (fp) - return fp; - if (!ip) - break; - prefix = ip->path; - ip = ip->next; - } - - error(ERR_FATAL, "unable to open include file `%s'", file); - return NULL; /* never reached - placate compilers */ -} - -/* - * Determine if we should warn on defining a single-line macro of - * name `name', with `nparam' parameters. If nparam is 0 or -1, will - * return TRUE if _any_ single-line macro of that name is defined. - * Otherwise, will return TRUE if a single-line macro with either - * `nparam' or no parameters is defined. - * - * If a macro with precisely the right number of parameters is - * defined, or nparam is -1, the address of the definition structure - * will be returned in `defn'; otherwise NULL will be returned. If `defn' - * is NULL, no action will be taken regarding its contents, and no - * error will occur. - * - * Note that this is also called with nparam zero to resolve - * `ifdef'. - * - * If you already know which context macro belongs to, you can pass - * the context pointer as first parameter; if you won't but name begins - * with %$ the context will be automatically computed. If all_contexts - * is true, macro will be searched in outer contexts as well. - */ -static int -smacro_defined(Context * ctx, char *name, int nparam, SMacro ** defn, - int nocase) -{ - SMacro *m; - - if (ctx) - m = ctx->localmac; - else if (name[0] == '%' && name[1] == '$') - { - if (cstk) - ctx = get_ctx(name, FALSE); - if (!ctx) - return FALSE; /* got to return _something_ */ - m = ctx->localmac; - } - else - m = smacros[hash(name)]; - - while (m) - { - if (!mstrcmp(m->name, name, m->casesense && nocase) && - (nparam <= 0 || m->nparam == 0 || nparam == m->nparam)) - { - if (defn) - { - if (nparam == m->nparam || nparam == -1) - *defn = m; - else - *defn = NULL; - } - return TRUE; - } - m = m->next; - } - - return FALSE; -} - -/* - * Count and mark off the parameters in a multi-line macro call. - * This is called both from within the multi-line macro expansion - * code, and also to mark off the default parameters when provided - * in a %macro definition line. - */ -static void -count_mmac_params(Token * t, int *nparam, Token *** params) -{ - int paramsize, brace; - - *nparam = paramsize = 0; - *params = NULL; - while (t) - { - if (*nparam >= paramsize) - { - paramsize += PARAM_DELTA; - *params = nasm_realloc(*params, sizeof(**params) * paramsize); - } - skip_white_(t); - brace = FALSE; - if (tok_is_(t, "{")) - brace = TRUE; - (*params)[(*nparam)++] = t; - while (tok_isnt_(t, brace ? "}" : ",")) - t = t->next; - if (t) - { /* got a comma/brace */ - t = t->next; - if (brace) - { - /* - * Now we've found the closing brace, look further - * for the comma. - */ - skip_white_(t); - if (tok_isnt_(t, ",")) - { - error(ERR_NONFATAL, - "braces do not enclose all of macro parameter"); - while (tok_isnt_(t, ",")) - t = t->next; - } - if (t) - t = t->next; /* eat the comma */ - } - } - } -} - -/* - * Determine whether one of the various `if' conditions is true or - * not. - * - * We must free the tline we get passed. - */ -static int -if_condition(Token * tline, int i) -{ - int j, casesense; - Token *t, *tt, **tptr, *origline; - struct tokenval tokval; - expr *evalresult; - - origline = tline; - - switch (i) - { - case PP_IFCTX: - case PP_ELIFCTX: - case PP_IFNCTX: - case PP_ELIFNCTX: - j = FALSE; /* have we matched yet? */ - while (cstk && tline) - { - skip_white_(tline); - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%s' expects context identifiers", - directives[i]); - free_tlist(origline); - return -1; - } - if (!nasm_stricmp(tline->text, cstk->name)) - j = TRUE; - tline = tline->next; - } - if (i == PP_IFNCTX || i == PP_ELIFNCTX) - j = !j; - free_tlist(origline); - return j; - - case PP_IFDEF: - case PP_ELIFDEF: - case PP_IFNDEF: - case PP_ELIFNDEF: - j = FALSE; /* have we matched yet? */ - while (tline) - { - skip_white_(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%s' expects macro identifiers", - directives[i]); - free_tlist(origline); - return -1; - } - if (smacro_defined(NULL, tline->text, 0, NULL, 1)) - j = TRUE; - tline = tline->next; - } - if (i == PP_IFNDEF || i == PP_ELIFNDEF) - j = !j; - free_tlist(origline); - return j; - - case PP_IFIDN: - case PP_ELIFIDN: - case PP_IFNIDN: - case PP_ELIFNIDN: - case PP_IFIDNI: - case PP_ELIFIDNI: - case PP_IFNIDNI: - case PP_ELIFNIDNI: - tline = expand_smacro(tline); - t = tt = tline; - while (tok_isnt_(tt, ",")) - tt = tt->next; - if (!tt) - { - error(ERR_NONFATAL, - "`%s' expects two comma-separated arguments", - directives[i]); - free_tlist(tline); - return -1; - } - tt = tt->next; - casesense = (i == PP_IFIDN || i == PP_ELIFIDN || - i == PP_IFNIDN || i == PP_ELIFNIDN); - j = TRUE; /* assume equality unless proved not */ - while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) - { - if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) - { - error(ERR_NONFATAL, "`%s': more than one comma on line", - directives[i]); - free_tlist(tline); - return -1; - } - if (t->type == TOK_WHITESPACE) - { - t = t->next; - continue; - } - if (tt->type == TOK_WHITESPACE) - { - tt = tt->next; - continue; - } - if (tt->type != t->type) - { - j = FALSE; /* found mismatching tokens */ - break; - } - /* Unify surrounding quotes for strings */ - if (t->type == TOK_STRING) - { - tt->text[0] = t->text[0]; - tt->text[strlen(tt->text) - 1] = t->text[0]; - } - if (mstrcmp(tt->text, t->text, casesense) != 0) - { - j = FALSE; /* found mismatching tokens */ - break; - } - - t = t->next; - tt = tt->next; - } - if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt) - j = FALSE; /* trailing gunk on one end or other */ - if (i == PP_IFNIDN || i == PP_ELIFNIDN || - i == PP_IFNIDNI || i == PP_ELIFNIDNI) - j = !j; - free_tlist(tline); - return j; - - case PP_IFMACRO: - case PP_ELIFMACRO: - case PP_IFNMACRO: - case PP_ELIFNMACRO: - { - int found = 0; - MMacro searching, *mmac; - - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tok_type_(tline, TOK_ID)) - { - error(ERR_NONFATAL, - "`%s' expects a macro name", - directives[i]); - return -1; - } - searching.name = nasm_strdup(tline->text); - searching.casesense = (i == PP_MACRO); - searching.plus = FALSE; - searching.nolist = FALSE; - searching.in_progress = FALSE; - searching.rep_nest = NULL; - searching.nparam_min = 0; - searching.nparam_max = INT_MAX; - tline = expand_smacro(tline->next); - skip_white_(tline); - if (!tline) - { - } else if (!tok_type_(tline, TOK_NUMBER)) - { - error(ERR_NONFATAL, - "`%s' expects a parameter count or nothing", - directives[i]); - } - else - { - searching.nparam_min = searching.nparam_max = - readnum(tline->text, &j); - if (j) - error(ERR_NONFATAL, - "unable to parse parameter count `%s'", - tline->text); - } - if (tline && tok_is_(tline->next, "-")) - { - tline = tline->next->next; - if (tok_is_(tline, "*")) - searching.nparam_max = INT_MAX; - else if (!tok_type_(tline, TOK_NUMBER)) - error(ERR_NONFATAL, - "`%s' expects a parameter count after `-'", - directives[i]); - else - { - searching.nparam_max = readnum(tline->text, &j); - if (j) - error(ERR_NONFATAL, - "unable to parse parameter count `%s'", - tline->text); - if (searching.nparam_min > searching.nparam_max) - error(ERR_NONFATAL, - "minimum parameter count exceeds maximum"); - } - } - if (tline && tok_is_(tline->next, "+")) - { - tline = tline->next; - searching.plus = TRUE; - } - mmac = mmacros[hash(searching.name)]; - while (mmac) - { - if (!strcmp(mmac->name, searching.name) && - (mmac->nparam_min <= searching.nparam_max - || searching.plus) - && (searching.nparam_min <= mmac->nparam_max - || mmac->plus)) - { - found = TRUE; - break; - } - mmac = mmac->next; - } - nasm_free(searching.name); - free_tlist(origline); - if (i == PP_IFNMACRO || i == PP_ELIFNMACRO) - found = !found; - return found; - } - - case PP_IFID: - case PP_ELIFID: - case PP_IFNID: - case PP_ELIFNID: - case PP_IFNUM: - case PP_ELIFNUM: - case PP_IFNNUM: - case PP_ELIFNNUM: - case PP_IFSTR: - case PP_ELIFSTR: - case PP_IFNSTR: - case PP_ELIFNSTR: - tline = expand_smacro(tline); - t = tline; - while (tok_type_(t, TOK_WHITESPACE)) - t = t->next; - j = FALSE; /* placate optimiser */ - if (t) - switch (i) - { - case PP_IFID: - case PP_ELIFID: - case PP_IFNID: - case PP_ELIFNID: - j = (t->type == TOK_ID); - break; - case PP_IFNUM: - case PP_ELIFNUM: - case PP_IFNNUM: - case PP_ELIFNNUM: - j = (t->type == TOK_NUMBER); - break; - case PP_IFSTR: - case PP_ELIFSTR: - case PP_IFNSTR: - case PP_ELIFNSTR: - j = (t->type == TOK_STRING); - break; - } - if (i == PP_IFNID || i == PP_ELIFNID || - i == PP_IFNNUM || i == PP_ELIFNNUM || - i == PP_IFNSTR || i == PP_ELIFNSTR) - j = !j; - free_tlist(tline); - return j; - - case PP_IF: - case PP_ELIF: - t = tline = expand_smacro(tline); - tptr = &t; - tokval.t_type = TOKEN_INVALID; - evalresult = evaluate(ppscan, tptr, &tokval, - NULL, pass | CRITICAL, error, NULL); - free_tlist(tline); - if (!evalresult) - return -1; - if (tokval.t_type) - error(ERR_WARNING, - "trailing garbage after expression ignored"); - if (!is_simple(evalresult)) - { - error(ERR_NONFATAL, - "non-constant value given to `%s'", directives[i]); - return -1; - } - return reloc_value(evalresult) != 0; - - default: - error(ERR_FATAL, - "preprocessor directive `%s' not yet implemented", - directives[i]); - free_tlist(origline); - return -1; /* yeah, right */ - } -} - -/* - * Expand macros in a string. Used in %error and %include directives. - * First tokenise the string, apply "expand_smacro" and then de-tokenise back. - * The returned variable should ALWAYS be freed after usage. - */ -void -expand_macros_in_string(char **p) -{ - Token *line = tokenise(*p); - line = expand_smacro(line); - *p = detoken(line, FALSE); -} - -/** - * find and process preprocessor directive in passed line - * Find out if a line contains a preprocessor directive, and deal - * with it if so. - * - * If a directive _is_ found, it is the responsibility of this routine - * (and not the caller) to free_tlist() the line. - * - * @param tline a pointer to the current tokeninzed line linked list - * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND - * - */ -static int -do_directive(Token * tline) -{ - int i, j, k, m, nparam, nolist; - int offset; - char *p, *mname; - Include *inc; - Context *ctx; - Cond *cond; - SMacro *smac, **smhead; - MMacro *mmac; - Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline; - Line *l; - struct tokenval tokval; - expr *evalresult; - MMacro *tmp_defining; /* Used when manipulating rep_nest */ - - origline = tline; - - skip_white_(tline); - if (!tok_type_(tline, TOK_PREPROC_ID) || - (tline->text[1] == '%' || tline->text[1] == '$' - || tline->text[1] == '!')) - return NO_DIRECTIVE_FOUND; - - i = -1; - j = elements(directives); - while (j - i > 1) - { - k = (j + i) / 2; - m = nasm_stricmp(tline->text, directives[k]); - if (m == 0) { - if (tasm_compatible_mode) { - i = k; - j = -2; - } else if (k != PP_ARG && k != PP_LOCAL && k != PP_STACKSIZE) { - i = k; - j = -2; - } - break; - } - else if (m < 0) { - j = k; - } - else - i = k; - } - - /* - * If we're in a non-emitting branch of a condition construct, - * or walking to the end of an already terminated %rep block, - * we should ignore all directives except for condition - * directives. - */ - if (((istk->conds && !emitting(istk->conds->state)) || - (istk->mstk && !istk->mstk->in_progress)) && - !is_condition(i)) - { - return NO_DIRECTIVE_FOUND; - } - - /* - * If we're defining a macro or reading a %rep block, we should - * ignore all directives except for %macro/%imacro (which - * generate an error), %endm/%endmacro, and (only if we're in a - * %rep block) %endrep. If we're in a %rep block, another %rep - * causes an error, so should be let through. - */ - if (defining && i != PP_MACRO && i != PP_IMACRO && - i != PP_ENDMACRO && i != PP_ENDM && - (defining->name || (i != PP_ENDREP && i != PP_REP))) - { - return NO_DIRECTIVE_FOUND; - } - - if (j != -2) - { - error(ERR_NONFATAL, "unknown preprocessor directive `%s'", - tline->text); - return NO_DIRECTIVE_FOUND; /* didn't get it */ - } - - switch (i) - { - case PP_STACKSIZE: - /* Directive to tell NASM what the default stack size is. The - * default is for a 16-bit stack, and this can be overriden with - * %stacksize large. - * the following form: - * - * ARG arg1:WORD, arg2:DWORD, arg4:QWORD - */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, "`%%stacksize' missing size parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - if (nasm_stricmp(tline->text, "flat") == 0) - { - /* All subsequent ARG directives are for a 32-bit stack */ - StackSize = 4; - StackPointer = "ebp"; - ArgOffset = 8; - LocalOffset = 4; - } - else if (nasm_stricmp(tline->text, "large") == 0) - { - /* All subsequent ARG directives are for a 16-bit stack, - * far function call. - */ - StackSize = 2; - StackPointer = "bp"; - ArgOffset = 4; - LocalOffset = 2; - } - else if (nasm_stricmp(tline->text, "small") == 0) - { - /* All subsequent ARG directives are for a 16-bit stack, - * far function call. We don't support near functions. - */ - StackSize = 2; - StackPointer = "bp"; - ArgOffset = 6; - LocalOffset = 2; - } - else - { - error(ERR_NONFATAL, "`%%stacksize' invalid size type"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_ARG: - /* TASM like ARG directive to define arguments to functions, in - * the following form: - * - * ARG arg1:WORD, arg2:DWORD, arg4:QWORD - */ - offset = ArgOffset; - do - { - char *arg, directive[256]; - int size = StackSize; - - /* Find the argument name */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, "`%%arg' missing argument parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - arg = tline->text; - - /* Find the argument size type */ - tline = tline->next; - if (!tline || tline->type != TOK_OTHER - || tline->text[0] != ':') - { - error(ERR_NONFATAL, - "Syntax error processing `%%arg' directive"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%%arg' missing size type parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - /* Allow macro expansion of type parameter */ - tt = tokenise(tline->text); - tt = expand_smacro(tt); - if (nasm_stricmp(tt->text, "byte") == 0) - { - size = MAX(StackSize, 1); - } - else if (nasm_stricmp(tt->text, "word") == 0) - { - size = MAX(StackSize, 2); - } - else if (nasm_stricmp(tt->text, "dword") == 0) - { - size = MAX(StackSize, 4); - } - else if (nasm_stricmp(tt->text, "qword") == 0) - { - size = MAX(StackSize, 8); - } - else if (nasm_stricmp(tt->text, "tword") == 0) - { - size = MAX(StackSize, 10); - } - else - { - error(ERR_NONFATAL, - "Invalid size type for `%%arg' missing directive"); - free_tlist(tt); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - free_tlist(tt); - - /* Now define the macro for the argument */ - snprintf(directive, sizeof(directive), "%%define %s (%s+%d)", arg, StackPointer, - offset); - do_directive(tokenise(directive)); - offset += size; - - /* Move to the next argument in the list */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - } - while (tline && tline->type == TOK_OTHER - && tline->text[0] == ','); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_LOCAL: - /* TASM like LOCAL directive to define local variables for a - * function, in the following form: - * - * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize - * - * The '= LocalSize' at the end is ignored by NASM, but is - * required by TASM to define the local parameter size (and used - * by the TASM macro package). - */ - offset = LocalOffset; - do - { - char *local, directive[256]; - int size = StackSize; - - /* Find the argument name */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%%local' missing argument parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - local = tline->text; - - /* Find the argument size type */ - tline = tline->next; - if (!tline || tline->type != TOK_OTHER - || tline->text[0] != ':') - { - error(ERR_NONFATAL, - "Syntax error processing `%%local' directive"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - tline = tline->next; - if (!tline || tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%%local' missing size type parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - /* Allow macro expansion of type parameter */ - tt = tokenise(tline->text); - tt = expand_smacro(tt); - if (nasm_stricmp(tt->text, "byte") == 0) - { - size = MAX(StackSize, 1); - } - else if (nasm_stricmp(tt->text, "word") == 0) - { - size = MAX(StackSize, 2); - } - else if (nasm_stricmp(tt->text, "dword") == 0) - { - size = MAX(StackSize, 4); - } - else if (nasm_stricmp(tt->text, "qword") == 0) - { - size = MAX(StackSize, 8); - } - else if (nasm_stricmp(tt->text, "tword") == 0) - { - size = MAX(StackSize, 10); - } - else - { - error(ERR_NONFATAL, - "Invalid size type for `%%local' missing directive"); - free_tlist(tt); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - free_tlist(tt); - - /* Now define the macro for the argument */ - snprintf(directive, sizeof(directive), "%%define %s (%s-%d)", local, StackPointer, - offset); - do_directive(tokenise(directive)); - offset += size; - - /* Now define the assign to setup the enter_c macro correctly */ - snprintf(directive, sizeof(directive), "%%assign %%$localsize %%$localsize+%d", - size); - do_directive(tokenise(directive)); - - /* Move to the next argument in the list */ - tline = tline->next; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - } - while (tline && tline->type == TOK_OTHER - && tline->text[0] == ','); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_CLEAR: - if (tline->next) - error(ERR_WARNING, - "trailing garbage after `%%clear' ignored"); - for (j = 0; j < NHASH; j++) - { - while (mmacros[j]) - { - MMacro *m = mmacros[j]; - mmacros[j] = m->next; - free_mmacro(m); - } - while (smacros[j]) - { - SMacro *s = smacros[j]; - smacros[j] = smacros[j]->next; - nasm_free(s->name); - free_tlist(s->expansion); - nasm_free(s); - } - } - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_INCLUDE: - tline = tline->next; - skip_white_(tline); - if (!tline || (tline->type != TOK_STRING && - tline->type != TOK_INTERNAL_STRING)) - { - error(ERR_NONFATAL, "`%%include' expects a file name"); - free_tlist(origline); - return DIRECTIVE_FOUND; /* but we did _something_ */ - } - if (tline->next) - error(ERR_WARNING, - "trailing garbage after `%%include' ignored"); - if (tline->type != TOK_INTERNAL_STRING) - { - p = tline->text + 1; /* point past the quote to the name */ - p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ - } - else - p = tline->text; /* internal_string is easier */ - expand_macros_in_string(&p); - inc = nasm_malloc(sizeof(Include)); - inc->next = istk; - inc->conds = NULL; - inc->fp = inc_fopen(p); - inc->fname = src_set_fname(p); - inc->lineno = src_set_linnum(0); - inc->lineinc = 1; - inc->expansion = NULL; - inc->mstk = NULL; - istk = inc; - list->uplevel(LIST_INCLUDE); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_PUSH: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tok_type_(tline, TOK_ID)) - { - error(ERR_NONFATAL, "`%%push' expects a context identifier"); - free_tlist(origline); - return DIRECTIVE_FOUND; /* but we did _something_ */ - } - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%push' ignored"); - ctx = nasm_malloc(sizeof(Context)); - ctx->next = cstk; - ctx->localmac = NULL; - ctx->name = nasm_strdup(tline->text); - ctx->number = unique++; - cstk = ctx; - free_tlist(origline); - break; - - case PP_REPL: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tok_type_(tline, TOK_ID)) - { - error(ERR_NONFATAL, "`%%repl' expects a context identifier"); - free_tlist(origline); - return DIRECTIVE_FOUND; /* but we did _something_ */ - } - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%repl' ignored"); - if (!cstk) - error(ERR_NONFATAL, "`%%repl': context stack is empty"); - else - { - nasm_free(cstk->name); - cstk->name = nasm_strdup(tline->text); - } - free_tlist(origline); - break; - - case PP_POP: - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%pop' ignored"); - if (!cstk) - error(ERR_NONFATAL, - "`%%pop': context stack is already empty"); - else - ctx_pop(); - free_tlist(origline); - break; - - case PP_ERROR: - tline->next = expand_smacro(tline->next); - tline = tline->next; - skip_white_(tline); - if (tok_type_(tline, TOK_STRING)) - { - p = tline->text + 1; /* point past the quote to the name */ - p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ - expand_macros_in_string(&p); - error(ERR_NONFATAL, "%s", p); - nasm_free(p); - } - else - { - p = detoken(tline, FALSE); - error(ERR_WARNING, "%s", p); - nasm_free(p); - } - free_tlist(origline); - break; - - case PP_IF: - case PP_IFCTX: - case PP_IFDEF: - case PP_IFID: - case PP_IFIDN: - case PP_IFIDNI: - case PP_IFMACRO: - case PP_IFNCTX: - case PP_IFNDEF: - case PP_IFNID: - case PP_IFNIDN: - case PP_IFNIDNI: - case PP_IFNMACRO: - case PP_IFNNUM: - case PP_IFNSTR: - case PP_IFNUM: - case PP_IFSTR: - if (istk->conds && !emitting(istk->conds->state)) - j = COND_NEVER; - else - { - j = if_condition(tline->next, i); - tline->next = NULL; /* it got freed */ - free_tlist(origline); - j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; - } - cond = nasm_malloc(sizeof(Cond)); - cond->next = istk->conds; - cond->state = j; - istk->conds = cond; - return DIRECTIVE_FOUND; - - case PP_ELIF: - case PP_ELIFCTX: - case PP_ELIFDEF: - case PP_ELIFID: - case PP_ELIFIDN: - case PP_ELIFIDNI: - case PP_ELIFMACRO: - case PP_ELIFNCTX: - case PP_ELIFNDEF: - case PP_ELIFNID: - case PP_ELIFNIDN: - case PP_ELIFNIDNI: - case PP_ELIFNMACRO: - case PP_ELIFNNUM: - case PP_ELIFNSTR: - case PP_ELIFNUM: - case PP_ELIFSTR: - if (!istk->conds) - error(ERR_FATAL, "`%s': no matching `%%if'", directives[i]); - if (emitting(istk->conds->state) - || istk->conds->state == COND_NEVER) - istk->conds->state = COND_NEVER; - else - { - /* - * IMPORTANT: In the case of %if, we will already have - * called expand_mmac_params(); however, if we're - * processing an %elif we must have been in a - * non-emitting mode, which would have inhibited - * the normal invocation of expand_mmac_params(). Therefore, - * we have to do it explicitly here. - */ - j = if_condition(expand_mmac_params(tline->next), i); - tline->next = NULL; /* it got freed */ - free_tlist(origline); - istk->conds->state = - j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; - } - return DIRECTIVE_FOUND; - - case PP_ELSE: - if (tline->next) - error(ERR_WARNING, "trailing garbage after `%%else' ignored"); - if (!istk->conds) - error(ERR_FATAL, "`%%else': no matching `%%if'"); - if (emitting(istk->conds->state) - || istk->conds->state == COND_NEVER) - istk->conds->state = COND_ELSE_FALSE; - else - istk->conds->state = COND_ELSE_TRUE; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_ENDIF: - if (tline->next) - error(ERR_WARNING, - "trailing garbage after `%%endif' ignored"); - if (!istk->conds) - error(ERR_FATAL, "`%%endif': no matching `%%if'"); - cond = istk->conds; - istk->conds = cond->next; - nasm_free(cond); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_MACRO: - case PP_IMACRO: - if (defining) - error(ERR_FATAL, - "`%%%smacro': already defining a macro", - (i == PP_IMACRO ? "i" : "")); - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tok_type_(tline, TOK_ID)) - { - error(ERR_NONFATAL, - "`%%%smacro' expects a macro name", - (i == PP_IMACRO ? "i" : "")); - return DIRECTIVE_FOUND; - } - defining = nasm_malloc(sizeof(MMacro)); - defining->name = nasm_strdup(tline->text); - defining->casesense = (i == PP_MACRO); - defining->plus = FALSE; - defining->nolist = FALSE; - defining->in_progress = FALSE; - defining->rep_nest = NULL; - tline = expand_smacro(tline->next); - skip_white_(tline); - if (!tok_type_(tline, TOK_NUMBER)) - { - error(ERR_NONFATAL, - "`%%%smacro' expects a parameter count", - (i == PP_IMACRO ? "i" : "")); - defining->nparam_min = defining->nparam_max = 0; - } - else - { - defining->nparam_min = defining->nparam_max = - readnum(tline->text, &j); - if (j) - error(ERR_NONFATAL, - "unable to parse parameter count `%s'", - tline->text); - } - if (tline && tok_is_(tline->next, "-")) - { - tline = tline->next->next; - if (tok_is_(tline, "*")) - defining->nparam_max = INT_MAX; - else if (!tok_type_(tline, TOK_NUMBER)) - error(ERR_NONFATAL, - "`%%%smacro' expects a parameter count after `-'", - (i == PP_IMACRO ? "i" : "")); - else - { - defining->nparam_max = readnum(tline->text, &j); - if (j) - error(ERR_NONFATAL, - "unable to parse parameter count `%s'", - tline->text); - if (defining->nparam_min > defining->nparam_max) - error(ERR_NONFATAL, - "minimum parameter count exceeds maximum"); - } - } - if (tline && tok_is_(tline->next, "+")) - { - tline = tline->next; - defining->plus = TRUE; - } - if (tline && tok_type_(tline->next, TOK_ID) && - !nasm_stricmp(tline->next->text, ".nolist")) - { - tline = tline->next; - defining->nolist = TRUE; - } - mmac = mmacros[hash(defining->name)]; - while (mmac) - { - if (!strcmp(mmac->name, defining->name) && - (mmac->nparam_min <= defining->nparam_max - || defining->plus) - && (defining->nparam_min <= mmac->nparam_max - || mmac->plus)) - { - error(ERR_WARNING, - "redefining multi-line macro `%s'", - defining->name); - break; - } - mmac = mmac->next; - } - /* - * Handle default parameters. - */ - if (tline && tline->next) - { - defining->dlist = tline->next; - tline->next = NULL; - count_mmac_params(defining->dlist, &defining->ndefs, - &defining->defaults); - } - else - { - defining->dlist = NULL; - defining->defaults = NULL; - } - defining->expansion = NULL; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_ENDM: - case PP_ENDMACRO: - if (!defining) - { - error(ERR_NONFATAL, "`%s': not defining a macro", - tline->text); - return DIRECTIVE_FOUND; - } - k = hash(defining->name); - defining->next = mmacros[k]; - mmacros[k] = defining; - defining = NULL; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_ROTATE: - if (tline->next && tline->next->type == TOK_WHITESPACE) - tline = tline->next; - if (tline->next == NULL) - { - free_tlist(origline); - error(ERR_NONFATAL, "`%%rotate' missing rotate count"); - return DIRECTIVE_FOUND; - } - t = expand_smacro(tline->next); - tline->next = NULL; - free_tlist(origline); - tline = t; - tptr = &t; - tokval.t_type = TOKEN_INVALID; - evalresult = - evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); - free_tlist(tline); - if (!evalresult) - return DIRECTIVE_FOUND; - if (tokval.t_type) - error(ERR_WARNING, - "trailing garbage after expression ignored"); - if (!is_simple(evalresult)) - { - error(ERR_NONFATAL, "non-constant value given to `%%rotate'"); - return DIRECTIVE_FOUND; - } - mmac = istk->mstk; - while (mmac && !mmac->name) /* avoid mistaking %reps for macros */ - mmac = mmac->next_active; - if (!mmac) - { - error(ERR_NONFATAL, - "`%%rotate' invoked outside a macro call"); - } - else if (mmac->nparam == 0) - { - error(ERR_NONFATAL, - "`%%rotate' invoked within macro without parameters"); - } - else - { - mmac->rotate = mmac->rotate + reloc_value(evalresult); - - if (mmac->rotate < 0) - mmac->rotate = - mmac->nparam - (-mmac->rotate) % mmac->nparam; - mmac->rotate %= mmac->nparam; - } - return DIRECTIVE_FOUND; - - case PP_REP: - nolist = FALSE; - do { - tline = tline->next; - } while (tok_type_(tline, TOK_WHITESPACE)); - - if (tok_type_(tline, TOK_ID) && - nasm_stricmp(tline->text, ".nolist") == 0) - { - nolist = TRUE; - do { - tline = tline->next; - } while (tok_type_(tline, TOK_WHITESPACE)); - } - - if (tline) - { - t = expand_smacro(tline); - tptr = &t; - tokval.t_type = TOKEN_INVALID; - evalresult = - evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); - if (!evalresult) - { - free_tlist(origline); - return DIRECTIVE_FOUND; - } - if (tokval.t_type) - error(ERR_WARNING, - "trailing garbage after expression ignored"); - if (!is_simple(evalresult)) - { - error(ERR_NONFATAL, "non-constant value given to `%%rep'"); - return DIRECTIVE_FOUND; - } - i = (int)reloc_value(evalresult) + 1; - } - else - { - error(ERR_NONFATAL, "`%%rep' expects a repeat count"); - i = 0; - } - free_tlist(origline); - - tmp_defining = defining; - defining = nasm_malloc(sizeof(MMacro)); - defining->name = NULL; /* flags this macro as a %rep block */ - defining->casesense = 0; - defining->plus = FALSE; - defining->nolist = nolist; - defining->in_progress = i; - defining->nparam_min = defining->nparam_max = 0; - defining->defaults = NULL; - defining->dlist = NULL; - defining->expansion = NULL; - defining->next_active = istk->mstk; - defining->rep_nest = tmp_defining; - return DIRECTIVE_FOUND; - - case PP_ENDREP: - if (!defining || defining->name) - { - error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'"); - return DIRECTIVE_FOUND; - } - - /* - * Now we have a "macro" defined - although it has no name - * and we won't be entering it in the hash tables - we must - * push a macro-end marker for it on to istk->expansion. - * After that, it will take care of propagating itself (a - * macro-end marker line for a macro which is really a %rep - * block will cause the macro to be re-expanded, complete - * with another macro-end marker to ensure the process - * continues) until the whole expansion is forcibly removed - * from istk->expansion by a %exitrep. - */ - l = nasm_malloc(sizeof(Line)); - l->next = istk->expansion; - l->finishes = defining; - l->first = NULL; - istk->expansion = l; - - istk->mstk = defining; - - list->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); - tmp_defining = defining; - defining = defining->rep_nest; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_EXITREP: - /* - * We must search along istk->expansion until we hit a - * macro-end marker for a macro with no name. Then we set - * its `in_progress' flag to 0. - */ - for (l = istk->expansion; l; l = l->next) - if (l->finishes && !l->finishes->name) - break; - - if (l) - l->finishes->in_progress = 0; - else - error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block"); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_XDEFINE: - case PP_IXDEFINE: - case PP_DEFINE: - case PP_IDEFINE: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%%%s%sdefine' expects a macro identifier", - ((i == PP_IDEFINE || i == PP_IXDEFINE) ? "i" : ""), - ((i == PP_XDEFINE || i == PP_IXDEFINE) ? "x" : "")); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - mname = tline->text; - last = tline; - param_start = tline = tline->next; - nparam = 0; - - /* Expand the macro definition now for %xdefine and %ixdefine */ - if ((i == PP_XDEFINE) || (i == PP_IXDEFINE)) - tline = expand_smacro(tline); - - if (tok_is_(tline, "(")) - { - /* - * This macro has parameters. - */ - - tline = tline->next; - while (1) - { - skip_white_(tline); - if (!tline) - { - error(ERR_NONFATAL, "parameter identifier expected"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - if (tline->type != TOK_ID) - { - error(ERR_NONFATAL, - "`%s': parameter identifier expected", - tline->text); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - tline->type = TOK_SMAC_PARAM + nparam++; - tline = tline->next; - skip_white_(tline); - if (tok_is_(tline, ",")) - { - tline = tline->next; - continue; - } - if (!tok_is_(tline, ")")) - { - error(ERR_NONFATAL, - "`)' expected to terminate macro template"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - break; - } - last = tline; - tline = tline->next; - } - if (tok_type_(tline, TOK_WHITESPACE)) - last = tline, tline = tline->next; - macro_start = NULL; - last->next = NULL; - t = tline; - while (t) - { - if (t->type == TOK_ID) - { - for (tt = param_start; tt; tt = tt->next) - if (tt->type >= TOK_SMAC_PARAM && - !strcmp(tt->text, t->text)) - t->type = tt->type; - } - tt = t->next; - t->next = macro_start; - macro_start = t; - t = tt; - } - /* - * Good. We now have a macro name, a parameter count, and a - * token list (in reverse order) for an expansion. We ought - * to be OK just to create an SMacro, store it, and let - * free_tlist have the rest of the line (which we have - * carefully re-terminated after chopping off the expansion - * from the end). - */ - if (smacro_defined(ctx, mname, nparam, &smac, i == PP_DEFINE)) - { - if (!smac) - { - error(ERR_WARNING, - "single-line macro `%s' defined both with and" - " without parameters", mname); - free_tlist(origline); - free_tlist(macro_start); - return DIRECTIVE_FOUND; - } - else - { - /* - * We're redefining, so we have to take over an - * existing SMacro structure. This means freeing - * what was already in it. - */ - nasm_free(smac->name); - free_tlist(smac->expansion); - } - } - else - { - smac = nasm_malloc(sizeof(SMacro)); - smac->next = *smhead; - *smhead = smac; - } - smac->name = nasm_strdup(mname); - smac->casesense = ((i == PP_DEFINE) || (i == PP_XDEFINE)); - smac->nparam = nparam; - smac->expansion = macro_start; - smac->in_progress = FALSE; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_UNDEF: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, "`%%undef' expects a macro identifier"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - if (tline->next) - { - error(ERR_WARNING, - "trailing garbage after macro name ignored"); - } - - /* Find the context that symbol belongs to */ - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - - mname = tline->text; - last = tline; - last->next = NULL; - - /* - * We now have a macro name... go hunt for it. - */ - while (smacro_defined(ctx, mname, -1, &smac, 1)) - { - /* Defined, so we need to find its predecessor and nuke it */ - SMacro **s; - for (s = smhead; *s && *s != smac; s = &(*s)->next); - if (*s) - { - *s = smac->next; - nasm_free(smac->name); - free_tlist(smac->expansion); - nasm_free(smac); - } - } - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_STRLEN: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%%strlen' expects a macro identifier as first parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - mname = tline->text; - last = tline; - tline = expand_smacro(tline->next); - last->next = NULL; - - t = tline; - while (tok_type_(t, TOK_WHITESPACE)) - t = t->next; - /* t should now point to the string */ - if (t->type != TOK_STRING) - { - error(ERR_NONFATAL, - "`%%strlen` requires string as second parameter"); - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - macro_start = nasm_malloc(sizeof(*macro_start)); - macro_start->next = NULL; - make_tok_num(macro_start, strlen(t->text) - 2); - macro_start->mac = NULL; - - /* - * We now have a macro name, an implicit parameter count of - * zero, and a numeric token to use as an expansion. Create - * and store an SMacro. - */ - if (smacro_defined(ctx, mname, 0, &smac, i == PP_STRLEN)) - { - if (!smac) - error(ERR_WARNING, - "single-line macro `%s' defined both with and" - " without parameters", mname); - else - { - /* - * We're redefining, so we have to take over an - * existing SMacro structure. This means freeing - * what was already in it. - */ - nasm_free(smac->name); - free_tlist(smac->expansion); - } - } - else - { - smac = nasm_malloc(sizeof(SMacro)); - smac->next = *smhead; - *smhead = smac; - } - smac->name = nasm_strdup(mname); - smac->casesense = (i == PP_STRLEN); - smac->nparam = 0; - smac->expansion = macro_start; - smac->in_progress = FALSE; - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_SUBSTR: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%%substr' expects a macro identifier as first parameter"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - mname = tline->text; - last = tline; - tline = expand_smacro(tline->next); - last->next = NULL; - - t = tline->next; - while (tok_type_(t, TOK_WHITESPACE)) - t = t->next; - - /* t should now point to the string */ - if (t->type != TOK_STRING) - { - error(ERR_NONFATAL, - "`%%substr` requires string as second parameter"); - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - tt = t->next; - tptr = &tt; - tokval.t_type = TOKEN_INVALID; - evalresult = - evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); - if (!evalresult) - { - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - if (!is_simple(evalresult)) - { - error(ERR_NONFATAL, "non-constant value given to `%%substr`"); - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - macro_start = nasm_malloc(sizeof(*macro_start)); - macro_start->next = NULL; - macro_start->text = nasm_strdup("'''"); - if (evalresult->value > 0 - && evalresult->value < strlen(t->text) - 1) - { - macro_start->text[1] = t->text[evalresult->value]; - } - else - { - macro_start->text[2] = '\0'; - } - macro_start->type = TOK_STRING; - macro_start->mac = NULL; - - /* - * We now have a macro name, an implicit parameter count of - * zero, and a numeric token to use as an expansion. Create - * and store an SMacro. - */ - if (smacro_defined(ctx, mname, 0, &smac, i == PP_SUBSTR)) - { - if (!smac) - error(ERR_WARNING, - "single-line macro `%s' defined both with and" - " without parameters", mname); - else - { - /* - * We're redefining, so we have to take over an - * existing SMacro structure. This means freeing - * what was already in it. - */ - nasm_free(smac->name); - free_tlist(smac->expansion); - } - } - else - { - smac = nasm_malloc(sizeof(SMacro)); - smac->next = *smhead; - *smhead = smac; - } - smac->name = nasm_strdup(mname); - smac->casesense = (i == PP_SUBSTR); - smac->nparam = 0; - smac->expansion = macro_start; - smac->in_progress = FALSE; - free_tlist(tline); - free_tlist(origline); - return DIRECTIVE_FOUND; - - - case PP_ASSIGN: - case PP_IASSIGN: - tline = tline->next; - skip_white_(tline); - tline = expand_id(tline); - if (!tline || (tline->type != TOK_ID && - (tline->type != TOK_PREPROC_ID || - tline->text[1] != '$'))) - { - error(ERR_NONFATAL, - "`%%%sassign' expects a macro identifier", - (i == PP_IASSIGN ? "i" : "")); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - ctx = get_ctx(tline->text, FALSE); - if (!ctx) - smhead = &smacros[hash(tline->text)]; - else - smhead = &ctx->localmac; - mname = tline->text; - last = tline; - tline = expand_smacro(tline->next); - last->next = NULL; - - t = tline; - tptr = &t; - tokval.t_type = TOKEN_INVALID; - evalresult = - evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); - free_tlist(tline); - if (!evalresult) - { - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - if (tokval.t_type) - error(ERR_WARNING, - "trailing garbage after expression ignored"); - - if (!is_simple(evalresult)) - { - error(ERR_NONFATAL, - "non-constant value given to `%%%sassign'", - (i == PP_IASSIGN ? "i" : "")); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - - macro_start = nasm_malloc(sizeof(*macro_start)); - macro_start->next = NULL; - make_tok_num(macro_start, reloc_value(evalresult)); - macro_start->mac = NULL; - - /* - * We now have a macro name, an implicit parameter count of - * zero, and a numeric token to use as an expansion. Create - * and store an SMacro. - */ - if (smacro_defined(ctx, mname, 0, &smac, i == PP_ASSIGN)) - { - if (!smac) - error(ERR_WARNING, - "single-line macro `%s' defined both with and" - " without parameters", mname); - else - { - /* - * We're redefining, so we have to take over an - * existing SMacro structure. This means freeing - * what was already in it. - */ - nasm_free(smac->name); - free_tlist(smac->expansion); - } - } - else - { - smac = nasm_malloc(sizeof(SMacro)); - smac->next = *smhead; - *smhead = smac; - } - smac->name = nasm_strdup(mname); - smac->casesense = (i == PP_ASSIGN); - smac->nparam = 0; - smac->expansion = macro_start; - smac->in_progress = FALSE; - free_tlist(origline); - return DIRECTIVE_FOUND; - - case PP_LINE: - /* - * Syntax is `%line nnn[+mmm] [filename]' - */ - tline = tline->next; - skip_white_(tline); - if (!tok_type_(tline, TOK_NUMBER)) - { - error(ERR_NONFATAL, "`%%line' expects line number"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - k = readnum(tline->text, &j); - m = 1; - tline = tline->next; - if (tok_is_(tline, "+")) - { - tline = tline->next; - if (!tok_type_(tline, TOK_NUMBER)) - { - error(ERR_NONFATAL, "`%%line' expects line increment"); - free_tlist(origline); - return DIRECTIVE_FOUND; - } - m = readnum(tline->text, &j); - tline = tline->next; - } - skip_white_(tline); - src_set_linnum(k); - istk->lineinc = m; - if (tline) - { - nasm_free(src_set_fname(detoken(tline, FALSE))); - } - free_tlist(origline); - return DIRECTIVE_FOUND; - - default: - error(ERR_FATAL, - "preprocessor directive `%s' not yet implemented", - directives[i]); - break; - } - return DIRECTIVE_FOUND; -} - -/* - * Ensure that a macro parameter contains a condition code and - * nothing else. Return the condition code index if so, or -1 - * otherwise. - */ -static int -find_cc(Token * t) -{ - Token *tt; - int i, j, k, m; - - skip_white_(t); - if (t->type != TOK_ID) - return -1; - tt = t->next; - skip_white_(tt); - if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ","))) - return -1; - - i = -1; - j = elements(conditions); - while (j - i > 1) - { - k = (j + i) / 2; - m = nasm_stricmp(t->text, conditions[k]); - if (m == 0) - { - i = k; - j = -2; - break; - } - else if (m < 0) - { - j = k; - } - else - i = k; - } - if (j != -2) - return -1; - return i; -} - -/* - * Expand MMacro-local things: parameter references (%0, %n, %+n, - * %-n) and MMacro-local identifiers (%%foo). - */ -static Token * -expand_mmac_params(Token * tline) -{ - Token *t, *tt, **tail, *thead; - - tail = &thead; - thead = NULL; - - while (tline) - { - if (tline->type == TOK_PREPROC_ID && - (((tline->text[1] == '+' || tline->text[1] == '-') - && tline->text[2]) || tline->text[1] == '%' - || (tline->text[1] >= '0' && tline->text[1] <= '9'))) - { - char *text = NULL; - int type = 0, cc; /* type = 0 to placate optimisers */ - char tmpbuf[30]; - int n, i; - MMacro *mac; - - t = tline; - tline = tline->next; - - mac = istk->mstk; - while (mac && !mac->name) /* avoid mistaking %reps for macros */ - mac = mac->next_active; - if (!mac) - error(ERR_NONFATAL, "`%s': not in a macro call", t->text); - else - switch (t->text[1]) - { - /* - * We have to make a substitution of one of the - * forms %1, %-1, %+1, %%foo, %0. - */ - case '0': - type = TOK_NUMBER; - snprintf(tmpbuf, sizeof(tmpbuf), "%d", mac->nparam); - text = nasm_strdup(tmpbuf); - break; - case '%': - type = TOK_ID; - snprintf(tmpbuf, sizeof(tmpbuf), "..@%lu.", mac->unique); - text = nasm_strcat(tmpbuf, t->text + 2); - break; - case '-': - n = atoi(t->text + 2) - 1; - if (n >= mac->nparam) - tt = NULL; - else - { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; - } - cc = find_cc(tt); - if (cc == -1) - { - error(ERR_NONFATAL, - "macro parameter %d is not a condition code", - n + 1); - text = NULL; - } - else - { - type = TOK_ID; - if (inverse_ccs[cc] == -1) - { - error(ERR_NONFATAL, - "condition code `%s' is not invertible", - conditions[cc]); - text = NULL; - } - else - text = - nasm_strdup(conditions[inverse_ccs - [cc]]); - } - break; - case '+': - n = atoi(t->text + 2) - 1; - if (n >= mac->nparam) - tt = NULL; - else - { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; - } - cc = find_cc(tt); - if (cc == -1) - { - error(ERR_NONFATAL, - "macro parameter %d is not a condition code", - n + 1); - text = NULL; - } - else - { - type = TOK_ID; - text = nasm_strdup(conditions[cc]); - } - break; - default: - n = atoi(t->text + 1) - 1; - if (n >= mac->nparam) - tt = NULL; - else - { - if (mac->nparam > 1) - n = (n + mac->rotate) % mac->nparam; - tt = mac->params[n]; - } - if (tt) - { - for (i = 0; i < mac->paramlen[n]; i++) - { - *tail = - new_Token(NULL, tt->type, tt->text, - 0); - tail = &(*tail)->next; - tt = tt->next; - } - } - text = NULL; /* we've done it here */ - break; - } - if (!text) - { - delete_Token(t); - } - else - { - *tail = t; - tail = &t->next; - t->type = type; - nasm_free(t->text); - t->text = text; - t->mac = NULL; - } - continue; - } - else - { - t = *tail = tline; - tline = tline->next; - t->mac = NULL; - tail = &t->next; - } - } - *tail = NULL; - t = thead; - for (; t && (tt = t->next) != NULL; t = t->next) - switch (t->type) - { - case TOK_WHITESPACE: - if (tt->type == TOK_WHITESPACE) - { - t->next = delete_Token(tt); - } - break; - case TOK_ID: - if (tt->type == TOK_ID || tt->type == TOK_NUMBER) - { - char *tmp = nasm_strcat(t->text, tt->text); - nasm_free(t->text); - t->text = tmp; - t->next = delete_Token(tt); - } - break; - case TOK_NUMBER: - if (tt->type == TOK_NUMBER) - { - char *tmp = nasm_strcat(t->text, tt->text); - nasm_free(t->text); - t->text = tmp; - t->next = delete_Token(tt); - } - break; - } - - return thead; -} - -/* - * Expand all single-line macro calls made in the given line. - * Return the expanded version of the line. The original is deemed - * to be destroyed in the process. (In reality we'll just move - * Tokens from input to output a lot of the time, rather than - * actually bothering to destroy and replicate.) - */ -static Token * -expand_smacro(Token * tline) -{ - Token *t, *tt, *mstart, **tail, *thead; - SMacro *head = NULL, *m; - Token **params; - int *paramsize; - int nparam, sparam, brackets, rescan; - Token *org_tline = tline; - Context *ctx; - char *mname; - - /* - * Trick: we should avoid changing the start token pointer since it can - * be contained in "next" field of other token. Because of this - * we allocate a copy of first token and work with it; at the end of - * routine we copy it back - */ - if (org_tline) - { - tline = - new_Token(org_tline->next, org_tline->type, org_tline->text, - 0); - tline->mac = org_tline->mac; - nasm_free(org_tline->text); - org_tline->text = NULL; - } - - again: - tail = &thead; - thead = NULL; - - while (tline) - { /* main token loop */ - if ((mname = tline->text)) - { - /* if this token is a local macro, look in local context */ - if (tline->type == TOK_ID || tline->type == TOK_PREPROC_ID) - ctx = get_ctx(mname, TRUE); - else - ctx = NULL; - if (!ctx) - head = smacros[hash(mname)]; - else - head = ctx->localmac; - /* - * We've hit an identifier. As in is_mmacro below, we first - * check whether the identifier is a single-line macro at - * all, then think about checking for parameters if - * necessary. - */ - for (m = head; m; m = m->next) - if (!mstrcmp(m->name, mname, m->casesense)) - break; - if (m) - { - mstart = tline; - params = NULL; - paramsize = NULL; - if (m->nparam == 0) - { - /* - * Simple case: the macro is parameterless. Discard the - * one token that the macro call took, and push the - * expansion back on the to-do stack. - */ - if (!m->expansion) - { - if (!strcmp("__FILE__", m->name)) - { - long num = 0; - src_get(&num, &(tline->text)); - nasm_quote(&(tline->text)); - tline->type = TOK_STRING; - continue; - } - if (!strcmp("__LINE__", m->name)) - { - nasm_free(tline->text); - make_tok_num(tline, src_get_linnum()); - continue; - } - tline = delete_Token(tline); - continue; - } - } - else - { - /* - * Complicated case: at least one macro with this name - * exists and takes parameters. We must find the - * parameters in the call, count them, find the SMacro - * that corresponds to that form of the macro call, and - * substitute for the parameters when we expand. What a - * pain. - */ - /*tline = tline->next; - skip_white_(tline);*/ - do { - t = tline->next; - while (tok_type_(t, TOK_SMAC_END)) - { - t->mac->in_progress = FALSE; - t->text = NULL; - t = tline->next = delete_Token(t); - } - tline = t; - } while (tok_type_(tline, TOK_WHITESPACE)); - if (!tok_is_(tline, "(")) - { - /* - * This macro wasn't called with parameters: ignore - * the call. (Behaviour borrowed from gnu cpp.) - */ - tline = mstart; - m = NULL; - } - else - { - int paren = 0; - int white = 0; - brackets = 0; - nparam = 0; - sparam = PARAM_DELTA; - params = nasm_malloc(sparam * sizeof(Token *)); - params[0] = tline->next; - paramsize = nasm_malloc(sparam * sizeof(int)); - paramsize[0] = 0; - while (TRUE) - { /* parameter loop */ - /* - * For some unusual expansions - * which concatenates function call - */ - t = tline->next; - while (tok_type_(t, TOK_SMAC_END)) - { - t->mac->in_progress = FALSE; - t->text = NULL; - t = tline->next = delete_Token(t); - } - tline = t; - - if (!tline) - { - error(ERR_NONFATAL, - "macro call expects terminating `)'"); - break; - } - if (tline->type == TOK_WHITESPACE - && brackets <= 0) - { - if (paramsize[nparam]) - white++; - else - params[nparam] = tline->next; - continue; /* parameter loop */ - } - if (tline->type == TOK_OTHER - && tline->text[1] == 0) - { - char ch = tline->text[0]; - if (ch == ',' && !paren && brackets <= 0) - { - if (++nparam >= sparam) - { - sparam += PARAM_DELTA; - params = nasm_realloc(params, - sparam * sizeof(Token *)); - paramsize = nasm_realloc(paramsize, - sparam * sizeof(int)); - } - params[nparam] = tline->next; - paramsize[nparam] = 0; - white = 0; - continue; /* parameter loop */ - } - if (ch == '{' && - (brackets > 0 || (brackets == 0 && - !paramsize[nparam]))) - { - if (!(brackets++)) - { - params[nparam] = tline->next; - continue; /* parameter loop */ - } - } - if (ch == '}' && brackets > 0) - if (--brackets == 0) - { - brackets = -1; - continue; /* parameter loop */ - } - if (ch == '(' && !brackets) - paren++; - if (ch == ')' && brackets <= 0) - if (--paren < 0) - break; - } - if (brackets < 0) - { - brackets = 0; - error(ERR_NONFATAL, "braces do not " - "enclose all of macro parameter"); - } - paramsize[nparam] += white + 1; - white = 0; - } /* parameter loop */ - nparam++; - while (m && (m->nparam != nparam || - mstrcmp(m->name, mname, - m->casesense))) - m = m->next; - if (!m) - error(ERR_WARNING | ERR_WARN_MNP, - "macro `%s' exists, " - "but not taking %d parameters", - mstart->text, nparam); - } - } - if (m && m->in_progress) - m = NULL; - if (!m) /* in progess or didn't find '(' or wrong nparam */ - { - /* - * Design question: should we handle !tline, which - * indicates missing ')' here, or expand those - * macros anyway, which requires the (t) test a few - * lines down? - */ - nasm_free(params); - nasm_free(paramsize); - tline = mstart; - } - else - { - /* - * Expand the macro: we are placed on the last token of the - * call, so that we can easily split the call from the - * following tokens. We also start by pushing an SMAC_END - * token for the cycle removal. - */ - t = tline; - if (t) - { - tline = t->next; - t->next = NULL; - } - tt = new_Token(tline, TOK_SMAC_END, NULL, 0); - tt->mac = m; - m->in_progress = TRUE; - tline = tt; - for (t = m->expansion; t; t = t->next) - { - if (t->type >= TOK_SMAC_PARAM) - { - Token *pcopy = tline, **ptail = &pcopy; - Token *ttt, *pt; - int i; - - ttt = params[t->type - TOK_SMAC_PARAM]; - for (i = paramsize[t->type - TOK_SMAC_PARAM]; - --i >= 0;) - { - pt = *ptail = - new_Token(tline, ttt->type, ttt->text, - 0); - ptail = &pt->next; - ttt = ttt->next; - } - tline = pcopy; - } - else - { - tt = new_Token(tline, t->type, t->text, 0); - tline = tt; - } - } - - /* - * Having done that, get rid of the macro call, and clean - * up the parameters. - */ - nasm_free(params); - nasm_free(paramsize); - free_tlist(mstart); - continue; /* main token loop */ - } - } - } - - if (tline->type == TOK_SMAC_END) - { - tline->mac->in_progress = FALSE; - tline = delete_Token(tline); - } - else - { - t = *tail = tline; - tline = tline->next; - t->mac = NULL; - t->next = NULL; - tail = &t->next; - } - } - - /* - * Now scan the entire line and look for successive TOK_IDs that resulted - * after expansion (they can't be produced by tokenise()). The successive - * TOK_IDs should be concatenated. - * Also we look for %+ tokens and concatenate the tokens before and after - * them (without white spaces in between). - */ - t = thead; - rescan = 0; - while (t) - { - while (t && t->type != TOK_ID && t->type != TOK_PREPROC_ID) - t = t->next; - if (!t || !t->next) - break; - if (t->next->type == TOK_ID || - t->next->type == TOK_PREPROC_ID || - t->next->type == TOK_NUMBER) - { - char *p = nasm_strcat(t->text, t->next->text); - nasm_free(t->text); - t->next = delete_Token(t->next); - t->text = p; - rescan = 1; - } - else if (t->next->type == TOK_WHITESPACE && t->next->next && - t->next->next->type == TOK_PREPROC_ID && - strcmp(t->next->next->text, "%+") == 0) - { - /* free the next whitespace, the %+ token and next whitespace */ - int i; - for (i = 1; i <= 3; i++) - { - if (!t->next || (i != 2 && t->next->type != TOK_WHITESPACE)) - break; - t->next = delete_Token(t->next); - } /* endfor */ - } - else - t = t->next; - } - /* If we concatenaded something, re-scan the line for macros */ - if (rescan) - { - tline = thead; - goto again; - } - - if (org_tline) - { - if (thead) - { - *org_tline = *thead; - /* since we just gave text to org_line, don't free it */ - thead->text = NULL; - delete_Token(thead); - } - else - { - /* the expression expanded to empty line; - we can't return NULL for some reasons - we just set the line to a single WHITESPACE token. */ - memset(org_tline, 0, sizeof(*org_tline)); - org_tline->text = NULL; - org_tline->type = TOK_WHITESPACE; - } - thead = org_tline; - } - - return thead; -} - -/* - * Similar to expand_smacro but used exclusively with macro identifiers - * right before they are fetched in. The reason is that there can be - * identifiers consisting of several subparts. We consider that if there - * are more than one element forming the name, user wants a expansion, - * otherwise it will be left as-is. Example: - * - * %define %$abc cde - * - * the identifier %$abc will be left as-is so that the handler for %define - * will suck it and define the corresponding value. Other case: - * - * %define _%$abc cde - * - * In this case user wants name to be expanded *before* %define starts - * working, so we'll expand %$abc into something (if it has a value; - * otherwise it will be left as-is) then concatenate all successive - * PP_IDs into one. - */ -static Token * -expand_id(Token * tline) -{ - Token *cur, *oldnext = NULL; - - if (!tline || !tline->next) - return tline; - - cur = tline; - while (cur->next && - (cur->next->type == TOK_ID || - cur->next->type == TOK_PREPROC_ID || cur->next->type == TOK_NUMBER)) - cur = cur->next; - - /* If identifier consists of just one token, don't expand */ - if (cur == tline) - return tline; - - if (cur) - { - oldnext = cur->next; /* Detach the tail past identifier */ - cur->next = NULL; /* so that expand_smacro stops here */ - } - - tline = expand_smacro(tline); - - if (cur) - { - /* expand_smacro possibly changhed tline; re-scan for EOL */ - cur = tline; - while (cur && cur->next) - cur = cur->next; - if (cur) - cur->next = oldnext; - } - - return tline; -} - -/* - * Determine whether the given line constitutes a multi-line macro - * call, and return the MMacro structure called if so. Doesn't have - * to check for an initial label - that's taken care of in - * expand_mmacro - but must check numbers of parameters. Guaranteed - * to be called with tline->type == TOK_ID, so the putative macro - * name is easy to find. - */ -static MMacro * -is_mmacro(Token * tline, Token *** params_array) -{ - MMacro *head, *m; - Token **params; - int nparam; - - head = mmacros[hash(tline->text)]; - - /* - * Efficiency: first we see if any macro exists with the given - * name. If not, we can return NULL immediately. _Then_ we - * count the parameters, and then we look further along the - * list if necessary to find the proper MMacro. - */ - for (m = head; m; m = m->next) - if (!mstrcmp(m->name, tline->text, m->casesense)) - break; - if (!m) - return NULL; - - /* - * OK, we have a potential macro. Count and demarcate the - * parameters. - */ - count_mmac_params(tline->next, &nparam, ¶ms); - - /* - * So we know how many parameters we've got. Find the MMacro - * structure that handles this number. - */ - while (m) - { - if (m->nparam_min <= nparam && (m->plus || nparam <= m->nparam_max)) - { - /* - * This one is right. Just check if cycle removal - * prohibits us using it before we actually celebrate... - */ - if (m->in_progress) - { -#if 0 - error(ERR_NONFATAL, - "self-reference in multi-line macro `%s'", m->name); -#endif - nasm_free(params); - return NULL; - } - /* - * It's right, and we can use it. Add its default - * parameters to the end of our list if necessary. - */ - if (m->defaults && nparam < m->nparam_min + m->ndefs) - { - params = - nasm_realloc(params, - ((m->nparam_min + m->ndefs + 1) * sizeof(*params))); - while (nparam < m->nparam_min + m->ndefs) - { - params[nparam] = m->defaults[nparam - m->nparam_min]; - nparam++; - } - } - /* - * If we've gone over the maximum parameter count (and - * we're in Plus mode), ignore parameters beyond - * nparam_max. - */ - if (m->plus && nparam > m->nparam_max) - nparam = m->nparam_max; - /* - * Then terminate the parameter list, and leave. - */ - if (!params) - { /* need this special case */ - params = nasm_malloc(sizeof(*params)); - nparam = 0; - } - params[nparam] = NULL; - *params_array = params; - return m; - } - /* - * This one wasn't right: look for the next one with the - * same name. - */ - for (m = m->next; m; m = m->next) - if (!mstrcmp(m->name, tline->text, m->casesense)) - break; - } - - /* - * After all that, we didn't find one with the right number of - * parameters. Issue a warning, and fail to expand the macro. - */ - error(ERR_WARNING | ERR_WARN_MNP, - "macro `%s' exists, but not taking %d parameters", - tline->text, nparam); - nasm_free(params); - return NULL; -} - -/* - * Expand the multi-line macro call made by the given line, if - * there is one to be expanded. If there is, push the expansion on - * istk->expansion and return 1. Otherwise return 0. - */ -static int -expand_mmacro(Token * tline) -{ - Token *startline = tline; - Token *label = NULL; - int dont_prepend = 0; - Token **params, *t, *tt; - MMacro *m; - Line *l, *ll; - int i, nparam, *paramlen; - - t = tline; - skip_white_(t); -/* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */ - if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID)) - return 0; - m = is_mmacro(t, ¶ms); - if (!m) - { - Token *last; - /* - * We have an id which isn't a macro call. We'll assume - * it might be a label; we'll also check to see if a - * colon follows it. Then, if there's another id after - * that lot, we'll check it again for macro-hood. - */ - label = last = t; - t = t->next; - if (tok_type_(t, TOK_WHITESPACE)) - last = t, t = t->next; - if (tok_is_(t, ":")) - { - dont_prepend = 1; - last = t, t = t->next; - if (tok_type_(t, TOK_WHITESPACE)) - last = t, t = t->next; - } - if (!tok_type_(t, TOK_ID) || (m = is_mmacro(t, ¶ms)) == NULL) - return 0; - last->next = NULL; - tline = t; - } - - /* - * Fix up the parameters: this involves stripping leading and - * trailing whitespace, then stripping braces if they are - * present. - */ - for (nparam = 0; params[nparam]; nparam++) - ; - paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL; - - for (i = 0; params[i]; i++) - { - int brace = FALSE; - int comma = (!m->plus || i < nparam - 1); - - t = params[i]; - skip_white_(t); - if (tok_is_(t, "{")) - t = t->next, brace = TRUE, comma = FALSE; - params[i] = t; - paramlen[i] = 0; - while (t) - { - if (comma && t->type == TOK_OTHER && !strcmp(t->text, ",")) - break; /* ... because we have hit a comma */ - if (comma && t->type == TOK_WHITESPACE && tok_is_(t->next, ",")) - break; /* ... or a space then a comma */ - if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}")) - break; /* ... or a brace */ - t = t->next; - paramlen[i]++; - } - } - - /* - * OK, we have a MMacro structure together with a set of - * parameters. We must now go through the expansion and push - * copies of each Line on to istk->expansion. Substitution of - * parameter tokens and macro-local tokens doesn't get done - * until the single-line macro substitution process; this is - * because delaying them allows us to change the semantics - * later through %rotate. - * - * First, push an end marker on to istk->expansion, mark this - * macro as in progress, and set up its invocation-specific - * variables. - */ - ll = nasm_malloc(sizeof(Line)); - ll->next = istk->expansion; - ll->finishes = m; - ll->first = NULL; - istk->expansion = ll; - - m->in_progress = TRUE; - m->params = params; - m->iline = tline; - m->nparam = nparam; - m->rotate = 0; - m->paramlen = paramlen; - m->unique = unique++; - m->lineno = 0; - - m->next_active = istk->mstk; - istk->mstk = m; - - for (l = m->expansion; l; l = l->next) - { - Token **tail; - - ll = nasm_malloc(sizeof(Line)); - ll->finishes = NULL; - ll->next = istk->expansion; - istk->expansion = ll; - tail = &ll->first; - - for (t = l->first; t; t = t->next) - { - Token *x = t; - if (t->type == TOK_PREPROC_ID && - t->text[1] == '0' && t->text[2] == '0') - { - dont_prepend = -1; - x = label; - if (!x) - continue; - } - tt = *tail = new_Token(NULL, x->type, x->text, 0); - tail = &tt->next; - } - *tail = NULL; - } - - /* - * If we had a label, push it on as the first line of - * the macro expansion. - */ - if (label) - { - if (dont_prepend < 0) - free_tlist(startline); - else - { - ll = nasm_malloc(sizeof(Line)); - ll->finishes = NULL; - ll->next = istk->expansion; - istk->expansion = ll; - ll->first = startline; - if (!dont_prepend) - { - while (label->next) - label = label->next; - label->next = tt = new_Token(NULL, TOK_OTHER, ":", 0); - } - } - } - - list->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); - - return 1; -} - -/* - * Since preprocessor always operate only on the line that didn't - * arrived yet, we should always use ERR_OFFBY1. Also since user - * won't want to see same error twice (preprocessing is done once - * per pass) we will want to show errors only during pass one. - */ -static void -error(int severity, const char *fmt, ...) -{ - va_list arg; - char buff[1024]; - - /* If we're in a dead branch of IF or something like it, ignore the error */ - if (istk && istk->conds && !emitting(istk->conds->state)) - return; - - va_start(arg, fmt); - vsnprintf(buff, sizeof(buff), fmt, arg); - va_end(arg); - - if (istk && istk->mstk && istk->mstk->name) - _error(severity | ERR_PASS1, "(%s:%d) %s", istk->mstk->name, - istk->mstk->lineno, buff); - else - _error(severity | ERR_PASS1, "%s", buff); -} - -static void -pp_reset(char *file, int apass, efunc errfunc, evalfunc eval, - ListGen * listgen) -{ - int h; - - _error = errfunc; - cstk = NULL; - istk = nasm_malloc(sizeof(Include)); - istk->next = NULL; - istk->conds = NULL; - istk->expansion = NULL; - istk->mstk = NULL; - istk->fp = fopen(file, "r"); - istk->fname = NULL; - src_set_fname(nasm_strdup(file)); - src_set_linnum(0); - istk->lineinc = 1; - if (!istk->fp) - error(ERR_FATAL | ERR_NOFILE, "unable to open input file `%s'", file); - defining = NULL; - for (h = 0; h < NHASH; h++) - { - mmacros[h] = NULL; - smacros[h] = NULL; - } - unique = 0; - if (tasm_compatible_mode) { - stdmacpos = stdmac; - } else { - stdmacpos = &stdmac[TASM_MACRO_COUNT]; - } - any_extrastdmac = (extrastdmac != NULL); - list = listgen; - evaluate = eval; - pass = apass; -} - -static char * -pp_getline(void) -{ - char *line; - Token *tline; - - while (1) - { - /* - * Fetch a tokenised line, either from the macro-expansion - * buffer or from the input file. - */ - tline = NULL; - while (istk->expansion && istk->expansion->finishes) - { - Line *l = istk->expansion; - if (!l->finishes->name && l->finishes->in_progress > 1) - { - Line *ll; - - /* - * This is a macro-end marker for a macro with no - * name, which means it's not really a macro at all - * but a %rep block, and the `in_progress' field is - * more than 1, meaning that we still need to - * repeat. (1 means the natural last repetition; 0 - * means termination by %exitrep.) We have - * therefore expanded up to the %endrep, and must - * push the whole block on to the expansion buffer - * again. We don't bother to remove the macro-end - * marker: we'd only have to generate another one - * if we did. - */ - l->finishes->in_progress--; - for (l = l->finishes->expansion; l; l = l->next) - { - Token *t, *tt, **tail; - - ll = nasm_malloc(sizeof(Line)); - ll->next = istk->expansion; - ll->finishes = NULL; - ll->first = NULL; - tail = &ll->first; - - for (t = l->first; t; t = t->next) - { - if (t->text || t->type == TOK_WHITESPACE) - { - tt = *tail = new_Token(NULL, t->type, t->text, 0); - tail = &tt->next; - } - } - - istk->expansion = ll; - } - } - else - { - /* - * Check whether a `%rep' was started and not ended - * within this macro expansion. This can happen and - * should be detected. It's a fatal error because - * I'm too confused to work out how to recover - * sensibly from it. - */ - if (defining) - { - if (defining->name) - error(ERR_PANIC, "defining with name in expansion"); - else if (istk->mstk->name) - error(ERR_FATAL, "`%%rep' without `%%endrep' within" - " expansion of macro `%s'", istk->mstk->name); - } - - /* - * FIXME: investigate the relationship at this point between - * istk->mstk and l->finishes - */ - { - MMacro *m = istk->mstk; - istk->mstk = m->next_active; - if (m->name) - { - /* - * This was a real macro call, not a %rep, and - * therefore the parameter information needs to - * be freed. - */ - nasm_free(m->params); - free_tlist(m->iline); - nasm_free(m->paramlen); - l->finishes->in_progress = FALSE; - } - else - free_mmacro(m); - } - istk->expansion = l->next; - nasm_free(l); - list->downlevel(LIST_MACRO); - } - } - while (1) - { /* until we get a line we can use */ - - if (istk->expansion) - { /* from a macro expansion */ - char *p; - Line *l = istk->expansion; - if (istk->mstk) - istk->mstk->lineno++; - tline = l->first; - istk->expansion = l->next; - nasm_free(l); - p = detoken(tline, FALSE); - list->line(LIST_MACRO, p); - nasm_free(p); - break; - } - line = read_line(); - if (line) - { /* from the current input file */ - line = prepreproc(line); - tline = tokenise(line); - nasm_free(line); - break; - } - /* - * The current file has ended; work down the istk - */ - { - Include *i = istk; - fclose(i->fp); - if (i->conds) - error(ERR_FATAL, "expected `%%endif' before end of file"); - /* only set line and file name if there's a next node */ - if (i->next) - { - src_set_linnum(i->lineno); - nasm_free(src_set_fname(i->fname)); - } - istk = i->next; - list->downlevel(LIST_INCLUDE); - nasm_free(i); - if (!istk) - return NULL; - } - } - - /* - * We must expand MMacro parameters and MMacro-local labels - * _before_ we plunge into directive processing, to cope - * with things like `%define something %1' such as STRUC - * uses. Unless we're _defining_ a MMacro, in which case - * those tokens should be left alone to go into the - * definition; and unless we're in a non-emitting - * condition, in which case we don't want to meddle with - * anything. - */ - if (!defining && !(istk->conds && !emitting(istk->conds->state))) - tline = expand_mmac_params(tline); - - /* - * Check the line to see if it's a preprocessor directive. - */ - if (do_directive(tline) == DIRECTIVE_FOUND) - { - continue; - } - else if (defining) - { - /* - * We're defining a multi-line macro. We emit nothing - * at all, and just - * shove the tokenised line on to the macro definition. - */ - Line *l = nasm_malloc(sizeof(Line)); - l->next = defining->expansion; - l->first = tline; - l->finishes = FALSE; - defining->expansion = l; - continue; - } - else if (istk->conds && !emitting(istk->conds->state)) - { - /* - * We're in a non-emitting branch of a condition block. - * Emit nothing at all, not even a blank line: when we - * emerge from the condition we'll give a line-number - * directive so we keep our place correctly. - */ - free_tlist(tline); - continue; - } - else if (istk->mstk && !istk->mstk->in_progress) - { - /* - * We're in a %rep block which has been terminated, so - * we're walking through to the %endrep without - * emitting anything. Emit nothing at all, not even a - * blank line: when we emerge from the %rep block we'll - * give a line-number directive so we keep our place - * correctly. - */ - free_tlist(tline); - continue; - } - else - { - tline = expand_smacro(tline); - if (!expand_mmacro(tline)) - { - /* - * De-tokenise the line again, and emit it. - */ - line = detoken(tline, TRUE); - free_tlist(tline); - break; - } - else - { - continue; /* expand_mmacro calls free_tlist */ - } - } - } - - return line; -} - -static void -pp_cleanup(int pass) -{ - int h; - - if (defining) - { - error(ERR_NONFATAL, "end of file while still defining macro `%s'", - defining->name); - free_mmacro(defining); - } - while (cstk) - ctx_pop(); - for (h = 0; h < NHASH; h++) - { - while (mmacros[h]) - { - MMacro *m = mmacros[h]; - mmacros[h] = mmacros[h]->next; - free_mmacro(m); - } - while (smacros[h]) - { - SMacro *s = smacros[h]; - smacros[h] = smacros[h]->next; - nasm_free(s->name); - free_tlist(s->expansion); - nasm_free(s); - } - } - while (istk) - { - Include *i = istk; - istk = istk->next; - fclose(i->fp); - nasm_free(i->fname); - nasm_free(i); - } - while (cstk) - ctx_pop(); - if (pass == 0) - { - free_llist(predef); - delete_Blocks(); - } -} - -void -pp_include_path(char *path) -{ - IncPath *i; -/* by alexfru: order of path inclusion fixed (was reverse order) */ - i = nasm_malloc(sizeof(IncPath)); - i->path = nasm_strdup(path); - i->next = NULL; - - if (ipath != NULL) - { - IncPath *j = ipath; - while (j->next != NULL) - j = j->next; - j->next = i; - } - else - { - ipath = i; -} -} - -/* - * added by alexfru: - * - * This function is used to "export" the include paths, e.g. - * the paths specified in the '-I' command switch. - * The need for such exporting is due to the 'incbin' directive, - * which includes raw binary files (unlike '%include', which - * includes text source files). It would be real nice to be - * able to specify paths to search for incbin'ned files also. - * So, this is a simple workaround. - * - * The function use is simple: - * - * The 1st call (with NULL argument) returns a pointer to the 1st path - * (char** type) or NULL if none include paths available. - * - * All subsequent calls take as argument the value returned by this - * function last. The return value is either the next path - * (char** type) or NULL if the end of the paths list is reached. - * - * It is maybe not the best way to do things, but I didn't want - * to export too much, just one or two functions and no types or - * variables exported. - * - * Can't say I like the current situation with e.g. this path list either, - * it seems to be never deallocated after creation... - */ -char** -pp_get_include_path_ptr (char **pPrevPath) -{ -/* This macro returns offset of a member of a structure */ -#define GetMemberOffset(StructType,MemberName)\ - ((size_t)&((StructType*)0)->MemberName) - IncPath *i; - - if (pPrevPath == NULL) - { - if(ipath != NULL) - return &ipath->path; - else - return NULL; - } - i = (IncPath*) ((char*)pPrevPath - GetMemberOffset(IncPath,path)); - i = i->next; - if (i != NULL) - return &i->path; - else - return NULL; -#undef GetMemberOffset -} - -void -pp_pre_include(char *fname) -{ - Token *inc, *space, *name; - Line *l; - - name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0); - space = new_Token(name, TOK_WHITESPACE, NULL, 0); - inc = new_Token(space, TOK_PREPROC_ID, "%include", 0); - - l = nasm_malloc(sizeof(Line)); - l->next = predef; - l->first = inc; - l->finishes = FALSE; - predef = l; -} - -void -pp_pre_define(char *definition) -{ - Token *def, *space; - Line *l; - char *equals; - - equals = strchr(definition, '='); - space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); - def = new_Token(space, TOK_PREPROC_ID, "%define", 0); - if (equals) - *equals = ' '; - space->next = tokenise(definition); - if (equals) - *equals = '='; - - l = nasm_malloc(sizeof(Line)); - l->next = predef; - l->first = def; - l->finishes = FALSE; - predef = l; -} - -void -pp_pre_undefine(char *definition) -{ - Token *def, *space; - Line *l; - - space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); - def = new_Token(space, TOK_PREPROC_ID, "%undef", 0); - space->next = tokenise(definition); - - l = nasm_malloc(sizeof(Line)); - l->next = predef; - l->first = def; - l->finishes = FALSE; - predef = l; -} - -void -pp_extra_stdmac(const char **macros) -{ - extrastdmac = macros; -} - -static void -make_tok_num(Token * tok, long val) -{ - char numbuf[20]; - snprintf(numbuf, sizeof(numbuf), "%ld", val); - tok->text = nasm_strdup(numbuf); - tok->type = TOK_NUMBER; -} - -Preproc nasmpp = { - pp_reset, - pp_getline, - pp_cleanup -}; +/* -*- mode: c; c-file-style: "bsd" -*- */ +/* preproc.c macro preprocessor for the Netwide Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 18/iii/97 by Simon Tatham + */ + +/* Typical flow of text through preproc + * + * pp_getline gets tokenised lines, either + * + * from a macro expansion + * + * or + * { + * read_line gets raw text from stdmacpos, or predef, or current input file + * tokenise converts to tokens + * } + * + * expand_mmac_params is used to expand %1 etc., unless a macro is being + * defined or a false conditional is being processed + * (%0, %1, %+1, %-1, %%foo + * + * do_directive checks for directives + * + * expand_smacro is used to expand single line macros + * + * expand_mmacro is used to expand multi-line macros + * + * detoken is used to convert the line back to text + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" + +typedef struct SMacro SMacro; +typedef struct MMacro MMacro; +typedef struct Context Context; +typedef struct Token Token; +typedef struct Blocks Blocks; +typedef struct Line Line; +typedef struct Include Include; +typedef struct Cond Cond; +typedef struct IncPath IncPath; + +/* + * Store the definition of a single-line macro. + */ +struct SMacro { + SMacro *next; + char *name; + int casesense; + int nparam; + int in_progress; + Token *expansion; +}; + +/* + * Store the definition of a multi-line macro. This is also used to + * store the interiors of `%rep...%endrep' blocks, which are + * effectively self-re-invoking multi-line macros which simply + * don't have a name or bother to appear in the hash tables. %rep + * blocks are signified by having a NULL `name' field. + * + * In a MMacro describing a `%rep' block, the `in_progress' field + * isn't merely boolean, but gives the number of repeats left to + * run. + * + * The `next' field is used for storing MMacros in hash tables; the + * `next_active' field is for stacking them on istk entries. + * + * When a MMacro is being expanded, `params', `iline', `nparam', + * `paramlen', `rotate' and `unique' are local to the invocation. + */ +struct MMacro { + MMacro *next; + char *name; + int casesense; + int nparam_min, nparam_max; + int plus; /* is the last parameter greedy? */ + int nolist; /* is this macro listing-inhibited? */ + int in_progress; + Token *dlist; /* All defaults as one list */ + Token **defaults; /* Parameter default pointers */ + int ndefs; /* number of default parameters */ + Line *expansion; + + MMacro *next_active; + MMacro *rep_nest; /* used for nesting %rep */ + Token **params; /* actual parameters */ + Token *iline; /* invocation line */ + int nparam, rotate, *paramlen; + unsigned long unique; + int lineno; /* Current line number on expansion */ +}; + +/* + * The context stack is composed of a linked list of these. + */ +struct Context { + Context *next; + SMacro *localmac; + char *name; + unsigned long number; +}; + +/* + * This is the internal form which we break input lines up into. + * Typically stored in linked lists. + * + * Note that `type' serves a double meaning: TOK_SMAC_PARAM is not + * necessarily used as-is, but is intended to denote the number of + * the substituted parameter. So in the definition + * + * %define a(x,y) ( (x) & ~(y) ) + * + * the token representing `x' will have its type changed to + * TOK_SMAC_PARAM, but the one representing `y' will be + * TOK_SMAC_PARAM+1. + * + * TOK_INTERNAL_STRING is a dirty hack: it's a single string token + * which doesn't need quotes around it. Used in the pre-include + * mechanism as an alternative to trying to find a sensible type of + * quote to use on the filename we were passed. + */ +struct Token { + Token *next; + char *text; + SMacro *mac; /* associated macro for TOK_SMAC_END */ + int type; +}; +enum { + TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING, + TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_SMAC_PARAM, + TOK_INTERNAL_STRING +}; + +/* + * Multi-line macro definitions are stored as a linked list of + * these, which is essentially a container to allow several linked + * lists of Tokens. + * + * Note that in this module, linked lists are treated as stacks + * wherever possible. For this reason, Lines are _pushed_ on to the + * `expansion' field in MMacro structures, so that the linked list, + * if walked, would give the macro lines in reverse order; this + * means that we can walk the list when expanding a macro, and thus + * push the lines on to the `expansion' field in _istk_ in reverse + * order (so that when popped back off they are in the right + * order). It may seem cockeyed, and it relies on my design having + * an even number of steps in, but it works... + * + * Some of these structures, rather than being actual lines, are + * markers delimiting the end of the expansion of a given macro. + * This is for use in the cycle-tracking and %rep-handling code. + * Such structures have `finishes' non-NULL, and `first' NULL. All + * others have `finishes' NULL, but `first' may still be NULL if + * the line is blank. + */ +struct Line { + Line *next; + MMacro *finishes; + Token *first; +}; + +/* + * To handle an arbitrary level of file inclusion, we maintain a + * stack (ie linked list) of these things. + */ +struct Include { + Include *next; + FILE *fp; + Cond *conds; + Line *expansion; + char *fname; + int lineno, lineinc; + MMacro *mstk; /* stack of active macros/reps */ +}; + +/* + * Include search path. This is simply a list of strings which get + * prepended, in turn, to the name of an include file, in an + * attempt to find the file if it's not in the current directory. + */ +struct IncPath { + IncPath *next; + char *path; +}; + +/* + * Conditional assembly: we maintain a separate stack of these for + * each level of file inclusion. (The only reason we keep the + * stacks separate is to ensure that a stray `%endif' in a file + * included from within the true branch of a `%if' won't terminate + * it and cause confusion: instead, rightly, it'll cause an error.) + */ +struct Cond { + Cond *next; + int state; +}; +enum { + /* + * These states are for use just after %if or %elif: IF_TRUE + * means the condition has evaluated to truth so we are + * currently emitting, whereas IF_FALSE means we are not + * currently emitting but will start doing so if a %else comes + * up. In these states, all directives are admissible: %elif, + * %else and %endif. (And of course %if.) + */ + COND_IF_TRUE, COND_IF_FALSE, + /* + * These states come up after a %else: ELSE_TRUE means we're + * emitting, and ELSE_FALSE means we're not. In ELSE_* states, + * any %elif or %else will cause an error. + */ + COND_ELSE_TRUE, COND_ELSE_FALSE, + /* + * This state means that we're not emitting now, and also that + * nothing until %endif will be emitted at all. It's for use in + * two circumstances: (i) when we've had our moment of emission + * and have now started seeing %elifs, and (ii) when the + * condition construct in question is contained within a + * non-emitting branch of a larger condition construct. + */ + COND_NEVER +}; +#define emitting(x) ( (x) == COND_IF_TRUE || (x) == COND_ELSE_TRUE ) + +/* + * These defines are used as the possible return values for do_directive + */ +#define NO_DIRECTIVE_FOUND 0 +#define DIRECTIVE_FOUND 1 + +/* + * Condition codes. Note that we use c_ prefix not C_ because C_ is + * used in nasm.h for the "real" condition codes. At _this_ level, + * we treat CXZ and ECXZ as condition codes, albeit non-invertible + * ones, so we need a different enum... + */ +static const char *conditions[] = { + "a", "ae", "b", "be", "c", "cxz", "e", "ecxz", "g", "ge", "l", "le", + "na", "nae", "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", + "np", "ns", "nz", "o", "p", "pe", "po", "s", "z" +}; +enum { + c_A, c_AE, c_B, c_BE, c_C, c_CXZ, c_E, c_ECXZ, c_G, c_GE, c_L, c_LE, + c_NA, c_NAE, c_NB, c_NBE, c_NC, c_NE, c_NG, c_NGE, c_NL, c_NLE, c_NO, + c_NP, c_NS, c_NZ, c_O, c_P, c_PE, c_PO, c_S, c_Z +}; +static int inverse_ccs[] = { + c_NA, c_NAE, c_NB, c_NBE, c_NC, -1, c_NE, -1, c_NG, c_NGE, c_NL, c_NLE, + c_A, c_AE, c_B, c_BE, c_C, c_E, c_G, c_GE, c_L, c_LE, c_O, c_P, c_S, + c_Z, c_NO, c_NP, c_PO, c_PE, c_NS, c_NZ +}; + +/* + * Directive names. + */ +static const char *directives[] = { + "%arg", + "%assign", "%clear", "%define", "%elif", "%elifctx", "%elifdef", + "%elifid", "%elifidn", "%elifidni", "%elifmacro", "%elifnctx", + "%elifndef", + "%elifnid", "%elifnidn", "%elifnidni", "%elifnmacro", "%elifnnum", + "%elifnstr", + "%elifnum", "%elifstr", "%else", "%endif", "%endm", "%endmacro", + "%endrep", "%error", "%exitrep", "%iassign", "%idefine", "%if", + "%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifmacro", + "%ifnctx", + "%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnmacro", "%ifnnum", + "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", + "%ixdefine", "%line", + "%local", + "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", + "%stacksize", + "%strlen", "%substr", "%undef", "%xdefine" +}; +enum { + PP_ARG, + PP_ASSIGN, PP_CLEAR, PP_DEFINE, PP_ELIF, PP_ELIFCTX, PP_ELIFDEF, + PP_ELIFID, PP_ELIFIDN, PP_ELIFIDNI, PP_ELIFMACRO, PP_ELIFNCTX, + PP_ELIFNDEF, + PP_ELIFNID, PP_ELIFNIDN, PP_ELIFNIDNI, PP_ELIFNMACRO, PP_ELIFNNUM, + PP_ELIFNSTR, + PP_ELIFNUM, PP_ELIFSTR, PP_ELSE, PP_ENDIF, PP_ENDM, PP_ENDMACRO, + PP_ENDREP, PP_ERROR, PP_EXITREP, PP_IASSIGN, PP_IDEFINE, PP_IF, + PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFMACRO, + PP_IFNCTX, + PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNMACRO, PP_IFNNUM, + PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, + PP_IXDEFINE, PP_LINE, + PP_LOCAL, + PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, + PP_STACKSIZE, + PP_STRLEN, PP_SUBSTR, PP_UNDEF, PP_XDEFINE +}; + +/* If this is a an IF, ELIF, ELSE or ENDIF keyword */ +static int is_condition(int arg) +{ + return ((arg >= PP_ELIF) && (arg <= PP_ENDIF)) || + ((arg >= PP_IF) && (arg <= PP_IFSTR)); +} + +/* For TASM compatibility we need to be able to recognise TASM compatible + * conditional compilation directives. Using the NASM pre-processor does + * not work, so we look for them specifically from the following list and + * then jam in the equivalent NASM directive into the input stream. + */ + +#ifndef MAX +# define MAX(a,b) ( ((a) > (b)) ? (a) : (b)) +#endif + +enum { + TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI, + TM_IFNDEF, TM_INCLUDE, TM_LOCAL +}; + +static const char *tasm_directives[] = { + "arg", "elif", "else", "endif", "if", "ifdef", "ifdifi", + "ifndef", "include", "local" +}; + +static int StackSize = 4; +static char *StackPointer = "ebp"; +static int ArgOffset = 8; +static int LocalOffset = 4; + +static Context *cstk; +static Include *istk; +static IncPath *ipath = NULL; + +static efunc _error; /* Pointer to client-provided error reporting function */ +static evalfunc evaluate; + +static int pass; /* HACK: pass 0 = generate dependencies only */ + +static unsigned long unique; /* unique identifier numbers */ + +static Line *predef = NULL; + +static ListGen *list; + +/* + * The number of hash values we use for the macro lookup tables. + * FIXME: We should *really* be able to configure this at run time, + * or even have the hash table automatically expanding when necessary. + */ +#define NHASH 31 + +/* + * The current set of multi-line macros we have defined. + */ +static MMacro *mmacros[NHASH]; + +/* + * The current set of single-line macros we have defined. + */ +static SMacro *smacros[NHASH]; + +/* + * The multi-line macro we are currently defining, or the %rep + * block we are currently reading, if any. + */ +static MMacro *defining; + +/* + * The number of macro parameters to allocate space for at a time. + */ +#define PARAM_DELTA 16 + +/* + * The standard macro set: defined as `static char *stdmac[]'. Also + * gives our position in the macro set, when we're processing it. + */ +#include "macros.c" +static const char **stdmacpos; + +/* + * The extra standard macros that come from the object format, if + * any. + */ +static const char **extrastdmac = NULL; +int any_extrastdmac; + +/* + * Tokens are allocated in blocks to improve speed + */ +#define TOKEN_BLOCKSIZE 4096 +static Token *freeTokens = NULL; +struct Blocks { + Blocks *next; + void *chunk; +}; + +static Blocks blocks = { NULL, NULL }; + +/* + * Forward declarations. + */ +static Token *expand_mmac_params(Token * tline); +static Token *expand_smacro(Token * tline); +static Token *expand_id(Token * tline); +static Context *get_ctx(char *name, int all_contexts); +static void make_tok_num(Token * tok, long val); +static void error(int severity, const char *fmt, ...); +static void *new_Block(size_t size); +static void delete_Blocks(void); +static Token *new_Token(Token * next, int type, char *text, int txtlen); +static Token *delete_Token(Token * t); + +/* + * Macros for safe checking of token pointers, avoid *(NULL) + */ +#define tok_type_(x,t) ((x) && (x)->type == (t)) +#define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next +#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v))) +#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v)))) + +/* Handle TASM specific directives, which do not contain a % in + * front of them. We do it here because I could not find any other + * place to do it for the moment, and it is a hack (ideally it would + * be nice to be able to use the NASM pre-processor to do it). + */ +static char *check_tasm_directive(char *line) +{ + int i, j, k, m, len; + char *p = line, *oldline, oldchar; + + /* Skip whitespace */ + while (isspace(*p) && *p != 0) + p++; + + /* Binary search for the directive name */ + i = -1; + j = elements(tasm_directives); + len = 0; + while (!isspace(p[len]) && p[len] != 0) + len++; + if (len) { + oldchar = p[len]; + p[len] = 0; + while (j - i > 1) { + k = (j + i) / 2; + m = nasm_stricmp(p, tasm_directives[k]); + if (m == 0) { + /* We have found a directive, so jam a % in front of it + * so that NASM will then recognise it as one if it's own. + */ + p[len] = oldchar; + len = strlen(p); + oldline = line; + line = nasm_malloc(len + 2); + line[0] = '%'; + if (k == TM_IFDIFI) { + /* NASM does not recognise IFDIFI, so we convert it to + * %ifdef BOGUS. This is not used in NASM comaptible + * code, but does need to parse for the TASM macro + * package. + */ + strcpy(line + 1, "ifdef BOGUS"); + } else { + memcpy(line + 1, p, len + 1); + } + nasm_free(oldline); + return line; + } else if (m < 0) { + j = k; + } else + i = k; + } + p[len] = oldchar; + } + return line; +} + +/* + * The pre-preprocessing stage... This function translates line + * number indications as they emerge from GNU cpp (`# lineno "file" + * flags') into NASM preprocessor line number indications (`%line + * lineno file'). + */ +static char *prepreproc(char *line) +{ + int lineno, fnlen; + char *fname, *oldline; + + if (line[0] == '#' && line[1] == ' ') { + oldline = line; + fname = oldline + 2; + lineno = atoi(fname); + fname += strspn(fname, "0123456789 "); + if (*fname == '"') + fname++; + fnlen = strcspn(fname, "\""); + line = nasm_malloc(20 + fnlen); + snprintf(line, 20 + fnlen, "%%line %d %.*s", lineno, fnlen, fname); + nasm_free(oldline); + } + if (tasm_compatible_mode) + return check_tasm_directive(line); + return line; +} + +/* + * The hash function for macro lookups. Note that due to some + * macros having case-insensitive names, the hash function must be + * invariant under case changes. We implement this by applying a + * perfectly normal hash function to the uppercase of the string. + */ +static int hash(char *s) +{ + unsigned int h = 0; + int i = 0; + /* + * Powers of three, mod 31. + */ + static const int multipliers[] = { + 1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, + 30, 28, 22, 4, 12, 5, 15, 14, 11, 2, 6, 18, 23, 7, 21 + }; + + while (*s) { + h += multipliers[i] * (unsigned char)(toupper(*s)); + s++; + if (++i >= elements(multipliers)) + i = 0; + } + h %= NHASH; + return h; +} + +/* + * Free a linked list of tokens. + */ +static void free_tlist(Token * list) +{ + while (list) { + list = delete_Token(list); + } +} + +/* + * Free a linked list of lines. + */ +static void free_llist(Line * list) +{ + Line *l; + while (list) { + l = list; + list = list->next; + free_tlist(l->first); + nasm_free(l); + } +} + +/* + * Free an MMacro + */ +static void free_mmacro(MMacro * m) +{ + nasm_free(m->name); + free_tlist(m->dlist); + nasm_free(m->defaults); + free_llist(m->expansion); + nasm_free(m); +} + +/* + * Pop the context stack. + */ +static void ctx_pop(void) +{ + Context *c = cstk; + SMacro *smac, *s; + + cstk = cstk->next; + smac = c->localmac; + while (smac) { + s = smac; + smac = smac->next; + nasm_free(s->name); + free_tlist(s->expansion); + nasm_free(s); + } + nasm_free(c->name); + nasm_free(c); +} + +#define BUF_DELTA 512 +/* + * Read a line from the top file in istk, handling multiple CR/LFs + * at the end of the line read, and handling spurious ^Zs. Will + * return lines from the standard macro set if this has not already + * been done. + */ +static char *read_line(void) +{ + char *buffer, *p, *q; + int bufsize, continued_count; + + if (stdmacpos) { + if (*stdmacpos) { + char *ret = nasm_strdup(*stdmacpos++); + if (!*stdmacpos && any_extrastdmac) { + stdmacpos = extrastdmac; + any_extrastdmac = FALSE; + return ret; + } + /* + * Nasty hack: here we push the contents of `predef' on + * to the top-level expansion stack, since this is the + * most convenient way to implement the pre-include and + * pre-define features. + */ + if (!*stdmacpos) { + Line *pd, *l; + Token *head, **tail, *t; + + for (pd = predef; pd; pd = pd->next) { + head = NULL; + tail = &head; + for (t = pd->first; t; t = t->next) { + *tail = new_Token(NULL, t->type, t->text, 0); + tail = &(*tail)->next; + } + l = nasm_malloc(sizeof(Line)); + l->next = istk->expansion; + l->first = head; + l->finishes = FALSE; + istk->expansion = l; + } + } + return ret; + } else { + stdmacpos = NULL; + } + } + + bufsize = BUF_DELTA; + buffer = nasm_malloc(BUF_DELTA); + p = buffer; + continued_count = 0; + while (1) { + q = fgets(p, bufsize - (p - buffer), istk->fp); + if (!q) + break; + p += strlen(p); + if (p > buffer && p[-1] == '\n') { + /* Convert backslash-CRLF line continuation sequences into + nothing at all (for DOS and Windows) */ + if (((p - 2) > buffer) && (p[-3] == '\\') && (p[-2] == '\r')) { + p -= 3; + *p = 0; + continued_count++; + } + /* Also convert backslash-LF line continuation sequences into + nothing at all (for Unix) */ + else if (((p - 1) > buffer) && (p[-2] == '\\')) { + p -= 2; + *p = 0; + continued_count++; + } else { + break; + } + } + if (p - buffer > bufsize - 10) { + long offset = p - buffer; + bufsize += BUF_DELTA; + buffer = nasm_realloc(buffer, bufsize); + p = buffer + offset; /* prevent stale-pointer problems */ + } + } + + if (!q && p == buffer) { + nasm_free(buffer); + return NULL; + } + + src_set_linnum(src_get_linnum() + istk->lineinc + + (continued_count * istk->lineinc)); + + /* + * Play safe: remove CRs as well as LFs, if any of either are + * present at the end of the line. + */ + while (--p >= buffer && (*p == '\n' || *p == '\r')) + *p = '\0'; + + /* + * Handle spurious ^Z, which may be inserted into source files + * by some file transfer utilities. + */ + buffer[strcspn(buffer, "\032")] = '\0'; + + list->line(LIST_READ, buffer); + + return buffer; +} + +/* + * Tokenise a line of text. This is a very simple process since we + * don't need to parse the value out of e.g. numeric tokens: we + * simply split one string into many. + */ +static Token *tokenise(char *line) +{ + char *p = line; + int type; + Token *list = NULL; + Token *t, **tail = &list; + + while (*line) { + p = line; + if (*p == '%') { + p++; + if (isdigit(*p) || + ((*p == '-' || *p == '+') && isdigit(p[1])) || + ((*p == '+') && (isspace(p[1]) || !p[1]))) { + do { + p++; + } + while (isdigit(*p)); + type = TOK_PREPROC_ID; + } else if (*p == '{') { + p++; + while (*p && *p != '}') { + p[-1] = *p; + p++; + } + p[-1] = '\0'; + if (*p) + p++; + type = TOK_PREPROC_ID; + } else if (isidchar(*p) || + ((*p == '!' || *p == '%' || *p == '$') && + isidchar(p[1]))) { + do { + p++; + } + while (isidchar(*p)); + type = TOK_PREPROC_ID; + } else { + type = TOK_OTHER; + if (*p == '%') + p++; + } + } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) { + type = TOK_ID; + p++; + while (*p && isidchar(*p)) + p++; + } else if (*p == '\'' || *p == '"') { + /* + * A string token. + */ + char c = *p; + p++; + type = TOK_STRING; + while (*p && *p != c) + p++; + + if (*p) { + p++; + } else { + error(ERR_WARNING, "unterminated string"); + /* Handling unterminated strings by UNV */ + /* type = -1; */ + } + } else if (isnumstart(*p)) { + /* + * A number token. + */ + type = TOK_NUMBER; + p++; + while (*p && isnumchar(*p)) + p++; + } else if (isspace(*p)) { + type = TOK_WHITESPACE; + p++; + while (*p && isspace(*p)) + p++; + /* + * Whitespace just before end-of-line is discarded by + * pretending it's a comment; whitespace just before a + * comment gets lumped into the comment. + */ + if (!*p || *p == ';') { + type = TOK_COMMENT; + while (*p) + p++; + } + } else if (*p == ';') { + type = TOK_COMMENT; + while (*p) + p++; + } else { + /* + * Anything else is an operator of some kind. We check + * for all the double-character operators (>>, <<, //, + * %%, <=, >=, ==, !=, <>, &&, ||, ^^), but anything + * else is a single-character operator. + */ + type = TOK_OTHER; + if ((p[0] == '>' && p[1] == '>') || + (p[0] == '<' && p[1] == '<') || + (p[0] == '/' && p[1] == '/') || + (p[0] == '<' && p[1] == '=') || + (p[0] == '>' && p[1] == '=') || + (p[0] == '=' && p[1] == '=') || + (p[0] == '!' && p[1] == '=') || + (p[0] == '<' && p[1] == '>') || + (p[0] == '&' && p[1] == '&') || + (p[0] == '|' && p[1] == '|') || + (p[0] == '^' && p[1] == '^')) { + p++; + } + p++; + } + + /* Handling unterminated string by UNV */ + /*if (type == -1) + { + *tail = t = new_Token(NULL, TOK_STRING, line, p-line+1); + t->text[p-line] = *line; + tail = &t->next; + } + else */ + if (type != TOK_COMMENT) { + *tail = t = new_Token(NULL, type, line, p - line); + tail = &t->next; + } + line = p; + } + return list; +} + +/* + * this function allocates a new managed block of memory and + * returns a pointer to the block. The managed blocks are + * deleted only all at once by the delete_Blocks function. + */ +static void *new_Block(size_t size) +{ + Blocks *b = &blocks; + + /* first, get to the end of the linked list */ + while (b->next) + b = b->next; + /* now allocate the requested chunk */ + b->chunk = nasm_malloc(size); + + /* now allocate a new block for the next request */ + b->next = nasm_malloc(sizeof(Blocks)); + /* and initialize the contents of the new block */ + b->next->next = NULL; + b->next->chunk = NULL; + return b->chunk; +} + +/* + * this function deletes all managed blocks of memory + */ +static void delete_Blocks(void) +{ + Blocks *a, *b = &blocks; + + /* + * keep in mind that the first block, pointed to by blocks + * is a static and not dynamically allocated, so we don't + * free it. + */ + while (b) { + if (b->chunk) + nasm_free(b->chunk); + a = b; + b = b->next; + if (a != &blocks) + nasm_free(a); + } +} + +/* + * this function creates a new Token and passes a pointer to it + * back to the caller. It sets the type and text elements, and + * also the mac and next elements to NULL. + */ +static Token *new_Token(Token * next, int type, char *text, int txtlen) +{ + Token *t; + int i; + + if (freeTokens == NULL) { + freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token)); + for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++) + freeTokens[i].next = &freeTokens[i + 1]; + freeTokens[i].next = NULL; + } + t = freeTokens; + freeTokens = t->next; + t->next = next; + t->mac = NULL; + t->type = type; + if (type == TOK_WHITESPACE || text == NULL) { + t->text = NULL; + } else { + if (txtlen == 0) + txtlen = strlen(text); + t->text = nasm_malloc(1 + txtlen); + strncpy(t->text, text, txtlen); + t->text[txtlen] = '\0'; + } + return t; +} + +static Token *delete_Token(Token * t) +{ + Token *next = t->next; + nasm_free(t->text); + t->next = freeTokens; + freeTokens = t; + return next; +} + +/* + * Convert a line of tokens back into text. + * If expand_locals is not zero, identifiers of the form "%$*xxx" + * will be transformed into ..@ctxnum.xxx + */ +static char *detoken(Token * tlist, int expand_locals) +{ + Token *t; + int len; + char *line, *p; + + len = 0; + for (t = tlist; t; t = t->next) { + if (t->type == TOK_PREPROC_ID && t->text[1] == '!') { + char *p = getenv(t->text + 2); + nasm_free(t->text); + if (p) + t->text = nasm_strdup(p); + else + t->text = NULL; + } + /* Expand local macros here and not during preprocessing */ + if (expand_locals && + t->type == TOK_PREPROC_ID && t->text && + t->text[0] == '%' && t->text[1] == '$') { + Context *ctx = get_ctx(t->text, FALSE); + if (ctx) { + char buffer[40]; + char *p, *q = t->text + 2; + + q += strspn(q, "$"); + snprintf(buffer, sizeof(buffer), "..@%lu.", ctx->number); + p = nasm_strcat(buffer, q); + nasm_free(t->text); + t->text = p; + } + } + if (t->type == TOK_WHITESPACE) { + len++; + } else if (t->text) { + len += strlen(t->text); + } + } + p = line = nasm_malloc(len + 1); + for (t = tlist; t; t = t->next) { + if (t->type == TOK_WHITESPACE) { + *p = ' '; + p++; + *p = '\0'; + } else if (t->text) { + strcpy(p, t->text); + p += strlen(p); + } + } + *p = '\0'; + return line; +} + +/* + * A scanner, suitable for use by the expression evaluator, which + * operates on a line of Tokens. Expects a pointer to a pointer to + * the first token in the line to be passed in as its private_data + * field. + */ +static int ppscan(void *private_data, struct tokenval *tokval) +{ + Token **tlineptr = private_data; + Token *tline; + + do { + tline = *tlineptr; + *tlineptr = tline ? tline->next : NULL; + } + while (tline && (tline->type == TOK_WHITESPACE || + tline->type == TOK_COMMENT)); + + if (!tline) + return tokval->t_type = TOKEN_EOS; + + if (tline->text[0] == '$' && !tline->text[1]) + return tokval->t_type = TOKEN_HERE; + if (tline->text[0] == '$' && tline->text[1] == '$' && !tline->text[2]) + return tokval->t_type = TOKEN_BASE; + + if (tline->type == TOK_ID) { + tokval->t_charptr = tline->text; + if (tline->text[0] == '$') { + tokval->t_charptr++; + return tokval->t_type = TOKEN_ID; + } + + /* + * This is the only special case we actually need to worry + * about in this restricted context. + */ + if (!nasm_stricmp(tline->text, "seg")) + return tokval->t_type = TOKEN_SEG; + + return tokval->t_type = TOKEN_ID; + } + + if (tline->type == TOK_NUMBER) { + int rn_error; + + tokval->t_integer = readnum(tline->text, &rn_error); + if (rn_error) + return tokval->t_type = TOKEN_ERRNUM; + tokval->t_charptr = NULL; + return tokval->t_type = TOKEN_NUM; + } + + if (tline->type == TOK_STRING) { + int rn_warn; + char q, *r; + int l; + + r = tline->text; + q = *r++; + l = strlen(r); + + if (l == 0 || r[l - 1] != q) + return tokval->t_type = TOKEN_ERRNUM; + tokval->t_integer = readstrnum(r, l - 1, &rn_warn); + if (rn_warn) + error(ERR_WARNING | ERR_PASS1, "character constant too long"); + tokval->t_charptr = NULL; + return tokval->t_type = TOKEN_NUM; + } + + if (tline->type == TOK_OTHER) { + if (!strcmp(tline->text, "<<")) + return tokval->t_type = TOKEN_SHL; + if (!strcmp(tline->text, ">>")) + return tokval->t_type = TOKEN_SHR; + if (!strcmp(tline->text, "//")) + return tokval->t_type = TOKEN_SDIV; + if (!strcmp(tline->text, "%%")) + return tokval->t_type = TOKEN_SMOD; + if (!strcmp(tline->text, "==")) + return tokval->t_type = TOKEN_EQ; + if (!strcmp(tline->text, "<>")) + return tokval->t_type = TOKEN_NE; + if (!strcmp(tline->text, "!=")) + return tokval->t_type = TOKEN_NE; + if (!strcmp(tline->text, "<=")) + return tokval->t_type = TOKEN_LE; + if (!strcmp(tline->text, ">=")) + return tokval->t_type = TOKEN_GE; + if (!strcmp(tline->text, "&&")) + return tokval->t_type = TOKEN_DBL_AND; + if (!strcmp(tline->text, "^^")) + return tokval->t_type = TOKEN_DBL_XOR; + if (!strcmp(tline->text, "||")) + return tokval->t_type = TOKEN_DBL_OR; + } + + /* + * We have no other options: just return the first character of + * the token text. + */ + return tokval->t_type = tline->text[0]; +} + +/* + * Compare a string to the name of an existing macro; this is a + * simple wrapper which calls either strcmp or nasm_stricmp + * depending on the value of the `casesense' parameter. + */ +static int mstrcmp(char *p, char *q, int casesense) +{ + return casesense ? strcmp(p, q) : nasm_stricmp(p, q); +} + +/* + * Return the Context structure associated with a %$ token. Return + * NULL, having _already_ reported an error condition, if the + * context stack isn't deep enough for the supplied number of $ + * signs. + * If all_contexts == TRUE, contexts that enclose current are + * also scanned for such smacro, until it is found; if not - + * only the context that directly results from the number of $'s + * in variable's name. + */ +static Context *get_ctx(char *name, int all_contexts) +{ + Context *ctx; + SMacro *m; + int i; + + if (!name || name[0] != '%' || name[1] != '$') + return NULL; + + if (!cstk) { + error(ERR_NONFATAL, "`%s': context stack is empty", name); + return NULL; + } + + for (i = strspn(name + 2, "$"), ctx = cstk; (i > 0) && ctx; i--) { + ctx = ctx->next; +/* i--; Lino - 02/25/02 */ + } + if (!ctx) { + error(ERR_NONFATAL, "`%s': context stack is only" + " %d level%s deep", name, i - 1, (i == 2 ? "" : "s")); + return NULL; + } + if (!all_contexts) + return ctx; + + do { + /* Search for this smacro in found context */ + m = ctx->localmac; + while (m) { + if (!mstrcmp(m->name, name, m->casesense)) + return ctx; + m = m->next; + } + ctx = ctx->next; + } + while (ctx); + return NULL; +} + +/* + * Open an include file. This routine must always return a valid + * file pointer if it returns - it's responsible for throwing an + * ERR_FATAL and bombing out completely if not. It should also try + * the include path one by one until it finds the file or reaches + * the end of the path. + */ +static FILE *inc_fopen(char *file) +{ + FILE *fp; + char *prefix = "", *combine; + IncPath *ip = ipath; + static int namelen = 0; + int len = strlen(file); + + while (1) { + combine = nasm_malloc(strlen(prefix) + len + 1); + strcpy(combine, prefix); + strcat(combine, file); + fp = fopen(combine, "r"); + if (pass == 0 && fp) { + namelen += strlen(combine) + 1; + if (namelen > 62) { + printf(" \\\n "); + namelen = 2; + } + printf(" %s", combine); + } + nasm_free(combine); + if (fp) + return fp; + if (!ip) + break; + prefix = ip->path; + ip = ip->next; + } + + error(ERR_FATAL, "unable to open include file `%s'", file); + return NULL; /* never reached - placate compilers */ +} + +/* + * Determine if we should warn on defining a single-line macro of + * name `name', with `nparam' parameters. If nparam is 0 or -1, will + * return TRUE if _any_ single-line macro of that name is defined. + * Otherwise, will return TRUE if a single-line macro with either + * `nparam' or no parameters is defined. + * + * If a macro with precisely the right number of parameters is + * defined, or nparam is -1, the address of the definition structure + * will be returned in `defn'; otherwise NULL will be returned. If `defn' + * is NULL, no action will be taken regarding its contents, and no + * error will occur. + * + * Note that this is also called with nparam zero to resolve + * `ifdef'. + * + * If you already know which context macro belongs to, you can pass + * the context pointer as first parameter; if you won't but name begins + * with %$ the context will be automatically computed. If all_contexts + * is true, macro will be searched in outer contexts as well. + */ +static int +smacro_defined(Context * ctx, char *name, int nparam, SMacro ** defn, + int nocase) +{ + SMacro *m; + + if (ctx) + m = ctx->localmac; + else if (name[0] == '%' && name[1] == '$') { + if (cstk) + ctx = get_ctx(name, FALSE); + if (!ctx) + return FALSE; /* got to return _something_ */ + m = ctx->localmac; + } else + m = smacros[hash(name)]; + + while (m) { + if (!mstrcmp(m->name, name, m->casesense && nocase) && + (nparam <= 0 || m->nparam == 0 || nparam == m->nparam)) { + if (defn) { + if (nparam == m->nparam || nparam == -1) + *defn = m; + else + *defn = NULL; + } + return TRUE; + } + m = m->next; + } + + return FALSE; +} + +/* + * Count and mark off the parameters in a multi-line macro call. + * This is called both from within the multi-line macro expansion + * code, and also to mark off the default parameters when provided + * in a %macro definition line. + */ +static void count_mmac_params(Token * t, int *nparam, Token *** params) +{ + int paramsize, brace; + + *nparam = paramsize = 0; + *params = NULL; + while (t) { + if (*nparam >= paramsize) { + paramsize += PARAM_DELTA; + *params = nasm_realloc(*params, sizeof(**params) * paramsize); + } + skip_white_(t); + brace = FALSE; + if (tok_is_(t, "{")) + brace = TRUE; + (*params)[(*nparam)++] = t; + while (tok_isnt_(t, brace ? "}" : ",")) + t = t->next; + if (t) { /* got a comma/brace */ + t = t->next; + if (brace) { + /* + * Now we've found the closing brace, look further + * for the comma. + */ + skip_white_(t); + if (tok_isnt_(t, ",")) { + error(ERR_NONFATAL, + "braces do not enclose all of macro parameter"); + while (tok_isnt_(t, ",")) + t = t->next; + } + if (t) + t = t->next; /* eat the comma */ + } + } + } +} + +/* + * Determine whether one of the various `if' conditions is true or + * not. + * + * We must free the tline we get passed. + */ +static int if_condition(Token * tline, int i) +{ + int j, casesense; + Token *t, *tt, **tptr, *origline; + struct tokenval tokval; + expr *evalresult; + + origline = tline; + + switch (i) { + case PP_IFCTX: + case PP_ELIFCTX: + case PP_IFNCTX: + case PP_ELIFNCTX: + j = FALSE; /* have we matched yet? */ + while (cstk && tline) { + skip_white_(tline); + if (!tline || tline->type != TOK_ID) { + error(ERR_NONFATAL, + "`%s' expects context identifiers", directives[i]); + free_tlist(origline); + return -1; + } + if (!nasm_stricmp(tline->text, cstk->name)) + j = TRUE; + tline = tline->next; + } + if (i == PP_IFNCTX || i == PP_ELIFNCTX) + j = !j; + free_tlist(origline); + return j; + + case PP_IFDEF: + case PP_ELIFDEF: + case PP_IFNDEF: + case PP_ELIFNDEF: + j = FALSE; /* have we matched yet? */ + while (tline) { + skip_white_(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) { + error(ERR_NONFATAL, + "`%s' expects macro identifiers", directives[i]); + free_tlist(origline); + return -1; + } + if (smacro_defined(NULL, tline->text, 0, NULL, 1)) + j = TRUE; + tline = tline->next; + } + if (i == PP_IFNDEF || i == PP_ELIFNDEF) + j = !j; + free_tlist(origline); + return j; + + case PP_IFIDN: + case PP_ELIFIDN: + case PP_IFNIDN: + case PP_ELIFNIDN: + case PP_IFIDNI: + case PP_ELIFIDNI: + case PP_IFNIDNI: + case PP_ELIFNIDNI: + tline = expand_smacro(tline); + t = tt = tline; + while (tok_isnt_(tt, ",")) + tt = tt->next; + if (!tt) { + error(ERR_NONFATAL, + "`%s' expects two comma-separated arguments", + directives[i]); + free_tlist(tline); + return -1; + } + tt = tt->next; + casesense = (i == PP_IFIDN || i == PP_ELIFIDN || + i == PP_IFNIDN || i == PP_ELIFNIDN); + j = TRUE; /* assume equality unless proved not */ + while ((t->type != TOK_OTHER || strcmp(t->text, ",")) && tt) { + if (tt->type == TOK_OTHER && !strcmp(tt->text, ",")) { + error(ERR_NONFATAL, "`%s': more than one comma on line", + directives[i]); + free_tlist(tline); + return -1; + } + if (t->type == TOK_WHITESPACE) { + t = t->next; + continue; + } + if (tt->type == TOK_WHITESPACE) { + tt = tt->next; + continue; + } + if (tt->type != t->type) { + j = FALSE; /* found mismatching tokens */ + break; + } + /* Unify surrounding quotes for strings */ + if (t->type == TOK_STRING) { + tt->text[0] = t->text[0]; + tt->text[strlen(tt->text) - 1] = t->text[0]; + } + if (mstrcmp(tt->text, t->text, casesense) != 0) { + j = FALSE; /* found mismatching tokens */ + break; + } + + t = t->next; + tt = tt->next; + } + if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt) + j = FALSE; /* trailing gunk on one end or other */ + if (i == PP_IFNIDN || i == PP_ELIFNIDN || + i == PP_IFNIDNI || i == PP_ELIFNIDNI) + j = !j; + free_tlist(tline); + return j; + + case PP_IFMACRO: + case PP_ELIFMACRO: + case PP_IFNMACRO: + case PP_ELIFNMACRO: + { + int found = 0; + MMacro searching, *mmac; + + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) { + error(ERR_NONFATAL, + "`%s' expects a macro name", directives[i]); + return -1; + } + searching.name = nasm_strdup(tline->text); + searching.casesense = (i == PP_MACRO); + searching.plus = FALSE; + searching.nolist = FALSE; + searching.in_progress = FALSE; + searching.rep_nest = NULL; + searching.nparam_min = 0; + searching.nparam_max = INT_MAX; + tline = expand_smacro(tline->next); + skip_white_(tline); + if (!tline) { + } else if (!tok_type_(tline, TOK_NUMBER)) { + error(ERR_NONFATAL, + "`%s' expects a parameter count or nothing", + directives[i]); + } else { + searching.nparam_min = searching.nparam_max = + readnum(tline->text, &j); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + } + if (tline && tok_is_(tline->next, "-")) { + tline = tline->next->next; + if (tok_is_(tline, "*")) + searching.nparam_max = INT_MAX; + else if (!tok_type_(tline, TOK_NUMBER)) + error(ERR_NONFATAL, + "`%s' expects a parameter count after `-'", + directives[i]); + else { + searching.nparam_max = readnum(tline->text, &j); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + if (searching.nparam_min > searching.nparam_max) + error(ERR_NONFATAL, + "minimum parameter count exceeds maximum"); + } + } + if (tline && tok_is_(tline->next, "+")) { + tline = tline->next; + searching.plus = TRUE; + } + mmac = mmacros[hash(searching.name)]; + while (mmac) { + if (!strcmp(mmac->name, searching.name) && + (mmac->nparam_min <= searching.nparam_max + || searching.plus) + && (searching.nparam_min <= mmac->nparam_max + || mmac->plus)) { + found = TRUE; + break; + } + mmac = mmac->next; + } + nasm_free(searching.name); + free_tlist(origline); + if (i == PP_IFNMACRO || i == PP_ELIFNMACRO) + found = !found; + return found; + } + + case PP_IFID: + case PP_ELIFID: + case PP_IFNID: + case PP_ELIFNID: + case PP_IFNUM: + case PP_ELIFNUM: + case PP_IFNNUM: + case PP_ELIFNNUM: + case PP_IFSTR: + case PP_ELIFSTR: + case PP_IFNSTR: + case PP_ELIFNSTR: + tline = expand_smacro(tline); + t = tline; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + j = FALSE; /* placate optimiser */ + if (t) + switch (i) { + case PP_IFID: + case PP_ELIFID: + case PP_IFNID: + case PP_ELIFNID: + j = (t->type == TOK_ID); + break; + case PP_IFNUM: + case PP_ELIFNUM: + case PP_IFNNUM: + case PP_ELIFNNUM: + j = (t->type == TOK_NUMBER); + break; + case PP_IFSTR: + case PP_ELIFSTR: + case PP_IFNSTR: + case PP_ELIFNSTR: + j = (t->type == TOK_STRING); + break; + } + if (i == PP_IFNID || i == PP_ELIFNID || + i == PP_IFNNUM || i == PP_ELIFNNUM || + i == PP_IFNSTR || i == PP_ELIFNSTR) + j = !j; + free_tlist(tline); + return j; + + case PP_IF: + case PP_ELIF: + t = tline = expand_smacro(tline); + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate(ppscan, tptr, &tokval, + NULL, pass | CRITICAL, error, NULL); + free_tlist(tline); + if (!evalresult) + return -1; + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + if (!is_simple(evalresult)) { + error(ERR_NONFATAL, + "non-constant value given to `%s'", directives[i]); + return -1; + } + return reloc_value(evalresult) != 0; + + default: + error(ERR_FATAL, + "preprocessor directive `%s' not yet implemented", + directives[i]); + free_tlist(origline); + return -1; /* yeah, right */ + } +} + +/* + * Expand macros in a string. Used in %error and %include directives. + * First tokenise the string, apply "expand_smacro" and then de-tokenise back. + * The returned variable should ALWAYS be freed after usage. + */ +void expand_macros_in_string(char **p) +{ + Token *line = tokenise(*p); + line = expand_smacro(line); + *p = detoken(line, FALSE); +} + +/** + * find and process preprocessor directive in passed line + * Find out if a line contains a preprocessor directive, and deal + * with it if so. + * + * If a directive _is_ found, it is the responsibility of this routine + * (and not the caller) to free_tlist() the line. + * + * @param tline a pointer to the current tokeninzed line linked list + * @return DIRECTIVE_FOUND or NO_DIRECTIVE_FOUND + * + */ +static int do_directive(Token * tline) +{ + int i, j, k, m, nparam, nolist; + int offset; + char *p, *mname; + Include *inc; + Context *ctx; + Cond *cond; + SMacro *smac, **smhead; + MMacro *mmac; + Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline; + Line *l; + struct tokenval tokval; + expr *evalresult; + MMacro *tmp_defining; /* Used when manipulating rep_nest */ + + origline = tline; + + skip_white_(tline); + if (!tok_type_(tline, TOK_PREPROC_ID) || + (tline->text[1] == '%' || tline->text[1] == '$' + || tline->text[1] == '!')) + return NO_DIRECTIVE_FOUND; + + i = -1; + j = elements(directives); + while (j - i > 1) { + k = (j + i) / 2; + m = nasm_stricmp(tline->text, directives[k]); + if (m == 0) { + if (tasm_compatible_mode) { + i = k; + j = -2; + } else if (k != PP_ARG && k != PP_LOCAL && k != PP_STACKSIZE) { + i = k; + j = -2; + } + break; + } else if (m < 0) { + j = k; + } else + i = k; + } + + /* + * If we're in a non-emitting branch of a condition construct, + * or walking to the end of an already terminated %rep block, + * we should ignore all directives except for condition + * directives. + */ + if (((istk->conds && !emitting(istk->conds->state)) || + (istk->mstk && !istk->mstk->in_progress)) && !is_condition(i)) { + return NO_DIRECTIVE_FOUND; + } + + /* + * If we're defining a macro or reading a %rep block, we should + * ignore all directives except for %macro/%imacro (which + * generate an error), %endm/%endmacro, and (only if we're in a + * %rep block) %endrep. If we're in a %rep block, another %rep + * causes an error, so should be let through. + */ + if (defining && i != PP_MACRO && i != PP_IMACRO && + i != PP_ENDMACRO && i != PP_ENDM && + (defining->name || (i != PP_ENDREP && i != PP_REP))) { + return NO_DIRECTIVE_FOUND; + } + + if (j != -2) { + error(ERR_NONFATAL, "unknown preprocessor directive `%s'", + tline->text); + return NO_DIRECTIVE_FOUND; /* didn't get it */ + } + + switch (i) { + case PP_STACKSIZE: + /* Directive to tell NASM what the default stack size is. The + * default is for a 16-bit stack, and this can be overriden with + * %stacksize large. + * the following form: + * + * ARG arg1:WORD, arg2:DWORD, arg4:QWORD + */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error(ERR_NONFATAL, "`%%stacksize' missing size parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (nasm_stricmp(tline->text, "flat") == 0) { + /* All subsequent ARG directives are for a 32-bit stack */ + StackSize = 4; + StackPointer = "ebp"; + ArgOffset = 8; + LocalOffset = 4; + } else if (nasm_stricmp(tline->text, "large") == 0) { + /* All subsequent ARG directives are for a 16-bit stack, + * far function call. + */ + StackSize = 2; + StackPointer = "bp"; + ArgOffset = 4; + LocalOffset = 2; + } else if (nasm_stricmp(tline->text, "small") == 0) { + /* All subsequent ARG directives are for a 16-bit stack, + * far function call. We don't support near functions. + */ + StackSize = 2; + StackPointer = "bp"; + ArgOffset = 6; + LocalOffset = 2; + } else { + error(ERR_NONFATAL, "`%%stacksize' invalid size type"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ARG: + /* TASM like ARG directive to define arguments to functions, in + * the following form: + * + * ARG arg1:WORD, arg2:DWORD, arg4:QWORD + */ + offset = ArgOffset; + do { + char *arg, directive[256]; + int size = StackSize; + + /* Find the argument name */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error(ERR_NONFATAL, "`%%arg' missing argument parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + arg = tline->text; + + /* Find the argument size type */ + tline = tline->next; + if (!tline || tline->type != TOK_OTHER + || tline->text[0] != ':') { + error(ERR_NONFATAL, + "Syntax error processing `%%arg' directive"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error(ERR_NONFATAL, "`%%arg' missing size type parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + /* Allow macro expansion of type parameter */ + tt = tokenise(tline->text); + tt = expand_smacro(tt); + if (nasm_stricmp(tt->text, "byte") == 0) { + size = MAX(StackSize, 1); + } else if (nasm_stricmp(tt->text, "word") == 0) { + size = MAX(StackSize, 2); + } else if (nasm_stricmp(tt->text, "dword") == 0) { + size = MAX(StackSize, 4); + } else if (nasm_stricmp(tt->text, "qword") == 0) { + size = MAX(StackSize, 8); + } else if (nasm_stricmp(tt->text, "tword") == 0) { + size = MAX(StackSize, 10); + } else { + error(ERR_NONFATAL, + "Invalid size type for `%%arg' missing directive"); + free_tlist(tt); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + free_tlist(tt); + + /* Now define the macro for the argument */ + snprintf(directive, sizeof(directive), "%%define %s (%s+%d)", + arg, StackPointer, offset); + do_directive(tokenise(directive)); + offset += size; + + /* Move to the next argument in the list */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + } + while (tline && tline->type == TOK_OTHER && tline->text[0] == ','); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_LOCAL: + /* TASM like LOCAL directive to define local variables for a + * function, in the following form: + * + * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize + * + * The '= LocalSize' at the end is ignored by NASM, but is + * required by TASM to define the local parameter size (and used + * by the TASM macro package). + */ + offset = LocalOffset; + do { + char *local, directive[256]; + int size = StackSize; + + /* Find the argument name */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error(ERR_NONFATAL, + "`%%local' missing argument parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + local = tline->text; + + /* Find the argument size type */ + tline = tline->next; + if (!tline || tline->type != TOK_OTHER + || tline->text[0] != ':') { + error(ERR_NONFATAL, + "Syntax error processing `%%local' directive"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error(ERR_NONFATAL, + "`%%local' missing size type parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + /* Allow macro expansion of type parameter */ + tt = tokenise(tline->text); + tt = expand_smacro(tt); + if (nasm_stricmp(tt->text, "byte") == 0) { + size = MAX(StackSize, 1); + } else if (nasm_stricmp(tt->text, "word") == 0) { + size = MAX(StackSize, 2); + } else if (nasm_stricmp(tt->text, "dword") == 0) { + size = MAX(StackSize, 4); + } else if (nasm_stricmp(tt->text, "qword") == 0) { + size = MAX(StackSize, 8); + } else if (nasm_stricmp(tt->text, "tword") == 0) { + size = MAX(StackSize, 10); + } else { + error(ERR_NONFATAL, + "Invalid size type for `%%local' missing directive"); + free_tlist(tt); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + free_tlist(tt); + + /* Now define the macro for the argument */ + snprintf(directive, sizeof(directive), "%%define %s (%s-%d)", + local, StackPointer, offset); + do_directive(tokenise(directive)); + offset += size; + + /* Now define the assign to setup the enter_c macro correctly */ + snprintf(directive, sizeof(directive), + "%%assign %%$localsize %%$localsize+%d", size); + do_directive(tokenise(directive)); + + /* Move to the next argument in the list */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + } + while (tline && tline->type == TOK_OTHER && tline->text[0] == ','); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_CLEAR: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%clear' ignored"); + for (j = 0; j < NHASH; j++) { + while (mmacros[j]) { + MMacro *m = mmacros[j]; + mmacros[j] = m->next; + free_mmacro(m); + } + while (smacros[j]) { + SMacro *s = smacros[j]; + smacros[j] = smacros[j]->next; + nasm_free(s->name); + free_tlist(s->expansion); + nasm_free(s); + } + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_INCLUDE: + tline = tline->next; + skip_white_(tline); + if (!tline || (tline->type != TOK_STRING && + tline->type != TOK_INTERNAL_STRING)) { + error(ERR_NONFATAL, "`%%include' expects a file name"); + free_tlist(origline); + return DIRECTIVE_FOUND; /* but we did _something_ */ + } + if (tline->next) + error(ERR_WARNING, + "trailing garbage after `%%include' ignored"); + if (tline->type != TOK_INTERNAL_STRING) { + p = tline->text + 1; /* point past the quote to the name */ + p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ + } else + p = tline->text; /* internal_string is easier */ + expand_macros_in_string(&p); + inc = nasm_malloc(sizeof(Include)); + inc->next = istk; + inc->conds = NULL; + inc->fp = inc_fopen(p); + inc->fname = src_set_fname(p); + inc->lineno = src_set_linnum(0); + inc->lineinc = 1; + inc->expansion = NULL; + inc->mstk = NULL; + istk = inc; + list->uplevel(LIST_INCLUDE); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_PUSH: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) { + error(ERR_NONFATAL, "`%%push' expects a context identifier"); + free_tlist(origline); + return DIRECTIVE_FOUND; /* but we did _something_ */ + } + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%push' ignored"); + ctx = nasm_malloc(sizeof(Context)); + ctx->next = cstk; + ctx->localmac = NULL; + ctx->name = nasm_strdup(tline->text); + ctx->number = unique++; + cstk = ctx; + free_tlist(origline); + break; + + case PP_REPL: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) { + error(ERR_NONFATAL, "`%%repl' expects a context identifier"); + free_tlist(origline); + return DIRECTIVE_FOUND; /* but we did _something_ */ + } + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%repl' ignored"); + if (!cstk) + error(ERR_NONFATAL, "`%%repl': context stack is empty"); + else { + nasm_free(cstk->name); + cstk->name = nasm_strdup(tline->text); + } + free_tlist(origline); + break; + + case PP_POP: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%pop' ignored"); + if (!cstk) + error(ERR_NONFATAL, "`%%pop': context stack is already empty"); + else + ctx_pop(); + free_tlist(origline); + break; + + case PP_ERROR: + tline->next = expand_smacro(tline->next); + tline = tline->next; + skip_white_(tline); + if (tok_type_(tline, TOK_STRING)) { + p = tline->text + 1; /* point past the quote to the name */ + p[strlen(p) - 1] = '\0'; /* remove the trailing quote */ + expand_macros_in_string(&p); + error(ERR_NONFATAL, "%s", p); + nasm_free(p); + } else { + p = detoken(tline, FALSE); + error(ERR_WARNING, "%s", p); + nasm_free(p); + } + free_tlist(origline); + break; + + case PP_IF: + case PP_IFCTX: + case PP_IFDEF: + case PP_IFID: + case PP_IFIDN: + case PP_IFIDNI: + case PP_IFMACRO: + case PP_IFNCTX: + case PP_IFNDEF: + case PP_IFNID: + case PP_IFNIDN: + case PP_IFNIDNI: + case PP_IFNMACRO: + case PP_IFNNUM: + case PP_IFNSTR: + case PP_IFNUM: + case PP_IFSTR: + if (istk->conds && !emitting(istk->conds->state)) + j = COND_NEVER; + else { + j = if_condition(tline->next, i); + tline->next = NULL; /* it got freed */ + free_tlist(origline); + j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; + } + cond = nasm_malloc(sizeof(Cond)); + cond->next = istk->conds; + cond->state = j; + istk->conds = cond; + return DIRECTIVE_FOUND; + + case PP_ELIF: + case PP_ELIFCTX: + case PP_ELIFDEF: + case PP_ELIFID: + case PP_ELIFIDN: + case PP_ELIFIDNI: + case PP_ELIFMACRO: + case PP_ELIFNCTX: + case PP_ELIFNDEF: + case PP_ELIFNID: + case PP_ELIFNIDN: + case PP_ELIFNIDNI: + case PP_ELIFNMACRO: + case PP_ELIFNNUM: + case PP_ELIFNSTR: + case PP_ELIFNUM: + case PP_ELIFSTR: + if (!istk->conds) + error(ERR_FATAL, "`%s': no matching `%%if'", directives[i]); + if (emitting(istk->conds->state) + || istk->conds->state == COND_NEVER) + istk->conds->state = COND_NEVER; + else { + /* + * IMPORTANT: In the case of %if, we will already have + * called expand_mmac_params(); however, if we're + * processing an %elif we must have been in a + * non-emitting mode, which would have inhibited + * the normal invocation of expand_mmac_params(). Therefore, + * we have to do it explicitly here. + */ + j = if_condition(expand_mmac_params(tline->next), i); + tline->next = NULL; /* it got freed */ + free_tlist(origline); + istk->conds->state = + j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; + } + return DIRECTIVE_FOUND; + + case PP_ELSE: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%else' ignored"); + if (!istk->conds) + error(ERR_FATAL, "`%%else': no matching `%%if'"); + if (emitting(istk->conds->state) + || istk->conds->state == COND_NEVER) + istk->conds->state = COND_ELSE_FALSE; + else + istk->conds->state = COND_ELSE_TRUE; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ENDIF: + if (tline->next) + error(ERR_WARNING, "trailing garbage after `%%endif' ignored"); + if (!istk->conds) + error(ERR_FATAL, "`%%endif': no matching `%%if'"); + cond = istk->conds; + istk->conds = cond->next; + nasm_free(cond); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_MACRO: + case PP_IMACRO: + if (defining) + error(ERR_FATAL, + "`%%%smacro': already defining a macro", + (i == PP_IMACRO ? "i" : "")); + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tok_type_(tline, TOK_ID)) { + error(ERR_NONFATAL, + "`%%%smacro' expects a macro name", + (i == PP_IMACRO ? "i" : "")); + return DIRECTIVE_FOUND; + } + defining = nasm_malloc(sizeof(MMacro)); + defining->name = nasm_strdup(tline->text); + defining->casesense = (i == PP_MACRO); + defining->plus = FALSE; + defining->nolist = FALSE; + defining->in_progress = FALSE; + defining->rep_nest = NULL; + tline = expand_smacro(tline->next); + skip_white_(tline); + if (!tok_type_(tline, TOK_NUMBER)) { + error(ERR_NONFATAL, + "`%%%smacro' expects a parameter count", + (i == PP_IMACRO ? "i" : "")); + defining->nparam_min = defining->nparam_max = 0; + } else { + defining->nparam_min = defining->nparam_max = + readnum(tline->text, &j); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", tline->text); + } + if (tline && tok_is_(tline->next, "-")) { + tline = tline->next->next; + if (tok_is_(tline, "*")) + defining->nparam_max = INT_MAX; + else if (!tok_type_(tline, TOK_NUMBER)) + error(ERR_NONFATAL, + "`%%%smacro' expects a parameter count after `-'", + (i == PP_IMACRO ? "i" : "")); + else { + defining->nparam_max = readnum(tline->text, &j); + if (j) + error(ERR_NONFATAL, + "unable to parse parameter count `%s'", + tline->text); + if (defining->nparam_min > defining->nparam_max) + error(ERR_NONFATAL, + "minimum parameter count exceeds maximum"); + } + } + if (tline && tok_is_(tline->next, "+")) { + tline = tline->next; + defining->plus = TRUE; + } + if (tline && tok_type_(tline->next, TOK_ID) && + !nasm_stricmp(tline->next->text, ".nolist")) { + tline = tline->next; + defining->nolist = TRUE; + } + mmac = mmacros[hash(defining->name)]; + while (mmac) { + if (!strcmp(mmac->name, defining->name) && + (mmac->nparam_min <= defining->nparam_max + || defining->plus) + && (defining->nparam_min <= mmac->nparam_max + || mmac->plus)) { + error(ERR_WARNING, + "redefining multi-line macro `%s'", defining->name); + break; + } + mmac = mmac->next; + } + /* + * Handle default parameters. + */ + if (tline && tline->next) { + defining->dlist = tline->next; + tline->next = NULL; + count_mmac_params(defining->dlist, &defining->ndefs, + &defining->defaults); + } else { + defining->dlist = NULL; + defining->defaults = NULL; + } + defining->expansion = NULL; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ENDM: + case PP_ENDMACRO: + if (!defining) { + error(ERR_NONFATAL, "`%s': not defining a macro", tline->text); + return DIRECTIVE_FOUND; + } + k = hash(defining->name); + defining->next = mmacros[k]; + mmacros[k] = defining; + defining = NULL; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ROTATE: + if (tline->next && tline->next->type == TOK_WHITESPACE) + tline = tline->next; + if (tline->next == NULL) { + free_tlist(origline); + error(ERR_NONFATAL, "`%%rotate' missing rotate count"); + return DIRECTIVE_FOUND; + } + t = expand_smacro(tline->next); + tline->next = NULL; + free_tlist(origline); + tline = t; + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = + evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); + free_tlist(tline); + if (!evalresult) + return DIRECTIVE_FOUND; + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + if (!is_simple(evalresult)) { + error(ERR_NONFATAL, "non-constant value given to `%%rotate'"); + return DIRECTIVE_FOUND; + } + mmac = istk->mstk; + while (mmac && !mmac->name) /* avoid mistaking %reps for macros */ + mmac = mmac->next_active; + if (!mmac) { + error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call"); + } else if (mmac->nparam == 0) { + error(ERR_NONFATAL, + "`%%rotate' invoked within macro without parameters"); + } else { + mmac->rotate = mmac->rotate + reloc_value(evalresult); + + if (mmac->rotate < 0) + mmac->rotate = + mmac->nparam - (-mmac->rotate) % mmac->nparam; + mmac->rotate %= mmac->nparam; + } + return DIRECTIVE_FOUND; + + case PP_REP: + nolist = FALSE; + do { + tline = tline->next; + } while (tok_type_(tline, TOK_WHITESPACE)); + + if (tok_type_(tline, TOK_ID) && + nasm_stricmp(tline->text, ".nolist") == 0) { + nolist = TRUE; + do { + tline = tline->next; + } while (tok_type_(tline, TOK_WHITESPACE)); + } + + if (tline) { + t = expand_smacro(tline); + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = + evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); + if (!evalresult) { + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + if (!is_simple(evalresult)) { + error(ERR_NONFATAL, "non-constant value given to `%%rep'"); + return DIRECTIVE_FOUND; + } + i = (int)reloc_value(evalresult) + 1; + } else { + error(ERR_NONFATAL, "`%%rep' expects a repeat count"); + i = 0; + } + free_tlist(origline); + + tmp_defining = defining; + defining = nasm_malloc(sizeof(MMacro)); + defining->name = NULL; /* flags this macro as a %rep block */ + defining->casesense = 0; + defining->plus = FALSE; + defining->nolist = nolist; + defining->in_progress = i; + defining->nparam_min = defining->nparam_max = 0; + defining->defaults = NULL; + defining->dlist = NULL; + defining->expansion = NULL; + defining->next_active = istk->mstk; + defining->rep_nest = tmp_defining; + return DIRECTIVE_FOUND; + + case PP_ENDREP: + if (!defining || defining->name) { + error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'"); + return DIRECTIVE_FOUND; + } + + /* + * Now we have a "macro" defined - although it has no name + * and we won't be entering it in the hash tables - we must + * push a macro-end marker for it on to istk->expansion. + * After that, it will take care of propagating itself (a + * macro-end marker line for a macro which is really a %rep + * block will cause the macro to be re-expanded, complete + * with another macro-end marker to ensure the process + * continues) until the whole expansion is forcibly removed + * from istk->expansion by a %exitrep. + */ + l = nasm_malloc(sizeof(Line)); + l->next = istk->expansion; + l->finishes = defining; + l->first = NULL; + istk->expansion = l; + + istk->mstk = defining; + + list->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); + tmp_defining = defining; + defining = defining->rep_nest; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_EXITREP: + /* + * We must search along istk->expansion until we hit a + * macro-end marker for a macro with no name. Then we set + * its `in_progress' flag to 0. + */ + for (l = istk->expansion; l; l = l->next) + if (l->finishes && !l->finishes->name) + break; + + if (l) + l->finishes->in_progress = 0; + else + error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block"); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_XDEFINE: + case PP_IXDEFINE: + case PP_DEFINE: + case PP_IDEFINE: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) { + error(ERR_NONFATAL, + "`%%%s%sdefine' expects a macro identifier", + ((i == PP_IDEFINE || i == PP_IXDEFINE) ? "i" : ""), + ((i == PP_XDEFINE || i == PP_IXDEFINE) ? "x" : "")); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + param_start = tline = tline->next; + nparam = 0; + + /* Expand the macro definition now for %xdefine and %ixdefine */ + if ((i == PP_XDEFINE) || (i == PP_IXDEFINE)) + tline = expand_smacro(tline); + + if (tok_is_(tline, "(")) { + /* + * This macro has parameters. + */ + + tline = tline->next; + while (1) { + skip_white_(tline); + if (!tline) { + error(ERR_NONFATAL, "parameter identifier expected"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (tline->type != TOK_ID) { + error(ERR_NONFATAL, + "`%s': parameter identifier expected", + tline->text); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + tline->type = TOK_SMAC_PARAM + nparam++; + tline = tline->next; + skip_white_(tline); + if (tok_is_(tline, ",")) { + tline = tline->next; + continue; + } + if (!tok_is_(tline, ")")) { + error(ERR_NONFATAL, + "`)' expected to terminate macro template"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + break; + } + last = tline; + tline = tline->next; + } + if (tok_type_(tline, TOK_WHITESPACE)) + last = tline, tline = tline->next; + macro_start = NULL; + last->next = NULL; + t = tline; + while (t) { + if (t->type == TOK_ID) { + for (tt = param_start; tt; tt = tt->next) + if (tt->type >= TOK_SMAC_PARAM && + !strcmp(tt->text, t->text)) + t->type = tt->type; + } + tt = t->next; + t->next = macro_start; + macro_start = t; + t = tt; + } + /* + * Good. We now have a macro name, a parameter count, and a + * token list (in reverse order) for an expansion. We ought + * to be OK just to create an SMacro, store it, and let + * free_tlist have the rest of the line (which we have + * carefully re-terminated after chopping off the expansion + * from the end). + */ + if (smacro_defined(ctx, mname, nparam, &smac, i == PP_DEFINE)) { + if (!smac) { + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + free_tlist(origline); + free_tlist(macro_start); + return DIRECTIVE_FOUND; + } else { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } else { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = ((i == PP_DEFINE) || (i == PP_XDEFINE)); + smac->nparam = nparam; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_UNDEF: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) { + error(ERR_NONFATAL, "`%%undef' expects a macro identifier"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (tline->next) { + error(ERR_WARNING, + "trailing garbage after macro name ignored"); + } + + /* Find the context that symbol belongs to */ + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + + mname = tline->text; + last = tline; + last->next = NULL; + + /* + * We now have a macro name... go hunt for it. + */ + while (smacro_defined(ctx, mname, -1, &smac, 1)) { + /* Defined, so we need to find its predecessor and nuke it */ + SMacro **s; + for (s = smhead; *s && *s != smac; s = &(*s)->next) ; + if (*s) { + *s = smac->next; + nasm_free(smac->name); + free_tlist(smac->expansion); + nasm_free(smac); + } + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_STRLEN: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) { + error(ERR_NONFATAL, + "`%%strlen' expects a macro identifier as first parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + t = tline; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + /* t should now point to the string */ + if (t->type != TOK_STRING) { + error(ERR_NONFATAL, + "`%%strlen` requires string as second parameter"); + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + make_tok_num(macro_start, strlen(t->text) - 2); + macro_start->mac = NULL; + + /* + * We now have a macro name, an implicit parameter count of + * zero, and a numeric token to use as an expansion. Create + * and store an SMacro. + */ + if (smacro_defined(ctx, mname, 0, &smac, i == PP_STRLEN)) { + if (!smac) + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } else { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_STRLEN); + smac->nparam = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_SUBSTR: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) { + error(ERR_NONFATAL, + "`%%substr' expects a macro identifier as first parameter"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + t = tline->next; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + + /* t should now point to the string */ + if (t->type != TOK_STRING) { + error(ERR_NONFATAL, + "`%%substr` requires string as second parameter"); + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + tt = t->next; + tptr = &tt; + tokval.t_type = TOKEN_INVALID; + evalresult = + evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); + if (!evalresult) { + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + if (!is_simple(evalresult)) { + error(ERR_NONFATAL, "non-constant value given to `%%substr`"); + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + macro_start->text = nasm_strdup("'''"); + if (evalresult->value > 0 + && evalresult->value < strlen(t->text) - 1) { + macro_start->text[1] = t->text[evalresult->value]; + } else { + macro_start->text[2] = '\0'; + } + macro_start->type = TOK_STRING; + macro_start->mac = NULL; + + /* + * We now have a macro name, an implicit parameter count of + * zero, and a numeric token to use as an expansion. Create + * and store an SMacro. + */ + if (smacro_defined(ctx, mname, 0, &smac, i == PP_SUBSTR)) { + if (!smac) + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } else { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_SUBSTR); + smac->nparam = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(tline); + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_ASSIGN: + case PP_IASSIGN: + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) { + error(ERR_NONFATAL, + "`%%%sassign' expects a macro identifier", + (i == PP_IASSIGN ? "i" : "")); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + ctx = get_ctx(tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + t = tline; + tptr = &t; + tokval.t_type = TOKEN_INVALID; + evalresult = + evaluate(ppscan, tptr, &tokval, NULL, pass, error, NULL); + free_tlist(tline); + if (!evalresult) { + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + if (tokval.t_type) + error(ERR_WARNING, + "trailing garbage after expression ignored"); + + if (!is_simple(evalresult)) { + error(ERR_NONFATAL, + "non-constant value given to `%%%sassign'", + (i == PP_IASSIGN ? "i" : "")); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + make_tok_num(macro_start, reloc_value(evalresult)); + macro_start->mac = NULL; + + /* + * We now have a macro name, an implicit parameter count of + * zero, and a numeric token to use as an expansion. Create + * and store an SMacro. + */ + if (smacro_defined(ctx, mname, 0, &smac, i == PP_ASSIGN)) { + if (!smac) + error(ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free(smac->name); + free_tlist(smac->expansion); + } + } else { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_ASSIGN); + smac->nparam = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist(origline); + return DIRECTIVE_FOUND; + + case PP_LINE: + /* + * Syntax is `%line nnn[+mmm] [filename]' + */ + tline = tline->next; + skip_white_(tline); + if (!tok_type_(tline, TOK_NUMBER)) { + error(ERR_NONFATAL, "`%%line' expects line number"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + k = readnum(tline->text, &j); + m = 1; + tline = tline->next; + if (tok_is_(tline, "+")) { + tline = tline->next; + if (!tok_type_(tline, TOK_NUMBER)) { + error(ERR_NONFATAL, "`%%line' expects line increment"); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + m = readnum(tline->text, &j); + tline = tline->next; + } + skip_white_(tline); + src_set_linnum(k); + istk->lineinc = m; + if (tline) { + nasm_free(src_set_fname(detoken(tline, FALSE))); + } + free_tlist(origline); + return DIRECTIVE_FOUND; + + default: + error(ERR_FATAL, + "preprocessor directive `%s' not yet implemented", + directives[i]); + break; + } + return DIRECTIVE_FOUND; +} + +/* + * Ensure that a macro parameter contains a condition code and + * nothing else. Return the condition code index if so, or -1 + * otherwise. + */ +static int find_cc(Token * t) +{ + Token *tt; + int i, j, k, m; + + skip_white_(t); + if (t->type != TOK_ID) + return -1; + tt = t->next; + skip_white_(tt); + if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ","))) + return -1; + + i = -1; + j = elements(conditions); + while (j - i > 1) { + k = (j + i) / 2; + m = nasm_stricmp(t->text, conditions[k]); + if (m == 0) { + i = k; + j = -2; + break; + } else if (m < 0) { + j = k; + } else + i = k; + } + if (j != -2) + return -1; + return i; +} + +/* + * Expand MMacro-local things: parameter references (%0, %n, %+n, + * %-n) and MMacro-local identifiers (%%foo). + */ +static Token *expand_mmac_params(Token * tline) +{ + Token *t, *tt, **tail, *thead; + + tail = &thead; + thead = NULL; + + while (tline) { + if (tline->type == TOK_PREPROC_ID && + (((tline->text[1] == '+' || tline->text[1] == '-') + && tline->text[2]) || tline->text[1] == '%' + || (tline->text[1] >= '0' && tline->text[1] <= '9'))) { + char *text = NULL; + int type = 0, cc; /* type = 0 to placate optimisers */ + char tmpbuf[30]; + int n, i; + MMacro *mac; + + t = tline; + tline = tline->next; + + mac = istk->mstk; + while (mac && !mac->name) /* avoid mistaking %reps for macros */ + mac = mac->next_active; + if (!mac) + error(ERR_NONFATAL, "`%s': not in a macro call", t->text); + else + switch (t->text[1]) { + /* + * We have to make a substitution of one of the + * forms %1, %-1, %+1, %%foo, %0. + */ + case '0': + type = TOK_NUMBER; + snprintf(tmpbuf, sizeof(tmpbuf), "%d", mac->nparam); + text = nasm_strdup(tmpbuf); + break; + case '%': + type = TOK_ID; + snprintf(tmpbuf, sizeof(tmpbuf), "..@%lu.", + mac->unique); + text = nasm_strcat(tmpbuf, t->text + 2); + break; + case '-': + n = atoi(t->text + 2) - 1; + if (n >= mac->nparam) + tt = NULL; + else { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + cc = find_cc(tt); + if (cc == -1) { + error(ERR_NONFATAL, + "macro parameter %d is not a condition code", + n + 1); + text = NULL; + } else { + type = TOK_ID; + if (inverse_ccs[cc] == -1) { + error(ERR_NONFATAL, + "condition code `%s' is not invertible", + conditions[cc]); + text = NULL; + } else + text = + nasm_strdup(conditions[inverse_ccs[cc]]); + } + break; + case '+': + n = atoi(t->text + 2) - 1; + if (n >= mac->nparam) + tt = NULL; + else { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + cc = find_cc(tt); + if (cc == -1) { + error(ERR_NONFATAL, + "macro parameter %d is not a condition code", + n + 1); + text = NULL; + } else { + type = TOK_ID; + text = nasm_strdup(conditions[cc]); + } + break; + default: + n = atoi(t->text + 1) - 1; + if (n >= mac->nparam) + tt = NULL; + else { + if (mac->nparam > 1) + n = (n + mac->rotate) % mac->nparam; + tt = mac->params[n]; + } + if (tt) { + for (i = 0; i < mac->paramlen[n]; i++) { + *tail = new_Token(NULL, tt->type, tt->text, 0); + tail = &(*tail)->next; + tt = tt->next; + } + } + text = NULL; /* we've done it here */ + break; + } + if (!text) { + delete_Token(t); + } else { + *tail = t; + tail = &t->next; + t->type = type; + nasm_free(t->text); + t->text = text; + t->mac = NULL; + } + continue; + } else { + t = *tail = tline; + tline = tline->next; + t->mac = NULL; + tail = &t->next; + } + } + *tail = NULL; + t = thead; + for (; t && (tt = t->next) != NULL; t = t->next) + switch (t->type) { + case TOK_WHITESPACE: + if (tt->type == TOK_WHITESPACE) { + t->next = delete_Token(tt); + } + break; + case TOK_ID: + if (tt->type == TOK_ID || tt->type == TOK_NUMBER) { + char *tmp = nasm_strcat(t->text, tt->text); + nasm_free(t->text); + t->text = tmp; + t->next = delete_Token(tt); + } + break; + case TOK_NUMBER: + if (tt->type == TOK_NUMBER) { + char *tmp = nasm_strcat(t->text, tt->text); + nasm_free(t->text); + t->text = tmp; + t->next = delete_Token(tt); + } + break; + } + + return thead; +} + +/* + * Expand all single-line macro calls made in the given line. + * Return the expanded version of the line. The original is deemed + * to be destroyed in the process. (In reality we'll just move + * Tokens from input to output a lot of the time, rather than + * actually bothering to destroy and replicate.) + */ +static Token *expand_smacro(Token * tline) +{ + Token *t, *tt, *mstart, **tail, *thead; + SMacro *head = NULL, *m; + Token **params; + int *paramsize; + int nparam, sparam, brackets, rescan; + Token *org_tline = tline; + Context *ctx; + char *mname; + + /* + * Trick: we should avoid changing the start token pointer since it can + * be contained in "next" field of other token. Because of this + * we allocate a copy of first token and work with it; at the end of + * routine we copy it back + */ + if (org_tline) { + tline = + new_Token(org_tline->next, org_tline->type, org_tline->text, + 0); + tline->mac = org_tline->mac; + nasm_free(org_tline->text); + org_tline->text = NULL; + } + + again: + tail = &thead; + thead = NULL; + + while (tline) { /* main token loop */ + if ((mname = tline->text)) { + /* if this token is a local macro, look in local context */ + if (tline->type == TOK_ID || tline->type == TOK_PREPROC_ID) + ctx = get_ctx(mname, TRUE); + else + ctx = NULL; + if (!ctx) + head = smacros[hash(mname)]; + else + head = ctx->localmac; + /* + * We've hit an identifier. As in is_mmacro below, we first + * check whether the identifier is a single-line macro at + * all, then think about checking for parameters if + * necessary. + */ + for (m = head; m; m = m->next) + if (!mstrcmp(m->name, mname, m->casesense)) + break; + if (m) { + mstart = tline; + params = NULL; + paramsize = NULL; + if (m->nparam == 0) { + /* + * Simple case: the macro is parameterless. Discard the + * one token that the macro call took, and push the + * expansion back on the to-do stack. + */ + if (!m->expansion) { + if (!strcmp("__FILE__", m->name)) { + long num = 0; + src_get(&num, &(tline->text)); + nasm_quote(&(tline->text)); + tline->type = TOK_STRING; + continue; + } + if (!strcmp("__LINE__", m->name)) { + nasm_free(tline->text); + make_tok_num(tline, src_get_linnum()); + continue; + } + tline = delete_Token(tline); + continue; + } + } else { + /* + * Complicated case: at least one macro with this name + * exists and takes parameters. We must find the + * parameters in the call, count them, find the SMacro + * that corresponds to that form of the macro call, and + * substitute for the parameters when we expand. What a + * pain. + */ + /*tline = tline->next; + skip_white_(tline); */ + do { + t = tline->next; + while (tok_type_(t, TOK_SMAC_END)) { + t->mac->in_progress = FALSE; + t->text = NULL; + t = tline->next = delete_Token(t); + } + tline = t; + } while (tok_type_(tline, TOK_WHITESPACE)); + if (!tok_is_(tline, "(")) { + /* + * This macro wasn't called with parameters: ignore + * the call. (Behaviour borrowed from gnu cpp.) + */ + tline = mstart; + m = NULL; + } else { + int paren = 0; + int white = 0; + brackets = 0; + nparam = 0; + sparam = PARAM_DELTA; + params = nasm_malloc(sparam * sizeof(Token *)); + params[0] = tline->next; + paramsize = nasm_malloc(sparam * sizeof(int)); + paramsize[0] = 0; + while (TRUE) { /* parameter loop */ + /* + * For some unusual expansions + * which concatenates function call + */ + t = tline->next; + while (tok_type_(t, TOK_SMAC_END)) { + t->mac->in_progress = FALSE; + t->text = NULL; + t = tline->next = delete_Token(t); + } + tline = t; + + if (!tline) { + error(ERR_NONFATAL, + "macro call expects terminating `)'"); + break; + } + if (tline->type == TOK_WHITESPACE + && brackets <= 0) { + if (paramsize[nparam]) + white++; + else + params[nparam] = tline->next; + continue; /* parameter loop */ + } + if (tline->type == TOK_OTHER + && tline->text[1] == 0) { + char ch = tline->text[0]; + if (ch == ',' && !paren && brackets <= 0) { + if (++nparam >= sparam) { + sparam += PARAM_DELTA; + params = nasm_realloc(params, + sparam * + sizeof(Token + *)); + paramsize = + nasm_realloc(paramsize, + sparam * + sizeof(int)); + } + params[nparam] = tline->next; + paramsize[nparam] = 0; + white = 0; + continue; /* parameter loop */ + } + if (ch == '{' && + (brackets > 0 || (brackets == 0 && + !paramsize[nparam]))) + { + if (!(brackets++)) { + params[nparam] = tline->next; + continue; /* parameter loop */ + } + } + if (ch == '}' && brackets > 0) + if (--brackets == 0) { + brackets = -1; + continue; /* parameter loop */ + } + if (ch == '(' && !brackets) + paren++; + if (ch == ')' && brackets <= 0) + if (--paren < 0) + break; + } + if (brackets < 0) { + brackets = 0; + error(ERR_NONFATAL, "braces do not " + "enclose all of macro parameter"); + } + paramsize[nparam] += white + 1; + white = 0; + } /* parameter loop */ + nparam++; + while (m && (m->nparam != nparam || + mstrcmp(m->name, mname, + m->casesense))) + m = m->next; + if (!m) + error(ERR_WARNING | ERR_WARN_MNP, + "macro `%s' exists, " + "but not taking %d parameters", + mstart->text, nparam); + } + } + if (m && m->in_progress) + m = NULL; + if (!m) { /* in progess or didn't find '(' or wrong nparam */ + /* + * Design question: should we handle !tline, which + * indicates missing ')' here, or expand those + * macros anyway, which requires the (t) test a few + * lines down? + */ + nasm_free(params); + nasm_free(paramsize); + tline = mstart; + } else { + /* + * Expand the macro: we are placed on the last token of the + * call, so that we can easily split the call from the + * following tokens. We also start by pushing an SMAC_END + * token for the cycle removal. + */ + t = tline; + if (t) { + tline = t->next; + t->next = NULL; + } + tt = new_Token(tline, TOK_SMAC_END, NULL, 0); + tt->mac = m; + m->in_progress = TRUE; + tline = tt; + for (t = m->expansion; t; t = t->next) { + if (t->type >= TOK_SMAC_PARAM) { + Token *pcopy = tline, **ptail = &pcopy; + Token *ttt, *pt; + int i; + + ttt = params[t->type - TOK_SMAC_PARAM]; + for (i = paramsize[t->type - TOK_SMAC_PARAM]; + --i >= 0;) { + pt = *ptail = + new_Token(tline, ttt->type, ttt->text, + 0); + ptail = &pt->next; + ttt = ttt->next; + } + tline = pcopy; + } else { + tt = new_Token(tline, t->type, t->text, 0); + tline = tt; + } + } + + /* + * Having done that, get rid of the macro call, and clean + * up the parameters. + */ + nasm_free(params); + nasm_free(paramsize); + free_tlist(mstart); + continue; /* main token loop */ + } + } + } + + if (tline->type == TOK_SMAC_END) { + tline->mac->in_progress = FALSE; + tline = delete_Token(tline); + } else { + t = *tail = tline; + tline = tline->next; + t->mac = NULL; + t->next = NULL; + tail = &t->next; + } + } + + /* + * Now scan the entire line and look for successive TOK_IDs that resulted + * after expansion (they can't be produced by tokenise()). The successive + * TOK_IDs should be concatenated. + * Also we look for %+ tokens and concatenate the tokens before and after + * them (without white spaces in between). + */ + t = thead; + rescan = 0; + while (t) { + while (t && t->type != TOK_ID && t->type != TOK_PREPROC_ID) + t = t->next; + if (!t || !t->next) + break; + if (t->next->type == TOK_ID || + t->next->type == TOK_PREPROC_ID || + t->next->type == TOK_NUMBER) { + char *p = nasm_strcat(t->text, t->next->text); + nasm_free(t->text); + t->next = delete_Token(t->next); + t->text = p; + rescan = 1; + } else if (t->next->type == TOK_WHITESPACE && t->next->next && + t->next->next->type == TOK_PREPROC_ID && + strcmp(t->next->next->text, "%+") == 0) { + /* free the next whitespace, the %+ token and next whitespace */ + int i; + for (i = 1; i <= 3; i++) { + if (!t->next + || (i != 2 && t->next->type != TOK_WHITESPACE)) + break; + t->next = delete_Token(t->next); + } /* endfor */ + } else + t = t->next; + } + /* If we concatenaded something, re-scan the line for macros */ + if (rescan) { + tline = thead; + goto again; + } + + if (org_tline) { + if (thead) { + *org_tline = *thead; + /* since we just gave text to org_line, don't free it */ + thead->text = NULL; + delete_Token(thead); + } else { + /* the expression expanded to empty line; + we can't return NULL for some reasons + we just set the line to a single WHITESPACE token. */ + memset(org_tline, 0, sizeof(*org_tline)); + org_tline->text = NULL; + org_tline->type = TOK_WHITESPACE; + } + thead = org_tline; + } + + return thead; +} + +/* + * Similar to expand_smacro but used exclusively with macro identifiers + * right before they are fetched in. The reason is that there can be + * identifiers consisting of several subparts. We consider that if there + * are more than one element forming the name, user wants a expansion, + * otherwise it will be left as-is. Example: + * + * %define %$abc cde + * + * the identifier %$abc will be left as-is so that the handler for %define + * will suck it and define the corresponding value. Other case: + * + * %define _%$abc cde + * + * In this case user wants name to be expanded *before* %define starts + * working, so we'll expand %$abc into something (if it has a value; + * otherwise it will be left as-is) then concatenate all successive + * PP_IDs into one. + */ +static Token *expand_id(Token * tline) +{ + Token *cur, *oldnext = NULL; + + if (!tline || !tline->next) + return tline; + + cur = tline; + while (cur->next && + (cur->next->type == TOK_ID || + cur->next->type == TOK_PREPROC_ID + || cur->next->type == TOK_NUMBER)) + cur = cur->next; + + /* If identifier consists of just one token, don't expand */ + if (cur == tline) + return tline; + + if (cur) { + oldnext = cur->next; /* Detach the tail past identifier */ + cur->next = NULL; /* so that expand_smacro stops here */ + } + + tline = expand_smacro(tline); + + if (cur) { + /* expand_smacro possibly changhed tline; re-scan for EOL */ + cur = tline; + while (cur && cur->next) + cur = cur->next; + if (cur) + cur->next = oldnext; + } + + return tline; +} + +/* + * Determine whether the given line constitutes a multi-line macro + * call, and return the MMacro structure called if so. Doesn't have + * to check for an initial label - that's taken care of in + * expand_mmacro - but must check numbers of parameters. Guaranteed + * to be called with tline->type == TOK_ID, so the putative macro + * name is easy to find. + */ +static MMacro *is_mmacro(Token * tline, Token *** params_array) +{ + MMacro *head, *m; + Token **params; + int nparam; + + head = mmacros[hash(tline->text)]; + + /* + * Efficiency: first we see if any macro exists with the given + * name. If not, we can return NULL immediately. _Then_ we + * count the parameters, and then we look further along the + * list if necessary to find the proper MMacro. + */ + for (m = head; m; m = m->next) + if (!mstrcmp(m->name, tline->text, m->casesense)) + break; + if (!m) + return NULL; + + /* + * OK, we have a potential macro. Count and demarcate the + * parameters. + */ + count_mmac_params(tline->next, &nparam, ¶ms); + + /* + * So we know how many parameters we've got. Find the MMacro + * structure that handles this number. + */ + while (m) { + if (m->nparam_min <= nparam + && (m->plus || nparam <= m->nparam_max)) { + /* + * This one is right. Just check if cycle removal + * prohibits us using it before we actually celebrate... + */ + if (m->in_progress) { +#if 0 + error(ERR_NONFATAL, + "self-reference in multi-line macro `%s'", m->name); +#endif + nasm_free(params); + return NULL; + } + /* + * It's right, and we can use it. Add its default + * parameters to the end of our list if necessary. + */ + if (m->defaults && nparam < m->nparam_min + m->ndefs) { + params = + nasm_realloc(params, + ((m->nparam_min + m->ndefs + + 1) * sizeof(*params))); + while (nparam < m->nparam_min + m->ndefs) { + params[nparam] = m->defaults[nparam - m->nparam_min]; + nparam++; + } + } + /* + * If we've gone over the maximum parameter count (and + * we're in Plus mode), ignore parameters beyond + * nparam_max. + */ + if (m->plus && nparam > m->nparam_max) + nparam = m->nparam_max; + /* + * Then terminate the parameter list, and leave. + */ + if (!params) { /* need this special case */ + params = nasm_malloc(sizeof(*params)); + nparam = 0; + } + params[nparam] = NULL; + *params_array = params; + return m; + } + /* + * This one wasn't right: look for the next one with the + * same name. + */ + for (m = m->next; m; m = m->next) + if (!mstrcmp(m->name, tline->text, m->casesense)) + break; + } + + /* + * After all that, we didn't find one with the right number of + * parameters. Issue a warning, and fail to expand the macro. + */ + error(ERR_WARNING | ERR_WARN_MNP, + "macro `%s' exists, but not taking %d parameters", + tline->text, nparam); + nasm_free(params); + return NULL; +} + +/* + * Expand the multi-line macro call made by the given line, if + * there is one to be expanded. If there is, push the expansion on + * istk->expansion and return 1. Otherwise return 0. + */ +static int expand_mmacro(Token * tline) +{ + Token *startline = tline; + Token *label = NULL; + int dont_prepend = 0; + Token **params, *t, *tt; + MMacro *m; + Line *l, *ll; + int i, nparam, *paramlen; + + t = tline; + skip_white_(t); +/* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */ + if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID)) + return 0; + m = is_mmacro(t, ¶ms); + if (!m) { + Token *last; + /* + * We have an id which isn't a macro call. We'll assume + * it might be a label; we'll also check to see if a + * colon follows it. Then, if there's another id after + * that lot, we'll check it again for macro-hood. + */ + label = last = t; + t = t->next; + if (tok_type_(t, TOK_WHITESPACE)) + last = t, t = t->next; + if (tok_is_(t, ":")) { + dont_prepend = 1; + last = t, t = t->next; + if (tok_type_(t, TOK_WHITESPACE)) + last = t, t = t->next; + } + if (!tok_type_(t, TOK_ID) || (m = is_mmacro(t, ¶ms)) == NULL) + return 0; + last->next = NULL; + tline = t; + } + + /* + * Fix up the parameters: this involves stripping leading and + * trailing whitespace, then stripping braces if they are + * present. + */ + for (nparam = 0; params[nparam]; nparam++) ; + paramlen = nparam ? nasm_malloc(nparam * sizeof(*paramlen)) : NULL; + + for (i = 0; params[i]; i++) { + int brace = FALSE; + int comma = (!m->plus || i < nparam - 1); + + t = params[i]; + skip_white_(t); + if (tok_is_(t, "{")) + t = t->next, brace = TRUE, comma = FALSE; + params[i] = t; + paramlen[i] = 0; + while (t) { + if (comma && t->type == TOK_OTHER && !strcmp(t->text, ",")) + break; /* ... because we have hit a comma */ + if (comma && t->type == TOK_WHITESPACE + && tok_is_(t->next, ",")) + break; /* ... or a space then a comma */ + if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}")) + break; /* ... or a brace */ + t = t->next; + paramlen[i]++; + } + } + + /* + * OK, we have a MMacro structure together with a set of + * parameters. We must now go through the expansion and push + * copies of each Line on to istk->expansion. Substitution of + * parameter tokens and macro-local tokens doesn't get done + * until the single-line macro substitution process; this is + * because delaying them allows us to change the semantics + * later through %rotate. + * + * First, push an end marker on to istk->expansion, mark this + * macro as in progress, and set up its invocation-specific + * variables. + */ + ll = nasm_malloc(sizeof(Line)); + ll->next = istk->expansion; + ll->finishes = m; + ll->first = NULL; + istk->expansion = ll; + + m->in_progress = TRUE; + m->params = params; + m->iline = tline; + m->nparam = nparam; + m->rotate = 0; + m->paramlen = paramlen; + m->unique = unique++; + m->lineno = 0; + + m->next_active = istk->mstk; + istk->mstk = m; + + for (l = m->expansion; l; l = l->next) { + Token **tail; + + ll = nasm_malloc(sizeof(Line)); + ll->finishes = NULL; + ll->next = istk->expansion; + istk->expansion = ll; + tail = &ll->first; + + for (t = l->first; t; t = t->next) { + Token *x = t; + if (t->type == TOK_PREPROC_ID && + t->text[1] == '0' && t->text[2] == '0') { + dont_prepend = -1; + x = label; + if (!x) + continue; + } + tt = *tail = new_Token(NULL, x->type, x->text, 0); + tail = &tt->next; + } + *tail = NULL; + } + + /* + * If we had a label, push it on as the first line of + * the macro expansion. + */ + if (label) { + if (dont_prepend < 0) + free_tlist(startline); + else { + ll = nasm_malloc(sizeof(Line)); + ll->finishes = NULL; + ll->next = istk->expansion; + istk->expansion = ll; + ll->first = startline; + if (!dont_prepend) { + while (label->next) + label = label->next; + label->next = tt = new_Token(NULL, TOK_OTHER, ":", 0); + } + } + } + + list->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); + + return 1; +} + +/* + * Since preprocessor always operate only on the line that didn't + * arrived yet, we should always use ERR_OFFBY1. Also since user + * won't want to see same error twice (preprocessing is done once + * per pass) we will want to show errors only during pass one. + */ +static void error(int severity, const char *fmt, ...) +{ + va_list arg; + char buff[1024]; + + /* If we're in a dead branch of IF or something like it, ignore the error */ + if (istk && istk->conds && !emitting(istk->conds->state)) + return; + + va_start(arg, fmt); + vsnprintf(buff, sizeof(buff), fmt, arg); + va_end(arg); + + if (istk && istk->mstk && istk->mstk->name) + _error(severity | ERR_PASS1, "(%s:%d) %s", istk->mstk->name, + istk->mstk->lineno, buff); + else + _error(severity | ERR_PASS1, "%s", buff); +} + +static void +pp_reset(char *file, int apass, efunc errfunc, evalfunc eval, + ListGen * listgen) +{ + int h; + + _error = errfunc; + cstk = NULL; + istk = nasm_malloc(sizeof(Include)); + istk->next = NULL; + istk->conds = NULL; + istk->expansion = NULL; + istk->mstk = NULL; + istk->fp = fopen(file, "r"); + istk->fname = NULL; + src_set_fname(nasm_strdup(file)); + src_set_linnum(0); + istk->lineinc = 1; + if (!istk->fp) + error(ERR_FATAL | ERR_NOFILE, "unable to open input file `%s'", + file); + defining = NULL; + for (h = 0; h < NHASH; h++) { + mmacros[h] = NULL; + smacros[h] = NULL; + } + unique = 0; + if (tasm_compatible_mode) { + stdmacpos = stdmac; + } else { + stdmacpos = &stdmac[TASM_MACRO_COUNT]; + } + any_extrastdmac = (extrastdmac != NULL); + list = listgen; + evaluate = eval; + pass = apass; +} + +static char *pp_getline(void) +{ + char *line; + Token *tline; + + while (1) { + /* + * Fetch a tokenised line, either from the macro-expansion + * buffer or from the input file. + */ + tline = NULL; + while (istk->expansion && istk->expansion->finishes) { + Line *l = istk->expansion; + if (!l->finishes->name && l->finishes->in_progress > 1) { + Line *ll; + + /* + * This is a macro-end marker for a macro with no + * name, which means it's not really a macro at all + * but a %rep block, and the `in_progress' field is + * more than 1, meaning that we still need to + * repeat. (1 means the natural last repetition; 0 + * means termination by %exitrep.) We have + * therefore expanded up to the %endrep, and must + * push the whole block on to the expansion buffer + * again. We don't bother to remove the macro-end + * marker: we'd only have to generate another one + * if we did. + */ + l->finishes->in_progress--; + for (l = l->finishes->expansion; l; l = l->next) { + Token *t, *tt, **tail; + + ll = nasm_malloc(sizeof(Line)); + ll->next = istk->expansion; + ll->finishes = NULL; + ll->first = NULL; + tail = &ll->first; + + for (t = l->first; t; t = t->next) { + if (t->text || t->type == TOK_WHITESPACE) { + tt = *tail = + new_Token(NULL, t->type, t->text, 0); + tail = &tt->next; + } + } + + istk->expansion = ll; + } + } else { + /* + * Check whether a `%rep' was started and not ended + * within this macro expansion. This can happen and + * should be detected. It's a fatal error because + * I'm too confused to work out how to recover + * sensibly from it. + */ + if (defining) { + if (defining->name) + error(ERR_PANIC, + "defining with name in expansion"); + else if (istk->mstk->name) + error(ERR_FATAL, + "`%%rep' without `%%endrep' within" + " expansion of macro `%s'", + istk->mstk->name); + } + + /* + * FIXME: investigate the relationship at this point between + * istk->mstk and l->finishes + */ + { + MMacro *m = istk->mstk; + istk->mstk = m->next_active; + if (m->name) { + /* + * This was a real macro call, not a %rep, and + * therefore the parameter information needs to + * be freed. + */ + nasm_free(m->params); + free_tlist(m->iline); + nasm_free(m->paramlen); + l->finishes->in_progress = FALSE; + } else + free_mmacro(m); + } + istk->expansion = l->next; + nasm_free(l); + list->downlevel(LIST_MACRO); + } + } + while (1) { /* until we get a line we can use */ + + if (istk->expansion) { /* from a macro expansion */ + char *p; + Line *l = istk->expansion; + if (istk->mstk) + istk->mstk->lineno++; + tline = l->first; + istk->expansion = l->next; + nasm_free(l); + p = detoken(tline, FALSE); + list->line(LIST_MACRO, p); + nasm_free(p); + break; + } + line = read_line(); + if (line) { /* from the current input file */ + line = prepreproc(line); + tline = tokenise(line); + nasm_free(line); + break; + } + /* + * The current file has ended; work down the istk + */ + { + Include *i = istk; + fclose(i->fp); + if (i->conds) + error(ERR_FATAL, + "expected `%%endif' before end of file"); + /* only set line and file name if there's a next node */ + if (i->next) { + src_set_linnum(i->lineno); + nasm_free(src_set_fname(i->fname)); + } + istk = i->next; + list->downlevel(LIST_INCLUDE); + nasm_free(i); + if (!istk) + return NULL; + } + } + + /* + * We must expand MMacro parameters and MMacro-local labels + * _before_ we plunge into directive processing, to cope + * with things like `%define something %1' such as STRUC + * uses. Unless we're _defining_ a MMacro, in which case + * those tokens should be left alone to go into the + * definition; and unless we're in a non-emitting + * condition, in which case we don't want to meddle with + * anything. + */ + if (!defining && !(istk->conds && !emitting(istk->conds->state))) + tline = expand_mmac_params(tline); + + /* + * Check the line to see if it's a preprocessor directive. + */ + if (do_directive(tline) == DIRECTIVE_FOUND) { + continue; + } else if (defining) { + /* + * We're defining a multi-line macro. We emit nothing + * at all, and just + * shove the tokenised line on to the macro definition. + */ + Line *l = nasm_malloc(sizeof(Line)); + l->next = defining->expansion; + l->first = tline; + l->finishes = FALSE; + defining->expansion = l; + continue; + } else if (istk->conds && !emitting(istk->conds->state)) { + /* + * We're in a non-emitting branch of a condition block. + * Emit nothing at all, not even a blank line: when we + * emerge from the condition we'll give a line-number + * directive so we keep our place correctly. + */ + free_tlist(tline); + continue; + } else if (istk->mstk && !istk->mstk->in_progress) { + /* + * We're in a %rep block which has been terminated, so + * we're walking through to the %endrep without + * emitting anything. Emit nothing at all, not even a + * blank line: when we emerge from the %rep block we'll + * give a line-number directive so we keep our place + * correctly. + */ + free_tlist(tline); + continue; + } else { + tline = expand_smacro(tline); + if (!expand_mmacro(tline)) { + /* + * De-tokenise the line again, and emit it. + */ + line = detoken(tline, TRUE); + free_tlist(tline); + break; + } else { + continue; /* expand_mmacro calls free_tlist */ + } + } + } + + return line; +} + +static void pp_cleanup(int pass) +{ + int h; + + if (defining) { + error(ERR_NONFATAL, "end of file while still defining macro `%s'", + defining->name); + free_mmacro(defining); + } + while (cstk) + ctx_pop(); + for (h = 0; h < NHASH; h++) { + while (mmacros[h]) { + MMacro *m = mmacros[h]; + mmacros[h] = mmacros[h]->next; + free_mmacro(m); + } + while (smacros[h]) { + SMacro *s = smacros[h]; + smacros[h] = smacros[h]->next; + nasm_free(s->name); + free_tlist(s->expansion); + nasm_free(s); + } + } + while (istk) { + Include *i = istk; + istk = istk->next; + fclose(i->fp); + nasm_free(i->fname); + nasm_free(i); + } + while (cstk) + ctx_pop(); + if (pass == 0) { + free_llist(predef); + delete_Blocks(); + } +} + +void pp_include_path(char *path) +{ + IncPath *i; +/* by alexfru: order of path inclusion fixed (was reverse order) */ + i = nasm_malloc(sizeof(IncPath)); + i->path = nasm_strdup(path); + i->next = NULL; + + if (ipath != NULL) { + IncPath *j = ipath; + while (j->next != NULL) + j = j->next; + j->next = i; + } else { + ipath = i; + } +} + +/* + * added by alexfru: + * + * This function is used to "export" the include paths, e.g. + * the paths specified in the '-I' command switch. + * The need for such exporting is due to the 'incbin' directive, + * which includes raw binary files (unlike '%include', which + * includes text source files). It would be real nice to be + * able to specify paths to search for incbin'ned files also. + * So, this is a simple workaround. + * + * The function use is simple: + * + * The 1st call (with NULL argument) returns a pointer to the 1st path + * (char** type) or NULL if none include paths available. + * + * All subsequent calls take as argument the value returned by this + * function last. The return value is either the next path + * (char** type) or NULL if the end of the paths list is reached. + * + * It is maybe not the best way to do things, but I didn't want + * to export too much, just one or two functions and no types or + * variables exported. + * + * Can't say I like the current situation with e.g. this path list either, + * it seems to be never deallocated after creation... + */ +char **pp_get_include_path_ptr(char **pPrevPath) +{ +/* This macro returns offset of a member of a structure */ +#define GetMemberOffset(StructType,MemberName)\ + ((size_t)&((StructType*)0)->MemberName) + IncPath *i; + + if (pPrevPath == NULL) { + if (ipath != NULL) + return &ipath->path; + else + return NULL; + } + i = (IncPath *) ((char *)pPrevPath - GetMemberOffset(IncPath, path)); + i = i->next; + if (i != NULL) + return &i->path; + else + return NULL; +#undef GetMemberOffset +} + +void pp_pre_include(char *fname) +{ + Token *inc, *space, *name; + Line *l; + + name = new_Token(NULL, TOK_INTERNAL_STRING, fname, 0); + space = new_Token(name, TOK_WHITESPACE, NULL, 0); + inc = new_Token(space, TOK_PREPROC_ID, "%include", 0); + + l = nasm_malloc(sizeof(Line)); + l->next = predef; + l->first = inc; + l->finishes = FALSE; + predef = l; +} + +void pp_pre_define(char *definition) +{ + Token *def, *space; + Line *l; + char *equals; + + equals = strchr(definition, '='); + space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); + def = new_Token(space, TOK_PREPROC_ID, "%define", 0); + if (equals) + *equals = ' '; + space->next = tokenise(definition); + if (equals) + *equals = '='; + + l = nasm_malloc(sizeof(Line)); + l->next = predef; + l->first = def; + l->finishes = FALSE; + predef = l; +} + +void pp_pre_undefine(char *definition) +{ + Token *def, *space; + Line *l; + + space = new_Token(NULL, TOK_WHITESPACE, NULL, 0); + def = new_Token(space, TOK_PREPROC_ID, "%undef", 0); + space->next = tokenise(definition); + + l = nasm_malloc(sizeof(Line)); + l->next = predef; + l->first = def; + l->finishes = FALSE; + predef = l; +} + +void pp_extra_stdmac(const char **macros) +{ + extrastdmac = macros; +} + +static void make_tok_num(Token * tok, long val) +{ + char numbuf[20]; + snprintf(numbuf, sizeof(numbuf), "%ld", val); + tok->text = nasm_strdup(numbuf); + tok->type = TOK_NUMBER; +} + +Preproc nasmpp = { + pp_reset, + pp_getline, + pp_cleanup +}; diff --git a/preproc.h b/preproc.h index e196d38e..62755b2e 100644 --- a/preproc.h +++ b/preproc.h @@ -9,12 +9,12 @@ #ifndef NASM_PREPROC_H #define NASM_PREPROC_H -void pp_include_path (char *); -char** pp_get_include_path_ptr (char **pPrevPath); -void pp_pre_include (char *); -void pp_pre_define (char *); -void pp_pre_undefine (char *); -void pp_extra_stdmac (const char **); +void pp_include_path(char *); +char **pp_get_include_path_ptr(char **pPrevPath); +void pp_pre_include(char *); +void pp_pre_define(char *); +void pp_pre_undefine(char *); +void pp_extra_stdmac(const char **); extern Preproc nasmpp; diff --git a/rdoff/collectn.c b/rdoff/collectn.c index 71dc10e7..ad43d856 100644 --- a/rdoff/collectn.c +++ b/rdoff/collectn.c @@ -12,19 +12,19 @@ void collection_init(Collection * c) int i; for (i = 0; i < 32; i++) - c->p[i] = NULL; + c->p[i] = NULL; c->next = NULL; } void **colln(Collection * c, int index) { while (index >= 32) { - index -= 32; - if (c->next == NULL) { - c->next = malloc(sizeof(Collection)); - collection_init(c->next); - } - c = c->next; + index -= 32; + if (c->next == NULL) { + c->next = malloc(sizeof(Collection)); + collection_init(c->next); + } + c = c->next; } return &(c->p[index]); } @@ -34,11 +34,11 @@ void collection_reset(Collection * c) int i; if (c->next) { - collection_reset(c->next); - free(c->next); + collection_reset(c->next); + free(c->next); } c->next = NULL; for (i = 0; i < 32; i++) - c->p[i] = NULL; + c->p[i] = NULL; } diff --git a/rdoff/collectn.h b/rdoff/collectn.h index dc4f7ccd..52647d1f 100644 --- a/rdoff/collectn.h +++ b/rdoff/collectn.h @@ -10,13 +10,13 @@ #define _COLLECTN_H typedef struct tagCollection { - void *p[32]; /* array of pointers to objects */ - + void *p[32]; /* array of pointers to objects */ + struct tagCollection *next; } Collection; -void collection_init(Collection * c); -void ** colln(Collection * c, int index); -void collection_reset(Collection * c); +void collection_init(Collection * c); +void **colln(Collection * c, int index); +void collection_reset(Collection * c); #endif diff --git a/rdoff/hash.c b/rdoff/hash.c dissimilarity index 89% index 7f28f12b..933754ab 100644 --- a/rdoff/hash.c +++ b/rdoff/hash.c @@ -1,94 +1,94 @@ -/* hash.h Routines to calculate a CRC32 hash value - * - * These routines donated to the NASM effort by Graeme Defty. - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ - -#include "hash.h" - -typedef unsigned int crc32; - -const crc32 consttab[] = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; - -unsigned -hash (const char *name) -{ - register const char *n; - register crc32 hashval = 0xffffffff; - - for (n=name; *n ; n++) - hashval = (hashval>>8) ^ consttab[(hashval^*n) & 0xff]; - - hashval ^= 0xffffffff; - - return (hashval); - -} +/* hash.h Routines to calculate a CRC32 hash value + * + * These routines donated to the NASM effort by Graeme Defty. + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include "hash.h" + +typedef unsigned int crc32; + +const crc32 consttab[] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +unsigned hash(const char *name) +{ + register const char *n; + register crc32 hashval = 0xffffffff; + + for (n = name; *n; n++) + hashval = (hashval >> 8) ^ consttab[(hashval ^ *n) & 0xff]; + + hashval ^= 0xffffffff; + + return (hashval); + +} diff --git a/rdoff/hash.h b/rdoff/hash.h index 2ccf9b96..cda4f61c 100644 --- a/rdoff/hash.h +++ b/rdoff/hash.h @@ -8,5 +8,4 @@ * distributed in the NASM archive. */ -unsigned hash (const char* name); - +unsigned hash(const char *name); diff --git a/rdoff/ldrdf.c b/rdoff/ldrdf.c dissimilarity index 67% index 22e077e6..977aeb8c 100644 --- a/rdoff/ldrdf.c +++ b/rdoff/ldrdf.c @@ -1,1297 +1,1328 @@ -/* - * ldrdf.c - RDOFF Object File linker/loader main program. - * - * Copyright (c) 1996,99 Julian Hall. All rights reserved. - * Improvements and fixes (c) 1999-2004 RET & COM Research. - * - * This file is distributed under the terms and conditions of the - * GNU Lesser Public License (LGPL), version 2.1. - * See http://www.gnu.org/copyleft/lgpl.html for details. - */ - -/* - * TODO: - * - enhance search of required export symbols in libraries (now depends - * on modules order in library) - * - keep a cache of symbol names in each library module so - * we don't have to constantly recheck the file - * - general performance improvements - * - * BUGS & LIMITATIONS: this program doesn't support multiple code, data - * or bss segments, therefore for 16 bit programs whose code, data or BSS - * segment exceeds 64K in size, it will not work. This program probably - * won't work if compiled by a 16 bit compiler. Try DJGPP if you're running - * under DOS. '#define STINGY_MEMORY' may help a little. - */ - -#include -#include -#include - -#define RDOFF_UTILS - -#include "rdoff.h" -#include "symtab.h" -#include "collectn.h" -#include "rdlib.h" -#include "segtab.h" - -#define LDRDF_VERSION "1.07" - -/* #define STINGY_MEMORY */ - -/* ======================================================================= - * Types & macros that are private to this program - */ - -struct segment_infonode { - int dest_seg; /* output segment to be placed into, -1 to - skip linking this segment */ - long reloc; /* segment's relocation factor */ -}; - - -struct modulenode { - rdffile f; /* the RDOFF file structure */ - struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing - with each segment? */ - void * header; - char * name; - struct modulenode * next; - long bss_reloc; -}; - -#include "ldsegs.h" - -#define newstr(str) strcpy(malloc(strlen(str) + 1),str) -#define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2) - -/* ========================================================================== - * Function prototypes of private utility functions - */ - -void processmodule(const char * filename, struct modulenode * mod); -int allocnewseg(uint16 type,uint16 reserved); -int findsegment(uint16 type,uint16 reserved); -void symtab_add(const char * symbol, int segment, long offset); -int symtab_get(const char * symbol, int * segment, long * offset); - -/* ========================================================================= - * Global data structures. - */ - -/* a linked list of modules that will be included in the output */ -struct modulenode * modules = NULL; -struct modulenode * lastmodule = NULL; - -/* a linked list of libraries to be searched for unresolved imported symbols */ -struct librarynode * libraries = NULL; -struct librarynode * lastlib = NULL; - -/* the symbol table */ -void * symtab = NULL; - -/* objects search path */ -char * objpath = NULL; - -/* libraries search path */ -char * libpath = NULL; - -/* file to embed as a generic record */ -char * generic_rec_file = NULL; - -/* error file */ -static FILE * error_file; - -/* the header of the output file, built up stage by stage */ -rdf_headerbuf * newheader = NULL; - -/* The current state of segment allocation, including information about - * which output segment numbers have been allocated, and their types and - * amount of data which has already been allocated inside them. - */ -struct SegmentHeaderRec outputseg[RDF_MAXSEGS]; -int nsegs = 0; -long bss_length; - -/* global options which affect how the program behaves */ -struct ldrdfoptions { - int verbose; - int align; - int dynalink; - int strip; - int respfile; - int stderr_redir; - int objpath; - int libpath; -} options; - -int errorcount = 0; /* determines main program exit status */ - - -/* ========================================================================= - * Utility functions - */ - -/* - * initsegments() - * - * sets up segments 0, 1, and 2, the initial code data and bss segments - */ -void initsegments() -{ - nsegs = 3; - outputseg[0].type = 1; - outputseg[0].number = 0; - outputseg[0].reserved = 0; - outputseg[0].length = 0; - outputseg[1].type = 2; - outputseg[1].number = 1; - outputseg[1].reserved = 0; - outputseg[1].length = 0; - outputseg[2].type = 0xFFFF; /* reserved segment type */ - outputseg[2].number = 2; - outputseg[2].reserved = 0; - outputseg[2].length = 0; - bss_length = 0; -} - - -/* - * loadmodule - * - * Determine the characteristics of a module, and decide what to do with - * each segment it contains (including determining destination segments and - * relocation factors for segments that are kept). - */ -void loadmodule(const char * filename) -{ - if (options.verbose) - printf("loading `%s'\n", filename); - - /* allocate a new module entry on the end of the modules list */ - if (!modules) { - modules = malloc (sizeof(*modules)); - lastmodule = modules; - } else { - lastmodule->next = malloc (sizeof(*modules)); - lastmodule = lastmodule->next; - } - - if (!lastmodule) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - - /* open the file using 'rdfopen', which returns nonzero on error */ - if (rdfopen(&lastmodule->f, filename) != 0) { - rdfperror("ldrdf", filename); - exit(1); - } - - /* - * store information about the module, and determine what segments - * it contains, and what we should do with them (determine relocation - * factor if we decide to keep them) - */ - lastmodule->header = NULL; - lastmodule->name = strdup(filename); - lastmodule->next = NULL; - - processmodule(filename, lastmodule); -} - - -/* - * processmodule() - * - * step through each segment, determine what exactly we're doing with - * it, and if we intend to keep it, determine (a) which segment to - * put it in and (b) whereabouts in that segment it will end up. - * (b) is fairly easy, because we're now keeping track of how big each - * segment in our output file is... - */ -void processmodule(const char * filename, struct modulenode * mod) -{ - struct segconfig sconf; - int seg, outseg; - void * header; - rdfheaderrec * hr; - long bssamount = 0; - int bss_was_referenced = 0; - - for (seg = 0; seg < mod->f.nsegs; seg++) { - /* - * get the segment configuration for this type from the segment - * table. getsegconfig() is a macro, defined in ldsegs.h. - */ - getsegconfig(sconf, mod->f.seg[seg].type); - - if (options.verbose > 1) { - printf ("%s %04x [%04x:%10s] ", filename, mod->f.seg[seg].number, - mod->f.seg[seg].type, sconf.typedesc); - } - /* - * sconf->dowhat tells us what to do with a segment of this type. - */ - switch (sconf.dowhat) { - case SEG_IGNORE: - /* - * Set destination segment to -1, to indicate that this segment - * should be ignored for the purpose of output, ie it is left - * out of the linked executable. - */ - mod->seginfo[seg].dest_seg = -1; - if (options.verbose > 1) printf("IGNORED\n"); - break; - - case SEG_NEWSEG: - /* - * The configuration tells us to create a new segment for - * each occurrence of this segment type. - */ - outseg = allocnewseg(sconf.mergetype, - mod->f.seg[seg].reserved); - mod->seginfo[seg].dest_seg = outseg; - mod->seginfo[seg].reloc = 0; - outputseg[outseg].length = mod->f.seg[seg].length; - if (options.verbose > 1) - printf ("=> %04x:%08lx (+%04lx)\n", outseg, - mod->seginfo[seg].reloc, - mod->f.seg[seg].length); - break; - - case SEG_MERGE: - /* - * The configuration tells us to merge the segment with - * a previously existing segment of type 'sconf.mergetype', - * if one exists. Otherwise a new segment is created. - * This is handled transparently by 'findsegment()'. - */ - outseg = findsegment(sconf.mergetype, - mod->f.seg[seg].reserved); - mod->seginfo[seg].dest_seg = outseg; - - /* - * We need to add alignment to these segments. - */ - if (outputseg[outseg].length % options.align != 0) - outputseg[outseg].length += - options.align - (outputseg[outseg].length % options.align); - - mod->seginfo[seg].reloc = outputseg[outseg].length; - outputseg[outseg].length += mod->f.seg[seg].length; - - if (options.verbose > 1) - printf ("=> %04x:%08lx (+%04lx)\n", outseg, - mod->seginfo[seg].reloc, - mod->f.seg[seg].length); - } - - } - - /* - * extract symbols from the header, and dump them into the - * symbol table - */ - header = malloc(mod->f.header_len); - if (!header) { - fprintf(stderr, "ldrdf: not enough memory\n"); - exit(1); - } - if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) { - rdfperror("ldrdf", filename); - exit(1); - } - - while ((hr = rdfgetheaderrec (&mod->f))) { - switch(hr->type) { - case RDFREC_IMPORT: /* imported symbol */ - case RDFREC_FARIMPORT: - /* Define with seg = -1 */ - symtab_add(hr->i.label, -1, 0); - break; - - case RDFREC_GLOBAL: { /* exported symbol */ - int destseg; - long destreloc; - - if (hr->e.segment == 2) { - bss_was_referenced = 1; - destreloc = bss_length; - if (destreloc % options.align != 0) - destreloc += options.align - (destreloc % options.align); - destseg = 2; - } else { - if ((destseg = mod->seginfo[(int)hr->e.segment].dest_seg) == -1) - continue; - destreloc = mod->seginfo[(int)hr->e.segment].reloc; - } - symtab_add(hr->e.label, destseg, destreloc + hr->e.offset); - break; - } - - case RDFREC_BSS: /* BSS reservation */ - /* - * first, amalgamate all BSS reservations in this module - * into one, because we allow this in the output format. - */ - bssamount += hr->b.amount; - break; - - case RDFREC_COMMON: { /* Common variable */ - symtabEnt *ste = symtabFind(symtab, hr->c.label); - - /* Is the symbol already in the table? */ - if (ste) break; - - /* Align the variable */ - if (bss_length % hr->c.align != 0) - bss_length += hr->c.align - (bss_length % hr->c.align); - if (options.verbose > 1) { - printf ("%s %04x common '%s' => 0002:%08lx (+%04lx)\n", - filename, hr->c.segment, hr->c.label, bss_length, hr->c.size); - } - - symtab_add(hr->c.label, 2, bss_length); - mod->bss_reloc = bss_length; - bss_length += hr->c.size; - break; - } - } - } - - if (bssamount != 0 || bss_was_referenced) { - /* - * handle the BSS segment - first pad the existing bss length - * to the correct alignment, then store the length in bss_reloc - * for this module. Then add this module's BSS length onto - * bss_length. - */ - if (bss_length % options.align != 0) - bss_length += options.align - (bss_length % options.align); - - mod->bss_reloc = bss_length; - if (options.verbose > 1) { - printf ("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n", - filename, bss_length, bssamount); - } - bss_length += bssamount; - } - -#ifdef STINGY_MEMORY - /* - * we free the header buffer here, to save memory later. - * this isn't efficient, but probably halves the memory usage - * of this program... - */ - mod->f.header_loc = NULL; - free(header); - -#endif - -} - - -/* - * Return 1 if a given module is in the list, 0 otherwise. - */ -int lookformodule(const char *name) -{ - struct modulenode *curr = modules; - - while(curr) { - if (!strcmp(name, curr->name)) return 1; - curr = curr->next; - } - return 0; -} - - -/* - * allocnewseg() - * findsegment() - * - * These functions manipulate the array of output segments, and are used - * by processmodule(). allocnewseg() allocates a segment in the array, - * initialising it to be empty. findsegment() first scans the array for - * a segment of the type requested, and if one isn't found allocates a - * new one. - */ -int allocnewseg(uint16 type,uint16 reserved) -{ - outputseg[nsegs].type = type; - outputseg[nsegs].number = nsegs; - outputseg[nsegs].reserved = reserved; - outputseg[nsegs].length = 0; - outputseg[nsegs].offset = 0; - outputseg[nsegs].data = NULL; - - return nsegs++; -} - -int findsegment(uint16 type,uint16 reserved) -{ - int i; - - for (i = 0; i < nsegs; i++) - if (outputseg[i].type == type) return i; - - return allocnewseg(type,reserved); -} - - -/* - * symtab_add() - * - * inserts a symbol into the global symbol table, which associates symbol - * names either with addresses, or a marker that the symbol hasn't been - * resolved yet, or possibly that the symbol has been defined as - * contained in a dynamic [load time/run time] linked library. - * - * segment = -1 => not yet defined - * segment = -2 => defined as dll symbol - * - * If the symbol is already defined, and the new segment >= 0, then - * if the original segment was < 0 the symbol is redefined, otherwise - * a duplicate symbol warning is issued. If new segment == -1, this - * routine won't change a previously existing symbol. It will change - * to segment = -2 only if the segment was previously < 0. - */ -void symtab_add(const char * symbol, int segment, long offset) -{ - symtabEnt * ste; - - ste = symtabFind(symtab, symbol); - if (ste) { - if (ste->segment >= 0) { - /* - * symbol previously defined - */ - if (segment < 0) return; - fprintf (error_file, "warning: `%s' redefined\n", symbol); - return; - } - - /* - * somebody wanted the symbol, and put an undefined symbol - * marker into the table - */ - if (segment == -1) return; - /* - * we have more information now - update the symbol's entry - */ - ste->segment = segment; - ste->offset = offset; - ste->flags = 0; - return; - } - /* - * this is the first declaration of this symbol - */ - ste = malloc(sizeof(symtabEnt)); - if (!ste) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - ste->name = strdup(symbol); - ste->segment = segment; - ste->offset = offset; - ste->flags = 0; - symtabInsert(symtab, ste); -} - -/* - * symtab_get() - * - * Retrieves the values associated with a symbol. Undefined symbols - * are assumed to have -1:0 associated. Returns 1 if the symbol was - * successfully located. - */ -int symtab_get(const char * symbol, int * segment, long * offset) -{ - symtabEnt * ste = symtabFind(symtab, symbol); - if (!ste) { - *segment = -1; - *offset = 0; - return 0; - } else { - *segment = ste->segment; - *offset = ste->offset; - return 1; - } -} - - -/* - * add_library() - * - * checks that a library can be opened and is in the correct format, - * then adds it to the linked list of libraries. - */ -void add_library(const char * name) -{ - if (rdl_verify(name)) { - rdl_perror("ldrdf", name); - errorcount++; - return; - } - if (!libraries) { - lastlib = libraries = malloc(sizeof(*libraries)); - if (! libraries) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - } else { - lastlib->next = malloc(sizeof(*libraries)); - if (!lastlib->next) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - lastlib = lastlib->next; - } - lastlib->next = NULL; - if (rdl_open(lastlib, name)) { - rdl_perror("ldrdf", name); - errorcount++; - return; - } -} - - -/* - * search_libraries() - * - * scans through the list of libraries, attempting to match symbols - * defined in library modules against symbols that are referenced but - * not defined (segment = -1 in the symbol table) - * - * returns 1 if any extra library modules are included, indicating that - * another pass through the library list should be made (possibly). - */ -int search_libraries() -{ - struct librarynode * cur; - rdffile f; - int i; - void * header; - int segment; - long offset; - int doneanything = 0, pass = 1, keepfile; - rdfheaderrec * hr; - - cur = libraries; - - while (cur) { - if (options.verbose > 2) - printf("scanning library `%s', pass %d...\n", cur->name, pass); - - for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) { - if (pass == 2 && lookformodule(f.name)) continue; - - if (options.verbose > 3) - printf(" looking in module `%s'\n", f.name); - - header = malloc(f.header_len); - if (!header) { - fprintf(stderr, "ldrdf: not enough memory\n"); - exit(1); - } - if (rdfloadseg(&f, RDOFF_HEADER, header)) { - rdfperror("ldrdf", f.name); - errorcount++; - return 0; - } - - keepfile = 0; - - while ((hr = rdfgetheaderrec (&f))) { - /* We're only interested in exports, so skip others */ - if (hr->type != RDFREC_GLOBAL) continue; - - /* - * If the symbol is marked as SYM_GLOBAL, somebody will be - * definitely interested in it.. - */ - if ((hr->e.flags & SYM_GLOBAL) == 0) { - /* - * otherwise the symbol is just public. Find it in - * the symbol table. If the symbol isn't defined, we - * aren't interested, so go on to the next. - * If it is defined as anything but -1, we're also not - * interested. But if it is defined as -1, insert this - * module into the list of modules to use, and go - * immediately on to the next module... - */ - if (!symtab_get(hr->e.label, &segment, &offset) || segment != -1) - continue; - } - - doneanything = 1; - keepfile = 1; - - /* - * as there are undefined symbols, we can assume that - * there are modules on the module list by the time - * we get here. - */ - lastmodule->next = malloc(sizeof(*lastmodule->next)); - if (!lastmodule->next) { - fprintf(stderr, "ldrdf: not enough memory\n"); - exit(1); - } - lastmodule = lastmodule->next; - memcpy(&lastmodule->f, &f, sizeof(f)); - lastmodule->name = strdup(f.name); - lastmodule->next = NULL; - processmodule(f.name, lastmodule); - break; - } - if (!keepfile) { - free(f.name); - f.name = NULL; - f.fp = NULL; - } - } - if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND) - rdl_perror("ldrdf", cur->name); - - cur = cur->next; - if (cur == NULL && pass == 1) { - cur = libraries; - pass++; - } - } - - return doneanything; -} - - -/* - * write_output() - * - * this takes the linked list of modules, and walks through it, merging - * all the modules into a single output module, and then writes this to a - * file. - */ -void write_output(const char * filename) -{ - FILE * f; - rdf_headerbuf * rdfheader; - struct modulenode * cur; - int i, availableseg, seg, localseg, isrelative; - void * header; - rdfheaderrec * hr, newrec; - symtabEnt * se; - segtab segs; - long offset; - byte * data; - - if ((f = fopen(filename, "wb"))==NULL) { - fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename); - exit(1); - } - if ((rdfheader=rdfnewheader())==NULL) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - - /* - * If '-g' option was given, first record in output file will be a - * `generic' record, filled with a given file content. - * This can be useful, for example, when constructing multiboot - * compliant kernels. - */ - if (generic_rec_file) { - FILE *ff; - - if (options.verbose) - printf("\nadding generic record from binary file %s\n", generic_rec_file); - - hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec)); - if ((ff = fopen(generic_rec_file, "r")) == NULL) { - fprintf(stderr, "ldrdf: couldn't open %s for input\n", generic_rec_file); - exit(1); - } - i = fread(hr->g.data, 1, sizeof(hr->g.data), ff); - fseek(ff, 0, SEEK_END); - if (ftell(ff) > sizeof(hr->g.data)) { - fprintf (error_file, "warning: maximum generic record size is %d, rest of file ignored\n", sizeof(hr->g.data)); - } - fclose(ff); - - hr->g.type = 0; - hr->g.reclen = i; - rdfaddheader(rdfheader, hr); - free(hr); - } - - if (options.verbose) - printf ("\nbuilding output module (%d segments)\n", nsegs); - - /* - * Allocate the memory for the segments. We may be better off - * building the output module one segment at a time when running - * under 16 bit DOS, but that would be a slower way of doing this. - * And you could always use DJGPP... - */ - for (i = 0; i < nsegs; i++) { - outputseg[i].data=NULL; - if(!outputseg[i].length) continue; - outputseg[i].data = malloc(outputseg[i].length); - if (!outputseg[i].data) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - } - - /* - * initialise availableseg, used to allocate segment numbers for - * imported and exported labels... - */ - availableseg = nsegs; - - /* - * Step through the modules, performing required actions on each one - */ - for (cur = modules; cur; cur=cur->next) { - /* - * Read the actual segment contents into the correct places in - * the newly allocated segments - */ - - for (i = 0; i < cur->f.nsegs; i++) { - int dest = cur->seginfo[i].dest_seg; - - if (dest == -1) continue; - if (rdfloadseg(&cur->f, i, - outputseg[dest].data + cur->seginfo[i].reloc)) { - rdfperror("ldrdf", cur->name); - exit(1); - } - } - - /* - * Perform fixups, and add new header records where required - */ - - header = malloc(cur->f.header_len); - if (!header) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - - if (cur->f.header_loc) - rdfheaderrewind(&cur->f); - else - if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) { - rdfperror("ldrdf", cur->name); - exit(1); - } - - /* - * we need to create a local segment number -> location - * table for the segments in this module. - */ - init_seglocations(&segs); - for (i = 0; i < cur->f.nsegs; i++) { - add_seglocation(&segs, cur->f.seg[i].number, - cur->seginfo[i].dest_seg, cur->seginfo[i].reloc); - } - /* - * and the BSS segment (doh!) - */ - add_seglocation(&segs, 2, 2, cur->bss_reloc); - - while ((hr = rdfgetheaderrec(&cur->f))) { - switch(hr->type) { - case RDFREC_RELOC: /* relocation record - need to do a fixup */ - /* - * First correct the offset stored in the segment from - * the start of the segment (which may well have changed). - * - * To do this we add to the number stored the relocation - * factor associated with the segment that contains the - * target segment. - * - * The relocation could be a relative relocation, in which - * case we have to first subtract the amount we've relocated - * the containing segment by. - */ - if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) { - fprintf(stderr, "%s: reloc to undefined segment %04x\n", - cur->name, (int) hr->r.refseg); - errorcount++; - break; - } - - isrelative = (hr->r.segment & RDOFF_RELATIVEMASK) == RDOFF_RELATIVEMASK; - hr->r.segment &= (RDOFF_RELATIVEMASK-1); - - if (hr->r.segment == 2 || - (localseg = rdffindsegment(&cur->f, hr->r.segment)) == -1) { - fprintf(stderr, "%s: reloc from %s segment (%d)\n", - cur->name, - hr->r.segment == 2 ? "BSS" : "unknown", - hr->r.segment); - errorcount++; - break; - } - - if (hr->r.length != 1 && hr->r.length != 2 && - hr->r.length != 4 ) { - fprintf(stderr, "%s: nonstandard length reloc " - "(%d bytes)\n", cur->name, hr->r.length); - errorcount++; - break; - } - - /* - * okay, now the relocation is in the segment pointed to by - * cur->seginfo[localseg], and we know everything else is - * okay to go ahead and do the relocation - */ - data = outputseg[cur->seginfo[localseg].dest_seg].data; - data += cur->seginfo[localseg].reloc + hr->r.offset; - - /* - * data now points to the reference that needs - * relocation. Calculate the relocation factor. - * Factor is: - * offset of referred object in segment [in offset] - * (- relocation of localseg, if ref is relative) - * For simplicity, the result is stored in 'offset'. - * Then add 'offset' onto the value at data. - */ - - if (isrelative) - offset -= cur->seginfo[localseg].reloc; - switch (hr->r.length) { - case 1: - offset += *data; - if (offset < -127 || offset > 128) - fprintf(error_file, "warning: relocation out of range " - "at %s(%02x:%08lx)\n", cur->name, - (int)hr->r.segment, hr->r.offset); - *data = (char) offset; - break; - case 2: - offset += * (short *)data; - if (offset < -32767 || offset > 32768) - fprintf(error_file, "warning: relocation out of range " - "at %s(%02x:%08lx)\n", cur->name, - (int)hr->r.segment, hr->r.offset); - * (short *)data = (short) offset; - break; - case 4: - * (long *)data += offset; - /* we can't easily detect overflow on this one */ - break; - } - - /* - * If the relocation was relative between two symbols in - * the same segment, then we're done. - * - * Otherwise, we need to output a new relocation record - * with the references updated segment and offset... - */ - if (!isrelative || cur->seginfo[localseg].dest_seg != seg) { - hr->r.segment = cur->seginfo[localseg].dest_seg; - hr->r.offset += cur->seginfo[localseg].reloc; - hr->r.refseg = seg; - if (isrelative) - hr->r.segment += RDOFF_RELATIVEMASK; - rdfaddheader(rdfheader, hr); - } - break; - - case RDFREC_IMPORT: /* import symbol */ - case RDFREC_FARIMPORT: - /* - * scan the global symbol table for the symbol - * and associate its location with the segment number - * for this module - */ - se = symtabFind(symtab, hr->i.label); - if (!se || se->segment == -1) { - if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) { - fprintf(error_file, "error: unresolved reference to `%s'" - " in module `%s'\n", hr->i.label, cur->name); - errorcount++; - } - /* - * we need to allocate a segment number for this - * symbol, and store it in the symbol table for - * future reference - */ - if (!se) { - se=malloc(sizeof(*se)); - if (!se) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - se->name = strdup(hr->i.label); - se->flags = 0; - se->segment = availableseg++; - se->offset = 0; - symtabInsert(symtab, se); - } - else { - se->segment = availableseg++; - se->offset = 0; - } - /* - * output a header record that imports it to the - * recently allocated segment number... - */ - newrec = *hr; - newrec.i.segment = se->segment; - rdfaddheader(rdfheader, &newrec); - } - - add_seglocation(&segs, hr->i.segment, se->segment, se->offset); - break; - - case RDFREC_GLOBAL: /* export symbol */ - /* - * need to insert an export for this symbol into the new - * header, unless we're stripping symbols. Even if we're - * stripping, put the symbol if it's marked as SYM_GLOBAL. - */ - if (options.strip && !(hr->e.flags & SYM_GLOBAL)) - break; - - if (hr->e.segment == 2) { - seg = 2; - offset = cur->bss_reloc; - } - else { - localseg = rdffindsegment(&cur->f, hr->e.segment); - if (localseg == -1) { - fprintf(stderr, "%s: exported symbol `%s' from " - "unrecognised segment\n", cur->name, - hr->e.label); - errorcount++; - break; - } - offset = cur->seginfo[localseg].reloc; - seg = cur->seginfo[localseg].dest_seg; - } - - hr->e.segment = seg; - hr->e.offset += offset; - rdfaddheader(rdfheader, hr); - break; - - case RDFREC_MODNAME: /* module name */ - /* - * Insert module name record if export symbols - * are not stripped. - * If module name begins with '$' - insert it anyway. - */ - if (options.strip && hr->m.modname[0] != '$') break; - rdfaddheader(rdfheader, hr); - break; - - case RDFREC_DLL: /* DLL name */ - /* - * Insert DLL name if it begins with '$' - */ - if (hr->d.libname[0] != '$') break; - rdfaddheader(rdfheader, hr); - break; - - case RDFREC_SEGRELOC: /* segment fixup */ - /* - * modify the segment numbers if necessary, and - * pass straight through to the output module header - * - * *** FIXME *** - */ - if (hr->r.segment == 2) { - fprintf(stderr, "%s: segment fixup in BSS section\n", - cur->name); - errorcount++; - break; - } - localseg = rdffindsegment(&cur->f, hr->r.segment); - if (localseg == -1) { - fprintf(stderr, "%s: segment fixup in unrecognised" - " segment (%d)\n", cur->name, hr->r.segment); - errorcount++; - break; - } - hr->r.segment = cur->seginfo[localseg].dest_seg; - hr->r.offset += cur->seginfo[localseg].reloc; - - if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) { - fprintf(stderr, "%s: segment fixup to undefined " - "segment %04x\n", cur->name, (int)hr->r.refseg); - errorcount++; - break; - } - hr->r.refseg = seg; - rdfaddheader(rdfheader, hr); - break; - - case RDFREC_COMMON: /* Common variable */ - /* Is this symbol already in the table? */ - se = symtabFind(symtab, hr->c.label); - if (!se) { - printf("%s is not in symtab yet\n", hr->c.label); - break; - } - /* Add segment location */ - add_seglocation(&segs, hr->c.segment, se->segment, se->offset); - break; - } - } - - free(header); - done_seglocations(&segs); - - } - - /* - * combined BSS reservation for the entire results - */ - newrec.type = RDFREC_BSS; - newrec.b.reclen = 4; - newrec.b.amount = bss_length; - rdfaddheader(rdfheader, &newrec); - - /* - * Write the header - */ - for (i = 0; i < nsegs; i++) { - if (i == 2) continue; - rdfaddsegment (rdfheader, outputseg[i].length); - } - - rdfwriteheader(f, rdfheader); - rdfdoneheader(rdfheader); - - /* - * Step through the segments, one at a time, writing out into - * the output file - */ - for (i = 0; i < nsegs; i++) { - uint16 s; - long l; - - if (i == 2) continue; - - s = translateshort(outputseg[i].type); - fwrite(&s, 2, 1, f); - s = translateshort(outputseg[i].number); - fwrite(&s, 2, 1, f); - s = translateshort(outputseg[i].reserved); - fwrite(&s, 2, 1, f); - l = translatelong(outputseg[i].length); - fwrite(&l, 4, 1, f); - - fwrite(outputseg[i].data, outputseg[i].length, 1, f); - } - - fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f); -} - -/* ========================================================================= - * Main program - */ - -void usage() -{ - printf("usage:\n" - " ldrdf [options] object modules ... [-llibrary ...]\n" - " ldrdf -r\n" - "options:\n" - " -v[=n] increase verbosity by 1, or set it to n\n" - " -a nn set segment alignment value (default 16)\n" - " -s strip public symbols\n" - " -dy Unix-style dynamic linking\n" - " -o name write output in file 'name'\n" - " -j path specify objects search path\n" - " -L path specify libraries search path\n" - " -g file embed 'file' as a first header record with type 'generic'\n"); - exit(0); -} - -int main(int argc, char ** argv) -{ - char * outname = "aout.rdf"; - int moduleloaded = 0; - char *respstrings[128] = {0, }; - - options.verbose = 0; - options.align = 16; - options.dynalink = 0; - options.strip = 0; - - error_file = stderr; - - argc--, argv++; - if (argc == 0) usage(); - while (argc && *argv && **argv == '-' && argv[0][1] != 'l') { - switch(argv[0][1]) { - case 'r': - printf("ldrdf (linker for RDF files) version " LDRDF_VERSION "\n"); - printf("RDOFF2 revision %s\n", RDOFF2_REVISION); - exit(0); - case 'v': - if (argv[0][2] == '=') { - options.verbose = argv[0][3] - '0'; - if (options.verbose < 0 || options.verbose > 9) { - fprintf(stderr, "ldrdf: verbosity level must be a number" - " between 0 and 9\n"); - exit(1); - } - } - else - options.verbose++; - break; - case 'a': - options.align = atoi(argv[1]); - if (options.align <= 0) { - fprintf(stderr, - "ldrdf: -a expects a positive number argument\n"); - exit(1); - } - argv++, argc--; - break; - case 's': - options.strip = 1; - break; - case 'd': - if (argv[0][2] == 'y') options.dynalink = 1; - break; - case 'o': - outname = argv[1]; - argv++, argc--; - break; - case 'j': - if (!objpath) { - options.objpath = 1; - objpath = argv[1]; - argv++, argc--; - break; - } else { - fprintf(stderr,"ldrdf: more than one objects search path specified\n"); - exit(1); - } - case 'L': - if (!libpath) { - options.libpath = 1; - libpath = argv[1]; - argv++, argc--; - break; - } else { - fprintf(stderr,"ldrdf: more than one libraries search path specified\n"); - exit(1); - } - case '@': { - int i=0; - char buf[256]; - FILE *f; - - options.respfile = 1; - if (argv[1] != NULL) f = fopen(argv[1],"r"); - else { - fprintf(stderr,"ldrdf: no response file name specified\n"); - exit(1); - } - - if (f == NULL) { - fprintf(stderr,"ldrdf: unable to open response file\n"); - exit(1); - } - - argv++, argc--; - while (fgets(buf, sizeof(buf), f) != NULL) { - char *p; - if (buf[0]=='\n') continue; - if ((p = strchr(buf,'\n')) != NULL) *p = '\0'; - if (i >= 128) { - fprintf(stderr,"ldrdf: too many input files\n"); - exit(1); - } - *(respstrings + i) = newstr(buf); - argc++, i++; - } - break; - } - case '2': - options.stderr_redir = 1; - error_file = stdout; - break; - case 'g': - generic_rec_file = argv[1]; - argv++, argc--; - break; - default: - usage(); - } - argv++, argc--; - } - - if (options.verbose > 4) { - printf("ldrdf invoked with options:\n"); - printf(" section alignment: %d bytes\n", options.align); - printf(" output name: `%s'\n", outname); - if (options.strip) - printf(" strip symbols\n"); - if (options.dynalink) - printf(" Unix-style dynamic linking\n"); - if (options.objpath) - printf(" objects search path: %s\n", objpath); - if (options.libpath) - printf(" libraries search path: %s\n", libpath); - printf("\n"); - } - - symtab = symtabNew(); - initsegments(); - - if (!symtab) { - fprintf(stderr, "ldrdf: out of memory\n"); - exit(1); - } - - while (argc) { - if (!*argv) argv = respstrings; - if (!*argv) break; - if (!strncmp(*argv, "-l", 2)) { - if(libpath && (argv[0][2] != '/')) - add_library(newstrcat(libpath,*argv + 2)); - else - add_library(*argv + 2); - } else { - if(objpath && (argv[0][0] != '/')) - loadmodule(newstrcat(objpath, *argv)); - else - loadmodule(*argv); - moduleloaded = 1; - } - argv++, argc--; - } - - if (! moduleloaded) { - printf("ldrdf: nothing to do. ldrdf -h for usage\n"); - return 0; - } - - search_libraries(); - - if (options.verbose > 2) - { - printf ("symbol table:\n"); - symtabDump(symtab, stdout); - } - - write_output(outname); - - if (errorcount > 0) exit(1); - return 0; -} - +/* + * ldrdf.c - RDOFF Object File linker/loader main program. + * + * Copyright (c) 1996,99 Julian Hall. All rights reserved. + * Improvements and fixes (c) 1999-2004 RET & COM Research. + * + * This file is distributed under the terms and conditions of the + * GNU Lesser Public License (LGPL), version 2.1. + * See http://www.gnu.org/copyleft/lgpl.html for details. + */ + +/* + * TODO: + * - enhance search of required export symbols in libraries (now depends + * on modules order in library) + * - keep a cache of symbol names in each library module so + * we don't have to constantly recheck the file + * - general performance improvements + * + * BUGS & LIMITATIONS: this program doesn't support multiple code, data + * or bss segments, therefore for 16 bit programs whose code, data or BSS + * segment exceeds 64K in size, it will not work. This program probably + * won't work if compiled by a 16 bit compiler. Try DJGPP if you're running + * under DOS. '#define STINGY_MEMORY' may help a little. + */ + +#include +#include +#include + +#define RDOFF_UTILS + +#include "rdoff.h" +#include "symtab.h" +#include "collectn.h" +#include "rdlib.h" +#include "segtab.h" + +#define LDRDF_VERSION "1.07" + +/* #define STINGY_MEMORY */ + +/* ======================================================================= + * Types & macros that are private to this program + */ + +struct segment_infonode { + int dest_seg; /* output segment to be placed into, -1 to + skip linking this segment */ + long reloc; /* segment's relocation factor */ +}; + +struct modulenode { + rdffile f; /* the RDOFF file structure */ + struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing + with each segment? */ + void *header; + char *name; + struct modulenode *next; + long bss_reloc; +}; + +#include "ldsegs.h" + +#define newstr(str) strcpy(malloc(strlen(str) + 1),str) +#define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1)+strlen(s2)+1),s1),s2) + +/* ========================================================================== + * Function prototypes of private utility functions + */ + +void processmodule(const char *filename, struct modulenode *mod); +int allocnewseg(uint16 type, uint16 reserved); +int findsegment(uint16 type, uint16 reserved); +void symtab_add(const char *symbol, int segment, long offset); +int symtab_get(const char *symbol, int *segment, long *offset); + +/* ========================================================================= + * Global data structures. + */ + +/* a linked list of modules that will be included in the output */ +struct modulenode *modules = NULL; +struct modulenode *lastmodule = NULL; + +/* a linked list of libraries to be searched for unresolved imported symbols */ +struct librarynode *libraries = NULL; +struct librarynode *lastlib = NULL; + +/* the symbol table */ +void *symtab = NULL; + +/* objects search path */ +char *objpath = NULL; + +/* libraries search path */ +char *libpath = NULL; + +/* file to embed as a generic record */ +char *generic_rec_file = NULL; + +/* error file */ +static FILE *error_file; + +/* the header of the output file, built up stage by stage */ +rdf_headerbuf *newheader = NULL; + +/* The current state of segment allocation, including information about + * which output segment numbers have been allocated, and their types and + * amount of data which has already been allocated inside them. + */ +struct SegmentHeaderRec outputseg[RDF_MAXSEGS]; +int nsegs = 0; +long bss_length; + +/* global options which affect how the program behaves */ +struct ldrdfoptions { + int verbose; + int align; + int dynalink; + int strip; + int respfile; + int stderr_redir; + int objpath; + int libpath; +} options; + +int errorcount = 0; /* determines main program exit status */ + +/* ========================================================================= + * Utility functions + */ + +/* + * initsegments() + * + * sets up segments 0, 1, and 2, the initial code data and bss segments + */ +void initsegments() +{ + nsegs = 3; + outputseg[0].type = 1; + outputseg[0].number = 0; + outputseg[0].reserved = 0; + outputseg[0].length = 0; + outputseg[1].type = 2; + outputseg[1].number = 1; + outputseg[1].reserved = 0; + outputseg[1].length = 0; + outputseg[2].type = 0xFFFF; /* reserved segment type */ + outputseg[2].number = 2; + outputseg[2].reserved = 0; + outputseg[2].length = 0; + bss_length = 0; +} + +/* + * loadmodule + * + * Determine the characteristics of a module, and decide what to do with + * each segment it contains (including determining destination segments and + * relocation factors for segments that are kept). + */ +void loadmodule(const char *filename) +{ + if (options.verbose) + printf("loading `%s'\n", filename); + + /* allocate a new module entry on the end of the modules list */ + if (!modules) { + modules = malloc(sizeof(*modules)); + lastmodule = modules; + } else { + lastmodule->next = malloc(sizeof(*modules)); + lastmodule = lastmodule->next; + } + + if (!lastmodule) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + + /* open the file using 'rdfopen', which returns nonzero on error */ + if (rdfopen(&lastmodule->f, filename) != 0) { + rdfperror("ldrdf", filename); + exit(1); + } + + /* + * store information about the module, and determine what segments + * it contains, and what we should do with them (determine relocation + * factor if we decide to keep them) + */ + lastmodule->header = NULL; + lastmodule->name = strdup(filename); + lastmodule->next = NULL; + + processmodule(filename, lastmodule); +} + +/* + * processmodule() + * + * step through each segment, determine what exactly we're doing with + * it, and if we intend to keep it, determine (a) which segment to + * put it in and (b) whereabouts in that segment it will end up. + * (b) is fairly easy, because we're now keeping track of how big each + * segment in our output file is... + */ +void processmodule(const char *filename, struct modulenode *mod) +{ + struct segconfig sconf; + int seg, outseg; + void *header; + rdfheaderrec *hr; + long bssamount = 0; + int bss_was_referenced = 0; + + for (seg = 0; seg < mod->f.nsegs; seg++) { + /* + * get the segment configuration for this type from the segment + * table. getsegconfig() is a macro, defined in ldsegs.h. + */ + getsegconfig(sconf, mod->f.seg[seg].type); + + if (options.verbose > 1) { + printf("%s %04x [%04x:%10s] ", filename, + mod->f.seg[seg].number, mod->f.seg[seg].type, + sconf.typedesc); + } + /* + * sconf->dowhat tells us what to do with a segment of this type. + */ + switch (sconf.dowhat) { + case SEG_IGNORE: + /* + * Set destination segment to -1, to indicate that this segment + * should be ignored for the purpose of output, ie it is left + * out of the linked executable. + */ + mod->seginfo[seg].dest_seg = -1; + if (options.verbose > 1) + printf("IGNORED\n"); + break; + + case SEG_NEWSEG: + /* + * The configuration tells us to create a new segment for + * each occurrence of this segment type. + */ + outseg = allocnewseg(sconf.mergetype, + mod->f.seg[seg].reserved); + mod->seginfo[seg].dest_seg = outseg; + mod->seginfo[seg].reloc = 0; + outputseg[outseg].length = mod->f.seg[seg].length; + if (options.verbose > 1) + printf("=> %04x:%08lx (+%04lx)\n", outseg, + mod->seginfo[seg].reloc, mod->f.seg[seg].length); + break; + + case SEG_MERGE: + /* + * The configuration tells us to merge the segment with + * a previously existing segment of type 'sconf.mergetype', + * if one exists. Otherwise a new segment is created. + * This is handled transparently by 'findsegment()'. + */ + outseg = findsegment(sconf.mergetype, + mod->f.seg[seg].reserved); + mod->seginfo[seg].dest_seg = outseg; + + /* + * We need to add alignment to these segments. + */ + if (outputseg[outseg].length % options.align != 0) + outputseg[outseg].length += + options.align - + (outputseg[outseg].length % options.align); + + mod->seginfo[seg].reloc = outputseg[outseg].length; + outputseg[outseg].length += mod->f.seg[seg].length; + + if (options.verbose > 1) + printf("=> %04x:%08lx (+%04lx)\n", outseg, + mod->seginfo[seg].reloc, mod->f.seg[seg].length); + } + + } + + /* + * extract symbols from the header, and dump them into the + * symbol table + */ + header = malloc(mod->f.header_len); + if (!header) { + fprintf(stderr, "ldrdf: not enough memory\n"); + exit(1); + } + if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) { + rdfperror("ldrdf", filename); + exit(1); + } + + while ((hr = rdfgetheaderrec(&mod->f))) { + switch (hr->type) { + case RDFREC_IMPORT: /* imported symbol */ + case RDFREC_FARIMPORT: + /* Define with seg = -1 */ + symtab_add(hr->i.label, -1, 0); + break; + + case RDFREC_GLOBAL:{ /* exported symbol */ + int destseg; + long destreloc; + + if (hr->e.segment == 2) { + bss_was_referenced = 1; + destreloc = bss_length; + if (destreloc % options.align != 0) + destreloc += + options.align - (destreloc % options.align); + destseg = 2; + } else { + if ((destseg = + mod->seginfo[(int)hr->e.segment].dest_seg) == -1) + continue; + destreloc = mod->seginfo[(int)hr->e.segment].reloc; + } + symtab_add(hr->e.label, destseg, destreloc + hr->e.offset); + break; + } + + case RDFREC_BSS: /* BSS reservation */ + /* + * first, amalgamate all BSS reservations in this module + * into one, because we allow this in the output format. + */ + bssamount += hr->b.amount; + break; + + case RDFREC_COMMON:{ /* Common variable */ + symtabEnt *ste = symtabFind(symtab, hr->c.label); + + /* Is the symbol already in the table? */ + if (ste) + break; + + /* Align the variable */ + if (bss_length % hr->c.align != 0) + bss_length += hr->c.align - (bss_length % hr->c.align); + if (options.verbose > 1) { + printf("%s %04x common '%s' => 0002:%08lx (+%04lx)\n", + filename, hr->c.segment, hr->c.label, + bss_length, hr->c.size); + } + + symtab_add(hr->c.label, 2, bss_length); + mod->bss_reloc = bss_length; + bss_length += hr->c.size; + break; + } + } + } + + if (bssamount != 0 || bss_was_referenced) { + /* + * handle the BSS segment - first pad the existing bss length + * to the correct alignment, then store the length in bss_reloc + * for this module. Then add this module's BSS length onto + * bss_length. + */ + if (bss_length % options.align != 0) + bss_length += options.align - (bss_length % options.align); + + mod->bss_reloc = bss_length; + if (options.verbose > 1) { + printf("%s 0002 [ BSS] => 0002:%08lx (+%04lx)\n", + filename, bss_length, bssamount); + } + bss_length += bssamount; + } +#ifdef STINGY_MEMORY + /* + * we free the header buffer here, to save memory later. + * this isn't efficient, but probably halves the memory usage + * of this program... + */ + mod->f.header_loc = NULL; + free(header); + +#endif + +} + +/* + * Return 1 if a given module is in the list, 0 otherwise. + */ +int lookformodule(const char *name) +{ + struct modulenode *curr = modules; + + while (curr) { + if (!strcmp(name, curr->name)) + return 1; + curr = curr->next; + } + return 0; +} + +/* + * allocnewseg() + * findsegment() + * + * These functions manipulate the array of output segments, and are used + * by processmodule(). allocnewseg() allocates a segment in the array, + * initialising it to be empty. findsegment() first scans the array for + * a segment of the type requested, and if one isn't found allocates a + * new one. + */ +int allocnewseg(uint16 type, uint16 reserved) +{ + outputseg[nsegs].type = type; + outputseg[nsegs].number = nsegs; + outputseg[nsegs].reserved = reserved; + outputseg[nsegs].length = 0; + outputseg[nsegs].offset = 0; + outputseg[nsegs].data = NULL; + + return nsegs++; +} + +int findsegment(uint16 type, uint16 reserved) +{ + int i; + + for (i = 0; i < nsegs; i++) + if (outputseg[i].type == type) + return i; + + return allocnewseg(type, reserved); +} + +/* + * symtab_add() + * + * inserts a symbol into the global symbol table, which associates symbol + * names either with addresses, or a marker that the symbol hasn't been + * resolved yet, or possibly that the symbol has been defined as + * contained in a dynamic [load time/run time] linked library. + * + * segment = -1 => not yet defined + * segment = -2 => defined as dll symbol + * + * If the symbol is already defined, and the new segment >= 0, then + * if the original segment was < 0 the symbol is redefined, otherwise + * a duplicate symbol warning is issued. If new segment == -1, this + * routine won't change a previously existing symbol. It will change + * to segment = -2 only if the segment was previously < 0. + */ +void symtab_add(const char *symbol, int segment, long offset) +{ + symtabEnt *ste; + + ste = symtabFind(symtab, symbol); + if (ste) { + if (ste->segment >= 0) { + /* + * symbol previously defined + */ + if (segment < 0) + return; + fprintf(error_file, "warning: `%s' redefined\n", symbol); + return; + } + + /* + * somebody wanted the symbol, and put an undefined symbol + * marker into the table + */ + if (segment == -1) + return; + /* + * we have more information now - update the symbol's entry + */ + ste->segment = segment; + ste->offset = offset; + ste->flags = 0; + return; + } + /* + * this is the first declaration of this symbol + */ + ste = malloc(sizeof(symtabEnt)); + if (!ste) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + ste->name = strdup(symbol); + ste->segment = segment; + ste->offset = offset; + ste->flags = 0; + symtabInsert(symtab, ste); +} + +/* + * symtab_get() + * + * Retrieves the values associated with a symbol. Undefined symbols + * are assumed to have -1:0 associated. Returns 1 if the symbol was + * successfully located. + */ +int symtab_get(const char *symbol, int *segment, long *offset) +{ + symtabEnt *ste = symtabFind(symtab, symbol); + if (!ste) { + *segment = -1; + *offset = 0; + return 0; + } else { + *segment = ste->segment; + *offset = ste->offset; + return 1; + } +} + +/* + * add_library() + * + * checks that a library can be opened and is in the correct format, + * then adds it to the linked list of libraries. + */ +void add_library(const char *name) +{ + if (rdl_verify(name)) { + rdl_perror("ldrdf", name); + errorcount++; + return; + } + if (!libraries) { + lastlib = libraries = malloc(sizeof(*libraries)); + if (!libraries) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + } else { + lastlib->next = malloc(sizeof(*libraries)); + if (!lastlib->next) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + lastlib = lastlib->next; + } + lastlib->next = NULL; + if (rdl_open(lastlib, name)) { + rdl_perror("ldrdf", name); + errorcount++; + return; + } +} + +/* + * search_libraries() + * + * scans through the list of libraries, attempting to match symbols + * defined in library modules against symbols that are referenced but + * not defined (segment = -1 in the symbol table) + * + * returns 1 if any extra library modules are included, indicating that + * another pass through the library list should be made (possibly). + */ +int search_libraries() +{ + struct librarynode *cur; + rdffile f; + int i; + void *header; + int segment; + long offset; + int doneanything = 0, pass = 1, keepfile; + rdfheaderrec *hr; + + cur = libraries; + + while (cur) { + if (options.verbose > 2) + printf("scanning library `%s', pass %d...\n", cur->name, pass); + + for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) { + if (pass == 2 && lookformodule(f.name)) + continue; + + if (options.verbose > 3) + printf(" looking in module `%s'\n", f.name); + + header = malloc(f.header_len); + if (!header) { + fprintf(stderr, "ldrdf: not enough memory\n"); + exit(1); + } + if (rdfloadseg(&f, RDOFF_HEADER, header)) { + rdfperror("ldrdf", f.name); + errorcount++; + return 0; + } + + keepfile = 0; + + while ((hr = rdfgetheaderrec(&f))) { + /* We're only interested in exports, so skip others */ + if (hr->type != RDFREC_GLOBAL) + continue; + + /* + * If the symbol is marked as SYM_GLOBAL, somebody will be + * definitely interested in it.. + */ + if ((hr->e.flags & SYM_GLOBAL) == 0) { + /* + * otherwise the symbol is just public. Find it in + * the symbol table. If the symbol isn't defined, we + * aren't interested, so go on to the next. + * If it is defined as anything but -1, we're also not + * interested. But if it is defined as -1, insert this + * module into the list of modules to use, and go + * immediately on to the next module... + */ + if (!symtab_get(hr->e.label, &segment, &offset) + || segment != -1) + continue; + } + + doneanything = 1; + keepfile = 1; + + /* + * as there are undefined symbols, we can assume that + * there are modules on the module list by the time + * we get here. + */ + lastmodule->next = malloc(sizeof(*lastmodule->next)); + if (!lastmodule->next) { + fprintf(stderr, "ldrdf: not enough memory\n"); + exit(1); + } + lastmodule = lastmodule->next; + memcpy(&lastmodule->f, &f, sizeof(f)); + lastmodule->name = strdup(f.name); + lastmodule->next = NULL; + processmodule(f.name, lastmodule); + break; + } + if (!keepfile) { + free(f.name); + f.name = NULL; + f.fp = NULL; + } + } + if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND) + rdl_perror("ldrdf", cur->name); + + cur = cur->next; + if (cur == NULL && pass == 1) { + cur = libraries; + pass++; + } + } + + return doneanything; +} + +/* + * write_output() + * + * this takes the linked list of modules, and walks through it, merging + * all the modules into a single output module, and then writes this to a + * file. + */ +void write_output(const char *filename) +{ + FILE *f; + rdf_headerbuf *rdfheader; + struct modulenode *cur; + int i, availableseg, seg, localseg, isrelative; + void *header; + rdfheaderrec *hr, newrec; + symtabEnt *se; + segtab segs; + long offset; + byte *data; + + if ((f = fopen(filename, "wb")) == NULL) { + fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename); + exit(1); + } + if ((rdfheader = rdfnewheader()) == NULL) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + + /* + * If '-g' option was given, first record in output file will be a + * `generic' record, filled with a given file content. + * This can be useful, for example, when constructing multiboot + * compliant kernels. + */ + if (generic_rec_file) { + FILE *ff; + + if (options.verbose) + printf("\nadding generic record from binary file %s\n", + generic_rec_file); + + hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec)); + if ((ff = fopen(generic_rec_file, "r")) == NULL) { + fprintf(stderr, "ldrdf: couldn't open %s for input\n", + generic_rec_file); + exit(1); + } + i = fread(hr->g.data, 1, sizeof(hr->g.data), ff); + fseek(ff, 0, SEEK_END); + if (ftell(ff) > sizeof(hr->g.data)) { + fprintf(error_file, + "warning: maximum generic record size is %d, rest of file ignored\n", + sizeof(hr->g.data)); + } + fclose(ff); + + hr->g.type = 0; + hr->g.reclen = i; + rdfaddheader(rdfheader, hr); + free(hr); + } + + if (options.verbose) + printf("\nbuilding output module (%d segments)\n", nsegs); + + /* + * Allocate the memory for the segments. We may be better off + * building the output module one segment at a time when running + * under 16 bit DOS, but that would be a slower way of doing this. + * And you could always use DJGPP... + */ + for (i = 0; i < nsegs; i++) { + outputseg[i].data = NULL; + if (!outputseg[i].length) + continue; + outputseg[i].data = malloc(outputseg[i].length); + if (!outputseg[i].data) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + } + + /* + * initialise availableseg, used to allocate segment numbers for + * imported and exported labels... + */ + availableseg = nsegs; + + /* + * Step through the modules, performing required actions on each one + */ + for (cur = modules; cur; cur = cur->next) { + /* + * Read the actual segment contents into the correct places in + * the newly allocated segments + */ + + for (i = 0; i < cur->f.nsegs; i++) { + int dest = cur->seginfo[i].dest_seg; + + if (dest == -1) + continue; + if (rdfloadseg(&cur->f, i, + outputseg[dest].data + cur->seginfo[i].reloc)) { + rdfperror("ldrdf", cur->name); + exit(1); + } + } + + /* + * Perform fixups, and add new header records where required + */ + + header = malloc(cur->f.header_len); + if (!header) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + + if (cur->f.header_loc) + rdfheaderrewind(&cur->f); + else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) { + rdfperror("ldrdf", cur->name); + exit(1); + } + + /* + * we need to create a local segment number -> location + * table for the segments in this module. + */ + init_seglocations(&segs); + for (i = 0; i < cur->f.nsegs; i++) { + add_seglocation(&segs, cur->f.seg[i].number, + cur->seginfo[i].dest_seg, + cur->seginfo[i].reloc); + } + /* + * and the BSS segment (doh!) + */ + add_seglocation(&segs, 2, 2, cur->bss_reloc); + + while ((hr = rdfgetheaderrec(&cur->f))) { + switch (hr->type) { + case RDFREC_RELOC: /* relocation record - need to do a fixup */ + /* + * First correct the offset stored in the segment from + * the start of the segment (which may well have changed). + * + * To do this we add to the number stored the relocation + * factor associated with the segment that contains the + * target segment. + * + * The relocation could be a relative relocation, in which + * case we have to first subtract the amount we've relocated + * the containing segment by. + */ + if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) { + fprintf(stderr, + "%s: reloc to undefined segment %04x\n", + cur->name, (int)hr->r.refseg); + errorcount++; + break; + } + + isrelative = + (hr->r.segment & RDOFF_RELATIVEMASK) == + RDOFF_RELATIVEMASK; + hr->r.segment &= (RDOFF_RELATIVEMASK - 1); + + if (hr->r.segment == 2 || + (localseg = + rdffindsegment(&cur->f, hr->r.segment)) == -1) { + fprintf(stderr, "%s: reloc from %s segment (%d)\n", + cur->name, + hr->r.segment == 2 ? "BSS" : "unknown", + hr->r.segment); + errorcount++; + break; + } + + if (hr->r.length != 1 && hr->r.length != 2 && + hr->r.length != 4) { + fprintf(stderr, "%s: nonstandard length reloc " + "(%d bytes)\n", cur->name, hr->r.length); + errorcount++; + break; + } + + /* + * okay, now the relocation is in the segment pointed to by + * cur->seginfo[localseg], and we know everything else is + * okay to go ahead and do the relocation + */ + data = outputseg[cur->seginfo[localseg].dest_seg].data; + data += cur->seginfo[localseg].reloc + hr->r.offset; + + /* + * data now points to the reference that needs + * relocation. Calculate the relocation factor. + * Factor is: + * offset of referred object in segment [in offset] + * (- relocation of localseg, if ref is relative) + * For simplicity, the result is stored in 'offset'. + * Then add 'offset' onto the value at data. + */ + + if (isrelative) + offset -= cur->seginfo[localseg].reloc; + switch (hr->r.length) { + case 1: + offset += *data; + if (offset < -127 || offset > 128) + fprintf(error_file, + "warning: relocation out of range " + "at %s(%02x:%08lx)\n", cur->name, + (int)hr->r.segment, hr->r.offset); + *data = (char)offset; + break; + case 2: + offset += *(short *)data; + if (offset < -32767 || offset > 32768) + fprintf(error_file, + "warning: relocation out of range " + "at %s(%02x:%08lx)\n", cur->name, + (int)hr->r.segment, hr->r.offset); + *(short *)data = (short)offset; + break; + case 4: + *(long *)data += offset; + /* we can't easily detect overflow on this one */ + break; + } + + /* + * If the relocation was relative between two symbols in + * the same segment, then we're done. + * + * Otherwise, we need to output a new relocation record + * with the references updated segment and offset... + */ + if (!isrelative || cur->seginfo[localseg].dest_seg != seg) { + hr->r.segment = cur->seginfo[localseg].dest_seg; + hr->r.offset += cur->seginfo[localseg].reloc; + hr->r.refseg = seg; + if (isrelative) + hr->r.segment += RDOFF_RELATIVEMASK; + rdfaddheader(rdfheader, hr); + } + break; + + case RDFREC_IMPORT: /* import symbol */ + case RDFREC_FARIMPORT: + /* + * scan the global symbol table for the symbol + * and associate its location with the segment number + * for this module + */ + se = symtabFind(symtab, hr->i.label); + if (!se || se->segment == -1) { + if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) { + fprintf(error_file, + "error: unresolved reference to `%s'" + " in module `%s'\n", hr->i.label, + cur->name); + errorcount++; + } + /* + * we need to allocate a segment number for this + * symbol, and store it in the symbol table for + * future reference + */ + if (!se) { + se = malloc(sizeof(*se)); + if (!se) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + se->name = strdup(hr->i.label); + se->flags = 0; + se->segment = availableseg++; + se->offset = 0; + symtabInsert(symtab, se); + } else { + se->segment = availableseg++; + se->offset = 0; + } + /* + * output a header record that imports it to the + * recently allocated segment number... + */ + newrec = *hr; + newrec.i.segment = se->segment; + rdfaddheader(rdfheader, &newrec); + } + + add_seglocation(&segs, hr->i.segment, se->segment, + se->offset); + break; + + case RDFREC_GLOBAL: /* export symbol */ + /* + * need to insert an export for this symbol into the new + * header, unless we're stripping symbols. Even if we're + * stripping, put the symbol if it's marked as SYM_GLOBAL. + */ + if (options.strip && !(hr->e.flags & SYM_GLOBAL)) + break; + + if (hr->e.segment == 2) { + seg = 2; + offset = cur->bss_reloc; + } else { + localseg = rdffindsegment(&cur->f, hr->e.segment); + if (localseg == -1) { + fprintf(stderr, "%s: exported symbol `%s' from " + "unrecognised segment\n", cur->name, + hr->e.label); + errorcount++; + break; + } + offset = cur->seginfo[localseg].reloc; + seg = cur->seginfo[localseg].dest_seg; + } + + hr->e.segment = seg; + hr->e.offset += offset; + rdfaddheader(rdfheader, hr); + break; + + case RDFREC_MODNAME: /* module name */ + /* + * Insert module name record if export symbols + * are not stripped. + * If module name begins with '$' - insert it anyway. + */ + if (options.strip && hr->m.modname[0] != '$') + break; + rdfaddheader(rdfheader, hr); + break; + + case RDFREC_DLL: /* DLL name */ + /* + * Insert DLL name if it begins with '$' + */ + if (hr->d.libname[0] != '$') + break; + rdfaddheader(rdfheader, hr); + break; + + case RDFREC_SEGRELOC: /* segment fixup */ + /* + * modify the segment numbers if necessary, and + * pass straight through to the output module header + * + * *** FIXME *** + */ + if (hr->r.segment == 2) { + fprintf(stderr, "%s: segment fixup in BSS section\n", + cur->name); + errorcount++; + break; + } + localseg = rdffindsegment(&cur->f, hr->r.segment); + if (localseg == -1) { + fprintf(stderr, "%s: segment fixup in unrecognised" + " segment (%d)\n", cur->name, hr->r.segment); + errorcount++; + break; + } + hr->r.segment = cur->seginfo[localseg].dest_seg; + hr->r.offset += cur->seginfo[localseg].reloc; + + if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) { + fprintf(stderr, "%s: segment fixup to undefined " + "segment %04x\n", cur->name, + (int)hr->r.refseg); + errorcount++; + break; + } + hr->r.refseg = seg; + rdfaddheader(rdfheader, hr); + break; + + case RDFREC_COMMON: /* Common variable */ + /* Is this symbol already in the table? */ + se = symtabFind(symtab, hr->c.label); + if (!se) { + printf("%s is not in symtab yet\n", hr->c.label); + break; + } + /* Add segment location */ + add_seglocation(&segs, hr->c.segment, se->segment, + se->offset); + break; + } + } + + free(header); + done_seglocations(&segs); + + } + + /* + * combined BSS reservation for the entire results + */ + newrec.type = RDFREC_BSS; + newrec.b.reclen = 4; + newrec.b.amount = bss_length; + rdfaddheader(rdfheader, &newrec); + + /* + * Write the header + */ + for (i = 0; i < nsegs; i++) { + if (i == 2) + continue; + rdfaddsegment(rdfheader, outputseg[i].length); + } + + rdfwriteheader(f, rdfheader); + rdfdoneheader(rdfheader); + + /* + * Step through the segments, one at a time, writing out into + * the output file + */ + for (i = 0; i < nsegs; i++) { + uint16 s; + long l; + + if (i == 2) + continue; + + s = translateshort(outputseg[i].type); + fwrite(&s, 2, 1, f); + s = translateshort(outputseg[i].number); + fwrite(&s, 2, 1, f); + s = translateshort(outputseg[i].reserved); + fwrite(&s, 2, 1, f); + l = translatelong(outputseg[i].length); + fwrite(&l, 4, 1, f); + + fwrite(outputseg[i].data, outputseg[i].length, 1, f); + } + + fwrite("\0\0\0\0\0\0\0\0\0\0", 10, 1, f); +} + +/* ========================================================================= + * Main program + */ + +void usage() +{ + printf("usage:\n" + " ldrdf [options] object modules ... [-llibrary ...]\n" + " ldrdf -r\n" + "options:\n" + " -v[=n] increase verbosity by 1, or set it to n\n" + " -a nn set segment alignment value (default 16)\n" + " -s strip public symbols\n" + " -dy Unix-style dynamic linking\n" + " -o name write output in file 'name'\n" + " -j path specify objects search path\n" + " -L path specify libraries search path\n" + " -g file embed 'file' as a first header record with type 'generic'\n"); + exit(0); +} + +int main(int argc, char **argv) +{ + char *outname = "aout.rdf"; + int moduleloaded = 0; + char *respstrings[128] = { 0, }; + + options.verbose = 0; + options.align = 16; + options.dynalink = 0; + options.strip = 0; + + error_file = stderr; + + argc--, argv++; + if (argc == 0) + usage(); + while (argc && *argv && **argv == '-' && argv[0][1] != 'l') { + switch (argv[0][1]) { + case 'r': + printf("ldrdf (linker for RDF files) version " LDRDF_VERSION + "\n"); + printf("RDOFF2 revision %s\n", RDOFF2_REVISION); + exit(0); + case 'v': + if (argv[0][2] == '=') { + options.verbose = argv[0][3] - '0'; + if (options.verbose < 0 || options.verbose > 9) { + fprintf(stderr, + "ldrdf: verbosity level must be a number" + " between 0 and 9\n"); + exit(1); + } + } else + options.verbose++; + break; + case 'a': + options.align = atoi(argv[1]); + if (options.align <= 0) { + fprintf(stderr, + "ldrdf: -a expects a positive number argument\n"); + exit(1); + } + argv++, argc--; + break; + case 's': + options.strip = 1; + break; + case 'd': + if (argv[0][2] == 'y') + options.dynalink = 1; + break; + case 'o': + outname = argv[1]; + argv++, argc--; + break; + case 'j': + if (!objpath) { + options.objpath = 1; + objpath = argv[1]; + argv++, argc--; + break; + } else { + fprintf(stderr, + "ldrdf: more than one objects search path specified\n"); + exit(1); + } + case 'L': + if (!libpath) { + options.libpath = 1; + libpath = argv[1]; + argv++, argc--; + break; + } else { + fprintf(stderr, + "ldrdf: more than one libraries search path specified\n"); + exit(1); + } + case '@':{ + int i = 0; + char buf[256]; + FILE *f; + + options.respfile = 1; + if (argv[1] != NULL) + f = fopen(argv[1], "r"); + else { + fprintf(stderr, + "ldrdf: no response file name specified\n"); + exit(1); + } + + if (f == NULL) { + fprintf(stderr, + "ldrdf: unable to open response file\n"); + exit(1); + } + + argv++, argc--; + while (fgets(buf, sizeof(buf), f) != NULL) { + char *p; + if (buf[0] == '\n') + continue; + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; + if (i >= 128) { + fprintf(stderr, "ldrdf: too many input files\n"); + exit(1); + } + *(respstrings + i) = newstr(buf); + argc++, i++; + } + break; + } + case '2': + options.stderr_redir = 1; + error_file = stdout; + break; + case 'g': + generic_rec_file = argv[1]; + argv++, argc--; + break; + default: + usage(); + } + argv++, argc--; + } + + if (options.verbose > 4) { + printf("ldrdf invoked with options:\n"); + printf(" section alignment: %d bytes\n", options.align); + printf(" output name: `%s'\n", outname); + if (options.strip) + printf(" strip symbols\n"); + if (options.dynalink) + printf(" Unix-style dynamic linking\n"); + if (options.objpath) + printf(" objects search path: %s\n", objpath); + if (options.libpath) + printf(" libraries search path: %s\n", libpath); + printf("\n"); + } + + symtab = symtabNew(); + initsegments(); + + if (!symtab) { + fprintf(stderr, "ldrdf: out of memory\n"); + exit(1); + } + + while (argc) { + if (!*argv) + argv = respstrings; + if (!*argv) + break; + if (!strncmp(*argv, "-l", 2)) { + if (libpath && (argv[0][2] != '/')) + add_library(newstrcat(libpath, *argv + 2)); + else + add_library(*argv + 2); + } else { + if (objpath && (argv[0][0] != '/')) + loadmodule(newstrcat(objpath, *argv)); + else + loadmodule(*argv); + moduleloaded = 1; + } + argv++, argc--; + } + + if (!moduleloaded) { + printf("ldrdf: nothing to do. ldrdf -h for usage\n"); + return 0; + } + + search_libraries(); + + if (options.verbose > 2) { + printf("symbol table:\n"); + symtabDump(symtab, stdout); + } + + write_output(outname); + + if (errorcount > 0) + exit(1); + return 0; +} diff --git a/rdoff/ldsegs.h b/rdoff/ldsegs.h index 8b516faa..2a8ae881 100644 --- a/rdoff/ldsegs.h +++ b/rdoff/ldsegs.h @@ -8,12 +8,12 @@ #endif struct segconfig { - UI16 typelow, typehi;/* range of seg nos for which this is valid */ - char * typedesc; /* a description of the segment type */ - UI16 dowhat; /* one of the SEG_xxxx values below */ - UI16 mergetype; /* if SEG_MERGE what type segment do we merge with? - 0 -> same type of segment. This type is also - used with SEG_NEWSEG. */ + UI16 typelow, typehi; /* range of seg nos for which this is valid */ + char *typedesc; /* a description of the segment type */ + UI16 dowhat; /* one of the SEG_xxxx values below */ + UI16 mergetype; /* if SEG_MERGE what type segment do we merge with? + 0 -> same type of segment. This type is also + used with SEG_NEWSEG. */ }; #define SEG_IGNORE 0 @@ -33,7 +33,8 @@ struct segconfig sconft[SEGCONFIGMAX] = { {0x0020, 0x0FFF, "reserved(MOSCOW)", 1, 0}, {0x1000, 0x7FFF, "reserved(system dependant)", 1, 0}, {0x8000, 0xFFFE, "reserved(other)", 1, 0}, - {0xFFFF, 0xFFFF, "invalid segment", 0, 0}}; + {0xFFFF, 0xFFFF, "invalid segment", 0, 0} +}; #define getsegconfig(target,number) \ { \ diff --git a/rdoff/rdf2bin.c b/rdoff/rdf2bin.c dissimilarity index 70% index aee6afb2..ac51c0ef 100644 --- a/rdoff/rdf2bin.c +++ b/rdoff/rdf2bin.c @@ -1,137 +1,134 @@ -/* - * rdf2bin.c - convert an RDOFF object file to flat binary - */ - -#include -#include -#include - -#include "rdfload.h" -#include "nasmlib.h" - -long origin = 0; -int align = 16; - -char *getfilename(char * pathname) -{ - char * lastslash = pathname - 1; - char * i = pathname; - - while ( *i ) { - if (*i == '/') lastslash = i; - i++; - } - return lastslash + 1; -} - -int main(int argc, char **argv) -{ - rdfmodule * m; - int tmp; - FILE *of; - char * padding; - int codepad, datapad, bsspad=0; - - if (argc < 2) { - puts("Usage: rdf2bin [-o relocation-origin] [-p segment-alignment] " - "input-file output-file"); - puts(" rdf2com [-p segment-alignment] input-file output-file"); - return 1; - } - - if (! nasm_stricmp(getfilename(*argv),"rdf2com")) { - origin = 0x100; - } - argv++, argc--; - - while (argc > 2) { - if (! strcmp(*argv,"-o")) { - argv++, argc--; - origin = readnum(*argv, &tmp); - if (tmp) { - fprintf(stderr,"rdf2bin: invalid parameter: %s\n",*argv); - return 1; - } - } else if (! strcmp(*argv,"-p")) { - argv++, argc--; - align = readnum(*argv, &tmp); - if (tmp) { - fprintf(stderr,"rdf2bin: invalid parameter: %s\n",*argv); - return 1; - } - } else if (! strcmp(*argv,"-b")) { - argv++, argc--; - bsspad = readnum(*argv, &tmp); - if (tmp) { - fprintf(stderr,"rdf2bin: invalid parameter: %s\n",*argv); - return 1; - } - } else - break; - - argv++, argc--; - } - if (argc < 2) { - puts("rdf2bin: required parameter missing"); - return -1; - } - m = rdfload(*argv); - - if (! m) { - rdfperror("rdf2bin",*argv); - return 1; - } - printf("relocating %s: origin=%lx, align=%d\n",*argv,origin,align); - - m->textrel = origin; - m->datarel = origin + m->f.seg[0].length; - if (m->datarel % align != 0) { - codepad = align - (m->datarel % align); - m->datarel += codepad; - } - else - codepad = 0; - - m->bssrel = m->datarel + m->f.seg[1].length; - if (m->bssrel % align != 0) { - datapad = align - (m->bssrel % align); - m->bssrel += datapad; - } - else - datapad = 0; - - printf("code: %08lx\ndata: %08lx\nbss: %08lx\n", - m->textrel, m->datarel, m->bssrel); - - rdf_relocate(m); - - argv++; - - of = fopen(*argv,"wb"); - if (!of) { - fprintf(stderr,"rdf2bin: could not open output file %s\n",*argv); - return 1; - } - - padding = malloc(align); - if (!padding) { - fprintf(stderr,"rdf2bin: out of memory\n"); - return 1; - } - - if (fwrite(m->t,1,m->f.seg[0].length,of) != m->f.seg[0].length || - fwrite(padding,1,codepad,of) != codepad || - fwrite(m->d,1,m->f.seg[1].length,of) != m->f.seg[1].length) - { - fprintf(stderr,"rdf2bin: error writing to %s\n", *argv); - return 1; - } - - if (bsspad) { - void *p = calloc(bsspad-=(m->bssrel - origin),1); - fwrite(p,1,bsspad,of); - } - - fclose(of); - return 0; -} +/* + * rdf2bin.c - convert an RDOFF object file to flat binary + */ + +#include +#include +#include + +#include "rdfload.h" +#include "nasmlib.h" + +long origin = 0; +int align = 16; + +char *getfilename(char *pathname) +{ + char *lastslash = pathname - 1; + char *i = pathname; + + while (*i) { + if (*i == '/') + lastslash = i; + i++; + } + return lastslash + 1; +} + +int main(int argc, char **argv) +{ + rdfmodule *m; + int tmp; + FILE *of; + char *padding; + int codepad, datapad, bsspad = 0; + + if (argc < 2) { + puts("Usage: rdf2bin [-o relocation-origin] [-p segment-alignment] " "input-file output-file"); + puts(" rdf2com [-p segment-alignment] input-file output-file"); + return 1; + } + + if (!nasm_stricmp(getfilename(*argv), "rdf2com")) { + origin = 0x100; + } + argv++, argc--; + + while (argc > 2) { + if (!strcmp(*argv, "-o")) { + argv++, argc--; + origin = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr, "rdf2bin: invalid parameter: %s\n", *argv); + return 1; + } + } else if (!strcmp(*argv, "-p")) { + argv++, argc--; + align = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr, "rdf2bin: invalid parameter: %s\n", *argv); + return 1; + } + } else if (!strcmp(*argv, "-b")) { + argv++, argc--; + bsspad = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr, "rdf2bin: invalid parameter: %s\n", *argv); + return 1; + } + } else + break; + + argv++, argc--; + } + if (argc < 2) { + puts("rdf2bin: required parameter missing"); + return -1; + } + m = rdfload(*argv); + + if (!m) { + rdfperror("rdf2bin", *argv); + return 1; + } + printf("relocating %s: origin=%lx, align=%d\n", *argv, origin, align); + + m->textrel = origin; + m->datarel = origin + m->f.seg[0].length; + if (m->datarel % align != 0) { + codepad = align - (m->datarel % align); + m->datarel += codepad; + } else + codepad = 0; + + m->bssrel = m->datarel + m->f.seg[1].length; + if (m->bssrel % align != 0) { + datapad = align - (m->bssrel % align); + m->bssrel += datapad; + } else + datapad = 0; + + printf("code: %08lx\ndata: %08lx\nbss: %08lx\n", + m->textrel, m->datarel, m->bssrel); + + rdf_relocate(m); + + argv++; + + of = fopen(*argv, "wb"); + if (!of) { + fprintf(stderr, "rdf2bin: could not open output file %s\n", *argv); + return 1; + } + + padding = malloc(align); + if (!padding) { + fprintf(stderr, "rdf2bin: out of memory\n"); + return 1; + } + + if (fwrite(m->t, 1, m->f.seg[0].length, of) != m->f.seg[0].length || + fwrite(padding, 1, codepad, of) != codepad || + fwrite(m->d, 1, m->f.seg[1].length, of) != m->f.seg[1].length) { + fprintf(stderr, "rdf2bin: error writing to %s\n", *argv); + return 1; + } + + if (bsspad) { + void *p = calloc(bsspad -= (m->bssrel - origin), 1); + fwrite(p, 1, bsspad, of); + } + + fclose(of); + return 0; +} diff --git a/rdoff/rdf2ihx.c b/rdoff/rdf2ihx.c dissimilarity index 89% index 43e5c720..512af558 100644 --- a/rdoff/rdf2ihx.c +++ b/rdoff/rdf2ihx.c @@ -1,190 +1,190 @@ -/* - * rdf2ihx.c - convert an RDOFF object file to Intel Hex format. - * This is based on rdf2bin. - * Note that this program only writes 16-bit HEX. - */ - -#include -#include -#include - -#include "rdfload.h" -#include "nasmlib.h" -#include "symtab.h" - -long origin = 0; -int align = 16; - -/* This function writes a single n-byte data record to of. Maximum value - for n is 255. */ -static int write_data_record(FILE *of, int ofs, int nbytes, - unsigned char *data) -{ - int i, iofs; - unsigned int checksum; - - iofs = ofs; - fprintf(of, ":%02X%04X00", nbytes, ofs); - checksum = 0; - for (i=0; i> 8) & 0xff) + /* high byte of load offset */ - (iofs & 0xff); /* low byte of load offset */ - checksum = ~checksum + 1; - fprintf(of, "%02X\n", checksum&0xff); - return(ofs); -} - -int main(int argc, char **argv) -{ - rdfmodule *m; - int tmp; - FILE *of; - char *padding; - unsigned char *segbin[2]; - int pad[2], segn, ofs, i; - long segaddr; - unsigned int checksum; - symtabEnt *s; - - if (argc < 2) { - puts("Usage: rdf2ihx [-o relocation-origin] [-p segment-alignment] " - "input-file output-file"); - return(1); - } - - argv++, argc--; - - while (argc > 2) { - if (strcmp(*argv,"-o") == 0) { - argv++, argc--; - origin = readnum(*argv, &tmp); - if (tmp) { - fprintf(stderr,"rdf2ihx: invalid parameter: %s\n",*argv); - return 1; - } - } else if (strcmp(*argv,"-p") == 0) { - argv++, argc--; - align = readnum(*argv, &tmp); - if (tmp) { - fprintf(stderr,"rdf2ihx: invalid parameter: %s\n",*argv); - return 1; - } - } else - break; - argv++, argc--; - } - if (argc < 2) { - puts("rdf2ihx: required parameter missing"); - return -1; - } - m = rdfload(*argv); - - if (!m) { - rdfperror("rdf2ihx",*argv); - return 1; - } - printf("relocating %s: origin=%lx, align=%d\n",*argv, origin, align); - - m->textrel = origin; - m->datarel = origin + m->f.seg[0].length; - if (m->datarel % align != 0) { - pad[0] = align - (m->datarel % align); - m->datarel += pad[0]; - } else { - pad[0] = 0; - } - - m->bssrel = m->datarel + m->f.seg[1].length; - if (m->bssrel % align != 0) { - pad[1] = align - (m->bssrel % align); - m->bssrel += pad[1]; - } else { - pad[1] = 0; - } - - printf("code: %08lx\ndata: %08lx\nbss: %08lx\n", - m->textrel, m->datarel, m->bssrel); - - rdf_relocate(m); - - argv++; - - of = fopen(*argv,"w"); - if (!of) { - fprintf(stderr,"rdf2ihx: could not open output file %s\n",*argv); - return(1); - } - - padding = malloc(align); - if (!padding) { - fprintf(stderr,"rdf2ihx: out of memory\n"); - return(1); - } - - /* write extended segment address record */ - fprintf(of, ":02000002"); /* Record mark, reclen, load offset & rectyp - fields for ext. seg. address record */ - segaddr = ((origin >> 16) & 0xffff); /* segment address */ - fprintf(of, "%04X", (unsigned int)(segaddr & 0xffff)); - checksum = 0x02 + /* reclen */ - 0x0000 + /* Load Offset */ - 0x02 + /* Rectyp */ - (segaddr & 0xff) + /* USBA low */ - ((segaddr >> 8) & 0xff); /* USBA high */ - checksum = ~checksum + 1; /* two's-complement the checksum */ - fprintf(of, "%02X\n", checksum & 0xff); - - /* See if there's a '_main' symbol in the symbol table */ - if ((s=symtabFind(m->symtab, "_main")) == NULL) { - printf("No _main symbol found, no start segment address record added\n"); - } else { - printf("_main symbol found at %04x:%04x\n", s->segment, - (unsigned int)(s->offset & 0xffff)); - /* Create a start segment address record for the _main symbol. */ - segaddr = ((s->segment & 0xffff) << 16) + ((s->offset) & 0xffff); - fprintf(of, ":04000003"); /* Record mark, reclen, load offset & rectyp - fields for start seg. addr. record */ - fprintf(of, "%08lX", segaddr); /* CS/IP field */ - checksum = 0x04 + /* reclen */ - 0x0000 + /* load offset */ - 0x03 + /* Rectyp */ - (segaddr & 0xff) + /* low-low byte of segaddr */ - ((segaddr >> 8) & 0xff) + /* low-high byte of segaddr */ - ((segaddr >> 16) & 0xff) + /* high-low byte of segaddr */ - ((segaddr >> 24) & 0xff); /* high-high byte of segaddr */ - checksum = ~checksum + 1; /* two's complement */ - fprintf(of, "%02X\n", checksum & 0xff); - } - - /* Now it's time to write data records from the code and data segments in. - This current version doesn't check for segment overflow; proper behavior - should be to output a segment address record for the code and data - segments. Something to do. */ - ofs = 0; - segbin[0] = m->t; - segbin[1] = m->d; - for (segn=0; segn<2; segn++) { - int mod, adr; - - if (m->f.seg[segn].length == 0) - continue; - for (i=0; i+15f.seg[segn].length; i+=16) { - ofs = write_data_record(of, ofs, 16, &segbin[segn][i]); - } - if ((mod=m->f.seg[segn].length & 0x000f) != 0) { - adr = m->f.seg[segn].length & 0xfff0; - ofs = write_data_record(of, ofs, mod, &segbin[segn][adr]); - } - } - /* output an end of file record */ - fprintf(of, ":00000001FF\n"); - - fclose(of); - return 0; -} +/* + * rdf2ihx.c - convert an RDOFF object file to Intel Hex format. + * This is based on rdf2bin. + * Note that this program only writes 16-bit HEX. + */ + +#include +#include +#include + +#include "rdfload.h" +#include "nasmlib.h" +#include "symtab.h" + +long origin = 0; +int align = 16; + +/* This function writes a single n-byte data record to of. Maximum value + for n is 255. */ +static int write_data_record(FILE * of, int ofs, int nbytes, + unsigned char *data) +{ + int i, iofs; + unsigned int checksum; + + iofs = ofs; + fprintf(of, ":%02X%04X00", nbytes, ofs); + checksum = 0; + for (i = 0; i < nbytes; i++) { + fprintf(of, "%02X", data[i]); + ofs++; + checksum += data[i]; + } + checksum = checksum + /* current checksum */ + nbytes + /* RECLEN (one byte) */ + ((iofs >> 8) & 0xff) + /* high byte of load offset */ + (iofs & 0xff); /* low byte of load offset */ + checksum = ~checksum + 1; + fprintf(of, "%02X\n", checksum & 0xff); + return (ofs); +} + +int main(int argc, char **argv) +{ + rdfmodule *m; + int tmp; + FILE *of; + char *padding; + unsigned char *segbin[2]; + int pad[2], segn, ofs, i; + long segaddr; + unsigned int checksum; + symtabEnt *s; + + if (argc < 2) { + puts("Usage: rdf2ihx [-o relocation-origin] [-p segment-alignment] " "input-file output-file"); + return (1); + } + + argv++, argc--; + + while (argc > 2) { + if (strcmp(*argv, "-o") == 0) { + argv++, argc--; + origin = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr, "rdf2ihx: invalid parameter: %s\n", *argv); + return 1; + } + } else if (strcmp(*argv, "-p") == 0) { + argv++, argc--; + align = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr, "rdf2ihx: invalid parameter: %s\n", *argv); + return 1; + } + } else + break; + argv++, argc--; + } + if (argc < 2) { + puts("rdf2ihx: required parameter missing"); + return -1; + } + m = rdfload(*argv); + + if (!m) { + rdfperror("rdf2ihx", *argv); + return 1; + } + printf("relocating %s: origin=%lx, align=%d\n", *argv, origin, align); + + m->textrel = origin; + m->datarel = origin + m->f.seg[0].length; + if (m->datarel % align != 0) { + pad[0] = align - (m->datarel % align); + m->datarel += pad[0]; + } else { + pad[0] = 0; + } + + m->bssrel = m->datarel + m->f.seg[1].length; + if (m->bssrel % align != 0) { + pad[1] = align - (m->bssrel % align); + m->bssrel += pad[1]; + } else { + pad[1] = 0; + } + + printf("code: %08lx\ndata: %08lx\nbss: %08lx\n", + m->textrel, m->datarel, m->bssrel); + + rdf_relocate(m); + + argv++; + + of = fopen(*argv, "w"); + if (!of) { + fprintf(stderr, "rdf2ihx: could not open output file %s\n", *argv); + return (1); + } + + padding = malloc(align); + if (!padding) { + fprintf(stderr, "rdf2ihx: out of memory\n"); + return (1); + } + + /* write extended segment address record */ + fprintf(of, ":02000002"); /* Record mark, reclen, load offset & rectyp + fields for ext. seg. address record */ + segaddr = ((origin >> 16) & 0xffff); /* segment address */ + fprintf(of, "%04X", (unsigned int)(segaddr & 0xffff)); + checksum = 0x02 + /* reclen */ + 0x0000 + /* Load Offset */ + 0x02 + /* Rectyp */ + (segaddr & 0xff) + /* USBA low */ + ((segaddr >> 8) & 0xff); /* USBA high */ + checksum = ~checksum + 1; /* two's-complement the checksum */ + fprintf(of, "%02X\n", checksum & 0xff); + + /* See if there's a '_main' symbol in the symbol table */ + if ((s = symtabFind(m->symtab, "_main")) == NULL) { + printf + ("No _main symbol found, no start segment address record added\n"); + } else { + printf("_main symbol found at %04x:%04x\n", s->segment, + (unsigned int)(s->offset & 0xffff)); + /* Create a start segment address record for the _main symbol. */ + segaddr = ((s->segment & 0xffff) << 16) + ((s->offset) & 0xffff); + fprintf(of, ":04000003"); /* Record mark, reclen, load offset & rectyp + fields for start seg. addr. record */ + fprintf(of, "%08lX", segaddr); /* CS/IP field */ + checksum = 0x04 + /* reclen */ + 0x0000 + /* load offset */ + 0x03 + /* Rectyp */ + (segaddr & 0xff) + /* low-low byte of segaddr */ + ((segaddr >> 8) & 0xff) + /* low-high byte of segaddr */ + ((segaddr >> 16) & 0xff) + /* high-low byte of segaddr */ + ((segaddr >> 24) & 0xff); /* high-high byte of segaddr */ + checksum = ~checksum + 1; /* two's complement */ + fprintf(of, "%02X\n", checksum & 0xff); + } + + /* Now it's time to write data records from the code and data segments in. + This current version doesn't check for segment overflow; proper behavior + should be to output a segment address record for the code and data + segments. Something to do. */ + ofs = 0; + segbin[0] = m->t; + segbin[1] = m->d; + for (segn = 0; segn < 2; segn++) { + int mod, adr; + + if (m->f.seg[segn].length == 0) + continue; + for (i = 0; i + 15 < m->f.seg[segn].length; i += 16) { + ofs = write_data_record(of, ofs, 16, &segbin[segn][i]); + } + if ((mod = m->f.seg[segn].length & 0x000f) != 0) { + adr = m->f.seg[segn].length & 0xfff0; + ofs = write_data_record(of, ofs, mod, &segbin[segn][adr]); + } + } + /* output an end of file record */ + fprintf(of, ":00000001FF\n"); + + fclose(of); + return 0; +} diff --git a/rdoff/rdfdump.c b/rdoff/rdfdump.c dissimilarity index 80% index 626fd2a1..de2bb595 100644 --- a/rdoff/rdfdump.c +++ b/rdoff/rdfdump.c @@ -1,303 +1,312 @@ -/* - * rdfdump.c - dump RDOFF file header. - */ - -#include -#include -#include - -#define RDOFF_UTILS - -#include "rdoff.h" - -#define PROGRAM_VERSION "2.3" - -FILE *infile; - -void print_header(long length, int rdf_version) -{ - char buf[129], t, l, s, flags; - unsigned char reclen; - long o, ll; - uint16 rs; - - while (length > 0) { - fread(&t, 1, 1, infile); - if (rdf_version >= 2) { - fread(&reclen, 1, 1, infile); - } - switch (t) { - case RDFREC_GENERIC: /* generic record */ - printf(" generic record (length=%d)\n", (int) reclen); - fseek(infile, reclen, SEEK_CUR); - break; - - case RDFREC_RELOC: /* relocation record */ - case RDFREC_SEGRELOC: /* segment relocation */ - fread(&s, 1, 1, infile); - fread(&o, 4, 1, infile); - fread(&l, 1, 1, infile); - fread(&rs, 2, 1, infile); - printf(" %s: location (%04x:%08lx), length %d, " - "referred seg %04x\n", t == 1 ? "relocation" : "seg relocation", - (int) s, translatelong(o), (int) l, translateshort(rs)); - if (rdf_version >= 2 && reclen != 8) - printf(" warning: reclen != 8\n"); - if (rdf_version == 1) - length -= 9; - if (rdf_version == 1 && t == 6) - printf(" warning: seg relocation not supported in RDOFF1\n"); - break; - - case RDFREC_IMPORT: /* import record */ - case RDFREC_FARIMPORT: /* import far symbol */ - fread(&flags, 1, 1, infile); - fread(&rs, 2, 1, infile); - ll = 0; - - if (rdf_version == 1) { - do { - fread(&buf[ll], 1, 1, infile); - } while (buf[ll++]); - } else { - for (; ll < reclen - 3; ll++) - fread(&buf[ll], 1, 1, infile); - } - - if (t == 7) - printf("far "); - printf((flags & SYM_IMPORT) ? " import" : " extern"); - if (flags & SYM_FUNCTION) - printf(" proc"); - if (flags & SYM_DATA) - printf(" data"); - printf(": segment %04x = %s\n", translateshort(rs), buf); - if (rdf_version == 1) - length -= ll + 3; - if (rdf_version == 1 && t == 7) - printf(" warning: far import not supported in RDOFF1\n"); - break; - - case RDFREC_GLOBAL: /* export record */ - fread(&flags, 1, 1, infile); - fread(&s, 1, 1, infile); - fread(&o, 4, 1, infile); - ll = 0; - - if (rdf_version == 1) { - do { - fread(&buf[ll], 1, 1, infile); - } while (buf[ll++]); - } else { - for (; ll < reclen - 6; ll++) - fread(&buf[ll], 1, 1, infile); - } - printf((flags & SYM_GLOBAL) ? " export" : " public"); - if (flags & SYM_FUNCTION) - printf(" proc"); - if (flags & SYM_DATA) - printf(" data"); - printf(": (%04x:%08lx) = %s\n", (int) s, translatelong(o), buf); - if (rdf_version == 1) - length -= ll + 6; - break; - - case RDFREC_DLL: /* DLL and Module records */ - case RDFREC_MODNAME: - ll = 0; - if (rdf_version == 1) { - do { - fread(&buf[ll], 1, 1, infile); - } while (buf[ll++]); - } else { - for (; ll < reclen; ll++) - fread(&buf[ll], 1, 1, infile); - } - if (t == 4) - printf(" dll: %s\n", buf); - else - printf(" module: %s\n", buf); - if (rdf_version == 1) - length -= ll + 1; - break; - - case RDFREC_BSS: /* BSS reservation */ - fread(&ll, 4, 1, infile); - printf(" bss reservation: %08lx bytes\n", translatelong(ll)); - if (rdf_version == 1) - length -= 5; - if (rdf_version > 1 && reclen != 4) - printf(" warning: reclen != 4\n"); - break; - - case RDFREC_COMMON: { - unsigned short seg, align; - unsigned long size; - - fread(&seg, 2, 1, infile); - fread(&size, 4, 1, infile); - fread(&align, 2, 1, infile); - for (ll = 0; ll < reclen - 8; ll++) - fread(buf + ll, 1, 1, infile); - printf(" common: segment %04x = %s, %ld:%d\n", translateshort(seg), - buf, translatelong(size), translateshort(align)); - break; - } - - default: - printf(" unrecognized record (type %d", (int) t); - if (rdf_version > 1) { - printf(", length %d", (int) reclen); - fseek(infile, reclen, SEEK_CUR); - } else - length--; - printf(")\n"); - } - if (rdf_version != 1) - length -= 2 + reclen; - } -} - -int main(int argc, char **argv) -{ - char id[7]; - long l; - uint16 s; - int verbose = 0; - long offset; - int foundnullsegment = 0; - int version; - long segmentcontentlength = 0; - int nsegments = 0; - long headerlength = 0; - long objectlength = 0; - - printf("RDOFF dump utility, version %s\n", PROGRAM_VERSION); - printf("RDOFF2 revision %s\n", RDOFF2_REVISION); - puts("Copyright (c) 1996,99 Julian R Hall\n" - "Improvements and fixes (c) 2002-2004 RET & COM Research."); - - if (argc < 2) { - fputs("Usage: rdfdump [-v] \n", stderr); - exit(1); - } - - if (!strcmp(argv[1], "-v")) { - verbose = 1; - if (argc < 3) { - fputs("required parameter missing\n", stderr); - exit(1); - } - argv++; - } - - infile = fopen(argv[1], "rb"); - if (!infile) { - fprintf(stderr, "rdfdump: Could not open %s\n", argv[1]); - exit(1); - } - - fread(id, 6, 1, infile); - if (strncmp(id, "RDOFF", 5)) { - fputs("rdfdump: File does not contain valid RDOFF header\n", stderr); - exit(1); - } - - printf("File %s: RDOFF version %c\n\n", argv[1], id[5]); - if (id[5] < '1' || id[5] > '2') { - fprintf(stderr, "rdfdump: unknown RDOFF version '%c'\n", id[5]); - exit(1); - } - version = id[5] - '0'; - - if (version > 1) { - fread(&l, 4, 1, infile); - objectlength = translatelong(l); - printf("Object content size: %ld bytes\n", objectlength); - } - - fread(&l, 4, 1, infile); - headerlength = translatelong(l); - printf("Header (%ld bytes):\n", headerlength); - print_header(headerlength, version); - - if (version == 1) { - fread(&l, 4, 1, infile); - l = translatelong(l); - printf("\nText segment length = %ld bytes\n", l); - offset = 0; - while (l--) { - fread(id, 1, 1, infile); - if (verbose) { - if (offset % 16 == 0) - printf("\n%08lx ", offset); - printf(" %02x", (int) (unsigned char) id[0]); - offset++; - } - } - if (verbose) - printf("\n\n"); - - fread(&l, 4, 1, infile); - l = translatelong(l); - printf("Data segment length = %ld bytes\n", l); - - if (verbose) { - offset = 0; - while (l--) { - fread(id, 1, 1, infile); - if (offset % 16 == 0) - printf("\n%08lx ", offset); - printf(" %02x", (int) (unsigned char) id[0]); - offset++; - } - printf("\n"); - } - } else { - do { - fread(&s, 2, 1, infile); - s = translateshort(s); - if (!s) { - printf("\nNULL segment\n"); - foundnullsegment = 1; - break; - } - printf("\nSegment:\n Type = %04X (%s)\n", (int) s, translatesegmenttype(s)); - nsegments++; - - fread(&s, 2, 1, infile); - printf(" Number = %04X\n", (int) translateshort(s)); - fread(&s, 2, 1, infile); - printf(" Resrvd = %04X\n", (int) translateshort(s)); - fread(&l, 4, 1, infile); - l = translatelong(l); - printf(" Length = %ld bytes\n", l); - segmentcontentlength += l; - - offset = 0; - while (l--) { - fread(id, 1, 1, infile); - if (verbose) { - if (offset % 16 == 0) - printf("\n%08lx ", offset); - printf(" %02x", (int) (unsigned char) id[0]); - offset++; - } - } - if (verbose) - printf("\n"); - } while (!feof(infile)); - if (!foundnullsegment) - printf("\nWarning: unexpected end of file - " "NULL segment not found\n"); - - printf("\nTotal number of segments: %d\n", nsegments); - printf("Total segment content length: %ld bytes\n", segmentcontentlength); - - /* calculate what the total object content length should have been */ - l = segmentcontentlength + 10 * (nsegments + 1) + headerlength + 4; - if (l != objectlength) - printf("Warning: actual object length (%ld) != " "stored object length (%ld)\n", l, objectlength); - } - fclose(infile); - return 0; -} +/* + * rdfdump.c - dump RDOFF file header. + */ + +#include +#include +#include + +#define RDOFF_UTILS + +#include "rdoff.h" + +#define PROGRAM_VERSION "2.3" + +FILE *infile; + +void print_header(long length, int rdf_version) +{ + char buf[129], t, l, s, flags; + unsigned char reclen; + long o, ll; + uint16 rs; + + while (length > 0) { + fread(&t, 1, 1, infile); + if (rdf_version >= 2) { + fread(&reclen, 1, 1, infile); + } + switch (t) { + case RDFREC_GENERIC: /* generic record */ + printf(" generic record (length=%d)\n", (int)reclen); + fseek(infile, reclen, SEEK_CUR); + break; + + case RDFREC_RELOC: /* relocation record */ + case RDFREC_SEGRELOC: /* segment relocation */ + fread(&s, 1, 1, infile); + fread(&o, 4, 1, infile); + fread(&l, 1, 1, infile); + fread(&rs, 2, 1, infile); + printf(" %s: location (%04x:%08lx), length %d, " + "referred seg %04x\n", + t == 1 ? "relocation" : "seg relocation", (int)s, + translatelong(o), (int)l, translateshort(rs)); + if (rdf_version >= 2 && reclen != 8) + printf(" warning: reclen != 8\n"); + if (rdf_version == 1) + length -= 9; + if (rdf_version == 1 && t == 6) + printf + (" warning: seg relocation not supported in RDOFF1\n"); + break; + + case RDFREC_IMPORT: /* import record */ + case RDFREC_FARIMPORT: /* import far symbol */ + fread(&flags, 1, 1, infile); + fread(&rs, 2, 1, infile); + ll = 0; + + if (rdf_version == 1) { + do { + fread(&buf[ll], 1, 1, infile); + } while (buf[ll++]); + } else { + for (; ll < reclen - 3; ll++) + fread(&buf[ll], 1, 1, infile); + } + + if (t == 7) + printf("far "); + printf((flags & SYM_IMPORT) ? " import" : " extern"); + if (flags & SYM_FUNCTION) + printf(" proc"); + if (flags & SYM_DATA) + printf(" data"); + printf(": segment %04x = %s\n", translateshort(rs), buf); + if (rdf_version == 1) + length -= ll + 3; + if (rdf_version == 1 && t == 7) + printf + (" warning: far import not supported in RDOFF1\n"); + break; + + case RDFREC_GLOBAL: /* export record */ + fread(&flags, 1, 1, infile); + fread(&s, 1, 1, infile); + fread(&o, 4, 1, infile); + ll = 0; + + if (rdf_version == 1) { + do { + fread(&buf[ll], 1, 1, infile); + } while (buf[ll++]); + } else { + for (; ll < reclen - 6; ll++) + fread(&buf[ll], 1, 1, infile); + } + printf((flags & SYM_GLOBAL) ? " export" : " public"); + if (flags & SYM_FUNCTION) + printf(" proc"); + if (flags & SYM_DATA) + printf(" data"); + printf(": (%04x:%08lx) = %s\n", (int)s, translatelong(o), buf); + if (rdf_version == 1) + length -= ll + 6; + break; + + case RDFREC_DLL: /* DLL and Module records */ + case RDFREC_MODNAME: + ll = 0; + if (rdf_version == 1) { + do { + fread(&buf[ll], 1, 1, infile); + } while (buf[ll++]); + } else { + for (; ll < reclen; ll++) + fread(&buf[ll], 1, 1, infile); + } + if (t == 4) + printf(" dll: %s\n", buf); + else + printf(" module: %s\n", buf); + if (rdf_version == 1) + length -= ll + 1; + break; + + case RDFREC_BSS: /* BSS reservation */ + fread(&ll, 4, 1, infile); + printf(" bss reservation: %08lx bytes\n", translatelong(ll)); + if (rdf_version == 1) + length -= 5; + if (rdf_version > 1 && reclen != 4) + printf(" warning: reclen != 4\n"); + break; + + case RDFREC_COMMON:{ + unsigned short seg, align; + unsigned long size; + + fread(&seg, 2, 1, infile); + fread(&size, 4, 1, infile); + fread(&align, 2, 1, infile); + for (ll = 0; ll < reclen - 8; ll++) + fread(buf + ll, 1, 1, infile); + printf(" common: segment %04x = %s, %ld:%d\n", + translateshort(seg), buf, translatelong(size), + translateshort(align)); + break; + } + + default: + printf(" unrecognized record (type %d", (int)t); + if (rdf_version > 1) { + printf(", length %d", (int)reclen); + fseek(infile, reclen, SEEK_CUR); + } else + length--; + printf(")\n"); + } + if (rdf_version != 1) + length -= 2 + reclen; + } +} + +int main(int argc, char **argv) +{ + char id[7]; + long l; + uint16 s; + int verbose = 0; + long offset; + int foundnullsegment = 0; + int version; + long segmentcontentlength = 0; + int nsegments = 0; + long headerlength = 0; + long objectlength = 0; + + printf("RDOFF dump utility, version %s\n", PROGRAM_VERSION); + printf("RDOFF2 revision %s\n", RDOFF2_REVISION); + puts("Copyright (c) 1996,99 Julian R Hall\n" + "Improvements and fixes (c) 2002-2004 RET & COM Research."); + + if (argc < 2) { + fputs("Usage: rdfdump [-v] \n", stderr); + exit(1); + } + + if (!strcmp(argv[1], "-v")) { + verbose = 1; + if (argc < 3) { + fputs("required parameter missing\n", stderr); + exit(1); + } + argv++; + } + + infile = fopen(argv[1], "rb"); + if (!infile) { + fprintf(stderr, "rdfdump: Could not open %s\n", argv[1]); + exit(1); + } + + fread(id, 6, 1, infile); + if (strncmp(id, "RDOFF", 5)) { + fputs("rdfdump: File does not contain valid RDOFF header\n", + stderr); + exit(1); + } + + printf("File %s: RDOFF version %c\n\n", argv[1], id[5]); + if (id[5] < '1' || id[5] > '2') { + fprintf(stderr, "rdfdump: unknown RDOFF version '%c'\n", id[5]); + exit(1); + } + version = id[5] - '0'; + + if (version > 1) { + fread(&l, 4, 1, infile); + objectlength = translatelong(l); + printf("Object content size: %ld bytes\n", objectlength); + } + + fread(&l, 4, 1, infile); + headerlength = translatelong(l); + printf("Header (%ld bytes):\n", headerlength); + print_header(headerlength, version); + + if (version == 1) { + fread(&l, 4, 1, infile); + l = translatelong(l); + printf("\nText segment length = %ld bytes\n", l); + offset = 0; + while (l--) { + fread(id, 1, 1, infile); + if (verbose) { + if (offset % 16 == 0) + printf("\n%08lx ", offset); + printf(" %02x", (int)(unsigned char)id[0]); + offset++; + } + } + if (verbose) + printf("\n\n"); + + fread(&l, 4, 1, infile); + l = translatelong(l); + printf("Data segment length = %ld bytes\n", l); + + if (verbose) { + offset = 0; + while (l--) { + fread(id, 1, 1, infile); + if (offset % 16 == 0) + printf("\n%08lx ", offset); + printf(" %02x", (int)(unsigned char)id[0]); + offset++; + } + printf("\n"); + } + } else { + do { + fread(&s, 2, 1, infile); + s = translateshort(s); + if (!s) { + printf("\nNULL segment\n"); + foundnullsegment = 1; + break; + } + printf("\nSegment:\n Type = %04X (%s)\n", (int)s, + translatesegmenttype(s)); + nsegments++; + + fread(&s, 2, 1, infile); + printf(" Number = %04X\n", (int)translateshort(s)); + fread(&s, 2, 1, infile); + printf(" Resrvd = %04X\n", (int)translateshort(s)); + fread(&l, 4, 1, infile); + l = translatelong(l); + printf(" Length = %ld bytes\n", l); + segmentcontentlength += l; + + offset = 0; + while (l--) { + fread(id, 1, 1, infile); + if (verbose) { + if (offset % 16 == 0) + printf("\n%08lx ", offset); + printf(" %02x", (int)(unsigned char)id[0]); + offset++; + } + } + if (verbose) + printf("\n"); + } while (!feof(infile)); + if (!foundnullsegment) + printf("\nWarning: unexpected end of file - " + "NULL segment not found\n"); + + printf("\nTotal number of segments: %d\n", nsegments); + printf("Total segment content length: %ld bytes\n", + segmentcontentlength); + + /* calculate what the total object content length should have been */ + l = segmentcontentlength + 10 * (nsegments + 1) + headerlength + 4; + if (l != objectlength) + printf("Warning: actual object length (%ld) != " + "stored object length (%ld)\n", l, objectlength); + } + fclose(infile); + return 0; +} diff --git a/rdoff/rdflib.c b/rdoff/rdflib.c dissimilarity index 75% index 41f92d2c..cd5861cf 100644 --- a/rdoff/rdflib.c +++ b/rdoff/rdflib.c @@ -1,407 +1,390 @@ -/* rdflib - manipulate RDOFF library files (.rdl) */ - -/* - * an rdoff library is simply a sequence of RDOFF object files, each - * preceded by the name of the module, an ASCII string of up to 255 - * characters, terminated by a zero. - * - * When a library is being created, special signature block is placed - * in the beginning of the file. It is a string 'RDLIB' followed by a - * version number, then long content size and a long time stamp. - * The module name of the signature block is '.sig'. - * - * - * There may be an optional directory placed on the end of the file. - * The format of the directory will be 'RDLDD' followed by a version - * number, followed by the length of the directory, and then the - * directory, the format of which has not yet been designed. - * The module name of the directory must be '.dir'. - * - * All module names beginning with '.' are reserved for possible future - * extensions. The linker ignores all such modules, assuming they have - * the format of a six byte type & version identifier followed by long - * content size, followed by data. - */ - -#include -#include -#include -#include -#include -#include - -/* functions supported: - * create a library (no extra operands required) - * add a module from a library (requires filename and name to give mod.) - * replace a module in a library (requires given name and filename) - * delete a module from a library (requires given name) - * extract a module from the library (requires given name and filename) - * list modules - */ - -const char *usage = - "usage:\n" - " rdflib x libname [extra operands]\n\n" - " where x is one of:\n" - " c - create library\n" - " a - add module (operands = filename module-name)\n" - " x - extract (module-name filename)\n" - " r - replace (module-name filename)\n" - " d - delete (module-name)\n" - " t - list\n"; - -/* Library signature */ -const char *rdl_signature = "RDLIB2", *sig_modname = ".sig"; - -char **_argv; - -#define _ENDIANNESS 0 /* 0 for little, 1 for big */ - -static void longtolocal(long * l) -{ -#if _ENDIANNESS - unsigned char t; - unsigned char * p = (unsigned char *) l; - - t = p[0]; - p[0] = p[3]; - p[3] = t; - t = p[1]; - p[1] = p[2]; - p[2] = p[1]; -#endif -} - -char copybytes(FILE *fp, FILE *fp2, int n) -{ - int i, t = 0; - - for (i = 0 ; i < n; i++ ) - { - t = fgetc(fp); - if (t == EOF) - { - fprintf(stderr,"rdflib: premature end of file in '%s'\n", - _argv[2]); - exit(1); - } - if (fp2) - if (fputc(t, fp2) == EOF) - { - fprintf(stderr,"rdflib: write error\n"); - exit(1); - } - } - return (char) t; /* return last char read */ -} - -long copylong(FILE *fp, FILE *fp2) -{ - long l; - int i,t; - unsigned char * p = (unsigned char *) &l; - - - for (i = 0 ; i < 4; i++ ) /* skip magic no */ - { - t = fgetc(fp); - if (t == EOF) - { - fprintf(stderr,"rdflib: premature end of file in '%s'\n", - _argv[2]); - exit(1); - } - if (fp2) - if (fputc(t, fp2) == EOF) - { - fprintf(stderr,"rdflib: write error\n"); - exit(1); - } - *p++ = t; - } - longtolocal (&l); - return l; -} - -int main(int argc, char **argv) -{ - FILE *fp, *fp2 = NULL, *fptmp; - char *p, buf[256], c; - int i; - long l; - time_t t; - char rdbuf[10]; - - _argv = argv; - - if (argc < 3 || !strncmp(argv[1],"-h",2) || !strncmp(argv[1],"--h",3)) - { - printf(usage); - exit(1); - } - - switch(argv[1][0]) - { - case 'c': /* create library */ - fp = fopen(argv[2],"wb"); - if (! fp) { - fprintf(stderr,"rdflib: could not open '%s'\n",argv[2]); - perror("rdflib"); - exit(1); - } - fwrite(sig_modname, 1, strlen(sig_modname)+1, fp); - fwrite(rdl_signature, 1, strlen(rdl_signature), fp); - l = sizeof(t = time(NULL)); - fwrite(&l, sizeof(l), 1, fp); - fwrite(&t, 1, l, fp); - fclose(fp); - break; - - case 'a': /* add module */ - if (argc < 5) { - fprintf(stderr,"rdflib: required parameter missing\n"); - exit(1); - } - fp = fopen(argv[2],"ab"); - if (! fp) - { - fprintf(stderr,"rdflib: could not open '%s'\n",argv[2]); - perror("rdflib"); - exit(1); - } - - fp2 = fopen(argv[3],"rb"); - if (! fp2) - { - fprintf(stderr,"rdflib: could not open '%s'\n",argv[3]); - perror("rdflib"); - exit(1); - } - - p = argv[4]; - do { - if ( fputc(*p,fp) == EOF ) { - fprintf(stderr,"rdflib: write error\n"); - exit(1); - } - } while (*p++); - - while (! feof (fp2) ) { - i = fgetc (fp2); - if (i == EOF) { - break; - } - - if ( fputc(i, fp) == EOF ) { - fprintf(stderr,"rdflib: write error\n"); - exit(1); - } - } - fclose(fp2); - fclose(fp); - break; - - case 'x': - if (argc < 5) { - fprintf(stderr, "rdflib: required parameter missing\n"); - exit(1); - } - case 't': - fp = fopen(argv[2],"rb"); - if (! fp) - { - fprintf(stderr,"rdflib: could not open '%s'\n",argv[2]); - perror("rdflib"); - exit(1); - } - - fp2 = NULL; - while (! feof(fp) ) { - /* read name */ - p = buf; - while( ( *(p++) = (char) fgetc(fp) ) ) - if (feof(fp)) break; - - if (feof(fp)) break; - - fp2 = NULL; - if (argv[1][0] == 'x') { - /* check against desired name */ - if (! strcmp(buf,argv[3]) ) - { - fp2 = fopen(argv[4],"wb"); - if (! fp2) - { - fprintf(stderr,"rdflib: could not open '%s'\n",argv[4]); - perror("rdflib"); - exit(1); - } - } - } - else - printf("%-40s ", buf); - - /* step over the RDOFF file, extracting type information for - * the listing, and copying it if fp2 != NULL */ - - if (buf[0] == '.') { - - if (argv[1][0] == 't') - for (i = 0; i < 6; i++) - printf("%c", copybytes(fp,fp2,1)); - else - copybytes(fp,fp2,6); - - l = copylong(fp,fp2); - - if (argv[1][0] == 't') printf(" %ld bytes content\n", l); - - copybytes(fp,fp2,l); - } - else if ((c=copybytes(fp,fp2,6)) >= '2') /* version 2 or above */ - { - l = copylong(fp,fp2); - - if (argv[1][0] == 't') - printf("RDOFF%c %ld bytes content\n", c, l); - copybytes(fp,fp2, l); /* entire object */ - } - else - { - if (argv[1][0] == 't') - printf("RDOFF1\n"); - /* - * version 1 object, so we don't have an object content - * length field. - */ - copybytes(fp,fp2, copylong(fp,fp2)); /* header */ - copybytes(fp,fp2, copylong(fp,fp2)); /* text */ - copybytes(fp,fp2, copylong(fp,fp2)); /* data */ - } - - if (fp2) - break; - } - fclose(fp); - if (fp2) - fclose(fp2); - else if (argv[1][0] == 'x') - { - fprintf(stderr,"rdflib: module '%s' not found in '%s'\n", - argv[3],argv[2]); - exit(1); - } - break; - - case 'r': /* replace module */ - argc--; - case 'd': /* delete module */ - if (argc < 4) { - fprintf(stderr, "rdflib: required parameter missing\n"); - exit(1); - } - - fp = fopen(argv[2],"rb"); - if (! fp) - { - fprintf(stderr, "rdflib: could not open '%s'\n", argv[2]); - perror("rdflib"); - exit(1); - } - - if (argv[1][0] == 'r') { - fp2 = fopen(argv[4],"rb"); - if (! fp2) - { - fprintf(stderr, "rdflib: could not open '%s'\n", argv[4]); - perror("rdflib"); - exit(1); - } - } - - fptmp = tmpfile(); - if (! fptmp) - { - fprintf(stderr,"rdflib: could not open temporary file\n"); - perror("rdflib"); - exit(1); - } - - /* copy library into temporary file */ - fseek(fp, 0, SEEK_END); /* get file length */ - l = ftell(fp); - fseek(fp, 0, SEEK_SET); - copybytes(fp, fptmp, l); - rewind(fptmp); - freopen(argv[2], "wb", fp); - - while (! feof(fptmp) ) { - /* read name */ - p = buf; - while( ( *(p++) = (char) fgetc(fptmp) ) ) - if (feof(fptmp)) break; - - if (feof(fptmp)) break; - - /* check against desired name */ - if (! strcmp(buf, argv[3]) ) { - fread(p=rdbuf, 1, sizeof(rdbuf), fptmp); - l = *(long*)(p+6); - fseek(fptmp, l, SEEK_CUR); - break; - } else { - fwrite(buf, 1, strlen(buf)+1, fp); /* module name */ - if ((c=copybytes(fptmp, fp, 6)) >= '2') { - l = copylong(fptmp, fp); /* version 2 or above */ - copybytes(fptmp, fp, l); /* entire object */ - } - } - } - - if (argv[1][0] == 'r') { - /* copy new module into library */ - p = argv[3]; - do { - if ( fputc(*p, fp) == EOF ) { - fprintf(stderr, "rdflib: write error\n"); - exit(1); - } - } while (*p++); - - while (! feof (fp2) ) { - i = fgetc (fp2); - if (i == EOF) { - break; - } - if ( fputc(i, fp) == EOF ) { - fprintf(stderr, "rdflib: write error\n"); - exit(1); - } - } - fclose(fp2); - } - - /* copy rest of library if any */ - while (! feof (fptmp) ) { - i = fgetc (fptmp); - if (i == EOF) { - break; - } - - if ( fputc(i, fp) == EOF ) { - fprintf(stderr,"rdflib: write error\n"); - exit(1); - } - } - - fclose(fp); - fclose(fptmp); - break; - - default: - fprintf(stderr,"rdflib: command '%c' not recognized\n", - argv[1][0]); - exit(1); - } - return 0; -} +/* rdflib - manipulate RDOFF library files (.rdl) */ + +/* + * an rdoff library is simply a sequence of RDOFF object files, each + * preceded by the name of the module, an ASCII string of up to 255 + * characters, terminated by a zero. + * + * When a library is being created, special signature block is placed + * in the beginning of the file. It is a string 'RDLIB' followed by a + * version number, then long content size and a long time stamp. + * The module name of the signature block is '.sig'. + * + * + * There may be an optional directory placed on the end of the file. + * The format of the directory will be 'RDLDD' followed by a version + * number, followed by the length of the directory, and then the + * directory, the format of which has not yet been designed. + * The module name of the directory must be '.dir'. + * + * All module names beginning with '.' are reserved for possible future + * extensions. The linker ignores all such modules, assuming they have + * the format of a six byte type & version identifier followed by long + * content size, followed by data. + */ + +#include +#include +#include +#include +#include +#include + +/* functions supported: + * create a library (no extra operands required) + * add a module from a library (requires filename and name to give mod.) + * replace a module in a library (requires given name and filename) + * delete a module from a library (requires given name) + * extract a module from the library (requires given name and filename) + * list modules + */ + +const char *usage = + "usage:\n" + " rdflib x libname [extra operands]\n\n" + " where x is one of:\n" + " c - create library\n" + " a - add module (operands = filename module-name)\n" + " x - extract (module-name filename)\n" + " r - replace (module-name filename)\n" + " d - delete (module-name)\n" " t - list\n"; + +/* Library signature */ +const char *rdl_signature = "RDLIB2", *sig_modname = ".sig"; + +char **_argv; + +#define _ENDIANNESS 0 /* 0 for little, 1 for big */ + +static void longtolocal(long *l) +{ +#if _ENDIANNESS + unsigned char t; + unsigned char *p = (unsigned char *)l; + + t = p[0]; + p[0] = p[3]; + p[3] = t; + t = p[1]; + p[1] = p[2]; + p[2] = p[1]; +#endif +} + +char copybytes(FILE * fp, FILE * fp2, int n) +{ + int i, t = 0; + + for (i = 0; i < n; i++) { + t = fgetc(fp); + if (t == EOF) { + fprintf(stderr, "rdflib: premature end of file in '%s'\n", + _argv[2]); + exit(1); + } + if (fp2) + if (fputc(t, fp2) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } + return (char)t; /* return last char read */ +} + +long copylong(FILE * fp, FILE * fp2) +{ + long l; + int i, t; + unsigned char *p = (unsigned char *)&l; + + for (i = 0; i < 4; i++) { /* skip magic no */ + t = fgetc(fp); + if (t == EOF) { + fprintf(stderr, "rdflib: premature end of file in '%s'\n", + _argv[2]); + exit(1); + } + if (fp2) + if (fputc(t, fp2) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + *p++ = t; + } + longtolocal(&l); + return l; +} + +int main(int argc, char **argv) +{ + FILE *fp, *fp2 = NULL, *fptmp; + char *p, buf[256], c; + int i; + long l; + time_t t; + char rdbuf[10]; + + _argv = argv; + + if (argc < 3 || !strncmp(argv[1], "-h", 2) + || !strncmp(argv[1], "--h", 3)) { + printf(usage); + exit(1); + } + + switch (argv[1][0]) { + case 'c': /* create library */ + fp = fopen(argv[2], "wb"); + if (!fp) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[2]); + perror("rdflib"); + exit(1); + } + fwrite(sig_modname, 1, strlen(sig_modname) + 1, fp); + fwrite(rdl_signature, 1, strlen(rdl_signature), fp); + l = sizeof(t = time(NULL)); + fwrite(&l, sizeof(l), 1, fp); + fwrite(&t, 1, l, fp); + fclose(fp); + break; + + case 'a': /* add module */ + if (argc < 5) { + fprintf(stderr, "rdflib: required parameter missing\n"); + exit(1); + } + fp = fopen(argv[2], "ab"); + if (!fp) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[2]); + perror("rdflib"); + exit(1); + } + + fp2 = fopen(argv[3], "rb"); + if (!fp2) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[3]); + perror("rdflib"); + exit(1); + } + + p = argv[4]; + do { + if (fputc(*p, fp) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } while (*p++); + + while (!feof(fp2)) { + i = fgetc(fp2); + if (i == EOF) { + break; + } + + if (fputc(i, fp) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } + fclose(fp2); + fclose(fp); + break; + + case 'x': + if (argc < 5) { + fprintf(stderr, "rdflib: required parameter missing\n"); + exit(1); + } + case 't': + fp = fopen(argv[2], "rb"); + if (!fp) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[2]); + perror("rdflib"); + exit(1); + } + + fp2 = NULL; + while (!feof(fp)) { + /* read name */ + p = buf; + while ((*(p++) = (char)fgetc(fp))) + if (feof(fp)) + break; + + if (feof(fp)) + break; + + fp2 = NULL; + if (argv[1][0] == 'x') { + /* check against desired name */ + if (!strcmp(buf, argv[3])) { + fp2 = fopen(argv[4], "wb"); + if (!fp2) { + fprintf(stderr, "rdflib: could not open '%s'\n", + argv[4]); + perror("rdflib"); + exit(1); + } + } + } else + printf("%-40s ", buf); + + /* step over the RDOFF file, extracting type information for + * the listing, and copying it if fp2 != NULL */ + + if (buf[0] == '.') { + + if (argv[1][0] == 't') + for (i = 0; i < 6; i++) + printf("%c", copybytes(fp, fp2, 1)); + else + copybytes(fp, fp2, 6); + + l = copylong(fp, fp2); + + if (argv[1][0] == 't') + printf(" %ld bytes content\n", l); + + copybytes(fp, fp2, l); + } else if ((c = copybytes(fp, fp2, 6)) >= '2') { /* version 2 or above */ + l = copylong(fp, fp2); + + if (argv[1][0] == 't') + printf("RDOFF%c %ld bytes content\n", c, l); + copybytes(fp, fp2, l); /* entire object */ + } else { + if (argv[1][0] == 't') + printf("RDOFF1\n"); + /* + * version 1 object, so we don't have an object content + * length field. + */ + copybytes(fp, fp2, copylong(fp, fp2)); /* header */ + copybytes(fp, fp2, copylong(fp, fp2)); /* text */ + copybytes(fp, fp2, copylong(fp, fp2)); /* data */ + } + + if (fp2) + break; + } + fclose(fp); + if (fp2) + fclose(fp2); + else if (argv[1][0] == 'x') { + fprintf(stderr, "rdflib: module '%s' not found in '%s'\n", + argv[3], argv[2]); + exit(1); + } + break; + + case 'r': /* replace module */ + argc--; + case 'd': /* delete module */ + if (argc < 4) { + fprintf(stderr, "rdflib: required parameter missing\n"); + exit(1); + } + + fp = fopen(argv[2], "rb"); + if (!fp) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[2]); + perror("rdflib"); + exit(1); + } + + if (argv[1][0] == 'r') { + fp2 = fopen(argv[4], "rb"); + if (!fp2) { + fprintf(stderr, "rdflib: could not open '%s'\n", argv[4]); + perror("rdflib"); + exit(1); + } + } + + fptmp = tmpfile(); + if (!fptmp) { + fprintf(stderr, "rdflib: could not open temporary file\n"); + perror("rdflib"); + exit(1); + } + + /* copy library into temporary file */ + fseek(fp, 0, SEEK_END); /* get file length */ + l = ftell(fp); + fseek(fp, 0, SEEK_SET); + copybytes(fp, fptmp, l); + rewind(fptmp); + freopen(argv[2], "wb", fp); + + while (!feof(fptmp)) { + /* read name */ + p = buf; + while ((*(p++) = (char)fgetc(fptmp))) + if (feof(fptmp)) + break; + + if (feof(fptmp)) + break; + + /* check against desired name */ + if (!strcmp(buf, argv[3])) { + fread(p = rdbuf, 1, sizeof(rdbuf), fptmp); + l = *(long *)(p + 6); + fseek(fptmp, l, SEEK_CUR); + break; + } else { + fwrite(buf, 1, strlen(buf) + 1, fp); /* module name */ + if ((c = copybytes(fptmp, fp, 6)) >= '2') { + l = copylong(fptmp, fp); /* version 2 or above */ + copybytes(fptmp, fp, l); /* entire object */ + } + } + } + + if (argv[1][0] == 'r') { + /* copy new module into library */ + p = argv[3]; + do { + if (fputc(*p, fp) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } while (*p++); + + while (!feof(fp2)) { + i = fgetc(fp2); + if (i == EOF) { + break; + } + if (fputc(i, fp) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } + fclose(fp2); + } + + /* copy rest of library if any */ + while (!feof(fptmp)) { + i = fgetc(fptmp); + if (i == EOF) { + break; + } + + if (fputc(i, fp) == EOF) { + fprintf(stderr, "rdflib: write error\n"); + exit(1); + } + } + + fclose(fp); + fclose(fptmp); + break; + + default: + fprintf(stderr, "rdflib: command '%c' not recognized\n", + argv[1][0]); + exit(1); + } + return 0; +} diff --git a/rdoff/rdfload.c b/rdoff/rdfload.c dissimilarity index 63% index 2f8bf6b1..e5da4230 100644 --- a/rdoff/rdfload.c +++ b/rdoff/rdfload.c @@ -1,180 +1,185 @@ -/* rdfload.c RDOFF Object File loader library - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - * - * Permission to use this file in your own projects is granted, as long - * as acknowledgement is given in an appropriate manner to its authors, - * with instructions of how to obtain a copy via ftp. - */ - -/* - * TODO: this has been modified from previous version only in very - * simplistic ways. Needs to be improved drastically, especially: - * - support for more than the 2 standard segments - * - support for segment relocations (hard to do in ANSI C) - */ - -#include -#include -#include - -#include "rdfload.h" -#include "symtab.h" -#include "collectn.h" - -extern int rdf_errno; - -rdfmodule * rdfload(const char *filename) -{ - rdfmodule * f; - long bsslength = 0; - char * hdr; - rdfheaderrec *r; - - f = malloc(sizeof(rdfmodule)); - if (f == NULL) { - rdf_errno = RDF_ERR_NOMEM; - return NULL; - } - - f->symtab = symtabNew(); - if (!f->symtab) { - free(f); - rdf_errno = RDF_ERR_NOMEM; - return NULL; - } - - /* open the file */ - if ( rdfopen( &(f->f), filename ) ) { - free(f); - return NULL; - } - - /* read in text and data segments, and header */ - - f->t = malloc (f->f.seg[0].length); - f->d = malloc (f->f.seg[1].length); /* BSS seg allocated later */ - hdr = malloc (f->f.header_len); - - if (! f->t || ! f->d || !hdr) { - rdf_errno = RDF_ERR_NOMEM; - rdfclose(&f->f); - if (f->t) free(f->t); - if (f->d) free(f->d); - free(f); - return NULL; - } - - if ( rdfloadseg (&f->f,RDOFF_HEADER,hdr) || - rdfloadseg (&f->f,RDOFF_CODE,f->t) || - rdfloadseg (&f->f,RDOFF_DATA,f->d) ) - { - rdfclose(&f->f); - free(f->t); - free(f->d); - free(f); - free(hdr); - return NULL; - } - - rdfclose(&f->f); - - /* Allocate BSS segment; step through header and count BSS records */ - - while ((r = rdfgetheaderrec(&f->f))) { - if (r->type == 5) - bsslength += r->b.amount; - } - - f->b = malloc ( bsslength ); - if (bsslength && (!f->b)) { - free(f->t); - free(f->d); - free(f); - free(hdr); - rdf_errno = RDF_ERR_NOMEM; - return NULL; - } - - rdfheaderrewind (&f->f); - - f->textrel = (long)f->t; - f->datarel = (long)f->d; - f->bssrel = (long)f->b; - - return f; -} - -int rdf_relocate(rdfmodule * m) -{ - rdfheaderrec * r; - Collection imports; - symtabEnt e; - long rel; - unsigned char * seg; - - rdfheaderrewind (&m->f); - collection_init(&imports); - - while ((r = rdfgetheaderrec(&m->f))) { - switch (r->type) { - case 1: /* Relocation record */ - - /* calculate relocation factor */ - - if (r->r.refseg == 0) rel = m->textrel; - else if (r->r.refseg == 1) rel = m->datarel; - else if (r->r.refseg == 2) rel = m->bssrel; - else - /* We currently do not support load-time linkage. - This should be added some time soon... */ - - return 1; /* return error code */ - - if ((r->r.segment & 63) == 0) seg = m->t; - else if ((r->r.segment & 63) == 1) seg = m->d; - else - continue; /* relocation not in a loaded segment */ - - /* it doesn't matter in this case that the code is non-portable, - as the entire concept of executing a module like this is - non-portable */ - switch(r->r.length) { - case 1: - seg[r->r.offset] += (char) rel; - break; - case 2: - *(uint16 *)(seg + r->r.offset) += (uint16) rel; - break; - case 4: - *(long *)(seg + r->r.offset) += rel; - break; - } - break; - - case 3: /* export record - add to symtab */ - e.segment = r->e.segment; - e.offset = r->e.offset + - (e.segment == 0 ? m->textrel : /* 0 -> code */ - e.segment == 1 ? m->datarel : /* 1 -> data */ - m->bssrel) ; /* 2 -> bss */ - e.flags = 0; - e.name = malloc(strlen(r->e.label) + 1); - if (! e.name) - return 1; - - strcpy(e.name,r->e.label); - symtabInsert(m->symtab,&e); - break; - - case 6: /* segment relocation */ - fprintf(stderr, "%s: segment relocation not supported by this " - "loader\n", m->f.name); - return 1; - } - } - return 0; -} +/* rdfload.c RDOFF Object File loader library + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * Permission to use this file in your own projects is granted, as long + * as acknowledgement is given in an appropriate manner to its authors, + * with instructions of how to obtain a copy via ftp. + */ + +/* + * TODO: this has been modified from previous version only in very + * simplistic ways. Needs to be improved drastically, especially: + * - support for more than the 2 standard segments + * - support for segment relocations (hard to do in ANSI C) + */ + +#include +#include +#include + +#include "rdfload.h" +#include "symtab.h" +#include "collectn.h" + +extern int rdf_errno; + +rdfmodule *rdfload(const char *filename) +{ + rdfmodule *f; + long bsslength = 0; + char *hdr; + rdfheaderrec *r; + + f = malloc(sizeof(rdfmodule)); + if (f == NULL) { + rdf_errno = RDF_ERR_NOMEM; + return NULL; + } + + f->symtab = symtabNew(); + if (!f->symtab) { + free(f); + rdf_errno = RDF_ERR_NOMEM; + return NULL; + } + + /* open the file */ + if (rdfopen(&(f->f), filename)) { + free(f); + return NULL; + } + + /* read in text and data segments, and header */ + + f->t = malloc(f->f.seg[0].length); + f->d = malloc(f->f.seg[1].length); /* BSS seg allocated later */ + hdr = malloc(f->f.header_len); + + if (!f->t || !f->d || !hdr) { + rdf_errno = RDF_ERR_NOMEM; + rdfclose(&f->f); + if (f->t) + free(f->t); + if (f->d) + free(f->d); + free(f); + return NULL; + } + + if (rdfloadseg(&f->f, RDOFF_HEADER, hdr) || + rdfloadseg(&f->f, RDOFF_CODE, f->t) || + rdfloadseg(&f->f, RDOFF_DATA, f->d)) { + rdfclose(&f->f); + free(f->t); + free(f->d); + free(f); + free(hdr); + return NULL; + } + + rdfclose(&f->f); + + /* Allocate BSS segment; step through header and count BSS records */ + + while ((r = rdfgetheaderrec(&f->f))) { + if (r->type == 5) + bsslength += r->b.amount; + } + + f->b = malloc(bsslength); + if (bsslength && (!f->b)) { + free(f->t); + free(f->d); + free(f); + free(hdr); + rdf_errno = RDF_ERR_NOMEM; + return NULL; + } + + rdfheaderrewind(&f->f); + + f->textrel = (long)f->t; + f->datarel = (long)f->d; + f->bssrel = (long)f->b; + + return f; +} + +int rdf_relocate(rdfmodule * m) +{ + rdfheaderrec *r; + Collection imports; + symtabEnt e; + long rel; + unsigned char *seg; + + rdfheaderrewind(&m->f); + collection_init(&imports); + + while ((r = rdfgetheaderrec(&m->f))) { + switch (r->type) { + case 1: /* Relocation record */ + + /* calculate relocation factor */ + + if (r->r.refseg == 0) + rel = m->textrel; + else if (r->r.refseg == 1) + rel = m->datarel; + else if (r->r.refseg == 2) + rel = m->bssrel; + else + /* We currently do not support load-time linkage. + This should be added some time soon... */ + + return 1; /* return error code */ + + if ((r->r.segment & 63) == 0) + seg = m->t; + else if ((r->r.segment & 63) == 1) + seg = m->d; + else + continue; /* relocation not in a loaded segment */ + + /* it doesn't matter in this case that the code is non-portable, + as the entire concept of executing a module like this is + non-portable */ + switch (r->r.length) { + case 1: + seg[r->r.offset] += (char)rel; + break; + case 2: + *(uint16 *) (seg + r->r.offset) += (uint16) rel; + break; + case 4: + *(long *)(seg + r->r.offset) += rel; + break; + } + break; + + case 3: /* export record - add to symtab */ + e.segment = r->e.segment; + e.offset = r->e.offset + (e.segment == 0 ? m->textrel : /* 0 -> code */ + e.segment == 1 ? m->datarel : /* 1 -> data */ + m->bssrel); /* 2 -> bss */ + e.flags = 0; + e.name = malloc(strlen(r->e.label) + 1); + if (!e.name) + return 1; + + strcpy(e.name, r->e.label); + symtabInsert(m->symtab, &e); + break; + + case 6: /* segment relocation */ + fprintf(stderr, "%s: segment relocation not supported by this " + "loader\n", m->f.name); + return 1; + } + } + return 0; +} diff --git a/rdoff/rdfload.h b/rdoff/rdfload.h index 3889a4e1..34446b6f 100644 --- a/rdoff/rdfload.h +++ b/rdoff/rdfload.h @@ -17,15 +17,15 @@ #include "rdoff.h" typedef struct RDFModuleStruct { - rdffile f; /* file structure */ - unsigned char * t, * d, * b; /* text, data, and bss segments */ - long textrel; - long datarel; - long bssrel; - void * symtab; + rdffile f; /* file structure */ + unsigned char *t, *d, *b; /* text, data, and bss segments */ + long textrel; + long datarel; + long bssrel; + void *symtab; } rdfmodule; -rdfmodule * rdfload(const char * filename); +rdfmodule *rdfload(const char *filename); int rdf_relocate(rdfmodule * m); #endif diff --git a/rdoff/rdlar.c b/rdoff/rdlar.c dissimilarity index 69% index cdbd1549..53c12c80 100644 --- a/rdoff/rdlar.c +++ b/rdoff/rdlar.c @@ -1,461 +1,463 @@ -/* - * rdlar.c - new librarian/archiver for RDOFF2. - * Copyright (c) 2002 RET & COM Research. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rdlar.h" - -#define PROGRAM_VERSION "0.1" - -/** Types **/ -typedef enum { FALSE, TRUE } bool; - -/** Constants **/ -const char commands[] = "adnrtx"; -const char modifiers[] = "cflouvV"; - -/** Global variables **/ -char *progname = "rdlar"; -char **_argv = NULL; -struct { - bool createok; - bool usefname; - bool align; - bool odate; - bool fresh; - int verbose; -} options = { 0, 0, 0, 0, 0, 0 }; - -#define _ENDIANNESS 0 /* 0 for little, 1 for big */ - - -/* - * Convert long to little endian (if we were compiled on big-endian machine) - */ -static void longtolocal(long * l) -{ -#if _ENDIANNESS - unsigned char t; - unsigned char * p = (unsigned char *) l; - - t = p[0]; - p[0] = p[3]; - p[3] = t; - t = p[1]; - p[1] = p[2]; - p[2] = p[1]; -#endif -} - -/* - * Print version information - */ -void show_version(void) -{ - puts("New RDOFF2 librarian/archiver, version " PROGRAM_VERSION "\n" - "Copyright (c) 2002 RET & COM Research.\n" - "This program is free software and distributed under GPL (version 2 or later);\n" - "see http://www.gnu.org/copyleft/gpl.html for details."); -} - - -/* - * Print usage instructions - */ -void usage(void) -{ - printf("Usage: %s [-]{%s}[%s] libfile [module-name] [files]\n", - progname, commands, modifiers); - puts(" commands:\n" - " a - add module(s) to the library\n" - " d - delete module(s) from the library\n" - " n - create the library\n" - " r - replace module(s)\n" - " t - display contents of library\n" - " x - extract module(s)\n" - " command specific modifiers:\n" - " o - preserve original dates\n" - " u - only replace modules that are newer than library contents\n" - " generic modifiers:\n" - " c - do not warn if the library had to be created\n" - " f - use file name as a module name\n" - " v - be verbose\n" - " V - display version information"); -} - - -/* - * Print an error message and exit - */ -void error_exit(int errcode, bool useperror, const char *fmt, ...) -{ - va_list ap; - - fprintf(stderr, "%s: ", progname); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - putc('\n', stderr); - if (useperror) perror(progname); - exit(errcode); -} - - -/* - * Fill in and write a header - */ -void put_header(struct rdlm_hdr *hdr, FILE *libfp, char *modname) -{ - int n = 0; - - hdr->hdrsize = sizeof(*hdr); - if (modname) hdr->hdrsize += (n = strlen(modname) + 1); - if (libfp == NULL) return; - if (fwrite(hdr, 1, sizeof(*hdr), libfp) != sizeof(*hdr) || - (modname && (fwrite(modname, 1, n, libfp) != n))) - error_exit(3, TRUE, "could not write header"); -} - -/* - * Copy n bytes from one file to another and return last character read. - */ -char copybytes(FILE *fp, FILE *fp2, int n) -{ - int i, t = 0; - - for (i = 0 ; i < n; i++) { - t = fgetc(fp); - if (t == EOF) - error_exit(1, FALSE, "premature end of file in '%s'", _argv[2]); - if (fp2) - if (fputc(t, fp2) == EOF) - error_exit(1, FALSE, "write error"); - } - return (char) t; -} - - -/* - * Copy unsigned long from one file to another. - * Return local presentation of long. - */ -long copylong(FILE *fp, FILE *fp2) -{ - long l; - int i,t; - unsigned char * p = (unsigned char *) &l; - - - for (i = 0 ; i < 4; i++ ) { - t = fgetc(fp); - if (t == EOF) - error_exit(1, FALSE, "premature end of file in '%s'", _argv[2]); - if (fp2) - if (fputc(t, fp2) == EOF) - error_exit(1, FALSE, "write error"); - *p++ = t; - } - longtolocal (&l); - return l; -} - - -/* - * Create a new library - */ -int create_library(char *libname) -{ - FILE *libfp; - struct rdlm_hdr hdr; - - hdr.magic = RDLAMAG; - hdr.hdrsize = 0; - hdr.date = time(NULL); - hdr.owner = getuid(); - hdr.group = getgid(); - hdr.mode = umask(022); - hdr.size = 0; - - libfp = fopen(libname, "wb"); - if (!libfp) - error_exit(1, TRUE, "could not open '%s'\n", libname); - - /* Write library header */ - put_header(&hdr, libfp, NULL); - - fclose(libfp); - return TRUE; -} - - -/* - * Add a module to the library - */ -int add_module(FILE *libfp, const char *fname, char *modname) -{ - FILE *modfp; - struct rdlm_hdr hdr = { RDLMMAG, 0, 0, 0, 0, 0, 0 }; - struct stat finfo; - int i; - - if (options.verbose) - fprintf(stderr, "adding module %s\n", modname); - - /* Initialize some fields in the module header */ - if (stat(fname, &finfo) < 0) - error_exit(1, TRUE, "could not stat '%s'", fname); - hdr.date = finfo.st_mtime; - hdr.owner = finfo.st_uid; - hdr.group = finfo.st_gid; - hdr.size = finfo.st_size; - - modfp = fopen(fname, "rb"); - if (!modfp) - error_exit(1, TRUE, "could not open '%s'", fname); - - /* Write module header */ - put_header(&hdr, libfp, modname); - - /* Put the module itself */ - while (! feof(modfp)) { - i = fgetc(modfp); - if (i == EOF) break; - if (fputc(i, libfp) == EOF ) - error_exit(1, FALSE, "write error"); - } - - fclose(modfp); - return TRUE; -} - - -/* - * Main - */ -int main(int argc, char *argv[]) -{ - FILE *libfp, *tmpfp, *modfp = NULL; - struct stat finfo; - struct rdlm_hdr hdr; - char buf[MAXMODNAMELEN], *p = NULL; - char c; - int i; - - progname = argv[0]; - _argv = argv; - - if (argc < 2) { - usage(); - exit(1); - } - - /* Check whether some modifiers were specified */ - for (i = 1; i < strlen(argv[1]); i++) { - switch (c = argv[1][i]) { - case 'c': - options.createok = TRUE; - break; - case 'f': - options.usefname = TRUE; - break; - case 'l': - options.align = TRUE; - break; - case 'o': - options.odate = TRUE; - break; - case 'u': - options.fresh = TRUE; - break; - case 'v': - options.verbose++; - break; - case 'V': - show_version(); - exit(0); - default: - if (strchr(commands, c) == NULL) - error_exit(2, FALSE, "invalid command or modifier '%c'", c); - } - } - - if (argc < 3) - error_exit(2, FALSE, "missing library name"); - - /* Process the command */ - if (argv[1][0] == '-') argv[1]++; - switch(c = argv[1][0]) { - case 'a': /* add a module */ - if (argc < 4 || (!options.usefname && argc != 5)) - error_exit(2, FALSE, "invalid number of arguments"); - - /* Check if a library already exists. If not - create it */ - if (access(argv[2], F_OK) < 0) { - if (!options.createok) - fprintf(stderr, "creating library %s\n", argv[2]); - create_library(argv[2]); - } - - libfp = fopen(argv[2], "ab"); - if (!libfp) - error_exit(1, TRUE, "could not open '%s'", argv[2]); - - if (!options.usefname) - add_module(libfp, argv[4], argv[3]); - else - for (i = 3; i < argc; i++) - add_module(libfp, argv[i], argv[i]); - - fclose(libfp); - break; - - case 'n': /* create library */ - create_library(argv[2]); - break; - - case 'x': /* extract module(s) */ - if (!options.usefname) - argc--; - if (argc < 4) - error_exit(2, FALSE, "required parameter missing"); - p = options.usefname ? argv[3] : argv[4]; - case 't': /* list library contents */ - libfp = fopen(argv[2],"rb"); - if (!libfp) - error_exit(1, TRUE, "could not open '%s'\n", argv[2]); - - /* Read library header */ - if (fread(&hdr, 1, sizeof(hdr), libfp) != sizeof(hdr) || - hdr.magic != RDLAMAG) - error_exit(1, FALSE, "invalid library format"); - - /* Walk through the library looking for requested module */ - while (!feof(libfp)) { - /* Read module header */ - i = fread(&hdr, 1, sizeof(hdr), libfp); - if (feof(libfp)) break; - if (i != sizeof(hdr) || hdr.magic != RDLMMAG) - error_exit(1, FALSE, "invalid module header"); - /* Read module name */ - i = hdr.hdrsize - sizeof(hdr); - if (i > sizeof(buf) || - fread(buf, 1, i, libfp) != i) - error_exit(1, FALSE, "invalid module name"); - if (c == 'x') { - /* Check against desired name */ - if (!strcmp(buf, argv[3])) { - if (options.verbose) - fprintf(stderr, "extracting module %s to file %s\n", - buf, p); - modfp = fopen(p, "wb"); - if (!modfp) - error_exit(1, TRUE, "could not open '%s'", p); - } - } else { - printf("%-40s ", buf); - if (options.verbose) { - printf("%ld bytes", hdr.size); - } - putchar('\n'); - } - - copybytes(libfp, modfp, hdr.size); - if (modfp) break; - } - - fclose(libfp); - if (modfp) - fclose(modfp); - else if (c == 'x') - error_exit(1, FALSE, "module '%s' not found in '%s'", - argv[3], argv[2]); - break; - - case 'r': /* replace module(s) */ - argc--; - if (stat(argv[4], &finfo) < 0) - error_exit(1, TRUE, "could not stat '%s'", argv[4]); - case 'd': /* delete module(s) */ - if (argc < 4) - error_exit(2, FALSE, "required parameter missing"); - - libfp = fopen(argv[2], "rb"); - if (!libfp) - error_exit(1, TRUE, "could not open '%s'", argv[2]); - - /* Copy the library into a temporary file */ - tmpfp = tmpfile(); - if (!tmpfp) - error_exit(1, TRUE, "could not open temporary file"); - - stat(argv[2], &finfo); - copybytes(libfp, tmpfp, finfo.st_size); - rewind(tmpfp); - freopen(argv[2], "wb", libfp); - - /* Read library header and write it to a new file */ - if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) || - hdr.magic != RDLAMAG) - error_exit(1, FALSE, "invalid library format"); - put_header(&hdr, libfp, NULL); - - /* Walk through the library looking for requested module */ - while (!feof(tmpfp)) { - /* Read module header */ - if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) || - hdr.magic != RDLMMAG) - error_exit(1, FALSE, "invalid module header"); - /* Read module name */ - i = hdr.hdrsize - sizeof(hdr); - if (i > sizeof(buf) || - fread(buf, 1, i, tmpfp) != i) - error_exit(1, FALSE, "invalid module name"); - /* Check against desired name */ - if (!strcmp(buf, argv[3]) && - (c == 'd' || !options.odate || finfo.st_mtime <= hdr.date)) { - if (options.verbose) - fprintf(stderr, "deleting module %s\n", buf); - fseek(tmpfp, hdr.size, SEEK_CUR); - break; - } else { - put_header(&hdr, libfp, buf); - copybytes(tmpfp, libfp, hdr.size); - } - } - - if (c == 'r') { - /* Copy new module into library */ - p = options.usefname ? argv[4] : argv[3]; - add_module(libfp, argv[4], p); - } - - /* Copy rest of library if any */ - while (!feof(tmpfp)) { - if ((i = fgetc(tmpfp)) == EOF) - break; - - if (fputc(i, libfp) == EOF) - error_exit(1, FALSE, "write error"); - } - - fclose(libfp); - fclose(tmpfp); - break; - - default: - error_exit(2, FALSE, "invalid command '%c'\n", c); - } - - return 0; -} +/* + * rdlar.c - new librarian/archiver for RDOFF2. + * Copyright (c) 2002 RET & COM Research. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rdlar.h" + +#define PROGRAM_VERSION "0.1" + +/** Types **/ +typedef enum { FALSE, TRUE } bool; + +/** Constants **/ +const char commands[] = "adnrtx"; +const char modifiers[] = "cflouvV"; + +/** Global variables **/ +char *progname = "rdlar"; +char **_argv = NULL; +struct { + bool createok; + bool usefname; + bool align; + bool odate; + bool fresh; + int verbose; +} options = { +0, 0, 0, 0, 0, 0}; + +#define _ENDIANNESS 0 /* 0 for little, 1 for big */ + +/* + * Convert long to little endian (if we were compiled on big-endian machine) + */ +static void longtolocal(long *l) +{ +#if _ENDIANNESS + unsigned char t; + unsigned char *p = (unsigned char *)l; + + t = p[0]; + p[0] = p[3]; + p[3] = t; + t = p[1]; + p[1] = p[2]; + p[2] = p[1]; +#endif +} + +/* + * Print version information + */ +void show_version(void) +{ + puts("New RDOFF2 librarian/archiver, version " PROGRAM_VERSION "\n" + "Copyright (c) 2002 RET & COM Research.\n" + "This program is free software and distributed under GPL (version 2 or later);\n" + "see http://www.gnu.org/copyleft/gpl.html for details."); +} + +/* + * Print usage instructions + */ +void usage(void) +{ + printf("Usage: %s [-]{%s}[%s] libfile [module-name] [files]\n", + progname, commands, modifiers); + puts(" commands:\n" + " a - add module(s) to the library\n" + " d - delete module(s) from the library\n" + " n - create the library\n" + " r - replace module(s)\n" + " t - display contents of library\n" + " x - extract module(s)\n" + " command specific modifiers:\n" + " o - preserve original dates\n" + " u - only replace modules that are newer than library contents\n" + " generic modifiers:\n" + " c - do not warn if the library had to be created\n" + " f - use file name as a module name\n" + " v - be verbose\n" + " V - display version information"); +} + +/* + * Print an error message and exit + */ +void error_exit(int errcode, bool useperror, const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", progname); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + putc('\n', stderr); + if (useperror) + perror(progname); + exit(errcode); +} + +/* + * Fill in and write a header + */ +void put_header(struct rdlm_hdr *hdr, FILE * libfp, char *modname) +{ + int n = 0; + + hdr->hdrsize = sizeof(*hdr); + if (modname) + hdr->hdrsize += (n = strlen(modname) + 1); + if (libfp == NULL) + return; + if (fwrite(hdr, 1, sizeof(*hdr), libfp) != sizeof(*hdr) || + (modname && (fwrite(modname, 1, n, libfp) != n))) + error_exit(3, TRUE, "could not write header"); +} + +/* + * Copy n bytes from one file to another and return last character read. + */ +char copybytes(FILE * fp, FILE * fp2, int n) +{ + int i, t = 0; + + for (i = 0; i < n; i++) { + t = fgetc(fp); + if (t == EOF) + error_exit(1, FALSE, "premature end of file in '%s'", + _argv[2]); + if (fp2) + if (fputc(t, fp2) == EOF) + error_exit(1, FALSE, "write error"); + } + return (char)t; +} + +/* + * Copy unsigned long from one file to another. + * Return local presentation of long. + */ +long copylong(FILE * fp, FILE * fp2) +{ + long l; + int i, t; + unsigned char *p = (unsigned char *)&l; + + for (i = 0; i < 4; i++) { + t = fgetc(fp); + if (t == EOF) + error_exit(1, FALSE, "premature end of file in '%s'", + _argv[2]); + if (fp2) + if (fputc(t, fp2) == EOF) + error_exit(1, FALSE, "write error"); + *p++ = t; + } + longtolocal(&l); + return l; +} + +/* + * Create a new library + */ +int create_library(char *libname) +{ + FILE *libfp; + struct rdlm_hdr hdr; + + hdr.magic = RDLAMAG; + hdr.hdrsize = 0; + hdr.date = time(NULL); + hdr.owner = getuid(); + hdr.group = getgid(); + hdr.mode = umask(022); + hdr.size = 0; + + libfp = fopen(libname, "wb"); + if (!libfp) + error_exit(1, TRUE, "could not open '%s'\n", libname); + + /* Write library header */ + put_header(&hdr, libfp, NULL); + + fclose(libfp); + return TRUE; +} + +/* + * Add a module to the library + */ +int add_module(FILE * libfp, const char *fname, char *modname) +{ + FILE *modfp; + struct rdlm_hdr hdr = { RDLMMAG, 0, 0, 0, 0, 0, 0 }; + struct stat finfo; + int i; + + if (options.verbose) + fprintf(stderr, "adding module %s\n", modname); + + /* Initialize some fields in the module header */ + if (stat(fname, &finfo) < 0) + error_exit(1, TRUE, "could not stat '%s'", fname); + hdr.date = finfo.st_mtime; + hdr.owner = finfo.st_uid; + hdr.group = finfo.st_gid; + hdr.size = finfo.st_size; + + modfp = fopen(fname, "rb"); + if (!modfp) + error_exit(1, TRUE, "could not open '%s'", fname); + + /* Write module header */ + put_header(&hdr, libfp, modname); + + /* Put the module itself */ + while (!feof(modfp)) { + i = fgetc(modfp); + if (i == EOF) + break; + if (fputc(i, libfp) == EOF) + error_exit(1, FALSE, "write error"); + } + + fclose(modfp); + return TRUE; +} + +/* + * Main + */ +int main(int argc, char *argv[]) +{ + FILE *libfp, *tmpfp, *modfp = NULL; + struct stat finfo; + struct rdlm_hdr hdr; + char buf[MAXMODNAMELEN], *p = NULL; + char c; + int i; + + progname = argv[0]; + _argv = argv; + + if (argc < 2) { + usage(); + exit(1); + } + + /* Check whether some modifiers were specified */ + for (i = 1; i < strlen(argv[1]); i++) { + switch (c = argv[1][i]) { + case 'c': + options.createok = TRUE; + break; + case 'f': + options.usefname = TRUE; + break; + case 'l': + options.align = TRUE; + break; + case 'o': + options.odate = TRUE; + break; + case 'u': + options.fresh = TRUE; + break; + case 'v': + options.verbose++; + break; + case 'V': + show_version(); + exit(0); + default: + if (strchr(commands, c) == NULL) + error_exit(2, FALSE, "invalid command or modifier '%c'", + c); + } + } + + if (argc < 3) + error_exit(2, FALSE, "missing library name"); + + /* Process the command */ + if (argv[1][0] == '-') + argv[1]++; + switch (c = argv[1][0]) { + case 'a': /* add a module */ + if (argc < 4 || (!options.usefname && argc != 5)) + error_exit(2, FALSE, "invalid number of arguments"); + + /* Check if a library already exists. If not - create it */ + if (access(argv[2], F_OK) < 0) { + if (!options.createok) + fprintf(stderr, "creating library %s\n", argv[2]); + create_library(argv[2]); + } + + libfp = fopen(argv[2], "ab"); + if (!libfp) + error_exit(1, TRUE, "could not open '%s'", argv[2]); + + if (!options.usefname) + add_module(libfp, argv[4], argv[3]); + else + for (i = 3; i < argc; i++) + add_module(libfp, argv[i], argv[i]); + + fclose(libfp); + break; + + case 'n': /* create library */ + create_library(argv[2]); + break; + + case 'x': /* extract module(s) */ + if (!options.usefname) + argc--; + if (argc < 4) + error_exit(2, FALSE, "required parameter missing"); + p = options.usefname ? argv[3] : argv[4]; + case 't': /* list library contents */ + libfp = fopen(argv[2], "rb"); + if (!libfp) + error_exit(1, TRUE, "could not open '%s'\n", argv[2]); + + /* Read library header */ + if (fread(&hdr, 1, sizeof(hdr), libfp) != sizeof(hdr) || + hdr.magic != RDLAMAG) + error_exit(1, FALSE, "invalid library format"); + + /* Walk through the library looking for requested module */ + while (!feof(libfp)) { + /* Read module header */ + i = fread(&hdr, 1, sizeof(hdr), libfp); + if (feof(libfp)) + break; + if (i != sizeof(hdr) || hdr.magic != RDLMMAG) + error_exit(1, FALSE, "invalid module header"); + /* Read module name */ + i = hdr.hdrsize - sizeof(hdr); + if (i > sizeof(buf) || fread(buf, 1, i, libfp) != i) + error_exit(1, FALSE, "invalid module name"); + if (c == 'x') { + /* Check against desired name */ + if (!strcmp(buf, argv[3])) { + if (options.verbose) + fprintf(stderr, + "extracting module %s to file %s\n", buf, + p); + modfp = fopen(p, "wb"); + if (!modfp) + error_exit(1, TRUE, "could not open '%s'", p); + } + } else { + printf("%-40s ", buf); + if (options.verbose) { + printf("%ld bytes", hdr.size); + } + putchar('\n'); + } + + copybytes(libfp, modfp, hdr.size); + if (modfp) + break; + } + + fclose(libfp); + if (modfp) + fclose(modfp); + else if (c == 'x') + error_exit(1, FALSE, "module '%s' not found in '%s'", + argv[3], argv[2]); + break; + + case 'r': /* replace module(s) */ + argc--; + if (stat(argv[4], &finfo) < 0) + error_exit(1, TRUE, "could not stat '%s'", argv[4]); + case 'd': /* delete module(s) */ + if (argc < 4) + error_exit(2, FALSE, "required parameter missing"); + + libfp = fopen(argv[2], "rb"); + if (!libfp) + error_exit(1, TRUE, "could not open '%s'", argv[2]); + + /* Copy the library into a temporary file */ + tmpfp = tmpfile(); + if (!tmpfp) + error_exit(1, TRUE, "could not open temporary file"); + + stat(argv[2], &finfo); + copybytes(libfp, tmpfp, finfo.st_size); + rewind(tmpfp); + freopen(argv[2], "wb", libfp); + + /* Read library header and write it to a new file */ + if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) || + hdr.magic != RDLAMAG) + error_exit(1, FALSE, "invalid library format"); + put_header(&hdr, libfp, NULL); + + /* Walk through the library looking for requested module */ + while (!feof(tmpfp)) { + /* Read module header */ + if (fread(&hdr, 1, sizeof(hdr), tmpfp) != sizeof(hdr) || + hdr.magic != RDLMMAG) + error_exit(1, FALSE, "invalid module header"); + /* Read module name */ + i = hdr.hdrsize - sizeof(hdr); + if (i > sizeof(buf) || fread(buf, 1, i, tmpfp) != i) + error_exit(1, FALSE, "invalid module name"); + /* Check against desired name */ + if (!strcmp(buf, argv[3]) && + (c == 'd' || !options.odate + || finfo.st_mtime <= hdr.date)) { + if (options.verbose) + fprintf(stderr, "deleting module %s\n", buf); + fseek(tmpfp, hdr.size, SEEK_CUR); + break; + } else { + put_header(&hdr, libfp, buf); + copybytes(tmpfp, libfp, hdr.size); + } + } + + if (c == 'r') { + /* Copy new module into library */ + p = options.usefname ? argv[4] : argv[3]; + add_module(libfp, argv[4], p); + } + + /* Copy rest of library if any */ + while (!feof(tmpfp)) { + if ((i = fgetc(tmpfp)) == EOF) + break; + + if (fputc(i, libfp) == EOF) + error_exit(1, FALSE, "write error"); + } + + fclose(libfp); + fclose(tmpfp); + break; + + default: + error_exit(2, FALSE, "invalid command '%c'\n", c); + } + + return 0; +} diff --git a/rdoff/rdlar.h b/rdoff/rdlar.h dissimilarity index 61% index 0a93888c..bf9e84f3 100644 --- a/rdoff/rdlar.h +++ b/rdoff/rdlar.h @@ -1,30 +1,30 @@ -/* - * rdlar.h - definitions of new RDOFF library/archive format. - */ - -#ifndef _RDLAR_H -#define _RDLAR_H - -#ifndef _POSIX_SOURCE -/* For some MS-DOS C compilers */ -#define getuid() 0 -#define getgid() 0 -#endif - -#define RDLAMAG 0x414C4452 /* Archive magic */ -#define RDLMMAG 0x4D4C4452 /* Member magic */ - -#define MAXMODNAMELEN 256 /* Maximum length of module name */ - -struct rdlm_hdr { - unsigned long magic; /* Must be RDLAMAG */ - unsigned long hdrsize; /* Header size + sizeof(module_name) */ - unsigned long date; /* Creation date */ - unsigned long owner; /* UID */ - unsigned long group; /* GID */ - unsigned long mode; /* File mode */ - unsigned long size; /* File size */ - /* NULL-terminated module name immediately follows */ -}; - -#endif +/* + * rdlar.h - definitions of new RDOFF library/archive format. + */ + +#ifndef _RDLAR_H +#define _RDLAR_H + +#ifndef _POSIX_SOURCE +/* For some MS-DOS C compilers */ +#define getuid() 0 +#define getgid() 0 +#endif + +#define RDLAMAG 0x414C4452 /* Archive magic */ +#define RDLMMAG 0x4D4C4452 /* Member magic */ + +#define MAXMODNAMELEN 256 /* Maximum length of module name */ + +struct rdlm_hdr { + unsigned long magic; /* Must be RDLAMAG */ + unsigned long hdrsize; /* Header size + sizeof(module_name) */ + unsigned long date; /* Creation date */ + unsigned long owner; /* UID */ + unsigned long group; /* GID */ + unsigned long mode; /* File mode */ + unsigned long size; /* File size */ + /* NULL-terminated module name immediately follows */ +}; + +#endif diff --git a/rdoff/rdlib.c b/rdoff/rdlib.c dissimilarity index 79% index 97f682f3..28a2bdf3 100644 --- a/rdoff/rdlib.c +++ b/rdoff/rdlib.c @@ -1,268 +1,261 @@ -/* - * rdlib.c - routines for manipulating RDOFF libraries (.rdl) - */ - -#include -#include -#include - -#define RDOFF_UTILS - -#include "rdoff.h" -#include "rdlib.h" -#include "rdlar.h" - -/* See Texinfo documentation about new RDOFF libraries format */ - -int rdl_error = 0; - -char *rdl_errors[5] = { - "no error","could not open file", "invalid file structure", - "file contains modules of an unsupported RDOFF version", - "module not found" -}; - -int rdl_verify(const char * filename) -{ - FILE * fp = fopen(filename, "rb"); - char buf[257]; - int i; - long length; - static char lastverified[256]; - static int lastresult = -1; - - if (lastresult != -1 && !strcmp(filename, lastverified)) - return lastresult; - - strcpy(lastverified, filename); - - if (!fp) - return (rdl_error = lastresult = 1); - - while (!feof(fp)) - { - i = 0; - - while (fread(buf + i,1,1,fp) == 1 && buf[i] && i < 257) - i++; - if (feof(fp)) break; - - if (buf[0] == '.') { - /* - * A special module, eg a signature block or a directory. - * Format of such a module is defined to be: - * six char type identifier - * long count bytes content - * content - * so we can handle it uniformaly with RDOFF2 modules. - */ - fread(buf, 6, 1, fp); - buf[6] = 0; - /* Currently, nothing useful to do with signature block.. */ - } else { - fread(buf, 6, 1, fp); - buf[6] = 0; - if (strncmp(buf, "RDOFF", 5)) { - return rdl_error = lastresult = 2; - } else if (buf[5] != '2') { - return rdl_error = lastresult = 3; - } - } - fread(&length, 4, 1, fp); - fseek(fp, length, SEEK_CUR); /* skip over the module */ - } - fclose(fp); - return lastresult = 0; /* library in correct format */ -} - -int rdl_open (struct librarynode * lib, const char * name) -{ - int i = rdl_verify(name); - if (i) return i; - - lib->fp = NULL; - lib->name = strdup(name); - lib->referenced = 0; - lib->next = NULL; - return 0; -} - -void rdl_close (struct librarynode * lib) -{ - if (lib->fp) - fclose(lib->fp); - free(lib->name); -} - -int rdl_searchlib (struct librarynode * lib, - const char * label, rdffile * f) -{ - char buf[512]; - int i, t; - void * hdr; - rdfheaderrec * r; - long l; - - rdl_error = 0; - lib->referenced ++; - - if (! lib->fp) - { - lib->fp = fopen(lib->name,"rb"); - - if (! lib->fp) { - rdl_error = 1; - return 0; - } - } - else - rewind(lib->fp); - - while (! feof(lib->fp) ) - { - /* - * read the module name from the file, and prepend - * the library name and '.' to it. - */ - strcpy(buf, lib->name); - - i = strlen(lib->name); - buf[i++] = '.'; t = i; - while (fread(buf + i,1,1,lib->fp) == 1 && buf[i] && i < 512) - i++; - - buf[i] = 0; - - if (feof(lib->fp)) break; - if (!strcmp(buf + t, ".dir")) /* skip over directory */ - { - fread (&l, 4, 1, lib->fp); - fseek (lib->fp, l, SEEK_CUR); - continue; - } - /* - * open the RDOFF module - */ - if ( rdfopenhere(f,lib->fp,&lib->referenced,buf) ) { - rdl_error = 16 * rdf_errno; - return 0; - } - /* - * read in the header, and scan for exported symbols - */ - hdr = malloc(f->header_len); - rdfloadseg(f,RDOFF_HEADER,hdr); - - while ((r = rdfgetheaderrec(f))) - { - if (r->type != 3) /* not an export */ - continue; - - if (! strcmp(r->e.label, label) ) /* match! */ - { - free(hdr); /* reset to 'just open' */ - f->header_loc = NULL; /* state... */ - f->header_fp = 0; - return 1; - } - } - - /* find start of next module... */ - i = f->eof_offset; - rdfclose(f); - fseek(lib->fp,i,SEEK_SET); - } - - /* - * close the file if nobody else is using it - */ - lib->referenced --; - if (! lib->referenced) - { - fclose(lib->fp); - lib->fp = NULL; - } - return 0; -} - -int rdl_openmodule (struct librarynode * lib, int moduleno, rdffile * f) -{ - char buf[512]; - int i, cmod, t; - long length; - - lib->referenced++; - - if (!lib->fp) - { - lib->fp = fopen(lib->name, "rb"); - if (!lib->fp) { - lib->referenced--; - return (rdl_error = 1); - } - } - else - rewind(lib->fp); - - cmod = -1; - while (!feof(lib->fp)) - { - strcpy(buf, lib->name); - i = strlen(buf); - buf[i++] = '.'; t = i; - while (fread(buf + i,1,1,lib->fp) == 1 && buf[i] && i < 512) - i++; - buf[i] = 0; - if (feof(lib->fp)) break; - - if (buf[t] != '.') /* special module - not counted in the numbering */ - cmod++; /* of RDOFF modules - must be referred to by name */ - - if (cmod == moduleno) { - rdl_error = 16 * - rdfopenhere(f, lib->fp, &lib->referenced, buf); - lib->referenced--; - if (!lib->referenced) { - fclose(lib->fp); - lib->fp = NULL; - } - return rdl_error; - } - - fread(buf, 6, 1, lib->fp); - buf[6] = 0; - if (buf[t] == '.') { - /* do nothing */ - } - else if (strncmp(buf, "RDOFF", 5)) { - if (! --lib->referenced) { - fclose(lib->fp); - lib->fp = NULL; - } - return rdl_error = 2; - } - else if (buf[5] != '2') { - if (! --lib->referenced) { - fclose(lib->fp); - lib->fp = NULL; - } - return rdl_error = 3; - } - - fread(&length, 4, 1, lib->fp); - fseek(lib->fp, length, SEEK_CUR); /* skip over the module */ - } - if (! --lib->referenced) { - fclose(lib->fp); - lib->fp = NULL; - } - return rdl_error = 4; /* module not found */ -} - -void rdl_perror(const char *apname, const char *filename) -{ - if (rdl_error >= 16) - rdfperror(apname, filename); - else - fprintf(stderr,"%s:%s:%s\n",apname,filename,rdl_errors[rdl_error]); -} +/* + * rdlib.c - routines for manipulating RDOFF libraries (.rdl) + */ + +#include +#include +#include + +#define RDOFF_UTILS + +#include "rdoff.h" +#include "rdlib.h" +#include "rdlar.h" + +/* See Texinfo documentation about new RDOFF libraries format */ + +int rdl_error = 0; + +char *rdl_errors[5] = { + "no error", "could not open file", "invalid file structure", + "file contains modules of an unsupported RDOFF version", + "module not found" +}; + +int rdl_verify(const char *filename) +{ + FILE *fp = fopen(filename, "rb"); + char buf[257]; + int i; + long length; + static char lastverified[256]; + static int lastresult = -1; + + if (lastresult != -1 && !strcmp(filename, lastverified)) + return lastresult; + + strcpy(lastverified, filename); + + if (!fp) + return (rdl_error = lastresult = 1); + + while (!feof(fp)) { + i = 0; + + while (fread(buf + i, 1, 1, fp) == 1 && buf[i] && i < 257) + i++; + if (feof(fp)) + break; + + if (buf[0] == '.') { + /* + * A special module, eg a signature block or a directory. + * Format of such a module is defined to be: + * six char type identifier + * long count bytes content + * content + * so we can handle it uniformaly with RDOFF2 modules. + */ + fread(buf, 6, 1, fp); + buf[6] = 0; + /* Currently, nothing useful to do with signature block.. */ + } else { + fread(buf, 6, 1, fp); + buf[6] = 0; + if (strncmp(buf, "RDOFF", 5)) { + return rdl_error = lastresult = 2; + } else if (buf[5] != '2') { + return rdl_error = lastresult = 3; + } + } + fread(&length, 4, 1, fp); + fseek(fp, length, SEEK_CUR); /* skip over the module */ + } + fclose(fp); + return lastresult = 0; /* library in correct format */ +} + +int rdl_open(struct librarynode *lib, const char *name) +{ + int i = rdl_verify(name); + if (i) + return i; + + lib->fp = NULL; + lib->name = strdup(name); + lib->referenced = 0; + lib->next = NULL; + return 0; +} + +void rdl_close(struct librarynode *lib) +{ + if (lib->fp) + fclose(lib->fp); + free(lib->name); +} + +int rdl_searchlib(struct librarynode *lib, const char *label, rdffile * f) +{ + char buf[512]; + int i, t; + void *hdr; + rdfheaderrec *r; + long l; + + rdl_error = 0; + lib->referenced++; + + if (!lib->fp) { + lib->fp = fopen(lib->name, "rb"); + + if (!lib->fp) { + rdl_error = 1; + return 0; + } + } else + rewind(lib->fp); + + while (!feof(lib->fp)) { + /* + * read the module name from the file, and prepend + * the library name and '.' to it. + */ + strcpy(buf, lib->name); + + i = strlen(lib->name); + buf[i++] = '.'; + t = i; + while (fread(buf + i, 1, 1, lib->fp) == 1 && buf[i] && i < 512) + i++; + + buf[i] = 0; + + if (feof(lib->fp)) + break; + if (!strcmp(buf + t, ".dir")) { /* skip over directory */ + fread(&l, 4, 1, lib->fp); + fseek(lib->fp, l, SEEK_CUR); + continue; + } + /* + * open the RDOFF module + */ + if (rdfopenhere(f, lib->fp, &lib->referenced, buf)) { + rdl_error = 16 * rdf_errno; + return 0; + } + /* + * read in the header, and scan for exported symbols + */ + hdr = malloc(f->header_len); + rdfloadseg(f, RDOFF_HEADER, hdr); + + while ((r = rdfgetheaderrec(f))) { + if (r->type != 3) /* not an export */ + continue; + + if (!strcmp(r->e.label, label)) { /* match! */ + free(hdr); /* reset to 'just open' */ + f->header_loc = NULL; /* state... */ + f->header_fp = 0; + return 1; + } + } + + /* find start of next module... */ + i = f->eof_offset; + rdfclose(f); + fseek(lib->fp, i, SEEK_SET); + } + + /* + * close the file if nobody else is using it + */ + lib->referenced--; + if (!lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return 0; +} + +int rdl_openmodule(struct librarynode *lib, int moduleno, rdffile * f) +{ + char buf[512]; + int i, cmod, t; + long length; + + lib->referenced++; + + if (!lib->fp) { + lib->fp = fopen(lib->name, "rb"); + if (!lib->fp) { + lib->referenced--; + return (rdl_error = 1); + } + } else + rewind(lib->fp); + + cmod = -1; + while (!feof(lib->fp)) { + strcpy(buf, lib->name); + i = strlen(buf); + buf[i++] = '.'; + t = i; + while (fread(buf + i, 1, 1, lib->fp) == 1 && buf[i] && i < 512) + i++; + buf[i] = 0; + if (feof(lib->fp)) + break; + + if (buf[t] != '.') /* special module - not counted in the numbering */ + cmod++; /* of RDOFF modules - must be referred to by name */ + + if (cmod == moduleno) { + rdl_error = 16 * + rdfopenhere(f, lib->fp, &lib->referenced, buf); + lib->referenced--; + if (!lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return rdl_error; + } + + fread(buf, 6, 1, lib->fp); + buf[6] = 0; + if (buf[t] == '.') { + /* do nothing */ + } else if (strncmp(buf, "RDOFF", 5)) { + if (!--lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return rdl_error = 2; + } else if (buf[5] != '2') { + if (!--lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return rdl_error = 3; + } + + fread(&length, 4, 1, lib->fp); + fseek(lib->fp, length, SEEK_CUR); /* skip over the module */ + } + if (!--lib->referenced) { + fclose(lib->fp); + lib->fp = NULL; + } + return rdl_error = 4; /* module not found */ +} + +void rdl_perror(const char *apname, const char *filename) +{ + if (rdl_error >= 16) + rdfperror(apname, filename); + else + fprintf(stderr, "%s:%s:%s\n", apname, filename, + rdl_errors[rdl_error]); +} diff --git a/rdoff/rdlib.h b/rdoff/rdlib.h dissimilarity index 61% index 62550248..36438bdf 100644 --- a/rdoff/rdlib.h +++ b/rdoff/rdlib.h @@ -1,27 +1,24 @@ -/* - * rdlib.h Functions for manipulating libraries of RDOFF object files. - */ - - -struct librarynode { - char * name; - FILE * fp; /* initialised to NULL - always check*/ - int referenced; /* & open if required. Close afterwards */ - struct librarynode * next; /* if ! referenced. */ -}; - - -extern int rdl_error; - -#define RDL_EOPEN 1 -#define RDL_EINVALID 2 -#define RDL_EVERSION 3 -#define RDL_ENOTFOUND 4 - -int rdl_verify (const char * filename); -int rdl_open (struct librarynode * lib, const char * filename); -int rdl_searchlib (struct librarynode * lib, - const char * label, rdffile * f); -int rdl_openmodule (struct librarynode * lib, int module, rdffile * f); - -void rdl_perror(const char *apname, const char *filename); +/* + * rdlib.h Functions for manipulating libraries of RDOFF object files. + */ + +struct librarynode { + char *name; + FILE *fp; /* initialised to NULL - always check */ + int referenced; /* & open if required. Close afterwards */ + struct librarynode *next; /* if ! referenced. */ +}; + +extern int rdl_error; + +#define RDL_EOPEN 1 +#define RDL_EINVALID 2 +#define RDL_EVERSION 3 +#define RDL_ENOTFOUND 4 + +int rdl_verify(const char *filename); +int rdl_open(struct librarynode *lib, const char *filename); +int rdl_searchlib(struct librarynode *lib, const char *label, rdffile * f); +int rdl_openmodule(struct librarynode *lib, int module, rdffile * f); + +void rdl_perror(const char *apname, const char *filename); diff --git a/rdoff/rdoff.c b/rdoff/rdoff.c index bfdb9cc1..8f19702d 100644 --- a/rdoff/rdoff.c +++ b/rdoff/rdoff.c @@ -41,87 +41,89 @@ * how long it is). * ======================================================================== */ - -memorybuffer * newmembuf() +memorybuffer *newmembuf() { - memorybuffer * t; + memorybuffer *t; t = malloc(sizeof(memorybuffer)); - if (!t) return NULL; + if (!t) + return NULL; t->length = 0; t->next = NULL; return t; } -void membufwrite(memorybuffer *const b, void *data, int bytes) +void membufwrite(memorybuffer * const b, void *data, int bytes) { uint16 w; long l; - if (b->next) { /* memory buffer full - use next buffer */ - membufwrite(b->next,data,bytes); - return; + if (b->next) { /* memory buffer full - use next buffer */ + membufwrite(b->next, data, bytes); + return; } if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN) - || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) - { - - /* buffer full and no next allocated... allocate and initialise next - * buffer */ - b->next = newmembuf(); - membufwrite(b->next,data,bytes); - return; + || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN)) { + + /* buffer full and no next allocated... allocate and initialise next + * buffer */ + b->next = newmembuf(); + membufwrite(b->next, data, bytes); + return; } - switch(bytes) { - case -4: /* convert to little-endian */ - l = * (long *) data ; - b->buffer[b->length++] = l & 0xFF; - l >>= 8 ; - b->buffer[b->length++] = l & 0xFF; - l >>= 8 ; - b->buffer[b->length++] = l & 0xFF; - l >>= 8 ; - b->buffer[b->length++] = l & 0xFF; - break; + switch (bytes) { + case -4: /* convert to little-endian */ + l = *(long *)data; + b->buffer[b->length++] = l & 0xFF; + l >>= 8; + b->buffer[b->length++] = l & 0xFF; + l >>= 8; + b->buffer[b->length++] = l & 0xFF; + l >>= 8; + b->buffer[b->length++] = l & 0xFF; + break; case -2: - w = * (uint16 *) data ; - b->buffer[b->length++] = w & 0xFF; - w >>= 8 ; - b->buffer[b->length++] = w & 0xFF; - break; + w = *(uint16 *) data; + b->buffer[b->length++] = w & 0xFF; + w >>= 8; + b->buffer[b->length++] = w & 0xFF; + break; default: - while(bytes--) { - b->buffer[b->length++] = *(* (unsigned char **) &data); - - (* (unsigned char **) &data)++ ; - } - break; + while (bytes--) { + b->buffer[b->length++] = *(*(unsigned char **)&data); + + (*(unsigned char **)&data)++; + } + break; } } -void membufdump(memorybuffer *b,FILE *fp) +void membufdump(memorybuffer * b, FILE * fp) { - if (!b) return; + if (!b) + return; + + fwrite(b->buffer, 1, b->length, fp); - fwrite (b->buffer, 1, b->length, fp); - - membufdump(b->next,fp); + membufdump(b->next, fp); } -int membuflength(memorybuffer *b) +int membuflength(memorybuffer * b) { - if (!b) return 0; + if (!b) + return 0; return b->length + membuflength(b->next); } -void freemembuf(memorybuffer *b) +void freemembuf(memorybuffer * b) { - if (!b) return; + if (!b) + return; freemembuf(b->next); free(b); } @@ -135,7 +137,7 @@ void freemembuf(memorybuffer *b) * * translate from little endian to local representation */ -long translatelong(long in) +long translatelong(long in) { long r; unsigned char *i; @@ -149,11 +151,11 @@ long translatelong(long in) return r; } -uint16 translateshort(uint16 in) +uint16 translateshort(uint16 in) { uint16 r; - unsigned char * i; - + unsigned char *i; + i = (unsigned char *)∈ r = (i[1] << 8) + i[0]; @@ -171,17 +173,17 @@ static char *knownsegtypes[8] = { char *translatesegmenttype(uint16 type) { if (type < 8) - return knownsegtypes[type]; + return knownsegtypes[type]; if (type < 0x0020) - return "reserved"; + return "reserved"; if (type < 0x1000) - return "reserved - Moscow"; + return "reserved - Moscow"; if (type < 0x8000) - return "reserved - system dependant"; + return "reserved - system dependant"; if (type < 0xFFFF) - return "reserved - other"; + return "reserved - other"; if (type == 0xFFFF) - return "invalid type code"; + return "invalid type code"; return "type code out of range"; } @@ -190,17 +192,17 @@ const char *RDOFFId = RDOFF2_SIGNATURE; /* Error messages. Must correspond to the codes defined in rdoff.h */ const char *rdf_errors[11] = { - /* 0 */ "no error occurred", - /* 1 */ "could not open file", - /* 2 */ "invalid file format", - /* 3 */ "error reading file", - /* 4 */ "unknown error", - /* 5 */ "header not read", - /* 6 */ "out of memory", - /* 7 */ "RDOFF v1 not supported", - /* 8 */ "unknown extended header record", - /* 9 */ "header record of known type but unknown length", - /* 10 */ "no such segment" + /* 0 */ "no error occurred", + /* 1 */ "could not open file", + /* 2 */ "invalid file format", + /* 3 */ "error reading file", + /* 4 */ "unknown error", + /* 5 */ "header not read", + /* 6 */ "out of memory", + /* 7 */ "RDOFF v1 not supported", + /* 8 */ "unknown extended header record", + /* 9 */ "header record of known type but unknown length", + /* 10 */ "no such segment" }; int rdf_errno = 0; @@ -209,18 +211,18 @@ int rdf_errno = 0; The library functions ======================================================================== */ -int rdfopen(rdffile *f, const char *name) +int rdfopen(rdffile * f, const char *name) { - FILE * fp; + FILE *fp; - fp = fopen(name,"rb"); + fp = fopen(name, "rb"); if (!fp) - return rdf_errno = RDF_ERR_OPEN; + return rdf_errno = RDF_ERR_OPEN; - return rdfopenhere(f,fp,NULL,name); + return rdfopenhere(f, fp, NULL, name); } -int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name) +int rdfopenhere(rdffile * f, FILE * fp, int *refcount, const char *name) { char buf[8]; long initpos; @@ -229,84 +231,87 @@ int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name) if (translatelong(0x01020304) != 0x01020304) { /* fix this to be portable! */ - fputs("*** this program requires a little endian machine\n",stderr); - fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304)); + fputs("*** this program requires a little endian machine\n", + stderr); + fprintf(stderr, "01020304h = %08lxh\n", translatelong(0x01020304)); exit(3); } f->fp = fp; initpos = ftell(fp); - fread(buf,6,1,f->fp); /* read header */ + fread(buf, 6, 1, f->fp); /* read header */ buf[6] = 0; - if (strcmp(buf,RDOFFId)) { - fclose(f->fp); - if (!strcmp(buf,"RDOFF1")) - return rdf_errno = RDF_ERR_VER; - return rdf_errno = RDF_ERR_FORMAT; + if (strcmp(buf, RDOFFId)) { + fclose(f->fp); + if (!strcmp(buf, "RDOFF1")) + return rdf_errno = RDF_ERR_VER; + return rdf_errno = RDF_ERR_FORMAT; } - if (fread(&l,1,4,f->fp) != 4 || fread(&f->header_len,1,4,f->fp) != 4) { - fclose(f->fp); - return rdf_errno = RDF_ERR_READ; + if (fread(&l, 1, 4, f->fp) != 4 + || fread(&f->header_len, 1, 4, f->fp) != 4) { + fclose(f->fp); + return rdf_errno = RDF_ERR_READ; } f->header_ofs = ftell(f->fp); f->eof_offset = f->header_ofs + translatelong(l) - 4; - if (fseek(f->fp,f->header_len,SEEK_CUR)) { - fclose(f->fp); - return rdf_errno = RDF_ERR_FORMAT; /* seek past end of file...? */ + if (fseek(f->fp, f->header_len, SEEK_CUR)) { + fclose(f->fp); + return rdf_errno = RDF_ERR_FORMAT; /* seek past end of file...? */ } - if (fread(&s,1,2,f->fp) != 2) { - fclose(f->fp); - return rdf_errno = RDF_ERR_READ; + if (fread(&s, 1, 2, f->fp) != 2) { + fclose(f->fp); + return rdf_errno = RDF_ERR_READ; } f->nsegs = 0; while (s != 0) { - f->seg[f->nsegs].type = s; - if (fread(&f->seg[f->nsegs].number,1,2,f->fp) != 2 || - fread(&f->seg[f->nsegs].reserved,1,2,f->fp) != 2 || - fread(&f->seg[f->nsegs].length,1,4,f->fp) != 4) { - fclose(f->fp); - return rdf_errno = RDF_ERR_READ; - } - - f->seg[f->nsegs].offset = ftell(f->fp); - if (fseek(f->fp,f->seg[f->nsegs].length,SEEK_CUR)) { - fclose(f->fp); - return rdf_errno = RDF_ERR_FORMAT; - } - f->nsegs++; - - if (fread(&s,1,2,f->fp) != 2) { - fclose(f->fp); - return rdf_errno = RDF_ERR_READ; - } + f->seg[f->nsegs].type = s; + if (fread(&f->seg[f->nsegs].number, 1, 2, f->fp) != 2 || + fread(&f->seg[f->nsegs].reserved, 1, 2, f->fp) != 2 || + fread(&f->seg[f->nsegs].length, 1, 4, f->fp) != 4) { + fclose(f->fp); + return rdf_errno = RDF_ERR_READ; + } + + f->seg[f->nsegs].offset = ftell(f->fp); + if (fseek(f->fp, f->seg[f->nsegs].length, SEEK_CUR)) { + fclose(f->fp); + return rdf_errno = RDF_ERR_FORMAT; + } + f->nsegs++; + + if (fread(&s, 1, 2, f->fp) != 2) { + fclose(f->fp); + return rdf_errno = RDF_ERR_READ; + } } - if (f->eof_offset != ftell(f->fp) + 8) { /* +8 = skip null segment header */ - fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset " - "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8); + if (f->eof_offset != ftell(f->fp) + 8) { /* +8 = skip null segment header */ + fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset " + "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8); } - fseek(f->fp,initpos,SEEK_SET); + fseek(f->fp, initpos, SEEK_SET); f->header_loc = NULL; f->name = newstr(name); f->refcount = refcount; - if (refcount) (*refcount)++; + if (refcount) + (*refcount)++; return RDF_OK; } -int rdfclose(rdffile *f) +int rdfclose(rdffile * f) { - if (! f->refcount || ! --(*f->refcount)) { - fclose(f->fp); - f->fp = NULL; + if (!f->refcount || !--(*f->refcount)) { + fclose(f->fp); + f->fp = NULL; } free(f->name); @@ -318,9 +323,9 @@ int rdfclose(rdffile *f) */ void rdfperror(const char *app, const char *name) { - fprintf(stderr,"%s:%s: %s\n",app,name,rdf_errors[rdf_errno]); + fprintf(stderr, "%s:%s: %s\n", app, name, rdf_errors[rdf_errno]); if (rdf_errno == RDF_ERR_OPEN || rdf_errno == RDF_ERR_READ) { - perror(app); + perror(app); } } @@ -332,39 +337,40 @@ int rdffindsegment(rdffile * f, int segno) { int i; for (i = 0; i < f->nsegs; i++) - if (f->seg[i].number == segno) return i; + if (f->seg[i].number == segno) + return i; return -1; } /* * Load the segment. Returns status. */ -int rdfloadseg(rdffile *f,int segment,void *buffer) +int rdfloadseg(rdffile * f, int segment, void *buffer) { long fpos, slen; - switch(segment) { - case RDOFF_HEADER: - fpos = f->header_ofs; - slen = f->header_len; - f->header_loc = (byte *)buffer; - f->header_fp = 0; - break; - default: - if (segment < f->nsegs) { - fpos = f->seg[segment].offset; - slen = f->seg[segment].length; - f->seg[segment].data = (byte *)buffer; - } else { - return rdf_errno = RDF_ERR_SEGMENT; - } + switch (segment) { + case RDOFF_HEADER: + fpos = f->header_ofs; + slen = f->header_len; + f->header_loc = (byte *) buffer; + f->header_fp = 0; + break; + default: + if (segment < f->nsegs) { + fpos = f->seg[segment].offset; + slen = f->seg[segment].length; + f->seg[segment].data = (byte *) buffer; + } else { + return rdf_errno = RDF_ERR_SEGMENT; + } } - if (fseek(f->fp,fpos,SEEK_SET)) - return rdf_errno = RDF_ERR_UNKNOWN; - - if (fread(buffer,1,slen,f->fp) != slen) - return rdf_errno = RDF_ERR_READ; + if (fseek(f->fp, fpos, SEEK_SET)) + return rdf_errno = RDF_ERR_UNKNOWN; + + if (fread(buffer, 1, slen, f->fp) != slen) + return rdf_errno = RDF_ERR_READ; return RDF_OK; } @@ -389,78 +395,79 @@ int rdfloadseg(rdffile *f,int segment,void *buffer) * Read a header record. * Returns the address of record, or NULL in case of error. */ -rdfheaderrec *rdfgetheaderrec(rdffile *f) +rdfheaderrec *rdfgetheaderrec(rdffile * f) { static rdfheaderrec r; int i; if (!f->header_loc) { - rdf_errno = RDF_ERR_HEADER; - return NULL; + rdf_errno = RDF_ERR_HEADER; + return NULL; } - if (f->header_fp >= f->header_len) return 0; + if (f->header_fp >= f->header_len) + return 0; RI8(r.type); RI8(r.g.reclen); - switch(r.type) { - case RDFREC_RELOC: /* Relocation record */ - case RDFREC_SEGRELOC: - if (r.r.reclen != 8) { - rdf_errno = RDF_ERR_RECLEN; - return NULL; - } - RI8(r.r.segment); - RI32(r.r.offset); - RI8(r.r.length); - RI16(r.r.refseg); - break; - - case RDFREC_IMPORT: /* Imported symbol record */ - case RDFREC_FARIMPORT: - RI8(r.i.flags); - RI16(r.i.segment); - RS(r.i.label, EXIM_LABEL_MAX); - break; - - case RDFREC_GLOBAL: /* Exported symbol record */ - RI8(r.e.flags); - RI8(r.e.segment); - RI32(r.e.offset); - RS(r.e.label, EXIM_LABEL_MAX); - break; - - case RDFREC_DLL: /* DLL record */ - RS(r.d.libname, MODLIB_NAME_MAX); - break; - - case RDFREC_BSS: /* BSS reservation record */ - if (r.r.reclen != 4) { - rdf_errno = RDF_ERR_RECLEN; - return NULL; - } - RI32(r.b.amount); - break; - - case RDFREC_MODNAME: /* Module name record */ - RS(r.m.modname, MODLIB_NAME_MAX); - break; - - case RDFREC_COMMON: /* Common variable */ - RI16(r.c.segment); - RI32(r.c.size); - RI16(r.c.align); - RS(r.c.label, EXIM_LABEL_MAX); - break; - - default: + switch (r.type) { + case RDFREC_RELOC: /* Relocation record */ + case RDFREC_SEGRELOC: + if (r.r.reclen != 8) { + rdf_errno = RDF_ERR_RECLEN; + return NULL; + } + RI8(r.r.segment); + RI32(r.r.offset); + RI8(r.r.length); + RI16(r.r.refseg); + break; + + case RDFREC_IMPORT: /* Imported symbol record */ + case RDFREC_FARIMPORT: + RI8(r.i.flags); + RI16(r.i.segment); + RS(r.i.label, EXIM_LABEL_MAX); + break; + + case RDFREC_GLOBAL: /* Exported symbol record */ + RI8(r.e.flags); + RI8(r.e.segment); + RI32(r.e.offset); + RS(r.e.label, EXIM_LABEL_MAX); + break; + + case RDFREC_DLL: /* DLL record */ + RS(r.d.libname, MODLIB_NAME_MAX); + break; + + case RDFREC_BSS: /* BSS reservation record */ + if (r.r.reclen != 4) { + rdf_errno = RDF_ERR_RECLEN; + return NULL; + } + RI32(r.b.amount); + break; + + case RDFREC_MODNAME: /* Module name record */ + RS(r.m.modname, MODLIB_NAME_MAX); + break; + + case RDFREC_COMMON: /* Common variable */ + RI16(r.c.segment); + RI32(r.c.size); + RI16(r.c.align); + RS(r.c.label, EXIM_LABEL_MAX); + break; + + default: #ifdef STRICT_ERRORS - rdf_errno = RDF_ERR_RECTYPE; /* unknown header record */ - return NULL; + rdf_errno = RDF_ERR_RECTYPE; /* unknown header record */ + return NULL; #else - for (i = 0; i < r.g.reclen; i++) - RI8(r.g.data[i]); + for (i = 0; i < r.g.reclen; i++) + RI8(r.g.data[i]); #endif } return &r; @@ -468,17 +475,17 @@ rdfheaderrec *rdfgetheaderrec(rdffile *f) /* * Rewind to the beginning of the file - */ -void rdfheaderrewind(rdffile *f) + */ +void rdfheaderrewind(rdffile * f) { f->header_fp = 0; } - -rdf_headerbuf * rdfnewheader(void) +rdf_headerbuf *rdfnewheader(void) { - rdf_headerbuf * hb = malloc(sizeof(rdf_headerbuf)); - if (hb == NULL) return NULL; + rdf_headerbuf *hb = malloc(sizeof(rdf_headerbuf)); + if (hb == NULL) + return NULL; hb->buf = newmembuf(); hb->nsegments = 0; @@ -492,81 +499,81 @@ int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r) #ifndef STRICT_ERRORS int i; #endif - membufwrite(h->buf,&r->type,1); - membufwrite(h->buf,&r->g.reclen,1); + membufwrite(h->buf, &r->type, 1); + membufwrite(h->buf, &r->g.reclen, 1); switch (r->type) { - case RDFREC_GENERIC: /* generic */ - membufwrite(h->buf, &r->g.data, r->g.reclen); - break; + case RDFREC_GENERIC: /* generic */ + membufwrite(h->buf, &r->g.data, r->g.reclen); + break; case RDFREC_RELOC: case RDFREC_SEGRELOC: - membufwrite(h->buf,&r->r.segment,1); - membufwrite(h->buf,&r->r.offset,-4); - membufwrite(h->buf,&r->r.length,1); - membufwrite(h->buf,&r->r.refseg,-2); /* 9 bytes written */ - break; + membufwrite(h->buf, &r->r.segment, 1); + membufwrite(h->buf, &r->r.offset, -4); + membufwrite(h->buf, &r->r.length, 1); + membufwrite(h->buf, &r->r.refseg, -2); /* 9 bytes written */ + break; - case RDFREC_IMPORT: /* import */ + case RDFREC_IMPORT: /* import */ case RDFREC_FARIMPORT: - membufwrite(h->buf,&r->i.flags,1); - membufwrite(h->buf,&r->i.segment,-2); - membufwrite(h->buf,&r->i.label,strlen(r->i.label) + 1); - break ; - - case RDFREC_GLOBAL: /* export */ - membufwrite(h->buf,&r->e.flags,1); - membufwrite(h->buf,&r->e.segment,1); - membufwrite(h->buf,&r->e.offset,-4); - membufwrite(h->buf,&r->e.label,strlen(r->e.label) + 1); - break ; - - case RDFREC_DLL: /* DLL */ - membufwrite(h->buf,&r->d.libname,strlen(r->d.libname) + 1); - break ; - - case RDFREC_BSS: /* BSS */ - membufwrite(h->buf,&r->b.amount,-4); - break ; - - case RDFREC_MODNAME: /* Module name */ - membufwrite(h->buf,&r->m.modname,strlen(r->m.modname) + 1); - break ; - + membufwrite(h->buf, &r->i.flags, 1); + membufwrite(h->buf, &r->i.segment, -2); + membufwrite(h->buf, &r->i.label, strlen(r->i.label) + 1); + break; + + case RDFREC_GLOBAL: /* export */ + membufwrite(h->buf, &r->e.flags, 1); + membufwrite(h->buf, &r->e.segment, 1); + membufwrite(h->buf, &r->e.offset, -4); + membufwrite(h->buf, &r->e.label, strlen(r->e.label) + 1); + break; + + case RDFREC_DLL: /* DLL */ + membufwrite(h->buf, &r->d.libname, strlen(r->d.libname) + 1); + break; + + case RDFREC_BSS: /* BSS */ + membufwrite(h->buf, &r->b.amount, -4); + break; + + case RDFREC_MODNAME: /* Module name */ + membufwrite(h->buf, &r->m.modname, strlen(r->m.modname) + 1); + break; + default: #ifdef STRICT_ERRORS - return rdf_errno = RDF_ERR_RECTYPE; + return rdf_errno = RDF_ERR_RECTYPE; #else - for (i = 0; i < r->g.reclen; i++) - membufwrite(h->buf, r->g.data[i], 1); + for (i = 0; i < r->g.reclen; i++) + membufwrite(h->buf, r->g.data[i], 1); #endif } return 0; } -int rdfaddsegment(rdf_headerbuf *h, long seglength) +int rdfaddsegment(rdf_headerbuf * h, long seglength) { - h->nsegments ++; + h->nsegments++; h->seglength += seglength; return 0; } int rdfwriteheader(FILE * fp, rdf_headerbuf * h) { - long l, l2; + long l, l2; - fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ; + fwrite(RDOFFId, 1, strlen(RDOFFId), fp); - l = membuflength (h->buf); - l2 = l + 14 + 10*h->nsegments + h->seglength; + l = membuflength(h->buf); + l2 = l + 14 + 10 * h->nsegments + h->seglength; l = translatelong(l); l2 = translatelong(l2); - fwrite (&l2, 4, 1, fp); /* object length */ - fwrite (&l, 4, 1, fp); /* header length */ + fwrite(&l2, 4, 1, fp); /* object length */ + fwrite(&l, 4, 1, fp); /* header length */ membufdump(h->buf, fp); - return 0; /* no error handling in here... CHANGE THIS! */ + return 0; /* no error handling in here... CHANGE THIS! */ } void rdfdoneheader(rdf_headerbuf * h) diff --git a/rdoff/rdoff.h b/rdoff/rdoff.h index d6c54b2b..68f156b8 100644 --- a/rdoff/rdoff.h +++ b/rdoff/rdoff.h @@ -10,7 +10,7 @@ * as acknowledgement is given in an appropriate manner to its authors, * with instructions of how to obtain a copy via ftp. */ - + #ifndef _RDOFF_H #define _RDOFF_H @@ -40,7 +40,6 @@ typedef unsigned int bool; /* Maximum number of segments that we can handle in one file */ #define RDF_MAXSEGS 64 - /* Record types that may present the RDOFF header */ #define RDFREC_GENERIC 0 #define RDFREC_RELOC 1 @@ -53,7 +52,6 @@ typedef unsigned int bool; #define RDFREC_MODNAME 8 #define RDFREC_COMMON 10 - /* * Generic record - contains the type and length field, plus a 128 byte * char array 'data' @@ -68,80 +66,80 @@ struct GenericRec { * Relocation record */ struct RelocRec { - byte type; /* must be 1 */ - byte reclen; /* content length */ - byte segment; /* only 0 for code, or 1 for data supported, - but add 64 for relative refs (ie do not require - reloc @ loadtime, only linkage) */ - long offset; /* from start of segment in which reference is loc'd */ - byte length; /* 1 2 or 4 bytes */ - uint16 refseg; /* segment to which reference refers to */ + byte type; /* must be 1 */ + byte reclen; /* content length */ + byte segment; /* only 0 for code, or 1 for data supported, + but add 64 for relative refs (ie do not require + reloc @ loadtime, only linkage) */ + long offset; /* from start of segment in which reference is loc'd */ + byte length; /* 1 2 or 4 bytes */ + uint16 refseg; /* segment to which reference refers to */ }; /* * Extern/import record */ struct ImportRec { - byte type; /* must be 2 */ - byte reclen; /* content length */ - byte flags; /* SYM_* flags (see below) */ - uint16 segment; /* segment number allocated to the label for reloc - records - label is assumed to be at offset zero - in this segment, so linker must fix up with offset - of segment and of offset within segment */ - char label[EXIM_LABEL_MAX]; /* zero terminated, should be written to file - until the zero, but not after it */ + byte type; /* must be 2 */ + byte reclen; /* content length */ + byte flags; /* SYM_* flags (see below) */ + uint16 segment; /* segment number allocated to the label for reloc + records - label is assumed to be at offset zero + in this segment, so linker must fix up with offset + of segment and of offset within segment */ + char label[EXIM_LABEL_MAX]; /* zero terminated, should be written to file + until the zero, but not after it */ }; /* * Public/export record */ struct ExportRec { - byte type; /* must be 3 */ - byte reclen; /* content length */ - byte flags; /* SYM_* flags (see below) */ - byte segment; /* segment referred to (0/1/2) */ - long offset; /* offset within segment */ - char label[EXIM_LABEL_MAX]; /* zero terminated as in import */ + byte type; /* must be 3 */ + byte reclen; /* content length */ + byte flags; /* SYM_* flags (see below) */ + byte segment; /* segment referred to (0/1/2) */ + long offset; /* offset within segment */ + char label[EXIM_LABEL_MAX]; /* zero terminated as in import */ }; /* * DLL record */ struct DLLRec { - byte type; /* must be 4 */ - byte reclen; /* content length */ - char libname[MODLIB_NAME_MAX]; /* name of library to link with at load time */ + byte type; /* must be 4 */ + byte reclen; /* content length */ + char libname[MODLIB_NAME_MAX]; /* name of library to link with at load time */ }; /* * BSS record */ struct BSSRec { - byte type; /* must be 5 */ - byte reclen; /* content length */ - long amount; /* number of bytes BSS to reserve */ + byte type; /* must be 5 */ + byte reclen; /* content length */ + long amount; /* number of bytes BSS to reserve */ }; /* * Module name record */ struct ModRec { - byte type; /* must be 8 */ - byte reclen; /* content length */ - char modname[MODLIB_NAME_MAX]; /* module name */ + byte type; /* must be 8 */ + byte reclen; /* content length */ + char modname[MODLIB_NAME_MAX]; /* module name */ }; /* * Common variable record */ struct CommonRec { - byte type; /* must be 10 */ - byte reclen; /* equals 7+label length */ - uint16 segment; /* segment number */ - long size; /* size of common variable */ - uint16 align; /* alignment (power of two) */ - char label[EXIM_LABEL_MAX]; /* zero terminated as in import */ + byte type; /* must be 10 */ + byte reclen; /* equals 7+label length */ + uint16 segment; /* segment number */ + long size; /* size of common variable */ + uint16 align; /* alignment (power of two) */ + char label[EXIM_LABEL_MAX]; /* zero terminated as in import */ }; /* Flags for ExportRec */ @@ -150,7 +148,6 @@ struct CommonRec { #define SYM_GLOBAL 4 #define SYM_IMPORT 8 - /*** The following part is used only by the utilities *************************/ #ifdef RDOFF_UTILS @@ -161,15 +158,15 @@ extern char *strdup(const char *); #endif typedef union RDFHeaderRec { - char type; /* invariant throughout all below */ - struct GenericRec g; /* type 0 */ - struct RelocRec r; /* type == 1 / 6 */ - struct ImportRec i; /* type == 2 / 7 */ - struct ExportRec e; /* type == 3 */ - struct DLLRec d; /* type == 4 */ - struct BSSRec b; /* type == 5 */ - struct ModRec m; /* type == 8 */ - struct CommonRec c; /* type == 10 */ + char type; /* invariant throughout all below */ + struct GenericRec g; /* type 0 */ + struct RelocRec r; /* type == 1 / 6 */ + struct ImportRec i; /* type == 2 / 7 */ + struct ExportRec e; /* type == 3 */ + struct DLLRec d; /* type == 4 */ + struct BSSRec b; /* type == 5 */ + struct ModRec m; /* type == 8 */ + struct CommonRec c; /* type == 10 */ } rdfheaderrec; struct SegmentHeaderRec { @@ -177,34 +174,34 @@ struct SegmentHeaderRec { uint16 type; uint16 number; uint16 reserved; - long length; + long length; /* information built up here */ - long offset; - byte *data; /* pointer to segment data if it exists in memory */ + long offset; + byte *data; /* pointer to segment data if it exists in memory */ }; typedef struct RDFFileInfo { - FILE *fp; /* file descriptor; must be open to use this struct */ - int rdoff_ver; /* should be 1; any higher => not guaranteed to work */ + FILE *fp; /* file descriptor; must be open to use this struct */ + int rdoff_ver; /* should be 1; any higher => not guaranteed to work */ long header_len; - long header_ofs; + long header_ofs; - byte *header_loc; /* keep location of header */ - long header_fp; /* current location within header for reading */ + byte *header_loc; /* keep location of header */ + long header_fp; /* current location within header for reading */ struct SegmentHeaderRec seg[RDF_MAXSEGS]; - int nsegs; + int nsegs; - long eof_offset; /* offset of the first byte beyond the end of this - module */ + long eof_offset; /* offset of the first byte beyond the end of this + module */ - char *name; /* name of module in libraries */ - int *refcount; /* pointer to reference count on file, or NULL */ + char *name; /* name of module in libraries */ + int *refcount; /* pointer to reference count on file, or NULL */ } rdffile; -#define BUF_BLOCK_LEN 4088 /* selected to match page size (4096) - * on 80x86 machines for efficiency */ +#define BUF_BLOCK_LEN 4088 /* selected to match page size (4096) + * on 80x86 machines for efficiency */ typedef struct memorybuffer { int length; byte buffer[BUF_BLOCK_LEN]; @@ -212,9 +209,9 @@ typedef struct memorybuffer { } memorybuffer; typedef struct { - memorybuffer * buf; /* buffer containing header records */ - int nsegments; /* number of segments to be written */ - long seglength; /* total length of all the segments */ + memorybuffer *buf; /* buffer containing header records */ + int nsegments; /* number of segments to be written */ + long seglength; /* total length of all the segments */ } rdf_headerbuf; /* segments used by RDOFF, understood by rdoffloadseg */ @@ -230,17 +227,17 @@ extern int rdf_errno; /* rdf_errno can hold these error codes */ enum { - /* 0 */ RDF_OK, - /* 1 */ RDF_ERR_OPEN, - /* 2 */ RDF_ERR_FORMAT, - /* 3 */ RDF_ERR_READ, - /* 4 */ RDF_ERR_UNKNOWN, - /* 5 */ RDF_ERR_HEADER, - /* 6 */ RDF_ERR_NOMEM, - /* 7 */ RDF_ERR_VER, - /* 8 */ RDF_ERR_RECTYPE, - /* 9 */ RDF_ERR_RECLEN, - /* 10 */ RDF_ERR_SEGMENT + /* 0 */ RDF_OK, + /* 1 */ RDF_ERR_OPEN, + /* 2 */ RDF_ERR_FORMAT, + /* 3 */ RDF_ERR_READ, + /* 4 */ RDF_ERR_UNKNOWN, + /* 5 */ RDF_ERR_HEADER, + /* 6 */ RDF_ERR_NOMEM, + /* 7 */ RDF_ERR_VER, + /* 8 */ RDF_ERR_RECTYPE, + /* 9 */ RDF_ERR_RECLEN, + /* 10 */ RDF_ERR_SEGMENT }; /* utility functions */ @@ -249,14 +246,14 @@ uint16 translateshort(uint16 in); char *translatesegmenttype(uint16 type); /* RDOFF file manipulation functions */ -int rdfopen(rdffile *f,const char *name); -int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name); -int rdfclose(rdffile *f); +int rdfopen(rdffile * f, const char *name); +int rdfopenhere(rdffile * f, FILE * fp, int *refcount, const char *name); +int rdfclose(rdffile * f); int rdffindsegment(rdffile * f, int segno); -int rdfloadseg(rdffile *f,int segment,void *buffer); -rdfheaderrec *rdfgetheaderrec(rdffile *f); /* returns static storage */ -void rdfheaderrewind(rdffile *f); /* back to start of header */ -void rdfperror(const char *app,const char *name); +int rdfloadseg(rdffile * f, int segment, void *buffer); +rdfheaderrec *rdfgetheaderrec(rdffile * f); /* returns static storage */ +void rdfheaderrewind(rdffile * f); /* back to start of header */ +void rdfperror(const char *app, const char *name); /* functions to write a new RDOFF header to a file - use rdfnewheader to allocate a header, rdfaddheader to add records to it, @@ -266,11 +263,11 @@ void rdfperror(const char *app,const char *name); to a file, and then rdfdoneheader to dispose of the header */ rdf_headerbuf *rdfnewheader(void); -int rdfaddheader(rdf_headerbuf *h,rdfheaderrec *r); -int rdfaddsegment(rdf_headerbuf *h, long seglength); -int rdfwriteheader(FILE *fp,rdf_headerbuf *h); -void rdfdoneheader(rdf_headerbuf *h); +int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r); +int rdfaddsegment(rdf_headerbuf * h, long seglength); +int rdfwriteheader(FILE * fp, rdf_headerbuf * h); +void rdfdoneheader(rdf_headerbuf * h); -#endif /* RDOFF_UTILS */ +#endif /* RDOFF_UTILS */ -#endif /* _RDOFF_H */ +#endif /* _RDOFF_H */ diff --git a/rdoff/rdx.c b/rdoff/rdx.c index 778b29fa..82210a65 100644 --- a/rdoff/rdx.c +++ b/rdoff/rdx.c @@ -18,39 +18,40 @@ #include "rdfload.h" #include "symtab.h" -typedef int (*main_fn) (int,char**); /* Main function prototype */ +typedef int (*main_fn) (int, char **); /* Main function prototype */ int main(int argc, char **argv) { - rdfmodule * m; - main_fn code; - symtabEnt * s; + rdfmodule *m; + main_fn code; + symtabEnt *s; if (argc < 2) { - puts("usage: rdx [params]\n"); - exit(255); + puts("usage: rdx [params]\n"); + exit(255); } m = rdfload(argv[1]); - if (! m) { - rdfperror("rdx",argv[1]); - exit(255); + if (!m) { + rdfperror("rdx", argv[1]); + exit(255); } - rdf_relocate(m); /* in this instance, the default relocation - values will work fine, but they may need changing - in other cases... */ + rdf_relocate(m); /* in this instance, the default relocation + values will work fine, but they may need changing + in other cases... */ s = symtabFind(m->symtab, "_main"); - if (! s) { - fprintf(stderr,"rdx: could not find symbol '_main' in '%s'\n",argv[1]); - exit(255); + if (!s) { + fprintf(stderr, "rdx: could not find symbol '_main' in '%s'\n", + argv[1]); + exit(255); } code = (main_fn) s->offset; - argv++, argc--; /* remove 'rdx' from command line */ + argv++, argc--; /* remove 'rdx' from command line */ - return code(argc,argv); /* execute */ + return code(argc, argv); /* execute */ } diff --git a/rdoff/segtab.c b/rdoff/segtab.c dissimilarity index 65% index f3168fc0..ed26aeae 100644 --- a/rdoff/segtab.c +++ b/rdoff/segtab.c @@ -1,142 +1,140 @@ -#include -#include -#include "segtab.h" - -struct segtabnode { - int localseg; - int destseg; - long offset; - - struct segtabnode * left; - struct segtabnode * right; - /* - * counts of how many are left or right, for use in reorganising - * the tree - */ - int leftcount; - int rightcount; -}; - -/* - * init_seglocations() - * add_seglocation() - * get_seglocation() - * done_seglocation() - * - * functions used by write_output() to manipulate associations - * between segment numbers and locations (which are built up on a per - * module basis, but we only need one module at a time...) - * - * implementation: we build a binary tree. - */ - - -void init_seglocations(segtab * root) -{ - *root = NULL; -} - -void descend_tree_add(struct segtabnode * * node, - int localseg, int destseg, long offset) -{ - struct segtabnode * n; - - if (*node == NULL) { - *node = malloc (sizeof (**node)); - if (!*node) { - fprintf(stderr, "segment table: out of memory\n"); - exit(1); - } - (*node)->localseg = localseg; - (*node)->offset = offset; - (*node)->left = NULL; - (*node)->leftcount = 0; - (*node)->right = NULL; - (*node)->rightcount = 0; - (*node)->destseg = destseg; - return; - } - - if (localseg < (*node)->localseg) - { - (*node)->leftcount++; - descend_tree_add(&(*node)->left, localseg, destseg, offset); - - if ((*node)->leftcount > (*node)->rightcount + 2) { - n = * node; - *node = n->left; - n->left = (*node)->right; - n->leftcount = (*node)->rightcount; - (*node)->right = n; - (*node)->rightcount = n->leftcount + n->rightcount + 1; - } - } - else - { - (*node)->rightcount++; - descend_tree_add(&(*node)->right, localseg, destseg, offset); - - if ((*node)->rightcount > (*node)->leftcount + 2) { - n = * node; - *node = n->right; - n->right= (*node)->left; - n->rightcount = (*node)->leftcount; - (*node)->left = n; - (*node)->leftcount = n->leftcount + n->rightcount + 1; - } - } -} - -void add_seglocation(segtab * root, int localseg, int destseg, long offset) -{ - descend_tree_add((struct segtabnode **) root, localseg, destseg, offset); -} - -int get_seglocation(segtab * root, int localseg, int * destseg, long * offset) -{ - struct segtabnode * n = (struct segtabnode *) *root; - - while (n && n->localseg != localseg) - { - if (localseg < n->localseg) - n = n->left; - else - n = n->right; - } - if (n) { - *destseg = n->destseg; - *offset = n->offset; - return 1; - } - else - return 0; -} - -void freenode(struct segtabnode * n) -{ - if (!n) return; - freenode (n->left); - freenode (n->right); - free(n); -} - -void done_seglocations(segtab * root) -{ - freenode(*root); - *root = NULL; -} - -#if 0 -void printnode(int i, struct segtabnode * n) -{ - if (!n) return; - printnode(i + 1, n->left); - printf ("%*s%d %d %ld\n", i, "", n->localseg, n->destseg, n->offset); - printnode(i + 1, n->right); -} - -void printtable() -{ - printnode(0,root); -} -#endif +#include +#include +#include "segtab.h" + +struct segtabnode { + int localseg; + int destseg; + long offset; + + struct segtabnode *left; + struct segtabnode *right; + /* + * counts of how many are left or right, for use in reorganising + * the tree + */ + int leftcount; + int rightcount; +}; + +/* + * init_seglocations() + * add_seglocation() + * get_seglocation() + * done_seglocation() + * + * functions used by write_output() to manipulate associations + * between segment numbers and locations (which are built up on a per + * module basis, but we only need one module at a time...) + * + * implementation: we build a binary tree. + */ + +void init_seglocations(segtab * root) +{ + *root = NULL; +} + +void descend_tree_add(struct segtabnode **node, + int localseg, int destseg, long offset) +{ + struct segtabnode *n; + + if (*node == NULL) { + *node = malloc(sizeof(**node)); + if (!*node) { + fprintf(stderr, "segment table: out of memory\n"); + exit(1); + } + (*node)->localseg = localseg; + (*node)->offset = offset; + (*node)->left = NULL; + (*node)->leftcount = 0; + (*node)->right = NULL; + (*node)->rightcount = 0; + (*node)->destseg = destseg; + return; + } + + if (localseg < (*node)->localseg) { + (*node)->leftcount++; + descend_tree_add(&(*node)->left, localseg, destseg, offset); + + if ((*node)->leftcount > (*node)->rightcount + 2) { + n = *node; + *node = n->left; + n->left = (*node)->right; + n->leftcount = (*node)->rightcount; + (*node)->right = n; + (*node)->rightcount = n->leftcount + n->rightcount + 1; + } + } else { + (*node)->rightcount++; + descend_tree_add(&(*node)->right, localseg, destseg, offset); + + if ((*node)->rightcount > (*node)->leftcount + 2) { + n = *node; + *node = n->right; + n->right = (*node)->left; + n->rightcount = (*node)->leftcount; + (*node)->left = n; + (*node)->leftcount = n->leftcount + n->rightcount + 1; + } + } +} + +void add_seglocation(segtab * root, int localseg, int destseg, long offset) +{ + descend_tree_add((struct segtabnode **)root, localseg, destseg, + offset); +} + +int get_seglocation(segtab * root, int localseg, int *destseg, + long *offset) +{ + struct segtabnode *n = (struct segtabnode *)*root; + + while (n && n->localseg != localseg) { + if (localseg < n->localseg) + n = n->left; + else + n = n->right; + } + if (n) { + *destseg = n->destseg; + *offset = n->offset; + return 1; + } else + return 0; +} + +void freenode(struct segtabnode *n) +{ + if (!n) + return; + freenode(n->left); + freenode(n->right); + free(n); +} + +void done_seglocations(segtab * root) +{ + freenode(*root); + *root = NULL; +} + +#if 0 +void printnode(int i, struct segtabnode *n) +{ + if (!n) + return; + printnode(i + 1, n->left); + printf("%*s%d %d %ld\n", i, "", n->localseg, n->destseg, n->offset); + printnode(i + 1, n->right); +} + +void printtable() +{ + printnode(0, root); +} +#endif diff --git a/rdoff/segtab.h b/rdoff/segtab.h index 7e8e1937..bd29357d 100644 --- a/rdoff/segtab.h +++ b/rdoff/segtab.h @@ -1,6 +1,6 @@ -typedef void * segtab; +typedef void *segtab; void init_seglocations(segtab * r); void add_seglocation(segtab * r, int localseg, int destseg, long offset); -int get_seglocation(segtab * r, int localseg, int * destseg, long * offset); +int get_seglocation(segtab * r, int localseg, int *destseg, long *offset); void done_seglocations(segtab * r); diff --git a/rdoff/symtab.c b/rdoff/symtab.c dissimilarity index 67% index 30379634..8d8ac629 100644 --- a/rdoff/symtab.c +++ b/rdoff/symtab.c @@ -1,130 +1,127 @@ -/* symtab.c Routines to maintain and manipulate a symbol table - * - * These routines donated to the NASM effort by Graeme Defty. - * - * The Netwide Assembler is copyright (C) 1996 Simon Tatham and - * Julian Hall. All rights reserved. The software is - * redistributable under the licence given in the file "Licence" - * distributed in the NASM archive. - */ -#include -#include -#include - -#include "symtab.h" -#include "hash.h" - -#define SYMTABSIZE 64 -#define slotnum(x) (hash((x)) % SYMTABSIZE) - -/* ------------------------------------- */ -/* Private data types */ - -typedef struct tagSymtabNode { - struct tagSymtabNode * next; - symtabEnt ent; -} symtabNode; - -typedef symtabNode *(symtabTab[SYMTABSIZE]); - -typedef symtabTab *symtab; - -/* ------------------------------------- */ -void * -symtabNew(void) -{ - symtab mytab; - - mytab = (symtabTab *) calloc(SYMTABSIZE ,sizeof(symtabNode *)); - if (mytab == NULL) { - fprintf(stderr,"symtab: out of memory\n"); - exit(3); - } - - return mytab; -} - -/* ------------------------------------- */ -void -symtabDone(void *stab) -{ - symtab mytab = (symtab)stab; - int i; - symtabNode *this, *next; - - for (i=0; i < SYMTABSIZE; ++i) { - - for (this = (*mytab)[i]; this; this=next) - { next = this->next; free (this); } - - } - free (*mytab); -} - -/* ------------------------------------- */ -void -symtabInsert(void *stab, symtabEnt *ent) -{ - symtab mytab = (symtab) stab; - symtabNode *node; - int slot; - - node = malloc(sizeof(symtabNode)); - if (node == NULL) { - fprintf(stderr,"symtab: out of memory\n"); - exit(3); - } - - slot = slotnum(ent->name); - - node->ent = *ent; - node->next = (*mytab)[slot]; - (*mytab)[slot] = node; -} - -/* ------------------------------------- */ -symtabEnt * -symtabFind(void *stab, const char *name) -{ - symtab mytab = (symtab) stab; - int slot = slotnum(name); - symtabNode *node = (*mytab)[slot]; - - while (node) { - if (!strcmp(node->ent.name,name)) { - return &(node->ent); - } - node = node->next; - } - - return NULL; -} - -/* ------------------------------------- */ -void -symtabDump(void *stab, FILE* of) -{ - symtab mytab = (symtab)stab; - int i; - char *SegNames[3]={"code","data","bss"}; - - fprintf(of, "Symbol table is ...\n"); - for (i=0; i < SYMTABSIZE; ++i) { - symtabNode *l = (symtabNode *)(*mytab)[i]; - - if (l) { - fprintf(of, " ... slot %d ...\n", i); - } - while(l) { - if ((l->ent.segment) == -1) { - fprintf(of,"%-32s Unresolved reference\n",l->ent.name); - } else { - fprintf(of, "%-32s %s:%08lx (%ld)\n",l->ent.name, - SegNames[l->ent.segment], - l->ent.offset, l->ent.flags); - } - l = l->next; - } - } - fprintf(of, "........... end of Symbol table.\n"); -} +/* symtab.c Routines to maintain and manipulate a symbol table + * + * These routines donated to the NASM effort by Graeme Defty. + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ +#include +#include +#include + +#include "symtab.h" +#include "hash.h" + +#define SYMTABSIZE 64 +#define slotnum(x) (hash((x)) % SYMTABSIZE) + +/* ------------------------------------- */ +/* Private data types */ + +typedef struct tagSymtabNode { + struct tagSymtabNode *next; + symtabEnt ent; +} symtabNode; + +typedef symtabNode *(symtabTab[SYMTABSIZE]); + +typedef symtabTab *symtab; + +/* ------------------------------------- */ +void *symtabNew(void) +{ + symtab mytab; + + mytab = (symtabTab *) calloc(SYMTABSIZE, sizeof(symtabNode *)); + if (mytab == NULL) { + fprintf(stderr, "symtab: out of memory\n"); + exit(3); + } + + return mytab; +} + +/* ------------------------------------- */ +void symtabDone(void *stab) +{ + symtab mytab = (symtab) stab; + int i; + symtabNode *this, *next; + + for (i = 0; i < SYMTABSIZE; ++i) { + + for (this = (*mytab)[i]; this; this = next) { + next = this->next; + free(this); + } + + } + free(*mytab); +} + +/* ------------------------------------- */ +void symtabInsert(void *stab, symtabEnt * ent) +{ + symtab mytab = (symtab) stab; + symtabNode *node; + int slot; + + node = malloc(sizeof(symtabNode)); + if (node == NULL) { + fprintf(stderr, "symtab: out of memory\n"); + exit(3); + } + + slot = slotnum(ent->name); + + node->ent = *ent; + node->next = (*mytab)[slot]; + (*mytab)[slot] = node; +} + +/* ------------------------------------- */ +symtabEnt *symtabFind(void *stab, const char *name) +{ + symtab mytab = (symtab) stab; + int slot = slotnum(name); + symtabNode *node = (*mytab)[slot]; + + while (node) { + if (!strcmp(node->ent.name, name)) { + return &(node->ent); + } + node = node->next; + } + + return NULL; +} + +/* ------------------------------------- */ +void symtabDump(void *stab, FILE * of) +{ + symtab mytab = (symtab) stab; + int i; + char *SegNames[3] = { "code", "data", "bss" }; + + fprintf(of, "Symbol table is ...\n"); + for (i = 0; i < SYMTABSIZE; ++i) { + symtabNode *l = (symtabNode *) (*mytab)[i]; + + if (l) { + fprintf(of, " ... slot %d ...\n", i); + } + while (l) { + if ((l->ent.segment) == -1) { + fprintf(of, "%-32s Unresolved reference\n", l->ent.name); + } else { + fprintf(of, "%-32s %s:%08lx (%ld)\n", l->ent.name, + SegNames[l->ent.segment], + l->ent.offset, l->ent.flags); + } + l = l->next; + } + } + fprintf(of, "........... end of Symbol table.\n"); +} diff --git a/rdoff/symtab.h b/rdoff/symtab.h index c1fe0315..5bd9bcb6 100644 --- a/rdoff/symtab.h +++ b/rdoff/symtab.h @@ -7,16 +7,14 @@ */ typedef struct { - char *name; - int segment; - long offset; - long flags; + char *name; + int segment; + long offset; + long flags; } symtabEnt; void *symtabNew(void); void symtabDone(void *symtab); -void symtabInsert(void *symtab,symtabEnt *ent); -symtabEnt *symtabFind(void *symtab,const char *name); -void symtabDump(void *symtab,FILE *of); - - +void symtabInsert(void *symtab, symtabEnt * ent); +symtabEnt *symtabFind(void *symtab, const char *name); +void symtabDump(void *symtab, FILE * of); diff --git a/sync.c b/sync.c index 261afbca..37bd221a 100644 --- a/sync.c +++ b/sync.c @@ -12,7 +12,7 @@ #include "sync.h" -#define SYNC_MAX 4096 /* max # of sync points */ +#define SYNC_MAX 4096 /* max # of sync points */ /* * This lot manages the current set of sync points by means of a @@ -25,7 +25,7 @@ static struct Sync { } *synx; static int nsynx; -void init_sync(void) +void init_sync(void) { /* * I'd like to allocate an array of size SYNC_MAX, then write @@ -41,72 +41,72 @@ void init_sync(void) * dynamically I avoid problems with the total size of DGROUP * in Borland C. */ - synx = malloc((SYNC_MAX+1) * sizeof(*synx)); + synx = malloc((SYNC_MAX + 1) * sizeof(*synx)); if (!synx) { - fprintf(stderr, "ndisasm: not enough memory for sync array\n"); - exit(1); + fprintf(stderr, "ndisasm: not enough memory for sync array\n"); + exit(1); } nsynx = 0; } -void add_sync(unsigned long pos, unsigned long length) +void add_sync(unsigned long pos, unsigned long length) { int i; if (nsynx == SYNC_MAX) - return; /* can't do anything - overflow */ + return; /* can't do anything - overflow */ nsynx++; synx[nsynx].pos = pos; synx[nsynx].length = length; for (i = nsynx; i > 1; i /= 2) { - if (synx[i/2].pos > synx[i].pos) { - struct Sync t; - t = synx[i/2]; /* structure copy */ - synx[i/2] = synx[i]; /* structure copy again */ - synx[i] = t; /* another structure copy */ - } + if (synx[i / 2].pos > synx[i].pos) { + struct Sync t; + t = synx[i / 2]; /* structure copy */ + synx[i / 2] = synx[i]; /* structure copy again */ + synx[i] = t; /* another structure copy */ + } } } -unsigned long next_sync(unsigned long position, unsigned long *length) +unsigned long next_sync(unsigned long position, unsigned long *length) { while (nsynx > 0 && synx[1].pos + synx[1].length <= position) { - int i, j; - struct Sync t; - t = synx[nsynx]; /* structure copy */ - synx[nsynx] = synx[1]; /* structure copy */ - synx[1] = t; /* ditto */ + int i, j; + struct Sync t; + t = synx[nsynx]; /* structure copy */ + synx[nsynx] = synx[1]; /* structure copy */ + synx[1] = t; /* ditto */ - nsynx--; + nsynx--; i = 1; - while (i*2 <= nsynx) { - j = i*2; - if (synx[j].pos < synx[i].pos && - (j+1 > nsynx || synx[j+1].pos > synx[j].pos)) { - t = synx[j]; /* structure copy */ - synx[j] = synx[i]; /* lots of these... */ - synx[i] = t; /* ...aren't there? */ - i = j; - } else if (j+1 <= nsynx && synx[j+1].pos < synx[i].pos) { - t = synx[j+1]; /* structure copy */ - synx[j+1] = synx[i]; /* structure copy */ - synx[i] = t; /* structure copy */ - i = j+1; - } else - break; - } + while (i * 2 <= nsynx) { + j = i * 2; + if (synx[j].pos < synx[i].pos && + (j + 1 > nsynx || synx[j + 1].pos > synx[j].pos)) { + t = synx[j]; /* structure copy */ + synx[j] = synx[i]; /* lots of these... */ + synx[i] = t; /* ...aren't there? */ + i = j; + } else if (j + 1 <= nsynx && synx[j + 1].pos < synx[i].pos) { + t = synx[j + 1]; /* structure copy */ + synx[j + 1] = synx[i]; /* structure copy */ + synx[i] = t; /* structure copy */ + i = j + 1; + } else + break; + } } if (nsynx > 0) { - if (length) - *length = synx[1].length; - return synx[1].pos; + if (length) + *length = synx[1].length; + return synx[1].pos; } else { - if (length) - *length = 0L; - return ULONG_MAX; + if (length) + *length = 0L; + return ULONG_MAX; } } diff --git a/test/aouttest.c b/test/aouttest.c index 9a8eba30..68b9f075 100644 --- a/test/aouttest.c +++ b/test/aouttest.c @@ -15,11 +15,12 @@ extern void *selfptr; extern void *textptr; extern int integer, commvar; -int main(void) { +int main(void) +{ printf("Testing lrotate: should get 0x00400000, 0x00000001\n"); - printf("lrotate(0x00040000, 4) = 0x%08lx\n", lrotate(0x40000,4)); - printf("lrotate(0x00040000, 14) = 0x%08lx\n", lrotate(0x40000,14)); + printf("lrotate(0x00040000, 4) = 0x%08lx\n", lrotate(0x40000, 4)); + printf("lrotate(0x00040000, 14) = 0x%08lx\n", lrotate(0x40000, 14)); printf("This string should read `hello, world': `%s'\n", asmstr); @@ -28,8 +29,7 @@ int main(void) { commvar = 4321; greet(); - printf("These pointers should be equal: %p and %p\n", - &greet, textptr); + printf("These pointers should be equal: %p and %p\n", &greet, textptr); printf("So should these: %p and %p\n", selfptr, &selfptr); } diff --git a/test/cofftest.c b/test/cofftest.c index 4dec0df9..e259aef2 100644 --- a/test/cofftest.c +++ b/test/cofftest.c @@ -14,11 +14,12 @@ extern void *selfptr; extern void *textptr; extern int integer, commvar; -int main(void) { +int main(void) +{ printf("Testing lrotate: should get 0x00400000, 0x00000001\n"); - printf("lrotate(0x00040000, 4) = 0x%08lx\n", lrotate(0x40000,4)); - printf("lrotate(0x00040000, 14) = 0x%08lx\n", lrotate(0x40000,14)); + printf("lrotate(0x00040000, 4) = 0x%08lx\n", lrotate(0x40000, 4)); + printf("lrotate(0x00040000, 14) = 0x%08lx\n", lrotate(0x40000, 14)); printf("This string should read `hello, world': `%s'\n", asmstr); @@ -27,8 +28,7 @@ int main(void) { commvar = 4321; greet(); - printf("These pointers should be equal: %p and %p\n", - &greet, textptr); + printf("These pointers should be equal: %p and %p\n", &greet, textptr); printf("So should these: %p and %p\n", selfptr, &selfptr); } diff --git a/test/elftest.c b/test/elftest.c index 1965fcf8..8ad481ed 100644 --- a/test/elftest.c +++ b/test/elftest.c @@ -15,11 +15,12 @@ extern void *selfptr; extern void *textptr; extern int integer, commvar; -int main(void) { +int main(void) +{ printf("Testing lrotate: should get 0x00400000, 0x00000001\n"); - printf("lrotate(0x00040000, 4) = 0x%08lx\n", lrotate(0x40000,4)); - printf("lrotate(0x00040000, 14) = 0x%08lx\n", lrotate(0x40000,14)); + printf("lrotate(0x00040000, 4) = 0x%08lx\n", lrotate(0x40000, 4)); + printf("lrotate(0x00040000, 14) = 0x%08lx\n", lrotate(0x40000, 14)); printf("This string should read `hello, world': `%s'\n", asmstr); @@ -28,8 +29,7 @@ int main(void) { commvar = 4321; greet(); - printf("These pointers should be equal: %p and %p\n", - &greet, textptr); + printf("These pointers should be equal: %p and %p\n", &greet, textptr); printf("So should these: %p and %p\n", selfptr, &selfptr); } diff --git a/test/objlink.c b/test/objlink.c index 9898e015..05ff732f 100644 --- a/test/objlink.c +++ b/test/objlink.c @@ -16,11 +16,12 @@ extern int bsssym, commvar; extern void *selfptr; extern void *selfptr2; -int main(void) { +int main(void) +{ printf("these should be identical: %p, %p\n", - (long) selfptr, (long) &selfptr); + (long)selfptr, (long)&selfptr); printf("these should be equivalent but different: %p, %p\n", - (long) selfptr2, (long) &selfptr2); + (long)selfptr2, (long)&selfptr2); printf("you should see \"hello, world\" twice:\n"); bsssym = 0xF00D; commvar = 0xD00F; -- 2.11.4.GIT