139172Sjkh/* $NetBSD: crunchide.c,v 1.8 1997/11/01 06:51:45 lukem Exp $ */ 21722Sjkh/* 339172Sjkh * Copyright (c) 1997 Christopher G. Demetriou. All rights reserved. 41722Sjkh * Copyright (c) 1994 University of Maryland 51722Sjkh * All Rights Reserved. 61722Sjkh * 71722Sjkh * Permission to use, copy, modify, distribute, and sell this software and its 81722Sjkh * documentation for any purpose is hereby granted without fee, provided that 91722Sjkh * the above copyright notice appear in all copies and that both that 101722Sjkh * copyright notice and this permission notice appear in supporting 111722Sjkh * documentation, and that the name of U.M. not be used in advertising or 121722Sjkh * publicity pertaining to distribution of the software without specific, 131722Sjkh * written prior permission. U.M. makes no representations about the 141722Sjkh * suitability of this software for any purpose. It is provided "as is" 151722Sjkh * without express or implied warranty. 161722Sjkh * 171722Sjkh * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 181722Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 191722Sjkh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 201722Sjkh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 211722Sjkh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 221722Sjkh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 231722Sjkh * 241722Sjkh * Author: James da Silva, Systems Design and Analysis Group 251722Sjkh * Computer Science Department 261722Sjkh * University of Maryland at College Park 271722Sjkh */ 281722Sjkh/* 291722Sjkh * crunchide.c - tiptoes through an a.out symbol table, hiding all defined 301722Sjkh * global symbols. Allows the user to supply a "keep list" of symbols 311722Sjkh * that are not to be hidden. This program relies on the use of the 321722Sjkh * linker's -dc flag to actually put global bss data into the file's 331722Sjkh * bss segment (rather than leaving it as undefined "common" data). 341722Sjkh * 351722Sjkh * The point of all this is to allow multiple programs to be linked 361722Sjkh * together without getting multiple-defined errors. 371722Sjkh * 381722Sjkh * For example, consider a program "foo.c". It can be linked with a 391722Sjkh * small stub routine, called "foostub.c", eg: 401722Sjkh * int foo_main(int argc, char **argv){ return main(argc, argv); } 411722Sjkh * like so: 421722Sjkh * cc -c foo.c foostub.c 431722Sjkh * ld -dc -r foo.o foostub.o -o foo.combined.o 441722Sjkh * crunchide -k _foo_main foo.combined.o 451722Sjkh * at this point, foo.combined.o can be linked with another program 461722Sjkh * and invoked with "foo_main(argc, argv)". foo's main() and any 471722Sjkh * other globals are hidden and will not conflict with other symbols. 481722Sjkh * 491722Sjkh * TODO: 501722Sjkh * - resolve the theoretical hanging reloc problem (see check_reloc() 511722Sjkh * below). I have yet to see this problem actually occur in any real 521722Sjkh * program. In what cases will gcc/gas generate code that needs a 531722Sjkh * relative reloc from a global symbol, other than PIC? The 541722Sjkh * solution is to not hide the symbol from the linker in this case, 551722Sjkh * but to generate some random name for it so that it doesn't link 561722Sjkh * with anything but holds the place for the reloc. 571722Sjkh * - arrange that all the BSS segments start at the same address, so 581722Sjkh * that the final crunched binary BSS size is the max of all the 591722Sjkh * component programs' BSS sizes, rather than their sum. 608857Srgrimes */ 61237625Sobrien 6239172Sjkh#include <sys/cdefs.h> 6339172Sjkh#ifndef lint 6439172Sjkh__RCSID("$NetBSD: crunchide.c,v 1.8 1997/11/01 06:51:45 lukem Exp $"); 6539172Sjkh#endif 66237625Sobrien__FBSDID("$FreeBSD$"); 6739172Sjkh 68237625Sobrien#include <sys/types.h> 69237625Sobrien#include <sys/stat.h> 70237625Sobrien#include <sys/errno.h> 7139172Sjkh#include <unistd.h> 721722Sjkh#include <stdio.h> 731722Sjkh#include <stdlib.h> 741722Sjkh#include <string.h> 7539172Sjkh#include <fcntl.h> 7639172Sjkh#include <a.out.h> 771722Sjkh 7839172Sjkh#include "extern.h" 7939172Sjkh 8039172Sjkhchar *pname = "crunchide"; 8139172Sjkh 821722Sjkhvoid usage(void); 831722Sjkh 841722Sjkhvoid add_to_keep_list(char *symbol); 851722Sjkhvoid add_file_to_keep_list(char *filename); 861722Sjkh 8739172Sjkhint hide_syms(const char *filename); 881722Sjkh 8939172Sjkhint verbose; 901722Sjkh 91173412Skevloint main(int, char *[]); 9239172Sjkh 93237625Sobrienint 94237625Sobrienmain(int argc, char **argv) 951722Sjkh{ 9639172Sjkh int ch, errors; 971722Sjkh 9839172Sjkh if(argc > 0) pname = argv[0]; 9939172Sjkh 10039172Sjkh while ((ch = getopt(argc, argv, "k:f:v")) != -1) 1011722Sjkh switch(ch) { 1021722Sjkh case 'k': 1031722Sjkh add_to_keep_list(optarg); 1041722Sjkh break; 1051722Sjkh case 'f': 1061722Sjkh add_file_to_keep_list(optarg); 1071722Sjkh break; 10839172Sjkh case 'v': 10939172Sjkh verbose = 1; 11039172Sjkh break; 1111722Sjkh default: 1121722Sjkh usage(); 1131722Sjkh } 1141722Sjkh 1151722Sjkh argc -= optind; 1161722Sjkh argv += optind; 1171722Sjkh 1181722Sjkh if(argc == 0) usage(); 1191722Sjkh 12039172Sjkh errors = 0; 1211722Sjkh while(argc) { 12239172Sjkh if (hide_syms(*argv)) 12339172Sjkh errors = 1; 1241722Sjkh argc--, argv++; 1251722Sjkh } 1261722Sjkh 12739172Sjkh return errors; 1281722Sjkh} 1291722Sjkh 130237625Sobrienvoid 131237625Sobrienusage(void) 1321722Sjkh{ 1331722Sjkh fprintf(stderr, 13495258Sdes "usage: %s [-k <symbol-name>] [-f <keep-list-file>] <files> ...\n", 13539172Sjkh pname); 1361722Sjkh exit(1); 1371722Sjkh} 1381722Sjkh 1391722Sjkh/* ---------------------------- */ 1401722Sjkh 1411722Sjkhstruct keep { 1421722Sjkh struct keep *next; 1431722Sjkh char *sym; 1441722Sjkh} *keep_list; 1451722Sjkh 146237625Sobrienvoid 147237625Sobrienadd_to_keep_list(char *symbol) 1481722Sjkh{ 1491722Sjkh struct keep *newp, *prevp, *curp; 1501722Sjkh int cmp; 1511722Sjkh 15239172Sjkh cmp = 0; 15339172Sjkh 1541722Sjkh for(curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next) 1551722Sjkh if((cmp = strcmp(symbol, curp->sym)) <= 0) break; 1561722Sjkh 1571722Sjkh if(curp && cmp == 0) 1581722Sjkh return; /* already in table */ 1591722Sjkh 1601722Sjkh newp = (struct keep *) malloc(sizeof(struct keep)); 1611722Sjkh if(newp) newp->sym = strdup(symbol); 1621722Sjkh if(newp == NULL || newp->sym == NULL) { 16339172Sjkh fprintf(stderr, "%s: out of memory for keep list\n", pname); 16439172Sjkh exit(1); 1651722Sjkh } 1661722Sjkh 1671722Sjkh newp->next = curp; 1681722Sjkh if(prevp) prevp->next = newp; 1691722Sjkh else keep_list = newp; 1701722Sjkh} 1711722Sjkh 172237625Sobrienint 173237625Sobrienin_keep_list(const char *symbol) 1741722Sjkh{ 1751722Sjkh struct keep *curp; 1761722Sjkh int cmp; 1771722Sjkh 17839172Sjkh cmp = 0; 17939172Sjkh 1801722Sjkh for(curp = keep_list; curp; curp = curp->next) 1811722Sjkh if((cmp = strcmp(symbol, curp->sym)) <= 0) break; 1821722Sjkh 1831722Sjkh return curp && cmp == 0; 1841722Sjkh} 1851722Sjkh 186237625Sobrienvoid 187237625Sobrienadd_file_to_keep_list(char *filename) 1881722Sjkh{ 1891722Sjkh FILE *keepf; 1901722Sjkh char symbol[1024]; 1911722Sjkh int len; 1921722Sjkh 1931722Sjkh if((keepf = fopen(filename, "r")) == NULL) { 19439172Sjkh perror(filename); 1951722Sjkh usage(); 1961722Sjkh } 1971722Sjkh 198167260Skevlo while(fgets(symbol, sizeof(symbol), keepf)) { 1991722Sjkh len = strlen(symbol); 2001722Sjkh if(len && symbol[len-1] == '\n') 2011722Sjkh symbol[len-1] = '\0'; 2021722Sjkh 2031722Sjkh add_to_keep_list(symbol); 2041722Sjkh } 2051722Sjkh fclose(keepf); 2061722Sjkh} 2071722Sjkh 20839172Sjkh/* ---------------------------- */ 2091722Sjkh 21039172Sjkhstruct { 21139172Sjkh const char *name; 21239172Sjkh int (*check)(int, const char *); /* 1 if match, zero if not */ 21339172Sjkh int (*hide)(int, const char *); /* non-zero if error */ 21439172Sjkh} exec_formats[] = { 21539172Sjkh#ifdef NLIST_AOUT 21639172Sjkh { "a.out", check_aout, hide_aout, }, 21739172Sjkh#endif 21839172Sjkh#ifdef NLIST_ECOFF 21939890Sjkh { "ECOFF", check_elf64, hide_elf64, }, 22039172Sjkh#endif 22139172Sjkh#ifdef NLIST_ELF32 22239172Sjkh { "ELF32", check_elf32, hide_elf32, }, 22339172Sjkh#endif 22439172Sjkh#ifdef NLIST_ELF64 22539172Sjkh { "ELF64", check_elf64, hide_elf64, }, 22639172Sjkh#endif 22739172Sjkh}; 2281722Sjkh 229237625Sobrienint 230237625Sobrienhide_syms(const char *filename) 2311722Sjkh{ 23239172Sjkh int fd, i, n, rv; 2331722Sjkh 23439172Sjkh fd = open(filename, O_RDWR, 0); 23539172Sjkh if (fd == -1) { 23639172Sjkh perror(filename); 23739172Sjkh return 1; 23839172Sjkh } 2391722Sjkh 24039172Sjkh rv = 0; 2411722Sjkh 24239172Sjkh n = sizeof exec_formats / sizeof exec_formats[0]; 24339172Sjkh for (i = 0; i < n; i++) { 24439172Sjkh if (lseek(fd, 0, SEEK_SET) != 0) { 24539172Sjkh perror(filename); 24639172Sjkh goto err; 24739172Sjkh } 24839172Sjkh if ((*exec_formats[i].check)(fd, filename) != 0) 24939172Sjkh break; 25039172Sjkh } 25139172Sjkh if (i == n) { 25239172Sjkh fprintf(stderr, "%s: unknown executable format\n", filename); 25339172Sjkh goto err; 25439172Sjkh } 2551722Sjkh 25639172Sjkh if (verbose) 25739172Sjkh fprintf(stderr, "%s is an %s binary\n", filename, 25839172Sjkh exec_formats[i].name); 2591722Sjkh 26039172Sjkh if (lseek(fd, 0, SEEK_SET) != 0) { 26139172Sjkh perror(filename); 26239172Sjkh goto err; 26339172Sjkh } 26439172Sjkh rv = (*exec_formats[i].hide)(fd, filename); 2651722Sjkh 26639172Sjkhout: 26739172Sjkh close (fd); 26839172Sjkh return (rv); 2691722Sjkh 27039172Sjkherr: 27139172Sjkh rv = 1; 27239172Sjkh goto out; 2731722Sjkh} 274