Personal tools
You are here: Home Projects C++ Cfront releases Release 3.0.3 source Patch BSDpatch.c
Document Actions


by Michael L Powell last modified 2007-01-26 03:25

Click here to get the file

Size 9.2 kB - File type text/plain

File contents

/*ident	"@(#)cls4:Patch/BSDpatch.c	1.3" */
C++ source for the C++ Language System, Release 3.0.  This product
is a new release of the original cfront developed in the computer
science research center of AT&T Bell Laboratories.

Copyright (c) 1993  UNIX System Laboratories, Inc.
Copyright (c) 1991, 1992 AT&T and UNIX System Laboratories, Inc.
Copyright (c) 1984, 1989, 1990 AT&T.  All Rights Reserved.

Laboratories, Inc.  The copyright notice above does not evidence
any actual or intended publication of such source code.

	- general speed up by reading symbol table at once
	- Added support for alliant compiler and linker
	- added support for entries of the form __link*
	  as well as just __link.  This provides support for generating
	  __link entries on machines in which static data symbols are
	  removed from the symbol table by the compiler if they are not
	  referenced.  (For example, by Alliant FX/C `optimizations')

/*patch: Patch an a.out to ensure that static constructors are called.
Currently this is in good-old-C.

	The program is passed one argument, the name of an executable
	C++ program.  It first reads the symbol table, remembering
	all symbols of the name __link.  
	  Each of these symbols points to a structure of the form:
		struct __linkl {
			struct __linkl *next;	//next link in the chain
			int (*ctor)();		//ptr to ctor function
			int (*dtor)();		//ptr to dtor function
	cfront puts one of these in each dot-o.  Patch finds them,
	and chains them together by writing
	(into the actual a.out) values for the "next"
	pointers.  A pointer to the start of the chain is written
	into the struct __linkl pointer named __head.
	 _main will follow this chain at runtime and 
	use the ctor and dtor function pointers to call the static
	ctors and dtors.

	The program allows a debug option: patch -d <filename>
#include <stdio.h>
#include <a.out.h>
#if mc300|ibm032
#include <sys/param.h>
#endif /* mc300|ibm032 */

void fatal_error();     /*prints error message and breaks*/
int debug = 0;          /*1 iff debug option set*/
int found_main = 0;	/*1 iff _main() has been seen*/
long head = 0;	        /*Address of the __head symbol*/
long data_infile;	/*offset in file of the data segment*/
long data_pa;	        /*physical address of start of data segment*/
long zero = 0;
long previous;		/*used to create links*/
char *filename;		/*Name of the file being patched*/

#define SUCCESS          0
#define FAILURE          1
#define HEADSZ          sizeof(struct exec)
#define BEGINNING        0   /*flag for reading, seeking, writing*/
#define ST_ENTRYSZ      sizeof(struct nlist)
#define N_SYMS(x)       x.a_syms/ST_ENTRYSZ  /*no. of syms in table*/
#define MAX_LINKS 5000  /*may need to increase*/
long addrs[MAX_LINKS];	/*array of addresses of __link symbols*/
long *addr_ptr = addrs;

int argc;
char *argv[];
	char *getname();	/*gets string from string table*/
	int stseek();           /*seeks to symbol table*/
	void data_addresses();  /*gets offset & physical address of data
				  section; depends on machine type*/
	struct exec header;     /*contains header info for a.out file*/
	FILE *fptr;
	long *symbol;		
	int x_sym;    	        /*index for accessing symbol table*/
        int n_syms;             /*number of symbols in table*/
        int sti_count = 0, std_count = 0,
            link_count = 0;     /*flags to check compilation*/
	struct nlist *syms;

       		/*Check for arguments*/
	if (argc == 3 && strcmp(argv[1], "-d")==0 )
		filename = argv[2];
		debug = 1;
	else if (argc == 2)
                filename = argv[1];
		fatal_error("usage: patch file");

		/*Try to open the file & get header info*/
	if ( (fptr = fopen(filename,"r")) == NULL)
		fatal_error("cannot open file");
	else  fread ((char *)&header, HEADSZ, 1, fptr);

		/*Get physical address of data section at
		  runtime and offset in a.out file*/
	data_addresses (header, &data_infile, &data_pa);

                /*Seek to beginning of symbol table*/
        if (stseek (fptr, header) == FAILURE)
                fatal_error("cannot get symbol table");

                /*Find the ___head and ___link variables in the a.out;
                  fill array addrs*/
        n_syms = N_SYMS(header);
	syms = (struct nlist *)malloc(sizeof(*syms)*n_syms);
	if (fread((char *)syms, ST_ENTRYSZ,n_syms,fptr) != n_syms)
	  fatal_error("error reading symbol table");
        for (x_sym=0; x_sym < n_syms; x_sym++)
            char *str;

                /*Read the symbol*/
            str = getname(fptr, header, syms[x_sym].n_un.n_strx);

	    if (*str++ != '_')
	    if ((str[0] == '_') && (str[1] == '_')) {
		str += 2;
		if (strcmp(str, "head") == 0)
		    if (debug)
			    printf("___head found at 0x%x\n",syms[x_sym].n_value);
		  head = syms[x_sym].n_value;

		else if (strncmp(str, "link",4) == 0)
		  if (addr_ptr >= addrs + MAX_LINKS)
		    fatal_error(" too many files");
		  *addr_ptr++ = syms[x_sym].n_value;
		  if (debug)
		    printf("%s found at 0x%x\n",str,syms[x_sym].n_value);

	    if (strcmp(str, "main") == 0)
            else if (debug)     
                if (strncmp(str,"_sti",4) == 0)
                else if (strncmp(str,"_std",4) == 0)
	if (!head)
		if (found_main == 0)
			fatal_error("_main() not found");
		fatal_error("Bad _main() loaded- libC probably not set up for patch");
			/*Now we have all of the __link pointers.
			  close the file, and reopen it for updating to
			  write the patches.  All hell will break loose
			  if someone writes the file in the meantime.*/

			/*If no symbols were found, quit*/
	if ( addr_ptr == addrs)
			printf("No __links found\n");

	if ( (fptr=fopen(filename, "r+")) == NULL)
		fatal_error(" can't reopen file");

			/*patch the first symbol*/
			/*seek to: physical adr. of symbol
				- physical adr of start of data
				+ file offset of start of data*/

	previous = head - data_pa + data_infile;

			/*Now, go thru the list of symbols. Each is
			  a pointer to the next link. Chain them up*/
			/*For non-obvious reasons, do this backwards.
			  This calls ctors from libraries first.*/

	for (symbol = addr_ptr - 1; symbol >= addrs; symbol --)
			/*Update the previous pointer to point to this one.*/
			printf("Write 0x%x at offset 0x%x\n",
			*symbol, previous );
		if (fseek(fptr, previous , 0))
			fatal_error("can't seek");
		if( fwrite((char *)symbol, sizeof(long), 1, fptr) == 0)
			fatal_error("can't write file");
		previous = *symbol - data_pa + data_infile;
	if (symbol>=addrs) { fprintf(stderr,"FX/C BUG!\n"); exit(1); }
			/*Zero out the last symbol*/
	if(fseek(fptr, previous , 0))
		fatal_error("can't seek");
	if (fwrite((char *)&zero, sizeof(long), 1, fptr) == 0)
		fatal_error("can't write");
	{	printf("Write 0 at offset 0x%x\n", previous );
		printf("sti_count = %d, std_count = %d, links = %d\n",
char * message;
	fprintf(stderr,"patch: file %s: %s\n", filename, message);

int stseek(fileptr, headinfo)
FILE *fileptr;
struct exec headinfo;
	if (!(fseek(fileptr, N_SYMOFF(headinfo), BEGINNING)))
		return (SUCCESS);

	else  return (FAILURE);

/*Return string associated with index in string table.*/
char *getname (fiptr, head, index)
FILE *fiptr;
struct exec head;
long index;
	static char *strings=0,*malloc();
	static int strsize=0;
	if (strings == 0) {
	    int nread;
	    if ((strings = malloc(strsize)) == 0)
		fatal_error("malloc error");
	    if (fseek(fiptr, N_STROFF(head), BEGINNING))
		    fatal_error("string table entry not found");
	    if ((nread=fread(strings,1,strsize,fiptr)) != strsize) {
		fatal_error("string table read error");
	if (index >= strsize) {
	    printf("index=%d, strsize=%d\n",index,strsize);
	    fatal_error("string seek past end");

void data_addresses(head, infile, pa)        
struct exec head;
long *infile, *pa;
#ifdef mc300
	*infile = HEADSZ + head.a_text;

	if ((head.a_magic==NMAGIC) || (head.a_magic==ZMAGIC))
		/*Data will appear at next address where mod 4K bytes is 0*/
		*pa = head.a_text - (head.a_text % NBPG) + NBPG;

        else if (head.a_magic==OMAGIC)
  		/*Old method; text not write-protected*/
		*pa = (head.a_text);
	else fatal_error("bad magic number");

#ifdef sun
	*infile = N_TXTOFF(head) + head.a_text;
	*pa = N_DATADDR(head);

#ifdef alliant
	*infile = N_TXTOFF(head) + head.a_text;
	*pa = head.a_data_addr;

#ifdef ibm032
	*infile = N_TXTOFF(head) + head.a_text;
	*pa = DATABASE;

#if defined(vax) || defined(tahoe)
	*infile = N_TXTOFF(head) + head.a_text;
	*pa = 	(head.a_magic==OMAGIC)
			? head.a_text
			: ((1023+head.a_text) & ~1023) ;

December 2012 »
Su Mo Tu We Th Fr Sa
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: