/* aout.c - parse and load the contents of a UNIX a.out file, for * several flavours of PDP-11 UNIX * * $Revision: 1.50 $ * $Date: 2002/06/10 11:43:24 $ */ #include "defines.h" #include "aout.h" /* Array of 64K for data and instruction space */ static u_int8_t darray[PDP_MEM_SIZE], iarray[PDP_MEM_SIZE]; #ifdef EMU211 /* 2.11BSD allows up to 16 8K overlays in the 0430 and 0431 a.out types. * Each overlay is loaded at the first 8K `click' above the end of the * main text. The following structures hold the overlays from the current * a.out, if there are any. Missing overlays have size 0 and pointer NULL. */ static struct { u_int16_t size; u_int8_t *ovlay; } ovlist[NOVL] = { {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL} }; static u_int8_t *ovbase; /* Base address of 2.11BSD overlays */ u_int32_t ov_changes = 0; /* Number of overlay changes */ u_int8_t current_ov = 0; /* Current overlay number */ #endif /* Global array of pointers to arguments and environment. This * allows load_a_out() to modify it when dealing with shell * scripts, before calling set_arg_env() */ char *Argv[MAX_ARGS], *Envp[MAX_ARGS]; int Argc, Envc; int Binary; /* Type of binary this a.out is */ /* For programs without an environment, we set the environment statically. * Eventually there will be code to get some environment variables */ static char *default_envp[4] = { "PATH=/bin:/usr/bin:/usr/sbin:/usr/ucb:/usr/games:/usr/local/bin:.", "HOME=/", "TERM=vt100", "USER=root" }; static int default_envc = 4; /* Prototypes */ static void set_arg_env(int want_env); /* Load the a.out header from the given file pointer, and return it. * Also return an integer describing which version of UNIX the a.out * belongs to. If errors on reading, return -1. */ int load_aout_header(FILE * zin, struct exec * E) { char *cptr; /* Read the a_magic value first */ /* This makes it easier to deal with */ /* parsing any script interpreter below */ if (fread(E, sizeof(u_int16_t), 1, zin) != 1) return (-1); switch (E->a_magic) { case ANY_SCRIPT: /* Shell script, return now */ return (IS_UNKNOWN); case V1_NORMAL: case ANY_NORMAL: /* These are recognised below */ case ANY_ROTEXT: case ANY_SPLITID: case BSD_OVERLAY: case BSD_ROVERLAY: case A68_MAGIC: break; default: /* Unrecognised binary, mark as such */ E->a_magic = UNKNOWN_AOUT; return (IS_UNKNOWN); } /* We can deal with this a.out, so */ /* read in the rest of the header */ cptr = (char *) &(E->a_text); if (fread(cptr, sizeof(struct exec) - sizeof(u_int16_t), 1, zin) != 1) return (-1); switch (E->a_magic) { case A68_MAGIC: if (E->a_data==A68_DATA) return(IS_A68); else { E->a_magic = UNKNOWN_AOUT; return (IS_UNKNOWN); } case V1_NORMAL: return (IS_V1); case BSD_OVERLAY: case BSD_ROVERLAY: return (IS_211BSD); case ANY_NORMAL: case ANY_ROTEXT: case ANY_SPLITID: /* Check crt0.o 2nd magic for V2/V6/V7/2.11BSD */ if (E->a_magic2 == V2_M2) return (IS_V2); if (E->a_magic2 == V6_M2) return (IS_V6); if (E->a_magic2 == V7_M2) return (IS_V7); if (E->a_magic2 == BSD_M2) return (IS_211BSD); /* Still no idea, use checksum to determine */ return(special_magic((u_int16_t *) E)); default: /* Should never get here */ E->a_magic = UNKNOWN_AOUT; return (IS_UNKNOWN); } } /* Read in the executable name and its arguments from the shell script, * and the re-call load_a_out to load in that binary. Returns 0 on * success, -1 on error. Input file is always closed by this routine. */ int load_script(const char *file, const char *origpath,FILE * zin, int want_env) { #define SCRIPT_LINESIZE 512 /* Max size of 1st line in script */ char *script_line; char *script_arg[MAX_ARGS]; int i, script_cnt = 0; char **ap; for (i=0;i= MAX_ARGS) break; } if (fclose(zin) != 0) { free(script_line); return (-1); } #ifdef DEBUG TrapDebug((dbg_file, "Script: extra args are is %d\n", script_cnt)); if (trap_debug) { for (i = 0; i < script_cnt; i++) fprintf(dbg_file, " script_arg[%d] is %s\n", i, script_arg[i]); } #endif /* Ensure we have room to shift the args */ if ((Argc + script_cnt) > MAX_ARGS) { (void) fprintf(stderr, "Apout - out of argv space in script\n"); free(script_line); return (-1); } /* Now shift the args up and insert new ones */ for (i = Argc - 1; i != 0; i--) Argv[i + script_cnt] = Argv[i]; for (i=0;i | argc | number of arguments * --------------------------------- * * Crt0 simply moves the argc down two places in the stack, calculates the * the addresses of argv[0] and envv[0], putting those values into the two * spaces opened up to set the stack up as main expects to see it. * * If want_env is set, create a stack by including environment variables: * used by V7, 2.9BSD, 2.11BSD. Otherwise, don't create environment * variables: used by V1 up to V6. */ static void set_arg_env(int want_env) { int i, posn, len; int eposn[MAX_ARGS]; int aposn[MAX_ARGS]; /* Set default environment if there is none */ if (Envp[0] == NULL) { Envc = default_envc; for (i = 0; i < Envc; i++) Envp[i] = default_envp[i]; } #ifdef DEBUG /* Set up the program's name -- used for debugging */ if (progname) free(progname); progname = strdup(Argv[0]); if (trap_debug) { fprintf(dbg_file, "In set_arg_env, Argc is %d\n", Argc); for (i = 0; i < Argc; i++) fprintf(dbg_file, " Argv[%d] is %s\n", i, Argv[i]); for (i = 0; i < Envc; i++) fprintf(dbg_file, " Envp[%d] is %s\n", i, Envp[i]); } #endif /* Now build the arguments and pointers on the stack */ #ifdef EMUV1 if ((Binary == IS_V1) || (Binary == IS_V2)) posn = KE11LO - 2; /* Start below the KE11A */ else #endif posn = PDP_MEM_SIZE - 2; sl_word(posn, 0); /* Put a NULL on top of stack */ if (want_env == 1) for (i = Envc - 1; i != -1; i--) { /* For each env string */ len = strlen(Envp[i]) + 1; /* get its length */ posn -= len; memcpy(&dspace[posn], Envp[i], (size_t) len); eposn[i] = posn; } for (i = Argc - 1; i != -1; i--) { /* For each arg string */ len = strlen(Argv[i]) + 1; /* get its length */ posn -= len; memcpy(&dspace[posn], Argv[i], (size_t) len); aposn[i] = posn; } posn -= 2; sl_word(posn, 0); /* Put a NULL at end of env array */ if (want_env == 1) { /* For each env string */ for (i = Envc - 1; i != -1; i--) { posn -= 2; /* put a pointer to the string */ sl_word(posn, (u_int16_t) eposn[i]); } posn -= 2; } /* Put a NULL or -1 before arg ptrs */ if (want_env == 0) sl_word(posn, -1) else sl_word(posn, 0); for (i = Argc - 1; i != -1; i--) { /* For each arg string */ posn -= 2; sl_word(posn, (u_int16_t) aposn[i]); /* put a ptr to the string */ } posn -= 2; sl_word(posn, (u_int16_t) Argc); /* Save the count of args */ regs[SP] = (u_int16_t) posn; /* and initialise the SP */ } #ifdef EMU211 /* This function probably belongs in bsdtrap.c, but all the vars are * here, so why not! * * Deal with overlay changes which come in via an emt instruction. */ void do_bsd_overlay() { int ov = regs[0] - 1; if (ovlist[ov].size == 0) { fprintf(stderr, "Apout - can't switch to empty overlay %d\n", ov); exit(EXIT_FAILURE); } JsrDebug((dbg_file, "switching to overlay %d\n", ov)); /* Memcpy overlay into main ispace */ memcpy(ovbase, ovlist[ov].ovlay, ovlist[ov].size); ov_changes++; current_ov = ov; } #endif