summaryrefslogtreecommitdiff
path: root/misc/buildroot/toolchain/nxflat/mknxflat.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc/buildroot/toolchain/nxflat/mknxflat.c')
-rw-r--r--misc/buildroot/toolchain/nxflat/mknxflat.c956
1 files changed, 956 insertions, 0 deletions
diff --git a/misc/buildroot/toolchain/nxflat/mknxflat.c b/misc/buildroot/toolchain/nxflat/mknxflat.c
new file mode 100644
index 000000000..7f1987486
--- /dev/null
+++ b/misc/buildroot/toolchain/nxflat/mknxflat.c
@@ -0,0 +1,956 @@
+/***********************************************************************
+ * xflat/tools/mknxflat.c
+ *
+ * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Modified from ldelflib (see http://xflat.org):
+ *
+ * Copyright (c) 2002, 2006, Cadenux, LLC. All rights reserved.
+ * Copyright (c) 2002, 2006, Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***********************************************************************/
+
+/***********************************************************************
+ * Included Files
+ ***********************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <bfd.h>
+
+#include "nxflat.h"
+#include "arch/arm.h"
+
+/***********************************************************************
+ * Definitions
+ ***********************************************************************/
+
+#define dbg(format, arg...) \
+ if (verbose) printf(format, ## arg)
+
+#define BSF_GLOBL_FUNC (BSF_GLOBAL|BSF_FUNCTION)
+#define BSF_WEAK_FUNC (BSF_WEAK|BSF_FUNCTION)
+#define BSF_DEFINED (BSF_LOCAL|BSF_GLOBAL)
+
+#define IS_GLOBL_FUNC(x) ((((x)->flags)&(BSF_GLOBL_FUNC))==(BSF_GLOBL_FUNC))
+#define IS_WEAK_FUNC(x) ((((x)->flags)&(BSF_WEAK_FUNC))==(BSF_WEAK_FUNC))
+#define IS_DEFINED(x) ((((x)->flags)&(BSF_DEFINED))!=0)
+#define IS_OBJECT(x) ((((x)->flags)&(BSF_OBJECT))!=0)
+#define IS_WEAK(x) ((((x)->flags)&(BSF_WEAK))!=0)
+
+#define MAX_EXPORT_NAMES 1024
+#define DEFAULT_MAX_THREADS 6
+#define MIN_THREADS 3
+
+/***********************************************************************
+ * Private Types
+ ***********************************************************************/
+
+typedef int (*symfunc_type) (asymbol * sym, void *arg);
+typedef int (*namefunc_type) (const char *name, void *arg);
+
+/***********************************************************************
+ * Private Variables
+ ***********************************************************************/
+
+/* Command line settings (counters but treated like booleans) */
+
+static int verbose = 0;
+static int weak_imports = 0;
+static int dsyms = 0;
+static int enable_trace = 0;
+static int max_threads = DEFAULT_MAX_THREADS;
+
+/* Characteristics of things */
+static int calls_nonreturning_functions = 0;
+static int calls_forkers = 0;
+
+/* Sizes of things */
+
+static long number_of_symbols = 0;
+static long number_undefined = 0;
+
+/* Names of things */
+
+static const char *program_name = NULL;
+static const char *bfd_filename = NULL;
+static const char *out_filename = NULL;
+
+/* The symbol table. */
+
+static asymbol **symbol_table = NULL;
+
+/* handle to included file */
+
+static FILE *include_stream = NULL;
+static char token[1024];
+
+static int counter;
+
+/***********************************************************************
+ * Private constant data
+ ***********************************************************************/
+
+/* All of the strings defining the generated file are here: */
+
+#include "arch/dyncall_skeleton.def"
+
+static const char dyn_symbol_prefix[] = "__dyn";
+#define DYN_SYMBOL_PREFIX_LEN 5
+
+/* This is the list of names of libc and libpthread functions that
+ * do not return. These may require some special handling -- at a
+ * minimum, they must tie up resources that can only be released
+ * when the function returns.
+ */
+
+static const char *const nonreturners[] = {
+ "abort", /* Never returns */
+ "err", /* Never returns */
+ "errx", /* Never returns */
+ "execl", /* Usually doesn't return */
+ "execle", /* Usually doesn't return */
+ "execlp", /* Usually doesn't return */
+ "execv", /* Usually doesn't return */
+ "execv", /* Usually doesn't return */
+ "execve", /* Usually doesn't return */
+ "execvp", /* Usually doesn't return */
+ "execvp", /* Usually doesn't return */
+ "exit", /* Never returns */
+ "_exit", /* Never returns */
+ "_Exit", /* Never returns */
+ "longjmp", /* Never returns */
+ "_longjmp", /* Never returns */
+ "pthread_exit", /* Never returns */
+ "siglongjmp", /* Never returns */
+ "__uClibc_main", /* Never returns */
+ "__uClibc_start_main", /* Never returns */
+ "verr", /* Never returns */
+ "verrx", /* Never returns */
+ NULL /* End of list */
+};
+
+/* This is the list of names of libc functions that behave very
+ * strangely: They return twice.
+ */
+
+static const char *const forkers[] = {
+ "clone",
+ "fork",
+ "setjmp",
+ "_setjmp",
+ "__sigsetjmp",
+ "vfork",
+ NULL /* End of list */
+};
+
+/***********************************************************************
+ * Private Functions
+ ***********************************************************************/
+
+/***********************************************************************
+ * show_usage
+ ***********************************************************************/
+
+static void show_usage(void)
+{
+ fprintf(stderr, "Usage: %s [options] <bfd-filename>\n\n", program_name);
+ fprintf(stderr, "Where options are one or more of the following. Note\n");
+ fprintf(stderr, "that a space is always required between the option and\n");
+ fprintf(stderr, "any following arguments.\n\n");
+ fprintf(stderr, " -d Use dynamic symbol table. [symtab]\n");
+ fprintf(stderr, " -f <cmd-filename>\n");
+ fprintf(stderr, " Take next commands from <cmd-filename> [cmd-line]\n");
+ fprintf(stderr, " -o <out-filename>\n");
+ fprintf(stderr, " Output to <out-filename> [stdout]\n");
+ fprintf(stderr, " -p <max_threads>\n");
+ fprintf(stderr,
+ " The maximum number of threads that can make simultaneous\n");
+ fprintf(stderr, " make calls into a shared library [6]\n");
+ fprintf(stderr, " -t Enable tracing of outbound shared library function\n");
+ fprintf(stderr, " calls. [no tracing]\n");
+ fprintf(stderr, " -v Verbose output [no output]\n");
+ fprintf(stderr, " -w Import weakly declared functions, i.e., weakly\n");
+ fprintf(stderr, " declared functions are expected to be provided at\n");
+ fprintf(stderr, " load-time [not imported]\n");
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+/***********************************************************************
+ * get_symbols
+ ***********************************************************************/
+
+static asymbol **get_symbols(bfd * abfd, long *num)
+{
+ long storage_needed;
+ asymbol **symbol_table;
+ long number_of_symbols;
+
+ if (dsyms)
+ storage_needed = bfd_get_dynamic_symtab_upper_bound(abfd);
+ else
+ storage_needed = bfd_get_symtab_upper_bound(abfd);
+
+ if (storage_needed < 0)
+ abort();
+
+ if (storage_needed == 0)
+ return NULL;
+
+ symbol_table = (asymbol **) malloc(storage_needed);
+
+ if (dsyms)
+ number_of_symbols = bfd_canonicalize_dynamic_symtab(abfd, symbol_table);
+ else
+ number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table);
+ if (number_of_symbols < 0)
+ abort();
+
+ *num = number_of_symbols;
+ return symbol_table;
+}
+
+/***********************************************************************
+ * traverse_undefined_functions
+ ***********************************************************************/
+
+static int traverse_undefined_functions(void *arg, symfunc_type fn)
+{
+ int i;
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ /* Check if it is undefined and not an object. I have found that symbol
+ * typing can be misleading: Imported functions are not marked as
+ * BSF_FUNCTION; weakly defined objects are listed as undefined objects.
+ * Conclusion: We will error if a object is truly undefined! */
+
+ if ((symbol_table[i]->value == 0) &&
+ (!IS_DEFINED(symbol_table[i])) && (!IS_OBJECT(symbol_table[i])))
+ {
+ /* Is is imported as a "weak" symbol? If so, we will process the
+ * symbol only if we were requested to do so from the command line. */
+
+ if ((!IS_WEAK(symbol_table[i])) || (weak_imports > 0))
+ {
+ /* Yes, process the symbol */
+
+ if (fn(symbol_table[i], arg) != 0)
+ {
+ /* If the function returns a non-zero value, then we
+ * terminate the traversal and return a non-zero value also. */
+
+ return 1;
+ }
+ }
+ }
+ }
+
+ /* Return 0 meaning that all undefined symbols were examined successfully. */
+
+ return 0;
+}
+
+/***********************************************************************
+ * put_string
+ ***********************************************************************/
+
+static void put_string(int fd, const char *string)
+{
+ ssize_t bytes_available = strlen(string);
+ ssize_t bytes_written = write(fd, string, bytes_available);
+ if (bytes_written < 0)
+ {
+ fprintf(stderr,
+ "Failed to write %ld bytes of string to output, errno=%d\n",
+ (long)bytes_available, errno);
+ exit(5);
+ }
+ else if (bytes_written != bytes_available)
+ {
+ fprintf(stderr, "Only wrote %ld of %ld bytes of string to output\n",
+ (long)bytes_written, (long)bytes_available);
+ exit(6);
+ }
+}
+
+/***********************************************************************
+ * does_not_return_name/sym
+ ***********************************************************************/
+
+static int does_not_return_name(const char *func_name)
+{
+ int i;
+
+ /* Check every name in the list of (usually) non-returning function */
+
+ for (i = 0; nonreturners[i] != NULL; i++)
+ {
+ /* Is this function name in the list */
+
+ if (strcmp(func_name, nonreturners[i]) == 0)
+ {
+ /* Yes, return true now. */
+
+ return 1;
+ }
+ }
+
+ /* Its not in the list, return false */
+
+ return 0;
+}
+
+static int does_not_return_sym(asymbol * sym, void *arg)
+{
+ const char *func_name = sym->name;
+ if (func_name)
+ return does_not_return_name(func_name);
+ else
+ return 0;
+}
+
+/***********************************************************************
+ * check_for_nonreturning_functions
+ ***********************************************************************/
+
+static void check_for_nonreturning_functions(void)
+{
+ calls_nonreturning_functions =
+ traverse_undefined_functions(NULL, does_not_return_sym);
+}
+
+/***********************************************************************
+ * is_forker_name/sym
+ ***********************************************************************/
+
+static int is_forker_name(const char *func_name)
+{
+ int i;
+
+ /* Check every name in the list of forkers */
+
+ for (i = 0; forkers[i] != NULL; i++)
+ {
+ /* Is this function name in the list */
+
+ if (strcmp(func_name, forkers[i]) == 0)
+ {
+ /* Yes, return true now. */
+
+ return 1;
+ }
+ }
+
+ /* Its not in the list, return false */
+
+ return 0;
+}
+
+static int is_forker_sym(asymbol * sym, void *arg)
+{
+ const char *func_name = sym->name;
+ if (func_name)
+ return does_not_return_name(func_name);
+ else
+ return 0;
+}
+
+/***********************************************************************
+ * check_for_forkers
+ ***********************************************************************/
+
+static void check_for_forkers(void)
+{
+ calls_forkers = traverse_undefined_functions(NULL, is_forker_sym);
+}
+
+/***********************************************************************
+ * count_undefined
+ ***********************************************************************/
+
+static int count_undefined(asymbol * sym, void *arg)
+{
+ number_undefined++;
+ return 0;
+}
+
+/***********************************************************************
+ * put_dynimport_decl
+ ***********************************************************************/
+
+static int put_dynimport_decl(asymbol * sym, void *arg)
+{
+ char dynimport_decl[1024];
+ const char *func_name = sym->name;
+ int fd = (int)arg;
+
+ /* Put the declaration for the dynamic info structure */
+ if (func_name)
+ {
+ sprintf(dynimport_decl, dynimport_decl_format,
+ MKINFODECLARGS(func_name, counter));
+ put_string(fd, dynimport_decl);
+ counter++;
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * put_dynimport_array
+ ***********************************************************************/
+
+static int put_dynimport_array(asymbol * sym, void *arg)
+{
+ char dynimport_array[1024];
+ const char *func_name = sym->name;
+ int fd = (int)arg;
+
+ /* Create the dynimport_array */
+
+ if (func_name)
+ {
+ sprintf(dynimport_array, dynimport_array_format,
+ MKINFOARGS(func_name, counter));
+ put_string(fd, dynimport_array);
+ counter++;
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * put_nxflat_import
+ ***********************************************************************/
+
+static int put_nxflat_import(asymbol * sym, void *arg)
+{
+ char thunk[4096];
+ const char *func_name = sym->name;
+ int fd = (int)arg;
+
+ if (func_name)
+ {
+ /* Create the thunk */
+
+ if (does_not_return_name(func_name) != 0)
+ {
+ /* The special case for functions that may not return */
+
+ sprintf(thunk, nonreturning_dyncall_format,
+ MKCALLARGS(func_name, counter));
+ }
+ else if (is_forker_name(func_name) != 0)
+ {
+ /* The special case for functions that fork */
+
+ sprintf(thunk, dyncall_format2, MKCALLARGS(func_name, counter));
+ }
+ else
+ {
+ /* The normal case */
+
+ sprintf(thunk, dyncall_format, MKCALLARGS(func_name, counter));
+ }
+
+ put_string(fd, thunk);
+ counter++;
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * put_all_nxflat_import
+ ***********************************************************************/
+
+static void put_all_nxflat_import(int fd)
+{
+ if (number_undefined > 0)
+ {
+ /* Put all of the declarations for the dynimport structures together. */
+
+ put_string(fd, dynimport_decl_prologue);
+ counter = 0;
+ (void)traverse_undefined_functions((void *)fd, put_dynimport_decl);
+
+ /* Put all of the dynimport structures together as an array */
+
+ put_string(fd, dynimport_array_prologue);
+ counter = 0;
+ (void)traverse_undefined_functions((void *)fd, put_dynimport_array);
+ put_string(fd, dynimport_array_epilogue);
+
+ /* Put all of the dyncall logic together */
+
+ put_string(fd, dyncall_decl_prologue);
+ counter = 0;
+ (void)traverse_undefined_functions((void *)fd, put_nxflat_import);
+ }
+}
+
+/***********************************************************************
+ * put_import_name
+ ***********************************************************************/
+
+static int put_import_name(asymbol * sym, void *arg)
+{
+ char import_name[512];
+ const char *func_name = sym->name;
+ int fd = (int)arg;
+
+ /* Create the import_name */
+
+ if (func_name)
+ {
+ sprintf(import_name, import_name_strtab_format,
+ MKIMPSTRTABARG(func_name, counter));
+ put_string(fd, import_name);
+ counter++;
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * put_import_name_strtab
+ ***********************************************************************/
+
+static void inline put_import_name_strtab(int fd)
+{
+ if (number_undefined > 0)
+ {
+ counter = 0;
+ put_string(fd, import_name_strtab_prologue);
+ (void)traverse_undefined_functions((void *)fd, put_import_name);
+ }
+}
+
+/***********************************************************************
+ * put_file_epilogue
+ ***********************************************************************/
+
+static void inline put_file_epilogue(int fd)
+{
+ /* Is it necessary to generate any thunk logic? */
+
+ if (number_undefined > 0)
+ {
+ /* Yes, was tracing enabled? */
+
+ if (enable_trace > 0)
+ {
+ /* Yes, generate the function to output the trace */
+
+ put_string(fd, dyntrace_function);
+ }
+
+ /* Output macros for managing the frame storage */
+
+ put_string(fd, frame_macros);
+
+ if (calls_nonreturning_functions)
+ {
+ /* Output special macros for managing frames for noreturning
+ * functions */
+
+ put_string(fd, nonreturning_frame_macros);
+ }
+
+ /* Output the beginning of the dynamic call function. */
+
+ put_string(fd, dyncall_prologue);
+
+ /* If tracing is enabled, then insert a call to the the trace generation
+ * function. */
+
+ if (enable_trace > 0)
+ {
+ put_string(fd, dyntrace_call);
+ }
+
+ /* Output the rest of the dynamic call function. */
+
+ put_string(fd, dyncall_epilogue);
+
+ /* Does the module call any non-returning functions? */
+
+ if (calls_nonreturning_functions)
+ {
+ /* Yes, output the beginning of a special dynamic call function. */
+
+ put_string(fd, nonreturning_dyncall_prologue);
+
+ /* If tracing is enabled, then insert a call to the the trace
+ * generation function. */
+
+ if (enable_trace > 0)
+ {
+ put_string(fd, dyntrace_call);
+ }
+
+ /* Output the rest of the special dynamic call function. */
+
+ put_string(fd, nonreturning_dyncall_epilogue);
+ }
+ }
+ put_string(fd, file_epilogue);
+}
+
+/***********************************************************************
+ * put_file_prologue
+ ***********************************************************************/
+
+static void inline put_file_prologue(int fd)
+{
+ put_string(fd, file_prologue);
+ if (enable_trace > 0)
+ {
+ put_string(fd, dyntrace_enable);
+ }
+ if (number_undefined > 0)
+ {
+ char frame_size[1024];
+
+ put_string(fd, import_prologue);
+ sprintf(frame_size, import_frame_size, max_threads);
+ put_string(fd, frame_size);
+ put_string(fd, dynamic_frames);
+
+ if (calls_nonreturning_functions)
+ {
+ put_string(fd, nonreturning_dynamic_frame);
+ }
+ }
+}
+
+/***********************************************************************
+ * get_file_token
+ ***********************************************************************/
+
+#define ISSPACE(c) \
+((c==' ')||(c=='\f')||(c=='\n')||(c=='\r')||(c=='\t')||(c=='\v'))
+
+#define ISTERMINATOR(c) (ISSPACE(c)||(c==EOF))
+
+static int get_file_token(FILE * in_stream)
+{
+ int i;
+ int c;
+
+ /* Skip over leading whitespace */
+
+ do
+ c = getc(in_stream);
+ while ISSPACE
+ (c);
+
+ if (c == EOF)
+ return EOF;
+
+ /* Add the token to the buffer. Copy characters until the buffer is full, or
+ * a terminator is encountered. */
+
+ for (i = 0; ((i < 1023) && !ISTERMINATOR(c)); i++, c = getc(in_stream))
+ {
+ token[i] = (char)c;
+ }
+
+ /* Handle the string truncation case. */
+
+ token[i] = '\0';
+ while (!ISTERMINATOR(c))
+ c = getc(in_stream);
+
+ /* Return success. On next entry, we will get the next character after the
+ * terminator. If the terminator was EOF, we should get EOF again. */
+
+ return 0;
+}
+
+/***********************************************************************
+ * get_token
+ ***********************************************************************/
+
+static char *get_token(int *argno, int argc, char **argv)
+{
+ char *retval = NULL;
+
+ if (include_stream)
+ {
+ if (get_file_token(include_stream) == EOF)
+ {
+ fclose(include_stream);
+ include_stream = NULL;
+ retval = get_token(argno, argc, argv);
+ }
+ else
+ {
+ retval = strdup(token);
+ }
+ }
+ else if (*argno >= argc)
+ {
+ retval = NULL;
+ }
+ else
+ {
+ retval = argv[*argno];
+ (*argno)++;
+ }
+ return retval;
+}
+
+/***********************************************************************
+ * get_arg
+ ***********************************************************************/
+
+static char *get_arg(int *argno, int argc, char **argv)
+{
+ char *retval;
+
+ /* Get the next argument */
+
+ retval = get_token(argno, argc, argv);
+ if ((retval == NULL) || (retval[0] == '-'))
+ {
+ fprintf(stderr, "Option requires an argument\n\n");
+ show_usage();
+ }
+ return retval;
+}
+
+/***********************************************************************
+ * get_opt
+ ***********************************************************************/
+
+static int get_opt(int *argno, int argc, char **argv)
+{
+ char *opt;
+ int len;
+ int retval = -1;
+
+ /* Get the next argument */
+
+ opt = get_token(argno, argc, argv);
+ if (opt != NULL)
+ {
+ /* It must be of length 2 and start with a '-' */
+
+ len = strlen(opt);
+ if ((len == 2) && (opt[0] == '-'))
+ {
+ retval = (int)opt[1];
+ }
+ else
+ {
+ fprintf(stderr, "%s Unrecognized option\n\n", opt);
+ show_usage();
+ }
+ }
+ return retval;
+}
+
+/***********************************************************************
+ * parse_args
+ ***********************************************************************/
+
+static void parse_args(int argc, char **argv)
+{
+ int argno = 1;
+ int opt;
+
+ /* Save our name (for show_usage) */
+
+ program_name = argv[0];
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "ERROR: Missing required arguments\n\n");
+ show_usage();
+ }
+
+ /* Get the name of the input BFD file. This is always the last thing in the
+ * argument list. We decrement argc so that the parsing logic will not look
+ * at it. */
+
+ bfd_filename = argv[argc - 1];
+ argc--;
+
+ /* Get miscellaneous options from the command line. */
+
+ while ((opt = get_opt(&argno, argc, argv)) != -1)
+ {
+ switch (opt)
+ {
+ case 'd':
+ dsyms++;
+ break;
+
+ case 'f':
+ {
+ char *filename = get_arg(&argno, argc, argv);
+ if (include_stream)
+ {
+ fprintf(stderr, "Cannot use -f from within a cmd-file\n\n");
+ show_usage();
+ }
+ else
+ {
+ include_stream = fopen(filename, "r");
+ if (!include_stream)
+ {
+ fprintf(stderr, "Could not open cmd-file %s\n\n", filename);
+ show_usage();
+ }
+ }
+ }
+ break;
+
+ case 'o':
+ out_filename = get_arg(&argno, argc, argv);
+ break;
+
+ case 'p':
+ {
+ int nthreads = atoi(get_arg(&argno, argc, argv));
+ if (nthreads < MIN_THREADS)
+ {
+ fprintf(stderr, "Invalid number of threads (%d) using %d\n",
+ nthreads, max_threads);
+ }
+ else
+ {
+ max_threads = nthreads;
+ }
+ }
+ break;
+
+ case 't':
+ enable_trace++;
+ break;
+
+ case 'v':
+ verbose++;
+ break;
+
+ case 'w':
+ weak_imports++;
+ break;
+
+ default:
+ fprintf(stderr, "%s Unknown option\n\n", argv[0]);
+ show_usage();
+ break;
+ }
+ }
+}
+
+/***********************************************************************
+ * Public Functions
+ ***********************************************************************/
+
+/***********************************************************************
+ * main
+ ***********************************************************************/
+
+int main(int argc, char **argv, char **envp)
+{
+ bfd *bf;
+ int out_fd = 0;
+
+ /* Get the input arguments */
+
+ parse_args(argc, argv);
+
+ /* Make sure that we can option the BFD file */
+
+ dbg("Opening BFD file: %s\n", bfd_filename);
+ if (!(bf = bfd_openr(bfd_filename, 0)))
+ {
+ fprintf(stderr, "Failed to open BFD file: %s, errno=%d\n",
+ bfd_filename, errno);
+ exit(2);
+ }
+
+ dbg("Checking format\n");
+ if (bfd_check_format(bf, bfd_object) == 0)
+ {
+ fprintf(stderr, "BFD file %s is not an object file\n", bfd_filename);
+ exit(3);
+ }
+
+ dbg("Loading symbol table from BFD file %s\n", bfd_filename);
+ symbol_table = get_symbols(bf, &number_of_symbols);
+
+ /* Count the number of undefined function symbols */
+
+ (void)traverse_undefined_functions(NULL, count_undefined);
+
+ /* Check if the module calls any non-returning functions (like exit). These
+ * will require some additional setup. */
+
+ check_for_nonreturning_functions();
+ check_for_forkers();
+
+ /* Make sure that we can open the output file if one is specified. If no
+ * out_filename is specified, we'll use stdout. */
+
+ if (out_filename)
+ {
+ out_fd = open(out_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (out_fd < 0)
+ {
+ fprintf(stderr, "Failed to open output file: %s, errno=%d\n",
+ out_filename, errno);
+ exit(4);
+ }
+ }
+
+ /* Output the thunk file in three pieces: 1. The constant file prologue 2.
+ * Library path information (if any) 3. Library file name information (if
+ * any) 4. Exported symbole information (if any) 5. Imported symbole
+ * information (if any) 6. The constant file epilogue. */
+
+ put_file_prologue(out_fd);
+ put_import_name_strtab(out_fd);
+ put_all_nxflat_import(out_fd);
+ put_file_epilogue(out_fd);
+
+ if (out_fd > 0)
+ close(out_fd);
+ exit(0);
+}