     1                                  ;*********************************************************************
     2                                  ;*   MLPASS2B.ASM                                                    *
     3                                  ;*                                                                   *
     4                                  ;*   By:            Michael Devore                                   *
     5                                  ;*   Date:          05/10/93                                         *
     6                                  ;*   Model:         Small                                            *
     7                                  ;*   Version:       2.7                                              *
     8                                  ;*   Assembler:     MASM 5.0                                         *
     9                                  ;*   Environment:   MS-DOS 2.x+                                      *
    10                                  ;*                                                                   *
    11                                  ;*   linker pass 2 routines part B                                   *
    12                                  ;*                                                                   *
    13                                  ;*********************************************************************
    14                                  
    15                                  ;TITLE   WARPLINK mlpass2b
    16                                  ;PAGE    50,80
    17                                  
    18                                  ;.MODEL  SMALL
    19                                  
    20                                  ;*****************************
    21                                  ;* Include files             *
    22                                  ;*****************************
    23                                  
    24                                  [list -]
    14                              <1> [list -]
    26                                  [list -]
    31                                       
    32                                  ;*****************************
    33                                  ;* Public declarations       *
    34                                  ;*****************************
    35                                  
    36                                  ; procedures
    37                                  PUBLIC  proc2_lnames,proc2_extdef,proc2_segdef,proc2_grpdef
    38                                  PUBLIC  find_pubdecl_entry,find_segdef_entry
    39                                  
    40                                  ; variables
    41                                  PUBLIC  ovl_code_count
    42                                  
    43                                  ;*****************************
    44                                  ;* Data begins               *
    45                                  ;*****************************
    46                                  
    47                                  .DATA
    48                                  
    49                                  ;*****************************
    50                                  ;* External declarations     *
    51                                  ;*****************************
    52                                  
    53                                  ; variables
    54                                  EXTRN   parse_complete:BYTE,name_field:BYTE,filename:BYTE
    55                                  EXTRN   class_name_index:WORD
    56                                  EXTRN   no_match_okay:BYTE,clarclass_text:BYTE
    57                                  EXTRN	is_local:BYTE,is_cextdef:BYTE
    58                                  
    59                                  ; initialized local variables
    60                                  
    61                                  EVEN                        ; maximize speed on 8086 and better
    62                                  
    63                                  ; word values
    64 00000000 0000                    ovl_code_count  DW  0       ; running count of overlaid code segments, used by Clarion code
    65                                  
    66 00000002 574C454D4954414C49-     string_wlemitalign:	asciz "WLEMITALIGN"
    66 0000000B 474E00             
    67                                  
    68                                  .DATA?
    69                                  
    70                                  ; uninitialized local variables
    71                                  
    72                                  ; byte values
    73                                  
    74                                  EVEN                        ; maximize speed on 8086 and better
    75 00000000 ??                      acbp_byte   DB  ?           ; ACBP byte in segdef record
    76 00000001 ??                      EVEN
    77 00000002 ??                      is_comdef   DB  ?           ; nonzero if record is a COMDEF record
    78 00000003 ??                      EVEN
    79 00000004 ??                      mustfind    DB  ?           ; nonzero if must find_segdef_entry must find entry
    80 00000005 ??                      EVEN
    81                                  
    82                                  ; word values
    83                                  EVEN
    84 00000006 ????                    segment_name_index  DW  ?   ; segment name index in segdef record
    85 00000008 ????                    frame_number    DW  ?       ; frame number in segdef record
    86                                  
    87                                  ;*****************************
    88                                  ;* Code begins               *
    89                                  ;*****************************
    90                                  
    91                                  .CODE
    92                                  
    93                                  ;*****************************
    94                                  ;* External declarations     *
    95                                  ;*****************************
    96                                  
    97                                  ; procedures
    98                                  EXTRN   link_error:NEAR,dos_error:NEAR,load_file:NEAR,link_warning:NEAR
    99                                  EXTRN   get_name:NEAR,get_hash:NEAR,write_bytes:NEAR,caseless_strcmp:NEAR
   100                                  EXTRN   map_detail_seg:NEAR
   101                                  EXTRN   scan_comfield:NEAR
   102                                  EXTRN	proc_cextdef:NEAR
   103                                  
   104                                  ;*****************************
   105                                  ;* PROC2_LNAMES              *
   106                                  ;*****************************
   107                                  
   108                                  ; pass 2 lnames record processing
   109                                  ; upon entry cx=record length,bp=buffer_end,al=record type
   110                                  ; es:si -> first byte of record past record length
   111                                  ; destroys ax,bx,dx,di
   112                                  ; updates si
   113                                  
   114                                  proc2_lnames    PROC
   115                                  pl_loop:
   116 00000000 FF06[0000]                  inc word [current_lnames]      ; bump count of lnames in file
   117 00000004 BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; point di at field to place name
   118 00000007 C606[0000]00            	mov	byte [is_local],0			; flag not a local for get_name
   119 0000000C E8(0000)                    call    get_name        ; get lnames logical name from record
   120 0000000F BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; point di at name
   121 00000012 803D00                      cmp BYTE PTR [di],0     ; check if null name
   122 00000015 7508                        jne pl_save_name        ; no, non-null name
   123 00000017 B8[0000]                    mov ax,OFFSET zero_table wrt DGROUP ; point to known zero value
   124 0000001A BA[ssss]                    mov dx,DGROUP
   125 0000001D EB03                        jmp SHORT pl_array
   126                                  
   127                                  pl_save_name:
   128 0000001F E82100                      call    find_lnames_entry   ; find lnames entry, return segment:offset pointer
   129                                  
   130                                  pl_array:
   131 00000022 8B3E[0000]                  mov di,[current_lnames]   ; get current lnames logical names count in di
   132 00000026 4F                          dec di                  ; make count relative zero
   133 00000027 D1E7                        shl di,1
   134 00000029 D1E7                        shl di,1                ; make lnames index value a doubleword offset into index pointer array
   135 0000002B BB[0000]                    mov bx,OFFSET lnames_ent_indptr wrt DGROUP  ; set bx to base of lnames index pointer array
   136 0000002E 8901                        mov [bx+di],ax             ; save lnames logical name offset
   137 00000030 895102                      mov [bx+di+2],dx           ; save lnames logical name segment
   138                                  
   139                                  pl_checksum:
   140 00000033 83F901                      cmp cx,1                ; check if at checksum byte
   141 00000036 7602                        jbe pl_out              ; yes, gobble it and return
   142 00000038 EBC6                        jmp pl_loop    ; loop back for next definition
   143                                  
   144                                  pl_out:
   145 0000003A 46                          inc si                  ; bump past checksum byte
   146 0000003B 39EE                        cmp si,bp               ; check boundary conditions
   147 0000003D 7203                        jb  pl_ret              ; okay
   148 0000003F E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   149                                  
   150                                  pl_ret:
   151 00000042 C3                          ret
   152                                  proc2_lnames    ENDP
   153                                  
   154                                  ;*****************************
   155                                  ;* FIND_LNAMES_ENTRY         *
   156                                  ;*****************************
   157                                  
   158                                  ; find entry for lnames name
   159                                  ; upon entry di -> warplink data location holding logical name
   160                                  ; returns segment:offset pointer to entry in dx:ax
   161                                  ; destroys ax,bx,dx,di
   162                                  
   163                                  find_lnames_entry   PROC
   164 00000043 51                          push    cx              ; save critical registers
   165 00000044 56                          push    si
   166 00000045 06                          push    es
   167 00000046 89FE                        mov si,di               ; si must -> name for get_hash procedure
   168 00000048 E8(0000)                    call    get_hash        ; get hash code of name in ax
   169 0000004B BE[0000]                    mov si,OFFSET lnames_hash wrt DGROUP    ; si -> base of hash pointers to lnames entries
   170 0000004E D1E0                        shl ax,1
   171 00000050 D1E0                        shl ax,1                ; convert ax to doubleword offset
   172 00000052 01C6                        add si,ax               ; si points to proper name hash code entry
   173 00000054 837C0200                    cmp WORD PTR [si+2],0   ; is hash code used (nonzero segment value)
   174 00000058 7509                        jne fle_2
   175                                  
   176                                  ; hash code for name unused, internal error
   177                                  fle_internal:
   178 0000005A B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
   179 0000005D B90300                      mov cx,3                ; internal error value
   180 00000060 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   181                                  
   182                                  fle_2:
   183 00000063 8B4402                      mov ax,[si+2]           ; get segment pointer to lnames entry
   184 00000066 8B14                        mov dx,[si]             ; get offset pointer to lnames entry
   185 00000068 89FE                        mov si,di               ; si -> name
   186                                  
   187                                  fle_testloop:
   188 0000006A 8EC0                        mov es,ax               ; es == segment of lnames entry testing name against
   189 0000006C 89D7                        mov di,dx               ; di == offset of lnames entry testing name against
   190 0000006E 89FB                        mov bx,di               ; save entry offset in bx
   191 00000070 83C708                      add di,8                ; scan past segment:offset high and low pointers
   192 00000073 56                          push    si              ; save si -> name
   193                                  
   194                                  ; ds:si -> name, es:di -> name to test against
   195                                  fle_byteloop:
   196 00000074 8A04                        mov al,[si]
   197 00000076 260A05                      or  al,[es:di]          ; see if both values are zero (matched to null terminator)
   198 00000079 741D                        je  fle_match           ; yes
   199 0000007B A6                          cmpsb                   ; compare a nonzero byte in the two names
   200 0000007C 74F6                        je  fle_byteloop        ; bytes match, loop for next byte test
   201 0000007E 720A                        jc  fle_5               ; old name greater than new name
   202                                  
   203                                  ; new name greater than old name
   204 00000080 268B4706                    mov ax,[es:bx+6]        ; get segment of lnames entry having a greater name
   205 00000084 268B5704                    mov dx,[es:bx+4]        ; get offset of lnames entry having greater name
   206 00000088 EB07                        jmp SHORT fle_6         ; check for null pointer
   207                                  
   208                                  ; old name greater than new name
   209                                  fle_5:
   210 0000008A 268B4702                    mov ax,[es:bx+2]        ; get segment of lnames entry having lesser name
   211 0000008E 268B17                      mov dx,[es:bx]          ; get offset of lnames entry having lesser name
   212                                  
   213                                  fle_6:
   214 00000091 5E                          pop si                  ; restore si -> name
   215 00000092 09C0                        or  ax,ax               ; check if a null pointer (segment value in ax=0)
   216 00000094 75D4                        jne fle_testloop        ; no, keep checking entries
   217 00000096 EBC2                        jmp SHORT fle_internal  ; no more entries, internal error
   218                                  
   219                                  ; names match, return pointer to name
   220                                  fle_match:
   221 00000098 5E                          pop si                  ; pull old si value off of stack, garbage
   222 00000099 89D0                        mov ax,dx               ; ax holds name offset
   223 0000009B 8CC2                        mov dx,es               ; dx holds name segment
   224                                  
   225 0000009D 07                          pop es                  ; restore critical registers
   226 0000009E 5E                          pop si
   227 0000009F 59                          pop cx
   228 000000A0 C3                          ret
   229                                  find_lnames_entry   ENDP
   230                                  
   231                                  ;*****************************
   232                                  ;* PROC2_EXTDEF              *
   233                                  ;*****************************
   234                                  
   235                                  ; process extdef records
   236                                  ; upon entry cx=record length,bp=buffer_end,al=record type
   237                                  ; si -> first byte of record past record length
   238                                  ; updates si
   239                                  ; destroys ax,dx,di
   240                                  
   241                                  proc2_extdef    PROC
   242 000000A1 30E4                        xor ah,ah
   243 000000A3 8826[0000]              	mov	[is_cextdef],ah		; init comdat extdef flag
   244 000000A7 3C8C                        cmp al,EXTDEF           ; see if a EXTDEF record
   245 000000A9 7406                        je	pe_1                ; no
   246 000000AB 3CB4                        cmp al,LEXTDEF			; see if a LEXTDEF record
   247 000000AD 7402                        je	pe_1                ; no
   248 000000AF FEC4                        inc ah                  ; set flag for COMDEF
   249                                  
   250                                  pe_1:
   251 000000B1 8826[0200]                  mov [is_comdef],ah        ; set appropriate flag value
   252                                  
   253 000000B5 30E4                        xor ah,ah				; init for is_local flag
   254 000000B7 3C8C                    	cmp	al,EXTDEF
   255 000000B9 7406                    	je	pe_saveloc
   256 000000BB 3CB0                    	cmp	al,COMDEF
   257 000000BD 7402                    	je	pe_saveloc
   258 000000BF FEC4                    	inc	ah					; flag local (LCOMDEF or LEXTDEF)
   259                                  
   260                                  pe_saveloc:
   261 000000C1 8826[0000]              	mov	[is_local],ah			; flag local or not
   262 000000C5 3CBC                        cmp al,CEXTDEF          ; see if COMDAT extdef
   263 000000C7 7503                        jne pe_loop				; no
   264 000000C9 A2[0000]                	mov	[is_cextdef],al		; yes, flag it
   265                                  
   266                                  pe_loop:
   267 000000CC 803E[0000]00            	cmp	byte [is_cextdef],0		; see if COMDAT extdef
   268 000000D1 7405                    	je	pe_notcext			; no
   269 000000D3 E8(0000)                	call	proc_cextdef	; parse COMDAT extdef entry
   270 000000D6 EB48                    	jmp	SHORT pe_3			; process regular extdef parsing
   271                                  
   272                                  pe_notcext:
   273 000000D8 BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; point di at field to place name
   274 000000DB E8(0000)                    call    get_name        ; get public name from record
   275                                  
   276 000000DE 268A04                      mov al,[es:si]          ; get type index byte
   277 000000E1 46                          inc si                  ; scan past first type index byte
   278 000000E2 49                          dec cx                  ; decrement record length to parse
   279 000000E3 39EE                        cmp si,bp               ; check boundary conditions
   280 000000E5 7203                        jb  pe_2                ; okay
   281 000000E7 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   282                                  
   283                                  pe_2:
   284 000000EA 2480                        and al,80h              ; see if two-byte type index 
   285 000000EC 7409                        je  pe_2a               ; no
   286 000000EE 46                          inc si                  ; scan past second type index byte
   287 000000EF 49                          dec cx                  ; decrement record length to parse
   288 000000F0 39EE                        cmp si,bp               ; check boundary conditions
   289 000000F2 7203                        jb  pe_2a               ; okay
   290 000000F4 E8(0000)                    call    load_file
   291                                  
   292                                  pe_2a:
   293 000000F7 803E[0200]00                cmp byte [is_comdef],0         ; see if comdef record
   294 000000FC 7422                        je  pe_3                ; no
   295                                  
   296                                  ; comdef record, scan past the data segment type, and communal length field
   297 000000FE 268A14                      mov dl,[es:si]          ; get data segment type
   298 00000101 46                          inc si
   299 00000102 49                          dec cx                  ; decrement record length to parse
   300 00000103 39EE                        cmp si,bp               ; check boundary conditions
   301 00000105 7203                        jb  pe_2b               ; okay
   302 00000107 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   303                                  
   304                                  pe_2b:
   305 0000010A 268A34                      mov dh,[es:si]          ; get low byte of variable size (NEAR)/number of elements (FAR)
   306 0000010D 80FA61                      cmp dl,61h              ; check if FAR variable
   307 00000110 750B                        jne pe_2c
   308 00000112 E8(0000)                    call    scan_comfield   ; scan past communal length field number of elements
   309 00000115 268A34                      mov dh,[es:si]          ; get low byte of element size
   310 00000118 E8(0000)                    call    scan_comfield   ; scan past communal length field element size
   311 0000011B EB03                        jmp SHORT pe_3          ; bypass NEAR variable code
   312                                  
   313                                  ; assume near variable
   314                                  pe_2c:
   315 0000011D E8(0000)                    call    scan_comfield   ; scan past communal length field variable size
   316                                  
   317                                  pe_3:
   318 00000120 BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; point di at name field for find_pubdecl_entry procedure
   319 00000123 E81700                      call    find_pubdecl_entry  ; find/return public declaration entry segment in ax
   320                                  
   321 00000126 BB[0000]                    mov bx,OFFSET ext_defent_indptr wrt DGROUP    ; bx -> base of array pointers to extdef'ed public entries
   322 00000129 8B3E[0000]                  mov di,[current_extdef]   ; get array element (current extdef number)
   323 0000012D D1E7                        shl di,1                ; make ax a word offset
   324 0000012F 01FB                        add bx,di               ; bx -> proper array element
   325 00000131 8907                        mov [bx],ax             ; save pointer to public declaration entry
   326 00000133 FF06[0000]                  inc word [current_extdef]      ; update global memory variable
   327                                  
   328                                  pe_checksum:
   329 00000137 83F901                      cmp cx,1                ; check if at checksum byte
   330 0000013A 7790                        ja  pe_loop             ; no, loop back for next definition
   331                                  
   332                                  pe_ret:
   333 0000013C C3                          ret
   334                                  proc2_extdef    ENDP
   335                                  
   336                                  ;*****************************
   337                                  ;* FIND_PUBDECL_ENTRY        *
   338                                  ;*****************************
   339                                  
   340                                  ; find pubdef declaration entry
   341                                  ; upon entry ds:di -> pubdef name
   342                                  ; return segment of entry in ax
   343                                  ; fatal error if not found
   344                                  ; destroys ax,bx,dx
   345                                  
   346                                  find_pubdecl_entry  PROC
   347 0000013D 56                          push    si              ; save critical register
   348 0000013E 89FE                        mov si,di               ; si -> name to get hash code of
   349 00000140 E8(0000)                    call    get_hash        ; get hash code of name in ax
   350                                  
   351 00000143 BE[0000]                    mov si,OFFSET pubdecl_hash wrt DGROUP   ; si -> base of hash pointers to public declaration entries
   352 00000146 D1E0                        shl ax,1                ; convert ax to word offset
   353 00000148 01C6                        add si,ax               ; si points to proper name hash code entry
   354 0000014A 833C00                      cmp WORD PTR [si],0     ; is hash code used (nonzero value)
   355 0000014D 7519                        jne fpe_2               ; yes
   356                                  
   357                                  ; hash code for name unused, internal error
   358                                  
   359                                  fpe_internal:
   360 0000014F B8[ssss]                    mov ax,DGROUP
   361 00000152 8ED8                        mov ds,ax               ; ds -> warplink data
   362 00000154 803E[0000]00                cmp byte [no_match_okay],0     ; check to see if no match okay flag is set
   363 00000159 7404                        je  fpe_int2            ; no
   364 0000015B 5E                          pop si                  ; restore si
   365 0000015C 31C0                        xor ax,ax               ; return null value to show no match
   366 0000015E C3                          ret
   367                                  
   368                                  fpe_int2:
   369 0000015F B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
   370 00000162 B90400                      mov cx,4                ; internal error value
   371 00000165 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   372                                  
   373                                  ; hash code used, check for hash collision
   374                                  fpe_2:
   375 00000168 06                          push    es              ; save critical register
   376 00000169 57                          push    di              ; save di pointing to name
   377 0000016A 8B04                        mov ax,[si]             ; get segment pointer to pubdef declaration entry
   378                                  
   379                                  fpe_testloop:
   380 0000016C 5E                          pop si                  ; si -> name
   381 0000016D 56                          push    si              ; put it back on stack
   382 0000016E 8EC0                        mov es,ax               ; es -> segment of pubdef declaration entry testing name against
   383 00000170 89C3                        mov bx,ax               ; save entry segment in bx
   384 00000172 26C43E0400                  les di,[es:4]           ; -> pubdef name in pubdef names block
   385                                  
   386                                  ; ds:si -> name, es:di -> name to test against
   387                                  fpe_byteloop:
   388 00000177 8A04                        mov al,[si]
   389 00000179 260A05                      or  al,[es:di]          ; see if both values are zero (matched to null terminator)
   390 0000017C 741D                        je  fpe_match           ; strings matched
   391 0000017E A6                          cmpsb                   ; compare a nonzero byte in the two names
   392 0000017F 74F6                        je  fpe_byteloop        ; bytes match, loop for next byte test
   393 00000181 8EC3                        mov es,bx               ; get pubdef declaration entry segment value
   394 00000183 7208                        jc  fpe_7               ; old name greater than new name
   395                                  
   396                                  ; new name greater than old name
   397 00000185 26A10C00                    mov ax,[es:12]          ; get entry having a greater name
   398 00000189 30D2                        xor dl,dl               ; flag new > old, update high pointer
   399 0000018B EB06                        jmp SHORT fpe_8         ; check for null pointer
   400                                  
   401                                  ; old name greater than new name
   402                                  fpe_7:
   403 0000018D 26A10A00                    mov ax,[es:10]          ; get entry having a lesser name
   404 00000191 B201                        mov dl,1                ; flag old > new update low pointer
   405                                  
   406                                  fpe_8:
   407 00000193 09C0                        or  ax,ax               ; check if a null pointer (ax=0)
   408 00000195 75D5                        jne fpe_testloop        ; no, loop back for next name check
   409 00000197 5F                          pop di                  ; restore di pointing to name
   410 00000198 07                          pop es                  ; restore critical register
   411 00000199 EBB4                        jmp SHORT fpe_internal  ; name must be previously stored
   412                                  
   413                                  ; names match
   414                                  fpe_match:
   415 0000019B 8EC3                        mov es,bx               ; get pubdef declaration entry segment value
   416 0000019D 26A00E00                    mov al,[es:14]          ; get definitions flag
   417 000001A1 2403                        and al,3                ; only keep pubdef/extdef/comdef/absolute field
   418 000001A3 3C02                        cmp al,2                ; check if previous entry was a pubdef/absolute
   419 000001A5 732F                        jae fpe_14              ; yes
   420 000001A7 26F6060F0040                test    BYTE PTR [es:15],40h    ; see if a communal
   421 000001AD 7527                        jne fpe_14              ; yes
   422                                  
   423                                  ; check if weak extdef
   424 000001AF 08C0                        or  al,al               ; declaration flag must be zero for weak extdef
   425 000001B1 7507                        jne fpe_unres           ; not a weak extdef
   426 000001B3 268B1E0000                  mov bx,[es:0]           ; bx -> default resolution extdef
   427 000001B8 EBE1                        jmp SHORT fpe_match     ; retry with new match entry
   428                                  
   429                                  ; unresolved external symbol
   430                                  fpe_unres:
   431 000001BA 1E                      	push	ds
   432 000001BB B8[ssss]                    mov ax,DGROUP
   433 000001BE 8ED8                        mov ds,ax               ; ds -> warplink data
   434 000001C0 803E[0000]00                cmp byte [no_match_okay],0     ; check to see if no match okay flag is set
   435 000001C5 1F                      	pop	ds
   436 000001C6 750E                        jne fpe_14				; no match flag set, don't report warning
   437                                  
   438 000001C8 26C43E0400                  les di,[es:4]           ; -> name
   439 000001CD BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   440 000001D0 B82D00                      mov ax,UNRES_EXT_WARN   ; flag unresolved external
   441 000001D3 E8(0000)                    call    link_warning    ; give warning feedback
   442                                  
   443                                  fpe_14:
   444 000001D6 89D8                        mov ax,bx               ; get segment value in ax
   445                                  
   446                                  fpe_15:
   447 000001D8 5F                          pop di                  ; restore di pointing to name
   448                                  
   449                                  fpe_ret:
   450 000001D9 07                          pop es                  ; restore critical register
   451 000001DA 5E                          pop si
   452 000001DB C3                          ret
   453                                  find_pubdecl_entry  ENDP
   454                                  
   455                                  ;*****************************
   456                                  ;* PROC2_SEGDEF              *
   457                                  ;*****************************
   458                                  
   459                                  ; pass 2 segdef record processing
   460                                  ; upon entry cx=record length,bp=buffer_end,al=record type
   461                                  ; es:si -> first byte of record past record length
   462                                  ; destroys ax,bx,dx,di
   463                                  ; updates si
   464                                  
   465                                  proc2_segdef    PROC
   466 000001DC 268A04                      mov al,[es:si]          ; get acbp byte
   467 000001DF A2[0000]                    mov [acbp_byte],al        ; save to memory
   468 000001E2 88C2                        mov dl,al               ; save acbp byte in dl
   469 000001E4 46                          inc si
   470 000001E5 49                          dec cx                  ; decrement record length to parse
   471 000001E6 39EE                        cmp si,bp               ; check boundary conditions
   472 000001E8 7203                        jb  ps_2                ; okay
   473 000001EA E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   474                                  ps_2:
   475 000001ED F6C2E0                      test    dl,0e0h         ; check if A bit field is zero
   476 000001F0 7525                        jne ps_scan_seglen      ; nonzero, no frame number
   477                                  
   478                                  ; A bit field is zero (absolute segment), frame number and offset bytes exist
   479 000001F2 268A14                      mov dl,[es:si]          ; get low byte of frame number
   480 000001F5 46                          inc si                  ; scan past low byte frame number
   481 000001F6 49                          dec cx                  ; decrement record length to parse
   482 000001F7 39EE                        cmp si,bp               ; check boundary conditions
   483 000001F9 7203                        jb  ps_3                ; okay
   484 000001FB E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   485                                  ps_3:
   486 000001FE 268A34                      mov dh,[es:si]          ; get high byte of frame number
   487 00000201 46                          inc si                  ; scan past high byte frame number
   488 00000202 49                          dec cx                  ; decrement record length to parse
   489 00000203 39EE                        cmp si,bp               ; check boundary conditions
   490 00000205 7203                        jb  ps_4                ; okay
   491 00000207 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   492                                  ps_4:
   493 0000020A 8916[0800]                  mov [frame_number],dx     ; save frame number
   494 0000020E 46                          inc si                  ; scan past offset byte
   495 0000020F 49                          dec cx                  ; decrement record length to parse
   496 00000210 39EE                        cmp si,bp               ; check boundary conditions
   497 00000212 7203                        jb  ps_scan_seglen      ; okay
   498 00000214 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   499                                  
   500                                  ps_scan_seglen:
   501 00000217 46                          inc si                  ; scan past low byte of segment length
   502 00000218 49                          dec cx                  ; decrement record length to parse
   503 00000219 39EE                        cmp si,bp               ; check boundary conditions
   504 0000021B 7203                        jb  ps_6                ; okay
   505 0000021D E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   506                                  ps_6:
   507 00000220 46                          inc si                  ; scan past high byte of segment length
   508 00000221 49                          dec cx                  ; decrement record length to parse
   509 00000222 39EE                        cmp si,bp               ; check boundary conditions
   510 00000224 7203                        jb  ps_7                ; okay
   511 00000226 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   512                                  
   513                                  ps_7:
   514 00000229 30E4                        xor ah,ah               ; zero high byte of index
   515 0000022B 268A04                      mov al,[es:si]          ; get low byte of segment name index
   516 0000022E 46                          inc si
   517 0000022F 49                          dec cx                  ; decrement record length to parse
   518 00000230 39EE                        cmp si,bp               ; check boundary conditions
   519 00000232 7203                        jb  ps_8                ; okay
   520 00000234 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   521                                  ps_8:
   522 00000237 3C80                        cmp al,80h              ; check if two byte index value
   523 00000239 7210                        jb  ps_10               ; no, continue
   524 0000023B 247F                        and al,7fh              ; mask off high bit
   525 0000023D 88C4                        mov ah,al               ; move value to high byte
   526                                  
   527 0000023F 268A04                      mov al,[es:si]          ; get second byte of index
   528 00000242 46                          inc si
   529 00000243 49                          dec cx                  ; decrement record length to parse
   530 00000244 39EE                        cmp si,bp               ; check boundary conditions
   531 00000246 7203                        jb  ps_10               ; okay
   532 00000248 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   533                                  
   534                                  ps_10:
   535 0000024B A3[0600]                    mov [segment_name_index],ax   ; save segment name index
   536                                  
   537 0000024E 30E4                        xor ah,ah               ; zero high byte of index
   538 00000250 268A04                      mov al,[es:si]          ; get low byte of class name index
   539 00000253 46                          inc si
   540 00000254 49                          dec cx                  ; decrement record length to parse
   541 00000255 39EE                        cmp si,bp               ; check boundary conditions
   542 00000257 7203                        jb  ps_11               ; okay
   543 00000259 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   544                                  ps_11:
   545 0000025C 3C80                        cmp al,80h              ; check if two byte index value
   546 0000025E 7210                        jb  ps_13               ; no, continue
   547                                  
   548 00000260 247F                        and al,7fh              ; mask off high bit
   549 00000262 88C4                        mov ah,al               ; move value to high byte
   550 00000264 268A04                      mov al,[es:si]          ; get second byte of index
   551 00000267 46                          inc si
   552 00000268 49                          dec cx                  ; decrement record length to parse
   553 00000269 39EE                        cmp si,bp               ; check boundary conditions
   554 0000026B 7203                        jb  ps_13               ; okay
   555 0000026D E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   556                                  ps_13:
   557 00000270 A3[0000]                    mov [class_name_index],ax ; save class name index
   558                                  
   559                                  ; scan the overlay name index value
   560 00000273 268A04                      mov al,[es:si]          ; get first byte
   561 00000276 46                          inc si                  ; scan past overlay name index
   562 00000277 49                          dec cx                  ; decrement record length to parse
   563 00000278 39EE                        cmp si,bp               ; check boundary conditions
   564 0000027A 7203                        jb  ps_13a              ; okay
   565 0000027C E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   566                                  ps_13a:
   567 0000027F 3C80                        cmp al,80h              ; check if more than one byte index value
   568 00000281 7209                        jb  ps_find_segdef      ; no, continue
   569 00000283 46                          inc si                  ; scan past second byte
   570 00000284 49                          dec cx                  ; decrement record length to parse
   571 00000285 39EE                        cmp si,bp               ; check boundary conditions
   572 00000287 7203                        jb  ps_find_segdef      ; okay
   573 00000289 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   574                                  
   575                                  ps_find_segdef:
   576 0000028C 06                          push    es              ; save es critical register
   577 0000028D B001                        mov al,1                ; flag that must find entry
   578 0000028F E87701                      call    find_segdef_entry   ; find segdef entry
   579 00000292 26A01A00                    mov al,[es:26]          ; get acbp byte
   580 00000296 24E0                        and al,0e0h             ; get align field
   581 00000298 7507                        jne ps_not_abs          ; not an absolute segment
   582                                  
   583                                  ; absolute segment, bypass segment partition stuff, use segdef entry as
   584                                  ; element in segment partition array
   585 0000029A 8B16[0000]                  mov dx,[current_segdef]
   586 0000029E E9F000                      jmp NEAR PTR ps_part_ptr
   587                                  
   588                                  ps_not_abs:
   589 000002A1 268E061600                  mov es,[es:22]          ; get segment of first segment partition entry
   590                                  
   591                                  ; scan past nonmatching object or library file segment partition entries
   592                                  ps_part_scan:
   593 000002A6 803E[0000]00                cmp byte [is_inlib],0          ; see if current processing library
   594 000002AB 7420                        je  ps_use_obj          ; no
   595                                  
   596                                  ps_idloop1:
   597 000002AD 26A10600                    mov ax,[es:6]           ; get low word of file_mod_id
   598 000002B1 3B06[0000]                  cmp ax,WORD PTR [lib_id]  ; compare to low word of library id
   599 000002B5 750A                        jne ps_13b              ; doesn't match
   600 000002B7 26A10800                    mov ax,[es:8]           ; get high word of file_mod_id
   601 000002BB 3B06[0200]                  cmp ax,WORD PTR [lib_id+2]    ; compare to high word of library id
   602 000002BF 742A                        je  ps_14               ; id's match
   603                                  
   604                                  ps_13b:
   605 000002C1 26A10200                    mov ax,[es:2]           ; get pointer to next entry
   606 000002C5 09C0                        or  ax,ax               ; check if null, no more entries
   607 000002C7 8EC0                        mov es,ax
   608 000002C9 75E2                        jne ps_idloop1          ; no, non-null
   609 000002CB EB15                        jmp SHORT ps_internal   ; no entry match found
   610                                  
   611                                  ps_use_obj:
   612 000002CD 8B16[0000]                  mov dx,[current_obj]
   613                                  
   614                                  ps_idloop2:
   615 000002D1 263B160600                  cmp dx,[es:6]           ; see if id number for object module matches current object number
   616 000002D6 7413                        je  ps_14               ; yes
   617 000002D8 26A10200                    mov ax,[es:2]           ; get pointer to next entry
   618 000002DC 09C0                        or  ax,ax               ; check if null, no more entries
   619 000002DE 8EC0                        mov es,ax
   620 000002E0 75EF                        jne ps_idloop2          ; no, non-null
   621                                  
   622                                  ; internal error, no matching partition entry found
   623                                  ps_internal:
   624 000002E2 B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
   625 000002E5 B90500                      mov cx,5                ; internal error value
   626 000002E8 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   627                                  
   628                                  ; scan past nonmatching index segment partition entries
   629                                  ps_14:
   630 000002EB 8B16[0000]                  mov dx,[current_segdef]
   631 000002EF 26A00A00                    mov al,[es:10]          ; get record index
   632 000002F3 30E4                        xor ah,ah               ; zap high byte
   633 000002F5 39D0                        cmp ax,dx               ; see if record index for object module matches current segdef number
   634 000002F7 740C                        je  ps_expmap_chk       ; yes
   635 000002F9 26A10200                    mov ax,[es:2]           ; get pointer to next entry
   636 000002FD 8EC0                        mov es,ax
   637 000002FF 09C0                        or  ax,ax               ; check if null, no more entries
   638 00000301 74DF                        je  ps_internal         ; null, internal error
   639 00000303 EBA1                        jmp SHORT ps_part_scan  ; loop back and try again
   640                                  
   641                                  ; found the proper segment partition entry
   642                                  
   643                                  ps_expmap_chk:
   644                                  
   645                                  check_emit_align:
   646 00000305 D006[0000]                  rol byte [is_wlemitalign_enabled], 1
   647 00000309 735E                        jnc do_not_emit_align
   648 0000030B 1E                      	push ds
   649 0000030C 06                      	push es
   650 0000030D 53                      	push bx
   651 0000030E 51                      	push cx
   652 0000030F 52                      	push dx
   653 00000310 56                      	push si
   654                                  
   655 00000311 8CC3                        mov bx,es               ; save -> segment partition entry
   656 00000313 26A10400                    mov ax,[es:4]           ; get master segdef entry/overlay identifier
   657 00000317 26F6060F0080                test    BYTE PTR [es:15],80h    ; see if overlaid segment
   658                                  %if 0
   659                                      je  .mds_2a              ; no, ax holds master segdef entry
   660                                  
   661                                  ; overlaid segment, ax holds overlay identifier
   662                                      mov [map_seg_ovl],ax      ; set overlaid segment flag with identifier
   663                                      mov si,ax
   664                                      dec si                  ; make relative zero
   665                                      shl si,1                ; convert to word offset
   666                                      mov es,[master_segblk]    ; es:si -> proper master segdef entry
   667                                      mov ax,[es:si]          ; get master segdef entry in ax
   668                                  
   669                                  .mds_2a:
   670                                  %else
   671 0000031D 7544                    	jne .mismatch
   672                                  %endif
   673 0000031F 50                          push ax              ; save -> segdef entry
   674 00000320 8ED8                        mov ds,ax               ; ds -> master segdef entry
   675 00000322 C5360800                    lds si,[8]           ; ds:si -> segment name
   676 00000326 83C608                      add si,8                ; adjust past doubleword pointers
   677                                  
   678 00000329 B8[ssss]                	mov ax, DGROUP
   679 0000032C 8EC0                    	mov es, ax
   680 0000032E BF[0200]                	mov di, string_wlemitalign
   681                                  @@:
   682 00000331 A6                      	cmpsb
   683 00000332 7508                    	jne .check
   684 00000334 807CFF00                	cmp byte [si - 1], 0
   685 00000338 75F7                    	jne @B
   686 0000033A EB07                    	jmp .match
   687                                  
   688                                  .check:
   689 0000033C 26807DFF00              	cmp byte [es:di - 1], 0
   690 00000341 751F                    	jne .mismatch_pop
   691                                  .match:
   692 00000343 06                      	push es
   693 00000344 1F                      	pop ds		; => DGROUP
   694 00000345 31C0                    	xor ax, ax
   695                                   extern rec_offset, data_offset
   696 00000347 A3[0000]                	mov word [rec_offset], ax
   697 0000034A A3[0000]                	mov word [data_offset], ax
   698 0000034D A3[0200]                	mov word [data_offset + 2], ax
   699                                  
   700 00000350 07                      	pop es
   701                                  
   702 00000351 53                      	push bx
   703 00000352 8CC3                    	mov bx, es	; bx => segdef entry
   704 00000354 07                      	pop es		; es => segment partition entry
   705                                   extern addtodataoffset
   706 00000355 E8(0000)                	call addtodataoffset
   707                                  
   708 00000358 1E                      	push ds
   709 00000359 07                      	pop es		; => DGROUP
   710 0000035A 31F6                    	xor si, si
   711 0000035C 31C9                    	xor cx, cx
   712 0000035E E8(0000)                	call write_bytes
   713                                  
   714 00000361 A8                      	db __TEST_IMM8		; skip pop
   715                                  .mismatch_pop:
   716 00000362 58                      	pop ax
   717                                  .mismatch:
   718                                  
   719 00000363 5E                      	pop si
   720 00000364 5A                      	pop dx
   721 00000365 59                      	pop cx
   722 00000366 5B                      	pop bx
   723 00000367 07                      	pop es
   724 00000368 1F                      	pop ds
   725                                  do_not_emit_align:
   726                                  
   727                                  ps_expmap_chk_real:
   728 00000369 803E[0000]00                cmp byte [is_mapexpand],0      ; check if expanded map file
   729 0000036E 7403                        je  ps_15               ; no
   730                                  
   731                                  ; write detailed segment map
   732 00000370 E8(0000)                    call    map_detail_seg
   733                                  
   734                                  ; check if segment partition is in overlaid public table by checking vectored written bit
   735                                  ps_15:
   736 00000373 803E[0000]00                cmp byte [is_clarion],0        ; see if clarion switch set
   737 00000378 740C                        je  ps_16               ; no
   738 0000037A 26A00F00                    mov al,[es:15]          ; get flag byte for segment partition entry
   739 0000037E 2480                        and al,80h              ; see if in an overlay
   740                                  
   741 00000380 7404                        je  ps_16
   742 00000382 FF06[0000]                  inc word [ovl_code_count]      ; bump count of overlaid code segments
   743                                  
   744                                  ps_16:
   745                                  %if 0
   746                                      xor ax,ax               ; zero out table entry pointer, overwriting unneeded file_mod_id
   747                                      mov [es:6],ax
   748                                      mov [es:8],ax
   749                                  %endif
   750                                  
   751 00000386 26A00F00                    mov al,[es:15]          ; get flag byte for segment partition entry
   752 0000038A 2420                        and al,20h              ; see if end vectors written
   753 0000038C 7403                        je  ps_part_ptr         ; no
   754                                  
   755                                  ; look up segment partition entry in overlaid public table
   756                                  ; save segment in old file/module identification word and set record index
   757                                  ; byte to 255 to eliminate possible match later
   758                                  ps_save_lookup:
   759 0000038E E81700                      call    find_seg_in_table   ; find segment partition entry in overlaid public table
   760                                  
   761                                  ; keep pointer to segment partition entry (segdef entry for absolute segment)
   762                                  ps_part_ptr:
   763 00000391 D1E2                        shl dx,1                ; convert dx to word offset
   764 00000393 BB[0000]                    mov bx,offset seg_partent_indptr wrt DGROUP  ; set bx to base of array
   765 00000396 01D3                        add bx,dx               ; bx -> proper array element
   766 00000398 8C07                        mov [bx],es             ; set array element pointer to segment partition entry segment
   767                                  
   768 0000039A FF06[0000]                  inc word [current_segdef]      ; bump count of current segdef record
   769 0000039E 46                          inc si                  ; bump past checksum byte
   770 0000039F 39EE                        cmp si,bp               ; check boundary conditions
   771 000003A1 7203                        jb  ps_ret              ; okay
   772 000003A3 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   773                                  
   774                                  ps_ret:
   775 000003A6 07                          pop es                  ; restore critical register
   776 000003A7 C3                          ret
   777                                  proc2_segdef    ENDP
   778                                  
   779                                  ;*****************************
   780                                  ;* FIND_SEG_IN_TABLE         *
   781                                  ;*****************************
   782                                  
   783                                  ; find segment partition entry in overlaid public table
   784                                  ; upon entry es -> segment partition entry
   785                                  ; BEWARE: uses ds to speed things up, don't make assumptions about
   786                                  ; automatic variable access when making changes
   787                                  ; destroys ax
   788                                  
   789                                  find_seg_in_table   PROC
   790 000003A8 53                          push    bx              ; save critical register
   791 000003A9 51                          push    cx
   792 000003AA 52                          push    dx
   793 000003AB 06                          push    es
   794                                  
   795 000003AC 8CC2                        mov dx,es               ; save compare value in dx
   796 000003AE A1[0000]                    mov ax,[first_ovlpubblk_ptr]  ; get first allocate overlaid public block
   797 000003B1 BB0200                      mov bx,2                ; init block position
   798 000003B4 8ED8                        mov ds,ax               ; ds -> public block
   799                                  
   800                                  ; no more overlaid publics for this segment, move to next, if any
   801                                  fsi_next_seg:
   802 000003B6 81FBF703                    cmp bx,OVLPUB_BLK_BYSIZE-9  ; see if at end of block
   803 000003BA 7207                        jb  fsi_1               ; no
   804 000003BC 8E1E0000                    mov ds,[0]           ; get pointer to next block in ax
   805 000003C0 BB0200                      mov bx,2                ; init block position
   806                                  
   807                                  fsi_1:
   808 000003C3 8A07                        mov al,[bx]             ; get flag byte
   809 000003C5 3C01                        cmp al,1                ; see if segment partition entry byte
   810 000003C7 7409                        je  fsi_get_seg         ; yes
   811 000003C9 3C02                        cmp al,2                ; see if non-overlay class segment partition entry byte
   812 000003CB 7405                        je  fsi_get_seg         ; yes
   813 000003CD 83C303                      add bx,3                ; move to next position in block
   814 000003D0 EBE4                        jmp SHORT fsi_next_seg  ; keep looking for segment partition info
   815                                  
   816                                  fsi_get_seg:
   817 000003D2 43                          inc bx
   818 000003D3 8B07                        mov ax,[bx]             ; get segment partition entry
   819 000003D5 8B4F02                      mov cx,[bx+2]           ; get total overlaid references in cx
   820 000003D8 39D0                        cmp ax,dx               ; see if current segment partition matches that in entry
   821 000003DA 740F                        je  fsi_matched         ; yes, save pointer to entry in table
   822 000003DC 83C308                      add bx,8                ; scan past info to first overlaid public
   823 000003DF D1E9                        shr cx,1                ; divide by two (can be double references per entry due to near/far)
   824 000003E1 89C8                        mov ax,cx
   825 000003E3 D1E1                        shl cx,1
   826 000003E5 01C1                        add cx,ax               ; get minimum number of bytes to scan past (cx*3)
   827 000003E7 01CB                        add bx,cx
   828 000003E9 EBCB                        jmp SHORT fsi_next_seg  ; try for next segment partition entry
   829                                  
   830                                  fsi_matched:
   831 000003EB 83C302                      add bx,2                ; adjust to proper block offset
   832 000003EE 8CD8                        mov ax,ds               ; ax holds block segment
   833 000003F0 07                          pop es                  ; restore es -> segment partition entry
   834 000003F1 26891E0600                  mov [es:6],bx           ; save entry's block offset
   835 000003F6 26A30800                    mov [es:8],ax           ; save entry's block segment
   836 000003FA 26C6060A00FF                mov BYTE PTR [es:10],255    ; force invalid record index so no mistaken matches
   837                                  
   838 00000400 B8[ssss]                    mov ax,DGROUP
   839 00000403 8ED8                        mov ds,ax               ; restore ds -> warplink data
   840 00000405 5A                          pop dx                  ; restore critical registers
   841 00000406 59                          pop cx
   842 00000407 5B                          pop bx
   843 00000408 C3                          ret
   844                                  find_seg_in_table   ENDP
   845                                  
   846                                  ;*****************************
   847                                  ;* FIND_SEGDEF_ENTRY         *
   848                                  ;*****************************
   849                                  
   850                                  ; find segdef entry
   851                                  ; upon entry, al is nonzero if an entry must be found
   852                                  ; return segment of entry in es, null if none
   853                                  ; destroys ax,dx,di,es
   854                                  
   855                                  find_segdef_entry   PROC
   856 00000409 A2[0400]                    mov [mustfind],al         ; save mustfind flag
   857 0000040C 56                          push    si              ; save critical register
   858 0000040D A1[0600]                    mov ax,[segment_name_index]   ; get index value for lnames array
   859 00000410 48                          dec    ax               ; make count relative zero
   860 00000411 D1E0                        shl ax,1                ; convert to word index
   861 00000413 D1E0                        shl ax,1                ; convert to doubleword index
   862 00000415 BE[0000]                    mov si,OFFSET lnames_ent_indptr wrt DGROUP  ; si -> base of lnames array
   863 00000418 01C6                        add si,ax               ; si -> array element with segment:offset of name in lnames block
   864 0000041A 8CDA                        mov dx,ds
   865 0000041C C534                        lds si,[si]             ; -> name
   866 0000041E BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; point to slot to place name
   867 00000421 8EC2                        mov es,dx               ; es -> warplink's data
   868                                  			; di -> name field, si -> name offset in lnames block
   869 00000423 83C608                      add si,8                ; bump si past hi/low segment:offset pointers in lnames entry
   870                                  
   871                                  ; ds:si -> lnames name, es:di -> warplink data name field
   872                                  fse_get_name:
   873 00000426 A4                          movsb                   ; transfer a char
   874 00000427 807CFF00                    cmp BYTE PTR [si-1],0   ; zero char flags end of transfer
   875 0000042B 75F9                        jne fse_get_name        ; not zero, keep transferring
   876                                  
   877 0000042D 8CC0                        mov ax,es               ; get warplink's data segment
   878 0000042F 8ED8                        mov ds,ax               ; restores ds -> warplink data
   879 00000431 BE[0000]                    mov si,OFFSET name_field wrt DGROUP ; si -> name to get hash code of
   880 00000434 E8(0000)                    call    get_hash        ; get hash code of name
   881 00000437 BE[0000]                    mov si,OFFSET segdef_hash wrt DGROUP   ; si -> base of hash pointers to segdef entries
   882 0000043A D1E0                        shl ax,1                ; convert ax to word offset
   883 0000043C 01C6                        add si,ax               ; si points to proper name hash code entry
   884 0000043E 833C00                      cmp WORD PTR [si],0     ; is hash code used (nonzero value)
   885 00000441 7517                        jne fse_2               ; yes
   886                                  
   887                                  ; hash code for name unused, internal error
   888                                  fse_internal:
   889 00000443 803E[0400]00                cmp byte [mustfind],0          ; see if must find entry
   890 00000448 7507                        jne fse_int             ; yes
   891 0000044A 31C0                        xor ax,ax
   892 0000044C 8EC0                        mov es,ax               ; null es
   893 0000044E E9CD00                      jmp NEAR PTR fse_ret    ; and return
   894                                  
   895                                  fse_int:
   896 00000451 B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
   897 00000454 B90600                      mov cx,6                ; internal error value
   898 00000457 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   899                                  
   900                                  ; hash code used, check for hash collision
   901                                  fse_2:
   902 0000045A 8B14                        mov dx,[si]             ; get segment pointer to segdef entry
   903                                  
   904                                  fse_testloop:
   905 0000045C 8EC2                        mov es,dx               ; es -> segdef entry
   906                                  
   907                                  ; check if hash code is absolute segment, bypass segment/class name checks if so
   908 0000045E 26A01A00                    mov al,[es:26]          ; get acbp byte
   909 00000462 24E0                        and al,0e0h             ; get align field
   910 00000464 744F                        je  fse_hash_abs        ; zero, segment is absolute
   911                                  
   912 00000466 26C43E0800                  les di,[es:8]           ; -> segment name in lnames block
   913 0000046B 83C708                      add di,8                ; adjust for 2 segment:offset pointers
   914 0000046E BE[0000]                    mov si,OFFSET name_field wrt DGROUP ; si -> name to get hash code of
   915                                  
   916                                  ; ds:si -> name, es:di -> name to test against
   917                                  fse_byteloop:
   918 00000471 8A04                        mov al,[si]
   919 00000473 260A05                      or  al,[es:di]          ; see if both values are zero (matched to null terminator)
   920 00000476 7410                        je  fse_match           ; strings matched
   921 00000478 A6                          cmpsb                   ; compare a nonzero byte in the two names
   922 00000479 74F6                        je  fse_byteloop        ; bytes match, loop for next byte test
   923                                  
   924                                  fse_next_entry:
   925 0000047B 8EC2                        mov es,dx               ; get segdef entry segment value
   926 0000047D 268B161400                  mov dx,[es:20]          ; get next entry
   927 00000482 09D2                        or  dx,dx               ; check if a null pointer (dx=0)
   928 00000484 75D6                        jne fse_testloop        ; no, keep checking entries
   929                                  
   930                                  ; internal error, no names found
   931 00000486 EBBB                        jmp SHORT fse_internal
   932                                  
   933                                  ; segment names match, check class names
   934                                  fse_match:
   935 00000488 8EC2                        mov es,dx               ; es -> segdef entry
   936 0000048A 1E                          push    ds              ; save data segment value, used
   937 0000048B 8B36[0000]                  mov si,[class_name_index] ; get index value for lnames array
   938 0000048F 4E                          dec si                  ; make count relative zero
   939 00000490 D1E6                        shl si,1                ; convert to word index
   940 00000492 D1E6                        shl si,1                ; convert to doubleword index
   941 00000494 C5B4[0000]                  lds si, [lnames_ent_indptr + si wrt DGROUP]
   942                                  			; -> name from lnames entry
   943 00000498 83C608                      add si,8                ; adjust past 2 doubleword pointers
   944                                  			; ds:si -> class name in lnames block from index
   945                                  
   946 0000049B 26C43E0C00                  les di,[es:12]          ; -> entry's class name
   947 000004A0 83C708                      add di,8                ; adjust past 2 doubleword pointers
   948                                  			; es:di -> test entry's class name in lnames block
   949                                  
   950                                  fse_matchloop:
   951 000004A3 A6                          cmpsb                   ; compare a char
   952 000004A4 7403                        je  fse_3               ; name char matched
   953 000004A6 1F                          pop ds                  ; match failed, restore segment register
   954 000004A7 EBD2                        jmp SHORT fse_next_entry    ; try next entry
   955                                  
   956                                  fse_3:
   957 000004A9 8A44FF                      mov al,[si-1]           ; matching zero chars flag successful end of compare
   958 000004AC 260A45FF                    or  al,[es:di-1]
   959 000004B0 75F1                        jne fse_matchloop       ; not done yet
   960                                  
   961                                  ; class names match, check ACBP bytes
   962                                  fse_class_match:
   963 000004B2 1F                          pop ds                  ; restore segment register
   964 000004B3 8EC2                        mov es,dx               ; es -> segdef entry
   965                                  
   966                                  fse_hash_abs:
   967 000004B5 A0[0000]                    mov al,[acbp_byte]
   968 000004B8 88C4                        mov ah,al
   969 000004BA 80E4E0                      and ah,0e0h             ; check if absolute segment
   970 000004BD 750C                        jne fse_not_abs         ; no
   971                                  
   972                                  ; absolute segment, check frame numbers to see if they are the same
   973                                  fse_is_abs:
   974 000004BF A1[0800]                    mov ax,[frame_number]     ; get frame number
   975 000004C2 263B060000                  cmp ax,[es:0]           ; compare to entry's frame number
   976 000004C7 75B2                        jne fse_next_entry      ; not the same absolute segment, try next entry
   977 000004C9 EB53                        jmp SHORT fse_ret       ; same absolute segment
   978                                  
   979                                  fse_not_abs:
   980 000004CB 241C                        and al,1ch              ; mask out all but combine field of acbp byte
   981 000004CD 740A                        je  fse_private         ; combine field is private (==0)
   982 000004CF 26A01A00                    mov al,[es:26]          ; get entry combine type
   983 000004D3 241C                        and al,1ch
   984 000004D5 7547                        jne fse_ret             ; both ACBP combineable types
   985 000004D7 EBA2                        jmp SHORT fse_next_entry    ; not combineable, try next entry
   986                                  
   987                                  ; current ACBP combine field private, check if entry is private as well
   988                                  fse_private:
   989 000004D9 26A01A00                    mov al,[es:26]          ; get entry combine type
   990 000004DD 241C                        and al,1ch
   991 000004DF 7402                        je  fse_4               ; both combine fields private types
   992 000004E1 EB98                        jmp SHORT fse_next_entry    ; not both private, try next segdef entry
   993                                  
   994                                  ; check file id and record index of first segment partition entry
   995                                  fse_4:
   996 000004E3 268E061600                  mov es,[es:22]          ; es -> first segment partition entry
   997 000004E8 803E[0000]00                cmp byte [is_inlib],0          ; check if processing library
   998 000004ED 750C                        jne fse_5               ; yes
   999                                  
  1000                                  ; processing object module, check against current object module number
  1001 000004EF A1[0000]                    mov ax,[current_obj]
  1002 000004F2 263B060600                  cmp ax,[es:6]           ; check if file id matches
  1003 000004F7 7416                        je  fse_6               ; yes
  1004                                  
  1005                                  fse_nomatch:
  1006 000004F9 EB80                        jmp NEAR PTR fse_next_entry ; no, try next segdef entry
  1007                                  
  1008                                  ; processing library, check against library id
  1009                                  fse_5:
  1010 000004FB 26A10600                    mov ax,[es:6]           ; get low word of file_mod_id
  1011 000004FF 3B06[0000]                  cmp ax,WORD PTR [lib_id]  ; compare to low word of library id
  1012 00000503 75F4                        jne fse_nomatch         ; doesn't match
  1013 00000505 26A10800                    mov ax,[es:8]           ; get high word of file_mod_id
  1014 00000509 3B06[0200]                  cmp ax,WORD PTR [lib_id+2]    ; compare to high word of library id
  1015 0000050D 75EA                        jne fse_nomatch         ; doesn't match
  1016                                  
  1017                                  fse_6:
  1018 0000050F A1[0000]                    mov ax,[current_segdef]
  1019 00000512 263A060A00                  cmp al,[es:10]          ; check if record index matches
  1020 00000517 8EC2                        mov es,dx               ; es -> segdef entry
  1021 00000519 7403                        je  fse_ret             ; yes
  1022 0000051B E95DFF                      jmp NEAR PTR fse_next_entry ; no, try next segdef entry
  1023                                  
  1024                                  ; names match, and ACBP combineable types OR first segment partition entry's file id and record index match
  1025                                  ; OR absolute segment and frame numbers match
  1026                                  fse_ret:
  1027 0000051E 5E                          pop si
  1028 0000051F C3                          ret
  1029                                  find_segdef_entry   ENDP
  1030                                  
  1031                                  ;*****************************
  1032                                  ;* PROC2_GRPDEF              *
  1033                                  ;*****************************
  1034                                  
  1035                                  ; pass 2 grpdef record processing
  1036                                  ; upon entry cx=record length,bp=buffer_end,al=record type
  1037                                  ; es:si -> first byte of record past record length
  1038                                  ; destroys ax,bx,dx,di
  1039                                  ; updates si
  1040                                  
  1041                                  proc2_grpdef    PROC
  1042 00000520 30E4                        xor ah,ah               ; zero high byte of index
  1043 00000522 268A04                      mov al,[es:si]          ; get group name index byte
  1044 00000525 46                          inc si                  ; scan past group name index byte
  1045 00000526 49                          dec cx                  ; decrement record length to parse
  1046 00000527 39EE                        cmp si,bp               ; check boundary conditions
  1047 00000529 7203                        jb  pg_2                ; okay
  1048 0000052B E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
  1049                                  pg_2:
  1050 0000052E 3C80                        cmp al,80h              ; see if two byte index
  1051 00000530 7210                        jb  pg_3                ; no
  1052 00000532 247F                        and al,7fh              ; mask off high bit
  1053 00000534 88C4                        mov ah,al               ; ah holds high word of index
  1054 00000536 268A04                      mov al,[es:si]          ; get second group name index byte
  1055 00000539 46                          inc si                  ; scan past group name index byte
  1056 0000053A 49                          dec cx                  ; decrement record length to parse
  1057 0000053B 39EE                        cmp si,bp               ; check boundary conditions
  1058 0000053D 7203                        jb  pg_3                ; okay
  1059 0000053F E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
  1060                                  
  1061                                  pg_3:
  1062 00000542 E81200                      call    find_grpdef_entry  ; find/return group entry segment in ax
  1063                                  
  1064 00000545 BB[0000]                    mov bx,OFFSET grp_ent_indptr wrt DGROUP    ; bx -> base of array pointers to group entries
  1065 00000548 8B3E[0000]                  mov di,[current_grpdef]   ; get array element (current grpdef number)
  1066 0000054C D1E7                        shl di,1                ; make ax a word offset
  1067 0000054E 01FB                        add bx,di               ; bx -> proper array element
  1068 00000550 8907                        mov [bx],ax             ; save pointer to public declaration entry
  1069 00000552 FF06[0000]                  inc word [current_grpdef]      ; bump count of current grpdef
  1070 00000556 C3                          ret
  1071                                  proc2_grpdef    ENDP
  1072                                  
  1073                                  ;*****************************
  1074                                  ;* FIND_GRPDEF_ENTRY         *
  1075                                  ;*****************************
  1076                                  
  1077                                  ; find group entry for group name
  1078                                  ; upon entry ax == group name index byte
  1079                                  ; returns segment of entry in ax
  1080                                  ; destroys ax,bx,dx,di
  1081                                  
  1082                                  find_grpdef_entry   PROC
  1083 00000557 06                          push    es              ; save critical register
  1084 00000558 48                          dec ax                  ; make group index relative zero
  1085 00000559 D1E0                        shl ax,1
  1086 0000055B D1E0                        shl ax,1                ; convert ax to double word offset into array
  1087 0000055D BB[0000]                    mov bx,OFFSET lnames_ent_indptr wrt DGROUP  ; set bx to base of lnames index pointer array
  1088 00000560 01C3                        add bx,ax               ; point to array element
  1089 00000562 8B3F                        mov di,[bx]             ; di holds offset
  1090 00000564 8B5F02                      mov bx,[bx+2]           ; bx holds segment
  1091                                  
  1092 00000567 8E06[0000]                  mov es,[first_grpblk_ptr] ; get segment of first allocated group block
  1093 0000056B 31D2                        xor dx,dx               ; dx hold group entry number
  1094                                  
  1095                                  fge_grp_loop:
  1096 0000056D 263B160000                  cmp dx,[es:0]           ; check if any more entries in group block
  1097 00000572 7215                        jb  fge_3               ; yes
  1098                                  
  1099                                  ; no more entries in group block, get next group block
  1100 00000574 26A10200                    mov ax,[es:2]           ; get pointer to next group
  1101 00000578 09C0                        or  ax,ax               ; check if null, no more group blocks
  1102 0000057A 7509                        jne fge_2               ; nonnull, get next group block
  1103                                  
  1104                                  ; internal error, group entry not found
  1105                                  fge_internal:
  1106 0000057C B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
  1107 0000057F B90700                      mov cx,7                ; internal error value
  1108 00000582 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  1109                                  
  1110                                  fge_2:
  1111 00000585 8EC0                        mov es,ax               ; es -> new block
  1112 00000587 31D2                        xor dx,dx               ; re-init group entry number
  1113                                  
  1114                                  fge_3:
  1115 00000589 06                          push    es              ; save es -> block
  1116 0000058A 8CC0                        mov ax,es               ; get block segment address
  1117 0000058C 01D0                        add ax,dx               ; get first free entry segment value
  1118 0000058E 40                          inc ax                  ; adjust for block system info size of 1 paragraph
  1119 0000058F 8EC0                        mov es,ax               ; es -> group entry
  1120 00000591 42                          inc dx                  ; bump entry number
  1121                                  
  1122 00000592 263B3E0400                  cmp di,[es:4]           ; see if offsets of lnames pointers match
  1123 00000597 7403                        je  fge_4               ; yes
  1124                                  
  1125                                  fge_nomatch:
  1126 00000599 07                          pop es                  ; restore es -> block
  1127 0000059A EBD1                        jmp SHORT fge_grp_loop  ; try next entry
  1128                                  
  1129                                  fge_4:
  1130 0000059C 263B1E0600                  cmp bx,[es:6]           ; see if segments of lnames pointer match
  1131 000005A1 75F6                        jne fge_nomatch         ; no
  1132                                  
  1133                                  ; names match, ax holds group entry segment
  1134                                  fge_ret:
  1135 000005A3 5B                          pop bx                  ; trash old es value on stack
  1136 000005A4 07                          pop es                  ; restore critical register
  1137 000005A5 C3                          ret
  1138                                  find_grpdef_entry   ENDP
  1139                                  
  1140                                  END
