     1                                  ;*********************************************************************
     2                                  ;*   MLPASS2C.ASM                                                    *
     3                                  ;*                                                                   *
     4                                  ;*   By:            Michael Devore                                   *
     5                                  ;*   Date:          03/12/93                                         *
     6                                  ;*   Model:         Small                                            *
     7                                  ;*   Version:       2.5                                              *
     8                                  ;*   Assembler:     MASM 5.0                                         *
     9                                  ;*   Environment:   MS-DOS 2.x+                                      *
    10                                  ;*                                                                   *
    11                                  ;*   linker pass 2 routines part C                                   *
    12                                  ;*                                                                   *
    13                                  ;*********************************************************************
    14                                  
    15                                  ;TITLE   WARPLINK mlpass2c
    16                                  ;PAGE    50,80
    17                                  
    18                                  ;.MODEL  SMALL
    19                                  
    20                                  ;*****************************
    21                                  ;* Include files             *
    22                                  ;*****************************
    23                                  
    24                                  [list -]
    14                              <1> [list -]
    26                                  [list -]
    31                                       
    32                                  ;*****************************
    33                                  ;* Public declarations       *
    34                                  ;*****************************
    35                                  
    36                                  ; procedures
    37                                  PUBLIC  proc2_data,get_data_off_seg
    38                                  PUBLIC  make_reloc_entry
    39                                  
    40                                  ; variables
    41                                  PUBLIC  data_offset,data_segment,prev_data_ptr,rec_offset
    42                                  PUBLIC  ovl_pub_seg_ptr,seg_fix_frame,data_seg_part
    43                                  PUBLIC  seg_ovl_class_flag
    44                                  PUBLIC	which_ledata,current_segind
    45                                  
    46                                  ;*****************************
    47                                  ;* Data begins               *
    48                                  ;*****************************
    49                                  
    50                                  .DATA
    51                                  
    52                                  ;*****************************
    53                                  ;* External declarations     *
    54                                  ;*****************************
    55                                  
    56                                  ; variables
    57                                  EXTRN   is_absseg:BYTE,ovl_code_count:WORD,filename:BYTE
    58                                  EXTRN   ovl_entry_id:WORD,clarclass_text:BYTE
    59                                  EXTRN	compress_this:BYTE,clipper_segindex:WORD
    60                                  EXTRN	ignore_fixupp_flag:BYTE
    61                                  
    62                                  ; initialized local variables
    63                                  
    64                                  EVEN                        ; maximize speed on 8086 and better
    65                                  
    66                                  .DATA?
    67                                  
    68                                  ; uninitialized local variables
    69                                  
    70                                  ; bytes values
    71                                  EVEN
    72 00000000 ??                      seg_ovl_class_flag  DB  ?   ; nonzero if L?DATA segment is overlay class
    73 00000001 ??                      which_ledata	DB	?		; ==1 if Clipper code, ==2 if SYMBOLS data, zero other
    74                                  
    75                                  ; word values
    76                                  EVEN
    77 00000002 ????                    data_segment    DW  ?       ; L?DATA data segment
    78 00000004 ????                    repeat_count    DW  ?       ; LIDATA iterated data block repeat count field
    79 00000006 ????                    block_count     DW  ?       ; LIDATA iterated data block block count field
    80 00000008 ????                    prev_data_ptr   DW  ?       ; pointer to start of data block/bytes in previous L?DATA
    81 0000000A ????                    rec_offset      DW  ?       ; L?DATA record offset
    82 0000000C ????                    current_segind	DW	?		; current segdef index, relative zero
    83                                  
    84                                  ; doubleword values
    85 0000000E ????????                data_offset DD  ?           ; L?DATA data offset from start of program (first segment address)
    86 00000012 ????                    seg_fix_frame   DW  ?       ; fixup frame for segment if overlaid
    87 00000014 ????                    data_seg_part   DW  ?       ; segment partition entry owning current L?DATA segment
    88 00000016 ????????                ovl_pub_seg_ptr DD  ?       ; pointer to overlaid public block entry of current segment partition
    89                                  
    90                                  ;*****************************
    91                                  ;* Code begins               *
    92                                  ;*****************************
    93                                  
    94                                  .CODE
    95                                  
    96                                  ;*****************************
    97                                  ;* External declarations     *
    98                                  ;*****************************
    99                                  
   100                                  ; procedures
   101                                  EXTRN   link_error:NEAR,dos_error:NEAR,load_file:NEAR,alloc_memory:NEAR
   102                                  EXTRN   write_bytes:NEAR,caseless_strcmp:NEAR
   103                                  EXTRN   write_ovl_reloc:NEAR
   104                                  EXTRN	fixup_clipper_tokens:NEAR,process_symbol_table:NEAR
   105                                  
   106                                  ;*****************************
   107                                  ;* PROC2_DATA                *
   108                                  ;*****************************
   109                                  
   110                                  ; process LIDATA and LEDATA records
   111                                  ; destroys ax,bx,dx,di
   112                                  
   113                                  proc2_data  PROC
   114 00000000 51                          push    cx              ; save critical register
   115 00000001 56                          push    si
   116 00000002 06                          push    es
   117                                  
   118 00000003 C606[0000]00            	mov	byte [ignore_fixupp_flag],0	; flag don't ignore fixupps
   119 00000008 E82200                      call    get_data_off_seg    ; get data record offset and segment
   120 0000000B 49                          dec cx                  ; adjust for record checksum byte, cx holds count of bytes to write
   121                                  
   122                                  ; check if absolute segment, if so, ignore write
   123 0000000C 803E[0000]00                cmp byte [is_absseg],0         ; check flag
   124 00000011 7516                        jne pd_ret              ; set, bypass L?DATA processing
   125                                  
   126                                  ; check which type of data record to process
   127 00000013 803E[0000]01                cmp byte [prev_flag],1         ; check if LEDATA record
   128 00000018 7505                        jne pd_6                ; no
   129 0000001A E8D101                      call    proc2_ledata    ; process LEDATA record
   130 0000001D EB0A                        jmp SHORT pd_ret        ; done
   131                                  
   132                                  pd_6:
   133 0000001F 803E[0000]02                cmp byte [prev_flag],2         ; check if LIDATA record
   134 00000024 7503                        jne pd_ret              ; no (shouldn't happen, but don't process based on bogus prev_flag value)
   135 00000026 E81902                      call    proc2_lidata    ; process LIDATA record
   136                                  
   137                                  pd_ret:
   138 00000029 07                          pop es                  ; restore critical register
   139 0000002A 5E                          pop si
   140 0000002B 59                          pop cx
   141 0000002C C3                          ret
   142                                  proc2_data  ENDP
   143                                  
   144                                  ;*****************************
   145                                  ;* GET_DATA_OFF_SEG          *
   146                                  ;*****************************
   147                                  
   148                                  ; get data record offset and segment, save to memory variables
   149                                  ; destroys all registers except ds and di
   150                                  ; ecm: cx is returned(?)
   151                                  
   152                                  get_data_off_seg    PROC
   153 0000002D 55                          push    bp
   154 0000002E C606[0000]00                mov byte [is_absseg],0         ; init absolute segment flag off
   155 00000033 8B36[0000]                  mov si,[prev_read_ptr]    ; point to previous record position
   156 00000037 8B0E[0000]                  mov cx,[prev_rec_len]     ; get length of record
   157 0000003B A1[0000]                    mov ax,[buffer_end]
   158 0000003E 89C5                        mov bp,ax               ; check only for end of physical buffer overflow
   159                                  
   160 00000040 268A14                      mov dl,[es:si]          ; get low byte of segment record index
   161 00000043 46                          inc si
   162 00000044 49                          dec cx                  ; decrement record length to parse
   163 00000045 39EE                        cmp si,bp               ; check boundary conditions
   164 00000047 7202                        jb  gds_2               ; okay
   165 00000049 31F6                        xor si,si               ; wrap to beginning of buffer
   166                                  gds_2:
   167 0000004B 80FA80                      cmp dl,80h              ; check if two byte index value
   168 0000004E 720B                        jb  gds_3               ; no, continue
   169 00000050 268A14                      mov dl,[es:si]          ; get second byte, actual value
   170 00000053 46                          inc si
   171 00000054 49                          dec cx                  ; decrement record length to parse
   172 00000055 39EE                        cmp si,bp               ; check boundary conditions
   173 00000057 7202                        jb  gds_3               ; okay
   174 00000059 31F6                        xor si,si               ; wrap to beginning of buffer
   175                                  
   176                                  gds_3:
   177 0000005B 30F6                        xor dh,dh               ; zap high byte of segment record index
   178                                  
   179 0000005D FECA                        dec dl                  ; make segment index relative zero
   180 0000005F 89D0                        mov ax,dx               ; save segment index relative zero
   181 00000061 A3[0C00]                	mov	[current_segind],ax	; save to memory variable for Clipper compression use
   182                                  
   183 00000064 D1E2                        shl dx,1                ; convert dx to word offset into array
   184 00000066 BB[0000]                    mov bx,OFFSET seg_partent_indptr wrt DGROUP  ; set bx to base of segment partition address array
   185 00000069 01D3                        add bx,dx               ; bx -> array element holding segment partition entry address
   186 0000006B 06                          push    es              ; save es -> file i/o buffer
   187 0000006C 8E07                        mov es,[bx]             ; es -> segment partition entry
   188 0000006E 89C3                        mov bx,ax               ; save segment index relative zero
   189 00000070 8CC2                        mov dx,es               ; save segment partition entry pointer
   190 00000072 26A10400                    mov ax,[es:4]           ; see if back pointer to master segdef entry
   191 00000076 09C0                        or  ax,ax               ; should be zero only if absolute segment (partition pointer really segdef pointer)
   192 00000078 7519                        jne gds_not_abs
   193                                  
   194                                  ; es should -> absolute segment segdef entry, but check acbp byte
   195                                  ; position to further verify
   196                                  
   197 0000007A 26A01A00                    mov al,[es:26]          ; get acbp byte
   198 0000007E 24E0                        and al,0e0h             ; get align field
   199 00000080 7508                        jne gds_internal        ; acbp byte doesn agree that an absolute segment
   200 00000082 C606[0000]01                mov byte [is_absseg],1         ; set absolute segment flag
   201 00000087 E98400                      jmp NEAR PTR gds_3a     ; allow file i/o buffer position adjustment
   202                                  
   203                                  ; inconsistent absolute segment indications
   204                                  gds_internal:
   205 0000008A B80000                      mov ax,INTERNAL_ERR
   206 0000008D B90A00                      mov cx,10               ; internal error value
   207 00000090 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   208                                  
   209                                  gds_not_abs:
   210 00000093 93                          xchg    bx,ax           ; bx -> master segdef entry from segment partition entry back pointer
   211                                                              ; ax holds segment index relative zero
   212                                  
   213 00000094 803E[0000]00                cmp byte [is_clarion],0        ; see if clarion flag set
   214 00000099 7473                        je  gds_3a              ; no
   215 0000009B 803E[0000]00                cmp byte [obj_ovl_flag],0      ; see if module in overlay
   216 000000A0 746C                        je  gds_3a              ; no
   217 000000A2 26F6060F0080                test BYTE PTR [es:15],80h   ; see if overlaid segment
   218 000000A8 7564                        jne gds_3a              ; yes
   219                                  
   220 000000AA 53                          push    bx              ; save critical register
   221 000000AB 52                          push    dx
   222 000000AC 57                          push    di
   223                                  
   224 000000AD 89C2                        mov dx,ax               ; dx holds segment index relative zero
   225                                  
   226                                  ; clarion switch set, nonoverlaid segment, module in overlay
   227                                  ; see if _DT or _DAT private segment, class CLARION
   228 000000AF 26A00B00                    mov al,[es:11]          ; get ACBP byte
   229 000000B3 241C                        and al,1ch              ; get combine value
   230 000000B5 7554                        jne gds_clardone        ; not a private segment
   231                                  
   232 000000B7 06                          push    es              ; save es -> segment partition entry
   233 000000B8 8EC3                        mov es,bx               ; es -> master segdef entry
   234 000000BA 26C41E0C00                  les bx,[es:12]          ; es:bx -> class name
   235 000000BF 83C308                      add bx,8                ; adjust bx past 2 doubleword pointers
   236 000000C2 BF[0000]                    mov di,OFFSET clarclass_text wrt DGROUP ; ds:di -> overlay class name
   237                                  
   238                                  ; perform a caseless string compare on the names
   239 000000C5 E8(0000)                    call    caseless_strcmp ; al return 0 if match, 1 if no match
   240 000000C8 07                          pop es                  ; restore es -> segment partition entry
   241 000000C9 08C0                        or  al,al               ; see if match
   242 000000CB 753E                        jne gds_clardone        ; no
   243                                  
   244 000000CD 89D0                        mov ax,dx               ; segment index relative zero in ax (al holds value, ah==0)
   245 000000CF B303                        mov bl,3
   246 000000D1 F6F3                        div bl                  ; get multiple clarion segment grouping (_dt, _dat, _code) count
   247 000000D3 88C3                        mov bl,al               ; save clarion segment grouping count
   248 000000D5 30FF                        xor bh,bh               ; zero high byte
   249                                  
   250 000000D7 A1[0000]                    mov ax,[ovl_entry_id]     ; get entry count of overlaid segments
   251 000000DA 40                          inc ax                  ; adjust for first current entry
   252 000000DB 01D8                        add ax,bx               ; adjust for multiple clarion segment grouping count, if any
   253 000000DD D1E0                        shl ax,1                ; x2
   254                                  
   255 000000DF 268E060400                  mov es,[es:4]           ; get master segdef entry
   256 000000E4 26C41E0800                  les bx,[es:8]
   257 000000E9 83C308                      add bx,8                ; es:bx -> segment name
   258 000000EC 26803F5F                    cmp BYTE PTR [es:bx],'_'
   259 000000F0 7519                        jne gds_clardone        ; no match against clarion data segment name
   260 000000F2 26807F0144                  cmp BYTE PTR [es:bx+1],'D'
   261 000000F7 7512                        jne gds_clardone
   262 000000F9 26807F0254                  cmp BYTE PTR [es:bx+2],'T'  ; see if _DT segment
   263 000000FE 7408                        je  gds_data_id         ; yes
   264 00000100 26807F0241                  cmp BYTE PTR [es:bx+2],'A'  ; see if _DA[T] segment (assume 'T')
   265 00000105 7504                        jne gds_clardone        ; no, no match
   266                                  
   267                                  ; _DT segment
   268 00000107 40                          inc ax                  ; offset by 1 for _DAT segment (after _DT segment)
   269                                  
   270                                  gds_data_id:
   271 00000108 A3[0000]                    mov [ovl_data_id],ax      ; save overlaid data identifier
   272                                  
   273                                  gds_clardone:
   274 0000010B 5F                          pop di                  ; restore critical register
   275 0000010C 5A                          pop dx
   276 0000010D 5B                          pop bx
   277                                  
   278                                  gds_3a:
   279 0000010E 07                          pop es                  ; restore es -> file i/o buffer
   280 0000010F 268A04                      mov al,[es:si]          ; get low byte of data offset
   281 00000112 46                          inc si
   282 00000113 49                          dec cx                  ; decrement record length to parse
   283 00000114 39EE                        cmp si,bp               ; check boundary conditions
   284 00000116 7202                        jb  gds_4               ; okay
   285 00000118 31F6                        xor si,si               ; wrap to beginning of buffer
   286                                  gds_4:
   287 0000011A 268A24                      mov ah,[es:si]          ; get high byte of data offset
   288 0000011D 46                          inc si
   289 0000011E 49                          dec cx                  ; decrement record length to parse
   290 0000011F 39EE                        cmp si,bp               ; check boundary conditions
   291 00000121 7202                        jb  gds_5               ; okay
   292 00000123 31F6                        xor si,si               ; wrap to beginning of buffer
   293                                  
   294                                  gds_5:
   295 00000125 803E[0000]00                cmp byte [is_absseg],0         ; see if absolute segment
   296 0000012A 740A                        je  gds_not_abs2        ; no
   297 0000012C 31C0                        xor ax,ax
   298 0000012E A3[0000]                    mov [ovl_code_id],ax      ; reset overlay class variables
   299 00000131 A2[0000]                    mov [seg_ovl_class_flag],al
   300 00000134 5D                          pop bp                  ; bypass data offset computation code
   301 00000135 C3                          ret
   302                                  
   303                                  gds_not_abs2:
   304 00000136 A3[0A00]                    mov [rec_offset],ax       ; save data record offset
   305 00000139 A3[0E00]                    mov WORD PTR [data_offset],ax ; save data offset to memory variable
   306 0000013C C706[1000]0000              mov WORD [data_offset+2],0    ; zero high word
   307 00000142 8936[0800]                  mov [prev_data_ptr],si    ; keep pointer to start of data bytes/block
   308                                  
   309 00000146 06                          push    es              ; save es -> file i/o buffer
   310 00000147 8EC2                        mov es,dx               ; es -> segment partition entry
   311                                  
   312 00000149 31C0                        xor ax,ax
   313 0000014B A3[0000]                    mov [ovl_code_id],ax      ; init overlay code identifier flag to zero (in case of overlay specified but none used)
   314 0000014E A2[0000]                    mov [seg_ovl_class_flag],al   ; init segment is overlay class flag
   315 00000151 3906[0000]                  cmp [ovl_count],ax        ; see if any overlays
   316 00000155 7462                        je  gds_6               ; no
   317                                  
   318 00000157 8CC0                        mov ax,es               ; get -> segment partition entry
   319 00000159 A3[1400]                    mov [data_seg_part],ax    ; save pointer to data segment partition entry owning L?DATA record
   320 0000015C 26F6060F0080                test BYTE PTR [es:15],80h   ; see if overlaid segment
   321 00000162 7511                        jne gds_5a              ; yes
   322                                  
   323 00000164 268E060400                  mov es,[es:4]           ; es -> master segdef entry
   324 00000169 8CC2                        mov dx,es               ; keep -> segdef entry in dx
   325 0000016B 26F6061C0001                test    BYTE PTR [es:28],1  ; see if overlay class segment
   326 00000171 8EC0                        mov es,ax               ; restore es -> segment partition entry
   327 00000173 7444                        je  gds_6               ; not overlay class
   328                                  
   329                                  ; overlaid or overlay class segment
   330                                  gds_5a:
   331 00000175 C606[0000]01                mov byte [seg_ovl_class_flag],1   ; set the segment is overlay class flag
   332                                  
   333                                  ; this segment may not be in the table, making the overlaid public pointers
   334                                  ; set invalid, but won't be used if that is the case
   335 0000017A 26A10600                    mov ax,[es:6]           ; get offset of overlaid public block -> segment partition entry
   336 0000017E A3[1600]                    mov WORD PTR [ovl_pub_seg_ptr],ax ; save it for fixup to vector reference
   337 00000181 26A10800                    mov ax,[es:8]           ; get segment of overlaid public block -> segment partition entry
   338 00000185 A3[1800]                    mov WORD PTR [ovl_pub_seg_ptr+2],ax   ; save it
   339                                  
   340 00000188 26F6060F0080                test    BYTE PTR [es:15],80h    ; see overlaid bit set
   341 0000018E 740E                        je  gds_5b              ; no
   342                                  
   343                                  ; segment is overlaid, set the ovl_code_id flag to proper nonzero value
   344 00000190 31C0                        xor ax,ax
   345                                  ;***    add WORD PTR data_offset,48 ; bump bytes to write offset to compensate for near vectors
   346                                  ;***    adc WORD PTR data_offset+2,ax   ; carry to high word
   347 00000192 A3[1200]                    mov [seg_fix_frame],ax    ; fixup frame of this segment is zero
   348 00000195 26A10400                    mov ax,[es:4]           ; get overlay identifier code
   349 00000199 A3[0000]                    mov [ovl_code_id],ax      ; put value in memory variable
   350 0000019C EB1E                        jmp SHORT gds_7         ; bypass the data_offset and data_segment calculation of values
   351                                  
   352                                  ; get segment frame for far fixups within segment (if overlays)
   353                                  gds_5b:
   354 0000019E 06                          push    es              ; save es -> segment partition entry
   355 0000019F 8EC2                        mov es,dx               ; es -> segdef entry
   356 000001A1 26A10200                    mov ax,[es:2]           ; get low word of offset
   357 000001A5 268B160400                  mov dx,[es:4]           ; get high word of offset
   358 000001AA 51                      	push cx
   359 000001AB B90400                  	mov cx, 4
   360                                  @@:
   361 000001AE D1EA                        shr dx,1                ; convert to segment (paragraph) value in ax
   362 000001B0 D1D8                        rcr ax,1
   363 000001B2 E2FA                    	loop @B
   364 000001B4 59                      	pop cx
   365 000001B5 A3[1200]                    mov [seg_fix_frame],ax    ; keep fixup frame of this segment
   366 000001B8 07                          pop es                  ; restore es -> segment partition entry
   367                                  
   368                                  gds_6:
   369 000001B9 E80300                  	call addtodataoffset
   370                                  gds_7:
   371 000001BC 07                          pop es                  ; restore es -> file i/o buffer
   372 000001BD 5D                          pop bp
   373 000001BE C3                          ret
   374                                  get_data_off_seg    ENDP
   375                                  
   376                                  
   377                                   global addtodataoffset
   378                                  addtodataoffset:
   379 000001BF 26A10000                    mov ax,[es:0]           ; get offset of segment partition entry
   380 000001C3 0106[0E00]                  add WORD PTR [data_offset],ax ; update offset from start of program
   381 000001C7 8316[1000]00                adc WORD [data_offset+2],0    ; carry to high word
   382 000001CC 8EC3                        mov es,bx               ; es -> segdef entry
   383 000001CE 26A10200                    mov ax,[es:2]           ; get low word of segment offset
   384 000001D2 0106[0E00]                  add WORD PTR [data_offset],ax ; update low word of offset from start of program
   385 000001D6 268B1E0400                  mov bx,[es:4]           ; get high word of segment offset
   386 000001DB 111E[1000]                  adc WORD PTR [data_offset+2],bx   ; update high word of offset from start of program
   387                                  
   388                                  ; convert offset in bx:ax to paragraphs
   389 000001DF 51                      	push cx
   390 000001E0 B90400                  	mov cx, 4
   391                                  @@:
   392 000001E3 D1EB                        shr bx,1
   393 000001E5 D1D8                        rcr ax,1                ; /2
   394 000001E7 E2FA                    	loop @B			; / 16
   395                                  				; bx should be zero by the final shift
   396 000001E9 59                      	pop cx
   397 000001EA A3[0200]                    mov [data_segment],ax     ; save segment of data
   398 000001ED C3                      	retn
   399                                  
   400                                  
   401                                  ;*****************************
   402                                  ;* PROC2_LEDATA              *
   403                                  ;*****************************
   404                                  
   405                                  ; process ledata record
   406                                  ; upon entry cx == count of data bytes, [es:si] -> first data byte
   407                                  ; destroys ax,bx,cx,dx,di
   408                                  
   409                                  proc2_ledata    PROC
   410 000001EE 30C0                    	xor	al,al
   411 000001F0 A2[0100]                	mov	[which_ledata],al		; init LEDATA flag
   412 000001F3 3806[0000]              	cmp	[compress_this],al	; see if compressing Clipper code
   413 000001F7 741D                    	je	pl_relloop			; no
   414                                  
   415                                  ; check if Clipper code (LEDATA segment index < clipper_segindex) or
   416                                  ; SYMBOLS data (LEDATA segment index == clipper_segindex)
   417 000001F9 A1[0C00]                	mov	ax,[current_segind]
   418 000001FC 3B06[0000]              	cmp	ax,[clipper_segindex]
   419 00000200 7714                    	ja	pl_relloop			; not Clipper code or symbols data
   420 00000202 740A                    	je	pl_symbols			; symbols data
   421                                  
   422                                  ; clipper code
   423 00000204 C606[0100]01            	mov	byte [which_ledata],1		; flag Clipper code to following fixups, if any
   424 00000209 E8(0000)                	call	fixup_clipper_tokens	; fixup tokens in Clipper code
   425 0000020C EB08                    	jmp	SHORT pl_relloop
   426                                  
   427                                  ; symbols data 
   428                                  pl_symbols:
   429 0000020E C606[0100]02            	mov	byte [which_ledata],2		; flag SYMBOLS data to following fixups, if any
   430 00000213 E8(0000)                	call	process_symbol_table	; process the symbol table data
   431                                  
   432                                  pl_relloop:
   433 00000216 833E[0000]00                cmp word [data_fixup_count],0  ; see if any relocation table entries
   434 0000021B 7421                        je  pl_2                ; no
   435                                  
   436 0000021D FF0E[0000]                  dec word [data_fixup_count]    ; drop count of entries
   437 00000221 BB[0000]                    mov bx,OFFSET data_fixup_flag wrt DGROUP    ; bx -> base of fixup flag array
   438 00000224 A1[0000]                    mov ax,[data_fixup_count] ; get count of fixups in data record
   439 00000227 D1E0                        shl ax,1                ; convert to word offset
   440 00000229 01C3                        add bx,ax               ; bx -> last used array element where data record offset of fixup stored
   441 0000022B 8B17                        mov dx,[bx]             ; dx holds data record offset
   442                                  
   443 0000022D 833E[0000]00                cmp word [ovl_code_id],0       ; see if relocation item write is for an overlay
   444 00000232 7405                        je  pl_1                ; no
   445 00000234 E8(0000)                    call    write_ovl_reloc ; write overlay file relocation entry
   446 00000237 EB03                        jmp SHORT pl_1a         ; bypass regular relocation entry handler
   447                                  
   448                                  pl_1:
   449 00000239 E80E01                      call    make_reloc_entry
   450                                  
   451                                  pl_1a:
   452 0000023C EBD8                        jmp SHORT pl_relloop    ; loop back and check for next item
   453                                  
   454                                  pl_2:
   455 0000023E E8(0000)                    call    write_bytes     ; write data to program's memory image
   456 00000241 C3                          ret
   457                                  proc2_ledata    ENDP
   458                                  
   459                                  ;*****************************
   460                                  ;* PROC2_LIDATA              *
   461                                  ;*****************************
   462                                  
   463                                  ; process lidata record
   464                                  ; upon entry cx == count of data bytes, [es:si] -> first data byte
   465                                  ; destroys ax,bx,cx,dx,di
   466                                  
   467                                  proc2_lidata    PROC
   468 00000242 31DB                        xor bx,bx               ; zero initial position in data record
   469 00000244 81F90002                    cmp cx,IDATA_BLK_MAX    ; check if iterated data block is too large
   470 00000248 7615                        jbe pli_2               ; no
   471                                  
   472 0000024A A1[0000]                    mov ax,WORD PTR [prev_pos_adj]    ; set file position adjustment to previous record position adjustment
   473 0000024D A3[0000]                    mov WORD PTR [file_pos_adj],ax
   474 00000250 A1[0200]                    mov ax,WORD PTR [prev_pos_adj+2]
   475 00000253 A3[0200]                    mov WORD PTR [file_pos_adj+2],ax
   476 00000256 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   477 00000259 B81F00                      mov ax,IDATA_BLK_SIZE_ERR   ; iterated data block larger than 512 bytes
   478 0000025C E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   479                                  
   480                                  pli_2:
   481 0000025F E305                        jcxz    pli_ret         ; no more bytes to write, all done
   482 00000261 E80900                      call    recurse_lidata  ; use recursion routine to extract data out of lidata record
   483 00000264 EBF9                        jmp SHORT pli_2         ; loop until no more bytes
   484                                  
   485                                  pli_ret:
   486 00000266 C706[0000]0000              mov word [data_fixup_count],0  ; re-init count of relocation items in array
   487 0000026C C3                          ret
   488                                  proc2_lidata    ENDP
   489                                  
   490                                  ;*****************************
   491                                  ;* RECURSE_LIDATA            *
   492                                  ;*****************************
   493                                  
   494                                  ; use recursion to get all data out of lidata record
   495                                  ; upon entry [es:si] -> current data byte, cx == size of data block,
   496                                  ; bx == position in record
   497                                  ; destroys all noncritical registers
   498                                  
   499                                  recurse_lidata  PROC
   500 0000026D 268A04                      mov al,[es:si]          ; get low byte of repeat count
   501 00000270 46                          inc si
   502 00000271 43                          inc bx                  ; bump position in record
   503 00000272 49                          dec cx                  ; decrement record length to parse
   504 00000273 39EE                        cmp si,bp               ; check boundary conditions
   505 00000275 7202                        jb  rl_2                ; okay
   506 00000277 31F6                        xor si,si               ; wrap to beginning of buffer
   507                                  rl_2:
   508 00000279 268A24                      mov ah,[es:si]          ; get high byte of repeat count
   509 0000027C 46                          inc si
   510 0000027D 43                          inc bx                  ; bump position in record
   511 0000027E 49                          dec cx                  ; decrement record length to parse
   512 0000027F 39EE                        cmp si,bp               ; check boundary conditions
   513 00000281 7202                        jb  rl_3                ; okay
   514 00000283 31F6                        xor si,si               ; wrap to beginning of buffer
   515                                  rl_3:
   516 00000285 A3[0400]                    mov [repeat_count],ax     ; save to memory variable
   517                                  
   518 00000288 268A04                      mov al,[es:si]          ; get low byte of block count
   519 0000028B 46                          inc si
   520 0000028C 43                          inc bx                  ; bump position in record
   521 0000028D 49                          dec cx                  ; decrement record length to parse
   522 0000028E 39EE                        cmp si,bp               ; check boundary conditions
   523 00000290 7202                        jb  rl_4                ; okay
   524 00000292 31F6                        xor si,si               ; wrap to beginning of buffer
   525                                  rl_4:
   526 00000294 268A24                      mov ah,[es:si]          ; get high byte of block count
   527 00000297 46                          inc si
   528 00000298 43                          inc bx                  ; bump position in record
   529 00000299 49                          dec cx                  ; decrement record length to parse
   530 0000029A 39EE                        cmp si,bp               ; check boundary conditions
   531 0000029C 7202                        jb  rl_5                ; okay
   532 0000029E 31F6                        xor si,si               ; wrap to beginning of buffer
   533                                  rl_5:
   534 000002A0 A3[0600]                    mov [block_count],ax      ; save to memory variable
   535                                  
   536 000002A3 56                          push    si              ; save buffer position
   537 000002A4 53                          push    bx              ; save record position
   538 000002A5 51                          push    cx              ; save record iterated data block length
   539                                  
   540                                  rl_reploop:
   541 000002A6 59                          pop cx                  ; restore record length
   542 000002A7 5B                          pop bx                  ; restore record position
   543 000002A8 5E                          pop si                  ; restore buffer position
   544 000002A9 56                          push    si              ; restore values to stack
   545 000002AA 53                          push    bx
   546 000002AB 51                          push    cx
   547                                  
   548 000002AC 833E[0600]00                cmp word [block_count],0       ; see if nested iterated data blocks
   549 000002B1 741D                        je  rl_data             ; no
   550                                  
   551                                  ; nested iterated data blocks
   552 000002B3 A1[0600]                    mov ax,[block_count]      ; get total number of blocks to loop through
   553                                  rl_blkloop:
   554 000002B6 50                          push    ax              ; save current number of blocks left to loop thru
   555 000002B7 FF36[0400]                  push    word [repeat_count]    ; save repeat value
   556 000002BB FF36[0600]                  push    word [block_count]     ; save block value
   557 000002BF E8ABFF                      call    recurse_lidata  ; nest down one level
   558 000002C2 8F06[0600]                  pop word [block_count]         ; restore block value
   559 000002C6 8F06[0400]                  pop word [repeat_count]        ; restore repeat value
   560 000002CA 58                          pop ax                  ; restore number of blocks left to loop thru
   561 000002CB 48                          dec ax                  ; one iteration completed
   562 000002CC 75E8                        jne rl_blkloop          ; loop is not complete, using Z flag from previous decrement
   563 000002CE EB6D                        jmp SHORT rl_end_reploop    ; loop is complete, end this iteration of the repeat loop
   564                                  
   565                                  ; block size is zero, data follows
   566                                  rl_data:
   567 000002D0 268A04                      mov al,[es:si]          ; get length of data to write
   568 000002D3 46                          inc si
   569 000002D4 43                          inc bx                  ; bump position in record
   570 000002D5 49                          dec cx                  ; decrement record length to parse
   571 000002D6 39EE                        cmp si,bp               ; check boundary conditions
   572 000002D8 7202                        jb  rl_6                ; okay
   573 000002DA 31F6                        xor si,si               ; wrap to beginning of buffer
   574                                  rl_6:
   575 000002DC 833E[0000]00                cmp word [data_fixup_count],0  ; see if any relocation table entries
   576 000002E1 743D                        je  rl_7                ; no
   577                                  
   578                                  ; possible relocation entries
   579 000002E3 50                          push    ax
   580 000002E4 89DA                        mov dx,bx
   581 000002E6 30E4                        xor ah,ah               ; zero high byte of data bytes
   582 000002E8 01C2                        add dx,ax               ; bx --> dx == range of bytes to check for relocation entries
   583 000002EA BF[0000]                    mov di,OFFSET data_fixup_flag wrt DGROUP    ; di -> base of fixup flag array
   584 000002ED A1[0000]                    mov ax,[data_fixup_count] ; get count of fixups in data record
   585                                  
   586 000002F0 48                          dec ax                  ; make count relative zero
   587 000002F1 D1E0                        shl ax,1                ; convert to word offset
   588 000002F3 01C7                        add di,ax               ; di -> last used array element where data record offset of fixup stored
   589                                  
   590                                  rl_reloc:
   591 000002F5 391D                        cmp [di],bx             ; check low bounds
   592 000002F7 7226                        jb  rl_6b               ; below lowest, done
   593 000002F9 3915                        cmp [di],dx             ; check high bounds
   594 000002FB 7317                        jae rl_6a               ; above highest bounds (equal to is out)
   595                                  
   596                                  ; make a relocation entry
   597 000002FD 52                          push    dx              ; save critical registers
   598 000002FE 57                          push    di
   599                                  
   600 000002FF 8B15                        mov dx,[di]             ; get record offset where relocation item goes
   601 00000301 29DA                        sub dx,bx               ; adjust to relative offset from start of data
   602                                  
   603 00000303 833E[0000]00                cmp word [ovl_code_id],0       ; see if relocation item write is for an overlay
   604 00000308 7405                        je  rel_rl2             ; no
   605 0000030A E8(0000)                    call    write_ovl_reloc ; write overlay file relocation entry
   606 0000030D EB03                        jmp SHORT rel_rl3       ; bypass regular relocation entry handler
   607                                  
   608                                  rel_rl2:
   609 0000030F E83800                      call    make_reloc_entry    ; make relocation item entry
   610                                  
   611                                  rel_rl3:
   612 00000312 5F                          pop di                  ; restore critical registers
   613 00000313 5A                          pop dx
   614                                  
   615                                  rl_6a:
   616 00000314 81FF[0000]                  cmp di,OFFSET data_fixup_flag wrt DGROUP    ; if equal than no more entries
   617 00000318 7405                        je  rl_6b               ; no more entries
   618 0000031A 83EF02                      sub di,2                ; back up one word array element
   619 0000031D EBD6                        jmp SHORT rl_reloc      ; loop back for next check
   620                                  
   621                                  rl_6b:
   622 0000031F 58                          pop ax
   623                                  
   624                                  ; write the data bytes
   625                                  rl_7:
   626 00000320 51                          push    cx              ; save record's total data length (in case of repeat loop termination)
   627 00000321 88C1                        mov cl,al               ; get data bytes to write in cl
   628 00000323 30ED                        xor ch,ch               ; zap high byte
   629 00000325 51                          push    cx              ; save data bytes written
   630 00000326 E8(0000)                    call    write_bytes     ; write the data bytes to program's memory image
   631 00000329 58                          pop ax                  ; get data bytes written
   632 0000032A 89C2                        mov dx,ax               ; save in dx
   633 0000032C 0306[0E00]                  add ax,WORD PTR [data_offset] ; add to data offset
   634 00000330 A3[0E00]                    mov WORD PTR [data_offset],ax ; update data offset low word
   635 00000333 8316[1000]00                adc WORD [data_offset+2],0    ; carry to high word
   636 00000338 59                          pop cx                  ; restore record's total data length (in case of repeat loop termination)
   637 00000339 29D1                        sub cx,dx               ; subtract off data bytes written
   638 0000033B 01D3                        add bx,dx               ; bump record position
   639                                  
   640                                  rl_end_reploop:
   641 0000033D FF0E[0400]                  dec word [repeat_count]        ; an iteration of the repeat loop was completed
   642                                  ;***    cmp repeat_count,0      ; see if loop is complete
   643 00000341 7403                        je  rl_end              ; yes
   644 00000343 E960FF                      jmp NEAR PTR rl_reploop ; no, go back for next iteration
   645                                  
   646                                  rl_end:
   647 00000346 83C406                      add sp,6                ; trash old record length, record and buffer position values on stack
   648 00000349 C3                          ret                     ; repeat loop complete, return to next highest level or proc2_lidata
   649                                  recurse_lidata  ENDP
   650                                  
   651                                  ;*****************************
   652                                  ;* MAKE_RELOC_ENTRY          *
   653                                  ;*****************************
   654                                  
   655                                  ; make relocation entry
   656                                  ; upon entry dx == record offset
   657                                  ; destroys ax,dx,di
   658                                  		; INP:	dword [data_offset] + dx -> relocation entry,
   659                                  		;	 including the segment (linear address)
   660                                  		;	word [data_segment] => relocation entry
   661                                  make_reloc_entry    PROC
   662 0000034A 53                          push    bx              ; save critical register
   663 0000034B 56                          push    si
   664 0000034C 06                          push    es
   665 0000034D A1[0000]                    mov ax,[alloc_relblk_ptr]
   666 00000350 09C0                        or  ax,ax               ; check if any relocation blocks were previously allocated
   667 00000352 751C                        jne mre_2               ; yes
   668                                  
   669                                  ; make initial relocation block allocation
   670 00000354 BB2000                      mov bx,REL_BLK_SIZE     ; number of paragraphs to allocate
   671 00000357 E8(0000)                    call    alloc_memory    ; get memory for block allocation
   672 0000035A A3[0000]                    mov [alloc_relblk_ptr],ax ; update last allocated block pointer
   673 0000035D A3[0000]                    mov [first_relblk_ptr],ax ; update first allocated block pointer
   674 00000360 8EC0                        mov es,ax               ; es -> block
   675 00000362 26C70600000000              mov WORD PTR [es:0],0   ; zero count of entries in block
   676 00000369 26C70602000000              mov WORD PTR [es:2],0   ; zero pointer to next entry
   677                                  
   678                                  mre_2:
   679 00000370 8EC0                        mov es,ax               ; es -> current block
   680 00000372 26833E00007F                cmp WORD PTR [es:0],REL_ITEM_COUNT  ; see if any free items in block
   681 00000378 7203                        jb  mre_3               ; yes
   682 0000037A E85300                      call    make_reloc_blk  ; no free entries in block, make a new block
   683                                  
   684                                  mre_3:
   685 0000037D 268B1E0000                  mov bx,[es:0]           ; get entry count
   686 00000382 43                          inc bx                  ; adjust for system info entry at beginning of block
   687 00000383 D1E3                        shl bx,1
   688 00000385 D1E3                        shl bx,1                ; make bx a doubleword offset (4 bytes/item)
   689 00000387 A1[0200]                    mov ax,[data_segment]
   690 0000038A 26894702                    mov [es:bx+2],ax        ; save segment of relocation entry
   691 0000038E A1[0E00]                    mov ax,WORD PTR [data_offset] ; get program offset of data low word
   692 00000391 8B3E[1000]                  mov di,WORD PTR [data_offset+2]   ; get program offset high word
   693 00000395 01D0                        add ax,dx               ; add in offset in data record
   694 00000397 83D700                      adc di,0                ; carry to high word, di:ax == program offset+record offset
   695 0000039A 31F6                        xor si,si
   696 0000039C 268B5702                    mov dx,[es:bx+2]        ; dx == relocation segment
   697 000003A0 51                      	push cx
   698 000003A1 B90400                  	mov cx, 4
   699                                  @@:
   700 000003A4 D1E2                        shl dx,1
   701 000003A6 D1D6                        rcl si,1                ; x2
   702 000003A8 E2FA                    	loop @B		; x16, si:dx == absolute byte value of data segment
   703 000003AA 59                      	pop cx
   704 000003AB 29D0                        sub ax,dx
   705 000003AD 19F7                        sbb di,si               ; di:ax == relocation entry offset, di should be zero
   706 000003AF 268907                      mov [es:bx],ax          ; save relocation item offset
   707                                  
   708 000003B2 26FF060000                  inc WORD PTR [es:0]     ; bump count of entries in relocation block
   709 000003B7 FF06[0000]                  inc word [number_reloc]        ; bump global count of relocation items
   710 000003BB 813E[0000]0080              cmp word [number_reloc],RELOC_MAX  ; check if too many relocation items
   711 000003C1 7704                        ja  mre_bounds          ; too many items
   712 000003C3 07                          pop es                  ; restore critical register
   713 000003C4 5E                          pop si
   714 000003C5 5B                          pop bx
   715 000003C6 C3                          ret                     ; done
   716                                  
   717                                  mre_bounds:
   718 000003C7 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   719 000003CA B81E00                      mov ax,RELOC_COUNT_ERR  ; more than 32768 .EXE file relocation table entries
   720 000003CD E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   721                                  make_reloc_entry    ENDP
   722                                  
   723                                  ;*****************************
   724                                  ;* MAKE_RELOC_BLK            *
   725                                  ;*****************************
   726                                  
   727                                  ; make relocation entry block
   728                                  ; return segment of block in es
   729                                  ; destroys ax,bx,es
   730                                  
   731                                  make_reloc_blk  PROC
   732 000003D0 52                          push    dx              ; save critical register
   733 000003D1 8B16[0000]                  mov dx,[alloc_relblk_ptr] ; keep previously last allocated block segment
   734 000003D5 BB2000                      mov bx,REL_BLK_SIZE     ; number of paragraphs to allocate
   735 000003D8 E8(0000)                    call    alloc_memory    ; get memory for block allocation
   736 000003DB A3[0000]                    mov [alloc_relblk_ptr],ax ; update last allocated block pointer
   737                                  
   738 000003DE 8EC2                        mov es,dx               ; es -> old block
   739 000003E0 26A30200                    mov [es:2],ax           ; update old block to point to new block
   740                                  
   741 000003E4 8EC0                        mov es,ax               ; es -> new block
   742 000003E6 26C70600000000              mov WORD PTR [es:0],0   ; zero count of entries in block
   743 000003ED 26C70602000000              mov WORD PTR [es:2],0   ; zero pointer to next entry
   744 000003F4 5A                          pop dx                  ; restore critical register
   745 000003F5 C3                          ret
   746                                  make_reloc_blk  ENDP
   747                                  
   748                                  END
