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

SVR4patch.c

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

Click here to get the file

Size 7.1 kB - File type text/plain

File contents

/*ident	"@(#)cls4:Patch/SVR4patch.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.

THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System
Laboratories, Inc.  The copyright notice above does not evidence
any actual or intended publication of such source code.

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

 This code uses -lelf, the Unix system V functions for accessing ELF files.
	The program is passed one argument, the name of an executable
	C++ program.  It first reads the ELF 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.
***************************************************************/

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <libelf.h>

#define MAX_FILES 5000

void	fatal_error();
int	ScnhRead();
int	debug = 0;
int	found_main = 0;		/*1 iff _main() has been seen*/
char	*file;			/*Name of the file being patched*/


Elf32_Addr head = 0;		/*Adress of the __head symbol*/
Elf32_Off  data_infile;		/*offset in file of the data segment*/
Elf32_Addr data_pa;		/*physical adress of start of data segment*/
Elf32_Addr zero = 0;
Elf32_Addr previous;

Elf32_Addr addrs[MAX_FILES];	/*array of addresses of __link symbols*/
Elf32_Addr *addr_ptr = addrs;

main(argc , argv)
int argc;
char *argv[];
{
	Elf		*elf;
	Elf_Cmd		cmd;
	Elf32_Ehdr	*ehead;
	Elf32_Shdr	*shead;
	Elf32_Addr	*symbol;
	FILE*		fptr;
	int		fid, fid1;
	int		x_sym, undr, sym_cnt;
	int		strndx, symndx, symsz;

	if (argc == 3 && strcmp(argv[1], "-d")==0 ) {
		file = argv[2];
		debug = 1;
	} else if (argc == 2)
		file = argv[1];
	else
		fatal_error("usage: patch file");

	/* Try to open the file */
	if ( (fid = open(file, O_RDONLY)) < 0)
		fatal_error("cannot open file");
	fid1 = open(file, O_RDONLY); /* we need another fid opened on the
					same file in order to have an fid
					to pass to the elf_begin() function */

	/* Try to access the elf headers */
	if (elf_version(EV_CURRENT) == EV_NONE)
		fatal_error("Elf version out-of-date");

	cmd = ELF_C_READ;
	if ((elf = elf_begin(fid1, cmd, (Elf*)0)) == 0)
		fatal_error("cannot elf_begin file");

	if ((ehead = elf32_getehdr( elf )) == 0) {
		elf_end( elf );
		fatal_error("cannot get elf header");
	}

	strndx = ehead->e_shstrndx;

	if (ScnhRead( elf, strndx, ".data", &shead) == 0)
		fatal_error("cannot get .data header");
	
	/* Remember the start of data section, both the physical
	 * address at runtime, and the offset in the file
	 */
	data_infile = shead->sh_offset;
	data_pa = shead->sh_addr;

	if (debug) {
		printf("data in file: 0x%x\n", data_infile);
		printf("\taddr: 0x%x\n", data_pa);
	}

	/* Get the index of the symbol string table */
	if ((symndx = ScnhRead( elf, strndx, ".strtab", &shead)) == 0)
		fatal_error("cannot get .strtab header");

	/* Seek to the beginning of the symbol table*/
	if (ScnhRead( elf, strndx, ".symtab", &shead) == 0)
		fatal_error("cannot get symbol table");

	symsz = shead->sh_entsize;
	lseek( fid, shead->sh_offset, 0 );

	if (debug) {
		printf("symbol table in file: 0x%x\n", shead->sh_offset);
		printf("\taddr: 0x%x, num=%d\n", shead->sh_addr, shead->sh_info);
	}

	sym_cnt = shead->sh_size / symsz;

	/* Find the magic symbols in the a.out*/
        for ( x_sym = 0; x_sym < sym_cnt; ++x_sym ) {
		char	  *str;
		Elf32_Sym sym;

                /*read the symbol*/
		if ( read( fid, (char *)&sym, symsz ) != symsz)
			break;

		if (sym.st_value  == 0)
			continue;

		str = elf_strptr( elf, symndx, (size_t)sym.st_name);

 		undr=0;
		while ( str[0] == '_' ) { str++; undr++; }

		if (undr == 2) {
			if (strcmp(str, "head") == 0) {
				if (debug)
					printf("__head found at 0x%x\n", 
					sym.st_value);
				head = sym.st_value;
			}
			else if (strcmp(str, "link")==0) {
				if (addr_ptr >= addrs + MAX_FILES)
					fatal_error(" too many files");
				*addr_ptr++ = sym.st_value;
				if (debug)
					printf("__link found at 0x%x\n",
					       sym.st_value);
			}
		}
		else if (undr == 1 && strcmp(str, "main") == 0)
			found_main++;

	}

	if (!head) {
		if (found_main == 0)
			fatal_error("_main() not found");
		else
			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.
	 */
	elf_end( elf );
	close( fid );
	close( fid1 );

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

	if ( (fptr = fopen(file, "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.*/
		if(debug)
			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(Elf32_Addr), 1, fptr) == 0)
			fatal_error("can't write file");

		previous = *symbol - data_pa + data_infile;
	}

	/*Zero out the last symbol*/
	if(fseek(fptr, previous , 0))
		fatal_error("can't seek");

	if (fwrite((char *)&zero, sizeof(Elf32_Addr), 1, fptr) == 0)
		fatal_error("can't write");

	if(debug)
		printf("Write 0 at offset 0x%x\n", previous );

	fclose(fptr);

	exit(0);
}

void
fatal_error(message)
char * message;
{
	fprintf(stderr,"patch: file %s: %s\n", file, message);
	exit(-1);
}
	
int
ScnhRead( elf, strndx, sname, shead)
Elf* elf;
int  strndx;
char* sname;
Elf32_Shdr** shead;
{
	Elf_Scn	*scn = 0;
	int	idx = 0;

	while ((scn = elf_nextscn(elf, scn)) != 0) {
		idx++;
		if ((*shead = elf32_getshdr(scn)) != 0)
			if (strcmp(sname, elf_strptr(elf, strndx, (size_t)(*shead)->sh_name)) == 0)
				break;
	}

	return idx;
}
February 2013 »
Su Mo Tu We Th Fr Sa
1 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
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: