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