DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T r

⟦8bf350ede⟧ TextFile

    Length: 16271 (0x3f8f)
    Types: TextFile
    Names: »robotussin.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦4ef0278ca⟧ »./binutils.tar.Z« 
        └─⟦3761b9c35⟧ 
            └─⟦this⟧ »binutils/robotussin.c« 

TextFile

/* Convert COFF-format object file to BSD format.
   Used for converting the system libraries so GNU ld can link them.
   Copyright (C) 1988 Free Software Foundation, Inc.

   This program 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 1, 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, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

/*
** Robotussin - convert COFF format object files to BSD format.
**
** written by Jeff Lewis, donated to the Free Software Foundation.
**
** BUGS:
**	Should do more to verify that the input COFF file meets our
** expectations.
**  On machines where the structure of the COFF data in the file does not
** match the structure of the COFF data declared (when, for example
** sizeof (struct filhdr) != FILHSZ), this program will fail.  (Don't
** ask me why this is ever allowed to come about).  Accessor functions/
** macros that painstakingly extract the data out of the file and stuff
** it in the memory struct should be written to fix this on such machines.
**
** CAVEATS:
**	This program cannot claim correctness, however, it does appear
** to work on my fairly vanilla Sys5r2 machine.  Someone with the time
** and a fine tooth comb (not to mention some documentation on COFF)
** should correct this!
*/

#ifndef COFF_ENCAPSULATE
#define COFF_ENCAPSULATE
#endif

/* Customization for particular machines.  */

#ifdef i386
#define INPUT_MAGIC I386MAGIC
#else /* not i386 */
#if defined (m68k) || defined (mc68000)
#define INPUT_MAGIC MC68MAGIC
#endif
#endif /* not i386 */

#include <stdio.h>
#include <varargs.h>
#include <fcntl.h>

#include "a.out.encap.h"
#define N_ABSOLUTE N_ABS		/* N_ABS will be redefined in syms.h */
#undef N_ABS

#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
#include <syms.h>
#include <reloc.h>
/* Because of struct alignment on dwords sizeof (struct syment) is different
   than the syments stored in the file.  Therefore, we must kludge:  */
#define sizeof_syment (SYMESZ)
#define sizeof_reloc (RELSZ)
#define sizeof_section (SCNHSZ)
#define sizeof_coff_header (FILHSZ)

extern long lseek ();
extern void exit ();
extern char *memcpy ();
extern int errno;

void error (), sys_error ();
static void reloc_segment ();
char *mem_alloc ();

int fd_in, fd_out;		/* input and output file descriptors */

struct filehdr coff_header;		/* file header from the input file */
struct exec bsd_header;		/* file header for the output file */

struct syment *coff_sym_listp;		/* list of symbols from the input */
int *symbol_map;			/* mapping of input symbol #'s to
				   output symbol numbers */
char *text_and_data;			/* space for text & data section data */
char *relocations;			/* space for output reloc entries */
int verbose_flag;			/* flag for debugging */

struct scnhdr coff_text_header;		/* COFF text section header */
struct scnhdr coff_data_header;		/* COFF data section header */
struct scnhdr coff_bss_header;		/* COFF bss section header */
int text_sect_num;			/* COFF section # for text */
int data_sect_num;			/* COFF section # for data */
int bss_sect_num;			/* COFF section # for bss */
\f


int
main (argc, argv)
     int argc;
     char **argv;
{
  int i, j;
  char *coff_string_table, *bsd_string_table;
  register char *pc, *pc2;
  int string_table_len;
  int symbol_count;
  struct scnhdr section;
  struct nlist name;

  if (argc < 3)
    error ("usage: %s cofffile bsdfile", argv[0]);
  if (argc > 3)
    verbose_flag = 1;

  fd_in = open (argv[1], O_RDONLY);
  if (fd_in < 0)
    sys_error ("can't open %s", argv[1]);

  fd_out = open (argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
  if (fd_out < 0)
    sys_error ("can't open %s", argv[2]);

  /*
   ** Read in the file header and all section headers searching
   ** for text, data and bss.  We note the section #'s of these
   ** sections for use when examining symbols.
   */

  if (read (fd_in, &coff_header, sizeof_coff_header) != sizeof_coff_header)
    error ("can't read file header");

  if (coff_header.f_magic != INPUT_MAGIC)
    error ("bad magic number in coff file\n");

  lseek (fd_in, sizeof_coff_header + coff_header.f_opthdr, 0);

  for (i = 1; i <= coff_header.f_nscns; ++i)
    {
      if (read (fd_in, &section, sizeof_section) != sizeof_section)
	error ("can't read section header #%d", i);
      if (strcmp (section.s_name, _TEXT) == 0)
	{
	  text_sect_num = i;
	  memcpy (&coff_text_header, &section, sizeof section);
	} 
      else if (strcmp (section.s_name, _DATA) == 0)
	{
	  data_sect_num = i;
	  memcpy (&coff_data_header, &section, sizeof section);
	} 
      else if (strcmp (section.s_name, _BSS) == 0)
	{
	  bss_sect_num = i;
	  memcpy (&coff_bss_header, &section, sizeof section);
	}
    }

  /*
   ** Pass1 thru the symbol table - count usable symbols and map
   ** old symbol #'s into new ones (as used by relocation
   ** info).  We're only interested in keeping the kinds of symbols
   ** we'd expect to find in a BSD library object file: no debug
   ** symbols, file names, section definition symbols, etc.
   ** Section definition symbols are referenced by reloc entries
   ** in the COFF file, so we note their position with a negative
   ** symbol number indicating the section.  -1 is used to flag
   ** symbols we're not interested in, yielding an unexpected error
   ** if we find any reloc entries referencing them.
   */

  coff_sym_listp =
    (struct syment *) mem_alloc (coff_header.f_nsyms * sizeof (struct syment));
  symbol_map = (int *) mem_alloc (coff_header.f_nsyms * sizeof *symbol_map);
  if (lseek (fd_in, coff_header.f_symptr, 0) < 0L)
    sys_error ("can't seek to COFF symbols");
  for (i = 0; i < coff_header.f_nsyms; ++i)
    {
      if (read (fd_in, coff_sym_listp + i, sizeof_syment) != sizeof_syment)
	error ("can't read COFF symbols");
    }
  symbol_count = 0;
  for (i = 0; i < coff_header.f_nsyms; ++i)
    {
      if (coff_sym_listp[i].n_scnum != N_DEBUG
	  && coff_sym_listp[i].n_name[0] != '.'
	  && coff_sym_listp[i].n_scnum != -1)
	{
	  if (verbose_flag)
	    printf ("map %d to %d\n", i, symbol_count);
	  symbol_map[i] = symbol_count++;
	} 
      else
	{
	  if (coff_sym_listp[i].n_sclass == C_STAT)
	    {
	      if (strcmp (coff_sym_listp[i].n_name, _TEXT) == 0)
		symbol_map[i] = -N_TEXT;
	      else if (strcmp (coff_sym_listp[i].n_name, _DATA) == 0)
		symbol_map[i] = -N_DATA;
	      else if (strcmp (coff_sym_listp[i].n_name, _BSS) == 0)
		symbol_map[i] = -N_BSS;
	      else
		symbol_map[i] = -1;
	    } 
	  else
	    {
	      symbol_map[i] = -1;
	    }
	}
      /* skip auxillary entries */
      j = coff_sym_listp[i].n_numaux;
      if (j != 0)
	{
	  if (j < 0)
	    error ("invalid numaux");
	  if (j != 1)
	    fprintf (stderr, "unlikely numaux value\n");
	  while (--j >= 0)
	    ++i;
	}
    }

  /* now we know enough to write the output file header */

  N_SET_MAGIC (bsd_header, OMAGIC);
  bsd_header.a_text = coff_text_header.s_size;
  bsd_header.a_data = coff_data_header.s_size;
  bsd_header.a_bss = coff_bss_header.s_size;
  bsd_header.a_syms = symbol_count * sizeof (struct nlist);
  bsd_header.a_entry = 0;
  bsd_header.a_trsize = coff_text_header.s_nreloc * sizeof (struct relocation_info);
  bsd_header.a_drsize = coff_data_header.s_nreloc * sizeof (struct relocation_info);
  if (write (fd_out, &bsd_header, sizeof bsd_header) != sizeof bsd_header)
    sys_error ("can't write BSD header");

  /*
   ** Read in and save text and data sections - some data in
   ** these sections may need to be altered due to relocations.
   */

  text_and_data = (char *) mem_alloc (coff_text_header.s_size + coff_data_header.s_size);
  if (lseek (fd_in, coff_text_header.s_scnptr, 0) < 0L)
    sys_error ("can't seek to text section");
  if (read (fd_in, text_and_data, coff_text_header.s_size) != coff_text_header.s_size)
    error ("can't read text section");
  if (lseek (fd_in, coff_data_header.s_scnptr, 0) < 0L)
    sys_error ("can't seek to data section");
  if (read (fd_in, text_and_data + coff_text_header.s_size, coff_data_header.s_size) != coff_data_header.s_size)
    error ("can't read data section");

  /*
   ** Convert the relocation entries and do any text or data
   ** modifications necessary.
   */

  relocations = (char *) mem_alloc (bsd_header.a_trsize + bsd_header.a_drsize);
  reloc_segment (&coff_text_header, relocations);
  reloc_segment (&coff_data_header, relocations + bsd_header.a_trsize);

  if (write (fd_out, text_and_data, coff_text_header.s_size + coff_data_header.s_size)
      != coff_text_header.s_size + coff_data_header.s_size)
    sys_error ("can't write text and data sections");
  /* ZZ - are there any alignment considerations?? */
  if ((coff_text_header.s_size & 1) || (coff_data_header.s_size & 1))
    fprintf (stderr, "non-aligned text or data section\n");
  if (write (fd_out, relocations, bsd_header.a_trsize + bsd_header.a_drsize)
      != bsd_header.a_trsize + bsd_header.a_drsize)
    sys_error ("can't write relocation entries");

  /*
   ** Second pass thru the symbol table.  
   ** a COFF symbol entry may contain up to 8 chars of symbol name
   ** in the entry itself - symbol names > 8 go into the string table,
   ** whereas the BSD entry puts all symbol names into the string
   ** table.
   */

  if (lseek (fd_in, coff_header.f_symptr + coff_header.f_nsyms * sizeof_syment, 0) < 0L)
    error ("can't seek to string table");

  i = read (fd_in, &string_table_len, sizeof string_table_len);
  if (i == sizeof string_table_len)
    {
      coff_string_table = mem_alloc (string_table_len);
      string_table_len -= sizeof string_table_len;
      i = read (fd_in, coff_string_table + sizeof string_table_len, string_table_len);
      if (i < 0)
	error ("can't read string table");
      if (i != string_table_len)
	error ("truncated string table - expected %d, got %d",
	       string_table_len, i);
    } 
  else
    {
      string_table_len = 0;
    }
  bsd_string_table = mem_alloc (string_table_len + coff_header.f_nsyms * (SYMNMLEN + 1));
  pc = bsd_string_table + sizeof string_table_len;
  for (i = 0; i < coff_header.f_nsyms; ++i)
    {
      if (coff_sym_listp[i].n_scnum != N_DEBUG
	  && coff_sym_listp[i].n_name[0] != '.'
	  && coff_sym_listp[i].n_scnum != -1)
	{
	  if (coff_sym_listp[i].n_zeroes == 0)
	    {
	      j = pc - bsd_string_table;
#ifndef nounderscore
	      if (coff_sym_listp[i].n_sclass == C_EXT
		  || coff_sym_listp[i].n_sclass == C_STAT)
		*pc++ = '_';
#endif
	      pc2 = coff_string_table + coff_sym_listp[i].n_offset;
	      while (*pc++ = *pc2++)
		/* null */ ;
	      name.n_un.n_strx = j;
	    } 
	  else
	    {
	      pc2 = &coff_sym_listp[i].n_name[0];
	      j = pc - bsd_string_table;
#ifndef nounderscore
	      if (coff_sym_listp[i].n_sclass == C_EXT
		  || coff_sym_listp[i].n_sclass == C_STAT)
		*pc++ = '_';
#endif
	      {
		int x;
		for (x = 0; x < SYMNMLEN; x++)
		  {
		    if (*pc2 == 0)
		      break;
		    *pc++ = *pc2++;
		  }
		*pc++ = 0;
	      }
	      name.n_un.n_strx = j;
	    }
	  switch (coff_sym_listp[i].n_scnum)
	    {
	    case N_ABS:
	      name.n_type = N_ABSOLUTE;
	      break;
	    case N_UNDEF:
	      name.n_type = N_UNDF;
	      break;
	    default:
	      if (coff_sym_listp[i].n_scnum == text_sect_num)
		name.n_type = N_TEXT;
	      else if (coff_sym_listp[i].n_scnum == data_sect_num)
		name.n_type = N_DATA;
	      else if (coff_sym_listp[i].n_scnum == bss_sect_num)
		name.n_type = N_BSS;
	      break;
	    }
	  if (coff_sym_listp[i].n_sclass == C_EXT)
	    name.n_type |= N_EXT;
	  name.n_other = 0;
	  name.n_desc = 0;
	  name.n_value = coff_sym_listp[i].n_value;

	  if (write (fd_out, &name, sizeof name) != sizeof name)
	    sys_error ("can't write symbol");
	}
      /* skip auxillary entries */
      j = coff_sym_listp[i].n_numaux;
      if (j != 0)
	{
	  while (--j >= 0)
	    ++i;
	}
    }
  i = *((int *) bsd_string_table) = pc - bsd_string_table;
  if (write (fd_out, bsd_string_table, i) != i)
    error ("can't write string table");

  close (fd_in);
  close (fd_out);
  exit (0);
}
\f


/*
** Convert the relocation entries and do any text or data
** modifications necessary.
*/

static void
reloc_segment (section_headerp, reloc_infop)
     struct scnhdr *section_headerp;
     struct relocation_info *reloc_infop;
{
  struct reloc coff_reloc;
  int i;

  if (lseek (fd_in, section_headerp->s_relptr, 0) < 0L)
    error ("can't seek to relocation entries");
  for (i = 0; i < section_headerp->s_nreloc; ++i)
    {
      if (read (fd_in, &coff_reloc, sizeof_reloc) != sizeof_reloc)
	error ("can't read relocation entry");
      if (verbose_flag)
	printf ("vaddr = 0x%x, symndx = %d\n", coff_reloc.r_vaddr, coff_reloc.r_symndx);
      /*
       ** The reloc references a symbol declared common, thus the
       ** value of the symbol holds its size (in bytes).  In COFF,
       ** apparently this info is also put into the binary -
       ** BSD doesn't like this, so we subtract it out.
       */
      if (coff_sym_listp[coff_reloc.r_symndx].n_scnum == N_UNDEF)
	{
	  if (coff_sym_listp[coff_reloc.r_symndx].n_value != 0)
	    {
	      if (verbose_flag)
		printf ("adjust common 0x%x (%d)\n",
			coff_sym_listp[coff_reloc.r_symndx].n_value,
			coff_sym_listp[coff_reloc.r_symndx].n_value);
	      switch (coff_reloc.r_type)
		{
		case R_RELBYTE:
		  *((char *) (text_and_data + coff_reloc.r_vaddr))
		    -= coff_sym_listp[coff_reloc.r_symndx].n_value;
		  break;
		case R_RELWORD:
		  *((short *) (text_and_data + coff_reloc.r_vaddr))
		    -= coff_sym_listp[coff_reloc.r_symndx].n_value;
		  break;
		case R_RELLONG:
	        case R_DIR32:	/* these are the only two that really show up */
	        case R_PCRLONG:
		  *((int *) (text_and_data + coff_reloc.r_vaddr))
		    -= coff_sym_listp[coff_reloc.r_symndx].n_value;
		  break;
	        default:
		  error ("unknown relocation type 0%o", coff_reloc.r_type);
		}
	    }
	}
      /*
       ** >= 0 means its an extern - value is the output symbol #.
       ** < 0 means its an intern - value is N_TEXT, N_DATA or N_BSS.
       */
      if (symbol_map[coff_reloc.r_symndx] >= 0)
	{
	  reloc_infop->r_symbolnum = symbol_map[coff_reloc.r_symndx];
	  reloc_infop->r_extern = 1;
	} 
      else
	{
	  if (symbol_map[coff_reloc.r_symndx] == -1)
	    error ("Oops! possible bug - reloc reference to ignored symbol");
	  reloc_infop->r_symbolnum = -symbol_map[coff_reloc.r_symndx];
	  reloc_infop->r_extern = 0;
	}
      /*
       ** COFF address includes the section address - BSD doesn't, so
       ** subtract it out.
       */
      reloc_infop->r_address = coff_reloc.r_vaddr - section_headerp->s_vaddr;
      switch (coff_reloc.r_type)
	{
	case R_PCRLONG:
	  reloc_infop->r_pcrel = 1;
	  reloc_infop->r_length = 2; /* 4 bytes */
	  break;
	case R_DIR32:
	case R_RELLONG:
	  reloc_infop->r_pcrel = 0;
	  reloc_infop->r_length = 2;
	  break;
	default:
	  error ("can't handle coff reloction type 0%o", coff_reloc.r_type);
	}

      if (verbose_flag)
	printf ("reloc: addr = 0x%x, synum = %d\n",
		reloc_infop->r_address, reloc_infop->r_symbolnum);
      reloc_infop->r_pad = 0;
      ++reloc_infop;
    }
}
\f


void
error (format, va_alist)
     char *format;
     va_dcl
{
  va_list args;

  va_start (args);
  fprintf (stderr, "robotussin: ");
  vfprintf (stderr, format, args);
  putc ('\n', stderr);
  va_end (args);
  exit (1);
}

extern char *sys_errlist[];
extern int errno;

void
sys_error (format, va_alist)
     char *format;
     va_dcl
{
  va_list args;

  va_start (args);
  fprintf (stderr, "robotussin: ");
  vfprintf (stderr, format, args);
  fprintf (stderr, ": %s\n", sys_errlist[errno]);
  va_end (args);
  exit (1);
}

extern char *malloc ();

char *
mem_alloc (size)
     int size;
{
  char *pc;

  if ((pc = malloc (size)) == NULL)
    error ("memory exhausted!");
  return pc;
}

/* end */