;*********************************************************************
;*   MLPASS1.ASM                                                     *
;*                                                                   *
;*   By:            Michael Devore                                   *
;*   Date:          09/28/92                                         *
;*   Model:         Small                                            *
;*   Version:       1.0                                              *
;*   Assembler:     MASM 5.0                                         *
;*   Environment:   MS-DOS 2.x+                                      *
;*                                                                   *
;*   linker pass 1 main driver                                       *
;*                                                                   *
;*********************************************************************

TITLE   WARPLINK mlpass1
PAGE    50,80

.MODEL  SMALL

;*****************************
;* Include files             *
;*****************************

INCLUDE MLEQUATE.INC
INCLUDE MLDATA.INC
     
;*****************************
;* Public declarations       *
;*****************************
     
PUBLIC  pass1,make_symbols

;*****************************
;* External declarations     *
;*****************************

EXTRN   perform_pass:NEAR,get_pubdecl_entry:NEAR,add_pubdef_name:NEAR
EXTRN   alloc_memory:NEAR,init_segdef_entry:NEAR

IFNDEF JUNIOR
EXTRN   save_lib_name:NEAR,check_extension:NEAR
ENDIF

;*****************************
;* Data begins               *
;*****************************
     
.DATA

.DATA?

; uninitialized local variables

nullcode_segdef DW  ?   ; segdef entry of null code first segment

;*****************************
;* External declarations     *
;*****************************

; variables
EXTRN   smartmem_count:WORD

;*****************************
;* Constant data             *
;*****************************

.CONST

; sumbols generated by use of DOSSEG switch
EVEN
_edatatext  DB  '_EDATA',0
EVEN
_end    DB  '_END',0
EVEN
lc_edatatext  DB  '_edata',0
EVEN
lc_end    DB  '_end',0

ovlclass_text   DB  '$$_OVL_MANAGER',0  ; class name for overlaid public lookup table segment
ovlseg_text     DB  '$$_OVL_LOOKUP_TABLE',0 ; segment name for overlaid public lookup table segment
ovlind_text     DB  '$$_OVL_IND_CALL_TABLE',0   ; segment name for indirect call vector segment
ovlscall_text   DB  '$$_OVL_SEG_CALL_TABLE',0   ; segment name for call via segment fixup
nullcode_text   DB  'NULLCODE',0        ; segment name for first code segment
ncode_text      DB  'CODE',0            ; class name for first code segment

smartmem_text   DB  'SMARTMEM.XXX',0

;*****************************
;* Code begins               *
;*****************************

.CODE

;*****************************
;* PASS1                     *
;*****************************

; main driver for pass 1 of linker
; all registers used or destroyed

pass1       PROC

IFNDEF JUNIOR
    xor ax,ax
    cmp any_ddl,al          ; see if DDL's used
    jne p3                  ; yes, bypass this other stuff
    cmp is_smartmem,al      ; see if smartmem option tripped
    je  p1                  ; no

    mov ax,lib_count        ; get count of libraries before adding SmartMem lib
    mov smartmem_count,ax   ; save as current library of SmartMem lib
    mov di,OFFSET DGROUP:smartmem_text+12   ; di-> null terminator for check_extension proc
    mov dx,OFFSET DGROUP:smartmem_text  ; dx -> filename for check_extension proc
    call    check_extension

    mov di,OFFSET DGROUP:smartmem_text  ; add SmartMem library to lib list
    call    save_lib_name
ENDIF

p1:
    cmp is_dosseg,0         ; see if dosseg switch set
    je  p2                  ; no
    call    make_symbols    ; generate _edata and _end symbol declarations

; see if overlays exist, if so, create $$_OVL_LOOKUP_TABLE segment
p2:
IFNDEF JUNIOR
    xor al,al
    cmp is_anyovls,al       ; see if any overlays
    je  p3                  ; no
    mov ovl_code_id,ax      ; init overlay code identifier
    or  al,any_ddl          ; see if creating or using DDL's
    jne p3                  ; yes, don't create fake segments
    call    create_lookup   ; create lookup table segment
ENDIF

p3:
    mov al,1                ; flag pass 1
    call    perform_pass    ; perform pass functions, al flags pass 1 specific routines
    ret
pass1       ENDP

;*****************************
;* MAKE_SYMBOLS              *
;*****************************

; generate a declaration for _edata and _end symbols for DOSSEG switch
; destroys ax,dx,di

make_symbols    PROC
    cmp any_ddl,0           ; see if creating or using DDLs
    je  ms_1                ; no
    ret                     ; yes, don't create symbols

ms_1:
    push    es              ; save critical register
    mov di,OFFSET DGROUP:_edatatext ; ds:di -> pubdef name
    cmp is_casesense,0      ; see if case sensitive names
    je  ms_2                ; no
    mov di,OFFSET DGROUP:lc_edatatext   ; ds:di -> lowercase pubdef name

ms_2:
    push    di
    mov al,1                ; flag to make_pubdecl_entry procedure that symbol is pubdef
    call    get_pubdecl_entry
	or	ax,ax				; see if zero (use dx)
	jne	ms_2a				; no
	mov	ax,dx

ms_2a:
    mov _edata_pubaddr,ax   ; keep public declaration entry segment
    mov es,ax               ; es -> public declaration entry
    mov BYTE PTR es:[14],2  ; flag as a pubdef
    pop di                  ; ds:di -> pubdef name
    call    add_pubdef_name
    mov es:[4],ax           ; keep offset of entry in lnames block
    mov es:[6],dx           ; keep segment of entry in lnames block

    mov di,OFFSET DGROUP:_end   ; ds:di -> pubdef name
    cmp is_casesense,0      ; see if case sensitive names
    je  ms_3                ; no
    mov di,OFFSET DGROUP:lc_end ; ds:di -> lowercase pubdef name

ms_3:
    push    di
    mov al,1                ; flag to make_pubdecl_entry procedure that symbol is pubdef
    call    get_pubdecl_entry
	or	ax,ax				; see if zero (use dx)
	jne	ms_3a				; no
	mov	ax,dx

ms_3a:
    mov _end_pubaddr,ax     ; keep public declaration entry segment
    mov es,ax               ; es -> public declaration entry
    mov BYTE PTR es:[14],2  ; flag as a pubdef
    pop di                  ; ds:di -> pubdef name
    call    add_pubdef_name
    mov es:[4],ax           ; keep offset of entry in lnames block
    mov es:[6],dx           ; keep segment of entry in lnames block

; adjust total number of public symbols
    add WORD PTR pub_sym_count,2
    adc WORD PTR pub_sym_count+2,0

    pop es                  ; restore critical register
    ret
make_symbols    ENDP

;*****************************
;* CREATE_LOOKUP             *
;*****************************

; create lookup table segment for overlaid publics, and
; indirect far call vector segment for overlaid publics
; this is always the first segment declared with overlays,
; so automatically set up the first block
; destroys ax,bx,cx,dx,di,si,es

create_lookup   PROC
    mov bx,SEG_DEFBLK_SIZE  ; number of paragraphs to allocate
    call    alloc_memory    ; get memory for block allocation
    mov alloc_segdefblk_ptr,ax  ; update last allocated block pointer
    mov first_segdefblk_ptr,ax  ; update first allocate block pointer
    mov es,ax               ; es == current (new) block segment
    xor ax,ax
    mov WORD PTR es:[0],ax  ; zero count of entries in block
    mov WORD PTR es:[2],ax  ; zero pointer to next entry

; create NULL code segment at start of program so that fixups of value zero
; (pointing to first segment) don't exist and fool the overlay manager into
; thinking that it is an overlay relative fixup instead of a root fixup.

    mov si,OFFSET DGROUP:nullcode_segdef    ; si -> place to put segdef segment
    mov cx,OFFSET DGROUP:nullcode_text-8    ; cx -> segment name, adjusted back 8 bytes to match lnames format
    call    lookup_sub      ; create segment and save segdef value
    mov ax,OFFSET DGROUP:ncode_text-8   ; get offset to segment class
    mov es:[12],ax          ; save offset pointer to segment class
    mov WORD PTR es:[6],16  ; make it a paragraph long

    mov si,OFFSET DGROUP:lookup_tbl_segdef  ; si -> place to put segdef segment
    mov cx,OFFSET DGROUP:ovlseg_text-8  ; cx -> segment name, adjusted back 8 bytes to match lnames format
    call    lookup_sub      ; create segment and save segdef value

    mov si,OFFSET DGROUP:ind_tbl_segdef ; si -> place to put segdef segment
    mov cx,OFFSET DGROUP:ovlind_text-8  ; cx -> segment name, adjusted back 8 bytes to match lnames format
    call    lookup_sub      ; create segment and save segdef value

    mov si,OFFSET DGROUP:segcall_tbl_segdef ; si -> place to put segdef segment
    mov cx,OFFSET DGROUP:ovlscall_text-8    ; cx -> segment name, adjusted back 8 bytes to match lnames format
    call    lookup_sub      ; create segment and save segdef value

    ret
create_lookup   ENDP

;*****************************
;* LOOKUP_SUB                *
;*****************************

; subroutine used by create_lookup procedure
; automates the repetitive segment creations
; upon entry si-> variable for segdef entry segment,
; cx holds offset of segment name
; destroys ax,bx,dx,di,es

lookup_sub  PROC
    mov es,alloc_segdefblk_ptr  ; es -> segdef block (the only one)
    call    init_segdef_entry   ; perform segdef entry initialization code
    mov es,di               ; es -> new segdef entry
    mov [si],di             ; save -> this segdef entry for resolution time
    inc WORD PTR seg_count  ; update count of total discrete segments

    mov ax,ds               ; update segment and class names, pointing them into warplink data
    mov es:[10],ax
    mov es:[14],ax          ; save segment pointer to segment and class names
    mov ax,cx               ; get offset to segment name
    mov es:[8],ax           ; save offset pointer to segment name
    mov ax,OFFSET DGROUP:ovlclass_text-8    ; get offset to segment class
    mov es:[12],ax          ; save offset pointer to segment class
    mov BYTE PTR es:[26],01100000b  ; paragraph aligned, private combine
    ret
lookup_sub  ENDP

END
