view lwlink/output.c @ 322:69adaab94ffd

Add notes about coding style and submission guidelines. As became clear from recent conversation, matching submitted code to the format of the existing code is not an obvious thing to do. (It should be but apparently it just doesn't occur to people.) Some description of the coding style is now present in the README. Additionally, submission guidelines have also been added to make it clear that patches (diffs) are the preferred means of providing code changes.
author William Astle <lost@l-w.ca>
date Mon, 03 Mar 2014 21:54:12 -0700
parents a640ff4ed95f
children 55c1f9a321e9
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_lwex0(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_LWEX0:
		do_output_lwex0(of);
		break;
	
	case OUTPUT_OS9:
		do_output_os9(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 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_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);
}