     1                                  ;*********************************************************************
     2                                  ;*   MLPASS1C.ASM                                                    *
     3                                  ;*                                                                   *
     4                                  ;*   By:            Michael Devore                                   *
     5                                  ;*   Date:          07/11/91                                         *
     6                                  ;*   Model:         Small                                            *
     7                                  ;*   Version:       1.0                                              *
     8                                  ;*   Assembler:     MASM 5.0                                         *
     9                                  ;*   Environment:   MS-DOS 2.x+                                      *
    10                                  ;*                                                                   *
    11                                  ;*   linker pass 1 routines part C                                   *
    12                                  ;*                                                                   *
    13                                  ;*********************************************************************
    14                                  
    15                                  ;TITLE   MACHLINK 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                                  PUBLIC  proc1_grpdef
    35                                  
    36                                  ;*****************************
    37                                  ;* Data begins               *
    38                                  ;*****************************
    39                                  
    40                                  .DATA
    41                                  
    42                                  ;*****************************
    43                                  ;* External declarations     *
    44                                  ;*****************************
    45                                  
    46                                  ; variables
    47                                  EXTRN   name_field:BYTE,filename:BYTE
    48                                  
    49                                  ; initialized local variables
    50                                  
    51                                  .DATA?
    52                                  
    53                                  ; uninitialized local variables
    54                                  
    55                                  ; byte values
    56                                  EVEN                        ; maximize speed on 8086 and better
    57                                  
    58                                  ; word value
    59 00000000 ????                    grp_ent_ptr DW  ?           ; segment pointer to group entry
    60                                  
    61                                  ;*****************************
    62                                  ;* Code begins               *
    63                                  ;*****************************
    64                                  
    65                                  .CODE
    66                                  
    67                                  ;*****************************
    68                                  ;* External declarations     *
    69                                  ;*****************************
    70                                  
    71                                  ; procedures
    72                                  EXTRN   link_error:NEAR,dos_error:NEAR,load_file:NEAR,link_warning:NEAR
    73                                  EXTRN   get_name:NEAR,get_hash:NEAR,alloc_memory:NEAR,error_bx_pos:NEAR
    74                                  
    75                                  ;*****************************
    76                                  ;* PROC1_GRPDEF              *
    77                                  ;*****************************
    78                                  
    79                                  ; process GRPDEF record
    80                                  ; upon entry cx=record length,bp=buffer_end,al=record type
    81                                  ; si -> first byte of record past record length
    82                                  ; updates si
    83                                  ; destroys ax,bx,dx,di
    84                                  
    85                                  proc1_grpdef    PROC
    86 00000000 30E4                        xor ah,ah               ; zero high byte
    87 00000002 268A04                      mov al,[es:si]          ; get low byte of group name index
    88 00000005 89F3                        mov bx,si               ; keep pointer to first index byte
    89 00000007 46                          inc si
    90 00000008 49                          dec cx                  ; decrement record length to parse
    91 00000009 39EE                        cmp si,bp               ; check boundary conditions
    92 0000000B 7203                        jb  pg_2                ; okay
    93 0000000D E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
    94                                  pg_2:
    95 00000010 08C0                        or  al,al               ; make sure value is nonzero
    96 00000012 742A                        je  pg_bad_grpind       ; zero value is invalid
    97 00000014 3C80                        cmp al,80h              ; check if more than one byte index value
    98 00000016 7210                        jb  pg_4                ; no, continue
    99 00000018 247F                        and al,7fh              ; mask off high bit
   100 0000001A 88C4                        mov ah,al               ; get high byte in ax
   101 0000001C 268A04                      mov al,[es:si]          ; get second byte of index
   102 0000001F 46                          inc si
   103 00000020 49                          dec cx                  ; decrement record length to parse
   104 00000021 39EE                        cmp si,bp               ; check boundary conditions
   105 00000023 7203                        jb  pg_4                ; okay
   106 00000025 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   107                                  
   108                                  pg_4:
   109 00000028 E8BA00                      call    get_group_entry ; make or find group entry with group index in ax, return in ax
   110 0000002B 8B3E[0000]                  mov di,[current_grpdef]   ; get number of current grpdef record
   111 0000002F D1E7                        shl di,1                ; convert di to word offset
   112 00000031 BB[0000]                    mov bx,offset grp_ent_indptr wrt DGROUP ; bx -> base of group index pointer array
   113 00000034 01FB                        add bx,di               ; bx -> proper array element
   114 00000036 8907                        mov [bx],ax             ; set array element pointer to group entry segment
   115 00000038 A3[0000]                    mov [grp_ent_ptr],ax      ; save pointer to group entry to local memory variable
   116 0000003B E99200                      jmp NEAR PTR pg_checksum    ; check if at checksum (no segment indices)
   117                                  
   118                                  pg_bad_grpind:
   119 0000003E BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   120 00000041 B80E00                      mov ax,GRPIND_VAL_ERR   ; Invalid GRPDEF group name index value
   121 00000044 E9(0000)                    jmp NEAR PTR error_bx_pos   ; transfer control to error handler
   122                                  
   123                                  ; pull segments and update their segdef entries to point to group entry
   124                                  pg_segloop:
   125 00000047 46                          inc si                  ; scan past type byte
   126 00000048 49                          dec cx                  ; decrement record length to parse
   127 00000049 39EE                        cmp si,bp               ; check boundary conditions
   128 0000004B 7203                        jb  pg_4a               ; okay
   129 0000004D E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   130                                  
   131                                  pg_4a:
   132 00000050 268A04                      mov al,[es:si]          ; get first byte of segment index
   133 00000053 89F3                        mov bx,si               ; keep pointer to first index byte
   134 00000055 46                          inc si
   135 00000056 49                          dec cx                  ; decrement record length to parse
   136 00000057 39EE                        cmp si,bp               ; check boundary conditions
   137 00000059 7203                        jb  pg_5                ; okay
   138 0000005B E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   139                                  
   140                                  pg_5:
   141 0000005E 3C80                        cmp al,80h              ; check if high bit set
   142 00000060 7217                        jb  pg_7                ; no, only 1 byte index
   143                                  
   144                                  ; two byte index, dh contains high-order byte with high bit set
   145 00000062 7409                        je  pg_6a               ; if greater than 0x80 then segment index > 255, out of bounds
   146                                  
   147                                  pg_bad_segind:
   148 00000064 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   149 00000067 B80900                      mov ax,SEGDEF_VAL_ERR   ; segment index greater than 255 maximum, or higher than count of segdef records
   150 0000006A E9(0000)                    jmp NEAR PTR error_bx_pos   ; transfer control to error handler
   151                                  
   152                                  pg_6a:
   153 0000006D 268A04                      mov al,[es:si]          ; get second byte of segment index
   154 00000070 46                          inc si
   155 00000071 49                          dec cx                  ; decrement record length to parse
   156 00000072 39EE                        cmp si,bp               ; check boundary conditions
   157 00000074 7203                        jb  pg_7                ; okay
   158 00000076 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   159                                  
   160                                  pg_7:
   161 00000079 08C0                        or  al,al               ; make sure that dh is nonzero value
   162 0000007B 74E7                        je  pg_bad_segind       ; zero value is invalid
   163                                  
   164                                  ; al contains segment index value
   165 0000007D BB[0000]                    mov bx,offset seg_defent_indptr wrt DGROUP  ; set bx to base of segment index pointer array
   166 00000080 FEC8                        dec al                  ; make segment name index relative zero
   167 00000082 30E4                        xor ah,ah               ; zap high byte
   168 00000084 D1E0                        shl ax,1                ; convert to word offset
   169 00000086 01C3                        add bx,ax               ; bx -> segdef entry of segment in group
   170 00000088 8CC2                        mov dx,es               ; save extra segment
   171 0000008A 8E07                        mov es,[bx]             ; get segment of segdef entry
   172 0000008C A1[0000]                    mov ax,[grp_ent_ptr]      ; get segment pointer to group entry
   173                                  
   174 0000008F 803E[0000]01                cmp byte [udl_proc_pass],1     ; see if udl processing
   175 00000094 7429                        je  pg_8                ; yes, bypass multi-group segment check
   176 00000096 26833E100000                cmp WORD PTR [es:16],0  ; see if previous pointer exists
   177 0000009C 7421                        je  pg_8                ; no
   178 0000009E 2639061000                  cmp [es:16],ax          ; is if previous entry matches this entry
   179 000000A3 741A                        je  pg_8                ; yes
   180                                  
   181                                  ; warning, segment declared in more than one group
   182 000000A5 268B3E0800                  mov di,[es:8]           ; get offset of name in di
   183 000000AA 83C708                      add di,8                ; adjust past 2 doubleword pointers
   184 000000AD 268E060A00                  mov es,[es:10]          ; get segment of name in es
   185 000000B2 52                          push    dx              ; save critical register
   186 000000B3 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   187 000000B6 B83000                      mov ax,SEG_GRP_DECL_WARN
   188 000000B9 E8(0000)                    call    link_warning    ; give warning feedback
   189 000000BC 5A                          pop dx                  ; restore critical register
   190 000000BD EB0F                        jmp SHORT pg_9          ; ignore new declaration
   191                                  
   192                                  pg_8:
   193 000000BF 803E[0000]00                cmp byte [any_ddl],0           ; see if using DDL's
   194 000000C4 7404                        je  pg_noddl            ; no
   195 000000C6 A1[0000]                    mov ax,[current_grpdef]   ; use group index instead of pointer for DDL's
   196 000000C9 40                          inc ax                  ; make relative one
   197                                  
   198                                  pg_noddl:
   199 000000CA 26A31000                    mov [es:16],ax          ; save pointer to group entry in segdef entry
   200                                  
   201                                  pg_9:
   202 000000CE 8EC2                        mov es,dx               ; restore extra segment
   203                                  
   204                                  pg_checksum:
   205 000000D0 83F901                      cmp cx,1                ; check if at checksum byte
   206 000000D3 7603                        jbe pg_out              ; yes, gobble it and return
   207 000000D5 E96FFF                      jmp NEAR PTR pg_segloop ; loop back for next definition
   208                                  
   209                                  pg_out:
   210 000000D8 FF06[0000]                  inc word [current_grpdef]      ; bump count of current grpdef record
   211 000000DC 46                          inc si                  ; bump past checksum byte
   212 000000DD 39EE                        cmp si,bp               ; check boundary conditions
   213 000000DF 7203                        jb  pg_ret              ; okay
   214 000000E1 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   215                                  
   216                                  pg_ret:
   217 000000E4 C3                          ret
   218                                  proc1_grpdef    ENDP
   219                                  
   220                                  ;*****************************
   221                                  ;* GET_GROUP_ENTRY           *
   222                                  ;*****************************
   223                                  
   224                                  ; find or create a group entry
   225                                  ; upon entry ax is the group name index
   226                                  ; return segment of entry in ax
   227                                  ; destroys ax
   228                                  
   229                                  get_group_entry PROC
   230 000000E5 53                          push    bx              ; save critical register
   231 000000E6 51                          push    cx
   232 000000E7 52                          push    dx
   233 000000E8 57                          push    di
   234 000000E9 06                          push    es
   235 000000EA 48                          dec    ax               ; make group name index count relative zero
   236 000000EB D1E0                        shl ax,1                ; convert to word index
   237 000000ED D1E0                        shl ax,1                ; convert to doubleword index
   238 000000EF BF[0000]                    mov di,OFFSET lnames_ent_indptr wrt DGROUP  ; si -> base of lnames array
   239 000000F2 01C7                        add di,ax               ; si -> array element with segment:offset of name in lnames block
   240                                  
   241 000000F4 8B4D02                      mov cx,[di+2]           ; get segment of name entry in cx
   242 000000F7 8B3D                        mov di,[di]             ; get offset of name entry in di
   243                                  
   244 000000F9 A1[0000]                    mov ax,[alloc_grpblk_ptr]
   245 000000FC 09C0                        or  ax,ax               ; check if any group blocks were previously allocated
   246 000000FE 751C                        jne gge_2               ; yes
   247                                  
   248                                  ; make initial group block allocation
   249 00000100 BB1100                      mov bx,GRP_BLK_SIZE     ; number of paragraphs to allocate
   250 00000103 E8(0000)                    call    alloc_memory    ; get memory for block allocation
   251 00000106 A3[0000]                    mov [alloc_grpblk_ptr],ax ; update last allocated block pointer
   252 00000109 A3[0000]                    mov [first_grpblk_ptr],ax ; update first allocated block pointer
   253 0000010C 8EC0                        mov es,ax               ; es -> block
   254 0000010E 26C70600000000              mov WORD PTR [es:0],0   ; zero count of entries in block
   255 00000115 26C70602000000              mov WORD PTR [es:2],0   ; zero pointer to next entry
   256                                  
   257                                  gge_2:
   258 0000011C 8EC0                        mov es,ax               ; es -> current block
   259 0000011E 31D2                        xor dx,dx               ; dx hold group entry number
   260                                  
   261                                  gge_grp_loop:
   262 00000120 263B160000                  cmp dx,[es:0]           ; check if any more entries in group block
   263 00000125 720C                        jb  gge_3               ; yes
   264                                  
   265                                  ; no more entries in group block, get next group block
   266 00000127 26A10200                    mov ax,[es:2]           ; get pointer to next group
   267 0000012B 09C0                        or  ax,ax               ; check if null, no more group blocks
   268 0000012D 7421                        je  gge_4               ; no more blocks, make new group name
   269 0000012F 8EC0                        mov es,ax               ; es -> new block
   270 00000131 31D2                        xor dx,dx               ; re-init group entry number
   271                                  
   272                                  gge_3:
   273 00000133 06                          push    es              ; save es -> block
   274 00000134 8CC0                        mov ax,es               ; get block segment address
   275 00000136 01D0                        add ax,dx               ; get first free entry segment value
   276 00000138 40                          inc ax                  ; adjust for block system info size of 1 paragraph
   277 00000139 8EC0                        mov es,ax               ; es -> group entry
   278 0000013B 42                          inc dx                  ; bump entry number
   279                                  
   280 0000013C 263B3E0400                  cmp di,[es:4]           ; see if offsets of lnames pointers match
   281 00000141 7403                        je  gge_3a              ; yes
   282                                  
   283                                  gge_nomatch:
   284 00000143 07                          pop es                  ; restore es -> block
   285 00000144 EBDA                        jmp SHORT gge_grp_loop  ; try next entry
   286                                  
   287                                  gge_3a:
   288 00000146 263B0E0600                  cmp cx,[es:6]           ; see if segments of lnames pointer match
   289 0000014B 75F6                        jne gge_nomatch         ; no
   290                                  
   291                                  ; names match, entry already made for this group
   292 0000014D 5B                          pop bx                  ; trash old es value on stack
   293 0000014E EB4E                        jmp SHORT gge_ret       ; leave without creating a new entry
   294                                  
   295                                  ; make new group entry
   296                                  gge_4:
   297 00000150 A1[0000]                    mov ax,[alloc_grpblk_ptr] ; get current group block
   298 00000153 8EC0                        mov es,ax               ; es -> block
   299 00000155 26833E000010                cmp WORD PTR [es:0],GRP_ENT_COUNT   ; check if room for any more entries
   300 0000015B 7205                        jb  gge_5               ; yes
   301 0000015D E84400                      call    make_group_blk  ; make a new group block, return segment in es
   302 00000160 31D2                        xor dx,dx               ; re-init group entry count
   303                                  
   304                                  gge_5:
   305 00000162 26FF060000                  inc WORD PTR [es:0]     ; bump count of entries in group block
   306 00000167 8CC0                        mov ax,es               ; get block segment address
   307 00000169 01D0                        add ax,dx               ; get first free entry segment value
   308 0000016B 40                          inc ax                  ; adjust for block system info size of 1 paragraph
   309 0000016C 8EC0                        mov es,ax               ; es -> free group entry
   310                                  
   311                                  ; set doubleword group offset to high value (force first segment compare to update)
   312 0000016E 26C7060000FFFF              mov word [es:0],0ffffh
   313 00000175 26C7060200FF7F              mov word [es:2],07fffh
   314                                  
   315 0000017C 26890E0600                  mov [es:6],cx           ; save segment pointer to group name entry in lnames block
   316 00000181 26893E0400                  mov [es:4],di           ; save offset pointer
   317 00000186 8B1E[0000]                  mov bx,[current_grpdef]   ; get count of current group
   318 0000018A 43                          inc bx                  ; make relative 1
   319 0000018B 26891E0800                  mov [es:8],bx           ; save it
   320 00000190 26C70608000000              mov WORD PTR [es:8],0   ; zero first segdef entry pointer
   321                                  	; ecm: "ges_grp_index" in mlequate.mac, but note how both
   322                                  	;  of the above two instructions write to the same word.
   323 00000197 26C7060E000000              mov WORD PTR [es:14],0  ; zero flag word
   324                                  	; ecm: this field was missing in struc GRP_ENT_STRUC (mlequate.mac)
   325                                  
   326                                  gge_ret:
   327 0000019E 07                          pop es                  ; restore critical registers
   328 0000019F 5F                          pop di
   329 000001A0 5A                          pop dx
   330 000001A1 59                          pop cx
   331 000001A2 5B                          pop bx
   332 000001A3 C3                          ret
   333                                  get_group_entry ENDP
   334                                  
   335                                  ;*****************************
   336                                  ;* MAKE_GROUP_BLK            *
   337                                  ;*****************************
   338                                  
   339                                  ; make a new group block
   340                                  ; return segment of block in es
   341                                  ; destroys ax,bx,dx,es
   342                                  
   343                                  make_group_blk  PROC
   344 000001A4 8B16[0000]                  mov dx,[alloc_grpblk_ptr] ; keep previously last allocated block segment
   345 000001A8 BB1100                      mov bx,GRP_BLK_SIZE     ; number of paragraphs to allocate
   346 000001AB E8(0000)                    call    alloc_memory    ; get memory for block allocation
   347 000001AE A3[0000]                    mov [alloc_grpblk_ptr],ax ; update last allocated block pointer
   348                                  
   349 000001B1 8EC2                        mov es,dx               ; es -> old block
   350 000001B3 26A30200                    mov [es:2],ax           ; update old block to point to new block
   351                                  
   352 000001B7 8EC0                        mov es,ax               ; es -> new block
   353 000001B9 31DB                        xor bx,bx
   354 000001BB 26891F                      mov [es:bx],bx          ; zero count of entries in block
   355 000001BE 26891E0200                  mov [es:2],bx           ; zero pointer to next entry
   356 000001C3 C3                          ret
   357                                  make_group_blk  ENDP
   358                                  
   359                                  END
