home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
zip
/
gnu
/
utlsrc33.lzh
/
UTLSRC33
/
STRIP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-30
|
17KB
|
748 lines
/*
* strip TOS executable format files of symbol table info
* usage: strip {-g | -k | -l names} [-t] files ...
*
* Original version by ++jrb bammi@dsrgsun.ces.cwru.edu
* (i.e. Jwahar Bammi)
* Modified to add extra options -g -k and -l by
* Michal Jaegermann ntomczak@ualtavm.bitnet
* November 1st, 1990
*
* -g keep all global symbols
* -k keep _stksize symbol, so stack size can be adjusted
* even for nearly-stripped gcc produced executables
* -l nms keep all symbols listed in a file 'nms'
* -t remove additional data from end of file
*
* Modified sources compile both with gcc and Sozobon C
*
* Added code to deal correctly with extended symbols produced
* by -G option of gcc
* Both -k and -l options convert extended symbols into
* regular ones.
*
* ++jrb 4/25/91:
* Macroized the code to take care of WORD_ALIGNED cross environments.
* Minor fixes for a !atari !gcc compiler.
*
* AL 08/02/92: (alexlehm@iti.informatik.th-darmstadt.de)
* Added -t option to strip TurboC / PureC style executables
* Support for little endian (BYTE_SWAPed) machines
*/
#include <stdio.h>
#ifdef atarist
#ifdef __GNUC__
# include <stddef.h>
# include <memory.h>
# include <unixlib.h>
#else
#include <malloc.h>
extern long lread();
extern long lwrite();
extern long lseek();
#endif
#endif
#ifdef unix
# include <strings.h>
# define lwrite write
# define lread read
extern char *malloc(), *realloc();
#else
# include <string.h>
#endif
#include <fcntl.h>
#define NEWBUFSIZ 16384L
char mybuf[NEWBUFSIZ];
char tmpname[128];
#define SYMLEN 8
#define GST_SYMLEN 22
typedef char symstr_t[GST_SYMLEN];
symstr_t stklist[] = {"__stksize", "__initial_stack"};
#ifdef atarist
long _stksize = 1L;
#endif
#ifndef __PROTO
# if __STDC__ || __cplusplus
# define __PROTO(s) s
# else
# define __PROTO(s) ()
# endif
#endif
/* function pointer type for the select functions */
typedef long (*select_fp) __PROTO((int, int, long, symstr_t *));
void usage __PROTO((char *s ));
int main __PROTO((int argc , char **argv ));
int strip __PROTO((char *name,symstr_t *nmlist,select_fp select,int cuttrail));
long copy __PROTO((int from , int to , long bytes ));
long copy_relo __PROTO((char *name,int from,int to));
void report __PROTO((char *s ));
symstr_t *mklist __PROTO((char *fname ));
long sel_globs __PROTO((int fd , int tfd , long sbytes , symstr_t *nmlist ));
long sel_listed __PROTO((int fd , int tfd , long sbytes , symstr_t *nmlist ));
extern char *getenv __PROTO((const char *));
int
main (argc, argv)
int argc;
char **argv;
{
int status = 0;
int flag = -1;
int cuttrail = 0;
symstr_t *nmlist = (symstr_t *) 0;
select_fp select=(select_fp)NULL;
#ifdef atarist
char *tmpdir;
register int l;
#endif
/* process arguments */
while (argv++, --argc) {
if ('-' != **argv)
break;
(*argv)++;
if( **argv=='t' ) {
cuttrail = 1;
} else {
if ((-1) != flag)
usage ("only one option at a time is accepted\n");
flag = **argv;
switch (flag) {
case 'g':
select = sel_globs;
break;
case 'k':
nmlist = stklist;
select = sel_listed;
break;
case 'l':
(*argv)++;
if ('\0' == **argv) {
--argc;
argv++;
if( argc==0 )
usage("missing names file\n");
}
if ((symstr_t *) NULL == (nmlist = mklist (*argv)))
usage ("cannot create a list of reserved names\n");
select = sel_listed;
break;
default:
usage ("");
break;
}
}
}
if (argc < 1) {
usage ("");
}
#ifdef __GNUC__
#ifdef atarist
tmpname[0] = '\0';
if ((tmpdir = getenv ("TEMP")) != NULL) {
strcpy (tmpname, tmpdir);
l = (int) strlen (tmpname) - 1;
if (tmpname[l] == '\\')
tmpname[l] = '\0';
}
strcat (tmpname, "\\STXXXXXX");
#else
strcpy (tmpname, "/tmp/STXXXXXX");
#endif
mktemp (tmpname);
#else /* not __GNUC__ */
# ifdef atarist
if ((tmpdir = getenv ("TEMP")) != NULL) {
strcpy (tmpname, tmpdir);
l = (int) strlen (tmpname) - 1;
if (tmpname[l] != '\\') {
l++;
tmpname[l] = '\\';
}
l++;
}
else {
l = 0;
}
tmpnam (&tmpname[l]);
# else
strcpy (tmpname, "/tmp/STXXXXXX");
mktemp(tmpname);
# endif
#endif /* __GNUC__ */
do {
status |= strip (*argv++, nmlist, select, cuttrail);
} while (--argc > 0);
unlink (tmpname);
return status;
}
void
usage (s)
char *s;
{
report (s);
report ("Usage: strip {-k | -l names | -g} [-t] files ...\n");
exit (1);
}
/* define macro for big and function for little endian machines */
#ifdef BYTE_SWAP
short swap_short __PROTO((short s));
long swap_long __PROTO((long l));
#else
#define swap_short(s) (s)
#define swap_long(l) (l)
#endif
#if (defined(__GNUC__)) && (!defined(unix))
#include <st-out.h>
#else
/* include relevant fragments of <st-out.h> file directly */
struct aexec {
short a_magic; /* magic number */
unsigned long a_text; /* size of text segment */
unsigned long a_data; /* size of initialized data */
unsigned long a_bss; /* size of uninitialized data */
unsigned long a_syms; /* size of symbol table */
unsigned long a_AZero1; /* always zero */
unsigned long a_AZero2; /* always zero */
unsigned short a_isreloc; /* is reloc info present */
};
#define CMAGIC 0x601A /* contiguous text */
/*
* Format of a symbol table entry
*/
struct asym
{
char a_name[SYMLEN]; /* symbol name */
unsigned short a_type; /* type flag */
unsigned long a_value; /* value of this symbol
(or sdb offset) */
};
#define A_GLOBL 0x2000 /* global */
#define A_LNAM 0x0048 /* extended name */
#endif /* __GNUC__ */
#if !__STDC__ && !__cplusplus
# ifndef offsetof
# define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0L)->MEMBER)
# endif
# ifndef CROSSHPUX
typedef unsigned long size_t;
# endif
#endif
#ifdef WORD_ALIGNED
# define SIZEOF_AEXEC ((2*sizeof(short)) + (6*sizeof(long)))
# define SIZEOF_ASYM ((SYMLEN*sizeof(char)) + sizeof(short) + sizeof(long))
# define SYM_OFFSET (sizeof(short) + (3*sizeof(long)))
int read_head __PROTO((int fd, struct aexec *a));
#else
# define SIZEOF_AEXEC (sizeof(struct aexec))
# define SIZEOF_ASYM (sizeof(struct asym))
# define SYM_OFFSET (offsetof (struct aexec, a_syms))
#endif
int
strip (name, nmlist, select, cuttrail)
char *name;
symstr_t * nmlist;
select_fp select;
int cuttrail;
{
register int fd;
register int tfd;
register long count, rbytes, sbytes;
long lbytes, swap_lbytes;
struct aexec ahead;
if ((fd = open (name, O_RDONLY, 0666)) < 0) {
perror (name);
return 2;
}
if ((tfd = open (tmpname, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) {
perror (tmpname);
close (fd);
return 4;
}
#ifndef WORD_ALIGNED
if ((count = lread (fd, &ahead, (long) sizeof (ahead)))
!= (long) sizeof (ahead)) {
#else
if (read_head (fd, &ahead)) {
#endif
perror (name);
close (tfd);
close (fd);
return 8;
}
if (swap_short(ahead.a_magic)!=CMAGIC) {
report (name);
report (": Bad Magic number\n");
close (tfd);
close (fd);
return 0x10;
}
sbytes = swap_long(ahead.a_syms);
if (0L == sbytes && !cuttrail) {
report (name);
report (": Already Stripped\n");
close (tfd);
close (fd);
return 0x20;
}
if (lseek (fd, 0L, 0) < 0) {
report (name);
report (": seek error\n");
close (tfd);
close (fd);
return 0x40;
}
count = SIZEOF_AEXEC + swap_long(ahead.a_text) + swap_long(ahead.a_data);
if (copy (fd, tfd, count) != count) {
close (tfd);
close (fd);
return 0x80;
}
if (NULL == select) { /* remove whole symbol table */
lbytes = 0L;
if (lseek (fd, sbytes, 1) < 0) {
report (name);
report (": seek error\n");
close (tfd);
close (fd);
return 0x100;
}
}
else {
lbytes = ( *select )(fd, tfd, sbytes, nmlist);
}
if( cuttrail ) {
if((rbytes = copy_relo(name,fd,tfd))<0) {
close(tfd);
close(fd);
return 0x8000;
}
if( lread( fd, &cuttrail, 1 )!=1 ) {
report (name);
report (": Already Stripped\n");
close (tfd);
close (fd);
return 0x20;
}
} else {
if ((rbytes = copy (fd, tfd, 0x7fffffffL)) < 0) {
close (tfd);
close (fd);
return 0x200;
}
}
if (lseek (tfd, (long)(SYM_OFFSET), 0) < 0) {
close (tfd);
close (fd);
return 0x400;
}
swap_lbytes=swap_long(lbytes);
if (lwrite (tfd, &swap_lbytes, (long)sizeof (lbytes)) !=
(long) sizeof (lbytes)) {
close (tfd);
close (fd);
return 0x800;
}
close (tfd);
close (fd);
if (rename(tmpname, name) == 0) return 0; /* try to rename it */
if ((fd = open (name, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0) {
perror (name);
return 0x1000;
}
if ((tfd = open (tmpname, O_RDONLY, 0666)) < 0) {
perror (tmpname);
close (fd);
return 0x2000;
}
count = SIZEOF_AEXEC + swap_long(ahead.a_text) + swap_long(ahead.a_data) + rbytes + lbytes;
if (copy (tfd, fd, count) != count) {
close (tfd);
close (fd);
return 0x4000;
}
close (tfd);
close (fd);
return 0;
}
/*
* copy from, to in NEWBUFSIZ chunks upto bytes or EOF whichever occurs first
* returns # of bytes copied
*/
long
copy (from, to, bytes)
int from, to;
long bytes;
{
register long todo, done = 0L, remaining = bytes, actual;
while (done != bytes) {
todo = (remaining > NEWBUFSIZ) ? NEWBUFSIZ : remaining;
if ((actual = lread (from, mybuf, todo)) != todo) {
if (actual < 0) {
report ("Error Reading\n");
return -done;
}
}
if (lwrite (to, mybuf, actual) != actual) {
report ("Error Writing\n");
return -done;
}
done += actual;
if (actual != todo) /* eof reached */
return done;
remaining -= actual;
}
return done;
}
/* copy TOS relocation table from `from` to `to`. Copy bytes until NUL byte or
first 4 bytes if == 0l.
returns length of relocation table or -1 in case of an error */
long
copy_relo(name,from,to)
char *name;
int from,to;
{
long res=0;
long bytes;
char *end;
int finished=0;
res=lread( from, mybuf, sizeof(long) );
if( res!=0 && res!=sizeof(long) ) {
report( "Error reading\n" );
return -1;
}
if( res==0 ) {
report("Warning: "); /* I think empty relocation tables are allowed,
report(name); but could cause trouble with certain programs */
report( ": No relocation table\n" );
return 0;
}
if( lwrite(to,mybuf,res)!=res ) {
report(name);
report( ": Error writing\n" );
return -1;
}
res=sizeof(long);
if( *(long*)mybuf == 0 ) return res; /* This is a clean version of an empty
relocation table */
while(!finished) {
if( (bytes=lread(from,mybuf,NEWBUFSIZ))<0 ) {
report(name);
report( ": Error reading\n" );
return -1;
}
if( bytes==0 ) {
report( "Warning: " );
report(name);
report( ": Unterminated relocation table\n" );
return res;
}
/* dont know if sozobon has memchr */
end=memchr(mybuf,0,bytes);
if(end) {
bytes=end-mybuf+1;
finished=1;
}
if( lwrite(to,mybuf,bytes)!=bytes ) {
report(name);
report(": Error writing\n");
return -1;
}
}
}
void
report (s)
char * s;
{
lwrite (2, s, (long) strlen (s));
}
/*
* Given a name of a file with reserved symbols create an array of
* reserved symbol names. To terminate create an entry which starts
* with a null character.
*/
#define LBUFSIZE 128
#define NMSTEP 10
symstr_t *
mklist (fname)
char * fname;
{
FILE *fp;
symstr_t *list = (symstr_t *) NULL;
int left = 0;
int pos = 0;
int i;
size_t max_size = 1;
char lbuf[LBUFSIZE];
char *in, *out;
#ifdef atarist
if (NULL == (fp = fopen (fname, "rt"))) {
#else
if (NULL == (fp = fopen (fname, "r"))) {
#endif
report (fname);
report (" -- ");
usage ("cannot open this file\n");
}
while (NULL != fgets (lbuf, LBUFSIZE, fp)) {
if (0 == left) {
max_size += NMSTEP;
if ((symstr_t *) NULL == list) {
list = (symstr_t *) malloc ( max_size * sizeof (symstr_t));
}
else {
list = (symstr_t *) realloc ((void *) list,
max_size * sizeof (symstr_t));
}
if ((symstr_t *) NULL == list) {
report ("out of memory making symbol list\n");
exit (-3);
}
left = NMSTEP;
}
/* strip all leading white space */
in = lbuf;
while (' ' == *in || '\t' == *in)
in++;
if ('\n' == *in)
continue; /* empty line - skip it */
out = &list[pos][0];
for (i = GST_SYMLEN; i > 0; --i) {
if ('\n' == *in || ' ' == *in || '\t' == *in) {
while (i-- > 0) *out++ = '\0';
break;
}
*out++ = *in++;
}
pos++;
--left;
} /* while */
if ((symstr_t *) NULL != list) {
list[pos][0] = '\0'; /* terminate created list */
}
return (list);
}
/*
* From a file handle fd to a file handle tfd copy up to 'sbytes' bytes
* of a symbol table selecting only those symbols which have A_GLOBL
* flag set. Table nmlist is not really used, but is here for a uniform
* interface. Returns a number of bytes copied.
*/
long
sel_globs (fd, tfd, sbytes, nmlist)
int fd, tfd;
long sbytes;
symstr_t * nmlist;
{
long lbytes = 0;
struct asym cur_sym;
int cont = 0;
while (sbytes) {
if ((long)SIZEOF_ASYM != lread (fd, &cur_sym,
(long)SIZEOF_ASYM)) {
report ("error on reading symbol table\n");
break;
}
if (0 == cont) { /* if we are not dealing with the second part */
cont = (0 != (swap_short(cur_sym.a_type) & A_LNAM));
if (swap_short(cur_sym.a_type) & A_GLOBL) {
cont = -cont;
if ((long)SIZEOF_ASYM != lwrite (tfd, &cur_sym,
(long)SIZEOF_ASYM)) {
report ("error on writing symbol table\n");
break;
}
lbytes += SIZEOF_ASYM;
}
}
else { /* this was an extended symbol */
if (cont < 0) { /* if global then write */
if ((long)SIZEOF_ASYM != lwrite (tfd, &cur_sym,
(long)SIZEOF_ASYM)) {
report ("error on writing symbol table\n");
break;
}
lbytes += SIZEOF_ASYM;
}
cont = 0;
}
sbytes -= SIZEOF_ASYM;
}
return (lbytes);
}
/*
* From a file handle fd to a file handle tfd copy up to 'sbytes' bytes
* of a symbol table selecting only those symbols which are on nmlist.
* Free nmlist if different from a default global one.
* Returns a number of bytes copied.
*/
long
sel_listed (fd, tfd, sbytes, nmlist)
int fd, tfd;
long sbytes;
symstr_t * nmlist;
{
long lbytes = 0;
symstr_t *kname;
struct asym cur_sym, spare;
if ((symstr_t *) NULL == nmlist)
return (0L);
while (sbytes) {
if ((long)SIZEOF_ASYM != lread (fd, &cur_sym,
(long) SIZEOF_ASYM)) {
report ("error on reading symbol table\n");
break;
}
for (kname = nmlist; '\0' != **kname; kname++) {
if (0 == strncmp (&(*kname)[0], &cur_sym.a_name[0], SYMLEN)) {
if ((A_LNAM & swap_short(cur_sym.a_type)) == A_LNAM) { /* if extended */
if ((long)SIZEOF_ASYM != lread (fd, &spare,
(long)SIZEOF_ASYM)) {
report ("error on reading symbol table\n");
goto leave; /* skip two loop levels */
}
sbytes -= SIZEOF_ASYM;
if (strncmp (&(*kname)[SYMLEN], (char *)&spare,
GST_SYMLEN-SYMLEN))
continue;
}
if ((long)SIZEOF_ASYM != lwrite (tfd, &cur_sym,
(long)SIZEOF_ASYM)) {
report ("error on writing symbol table\n");
goto leave;
}
if ((swap_short(cur_sym.a_type) & A_LNAM) == A_LNAM)
{
if (lwrite (tfd, &spare, (long)SIZEOF_ASYM) != SIZEOF_ASYM)
{
report ("error on writing symbol table\n");
goto leave;
}
lbytes += SIZEOF_ASYM;
}
lbytes += SIZEOF_ASYM;
break;
}
} /* for */
sbytes -= SIZEOF_ASYM;
} /* while */
leave:
if (nmlist != stklist) {
free (nmlist);
nmlist = (symstr_t *) NULL;
}
return (lbytes);
}
#ifdef WORD_ALIGNED
/*
* read header -- return !0 on err
*/
#define ck_read(fd, addr, siz) \
if((long)siz != lread(fd, addr, (long)siz)) return !0;
int read_head (fd, a)
int fd;
struct aexec *a;
{
ck_read(fd, &a->a_magic, sizeof(a->a_magic));
ck_read(fd, &a->a_text, sizeof(a->a_text));
ck_read(fd, &a->a_data, sizeof(a->a_data));
ck_read(fd, &a->a_bss, sizeof(a->a_bss));
ck_read(fd, &a->a_syms, sizeof(a->a_syms));
ck_read(fd, &a->a_AZero1, sizeof(a->a_AZero1));
ck_read(fd, &a->a_AZero2, sizeof(a->a_AZero2));
ck_read(fd, &a->a_isreloc, sizeof(a->a_isreloc));
return 0;
}
#endif
#ifdef CROSSHPUX
char *xmalloc(n)
unsigned n;
{
extern char *malloc();
char *ret = malloc(n);
if(!ret)
{
fprintf(stderr,"Out of memory!\n");
exit(1);
}
return ret;
}
#endif
#ifdef BYTE_SWAP
/* these routines work for big endian machines as well, but are not needed */
long swap_long(l)
long l;
{
long l1=l;
unsigned char *p=(unsigned char *)&l1;
return (long)p[3]|((long)p[2]<<8)|((long)p[1]<<16)|((long)p[0]<<24);
}
short swap_short(s)
short s;
{
short s1=s;
unsigned char *p=(unsigned char *)&s1;
return (short)p[1]|((short)p[0]<<8);
}
#endif