#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <mach-o/reloc.h>
#include <libc.h>
#include <mach/mach.h>
#include "stuff/arch.h"
#include "stuff/errors.h"
#include "stuff/allocate.h"
#include "stuff/hash_string.h"
#include "libgcc.h"
#include "mkshlib.h"
#include "branch.h"
__private_extern__
char *progname = NULL;
char *spec_filename;
char *host_filename;
char *target_filename;
char *shlib_symbol_name;
char *shlib_reference_name;
char *target_base_name;
long vflag = 0;
long dflag = 0;
static long fflag = 0;
struct arch_flag arch_flag = { 0 };
enum byte_sex host_byte_sex = UNKNOWN_BYTE_SEX;
enum byte_sex target_byte_sex = UNKNOWN_BYTE_SEX;
char **ldflags = NULL;
unsigned long nldflags = 0;
#define MKSHLIBNAME "mkshlib"
#define ASNAME "as"
#define LDNAME "ld"
char *asname;
char *ldname;
static void usage(void);
static void libdef_sym(void);
static struct {
int size;
int next;
char **strings;
} runlist;
int
main(
int argc,
char *argv[],
char *envp[])
{
long i;
progname = argv[0];
signal(SIGINT, cleanup);
host_byte_sex = get_host_byte_sex();
asname = ASNAME;
ldname = LDNAME;
for(i = 1; i < argc; i++){
if(argv[i][0] != '-'){
error("unknown flag %s", argv[i]);
usage();
}
switch(argv[i][1]){
case 'a':
if(strcmp(argv[i], "-arch") == 0){
if(++i >= argc)
fatal("-arch: argument missing");
if(arch_flag.name != NULL)
fatal("-arch: multiply specified");
if(get_arch_from_flag(argv[i], &arch_flag) == 0){
error("unknown architecture specification flag: "
"-arch %s", argv[i]);
arch_usage();
usage();
}
}
else
goto unknown_flag;
break;
case 's':
if(strcmp(argv[i], "-sectcreate") == 0 ||
strcmp(argv[i], "-segcreate") == 0 ||
strcmp(argv[i], "-sectorder") == 0 ||
strcmp(argv[i], "-sectalign") == 0 ||
strcmp(argv[i], "-segprot") == 0){
if(i + 3 >= argc){
error("not enough arguments follow %s", argv[i]);
usage();
}
ldflags = reallocate(ldflags, sizeof(char * ) *
(nldflags + 4));
ldflags[nldflags++] = argv[i];
ldflags[nldflags++] = argv[i + 1];
ldflags[nldflags++] = argv[i + 2];
ldflags[nldflags++] = argv[i + 3];
i += 3;
break;
}
if(strcmp(argv[i], "-segaddr") == 0){
if(i + 2 >= argc){
error("not enough arguments follow %s", argv[i]);
usage();
}
ldflags = reallocate(ldflags, sizeof(char * ) *
(nldflags + 3));
ldflags[nldflags++] = argv[i];
ldflags[nldflags++] = argv[i + 1];
ldflags[nldflags++] = argv[i + 2];
i += 2;
break;
}
if(strcmp(argv[i], "-segalign") == 0){
if(i + 1 >= argc){
error("not enough arguments follow %s", argv[i]);
usage();
}
ldflags = reallocate(ldflags, sizeof(char * ) *
(nldflags + 2));
ldflags[nldflags++] = argv[i];
ldflags[nldflags++] = argv[i + 1];
i += 1;
break;
}
if(strcmp(argv[i], "-seglinkedit") == 0 ||
strcmp(argv[i], "-sectorder_detail") == 0){
ldflags = reallocate(ldflags, sizeof(char * ) *
(nldflags + 1));
ldflags[nldflags++] = argv[i];
break;
}
if(i + 1 == argc){
error("missing file name for %s", argv[i]);
usage();
}
i++;
spec_filename = argv[i];
break;
case 'h':
if(i + 1 == argc){
error("missing file name for %s", argv[i]);
usage();
}
i++;
host_filename = argv[i];
break;
case 't':
if(i + 1 == argc){
error("missing file name for %s", argv[i]);
usage();
}
i++;
target_filename = argv[i];
break;
case 'f':
fflag++;
break;
case 'u':
fatal("-u flag obsolete, use #undefined in spec file to "
"list expected undefined symbol names");
case 'm':
if(strcmp(argv[i], "-minor_version") == 0){
if(i + 1 == argc){
error("argument for %s missing", argv[i]);
usage();
}
i++;
if(minor_version != 0)
fatal("minor_version already specified");
minor_version = atol(argv[i]);
if(minor_version <= 0)
fatal("minor_version value: %ld must be "
"greater than 0", minor_version);
break;
}
goto unknown_flag;
case 'i':
if(strcmp(argv[i], "-image_version") == 0){
if(i + 1 == argc){
error("argument for %s missing", argv[i]);
usage();
}
i++;
if(image_version != 0)
fatal("image_version already specified");
image_version = atol(argv[i]);
if(image_version <= 0)
fatal("image_version value: %ld must be "
"greater than 0", image_version);
break;
}
goto unknown_flag;
case 'v':
vflag++;
break;
case 'd':
dflag++;
break;
default:
if(strcmp(argv[i], "-u") == 0 ||
strcmp(argv[i], "-U") == 0){
if(i + 1 >= argc){
error("not enough arguments follow %s", argv[i]);
usage();
}
ldflags = reallocate(ldflags, sizeof(char * ) *
(nldflags + 2));
ldflags[nldflags++] = argv[i];
ldflags[nldflags++] = argv[i + 1];
i += 1;
break;
}
if(strncmp(argv[i], "-y", 2) == 0 ||
strcmp(argv[i], "-M") == 0 ||
strcmp(argv[i], "-noseglinkedit") == 0){
ldflags = reallocate(ldflags, sizeof(char * ) *
(nldflags + 1));
ldflags[nldflags++] = argv[i];
break;
}
unknown_flag:
error("unknown flag %s", argv[i]);
usage();
}
}
if(spec_filename == (char *)0){
error("no library specification file specified (use -s filename)");
usage();
}
if(!fflag && host_filename == (char *)0){
error("no host shared library file name specified (use -h "
"filename)");
usage();
}
if(target_filename == (char *)0){
error("no target shared library file name specified (use -t "
"filename)");
usage();
}
parse_spec();
libdef_sym();
target();
if(!fflag)
host();
if(errors)
cleanup(0);
return(EXIT_SUCCESS);
}
static
void
usage(void)
{
fprintf(stderr, "Usage: %s -s specfile -h hostfile -t targetfile "
"[options] ...\n", progname);
exit(EXIT_FAILURE);
}
static
void
libdef_sym(void)
{
char *p;
target_base_name = strrchr(target_name, '/');
if(target_base_name != (char *)0)
target_base_name++;
else
target_base_name = target_name;
shlib_symbol_name = makestr(SHLIB_SYMBOL_NAME, target_base_name,
(char *)0);
shlib_reference_name = makestr(target_base_name, (char *)0);
p = strchr(shlib_reference_name, '.');
if(p != NULL)
*p = '\0';
}
void
cleanup(
int sig)
{
if(!dflag){
unlink(branch_source_filename);
unlink(branch_object_filename);
unlink(lib_id_object_filename);
unlink(target_filename);
unlink(host_filename);
}
exit(EXIT_FAILURE);
}
char *
branch_slot_symbol(
long i)
{
static char buf[40];
sprintf(buf, "%s%ld", BRANCH_SLOT_NAME, i);
return(buf);
}
long
is_branch_slot_symbol(
char *p)
{
return(strncmp(p, BRANCH_SLOT_NAME, sizeof(BRANCH_SLOT_NAME) - 1) == 0);
}
long
is_libdef_symbol(
char *p)
{
return(strncmp(p, SHLIB_SYMBOL_NAME, sizeof(SHLIB_SYMBOL_NAME)-1) == 0);
}
long
run(void)
{
char *cmd, **ex, **p;
int forkpid, waitpid, termsig;
#ifndef __OPENSTEP__
int waitstatus;
#else
union wait waitstatus;
#endif
ex = runlist.strings;
cmd = runlist.strings[0];
if(vflag){
fprintf(stderr, "+ %s ", cmd);
p = &(ex[1]);
while(*p != (char *)0)
fprintf(stderr, "%s ", *p++);
fprintf(stderr, "\n");
}
forkpid = fork();
if(forkpid == -1)
system_fatal("can't fork a new process to run: %s", cmd);
if(forkpid == 0){
if(execvp(cmd, ex) == -1)
system_fatal("can't find or exec: %s", cmd);
}
else{
waitpid = wait(&waitstatus);
if(waitpid == -1)
system_fatal("wait on forked process %d failed", forkpid);
#ifndef __OPENSTEP__
termsig = WTERMSIG(waitstatus);
#else
termsig = waitstatus.w_termsig;
#endif
if(termsig != 0 && termsig != SIGINT)
fatal("fatal error in %s", cmd);
return(
#ifndef __OPENSTEP__
WEXITSTATUS(waitstatus) != 0 ||
#else
waitstatus.w_retcode != 0 ||
#endif
termsig != 0);
}
return(0);
}
void
add_runlist(
char *str)
{
if(runlist.strings == (char **)0){
runlist.next = 0;
runlist.size = 128;
runlist.strings = allocate(runlist.size * sizeof(char **));
}
if(runlist.next + 1 >= runlist.size){
runlist.strings = reallocate(runlist.strings,
(runlist.size * 2) * sizeof(char **));
runlist.size *= 2;
}
runlist.strings[runlist.next++] = str;
runlist.strings[runlist.next] = (char *)0;
}
void
reset_runlist(void)
{
runlist.next = 0;
}