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