[comp.realtime] supplied: source for a.out to s-record converter

pete@ohm.york.ac.uk (-Pete French.) (06/17/91)

in article <43328@cup.portal.com>, Stuart_Jefferson_Adams@cup.portal.com says:
> 
> can anyone either send me or point me to the sources for a program which
> convertes unix (bsd/gnu) a.out format files to s-records??

This might actually be usefull to other ppl so I am posting it here :
The program was written to enable us to use gcc on the SUNs to make
executable files for some 68000 lab kits we have here. I will dump SUN
407 format executables (use the -N option) compiled for a 68010. These
restrictins are trivial to alter in the program (though dumping anything
other than 407 executables is generally a bad move - do a "size" on one)

The program includes an a.out.h from the local directory - this was because
the program was written to run on a MIPS not a SUN and so just including the
standard a.out.h whould not work - I had to copy the SUN a.out.h into the
directory that I build s-dump in. Inclkuding the standard a.out.h should
work on a SUN.

-bat.

-----------------------------------------------------------------------------

/*
 * s-dump.c : dump a.out files in Motorola S-record format
 *             -Pete French. 9/7/1990
 *
 * This program is designed for dumping files generated by gcc
 * for the 68000 lab kits. It will therefore only dump files
 * that have a machine type of M_68010 and a magic number of
 * OMAGIC (407 executable). This should prevent people trying to
 * run standard a.out binaries on the 68000 kits.
 */

#include "a.out.h"
#include <stdio.h>
#include <sys/file.h>

#define	S_HEAD	0
#define	S_DATA	2
#define	S_EOF	8
#define	MAXSREC	32

extern int errno;

/*
 * h_out(val)
 *
 * This function prints a two digit
 * hex value to stdout. printf cannot
 * be used on its own since the
 * braindamaged monitor in the 68000
 * kits cannot cope with small letters
 * in hex numbers !
 */

char conv[16]={'0','1','2','3','4','5','6','7',
               '8','9','A','B','C','D','E','F'};
h_out(val)
int val;
{
 val=val & 0xff;
 printf("%c%c",conv[val>>4],conv[val & 0x0f]);
}

/*
 * s_dump(type,addr,ptr,len)
 *
 * This function dumps out "len" bytes
 * from memory starting at location "ptr"
 * as an s-record of type "type". For
 * data records the load address is set
 * to "addr" and a checksum of the data
 * is returned (this is not the same as the
 * s-record checksum itself which includes
 * the size byte)
 */

int s_dump(type,addr,ptr,len)
int type,addr;
char *ptr;
int len;
{
int chck1,chck2;	/* two checksums - one for data, one for everything */
int i;			/* loop counter for outputting bytes */
chck1=(type==S_HEAD)?len+1:len+4;
printf("S%1d",type);
h_out(chck1);
if(type!=S_HEAD)
 {
  int top=(int)((addr & 0xff0000) >> 16);	/* top byte of address */
  int mid=(int)((addr & 0xff00) >> 8);		/* middle byte of address */
  int bot=(int)(addr & 0xff);			/* bottom byte of address */
  h_out(top);
  h_out(mid);
  h_out(bot);
  chck1=chck1+top+mid+bot;			/* add bytes to checksum */
 }
chck2=0;			/* zero data checksum */
for(i=0;i<len;i++)
 {
  h_out((int)ptr[i]);		/* print a byte of the data */
  chck1+=(int)ptr[i];		/* add byte to total checksum */
  chck2+=(int)ptr[i];		/* add byte to data checksum */
 }
h_out((int)(~chck1 & 0xff));	/* print checksum for record */
puts("");
return(chck2);			/* return data checksum */
}

/*
 * main(argc,argv)
 *
 * This is the main body of the program. It checks
 * to see that it has been called with a valid
 * argument, attempts to open the object file and
 * if successful checks its type. Once this has
 * been done the program loops reading in MAXSREC byte
 * blocks of data and calling "s_dump" to output
 * them as s-records.
 */

main(argc,argv)
int argc;
char *argv[];
{
int fd;			/* object file file descriptor */
struct exec hdr;	/* object file a.out header */
int i,len;		/* general purpose loop and length variables */
int t_load,d_load;	/* text and data load addresses */
int t_len,d_len;	/* text and data segment lengths */
int b_start,b_len;	/* bss segment start and length */
int c_addr,g_chk;	/* current address and global checksum */
char buffer[MAXSREC];	/* buffer for data bytes */

/*
 * Check that the correct number
 * of arguments have been passed
 * to s-dump.
 */

if (argc!=2)
 {
  fprintf(stderr,"usage: s-dump <object file>\n");
  exit(1);
 }

/*
 * Open the file check that
 * it was opened correctly
 * and that we can read the
 * header structure.
 */

fd=open(argv[1],O_RDONLY,0);
if(fd==-1)
 {
  perror(argv[1]);
  exit(errno);
 }
len=read(fd,(char*)&hdr,sizeof(struct exec));
if(len!=sizeof(struct exec))
 {
  fprintf(stderr,"s-dump: cannot read a.out header structure\n");
  exit(1);
 }

/*
 * Now we check that the file
 * is actually an executable
 * and that it is the correct
 * type of executable.
 */


if(N_BADMAG(hdr))
 {
  fprintf(stderr,"s-dump: this is not a correct a.out format file\n");
  exit(1);
 }
switch(hdr.a_magic)
 {
  case OMAGIC :
   break;
  case NMAGIC :
   fprintf(stderr,"s-dump: read-only text executables not supported\n");
   exit(1);
   break;
  case ZMAGIC :
   fprintf(stderr,"s-dump: demand load executables not supported\n");
   exit(1);
   break;
  }
if(hdr.a_machtype!=M_68010)
 {
  fprintf(stderr,"s-dump: this executable is not for 68000/68010 processor\n");
  exit(1);
 }

/*
 * We now have an open file
 * of the correct format.
 * Calculate the lengths and
 * addresses of the segments
 */

t_load=hdr.a_entry;
t_len=hdr.a_text;
d_load=t_load+t_len;
d_len=hdr.a_data;
b_start=d_load+d_len;
b_len=hdr.a_bss;

/*
 * Print out the filename
 * and the areas in memory
 * occupied by the various
 * segments.
 */

printf("dumping file %s as s-records: -Pete French. 9/7/1990\n",argv[1]);
printf("text segment:\tstarts at 0x%08x for 0x%x bytes\n",t_load,t_len);
printf("data segment:\tstarts at 0x%08x for 0x%x bytes\n",d_load,d_len);
printf("bss segment:\tstarts at 0x%08x for 0x%x bytes\n",b_start,b_len);

/*
 * Start dumping the S-records
 * beginning with the header
 * containing the filename.
 */

len=strlen(argv[1]);
if(len>MAXSREC)			/* truncate filenames over MAXSREC characters */
 len=MAXSREC;
puts("header");
s_dump(S_HEAD,0,argv[1],len);	/* dump the header s-record */
g_chk=0;			/* zero the global checksum */

/*
 * Now read in the text
 * segment in MAXSREC byte parts
 * and dump each part as an
 * s-record
 */

c_addr=t_load;
puts("text");
while(c_addr!=d_load)
 {
  len=d_load-c_addr;
  if(len>MAXSREC)		/* dump in MAXSREC byte s-records */
   len=MAXSREC;
  if(len!=read(fd,buffer,len))
   {
    fprintf("s-dump: file ran out prematurely in text segment\n");
    exit(1);
   }
  g_chk+=s_dump(S_DATA,c_addr,buffer,len);
  c_addr+=len;
 }

/*
 * Next we read in the data
 * segment and dump it in a similar
 * way in MAXREC byte parts.
 */

c_addr=d_load;
puts("data");
while(c_addr!=b_start)
 {
  int r_type;		/* s-record type */
  len=b_start-c_addr;
  if(len>MAXSREC)		/* dump in MAXSREC byte s-records */
   len=MAXSREC;
  if(len!=read(fd,buffer,len))
   {
    fprintf("s-dump: file ran out prematurely in data segment\n");
    exit(1);
   }
  g_chk+=s_dump(S_DATA,c_addr,buffer,len);
  c_addr+=len;
 }

/*
 * And finally and EOF
 * record is generated to
 * indicate the end of
 * the file. This
 * contains no data
 */

puts("eof");
s_dump(S_EOF,t_load,0,0);

/*
 * The global checksum is not used
 * yet - it is included for future
 * expansion at the request of Ross
 * Kirk.
 */

/* printf("global checksum is 0x%08x\n",g_chk & 0xffffffff); */
}

-- 
-Pete French. (the -bat. )         /  "Two wrongs don't make a right,
Adaptive Systems Engineering      /    - but three lefts do !"

"Look here, a Brit who has obviously been driving in California!"