Minimal changes to get m6502 to compile (won't work)
[Apout.git] / aout.c
1 /* aout.c - parse and load the contents of a UNIX a.out file, for
2  * several flavours of PDP-11 UNIX
3  *
4  * $Revision: 1.51 $
5  * $Date: 2008/05/19 13:42:39 $
6  */
7 #include <assert.h>
8 #include <stdbool.h>
9 #include "defines.h"
10 #include "aout.h"
11
12 /* Array of 64K for data and instruction space */
13 u_int8_t *ispace, *dspace;      /* Instruction and Data spaces */
14 static u_int8_t darray[PDP_MEM_SIZE], iarray[PDP_MEM_SIZE];
15
16 #ifdef EMU211
17 /* 2.11BSD allows up to 16 8K overlays in the 0430 and 0431 a.out types.
18  * Each overlay is loaded at the first 8K `click' above the end of the
19  * main text. The following structures hold the overlays from the current
20  * a.out, if there are any. Missing overlays have size 0 and pointer NULL.
21  */
22 static struct {
23     u_int16_t size;
24     u_int8_t *ovlay;
25 } ovlist[NOVL] = {
26     {
27         0, NULL
28     }, {
29         0, NULL
30     }, {
31         0, NULL
32     }, {
33         0, NULL
34     }, {
35         0, NULL
36     }, {
37         0, NULL
38     }, {
39         0, NULL
40     }, {
41         0, NULL
42     }, {
43         0, NULL
44     }, {
45         0, NULL
46     }, {
47         0, NULL
48     }, {
49         0, NULL
50     }, {
51         0, NULL
52     }, {
53         0, NULL
54     }, {
55         0, NULL
56     }
57 };
58
59 static u_int8_t *ovbase;        /* Base address of 2.11BSD overlays */
60 u_int32_t ov_changes = 0;       /* Number of overlay changes */
61 u_int8_t current_ov = 0;        /* Current overlay number */
62 #endif
63
64 /* Global array of pointers to arguments and environment. This
65  * allows load_a_out() to modify it when dealing with shell
66  * scripts, before calling set_arg_env()
67  */
68 char *Argv[MAX_ARGS], *Envp[MAX_ARGS];
69 int Argc, Envc;
70 int Binary;                     /* Type of binary this a.out is */
71
72 /* For programs without an environment, we set the environment statically.
73  * Eventually there will be code to get some environment variables
74  */
75 static char *default_envp[4] = {
76     "PATH=/bin:/usr/bin:/usr/sbin:/usr/ucb:/usr/games:/usr/local/bin:.",
77     "HOME=/",
78     "TERM=vt100",
79     "USER=root"
80 };
81
82 static int default_envc = 4;
83
84 /* Prototypes */
85 static void set_arg_env(int want_env);
86
87
88 /* Load the a.out header from the given file pointer, and return it.
89  * Also return an integer describing which version of UNIX the a.out
90  * belongs to. If errors on reading, return -1.
91  */
92 int load_aout_header(FILE * zin, struct exec *E)
93 {
94     char *cptr;
95
96     /* Read the a_magic value first */
97     /* This makes it easier to deal with */
98     /* parsing any script interpreter below */
99     if (fread(E, sizeof(u_int16_t), 1, zin) != 1)
100         return (-1);
101
102     switch (E->a_magic) {
103     case ANY_SCRIPT:    /* Shell script, return now */
104         return (IS_UNKNOWN);
105     case V1_NORMAL:
106     case ANY_NORMAL:    /* These are recognised below */
107     case ANY_ROTEXT:
108     case ANY_SPLITID:
109     case BSD_OVERLAY:
110     case BSD_ROVERLAY:
111     case A68_MAGIC:
112         break;
113
114     default:            /* Unrecognised binary, mark as such */
115         E->a_magic = UNKNOWN_AOUT;
116         return (IS_UNKNOWN);
117     }
118
119     /* We can deal with this a.out, so */
120     /* read in the rest of the header */
121     cptr = (char *) &(E->a_text);
122     if (fread(cptr, 1, sizeof(struct exec) - sizeof(u_int16_t), zin)
123             < 16 - sizeof(u_int16_t))
124         return (-1);
125
126     switch (E->a_magic) {
127     case A68_MAGIC:
128         if (E->a_data == A68_DATA)
129             return (IS_A68);
130         else {
131             E->a_magic = UNKNOWN_AOUT;
132             return (IS_UNKNOWN);
133         }
134     case V1_NORMAL:
135         return (IS_V1);
136     case BSD_OVERLAY:
137     case BSD_ROVERLAY:
138         return (IS_211BSD);
139     case ANY_NORMAL:
140     case ANY_ROTEXT:
141     case ANY_SPLITID:   /* Check crt0.o 2nd magic for V2/V6/V7/2.11BSD */
142         if (E->a_magic2 == V2_M2)
143             return (IS_V2);
144         if (E->a_magic2 == V6_M2)
145             return (IS_V6);
146         if (E->a_magic2 == V7_M2)
147             return (IS_V7);
148         if (E->a_magic2 == BSD_M2)
149             return (IS_211BSD);
150
151         /* Still no idea, use checksum to determine */
152         return (special_magic((u_int16_t *) E));
153
154     default:            /* Should never get here */
155         E->a_magic = UNKNOWN_AOUT;
156         return (IS_UNKNOWN);
157     }
158 }
159
160
161 /* Read in the executable name and its arguments from the shell script,
162  * and the re-call load_a_out to load in that binary. Returns 0 on
163  * success, -1 on error. Input file is always closed by this routine.
164  */
165 int load_script(const char *file, const char *origpath, FILE * zin,
166                 int want_env)
167 {
168 #define SCRIPT_LINESIZE 512     /* Max size of 1st line in script */
169     char *script_line;
170     char *script_arg[MAX_ARGS];
171     int i, script_cnt = 0;
172     char **ap;
173
174     for (i = 0; i < Argc; i++)
175         TrapDebug((dbg_file, "In load_script Argv[%d] is %s\n", i,
176                    Argv[i]));
177     /* Get the first line of the file */
178     if (((script_line = (char *) malloc(SCRIPT_LINESIZE)) == NULL) ||
179             (fgets(script_line, SCRIPT_LINESIZE, zin) == NULL)) {
180         (void) fprintf(stderr,
181                        "Apout - could not read 1st line of script\n");
182         (void) fclose(zin);
183         return (-1);
184     }
185     /* Now break into separate words */
186     for (ap = script_arg; (*ap = strsep(&script_line, " \t\n")) != NULL;)
187         if (**ap != '\0') {
188             ap++;
189             script_cnt++;
190             if (script_cnt >= MAX_ARGS)
191                 break;
192         }
193     if (fclose(zin) != 0) {
194         free(script_line);
195         return (-1);
196     }
197 #ifdef DEBUG
198     TrapDebug((dbg_file, "Script: extra args are is %d\n", script_cnt));
199     if (trap_debug) {
200         for (i = 0; i < script_cnt; i++)
201             fprintf(dbg_file, " script_arg[%d] is %s\n", i, script_arg[i]);
202     }
203 #endif
204
205     /* Ensure we have room to shift the args */
206     if ((Argc + script_cnt) > MAX_ARGS) {
207         (void) fprintf(stderr, "Apout - out of argv space in script\n");
208         free(script_line);
209         return (-1);
210     }
211     /* Now shift the args up and insert new ones */
212     for (i = Argc - 1; i != 0; i--)
213         Argv[i + script_cnt] = Argv[i];
214     for (i = 0; i < Argc; i++)
215         TrapDebug((dbg_file, "Part A load_script Argv[%d] is %s\n", i,
216                    Argv[i]));
217     for (i = 0; i < script_cnt; i++)
218         Argv[i] = script_arg[i];
219     if (origpath != NULL)
220         Argv[i] = strdup(origpath);
221     else
222         Argv[i] = strdup(file);
223     Argc += script_cnt;
224     for (i = 0; i < Argc; i++)
225         TrapDebug((dbg_file, "Part B load_script Argv[%d] is %s\n", i,
226                    Argv[i]));
227
228     file = xlate_filename(script_arg[0]);
229     free(script_line);
230     for (i = 0; i < Argc; i++)
231         TrapDebug((dbg_file, "Leaving load_script Argv[%d] is %s\n", i,
232                    Argv[i]));
233     return (load_a_out(file, origpath, want_env));
234 }
235
236
237 /* Load the named PDP-11 executable file into the emulator's memory.
238  * Returns 0 if ok, -1 if error. Also initialise the simulator and set
239  * up the stack for the process with Argc, Argv, Envc, Envp.
240  * origpath is the path to the executable as seen by the simulated
241  * parent, or NULL if this is not known.
242  */
243 int load_a_out(const char *file, const char *origpath, int want_env)
244 {
245 #ifdef CPU_PDP11
246     /* @globals errno,stdout,stderr; @ */
247 #define V12_MEMBASE 16384       /* Offset for V1/V2 binaries load */
248     FILE *zin;
249     struct exec e;
250     u_int8_t *ibase, *dbase, *bbase;    /* Instruction, data, bss bases */
251     u_int16_t size;
252     int i;
253 #ifdef EMU211
254     int j;
255 #endif
256 #ifdef RUN_V1_RAW
257     struct stat stb;
258 #endif
259
260     for (i = 0; i < Argc; i++)
261         TrapDebug((dbg_file, "In load_a_out Argv[%d] is %s\n", i,
262                    Argv[i]));
263
264     (void) signal(SIGBUS, bus_error);   /* Catch all bus errors here */
265
266     if ((zin = fopen(file, "r")) == NULL)       /* Open the file */
267         return (-1);
268
269     Binary = load_aout_header(zin, &e); /* Determine a.out & Unix type */
270
271     if (e.a_magic == ANY_SCRIPT) {      /* Shell script, run that */
272         return (load_script(file, origpath, zin, want_env));
273     }
274 #ifndef EMU211
275     if (Binary == IS_211BSD) {
276         (void) fprintf(stderr,
277                        "Apout not compiled to support 2.11BSD binaries\n");
278         (void) fclose(zin);
279         return (-1);
280     }
281 #endif
282 #ifndef EMUV1
283     if (Binary == IS_V1) {
284         (void) fprintf(stderr,
285                        "Apout not compiled to support 1st Edition binaries\n");
286         (void) fclose(zin);
287         return (-1);
288     }
289     if (Binary == IS_V2) {
290         (void) fprintf(stderr,
291                        "Apout not compiled to support 2nd Edition binaries\n");
292         (void) fclose(zin);
293         return (-1);
294     }
295 #endif
296
297 #ifdef NATIVES
298     /* Executable was not recognised.
299      * Try to exec it as a native binary.
300      * If it fails, doesn't matter. If it
301      * succeeds, then great. This allows
302      * us to have mixed native and PDP-11
303      * binaries in the same filespace.
304      */
305     if (e.a_magic == UNKNOWN_AOUT) {
306 #ifdef DEBUG
307         TrapDebug((dbg_file, "About to try native exec on %s\n", file));
308         fflush(dbg_file);
309 #endif
310         (void) fclose(zin);
311         execv(file, Argv);      /* envp[] is the one Apout's main() got */
312         TrapDebug((dbg_file, "Nope, didn't work\n"));
313 #endif
314
315 #ifdef RUN_V1_RAW
316         /* Try to run it as a V1 raw binary */
317 #ifdef DEBUG
318         TrapDebug((dbg_file, "About to try PDP-11 raw exec on %s\n",
319                    file));
320         fflush(dbg_file);
321 #endif                          /* DEBUG */
322         if ((zin = fopen(file, "r")) == NULL)   /* reopen the file */
323             return (-1);
324         e.a_magic = V1_RAW;
325         Binary = IS_V1;
326 #else
327         (void) fprintf(stderr, "Apout - unknown a.out file %s\n", file);
328         return (-1);
329 #endif                          /* RUN_V1_RAW */
330     }
331     /* Now we know what environment to
332      * create, set up the memory areas
333      * according to the magic numbers
334      */
335 #ifdef DEBUG
336     switch (Binary) {
337     case IS_A68:
338         TrapDebug((dbg_file, "A68 binary\n"));
339         break;
340     case IS_V1:
341         TrapDebug((dbg_file, "V1 binary\n"));
342         break;
343     case IS_V2:
344         TrapDebug((dbg_file, "V2 binary\n"));
345         break;
346     case IS_V5:
347         TrapDebug((dbg_file, "V5 binary\n"));
348         break;
349     case IS_V6:
350         TrapDebug((dbg_file, "V6 binary\n"));
351         break;
352     case IS_V7:
353         TrapDebug((dbg_file, "V7 binary\n"));
354         break;
355     case IS_211BSD:
356         TrapDebug((dbg_file, "2.11BSD binary\n"));
357         break;
358     }
359 #endif
360
361     switch (e.a_magic) {
362 #ifdef RUN_V1_RAW
363     case V1_RAW:
364         if (fseek(zin, 0, SEEK_SET) != 0) {
365             (void) fclose(zin);
366             return (-1);
367         }
368         ispace = dspace = darray;
369         ibase = &(ispace[V12_MEMBASE]); /* Load & run the binary starting */
370         dbase = ibase;  /* at address 16384 (040000) */
371         dwrite_base = 0;
372         e.a_entry = V12_MEMBASE;
373         /* Reset the exec header fields to make loading code below
374          * work properly
375          */
376         if (stat(file, &stb)) {
377             fprintf(stderr, "Apout - cannot stat %s\n", file);
378             return -1;
379         }
380         e.a_text = stb.st_size;
381         bbase = &(ispace[V12_MEMBASE + e.a_text]);
382         e.a_data = 0;
383         break;
384 #endif
385 #ifdef EMUV1
386     case V1_NORMAL:     /* V1 a.out binary looks like */
387         e.a_bss = e.a_syms;     /* 0405                       */
388         e.a_syms = e.a_data;    /* size of text               */
389         e.a_data = 0;   /* size of symbol table       */
390         /* reloc bits                 */
391         /* size of data (i.e bss)     */
392         /* unused and zeroed          */
393         /* We must rearrange fields   */
394         /* Move back to start of V1 header */
395         if (fseek(zin, 0, SEEK_SET) != 0) {
396             (void) fclose(zin);
397             return (-1);
398         }
399         ispace = dspace = darray;
400         ibase = &(ispace[V12_MEMBASE]); /* Load & run the binary starting */
401         dbase = &(ispace[e.a_text]);    /* at address 16384 (040000) */
402         bbase = &(ispace[e.a_text + e.a_data]);
403         dwrite_base = 0;
404         e.a_entry = V12_MEMBASE;
405         break;
406 #endif
407     case A68_MAGIC:     /* Algol 68 image */
408         if (fseek(zin, 0, SEEK_SET) != 0) {
409             (void) fclose(zin);
410             return (-1);
411         }
412         e.a_text = e.ov_siz[0] + 1;
413         e.a_data = 0;
414         e.a_bss = 0160000 - e.a_text;
415         e.a_entry = e.a_flag;
416         ibase = ispace = dspace = darray;
417         dbase = ibase;
418         dwrite_base = 0;
419         bbase = &(ispace[e.a_text + e.a_data]);
420         break;
421     case ANY_NORMAL:
422         /* Move back to end of V5/6/7 header */
423         if (fseek(zin, 16, SEEK_SET) != 0) {
424             (void) fclose(zin);
425             return (-1);
426         }
427         ibase = ispace = dspace = darray;
428 #ifdef EMUV1
429         if (Binary == IS_V2) {
430             ibase = &(ispace[V12_MEMBASE]);
431             e.a_entry = V12_MEMBASE;
432             dbase = &(ispace[e.a_text + V12_MEMBASE]);
433             bbase = &(ispace[e.a_text + e.a_data + V12_MEMBASE]);
434         } else
435 #endif
436         {
437             dbase = &(ispace[e.a_text]);
438             bbase = &(ispace[e.a_text + e.a_data]);
439         }
440         if ((Binary < IS_V7))
441             dwrite_base = 0;
442         else
443             dwrite_base = e.a_text;
444         break;
445     case ANY_ROTEXT:
446         /* Move back to end of V5/6/7 header */
447         if (fseek(zin, 16, SEEK_SET) != 0) {
448             (void) fclose(zin);
449             return (-1);
450         }
451     /* @fallthrough@ */
452     case BSD_OVERLAY:
453         /* Round up text area to next 8K boundary */
454         if (e.a_text % EIGHT_K) {
455             size = EIGHT_K * (1 + e.a_text / EIGHT_K);
456         } else
457             size = e.a_text;
458         /* And the next 8K boundary if overlays! */
459         if (e.a_magic == BSD_OVERLAY) {
460             if (e.max_ovl % EIGHT_K) {
461                 size += EIGHT_K * (1 + e.max_ovl / EIGHT_K);
462             } else
463                 size += e.max_ovl;
464         }
465         ibase = ispace = dspace = darray;
466         dbase = &(ispace[size]);
467         bbase = &(ispace[size + e.a_data]);
468         dwrite_base = size;
469         break;
470     case ANY_SPLITID:
471         /* Move back to end of V5/6/7 header */
472         if (fseek(zin, 16, SEEK_SET) != 0) {
473             (void) fclose(zin);
474             return (-1);
475         }
476     /* @fallthrough@ */
477     case BSD_ROVERLAY:
478         ibase = ispace = iarray;
479         dbase = dspace = darray;
480         bbase = &(dspace[e.a_data]);
481
482         /* Try to stop null refs */
483         if (Binary == IS_211BSD)
484             dwrite_base = 0;
485         else
486             dwrite_base = 2;
487         break;
488     default:
489         (void) fprintf(stderr, "Apout - unknown a.out format 0%o\n",
490                        e.a_magic);
491         (void) fclose(zin);
492         return (-1);
493     }
494
495
496     /* Initialise the instruction table for our environment */
497     switch (Binary) {
498 #ifdef EMU211
499     case IS_211BSD:
500         for (i = 548; i < 552; i++)
501             itab[i] = bsdtrap;
502         break;
503 #endif
504 #ifdef EMUV1
505     case IS_V1:
506     case IS_V2:
507         for (i = 544; i < 548; i++)
508             itab[i] = rts;
509         for (i = 548; i < 552; i++)
510             itab[i] = v1trap;
511         break;
512 #endif
513     case IS_A68:
514         for (i = 544; i < 552; i++)
515             itab[i] = v7trap;
516         break;
517     case IS_V5:
518     case IS_V6:
519     case IS_V7:
520         for (i = 548; i < 552; i++)
521             itab[i] = v7trap;
522         break;
523     default:
524         fprintf(stderr, "Apout - unknown Unix version for %s\n", file);
525         exit(EXIT_FAILURE);
526     }
527
528 #ifdef ZERO_MEMORY
529     memset(darray, 0, PDP_MEM_SIZE);    /* Clear all memory */
530     if (ispace != dspace)
531         memset(iarray, 0, PDP_MEM_SIZE);
532 #endif
533
534     /* Now load the text into ibase */
535     for (size = e.a_text; size;) {
536         i = (int) fread(ibase, 1, (size_t) size, zin);
537         if (i == -1) {
538             (void) fclose(zin);
539             return (i);
540         }
541         size -= i;
542         ibase += i;
543     }
544
545 #ifdef EMU211
546     /* Now deal with any overlays */
547     if (Binary == IS_211BSD)
548         switch (e.a_magic) {
549         case BSD_OVERLAY:
550         case BSD_ROVERLAY:
551             /* Round up text area to next 8K boundary */
552             if (e.a_text % EIGHT_K) {
553                 size = EIGHT_K * (1 + e.a_text / EIGHT_K);
554             } else
555                 size = e.a_text;
556             ovbase = &ispace[size];
557
558             for (i = 0; i < NOVL; i++) {
559                 if (e.ov_siz[i] == 0) {
560                     ovlist[i].size = 0;
561                     ovlist[i].ovlay = NULL;
562                     continue;
563                 }
564                 /* Create memory for the overlay */
565                 ovlist[i].size = e.ov_siz[i];
566                 if (ovlist[i].ovlay)
567                     free(ovlist[i].ovlay);
568                 ovlist[i].ovlay = (u_int8_t *) malloc(e.ov_siz[i]);
569                 if (ovlist[i].ovlay == NULL) {
570                     fprintf(stderr, "Apout - can't malloc overlay!\n");
571                     exit(EXIT_FAILURE);
572                 }
573                 /* Load the overlay into memory */
574                 for (size = ovlist[i].size, ibase = ovlist[i].ovlay;
575                         size;) {
576                     j = fread(ibase, 1, size, zin);
577                     if (j == -1) {
578                         fclose(zin);
579                         return (j);
580                     }
581                     size -= j;
582                     ibase += j;
583                 }
584             }
585
586             /* And deal with the emt instructions */
587             for (i = 544; i < 548; i++)
588                 itab[i] = do_bsd_overlay;
589         }
590 #endif
591
592     /* Now load the data into dbase */
593     if (dbase)
594         for (size = e.a_data; size;) {
595             i = (int) fread(dbase, 1, (size_t) size, zin);
596             if (i == -1) {
597                 (void) fclose(zin);
598                 return (i);
599             }
600             size -= i;
601             dbase += i;
602         }
603
604     /* Now clear the bss */
605     if ((bbase != 0) && (e.a_bss != 0))
606         memset(bbase, 0, (size_t) e.a_bss);
607
608
609     /* Set up the registers and flags, and the stack */
610     (void) fclose(zin);
611     sim_init();
612     regs[PC] = e.a_entry;
613     if (Binary == IS_A68) {
614         regs[5] = e.max_ovl;
615         regs[4] = 0160000;
616     }
617     set_arg_env(want_env);
618     return (0);
619 #else
620  assert(false);
621 #endif
622 }
623
624 /*
625  * C runtime startoff.  When an a.out is loaded by the kernel, the kernel
626  * sets up the stack as follows:
627  *
628  *      _________________________________
629  *      | (NULL)                        | 0177776: top of memory
630  *      |-------------------------------|
631  *      |                               |
632  *      | environment strings           |
633  *      |                               |
634  *      |-------------------------------|
635  *      |                               |
636  *      | argument strings              |
637  *      |                               |
638  *      |-------------------------------|
639  *      | envv[envc] (NULL)             | end of environment vector tag, a 0
640  *      |-------------------------------|
641  *      | envv[envc-1]                  | pointer to last environment string
642  *      |-------------------------------|
643  *      | ...                           |
644  *      |-------------------------------|
645  *      | envv[0]                       | pointer to first environment string
646  *      |-------------------------------|
647  *      | argv[argc] (NULL)             | end of argument vector tag, a 0
648  *      |-------------------------------|
649  *      | argv[argc-1]                  | pointer to last argument string
650  *      |-------------------------------|
651  *      | ...                           |
652  *      |-------------------------------|
653  *      | argv[0]                       | pointer to first argument string
654  *      |-------------------------------|
655  * sp-> | argc                          | number of arguments
656  *      ---------------------------------
657  *
658  * Crt0 simply moves the argc down two places in the stack, calculates the
659  * the addresses of argv[0] and envv[0], putting those values into the two
660  * spaces opened up to set the stack up as main expects to see it.
661  *
662  * If want_env is set, create a stack by including environment variables:
663  * used by V7, 2.9BSD, 2.11BSD. Otherwise, don't create environment
664  * variables: used by V1 up to V6.
665  */
666 static void set_arg_env(int want_env)
667 {
668 #ifdef CPU_PDP11
669     int i, posn, len;
670     int eposn[MAX_ARGS];
671     int aposn[MAX_ARGS];
672
673     /* Set default environment if there is none */
674     if (Envp[0] == NULL) {
675         Envc = default_envc;
676         for (i = 0; i < Envc; i++)
677             Envp[i] = default_envp[i];
678     }
679 #ifdef DEBUG
680     /* Set up the program's name -- used for debugging */
681     if (progname)
682         free(progname);
683     progname = strdup(Argv[0]);
684
685     if (trap_debug) {
686         fprintf(dbg_file, "In set_arg_env, Argc is %d\n", Argc);
687         for (i = 0; i < Argc; i++)
688             fprintf(dbg_file, "  Argv[%d] is %s\n", i, Argv[i]);
689         for (i = 0; i < Envc; i++)
690             fprintf(dbg_file, "  Envp[%d] is %s\n", i, Envp[i]);
691     }
692 #endif
693
694     /* Now build the arguments and pointers on the stack */
695
696 #ifdef EMUV1
697     if ((Binary == IS_V1) || (Binary == IS_V2))
698         posn = KE11LO - 2;      /* Start below the KE11A */
699     else
700 #endif
701         posn = PDP_MEM_SIZE - 2;
702     sl_word(posn, 0);           /* Put a NULL on top of stack */
703
704     if (want_env == 1)
705         for (i = Envc - 1; i != -1; i--) {      /* For each env string */
706             len = strlen(Envp[i]) + 1;  /* get its length */
707             posn -= len;
708             memcpy(&dspace[posn], Envp[i], (size_t) len);
709             eposn[i] = posn;
710         }
711
712     for (i = Argc - 1; i != -1; i--) {  /* For each arg string */
713         len = strlen(Argv[i]) + 1;      /* get its length */
714         posn -= len;
715         memcpy(&dspace[posn], Argv[i], (size_t) len);
716         aposn[i] = posn;
717     }
718     posn -= 2;
719     sl_word(posn, 0);           /* Put a NULL at end of env array */
720
721     if (want_env == 1) {        /* For each env string */
722         for (i = Envc - 1; i != -1; i--) {
723             posn -= 2;          /* put a pointer to the string */
724             sl_word(posn, (u_int16_t) eposn[i]);
725         }
726         posn -= 2;
727     }
728     /* Put a NULL or -1 before arg ptrs */
729     if (want_env == 0)
730         sl_word(posn, -1)
731         else
732             sl_word(posn, 0);
733
734     for (i = Argc - 1; i != -1; i--) {  /* For each arg string */
735         posn -= 2;
736         sl_word(posn, (u_int16_t) aposn[i]);    /* put a ptr to the string */
737     }
738     posn -= 2;
739     sl_word(posn, (u_int16_t) Argc);    /* Save the count of args */
740     regs[SP] = (u_int16_t) posn;        /* and initialise the SP */
741 #else
742  assert(false);
743 #endif
744 }
745
746
747 #ifdef EMU211
748 /* This function probably belongs in bsdtrap.c, but all the vars are
749  * here, so why not!
750  *
751  * Deal with overlay changes which come in via an emt instruction.
752  */
753
754 void do_bsd_overlay()
755 {
756     int ov = regs[0] - 1;
757
758     if (ovlist[ov].size == 0) {
759         fprintf(stderr, "Apout - can't switch to empty overlay %d\n", ov);
760         exit(EXIT_FAILURE);
761     }
762     JsrDebug((dbg_file, "switching to overlay %d\n", ov));
763
764     /* Memcpy overlay into main ispace */
765     memcpy(ovbase, ovlist[ov].ovlay, ovlist[ov].size);
766     ov_changes++;
767     current_ov = ov;
768 }
769 #endif