Home | History | Annotate | Line # | Download | only in crunchide
crunchide.c revision 1.5
      1  1.1  cgd /*
      2  1.3  cgd  * Copyright (c) 1997 Christopher G. Demetriou.  All rights reserved.
      3  1.1  cgd  * Copyright (c) 1994 University of Maryland
      4  1.1  cgd  * All Rights Reserved.
      5  1.1  cgd  *
      6  1.1  cgd  * Permission to use, copy, modify, distribute, and sell this software and its
      7  1.1  cgd  * documentation for any purpose is hereby granted without fee, provided that
      8  1.1  cgd  * the above copyright notice appear in all copies and that both that
      9  1.1  cgd  * copyright notice and this permission notice appear in supporting
     10  1.1  cgd  * documentation, and that the name of U.M. not be used in advertising or
     11  1.1  cgd  * publicity pertaining to distribution of the software without specific,
     12  1.1  cgd  * written prior permission.  U.M. makes no representations about the
     13  1.1  cgd  * suitability of this software for any purpose.  It is provided "as is"
     14  1.1  cgd  * without express or implied warranty.
     15  1.1  cgd  *
     16  1.1  cgd  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
     17  1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
     18  1.1  cgd  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19  1.1  cgd  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     20  1.1  cgd  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     21  1.1  cgd  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     22  1.1  cgd  *
     23  1.1  cgd  * Author: James da Silva, Systems Design and Analysis Group
     24  1.1  cgd  *			   Computer Science Department
     25  1.1  cgd  *			   University of Maryland at College Park
     26  1.1  cgd  */
     27  1.1  cgd /*
     28  1.1  cgd  * crunchide.c - tiptoes through an a.out symbol table, hiding all defined
     29  1.1  cgd  *	global symbols.  Allows the user to supply a "keep list" of symbols
     30  1.1  cgd  *	that are not to be hidden.  This program relies on the use of the
     31  1.1  cgd  * 	linker's -dc flag to actually put global bss data into the file's
     32  1.1  cgd  * 	bss segment (rather than leaving it as undefined "common" data).
     33  1.1  cgd  *
     34  1.1  cgd  * 	The point of all this is to allow multiple programs to be linked
     35  1.1  cgd  *	together without getting multiple-defined errors.
     36  1.1  cgd  *
     37  1.1  cgd  *	For example, consider a program "foo.c".  It can be linked with a
     38  1.1  cgd  *	small stub routine, called "foostub.c", eg:
     39  1.1  cgd  *	    int foo_main(int argc, char **argv){ return main(argc, argv); }
     40  1.1  cgd  *      like so:
     41  1.1  cgd  *	    cc -c foo.c foostub.c
     42  1.1  cgd  *	    ld -dc -r foo.o foostub.o -o foo.combined.o
     43  1.1  cgd  *	    crunchide -k _foo_main foo.combined.o
     44  1.1  cgd  *	at this point, foo.combined.o can be linked with another program
     45  1.1  cgd  * 	and invoked with "foo_main(argc, argv)".  foo's main() and any
     46  1.1  cgd  * 	other globals are hidden and will not conflict with other symbols.
     47  1.1  cgd  *
     48  1.1  cgd  * TODO:
     49  1.1  cgd  *	- resolve the theoretical hanging reloc problem (see check_reloc()
     50  1.1  cgd  *	  below). I have yet to see this problem actually occur in any real
     51  1.1  cgd  *	  program. In what cases will gcc/gas generate code that needs a
     52  1.1  cgd  *	  relative reloc from a global symbol, other than PIC?  The
     53  1.1  cgd  *	  solution is to not hide the symbol from the linker in this case,
     54  1.1  cgd  *	  but to generate some random name for it so that it doesn't link
     55  1.1  cgd  *	  with anything but holds the place for the reloc.
     56  1.1  cgd  *      - arrange that all the BSS segments start at the same address, so
     57  1.1  cgd  *	  that the final crunched binary BSS size is the max of all the
     58  1.1  cgd  *	  component programs' BSS sizes, rather than their sum.
     59  1.1  cgd  */
     60  1.1  cgd #include <unistd.h>
     61  1.1  cgd #include <stdio.h>
     62  1.1  cgd #include <stdlib.h>
     63  1.1  cgd #include <string.h>
     64  1.1  cgd #include <fcntl.h>
     65  1.1  cgd #include <a.out.h>
     66  1.1  cgd #include <sys/types.h>
     67  1.1  cgd #include <sys/stat.h>
     68  1.1  cgd #include <sys/errno.h>
     69  1.1  cgd 
     70  1.4  cgd #include "extern.h"
     71  1.4  cgd 
     72  1.1  cgd char *pname = "crunchide";
     73  1.1  cgd 
     74  1.1  cgd void usage(void);
     75  1.1  cgd 
     76  1.1  cgd void add_to_keep_list(char *symbol);
     77  1.1  cgd void add_file_to_keep_list(char *filename);
     78  1.1  cgd 
     79  1.3  cgd int hide_syms(const char *filename);
     80  1.1  cgd 
     81  1.3  cgd int verbose;
     82  1.1  cgd 
     83  1.1  cgd int main(argc, argv)
     84  1.1  cgd int argc;
     85  1.1  cgd char **argv;
     86  1.1  cgd {
     87  1.3  cgd     int ch, errors;
     88  1.1  cgd 
     89  1.1  cgd     if(argc > 0) pname = argv[0];
     90  1.1  cgd 
     91  1.3  cgd     while ((ch = getopt(argc, argv, "k:f:v")) != EOF)
     92  1.1  cgd 	switch(ch) {
     93  1.1  cgd 	case 'k':
     94  1.1  cgd 	    add_to_keep_list(optarg);
     95  1.1  cgd 	    break;
     96  1.1  cgd 	case 'f':
     97  1.1  cgd 	    add_file_to_keep_list(optarg);
     98  1.1  cgd 	    break;
     99  1.3  cgd 	case 'v':
    100  1.3  cgd 	    verbose = 1;
    101  1.3  cgd 	    break;
    102  1.1  cgd 	default:
    103  1.1  cgd 	    usage();
    104  1.1  cgd 	}
    105  1.1  cgd 
    106  1.1  cgd     argc -= optind;
    107  1.1  cgd     argv += optind;
    108  1.1  cgd 
    109  1.1  cgd     if(argc == 0) usage();
    110  1.1  cgd 
    111  1.3  cgd     errors = 0;
    112  1.1  cgd     while(argc) {
    113  1.3  cgd 	if (hide_syms(*argv))
    114  1.3  cgd 		errors = 1;
    115  1.1  cgd 	argc--, argv++;
    116  1.1  cgd     }
    117  1.1  cgd 
    118  1.3  cgd     return errors;
    119  1.1  cgd }
    120  1.1  cgd 
    121  1.1  cgd void usage(void)
    122  1.1  cgd {
    123  1.1  cgd     fprintf(stderr,
    124  1.1  cgd 	    "Usage: %s [-k <symbol-name>] [-f <keep-list-file>] <files> ...\n",
    125  1.1  cgd 	    pname);
    126  1.1  cgd     exit(1);
    127  1.1  cgd }
    128  1.1  cgd 
    129  1.1  cgd /* ---------------------------- */
    130  1.1  cgd 
    131  1.1  cgd struct keep {
    132  1.1  cgd     struct keep *next;
    133  1.1  cgd     char *sym;
    134  1.1  cgd } *keep_list;
    135  1.1  cgd 
    136  1.1  cgd void add_to_keep_list(char *symbol)
    137  1.1  cgd {
    138  1.1  cgd     struct keep *newp, *prevp, *curp;
    139  1.1  cgd     int cmp;
    140  1.1  cgd 
    141  1.1  cgd     for(curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next)
    142  1.1  cgd 	if((cmp = strcmp(symbol, curp->sym)) <= 0) break;
    143  1.1  cgd 
    144  1.1  cgd     if(curp && cmp == 0)
    145  1.1  cgd 	return;	/* already in table */
    146  1.1  cgd 
    147  1.1  cgd     newp = (struct keep *) malloc(sizeof(struct keep));
    148  1.1  cgd     if(newp) newp->sym = strdup(symbol);
    149  1.1  cgd     if(newp == NULL || newp->sym == NULL) {
    150  1.1  cgd 	fprintf(stderr, "%s: out of memory for keep list\n", pname);
    151  1.1  cgd 	exit(1);
    152  1.1  cgd     }
    153  1.1  cgd 
    154  1.1  cgd     newp->next = curp;
    155  1.1  cgd     if(prevp) prevp->next = newp;
    156  1.1  cgd     else keep_list = newp;
    157  1.1  cgd }
    158  1.1  cgd 
    159  1.3  cgd int in_keep_list(const char *symbol)
    160  1.1  cgd {
    161  1.1  cgd     struct keep *curp;
    162  1.1  cgd     int cmp;
    163  1.1  cgd 
    164  1.1  cgd     for(curp = keep_list; curp; curp = curp->next)
    165  1.1  cgd 	if((cmp = strcmp(symbol, curp->sym)) <= 0) break;
    166  1.1  cgd 
    167  1.1  cgd     return curp && cmp == 0;
    168  1.1  cgd }
    169  1.1  cgd 
    170  1.1  cgd void add_file_to_keep_list(char *filename)
    171  1.1  cgd {
    172  1.1  cgd     FILE *keepf;
    173  1.1  cgd     char symbol[1024];
    174  1.1  cgd     int len;
    175  1.1  cgd 
    176  1.1  cgd     if((keepf = fopen(filename, "r")) == NULL) {
    177  1.1  cgd 	perror(filename);
    178  1.1  cgd 	usage();
    179  1.1  cgd     }
    180  1.1  cgd 
    181  1.1  cgd     while(fgets(symbol, 1024, keepf)) {
    182  1.1  cgd 	len = strlen(symbol);
    183  1.1  cgd 	if(len && symbol[len-1] == '\n')
    184  1.1  cgd 	    symbol[len-1] = '\0';
    185  1.1  cgd 
    186  1.1  cgd 	add_to_keep_list(symbol);
    187  1.1  cgd     }
    188  1.1  cgd     fclose(keepf);
    189  1.1  cgd }
    190  1.1  cgd 
    191  1.3  cgd /* ---------------------------- */
    192  1.1  cgd 
    193  1.3  cgd struct {
    194  1.3  cgd 	const char *name;
    195  1.3  cgd 	int	(*check)(int, const char *);	/* 1 if match, zero if not */
    196  1.3  cgd 	int	(*hide)(int, const char *);	/* non-zero if error */
    197  1.3  cgd } exec_formats[] = {
    198  1.3  cgd #ifdef NLIST_AOUT
    199  1.3  cgd 	{	"a.out",	check_aout,	hide_aout,	},
    200  1.3  cgd #endif
    201  1.5  cgd #ifdef NLIST_ECOFF
    202  1.5  cgd 	{	"ECOFF",	check_ecoff,	hide_ecoff,	},
    203  1.5  cgd #endif
    204  1.3  cgd #ifdef NLIST_ELF32
    205  1.3  cgd 	{	"ELF32",	check_elf32,	hide_elf32,	},
    206  1.3  cgd #endif
    207  1.3  cgd #ifdef NLIST_ELF64
    208  1.3  cgd 	{	"ELF64",	check_elf64,	hide_elf64,	},
    209  1.2   pk #endif
    210  1.3  cgd };
    211  1.1  cgd 
    212  1.3  cgd int hide_syms(const char *filename)
    213  1.1  cgd {
    214  1.3  cgd 	int fd, i, n, rv;
    215  1.1  cgd 
    216  1.3  cgd 	fd = open(filename, O_RDWR, 0);
    217  1.3  cgd 	if (fd == -1) {
    218  1.3  cgd 		perror(filename);
    219  1.3  cgd 		return 1;
    220  1.3  cgd 	}
    221  1.1  cgd 
    222  1.3  cgd 	rv = 0;
    223  1.1  cgd 
    224  1.3  cgd         n = sizeof exec_formats / sizeof exec_formats[0];
    225  1.3  cgd         for (i = 0; i < n; i++) {
    226  1.3  cgd 		if (lseek(fd, 0, SEEK_SET) != 0) {
    227  1.3  cgd 			perror(filename);
    228  1.3  cgd 			goto err;
    229  1.3  cgd 		}
    230  1.3  cgd                 if ((*exec_formats[i].check)(fd, filename) != 0)
    231  1.3  cgd                         break;
    232  1.3  cgd 	}
    233  1.3  cgd 	if (i == n) {
    234  1.4  cgd 		fprintf(stderr, "%s: unknown executable format\n", filename);
    235  1.3  cgd 		goto err;
    236  1.3  cgd 	}
    237  1.1  cgd 
    238  1.3  cgd 	if (verbose)
    239  1.3  cgd 		fprintf(stderr, "%s is an %s binary\n", filename,
    240  1.3  cgd 		    exec_formats[i].name);
    241  1.3  cgd 
    242  1.3  cgd 	if (lseek(fd, 0, SEEK_SET) != 0) {
    243  1.3  cgd 		perror(filename);
    244  1.3  cgd 		goto err;
    245  1.3  cgd 	}
    246  1.3  cgd 	rv = (*exec_formats[i].hide)(fd, filename);
    247  1.1  cgd 
    248  1.3  cgd out:
    249  1.3  cgd 	close (fd);
    250  1.3  cgd 	return (rv);
    251  1.3  cgd 
    252  1.3  cgd err:
    253  1.3  cgd 	rv = 1;
    254  1.3  cgd 	goto out;
    255  1.1  cgd }
    256