Path: blob/main/usr.sbin/crunch/crunchide/crunchide.c
106842 views
/* $NetBSD: crunchide.c,v 1.8 1997/11/01 06:51:45 lukem Exp $ */1/*2* Copyright (c) 1997 Christopher G. Demetriou. All rights reserved.3* Copyright (c) 1994 University of Maryland4* All Rights Reserved.5*6* Permission to use, copy, modify, distribute, and sell this software and its7* documentation for any purpose is hereby granted without fee, provided that8* the above copyright notice appear in all copies and that both that9* copyright notice and this permission notice appear in supporting10* documentation, and that the name of U.M. not be used in advertising or11* publicity pertaining to distribution of the software without specific,12* written prior permission. U.M. makes no representations about the13* suitability of this software for any purpose. It is provided "as is"14* without express or implied warranty.15*16* U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.18* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES19* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION20* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN21* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.22*23* Author: James da Silva, Systems Design and Analysis Group24* Computer Science Department25* University of Maryland at College Park26*/27/*28* crunchide.c - tiptoes through a symbol table, hiding all defined29* global symbols. Allows the user to supply a "keep list" of symbols30* that are not to be hidden.31*32* The point of all this is to allow multiple programs to be linked33* together without getting multiple-defined errors.34*35* For example, consider a program "foo.c". It can be linked with a36* small stub routine, called "foostub.c", eg:37* int foo_main(int argc, char **argv){ return main(argc, argv); }38* like so:39* cc -c foo.c foostub.c40* ld -r foo.o foostub.o -o foo.combined.o41* crunchide -k _foo_main foo.combined.o42* at this point, foo.combined.o can be linked with another program43* and invoked with "foo_main(argc, argv)". foo's main() and any44* other globals are hidden and will not conflict with other symbols.45*46* TODO:47* - resolve the theoretical hanging reloc problem (see check_reloc()48* below). I have yet to see this problem actually occur in any real49* program. In what cases will gcc/gas generate code that needs a50* relative reloc from a global symbol, other than PIC? The51* solution is to not hide the symbol from the linker in this case,52* but to generate some random name for it so that it doesn't link53* with anything but holds the place for the reloc.54* - arrange that all the BSS segments start at the same address, so55* that the final crunched binary BSS size is the max of all the56* component programs' BSS sizes, rather than their sum.57*/5859#include <sys/cdefs.h>60#ifndef lint61__RCSID("$NetBSD: crunchide.c,v 1.8 1997/11/01 06:51:45 lukem Exp $");62#endif63#include <sys/types.h>64#include <sys/stat.h>65#include <sys/errno.h>66#include <unistd.h>67#include <stdio.h>68#include <stdlib.h>69#include <string.h>70#include <fcntl.h>7172#include "extern.h"7374static const char *pname = "crunchide";7576static void usage(void) __dead2;7778static void add_to_keep_list(char *symbol);79static void add_file_to_keep_list(char *filename);8081static int hide_syms(const char *filename);8283static int verbose;8485int main(int, char *[]);8687int88main(int argc, char **argv)89{90int ch, errors;9192if(argc > 0) pname = argv[0];9394while ((ch = getopt(argc, argv, "k:f:v")) != -1)95switch(ch) {96case 'k':97add_to_keep_list(optarg);98break;99case 'f':100add_file_to_keep_list(optarg);101break;102case 'v':103verbose = 1;104break;105default:106usage();107}108109argc -= optind;110argv += optind;111112if(argc == 0) usage();113114errors = 0;115while(argc) {116if (hide_syms(*argv))117errors = 1;118argc--, argv++;119}120121return errors;122}123124static void125usage(void)126{127fprintf(stderr,128"usage: %s [-k <symbol-name>] [-f <keep-list-file>] <files> ...\n",129pname);130exit(1);131}132133/* ---------------------------- */134135static struct keep {136struct keep *next;137char *sym;138} *keep_list;139140static void141add_to_keep_list(char *symbol)142{143struct keep *newp, *prevp, *curp;144int cmp;145146cmp = 0;147148for(curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next)149if((cmp = strcmp(symbol, curp->sym)) <= 0) break;150151if(curp && cmp == 0)152return; /* already in table */153154newp = (struct keep *) malloc(sizeof(struct keep));155if(newp) newp->sym = strdup(symbol);156if(newp == NULL || newp->sym == NULL) {157fprintf(stderr, "%s: out of memory for keep list\n", pname);158exit(1);159}160161newp->next = curp;162if(prevp) prevp->next = newp;163else keep_list = newp;164}165166int167in_keep_list(const char *symbol)168{169struct keep *curp;170int cmp;171172cmp = 0;173174for(curp = keep_list; curp; curp = curp->next)175if((cmp = strcmp(symbol, curp->sym)) <= 0) break;176177return curp && cmp == 0;178}179180static void181add_file_to_keep_list(char *filename)182{183FILE *keepf;184char symbol[1024];185int len;186187if((keepf = fopen(filename, "r")) == NULL) {188perror(filename);189usage();190}191192while(fgets(symbol, sizeof(symbol), keepf)) {193len = strlen(symbol);194if(len && symbol[len-1] == '\n')195symbol[len-1] = '\0';196197add_to_keep_list(symbol);198}199fclose(keepf);200}201202/* ---------------------------- */203204static struct {205const char *name;206int (*check)(int, const char *); /* 1 if match, zero if not */207int (*hide)(int, const char *); /* non-zero if error */208} exec_formats[] = {209#ifdef NLIST_ELF32210{ "ELF32", check_elf32, hide_elf32, },211#endif212#ifdef NLIST_ELF64213{ "ELF64", check_elf64, hide_elf64, },214#endif215};216217static int218hide_syms(const char *filename)219{220int fd, i, n, rv;221222fd = open(filename, O_RDWR, 0);223if (fd == -1) {224perror(filename);225return 1;226}227228rv = 0;229230n = sizeof exec_formats / sizeof exec_formats[0];231for (i = 0; i < n; i++) {232if (lseek(fd, 0, SEEK_SET) != 0) {233perror(filename);234goto err;235}236if ((*exec_formats[i].check)(fd, filename) != 0)237break;238}239if (i == n) {240fprintf(stderr, "%s: unknown executable format\n", filename);241goto err;242}243244if (verbose)245fprintf(stderr, "%s is an %s binary\n", filename,246exec_formats[i].name);247248if (lseek(fd, 0, SEEK_SET) != 0) {249perror(filename);250goto err;251}252rv = (*exec_formats[i].hide)(fd, filename);253254out:255close (fd);256return (rv);257258err:259rv = 1;260goto out;261}262263264