     1                                  ;*********************************************************************
     2                                  ;*   MLCOMM.ASM                                                      *
     3                                  ;*                                                                   *
     4                                  ;*   By:            Michael Devore                                   *
     5                                  ;*   Date:          12/22/92                                         *
     6                                  ;*   Model:         Small                                            *
     7                                  ;*   Version:       1.0                                              *
     8                                  ;*   Assembler:     MASM 5.0                                         *
     9                                  ;*   Environment:   MS-DOS 2.x+                                      *
    10                                  ;*                                                                   *
    11                                  ;*   linker communal variable routines                               *
    12                                  ;*                                                                   *
    13                                  ;*********************************************************************
    14                                  
    15                                  ;TITLE   WARPLINK mlcomm
    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  resolve_communals,scan_comfield
    36                                  ;***PUBLIC	save_local_comm,get_local_comm
    37                                  PUBLIC  compute_comm_len
    38                                  
    39                                  ;*****************************
    40                                  ;* Data begins               *
    41                                  ;*****************************
    42                                  
    43                                  .DATA
    44                                  
    45                                  ;*****************************
    46                                  ;* External declarations     *
    47                                  ;*****************************
    48                                  
    49                                  ; variables
    50                                  EXTRN   filename:BYTE,pass_number:BYTE
    51                                  ;***EXTRN	local_comm_count:WORD
    52                                  EXTRN   com_val1:DWORD,com_val2:DWORD,name_field:BYTE
    53                                  EXTRN   dgrouptext:BYTE
    54                                  
    55                                  ; initialized local variables
    56                                  
    57                                  EVEN                        ; maximize speed on 8086 and better
    58                                  
    59                                  ; word values
    60 00000000 0000                    near_comm_segptr    DW  0   ; pointer to segdef entry of segment used for near communals
    61 00000002 0000                    far_comm_segptr     DW  0   ; pointer to segdef entry of segment currently used for far communals
    62 00000004 0000                    huge_comm_len   DW  0       ; length of huge communal variable modulo 64K
    63 00000006 0000                    nc_group_ptr    DW  0       ; pointer to near communal group entry
    64                                  
    65                                  ; double word values
    66 00000008 00000000                far_comm_len    DD  0       ; running length of far communal variables
    67                                  
    68                                  .DATA?
    69                                  
    70                                  ; uninitialized local variables
    71                                  
    72                                  EVEN
    73                                  
    74                                  ; doubleword values
    75 00000000 ????????                temp_com_val    DD  ?       ; temporary storage for computing communal variable length
    76                                  
    77                                  ;*****************************
    78                                  ;* Constant data             *
    79                                  ;*****************************
    80                                  
    81                                  .CONST
    82                                  
    83                                  EVEN
    84 00000000 635F636F6D6D6F6E00      c_commontext    DB  'c_common',0    ; segment name to check against for near communal use
    85 00000009 42535300                bsstext DB  'BSS',0         ; class name to check against for near communal use
    86 0000000D 4641525F42535300        far_bsstext DB  'FAR_BSS',0 ; segment/class name for far communal variables
    87 00000015 485547455F42535300      huge_bsstext    DB  'HUGE_BSS',0    ; segment/class name for huge communal variables
    88                                  
    89                                  ;*****************************
    90                                  ;* Code begins               *
    91                                  ;*****************************
    92                                  
    93                                  .CODE
    94                                  
    95                                  ;*****************************
    96                                  ;* External declarations     *
    97                                  ;*****************************
    98                                  
    99                                  ; procedures
   100                                  EXTRN   link_error:NEAR,load_file:NEAR,error_bx_pos:NEAR
   101                                  EXTRN   make_pubdecl_blk:NEAR,alloc_memory:NEAR
   102                                  EXTRN   make_segdef_blk:NEAR,init_segdef_entry:NEAR,get_hash:NEAR
   103                                  EXTRN   make_segpart_blk:NEAR
   104                                  
   105                                  ;*****************************
   106                                  ;* SCAN_COMFIELD             *
   107                                  ;*****************************
   108                                  
   109                                  ; scan past communal length field variables
   110                                  ; upon entry dh == field value, si -> current buffer position,
   111                                  ; bx == original byte offset, di-> 4 byte memory location (pass 1 only)
   112                                  ; if pass 1 returns value of field in 4-byte memory location pointed by di
   113                                  ; destroys dx,di
   114                                  ; updates si
   115                                  
   116                                  scan_comfield   PROC
   117 00000000 80FE80                      cmp dh,80h              ; check if one byte field
   118 00000003 7304                        jae sc_2                ; no
   119 00000005 B201                        mov dl,1                ; dl holds number of bytes to scan past
   120 00000007 EB24                        jmp SHORT sc_start_scan ; scan them
   121                                  
   122                                  sc_2:
   123 00000009 80FE81                      cmp dh,81h              ; check if two byte field
   124 0000000C 7504                        jne sc_3                ; no
   125 0000000E B203                        mov dl,3                ; dl holds number of bytes to scan past, including variable size
   126 00000010 EB1B                        jmp SHORT sc_start_scan ; scan them
   127                                  
   128                                  sc_3:
   129 00000012 80FE84                      cmp dh,84h              ; check if three byte field
   130 00000015 7504                        jne sc_4                ; no
   131 00000017 B204                        mov dl,4                ; dl holds number of bytes to scan past
   132 00000019 EB12                        jmp SHORT sc_start_scan ; scan them
   133                                  
   134                                  sc_4:
   135 0000001B 80FE88                      cmp dh,88h              ; check if four byte field
   136 0000001E 740B                        je  sc_5                ; yes
   137                                  
   138 00000020 88F1                        mov cl,dh               ; get value in cl
   139 00000022 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   140 00000025 B80C00                      mov ax,INV_COMFIELD_VAL_ERR ; invalid communal length field value
   141 00000028 E9(0000)                    jmp NEAR PTR error_bx_pos   ; transfer control to error handler
   142                                  
   143                                  sc_5:
   144 0000002B B205                        mov dl,5                ; dl holds number of bytes to scan past
   145                                  
   146                                  ; dl holds number of bytes to scan past
   147                                  sc_start_scan:
   148 0000002D 80FA01                      cmp dl,1                ; check if one byte value
   149 00000030 750D                        jne sc_7                ; no, first byte isn't part of value
   150                                  
   151                                  sc_loop:
   152 00000032 803E[0000]02                cmp byte [pass_number],2       ; if pass two, don't save length values (memory allocations already made)
   153 00000037 7406                        je  sc_7
   154                                  
   155                                  ; pass 1, save number of bytes in communal variable for allocating
   156 00000039 268A04                      mov al,[es:si]          ; get byte value
   157 0000003C 8805                        mov [di],al             ; save it
   158                                  
   159                                  sc_6:
   160 0000003E 47                          inc di                  ; bump to next byte position of communal value
   161                                  
   162                                  sc_7:
   163 0000003F 46                          inc si
   164 00000040 49                          dec cx                  ; decrement record length to parse
   165 00000041 39EE                        cmp si,bp               ; check boundary conditions
   166 00000043 7203                        jb  sc_8                ; okay
   167 00000045 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   168                                  
   169                                  sc_8:
   170 00000048 FECA                        dec dl                  ; drop count of to-scan bytes
   171 0000004A 75E6                        jne sc_loop             ; not done, scan another byte
   172 0000004C C3                          ret                     ; done scanning, return
   173                                  scan_comfield   ENDP
   174                                  
   175                                  %if 0 ;COMMENT # **********
   176                                  
   177                                  ;*****************************
   178                                  ;* SAVE_LOCAL_COMM           *
   179                                  ;*****************************
   180                                  
   181                                  ; pass 1 save local communals to nonlocal communal block, setting
   182                                  ; the local flag (bit 5, 20h) and putting the lib_id (library processing)
   183                                  ; or current_obj (object module processing) in place of the
   184                                  ; pub_declent_loptr and pub_declent_hiptr bytes.  Use a zero word for
   185                                  ; the high word of current_obj (pub_declent_hiptr).
   186                                  ; destroys ax,cx,dx,di,es
   187                                  
   188                                  save_local_comm PROC
   189                                      mov ax,[first_local_ptr]  ; get pointer to first block
   190                                  
   191                                  slc_blkloop:
   192                                      or  ax,ax               ; see if any more blocks
   193                                      je  slc_ret             ; no, return
   194                                      mov es,ax               ; es -> block
   195                                      mov cx,[es:0]           ; get count of entries
   196                                      jcxz    slc_ret         ; no more entries
   197                                      inc ax                  ; point to first entry
   198                                  
   199                                  slc_entloop:
   200                                      push    es              ; save -> block
   201                                      mov es,ax               ; es -> entry
   202                                      test    BYTE PTR [es:15],40h    ; see if local communal
   203                                      je  slc_trynext         ; no
   204                                  
   205                                  ; local communal, transfer to nonlocal communal block
   206                                      call    local_transfer
   207                                  
   208                                  slc_trynext:
   209                                      mov ax,[es:6]           ; get length of name
   210                                      add ax,1fh              ; add in size of local public entry and round up to nearest paragraph
   211                                      shr ax,1                ; convert to segment value, /2
   212                                      shr ax,1                ; /4
   213                                      shr ax,1                ; /8
   214                                      shr ax,1                ; /16
   215                                      pop es
   216                                      mov bx,es               ; bx holds block segment
   217                                      add ax,bx               ; ax holds segment of next entry
   218                                      loop    slc_entloop     ; check next entry, if any
   219                                      mov ax,[es:2]           ; no more entries in this block, get pointer to next block
   220                                      jmp SHORT slc_blkloop   ; try next block
   221                                  
   222                                  slc_ret:
   223                                      ret
   224                                  save_local_comm ENDP
   225                                  
   226                                  ;*****************************
   227                                  ;* LOCAL_TRANSFER            *
   228                                  ;*****************************
   229                                  
   230                                  ; transfer local communal to nonlocal communal block
   231                                  ; destroys ax
   232                                  
   233                                  local_transfer  PROC
   234                                      push    es              ; save critical register
   235                                      mov ax,[alloc_cdeclblk_ptr]
   236                                      or  ax,ax               ; check if any comdef declarations blocks were previously allocated
   237                                      jne slc_2               ; yes
   238                                  
   239                                  ; make initial comdef declarations block allocation
   240                                      mov bx,PUB_DECLBLK_SIZE ; number of paragraphs to allocate
   241                                      call    alloc_memory    ; get memory for block allocation
   242                                      mov [alloc_cdeclblk_ptr],ax   ; update last allocated block pointer
   243                                  
   244                                      mov [first_cdeclblk_ptr],ax   ; update first allocated block pointer
   245                                  
   246                                      mov es,ax               ; es == current (new) block segment
   247                                      xor ax,ax
   248                                      mov WORD PTR [es:0],ax  ; zero count of entries in block
   249                                      mov WORD PTR [es:2],ax  ; zero pointer to next block
   250                                      jmp SHORT slc_3         ; bypass block full check code
   251                                  
   252                                  ; at least one prior comdef declaration made, check if block is full
   253                                  slc_2:
   254                                      mov es,ax               ; es -> current block
   255                                      cmp WORD PTR [es:0],PUB_DECLENT_COUNT  ; see if any free entries in block
   256                                      jb  slc_3               ; yes
   257                                      call    make_pubdecl_blk    ; no free entries in block, make a new block
   258                                  
   259                                  slc_3:
   260                                      mov ax,es               ; get block segment address in ax
   261                                      add ax,[es:0]           ; compute first free entry segment value
   262                                      inc WORD PTR [es:0]     ; bump count of entries
   263                                      inc ax                  ; adjust for block system info size of 1 paragraph
   264                                      push    ds              ; save -> warplink data
   265                                      mov ds,ax               ; ds -> new entry
   266                                  
   267                                  ; transfer pertinent information from local communal block to nonlocal block
   268                                      mov ax,[es:2]           ; transfer communal length high word
   269                                      mov [2],ax
   270                                      mov ax,[es:4]           ; transfer current extdef (LCOMDEF identifier)
   271                                      mov [4],ax
   272                                      mov ax,[es:8]           ; transfer communal length low word
   273                                      mov [8],ax
   274                                      mov BYTE PTR [14],1  ; flag extdef/comdef
   275                                      mov ax,[es:15]          ; transfer NEAR communal bit
   276                                      mov [15],ax
   277                                      or  BYTE PTR [15],60h    ; set communal and local bits
   278                                  
   279                                      mov ax,ds
   280                                      mov es,ax               ; es -> new entry
   281                                      pop ds                  ; ds -> warplink data
   282                                      cmp byte [is_inlib],0          ; see if processing library
   283                                      je  slc_4               ; no
   284                                      mov ax,WORD PTR [lib_id+2]    ; get high word of library id
   285                                      mov [es:12],ax          ; transfer it
   286                                      mov ax,WORD PTR [lib_id]  ; get low word of library id
   287                                      jmp SHORT slc_5         ; jump to shared code
   288                                  
   289                                  slc_4:
   290                                      mov ax,[current_obj]
   291                                  
   292                                  slc_5:
   293                                      mov [es:10],ax          ; transfer value used for identification
   294                                      pop es                  ; restore critical register
   295                                      ret
   296                                  local_transfer  ENDP
   297                                  
   298                                  ;*****************************
   299                                  ;* GET_LOCAL_COMM            *
   300                                  ;*****************************
   301                                  
   302                                  ; pass 2 get local communals from nonlocal communal block
   303                                  ; returns segment of entry in ax, 0 if not found (LCOMDEF had corresponding LPUBDEF)
   304                                  ; destroys ax,bx,dx,es
   305                                  
   306                                  get_local_comm  PROC
   307                                      mov ax,[first_cdeclblk_ptr]
   308                                  
   309                                  glc_blkloop:
   310                                      or  ax,ax               ; check if any comdef declarations blocks left
   311                                      je  glc_ret             ; no, all done
   312                                      mov es,ax               ; es -> block
   313                                      mov bx,ax               ; save -> block
   314                                      mov dx,[es:0]           ; get count of entries
   315                                      or  dx,dx
   316                                      je  glc_ret             ; no more entries
   317                                      inc ax                  ; point to first entry
   318                                  
   319                                  glc_entloop:
   320                                      mov es,ax               ; es -> entry
   321                                      test    BYTE PTR [es:15],20h    ; see if local communal bit set
   322                                      je  glc_next_entry      ; no
   323                                  
   324                                      cmp byte [is_inlib],0          ; check if library processing
   325                                      je  glc_2               ; no
   326                                  
   327                                  ; processing library, check library id against entry's
   328                                      mov ax,WORD PTR [lib_id+2]    ; get high word
   329                                      cmp ax,[es:12]          ; see if matches
   330                                      jne glc_next_entry      ; no
   331                                      mov ax,WORD PTR [lib_id]  ; get low word
   332                                      jmp SHORT glc_shared    ; jump to shared code
   333                                  
   334                                  glc_2:
   335                                      mov ax,[current_obj]      ; get current object module number for id purposes
   336                                  
   337                                  glc_shared:
   338                                      cmp ax,[es:10]          ; see if ids match
   339                                      jne glc_next_entry
   340                                  
   341                                  ; file ids match, check if extdef numbers match
   342                                      mov ax,[current_extdef]   ; get current extdef number
   343                                      cmp ax,[es:4]           ; see if matches entry's
   344                                      mov ax,es               ; preload ax, flags not affected
   345                                      je  glc_ret             ; entry matches, return segment in ax
   346                                  
   347                                  glc_next_entry:
   348                                      inc ax                  ; point to next entry (each entry 16 bytes)
   349                                      dec dx                  ; drop count of entries
   350                                      jne glc_entloop         ; more left, check them
   351                                      mov es,bx               ; es -> communal block
   352                                      mov ax,[es:2]           ; get pointer to next block
   353                                      jmp SHORT glc_blkloop   ; pull entries from next block, if any
   354                                  
   355                                  glc_ret:
   356                                      ret
   357                                  get_local_comm  ENDP
   358                                  
   359                                  ********** END COMMENT #
   360                                  %endif
   361                                  
   362                                  ;*****************************
   363                                  ;* COMPUTE_COMM_LEN          *
   364                                  ;*****************************
   365                                  
   366                                  ; compute communal length from memory variables com_val1 and com_val2
   367                                  ; return product in com_val1
   368                                  ; destroys ax,dx
   369                                  
   370                                  compute_comm_len    PROC
   371 0000004D 51                          push    cx              ; save critical register
   372 0000004E A1[0000]                    mov ax,WORD PTR [com_val1]    ; get low word of first value
   373 00000051 F726[0000]                  mul WORD [com_val2]       ; multiply by low word of second value
   374 00000055 A3[0000]                    mov WORD PTR [temp_com_val],ax
   375 00000058 8916[0200]                  mov WORD PTR [temp_com_val+2],dx  ; save to temporary value
   376 0000005C A1[0000]                    mov ax,WORD PTR [com_val1]    ; get low word of first value
   377 0000005F F726[0200]                  mul WORD [com_val2+2]     ; multiply by high word of second value
   378 00000063 09D2                        or  dx,dx                   ; see if overflow occurred
   379 00000065 7530                        jne ccl_overflow            ; yes, fatal error
   380 00000067 0106[0200]                  add WORD PTR [temp_com_val+2],ax
   381 0000006B 722A                        jc  ccl_overflow            ; high word cannot overflow
   382 0000006D A1[0200]                    mov ax,WORD PTR [com_val1+2]  ; get high word of first value
   383 00000070 F726[0000]                  mul WORD [com_val2]       ; multiply by low word of second value
   384 00000074 09D2                        or  dx,dx                   ; see if overflow occurred
   385 00000076 751F                        jne ccl_overflow            ; yes, fatal error
   386 00000078 0106[0200]                  add WORD PTR [temp_com_val+2],ax
   387 0000007C 7219                        jc  ccl_overflow            ; high word cannot overflow
   388 0000007E A1[0200]                    mov ax,WORD PTR [com_val1+2]  ; get high word of first value
   389 00000081 F726[0200]                  mul WORD [com_val2+2]     ; multiply by high word of second value
   390 00000085 09C2                        or  dx,ax                   ; value should be zero
   391 00000087 750E                        jne ccl_overflow            ; not zero, overflow occurred
   392 00000089 A1[0000]                    mov ax,WORD PTR [temp_com_val]    ; stuff value back into com_val1
   393 0000008C A3[0000]                    mov WORD PTR [com_val1],ax
   394 0000008F A1[0200]                    mov ax,WORD PTR [temp_com_val+2]
   395 00000092 A3[0200]                    mov WORD PTR [com_val1+2],ax
   396                                  %if 01	; disable to check COMM_OVRFLW_ERR
   397 00000095 59                          pop cx                  ; restore critical register
   398 00000096 C3                          ret
   399                                  %endif
   400                                  
   401                                  ; communal variable overflow
   402                                  ccl_overflow:
   403 00000097 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   404 0000009A B83800                      mov ax,COMM_OVRFLW_ERR
   405 0000009D B9[0000]                    mov cx,OFFSET name_field wrt DGROUP ; cx -> symbol name for this error
   406 000000A0 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   407                                  
   408                                  compute_comm_len    ENDP
   409                                  
   410                                  ;*****************************
   411                                  ;* RESOLVE_COMMUNALS         *
   412                                  ;*****************************
   413                                  
   414                                  ; resolve communal variables addresses that have no corresponding PUBDEF,
   415                                  ; adjusting or creating segments as necessary
   416                                  ; destroys ax,bx,cx,dx,di,si,es
   417                                  
   418                                  resolve_communals   PROC
   419 000000A3 833E[0000]00                cmp word [communal_count],0    ; see if any communals to resolve
   420 000000A8 743A                        je  rc_ret              ; no
   421                                  
   422 000000AA A1[0000]                    mov ax,[first_cdeclblk_ptr]
   423                                  
   424                                  rc_blkloop:
   425 000000AD 09C0                        or  ax,ax               ; check if any comdef declarations blocks left
   426 000000AF 7433                        je  rc_ret              ; no, all done
   427 000000B1 8EC0                        mov es,ax               ; es -> block
   428 000000B3 89C3                        mov bx,ax               ; save -> block
   429 000000B5 268B0E0000                  mov cx,[es:0]           ; get count of entries
   430 000000BA E328                        jcxz    rc_ret          ; no more entries
   431 000000BC 40                          inc ax                  ; point to first entry
   432                                  
   433                                  rc_entloop:
   434 000000BD 8EC0                        mov es,ax               ; es -> entry
   435 000000BF 26F6060F0040                test    BYTE PTR [es:15],40h    ; see if communal bit set
   436 000000C5 7410                        je  rc_next_entry       ; no
   437 000000C7 26F6060F0010                test    BYTE PTR [es:15],10h    ; see if near communal
   438 000000CD 7505                        jne rc_near             ; yes
   439 000000CF E8F800                      call    res_far_communal    ; resolve far communal
   440 000000D2 EB03                        jmp SHORT rc_next_entry ; check next entry, if any
   441                                  
   442                                  rc_near:
   443 000000D4 E80E00                      call    res_near_communal   ; resolve near communal
   444                                  
   445                                  rc_next_entry:
   446 000000D7 8CC0                        mov ax,es
   447 000000D9 40                          inc ax                  ; point to next entry (each entry 16 bytes)
   448 000000DA E2E1                        loop    rc_entloop      ; loop thru all entries
   449 000000DC 8EC3                        mov es,bx               ; es -> communal block
   450 000000DE 26A10200                    mov ax,[es:2]           ; get pointer to next block
   451 000000E2 EBC9                        jmp SHORT rc_blkloop    ; pull entries from next block, if any
   452                                  
   453                                  rc_ret:
   454 000000E4 C3                          ret
   455                                  resolve_communals   ENDP
   456                                  
   457                                  ;*****************************
   458                                  ;* RES_NEAR_COMMUNAL         *
   459                                  ;*****************************
   460                                  
   461                                  ; resolve near communal variables
   462                                  ; upon entry es -> communal declaration entry
   463                                  ; destroys ax,dx,di,si
   464                                  
   465                                  res_near_communal   PROC
   466 000000E5 53                          push    bx              ; save critical register
   467 000000E6 51                          push    cx
   468 000000E7 06                          push    es              ; save -> communal entry
   469 000000E8 A1[0000]                    mov ax,[near_comm_segptr] ; get pointer to segdef entry of segment for near communal variables
   470 000000EB 09C0                        or  ax,ax               ; see if set yet
   471 000000ED 7408                        je  rnc_create          ; no, create segment
   472 000000EF 8B16[0600]                  mov dx,[nc_group_ptr]     ; get pointer to group entry (if any) in dx
   473 000000F3 8EC0                        mov es,ax               ; es -> segdef entry
   474 000000F5 EB7A                        jmp NEAR PTR rnc_res_com    ; bypass segment search
   475                                  
   476                                  ; create segment c_common, class BSS, group DGROUP
   477                                  rnc_create:
   478 000000F7 E8C501                      call    create_comm_segment ; create segdef and segment partition entry for new segment
   479 000000FA A3[0000]                    mov [near_comm_segptr],ax ; save pointer to near communal variables segdef entry
   480 000000FD 8CD8                        mov ax,ds               ; update segment and class names, pointing them into warplink data
   481 000000FF 26A30A00                    mov [es:10],ax
   482 00000103 26A30E00                    mov [es:14],ax          ; save segment pointer to segment and class names
   483 00000107 B8[F8FF]                    mov ax,OFFSET c_commontext-8 wrt DGROUP ; get offset to segment name, back off 8 bytes to match lnames entry format
   484 0000010A 26A30800                    mov [es:8],ax           ; save offset pointer to segment name
   485 0000010E B8[0100]                    mov ax,OFFSET bsstext-8 wrt DGROUP  ; get offset to segment class, back off 8 bytes to match lnames entry format
   486 00000111 26A30C00                    mov [es:12],ax          ; save offset pointer to segment class
   487 00000115 26C6061A0060                mov BYTE PTR [es:26],01100000b  ; paragraph aligned, private combine
   488 0000011B 31C0                        xor ax,ax
   489 0000011D 26A31B00                    mov [es:27],ax          ; zero miscellaneous flag bytes
   490                                  
   491                                  ; point segment at group DGROUP if it exists
   492 00000121 06                          push    es              ; save es -> segdef entry
   493 00000122 A1[0000]                    mov ax,[first_grpblk_ptr] ; get segment of first allocated group block
   494                                  
   495                                  rnc_group_loop:
   496 00000125 09C0                        or  ax,ax               ; check if null block
   497 00000127 7445                        je  rnc_nomatch         ; null, no more entries, no match occurred
   498 00000129 8EC0                        mov es,ax               ; es -> group block
   499 0000012B 8CC3                        mov bx,es               ; save -> group block
   500 0000012D 268B0E0000                  mov cx,[es:0]           ; get number of entries in group block
   501 00000132 E33A                        jcxz    rnc_nomatch     ; no more entries, no match found
   502 00000134 40                          inc ax                  ; ax -> first entry
   503                                  
   504                                  rnc_group_entry:
   505 00000135 8EC0                        mov es,ax               ; es -> group entry
   506 00000137 89C2                        mov dx,ax               ; save -> group entry
   507 00000139 BE[0000]                    mov si,OFFSET dgrouptext wrt DGROUP ; ds:si -> DGROUP name
   508 0000013C 26C43E0400                  les di,[es:4]           ; -> group name in lnames block
   509 00000141 83C708                      add di,8                ; adjust past 2 doubleword pointers in lnames entry
   510                                  
   511                                  ; es:di -> group entry name, ds:si -> DGROUP name
   512                                  rnc_matchloop:
   513 00000144 8A04                        mov al,[si]
   514 00000146 260A05                      or  al,[es:di]          ; see if both values are zero (matched to null terminator)
   515 00000149 7410                        je  rnc_match           ; yes
   516 0000014B A6                          cmpsb                   ; compare a nonzero byte in the two names
   517 0000014C 74F6                        je  rnc_matchloop       ; bytes match, loop for next byte test
   518                                  
   519                                  rnc_next_entry:
   520 0000014E 89D0                        mov ax,dx               ; ax -> last group entry
   521 00000150 40                          inc ax                  ; point to next group entry
   522 00000151 E2E2                        loop    rnc_group_entry ; loop thru all entries in block
   523                                  
   524                                  ; no more entries in group block, get next group block
   525 00000153 8EC3                        mov es,bx               ; es -> group block
   526 00000155 26A10200                    mov ax,[es:2]           ; get pointer to next group
   527 00000159 EBCA                        jmp SHORT rnc_group_loop
   528                                  
   529                                  ; DGROUP group entry found, segment in dx
   530                                  rnc_match:
   531 0000015B 07                          pop es                  ; restore es -> segdef entry
   532 0000015C 2689161000                  mov [es:16],dx          ; save -> group entry in segdef entry
   533 00000161 1F                          pop ds                  ; ds -> communal entry
   534 00000162 1E                          push    ds
   535 00000163 B8[ssss]                    mov ax,DGROUP
   536 00000166 8ED8                        mov ds,ax               ; ds -> WarpLink data
   537 00000168 8916[0600]                  mov [nc_group_ptr],dx     ; save near communal group entry pointer
   538 0000016C EB03                        jmp SHORT rnc_res_com   ; bypass no group match code restore from stack
   539                                  
   540                                  rnc_nomatch:
   541 0000016E 31D2                        xor dx,dx               ; zero dx to show no group match
   542 00000170 07                          pop es                  ; restore es -> segdef entry
   543                                  
   544                                  ; segment created, es -> segdef entry, now resolve communal
   545                                  rnc_res_com:
   546 00000171 1F                          pop ds                  ; ds -> communal entry
   547 00000172 09D2                        or  dx,dx               ; see if a group pointer to near communals
   548 00000174 7409                        je  rnc_5               ; no
   549                                  
   550 00000176 800E0F0080                  or  BYTE PTR [15],80h    ; flag that group is associated with communal declaration
   551 0000017B 89160200                    mov [2],dx           ; save pointer to group entry in communal declaration
   552                                  
   553                                  rnc_5:
   554 0000017F 26A11600                    mov ax,[es:22]          ; get pointer to first segment partition entry
   555 00000183 A30000                      mov [0],ax           ; save pointer in communal declaration entry
   556 00000186 C6060E0002                  mov BYTE PTR [14],2  ; flag as resolved public
   557 0000018B 26A10600                    mov ax,[es:6]           ; get old segment length
   558 0000018F 83F8FF                      cmp ax,0ffffh           ; see if segment overflow will occur
   559 00000192 742D                        je  rnc_segover_err     ; segment too large
   560 00000194 26F6061A0002                test    BYTE PTR [es:26],2  ; see if Big bit is set
   561 0000019A 7525                        jne rnc_segover_err     ; yes
   562                                  
   563 0000019C 8B0E0800                    mov cx,[8]           ; get low word of communal length
   564 000001A0 A30800                      mov [8],ax           ; save communal variable offset (previous end of segment)
   565 000001A3 01C8                        add ax,cx
   566 000001A5 730A                        jnc rnc_6               ; no overflow
   567 000001A7 09C0                        or  ax,ax               ; overflow, check if ax is zero (segment exactly 64k)
   568 000001A9 7516                        jne rnc_segover_err     ; no, true segment overflow
   569 000001AB 26800E1A0002                or  BYTE PTR [es:26],2  ; set Big bit
   570                                  
   571                                  rnc_6:
   572 000001B1 26A30600                    mov [es:6],ax           ; save new segment length
   573 000001B5 8CD8                        mov ax,ds
   574 000001B7 8EC0                        mov es,ax               ; restore es -> communal entry
   575 000001B9 B8[ssss]                    mov ax,DGROUP
   576 000001BC 8ED8                        mov ds,ax               ; ds -> warplink data
   577 000001BE 59                          pop cx
   578 000001BF 5B                          pop bx
   579 000001C0 C3                          ret
   580                                  
   581                                  rnc_segover_err:
   582 000001C1 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
   583 000001C4 B83900                      mov ax,DEF_SEG_OVRFLW_ERR   ; default data segment size exceeds 64K
   584 000001C7 E9(0000)                    jmp NEAR PTR link_error     ; transfer control to error handler
   585                                  
   586                                  res_near_communal   ENDP
   587                                  
   588                                  ;*****************************
   589                                  ;* RES_FAR_COMMUNAL          *
   590                                  ;*****************************
   591                                  
   592                                  ; resolve far communal variables
   593                                  ; upon entry es -> communal declaration entry
   594                                  ; destroys ax,dx,di,si
   595                                  
   596                                  res_far_communal    PROC
   597 000001CA 53                          push    bx              ; save critical register
   598 000001CB 51                          push    cx
   599 000001CC 06                          push    es              ; save -> communal declaration entry
   600 000001CD 26A10800                    mov ax,[es:8]           ; get low word of communal length in ax
   601 000001D1 26833E020001                cmp WORD PTR [es:2],1   ; high word length more than 1 if huge
   602 000001D7 7206                        jb  rfc_far             ; zero if far
   603 000001D9 776D                        ja  rfc_huge            ; huge communal
   604 000001DB 09C0                        or  ax,ax               ; low word length nonzero if huge
   605 000001DD 7569                        jne rfc_huge            ; nonzero with nonzero high word, huge communal
   606                                  
   607                                  ; far communal variable (<64k)
   608                                  rfc_far:
   609 000001DF 0306[0800]                  add ax,WORD PTR [far_comm_len]    ; add in previous communal lengths
   610 000001E3 268B1E0200                  mov bx,[es:2]           ; get high word of communal length
   611 000001E8 131E[0A00]                  adc bx,WORD PTR [far_comm_len+2]  ; add with carry in high word of previous lengths
   612                                  
   613 000001EC 83FB01                      cmp bx,1                ; see if >64K total length
   614 000001EF 7206                        jb  rfc_nonew           ; no, add to total running communal variable length
   615 000001F1 770C                        ja  rfc_new             ; yes, create a new segment for previous communals
   616 000001F3 09C0                        or  ax,ax               ; could be exactly 64K, check for nonzero low word
   617 000001F5 7508                        jne rfc_new             ; nonzero, >64K length, create new segment
   618                                  
   619                                  rfc_nonew:
   620 000001F7 8B16[0200]                  mov dx,[far_comm_segptr]  ; get pointer to segdef entry for far communals
   621 000001FB 09D2                        or  dx,dx               ; see if null (no far communal segment created yet)
   622 000001FD 7517                        jne rfc_1               ; non-null, communal segment exists
   623                                  
   624                                  rfc_new:
   625 000001FF BE[0500]                    mov si,OFFSET far_bsstext-8 wrt DGROUP  ; get offset to segment name, back off 8 bytes to match lnames entry format
   626 00000202 E89600                      call    update_comm_segment
   627                                  
   628 00000205 8CC2                        mov dx,es               ; save -> segdef entry in dx
   629 00000207 8916[0200]                  mov [far_comm_segptr],dx  ; save pointer to segdef entry in memory variable
   630 0000020B 07                          pop es                  ; es -> communal variable entry
   631 0000020C 06                          push    es              ; restore -> communal variable to stack
   632 0000020D 26A10800                    mov ax,[es:8]           ; get low word of communal length
   633 00000211 268B1E0200                  mov bx,[es:2]           ; get high word of communal length
   634                                  
   635                                  rfc_1:
   636 00000216 8EC2                        mov es,dx               ; es -> segdef entry
   637 00000218 268B160600                  mov dx,[es:6]           ; get previous segment length for public offset
   638 0000021D 26A30600                    mov [es:6],ax           ; save new segment length
   639 00000221 09DB                        or  bx,bx               ; see if high word nonzero
   640 00000223 7406                        je  rfc_2               ; no
   641 00000225 26800E1A0002                or  BYTE PTR [es:26],2  ; nonzero (64K segment), set Big bit
   642                                  
   643                                  rfc_2:
   644 0000022B A3[0800]                    mov WORD PTR [far_comm_len],ax
   645 0000022E 891E[0A00]                  mov WORD PTR [far_comm_len+2],bx  ; save new communal variable length
   646 00000232 26A11600                    mov ax,[es:22]          ; get pointer to segment partition entry
   647 00000236 07                          pop es                  ; es -> communal declaration entry
   648 00000237 26A30000                    mov [es:0],ax           ; update communal entry segment partition entry pointer
   649 0000023B 2689160800                  mov [es:8],dx           ; save offset of variable
   650 00000240 26C6060E0002                mov BYTE PTR [es:14],2  ; flag as resolved public
   651 00000246 EB50                        jmp SHORT rfc_ret       ; return
   652                                  
   653                                  ; huge communal variable (>=64k)
   654                                  rfc_huge:
   655 00000248 A3[0400]                    mov [huge_comm_len],ax    ; save length of huge communal variable modulo 64K
   656 0000024B 268B0E0200                  mov cx,[es:2]           ; get count of 64K huge segments to create
   657 00000250 31D2                        xor dx,dx               ; nonzero dx flags not first time thru segment creation loop
   658                                  
   659                                  rfc_loop:
   660 00000252 BE[0D00]                    mov si,OFFSET huge_bsstext-8 wrt DGROUP ; get offset to segment name, back off 8 bytes to match lnames entry format
   661 00000255 E84300                      call    update_comm_segment
   662                                  
   663 00000258 26C70606000000              mov WORD PTR [es:6],0   ; zero segment length
   664 0000025F 26800E1A0002                or  BYTE PTR [es:26],2  ; set Big bit
   665 00000265 09D2                        or  dx,dx               ; see if first time thru loop
   666 00000267 751A                        jne rfc_3               ; no, bypass communal entry update
   667                                  
   668 00000269 BA0100                      mov dx,1                ; set flag so update only occurs once
   669 0000026C 26A11600                    mov ax,[es:22]          ; get pointer to segment partition entry
   670 00000270 07                          pop es                  ; es -> communal declaration entry
   671 00000271 06                          push    es              ; restore -> communal entry to stack
   672 00000272 26A30000                    mov [es:0],ax           ; update communal entry segment partition entry pointer
   673 00000276 26C6060E0002                mov BYTE PTR [es:14],2  ; flag as resolved public
   674 0000027C 26C70608000000              mov WORD PTR [es:8],0   ; zero offset of variable
   675                                  
   676                                  rfc_3:
   677 00000283 E2CD                        loop rfc_loop           ; loop until all 64K segments created
   678                                  
   679 00000285 BE[0D00]                    mov si,OFFSET huge_bsstext-8 wrt DGROUP ; get offset to segment name, back off 8 bytes to match lnames entry format
   680 00000288 E81000                      call    update_comm_segment
   681                                  
   682 0000028B B8[ssss]                    mov ax,DGROUP
   683 0000028E 8ED8                        mov ds,ax               ; ds -> warplink data
   684 00000290 A1[0400]                    mov ax,[huge_comm_len]    ; get low word of communal length
   685 00000293 26A30600                    mov [es:6],ax           ; save length of segment (communal length modulo 64K)
   686 00000297 07                          pop es                  ; restore es -> communal entry
   687                                  
   688                                  rfc_ret:
   689 00000298 59                          pop cx                  ; restore critical register
   690 00000299 5B                          pop bx
   691 0000029A C3                          ret
   692                                  res_far_communal    ENDP
   693                                  
   694                                  ;*****************************
   695                                  ;* UPDATE_COMM_SEGMENT       *
   696                                  ;*****************************
   697                                  
   698                                  ; update segment and class name and acbp byte of far or huge communal segment
   699                                  ; upon entry si -> offset of segment/class name (adjusted back 8 bytes to emulate lnames entries)
   700                                  ; destroys ax,bx,di,es
   701                                  
   702                                  update_comm_segment PROC
   703 0000029B E82100                      call    create_comm_segment
   704 0000029E 8CD8                        mov ax,ds               ; update segment and class names, pointing them into warplink data
   705 000002A0 26A30A00                    mov [es:10],ax
   706 000002A4 26A30E00                    mov [es:14],ax          ; save segment pointer to segment and class names
   707 000002A8 2689360800                  mov [es:8],si           ; save offset pointer to segment name
   708 000002AD 2689360C00                  mov [es:12],si          ; save offset pointer to segment class
   709 000002B2 26C6061A0060                mov BYTE PTR [es:26],01100000b  ; para aligned, private combine
   710 000002B8 31C0                        xor ax,ax
   711 000002BA 26A31B00                    mov [es:27],ax          ; zero miscellaneous flag bytes
   712 000002BE C3                          ret
   713                                  update_comm_segment ENDP
   714                                  
   715                                  ;*****************************
   716                                  ;* CREATE_COMM_SEGMENT       *
   717                                  ;*****************************
   718                                  
   719                                  ; create segment for communal variable
   720                                  ; returns segment of segdef entry in es,ax
   721                                  ; destroys ax,bx,di,es
   722                                  
   723                                  create_comm_segment PROC
   724 000002BF 52                          push    dx              ; save critical register
   725 000002C0 A1[0000]                    mov ax,[alloc_segdefblk_ptr]
   726 000002C3 09C0                        or  ax,ax               ; check if any segdef blocks were previously allocated
   727 000002C5 751A                        jne ccs_2               ; yes
   728                                  
   729                                  ; make initial segdef block allocation
   730 000002C7 BB4100                      mov bx,SEG_DEFBLK_SIZE  ; number of paragraphs to allocate
   731 000002CA E8(0000)                    call    alloc_memory    ; get memory for block allocation
   732 000002CD A3[0000]                    mov [alloc_segdefblk_ptr],ax  ; update last allocated block pointer
   733 000002D0 A3[0000]                    mov [first_segdefblk_ptr],ax  ; update first allocate block pointer
   734 000002D3 8EC0                        mov es,ax               ; es == current (new) block segment
   735 000002D5 31C0                        xor ax,ax
   736 000002D7 26A30000                    mov WORD PTR [es:0],ax  ; zero count of entries in block
   737 000002DB 26A30200                    mov WORD PTR [es:2],ax  ; zero pointer to next entry
   738 000002DF EB0D                        jmp SHORT ccs_3         ; bypass block full check code
   739                                  
   740                                  ; at least one prior segdef entry made, check if block is full
   741                                  ccs_2:
   742 000002E1 8EC0                        mov es,ax               ; es -> current block
   743 000002E3 26833E000020                cmp WORD PTR [es:0],SEG_DEFENT_COUNT    ; see if any free entries in block
   744 000002E9 7203                        jb  ccs_3                ; yes
   745 000002EB E8(0000)                    call    make_segdef_blk ; no free entries in block, make a new block
   746                                  
   747                                  ccs_3:
   748 000002EE E8(0000)                    call    init_segdef_entry   ; perform segdef entry initialization code
   749 000002F1 8EC7                        mov es,di               ; es -> new segdef entry
   750 000002F3 FF06[0000]                  inc WORD [seg_count]  ; update count of total discrete segments
   751                                  
   752                                  ; make a dummy segment partition entry for the new segment (so fixup routines work correctly)
   753 000002F7 06                          push    es              ; save es -> segdef entry
   754 000002F8 A1[0000]                    mov ax,[alloc_segpartblk_ptr] ; get last allocated block segment
   755 000002FB 09C0                        or  ax,ax               ; was there a previous block
   756 000002FD 751E                        jne ccs_4               ; yes
   757                                  
   758                                  ; make initial pubdef declarations block allocation
   759 000002FF BB4100                      mov bx,SEG_PARTBLK_SIZE ; number of paragraphs to allocate
   760 00000302 E8(0000)                    call    alloc_memory    ; get memory for block allocation
   761 00000305 A3[0000]                    mov [alloc_segpartblk_ptr],ax ; update last allocated block pointer
   762 00000308 A3[0000]                    mov [first_segpartblk_ptr],ax ; update first
   763 0000030B 8EC0                        mov es,ax               ; es -> block
   764 0000030D 26C70600000000              mov WORD PTR [es:0],0   ; zero count of entries in block
   765 00000314 26C70602000000              mov WORD PTR [es:2],0   ; zero pointer to next entry
   766 0000031B EB0D                        jmp SHORT ccs_5         ; bypass block full check code
   767                                  
   768                                  ; at least one prior segment partition block, check if block is full
   769                                  ccs_4:
   770 0000031D 8EC0                        mov es,ax               ; es -> current block
   771 0000031F 26833E000040                cmp WORD PTR [es:0],SEG_PARTENT_COUNT   ; see if any free entries in block
   772 00000325 7203                        jb  ccs_5               ; yes
   773 00000327 E8(0000)                    call    make_segpart_blk    ; no free entries in block, make a new block
   774                                  
   775                                  ccs_5:
   776 0000032A 268B1E0000                  mov bx,[es:0]           ; get entry count
   777 0000032F 8CC0                        mov ax,es               ; get block segment address
   778 00000331 01C3                        add bx,ax               ; get first free entry segment value
   779 00000333 43                          inc bx                  ; adjust for block system info size of 1 paragraph
   780 00000334 26FF060000                  inc WORD PTR [es:0]     ; increment count of entries in segment partition block
   781                                  
   782 00000339 8EC3                        mov es,bx               ; es -> segment partition entry
   783 0000033B 31C0                        xor ax,ax
   784 0000033D 26A30200                    mov [es:2],ax           ; zero pointer to next block
   785 00000341 26A20F00                    mov [es:15],al          ; zero flag byte
   786                                  
   787 00000345 58                          pop ax                  ; get segdef entry segment pointer
   788 00000346 26A30400                    mov [es:4],ax           ; save pointer to master segdef entry
   789 0000034A 26C70600000000              mov WORD PTR [es:0],0   ; zero segment partition offset
   790 00000351 8EC0                        mov es,ax               ; restore es -> segdef entry
   791 00000353 26891E1600                  mov [es:22],bx          ; save -> first segment partition entry
   792 00000358 5A                          pop dx                  ; restore critical register
   793 00000359 C3                          ret
   794                                  create_comm_segment ENDP
   795                                  
   796                                  END
