File contents
/*ident "@(#)cls4:Patch/patch.c 1.1" */
/*******************************************************************************
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) 1991 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 -lld, the Unix system V functions for accessing COFF files.
The program is passed one argument, the name of an executable
C++ program. It first reads the COFF 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 <stdio.h>
#include <filehdr.h>
#include <scnhdr.h>
#include <syms.h>
#include <ldfcn.h>
typedef long PHSADDR;
char *ldgetname();
void fatal_error();
int debug = 0;
int found_main = 0; /*1 iff _main() has been seen*/
PHSADDR head = 0; /*Adress of the __head symbol*/
PHSADDR data_infile; /*offset in file of the data segment*/
PHSADDR data_pa; /*physical adress of start of data segment*/
PHSADDR zero = 0;
PHSADDR previous;
char *file; /*Name of the file being patched*/
#define MAX_FILES 5000
PHSADDR addrs[MAX_FILES]; /*array of addresses of __link symbols*/
PHSADDR *addr_ptr = addrs;
main(argc , argv)
int argc;
char *argv[];
{
LDFILE *ldptr;
SCNHDR secthead;
FILE *fptr;
PHSADDR *symbol;
int x_sym, undr;
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 ( (ldptr = ldopen(file, NULL)) == NULL)
fatal_error("cannot open file");
/*Find the beginning of the .data section*/
if (ldnshread( ldptr, ".data", §head) == FAILURE)
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 = secthead.s_scnptr;
data_pa = secthead.s_paddr;
if (debug)
{
printf("data in file: 0x%x\n", data_infile);
printf("\taddr: 0x%x\n", data_pa);
}
/*seek to the beginning of the symbol table*/
if (ldtbseek(ldptr) == FAILURE)
fatal_error("cannot get symbol table");
/*Find the magic symbols in the a.out*/
#ifndef SYMR
for ( x_sym = 0; x_sym < HEADER(ldptr).f_nsyms; ++x_sym)
#else
for ( x_sym = 0; x_sym < SYMHEADER(ldptr).isymMax + SYMHEADER(ldptr).iextMax; ++x_sym)
#endif
{
char *str;
#ifndef SYMR
SYMENT sym;
#else
SYMR sym;
#endif
#ifndef SYMR
/*read the symbol*/
if ( FREAD( (char *)&sym, SYMESZ, 1, ldptr) != 1)
break;
#else
if (ldtbread(ldptr, x_sym, &sym) == FAILURE)
break;
#endif
str = ldgetname(ldptr,&sym);
#if vax || BSD
str++; /* skip extra underscore */
#endif
undr=0; while ( str[0] == '_' ) { str++; undr++; }
if (undr == 2) {
if (strcmp(str, "head") == 0)
{
#ifndef SYMR
if (debug)
printf("__head found at 0x%x\n",
sym.n_value);
head = sym.n_value;
#else
if (debug)
printf("__head found at 0x%x\n",
sym.value);
head = sym.value;
#endif
}
else if (strcmp(str, "link")==0)
{
if (addr_ptr >= addrs + MAX_FILES)
fatal_error(" too many files");
#ifndef SYMR
*addr_ptr++ = sym.n_value;
if (debug)
printf("__link found at 0x%x\n",
sym.n_value);
#else
*addr_ptr++ = sym.value;
if (debug)
printf("__link found at 0x%x\n",
sym.value);
#endif
}
}
else if (undr == 1 && strcmp(str, "main") == 0)
found_main++;
#ifndef SYMR
/*Skip auxiliary entries*/
if (sym.n_numaux)
{
x_sym += sym.n_numaux;
FSEEK(ldptr, sym.n_numaux*SYMESZ, 1);
}
#endif
}
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.*/
ldclose(ldptr);
/*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(PHSADDR), 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(PHSADDR), 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);
}