1 ; SCCSID = @(#)exec.asm 1.3 85/08/13
2 ; SCCSID = @(#)exec.asm 1.3 85/08/13
3 ; AN000 version 4.0 jan. 1988
4 ; A007 PTM 3957 - fake vesrion for IBMCACHE.COM
5 ; A008 PTM 4070 - fake version for MS WINDOWS
7 SUBTTL $exec
- load/go a program
19 ; 0 Load and execute the program.
20 ; 1 Load, create the program header but do not
22 ; 3 Load overlay. No header created.
24 ; AL = 0 -> load/execute program
26 ; +---------------------------+
27 ; | WORD segment address of |
29 ; +---------------------------+
30 ; | DWORD pointer to ASCIZ |
31 ; | command line at 80h |
32 ; +---------------------------+
33 ; | DWORD pointer to default |
34 ; | FCB to be passed at 5Ch |
35 ; +---------------------------+
36 ; | DWORD pointer to default |
37 ; | FCB to be passed at 6Ch |
38 ; +---------------------------+
40 ; AL = 1 -> load program
42 ; +---------------------------+
43 ; | WORD segment address of |
45 ; +---------------------------+
46 ; | DWORD pointer to ASCIZ |
47 ; | command line at 80h |
48 ; +---------------------------+
49 ; | DWORD pointer to default |
50 ; | FCB to be passed at 5Ch |
51 ; +---------------------------+
52 ; | DWORD pointer to default |
53 ; | FCB to be passed at 6Ch |
54 ; +---------------------------+
55 ; | DWORD returned value of |
57 ; +---------------------------+
58 ; | DWORD returned value of |
60 ; +---------------------------+
62 ; AL = 3 -> load overlay
64 ; +---------------------------+
65 ; | WORD segment address where|
66 ; | file will be loaded. |
67 ; +---------------------------+
68 ; | WORD relocation factor to |
69 ; | be applied to the image. |
70 ; +---------------------------+
73 ; AX = error_invalid_function
75 ; = error_bad_environment
76 ; = error_not_enough_memory
77 ; = error_file_not_found
81 ; A000 version 4.00 Jan. 1988
86 I_Need Temp_Var2
,WORD ;AN000;file type from $open
87 I_Need Special_Entries
,WORD ;AN007;address of special entries
88 I_Need Special_Version
,WORD ;AN007;special version number
89 I_Need Fake_Count
,BYTE ;AN008;fake version count
92 extrn restore_user_map
:near
102 exec_internal_buffer EQU OpenBuf
104 exec_signature
DW ?
; must contain 4D5A (yay zibo!)
105 exec_len_mod_512
DW ?
; low 9 bits of length
106 exec_pages
DW ?
; number of 512b pages in file
107 exec_rle_count
DW ?
; count of reloc entries
108 exec_par_dir
DW ?
; number of paragraphs before image
109 exec_min_BSS
DW ?
; minimum number of para of BSS
110 exec_max_BSS
DW ?
; max number of para of BSS
111 exec_SS
DW ?
; stack of image
112 exec_SP
DW ?
; SP of image
113 exec_chksum
DW ?
; checksum of file (ignored)
114 exec_IP
DW ?
; IP of entry
115 exec_CS
DW ?
; CS of entry
116 exec_rle_table
DW ?
; byte offset of reloc table
117 Exec_header_len EQU
$-Exec_Signature
119 exec_internal_buffer_size EQU
(128+128+53+curdirLEN
)
120 %
out Please make sure that the following are contiguous
and of the
121 %
out following sizes
:
126 %
out DummyCDS CurDirLen
133 ASSUME
DS:NOTHING
, ES:NOTHING
134 PUBLIC EXEC001S
,EXEC001E
136 LocalVar exec_blk
,DWORD
137 LocalVar exec_func
,BYTE
138 LocalVar exec_load_high
,BYTE
139 LocalVar exec_fh
,WORD
140 LocalVar exec_rel_fac
,WORD
141 LocalVar exec_res_len_para
,WORD
142 LocalVar exec_environ
,WORD
143 LocalVar exec_size
,WORD
144 LocalVar exec_load_block
,WORD
145 LocalVar exec_dma
,WORD
146 LocalVar execNameLen
,WORD
147 LocalVar execName
,DWORD
154 CMP AL,3 ; only 0, 1 or 3 are allowed
158 MOV EXTERR_LOCUS
,errLOC_Unk
; Extended Error Locus
159 mov al,error_invalid_function
169 MOV exec_blkL
,BX ; stash args
174 ; set up length of exec name
178 MOV SI,DX ; move pointer to convenient place
180 MOV ExecNameLen
,CX ; save length
182 XOR AL,AL ; open for reading
184 invoke $OPEN
; is the file there?
188 ; CMP BYTE PTR [Temp_Var2],EAEXISTING ;AN000;;FT. old file ?
189 ; JZ oldexf ;AN000;;FT. yes
190 ; TEST BYTE PTR EXEC_FUNC,EXEC_FUNC_OVERLAY ;AN000;;FT. exec overlay?
191 ; JNZ exovrly ;AN000;;FT. yes
192 ; CMP BYTE PTR [Temp_Var2],EAEXECUTABLE ;AN000;;FT. only file type
193 ; JZ oldexf ;AN000;;FT. 3 & 4 will pass
194 ; CMP BYTE PTR [Temp_Var2],EAINSTALLABLE ;AN000;;FT.
195 ; JZ oldexf ;AN000;;FT.
197 ; MOV AL,error_access_denied ;AN000;;FT. error
198 ; JMP exec_ret_err ;AN000;;FT.
199 ;exovrly: ;AN000;;FT.
200 ; CMP BYTE PTR [Temp_Var2],EAOVERLAY ;AN000;;FT. only 5,6,7 pass
201 ; JZ oldexf ;AN000;;FT.
202 ; CMP BYTE PTR [Temp_Var2],EADEV_DRIVER ;AN000;;FT.
203 ; JZ oldexf ;AN000;;FT.
204 ; CMP BYTE PTR [Temp_Var2],EAIFS_DRIVER ;AN000;;FT.
205 ; JNZ exerr ;AN000;;FT.
216 JZ exec_check_environ
217 MOV AL,error_file_not_found
222 MOV AL,error_bad_environment
226 MOV exec_load_block
,0
229 TEST BYTE PTR exec_func
,exec_func_overlay
; overlays... no environment
231 LDS SI,exec_blk
; get block
232 MOV AX,[SI].Exec1_environ
; address of environ
236 MOV AX,DS:[PDB_environ
]
244 MOV CX,07FFFh ; at most 32k of environment
247 exec_get_environ_len:
248 REPNZ SCASB ; find that nul byte
250 DEC CX ; Dec CX for the next nul byte test
251 JB BadEnv
; gone beyond the end of the environment
252 SCASB ; is there another nul byte?
253 JNZ exec_get_environ_len
; no, scan some more
256 ADD BX,ExecNameLen
; BX <- length of environment
257 ; remember argv[0] length
258 ; round up and remember argc
260 SHR BX,CL ; number of paragraphs needed
262 invoke $ALLOC
; can we get the space?
265 JNC exec_save_environ
266 JMP exec_no_mem
; nope... cry and sob
270 MOV exec_environ
,AX ; save him for a rainy day
273 REP MOVSB ; copy the environment
282 ; We read in the program header into the above data area and determine
283 ; where in this memory the image will be located.
286 MOV CX,exec_header_len
; header size
287 MOV DX,OFFSET DOSGROUP
:exec_signature
296 CMP AX,exec_header_len
; did we read the right number?
297 JNZ exec_com_filej
; yep... continue
298 TEST exec_max_BSS
,-1 ; indicate load high?
300 MOV exec_load_high
,-1
302 MOV AX,exec_signature
303 CMP AX,exe_valid_signature
; zibo arises!
304 JZ exec_save_start
; assume com file if no signature
305 CMP AX,exe_valid_old_signature
; zibo arises!
306 JZ exec_save_start
; assume com file if no signature
312 ; We have the program header... determine memory requirements
315 MOV AX,exec_pages
; get 512-byte pages
316 MOV CL,5 ; convert to paragraphs
318 SUB AX,exec_par_dir
; AX = size in paragraphs
319 MOV exec_res_len_para
,AX
322 ; Do we need to allocate memory? Yes if function is not load-overlay
324 TEST BYTE PTR exec_func
,exec_func_overlay
325 JZ exec_allocate
; allocation of space
327 ; get load address from block
330 MOV AX,ES:[DI].exec3_load_addr
332 MOV AX,ES:[DI].exec3_reloc_fac
337 JMP SHORT exec_find_res
341 MOV AL,error_not_enough_memory
345 MOV AL,error_bad_format
348 ASSUME
DS:NOTHING
,ES:NOTHING
358 DOSAssume
CS,<DS>,"EXEC/exec_allocate"
360 MOV BX,0FFFFh ; see how much room in arena
362 invoke $ALLOC
; should have carry set and BX has max
365 ADD AX,10h
; room for header
366 CMP BX,11h
; enough room for a header
368 CMP AX,BX ; is there enough for bare image?
370 TEST exec_load_high
,-1 ; if load high, use max
371 JNZ exec_BX_max
; use max
372 ADD AX,exec_min_BSS
; go for min allocation
373 JC exec_no_mem
; oops! carry
374 CMP AX,BX ; enough space?
375 JA exec_no_mem
; nope...
377 ADD AX,exec_max_BSS
; go for the MAX
389 invoke $ALLOC
; get the space
392 MOV exec_load_block
,AX
394 TEST exec_load_high
,-1
395 JZ exec_use_ax
; use ax for load info
396 ADD AX,exec_size
; go to end
397 SUB AX,exec_res_len_para
; drop off header
398 SUB AX,10h
; drop off pdb
400 MOV exec_rel_fac
,AX ; new segment
401 MOV exec_dma
,AX ; beginning of dma
404 ; Determine the location in the file of the beginning of the resident
410 SHL DX,CL ; low word of location
413 SHR AX,CL ; high word of location
414 MOV CX,AX ; CX <- high
417 ; Read in the resident image (first, seek to it)
422 invoke $LSEEK
; seek to resident
427 exec_big_read: ; Read resident into memory
428 MOV BX,exec_res_len_para
429 CMP BX,1000h
; too many bytes to read?
431 MOV BX,0FE0h ; max in one chunk FE00 bytes
434 SUB exec_res_len_para
,BX ; we read (soon) this many
437 SHL BX,CL ; get count in bytes from paras
438 MOV CX,BX ; count in correct register
440 MOV DS,exec_dma
; Set up read buffer
443 PUSH CX ; save our count
445 POP CX ; get old count to verify
448 DOSAssume
CS,<DS>,"EXEC/exec_read_ok"
449 CMP CX,AX ; did we read enough?
450 POP BX ; get paragraph count back
451 JZ execCheckEnd
; and do reloc if no more to read
453 ; The read did not match the request. If we are off by 512 bytes or more
454 ; then the header lied and we have an error.
460 ; We've read in CX bytes... bump DTA location
463 ADD exec_dma
,BX ; bump dma address
464 TEST exec_res_len_para
,-1
467 ; The image has now been read in. We must perform relocation to
468 ; the current location.
472 MOV AX,exec_SS
; get initial SS
473 ADD AX,CX ; and relocate him
476 MOV AX,exec_SP
; initial SP
479 LES AX,DWORD PTR exec_IP
482 ADD AX,CX ; relocated...
486 MOV DX,exec_rle_table
498 MOV DX,exec_rle_count
; Number of entries left
503 MOV DX,OFFSET DOSGROUP
:exec_internal_buffer
504 MOV CX,((exec_internal_buffer_size
)/4)*4
510 MOV CX,(exec_internal_buffer_size
)/4
511 MOV DI,OFFSET DOSGROUP
:exec_internal_buffer
; Pointer to byte location in header
513 ; Relocate a single address
518 OR DX,DX ; Any more entries?
522 LDS BX,DWORD PTR ES:[DI] ; Get ra/sa of entry
523 MOV AX,DS ; Relocate address of item
529 LOOP exec_reloc_one
; End of internal buffer?
532 ; We've exhausted a single buffer's worth. Read in the next piece
533 ; of the relocation table.
547 ; we have a .COM file. First, determine if we are merely loading an overlay.
550 TEST BYTE PTR exec_func
,exec_func_overlay
551 JZ exec_alloc_com_file
552 LDS SI,exec_blk
; get arg block
553 LODSW ; get load address
556 JMP SHORT exec_read_block
; read it all!
558 ; We must allocate the max possible size block (ick!) and set up
559 ; CS=DS=ES=SS=PDB pointer, IP=100, SP=max size of block.
563 invoke $ALLOC
; largest piece available as error
566 MOV exec_size
,BX ; save size of allocation block
568 invoke $ALLOC
; largest piece available as error
569 POP BX ; get size of block...
570 MOV exec_load_block
,AX
571 ADD AX,10h
; increment for header
573 XOR AX,AX ; presume 64K read...
574 CMP BX,1000h
; 64k or more in block?
575 JAE exec_read_com
; yes, read only 64k
576 MOV AX,BX ; convert size to bytes
580 SUB AX,100h
; remember size of psp
582 PUSH AX ; save number to read
583 MOV BX,exec_fh
; of com file
584 XOR CX,CX ; but seek to 0:0
586 XOR AX,AX ; seek relative to beginning
587 invoke $LSEEK
; back to beginning of file
588 POP CX ; number to read
593 POP SI ; get number of bytes to read
597 CMP AX,SI ; did we read them all?
598 JZ exec_no_memj
; exactly the wrong number... no memory
599 TEST BYTE PTR exec_func
,exec_func_overlay
600 JNZ exec_set_PDB
; no starto, chumo!
604 MOV exec_init_IP
,100h
; initial IP is 100
606 ; SI is at most FF00h. Add FE to account for PSP - word of 0 on stack.
608 ADD SI,0FEh ; make room for stack
609 MOV exec_init_SP
,SI ; max value for read is also SP!
612 MOV WORD PTR [SI],0 ; 0 for return
615 MOV BX,exec_fh
; we are finished with the file.
618 invoke $CLOSE
; release the jfn
621 TEST BYTE PTR exec_func
,exec_func_overlay
623 CALL Scan_Execname
;MS.;AN007;
624 CALL Scan_Special_Entries
;MS.;AN007;
626 transfer SYS_RET_OK
; overlay load -> done
629 MOV DX,exec_load_block
631 ; assign the space to the process
634 MOV SI,arena_owner
; pointer to owner field
636 MOV AX,exec_environ
; get environ pointer
638 JZ NO_OWNER
; no environment
639 DEC AX ; point to header
641 MOV [SI],DX ; assign ownership
643 MOV AX,exec_load_block
; get load block pointer
645 MOV DS,AX ; point to header
646 MOV [SI],DX ; assign ownership
648 PUSH DS ;AN000;MS. make ES=DS
650 MOV DI,ARENA_NAME
;AN000;MS. ES:DI points to destination
651 CALL Scan_Execname
;AN007;MS. parse execname
652 ; ds:si->name, cx=name length
653 PUSH CX ;AN007;;MS. save for fake version
654 PUSH SI ;AN007;;MS. save for fake version
657 LODSB ;AN000;;MS. get char
658 CMP AL,'.' ;AN000;;MS. is '.' ,may be name.exe
659 JZ mem_done
;AN000;;MS. no, move to header
661 STOSB ;AN000;;MS. move char
662 LOOP movename
;AN000;;MS. continue
664 XOR AL,AL ;AN000;;MS. make ASCIIZ
665 CMP DI,SIZE ARENA
;AN000;MS. if not all filled
669 POP SI ;AN007;MS. ds:si -> file name
672 CALL Scan_Special_Entries
;AN007;MS.
677 invoke $Dup_PDB
; ES is now PDB
683 ; set up proper command line stuff
685 LDS SI,exec_blk
; get the block
686 PUSH DS ; save its location
688 LDS SI,[SI.exec0_5C_FCB
] ; get the 5c fcb
690 ; DS points to user space 5C FCB
692 MOV CX,12 ; copy drive, name and ext
698 ; DI = 5Ch + 12 = 5Ch + 0Ch = 68h
700 XOR AX,AX ; zero extent, etc for CPM
704 ; DI = 5Ch + 12 + 4 = 5Ch + 10h = 6Ch
709 PUSH DS ; save (again)
711 LDS SI,[SI.exec0_6C_FCB
] ; get 6C FCB
713 ; DS points to user space 6C FCB
715 MOV BH,[SI] ; do same as above
719 POP SI ; get block (last time)
721 LDS SI,[SI.exec0_com_line
] ; command line
723 ; DS points to user space 80 command line
729 ; Process BX into default AX (validity of drive specs on args). We no longer
732 DEC CL ; get 0FFh in CL
745 invoke get_user_stack
; get his return address
746 PUSH [SI.user_CS
] ; suck out the CS and IP
748 PUSH [SI.user_CS
] ; suck out the CS and IP
750 POP WORD PTR ES:[PDB_Exit
]
751 POP WORD PTR ES:[PDB_Exit
+2]
754 POP DS:[addr_int_terminate
] ; save them where we can get them later
755 POP DS:[addr_int_terminate
+2] ; when the child exits.
756 MOV WORD PTR DMAADD
,80h
758 MOV WORD PTR DMAADD
+2,DS
759 TEST BYTE PTR exec_func
,exec_func_no_execute
762 LDS SI,DWORD PTR exec_init_SP
; get stack
763 LES DI,exec_blk
; and block for return
764 MOV ES:[DI].exec1_SS
,DS ; return SS
766 DEC SI ; 'push' default AX
768 MOV [SI],BX ; save default AX reg
769 MOV ES:[DI].exec1_SP
,SI ; return 'SP'
771 LDS AX,DWORD PTR exec_init_IP
772 MOV ES:[DI].exec1_CS
,DS ; initial entry stuff
774 MOV ES:[DI].exec1_IP
,AX
779 LDS SI,DWORD PTR exec_init_IP
; get entry point
780 LES DI,DWORD PTR exec_init_SP
; new stack
783 ; DS:SI points to entry point
784 ; AX:DI points to initial stack
786 ; BX has initial AX value
791 MOV SS,AX ; set up user's stack
794 PUSH DS ; fake long call to entry
796 MOV ES,DX ; set up proper seg registers
798 MOV AX,BX ; set up proper AX
799 procedure exec_long_ret
,FAR
802 invoke restore_user_map
806 EndProc exec_long_ret
810 Procedure ExecRead
,NEAR
820 procedure exec_dealloc
,near
821 ASSUME
DS:NOTHING
,ES:NOTHING
823 MOV BX,arena_owner_system
830 procedure exec_alloc
,near
839 procedure ChangeOwners
,NEAR
844 MOV AX,exec_load_block
851 Procedure ChangeOwner
,near
852 OR AX,AX ; is area allocated?
853 retz
; no, do nothing
857 MOV DS:[arena_owner
],BX
862 Procedure Scan_Execname
,near ;AN000;MS.
864 LDS SI,execName
;AN000;MS. DS:SI points to name
866 MOV CX,SI ;AN000;MS. CX= starting addr
868 LODSB ;AN000;MS. get char
869 CMP AL,':' ;AN000;;MS. is ':' , may be A:name
870 JZ save_begin
;AN000;;MS. yes, save si
871 CMP AL,'\' ;AN000;;MS. is '\', may be A
:\name
872 JZ save_begin
;AN000;;MS. yes, save si
873 CMP AL,0 ;AN000;;MS. is end of name
874 JNZ scan0
;AN000;;MS. no, continue scanning
875 SUB SI,CX ;AN000;;MS. get name's length
876 XCHG SI,CX ;AN000;;MS. cx= length, si= starting addr
879 EndProc Scan_Execname
;AN000;;MS.
882 Procedure Scan_Special_Entries
,near ;AN000;MS.
884 DEC CX ;AN007;MS. cx= name length
885 MOV DI,CS:[Special_Entries
] ;AN007;MS. es:di -> addr of special entries
886 CALL Reset_Version
;AN008;MS.
889 Getentries: ;AN007;MS.
890 MOV AL,ES:[DI] ;AN007;MS. end of list
892 JZ end_list
;AN007;MS. yes
893 MOV CS:[Temp_Var2
],DI ;AN007;MS. save di
894 CMP AL,CL ;AN007;MS. same length ?
895 JNZ skipone
;AN007;MS. no
896 INC DI ;AN007;MS. es:di -> special name
897 PUSH CX ;AN007;MS. save length and name addr
899 REPZ CMPSB ;AN007;MS. same name ?
900 JNZ not_matched
;AN007;MS. no
901 MOV AX,ES:[DI] ;AN007;MS. get special version
902 MOV CS:[Special_Version
],AX ;AN007;MS. save it
903 MOV AL,ES:[DI+2] ;AN008;MS. get fake count
904 MOV CS:[Fake_Count
],AL ;AN007;MS. save it
907 JMP SHORT end_list
;AN007;MS.
908 not_matched: ;AN007;MS.
909 POP SI ;AN007;MS. restore si,cx
912 MOV DI,CS:[Temp_Var2
] ;AN007;MS. restore old di
913 XOR AH,AH ;AN007;MS. position to next entry
916 JMP Getentries
;AN007;MS.
921 EndProc Scan_Special_Entries
;AN000;;MS.
923 Procedure Reset_Version
,near ;AN008;MS.
925 CMP CS:[Fake_Count
],0FFH ;AN008;MS.
926 JNZ dont_reset
;AN008;MS.
927 MOV CS:[Special_Version
],0 ;AN008;MS. reset to current version
930 EndProc Reset_Version
,near ;AN008;;MS.