Mercurial > hg > index.cgi
view lwlink/output.c @ 560:dba08c7dff96
Fix off by one handling MOD directive optional arguments
Fixes an off by one in handling the optional arguments to the MOD directive
as of changeset 928c033c0cd0.
Thanks to Alex Evans <varmfskii@gmail.com> for reporting the problem and a
suggested fix. This fix is different but should be more stable should the
rest of the parsing code be refactored in the future.
author | William Astle <lost@l-w.ca> |
---|---|
date | Fri, 22 Sep 2023 12:15:09 -0600 |
parents | cde1a5a48636 |
children |
line wrap: on
line source
/* output.c Copyright © 2009 William Astle This file is part of LWLINK. LWLINK is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Actually output the binary */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "lwlink.h" // this prevents warnings about not using the return value of fwrite() // and, theoretically, can be replaced with a function that handles things // better in the future //#define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); (void)r; } while (0) #define writebytes(s, l, c, f) do { (void)(fwrite((s), (l), (c), (f)) && 1); } while (0) void do_output_os9(FILE *of); void do_output_decb(FILE *of); void do_output_raw(FILE *of); void do_output_raw2(FILE *of); void do_output_lwex0(FILE *of); void do_output_srec(FILE *of); void do_output_ihex(FILE *of); void do_output(void) { FILE *of; of = fopen(outfile, "wb"); if (!of) { fprintf(stderr, "Cannot open output file %s: ", outfile); perror(""); exit(1); } switch (outformat) { case OUTPUT_DECB: do_output_decb(of); break; case OUTPUT_RAW: do_output_raw(of); break; case OUTPUT_RAW2: do_output_raw2(of); break; case OUTPUT_LWEX0: do_output_lwex0(of); break; case OUTPUT_OS9: do_output_os9(of); break; case OUTPUT_SREC: do_output_srec(of); break; case OUTPUT_IHEX: do_output_ihex(of); break; default: fprintf(stderr, "Unknown output format doing output!\n"); exit(111); } fclose(of); } void do_output_decb(FILE *of) { int sn, sn2; int cloc, olen; unsigned char buf[5]; for (sn = 0; sn < nsects; sn++) { if (sectlist[sn].ptr -> flags & SECTION_BSS) { // no output for a BSS section continue; } if (sectlist[sn].ptr -> codesize == 0) { // don't generate output for a zero size section continue; } // calculate the length of this output block cloc = sectlist[sn].ptr -> loadaddress; olen = 0; for (sn2 = sn; sn2 < nsects; sn2++) { // ignore BSS sections if (sectlist[sn2].ptr -> flags & SECTION_BSS) continue; // ignore zero length sections if (sectlist[sn2].ptr -> codesize == 0) continue; if (cloc != sectlist[sn2].ptr -> loadaddress) break; olen += sectlist[sn2].ptr -> codesize; cloc += sectlist[sn2].ptr -> codesize; } // write a preamble buf[0] = 0x00; buf[1] = olen >> 8; buf[2] = olen & 0xff; buf[3] = sectlist[sn].ptr -> loadaddress >> 8; buf[4] = sectlist[sn].ptr -> loadaddress & 0xff; writebytes(buf, 1, 5, of); for (; sn < sn2; sn++) { if (sectlist[sn].ptr -> flags & SECTION_BSS) continue; if (sectlist[sn].ptr -> codesize == 0) continue; writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of); } sn--; } // write a postamble buf[0] = 0xff; buf[1] = 0x00; buf[2] = 0x00; buf[3] = linkscript.execaddr >> 8; buf[4] = linkscript.execaddr & 0xff; writebytes(buf, 1, 5, of); } void do_output_raw(FILE *of) { int sn; for (sn = 0; sn < nsects; sn++) { if (sectlist[sn].ptr -> flags & SECTION_BSS) { // no output for a BSS section continue; } writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of); } } void do_output_raw2(FILE *of) { int nskips = 0; // used to output blanks for BSS inline int sn; for (sn = 0; sn < nsects; sn++) { if (sectlist[sn].ptr -> flags & SECTION_BSS) { // no output for a BSS section nskips += sectlist[sn].ptr -> codesize; continue; } while (nskips > 0) { // the "" is not an error - it turns into a single NUL byte! writebytes("", 1, 1, of); nskips--; } writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of); } } void do_output_srec(FILE *of) { const int SRECLEN = 16; int sn; int remainingcodebytes; int codeaddr; int i; int recaddr = 0; int recdlen = 0; int recsum; int reccnt = -1; unsigned char* sectcode; // no header yet; unnecessary for (sn = 0; sn < nsects; sn++) // check all sections { if (sectlist[sn].ptr -> flags & SECTION_BSS) // ignore BSS sections continue; if (sectlist[sn].ptr -> codesize == 0) // ignore empty sections continue; recaddr = sectlist[sn].ptr -> loadaddress; remainingcodebytes = sectlist[sn].ptr -> codesize; sectcode = sectlist[sn].ptr -> code; while (remainingcodebytes) { recdlen = (SRECLEN>remainingcodebytes)?remainingcodebytes:SRECLEN; recsum = recdlen + 3; codeaddr = recaddr - sectlist[sn].ptr -> loadaddress; fprintf(of, "S1%02X%04X", recdlen + 3, recaddr & 0xffff); for (i = 0; i < recdlen; i++) { fprintf(of, "%02X", sectcode[codeaddr+i]); recsum += sectcode[codeaddr+i]; } recsum += (recaddr >> 8) & 0xFF; recsum += recaddr & 0xFF; fprintf(of, "%02X\r\n", (unsigned char)(~recsum)); reccnt += 1; remainingcodebytes -= recdlen; recaddr += recdlen; } } // S9 record as a footer to inform about start addr recsum = 3; recsum += (linkscript.execaddr >> 8) & 0xFF; recsum += linkscript.execaddr & 0xFF; fprintf(of,"S903%04X%02X\r\n",linkscript.execaddr,(unsigned char)(~recsum)); } void do_output_ihex(FILE *of) { const int IRECLEN = 16; int sn; int remainingcodebytes; int codeaddr; int i; int recaddr = 0; int recdlen = 0; int recsum; int reccnt = -1; unsigned char* sectcode; // no header yet; unnecessary for (sn = 0; sn < nsects; sn++) // check all sections { if (sectlist[sn].ptr -> flags & SECTION_BSS) // ignore BSS sections continue; if (sectlist[sn].ptr -> codesize == 0) // ignore empty sections continue; recaddr = sectlist[sn].ptr -> loadaddress; remainingcodebytes = sectlist[sn].ptr -> codesize; sectcode = sectlist[sn].ptr -> code; while (remainingcodebytes) { recdlen = (IRECLEN>remainingcodebytes)?remainingcodebytes:IRECLEN; recsum = recdlen; codeaddr = recaddr - sectlist[sn].ptr -> loadaddress; fprintf(of, ":%02X%04X00", recdlen, recaddr & 0xffff); for (i = 0; i < recdlen; i++) { fprintf(of, "%02X", sectcode[codeaddr+i]); recsum += sectcode[codeaddr+i]; } recsum += (recaddr >> 8) & 0xFF; recsum += recaddr & 0xFF; fprintf(of, "%02X\r\n", (unsigned char)(256 - recsum)); reccnt += 1; remainingcodebytes -= recdlen; recaddr += recdlen; } } if (reccnt > 0) { fprintf(of, ":00%04X01FF\r\n", linkscript.execaddr); } } void do_output_lwex0(FILE *of) { int nskips = 0; // used to output blanks for BSS inline int sn; int codedatasize = 0; unsigned char buf[32]; // calculate items for the file header for (sn = 0; sn < nsects; sn++) { if (sectlist[sn].ptr -> flags & SECTION_BSS) { // no output for a BSS section nskips += sectlist[sn].ptr -> codesize; continue; } codedatasize += nskips; nskips = 0; codedatasize += sectlist[sn].ptr -> codesize; } // output the file header buf[0] = 'L'; buf[1] = 'W'; buf[2] = 'E'; buf[3] = 'X'; buf[4] = 0; // version 0 buf[5] = 0; // low stack buf[6] = linkscript.stacksize / 256; buf[7] = linkscript.stacksize & 0xff; buf[8] = nskips / 256; buf[9] = nskips & 0xff; buf[10] = codedatasize / 256; buf[11] = codedatasize & 0xff; buf[12] = linkscript.execaddr / 256; buf[13] = linkscript.execaddr & 0xff; memset(buf + 14, 0, 18); writebytes(buf, 1, 32, of); // output the data // NOTE: disjoint load addresses will not work correctly!!!!! nskips = 0; for (sn = 0; sn < nsects; sn++) { if (sectlist[sn].ptr -> flags & SECTION_BSS) { // no output for a BSS section nskips += sectlist[sn].ptr -> codesize; continue; } while (nskips > 0) { // the "" is not an error - it turns into a single NUL byte! writebytes("", 1, 1, of); nskips--; } writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of); } } void os9crc(unsigned char crc[3], unsigned char b) { b ^= crc[0]; crc[0] = crc[1]; crc[1] = crc[2]; crc[1] ^= b >> 7; crc[2] = b << 1; crc[1] ^= b >> 2; crc[2] ^= b << 6; b ^= b << 1; b ^= b << 2; b ^= b << 4; if (b & 0x80) { crc[0] ^= 0x80; crc[2] ^= 0x21; } } void do_output_os9(FILE *of) { int sn; int codedatasize = 0; int bsssize = 0; int nameoff; int i; unsigned char buf[16]; unsigned char crc[3]; // calculate items for the file header for (sn = 0; sn < nsects; sn++) { if (sectlist[sn].ptr -> flags & SECTION_BSS) { // no output for a BSS section bsssize += sectlist[sn].ptr -> codesize; continue; } codedatasize += sectlist[sn].ptr -> codesize; } bsssize += linkscript.stacksize; // now bss size is the data size for the module // and codesize is the length of the module minus the module header // and CRC codedatasize += 13; // add in headers nameoff = codedatasize; // we'll put the name at the end codedatasize += 3; // add in CRC codedatasize += strlen(linkscript.name); // add in name length if (linkscript.edition >= 0) codedatasize += 1; // output the file header buf[0] = 0x87; buf[1] = 0xCD; buf[2] = (codedatasize >> 8) & 0xff; buf[3] = codedatasize & 0xff; buf[4] = (nameoff >> 8) & 0xff; buf[5] = nameoff & 0xff; buf[6] = (linkscript.modtype << 4) | (linkscript.modlang); buf[7] = (linkscript.modattr << 4) | (linkscript.modrev); buf[8] = (~(buf[0] ^ buf[1] ^ buf[2] ^ buf[3] ^ buf[4] ^ buf[5] ^ buf[6] ^ buf[7])) & 0xff; buf[9] = (linkscript.execaddr >> 8) & 0xff; buf[10] = linkscript.execaddr & 0xff; buf[11] = (bsssize >> 8) & 0xff; buf[12] = bsssize & 0xff; crc[0] = 0xff; crc[1] = 0xff; crc[2] = 0xff; os9crc(crc, buf[0]); os9crc(crc, buf[1]); os9crc(crc, buf[2]); os9crc(crc, buf[3]); os9crc(crc, buf[4]); os9crc(crc, buf[5]); os9crc(crc, buf[6]); os9crc(crc, buf[7]); os9crc(crc, buf[8]); os9crc(crc, buf[9]); os9crc(crc, buf[10]); os9crc(crc, buf[11]); os9crc(crc, buf[12]); writebytes(buf, 1, 13, of); // output the data // NOTE: disjoint load addresses will not work correctly!!!!! for (sn = 0; sn < nsects; sn++) { if (sectlist[sn].ptr -> flags & SECTION_BSS) { // no output for a BSS section continue; } writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of); for (i = 0; i < sectlist[sn].ptr -> codesize; i++) os9crc(crc, sectlist[sn].ptr -> code[i]); } // output the name for (i = 0; linkscript.name[i + 1]; i++) { writebytes(linkscript.name + i, 1, 1, of); os9crc(crc, linkscript.name[i]); } buf[0] = linkscript.name[i] | 0x80; writebytes(buf, 1, 1, of); os9crc(crc, buf[0]); if (linkscript.edition >= 0) { buf[0] = linkscript.edition & 0xff; writebytes(buf, 1, 1, of); os9crc(crc, buf[0]); } crc[0] ^= 0xff; crc[1] ^= 0xff; crc[2] ^= 0xff; writebytes(crc, 1, 3, of); }