;*********************************************************************
;*   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             *
;*****************************

[list -]
%include "mlequate.mac"
%include "mldata.mac"
[list +]
     
;*****************************
;* 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 smartmem_text+12 wrt DGROUP   ; di-> null terminator for check_extension proc
    mov dx,OFFSET smartmem_text wrt DGROUP  ; dx -> filename for check_extension proc
    call    check_extension

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

p1:
    cmp byte [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:
 extern create_wllist_temps
	call create_wllist_temps
    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 byte [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 _edatatext wrt DGROUP ; ds:di -> pubdef name
    cmp byte [is_casesense],0      ; see if case sensitive names
    je  ms_2                ; no
    mov di,OFFSET lc_edatatext wrt DGROUP   ; 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 _end wrt DGROUP   ; ds:di -> pubdef name
    cmp byte [is_casesense],0      ; see if case sensitive names
    je  ms_3                ; no
    mov di,OFFSET lc_end wrt DGROUP ; 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 [pub_sym_count],2
    adc WORD [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 nullcode_segdef wrt DGROUP    ; si -> place to put segdef segment
    mov cx,OFFSET nullcode_text-8 wrt DGROUP    ; cx -> segment name, adjusted back 8 bytes to match lnames format
    call    lookup_sub      ; create segment and save segdef value
    mov ax,OFFSET ncode_text-8 wrt DGROUP   ; 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 lookup_tbl_segdef wrt DGROUP  ; si -> place to put segdef segment
    mov cx,OFFSET ovlseg_text-8 wrt DGROUP  ; cx -> segment name, adjusted back 8 bytes to match lnames format
    call    lookup_sub      ; create segment and save segdef value

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

    mov si,OFFSET segcall_tbl_segdef wrt DGROUP ; si -> place to put segdef segment
    mov cx,OFFSET ovlscall_text-8 wrt DGROUP    ; 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 [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 ovlclass_text-8 wrt DGROUP    ; 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
