     1                                  ;*********************************************************************
     2                                  ;*   MLPASS1B.ASM                                                    *
     3                                  ;*                                                                   *
     4                                  ;*   By:            Michael Devore                                   *
     5                                  ;*   Date:          12/21/92                                         *
     6                                  ;*   Model:         Small                                            *
     7                                  ;*   Version:       2.5                                              *
     8                                  ;*   Assembler:     MASM 5.0                                         *
     9                                  ;*   Environment:   MS-DOS 2.x+                                      *
    10                                  ;*                                                                   *
    11                                  ;*   linker pass 1 routines part B                                   *
    12                                  ;*                                                                   *
    13                                  ;*********************************************************************
    14                                  
    15                                  ;TITLE   WARPLINK mlpass1a
    16                                  ;PAGE    50,80
    17                                  
    18                                  ;.MODEL  SMALL
    19                                  
    20                                  ;*****************************
    21                                  ;* Include files             *
    22                                  ;*****************************
    23                                  
    24                                  [list -]
    29                                  
    30                                  ;*****************************
    31                                  ;* Public declarations       *
    32                                  ;*****************************
    33                                  
    34                                  ; procedures
    35                                  PUBLIC  proc1_lnames,proc1_segdef,init_segdef_entry,make_segdef_blk
    36                                  PUBLIC  make_segpart_blk
    37                                   global align_ax_from_bl
    38                                  
    39                                  ; variables
    40                                  PUBLIC  is_absseg,dgrouptext,class_name_index,first_lnamesblk_ptr
    41                                  
    42                                  ;*****************************
    43                                  ;* Data begins               *
    44                                  ;*****************************
    45                                  
    46                                  .DATA
    47                                  
    48                                  ;*****************************
    49                                  ;* External declarations     *
    50                                  ;*****************************
    51                                  
    52                                  EXTRN   parse_complete:BYTE,name_field:BYTE,filename:BYTE
    53                                  EXTRN   mod_ovl_count:WORD,clip_libnum:WORD
    54                                  EXTRN	maybe_clipper:BYTE,symbol_overflow:BYTE
    55                                  EXTRN	clipper_segdef_ptr:WORD,clipper_symseg_ptr:WORD,clipper_segindex:WORD
    56                                  EXTRN	is_local:BYTE
    57                                  
    58                                  ; initialized local variables
    59                                  
    60                                  ; byte values
    61                                  EVEN                        ; maximize speed on 8086 and better
    62 00000000 00                      _textflag   DB  0           ; nonzero if DOSSEG and segment _TEXT has 16 bytes inserted
    63 00000001 0000                    first_lnamesblk_ptr DW  0   ; segment of first allocated lnames logical names block
    64                                  
    65                                  .DATA?
    66                                  
    67                                  ; uninitialized local variables
    68                                  
    69                                  ; byte values
    70                                  EVEN
    71 00000000 ??                      hash_used   DB  ?           ; nonzero if lnames hash code previously used
    72 00000001 ??                      EVEN
    73 00000002 ??                      acbp_byte   DB  ?           ; ACBP byte in segdef record
    74 00000003 ??                      EVEN
    75 00000004 ??                      is_absseg   DB  ?           ; nonzero if segment is absolute
    76 00000005 ??                      EVEN
    77 00000006 ??                      is_common   DB  ?           ; nonzero if segment is COMMON type
    78 00000007 ??                      EVEN
    79 00000008 ??                      ovl_seg_flag    DB  ?       ; nonzero if current segment is in an overlay
    80                                  
    81                                  ; word values
    82 00000009 ??                      EVEN
    83 0000000A ????                    segment_name_index  DW  ?   ; segment name index in segdef record
    84 0000000C ????                    class_name_index    DW  ?   ; class name index in segdef record
    85 0000000E ????                    frame_number    DW  ?       ; frame number in segdef record
    86                                  
    87                                  ; doubleword values
    88 00000010 ????????                old_lnamesent_ptr   DD  ?   ; previous lnames entry pointer
    89 00000014 ????????                segment_length  DD  ?       ; segment length in segdef record
    90 00000018 ????????                no_align_length DD  ?       ; segment length without alignment adjustment, saved to partition entry
    91                                  
    92                                  ;*****************************
    93                                  ;* Constant data             *
    94                                  ;*****************************
    95                                  
    96                                  .CONST
    97                                  
    98                                  EVEN
    99                                  alignment_table:
   100 00000000 0000                    	dw 1-1	; A0 = absolute segment, not an alignment
   101 00000002 0000                    	dw 1-1	; A1 = byte
   102 00000004 0100                    	dw 2-1	; A2 = word
   103 00000006 0F00                    	dw 16-1	; A3 = para (16)
   104 00000008 FF00                    	dw 256-1; A4 = page (256)
   105 0000000A 0300                    	dw 4-1	; A5 = dword
   106 0000000C FF0F                    	dw 4096-1	; A6 = 4 KiB (PharLap extension)
   107 0000000E 0000                    	dw 1-1	; A7 = undefined (we treat it as byte alignment)
   108                                  
   109                                  alignment_order:
   110                                  ; 4kib (A6) > page (A4) > para (A3) > dword (A5) > word (A2) > byte (A1) > A7 > A0
   111 00000010 00                      	db 0	; A0 = absolute segment, not an alignment
   112 00000011 02                      	db 2	; A1 = byte
   113 00000012 03                      	db 3	; A2 = word
   114 00000013 05                      	db 5	; A3 = para (16)
   115 00000014 06                      	db 6	; A4 = page (256)
   116 00000015 04                      	db 4	; A5 = dword
   117 00000016 07                      	db 7	; A6 = 4 KiB (PharLap extension)
   118 00000017 01                      	db 1	; A7 = undefined (we treat it as byte alignment)
   119                                  .para: equ 5
   120                                  
   121 00000018 5F5445585400            _texttext   DB  '_TEXT',0   ; segment name to check against for DOSSEG use
   122 0000001E 4447524F555000          dgrouptext  DB  'DGROUP',0  ; segment name to check to set is_dgroup flag
   123 00000025 53594D424F4C5300        symbolstext	DB	'SYMBOLS',0	; segment/class to check for Clipper code
   124                                  
   125                                  ;*****************************
   126                                  ;* Code begins               *
   127                                  ;*****************************
   128                                  
   129                                  .CODE
   130                                  
   131                                  ;*****************************
   132                                  ;* External declarations     *
   133                                  ;*****************************
   134                                  
   135                                  EXTRN   link_error:NEAR,dos_error:NEAR,load_file:NEAR
   136                                  EXTRN   get_name:NEAR,get_hash:NEAR,alloc_memory:NEAR
   137                                  EXTRN   error_bx_pos:NEAR,error_read_buff_pos:NEAR
   138                                  EXTRN   chk_seg_ovl_class:NEAR
   139                                  
   140                                  ;*****************************
   141                                  ;* PROC1_LNAMES              *
   142                                  ;*****************************
   143                                  
   144                                  ; process LNAMES record
   145                                  ; upon entry cx=record length,bp=buffer_end,al=record type
   146                                  ; es:si -> first byte of record past record length
   147                                  ; destroys ax,bx,dx,di
   148                                  ; updates si
   149                                  
   150                                  proc1_lnames    PROC
   151                                  pl_loop:
   152 00000000 A1[0000]                    mov ax,[current_lnames]   ; get count of lnames logical names in file
   153 00000003 3DFF01                      cmp ax,LNAMES_MAX       ; see if at or beyond maximum
   154 00000006 7209                        jb  pl_2                ; no
   155 00000008 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   156 0000000B B80D00                      mov ax,LNAMES_COUNT_ERR ; too many LNAMES logical names in file
   157 0000000E E9(0000)                    jmp NEAR PTR error_read_buff_pos    ; transfer control to error handler
   158                                  
   159                                  pl_2:
   160 00000011 40                          inc ax                  ; bump count of lnames logical names
   161 00000012 A3[0000]                    mov [current_lnames],ax   ; save back to global memory variable
   162 00000015 89C3                        mov bx,ax               ; save value
   163 00000017 BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; point di at field to place name
   164 0000001A C606[0000]00            	mov	byte [is_local],0			; flag not a local for get_name
   165 0000001F E8(0000)                    call    get_name        ; get lnames logical name from record
   166 00000022 BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; point di at name
   167 00000025 803D00                      cmp BYTE PTR [di],0     ; check if null name
   168 00000028 7508                        jne pl_save_name        ; no, non-null name
   169 0000002A B8[0000]                    mov ax,OFFSET zero_table wrt DGROUP ; point to known zero value
   170 0000002D BA[ssss]                    mov dx,DGROUP
   171 00000030 EB03                        jmp SHORT pl_array
   172                                  
   173                                  pl_save_name:
   174 00000032 E82100                      call    get_lnames_entry    ; find or create entry, return segment:offset pointer
   175                                  
   176                                  pl_array:
   177 00000035 89DF                        mov di,bx               ; get current lnames logical names count in di
   178 00000037 4F                          dec di                  ; make count relative zero
   179 00000038 D1E7                        shl di,1
   180 0000003A D1E7                        shl di,1                ; make lnames index value a doubleword offset into index pointer array
   181 0000003C BB[0000]                    mov bx,OFFSET lnames_ent_indptr wrt DGROUP  ; set bx to base of lnames index pointer array
   182 0000003F 01FB                        add bx,di               ; point to array element
   183 00000041 8907                        mov [bx],ax             ; save lnames logical name offset
   184 00000043 895702                      mov [bx+2],dx           ; save lnames logical name segment
   185                                  
   186                                  pl_checksum:
   187 00000046 83F901                      cmp cx,1                ; check if at checksum byte
   188 00000049 7602                        jbe pl_out              ; yes, gobble it and return
   189 0000004B EBB3                        jmp pl_loop    ; loop back for next definition
   190                                  
   191                                  pl_out:
   192 0000004D 46                          inc si                  ; bump past checksum byte
   193 0000004E 39EE                        cmp si,bp               ; check boundary conditions
   194 00000050 7203                        jb  pl_ret              ; okay
   195 00000052 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   196                                  
   197                                  pl_ret:
   198 00000055 C3                          ret
   199                                  proc1_lnames    ENDP
   200                                  
   201                                  ;*****************************
   202                                  ;* GET_LNAMES_ENTRY          *
   203                                  ;*****************************
   204                                  
   205                                  ; find or make entry for lnames logical name
   206                                  ; upon entry di -> warplink data location holding logical name
   207                                  ; returns segment:offset pointer to entry in dx:ax
   208                                  ; destroys ax,dx,di
   209                                  
   210                                  get_lnames_entry    PROC
   211 00000056 53                          push    bx              ; save critical registers
   212 00000057 51                          push    cx
   213 00000058 56                          push    si
   214 00000059 06                          push    es
   215 0000005A 30C0                        xor al,al
   216 0000005C A2[0000]                    mov [hash_used],al        ; init hash_used flag
   217 0000005F 89FE                        mov si,di               ; si -> name to get hash code of
   218 00000061 E8(0000)                    call    get_hash        ; get hash code of name in ax
   219                                  
   220 00000064 BE[0000]                    mov si,OFFSET lnames_hash wrt DGROUP    ; si -> base of hash pointers to lnames entries
   221 00000067 D1E0                        shl ax,1
   222 00000069 D1E0                        shl ax,1                ; convert ax to doubleword offset
   223 0000006B 01C6                        add si,ax               ; si points to proper name hash code entry
   224 0000006D 56                          push    si              ; save pointer to hash code entry
   225 0000006E 837C0200                    cmp WORD PTR [si+2],0   ; is hash code used (nonzero segment value)
   226 00000072 7525                        jne gle_2
   227 00000074 A1[0000]                    mov ax,[alloc_lnamesblk_ptr]
   228 00000077 8EC0                        mov es,ax               ; es -> current block
   229 00000079 09C0                        or  ax,ax               ; check if any lnames blocks were previously allocated
   230 0000007B 756D                        jne gle_3               ; yes
   231                                  
   232                                  ; make initial lnames allocation
   233 0000007D BB5600                      mov bx,LNAMES_BLK_SIZE  ; number of paragraphs to allocate
   234 00000080 E8(0000)                    call    alloc_memory    ; get memory for block allocation
   235 00000083 A3[0100]                    mov [first_lnamesblk_ptr],ax  ; save first lnames block pointer
   236 00000086 A3[0000]                    mov [alloc_lnamesblk_ptr],ax  ; update last allocated block pointer
   237 00000089 8EC0                        mov es,ax               ; es == current (new) block segment
   238 0000008B 31DB                        xor bx,bx
   239 0000008D 26C7075C05                  mov word [es:bx],LNAMES_LIST_SIZE    ; all lnames entry space is free
   240 00000092 26891E0200                  mov WORD PTR [es:2],bx  ; zero pointer to next entry
   241 00000097 EB51                        jmp SHORT gle_3         ; bypass duplicate name /hash collision code
   242                                  
   243                                  ; hash code used, check whether duplicate name or hash collision
   244                                  gle_2:
   245 00000099 FE06[0000]                  inc byte [hash_used]           ; nonzero value flags that hash code was previously used
   246 0000009D 57                          push    di              ; save di pointing to name
   247 0000009E 8B4402                      mov ax,[si+2]           ; get segment pointer to lnames entry
   248 000000A1 8B14                        mov dx,[si]             ; get offset pointer to lnames entry
   249                                  
   250                                  gle_testloop:
   251 000000A3 8EC0                        mov es,ax               ; es == segment of lnames entry testing name against
   252 000000A5 89D7                        mov di,dx               ; di == offset of lnames entry testing name against
   253 000000A7 89FB                        mov bx,di               ; save entry offset in bx
   254 000000A9 83C708                      add di,8                ; scan past segment:offset high and low pointers
   255 000000AC 5E                          pop si                  ; si -> name
   256 000000AD 56                          push    si
   257                                  
   258                                  ; ds:si -> name, es:di -> name to test against
   259                                  gle_byteloop:
   260 000000AE 8A04                        mov al,[si]
   261 000000B0 260A05                      or  al,[es:di]          ; see if both values are zero (matched to null terminator)
   262 000000B3 7509                        jne  gle_4              ; at least one char left in at least one string
   263                                  
   264                                  ; names match, return pointer to name
   265 000000B5 5F                          pop di                  ; trash hash point on stack
   266 000000B6 5F                          pop di                  ; restore di -> name
   267 000000B7 89D0                        mov ax,dx               ; ax holds name offset
   268 000000B9 8CC2                        mov dx,es               ; dx holds name segment
   269 000000BB E9B700                      jmp NEAR PTR gle_out
   270                                  
   271                                  gle_4:
   272 000000BE A6                          cmpsb                   ; compare a nonzero byte in the two names
   273 000000BF 74ED                        je  gle_byteloop        ; bytes match, loop for next byte test
   274 000000C1 891E[1000]                  mov WORD PTR [old_lnamesent_ptr],bx   ; save offset of nonmatching lnames entry
   275 000000C5 8C06[1200]                  mov WORD PTR [old_lnamesent_ptr+2],es ; save segment of nonmatching lnames entry
   276 000000C9 720C                        jc  gle_5               ; old name greater than new name
   277                                  
   278                                  ; new name greater than old name
   279 000000CB 268B4706                    mov ax,[es:bx+6]        ; get segment of lnames entry having a greater name
   280 000000CF 268B5704                    mov dx,[es:bx+4]        ; get offset of lnames entry having greater name
   281 000000D3 30C9                        xor cl,cl               ; flag new > old, update high pointer
   282 000000D5 EB09                        jmp SHORT gle_6         ; check for null pointer
   283                                  
   284                                  ; old name greater than new name
   285                                  gle_5:
   286 000000D7 268B4702                    mov ax,[es:bx+2]        ; get segment of lnames entry having lesser name
   287 000000DB 268B17                      mov dx,[es:bx]          ; get offset of lnames entry having lesser name
   288 000000DE B101                        mov cl,1                ; flag old > new update low pointer
   289                                  
   290                                  gle_6:
   291 000000E0 09C0                        or  ax,ax               ; check if a null pointer (segment value in ax=0)
   292 000000E2 75BF                        jne gle_testloop        ; no, keep checking entries
   293                                  
   294 000000E4 A1[0000]                    mov ax,[alloc_lnamesblk_ptr]  ; get last allocated block pointer
   295 000000E7 8EC0                        mov es,ax               ; es -> lnames block
   296 000000E9 5F                          pop di                  ; restore di -> name
   297                                  
   298                                  gle_3:
   299                                  ; get length of name in dx INCLUDING zero terminator
   300 000000EA 31DB                        xor bx,bx               ; bx will offset into name
   301 000000EC BA0100                      mov dx,1                ; init length of name
   302                                  gle_lenloop:
   303 000000EF 803900                      cmp BYTE PTR [bx+di],0  ; check if at end of name
   304 000000F2 7404                        je  gle_7               ; yes, at end
   305 000000F4 42                          inc dx                  ; bump count of chars in string
   306 000000F5 43                          inc bx                  ; point to next char
   307 000000F6 EBF7                        jmp SHORT gle_lenloop   ; check next char
   308                                  
   309                                  gle_7:
   310 000000F8 83C208                      add dx,8                ; add in space for segment:offset high and low pointers
   311 000000FB 26A10000                    mov ax,[es:0]           ; get free lnames entry space
   312                                  
   313 000000FF 52                          push    dx              ; save length of name entry on stack
   314 00000100 39C2                        cmp dx,ax               ; see if lnames entry will fit in block
   315 00000102 7707                        ja  gle_8               ; no, it won't
   316                                  
   317                                  ; name will fit into current pubdef names block
   318 00000104 BA5C05                      mov dx,LNAMES_LIST_SIZE
   319 00000107 29C2                        sub dx,ax               ; get beginning slot for lnames entry
   320 00000109 EB05                        jmp SHORT gle_9         ; bypass block allocation code
   321                                  
   322                                  ; not enough room for name in this block, allocate another lnames block
   323                                  gle_8:
   324 0000010B E86C00                      call    make_lnames_blk
   325 0000010E 31D2                        xor dx,dx               ; first name entry starts at offset zero
   326                                  
   327                                  gle_9:
   328 00000110 5E                          pop si                  ; get length of entry
   329 00000111 26A10000                    mov ax,[es:0]           ; get free lnames entry space
   330 00000115 29F0                        sub ax,si               ; subtract name length including terminator byte and hi/low pointer space
   331 00000117 26A30000                    mov [es:0],ax           ; update free lnames entry space
   332                                  
   333 0000011B 83C20C                      add dx,12               ; adjust name entry offset past 2 system info words and hi/low pointers
   334 0000011E 88CB                        mov bl,cl               ; save hi/low flag from cl
   335 00000120 89F1                        mov cx,si               ; cx == bytes to transfer (length of entry)
   336 00000122 83E908                      sub cx,8                ; adjust for hi/low pointer doublewords
   337 00000125 89FE                        mov si,di               ; si -> lnames logical name
   338 00000127 89D7                        mov di,dx               ; di -> destination of name in lnames block
   339 00000129 D1E9                        shr cx,1                ; convert to words
   340 0000012B F3A5                        rep movsw               ; move the string
   341 0000012D D1D1                        rcl cx,1                ; pick up carry
   342 0000012F F3A4                        rep movsb               ; transfer leftover byte, if any
   343 00000131 88D9                        mov cl,bl               ; restore hi/low flag to proper state
   344                                  
   345 00000133 83EA08                      sub dx,8                ; back dx up to beginning of entry
   346 00000136 89D7                        mov di,dx
   347 00000138 31C0                        xor ax,ax
   348 0000013A 268905                      mov [es:di],ax          ; zero segment:offset low and high pointers
   349 0000013D 26894502                    mov [es:di+2],ax
   350 00000141 26894504                    mov [es:di+4],ax
   351 00000145 26894506                    mov [es:di+6],ax
   352                                  
   353 00000149 5E                          pop si                  ; get pointer to hash code array entry
   354 0000014A 8CC2                        mov dx,es               ; get segment of new lnames entry in dx
   355 0000014C 89F8                        mov ax,di               ; get offset of new lnames entry in ax
   356                                  
   357 0000014E 803E[0000]00                cmp byte [hash_used],0         ; check if hash code was used
   358 00000153 7507                        jne gle_10              ; yes it was
   359                                  
   360                                  ; hash code previously unused, update hash code pointer
   361 00000155 8904                        mov [si],ax             ; save offset
   362 00000157 895402                      mov [si+2],dx           ; save segment
   363 0000015A EB19                        jmp SHORT gle_out       ; done, restore critical registers and return
   364                                  
   365                                  gle_10:
   366 0000015C C43E[1000]                  les di,[old_lnamesent_ptr]    ; get segment:offset of previous lnames entry
   367 00000160 08C9                        or  cl,cl               ; see which pointer to update
   368 00000162 750A                        jne gle_11              ; nonzero, update low name pointer
   369 00000164 26894504                    mov [es:di+4],ax        ; update offset of high name pointer
   370 00000168 26895506                    mov [es:di+6],dx        ; update segment of high name pointer
   371 0000016C EB07                        jmp SHORT gle_out       ; done, restore critical registers and return
   372                                  
   373                                  gle_11:
   374 0000016E 268905                      mov [es:di],ax          ; update offset of low name pointer
   375 00000171 26895502                    mov [es:di+2],dx        ; update segment of low name pointer
   376                                  
   377                                  gle_out:
   378 00000175 07                          pop es                  ; restore critical registers
   379 00000176 5E                          pop si
   380 00000177 59                          pop cx
   381 00000178 5B                          pop bx
   382 00000179 C3                          ret
   383                                  get_lnames_entry    ENDP
   384                                  
   385                                  ;*****************************
   386                                  ;* MAKE_LNAMES_BLK           *
   387                                  ;*****************************
   388                                  
   389                                  ; make a new lnames block
   390                                  ; return segment of new block in es
   391                                  ; destroys ax,es
   392                                  
   393                                  make_lnames_blk PROC
   394 0000017A 52                          push    dx              ; save critical register
   395 0000017B 8B16[0000]                  mov dx,[alloc_lnamesblk_ptr]  ; keep previously last allocated block segment
   396 0000017F BB5600                      mov bx,LNAMES_BLK_SIZE  ; number of paragraphs to allocate
   397 00000182 E8(0000)                    call    alloc_memory    ; get memory for block allocation
   398 00000185 A3[0000]                    mov [alloc_lnamesblk_ptr],ax  ; update last allocated block pointer
   399                                  
   400 00000188 8EC2                        mov es,dx               ; es -> old block
   401 0000018A 26A30200                    mov [es:2],ax           ; update old block to point to new block
   402                                  
   403 0000018E 8EC0                        mov es,ax               ; es -> new block
   404 00000190 26C70600005C05              mov word [es:0],LNAMES_LIST_SIZE ; all name list space is free
   405 00000197 26C70602000000              mov WORD PTR [es:2],0   ; zero pointer to next entry
   406 0000019E 5A                          pop dx                  ; restore critical registers
   407 0000019F C3                          ret
   408                                  make_lnames_blk ENDP
   409                                  
   410                                  ;*****************************
   411                                  ;* PROC1_SEGDEF              *
   412                                  ;*****************************
   413                                  
   414                                  ; process SEGDEF record
   415                                  ; upon entry cx=record length,bp=buffer_end,al=record type
   416                                  ; es:si -> first byte of record past record length
   417                                  ; updates si
   418                                  ; destroys ax,bx,dx,di,es
   419                                  
   420                                  proc1_segdef    PROC
   421 000001A0 31C0                        xor ax,ax
   422 000001A2 A3[0E00]                    mov [frame_number],ax     ; init frame number to zero
   423 000001A5 268A04                      mov al,[es:si]          ; get acbp byte
   424 000001A8 A2[0200]                    mov [acbp_byte],al        ; save to memory
   425 000001AB 88C2                        mov dl,al               ; save acbp byte in dl
   426 000001AD 46                          inc si
   427 000001AE 49                          dec cx                  ; decrement record length to parse
   428 000001AF 39EE                        cmp si,bp               ; check boundary conditions
   429 000001B1 7203                        jb  ps_2                ; okay
   430 000001B3 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   431                                  ps_2:
   432 000001B6 C606[0400]00                mov byte [is_absseg],0         ; init absolute segment flag
   433 000001BB C606[0600]00                mov byte [is_common],0         ; init common segment flag
   434 000001C0 F6C2E0                      test    dl,0e0h         ; check if A bit field is zero
   435 000001C3 752A                        jne ps_get_seglen       ; nonzero, no frame number
   436                                  
   437                                  ; A bit field is zero (absolute segment), frame number and offset bytes exist
   438 000001C5 C606[0400]01                mov byte [is_absseg],1         ; set absolute segment flag
   439 000001CA 268A14                      mov dl,[es:si]          ; get low byte of frame number
   440 000001CD 46                          inc si
   441 000001CE 49                          dec cx                  ; decrement record length to parse
   442 000001CF 39EE                        cmp si,bp               ; check boundary conditions
   443 000001D1 7203                        jb  ps_3                ; okay
   444 000001D3 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   445                                  ps_3:
   446 000001D6 268A34                      mov dh,[es:si]          ; get high byte of frame number
   447 000001D9 46                          inc si
   448 000001DA 49                          dec cx                  ; decrement record length to parse
   449 000001DB 39EE                        cmp si,bp               ; check boundary conditions
   450 000001DD 7203                        jb  ps_4                ; okay
   451 000001DF E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   452                                  ps_4:
   453 000001E2 8916[0E00]                  mov [frame_number],dx     ; save frame number
   454 000001E6 46                          inc si                  ; scan past offset byte
   455 000001E7 49                          dec cx                  ; decrement record length to parse
   456 000001E8 39EE                        cmp si,bp               ; check boundary conditions
   457 000001EA 7203                        jb  ps_get_seglen       ; okay
   458 000001EC E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   459                                  
   460                                  ps_get_seglen:
   461 000001EF 268A14                      mov dl,[es:si]          ; get low byte of segment length
   462 000001F2 89F3                        mov bx,si               ; keep pointer to first index byte
   463 000001F4 46                          inc si
   464 000001F5 49                          dec cx                  ; decrement record length to parse
   465 000001F6 39EE                        cmp si,bp               ; check boundary conditions
   466 000001F8 7203                        jb  ps_6                ; okay
   467 000001FA E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   468                                  ps_6:
   469 000001FD 268A34                      mov dh,[es:si]          ; get high byte of segment length
   470 00000200 46                          inc si
   471 00000201 49                          dec cx                  ; decrement record length to parse
   472 00000202 39EE                        cmp si,bp               ; check boundary conditions
   473 00000204 7203                        jb  ps_7                ; okay
   474 00000206 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   475                                  ps_7:
   476 00000209 8916[1400]                  mov WORD PTR [segment_length],dx  ; save segment length low word
   477 0000020D 8916[1800]                  mov WORD PTR [no_align_length],dx ; save to no alignment adjustment segment length
   478 00000211 31C0                        xor ax,ax
   479 00000213 A3[1600]                    mov WORD PTR [segment_length+2],ax    ; zero segment length high word
   480 00000216 A3[1A00]                    mov WORD PTR [no_align_length+2],ax
   481                                  
   482 00000219 30E4                        xor ah,ah               ; zero high byte
   483 0000021B 268A04                      mov al,[es:si]          ; get low byte of segment name index
   484 0000021E 46                          inc si
   485 0000021F 49                          dec cx                  ; decrement record length to parse
   486 00000220 39EE                        cmp si,bp               ; check boundary conditions
   487 00000222 7217                        jb  ps_8                ; okay
   488 00000224 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   489 00000227 EB12                        jmp SHORT ps_8          ; bypass error message code
   490                                  
   491                                  ps_bad_segnam:
   492 00000229 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   493 0000022C B80F00                      mov ax,SEGNAM_IND_ERR   ; Invalid SEGDEF segment name index value
   494 0000022F E9(0000)                    jmp NEAR PTR error_bx_pos   ; transfer control to error handler
   495                                  
   496                                  ps_bad_classnam:
   497 00000232 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   498 00000235 B81000                      mov ax,CLASSNAM_IND_ERR ; Invalid SEGDEF class name index value
   499 00000238 E9(0000)                    jmp NEAR PTR error_bx_pos   ; transfer control to error handler
   500                                  
   501                                  ps_8:
   502 0000023B 08C0                        or  al,al               ; make sure value is nonzero
   503 0000023D 74EA                        je  ps_bad_segnam       ; zero value is invalid
   504 0000023F 3C80                        cmp al,80h              ; check if more than one byte index value
   505 00000241 7210                        jb  ps_10               ; no, continue
   506 00000243 247F                        and al,7fh              ; mask off high bit
   507 00000245 88C4                        mov ah,al               ; transfer to high word
   508 00000247 268A04                      mov al,[es:si]          ; get second byte, actual value
   509 0000024A 46                          inc si
   510 0000024B 49                          dec cx                  ; decrement record length to parse
   511 0000024C 39EE                        cmp si,bp               ; check boundary conditions
   512 0000024E 7203                        jb  ps_10               ; okay
   513 00000250 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   514                                  
   515                                  ps_10:
   516 00000253 A3[0A00]                    mov [segment_name_index],ax   ; save segment name index
   517                                  
   518 00000256 30E4                        xor ah,ah               ; zero high byte of index
   519 00000258 268A04                      mov al,[es:si]          ; get low byte of class name index
   520 0000025B 89F3                        mov bx,si               ; keep pointer to first index byte
   521 0000025D 46                          inc si
   522 0000025E 49                          dec cx                  ; decrement record length to parse
   523 0000025F 39EE                        cmp si,bp               ; check boundary conditions
   524 00000261 7203                        jb  ps_12               ; okay
   525 00000263 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   526                                  
   527                                  ps_12:
   528 00000266 08C0                        or  al,al               ; make sure value is nonzero
   529 00000268 74C8                        je  ps_bad_classnam     ; zero value is invalid
   530 0000026A 3C80                        cmp al,80h              ; check if more than one byte index value
   531 0000026C 7210                        jb  ps_13               ; no, continue
   532 0000026E 247F                        and al,7fh              ; mask off high bit
   533 00000270 88C4                        mov ah,al               ; transfer to high word
   534 00000272 268A04                      mov al,[es:si]          ; get second byte, actual value
   535 00000275 46                          inc si
   536 00000276 49                          dec cx                  ; decrement record length to parse
   537 00000277 39EE                        cmp si,bp               ; check boundary conditions
   538 00000279 7203                        jb  ps_13               ; okay
   539 0000027B E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   540                                  
   541                                  ps_13:
   542 0000027E A3[0C00]                    mov [class_name_index],ax ; save class name index
   543                                  
   544                                  ; gobble the overlay name index value
   545 00000281 268A04                      mov al,[es:si]          ; get low byte of overlay name index
   546 00000284 46                          inc si
   547 00000285 49                          dec cx                  ; decrement record length to parse
   548 00000286 39EE                        cmp si,bp               ; check boundary conditions
   549 00000288 7203                        jb  ps_13a              ; okay
   550 0000028A E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   551                                  ps_13a:
   552 0000028D 3C80                        cmp al,80h              ; check if more than one byte index value
   553 0000028F 7209                        jb  ps_get_segdef       ; no, continue
   554 00000291 46                          inc si                  ; scan past second byte
   555 00000292 49                          dec cx                  ; decrement record length to parse
   556 00000293 39EE                        cmp si,bp               ; check boundary conditions
   557 00000295 7203                        jb  ps_get_segdef       ; okay
   558 00000297 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   559                                  
   560                                  ; find or create segdef entry, return segment in es
   561                                  ps_get_segdef:
   562 0000029A 06                          push    es              ; save critical register
   563 0000029B E88C03                      call    get_segdef_entry
   564                                  
   565 0000029E 8B3E[0000]                  mov di,[current_segdef]   ; get number current segdef record
   566 000002A2 D1E7                        shl di,1                ; convert di to word offset
   567 000002A4 BB[0000]                    mov bx,offset seg_defent_indptr wrt DGROUP  ; set bx to base of segment index pointer array
   568 000002A7 8C01                        mov [bx+di],es          ; set array element pointer to segdef entry segment
   569                                  
   570 000002A9 26A01A00                    mov al,[es:26]          ; get acbp byte
   571 000002AD 08C0                        or  al,al               ; zero if absolute or first entry
   572 000002AF 7406                        je  ps_chk_common       ; bypass common check for this entry
   573 000002B1 241C                        and al,1ch              ; get combine field
   574 000002B3 3C18                        cmp al,18h              ; see if common combine type
   575 000002B5 750E                        jne ps_chk_abs          ; no, see if absolute segment
   576                                  
   577                                  ps_chk_common:
   578 000002B7 A0[0200]                    mov al,[acbp_byte]        ; get current acbp_byte
   579 000002BA 241C                        and al,1ch              ; get combine field
   580 000002BC 3C18                        cmp al,18h              ; see if common combine type
   581 000002BE 7505                        jne ps_chk_abs          ; no, see if absolute segment
   582                                  
   583                                  ; this segment and any previous matching segdef entry are common combine types
   584 000002C0 C606[0600]01                mov byte [is_common],1         ; flag that a common segment
   585                                  
   586                                  ps_chk_abs:
   587 000002C5 803E[0400]00                cmp byte [is_absseg],0         ; see if absolute segment
   588 000002CA 7427                        je  ps_13b              ; no
   589                                  
   590                                  ; absolute segment, update frame number, acbp byte, point segment and
   591                                  ; class names at zero_table, and return
   592 000002CC A1[0E00]                    mov ax,[frame_number]
   593 000002CF 26A30000                    mov [es:0],ax
   594 000002D3 A0[0200]                    mov al,[acbp_byte]        ; get current acbp byte
   595 000002D6 26A21A00                    mov [es:26],al
   596 000002DA B8[0000]                    mov ax,OFFSET zero_table wrt DGROUP ; make segment and class names point to known null value
   597 000002DD 26A30800                    mov [es:8],ax
   598 000002E1 26A30C00                    mov [es:12],ax
   599 000002E5 B8[ssss]                    mov ax,DGROUP
   600 000002E8 26A30A00                    mov [es:10],ax
   601 000002EC 26A30E00                    mov [es:14],ax
   602 000002F0 E91403                      jmp NEAR PTR ps_out
   603                                  
   604                                  ; get adjustment to current segment length before saving segment partition entry
   605                                  ; stack combine type forces paragraph alignment, no segment adjustment
   606                                  ps_13b:
   607 000002F3 FF06[0000]                  inc word [segdef_count]        ; bump count of segdefs encountered (don't count absolutes)
   608 000002F7 8A16[0200]                  mov dl,[acbp_byte]
   609 000002FB 80E2E0                      and dl,0e0h             ; dl holds align field value
   610 000002FE 30F6                        xor dh,dh               ; dh holds segment adjustment value
   611 00000300 26A01A00                    mov al,[es:26]          ; get previous segdef entry acbp byte
   612 00000304 241C                        and al,1ch              ; get combine field value
   613 00000306 3C14                        cmp al,14h              ; check if stack combine type
   614 00000308 7425                        je  ps_make_spart       ; yes, no segment adjustment
   615                                  
   616 0000030A A0[0200]                    mov al,[acbp_byte]        ; get current acbp byte
   617 0000030D 241C                        and al,1ch              ; get combine field value
   618 0000030F 3C14                        cmp al,14h              ; check if stack combine type
   619 00000311 741C                        je  ps_make_spart       ; yes, no segment adjustment
   620                                  
   621 00000313 26A10600                    mov ax,[es:6]           ; get segment length in ax
   622 00000317 88D3                        mov bl, dl			; = acbp byte
   623 00000319 E8F902                      call align_ax_from_bl
   624                                  
   625                                  ps_seg_adjust:
   626 0000031C 803E[0600]00                cmp byte [is_common],0         ; see if common segment
   627 00000321 750C                        jne ps_make_spart       ; yes, bypass segment length adjustment
   628                                  
   629                                  ;    xor al,al
   630                                  ;    mov dh,al               ; init segment adjustment values 
   631                                  ;    cmp WORD PTR segment_length,0   ; check if a zero length segment
   632                                  ;    je  ps_15a              ; zero length, don't adjust (0 adjustment)
   633                                  
   634 00000323 89C2                        mov dx,ax               ; save segment adjustment value in dx
   635                                  
   636                                  ps_15a:
   637 00000325 0106[1400]                  add WORD PTR [segment_length],ax  ; update segment length low word
   638 00000329 8316[1600]00                adc WORD [segment_length+2],0 ; update segment length high word
   639                                  
   640                                  ; make a new segment partition entry for this segdef record, return segment in es
   641 0000032E A9                      	db 0A9h			; test ax, imm16 (skip xor)
   642                                  ps_make_spart:
   643 0000032F 31D2                    	xor dx, dx
   644                                  
   645                                  ; Check if DOSSEG switch set.  If it is, check if this is first
   646                                  ; declaration of segment _TEXT.  If it is, make a segment partition
   647                                  ; entry of 16 bytes first and adjust the segment length accordingly.
   648                                  ; ONLY do this if not use DDL's
   649                                  
   650 00000331 31C0                        xor ax,ax
   651 00000333 3806[0000]                  cmp [is_dosseg],al        ; check DOSSEG switch
   652 00000337 7503                        jne  pms_1              ; set
   653                                  
   654                                  to_pms_3:
   655 00000339 E9A700                      jmp  NEAR PTR pms_3     ; not set
   656                                  
   657                                  pms_1:
   658 0000033C 3806[0000]                  cmp [any_ddl],al          ; see if using DDLs
   659 00000340 75F7                        jne to_pms_3            ; yes, ignore DOSSEG segment stuff
   660 00000342 3806[0000]                  cmp [_textflag],al        ; see if segment _TEXT already adjusted
   661 00000346 757B                        jne pms_2               ; yes
   662 00000348 BB[1800]                    mov bx,OFFSET _texttext wrt DGROUP  ; text to check segment name against
   663 0000034B BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; text of segment name
   664                                  
   665                                  pm_textloop:
   666 0000034E 8A07                        mov al,[bx]
   667 00000350 0A05                        or  al,[di]             ; if both zero then successful match
   668 00000352 7408                        je  pm_insert_bytes     ; matched, insert bytes in front of segment
   669 00000354 3A05                        cmp al,[di]             ; see if this char matches
   670 00000356 756B                        jne pms_2               ; no, segment is not _TEXT
   671 00000358 43                          inc bx
   672 00000359 47                          inc di                  ; bump to next char to compare
   673 0000035A EBF2                        jmp SHORT pm_textloop   ; loop back to test next char
   674                                  
   675                                  pm_insert_bytes:
   676 0000035C C606[0000]01                mov byte [_textflag],1         ; set _textflag so insertion only occurs once
   677 00000361 06                          push    es              ; save es -> segdef entry
   678 00000362 E83504                      call    make_segpart_entry  ; create a partition entry for 16 zero bytes
   679 00000365 26C7060A00FF00              mov WORD PTR [es:10],255    ; make record index invalid amount (no pass 2 segdef lookup)
   680 0000036C A0[0200]                    mov al,[acbp_byte]
   681 0000036F 26A20B00                    mov [es:11],al          ; save segment partition entry acbp byte
   682 00000373 31C0                        xor ax,ax
   683 00000375 26A30000                    mov [es:0],ax           ; zero partition offset
   684 00000379 26C7060C001000              mov WORD PTR [es:12],16 ; partition length is 16 bytes
   685 00000380 8CC0                        mov ax,es               ; save segment pointer to partition entry in ax
   686 00000382 07                          pop es                  ; restore es -> segdef entry
   687 00000383 26833E160000                cmp WORD PTR [es:22],0  ; see if previous partition entry
   688 00000389 7427                        je  pm_insert2          ; no
   689                                  
   690                                  ; previous partition entry exists, insert the 16 zero byte partition entry in
   691                                  ; as the first partition entry, make it point to the original first partition
   692                                  ; entry and adjust the original first partition entry's offset by 16 bytes
   693 0000038B 268306060010                add WORD PTR [es:6],16  ; add 16 bytes to segment length
   694 00000391 268B1E1600                  mov bx,[es:22]          ; bx-> first segment partition entry
   695 00000396 06                          push    es              ; save es -> segdef entry
   696                                  
   697 00000397 8EC0                        mov es,ax               ; es -> 16 zero byte partition entry
   698 00000399 26891E0200                  mov [es:2],bx           ; make 16 zero byte partition entry point to (previously) first entry
   699                                  
   700                                  pm_partloop:
   701 0000039E 8EC3                        mov es,bx               ; es -> segment partition entry
   702 000003A0 268306000010                add WORD PTR [es:0],16  ; adjust offset by 16 bytes
   703 000003A6 268B1E0200                  mov bx,[es:2]           ; get next segment partition entry, if any
   704 000003AB 09DB                        or  bx,bx               ; check if non-null (entry exists)
   705 000003AD 75EF                        jne pm_partloop         ; yes
   706                                  
   707 000003AF 07                          pop es                  ; restore es -> segdef entry
   708 000003B0 EB0B                        jmp SHORT pm_insert3
   709                                  
   710                                  pm_insert2:
   711 000003B2 26C70606001000              mov WORD PTR [es:6],16  ; insert 16 bytes into segment (increase segment length)
   712 000003B9 26A31800                    mov WORD PTR [es:24],ax ; update last segment partition entry pointer
   713                                  
   714                                  pm_insert3:
   715 000003BD 26A31600                    mov WORD PTR [es:22],ax ; update first segment partition entry pointer
   716 000003C1 EB20                        jmp SHORT pms_3         ; bypass DGROUP code
   717                                  
   718                                  ; check if segment is DGROUP, set flag if so
   719                                  pms_2:
   720 000003C3 803E[0000]00                cmp byte [is_dgroup],0         ; see if flag already set
   721 000003C8 7519                        jne pms_3               ; yes, bypass check for setting flag
   722 000003CA BB[1E00]                    mov bx,OFFSET dgrouptext wrt DGROUP  ; text to check segment name against
   723 000003CD BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; text of segment name
   724                                  
   725                                  pm_dgroup_loop:
   726 000003D0 8A07                        mov al,[bx]
   727 000003D2 0A05                        or  al,[di]             ; if both zero then successful match
   728 000003D4 7408                        je  pm_isdgroup         ; matched, set dgroup flag
   729 000003D6 3A05                        cmp al,[di]             ; see if this char matches
   730 000003D8 7509                        jne pms_3               ; no, segment is not DGROUP
   731 000003DA 43                          inc bx
   732 000003DB 47                          inc di                  ; bump to next char to compare
   733 000003DC EBF2                        jmp SHORT pm_dgroup_loop    ; loop back to test next char
   734                                  
   735                                  pm_isdgroup:
   736 000003DE C606[0000]01                mov byte [is_dgroup],1         ; set dgroup flag
   737                                  
   738                                  pms_3:
   739 000003E3 06                          push    es              ; save es -> segdef entry
   740 000003E4 E8B303                      call    make_segpart_entry
   741 000003E7 A0[0200]                    mov al,[acbp_byte]
   742 000003EA 26A20B00                    mov [es:11],al          ; save segment partition entry acbp byte
   743 000003EE A1[1800]                    mov ax,WORD PTR [no_align_length]
   744 000003F1 26A30C00                    mov [es:12],ax          ; save segment partition length
   745                                  
   746                                  ; if overlaid segment partition, check length and bypass partition adjustment
   747 000003F5 803E[0800]00                cmp byte [ovl_seg_flag],0      ; see if this partition is an overlay
   748 000003FA 750E                        jne pms_zero            ; yes, zero segment partition offset
   749                                  
   750                                  pms_3a:
   751 000003FC 89D0                        mov ax,dx               ; ax holds segment adjustment value
   752 000003FE 2601060000                  add [es:0],ax           ; adjust segment offset for alignment
   753                                  
   754                                  ; check if common segment, if common then zero segment partition offset
   755 00000403 803E[0600]00                cmp byte [is_common],0         ; see if common segment
   756 00000408 7407                        je  pms_4               ; yes
   757                                  
   758                                  pms_zero:
   759 0000040A 26C70600000000              mov WORD PTR [es:0],0   ; zero segment partition offset
   760                                  
   761                                  pms_4:
   762 00000411 8CC2                        mov dx,es               ; save segment pointer to partition entry in dx
   763 00000413 07                          pop es                  ; restore es -> segdef entry
   764 00000414 26A11800                    mov ax,[es:24]          ; get segment of previously last partition entry, if any, in ax
   765 00000418 2689161800                  mov [es:24],dx          ; update segment pointer to last partition entry to current partition entry
   766 0000041D 09C0                        or  ax,ax               ; see if previous segment partition entries
   767 0000041F 7507                        jne ps_16               ; at least one previous partition entry
   768 00000421 2689161600                  mov [es:22],dx          ; save pointer to current partition entry as first entry
   769 00000426 EB0B                        jmp SHORT ps_17         ; bypass partition entry update code
   770                                  
   771                                  ps_16:
   772 00000428 8CC3                        mov bx,es               ; save segment pointer to segdef entry in bx
   773 0000042A 8EC0                        mov es,ax               ; set es to partition entry segment for update
   774 0000042C 2689160200                  mov [es:2],dx           ; update next pointer of partition entry to current partition entry segment
   775 00000431 8EC3                        mov es,bx               ; restore es -> segdef entry
   776                                  
   777                                  ; if segment is overlay class make at least paragraph alignment
   778                                  ps_17:
   779 00000433 51                      	push cx
   780 00000434 B105                    	mov cl, 5
   781 00000436 BB[1000]                	mov bx, alignment_order		; ds:bx -> alignment order bytes table
   782                                  
   783 00000439 803E[0000]00                cmp byte [any_ddl],0           ; see if using/creating DDL's
   784 0000043E 751E                        jne ps_high_align       ; yes, don't force paragraph alignment (do it at runtime)
   785                                  
   786 00000440 26A01C00                    mov al,[es:28]          ; get overlay flag
   787 00000444 08C0                        or  al,al               ; see if overlay class
   788 00000446 7416                        je  ps_high_align       ; no
   789 00000448 A0[0200]                    mov al,[acbp_byte]        ; get this segment's acbp byte
   790 0000044B 88C4                        mov ah,al               ; save in ah
   791 0000044D D2E8                        shr al, cl			; al = align field of acpb_byte
   792 0000044F D7                          xlatb			; = order of align field
   793 00000450 3C05                        cmp al, alignment_order.para; see if paragraph alignment or better
   794 00000452 730A                        jae ps_high_align       ; yes
   795 00000454 80E41F                      and ah,01fh             ; mask out previous align field
   796 00000457 80CC60                      or  ah,060h             ; force paragraph alignment
   797 0000045A 8826[0200]                  mov [acbp_byte],ah        ; save back to memory variable
   798                                  
   799                                  ; if preexisting ACBP byte, keep highest of two Align fields
   800                                  ps_high_align:
   801 0000045E 26A01A00                    mov al,[es:26]          ; get segdef entry acbp byte
   802 00000462 08C0                        or  al,al               ; check if nonzero, previous entry existed
   803 00000464 7507                        jne ps_17a              ; yes it did
   804 00000466 A0[0200]                    mov al,[acbp_byte]        ; get current acbp byte
   805 00000469 26A21A00                    mov [es:26],al          ; save as entry acbp byte
   806                                  
   807                                  ps_17a:
   808 0000046D 8A26[0200]              	mov ah, [acbp_byte]
   809 00000471 89C2                    	mov dx, ax			; dh = acbp_byte, dl = segdef entry's
   810 00000473 D2EC                    	shr ah, cl			; ah = A field of acbp_byte
   811 00000475 D2E8                    	shr al, cl			; al = A field of segdef entry's
   812 00000477 59                      	pop cx
   813 00000478 D7                      	xlatb				; al = order of segdef entry's
   814 00000479 86C4                    	xchg al, ah			; ah = order of segdef entry's
   815 0000047B D7                      	xlatb				; al = order of acbp_byte
   816 0000047C 38C4                    	cmp ah, al			; reverse order !
   817                                      ; cmp al,[acbp_byte]        ; compare to current acbp byte
   818 0000047E 7311                        jae ps_18               ; entry acbp byte is highest
   819                                  
   820 00000480 88D4                        mov ah, dl               ; keep nonaligned fields in ah
   821                                  	; ah = segdef entry's acbp
   822 00000482 80E41F                      and ah, 1Fh              ; mask align field off of entry acbp byte
   823 00000485 88F0                        mov al, dh              ; get current acbp byte
   824 00000487 24E0                        and al,0e0h             ; mask off all but align field
   825 00000489 08E0                        or  al,ah               ; merge in old nonalign fields
   826 0000048B 26A21A00                    mov [es:26],al          ; save new acbp byte value
   827 0000048F 88C2                        mov dl,al
   828                                  	; dl = new acbp value
   829                                  
   830                                  ; update the combine field, giving proper precedence
   831                                  ps_18:
   832 00000491 88D0                        mov al, dl
   833 00000493 80E2E3                      and dl,0e3h             ; dl holds entry's noncombine fields
   834 00000496 88C6                        mov dh,al
   835 00000498 80E61C                      and dh,1ch              ; dh holds entry's combine field
   836 0000049B A0[0200]                    mov al,[acbp_byte]
   837 0000049E 241C                        and al,1ch              ; get current combine field
   838 000004A0 743A                        je  ps_19               ; no previous acbp byte, each private (combine==0) has its own entry
   839 000004A2 3C0C                        cmp al,0ch              ; check for unused combine type
   840 000004A4 7404                        je  ps_bad_combine      ; bad combine value
   841 000004A6 3C04                        cmp al,4                ; check for unused combine type
   842 000004A8 7509                        jne ps_20               ; okay
   843                                  
   844                                  ps_bad_combine:
   845 000004AA BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   846 000004AD B81100                      mov ax,COMBINE_VAL_ERR  ; Invalid SEGDEF combine field value
   847 000004B0 E9(0000)                    jmp NEAR PTR error_read_buff_pos    ; transfer control to error handler
   848                                  
   849                                  ps_20:
   850 000004B3 3C14                        cmp al,14h              ; check if stack combine type
   851 000004B5 7505                        jne ps_21               ; no
   852 000004B7 80CA14                      or  dl,14h              ; merge stack combine type in noncombine fields
   853 000004BA EB1B                        jmp SHORT ps_23         ; bypass other update code
   854                                  
   855                                  ps_21:
   856 000004BC 3C18                        cmp al,18h              ; check if common combine type
   857 000004BE 750F                        jne ps_22               ; no
   858 000004C0 80FE14                      cmp dh,14h              ; stack combine has precedence
   859 000004C3 7417                        je  ps_19               ; don't update entry
   860 000004C5 80FE08                      cmp dh,8                ; public combine type has precedence
   861 000004C8 7412                        je  ps_19               ; don't update entry
   862 000004CA 80CA18                      or  dl,18h              ; merge common combine type in noncombine fields
   863 000004CD EB08                        jmp SHORT ps_23         ; bypass other update code
   864                                  
   865                                  ; public combine type, values 8,10,1ch
   866                                  ps_22:
   867 000004CF 80FE14                      cmp dh,14h              ; stack combine has precedence
   868 000004D2 7408                        je  ps_19               ; don't update entry
   869 000004D4 80CA08                      or  dl,8                ; merge public combine type in noncomine fields
   870                                  
   871                                  ps_23:
   872 000004D7 2688161A00                  mov [es:26],dl          ; save updated entry acbp byte
   873                                  
   874                                  ps_19:
   875 000004DC 26A01A00                    mov al,[es:26]          ; get entry acbp byte
   876 000004E0 88C4                        mov ah,al               ; save in ah
   877 000004E2 241C                        and al,1ch              ; get combine type
   878 000004E4 3C14                        cmp al,14h              ; check if stack combine type
   879 000004E6 750B                        jne ps_24               ; no
   880                                  
   881                                  ; stack combine type forces paragraph alignment
   882 000004E8 80E41F                      and ah,1fh              ; clear previous align type bit
   883 000004EB 80CC60                      or  ah,60h              ; set paragraph align type
   884 000004EE 2688261A00                  mov [es:26],ah          ; update entry's acbp byte
   885                                  
   886                                  ; get segment name from previous lnames record
   887                                  ps_24:
   888 000004F3 A1[0A00]                    mov ax,[segment_name_index]   ; get segment name index
   889 000004F6 48                          dec ax                  ; make count relative zero
   890 000004F7 D1E0                        shl ax,1
   891 000004F9 D1E0                        shl ax,1                ; make segment name index a doubleword offset into index pointer array
   892 000004FB BF[0000]                    mov di,offset lnames_ent_indptr wrt DGROUP  ; set di to base of lnames index pointer array
   893 000004FE 01C7                        add di,ax               ; di -> proper array element
   894 00000500 8B05                        mov ax,[di]             ; get offset of segment name from lnames entry
   895 00000502 26A30800                    mov [es:8],ax           ; save offset of segment name
   896 00000506 8B4502                      mov ax,[di+2]           ; get segment of segment name from lnames entry
   897 00000509 26A30A00                    mov [es:10],ax          ; save segment of segment name
   898                                  
   899                                  ; get class name from previous lnames record
   900 0000050D A1[0C00]                    mov ax,[class_name_index] ; get class name index
   901 00000510 48                          dec ax                  ; make count relative zero
   902 00000511 D1E0                        shl ax,1
   903 00000513 D1E0                        shl ax,1                ; make class name index a doubleword offset into index pointer array
   904 00000515 BF[0000]                    mov di,offset lnames_ent_indptr wrt DGROUP  ; set di to base of lnames index pointer array
   905 00000518 01C7                        add di,ax               ; di -> proper array element
   906 0000051A 8B05                        mov ax,[di]             ; get offset of class name from lnames entry
   907 0000051C 26A30C00                    mov [es:12],ax          ; save offset of class name
   908 00000520 8B4502                      mov ax,[di+2]           ; get segment of class name from lnames entry
   909 00000523 26A30E00                    mov [es:14],ax          ; save segment of class name
   910                                  
   911                                  ; if is_sympac and !maybe_clipper and !symbol_overflow,
   912                                  ; see if name SYMBOLS, class SYMBOLS, if so then set maybe_clipper
   913                                  ; and keep segment index value (for LEDATA lookup)
   914                                  ; and pointer to segdef entry (in es)
   915 00000527 30C0                    	xor	al,al
   916 00000529 3806[0000]              	cmp	[is_sympac],al		; see if symbol table compression on
   917 0000052D 7451                    	je	ps_ddlchk			; no
   918 0000052F 3806[0000]              	cmp	[maybe_clipper],al	; see if possible clipper module already
   919 00000533 754B                    	jne	ps_ddlchk			; yes
   920 00000535 3806[0000]              	cmp	[symbol_overflow],al	; see if symbol table compaction routine has overflowed
   921 00000539 7545                    	jne	ps_ddlchk			; yes
   922                                  
   923 0000053B 51                      	push	cx				; save critical register
   924 0000053C 56                      	push	si
   925                                  
   926 0000053D 06                      	push	es
   927 0000053E 26C43E0800              	les	di,[es:8]			; es:di -> lnames segment name entry
   928 00000543 B90800                  	mov	cx,8				; eight chars in SYMBOLS including null terminator
   929 00000546 01CF                    	add	di,cx				; adjust past hi/low pointers
   930 00000548 BE[2500]                	mov	si,OFFSET symbolstext wrt DGROUP
   931 0000054B 89F2                    	mov	dx,si				; save text offset
   932 0000054D F3A6                    	repe	cmpsb			; compare entry name to SYMBOLS
   933 0000054F 07                      	pop	es
   934 00000550 752C                    	jne	ps_symout			; failed
   935                                  
   936 00000552 06                      	push	es
   937 00000553 26C43E0C00              	les	di,[es:12]			; es:di -> lnames class name entry
   938 00000558 B90800                  	mov	cx,8				; eight chars in SYMBOLS including null terminator
   939 0000055B 01CF                    	add	di,cx				; adjust past hi/low pointers
   940 0000055D 89D6                    	mov	si,dx				; get SYMBOLS offset in si
   941 0000055F F3A6                    	repe	cmpsb			; compare entry name to SYMBOLS
   942 00000561 07                      	pop	es
   943 00000562 751A                    	jne	ps_symout			; failed
   944                                  
   945                                  ; success, segment is name SYMBOLS class SYMBOLS
   946 00000564 C606[0000]01            	mov	byte [maybe_clipper],1		; set maybe clipper flag
   947 00000569 8C06[0000]              	mov	[clipper_segdef_ptr],es	; save -> this segdef for length modification
   948                                  
   949 0000056D A1[0000]                	mov	ax,[current_segdef]	; get current segdef index, relative zero
   950 00000570 A3[0000]                	mov	[clipper_segindex],ax	; save symbols segment index for LEDATA lookup
   951 00000573 833E[0000]00            	cmp	word [clipper_symseg_ptr],0	; see if this is the first SYMBOLS segment
   952 00000578 7504                    	jne	ps_symout			; no
   953 0000057A 8C06[0000]              	mov	[clipper_symseg_ptr],es	; save -> first SYMBOLS segment for later fixups
   954                                  
   955                                  ps_symout:
   956 0000057E 5E                      	pop	si					; restore critical register
   957 0000057F 59                      	pop	cx
   958                                  
   959                                  ; if segment partition is an overlay and not using DDLs, bypass segment length update
   960                                  ps_ddlchk:
   961 00000580 30C0                        xor al,al
   962 00000582 3806[0000]                  cmp [any_ddl],al          ; see if using/creating DDLs
   963 00000586 7506                        jne ps_24a              ; yes
   964 00000588 3806[0800]                  cmp [ovl_seg_flag],al     ; see if this partition is an overlay
   965 0000058C 7579                        jne ps_out              ; yes, bypass segment length update
   966                                  
   967                                  ps_24a:
   968 0000058E 268A161A00                  mov dl,[es:26]          ; get entry acbp byte
   969 00000593 88D0                        mov al,dl
   970 00000595 80E202                      and dl,2                ; get status of entry Big bit in dl
   971 00000598 8A36[0200]                  mov dh,[acbp_byte]        ; get current acbp byte
   972 0000059C 80E602                      and dh,2                ; get status of current Big bit in dh
   973                                  
   974 0000059F 241C                        and al,1ch              ; get combine field of entry
   975 000005A1 3C18                        cmp al,18h              ; check if common combine type
   976 000005A3 752A                        jne ps_25               ; nope
   977 000005A5 09D2                        or  dx,dx               ; is either Big bit set
   978 000005A7 755E                        jne ps_out              ; yes
   979 000005A9 833E[1600]00                cmp WORD [segment_length+2],0 ; check if segment is Big (64K long)
   980 000005AE 7557                        jne ps_out              ; yes
   981                                  
   982                                  ; segment is less than 64K long, keep largest segment length in entry
   983 000005B0 A1[1400]                    mov ax,WORD PTR [segment_length]  ; get segment length
   984 000005B3 263B060600                  cmp ax,[es:6]           ; check if current length longer than segment entry's
   985 000005B8 764D                        jbe ps_out              ; no, all done
   986 000005BA 26A30600                    mov [es:6],ax           ; save current length as new entry segment length
   987 000005BE EB47                        jmp SHORT ps_out        ; all done
   988                                  
   989                                  ; segment is exactly 64K long
   990                                  ps_seg_equ_64k:
   991 000005C0 26800E1A0002                or  BYTE PTR [es:26],2      ; set Big bit in entry
   992 000005C6 26C70606000000              mov WORD PTR [es:6],0       ; zero segment length (>64K not allowed)
   993 000005CD EB38                        jmp SHORT ps_out            ; all done
   994                                  
   995                                  ; segdef entry is not common or private combine type
   996                                  ps_25:
   997 000005CF 26A10600                    mov ax,[es:6]
   998 000005D3 0106[1400]                  add WORD PTR [segment_length],ax  ; add current length for total the segment length
   999 000005D7 8316[1600]00                adc WORD [segment_length+2],0 ; update high word
  1000 000005DC A1[1600]                    mov ax,WORD PTR [segment_length+2]    ; get high word
  1001 000005DF 8B3E[1400]                  mov di,WORD PTR [segment_length]  ; get low word
  1002 000005E3 09C0                        or  ax,ax               ; is high word nonzero
  1003 000005E5 740D                        je  ps_27               ; yes, no overflow yet
  1004 000005E7 09FF                        or  di,di               ; is low word and high word nonzero
  1005 000005E9 7411                        je  ps_28               ; no, no overflow
  1006                                  
  1007                                  ps_seglen_err:
  1008 000005EB B81200                      mov ax,SEGMENT_LEN_ERR  ; segment size exceeds 64K
  1009                                  
  1010                                  ps_to_linkerr:
  1011 000005EE BA[0000]                    mov dx,OFFSET filename wrt DGROUP
  1012 000005F1 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  1013                                  
  1014                                  ; check for Big bit set with nonzero segment length
  1015                                  ps_27:
  1016 000005F4 09D2                        or  dx,dx               ; check if either Big bit set
  1017 000005F6 7404                        je  ps_28               ; no
  1018 000005F8 09FF                        or  di,di               ; check if low word of segment length nonzero
  1019 000005FA 75EF                        jne ps_seglen_err       ; yes, segment size overflow
  1020                                  
  1021                                  ps_28:
  1022 000005FC 09C0                        or  ax,ax               ; is high word of segment nonzero (bit 0 set)
  1023 000005FE 75C0                        jne ps_seg_equ_64k      ; yes, segment is exactly 64K long
  1024                                  
  1025                                  ; save segment length to segdef entry
  1026 00000600 A1[1400]                    mov ax,WORD PTR [segment_length]
  1027 00000603 26A30600                    mov [es:6],ax           ; save low word as total length
  1028                                  
  1029                                  ps_out:
  1030 00000607 FF06[0000]                  inc word [current_segdef]      ; bump count of current segdef record
  1031 0000060B 46                          inc si                  ; bump past checksum byte
  1032 0000060C 39EE                        cmp si,bp               ; check boundary conditions
  1033 0000060E 7203                        jb  ps_ret              ; okay
  1034 00000610 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
  1035                                  
  1036                                  ps_ret:
  1037 00000613 07                          pop es                  ; restore critical register
  1038 00000614 C3                          ret
  1039                                  proc1_segdef    ENDP
  1040                                  
  1041                                  
  1042                                  		; INP:	bl = acbp byte
  1043                                  		;	ax = value to align
  1044                                  		; CHG:	bx
  1045                                  		; OUT:	ax = how much to add for alignment
  1046                                  align_ax_from_bl:
  1047 00000615 B700                        mov bh, 0
  1048 00000617 51                          push cx
  1049 00000618 B105                        mov cl, 5
  1050 0000061A D3EB                        shr bx, cl			; bx = index
  1051 0000061C 59                          pop cx
  1052 0000061D 01DB                        add bx, bx			; bx = word index
  1053 0000061F 8B9F[0000]                  mov bx, [alignment_table + bx]	; bx = alignment mask
  1054 00000623 21D8                    	and ax, bx
  1055 00000625 F7D8                    	neg ax
  1056 00000627 21D8                    	and ax, bx
  1057 00000629 C3                      	retn
  1058                                  
  1059                                  
  1060                                  ;*****************************
  1061                                  ;* GET_SEGDEF_ENTRY          *
  1062                                  ;*****************************
  1063                                  
  1064                                  ; find or create segdef entry
  1065                                  ; return segment of entry in es
  1066                                  ; destroys ax,es
  1067                                  
  1068                                  get_segdef_entry    PROC
  1069 0000062A 53                          push    bx              ; save critical register
  1070 0000062B 52                          push    dx
  1071 0000062C 56                          push    si
  1072 0000062D 57                          push    di
  1073 0000062E A1[0A00]                    mov ax,[segment_name_index]   ; get index value for lnames array
  1074 00000631 48                          dec ax                  ; make count relative zero
  1075 00000632 D1E0                        shl ax,1                ; convert to word index
  1076 00000634 D1E0                        shl ax,1                ; convert to doubleword index
  1077 00000636 BE[0000]                    mov si,OFFSET lnames_ent_indptr wrt DGROUP  ; si -> base of lnames array
  1078 00000639 01C6                        add si,ax               ; si -> array element with segment:offset of name in lnames block
  1079                                  
  1080 0000063B 8CDA                        mov dx,ds               ; save warplink's data segment
  1081 0000063D 8EC2                        mov es,dx               ; es -> warplink's data
  1082 0000063F C534                        lds si,[si]             ; -> name
  1083 00000641 BF[0000]                    mov di,OFFSET name_field wrt DGROUP ; point to slot to place name
  1084 00000644 83C608                      add si,8                ; bump si past hi/low segment:offset pointers in lnames entry
  1085                                  
  1086                                  ; ds:si -> lnames name, es:di -> warplink data name field
  1087                                  gse_get_name:
  1088 00000647 A4                          movsb                   ; transfer a char
  1089 00000648 807CFF00                    cmp BYTE PTR [si-1],0   ; zero char flags end of transfer
  1090 0000064C 75F9                        jne gse_get_name        ; not zero, keep transferring
  1091                                  
  1092 0000064E 8CC0                        mov ax,es               ; get warplink's data segment
  1093 00000650 8ED8                        mov ds,ax               ; restores ds -> warplink data
  1094 00000652 BE[0000]                    mov si,OFFSET name_field wrt DGROUP ; si -> name to get hash code of
  1095 00000655 E8(0000)                    call    get_hash        ; get hash code of name
  1096 00000658 BE[0000]                    mov si,OFFSET segdef_hash wrt DGROUP   ; si -> base of hash pointers to segdef entries
  1097 0000065B D1E0                        shl ax,1                ; convert ax to word offset
  1098 0000065D 01C6                        add si,ax               ; si points to proper name hash code entry
  1099 0000065F 833C00                      cmp WORD PTR [si],0     ; is hash code used (nonzero value)
  1100 00000662 7542                        jne gse_2               ; yes
  1101                                  
  1102                                  gse_make_ent:
  1103 00000664 A1[0000]                    mov ax,[alloc_segdefblk_ptr]
  1104 00000667 09C0                        or  ax,ax               ; check if any segdef blocks were previously allocated
  1105 00000669 751A                        jne gse_3               ; yes
  1106                                  
  1107                                  ; make initial segdef block allocation
  1108 0000066B BB4100                      mov bx,SEG_DEFBLK_SIZE  ; number of paragraphs to allocate
  1109 0000066E E8(0000)                    call    alloc_memory    ; get memory for block allocation
  1110 00000671 A3[0000]                    mov [alloc_segdefblk_ptr],ax  ; update last allocated block pointer
  1111 00000674 A3[0000]                    mov [first_segdefblk_ptr],ax  ; update first allocate block pointer
  1112 00000677 8EC0                        mov es,ax               ; es == current (new) block segment
  1113 00000679 31C0                        xor ax,ax
  1114 0000067B 26A30000                    mov WORD PTR [es:0],ax  ; zero count of entries in block
  1115 0000067F 26A30200                    mov WORD PTR [es:2],ax  ; zero pointer to next entry
  1116 00000683 EB0D                        jmp SHORT gse_4         ; bypass block full check code
  1117                                  
  1118                                  ; at least one prior segdef entry made, check if block is full
  1119                                  gse_3:
  1120 00000685 8EC0                        mov es,ax               ; es -> current block
  1121 00000687 26833E000020                cmp WORD PTR [es:0],SEG_DEFENT_COUNT    ; see if any free entries in block
  1122 0000068D 7203                        jb  gse_4                ; yes
  1123 0000068F E8E000                      call    make_segdef_blk ; no free entries in block, make a new block
  1124                                  
  1125                                  gse_4:
  1126 00000692 E8B000                      call    init_segdef_entry   ; perform segdef entry initialization code
  1127                                  
  1128 00000695 803E[0400]00                cmp byte [is_absseg],0         ; if absolute segment don't check overlay class
  1129 0000069A 7503                        jne gse_4a              ; absolute, bypass check
  1130 0000069C E8(0000)                    call    chk_seg_ovl_class   ; check if segment is overlay class, if overlays
  1131                                  
  1132                                  gse_4a:
  1133 0000069F 893C                        mov [si],di             ; update hash code segment pointer
  1134 000006A1 8EC7                        mov es,di               ; es -> new segdef entry for return
  1135 000006A3 E99600                      jmp NEAR PTR gse_5      ; bypass dup/collision code
  1136                                  
  1137                                  ; hash code used, check whether duplicate name or hash collision
  1138                                  gse_2:
  1139 000006A6 8B1C                        mov bx,[si]             ; get segment pointer to segdef entry in bx (will be parent entry to new entry)
  1140 000006A8 A0[0200]                    mov al,[acbp_byte]        ; get current acbp byte in dl
  1141 000006AB 241C                        and al,1ch              ; combine field only
  1142 000006AD 7510                        jne gse_2a              ; if nonzero then segments combineable
  1143                                  
  1144                                  ; private segment, not combineable
  1145 000006AF 8B1C                        mov bx,[si]             ; get segment pointer to segdef entry in bx (will be parent entry to new entry)
  1146                                  
  1147                                  gse_privloop:
  1148 000006B1 8EC3                        mov es,bx               ; es -> segdef entry
  1149 000006B3 26A11400                    mov ax,[es:20]          ; get pointer to next entry
  1150 000006B7 09C0                        or  ax,ax               ; if null, then at end of parent/child chain, last child becomes new parent
  1151 000006B9 7428                        je  SHORT gse_new_name  ; make new segdef entry for private segment
  1152 000006BB 89C3                        mov bx,ax               ; update parent entry
  1153 000006BD EBF2                        jmp SHORT gse_privloop  ; loop until final link in parent/child chain found
  1154                                  
  1155                                  gse_2a:
  1156 000006BF 8B04                        mov ax,[si]             ; get segment pointer to segdef entry
  1157                                  
  1158                                  gse_testloop:
  1159 000006C1 8EC0                        mov es,ax               ; es -> segment of segdef entry testing name against
  1160 000006C3 93                          xchg bx,ax               ; save entry segment in bx
  1161 000006C4 26C43E0800                  les di,[es:8]           ; -> segment name in lnames block
  1162 000006C9 83C708                      add di,8                ; adjust for 2 doubleword pointers in front of name
  1163 000006CC BE[0000]                    mov si,OFFSET name_field wrt DGROUP ; si -> name to get hash code of
  1164                                  
  1165                                  ; ds:si -> name, es:di -> name to test against
  1166                                  gse_byteloop:
  1167 000006CF 8A04                        mov al,[si]
  1168 000006D1 260A05                      or  al,[es:di]          ; see if both values are zero (matched to null terminator)
  1169 000006D4 742E                        je  gse_match           ; strings matched
  1170 000006D6 A6                          cmpsb                   ; compare a nonzero byte in the two names
  1171 000006D7 74F6                        je  gse_byteloop        ; bytes match, loop for next byte test
  1172 000006D9 8EC3                        mov es,bx               ; get segdef entry segment value
  1173                                  
  1174                                  gse_next_ptr:
  1175 000006DB 26A11400                    mov ax,[es:20]          ; get next entry
  1176 000006DF 09C0                        or  ax,ax               ; check if a null pointer (ax=0)
  1177 000006E1 75DE                        jne gse_testloop        ; no, keep checking entries
  1178                                  
  1179                                  ; new name, no matches for any segdef entry
  1180                                  gse_new_name:
  1181 000006E3 A1[0000]                    mov ax,[alloc_segdefblk_ptr]   ; get last allocated block
  1182 000006E6 8EC0                        mov es,ax               ; es -> block
  1183 000006E8 26833E000020                cmp WORD PTR [es:0],SEG_DEFENT_COUNT    ; see if any free entries in block
  1184 000006EE 7203                        jb  gse_9               ; yes
  1185 000006F0 E87F00                      call    make_segdef_blk    ; no free entries in block, make a new block
  1186                                  
  1187                                  gse_9:
  1188 000006F3 E84F00                      call    init_segdef_entry   ; perform segdef entry initialization code
  1189 000006F6 E8(0000)                    call    chk_seg_ovl_class   ; check if segment is overlay class, if overlays
  1190                                  
  1191 000006F9 8EC3                        mov es,bx               ; get entry that points to this new entry (parent entry)
  1192 000006FB 26893E1400                  mov [es:20],di          ; update next entry pointer
  1193 00000700 8EC7                        mov es,di               ; return es -> new segdef entry
  1194 00000702 EB38                        jmp SHORT gse_5         ; perform new entry code
  1195                                  
  1196                                  ; segment names match, check class names
  1197                                  gse_match:
  1198 00000704 8EC3                        mov es,bx               ; get segdef entry segment value
  1199 00000706 06                          push    es              ; save entry segment in es, used
  1200 00000707 1E                          push    ds              ; save data segment value, used
  1201 00000708 A1[0C00]                    mov ax,[class_name_index] ; get index value for lnames array
  1202 0000070B 48                          dec ax                  ; make count relative zero
  1203 0000070C D1E0                        shl ax,1                ; convert to word index
  1204 0000070E D1E0                        shl ax,1                ; convert to doubleword index
  1205 00000710 BE[0000]                    mov si,OFFSET lnames_ent_indptr wrt DGROUP  ; si -> base of lnames array
  1206 00000713 01C6                        add si,ax               ; si -> array element with segment:offset of name in lnames block
  1207 00000715 C534                        lds si,[si]             ; -> class name in lnames block from index
  1208 00000717 83C608                      add si,8                ; adjust past doubleword pointers
  1209                                  
  1210 0000071A 26C43E0C00                  les di,[es:12]          ; es:di -> test entry's class name in lnames block
  1211 0000071F 83C708                      add di,8                ; adjust past doubleword pointers
  1212                                  
  1213                                  gse_matchloop:
  1214 00000722 A6                          cmpsb                   ; compare a char
  1215 00000723 7513                        jne gse_nomatch         ; class names didn't match
  1216 00000725 8A04                        mov al,[si]
  1217 00000727 260A05                      or  al,[es:di]          ; see if both values are zero (matched to null terminator)
  1218 0000072A 75F6                        jne gse_matchloop       ; not done yet
  1219                                  
  1220 0000072C 1F                          pop ds                  ; restore data segment
  1221 0000072D 07                          pop es                  ; restore pointer to segdef entry
  1222 0000072E 26A01A00                    mov al,[es:26]          ; get test entry acbp byte
  1223 00000732 241C                        and al,1ch              ; combine field only
  1224 00000734 750A                        jne gse_ret             ; names match and ACBP combineable types
  1225 00000736 EBA3                        jmp gse_next_ptr   ; private combine, try next entry
  1226                                  
  1227                                  ; class names didn't match, try next entry
  1228                                  gse_nomatch:
  1229 00000738 1F                          pop ds                  ; restore segment registers
  1230 00000739 07                          pop es                  ; restore pointer to segdef entry
  1231 0000073A EB9F                        jmp gse_next_ptr
  1232                                  
  1233                                  gse_5:
  1234 0000073C FF06[0000]                  inc WORD [seg_count]  ; update count of total discrete segments
  1235                                  
  1236                                  gse_ret:
  1237 00000740 5F                          pop di                  ; restore critical registersr
  1238 00000741 5E                          pop si
  1239 00000742 5A                          pop dx
  1240 00000743 5B                          pop bx
  1241 00000744 C3                          ret
  1242                                  get_segdef_entry    ENDP
  1243                                  
  1244                                  ;*****************************
  1245                                  ;* INIT_SEGDEF_ENTRY         *
  1246                                  ;*****************************
  1247                                  
  1248                                  ; initialize segdef entry
  1249                                  ; upon entry es -> segdef block
  1250                                  ; returns new segdef entry segment in di
  1251                                  ; destroys ax,dx,di
  1252                                  
  1253                                  init_segdef_entry   PROC
  1254 00000745 268B3E0000                  mov di,[es:0]           ; get old entry count
  1255 0000074A 26FF060000                  inc WORD PTR [es:0]     ; bump count of entries
  1256 0000074F D1E7                        shl di,1                ; each entry takes up two paragraphs
  1257 00000751 8CC0                        mov ax,es               ; get block segment address
  1258 00000753 01C7                        add di,ax               ; get first free entry segment value
  1259 00000755 47                          inc di                  ; adjust for block system info size of 1 paragraph
  1260                                  
  1261 00000756 8CC2                        mov dx,es               ; save critical register
  1262 00000758 8EC7                        mov es,di               ; ds -> new segdef entry
  1263 0000075A 57                          push    di
  1264 0000075B 31C0                        xor ax,ax
  1265 0000075D 89C7                        mov di,ax
  1266 0000075F AB                          stosw                   ; zero init values in segdef entry
  1267 00000760 AB                          stosw
  1268 00000761 AB                          stosw
  1269 00000762 AB                          stosw
  1270 00000763 BF1000                      mov di,16
  1271 00000766 AB                          stosw
  1272 00000767 AB                          stosw
  1273 00000768 AB                          stosw
  1274 00000769 AB                          stosw
  1275 0000076A AB                          stosw
  1276 0000076B AB                          stosw
  1277 0000076C AB                          stosw
  1278 0000076D AB                          stosw
  1279 0000076E 5F                          pop di
  1280 0000076F 8EC2                        mov es,dx               ; restore critical register
  1281 00000771 C3                          ret
  1282                                  init_segdef_entry   ENDP
  1283                                  
  1284                                  ;*****************************
  1285                                  ;* MAKE_SEGDEF_BLK           *
  1286                                  ;*****************************
  1287                                  
  1288                                  ; make a new segdef block
  1289                                  ; return segment of new block in es
  1290                                  ; destroys ax,es
  1291                                  
  1292                                  make_segdef_blk PROC
  1293 00000772 52                          push    dx              ; save critical register
  1294 00000773 53                          push    bx
  1295 00000774 8B16[0000]                  mov dx,[alloc_segdefblk_ptr]  ; keep previously last allocated block segment
  1296 00000778 BB4100                      mov bx,SEG_DEFBLK_SIZE  ; number of paragraphs to allocate
  1297 0000077B E8(0000)                    call    alloc_memory    ; get memory for block allocation
  1298 0000077E A3[0000]                    mov [alloc_segdefblk_ptr],ax  ; update last allocated block pointer
  1299                                  
  1300 00000781 8EC2                        mov es,dx               ; es -> old block
  1301 00000783 26A30200                    mov [es:2],ax           ; update old block to point to new block
  1302                                  
  1303 00000787 8EC0                        mov es,ax               ; es -> new block
  1304 00000789 26C70600000000              mov WORD PTR [es:0],0   ; zero count of entries in block
  1305 00000790 26C70602000000              mov WORD PTR [es:2],0   ; zero pointer to next entry
  1306 00000797 5B                          pop bx
  1307 00000798 5A                          pop dx                  ; restore critical registers
  1308 00000799 C3                          ret
  1309                                  make_segdef_blk ENDP
  1310                                  
  1311                                  ;*****************************
  1312                                  ;* MAKE_SEGPART_ENTRY        *
  1313                                  ;*****************************
  1314                                  
  1315                                  ; make segment partition entry
  1316                                  ; upon entry es -> segdef entry
  1317                                  ; return segment of entry in es
  1318                                  ; destroys ax,bx,es
  1319                                  
  1320                                  make_segpart_entry  PROC
  1321 0000079A 51                          push    cx              ; save critical register
  1322 0000079B 06                          push    es              ; save pointer to segdef entry
  1323                                  
  1324                                  ; check if segdef is overlay class, if so and overlay flag for this
  1325                                  ; module is set, this partition entry forms an overlay
  1326                                  ; re/set overlay segment flag accordingly
  1327 0000079C 30C0                        xor al,al
  1328 0000079E A2[0800]                    mov [ovl_seg_flag],al     ; init overlay current segment flag
  1329 000007A1 2638061C00                  cmp BYTE PTR [es:28],al ; check segment overlay class flag
  1330 000007A6 7432                        je  mse_1               ; not overlay class
  1331 000007A8 8B1E[1400]                  mov bx,WORD PTR [segment_length]
  1332 000007AC 0B1E[1600]                  or  bx,WORD PTR [segment_length+2]    ; don't overlay zero length segment
  1333 000007B0 7428                        je  mse_1               ; zero length segment, don't make an overlay
  1334 000007B2 C606[0000]01                mov byte [seg_ovlclass],1      ; set overlay class segment in module flag
  1335                                  
  1336 000007B7 3806[0000]                  cmp [is_inlib],al         ; see if parsing library
  1337 000007BB 740D                        je  mse_chkovl          ; no
  1338 000007BD 3806[0000]                  cmp [is_clip5],al         ; see if Clipper 5 switch set
  1339 000007C1 7407                        je  mse_chkovl          ; no
  1340                                  
  1341                                  ; check if CLIPPER.LIB, if so, only overlay non-_TEXT segments
  1342 000007C3 E8C600                      call    check_clp5_lib
  1343 000007C6 08C0                        or  al,al               ; nonzero if CLIPPER.LIB or EXTEND.LIB nonoverlayable
  1344 000007C8 7510                        jne mse_1
  1345                                  
  1346                                  mse_chkovl:
  1347 000007CA 803E[0000]00                cmp byte [obj_ovl_flag],0      ; check if module is in an overlay
  1348 000007CF 7409                        je  mse_1               ; no
  1349                                  
  1350                                  mse_ovl:
  1351 000007D1 C606[0800]01                mov byte [ovl_seg_flag],1      ; set overlay segment flag
  1352 000007D6 FF06[0000]                  inc word [ovl_code_id]         ; bump overlay code id (used for Clarion data overlay stuff)
  1353                                  
  1354                                  mse_1:
  1355 000007DA A1[0000]                    mov ax,[alloc_segpartblk_ptr] ; get last allocated block segment
  1356 000007DD 09C0                        or  ax,ax               ; was there a previous block
  1357 000007DF 751E                        jne mse_2               ; yes
  1358                                  
  1359                                  ; make initial pubdef declarations block allocation
  1360 000007E1 BB4100                      mov bx,SEG_PARTBLK_SIZE ; number of paragraphs to allocate
  1361 000007E4 E8(0000)                    call    alloc_memory    ; get memory for block allocation
  1362 000007E7 A3[0000]                    mov [alloc_segpartblk_ptr],ax ; update last allocated block pointer
  1363 000007EA A3[0000]                    mov [first_segpartblk_ptr],ax ; update first
  1364 000007ED 8EC0                        mov es,ax               ; es -> block
  1365 000007EF 26C70600000000              mov WORD PTR [es:0],0   ; zero count of entries in block
  1366 000007F6 26C70602000000              mov WORD PTR [es:2],0   ; zero pointer to next entry
  1367 000007FD EB0D                        jmp SHORT mse_3         ; bypass block full check code
  1368                                  
  1369                                  ; at least one prior segment partition block, check if block is full
  1370                                  mse_2:
  1371 000007FF 8EC0                        mov es,ax               ; es -> current block
  1372 00000801 26833E000040                cmp WORD PTR [es:0],SEG_PARTENT_COUNT   ; see if any free entries in block
  1373 00000807 7203                        jb  mse_3               ; yes
  1374 00000809 E8BA00                      call    make_segpart_blk    ; no free entries in block, make a new block
  1375                                  
  1376                                  mse_3:
  1377 0000080C 268B1E0000                  mov bx,[es:0]           ; get entry count
  1378 00000811 8CC0                        mov ax,es               ; get block segment address
  1379 00000813 01C3                        add bx,ax               ; get first free entry segment value
  1380 00000815 43                          inc bx                  ; adjust for block system info size of 1 paragraph
  1381                                  
  1382 00000816 26FF060000                  inc WORD PTR [es:0]     ; increment count of entries in segment partition block
  1383                                  
  1384 0000081B 8EC3                        mov es,bx               ; es -> segment partition entry
  1385 0000081D 803E[0000]00                cmp byte [is_inlib],0          ; see if processing library module
  1386 00000822 7410                        je  mse_4               ; no
  1387 00000824 A1[0000]                    mov ax,WORD PTR [lib_id]  ; get library id low word
  1388 00000827 26A30600                    mov [es:6],ax           ; save to file_mod_id number low word
  1389 0000082B A1[0200]                    mov ax,WORD PTR [lib_id+2]    ; get library id high word
  1390 0000082E 26A30800                    mov [es:8],ax           ; save to file_mod_id number high word
  1391 00000832 EB0D                        jmp SHORT mse_5         ; bypass nonlibrary code
  1392                                  
  1393                                  mse_4:
  1394 00000834 A1[0000]                    mov ax,[current_obj]
  1395 00000837 26A30600                    mov [es:6],ax           ; keep id number for pass 2 lookup
  1396 0000083B 31C0                        xor ax,ax
  1397 0000083D 26A30800                    mov [es:8],ax           ; zero high word of id number
  1398                                  
  1399                                  mse_5:
  1400 00000841 A1[0000]                    mov ax,[current_segdef]
  1401 00000844 26A20A00                    mov [es:10],al          ; keep segment record index for pass 2 lookup
  1402 00000848 31C0                        xor ax,ax
  1403 0000084A 26A30200                    mov WORD PTR [es:2],ax  ; zero pointer to next block
  1404 0000084E 26A30E00                    mov WORD PTR [es:14],ax ; zero flag word
  1405                                  
  1406 00000852 58                          pop ax                  ; get segdef entry segment pointer
  1407 00000853 26A30400                    mov [es:4],ax           ; save pointer to master segdef entry
  1408                                  
  1409 00000857 803E[0800]00                cmp byte [ovl_seg_flag],0      ; see if this partition is an overlay
  1410 0000085C 741E                        je  mse_6               ; no, update partition offset
  1411 0000085E FF06[0000]                  inc word [mod_ovl_count]       ; bump count of overlays in this module
  1412 00000862 FF06[0000]                  inc word [ovl_count]           ; bump total count of overlays
  1413 00000866 A1[0000]                    mov ax,[ovl_count]        ; get count of overlays
  1414 00000869 3DFF0F                      cmp ax,OVERLAY_MAX_COUNT    ; make sure that count of overlays wasn't exceeded
  1415 0000086C 7606                        jbe mse_5a              ; not exceeded
  1416                                  
  1417                                  ; too many overlays, fatal error
  1418 0000086E B83E00                      mov ax,OVERLAY_COUNT_ERR
  1419 00000871 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  1420                                  
  1421                                  mse_5a:
  1422 00000874 26C6060F0080                mov BYTE PTR [es:15],80h    ; set high bit of byte to indicate overlaid partition
  1423 0000087A EB0E                        jmp SHORT mse_ret       ; yes, bypass partition offset update
  1424                                  
  1425                                  mse_6:
  1426 0000087C 8CC1                        mov cx,es               ; save pointer to segment partition entry
  1427 0000087E 8EC0                        mov es,ax               ; point to segdef entry
  1428 00000880 26A10600                    mov ax,[es:6]           ; get segment length of segdef entry
  1429 00000884 8EC1                        mov es,cx               ; restore es -> segment partition entry
  1430 00000886 26A30000                    mov [es:0],ax           ; this segment partition starts at end of last partition, if any
  1431                                  
  1432                                  mse_ret:
  1433 0000088A 59                          pop cx                  ; restore critical register
  1434 0000088B C3                          ret
  1435                                  make_segpart_entry  ENDP
  1436                                  
  1437                                  ;*****************************
  1438                                  ;* CHECK_CLP5_LIB            *
  1439                                  ;*****************************
  1440                                  
  1441                                  ; returns al==0 if overlay name doesn't end in _TEXT or current file
  1442                                  ; is not CLIPPER.LIB (segment potentially overlayable),
  1443                                  ; otherwise return al != 0
  1444                                  ; destroys ax,bx
  1445                                  
  1446                                  check_clp5_lib  PROC
  1447 0000088C 56                          push    si              ; save critical register
  1448 0000088D A1[0000]                    mov ax,[current_lib]
  1449 00000890 3B06[0000]                  cmp ax,[clip_libnum]      ; see if current lib is CLIPPER.LIB
  1450 00000894 752C                        jne ccl_ovl             ; no
  1451                                  
  1452 00000896 BE[0000]                    mov si,OFFSET name_field wrt DGROUP
  1453                                  
  1454                                  ccl_searchloop:
  1455 00000899 AC                          lodsb                   ; search for null terminator of segment name
  1456 0000089A 08C0                        or  al,al               ; at null terminator?
  1457 0000089C 75FB                        jne ccl_searchloop      ; no
  1458                                  
  1459 0000089E 83EE06                      sub si,6                ; si -> where _TEXT should start
  1460 000008A1 803C5F                      cmp BYTE PTR [si],'_'   ; see if _TEXT
  1461 000008A4 751C                        jne ccl_ovl             ; no
  1462 000008A6 807C0154                    cmp BYTE PTR [si+1],'T' ; see if _TEXT
  1463 000008AA 7516                        jne ccl_ovl             ; no
  1464 000008AC 807C0245                    cmp BYTE PTR [si+2],'E' ; see if _TEXT
  1465 000008B0 7510                        jne ccl_ovl             ; no
  1466 000008B2 807C0358                    cmp BYTE PTR [si+3],'X' ; see if _TEXT
  1467 000008B6 750A                        jne ccl_ovl             ; no
  1468 000008B8 807C0454                    cmp BYTE PTR [si+4],'T' ; see if _TEXT
  1469 000008BC 7504                        jne ccl_ovl             ; no
  1470                                  
  1471                                  ccl_nonovl:
  1472 000008BE B001                        mov al,1                ; current segment is NOT overlayable
  1473 000008C0 EB02                        jmp SHORT ccl_exit
  1474                                  
  1475                                  ccl_ovl:
  1476 000008C2 30C0                        xor al,al               ; current segment is overlayable
  1477                                  
  1478                                  ccl_exit:
  1479 000008C4 5E                          pop si                  ; restore critical register
  1480 000008C5 C3                          ret
  1481                                  check_clp5_lib  ENDP
  1482                                  
  1483                                  ;*****************************
  1484                                  ;* MAKE_SEGPART_BLK          *
  1485                                  ;*****************************
  1486                                  
  1487                                  ; make a new segment partition block
  1488                                  ; return segment of new block in es
  1489                                  ; destroys ax,es
  1490                                  
  1491                                  make_segpart_blk    PROC
  1492 000008C6 52                          push    dx              ; save critical register
  1493 000008C7 8B16[0000]                  mov dx,[alloc_segpartblk_ptr] ; keep previously last allocated block segment
  1494 000008CB BB4100                      mov bx,SEG_PARTBLK_SIZE ; number of paragraphs to allocate
  1495 000008CE E8(0000)                    call    alloc_memory    ; get memory for block allocation
  1496 000008D1 A3[0000]                    mov [alloc_segpartblk_ptr],ax ; update last allocated block pointer
  1497                                  
  1498 000008D4 8EC2                        mov es,dx               ; es -> old block
  1499 000008D6 26A30200                    mov [es:2],ax           ; update old block to point to new block
  1500                                  
  1501 000008DA 8EC0                        mov es,ax               ; es -> new block
  1502 000008DC 26C70600000000              mov WORD PTR [es:0],0   ; zero count of entries in block
  1503 000008E3 26C70602000000              mov WORD PTR [es:2],0   ; zero pointer to next entry
  1504 000008EA 5A                          pop dx                  ; restore critical registers
  1505 000008EB C3                          ret
  1506                                  make_segpart_blk    ENDP
  1507                                  
  1508                                  END
