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