Home | History | Annotate | Line # | Download | only in crunchide
      1  1.14    joerg /* $NetBSD: crunchide.c,v 1.14 2011/08/30 23:15:14 joerg 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.13       he  * crunchide.c - tiptoes through a 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.14    joerg __RCSID("$NetBSD: crunchide.c,v 1.14 2011/08/30 23:15:14 joerg 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 <sys/types.h>
     76   1.1      cgd #include <sys/stat.h>
     77   1.1      cgd 
     78   1.4      cgd #include "extern.h"
     79   1.4      cgd 
     80  1.14    joerg __dead static void usage(void);
     81   1.1      cgd 
     82  1.14    joerg static void add_to_keep_list(char *symbol);
     83  1.14    joerg static void add_file_to_keep_list(char *filename);
     84   1.1      cgd 
     85  1.14    joerg static int hide_syms(const char *filename);
     86   1.1      cgd 
     87  1.14    joerg static int verbose;
     88   1.1      cgd 
     89  1.12      wiz int
     90  1.12      wiz main(int argc, char *argv[])
     91   1.1      cgd {
     92  1.12      wiz 	int ch, errors;
     93   1.1      cgd 
     94  1.12      wiz 	setprogname(argv[0]);
     95   1.1      cgd 
     96  1.12      wiz 	while ((ch = getopt(argc, argv, "k:f:v")) != -1)
     97  1.12      wiz 		switch(ch) {
     98  1.12      wiz 		case 'k':
     99  1.12      wiz 			add_to_keep_list(optarg);
    100  1.12      wiz 			break;
    101  1.12      wiz 		case 'f':
    102  1.12      wiz 			add_file_to_keep_list(optarg);
    103  1.12      wiz 			break;
    104  1.12      wiz 		case 'v':
    105  1.12      wiz 			verbose = 1;
    106  1.12      wiz 			break;
    107  1.12      wiz 		default:
    108  1.12      wiz 			usage();
    109  1.12      wiz 		}
    110   1.1      cgd 
    111  1.12      wiz 	argc -= optind;
    112  1.12      wiz 	argv += optind;
    113   1.1      cgd 
    114  1.12      wiz 	if (argc == 0)
    115  1.12      wiz 		usage();
    116   1.1      cgd 
    117  1.12      wiz 	errors = 0;
    118  1.12      wiz 	while (argc) {
    119  1.12      wiz 		if (hide_syms(*argv))
    120  1.12      wiz 			errors = 1;
    121  1.12      wiz 		argc--, argv++;
    122  1.12      wiz 	}
    123   1.1      cgd 
    124  1.12      wiz 	return errors;
    125   1.1      cgd }
    126   1.1      cgd 
    127  1.14    joerg static void
    128  1.12      wiz usage(void)
    129   1.1      cgd {
    130  1.12      wiz 	fprintf(stderr,
    131  1.12      wiz 		"Usage: %s [-k keep-symbol] [-f keep-list-file] object-file\n"
    132  1.12      wiz 		"\t\t [object-file ...]\n",
    133  1.12      wiz 		getprogname());
    134  1.12      wiz 	exit(1);
    135   1.1      cgd }
    136   1.1      cgd 
    137   1.1      cgd /* ---------------------------- */
    138   1.1      cgd 
    139  1.14    joerg static struct keep {
    140  1.12      wiz 	struct keep *next;
    141  1.12      wiz 	char *sym;
    142   1.1      cgd } *keep_list;
    143   1.1      cgd 
    144  1.14    joerg static void
    145  1.12      wiz add_to_keep_list(char *symbol)
    146   1.1      cgd {
    147  1.12      wiz 	struct keep *newp, *prevp, *curp;
    148  1.12      wiz 	int cmp;
    149   1.7  hannken 
    150  1.12      wiz 	cmp = 0;
    151   1.1      cgd 
    152  1.12      wiz 	for (curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next)
    153  1.12      wiz 		if ((cmp = strcmp(symbol, curp->sym)) <= 0)
    154  1.12      wiz 			break;
    155  1.12      wiz 
    156  1.12      wiz 	if (curp && cmp == 0)
    157  1.12      wiz 		return;	/* already in table */
    158  1.12      wiz 
    159  1.12      wiz 	newp = (struct keep *) malloc(sizeof(struct keep));
    160  1.12      wiz 	if (newp)
    161  1.12      wiz 		newp->sym = strdup(symbol);
    162  1.12      wiz 	if (newp == NULL || newp->sym == NULL) {
    163  1.12      wiz 		fprintf(stderr, "%s: out of memory for keep list\n", getprogname());
    164  1.12      wiz 		exit(1);
    165  1.12      wiz 	}
    166   1.1      cgd 
    167  1.12      wiz 	newp->next = curp;
    168  1.12      wiz 	if (prevp)
    169  1.12      wiz 		prevp->next = newp;
    170  1.12      wiz 	else
    171  1.12      wiz 		keep_list = newp;
    172   1.1      cgd }
    173   1.1      cgd 
    174  1.12      wiz int
    175  1.12      wiz in_keep_list(const char *symbol)
    176   1.1      cgd {
    177  1.12      wiz 	struct keep *curp;
    178  1.12      wiz 	int cmp;
    179   1.6    perry 
    180  1.12      wiz 	cmp = 0;
    181   1.1      cgd 
    182  1.12      wiz 	for (curp = keep_list; curp; curp = curp->next)
    183  1.12      wiz 		if((cmp = strcmp(symbol, curp->sym)) <= 0)
    184  1.12      wiz 			break;
    185   1.1      cgd 
    186  1.12      wiz 	return curp && cmp == 0;
    187   1.1      cgd }
    188   1.1      cgd 
    189  1.14    joerg static void
    190  1.12      wiz add_file_to_keep_list(char *filename)
    191   1.1      cgd {
    192  1.12      wiz 	FILE *keepf;
    193  1.12      wiz 	char symbol[1024];
    194  1.12      wiz 	int len;
    195  1.12      wiz 
    196  1.12      wiz 	if ((keepf = fopen(filename, "r")) == NULL) {
    197  1.12      wiz 		perror(filename);
    198  1.12      wiz 		usage();
    199  1.12      wiz 	}
    200  1.12      wiz 
    201  1.12      wiz 	while (fgets(symbol, 1024, keepf)) {
    202  1.12      wiz 		len = strlen(symbol);
    203  1.12      wiz 		if (len && symbol[len-1] == '\n')
    204  1.12      wiz 			symbol[len-1] = '\0';
    205  1.12      wiz 
    206  1.12      wiz 		add_to_keep_list(symbol);
    207  1.12      wiz 	}
    208  1.12      wiz 	fclose(keepf);
    209   1.1      cgd }
    210   1.1      cgd 
    211   1.3      cgd /* ---------------------------- */
    212   1.1      cgd 
    213  1.14    joerg static struct {
    214   1.3      cgd 	const char *name;
    215   1.3      cgd 	int	(*check)(int, const char *);	/* 1 if match, zero if not */
    216   1.3      cgd 	int	(*hide)(int, const char *);	/* non-zero if error */
    217   1.3      cgd } exec_formats[] = {
    218   1.3      cgd #ifdef NLIST_AOUT
    219   1.3      cgd 	{	"a.out",	check_aout,	hide_aout,	},
    220  1.10  msaitoh #endif
    221  1.10  msaitoh #ifdef NLIST_COFF
    222  1.10  msaitoh 	{	"COFF",		check_coff,	hide_coff,	},
    223   1.3      cgd #endif
    224   1.5      cgd #ifdef NLIST_ECOFF
    225   1.5      cgd 	{	"ECOFF",	check_ecoff,	hide_ecoff,	},
    226   1.5      cgd #endif
    227   1.3      cgd #ifdef NLIST_ELF32
    228   1.3      cgd 	{	"ELF32",	check_elf32,	hide_elf32,	},
    229   1.3      cgd #endif
    230   1.3      cgd #ifdef NLIST_ELF64
    231   1.3      cgd 	{	"ELF64",	check_elf64,	hide_elf64,	},
    232   1.2       pk #endif
    233   1.3      cgd };
    234   1.1      cgd 
    235  1.14    joerg static int
    236  1.12      wiz hide_syms(const char *filename)
    237   1.1      cgd {
    238   1.3      cgd 	int fd, i, n, rv;
    239   1.1      cgd 
    240   1.3      cgd 	fd = open(filename, O_RDWR, 0);
    241   1.3      cgd 	if (fd == -1) {
    242   1.3      cgd 		perror(filename);
    243   1.3      cgd 		return 1;
    244   1.3      cgd 	}
    245   1.1      cgd 
    246   1.3      cgd 	rv = 0;
    247   1.1      cgd 
    248   1.3      cgd         n = sizeof exec_formats / sizeof exec_formats[0];
    249   1.3      cgd         for (i = 0; i < n; i++) {
    250   1.3      cgd 		if (lseek(fd, 0, SEEK_SET) != 0) {
    251   1.3      cgd 			perror(filename);
    252   1.3      cgd 			goto err;
    253   1.3      cgd 		}
    254   1.3      cgd                 if ((*exec_formats[i].check)(fd, filename) != 0)
    255   1.3      cgd                         break;
    256   1.3      cgd 	}
    257   1.3      cgd 	if (i == n) {
    258   1.4      cgd 		fprintf(stderr, "%s: unknown executable format\n", filename);
    259   1.3      cgd 		goto err;
    260   1.3      cgd 	}
    261   1.1      cgd 
    262   1.3      cgd 	if (verbose)
    263   1.3      cgd 		fprintf(stderr, "%s is an %s binary\n", filename,
    264   1.3      cgd 		    exec_formats[i].name);
    265   1.3      cgd 
    266   1.3      cgd 	if (lseek(fd, 0, SEEK_SET) != 0) {
    267   1.3      cgd 		perror(filename);
    268   1.3      cgd 		goto err;
    269   1.3      cgd 	}
    270   1.3      cgd 	rv = (*exec_formats[i].hide)(fd, filename);
    271   1.1      cgd 
    272   1.3      cgd out:
    273  1.12      wiz 	close(fd);
    274  1.12      wiz 	return rv;
    275   1.3      cgd 
    276   1.3      cgd err:
    277   1.3      cgd 	rv = 1;
    278   1.3      cgd 	goto out;
    279   1.1      cgd }
    280