summaryrefslogtreecommitdiff
path: root/cross/bfd-crunchide/files/crunchide.c
diff options
context:
space:
mode:
Diffstat (limited to 'cross/bfd-crunchide/files/crunchide.c')
-rw-r--r--cross/bfd-crunchide/files/crunchide.c443
1 files changed, 443 insertions, 0 deletions
diff --git a/cross/bfd-crunchide/files/crunchide.c b/cross/bfd-crunchide/files/crunchide.c
new file mode 100644
index 00000000000..848edc8931b
--- /dev/null
+++ b/cross/bfd-crunchide/files/crunchide.c
@@ -0,0 +1,443 @@
+/* $NetBSD: crunchide.c,v 1.1.1.1 1999/12/20 05:57:40 sakamoto Exp $ */
+/* NetBSD: crunchide.c,v 1.9 1999/01/11 22:40:00 kleink Exp */
+
+/*
+ * Copyright (c) 1997 Christopher G. Demetriou. All rights reserved.
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * crunchide.c - tiptoes through an a.out symbol table, hiding all defined
+ * global symbols. Allows the user to supply a "keep list" of symbols
+ * that are not to be hidden. This program relies on the use of the
+ * linker's -dc flag to actually put global bss data into the file's
+ * bss segment (rather than leaving it as undefined "common" data).
+ *
+ * The point of all this is to allow multiple programs to be linked
+ * together without getting multiple-defined errors.
+ *
+ * For example, consider a program "foo.c". It can be linked with a
+ * small stub routine, called "foostub.c", eg:
+ * int foo_main(int argc, char **argv){ return main(argc, argv); }
+ * like so:
+ * cc -c foo.c foostub.c
+ * ld -dc -r foo.o foostub.o -o foo.combined.o
+ * crunchide -k _foo_main foo.combined.o
+ * at this point, foo.combined.o can be linked with another program
+ * and invoked with "foo_main(argc, argv)". foo's main() and any
+ * other globals are hidden and will not conflict with other symbols.
+ *
+ * TODO:
+ * - resolve the theoretical hanging reloc problem (see check_reloc()
+ * below). I have yet to see this problem actually occur in any real
+ * program. In what cases will gcc/gas generate code that needs a
+ * relative reloc from a global symbol, other than PIC? The
+ * solution is to not hide the symbol from the linker in this case,
+ * but to generate some random name for it so that it doesn't link
+ * with anything but holds the place for the reloc.
+ * - arrange that all the BSS segments start at the same address, so
+ * that the final crunched binary BSS size is the max of all the
+ * component programs' BSS sizes, rather than their sum.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: crunchide.c,v 1.1.1.1 1999/12/20 05:57:40 sakamoto Exp $");
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <a.out.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <bfd.h>
+
+extern const char *__progname;
+
+void usage __P((void));
+void add_to_keep_list __P((char *));
+void add_file_to_keep_list __P((char *));
+int hide_syms __P((const char *, char *));
+static void setup_section __P((bfd *, sec_ptr, PTR));
+static void copy_section __P((bfd *, sec_ptr, PTR));
+
+int verbose;
+
+struct keep {
+ struct keep *next;
+ char *sym;
+} *keep_list;
+
+struct bfd_cookie {
+ bfd *bfd;
+ asymbol **symtable;
+};
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch, errors;
+ char *bfdname = NULL;
+
+ while ((ch = getopt(argc, argv, "b:k:f:v")) != -1)
+ switch (ch) {
+ case 'b':
+ bfdname = optarg;
+ break;
+ case 'k':
+ add_to_keep_list(optarg);
+ break;
+ case 'f':
+ add_file_to_keep_list(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ errors = 0;
+ while (argc) {
+ if (hide_syms(*argv, bfdname))
+ errors = 1;
+ argc--, argv++;
+ }
+
+ return errors;
+}
+
+void
+usage()
+{
+ const char **list;
+
+ fprintf(stderr,
+"Usage: %s [-b bfdname] [-k <symbol-name>] [-f <keep-list-file>] <files> ...\n",
+ __progname);
+ fprintf(stderr, "supported targets:");
+ for (list = bfd_target_list(); *list != NULL; list++)
+ fprintf(stderr, " %s", *list);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+void
+add_to_keep_list(symbol)
+ char *symbol;
+{
+ struct keep *newp, *prevp, *curp;
+ int cmp;
+
+ cmp = 0;
+
+ for (curp = keep_list, prevp = NULL; curp;
+ prevp = curp, curp = curp->next)
+ if ((cmp = strcmp(symbol, curp->sym)) <= 0)
+ break;
+
+ if (curp && cmp == 0)
+ return; /* already in table */
+
+ newp = (struct keep *)malloc(sizeof (struct keep));
+ if (newp)
+ newp->sym = strdup(symbol);
+ if (newp == NULL || newp->sym == NULL) {
+ fprintf(stderr,
+ "%s: out of memory for keep list\n", __progname);
+ exit(1);
+ }
+ newp->next = curp;
+ if (prevp)
+ prevp->next = newp;
+ else
+ keep_list = newp;
+}
+
+int
+in_keep_list(symbol)
+ const char *symbol;
+{
+ struct keep *curp;
+ int cmp;
+
+ cmp = 0;
+
+ for (curp = keep_list; curp; curp = curp->next)
+ if ((cmp = strcmp(symbol, curp->sym)) <= 0)
+ break;
+
+ return curp && cmp == 0;
+}
+
+void
+add_file_to_keep_list(filename)
+ char *filename;
+{
+ FILE *keepf;
+ char symbol[1024];
+ int len;
+
+ if ((keepf = fopen(filename, "r")) == NULL) {
+ perror(filename);
+ usage();
+ }
+ while (fgets(symbol, 1024, keepf)) {
+ len = strlen(symbol);
+ if (len && symbol[len - 1] == '\n')
+ symbol[len - 1] = '\0';
+
+ add_to_keep_list(symbol);
+ }
+ fclose(keepf);
+}
+
+int
+hide_syms(filename, bfdname)
+ const char *filename;
+ char *bfdname;
+{
+ int i, n, rv = 0;
+ bfd *org_bfd = NULL, *new_bfd = NULL;
+ char *tempname;
+ char **name;
+ long storage_needed, number_of_symbols;
+ size_t fn_size;
+ asymbol **org_symtable, **new_symtable;
+
+ fn_size = strlen(filename);
+
+ bfd_init();
+ if ((org_bfd = bfd_openr(filename, bfdname)) == NULL) {
+ bfd_perror(filename);
+ return 1;
+ }
+ if (!bfd_check_format(org_bfd, bfd_object)) {
+ bfd_perror(filename);
+ goto err;
+ }
+
+ bfdname = bfd_get_target(org_bfd);
+ tempname = tempnam(".", NULL);
+ if ((new_bfd = bfd_openw(tempname, bfdname)) == NULL) {
+ bfd_perror(tempname);
+ goto err;
+ }
+
+ if (!bfd_set_format(new_bfd, bfd_get_format(org_bfd)) ||
+ !bfd_set_start_address(new_bfd, bfd_get_start_address(org_bfd)) ||
+ !bfd_set_file_flags(new_bfd, (bfd_get_file_flags(org_bfd) &
+ bfd_applicable_file_flags(new_bfd))) ||
+ !bfd_set_arch_mach (new_bfd, bfd_get_arch (org_bfd),
+ bfd_get_mach (org_bfd))) {
+ bfd_perror(tempname);
+ goto err;
+ }
+ bfd_map_over_sections(org_bfd, setup_section, (void *)new_bfd);
+
+ storage_needed = bfd_get_symtab_upper_bound(org_bfd);
+ if (storage_needed < 0)
+ goto err;
+ if (storage_needed == 0)
+ goto out;
+
+ org_symtable = (asymbol **)malloc(storage_needed);
+ number_of_symbols = bfd_canonicalize_symtab(org_bfd, org_symtable);
+ if (number_of_symbols < 0)
+ goto err;
+
+ new_symtable = (asymbol **)malloc(storage_needed);
+ if (new_symtable == NULL)
+ goto err;
+ name = (char **)calloc(sizeof (char *), number_of_symbols);
+ if (name == NULL)
+ goto err;
+
+ n = 0;
+ for (i = 0; i < number_of_symbols; i++) {
+ const char *symname;
+
+ new_symtable[i] = org_symtable[i];
+ if (!(new_symtable[i]->flags & BSF_GLOBAL))
+ continue;
+
+ symname = bfd_asymbol_name(new_symtable[i]);
+ if (symname[0] == '_')
+ symname++;
+ if (in_keep_list(symname))
+ continue;
+
+ n++;
+
+ /*
+ * make sure there's size for the next entry, even if it's
+ * as large as it can be.
+ *
+ * "_$$hide$$ <filename> <symname><NUL>" ->
+ * 9 + 3 + sizes of fn and sym name
+ */
+ name[i] = (char *)malloc(12 + fn_size + strlen(symname));
+ sprintf(name[i], "_$$hide$$ %s %s", filename, symname);
+ new_symtable[i]->name = name[i];
+ }
+
+ if (n > 0) {
+ struct bfd_cookie cookie;
+
+ new_symtable[number_of_symbols] = NULL;
+ bfd_set_symtab(new_bfd, new_symtable, number_of_symbols);
+
+ cookie.bfd = new_bfd;
+ cookie.symtable = org_symtable;
+ bfd_map_over_sections(org_bfd, copy_section, (void *)&cookie);
+
+ if (!bfd_copy_private_bfd_data(org_bfd, new_bfd)) {
+ bfd_perror("bfd_copy_private_bfd_data");
+ goto err;
+ }
+ }
+
+ bfd_close(new_bfd);
+ bfd_close(org_bfd);
+
+ if (rename(tempname, filename) < 0)
+ perror("rename");
+ unlink(tempname);
+
+ for (i = 0; i < number_of_symbols; i++)
+ if (name[i])
+ free(name[i]);
+ free(new_symtable);
+ free(name);
+
+out:
+ return (rv);
+
+err:
+ rv = 1;
+ if (org_bfd)
+ bfd_close(org_bfd);
+ if (new_bfd) {
+ unlink(tempname);
+ bfd_close(new_bfd);
+ }
+ goto out;
+}
+
+static void
+setup_section(ibfd, isection, arg)
+ bfd *ibfd;
+ sec_ptr isection;
+ PTR arg;
+{
+ sec_ptr osection;
+ bfd *obfd = (bfd *)arg;
+
+ if ((osection = bfd_make_section_anyway(obfd,
+ bfd_section_name(ibfd, isection))) == NULL ||
+ !bfd_set_section_size(obfd, osection,
+ bfd_section_size(ibfd, isection)) ||
+ !bfd_set_section_vma(obfd, osection,
+ bfd_section_vma(ibfd, isection)) ||
+ !bfd_set_section_alignment(obfd, osection,
+ bfd_section_alignment(ibfd, isection)) ||
+ !bfd_set_section_flags(obfd, osection,
+ bfd_get_section_flags(ibfd, isection))) {
+ bfd_perror("setup_section");
+ return;
+ }
+
+ isection->output_section = osection;
+ isection->output_offset = 0;
+ if (!bfd_copy_private_section_data(ibfd, isection, obfd, osection)) {
+ bfd_perror("setup_section");
+ return;
+ }
+}
+
+static void
+copy_section(ibfd, isection, arg)
+ bfd *ibfd;
+ sec_ptr isection;
+ PTR arg;
+{
+ struct bfd_cookie *bc = (struct bfd_cookie *)arg;
+ bfd *obfd = bc->bfd;
+ asymbol **isym = bc->symtable;
+ arelent **relpp;
+ sec_ptr osection;
+ PTR memhunk;
+ bfd_size_type size;
+ long relcount, relsize;
+
+ osection = isection->output_section;
+ size = bfd_get_section_size_before_reloc(isection);
+ if (size == 0 || osection == 0)
+ return;
+
+ relsize = bfd_get_reloc_upper_bound(ibfd, isection);
+ if (relsize < 0) {
+ bfd_perror(bfd_get_filename(ibfd));
+ }
+ if (relsize == 0) {
+ bfd_set_reloc(obfd, osection, NULL, 0);
+ } else {
+ relpp = (arelent **)malloc(relsize);
+ relcount = bfd_canonicalize_reloc(ibfd, isection, relpp, isym);
+ if (relcount < 0)
+ bfd_perror(bfd_get_filename(ibfd));
+ bfd_set_reloc(obfd, osection, relpp, relcount);
+ }
+
+ isection->_cooked_size = isection->_raw_size;
+ isection->reloc_done = true;
+
+ if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS) {
+ memhunk = (PTR)malloc((unsigned int)size);
+ if (!bfd_get_section_contents(ibfd, isection, memhunk, 0, size))
+ bfd_perror(bfd_get_filename(ibfd));
+ if (!bfd_set_section_contents(obfd, osection, memhunk, 0, size))
+ bfd_perror(bfd_get_filename(obfd));
+ free(memhunk);
+ } else if (bfd_get_section_flags(ibfd, isection) & SEC_LOAD) {
+ memhunk = (PTR)malloc((unsigned int)size);
+ memset(memhunk, 0, size);
+ if (!bfd_set_section_contents(obfd, osection, memhunk, 0, size))
+ bfd_perror(bfd_get_filename(obfd));
+ free(memhunk);
+ }
+}