1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
|
; SCCSID = @(#)exec.asm 1.3 85/08/13
; SCCSID = @(#)exec.asm 1.3 85/08/13
; AN000 version 4.0 jan. 1988
; A007 PTM 3957 - fake vesrion for IBMCACHE.COM
; A008 PTM 4070 - fake version for MS WINDOWS
SUBTTL $exec - load/go a program
PAGE
;
; Assembler usage:
; LDS DX, name
; LES BX, blk
; MOV AH, Exec
; MOV AL, func
; INT int_command
;
; AL Function
; -- --------
; 0 Load and execute the program.
; 1 Load, create the program header but do not
; begin execution.
; 3 Load overlay. No header created.
;
; AL = 0 -> load/execute program
;
; +---------------------------+
; | WORD segment address of |
; | environment. |
; +---------------------------+
; | DWORD pointer to ASCIZ |
; | command line at 80h |
; +---------------------------+
; | DWORD pointer to default |
; | FCB to be passed at 5Ch |
; +---------------------------+
; | DWORD pointer to default |
; | FCB to be passed at 6Ch |
; +---------------------------+
;
; AL = 1 -> load program
;
; +---------------------------+
; | WORD segment address of |
; | environment. |
; +---------------------------+
; | DWORD pointer to ASCIZ |
; | command line at 80h |
; +---------------------------+
; | DWORD pointer to default |
; | FCB to be passed at 5Ch |
; +---------------------------+
; | DWORD pointer to default |
; | FCB to be passed at 6Ch |
; +---------------------------+
; | DWORD returned value of |
; | CS:IP |
; +---------------------------+
; | DWORD returned value of |
; | SS:IP |
; +---------------------------+
;
; AL = 3 -> load overlay
;
; +---------------------------+
; | WORD segment address where|
; | file will be loaded. |
; +---------------------------+
; | WORD relocation factor to |
; | be applied to the image. |
; +---------------------------+
;
; Returns:
; AX = error_invalid_function
; = error_bad_format
; = error_bad_environment
; = error_not_enough_memory
; = error_file_not_found
;
; Revision history:
;
; A000 version 4.00 Jan. 1988
;
include EA.INC
include version.inc
I_Need Temp_Var2,WORD ;AN000;file type from $open
I_Need Special_Entries,WORD ;AN007;address of special entries
I_Need Special_Version,WORD ;AN007;special version number
I_Need Fake_Count,BYTE ;AN008;fake version count
IF BUFFERFLAG
extrn restore_user_map:near
ENDIF
TABLE SEGMENT
exec_init_SP DW ?
exec_init_SS DW ?
exec_init_IP DW ?
exec_init_CS DW ?
exec_internal_buffer EQU OpenBuf
exec_signature DW ? ; must contain 4D5A (yay zibo!)
exec_len_mod_512 DW ? ; low 9 bits of length
exec_pages DW ? ; number of 512b pages in file
exec_rle_count DW ? ; count of reloc entries
exec_par_dir DW ? ; number of paragraphs before image
exec_min_BSS DW ? ; minimum number of para of BSS
exec_max_BSS DW ? ; max number of para of BSS
exec_SS DW ? ; stack of image
exec_SP DW ? ; SP of image
exec_chksum DW ? ; checksum of file (ignored)
exec_IP DW ? ; IP of entry
exec_CS DW ? ; CS of entry
exec_rle_table DW ? ; byte offset of reloc table
Exec_header_len EQU $-Exec_Signature
exec_internal_buffer_size EQU (128+128+53+curdirLEN)
%out Please make sure that the following are contiguous and of the
%out following sizes:
%out
%out OpenBuf 128
%out RenBuf 128
%out SearchBuf 53
%out DummyCDS CurDirLen
TABLE ENDS
.sall
procedure $Exec,NEAR
ASSUME DS:NOTHING, ES:NOTHING
PUBLIC EXEC001S,EXEC001E
EXEC001S:
LocalVar exec_blk,DWORD
LocalVar exec_func,BYTE
LocalVar exec_load_high,BYTE
LocalVar exec_fh,WORD
LocalVar exec_rel_fac,WORD
LocalVar exec_res_len_para,WORD
LocalVar exec_environ,WORD
LocalVar exec_size,WORD
LocalVar exec_load_block,WORD
LocalVar exec_dma,WORD
LocalVar execNameLen,WORD
LocalVar execName,DWORD
EXEC001E:
Enter
;
; validate function
;
CMP AL,3 ; only 0, 1 or 3 are allowed
JNA exec_check_2
exec_bad_fun:
MOV EXTERR_LOCUS,errLOC_Unk ; Extended Error Locus
mov al,error_invalid_function
exec_ret_err:
Leave
transfer SYS_RET_ERR
exec_check_2:
CMP AL,2
JZ exec_bad_fun
MOV exec_blkL,BX ; stash args
MOV exec_blkH,ES
MOV exec_func,AL
MOV exec_load_high,0
;
; set up length of exec name
;
MOV execNameL,DX
MOV execNameH,DS
MOV SI,DX ; move pointer to convenient place
invoke DStrLen
MOV ExecNameLen,CX ; save length
XOR AL,AL ; open for reading
PUSH BP
invoke $OPEN ; is the file there?
POP BP
JC exec_ret_err
;File Type Checking
; CMP BYTE PTR [Temp_Var2],EAEXISTING ;AN000;;FT. old file ?
; JZ oldexf ;AN000;;FT. yes
; TEST BYTE PTR EXEC_FUNC,EXEC_FUNC_OVERLAY ;AN000;;FT. exec overlay?
; JNZ exovrly ;AN000;;FT. yes
; CMP BYTE PTR [Temp_Var2],EAEXECUTABLE ;AN000;;FT. only file type
; JZ oldexf ;AN000;;FT. 3 & 4 will pass
; CMP BYTE PTR [Temp_Var2],EAINSTALLABLE ;AN000;;FT.
; JZ oldexf ;AN000;;FT.
;exerr: ;AN000;;FT.
; MOV AL,error_access_denied ;AN000;;FT. error
; JMP exec_ret_err ;AN000;;FT.
;exovrly: ;AN000;;FT.
; CMP BYTE PTR [Temp_Var2],EAOVERLAY ;AN000;;FT. only 5,6,7 pass
; JZ oldexf ;AN000;;FT.
; CMP BYTE PTR [Temp_Var2],EADEV_DRIVER ;AN000;;FT.
; JZ oldexf ;AN000;;FT.
; CMP BYTE PTR [Temp_Var2],EAIFS_DRIVER ;AN000;;FT.
; JNZ exerr ;AN000;;FT.
;
;oldexf: ;AN000;
;File Type Checking
MOV exec_fh,AX
MOV BX,AX
XOR AL,AL
invoke $IOCTL
JC Exec_bombJ
TEST DL,devid_ISDEV
JZ exec_check_environ
MOV AL,error_file_not_found
Exec_bombJ:
JMP Exec_Bomb
BadEnv:
MOV AL,error_bad_environment
JMP exec_bomb
exec_check_environ:
MOV exec_load_block,0
MOV exec_environ,0
TEST BYTE PTR exec_func,exec_func_overlay ; overlays... no environment
JNZ exec_read_header
LDS SI,exec_blk ; get block
MOV AX,[SI].Exec1_environ ; address of environ
OR AX,AX
JNZ exec_scan_env
MOV DS,CurrentPDB
MOV AX,DS:[PDB_environ]
MOV exec_environ,AX
OR AX,AX
JZ exec_read_header
exec_scan_env:
MOV ES,AX
XOR DI,DI
MOV CX,07FFFh ; at most 32k of environment
XOR AL,AL
exec_get_environ_len:
REPNZ SCASB ; find that nul byte
JNZ BadEnv
DEC CX ; Dec CX for the next nul byte test
JB BadEnv ; gone beyond the end of the environment
SCASB ; is there another nul byte?
JNZ exec_get_environ_len ; no, scan some more
PUSH DI
LEA BX,[DI+0Fh+2]
ADD BX,ExecNameLen ; BX <- length of environment
; remember argv[0] length
; round up and remember argc
MOV CL,4
SHR BX,CL ; number of paragraphs needed
PUSH ES
invoke $ALLOC ; can we get the space?
POP DS
POP CX
JNC exec_save_environ
JMP exec_no_mem ; nope... cry and sob
exec_save_environ:
MOV ES,AX
MOV exec_environ,AX ; save him for a rainy day
XOR SI,SI
MOV DI,SI
REP MOVSB ; copy the environment
MOV AX,1
STOSW
LDS SI,execName
MOV CX,execNameLen
REP MOVSB
exec_read_header:
;
; We read in the program header into the above data area and determine
; where in this memory the image will be located.
;
Context DS
MOV CX,exec_header_len ; header size
MOV DX,OFFSET DOSGROUP:exec_signature
PUSH ES
PUSH DS
CALL ExecRead
POP DS
POP ES
JC exec_bad_file
OR AX,AX
JZ exec_bad_file
CMP AX,exec_header_len ; did we read the right number?
JNZ exec_com_filej ; yep... continue
TEST exec_max_BSS,-1 ; indicate load high?
JNZ exec_check_sig
MOV exec_load_high,-1
exec_check_sig:
MOV AX,exec_signature
CMP AX,exe_valid_signature ; zibo arises!
JZ exec_save_start ; assume com file if no signature
CMP AX,exe_valid_old_signature ; zibo arises!
JZ exec_save_start ; assume com file if no signature
exec_com_filej:
JMP exec_com_file
;
; We have the program header... determine memory requirements
;
exec_save_start:
MOV AX,exec_pages ; get 512-byte pages
MOV CL,5 ; convert to paragraphs
SHL AX,CL
SUB AX,exec_par_dir ; AX = size in paragraphs
MOV exec_res_len_para,AX
;
; Do we need to allocate memory? Yes if function is not load-overlay
;
TEST BYTE PTR exec_func,exec_func_overlay
JZ exec_allocate ; allocation of space
;
; get load address from block
;
LES DI,exec_blk
MOV AX,ES:[DI].exec3_load_addr
MOV exec_dma,AX
MOV AX,ES:[DI].exec3_reloc_fac
MOV exec_rel_fac,AX
IF DEBUG
JMP exec_find_res
ELSE
JMP SHORT exec_find_res
ENDIF
exec_no_mem:
MOV AL,error_not_enough_memory
JMP SHORT exec_bomb
exec_bad_file:
MOV AL,error_bad_format
exec_bomb:
ASSUME DS:NOTHING,ES:NOTHING
MOV BX,exec_fh
CALL exec_dealloc
LeaveCrit CritMem
SaveReg <AX,BP>
invoke $CLOSE
RestoreReg <BP,AX>
JMP Exec_Ret_Err
exec_allocate:
DOSAssume CS,<DS>,"EXEC/exec_allocate"
PUSH AX
MOV BX,0FFFFh ; see how much room in arena
PUSH DS
invoke $ALLOC ; should have carry set and BX has max
POP DS
POP AX
ADD AX,10h ; room for header
CMP BX,11h ; enough room for a header
JB exec_no_mem
CMP AX,BX ; is there enough for bare image?
JA exec_no_mem
TEST exec_load_high,-1 ; if load high, use max
JNZ exec_BX_max ; use max
ADD AX,exec_min_BSS ; go for min allocation
JC exec_no_mem ; oops! carry
CMP AX,BX ; enough space?
JA exec_no_mem ; nope...
SUB AX,exec_min_BSS
ADD AX,exec_max_BSS ; go for the MAX
JC exec_BX_max
CMP AX,BX
JBE exec_got_block
exec_BX_max:
MOV AX,BX
exec_got_block:
PUSH DS
MOV BX,AX
MOV exec_size,BX
invoke $ALLOC ; get the space
POP DS
JC exec_no_mem
MOV exec_load_block,AX
ADD AX,10h
TEST exec_load_high,-1
JZ exec_use_ax ; use ax for load info
ADD AX,exec_size ; go to end
SUB AX,exec_res_len_para ; drop off header
SUB AX,10h ; drop off pdb
exec_use_ax:
MOV exec_rel_fac,AX ; new segment
MOV exec_dma,AX ; beginning of dma
;
; Determine the location in the file of the beginning of the resident
;
exec_find_res:
MOV DX,exec_par_dir
PUSH DX
MOV CL,4
SHL DX,CL ; low word of location
POP AX
MOV CL,12
SHR AX,CL ; high word of location
MOV CX,AX ; CX <- high
;
; Read in the resident image (first, seek to it)
;
MOV BX,exec_fh
PUSH DS
XOR AL,AL
invoke $LSEEK ; seek to resident
POP DS
jnc exec_big_read
jmp exec_bomb
exec_big_read: ; Read resident into memory
MOV BX,exec_res_len_para
CMP BX,1000h ; too many bytes to read?
JB exec_read_ok
MOV BX,0FE0h ; max in one chunk FE00 bytes
exec_read_ok:
SUB exec_res_len_para,BX ; we read (soon) this many
PUSH BX
MOV CL,4
SHL BX,CL ; get count in bytes from paras
MOV CX,BX ; count in correct register
PUSH DS
MOV DS,exec_dma ; Set up read buffer
ASSUME DS:NOTHING
XOR DX,DX
PUSH CX ; save our count
CALL ExecRead
POP CX ; get old count to verify
POP DS
JC exec_bad_fileJ
DOSAssume CS,<DS>,"EXEC/exec_read_ok"
CMP CX,AX ; did we read enough?
POP BX ; get paragraph count back
JZ execCheckEnd ; and do reloc if no more to read
;
; The read did not match the request. If we are off by 512 bytes or more
; then the header lied and we have an error.
;
SUB CX,AX
CMP CX,512
JAE Exec_Bad_fileJ
;
; We've read in CX bytes... bump DTA location
;
ExecCheckEnd:
ADD exec_dma,BX ; bump dma address
TEST exec_res_len_para,-1
JNZ exec_big_read
;
; The image has now been read in. We must perform relocation to
; the current location.
;
exec_do_reloc:
MOV CX,exec_rel_fac
MOV AX,exec_SS ; get initial SS
ADD AX,CX ; and relocate him
MOV exec_init_SS,AX
MOV AX,exec_SP ; initial SP
MOV exec_init_SP,AX
LES AX,DWORD PTR exec_IP
MOV exec_init_IP,AX
MOV AX,ES
ADD AX,CX ; relocated...
MOV exec_init_CS,AX
XOR CX,CX
MOV DX,exec_rle_table
MOV BX,exec_fh
PUSH DS
XOR AX,AX
invoke $LSEEK
POP DS
JNC exec_get_entries
exec_bad_filej:
JMP exec_bad_file
exec_get_entries:
MOV DX,exec_rle_count ; Number of entries left
exec_read_reloc:
ASSUME DS:NOTHING
PUSH DX
MOV DX,OFFSET DOSGROUP:exec_internal_buffer
MOV CX,((exec_internal_buffer_size)/4)*4
PUSH DS
CALL ExecRead
POP ES
POP DX
JC exec_bad_filej
MOV CX,(exec_internal_buffer_size)/4
MOV DI,OFFSET DOSGROUP:exec_internal_buffer ; Pointer to byte location in header
;
; Relocate a single address
;
MOV SI,exec_rel_fac
exec_reloc_one:
OR DX,DX ; Any more entries?
JE exec_set_PDBJ
exec_get_addr:
LDS BX,DWORD PTR ES:[DI] ; Get ra/sa of entry
MOV AX,DS ; Relocate address of item
ADD AX,SI
MOV DS,AX
ADD [BX],SI
ADD DI,4
DEC DX
LOOP exec_reloc_one ; End of internal buffer?
;
; We've exhausted a single buffer's worth. Read in the next piece
; of the relocation table.
;
PUSH ES
POP DS
JMP exec_read_reloc
exec_set_PDBJ:
JMP exec_set_PDB
exec_no_memj:
JMP exec_no_mem
;
; we have a .COM file. First, determine if we are merely loading an overlay.
;
exec_com_file:
TEST BYTE PTR exec_func,exec_func_overlay
JZ exec_alloc_com_file
LDS SI,exec_blk ; get arg block
LODSW ; get load address
MOV exec_dma,AX
MOV AX,0FFFFh
JMP SHORT exec_read_block ; read it all!
; We must allocate the max possible size block (ick!) and set up
; CS=DS=ES=SS=PDB pointer, IP=100, SP=max size of block.
;
exec_alloc_com_file:
MOV BX,0FFFFh
invoke $ALLOC ; largest piece available as error
OR BX,BX
JZ exec_no_memj
MOV exec_size,BX ; save size of allocation block
PUSH BX
invoke $ALLOC ; largest piece available as error
POP BX ; get size of block...
MOV exec_load_block,AX
ADD AX,10h ; increment for header
MOV exec_dma,AX
XOR AX,AX ; presume 64K read...
CMP BX,1000h ; 64k or more in block?
JAE exec_read_com ; yes, read only 64k
MOV AX,BX ; convert size to bytes
MOV CL,4
SHL AX,CL
exec_read_com:
SUB AX,100h ; remember size of psp
exec_read_block:
PUSH AX ; save number to read
MOV BX,exec_fh ; of com file
XOR CX,CX ; but seek to 0:0
MOV DX,CX
XOR AX,AX ; seek relative to beginning
invoke $LSEEK ; back to beginning of file
POP CX ; number to read
MOV DS,exec_dma
XOR DX,DX
PUSH CX
CALL ExecRead
POP SI ; get number of bytes to read
jnc OkRead
jmp exec_bad_file
OkRead:
CMP AX,SI ; did we read them all?
JZ exec_no_memj ; exactly the wrong number... no memory
TEST BYTE PTR exec_func,exec_func_overlay
JNZ exec_set_PDB ; no starto, chumo!
MOV AX,exec_DMA
SUB AX,10h
MOV exec_init_CS,AX
MOV exec_init_IP,100h ; initial IP is 100
;
; SI is at most FF00h. Add FE to account for PSP - word of 0 on stack.
;
ADD SI,0FEh ; make room for stack
MOV exec_init_SP,SI ; max value for read is also SP!
MOV exec_init_SS,AX
MOV DS,AX
MOV WORD PTR [SI],0 ; 0 for return
exec_set_PDB:
MOV BX,exec_fh ; we are finished with the file.
CALL exec_dealloc
PUSH BP
invoke $CLOSE ; release the jfn
POP BP
CALL exec_alloc
TEST BYTE PTR exec_func,exec_func_overlay
JZ exec_build_header
CALL Scan_Execname ;MS.;AN007;
CALL Scan_Special_Entries ;MS.;AN007;
Leave
transfer SYS_RET_OK ; overlay load -> done
exec_build_header:
MOV DX,exec_load_block
;
; assign the space to the process
;
MOV SI,arena_owner ; pointer to owner field
MOV AX,exec_environ ; get environ pointer
OR AX,AX
JZ NO_OWNER ; no environment
DEC AX ; point to header
MOV DS,AX
MOV [SI],DX ; assign ownership
NO_OWNER:
MOV AX,exec_load_block ; get load block pointer
DEC AX
MOV DS,AX ; point to header
MOV [SI],DX ; assign ownership
PUSH DS ;AN000;MS. make ES=DS
POP ES ;AN000;MS.
MOV DI,ARENA_NAME ;AN000;MS. ES:DI points to destination
CALL Scan_Execname ;AN007;MS. parse execname
; ds:si->name, cx=name length
PUSH CX ;AN007;;MS. save for fake version
PUSH SI ;AN007;;MS. save for fake version
movename: ;AN000;
LODSB ;AN000;;MS. get char
CMP AL,'.' ;AN000;;MS. is '.' ,may be name.exe
JZ mem_done ;AN000;;MS. no, move to header
;AN000;
STOSB ;AN000;;MS. move char
LOOP movename ;AN000;;MS. continue
mem_done: ;AN000;
XOR AL,AL ;AN000;;MS. make ASCIIZ
CMP DI,SIZE ARENA ;AN000;MS. if not all filled
JAE fill8 ;AN000;MS.
STOSB ;AN000;MS.
fill8: ;AN000;
POP SI ;AN007;MS. ds:si -> file name
POP CX ;AN007;MS.
CALL Scan_Special_Entries ;AN007;MS.
PUSH DX
MOV SI,exec_size
ADD SI,DX
invoke $Dup_PDB ; ES is now PDB
POP DX
PUSH exec_environ
POP ES:[PDB_environ]
;
; set up proper command line stuff
;
LDS SI,exec_blk ; get the block
PUSH DS ; save its location
PUSH SI
LDS SI,[SI.exec0_5C_FCB] ; get the 5c fcb
;
; DS points to user space 5C FCB
;
MOV CX,12 ; copy drive, name and ext
PUSH CX
MOV DI,5Ch
MOV BL,[SI]
REP MOVSB
;
; DI = 5Ch + 12 = 5Ch + 0Ch = 68h
;
XOR AX,AX ; zero extent, etc for CPM
STOSW
STOSW
;
; DI = 5Ch + 12 + 4 = 5Ch + 10h = 6Ch
;
POP CX
POP SI ; get block
POP DS
PUSH DS ; save (again)
PUSH SI
LDS SI,[SI.exec0_6C_FCB] ; get 6C FCB
;
; DS points to user space 6C FCB
;
MOV BH,[SI] ; do same as above
REP MOVSB
STOSW
STOSW
POP SI ; get block (last time)
POP DS
LDS SI,[SI.exec0_com_line] ; command line
;
; DS points to user space 80 command line
;
OR CL,80h
MOV DI,CX
REP MOVSB ; Wham!
;
; Process BX into default AX (validity of drive specs on args). We no longer
; care about DS:SI.
;
DEC CL ; get 0FFh in CL
MOV AL,BH
XOR BH,BH
invoke GetVisDrv
JNC exec_BL
MOV BH,CL
exec_BL:
MOV AL,BL
XOR BL,BL
invoke GetVisDrv
JNC exec_Set_Return
MOV BL,CL
exec_set_return:
invoke get_user_stack ; get his return address
PUSH [SI.user_CS] ; suck out the CS and IP
PUSH [SI.user_IP]
PUSH [SI.user_CS] ; suck out the CS and IP
PUSH [SI.user_IP]
POP WORD PTR ES:[PDB_Exit]
POP WORD PTR ES:[PDB_Exit+2]
XOR AX,AX
MOV DS,AX
POP DS:[addr_int_terminate] ; save them where we can get them later
POP DS:[addr_int_terminate+2] ; when the child exits.
MOV WORD PTR DMAADD,80h
MOV DS,CurrentPDB
MOV WORD PTR DMAADD+2,DS
TEST BYTE PTR exec_func,exec_func_no_execute
JZ exec_go
LDS SI,DWORD PTR exec_init_SP ; get stack
LES DI,exec_blk ; and block for return
MOV ES:[DI].exec1_SS,DS ; return SS
DEC SI ; 'push' default AX
DEC SI
MOV [SI],BX ; save default AX reg
MOV ES:[DI].exec1_SP,SI ; return 'SP'
LDS AX,DWORD PTR exec_init_IP
MOV ES:[DI].exec1_CS,DS ; initial entry stuff
MOV ES:[DI].exec1_IP,AX
Leave
transfer SYS_RET_OK
exec_go:
LDS SI,DWORD PTR exec_init_IP ; get entry point
LES DI,DWORD PTR exec_init_SP ; new stack
MOV AX,ES
;
; DS:SI points to entry point
; AX:DI points to initial stack
; DX has PDB pointer
; BX has initial AX value
;
CLI
MOV BYTE PTR INDOS,0
ASSUME SS:NOTHING
MOV SS,AX ; set up user's stack
MOV SP,DI ; and SP
STI
PUSH DS ; fake long call to entry
PUSH SI
MOV ES,DX ; set up proper seg registers
MOV DS,DX
MOV AX,BX ; set up proper AX
procedure exec_long_ret,FAR
IF BUFFERFLAG
invoke restore_user_map
ENDIF
RET
EndProc exec_long_ret
EndProc $Exec
Procedure ExecRead,NEAR
CALL exec_dealloc
MOV bx,exec_fh
PUSH BP
invoke $READ
POP BP
CALL exec_alloc
return
EndProc ExecRead
procedure exec_dealloc,near
ASSUME DS:NOTHING,ES:NOTHING
PUSH BX
MOV BX,arena_owner_system
EnterCrit CritMEM
CALL ChangeOwners
POP BX
return
EndProc exec_dealloc
procedure exec_alloc,near
PUSH BX
MOV BX,CurrentPDB
CALL ChangeOwners
LeaveCrit CritMEM
POP BX
return
EndProc exec_alloc
procedure ChangeOwners,NEAR
pushf
PUSH AX
MOV AX,exec_environ
CALL ChangeOwner
MOV AX,exec_load_block
Call ChangeOwner
POP AX
popf
return
EndProc ChangeOwners
Procedure ChangeOwner,near
OR AX,AX ; is area allocated?
retz ; no, do nothing
DEC AX
PUSH DS
MOV DS,AX
MOV DS:[arena_owner],BX
POP DS
return
EndProc ChangeOwner
Procedure Scan_Execname,near ;AN000;MS.
LDS SI,execName ;AN000;MS. DS:SI points to name
save_begin: ;AN000;
MOV CX,SI ;AN000;MS. CX= starting addr
scan0: ;AN000;
LODSB ;AN000;MS. get char
CMP AL,':' ;AN000;;MS. is ':' , may be A:name
JZ save_begin ;AN000;;MS. yes, save si
CMP AL,'\' ;AN000;;MS. is '\', may be A:\name
JZ save_begin ;AN000;;MS. yes, save si
CMP AL,0 ;AN000;;MS. is end of name
JNZ scan0 ;AN000;;MS. no, continue scanning
SUB SI,CX ;AN000;;MS. get name's length
XCHG SI,CX ;AN000;;MS. cx= length, si= starting addr
return ;AN000;;MS.
EndProc Scan_Execname ;AN000;;MS.
Procedure Scan_Special_Entries,near ;AN000;MS.
DEC CX ;AN007;MS. cx= name length
MOV DI,CS:[Special_Entries] ;AN007;MS. es:di -> addr of special entries
CALL Reset_Version ;AN008;MS.
PUSH CS ;AN007;MS.
POP ES ;AN007;MS.
Getentries: ;AN007;MS.
MOV AL,ES:[DI] ;AN007;MS. end of list
OR AL,AL ;AN007;MS.
JZ end_list ;AN007;MS. yes
MOV CS:[Temp_Var2],DI ;AN007;MS. save di
CMP AL,CL ;AN007;MS. same length ?
JNZ skipone ;AN007;MS. no
INC DI ;AN007;MS. es:di -> special name
PUSH CX ;AN007;MS. save length and name addr
PUSH SI ;AN007;MS.
REPZ CMPSB ;AN007;MS. same name ?
JNZ not_matched ;AN007;MS. no
MOV AX,ES:[DI] ;AN007;MS. get special version
MOV CS:[Special_Version],AX ;AN007;MS. save it
MOV AL,ES:[DI+2] ;AN008;MS. get fake count
MOV CS:[Fake_Count],AL ;AN007;MS. save it
POP SI ;AN007;MS.
POP CX ;AN007;MS.
JMP SHORT end_list ;AN007;MS.
not_matched: ;AN007;MS.
POP SI ;AN007;MS. restore si,cx
POP CX ;AN007;MS.
skipone: ;AN007;MS.
MOV DI,CS:[Temp_Var2] ;AN007;MS. restore old di
XOR AH,AH ;AN007;MS. position to next entry
ADD DI,AX ;AN007;MS.
ADD DI,4 ;AN007;MS.
JMP Getentries ;AN007;MS.
end_list: ;AN007;MS.
return
EndProc Scan_Special_Entries ;AN000;;MS.
Procedure Reset_Version,near ;AN008;MS.
CMP CS:[Fake_Count],0FFH ;AN008;MS.
JNZ dont_reset ;AN008;MS.
MOV CS:[Special_Version],0 ;AN008;MS. reset to current version
dont_reset:
return
EndProc Reset_Version,near ;AN008;;MS.
|