     1                                  ;*********************************************************************
     2                                  ;*   MLIMAGE1.ASM                                                    *
     3                                  ;*                                                                   *
     4                                  ;*   By:            Michael Devore                                   *
     5                                  ;*   Date:          12/30/92                                         *
     6                                  ;*   Model:         Small                                            *
     7                                  ;*   Version:       2.5                                              *
     8                                  ;*   Assembler:     MASM 5.0                                         *
     9                                  ;*   Environment:   MS-DOS 2.x+                                      *
    10                                  ;*                                                                   *
    11                                  ;*   memory image routines, part 1                                   *
    12                                  ;*                                                                   *
    13                                  ;*********************************************************************
    14                                  
    15                                  ;TITLE   WARPLINK mlimage1
    16                                  ;PAGE    50,80
    17                                  
    18                                  ;.MODEL  SMALL
    19                                  
    20                                  ;*****************************
    21                                  ;* Include files             *
    22                                  ;*****************************
    23                                  
    24                                  [list -]
    14                              <2> [list -]
    14                              <1> [list -]
    26                                  [list -]
    31                                       
    32                                  ;*****************************
    33                                  ;* Public declarations       *
    34                                  ;*****************************
    35                                  
    36                                  ; procedures
    37                                  PUBLIC  setup_exe_image,write_program,write_bytes,caseless_strcmp
    38                                  PUBLIC	compute_seg_frames
    39                                  public	check_com_cut
    40                                  
    41                                  ; variables
    42                                  PUBLIC  exe_handle,segment_start,segment_stop,true_seg_len
    43                                  
    44                                  ;*****************************
    45                                  ;* Data begins               *
    46                                  ;*****************************
    47                                  
    48                                  .DATA
    49                                  
    50                                  ;*****************************
    51                                  ;* External declarations     *
    52                                  ;*****************************
    53                                  
    54                                   extern align_ax_from_bl
    55                                  EXTRN   data_segment:WORD,data_offset:DWORD,filename:BYTE
    56                                  EXTRN   is_emsxms_ovl:BYTE
    57                                  EXTRN	filesize_text:BYTE
    58                                  EXTRN	first_clipmod_ptr:WORD,is_summer87:BYTE,is_clipper5:BYTE
    59                                  extern	skip_length
    60                                  
    61                                  ; initialized local variables
    62                                  
    63                                  ; byte values
    64                                  EVEN                        ; maximize speed on 8086 and better
    65 00000000 00                      stack_found DB  0           ; nonzero if stack segment encountered
    66 00000001 00                      EVEN
    67 00000002 00                      phase   DB  0               ; DOSSEG segment ordering phase
    68 00000003 00                      EVEN
    69 00000004 00                      com_end_flag    DB  0       ;  1 if $$_COM_END variable allocated, 2 if not used
    70 00000005 00                      EVEN
    71                                  
    72 00000006 00                      res_incflag DB  0           ; 1 if Clipper incremental link and current class 'CODE'
    73                                                              ; 2 if class 'SYMBOLS'
    74 00000007 00                      EVEN
    75 00000008 0000                    _wlcalc_pass:		dw 0
    76 0000000A 0000                    _wlcalc_maximum_pass:	dw 0
    77                                  
    78                                  EVEN
    79                                  ; doubleword values
    80 0000000C 00000000                segment_start   DD  0       ; start of segments
    81                                  
    82                                  ; structures
    83                                  EXE_HEADER_STRUC    STRUC
    84 00000000 ??                          eh_sig1 DB  ?           ; EXE file signature bytes
    85 00000001 ??                          eh_sig2 DB  ?
    86 00000002 ????                        eh_flen DW  ?           ; length of file module 512 */
    87 00000004 ????                        eh_fsize    DW  ?       ; size of file in 512-byte pages, including header
    88 00000006 ????                        eh_numrel   DW  ?       ; number of relocation items
    89 00000008 ????                        eh_hsize    DW  ?       ; size of header in paragraphs
    90 0000000A ????                        eh_minalloc DW  ?       ; minimum number of paragraphs needed above program
    91 0000000C ????                        eh_maxalloc DW  ?       ; maximum number of paragraphs needed above program
    92 0000000E ????                        eh_ss   DW  ?           ; SS at entry
    93 00000010 ????                        eh_sp   DW  ?           ; SP at entry
    94 00000012 ????                        eh_chksum   DW  ?       ; word checksum (unused
    95 00000014 ????                        eh_ip   DW  ?           ; contents of IP register at entry
    96 00000016 ????                        eh_cs   DW  ?           ; CS at entry
    97 00000018 ????                        eh_roff DW  ?           ; offset of first relocation item in file
    98 0000001A ??                          eh_ovnum    DB  ?       ; overlay number
    99 0000001B ??????                      eh_filler   DB  3 DUP (?)   ; not used
   100                                  EXE_HEADER_STRUC    ENDS
   101                                  
   102                                  exe_header:
   103                                  istruc EXE_HEADER_STRUC
   104                                  at eh_sig1
   105 00000010 4D                      exe_header.eh_sig1:	db 4dh
   106                                  at eh_sig2
   107 00000011 5A                      exe_header.eh_sig2:	db 5ah
   108                                  at eh_flen
   109                                  exe_header.eh_flen:
   110 00000012 00<rep 2h>              at eh_fsize
   111                                  exe_header.eh_fsize:
   112 00000014 00<rep 2h>              at eh_numrel
   113                                  exe_header.eh_numrel:
   114 00000016 00<rep 2h>              at eh_hsize
   115                                   global exe_header.eh_hsize
   116                                  exe_header.eh_hsize:
   117 00000018 00<rep 2h>              at eh_minalloc
   118                                  exe_header.eh_minalloc:
   119 0000001A 00<rep 2h>              at eh_maxalloc
   120 0000001C FFFF                    exe_header.eh_maxalloc:	dw 0ffffh
   121                                  at eh_ss
   122                                  exe_header.eh_ss:
   123 0000001E 00<rep 2h>              at eh_sp
   124                                  exe_header.eh_sp:
   125 00000020 00<rep 2h>              at eh_chksum
   126 00000022 0000                    exe_header.eh_chksum:	dw 0
   127                                  at eh_ip
   128                                  exe_header.eh_ip:
   129 00000024 00<rep 2h>              at eh_cs
   130                                  exe_header.eh_cs:
   131 00000026 00<rep 2h>              at eh_roff
   132 00000028 1E00                    exe_header.eh_roff:	dw 30
   133                                  at eh_ovnum
   134 0000002A 00                      exe_header.eh_ovnum:	db 0
   135                                  at eh_filler
   136                                  exe_header.eh_filler:
   137 0000002B 00<rep 3h>              iend
   138                                  
   139                                  EVEN
   140                                  _wlcalc_do_table:
   141 0000002E [7C00][EE12]            	dw string_div, _wlcalc_do_div
   142 00000032 [8000][3113]            	dw string_mul, _wlcalc_do_mul
   143 00000036 [8400][4A13]            	dw string_shr, _wlcalc_do_shr
   144 0000003A [8800][5613]            	dw string_shl, _wlcalc_do_shl
   145 0000003E [8C00][6213]            	dw string_xor, _wlcalc_do_xor
   146 00000042 [9000][6713]            	dw string_or, _wlcalc_do_or
   147 00000046 [9300][6C13]            	dw string_and, _wlcalc_do_and
   148 0000004A [9700][7113]            	dw string_clr, _wlcalc_do_clr
   149 0000004E [9B00][7A13]            	dw string_add, _wlcalc_do_add
   150 00000052 [A300][8013]            	dw string_subr, _wlcalc_do_subr	; must be before SUB
   151 00000056 [9F00][8313]            	dw string_sub, _wlcalc_do_sub
   152 0000005A [D400][8B13]            	dw string_itoa, _wlcalc_do_itoa
   153 0000005E [AC00]0200              	dw string_minussegrel, _wlcalc_do_minussegrel
   154 00000062 [B100]0100              	dw string_segrel, _wlcalc_do_segrel	; must be before SEG
   155 00000066 [A800]0000              	dw string_seg, _wlcalc_do_seg
   156 0000006A [D900]0800              	dw string_wrt, _wlcalc_do_wrt
   157                                  .ext:
   158 0000006E [CE00]0700              	dw string_opext, _wlcalc_do_opext
   159 00000072 [C100]0600              	dw string_minusextpara, _wlcalc_do_minusextpara	; must be before MINUSEXT
   160 00000076 [C600]0500              	dw string_extpara, _wlcalc_do_extpara	; must be before EXT
   161 0000007A [B800]0400              	dw string_minusext, _wlcalc_do_minusext
   162 0000007E [BD00]0300              	dw string_ext, _wlcalc_do_ext
   163 00000082 0000                    	dw 0
   164                                  
   165                                  _wlcalc_size_table:
   166 00000084 [EA00]0100              	dw string_byte, 1
   167 00000088 [F000]0200              	dw string_word, 2
   168 0000008C [E900]0300              	dw string_3byte, 3
   169 00000090 [EF00]0400              	dw string_dword, 4
   170 00000094 0000                    	dw 0
   171                                  
   172                                  .DATA?
   173                                  
   174                                  ; uninitialized local variables
   175                                  
   176                                  ; byte values
   177                                  EVEN
   178 00000000 ??                      res_occurred    DB  ?       ; nonzero flags a segment resolved in resolution pass
   179 00000001 ??                      EVEN
   180 00000002 ??                      using_class DB  ?           ; nonzero if resolving segments for a class, zero if no class selected yet
   181 00000003 ??                      EVEN
   182 00000004 ??                      _wlcalc_create_relocations:	db ?
   183                                  
   184 00000005 ??                      EVEN
   185                                  
   186                                  ; word values
   187 00000006 ????                    _wlcalc_obj_index:	dw ?
   188 00000008 ????                    _wlcalc_pubdef:		dw ?
   189 0000000A ????????                _wlcalc_wrt_pointer:	dd ?
   190 0000000E ????                    _wlcalc_offset:	dw ?
   191 00000010 ????                    _wlcalc_segment:	dw ?
   192 00000012 ????                    unresolved_segs DW  ?       ; count of segments still have their addresses resolved
   193 00000014 ????                    segdef_block_ptr    DW  ?   ; current pointer to segdef block
   194 00000016 ????                    entry_number    DW  ?       ; current entry in segdef block
   195 00000018 ????                    exe_handle  DW  ?           ; handle of executable file
   196 0000001A ????                    com_end_pubptr  DW  ?       ; pointer to $$_COM_END public declaration entry
   197 0000001C ????                    temp_buffer_size    DW  ?   ; size of temporary buffer
   198 0000001E ????                    temp_buffer_base    DW  ?   ; segment pointer to start of temporary buffer
   199 00000020 ????                    class_group DW  ?           ; group entry segment of class-setting segment, only used by DOSSEG
   200                                  
   201                                  ; doubleword values
   202 00000022 ????????                true_seg_len    DD  ?       ; true segment length (can be 10000h from Big bit)
   203 00000026 ????????                segment_stop    DD  ?       ; segment stop address
   204                                  
   205                                  ; byte strings
   206                                  symname_buffer	LABEL	BYTE
   206                              <1> symname_buffer :
   207 0000002A <res 80h>               class_name_field    DB  128 DUP (?) ; class name of segdef entry
   208 000000AA <res 80h>               group_name_field    DB  128 DUP (?) ; group name of segdef entry
   209                                  
   210                                  ;*****************************
   211                                  ;* Constant data             *
   212                                  ;*****************************
   213                                  
   214                                  .CONST
   215                                  
   216                                  ; constant strings in DOSSEG segment class type computation
   217                                  EVEN
   218 00000000 434F444500              codetext    DB  'CODE',0
   219 00000005 00                      EVEN
   220 00000006 4245474441544100        begdatatext DB  'BEGDATA',0
   221                                  EVEN
   222 0000000E 42535300                bsstext     DB  'BSS',0
   223                                  EVEN
   224 00000012 535441434B00            stacktext   DB  'STACK',0
   225                                  EVEN
   226 00000018 24245F434F4D5F454E-     com_end_text    DB  '$$_COM_END',0
   226 00000021 4400               
   227                                  
   228 00000023 5000                    maxalloc_len    DW  maxalloc_stop-maxalloc_warn
   229 00000025 0D0A4D6178696D756D-     maxalloc_warn   DB  CR,LF,'Maximum program allocation space less than minimum required, maximum adjusted.'
   229 0000002E 2070726F6772616D20-
   229 00000037 616C6C6F636174696F-
   229 00000040 6E207370616365206C-
   229 00000049 657373207468616E20-
   229 00000052 6D696E696D756D2072-
   229 0000005B 657175697265642C20-
   229 00000064 6D6178696D756D2061-
   229 0000006D 646A75737465642E   
   230                                  maxalloc_stop   equ   $
   231                                  
   232 00000075 574C43414C4300          string_wlcalc:	asciz "WLCALC"
   233 0000007C 44495600                string_div:	asciz "DIV"
   234 00000080 4D554C00                string_mul:	asciz "MUL"
   235 00000084 53485200                string_shr:	asciz "SHR"
   236 00000088 53484C00                string_shl:	asciz "SHL"
   237 0000008C 584F5200                string_xor:	asciz "XOR"
   238 00000090 4F5200                  string_or:	asciz "OR"
   239 00000093 414E4400                string_and:	asciz "AND"
   240 00000097 434C5200                string_clr:	asciz "CLR"
   241 0000009B 41444400                string_add:	asciz "ADD"
   242 0000009F 53554200                string_sub:	asciz "SUB"
   243 000000A3 5355425200              string_subr:	asciz "SUBR"
   244 000000A8 53454700                string_seg:	asciz "SEG"
   245                                  string_minussegrel:
   246 000000AC 4D494E5553              		db "MINUS"
   247 000000B1 53454752454C00          string_segrel:	asciz "SEGREL"
   248                                  string_minusext:
   249 000000B8 4D494E5553              		db "MINUS"
   250 000000BD 45585400                string_ext:	asciz "EXT"
   251                                  string_minusextpara:
   252 000000C1 4D494E5553              		db "MINUS"
   253 000000C6 4558545041524100        string_extpara:	asciz "EXTPARA"
   254 000000CE 4F5045585400            string_opext:	asciz "OPEXT"
   255 000000D4 49544F4100              string_itoa:	asciz "ITOA"
   256 000000D9 57525400                string_wrt:	asciz "WRT"
   257 000000DD 52455045415400          string_repeat:	asciz "REPEAT"
   258 000000E4 5041535300              string_pass:	asciz "PASS"
   259 000000E9 33                      string_3byte:	db "3"
   260 000000EA 4259544500              string_byte:	asciz "BYTE"
   261 000000EF 44                      string_dword:	db "D"
   262 000000F0 574F524400              string_word:	asciz "WORD"
   263                                  
   264                                  string_invalid_filename:
   265 000000F5 28496E76616C696420-     .:		asciz "(Invalid filename)"
   265 000000FE 66696C656E616D6529-
   265 00000107 00                 
   266                                  .size equ $ - .
   267                                  string_unknown_filename:
   268 00000108 28556E6B6E6F776E20-     .:		asciz "(Unknown filename)"
   268 00000111 66696C656E616D6529-
   268 0000011A 00                 
   269                                  .size equ $ - .
   270                                  
   271                                  ;*****************************
   272                                  ;* Code begins               *
   273                                  ;*****************************
   274                                  
   275                                  .CODE
   276                                  
   277                                  ;*****************************
   278                                  ;* External declarations     *
   279                                  ;*****************************
   280                                  
   281                                  ; procedures
   282                                  EXTRN   link_error:NEAR,dos_error:NEAR,alloc_memory:NEAR
   283                                  EXTRN   get_memory:NEAR,free_memory:NEAR,link_warning:NEAR
   284                                  EXTRN   zero_mem_image:NEAR,update_temp_file:NEAR,create_temp_file:NEAR
   285                                  EXTRN   temp_file_write:NEAR,dump_temp_file:NEAR
   286                                  EXTRN   map_segments:NEAR,map_groups:NEAR,error_read_buff_pos:NEAR
   287                                  EXTRN   get_pubdecl_entry:NEAR,add_pubdef_name:NEAR,find_pubdecl_entry:NEAR
   288                                  EXTRN   resolve_ovl_info:NEAR,write_vectors:NEAR,flush_ovl_page:NEAR
   289                                  EXTRN   ovl_file_write:NEAR,flush_reloc_array:NEAR
   290                                  EXTRN   res_ilfseg:NEAR,ilf_rewind:NEAR,write_clar_data:NEAR
   291                                  EXTRN   make_master_segblk:NEAR
   292                                  EXTRN   map_ems_page:NEAR,ems_ovl_to_file:NEAR,restore_ems_map:NEAR
   293                                  EXTRN	get_symbol_offset:NEAR,read_to_ems:NEAR
   294                                  
   295                                  ;*****************************
   296                                  ;* SETUP_EXE_IMAGE           *
   297                                  ;*****************************
   298                                  
   299                                  ; compute segment frame values and allocate disk or memory space for the
   300                                  ; executable image of the program
   301                                  ; destroys all registers except ds
   302                                  
   303                                  setup_exe_image PROC
   304 00000000 31C0                        xor ax,ax
   305 00000002 A3[0000]                    mov [ovl_data_id],ax      ; zero overlaid data flag
   306                                  
   307 00000005 E8(0000)                    call    get_memory      ; allocate memory for warplink use
   308                                  
   309 00000008 803E[0000]00                cmp byte [is_comfile],0        ; see if is a com file
   310 0000000D 7507                        jne sei_iscom           ; yes
   311                                  
   312                                  sei_no_com_end:
   313 0000000F C606[0400]02                mov byte [com_end_flag],2      ; flag that $$_COM_END variable is not used
   314 00000014 EB2E                        jmp SHORT sei_1         ; bypass $$_COM_END variable check
   315                                  
   316                                  ; com file, check if $$_COM_END was previously declared
   317                                  sei_iscom:
   318 00000016 BF[1800]                    mov di,OFFSET com_end_text wrt DGROUP   ; ds:di -> declaration name
   319 00000019 B001                        mov al,1                ; attempt public declaration
   320 0000001B E8(0000)                    call    get_pubdecl_entry   ; make or find previous public declaration entry
   321 0000001E 09C0                        or  ax,ax               ; see if segment is null
   322 00000020 74ED                        je  sei_no_com_end      ; yes, previous $$_COM_END definition
   323 00000022 A3[1A00]                    mov [com_end_pubptr],ax   ; save -> entry
   324 00000025 8EC0                        mov es,ax               ; es -> $$_COM_END declaration entry
   325 00000027 26803E0E0000                cmp BYTE PTR [es:14],0  ; see if this was the first ever use of $$_COM_END
   326 0000002D 74E0                        je  sei_no_com_end      ; yes, not used as an external anywhere, don't bother creating it
   327 0000002F 26C6060E0002                mov BYTE PTR [es:14],2  ; flag as public declaration
   328 00000035 BF[1800]                    mov di,OFFSET com_end_text wrt DGROUP   ; ds:di -> declaration name
   329 00000038 E8(0000)                    call    add_pubdef_name ; save public name
   330 0000003B 26A30400                    mov [es:4],ax           ; save offset pointer to name in pubdef names block
   331 0000003F 2689160600                  mov [es:6],dx           ; save segment pointer to name in pubdef names block
   332                                  
   333                                  sei_1:
   334 00000044 833E[0000]00                cmp word [ovl_count],0         ; see if any overlays
   335 00000049 7406                        je  sei_1a              ; no
   336 0000004B E8(0000)                    call    make_master_segblk  ; create block holding entries for all master segdefs of overlaid segparts
   337 0000004E E8(0000)                    call    resolve_ovl_info    ; resolve all overlay information, create overlay file
   338                                  
   339                                  sei_1a:
   340 00000051 E8DB00                      call    compute_seg_frames
   341                                  
   342                                  sei_1b:
   343 00000054 E8(0000)                    call    free_memory     ; de-allocate unused memory
   344 00000057 A1[2200]                	mov ax, word [true_seg_len]	; last segment is empty ?
   345 0000005A 0B06[2400]              	or ax, word [true_seg_len + 2]	; set ZF
   346 0000005E A1[2600]                    mov ax,WORD PTR [segment_stop]    ; get final segment stop low word
   347 00000061 8B1E[2800]                  mov bx,WORD PTR [segment_stop+2]  ; get final segment stop high word
   348 00000065 7406                    	jz @F				; yes last segment is empty -->
   349 00000067 83C001                      add ax,1                ; add one to value to get total program size
   350 0000006A 83D300                      adc bx,0                ; adjust high word
   351                                  @@:
   352 0000006D A3[0000]                    mov WORD PTR [image_size],ax  ; save low word of size
   353 00000070 891E[0200]                  mov WORD PTR [image_size+2],bx    ; save high word of size
   354                                  
   355 00000074 B448                        mov ah,48h              ; allocate memory
   356 00000076 BBFFFF                      mov bx,0ffffh           ; force request to fail, function will return largest available block
   357 00000079 CD21                        int 21h
   358 0000007B 83F808                      cmp ax,8                ; insufficient memory error is expected
   359 0000007E 7403                        je sei_2
   360                                  
   361                                  sei_todos_err:
   362 00000080 E9(0000)                    jmp NEAR PTR dos_error  ; other errors are fatal
   363                                  
   364                                  sei_2:
   365 00000083 81FB0005                    cmp bx,500h             ; block size must be >=20K (500h paragraphs)
   366 00000087 76F7                        jbe sei_todos_err       ; not enough memory for building executable, ax holds insufficent memory error value
   367                                  
   368 00000089 89D8                        mov ax,bx
   369 0000008B 2D0004                      sub ax,400h             ; must leave at least 16K for i/o buffers and remaining tables
   370 0000008E 31D2                        xor dx,dx               ; dx:ax will hold bytes of of space available
   371 00000090 B90400                  	mov cx, 4
   372                                  @@:
   373 00000093 D1E0                        shl ax,1                ; convert paragraphs available in ax into bytes in dx:ax
   374 00000095 D1D2                        rcl dx,1                ; x2
   375 00000097 E2FA                    	loop @B			; x16, paragraph converted to bytes
   376 00000099 3B16[0200]                  cmp dx,WORD PTR [image_size+2]    ; compare high word of space available to image size
   377 0000009D 7504                    	jne @F
   378 0000009F 3B06[0000]                  cmp ax,WORD PTR [image_size]  ; compare low word of space available to image size
   379                                  @@:
   380 000000A3 730A                        jae sei_inmemory        ; enough available space to place image in memory
   381                                  				; too little space to build executable in memory
   382                                  sei_ondisk:
   383 000000A5 C606[0000]01                mov BYTE [is_ondisk],1    ; flag that image is on disk
   384 000000AA E8(0000)                    call    create_temp_file    ; create temporary file for executable image
   385 000000AD EB39                        jmp SHORT sei_4         ; bypass memory image code
   386                                  
   387                                  sei_inmemory:
   388 000000AF D006[0000]              	rol byte [is_temp_forced], 1
   389 000000B3 72F0                    	jc sei_ondisk
   390 000000B5 C606[0000]01                mov BYTE [is_inmem],1     ; flag that image is in memory
   391 000000BA 8B1E[0000]                  mov bx,WORD PTR [image_size]  ; get low word of image size
   392 000000BE 83C30F                      add bx,15               ; round up for paragraph computation
   393 000000C1 8B16[0200]                  mov dx,WORD PTR [image_size+2]    ; get high word of image size
   394 000000C5 83D200                      adc dx,0                ; carry to high word
   395                                  
   396                                  ; convert image size in dx:bx to paragraphs
   397 000000C8 B90400                  	mov cx, 4
   398                                  @@:
   399 000000CB D1EA                        shr dx,1
   400 000000CD D1DB                        rcr bx,1                ; /2
   401 000000CF E2FA                        loop @B			; 4 times / 2 = / 16
   402                                  				; dx should be zero by the final shift
   403                                  
   404 000000D1 B448                        mov ah,48h              ; allocate memory
   405 000000D3 CD21                        int 21h
   406 000000D5 7303                        jnc sei_3               ; no errors
   407 000000D7 E9(0000)                    jmp NEAR PTR dos_error  ; any error is fatal
   408                                  
   409                                  sei_3:
   410 000000DA A3[0000]                    mov [image_mem_ptr],ax    ; save pointer to memory image
   411 000000DD 8B1E[0000]                  mov bx,WORD PTR [image_size]  ; get low word of image size to zero
   412 000000E1 8B16[0200]                  mov dx,WORD PTR [image_size+2]    ; get high word of image size to zero
   413 000000E5 E8(0000)                    call    zero_mem_image  ; fill memory image with zeros
   414                                  
   415                                  sei_4:
   416 000000E8 833E[0000]00                cmp word [ovl_count],0         ; see if any overlays
   417 000000ED 7409                        je  sei_5               ; no
   418 000000EF E8(0000)                    call    get_memory      ; allocate memory for warplink use
   419 000000F2 E8(0000)                    call    write_vectors   ; write vector values to overlay class segments
   420 000000F5 E8(0000)                    call    free_memory     ; de-allocate unused memory
   421                                  
   422                                  ;if $$_COM_END variable exists, put program size at its location
   423                                  sei_5:
   424 000000F8 803E[0400]01                cmp byte [com_end_flag],1      ; see if $$_COM_END variable declared
   425 000000FD 752F                        jne sei_ret             ; no
   426                                  
   427 000000FF A1[1A00]                    mov ax,[com_end_pubptr]
   428 00000102 8EC0                        mov es,ax               ; es -> $$_COM_END public declaration entry
   429 00000104 26A10800                    mov ax,[es:8]           ; get public offset
   430 00000108 A3[0000]                    mov WORD PTR [data_offset],ax ; store in data_offset variable for write_bytes procedure
   431 0000010B 31C0                        xor ax,ax
   432 0000010D A3[0200]                    mov WORD PTR [data_offset+2],ax   ; zero high word of data_offset
   433 00000110 26A10000                    mov ax,[es:0]           ; get pointer to segment partition entry
   434 00000114 8EC0                        mov es,ax               ; es -> segment partition entry
   435 00000116 268E060400                  mov es,[es:4]           ; es -> master segdef entry of $$_COM_END variable
   436 0000011B 26A10200                    mov ax,[es:2]           ; get segment offset
   437 0000011F 0106[0000]                  add WORD PTR [data_offset],ax ; add in segment offset to data_offset
   438 00000123 BE[0000]                    mov si,OFFSET image_size wrt DGROUP ; get image size
   439 00000126 1E                      	push	ds
   440 00000127 07                      	pop	es					; es:si -> image_size byte values
   441 00000128 B90200                      mov cx,2                ; write two bytes
   442 0000012B E88A14                      call    write_bytes     ; write 'em
   443                                  
   444                                  sei_ret:
   445 0000012E C3                          ret
   446                                  setup_exe_image ENDP
   447                                  
   448                                  ;*****************************
   449                                  ;* COMPUTE_SEG_FRAMES        *
   450                                  ;*****************************
   451                                  
   452                                  ; compute segment frame values
   453                                  ; destroys all registers except ds
   454                                  
   455                                  compute_seg_frames  PROC
   456 0000012F A1[0000]                    mov ax,[seg_count]
   457 00000132 A3[1200]                    mov [unresolved_segs],ax  ; init count of unresolved address segments
   458                                  
   459 00000135 803E[0000]00                cmp byte [is_anyovls],0        ; see if any overlaid modules specified
   460 0000013A 7531                    	jne	csf_res3			; yes
   461                                  
   462                                  csf_1:
   463 0000013C C606[0000]01                mov byte [res_occurred],1      ; init flag on to avoid error message
   464                                  
   465                                  csf_resloop:
   466 00000141 833E[1200]00                cmp word [unresolved_segs],0   ; check if all segments have been resolved
   467 00000146 7503                        jne csf_2               ; not yet
   468 00000148 E9CC02                      jmp NEAR PTR csf_res_done   ; yes, all segment addresses resolved
   469                                  
   470                                  csf_2:
   471 0000014B 803E[0000]00                cmp byte [res_occurred],0      ; see if segment resolved this pass
   472 00000150 751B                        jne csf_res3            ; yes
   473 00000152 803E[0000]00                cmp byte [is_dosseg],0         ; see if dosseg switch set
   474 00000157 7509                        jne csf_res2            ; yes
   475                                  
   476                                  ; no segment resolved last pass and not using DOSSEG segment ordering, internal error
   477                                  csf_internal:
   478 00000159 B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
   479 0000015C B90100                      mov cx,1                ; internal error value
   480 0000015F E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   481                                  
   482                                  csf_res2:
   483 00000162 FE06[0200]                  inc byte [phase]               ; bump phase of segment ordering
   484 00000166 803E[0200]06                cmp byte [phase],6             ; see if phase out of bounds
   485 0000016B 73EC                        jae csf_internal        ; yes, out of bounds
   486                                  
   487                                  csf_res3:
   488 0000016D 31C0                        xor ax,ax
   489 0000016F A3[1600]                    mov [entry_number],ax     ; init entry number
   490                                  
   491                                  csf_res4:
   492 00000172 A1[0000]                    mov ax,[first_segdefblk_ptr]
   493 00000175 A3[1400]                    mov [segdef_block_ptr],ax ; init current pointer to segdef block
   494 00000178 30C0                        xor al,al
   495 0000017A A2[0000]                    mov [res_occurred],al     ; reset segment resolution flag
   496 0000017D A2[0200]                    mov [using_class],al      ; init using class name flag
   497                                  
   498                                  csf_segblk_loop:
   499 00000180 A1[1400]                    mov ax,[segdef_block_ptr]
   500 00000183 09C0                        or  ax,ax               ; check if any more segdef entries
   501 00000185 74BA                        je  csf_resloop         ; no, move to next segment
   502 00000187 8EC0                        mov es,ax               ; es -> segdef entry
   503                                  
   504 00000189 A1[1600]                    mov ax,[entry_number]     ; get current entry number
   505 0000018C 83F820                      cmp ax,SEG_DEFENT_COUNT ; check if any room for more entries in block
   506 0000018F 720E                        jb  csf_3               ; yes
   507 00000191 26A10200                    mov ax,[es:2]           ; point to next block
   508 00000195 A3[1400]                    mov [segdef_block_ptr],ax ; save back to memory variable
   509 00000198 31C0                        xor ax,ax
   510 0000019A A3[1600]                    mov [entry_number],ax     ; reinit entry number
   511 0000019D EBE1                        jmp SHORT csf_segblk_loop  ; loop back for next block entry
   512                                  
   513                                  csf_3:
   514 0000019F 263B060000                  cmp ax,[es:0]           ; see if any more entries in block
   515 000001A4 739B                        jae csf_resloop         ; no, break out to main segment resolution loop
   516                                  
   517                                  ; get an entry from the current block
   518                                  csf_4:
   519 000001A6 8B1E[1600]                  mov bx,[entry_number]     ; get entry number
   520 000001AA D1E3                        shl bx,1                ; each entry takes up two paragraphs
   521 000001AC 8CC0                        mov ax,es               ; get block segment address
   522 000001AE 01C3                        add bx,ax               ; get entry's segment value
   523 000001B0 43                          inc bx                  ; adjust for block system info size of 1 paragraph
   524 000001B1 8EC3                        mov es,bx               ; es -> segdef entry
   525                                  
   526 000001B3 26803E1B0000                cmp BYTE PTR [es:27],0  ; check segment resolution flag
   527 000001B9 7406                        je  csf_5               ; segment not yet resolved
   528 000001BB FF06[1600]                  inc word [entry_number]        ; bump to next segdef entry
   529 000001BF EBBF                        jmp SHORT csf_segblk_loop     ; loop back to check next segdef entry
   530                                  
   531                                  csf_5:
   532 000001C1 BF[2A00]                    mov di,OFFSET class_name_field wrt DGROUP
   533 000001C4 268B360C00                  mov si,[es:12]          ; get segdef entry class name offset into lnames block
   534 000001C9 83C608                      add si,8                ; adjust past two doubleword pointers at beginning of lnames entry
   535 000001CC 268B1E0E00                  mov bx,[es:14]          ; get segdef entry class name segment into lnames block
   536                                  
   537 000001D1 8CDA                        mov dx,ds               ; save data segment
   538 000001D3 8EDB                        mov ds,bx               ; ds:si -> segdef entry class name
   539 000001D5 8CC3                        mov bx,es               ; save pointer to segdef entry
   540 000001D7 8EC2                        mov es,dx               ; es:di -> WarpLink data class name field
   541                                  
   542 000001D9 26803E[0200]00              cmp byte [es:using_class],0    ; check if class selected yet
   543 000001DF 7403                        je  csf_noclass         ; no
   544 000001E1 E9CD00                      jmp NEAR PTR csf_6      ; yes
   545                                  
   546                                  ; no class selected yet
   547                                  csf_noclass:
   548 000001E4 26803E[0400]00              cmp byte [es:com_end_flag],0   ; see $$_COM_END variable used and not allocated yet
   549 000001EA 7529                        jne csf_5a              ; no
   550 000001EC E8D514                      call    get_class_type  ; get class type, returned in al
   551 000001EF 08C0                        or  al,al               ; see if class CODE
   552 000001F1 7522                        jne csf_5a              ; no
   553                                  
   554                                  ; allocate room for $$_COM_END variable at end of segment
   555 000001F3 26C606[0400]01              mov byte [es:com_end_flag],1   ; yes, set com_end_flag
   556 000001F9 1E                          push    ds              ; save critical register
   557 000001FA 8EDB                        mov ds,bx               ; ds -> segdef entry
   558 000001FC 8B0E0600                    mov cx,[6]           ; get previous segment length
   559                                  
   560                                  ;*** check for segment length overflow after 2-byte addition?
   561                                  
   562 00000200 8306060002                  add WORD PTR [6],2   ; adjust length by two bytes for $$_COM_END variable
   563 00000205 A11600                      mov ax,[22]          ; get pointer to first segment partition entry
   564 00000208 268E1E[1A00]                mov ds,[es:com_end_pubptr]    ; ds -> $$_COM_END declaration entry
   565 0000020D A30000                      mov [0],ax           ; update segment pointer to segdef partition entry
   566 00000210 890E0800                    mov [8],cx           ; offset of variable is previous end of segment
   567 00000214 1F                          pop ds                  ; restore critical register
   568                                  
   569                                  csf_5a:
   570 00000215 26803E[0000]00              cmp byte [es:is_dosseg],0      ; see if DOSSEG segment ordering in force
   571 0000021B 7430                        je  csf_clname_loop     ; no
   572                                  
   573                                  ; generate proper DOSSEG segment ordering
   574 0000021D E8A414                      call    get_class_type  ; get class type, returned in al
   575 00000220 263A06[0200]                cmp al,[es:phase]         ; see if phase matches type
   576 00000225 7513                        jne to_csf_restore      ; no
   577 00000227 3C04                        cmp al,4                ; see if class BSS
   578 00000229 7511                        jne csf_not_bss         ; no
   579 0000022B 26833E[0000]00              cmp word [es:_edata_segaddr],0 ; see if beginning BSS address set yet
   580 00000231 751A                        jne csf_clname_loop     ; yes
   581 00000233 26891E[0000]                mov [es:_edata_segaddr],bx    ; keep segdef entry segment pointer to BSS
   582 00000238 EB13                        jmp SHORT csf_clname_loop
   583                                  
   584                                  to_csf_restore:
   585 0000023A EB78                        jmp NEAR PTR csf_restore
   586                                  
   587                                  csf_not_bss:
   588 0000023C 3C05                        cmp al,5                ; see if class STACK
   589 0000023E 750D                        jne csf_clname_loop     ; no
   590 00000240 26833E[0000]00              cmp word [es:_end_segaddr],0   ; see if beginning STACK address set yet
   591 00000246 7505                        jne csf_clname_loop     ; yes
   592 00000248 26891E[0000]                mov [es:_end_segaddr],bx  ; keep segdef entry segment pointer to BSS
   593                                  
   594                                  ; select a class, use entry class name
   595                                  csf_clname_loop:
   596 0000024D A4                          movsb                   ; transfer a char from entry class name to current class name
   597 0000024E 807CFF00                    cmp BYTE PTR [si-1],0   ; zero byte signals end of transfer
   598 00000252 75F9                        jne csf_clname_loop     ; nonzero, keep looping
   599 00000254 26C606[0200]01              mov byte [es:using_class],1    ; flag that a class is in use
   600                                  
   601 0000025A 26803E[0000]00              cmp byte [es:is_clpinc],0      ; see if Clipper incremental link in process
   602 00000260 7439                        je  csf_5b              ; no
   603 00000262 817CFB434F                  cmp word [si-5], "CO"
   604 00000267 750F                        jne csf_chksym          ; not class 'CODE'
   605 00000269 817CFD4445                  cmp word [si-3], "DE"
   606 0000026E 7508                        jne csf_chksym          ; not class 'CODE'
   607 00000270 26C606[0600]01              mov byte [es:res_incflag],1    ; set incremental link segment resolution flag for CODE
   608 00000276 EB29                        jmp SHORT csf_5c
   609                                  
   610                                  ; check if class 'SYMBOLS'
   611                                  csf_chksym:
   612 00000278 817CF85359                  cmp word [si-8], "SY"
   613 0000027D 751C                        jne csf_5b              ; not class 'SYMBOLS'
   614 0000027F 817CFA4D42                  cmp word [si-6], "MB"
   615 00000284 7515                        jne csf_5b
   616 00000286 817CFC4F4C                  cmp word [si-4], "OL"
   617 0000028B 750E                        jne csf_5b
   618 0000028D 807CFE53                    cmp BYTE PTR [si-2],'S'
   619 00000291 7508                        jne csf_5b
   620 00000293 26C606[0600]02              mov byte [es:res_incflag],2    ; set incremental link segment resolution flag for SYMBOLS
   621 00000299 EB06                        jmp SHORT csf_5c
   622                                  
   623                                  ; not proper class
   624                                  csf_5b:
   625 0000029B 26C606[0600]00              mov byte [es:res_incflag],0    ; zero incremental link segment resolution flag
   626                                  
   627                                  csf_5c:
   628 000002A1 8CC2                        mov dx,es               ; save es -> WarpLink data
   629 000002A3 8EC3                        mov es,bx               ; es -> segdef entry
   630 000002A5 26A11000                    mov ax,[es:16]          ; get group entry segment, if any
   631 000002A9 8EC2                        mov es,dx               ; es -> WarpLink data
   632 000002AB 26A3[2000]                  mov [es:class_group],ax   ; save group entry segment of class-setting segment, only used by DOSSEG
   633 000002AF EB30                        jmp SHORT csf_7         ; bypass class selected code
   634                                  
   635                                  ; class has already been selected
   636                                  csf_6:
   637 000002B1 A6                          cmpsb                   ; compare a entry class name char to current class name char
   638 000002B2 740B                        je  csf_6a              ; okay so far
   639                                  
   640                                  csf_restore:
   641 000002B4 06                      	push	es
   642 000002B5 1F                      	pop	ds					; restore ds -> WarpLink's data
   643 000002B6 8EC3                        mov es,bx               ; restore es -> segdef entry
   644 000002B8 FF06[1600]                  inc word [entry_number]        ; bump to next segdef entry
   645 000002BC E9C1FE                      jmp NEAR PTR csf_segblk_loop    ; loop back to check next segdef entry
   646                                  
   647                                  csf_6a:
   648 000002BF 268A45FF                    mov al,[es:di-1]        ; two matching zero bytes signals end of compare
   649 000002C3 0A44FF                      or al,[si-1]
   650 000002C6 75E9                        jne csf_6               ; nonzero, keep looping
   651                                  
   652                                  ; now, if the DOSSEG switch is tripped, compare and see if the group
   653                                  ; entries match.  If not, then do not group them together.
   654 000002C8 26803E[0000]00              cmp byte [es:is_dosseg],0      ; see if DOSSEG segment ordering in force
   655 000002CE 7411                        je  csf_7               ; no
   656                                  
   657 000002D0 8CC2                        mov dx,es               ; save es -> WarpLink data
   658 000002D2 8EC3                        mov es,bx               ; es -> segdef entry
   659 000002D4 26A11000                    mov ax,[es:16]          ; get group entry segment, if any
   660 000002D8 8EC2                        mov es,dx               ; es -> WarpLink data
   661 000002DA 263B06[2000]                cmp ax,[es:class_group]   ; see if group entry segment matches class-setting segment group
   662 000002DF 75D3                        jne csf_restore         ; no, don't use this segment
   663                                  
   664                                  csf_7:
   665 000002E1 06                      	push	es
   666 000002E2 1F                      	pop	ds					; restore ds -> WarpLink data
   667 000002E3 8EC3                        mov es,bx               ; restore es -> segdef entry
   668 000002E5 268A161A00                  mov dl,[es:26]          ; dl holds acbp byte
   669 000002EA 88D6                        mov dh,dl
   670 000002EC 80E6E0                      and dh,0e0h             ; dh holds align field
   671 000002EF 26C6061B0001                mov BYTE PTR [es:27],1  ; flag that this segment was resolved
   672 000002F5 C606[0000]01                mov byte [res_occurred],1      ; flag that a segment was resolved this pass
   673 000002FA FF0E[1200]                  dec word [unresolved_segs]     ; decrement number of unresolved segments
   674                                  
   675 000002FE 08F6                        or  dh,dh               ; check if absolute frame address, align field==0
   676 00000300 7503                        jne csf_8               ; not absolute, resolve segment
   677                                  
   678                                  ; absolute segment, do not resolve segment
   679 00000302 E90B01                      jmp NEAR PTR csf_next_entry ; bump entry count and reloop
   680                                  
   681                                  ; not an absolute frame address resolve segment address
   682                                  csf_8:
   683 00000305 A1[0C00]                    mov ax, word [segment_start] ; get low word of segment start
   684 00000308 88F3                        mov bl, dh			; = acbp byte
   685 0000030A E8(0000)                    call align_ax_from_bl
   686                                  
   687                                  ; ax holds amount to add to segment start
   688                                  csf_adj_segstart:
   689 0000030D 0106[0C00]                  add WORD PTR [segment_start],ax   ; adjust low word
   690 00000311 8316[0E00]00                adc WORD [segment_start+2],0  ; add in carry from low word
   691                                  
   692                                  csf_10a:
   693 00000316 A1[0C00]                    mov ax,WORD PTR [segment_start]
   694 00000319 26A30200                    mov [es:2],ax           ; save segment's start address low word
   695 0000031D A1[0E00]                    mov ax,WORD PTR [segment_start+2]
   696 00000320 26A30400                    mov [es:4],ax           ; save segment's start address high word
   697                                  
   698 00000324 A0[0600]                    mov al,[res_incflag]
   699 00000327 08C0                        or  al,al               ; see if should resolve incremental link segment info
   700 00000329 7405                        je  csf_10b             ; no
   701 0000032B 2401                        and al,1                ; zero al passed parameter if SYMBOLS (value of 2)
   702 0000032D E8(0000)                    call    res_ilfseg      ; resolve segment information in ILF file
   703                                  
   704                                  csf_10b:
   705 00000330 88D0                        mov al,dl               ; get acbp byte
   706 00000332 83E002                      and ax,2                ; check big bit status
   707 00000335 D1E8                        shr ax,1                ; make word value from bit either 1 or 0
   708 00000337 268B1E0600                  mov bx,[es:6]           ; get segment length from segdef entry
   709 0000033C 891E[2200]                  mov WORD PTR [true_seg_len],bx    ; save low word of segment length
   710 00000340 A3[2400]                    mov WORD PTR [true_seg_len+2],ax  ; save high word of segment length
   711 00000343 88D6                        mov dh,dl               ; get acbp byte
   712 00000345 80E61C                      and dh,1ch              ; get combine field
   713 00000348 80FE14                      cmp dh,14h              ; check if segment is a stack segment
   714 0000034B 7402                        je  csf_11              ; yes, leave nonzero to flag stack segment
   715 0000034D 30F6                        xor dh,dh               ; zero dh to flag not at stack segment
   716                                  
   717                                  csf_11:
   718 0000034F 0836[0000]                  or  [stack_found],dh      ; track whether a stack segment is in the program
   719 00000353 80E301                      and bl,1                ; check if segment length is odd
   720 00000356 7421                        je  csf_12              ; no
   721 00000358 08F6                        or  dh,dh               ; check if segment is stack combine type
   722 0000035A 741D                        je  csf_12              ; no
   723                                  
   724                                  ; stack segment cannot have odd byte length
   725 0000035C 26FF060600                  inc WORD PTR [es:6]     ; bump segment length by one
   726 00000361 26833E060000                cmp WORD PTR [es:6],0   ; check if overflowed to zero
   727 00000367 7506                        jne csf_11a             ; no
   728 00000369 26800E1A0002                or  BYTE PTR [es:26],2  ; set big bit in acbp byte
   729                                  
   730                                  csf_11a:
   731 0000036F 8306[2200]01                add WORD [true_seg_len],1 ; bump true segment length by one byte adjustment
   732 00000374 8316[2200]00                adc WORD [true_seg_len],0 ; carry bit to high word
   733                                  
   734                                  ;*** check for segment length overflow?
   735                                  
   736                                  csf_12:
   737 00000379 08F6                        or  dh,dh               ; check if stack combine type
   738 0000037B 7437                        je csf_13               ; no
   739 0000037D 803E[0000]00                cmp byte [is_comfile],0        ; check if .COM file type
   740 00000382 7530                        jne csf_13              ; yes
   741                                  
   742                                  ; set up EXE initial stack values
   743 00000384 A1[2400]                    mov ax,WORD PTR [true_seg_len+2]  ; check that stack segment is < 64K
   744 00000387 09C0                        or  ax,ax
   745 00000389 7409                        je  csf_12a             ; not 64K
   746                                  
   747                                  ; stack exceeds 64K-2 bytes
   748                                  csf_stack_err:
   749 0000038B BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
   750 0000038E B81400                      mov ax,STACK_SIZE_ERR   ; stack segment too big
   751 00000391 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   752                                  
   753                                  csf_12a:
   754 00000394 833E[2200]FE                cmp WORD [true_seg_len],65534 ; check that stack segment is < 64K-2
   755 00000399 77F0                        ja  csf_stack_err       ; stack segment is too big
   756                                  
   757                                  ; check program's initial SS:SP value
   758 0000039B A1[0C00]                    mov ax,WORD PTR [segment_start]   ; get low word of start in ax
   759 0000039E 8B1E[0E00]                  mov bx,WORD PTR [segment_start+2] ; get high word of start in bx
   760 000003A2 B90400                  	mov cx, 4
   761                                  @@:
   762 000003A5 D1EB                        shr bx,1
   763 000003A7 D1D8                        rcr ax,1                ; /2
   764 000003A9 E2FA                    	loop @B			; / 16
   765                                  
   766                                  ; ax == segment frame paragraph (segment start/16)
   767 000003AB A3[0000]                    mov [stack_segval],ax     ; save initial SS
   768 000003AE A1[2200]                    mov ax,WORD PTR [true_seg_len]    ; get end of stack segment (high word is zero)
   769 000003B1 A3[0000]                    mov [stack_offval],ax     ; save initial SP
   770                                  
   771                                  ; compute segment stop address (segment_start+true_seg_len-1)
   772                                  csf_13:
   773 000003B4 A1[0C00]                    mov ax,WORD PTR [segment_start]
   774 000003B7 0306[2200]                  add ax,WORD PTR [true_seg_len]    ; ax contains low word of sum
   775 000003BB 8B1E[0E00]                  mov bx,WORD PTR [segment_start+2]
   776 000003BF 131E[2400]                  adc bx,WORD PTR [true_seg_len+2]  ; bx contains high word of sum
   777 000003C3 89C1                        mov cx,ax
   778 000003C5 09D9                        or  cx,bx                       ; see if segment stop address is zero (zero length starting segment)
   779 000003C7 740E                        je  csf_zerolen_seg             ; yes, zero the segment stop
   780 000003C9 83E801                      sub ax,1                        ; subtract one from value
   781 000003CC 83DB00                      sbb bx,0                        ; borrow from high word
   782                                  
   783                                  ; bx:ax == segment stop value
   784 000003CF 3B1E[0E00]                  cmp bx,WORD PTR [segment_start+2] ; check that segment stop>=segment length in high word
   785 000003D3 7711                        ja  csf_newstop                 ; yes
   786 000003D5 7409                        je  csf_14                      ; maybe, check low word
   787                                  
   788                                  csf_zerolen_seg:
   789 000003D7 8B1E[0E00]                  mov bx,WORD PTR [segment_start+2] ; make segment stop = segment length
   790 000003DB A1[0C00]                    mov ax,WORD PTR [segment_start]
   791 000003DE EB06                        jmp SHORT csf_newstop           ; bypass low word check
   792                                  
   793                                  csf_14:
   794 000003E0 3B06[0C00]                  cmp ax,WORD PTR [segment_start]   ; check that segment stop>=segment length in low word
   795 000003E4 72F1                        jb csf_zerolen_seg              ; no, adjust segment stop
   796                                  
   797                                  csf_newstop:
   798 000003E6 A3[2600]                    mov WORD PTR [segment_stop],ax    ; update segment stop variable
   799 000003E9 891E[2800]                  mov WORD PTR [segment_stop+2],bx
   800                                  
   801 000003ED 803E[0000]00                cmp byte [is_mapfile],0                ; see if need to write segments to map file
   802 000003F2 7403                        je  csf_15                      ; no
   803 000003F4 E8(0000)                    call    map_segments            ; yes, do it
   804                                  
   805                                  csf_15:
   806 000003F7 26833E100000                cmp WORD PTR [es:16],0          ; see if segment has associated group
   807 000003FD 7403                        je  csf_15a                     ; nope
   808 000003FF E89012                      call    update_grp_off          ; update group entry's offset, if necessary
   809                                  
   810                                  csf_15a:
   811 00000402 A1[2200]                    mov ax,WORD PTR [true_seg_len]
   812 00000405 0106[0C00]                  add WORD PTR [segment_start],ax   ; update low word of segment start (next segment)
   813 00000409 A1[2400]                    mov ax,WORD PTR [true_seg_len+2]
   814 0000040C 1106[0E00]                  adc WORD PTR [segment_start+2],ax ; update high word of segment start (next segment)
   815                                  
   816                                  csf_next_entry:
   817 00000410 FF06[1600]                  inc word [entry_number]        ; bump to next segdef entry
   818 00000414 E969FD                      jmp NEAR PTR csf_segblk_loop    ; loop back to check next segdef entry
   819                                  
   820                                  csf_res_done:
   821 00000417 803E[0000]00                cmp byte [stack_found],0       ; check if stack segment
   822 0000041C 7416                        je  csf_16              ; no
   823 0000041E 803E[0000]00                cmp byte [is_comfile],0        ; check if .COM file
   824 00000423 7423                        je  csf_ret             ; no
   825 00000425 D006[0000]              	rol byte [is_comstack_set], 1
   826 00000429 721D                    	jc csf_ret
   827                                  
   828                                  ; stack segment in .COM file, fatal error
   829 0000042B BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
   830 0000042E B81500                      mov ax,COM_STACK_ERR    ; stack segment in .COM file error
   831 00000431 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   832                                  
   833                                  ; no stack segment found
   834                                  csf_16:
   835 00000434 803E[0000]00                cmp byte [is_comfile],0        ; check if .COM file
   836 00000439 750D                        jne csf_ret             ; yes
   837                                  
   838                                  ; EXE file with no stack, issue warning
   839 0000043B F616[0000]              	not byte [is_stack_warning]
   840 0000043F BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
   841 00000442 B82C00                      mov ax,NO_EXE_STACK_WARN
   842 00000445 E8(0000)                    call    link_warning
   843                                  
   844                                  csf_ret:
   845 00000448 803E[0000]00                cmp byte [is_mapfile],0                ; see if need to write groups to map file
   846 0000044D 7403                        je  csf_out                     ; no
   847 0000044F E8(0000)                    call    map_groups              ; map groups, if any
   848                                  
   849                                  csf_out:
   850 00000452 C3                          ret
   851                                  compute_seg_frames  ENDP
   852                                  
   853                                  ;*****************************
   854                                  ;* WRITE_PROGRAM             *
   855                                  ;*****************************
   856                                  
   857                                  ; write finished .COM or .EXE program based upon executable image
   858                                  ; destroys all registers except ds,es
   859                                  
   860                                  write_program   PROC
   861 00000453 803E[0000]00                cmp byte [is_comfile],0        ; see if COM file
   862 00000458 7520                        jne wp_com              ; yes
   863                                  
   864                                  ; set .EXE header variables
   865                                  wp_1:
   866 0000045A A1[0000]                    mov ax,[number_reloc]
   867 0000045D A3[1600]                    mov [exe_header.eh_numrel],ax
   868 00000460 A1[0000]                    mov ax,[stack_segval]
   869 00000463 A3[1E00]                    mov [exe_header.eh_ss],ax
   870 00000466 A1[0000]                    mov ax,[stack_offval]
   871 00000469 A3[2000]                    mov [exe_header.eh_sp],ax
   872 0000046C A1[0000]                    mov ax,[entry_segval]
   873 0000046F A3[2600]                    mov [exe_header.eh_cs],ax
   874 00000472 A1[0000]                    mov ax,[entry_offval]
   875 00000475 A3[2400]                    mov [exe_header.eh_ip],ax
   876 00000478 EB2F                        jmp SHORT wp_3              ; bypass COM code
   877                                  
   878                                  ; check for proper .COM file format
   879                                  wp_com:
   880 0000047A D006[0000]              	rol byte [is_comseg_set], 1
   881 0000047E 7210                    	jc wp_2
   882 00000480 833E[0000]00                cmp word [number_reloc],0      ; check if any relocation items
   883 00000485 7409                        je  wp_2                ; no
   884                                  
   885                                  ; can't have relocation items for a .COM file
   886 00000487 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
   887 0000048A B81600                      mov ax,COM_FIXUP_ERR    ; program has segment-relative fixups, bad .COM format
   888 0000048D E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   889                                  
   890                                  ; check if COM file has good entry point
   891                                  wp_2:
   892 00000490 833E[0000]00                cmp word [entry_segval],0      ; see if begins at 0:100h
   893 00000495 7409                        je  pm_2a               ; okay so far
   894                                  
   895                                  ; bad entry point address for com file
   896                                  wp_com_entry:
   897 00000497 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
   898 0000049A B83100                      mov ax,COM_ENTRY_ERR
   899 0000049D E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   900                                  
   901                                  pm_2a:
   902 000004A0 A1[0000]                	mov ax, [comfile_cut_length]
   903 000004A3 3906[0000]                  cmp word [entry_offval], ax   ; check offset
   904 000004A7 75EE                        jne wp_com_entry        ; bad offset
   905                                  
   906                                  ; update temporary file from memory pages, if exists
   907                                  wp_3:
   908 000004A9 803E[0000]00                cmp byte [is_ondisk],0         ; check if temporary file in use
   909 000004AE 7403                        je  wp_3a               ; no
   910 000004B0 E8(0000)                    call    update_temp_file    ; flush pages to disk
   911                                  
   912                                  wp_3a:
   913 000004B3 833E[0000]00                cmp word [ovl_count],0         ; see if any overlays
   914 000004B8 7410                        je  wp_3b               ; no
   915 000004BA E8(0000)                    call    flush_ovl_page  ; flush overlay file memory page
   916 000004BD E8(0000)                    call    flush_reloc_array   ; flush relocation array to disk
   917 000004C0 803E[0000]00                cmp byte [is_emsxms_ovl],0     ; see if overlays in EMS/XMS
   918 000004C5 7403                        je  wp_3b               ; no
   919 000004C7 E8(0000)                    call    ems_ovl_to_file ; flush overlays from EMS/XMS to disk
   920                                  
   921                                  wp_3b:
   922 000004CA BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP   ; DS:DX -> ASCIIZ file specification
   923 000004CD B43C                        mov ah,3ch              ; create/truncate file
   924 000004CF 31C9                        xor cx,cx               ; normal file attribute
   925 000004D1 CD21                        int 21h
   926 000004D3 E8(0000)                    call    restore_ems_map
   927 000004D6 7303                        jnc wp_4                ; no errors
   928 000004D8 E9(0000)                    jmp NEAR PTR dos_error  ; error opening file
   929                                  
   930                                  ; write program image to highest write address (above is uninit'ed data)
   931                                  ; di:si will hold number of bytes to write
   932                                  wp_4:
   933 000004DB A3[1800]                    mov [exe_handle],ax       ; keep file handle of executable file
   934 000004DE 8B36[0000]                  mov si,WORD PTR [highest_exe_write]   ; get low word
   935 000004E2 8B3E[0200]                  mov di,WORD PTR [highest_exe_write+2] ; get high word
   936 000004E6 83C601                      add si,1                ; amount to write is one more than highest write amount
   937 000004E9 83D700                      adc di,0                ; carry to high word
   938                                  
   939 000004EC 803E[0000]00                cmp  byte [is_comfile],0       ; check if .COM file
   940 000004F1 7429                        je  wp_5                ; no
   941                                  
   942 000004F3 D006[0000]              	rol byte [is_combig_set], 1
   943 000004F7 7216                    	jc wp_com2
   944 000004F9 09FF                        or  di,di               ; check if file is 64K or larger
   945 000004FB 7412                        je  wp_com2             ; no
   946 000004FD 83FF02                      cmp di,2                ; check that file doesn't exceed 64K in high word
   947 00000500 7304                        jae wp_com_size         ; it does, com file too large
   948 00000502 09F6                        or  si,si               ; file is at least 64K, check that it isn't more
   949 00000504 7409                        je  wp_com2             ; file is exactly 64K
   950                                  
   951                                  ; .COM file is larger than 65536 bytes
   952                                  wp_com_size:
   953 00000506 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
   954 00000509 B81700                      mov ax,COM_SIZE_ERR     ; program larger than 64K, bad .COM format
   955 0000050C E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   956                                  
   957                                  ; start writing offset 100h for .COM file
   958                                  wp_com2:
   959 0000050F A1[0000]                	mov ax, word [comfile_cut_length]
   960 00000512 A3[0000]                	mov word [skip_length], ax
   961 00000515 8B1E[1800]                  mov bx,[exe_handle]       ; file handle
   962 00000519 E97D01                      jmp NEAR PTR wp_write_img   ; bypass EXE relocation table write code
   963                                  
   964                                  wp_5:
   965                                  ; compute size of and allocate space for uninit'ed data
   966 0000051C A1[0000]                    mov ax,WORD PTR [image_size]
   967 0000051F 8B1E[0200]                  mov bx,WORD PTR [image_size+2]    ; bx:ax == program image size
   968 00000523 29F0                        sub ax,si               ; subtract low word of executable bytes
   969 00000525 19FB                        sbb bx,di               ; subtract high word of executable bytes
   970 00000527 83C00F                      add ax,15
   971 0000052A 83D300                      adc bx,0                ; force paragraph computation to round up
   972 0000052D B90400                  	mov cx, 4
   973                                  @@:
   974 00000530 D1EB                        shr bx,1
   975 00000532 D1D8                        rcr ax,1                ; /2
   976 00000534 E2FA                    	loop @B			; /16, ax holds paragraphs of uninit'ed data
   977 00000536 A3[1A00]                    mov [exe_header.eh_minalloc],ax   ; save it as exe header value
   978                                  
   979 00000539 89F0                        mov ax,si               ; get low word of executable bytes
   980 0000053B 25FF01                      and ax,511              ; make file length modulo 512
   981 0000053E A3[1200]                    mov [exe_header.eh_flen],ax   ; save as exe header value
   982                                  
   983 00000541 31DB                        xor bx,bx
   984 00000543 A1[0000]                    mov ax,[number_reloc]     ; get number of relocation items
   985 00000546 B102                    	mov cl, 2
   986                                  @@:
   987 00000548 D1E0                        shl ax,1                ; convert items to bytes (4 bytes/item)
   988 0000054A D1D3                        rcl bx,1                ; x2
   989 0000054C E2FA                    	loop @B			; x4, bx:ax holds relocation item bytes
   990 0000054E 0306[2800]                  add ax,[exe_header.eh_roff]   ; get header size in bytes
   991 00000552 83D300                      adc bx,0                ; carry to bx
   992 00000555 A9FF01                      test    ax,511          ; see if on 512-byte boundary
   993 00000558 740F                        je  wp_6                ; yes
   994                                  		; The above branch cannot currently be taken because
   995                                  		;  exeRelocTable (eh_roff) is a constant 30 and the
   996                                  		;  amount of bytes used by the relocation table is
   997                                  		;  always a multiple of 4. So ax & 511 is always a
   998                                  		;  nonzero value.
   999                                  		; Note that this calculation of the padding length
  1000                                  		;  must match the write length determined for the
  1001                                  		;  zero_table write to the executable output file.
  1002 0000055A B502                        mov ch,512 >> 8		; cl already 0
  1003 0000055C 89C2                        mov dx,ax
  1004 0000055E 81E2FF01                    and dx,511              ; get odd page value in dx
  1005 00000562 29D1                        sub cx,dx               ; compute amount to add to bring to 512-byte boundary
  1006 00000564 01C8                        add ax,cx               ; add in amount
  1007 00000566 83D300                      adc bx,0                ; carry to bx
  1008                                  
  1009                                  wp_6:
  1010 00000569 53                          push    bx              ; save header size in bytes high word
  1011 0000056A 50                          push    ax              ; save header size in bytes low word
  1012 0000056B B90400                  	mov cx, 4
  1013                                  @@:
  1014 0000056E D1EB                        shr bx,1                ; convert header size to paragraphs
  1015 00000570 D1D8                        rcr ax,1                ; /2
  1016 00000572 E2FA                    	loop @B			; /16, ax holds header size in paragraphs
  1017                                  				; bx should be zero value by this shift
  1018 00000574 A3[1800]                    mov [exe_header.eh_hsize],ax  ; save as exe header value
  1019                                  
  1020 00000577 31C9                        xor cx,cx               ; adjustment value to bring to 512-byte boundary
  1021 00000579 89F0                        mov ax,si               ; get low word of executable bytes
  1022 0000057B 25FF01                      and ax,511              ; see if already on 512-byte boundary
  1023 0000057E 7405                        je  wp_7                ; yes
  1024 00000580 B90002                      mov cx,512
  1025 00000583 29C1                        sub cx,ax               ; compute amount to add to bring to 512-byte boundary
  1026                                  
  1027                                  wp_7:
  1028 00000585 89FB                        mov bx,di
  1029 00000587 89F0                        mov ax,si
  1030 00000589 01C8                        add ax,cx               ; bring file size to 512-byte boundary
  1031 0000058B 83D300                      adc bx,0                ; carry to bx
  1032 0000058E 59                          pop cx                  ; get header size in bytes low word
  1033 0000058F 5A                          pop dx                  ; get header size in bytes high word
  1034 00000590 01C8                        add ax,cx
  1035 00000592 11D3                        adc bx,dx               ; get file size INCLUDING header in bytes
  1036                                  
  1037                                  ; compute file size in 512-byte pages
  1038 00000594 88E0                        mov al,ah
  1039 00000596 88DC                        mov ah,bl
  1040 00000598 88FB                        mov bl,bh
  1041 0000059A 30FF                        xor bh,bh               ; register shifts do effective divide by 256
  1042 0000059C D1EB                        shr bx,1
  1043 0000059E D1D8                        rcr ax,1                ; /512
  1044 000005A0 A3[1400]                    mov [exe_header.eh_fsize],ax  ; save file size in 512-byte pages in exe header
  1045                                  
  1046 000005A3 803E[0000]00                cmp byte [is_stackval],0       ; see if stack value specified
  1047 000005A8 7442                        je  wp_8                ; no
  1048 000005AA A1[0000]                    mov ax,WORD PTR [image_size]
  1049 000005AD 8B1E[0200]                  mov bx,WORD PTR [image_size+2]    ; bx:ax == program image size
  1050 000005B1 8B0E[0000]                  mov cx,[stack_segval]
  1051 000005B5 31D2                        xor dx,dx
  1052 000005B7 D1E1                        shl cx,1                ; convert paragraphs available in cx into bytes in dx:cx
  1053 000005B9 D1D2                        rcl dx,1                ; x2
  1054 000005BB D1E1                        shl cx,1
  1055 000005BD D1D2                        rcl dx,1                ; x4
  1056 000005BF D1E1                        shl cx,1
  1057 000005C1 D1D2                        rcl dx,1                ; x8
  1058 000005C3 D1E1                        shl cx,1
  1059 000005C5 D1D2                        rcl dx,1                ; x16, paragraph converted to bytes
  1060 000005C7 29C8                        sub ax,cx
  1061 000005C9 19D3                        sbb bx,dx               ; bx:ax holds program bytes above stack allocation start
  1062 000005CB 09DB                        or  bx,bx               ; see if >64K (always room for stack specified)
  1063 000005CD 7517                        jne wp_7a               ; yes
  1064 000005CF 8B0E[0000]                  mov cx,[stack_value]
  1065 000005D3 29C1                        sub cx,ax               ; see if remainder is > specified stack
  1066 000005D5 720F                        jc  wp_7a               ; yes
  1067                                  
  1068                                  ; specified stack is greater than memory image, bump minimum value by difference (in paras)
  1069 000005D7 83C10F                      add cx,15               ; round up to next paragraph
  1070 000005DA D1E9                        shr cx,1
  1071 000005DC D1E9                        shr cx,1
  1072 000005DE D1E9                        shr cx,1
  1073 000005E0 D1E9                        shr cx,1                ; bytes converted to paragraphs
  1074 000005E2 010E[1A00]                  add [exe_header.eh_minalloc],cx   ; add to previous minimum value
  1075                                  
  1076                                  ; set new stack value
  1077                                  wp_7a:
  1078 000005E6 A1[0000]                    mov ax,[stack_value]
  1079 000005E9 A3[2000]                    mov [exe_header.eh_sp],ax
  1080                                  
  1081                                  ; see if maximum paragraph allocation space specified
  1082                                  ; if less than minimum, give feeback and set to minimum
  1083                                  wp_8:
  1084 000005EC 803E[0000]00                cmp byte [is_maxparval],0      ; see if allocation value specified
  1085 000005F1 7423                        je  wp_8a               ; no
  1086 000005F3 A1[0000]                    mov ax,[maxpar_value]     ; get allocation value
  1087 000005F6 A3[1C00]                    mov [exe_header.eh_maxalloc],ax   ; save it in header variable
  1088 000005F9 3B06[1A00]                  cmp ax,[exe_header.eh_minalloc]   ; make sure >= minimum allocation
  1089 000005FD 7317                        jae wp_8a               ; okay value
  1090                                  
  1091                                  ; specified maximum paragraph allocation is less than minimum
  1092 000005FF BA[2500]                    mov dx,OFFSET maxalloc_warn wrt DGROUP  ; ds:dx -> write buffer area
  1093 00000602 8B0E[2300]                  mov cx,[maxalloc_len]
  1094 00000606 BB0100                      mov bx,STDOUT
  1095 00000609 B440                        mov ah,40h              ; write to standard output device
  1096 0000060B CD21                        int 21h
  1097 0000060D E8(0000)                    call    restore_ems_map
  1098                                  
  1099 00000610 A1[1A00]                    mov ax,[exe_header.eh_minalloc]   ; get minimum allocation
  1100 00000613 A3[1C00]                    mov [exe_header.eh_maxalloc],ax   ; save as maximum
  1101                                  
  1102                                  ; write .EXE file header
  1103                                  wp_8a:
  1104 00000616 BA[1000]                    mov dx,OFFSET exe_header wrt DGROUP ; ds:dx -> write buffer area
  1105 00000619 B91E00                      mov cx,30               ; size of EXE header control info
  1106 0000061C 8B1E[1800]                  mov bx,[exe_handle]       ; file handle
  1107 00000620 B440                        mov ah,40h              ; write to file
  1108 00000622 CD21                        int 21h
  1109 00000624 E8(0000)                    call    restore_ems_map
  1110 00000627 7266                        jc  wp_to_dos_error     ; error writing to file
  1111                                  
  1112 00000629 39C8                        cmp ax, cx			; see if out of disk space
  1113 0000062B 7409                        je wp_9a			; no
  1114                                  
  1115                                  ; out of disk space for executable file
  1116                                  wp_diskspace:
  1117 0000062D B83A00                      mov ax,DISK_FULL_ERR
  1118 00000630 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
  1119 00000633 E9(0000)                    jmp NEAR PTR link_error ; transfer to error handler
  1120                                  
  1121                                  wp_9a:
  1122 00000636 A1[0000]                    mov ax,[first_relblk_ptr] ; get first relocation table block
  1123                                  
  1124                                  wp_rel_loop:
  1125 00000639 09C0                        or  ax,ax               ; check that is non-null
  1126 0000063B 7428                        je  wp_10               ; no more relocation entries
  1127 0000063D 1E                          push    ds              ; save ds -> warplink data segment, used
  1128 0000063E 8ED8                        mov ds,ax               ; ds -> block
  1129 00000640 BA0400                      mov dx,4                ; ds:dx -> relocation items to write
  1130 00000643 8B0E0000                    mov cx,[0]           ; get number of entries
  1131 00000647 D1E1                        shl cx,1
  1132 00000649 D1E1                        shl cx,1                ; entries * 4 == byte count to write
  1133 0000064B B440                        mov ah,40h              ; write to file
  1134 0000064D CD21                        int 21h
  1135 0000064F E8(0000)                    call    restore_ems_map
  1136 00000652 720A                    	jc @F
  1137 00000654 39C8                        cmp ax, cx			; see if out of disk space
  1138 00000656 75D5                        jne  wp_diskspace        ; yes
  1139 00000658 A10200                      mov ax,[2]           ; get pointer to next block, if any
  1140 0000065B 1F                          pop ds                  ; restore ds -> warplink data
  1141 0000065C EBDB                        jmp wp_rel_loop         ; no errors, loop for next block write
  1142                                  
  1143                                  @@:
  1144 0000065E 1F                      	pop ds
  1145 0000065F BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
  1146 00000662 E9(0000)                    jmp NEAR PTR dos_error  ; error writing to file
  1147                                  
  1148                                  wp_10:
  1149 00000665 31C9                        xor cx,cx
  1150 00000667 A1[0000]                    mov ax,[number_reloc]
  1151 0000066A D1E0                        shl ax,1
  1152 0000066C D1D1                        rcl cx,1                ; x2
  1153 0000066E D1E0                        shl ax,1
  1154 00000670 D1D1                        rcl cx,1                ; x4, cx:ax hold bytes of relocation items
  1155 00000672 0306[2800]                  add ax,[exe_header.eh_roff]   ; add in header offset, ignore carry
  1156 00000676 25FF01                  	and ax, 511		; get header size modulo 512 (0..511)
  1157 00000679 B90002                  	mov cx, 512		; cx = 512
  1158 0000067C 29C1                    	sub cx, ax		; cx = 512 - header size modulo 512 (1..512)
  1159 0000067E 80E501                  	and ch, 511 >> 8	; convert 512 to 0, so cx = 0..511,
  1160                                  				;  now cx holds number of zero byte values
  1161                                  				;  needed for header to be on 512-byte page
  1162 00000681 E316                    	jcxz wp_write_img	; no bytes needed
  1163                                  		; The above branch never is taken currently, because the
  1164                                  		;  exeRelocTable (eh_roff) field is always a constant 30
  1165                                  		;  (001Eh) and the calculated amount of bytes for the
  1166                                  		;  relocation table is always a multiple of 4. Therefore,
  1167                                  		;  the header size modulo 512 is never equal to zero.
  1168                                  		; This calculation must match the code around wp_6 which
  1169                                  		;  calculates exeHeaderSize (eh_hsize).
  1170                                  
  1171 00000683 BA[0000]                    mov dx,OFFSET zero_table wrt DGROUP ; ds:dx point to table of zeros to write
  1172 00000686 B440                        mov ah,40h              ; write to file
  1173 00000688 CD21                        int 21h
  1174 0000068A E8(0000)                    call    restore_ems_map
  1175 0000068D 7306                    	jnc @F			; no errors
  1176                                  
  1177                                  wp_to_dos_error:
  1178 0000068F BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
  1179 00000692 E9(0000)                    jmp NEAR PTR dos_error  ; error writing to file
  1180                                  
  1181                                  @@:
  1182 00000695 39C8                        cmp ax, cx			; see if out of disk space
  1183 00000697 7594                        jne  wp_diskspace        ; yes
  1184                                  
  1185                                  wp_write_img:
  1186 00000699 803E[0000]00                cmp byte [is_ondisk],0         ; check if memory image is on disk
  1187 0000069E 7405                        je  wp_mem_write        ; no
  1188                                  
  1189 000006A0 E8(0000)                    call    dump_temp_file  ; dump temporary file bytes into executable file
  1190 000006A3 EB59                        jmp SHORT wp_ovlclose   ; close overlay file if exists
  1191                                  
  1192                                  ; transfer program to disk in 64K-16 chunks
  1193                                  ; di:si contain number of bytes to write, bx == file handle
  1194                                  wp_mem_write:
  1195 000006A5 B9F0FF                      mov cx, 0FFF0h		; number of bytes to write (64K-16)
  1196 000006A8 85FF                        test di, di			; see if byte count to write is 64K or more
  1197 000006AA 7508                        jne wp_11			; yes, write a 64K-16 chunk -->
  1198 000006AC 39CE                        cmp si, cx			; see if byte count is at least 64K-16
  1199 000006AE 7304                        jae wp_11
  1200                                  
  1201                                  ; transfer leftover bytes (file size modulo 0fff0h)
  1202 000006B0 89F1                        mov cx, si			; cx holds bytes to write
  1203 000006B2 E34A                        jcxz wp_ovlclose		; no bytes to write
  1204                                  
  1205                                  wp_11:
  1206 000006B4 A1[0000]                    mov ax,[image_mem_ptr]
  1207 000006B7 31D2                        xor dx,dx               ; zero offset of write buffer
  1208 000006B9 51                      	push cx
  1209 000006BA 8716[0000]              	xchg dx, word [skip_length]	; reset for next iteration, dx -> data
  1210 000006BE 29D1                    	sub cx, dx			; skip this part
  1211 000006C0 7309                    	jae @F				; if not negative -->
  1212 000006C2 B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
  1213 000006C5 B93500                      mov cx, 53              ; internal error value
  1214 000006C8 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  1215                                  
  1216                                  @@:
  1217 000006CB 85D2                    	test dx, dx
  1218 000006CD 740D                    	jz @F
  1219 000006CF 51                      	push cx
  1220 000006D0 06                      	push es
  1221 000006D1 50                      	push ax
  1222 000006D2 89D1                    	mov cx, dx
  1223 000006D4 8EC0                    	mov es, ax
  1224 000006D6 E8F910                  	call check_com_cut
  1225 000006D9 58                      	pop ax
  1226 000006DA 07                      	pop es
  1227 000006DB 59                      	pop cx
  1228                                  @@:
  1229 000006DC 1E                          push    ds              ; save ds, critical register
  1230 000006DD 8ED8                        mov ds,ax               ; ds -> segment to start write
  1231 000006DF B440                        mov ah,40h              ; write to file
  1232 000006E1 CD21                        int 21h
  1233 000006E3 E8(0000)                    call    restore_ems_map
  1234 000006E6 1F                          pop ds                  ; restore ds -> warplink data
  1235 000006E7 72A6                        jc wp_to_dos_error
  1236 000006E9 39C8                        cmp ax, cx			; see if out of disk space
  1237 000006EB 7403E93DFF                  jne  wp_diskspace        ; yes
  1238 000006F0 59                      	pop cx
  1239 000006F1 29CE                        sub si, cx           ; back off number of bytes written from bytes to write
  1240 000006F3 83DF00                      sbb di,0                ; borrow to high word
  1241 000006F6 8106[0000]FF0F              add word [image_mem_ptr],0fffh ; adjust segment pointer past 64K-16 written (4K-1 paragraphs)
  1242 000006FC EBA7                        jmp SHORT wp_mem_write  ; loop for next write
  1243                                  
  1244                                  wp_ovlclose:
  1245 000006FE 8B1E[0000]                  mov bx,[ovl_handle]       ; get overlay file handle
  1246 00000702 09DB                        or  bx,bx               ; make sure nonzero
  1247 00000704 7413                        je  wp_ret              ; zero, don't close (no file)
  1248                                  
  1249 00000706 803E[0000]00                cmp byte [is_internal],0       ; check if temporary overlay file
  1250 0000070B 7509                        jne wp_tmpovl           ; yes
  1251 0000070D B43E                        mov ah,3eh              ; close overlay file
  1252 0000070F CD21                        int 21h
  1253 00000711 E8(0000)                    call    restore_ems_map
  1254 00000714 EB03                        jmp SHORT wp_ret        ; bypass temporary overlay file code
  1255                                  
  1256                                  wp_tmpovl:
  1257 00000716 E8440D                      call    dump_ovl_file   ; dump temporary overlay file to end of executable file
  1258                                  
  1259                                  wp_ret:
  1260 00000719 D006[0000]                  rol byte [is_wlcalc_enabled], 1
  1261 0000071D 7312                        jnc @F
  1262                                  _wlcalc_do_pass:
  1263 0000071F 31C0                    	xor ax, ax
  1264 00000721 E8C100                  	call patch_wlcalc_sites
  1265 00000724 FF06[0800]              	inc word [_wlcalc_pass]
  1266 00000728 A1[0800]                	mov ax, word [_wlcalc_pass]
  1267 0000072B 3B06[0A00]              	cmp ax, word [_wlcalc_maximum_pass]
  1268 0000072F 76EE                    	jbe _wlcalc_do_pass
  1269                                  @@:
  1270                                  do_comseg:
  1271 00000731 803E[0000]00            	cmp byte [is_comfile], 0
  1272 00000736 7503E99900              	je .none
  1273 0000073B D006[0000]              	rol byte [is_comseg_set], 1
  1274 0000073F 7203E99000              	jnc .none
  1275 00000744 8B1E[1800]                  mov bx,[exe_handle]
  1276 00000748 A1[0000]                    mov ax,[first_relblk_ptr] ; get first relocation table block
  1277                                  .loopouter:
  1278 0000074B 85C0                    	test ax, ax		; check that is non-null
  1279 0000074D 7503E98200              	jz .done		; no more relocation entries
  1280 00000752 1E                      	push ds
  1281 00000753 07                      	pop es			; es => DGROUP
  1282 00000754 1E                          push    ds              ; save ds -> warplink data segment, used
  1283 00000755 8ED8                        mov ds,ax               ; ds -> block
  1284 00000757 BE0400                      mov si,4                ; ds:dx -> relocation items to write
  1285 0000075A 8B3E0000                    mov di,[0]           ; get number of entries
  1286 0000075E 85FF                    	test di, di
  1287 00000760 746B                    	jz .nextouter
  1288                                  .loopinner:
  1289 00000762 AD                      	lodsw
  1290 00000763 50                      	push ax			; = offset
  1291 00000764 AD                      	lodsw
  1292 00000765 92                      	xchg dx, ax
  1293 00000766 31C0                    	xor ax, ax		; ax:dx = segment
  1294 00000768 B90400                  	mov cx, 4
  1295                                  @@:
  1296 0000076B D1E2                    	shl dx, 1
  1297 0000076D D1D0                    	rcl ax, 1
  1298 0000076F E2FA                    	loop @B			; ax:dx = linear from segment
  1299 00000771 59                      	pop cx
  1300 00000772 01CA                    	add dx, cx
  1301 00000774 83D000                  	adc ax, 0		; ax:dx = linear
  1302 00000777 91                      	xchg cx, ax		; cx:dx = linear
  1303 00000778 262B16[0000]            	sub dx, word [es:comfile_cut_length]
  1304 0000077D 83D900                  	sbb cx, 0		; = file seek
  1305                                  
  1306 00000780 B80042                  	mov ax, 4200h
  1307 00000783 CD21                    	int 21h			; seek to relocation
  1308 00000785 7216                    	jc .dos_error
  1309                                  
  1310 00000787 1E                      	push ds
  1311 00000788 16                      	 push ss
  1312 00000789 1F                      	 pop ds			; => stack
  1313 0000078A 50                      	push ax			; make space for word buffer
  1314 0000078B 89E2                    	mov dx, sp
  1315 0000078D B90200                  	mov cx, 2
  1316 00000790 B43F                    	mov ah, 3Fh
  1317 00000792 CD21                    	int 21h			; read word
  1318 00000794 7207                    	jc .dos_error
  1319 00000796 39C8                    	cmp ax, cx
  1320 00000798 7406                    	je @F
  1321 0000079A B8FEFF                  	mov ax, -2		; short read code
  1322                                  .dos_error:
  1323 0000079D E9EFFE                  	jmp wp_to_dos_error
  1324                                  
  1325                                  @@:
  1326 000007A0 58                      	pop ax			; get word read from file
  1327 000007A1 260306[0000]            	add ax, word [es:comseg_relocation_factor]
  1328                                  				; apply relocation
  1329 000007A6 50                      	push ax			; put it back onto the stack
  1330 000007A7 B9FFFF                  	mov cx, -1
  1331 000007AA BAFEFF                  	mov dx, -2
  1332 000007AD B80142                  	mov ax, 4201h
  1333 000007B0 CD21                    	int 21h			; seek back
  1334 000007B2 72E9                    	jc .dos_error
  1335 000007B4 89E2                    	mov dx, sp
  1336 000007B6 B90200                  	mov cx, 2
  1337 000007B9 B440                    	mov ah, 40h
  1338 000007BB CD21                    	int 21h			; write word
  1339 000007BD 72DE                    	jc .dos_error
  1340 000007BF 39C8                    	cmp ax, cx
  1341 000007C1 7405                    	je @F
  1342 000007C3 B82700                  	mov ax, 27h
  1343 000007C6 EBD5                    	jmp .dos_error
  1344                                  @@:
  1345 000007C8 58                      	pop ax			; discard stack variable
  1346 000007C9 1F                      	pop ds
  1347 000007CA 4F                      	dec di			; count down this block's relocations
  1348 000007CB 7595                    	jnz .loopinner		; more to go -->
  1349                                  .nextouter:
  1350 000007CD A10200                      mov ax,[2]           ; get pointer to next block, if any
  1351 000007D0 1F                          pop ds                  ; restore ds -> warplink data
  1352 000007D1 E977FF                      jmp .loopouter         ; no errors, loop for next block write
  1353                                  
  1354                                  .done:
  1355                                  .none:
  1356 000007D4 8B1E[1800]                  mov bx,[exe_handle]
  1357 000007D8 B43E                        mov ah,3eh              ; close executable file
  1358 000007DA CD21                        int 21h
  1359 000007DC E8(0000)                    call    restore_ems_map
  1360                                   extern delete_wllist_temps
  1361 000007DF 31C0                    	xor ax, ax
  1362 000007E1 E8(0000)                	call delete_wllist_temps
  1363 000007E4 C3                          ret
  1364                                  write_program   ENDP
  1365                                  
  1366                                  
  1367                                  		; INP:	al = 0 if normal run (post-link)
  1368                                  		;	al = 1 if to create relocations
  1369                                  		; CHG:	all
  1370                                  		; STT:	ds => DGROUP
  1371                                  		; REM:	based on mlmap.nas map_publics
  1372                                   global patch_wlcalc_sites
  1373                                  patch_wlcalc_sites:
  1374 000007E5 A2[0400]                	mov byte [_wlcalc_create_relocations], al
  1375 000007E8 A1[0000]                    mov ax,[first_pdeclblk_ptr]   ; get pointer to first public declarations block
  1376 000007EB 09C0                        or  ax,ax               ; check if non-null
  1377 000007ED 7503                        jne pws_blkloop          ; non-null, public declarations exist
  1378 000007EF E97F06                      jmp NEAR PTR pws_communal_chk    ; null, try communal declarations block
  1379                                  
  1380                                  pws_blkloop:
  1381 000007F2 50                          push    ax              ; save -> block on stack
  1382 000007F3 8EC0                        mov es,ax               ; es -> declarations block
  1383 000007F5 268B360000                  mov si,[es:0]           ; get count of entries in block
  1384                                  
  1385                                  pws_entloop:
  1386 000007FA 830E[0600]FF            	or word [_wlcalc_obj_index], -1
  1387 000007FF 40                          inc ax                  ; ax -> next entry in block
  1388 00000800 8EC0                        mov es,ax               ; es -> declaration entry
  1389 00000802 06                          push    es              ; save -> declaration entry
  1390                                  
  1391                                  ; 12/21/92
  1392                                  ;***	test    BYTE PTR [es:15],20h    ; see if local communal (don't list locals)
  1393 00000803 26F6060F0024                test    BYTE PTR [es:15],24h    ; see if local
  1394                                  
  1395 00000809 7404                        je  pws_not_local        ; no
  1396                                  
  1397                                  pws_noprint:
  1398 0000080B 07                          pop es                  ; restore stack
  1399 0000080C E94E06                      jmp NEAR PTR pws_next_entry  ; try next entry in block
  1400                                  
  1401                                  pws_not_local:
  1402 0000080F 26F6060E0003                test    BYTE PTR [es:14],3  ; see if weak extdef
  1403 00000815 74F4                        je  pws_noprint          ; yes, don't print it
  1404                                  
  1405 00000817 268A260F00                  mov ah,[es:15]          ; get general flags
  1406 0000081C F6C401                      test    ah,1            ; get in overlay flag
  1407 0000081F 751B                        jne pws_overlaid         ; set, in overlay, zero segment offset
  1408 00000821 26A00E00                    mov al,[es:14]          ; get definition flag
  1409 00000825 2403                        and al,3                ; get definition bits
  1410 00000827 3C03                        cmp al,3                ; see if absolute
  1411 00000829 7509                        jne pws_not_abs          ; no
  1412                                  
  1413                                  ; absolute symbol
  1414 0000082B 268B0E0200                  mov cx,[es:2]           ; get frame number in cx
  1415                                  
  1416                                  pws_zero_offset:
  1417 00000830 31FF                        xor di,di               ; di==low nybble of segment offset (always zero)
  1418 00000832 EB7F                        jmp SHORT pws_3          ; bypass segment frame code
  1419                                  
  1420                                  pws_not_abs:
  1421 00000834 3C02                        cmp al,2                ; see if resolved
  1422 00000836 740A                        je  pws_2a               ; yes
  1423 00000838 31C9                        xor cx,cx               ; zero frame
  1424 0000083A EBF4                        jmp SHORT pws_zero_offset    ; go to zero offset code
  1425                                  
  1426                                  pws_overlaid:
  1427 0000083C 31C9                        xor cx,cx               ; zero frame
  1428 0000083E 89CF                        mov di,cx               ; zero public offset
  1429 00000840 EB71                        jmp SHORT pws_3          ; bypass segment frame code
  1430                                  
  1431                                  pws_2a:
  1432 00000842 268E060000                  mov es,[es:0]           ; es -> segment partition entry
  1433 00000847 26833E080000            	cmp word [es:file_mod_id + 2], 0
  1434 0000084D 7509                    	jne @F
  1435 0000084F 268B0E0600              	mov cx, word [es:file_mod_id]
  1436 00000854 890E[0600]              	mov word [_wlcalc_obj_index], cx
  1437                                  @@:
  1438 00000858 268B0E0000                  mov cx,[es:0]           ; get segment partition offset
  1439 0000085D 268E060400                  mov es,[es:4]           ; es -> segdef entry
  1440                                  
  1441 00000862 80E480                      and ah,80h              ; see if public is in group
  1442 00000865 743F                        je  pws_2b               ; no
  1443                                  
  1444 00000867 89CF                        mov di,cx               ; di holds segment partition entry offset
  1445                                  
  1446 00000869 268B0E0200                  mov cx,[es:2]           ; get low word of segment offset
  1447 0000086E 26A10400                    mov ax,[es:4]           ; get high word of segment offset
  1448 00000872 07                          pop es                  ; es -> public declaration entry
  1449 00000873 06                          push    es              ; restore -> public declaration entry to stack
  1450 00000874 268E060200                  mov es,[es:2]           ; es -> group entry
  1451 00000879 262B0E0000                  sub cx,[es:0]           ; compute low word difference in group/segment offset
  1452 0000087E 261B060200                  sbb ax,[es:2]           ; compute high word difference in group/segment offset
  1453 00000883 01CF                        add di,cx               ; add difference into di, public offset
  1454                                  
  1455 00000885 26A10000                    mov ax,[es:0]           ; get low word of group offset
  1456 00000889 89C1                        mov cx,ax               ; save in cx
  1457 0000088B 83E00F                      and ax,0fh              ; get paragraph remainder
  1458 0000088E 01C7                        add di,ax               ; add to public offset
  1459                                  
  1460 00000890 26A10200                    mov ax,[es:2]           ; get high word of group offset
  1461 00000894 D1E8                        shr ax,1                ; convert offset in ax:cx to paragraphs
  1462 00000896 D1D9                        rcr cx,1                ; /2
  1463 00000898 D1E8                        shr ax,1
  1464 0000089A D1D9                        rcr cx,1                ; /4
  1465 0000089C D1E8                        shr ax,1
  1466 0000089E D1D9                        rcr cx,1                ; /8
  1467 000008A0 D1E8                        shr ax,1
  1468 000008A2 D1D9                        rcr cx,1                ; /16
  1469 000008A4 EB0D                        jmp SHORT pws_3          ; bypass segment specific code
  1470                                  
  1471                                  ; non-group public
  1472                                  pws_2b:
  1473 000008A6 268B3E0200                  mov di,[es:2]           ; get low word of segment offset
  1474 000008AB 83E70F                      and di,0fh              ; di==low nybble of segment offset
  1475 000008AE 01CF                        add di,cx               ; add in segment partition entry offset
  1476                                  
  1477                                   extern seg_offset_to_para
  1478 000008B0 E8(0000)                    call    seg_offset_to_para  ; get segment offset in paragraphs (frame) in cx
  1479                                  
  1480                                  pws_3:
  1481 000008B3 890E[1000]              	mov word [_wlcalc_segment], cx
  1482 000008B7 07                          pop es                  ; es -> declaration entry
  1483 000008B8 26033E0800                  add di,[es:8]           ; add in public offset
  1484 000008BD 89F9                        mov cx,di
  1485 000008BF 890E[0E00]              	mov word [_wlcalc_offset], cx
  1486                                  
  1487                                  pws_4:
  1488 000008C3 26A00F00                    mov al,[es:15]          ; get general flag
  1489 000008C7 2401                        and al,1                ; see if overlaid
  1490 000008C9 7518                        jne pws_ovl              ; yes
  1491 000008CB 26A00E00                    mov al,[es:14]          ; get definitions flag
  1492 000008CF 2403                        and al,3                ; get definition bits
  1493 000008D1 3C03                        cmp al,3                ; see if absolute
  1494 000008D3 741A                        je  pws_abs              ; no
  1495 000008D5 3C02                        cmp al,2                ; see if resolved public/communal
  1496 000008D7 7516                        jne pws_unres            ; no
  1497 000008D9 26F6060F0040                test    BYTE PTR [es:15],40h    ; see if communal
  1498 000008DF 740E                        je  pws_res              ; no, resolved public
  1499                                  
  1500                                  ;communal variable
  1501 000008E1 EB0C                        jmp SHORT pws_print_pubtype
  1502                                  
  1503                                  ; overlaid variable
  1504                                  pws_ovl:
  1505 000008E3 06                          push    es              ; save critical register
  1506 000008E4 268E060000                  mov es,[es:0]           ; es -> segment partition entry
  1507 000008E9 268B0E0400                  mov cx,[es:4]           ; get overlay identifier
  1508 000008EE 07                          pop es                  ; restore critical register
  1509                                  ; absolute variable
  1510                                  pws_abs:
  1511                                  ; resolved public
  1512                                  pws_res:
  1513                                  ; unresolved public
  1514                                  pws_unres:
  1515                                  pws_print_pubtype:
  1516 000008EF 1E                          push    ds              ; save critical register
  1517                                  
  1518                                  handle_wlcalc:
  1519 000008F0 26C53E0400                  lds di,[es:4]           ; get -> pubdef name in es:bx
  1520 000008F5 1E                      	push ds
  1521 000008F6 06                      	push es
  1522 000008F7 56                      	push si
  1523 000008F8 57                      	push di
  1524 000008F9 53                      	push bx
  1525                                  	lframe
  1526                                  	lvar word, do
  1527                                  	lvar word, size
  1528                                  	lequ 10, buffersize
  1529                                  	lvar ?buffersize, buffer
  1530 000008FA 5589E58D66F2            	lenter
  1531 00000900 1E                      	 push ds
  1532 00000901 57                      	 push di
  1533                                  	lvar dword, namepointer
  1534 00000902 31C0                    	xor ax, ax
  1535 00000904 50                      	 push ax
  1536                                  	lvar word, pass
  1537 00000905 50                      	 push ax
  1538 00000906 40                      	inc ax
  1539 00000907 50                      	 push ax
  1540                                  	lvar dword, repeat
  1541                                  
  1542 00000908 89FE                    	mov si, di
  1543 0000090A B8[ssss]                	mov ax, DGROUP
  1544 0000090D 8EC0                    	mov es, ax
  1545 0000090F BF[7500]                	mov di, string_wlcalc
  1546                                  @@:
  1547 00000912 A6                      	cmpsb
  1548 00000913 7403E9B300              	jne .check
  1549 00000918 807CFF00                	cmp byte [si - 1], 0
  1550 0000091C 75F4                    	jne @B
  1551                                  
  1552                                  .unknown:
  1553 0000091E B84B00                      mov ax,_WLCALC_ERR
  1554                                  
  1555                                  .wlcalc_error:
  1556 00000921 26803E[0400]00          	cmp byte [es:_wlcalc_create_relocations], 0
  1557 00000927 7403E92805              	jne .mismatch_pop
  1558 0000092C 26D006[0000]            	rol byte [es:is_wlcalc_error_as_warning], 1
  1559 00000931 730F                    	jnc @F
  1560                                  		; warning only
  1561 00000933 E81D00                  	call .copy_namepointer
  1562 00000936 E82B00                  	call .get_object_filename
  1563 00000939 BF[0000]                	mov di, name_field
  1564 0000093C E8(0000)                	call link_warning	; give warning feedback
  1565 0000093F E91205                  	jmp .mismatch_pop
  1566                                  @@:
  1567                                  		; error on first unknown
  1568 00000942 EB03                    	jmp .wlcalc_always_error
  1569                                  
  1570                                  .overflow:
  1571 00000944 B84C00                      mov ax,_WLCALC_OVERFLOW_ERR
  1572                                  
  1573                                  .wlcalc_always_error:
  1574 00000947 E80900                  	call .copy_namepointer
  1575 0000094A E81700                  	call .get_object_filename
  1576 0000094D B9[0000]                    mov cx,OFFSET name_field wrt DGROUP ; cx -> symbol name for this error
  1577 00000950 E9(0000)                    jmp NEAR PTR link_error	; transfer control to error handler
  1578                                  
  1579                                   extern obj_block_ptr, get_curr_obj, pos_in_list
  1580                                   global handle_wlcalc.get_object_filename
  1581                                   global _wlcalc_obj_index
  1582                                  
  1583                                   extern name_field
  1584                                  .copy_namepointer:
  1585 00000953 B9[ssss]                	mov cx, DGROUP
  1586 00000956 8EC1                    	mov es, cx
  1587 00000958 BF[0000]                	mov di, name_field
  1588 0000095B B98000                  	mov cx, words(256)
  1589 0000095E C576EE                  	lds si, [bp + ?namepointer]
  1590 00000961 F3A5                    	rep movsw
  1591 00000963 C3                      	retn
  1592                                  
  1593                                  .get_object_filename:
  1594 00000964 B9[ssss]                	mov cx, DGROUP
  1595 00000967 8ED9                    	mov ds, cx
  1596 00000969 8EC1                    	mov es, cx
  1597 0000096B 50                      	push ax
  1598 0000096C FF36[0000]              	push word [current_obj]
  1599 00000970 FF36[0000]              	push word [obj_block_ptr]
  1600 00000974 FF36[0000]              	push word [pos_in_list]
  1601 00000978 833E[0600]FF            	cmp word [_wlcalc_obj_index], -1
  1602 0000097D 750D                    	jne @F
  1603 0000097F BE[0801]                	mov si, string_unknown_filename
  1604 00000982 B91300                  	mov cx, string_unknown_filename.size
  1605                                  .gof_fill:
  1606 00000985 BF[0000]                	mov di, filename
  1607 00000988 F3A4                    	rep movsb
  1608 0000098A EB2E                    	jmp .gof_done
  1609                                  @@:
  1610 0000098C 8326[0000]00                and word [current_obj],0       ; init current object module number
  1611 00000991 A1[0000]                    mov ax,[first_objblk_ptr]
  1612 00000994 A3[0000]                    mov [obj_block_ptr],ax    ; init current block pointer to first block
  1613                                  
  1614                                  .gof_loop:
  1615 00000997 A1[0000]                    mov ax,[obj_count]        ; get total count of object modules
  1616 0000099A 3B06[0000]                  cmp ax,[current_obj]      ; end loop when current equals total
  1617 0000099E 7708                        ja  .gof_getobj           ; more object modules
  1618 000009A0 BE[F500]                	mov si, string_invalid_filename
  1619 000009A3 B91300                  	mov cx, string_invalid_filename.size
  1620 000009A6 EBDD                    	jmp .gof_fill
  1621                                  
  1622                                  .gof_getobj:
  1623 000009A8 E8(0000)                	call get_curr_obj
  1624 000009AB A1[0000]                	mov ax, [current_obj]
  1625 000009AE 3B06[0600]              	cmp ax, [_wlcalc_obj_index]
  1626 000009B2 7406                    	je .gof_done
  1627 000009B4 FF06[0000]              	inc word [current_obj]
  1628 000009B8 EBDD                    	jmp .gof_loop
  1629                                  
  1630                                  .gof_done:
  1631 000009BA BA[0000]                	mov dx, filename
  1632 000009BD 8F06[0000]              	pop word [pos_in_list]
  1633 000009C1 8F06[0000]              	pop word [obj_block_ptr]
  1634 000009C5 8F06[0000]              	pop word [current_obj]
  1635 000009C9 58                      	pop ax
  1636 000009CA C3                      	retn
  1637                                  
  1638                                  .check:
  1639 000009CB 26807DFF00              	cmp byte [es:di - 1], 0
  1640 000009D0 7403E97F04              	jne .mismatch_pop
  1641                                  .match:
  1642 000009D5 4E                      	dec si
  1643                                  @@:
  1644 000009D6 AC                      	lodsb
  1645 000009D7 3C5F                    	cmp al, '_'
  1646 000009D9 74FB                    	je @B
  1647 000009DB 4E                      	dec si
  1648 000009DC 89F2                    	mov dx, si
  1649 000009DE BB[8000]                	mov bx, _wlcalc_size_table - 4
  1650                                  .getsizeloop:
  1651 000009E1 83C304                  	add bx, 4
  1652 000009E4 268B3F                  	mov di, [es:bx]
  1653 000009E7 85FF                    	test di, di
  1654 000009E9 7503E9B701              	jz .unknown_size
  1655 000009EE 89D6                    	mov si, dx
  1656                                  @@:
  1657 000009F0 A6                      	cmpsb
  1658 000009F1 7509                    	jne .checksize
  1659 000009F3 807CFF00                	cmp byte [si - 1], 0
  1660 000009F7 75F7                    	jne @B
  1661 000009F9 E9AF01                  	jmp .unknown_size_only
  1662                                  
  1663                                  .checksize:
  1664 000009FC 26807DFF00              	cmp byte [es:di - 1], 0
  1665 00000A01 75DE                    	jne .getsizeloop
  1666 00000A03 26FF7702                	push word [es:bx + 2]
  1667 00000A07 8F46FC                  	pop word [bp + ?size]
  1668                                  
  1669 00000A0A 4E                      	dec si
  1670                                  @@:
  1671 00000A0B AC                      	lodsb
  1672 00000A0C 3C5F                    	cmp al, '_'
  1673 00000A0E 74FB                    	je @B
  1674 00000A10 4E                      	dec si
  1675 00000A11 89F2                    	mov dx, si
  1676 00000A13 BF[E400]                	mov di, string_pass
  1677                                  @@:
  1678 00000A16 A6                      	cmpsb
  1679 00000A17 7508                    	jne .checkpassearly
  1680 00000A19 807CFF00                	cmp byte [si - 1], 0
  1681 00000A1D 75F7                    	jne @B
  1682 00000A1F EB31                    	jmp .notpassearly
  1683                                  
  1684                                  .checkpassearly:
  1685 00000A21 26807DFF00              	cmp byte [es:di - 1], 0
  1686 00000A26 752A                    	jne .notpassearly
  1687                                  
  1688 00000A28 4E                      	dec si
  1689                                  @@:
  1690 00000A29 AC                      	lodsb
  1691 00000A2A 3C5F                    	cmp al, '_'
  1692 00000A2C 74FB                    	je @B
  1693 00000A2E 4E                      	dec si
  1694 00000A2F E8D207                  	call _wlcalc_parse_number.decimalonly
  1695 00000A32 7308                    	jnc @F
  1696 00000A34 7503E97701              	jz .overflow_pass
  1697 00000A39 E97A01                  	jmp .unknown_invalid_pass
  1698                                  
  1699                                  @@:
  1700 00000A3C 85D2                    	test dx, dx
  1701 00000A3E 7403E96D01              	jnz .overflow_pass
  1702 00000A43 263906[0A00]            	cmp word [es:_wlcalc_maximum_pass], ax
  1703 00000A48 7304                    	jae @F
  1704 00000A4A 26A3[0A00]              	mov word [es:_wlcalc_maximum_pass], ax
  1705                                  @@:
  1706 00000A4E 8946EC                  	mov word [bp + ?pass], ax
  1707 00000A51 A9                      	db __TEST_IMM16		; skip mov si
  1708                                  
  1709                                  .notpassearly:
  1710 00000A52 89D6                    	mov si, dx
  1711                                  @@:
  1712 00000A54 AC                      	lodsb
  1713 00000A55 3C5F                    	cmp al, '_'
  1714 00000A57 74FB                    	je @B
  1715 00000A59 4E                      	dec si
  1716 00000A5A E87B00                  	call .getdo
  1717                                  
  1718 00000A5D 26830E[0A00]FF          	or word [es:_wlcalc_wrt_pointer], -1
  1719 00000A63 837EFE08                	cmp word [bp + ?do], _wlcalc_do_wrt
  1720 00000A67 7543                    	jne .notwrt
  1721                                  
  1722 00000A69 B45F                    	mov ah, '_'
  1723 00000A6B 803C40                  	cmp byte [si], '@'
  1724 00000A6E 750E                    	jne @F
  1725 00000A70 46                      	inc si
  1726 00000A71 AC                      	lodsb
  1727 00000A72 88C4                    	mov ah, al
  1728 00000A74 84C0                    	test al, al
  1729 00000A76 7506                    	jnz @F
  1730 00000A78 B86A00                  	mov ax, _WLCALC_QUOTE_NUL_ERR
  1731 00000A7B E9A3FE                  	jmp .wlcalc_error
  1732                                  @@:
  1733 00000A7E E88F00                  	call .get_seg_ext_name_ah
  1734                                  @@:
  1735 00000A81 AC                      	lodsb
  1736 00000A82 38E0                    	cmp al, ah
  1737 00000A84 74FB                    	je @B
  1738 00000A86 3C5F                    	cmp al, '_'
  1739 00000A88 74F7                    	je @B
  1740 00000A8A 4E                      	dec si
  1741 00000A8B 1E                      	push ds
  1742 00000A8C E8E303                  	call _wlcalc_get_segdef_entry
  1743 00000A8F 730A                    	jnc @F
  1744 00000A91 E82A04                  	call _wlcalc_get_grpdef_entry
  1745 00000A94 7305                    	jnc @F
  1746 00000A96 1E                      	push ds
  1747 00000A97 07                      	pop es
  1748 00000A98 E90501                  	jmp .seg_not_found_error
  1749                                  @@:
  1750 00000A9B 891E[0A00]              	mov word [_wlcalc_wrt_pointer], bx
  1751 00000A9F 8C06[0C00]              	mov word [_wlcalc_wrt_pointer + 2], es
  1752 00000AA3 1E                      	 push ds
  1753 00000AA4 07                      	 pop es
  1754 00000AA5 1F                      	pop ds
  1755 00000AA6 BB[6A00]                	mov bx, _wlcalc_do_table.ext - 4
  1756 00000AA9 E82F00                  	call .getdo_bx
  1757                                  
  1758                                  .notwrt:
  1759 00000AAC 837EFE07                	cmp word [bp + ?do], _wlcalc_do_opext
  1760 00000AB0 757D                    	jne .notopext
  1761                                  
  1762 00000AB2 E82300                  	call .getdo
  1763 00000AB5 837EFE08                	cmp word [bp + ?do], _wlcalc_highest_seg_ext
  1764 00000AB9 7703E9FD00              	jbe .unknown_opext_invalid
  1765 00000ABE E84D00                  	call .get_seg_ext_name
  1766 00000AC1 06                      	push es
  1767 00000AC2 1F                      	pop ds			; => DGROUP
  1768                                  
  1769 00000AC3 803E[0400]00            	cmp byte [_wlcalc_create_relocations], 0
  1770 00000AC8 7403E98703              	jne .mismatch_pop	; do it later only -->
  1771                                  
  1772 00000ACD E83C04                  	call _wlcalc_perform_fixup
  1773 00000AD0 7303E9D300              	jc .wlcalc_error_j1
  1774                                  		; dx:ax = number
  1775 00000AD5 E9C001                  	jmp .ext_common
  1776                                  
  1777                                  .getdo:
  1778 00000AD8 BB[2A00]                	mov bx, _wlcalc_do_table - 4
  1779                                  .getdo_bx:
  1780 00000ADB 89F2                    	mov dx, si
  1781                                  .getdoloop:
  1782 00000ADD 83C304                  	add bx, 4
  1783 00000AE0 268B3F                  	mov di, [es:bx]
  1784 00000AE3 85FF                    	test di, di
  1785 00000AE5 7503E9D600              	jz .unknown_do
  1786 00000AEA 89D6                    	mov si, dx
  1787                                  @@:
  1788 00000AEC A6                      	cmpsb
  1789 00000AED 7509                    	jne .checkdo
  1790 00000AEF 807CFF00                	cmp byte [si - 1], 0
  1791 00000AF3 75F7                    	jne @B
  1792 00000AF5 E9CD00                  	jmp .unknown_do_only
  1793                                  
  1794                                  .checkdo:
  1795 00000AF8 26807DFF00              	cmp byte [es:di - 1], 0
  1796 00000AFD 75DE                    	jne .getdoloop
  1797 00000AFF 26FF7702                	push word [es:bx + 2]
  1798 00000B03 8F46FE                  	pop word [bp + ?do]
  1799                                  
  1800 00000B06 4E                      	dec si
  1801                                  @@:
  1802 00000B07 AC                      	lodsb
  1803 00000B08 3C5F                    	cmp al, '_'
  1804 00000B0A 74FB                    	je @B
  1805 00000B0C 4E                      	dec si
  1806 00000B0D C3                      	retn
  1807                                  
  1808                                  
  1809                                  .get_seg_ext_name:
  1810 00000B0E B400                    	mov ah, 0
  1811                                  .get_seg_ext_name_ah:
  1812 00000B10 89F2                    	mov dx, si
  1813                                  @@:
  1814 00000B12 AC                      	lodsb
  1815 00000B13 38E0                    	cmp al, ah
  1816 00000B15 7408                    	je @F
  1817 00000B17 3C00                    	cmp al, 0
  1818 00000B19 7404                    	je @F
  1819 00000B1B 3C3F                    	cmp al, '?'
  1820 00000B1D 75F3                    	jne @B
  1821                                  @@:
  1822 00000B1F 4E                      	dec si
  1823 00000B20 89F1                    	mov cx, si
  1824 00000B22 29D1                    	sub cx, dx
  1825 00000B24 89D6                    	mov si, dx
  1826                                  
  1827                                  %if 0
  1828                                  	push ax
  1829                                  	mov ah, 40h
  1830                                  	mov bx, 1
  1831                                  	int 21h
  1832                                  	mov ah, 02h
  1833                                  	mov dl, 13
  1834                                  	int 21h
  1835                                  	mov ah, 02h
  1836                                  	mov dl, 10
  1837                                  	int 21h
  1838                                  	pop ax
  1839                                  %endif
  1840                                  
  1841 00000B26 BF[0000]                	mov di, name_field
  1842 00000B29 F3A4                    	rep movsb
  1843 00000B2B B000                    	mov al, 0
  1844 00000B2D AA                      	stosb
  1845 00000B2E C3                      	retn
  1846                                  
  1847                                  
  1848                                  .notopext:
  1849 00000B2F 837EFE04                	cmp word [bp + ?do], _wlcalc_do_minusext
  1850 00000B33 7438                    	je @F
  1851 00000B35 837EFE03                	cmp word [bp + ?do], _wlcalc_do_ext
  1852 00000B39 7432                    	je @F
  1853 00000B3B 837EFE06                	cmp word [bp + ?do], _wlcalc_do_minusextpara
  1854 00000B3F 742C                    	je @F
  1855 00000B41 837EFE05                	cmp word [bp + ?do], _wlcalc_do_extpara
  1856 00000B45 7426                    	je @F
  1857 00000B47 837EFE02                	cmp word [bp + ?do], _wlcalc_do_minussegrel
  1858 00000B4B 7420                    	je @F
  1859 00000B4D 837EFE01                	cmp word [bp + ?do], _wlcalc_do_segrel
  1860 00000B51 741A                    	je @F
  1861 00000B53 837EFE00                	cmp word [bp + ?do], _wlcalc_do_seg
  1862 00000B57 7403E94301              	jne .notseg
  1863 00000B5C 837EFC02                	cmp word [bp + ?size], 2
  1864 00000B60 7568                    	jne .unknown_seg_nonword
  1865 00000B62 26833E[0E00]FF          	cmp word [es:_wlcalc_offset], -1
  1866 00000B68 7503E9D7FD              	je .overflow
  1867                                  @@:
  1868 00000B6D E89EFF                  	call .get_seg_ext_name
  1869 00000B70 837EFE04                	cmp word [bp + ?do], _wlcalc_do_minusext
  1870 00000B74 7503E9DA00              	je .ext
  1871 00000B79 837EFE03                	cmp word [bp + ?do], _wlcalc_do_ext
  1872 00000B7D 7503E9D100              	je .ext
  1873 00000B82 837EFE06                	cmp word [bp + ?do], _wlcalc_do_minusextpara
  1874 00000B86 7503E9C800              	je .ext
  1875 00000B8B 837EFE05                	cmp word [bp + ?do], _wlcalc_do_extpara
  1876 00000B8F 7503E9BF00              	je .ext
  1877 00000B94 E8DB02                  	call _wlcalc_get_segdef_entry
  1878 00000B97 7359                    	jnc @F
  1879 00000B99 E82203                  	call _wlcalc_get_grpdef_entry
  1880 00000B9C 7354                    	jnc @F
  1881 00000B9E 1E                      	push ds
  1882 00000B9F 07                      	pop es
  1883                                  .seg_not_found_error:
  1884 00000BA0 B85800                  	mov ax, _WLCALC_SEG_NOT_FOUND_ERR
  1885 00000BA3 EB03                    	jmp .wlcalc_error_j1
  1886                                  
  1887                                  .unknown_size:
  1888 00000BA5 B85900                  	mov ax, _WLCALC_UNKNOWN_SIZE_ERR
  1889                                  .wlcalc_error_j1:
  1890 00000BA8 E976FD                  	jmp .wlcalc_error
  1891                                  
  1892                                  .unknown_size_only:
  1893 00000BAB B85A00                  	mov ax, _WLCALC_MISSING_OPERATION_ERR
  1894 00000BAE EBF8                    	jmp .wlcalc_error_j1
  1895                                  
  1896                                  .overflow_pass:
  1897 00000BB0 B85B00                  	mov ax, _WLCALC_OVERFLOW_PASS_ERR
  1898                                  .wlcalc_always_error_j1:
  1899 00000BB3 E991FD                  	jmp .wlcalc_always_error
  1900                                  
  1901                                  .unknown_invalid_pass:
  1902 00000BB6 B85C00                  	mov ax, _WLCALC_INVALID_PASS_ERR
  1903 00000BB9 EBED                    	jmp .wlcalc_error_j1
  1904                                  
  1905                                  .unknown_opext_invalid:
  1906 00000BBB B85D00                  	mov ax, _WLCALC_OPEXT_INVALID_ERR
  1907 00000BBE EBE8                    	jmp .wlcalc_error_j1
  1908                                  
  1909                                  .unknown_do:
  1910 00000BC0 B85F00                  	mov ax, _WLCALC_UNKNOWN_DO_ERR
  1911 00000BC3 EBE3                    	jmp .wlcalc_error_j1
  1912                                  
  1913                                  .unknown_do_only:
  1914 00000BC5 B86000                  	mov ax, _WLCALC_MISSING_OPERAND_ERR
  1915 00000BC8 EBDE                    	jmp .wlcalc_error_j1
  1916                                  
  1917                                  .unknown_seg_nonword:
  1918 00000BCA B86100                  	mov ax, _WLCALC_SEG_NOT_WORD_ERR
  1919 00000BCD EBD9                    	jmp .wlcalc_error_j1
  1920                                  
  1921                                  .overflow_constant:
  1922 00000BCF B86200                  	mov ax, _WLCALC_OVERFLOW_CONSTANT_ERR
  1923 00000BD2 EBDF                    	jmp .wlcalc_always_error_j1
  1924                                  
  1925                                  .unknown_invalid_constant:
  1926 00000BD4 B86300                  	mov ax, _WLCALC_INVALID_CONSTANT_ERR
  1927 00000BD7 EBCF                    	jmp .wlcalc_error_j1
  1928                                  
  1929                                  .unknown_repeat_only:
  1930 00000BD9 B86400                  	mov ax, _WLCALC_MISSING_REPEAT_ERR
  1931 00000BDC EBCA                    	jmp .wlcalc_error_j1
  1932                                  
  1933                                  .overflow_repeat:
  1934 00000BDE B86500                  	mov ax, _WLCALC_OVERFLOW_REPEAT_ERR
  1935 00000BE1 EBD0                    	jmp .wlcalc_always_error_j1
  1936                                  
  1937                                  .unknown_invalid_repeat:
  1938 00000BE3 B86600                  	mov ax, _WLCALC_INVALID_REPEAT_ERR
  1939 00000BE6 EBC0                    	jmp .wlcalc_error_j1
  1940                                  
  1941                                  .unknown_pass_only:
  1942 00000BE8 B86700                  	mov ax, _WLCALC_MISSING_PASS_ERR
  1943 00000BEB EBBB                    	jmp .wlcalc_error_j1
  1944                                  
  1945                                  .unknown_trailer:
  1946 00000BED B86800                  	mov ax, _WLCALC_UNKNOWN_TRAILER_ERR
  1947 00000BF0 EBB6                    	jmp .wlcalc_error_j1
  1948                                  
  1949                                  @@:
  1950 00000BF2 803E[0400]00            	cmp byte [_wlcalc_create_relocations], 0
  1951 00000BF7 742C                    	je .seg_value
  1952 00000BF9 837EFE00                	cmp word [bp + ?do], _wlcalc_do_seg
  1953 00000BFD 7523                    	jne .skip		; segrel or minussegrel -->
  1954                                  
  1955 00000BFF A1[1000]                	mov ax, word [_wlcalc_segment]
  1956 00000C02 31D2                    	xor dx, dx
  1957 00000C04 A3[0000]                	mov word [data_segment], ax
  1958 00000C07 B90400                  	mov cx, 4
  1959                                  @@:
  1960 00000C0A 01C0                    	add ax, ax
  1961 00000C0C 11D2                    	adc dx, dx
  1962 00000C0E E2FA                    	loop @B
  1963 00000C10 0306[0E00]              	add ax, word [_wlcalc_offset]
  1964 00000C14 11CA                    	adc dx, cx
  1965                                  
  1966 00000C16 A3[0000]                	mov word [data_offset], ax
  1967 00000C19 8916[0200]              	mov word [data_offset + 2], dx
  1968 00000C1D 31D2                    	xor dx, dx
  1969                                   extern make_reloc_entry
  1970 00000C1F E8(0000)                	call make_reloc_entry
  1971                                  .skip:
  1972 00000C22 E92F02                  	jmp .mismatch_pop
  1973                                  
  1974                                  .seg_value:
  1975 00000C25 268B07                      mov ax,[es:bx + 0]           ; get low word of segment offset
  1976 00000C28 268B5F02                    mov bx,[es:bx + 2]           ; get high word of segment offset
  1977 00000C2C D1EB                        shr bx,1
  1978 00000C2E D1D8                        rcr ax,1                ; /2
  1979 00000C30 D1EB                        shr bx,1
  1980 00000C32 D1D8                        rcr ax,1                ; /4
  1981 00000C34 D1EB                        shr bx,1
  1982 00000C36 D1D8                        rcr ax,1                ; /8
  1983 00000C38 D1EB                        shr bx,1
  1984 00000C3A D1D8                        rcr ax,1                ; /16, have paragraph value of offset (segment value)
  1985 00000C3C 53                      	push bx
  1986 00000C3D 50                      	push ax
  1987 00000C3E 837EFE02                	cmp word [bp + ?do], _wlcalc_do_minussegrel
  1988 00000C42 C746FE[7A13]            	mov word [bp + ?do], _wlcalc_do_add
  1989 00000C47 7505                    	jne @F			; not minussegrel -->
  1990 00000C49 C746FE[8313]            	mov word [bp + ?do], _wlcalc_do_sub
  1991                                  @@:
  1992 00000C4E 1E                      	push ds
  1993 00000C4F 07                      	pop es			; => DGROUP
  1994 00000C50 E90601                  	jmp .norepeat
  1995                                  
  1996                                  .ext:
  1997 00000C53 06                      	push es
  1998 00000C54 1F                      	pop ds			; => DGROUP
  1999                                  
  2000 00000C55 803E[0400]00            	cmp byte [_wlcalc_create_relocations], 0
  2001 00000C5A 7403E9F501              	jne .mismatch_pop	; do it later only -->
  2002                                  
  2003 00000C5F E8AA02                  	call _wlcalc_perform_fixup
  2004 00000C62 7303E941FF              	jc .wlcalc_error_j1
  2005                                  		; dx:ax = number
  2006 00000C67 837EFE05                	cmp word [bp + ?do], _wlcalc_do_extpara
  2007 00000C6B 7406                    	je .extpara
  2008 00000C6D 837EFE06                	cmp word [bp + ?do], _wlcalc_do_minusextpara
  2009 00000C71 750F                    	jne .not_extpara
  2010                                  .extpara:
  2011 00000C73 B90400                  	mov cx, 4
  2012 00000C76 83C00F                  	add ax, 15
  2013 00000C79 83D200                  	adc dx, 0
  2014                                  @@:
  2015 00000C7C D1EA                    	shr dx, 1
  2016 00000C7E D1D8                    	rcr ax, 1
  2017 00000C80 E2FA                    	loop @B
  2018                                  .not_extpara:
  2019 00000C82 837EFE06                	cmp word [bp + ?do], _wlcalc_do_minusextpara
  2020 00000C86 740B                    	je .minusext
  2021 00000C88 837EFE04                	cmp word [bp + ?do], _wlcalc_do_minusext
  2022 00000C8C C746FE[7A13]            	mov word [bp + ?do], _wlcalc_do_add
  2023 00000C91 7505                    	jne @F			; not minusext -->
  2024                                  .minusext:
  2025 00000C93 C746FE[8313]            	mov word [bp + ?do], _wlcalc_do_sub
  2026                                  @@:
  2027                                  .ext_common:
  2028 00000C98 52                      	push dx
  2029 00000C99 50                      	push ax
  2030 00000C9A 1E                      	push ds
  2031 00000C9B 07                      	pop es			; => DGROUP
  2032 00000C9C E9BA00                  	jmp .norepeat
  2033                                  
  2034                                  .notseg:
  2035 00000C9F E85F05                  	call _wlcalc_parse_number
  2036 00000CA2 7308                    	jnc @F
  2037 00000CA4 7503E926FF              	jz .overflow_constant
  2038 00000CA9 E928FF                  	jmp .unknown_invalid_constant
  2039                                  
  2040                                  @@:
  2041 00000CAC 52                      	 push dx
  2042 00000CAD 50                      	 push ax
  2043                                  	lvar dword, number
  2044                                  
  2045 00000CAE 803C3F                  	cmp byte [si], '?'
  2046 00000CB1 7503E9A300              	je .norepeat
  2047 00000CB6 803C00                  	cmp byte [si], 0
  2048 00000CB9 7503E99B00              	je .norepeat
  2049                                  
  2050                                  @@:
  2051 00000CBE AC                      	lodsb
  2052 00000CBF 3C5F                    	cmp al, '_'
  2053 00000CC1 74FB                    	je @B
  2054 00000CC3 4E                      	dec si
  2055 00000CC4 89F2                    	mov dx, si
  2056 00000CC6 BF[DD00]                	mov di, string_repeat
  2057                                  @@:
  2058 00000CC9 A6                      	cmpsb
  2059 00000CCA 7509                    	jne .checkrepeat
  2060 00000CCC 807CFF00                	cmp byte [si - 1], 0
  2061 00000CD0 75F7                    	jne @B
  2062 00000CD2 E904FF                  	jmp .unknown_repeat_only
  2063                                  
  2064                                  .checkrepeat:
  2065 00000CD5 26807DFF00              	cmp byte [es:di - 1], 0
  2066 00000CDA 752C                    	jne .trypass
  2067                                  
  2068 00000CDC 4E                      	dec si
  2069                                  @@:
  2070 00000CDD AC                      	lodsb
  2071 00000CDE 3C5F                    	cmp al, '_'
  2072 00000CE0 74FB                    	je @B
  2073 00000CE2 4E                      	dec si
  2074 00000CE3 E81B05                  	call _wlcalc_parse_number
  2075 00000CE6 7308                    	jnc @F
  2076 00000CE8 7503E9F1FE              	jz .overflow_repeat
  2077 00000CED E9F3FE                  	jmp .unknown_invalid_repeat
  2078                                  
  2079                                  @@:
  2080 00000CF0 8946E8                  	mov word [bp + ?repeat], ax
  2081 00000CF3 8956EA                  	mov word [bp + ?repeat + 2], dx
  2082                                  
  2083 00000CF6 803C3F                  	cmp byte [si], '?'
  2084 00000CF9 745E                    	je .gotrepeat
  2085 00000CFB 803C00                  	cmp byte [si], 0
  2086 00000CFE 7459                    	je .gotrepeat
  2087                                  
  2088                                  @@:
  2089 00000D00 AC                      	lodsb
  2090 00000D01 3C5F                    	cmp al, '_'
  2091 00000D03 74FB                    	je @B
  2092 00000D05 4E                      	dec si
  2093 00000D06 89F2                    	mov dx, si
  2094                                  .trypass:
  2095 00000D08 89D6                    	mov si, dx
  2096 00000D0A BF[E400]                	mov di, string_pass
  2097                                  @@:
  2098 00000D0D A6                      	cmpsb
  2099 00000D0E 7509                    	jne .checkpass
  2100 00000D10 807CFF00                	cmp byte [si - 1], 0
  2101 00000D14 75F7                    	jne @B
  2102 00000D16 E9CFFE                  	jmp .unknown_pass_only
  2103                                  
  2104                                  .checkpass:
  2105 00000D19 26807DFF00              	cmp byte [es:di - 1], 0
  2106 00000D1E 7403E9CAFE              	jne .unknown_trailer
  2107                                  
  2108 00000D23 4E                      	dec si
  2109                                  @@:
  2110 00000D24 AC                      	lodsb
  2111 00000D25 3C5F                    	cmp al, '_'
  2112 00000D27 74FB                    	je @B
  2113 00000D29 4E                      	dec si
  2114 00000D2A E8D404                  	call _wlcalc_parse_number
  2115 00000D2D 7308                    	jnc @F
  2116 00000D2F 7503E97CFE              	jz .overflow_pass
  2117 00000D34 E97FFE                  	jmp .unknown_invalid_pass
  2118                                  
  2119                                  @@:
  2120 00000D37 803C3F                  	cmp byte [si], '?'
  2121 00000D3A 7408                    	je @F
  2122 00000D3C 803C00                  	cmp byte [si], 0
  2123 00000D3F 7403                    	je @F
  2124 00000D41 E9DAFB                  	jmp .unknown
  2125                                  
  2126                                  @@:
  2127 00000D44 85D2                    	test dx, dx
  2128 00000D46 7403E965FE              	jnz .overflow_pass
  2129 00000D4B 06                      	push es
  2130 00000D4C 1F                      	pop ds		; => DGROUP
  2131 00000D4D 3906[0A00]              	cmp word [_wlcalc_maximum_pass], ax
  2132 00000D51 7303                    	jae @F
  2133 00000D53 A3[0A00]                	mov word [_wlcalc_maximum_pass], ax
  2134                                  @@:
  2135 00000D56 8946EC                  	mov word [bp + ?pass], ax
  2136                                  
  2137                                  .gotrepeat:
  2138                                  .norepeat:
  2139 00000D59 06                      	push es
  2140 00000D5A 1F                      	pop ds		; => DGROUP
  2141                                  
  2142 00000D5B 803E[0400]00            	cmp byte [_wlcalc_create_relocations], 0
  2143 00000D60 7403E9EF00              	jne .mismatch_pop
  2144                                  
  2145 00000D65 A1[0800]                	mov ax, word [_wlcalc_pass]
  2146 00000D68 3946EC                  	cmp word [bp + ?pass], ax
  2147 00000D6B 7403E9E400              	jne .repeatzero
  2148                                  
  2149 00000D70 8B46E8                  	mov ax, word [bp + ?repeat]
  2150 00000D73 8B56EA                  	mov dx, word [bp + ?repeat + 2]
  2151 00000D76 09D0                    	or ax, dx
  2152 00000D78 7503E9D700              	jz .repeatzero
  2153                                  
  2154 00000D7D B90400                  	mov cx, 4
  2155 00000D80 A1[1800]                	mov ax, [exe_header.eh_hsize]	; = 0 if generating a .COM file
  2156 00000D83 31D2                    	xor dx, dx
  2157                                  @@:
  2158 00000D85 01C0                    	add ax, ax
  2159 00000D87 11D2                    	adc dx, dx
  2160 00000D89 E2FA                    	loop @B
  2161                                  
  2162 00000D8B 31F6                    	xor si, si
  2163 00000D8D 8B3E[1000]              	mov di, word [_wlcalc_segment]
  2164 00000D91 B104                    	mov cl, 4
  2165                                  @@:
  2166 00000D93 01FF                    	add di, di
  2167 00000D95 11F6                    	adc si, si
  2168 00000D97 E2FA                    	loop @B
  2169                                  
  2170 00000D99 01F8                    	add ax, di
  2171 00000D9B 11F2                    	adc dx, si
  2172 00000D9D 7303E9A2FB              	jc .overflow
  2173 00000DA2 0306[0E00]              	add ax, word [_wlcalc_offset]
  2174 00000DA6 83D200                  	adc dx, 0
  2175 00000DA9 7303E996FB              	jc .overflow
  2176                                  
  2177 00000DAE 803E[0000]00            	cmp byte [is_comfile], 0	; check if .COM file
  2178 00000DB3 740C                    	je @F				; no -->
  2179 00000DB5 2B06[0000]              	sub ax, [comfile_cut_length]
  2180 00000DB9 83DA00                  	sbb dx, 0			; adjust for .COM file entry
  2181 00000DBC 7303E983FB              	jc .overflow			; mustn't write before SOF -->
  2182                                  
  2183                                  @@:
  2184 00000DC1 8B1E[1800]              	mov bx, [exe_handle]
  2185 00000DC5 92                      	xchg dx, ax		; ax:dx
  2186 00000DC6 91                      	xchg cx, ax		; cx:dx
  2187 00000DC7 B80042                  	mov ax, 4200h
  2188 00000DCA CD21                    	int 21h
  2189 00000DCC E8(0000)                    call restore_ems_map
  2190 00000DCF 7308                        jnc @F
  2191                                  pws_exe_error: equ $
  2192 00000DD1 06                      	push es
  2193 00000DD2 1F                      	pop ds		; => DGROUP
  2194 00000DD3 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
  2195 00000DD6 E9(0000)                    jmp NEAR PTR dos_error
  2196                                  @@:
  2197                                  
  2198                                  .repeat:
  2199 00000DD9 31C0                    	xor ax, ax
  2200 00000DDB 8946F2                  	mov word [bp + ?buffer], ax
  2201 00000DDE 8946F4                  	mov word [bp + ?buffer + 2], ax
  2202 00000DE1 16                      	push ss
  2203 00000DE2 1F                      	pop ds
  2204 00000DE3 8D56F2                  	lea dx, [bp + ?buffer]
  2205 00000DE6 8B4EFC                  	mov cx, word [bp + ?size]
  2206 00000DE9 B43F                    	mov ah, 3Fh
  2207 00000DEB CD21                    	int 21h
  2208 00000DED E8(0000)                    call restore_ems_map
  2209 00000DF0 72DF                    	jc pws_exe_error
  2210 00000DF2 39C8                    	cmp ax, cx
  2211 00000DF4 B8FEFF                  	mov ax, -2		; short read code
  2212 00000DF7 75D8                    	jne pws_exe_error
  2213                                  
  2214 00000DF9 89CA                    	mov dx, cx			; = size
  2215 00000DFB F7DA                    	neg dx				; = minus size
  2216 00000DFD B9FFFF                  	mov cx, -1			; sign-extend
  2217 00000E00 B80142                  	mov ax, 4201h
  2218 00000E03 CD21                    	int 21h				; seek back
  2219 00000E05 E8(0000)                    call restore_ems_map
  2220 00000E08 72C7                    	jc pws_exe_error
  2221                                  
  2222 00000E0A 06                      	push es
  2223 00000E0B 1F                      	pop ds		; => DGROUP
  2224 00000E0C 8B5EE6                  	mov bx, word [bp + ?number + 2]
  2225 00000E0F 8B4EE4                  	mov cx, word [bp + ?number]
  2226 00000E12 8B56F4                  	mov dx, word [bp + ?buffer + 2]
  2227 00000E15 8B46F2                  	mov ax, word [bp + ?buffer + 0]
  2228 00000E18 FF56FE                  	call near [bp + ?do]
  2229 00000E1B 8B1E[1800]              	mov bx, [exe_handle]
  2230 00000E1F 7303E920FB              	jc .overflow
  2231 00000E24 8956F4                  	mov word [bp + ?buffer + 2], dx
  2232 00000E27 8946F2                  	mov word [bp + ?buffer + 0], ax
  2233                                  
  2234 00000E2A 16                      	push ss
  2235 00000E2B 1F                      	pop ds
  2236 00000E2C 8D56F2                  	lea dx, [bp + ?buffer]
  2237 00000E2F 8B4EFC                  	mov cx, word [bp + ?size]
  2238 00000E32 B440                    	mov ah, 40h
  2239 00000E34 CD21                    	int 21h
  2240 00000E36 E8(0000)                    call restore_ems_map
  2241 00000E39 7296                    	jc pws_exe_error
  2242 00000E3B 39C8                    	cmp ax, cx
  2243 00000E3D B82700                  	mov ax, 27h			; insufficient disk space error
  2244 00000E40 758F                    	jne pws_exe_error
  2245                                  
  2246                                  		; After a successful write, the file seek points past
  2247                                  		;  the written element. This is used by the REPEAT
  2248                                  		;  wlcalc to find the next element on which to operate.
  2249 00000E42 836EE801                	sub word [bp + ?repeat], 1
  2250 00000E46 7406                    	jz @F
  2251                                  .nextsbb:
  2252 00000E48 835EE800                	sbb word [bp + ?repeat], 0
  2253                                  .repeat_j:
  2254 00000E4C EB8B                    	jmp .repeat
  2255                                  @@:
  2256 00000E4E 835EE800                	sbb word [bp + ?repeat], 0
  2257 00000E52 75F8                    	jnz .repeat_j
  2258                                  
  2259                                  .repeatzero:
  2260                                  .mismatch_pop:
  2261 00000E54 89EC5D                  	lleave
  2262 00000E57 5B                      	pop bx
  2263 00000E58 5F                      	pop di
  2264 00000E59 5E                      	pop si
  2265 00000E5A 07                      	pop es
  2266 00000E5B 1F                      	pop ds
  2267                                  %if 0
  2268                                      mov dx,di               ; save -> name
  2269                                      xor cx,cx               ; cx will hold of chars in name
  2270                                  
  2271                                  pws_loop:
  2272                                      cmp BYTE PTR [di],0     ; see if zero terminator in symbol name found
  2273                                      je  pws_5                ; yes
  2274                                      inc cx                  ; bump count of chars in string
  2275                                      inc di                  ; move to next char slot to test
  2276                                      jmp SHORT pws_loop       ; loop back to test next char
  2277                                  %endif
  2278                                  
  2279                                  pws_5:
  2280 00000E5C 1F                          pop ds                  ; restore ds -> machlink data
  2281                                  
  2282                                  pws_next_entry:
  2283 00000E5D 8CC0                        mov ax,es               ; ax -> current entry
  2284 00000E5F 4E                          dec si                  ; drop count of entries in block
  2285 00000E60 7403                        je  pws_next_block       ; no more entries try next block
  2286 00000E62 E995F9                      jmp NEAR PTR pws_entloop ; print next entry
  2287                                  
  2288                                  pws_next_block:
  2289 00000E65 07                          pop es                  ; restore es -> block
  2290 00000E66 26A10200                    mov ax,[es:2]           ; get pointer to next block, if any
  2291 00000E6A 09C0                        or  ax,ax               ; check if non-null
  2292 00000E6C 7403                        je  pws_communal_chk     ; null, check communals
  2293 00000E6E E981F9                      jmp NEAR PTR pws_blkloop ; loop back for more publics
  2294                                  
  2295                                  pws_communal_chk:
  2296                                  %if 0
  2297                                      inc byte [comm_loop_flag]      ; bump counter
  2298                                      cmp byte [comm_loop_flag],1    ; see if communal blocks printed yet
  2299                                      ja  pws_ret              ; yes
  2300                                      mov ax,[first_cdeclblk_ptr]   ; get pointer to first communal declarations block
  2301                                      or  ax,ax               ; check if non-null
  2302                                      je  pws_ret              ; null, done
  2303                                      jmp NEAR PTR pws_blkloop ; non-null, print declarations in communal block
  2304                                  %endif
  2305                                  
  2306                                  pws_ret:
  2307 00000E71 C3                          ret
  2308                                  
  2309                                  
  2310                                  		; Find a segdef entry (SEG_DEFENT_STRUC) from name
  2311                                  		;
  2312                                  		; INP:	name_field -> ASCIZ name
  2313                                  		; OUT:	NC if found,
  2314                                  		;	 ax = es => segment of entry
  2315                                  		;	 dword [es:bx] = segdef's offset from start of program
  2316                                  		;	CY if not found
  2317                                  		;	ds => DGROUP
  2318                                  		; CHG:	ax, bx, es, ds
  2319                                  		; REM:	based on get_segdef_entry in mlpass1b.nas
  2320                                  _wlcalc_get_segdef_entry:
  2321 00000E72 52                          push    dx
  2322 00000E73 56                          push    si
  2323 00000E74 57                          push    di
  2324 00000E75 B8[ssss]                	mov ax, DGROUP		; get warplink's data segment
  2325 00000E78 8ED8                        mov ds,ax               ; ds => warplink data
  2326 00000E7A BE[0000]                    mov si,OFFSET name_field wrt DGROUP ; si -> name to get hash code of
  2327                                   extern get_hash
  2328 00000E7D E8(0000)                    call    get_hash        ; get hash code of name
  2329 00000E80 BE[0000]                    mov si,OFFSET segdef_hash wrt DGROUP   ; si -> base of hash pointers to segdef entries
  2330 00000E83 D1E0                        shl ax,1                ; convert ax to word offset
  2331 00000E85 01C6                        add si,ax               ; si points to proper name hash code entry
  2332 00000E87 833C00                      cmp WORD PTR [si],0     ; is hash code used (nonzero value)
  2333 00000E8A 742A                    	je wgse_ret_CY
  2334                                  
  2335                                  ; hash code used, check whether duplicate name or hash collision
  2336                                  wgse_2:
  2337                                  wgse_2a:
  2338 00000E8C 8B04                        mov ax,[si]             ; get segment pointer to segdef entry
  2339                                  
  2340                                  wgse_testloop:
  2341 00000E8E 8EC0                        mov es,ax               ; es -> segment of segdef entry testing name against
  2342 00000E90 93                          xchg bx,ax               ; save entry segment in bx
  2343 00000E91 26C43E0800                  les di,[es:8]           ; -> segment name in lnames block
  2344 00000E96 83C708                      add di,8                ; adjust for 2 doubleword pointers in front of name
  2345 00000E99 BE[0000]                    mov si,OFFSET name_field wrt DGROUP ; si -> name to get hash code of
  2346                                  
  2347                                  ; ds:si -> name, es:di -> name to test against
  2348                                  wgse_byteloop:
  2349 00000E9C 8A04                        mov al,[si]
  2350 00000E9E 260A05                      or  al,[es:di]          ; see if both values are zero (matched to null terminator)
  2351 00000EA1 740F                        je  wgse_match           ; strings matched
  2352 00000EA3 A6                          cmpsb                   ; compare a nonzero byte in the two names
  2353 00000EA4 74F6                        je  wgse_byteloop        ; bytes match, loop for next byte test
  2354 00000EA6 8EC3                        mov es,bx               ; get segdef entry segment value
  2355                                  
  2356                                  wgse_next_ptr:
  2357 00000EA8 26A11400                    mov ax,[es:20]          ; get next entry
  2358 00000EAC 09C0                        or  ax,ax               ; check if a null pointer (ax=0)
  2359 00000EAE 75DE                        jne wgse_testloop        ; no, keep checking entries
  2360 00000EB0 EB04                    	jmp wgse_ret_CY
  2361                                  
  2362                                  ; segment names match, check class names
  2363                                  wgse_match:
  2364 00000EB2 8EC3                        mov es,bx               ; get segdef entry segment value
  2365 00000EB4 93                          xchg ax, bx			; also return ax
  2366 00000EB5 A8                      	db __TEST_IMM8		; NC, skip stc
  2367                                  wgse_ret_CY:
  2368 00000EB6 F9                      	stc
  2369 00000EB7 5F                          pop di                  ; restore critical registersr
  2370 00000EB8 5E                          pop si
  2371 00000EB9 5A                          pop dx
  2372 00000EBA BB0200                  	mov bx, sdes_offset
  2373 00000EBD C3                          ret
  2374                                  
  2375                                  
  2376                                  		; Find a grpdef entry (GRP_ENT_STRUC) from name
  2377                                  		;
  2378                                  		; INP:	name_field -> ASCIZ name
  2379                                  		; OUT:	NC if found,
  2380                                  		;	 ax = es => GRP_ENT_STRUC entry
  2381                                  		;	 dword [es:bx] = grpdef's offset from start of program
  2382                                  		;	CY else
  2383                                  		; CHG:	ax, bx, es
  2384                                  		; STT:	ds => DGROUP
  2385                                  		; REM:	based on get_group_entry in mlpass1c.nas
  2386                                  _wlcalc_get_grpdef_entry:
  2387 00000EBE 51                          push    cx
  2388 00000EBF 52                          push    dx
  2389 00000EC0 57                          push    di
  2390 00000EC1 56                          push si
  2391                                  
  2392 00000EC2 A1[0000]                    mov ax,[alloc_grpblk_ptr]
  2393 00000EC5 85C0                        test ax, ax               ; check if any group blocks were previously allocated
  2394 00000EC7 7438                    	jz wgge_ret_CY
  2395                                  
  2396                                  wgge_2:
  2397 00000EC9 8EC0                        mov es,ax               ; es -> current block
  2398 00000ECB 31D2                        xor dx,dx               ; dx hold group entry number
  2399                                  
  2400 00000ECD A8                      	db __TEST_IMM8		; skip pop
  2401                                  wgge_nomatch:
  2402 00000ECE 07                          pop es                  ; restore es -> block
  2403                                  wgge_grp_loop:
  2404 00000ECF 263B160000                  cmp dx,[es:0]           ; check if any more entries in group block
  2405 00000ED4 720C                        jb  wgge_3               ; yes
  2406                                  
  2407                                  ; no more entries in group block, get next group block
  2408 00000ED6 26A10200                    mov ax,[es:2]           ; get pointer to next group
  2409 00000EDA 85C0                        test ax, ax               ; check if null, no more group blocks
  2410 00000EDC 7423                        jz wgge_ret_CY
  2411 00000EDE 8EC0                        mov es,ax               ; es -> new block
  2412 00000EE0 31D2                        xor dx,dx               ; re-init group entry number
  2413                                  
  2414                                  wgge_3:
  2415 00000EE2 06                          push    es              ; save es -> block
  2416 00000EE3 8CC0                        mov ax,es               ; get block segment address
  2417 00000EE5 01D0                        add ax,dx               ; get first free entry segment value
  2418 00000EE7 40                          inc ax                  ; adjust for block system info size of 1 paragraph
  2419 00000EE8 8EC0                        mov es,ax               ; es -> group entry
  2420 00000EEA 42                          inc dx                  ; bump entry number
  2421 00000EEB 26C43E0400              	les di, [es:ges_grp_nament_ptr]
  2422 00000EF0 83C708                  	add di, 8		; skip pointers
  2423 00000EF3 BE[0000]                	mov si, name_field
  2424                                  .loop:
  2425 00000EF6 A6                      	cmpsb			; compare byte
  2426 00000EF7 75D5                    	jne wgge_nomatch	; mismatch, try next entry -->
  2427 00000EF9 807CFF00                	cmp byte [si - 1], 0	; matched the NUL ?
  2428 00000EFD 75F7                    	jne .loop		; not yet -->
  2429                                  wgge_3a:
  2430                                  ; names match
  2431 00000EFF 5B                          pop bx                  ; trash old es value on stack
  2432 00000F00 A8                      	db __TEST_IMM8		; skip stc, NC
  2433                                  wgge_ret_CY:
  2434 00000F01 F9                      	stc
  2435                                  wgge_ret:
  2436 00000F02 8EC0                    	mov es, ax
  2437 00000F04 5E                      	pop si
  2438 00000F05 5F                          pop di
  2439 00000F06 5A                          pop dx
  2440 00000F07 59                          pop cx
  2441 00000F08 BB0000                  	mov bx, ges_offset
  2442 00000F0B C3                          ret
  2443                                  
  2444                                  
  2445                                   extern clipper_segindex, compress_this
  2446                                   extern current_segind, fixupp_offset_err, frame_ent_ptr, frame_method
  2447                                   extern frext_ingroup, gen_flags, is_abspub, is_absseg, is_ind_call
  2448                                   extern is_relocatable, is_resolved, loc, locat
  2449                                   extern no_fixbyte_flag, no_match_okay, targ_ent_ptr, target_disp
  2450                                   extern target_index, target_method, target_prog_off, target_segment
  2451                                  
  2452                                  		; Perform a fixup
  2453                                  		;
  2454                                  		; INP:	name_field -> ASCIZ extern label name
  2455                                  		;	word [_wlcalc_wrt_pointer] = -1 if no WRT clause parsed
  2456                                  		;	else:
  2457                                  		;	 dword [_wlcalc_wrt_pointer] -> dword WRT base
  2458                                  		;		(this is an executable image linear address that
  2459                                  		;		corresponds to the relative segment value to use)
  2460                                  		; OUT:	CY if not found,
  2461                                  		;	 ax = error code
  2462                                  		;	 if not found, _WLCALC_EXT_NOT_FOUND_ERR
  2463                                  		;	 if WRT clause parsed but absolute PUBDEF,
  2464                                  		;	  _WLCALC_ABS_WRT_ERR
  2465                                  		;	NC if found,
  2466                                  		;	 dx:ax = resolved extern label number
  2467                                  		;	does not return if internal error occurs (44 to 49)
  2468                                  		; CHG:	ax, bx, cx, dx, si, di
  2469                                  		; STT:	ds => DGROUP
  2470                                  		; REM:	based on mlpass2d.nas perform_fixup
  2471                                  _wlcalc_perform_fixup:
  2472 00000F0C 30C0                        xor al,al
  2473 00000F0E A2[0000]                    mov [is_absseg],al        ; init absolute flags
  2474 00000F11 A2[0000]                    mov [is_abspub],al
  2475 00000F14 B0C4                        mov al, 0C4h		; get low byte of locat field
  2476 00000F16 B400                        mov ah, 0
  2477 00000F18 A3[0000]                    mov [locat],ax            ; save locat field to memory variable
  2478                                  
  2479 00000F1B 88C2                        mov dl,al
  2480 00000F1D 80E21C                      and dl,1ch              ; get loc field
  2481 00000F20 D0EA                        shr dl,1
  2482 00000F22 D0EA                        shr dl,1                ; make loc value relative zero
  2483 00000F24 8816[0000]                  mov [loc],dl              ; save loc value
  2484                                  
  2485                                  %if 0
  2486                                      mov BYTE PTR [data_rec_offset],ah ; save bit 7-0 of data record offset in locat high byte
  2487                                      and al,3                ; get bit 9-8 of data record offset in locat low byte
  2488                                      mov BYTE PTR [data_rec_offset+1],al   ; and save it
  2489                                  %endif
  2490                                  
  2491 00000F28 B256                        mov dl, 56h			; get fix dat field
  2492 00000F2A 88D6                        mov dh,dl               ; dh holds fix dat field value
  2493 00000F2C 80E670                      and dh,70h              ; get frame field in dh
  2494                                  		; dh = 50h
  2495 00000F2F D0EE                        shr dh,1
  2496 00000F31 D0EE                        shr dh,1
  2497 00000F33 D0EE                        shr dh,1
  2498 00000F35 D0EE                        shr dh,1                ; make frame value relative zero
  2499                                  		; dh = 5h
  2500                                  
  2501                                  ; no thread field for frame
  2502 00000F37 80FE02                      cmp dh,2                ; see if index specified for this frame
  2503 00000F3A 7709                        ja  wpef_5               ; no
  2504                                  	;int3
  2505 00000F3C B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
  2506 00000F3F B92C00                      mov cx, 44              ; internal error value
  2507 00000F42 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  2508                                  
  2509                                  wpef_5:
  2510 00000F45 8836[0000]                  mov [frame_method],dh     ; frame method is the frame field
  2511                                  		; frame_method = 5
  2512                                  
  2513                                  wpef_6:
  2514 00000F49 88D0                        mov al,dl               ; get fix dat field
  2515 00000F4B A808                        test    al,8            ; check if thread field for target (tbit)
  2516 00000F4D 7519                        jne wpef_thrdtarg        ; yes
  2517                                  
  2518                                  ; no thread field for target
  2519                                  wpef_6b:
  2520                                  ;    mov [target_index],ax     ; target index, if any
  2521 00000F4F 88D0                        mov al,dl               ; get fix dat field
  2522 00000F51 2403                        and al,3                ; break out targt field
  2523                                  		; al = 2
  2524 00000F53 A2[0000]                    mov [target_method],al    ; target method is the targt field
  2525 00000F56 EB22                        jmp SHORT wpef_7         ; bypass target thread field code
  2526                                  
  2527                                  ; illegal frame method is 3, 6, or 7
  2528                                  wpef_bad_frame:
  2529 00000F58 88D9                        mov cl,bl
  2530 00000F5A B83500                      mov ax,FRAME_METH_ERR
  2531 00000F5D E9(0000)                    jmp NEAR PTR fixupp_offset_err  ; transfer control to error handler
  2532                                  
  2533                                  ; bad target method of 3 (prior to P bit modifier)
  2534                                  wpef_bad_target:
  2535 00000F60 88D9                        mov cl,bl
  2536 00000F62 B83600                      mov ax,TARGET_METH_ERR
  2537 00000F65 E9(0000)                    jmp NEAR PTR fixupp_offset_err  ; transfer control to error handler
  2538                                  
  2539                                  ; thread field for target
  2540                                  wpef_thrdtarg:
  2541                                  	;int3
  2542 00000F68 B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
  2543 00000F6B B92D00                      mov cx, 45              ; internal error value
  2544 00000F6E E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  2545                                  
  2546                                  @@:
  2547                                  	;int3
  2548 00000F71 B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
  2549 00000F74 B92E00                      mov cx, 46              ; internal error value
  2550 00000F77 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  2551                                  
  2552                                  ; check index validity
  2553                                  wpef_7:
  2554 00000F7A 8A1E[0000]                  mov bl,[frame_method]
  2555                                  		; frame_method = 5
  2556                                  		; bl = 5
  2557 00000F7E 80FB05                  	cmp bl, 5
  2558 00000F81 75EE                    	jne @B
  2559                                  
  2560                                  wpef_8:
  2561 00000F83 8A1E[0000]                  mov bl,[target_method]
  2562 00000F87 80FB03                      cmp bl,3                ; check for bad target method
  2563 00000F8A 74D4                        je  wpef_bad_target      ; bad target method
  2564                                  
  2565 00000F8C 88D0                        mov al,dl               ; get fix dat field
  2566 00000F8E 2404                        and al,4                ; get P bit field
  2567 00000F90 0806[0000]                  or  [target_method],al    ; P bit modifies target method, merge it in
  2568                                  
  2569 00000F94 08C0                        or  al,al               ; check if P bit set
  2570 00000F96 B80000                      mov ax,0                ; assume it is, setup for zero'ing target displacment, don't change flags via xor
  2571 00000F99 7509                        jne wpef_10              ; yes, P bit set, force target displacement value to zero
  2572                                  
  2573                                  ; get target displacement field if P bit is zero
  2574                                  	;int3
  2575 00000F9B B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
  2576 00000F9E B92F00                      mov cx, 47              ; internal error value
  2577 00000FA1 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  2578                                  
  2579                                  wpef_10:
  2580 00000FA4 A3[0000]                    mov WORD PTR [target_disp],ax ; save target displacement value
  2581 00000FA7 99                          cwd
  2582 00000FA8 8916[0200]                  mov WORD PTR [target_disp+2],dx   ; save sign extension of target displacement
  2583                                  
  2584                                  ; compute program offset of target address and its frame
  2585 00000FAC 30C0                        xor al,al
  2586 00000FAE A2[0000]                    mov [is_ind_call],al      ; init indirect call to overlaid public flag
  2587 00000FB1 A2[0000]                    mov [no_fixbyte_flag],al  ; init flag for fixup bytes
  2588 00000FB4 A2[0000]                    mov [gen_flags],al        ; init general flags
  2589                                  
  2590 00000FB7 FEC0                        inc al
  2591 00000FB9 A2[0000]                    mov [is_resolved],al      ; init is_resolved flag to assume fixup okay
  2592 00000FBC E88101                      call    _wlcalc_get_target_addr
  2593 00000FBF 7211                    	jc wpef_ret
  2594                                  
  2595                                  ; see if absolute segment or absolute public declaration, no frame computation
  2596 00000FC1 A0[0000]                    mov al,[is_absseg]
  2597 00000FC4 0A06[0000]                  or  al,[is_abspub]
  2598 00000FC8 7514                        jne wpef_resolved        ; either absolute segment or absolute public declaration
  2599                                  
  2600 00000FCA A0[0000]                    mov al,[frame_method]
  2601                                  		; frame_method = 5
  2602                                  wpef_11:
  2603                                      ; mov al,1                ; flag to get_frame_addr procedure to use target data
  2604 00000FCD E86600                      call _wlcalc_get_frame_addr
  2605 00000FD0 7301                    	jnc wpef_13        ; bypass other target segment computation code
  2606                                  
  2607                                  wpef_ret:
  2608 00000FD2 C3                          ret                     ; early return from routine
  2609                                  
  2610                                  wpef_13:
  2611 00000FD3 A0[0000]                    mov al,[is_resolved]
  2612 00000FD6 08C0                        or  al,al               ; check if reference to unresolved external
  2613 00000FD8 F9                      	stc
  2614 00000FD9 B85E00                  	mov ax, _WLCALC_EXT_NOT_FOUND_ERR
  2615 00000FDC 74F4                        je  wpef_ret             ; yes, don't perform a fixup
  2616                                  
  2617                                  ; convert target segment and target program offset to segment:offset format
  2618                                  wpef_resolved:
  2619                                  ; see if absolute segment or absolute public declaration, no address adjustment
  2620 00000FDE A0[0000]                    mov al,[is_absseg]
  2621 00000FE1 0A06[0000]                  or  al,[is_abspub]
  2622 00000FE5 7510                        jne wpef_seg_rel         ; either absolute segment or absolute public declaration
  2623                                  
  2624                                  ; check M bit for self-relative fixup
  2625 00000FE7 A0[0000]                    mov al,BYTE PTR [locat]   ; get locat field low byte
  2626 00000FEA 2440                        and al,40h              ; get M bit field value
  2627                                  ;    je  wpef_self_rel        ; M bit reset, fixup self-relative
  2628 00000FEC 7509                    	jnz wpef_seg_rel
  2629                                  	;int3
  2630 00000FEE B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
  2631 00000FF1 B93100                      mov cx, 49              ; internal error value
  2632 00000FF4 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  2633                                  
  2634                                  ; fixup segment relative
  2635                                  wpef_seg_rel:
  2636 00000FF7 A1[0000]                    mov ax,[target_segment]
  2637 00000FFA 31DB                        xor bx,bx               ; bx:ax will hold byte value of target segment
  2638 00000FFC D1E0                        shl ax,1
  2639 00000FFE D1D3                        rcl bx,1                ; x2
  2640 00001000 D1E0                        shl ax,1
  2641 00001002 D1D3                        rcl bx,1                ; x4
  2642 00001004 D1E0                        shl ax,1
  2643 00001006 D1D3                        rcl bx,1                ; x8
  2644 00001008 D1E0                        shl ax,1
  2645 0000100A D1D3                        rcl bx,1                ; x16
  2646                                  
  2647                                  ; get target offset in bx:di
  2648 0000100C 8B3E[0000]                  mov di,WORD PTR [target_prog_off] ; get absolute offset low word
  2649 00001010 29C7                        sub di,ax               ; compute low word difference
  2650 00001012 89D8                        mov ax,bx
  2651 00001014 8B1E[0200]                  mov bx,WORD PTR [target_prog_off+2]   ; get absolute offset high word
  2652 00001018 19C3                        sbb bx,ax               ; compute high word difference, with borrow
  2653                                      ; jmp SHORT wpef_14        ; bypass self-relative fixup code
  2654                                  
  2655                                  ;ready to fixup the address
  2656                                  wpef_14:
  2657                                  
  2658                                  %if 0
  2659                                  	push bx
  2660                                  ; check if fixup overflow, bx should be 0 or 0ffffh (-64K >= offset <= 64K)
  2661                                      inc bx
  2662                                      cmp bx,1
  2663                                      jbe wpef_14a             ; no fixup overflow
  2664                                  
  2665                                  ; check if possible lack of sign extension in data_offset vs. target_prog_off
  2666                                      cmp bx,0ffffh
  2667                                      jne wpef_fixwarn         ; bx not equal to -1
  2668                                  
  2669                                  ; lack of sign extension only if target_disp+2==0FFFFh
  2670                                      mov ax,WORD PTR [target_disp+2]
  2671                                      cmp ax,0ffffh
  2672                                      je  wpef_14a             ; target_disp+2 == 0FFFFh
  2673                                  
  2674                                  wpef_fixwarn:
  2675                                      call    fixup_warning   ; yes, print warning message
  2676                                  
  2677                                  wpef_14a:
  2678                                  	pop bx
  2679                                  %endif
  2680                                  
  2681 0000101A 803E[0000]00            	cmp	byte [compress_this],0		; see if compressing Clipper code
  2682 0000101F 740F                    	je	wpef_notsymcomp		; no
  2683 00001021 A1[0000]                	mov	ax,[current_segind]
  2684 00001024 3B06[0000]              	cmp	ax,[clipper_segindex]	; see if fixing up a SYMBOLS table during compression
  2685 00001028 7506                    	jne	wpef_notsymcomp		; not
  2686                                  ;	call	compsym_fixup	; fixup of compressed symbols, modify data_rec_offset if compress
  2687                                  ;	jc	wpef_out				; return carry flag set if throw away fixup
  2688 0000102A F9                      	stc
  2689 0000102B B85E00                  	mov ax, _WLCALC_EXT_NOT_FOUND_ERR
  2690 0000102E EB05                    	jmp wpef_out
  2691                                  
  2692                                  wpef_notsymcomp:
  2693 00001030 89F8                        mov ax, di               ; get 2-byte offset in ax
  2694 00001032 89DA                        mov dx, bx
  2695 00001034 F8                      	clc
  2696                                  ; offset or loader-resolved offset
  2697                                  wpef_15a:
  2698                                  wpef_out:
  2699 00001035 C3                          ret                     ; done
  2700                                  
  2701                                  
  2702                                  ; compute frame for fixupp address
  2703                                  ; use target data
  2704                                  ; uses target_method,target_index memory variables
  2705                                  ; can reset is_resolved memory variable flag
  2706                                  ; return frame in memory variable target_segment
  2707                                  		; INP:	byte [target_method] = 6
  2708                                  		;	word [_wlcalc_pubdef] => PUB_DECLENT_STRUC
  2709                                  		;	word [_wlcalc_wrt_pointer] = -1 if no WRT clause parsed
  2710                                  		;	else:
  2711                                  		;	 dword [_wlcalc_wrt_pointer] -> dword WRT base
  2712                                  		;		(this is an executable image linear address that
  2713                                  		;		corresponds to the relative segment value to use)
  2714                                  		; OUT:	CY if not found,
  2715                                  		;	 ax = error code
  2716                                  		;	 if not found, _WLCALC_EXT_NOT_FOUND_ERR
  2717                                  		;	 if WRT clause parsed but absolute PUBDEF,
  2718                                  		;	  _WLCALC_ABS_WRT_ERR
  2719                                  		;	NC if found,
  2720                                  		;	 word [target_segment] = relative segment value for PUBDEF
  2721                                  		;	does not return if internal error occurs (44 to 49)
  2722                                  		; CHG:	ax, bx
  2723                                  		; STT:	ds => DGROUP
  2724                                  		; REM:	based on mlpass2d.nas get_frame_addr
  2725                                  _wlcalc_get_frame_addr:
  2726 00001036 06                          push    es              ; save critical register
  2727                                  
  2728                                  wgfa_2:
  2729 00001037 8A1E[0000]                  mov bl,[target_method]
  2730                                  		; target_method = 6
  2731 0000103B 80E303                      and bl,3                ; mask off high bit to convert to segment/group/external value
  2732                                  		; bl = 2
  2733                                  
  2734                                  wgfa_3:
  2735 0000103E E98400                  	jmp wgfa_5
  2736                                  
  2737                                  wgfa_spart_entry:
  2738 00001041 26F6060F0080                test    BYTE PTR [es:15],80h    ; see if overlaid segment
  2739 00001047 752C                        jne wgfa_overlaid        ; yes
  2740                                  
  2741 00001049 26A10400                    mov ax,[es:4]           ; get master segdef entry
  2742 0000104D 8EC0                        mov es,ax               ; es -> segdef entry
  2743                                  
  2744 0000104F 26F6061C0001                test    BYTE PTR [es:28],1  ; see if segment if overlay class
  2745 00001055 7424                        je  wgfa_3a              ; no
  2746 00001057 833E[0000]00                cmp word [ovl_code_id],0       ; see if current L?DATA is owned by overlaid segment
  2747 0000105C 741D                        je  wgfa_3a              ; no
  2748 0000105E 803E[0000]00                cmp byte [nonovl_rvect],0      ; see if nonvector root calls flag set
  2749 00001063 7516                        jne wgfa_3a              ; yes, bypass vectoring
  2750                                  
  2751                                  ; special case to allow accessing overlay class nonoverlaid code address from
  2752                                  ; an overlaid segment.  If target displacement is nonzero then assume
  2753                                  ; that the program really wants the address and not a vectored address.
  2754                                  
  2755 00001065 A1[0000]                    mov ax,WORD PTR [target_disp]
  2756 00001068 0B06[0200]                  or  ax,WORD PTR [target_disp+2]   ; see if nonzero target displacement
  2757 0000106C 750D                        jne wgfa_3a              ; yes
  2758                                  
  2759                                  ; if gen_flags bit 0 is set, then do no vector address changes
  2760                                  ; Near/offset reference to different segment with no matching base references
  2761                                  ; in fixup_ovl_extdef
  2762                                  
  2763 0000106E A0[0000]                    mov al,[gen_flags]
  2764 00001071 2401                        and al,1                ; see if no vector address change flag set
  2765 00001073 7506                        jne wgfa_3a              ; yes
  2766                                  
  2767                                  ; frame is overlay class within an overlaid segment
  2768                                  ; or frame is an overlaid segment
  2769                                  ; es -> segment partition entry
  2770                                  wgfa_overlaid:
  2771                                  wgfa_ret_not_found:
  2772 00001075 B85E00                  	mov ax, _WLCALC_EXT_NOT_FOUND_ERR
  2773                                  wgfa_ret_CY_ax:
  2774 00001078 F9                      	stc
  2775 00001079 07                      	pop es
  2776 0000107A C3                      	retn
  2777                                  
  2778                                  wgfa_3a:
  2779 0000107B A3[0000]                    mov [frame_ent_ptr],ax    ; save pointer to frame entry
  2780 0000107E 26A10200                    mov ax,[es:2]           ; get low word of segment offset
  2781 00001082 268B1E0400                  mov bx,[es:4]           ; get high word of segment offset
  2782 00001087 D1EB                        shr bx,1
  2783 00001089 D1D8                        rcr ax,1                ; /2
  2784 0000108B D1EB                        shr bx,1
  2785 0000108D D1D8                        rcr ax,1                ; /4
  2786 0000108F D1EB                        shr bx,1
  2787 00001091 D1D8                        rcr ax,1                ; /8
  2788 00001093 D1EB                        shr bx,1
  2789 00001095 D1D8                        rcr ax,1                ; /16, have paragraph value of offset (segment value)
  2790                                  
  2791                                  wgfa_save_seg:
  2792 00001097 A3[0000]                    mov [target_segment],ax   ; save to memory variable
  2793 0000109A EB21                        jmp SHORT wgfa_reloc
  2794                                  
  2795                                  wgfa_group_entry:
  2796 0000109C 8CC0                        mov ax,es
  2797 0000109E A3[0000]                    mov [frame_ent_ptr],ax    ; save pointer to frame entry
  2798 000010A1 26A10000                    mov ax,[es:0]           ; get low word of group offset
  2799 000010A5 268B1E0200                  mov bx,[es:2]           ; get high word of group offset
  2800                                  wgfa_wrt:
  2801 000010AA D1EB                        shr bx,1
  2802 000010AC D1D8                        rcr ax,1                ; /2
  2803 000010AE D1EB                        shr bx,1
  2804 000010B0 D1D8                        rcr ax,1                ; /4
  2805 000010B2 D1EB                        shr bx,1
  2806 000010B4 D1D8                        rcr ax,1                ; /8
  2807 000010B6 D1EB                        shr bx,1
  2808 000010B8 D1D8                        rcr ax,1                ; /16, have paragraph value of offset (segment value)
  2809 000010BA A3[0000]                    mov [target_segment],ax   ; save to memory variable
  2810                                  
  2811                                  wgfa_reloc:
  2812 000010BD B001                        mov al,1
  2813 000010BF A2[0000]                    mov [is_relocatable],al   ; relocatable segment (assume group is always relocatable)
  2814 000010C2 07                          pop es
  2815 000010C3 F8                          clc
  2816 000010C4 C3                          ret
  2817                                  
  2818                                  ; external index
  2819                                  wgfa_5:
  2820 000010C5 8E06[0800]              	mov es, word [_wlcalc_pubdef]
  2821                                  				; es -> pubdef declarations entry
  2822 000010C9 26800E0E0040                or  BYTE PTR [es:14],40h    ; flag that used in fixup
  2823                                  
  2824 000010CF 26A00E00                    mov al,[es:14]          ; get definitions byte value
  2825 000010D3 2403                        and al,3                ; only keep pubdef/extdef/comdef/absolute field
  2826 000010D5 3C02                        cmp al,2                ; check if unresolved external
  2827 000010D7 725F                        jb  wgfa_unres_ext       ; unresolved external
  2828 000010D9 7739                        ja  wgfa_abs             ; absolute public declaration
  2829                                  
  2830                                  ; pubdef declaration (not absolute)
  2831                                  
  2832 000010DB 833E[0A00]FF            	cmp word [_wlcalc_wrt_pointer], -1
  2833 000010E0 740D                    	je @F
  2834 000010E2 C41E[0A00]              	les bx, [_wlcalc_wrt_pointer]
  2835 000010E6 268B07                      mov ax,[es:bx + 0]           ; get low word of segment offset
  2836 000010E9 268B5F02                    mov bx,[es:bx + 2]           ; get high word of segment offset
  2837 000010ED EBBB                    	jmp wgfa_wrt
  2838                                  
  2839                                  @@:
  2840                                  
  2841                                  ; check if pubdef has a group associated with it
  2842 000010EF 26A00F00                    mov al,[es:15]
  2843 000010F3 A880                        test    al,80h          ; high bit set if group associated with public declaration
  2844 000010F5 7410                        je  wgfa_6               ; no group
  2845                                  
  2846 000010F7 2401                        and al,1                ; see if overlaid public
  2847 000010F9 750C                        jne wgfa_6               ; yes, flush group association
  2848                                  
  2849 000010FB B001                        mov al,1
  2850 000010FD A2[0000]                    mov [frext_ingroup],al    ; flag external has associated group
  2851 00001100 268E060200                  mov es,[es:2]           ; es -> group entry
  2852 00001105 EB95                        jmp SHORT wgfa_group_entry   ; perform code in common with group index
  2853                                  
  2854                                  wgfa_6:
  2855 00001107 30C0                        xor al,al
  2856 00001109 A2[0000]                    mov [frext_ingroup],al    ; flag external has no associated group
  2857 0000110C 268E060000                  mov es,[es:0]           ; es -> segment partition entry
  2858 00001111 E92DFF                      jmp NEAR PTR wgfa_spart_entry     ; external resolved, perform code in common with segment index
  2859                                  
  2860                                  ; absolute public declaration
  2861                                  wgfa_abs:
  2862 00001114 B86900                  	mov ax, _WLCALC_ABS_WRT_ERR
  2863 00001117 833E[0A00]FF            	cmp word [_wlcalc_wrt_pointer], -1
  2864 0000111C 7403E957FF              	jne wgfa_ret_CY_ax
  2865 00001121 31C0                        xor ax,ax
  2866 00001123 A2[0000]                    mov [is_relocatable],al   ; nonrelocatable segment
  2867 00001126 A3[0000]                    mov [frame_ent_ptr],ax    ; zero frame entry pointer
  2868 00001129 FEC0                        inc al
  2869 0000112B A2[0000]                    mov [is_abspub],al        ; flag absolute public declaration
  2870 0000112E 26A10200                    mov ax,[es:2]           ; get frame number of public entry
  2871 00001132 A3[0000]                    mov [target_segment],ax   ; save to target segment
  2872 00001135 07                          pop es
  2873 00001136 F8                          clc
  2874 00001137 C3                          ret
  2875                                  
  2876                                  ; unresolved external, no fixup
  2877                                  wgfa_unres_ext:
  2878 00001138 C606[0000]00                mov byte [is_resolved],0       ; flag no fixup
  2879 0000113D E935FF                  	jmp wgfa_ret_not_found
  2880                                  
  2881                                  
  2882                                  ; compute target program offset for fixupp address
  2883                                  ; uses target_method,target_index,target_disp memory variables
  2884                                  ; can reset is_resolved memory variable flag
  2885                                  		; INP:	name_field -> ASCIZ extern label name
  2886                                  		;	dword [target_disp] = displacement (always zero)
  2887                                  		;	word [_wlcalc_wrt_pointer] = -1 if no WRT clause parsed
  2888                                  		;	else: WRT clause parsed (exact value not used here)
  2889                                  		; CHG:	ax, bx
  2890                                  		; OUT:	CY if not found,
  2891                                  		;	 ax = error code
  2892                                  		;	 if not found, _WLCALC_EXT_NOT_FOUND_ERR
  2893                                  		;	 if WRT clause parsed but absolute PUBDEF,
  2894                                  		;	  _WLCALC_ABS_WRT_ERR
  2895                                  		;	NC if found,
  2896                                  		;	 word [_wlcalc_pubdef] => PUB_DECLENT_STRUC
  2897                                  		;	 dword [target_prog_off] = executable image linear address
  2898                                  		;	does not return if internal error occurs (44 to 49)
  2899                                  		; STT:	ds => DGROUP
  2900                                  		; REM:	based on mlpass2d.nas get_target_addr
  2901                                  _wlcalc_get_target_addr:
  2902 00001140 06                          push    es              ; save critical register
  2903                                  
  2904                                  ; external index, method 2 or 6
  2905                                  wgta_ext:
  2906 00001141 FF36[0000]              	push word [no_match_okay]
  2907 00001145 C606[0000]01            	mov byte [no_match_okay], 1
  2908 0000114A BF[0000]                	mov di, name_field
  2909 0000114D E8(0000)                	call find_pubdecl_entry
  2910 00001150 8F06[0000]              	pop word [no_match_okay]
  2911 00001154 85C0                    	test ax, ax
  2912 00001156 741F                    	jz wgta_ret_not_found
  2913 00001158 A3[0800]                	mov word [_wlcalc_pubdef], ax
  2914 0000115B 8EC0                        mov es, ax			; es -> pubdef declarations entry
  2915 0000115D 26800E0E0040                or  BYTE PTR [es:14],40h    ; flag that used in fixup
  2916 00001163 A3[0000]                    mov [targ_ent_ptr],ax     ; save pointer to target entry
  2917 00001166 26F6060F0001                test    BYTE PTR [es:15],1  ; see if public is overlaid
  2918 0000116C 740F                        je  wgta_2               ; no
  2919                                  
  2920                                  	;int3
  2921 0000116E B80000                      mov ax,INTERNAL_ERR     ; put warplink error code in ax
  2922 00001171 B93000                      mov cx, 48              ; internal error value
  2923 00001174 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
  2924                                  
  2925                                  wgta_ret_not_found:
  2926 00001177 B85E00                  	mov ax, _WLCALC_EXT_NOT_FOUND_ERR
  2927                                  wgta_ret_CY_ax:
  2928 0000117A F9                      	stc
  2929                                  wgta_ret:
  2930 0000117B 07                          pop es                  ; restore critical register
  2931 0000117C C3                          ret
  2932                                  
  2933                                  wgta_2:
  2934 0000117D A1[0000]                    mov ax,WORD PTR [target_disp] ; get original target displacement
  2935 00001180 2603060800                  add ax,[es:8]           ; add in offset of pubdef declarations entry
  2936 00001185 A3[0000]                    mov WORD PTR [target_prog_off],ax ; update target program offset low word
  2937 00001188 A1[0200]                    mov ax,WORD PTR [target_disp+2]
  2938 0000118B 83D000                      adc ax,0                ; carry to high word
  2939 0000118E A3[0200]                    mov WORD PTR [target_prog_off+2],ax   ; carry to target program offset high word
  2940                                  
  2941 00001191 26F6060F0001                test    BYTE PTR [es:15],1  ; see if overlaid public (referenced within same segment)
  2942                                  		; NC
  2943 00001197 75E2                        jne wgta_ret             ; yes, don't add in segment partition/sefdef offsets
  2944                                  
  2945 00001199 26A00E00                    mov al,[es:14]          ; get definitions byte value
  2946 0000119D 2403                        and al,3                ; only keep pubdef/extdef/comdef field
  2947 0000119F 3C02                        cmp al,2                ; check if unresolved external
  2948 000011A1 7237                        jb wgta_3                ; unresolved external
  2949                                  
  2950                                  ; external resolved, fixup okay
  2951 000011A3 3C03                        cmp al,3                ; see if absolute public declaration
  2952 000011A5 743A                        je  wgta_4               ; yes
  2953                                  
  2954                                  ; pubdef, not absolute
  2955 000011A7 268E060000                  mov es,[es:0]           ; es -> segment partition entry
  2956 000011AC 26F6060F0080                test    BYTE PTR [es:15],80h    ; see if overlaid segment (local public with overlaid flag not set)
  2957                                  		; NC
  2958 000011B2 75C7                        jne wgta_ret             ; yes, don't add in segment partition/sefdef offsets
  2959 000011B4 26A10000                    mov ax,[es:0]           ; get offset of segment partition entry
  2960 000011B8 0106[0000]                  add WORD PTR [target_prog_off],ax ; update target program offset low word
  2961 000011BC 8316[0200]00                adc WORD [target_prog_off+2],0    ; carry to target program offset high word
  2962 000011C1 26A10400                    mov ax,[es:4]           ; get master segdef entry from segment partition entry back pointer
  2963                                      ; jmp NEAR PTR wgta_segdef_entry   ; do segdef entry offset addition
  2964                                  
  2965                                  wgta_segdef_entry:
  2966 000011C5 8EC0                        mov es,ax               ; es -> master segdef entry
  2967 000011C7 26A10200                    mov ax,[es:2]           ; get low word of segment offset
  2968                                      ; mov WORD PTR [lseg_canon],ax  ; save low word of offset for canonical computation
  2969 000011CB 0106[0000]                  add WORD PTR [target_prog_off],ax ; add to target program offset low word
  2970 000011CF 26A10400                    mov ax,[es:4]           ; get high word of segment offset
  2971                                      ; mov WORD PTR [lseg_canon+2],ax    ; save high word of offset for canonical computation
  2972 000011D3 1106[0200]                  adc WORD PTR [target_prog_off+2],ax   ; add to target program offset high word with carry
  2973 000011D7 07                          pop es
  2974 000011D8 F8                          clc
  2975 000011D9 C3                          ret
  2976                                  
  2977                                  ; unresolved external, no fixup
  2978                                  wgta_3:
  2979 000011DA C606[0000]00                mov byte [is_resolved],0       ; flag no fixup
  2980 000011DF EB96                        jmp wgta_ret_not_found    ; exit without further processing
  2981                                  
  2982                                  ; absolute, no segment partition or segdef entry offsets
  2983                                  wgta_4:
  2984 000011E1 B86900                  	mov ax, _WLCALC_ABS_WRT_ERR
  2985 000011E4 833E[0A00]FF            	cmp word [_wlcalc_wrt_pointer], -1
  2986 000011E9 758F                    	jne wgta_ret_CY_ax
  2987 000011EB 31C0                        xor ax,ax
  2988                                  		; NC
  2989 000011ED A2[0000]                    mov [is_relocatable],al   ; nonrelocatable segment
  2990 000011F0 A3[0000]                    mov [targ_ent_ptr],ax     ; zero frame entry pointer
  2991 000011F3 FEC0                        inc al
  2992 000011F5 A2[0000]                    mov [is_abspub],al        ; flag absolute public declaration
  2993 000011F8 26A10200                    mov ax,[es:2]           ; get frame number in target_segment in case of LOC frame fixup
  2994 000011FC A3[0000]                    mov [target_segment],ax
  2995 000011FF 07                          pop es                  ; restore critical register
  2996 00001200 C3                          ret
  2997                                  
  2998                                  
  2999                                  		; INP:	ds:si -> number
  3000                                  		; OUT:	CY if invalid,
  3001                                  		;	 ZR if overflow
  3002                                  		;	 NZ if invalid syntax
  3003                                  		;	NC if valid,
  3004                                  		;	 ds:si -> past number
  3005                                  		;	 dx:ax = number
  3006                                  		; CHG:	si, ax, bx, cx, dx
  3007                                   global _wlcalc_parse_number
  3008                                  _wlcalc_parse_number:
  3009 00001201 31D2                    	xor dx, dx
  3010 00001203 A9                      	db __TEST_IMM16		; skip mov dl
  3011                                  .decimalonly:
  3012 00001204 B201                    	mov dl, 1
  3013                                  		;	dl = 0 if to allow any supported base
  3014                                  		;	dl != 0 to allow only decimal
  3015                                  	lframe
  3016 00001206 5589E5                  	lenter
  3017 00001209 52                      	 push dx
  3018                                  	lvar word, onlydecimal
  3019 0000120A B90A00                  	mov cx, 10
  3020                                  @@:
  3021 0000120D 89F3                    	mov bx, si
  3022 0000120F AC                      	lodsb
  3023 00001210 3C5F                    	cmp al, '_'
  3024 00001212 74F9                    	je @B
  3025 00001214 E8B500                  	call ishex
  3026 00001217 727E                    	jc .invalid
  3027 00001219 E88D00                  	call .preloop
  3028                                  @@:
  3029 0000121C 4E                      	dec si			; -> last byte
  3030 0000121D 803C5F                  	cmp byte [si], '_'	; is it underscore ?
  3031 00001220 74FA                    	je @B			; yes, strip it
  3032 00001222 AC                      	lodsb			; al = last byte, si -> past last byte
  3033 00001223 E8BD00                  	call capitalise
  3034 00001226 88C4                    	mov ah, al		; ah = al = suffix
  3035 00001228 3C48                    	cmp al, 'H'
  3036 0000122A 7505                    	jne @F
  3037 0000122C B110                    	mov cl, 16
  3038 0000122E 4E                      	dec si			; decrease expected end
  3039 0000122F EB27                    	jmp .gotbase
  3040                                  
  3041                                  @@:
  3042 00001231 8A4701                  	mov al, [bx + 1]
  3043 00001234 E8AC00                  	call capitalise		; al = prefix after zero
  3044                                  
  3045 00001237 803F30                  	cmp byte [bx], '0'	; zero ?
  3046 0000123A 7514                    	jne @FF			; no --> (skip one @@)
  3047 0000123C 3C42                    	cmp al, 'B'
  3048 0000123E 7506                    	jne @F
  3049 00001240 43                      	inc bx
  3050 00001241 43                      	inc bx			; increase pp
  3051 00001242 B102                    	mov cl, 2
  3052 00001244 EB12                    	jmp .gotbase
  3053                                  
  3054                                  @@:
  3055 00001246 3C58                    	cmp al, 'X'
  3056 00001248 7506                    	jne @F
  3057 0000124A 43                      	inc bx
  3058 0000124B 43                      	inc bx			; increase pp
  3059 0000124C B110                    	mov cl, 16
  3060 0000124E EB08                    	jmp .gotbase
  3061                                  
  3062                                  @@:
  3063 00001250 80FC42                  	cmp ah, 'B'
  3064 00001253 7503                    	jne @F
  3065 00001255 B102                    	mov cl, 2
  3066 00001257 4E                      	dec si			; decrease expected end
  3067                                  .gotbase:
  3068                                  @@:
  3069 00001258 87DE                    	xchg bx, si
  3070 0000125A 31C0                    	xor ax, ax
  3071 0000125C 50                      	 push ax
  3072 0000125D 50                      	 push ax
  3073                                  	lvar dword, number
  3074                                  .loop:
  3075 0000125E 39F3                    	cmp bx, si
  3076 00001260 763A                    	jbe .end
  3077 00001262 AC                      	lodsb
  3078 00001263 3C5F                    	cmp al, '_'
  3079 00001265 74F7                    	je .loop
  3080 00001267 E86200                  	call ishex
  3081 0000126A 722B                    	jc .invalid
  3082 0000126C 38C8                    	cmp al, cl
  3083 0000126E 7327                    	jae .invalid
  3084 00001270 50                      	push ax
  3085 00001271 8B46FA                  	mov ax, [bp + ?number]
  3086 00001274 F7E1                    	mul cx
  3087 00001276 8946FA                  	mov word [bp + ?number], ax
  3088 00001279 92                      	xchg ax, dx
  3089 0000127A 8746FC                  	xchg ax, word [bp + ?number + 2]
  3090                                  				; ?number = low word times base, ax = high word
  3091 0000127D F7E1                    	mul cx
  3092 0000127F 0146FC                  	add word [bp + ?number + 2], ax
  3093 00001282 720E                    	jc .overflow
  3094 00001284 85D2                    	test dx, dx
  3095 00001286 750A                    	jnz .overflow
  3096 00001288 58                      	pop ax
  3097 00001289 98                      	cbw
  3098 0000128A 0146FA                  	add word [bp + ?number], ax
  3099 0000128D 1156FC                  	adc word [bp + ?number + 2], dx
  3100 00001290 73CC                    	jnc .loop
  3101                                  .overflow:
  3102 00001292 38C0                    	cmp al, al
  3103 00001294 F9                      	stc
  3104 00001295 EB0E                    	jmp .ret
  3105                                  
  3106                                  .invalid:
  3107 00001297 0C01                    	or al, 1
  3108 00001299 F9                      	stc
  3109 0000129A EB09                    	jmp .ret
  3110                                  
  3111                                  .end:
  3112 0000129C 8B56FE                  	mov dx, word [bp + ?onlydecimal]
  3113 0000129F E80700                  	call .preloop
  3114 000012A2 58                      	pop ax
  3115 000012A3 5A                      	pop dx			; get ?number
  3116 000012A4 F8                      	clc
  3117                                  .ret:
  3118 000012A5 89EC5D                  	lleave
  3119 000012A8 C3                      	retn
  3120                                  
  3121                                  
  3122                                  .preloop:
  3123 000012A9 AC                      	lodsb
  3124 000012AA E83600                  	call capitalise
  3125 000012AD 3C5F                    	cmp al, '_'
  3126 000012AF 74F8                    	je .preloop
  3127 000012B1 84D2                    	test dl, dl
  3128 000012B3 7408                    	jz @F
  3129 000012B5 3C30                    	cmp al, '0'
  3130 000012B7 7211                    	jb .retpre
  3131 000012B9 3C39                    	cmp al, '9'
  3132 000012BB 770D                    	ja .retpre
  3133                                  @@:
  3134 000012BD 3C58                    	cmp al, 'X'
  3135 000012BF 74E8                    	je .preloop
  3136 000012C1 3C48                    	cmp al, 'H'
  3137 000012C3 74E4                    	je .preloop
  3138 000012C5 E80400                  	call ishex
  3139 000012C8 73DF                    	jnc .preloop
  3140                                  .retpre:
  3141 000012CA 4E                      	dec si			; -> expected end
  3142 000012CB C3                      	retn
  3143                                  
  3144                                  
  3145                                  ishex:
  3146 000012CC E81400                  	call capitalise
  3147 000012CF 2C30                    	sub al, '0'
  3148 000012D1 720F                    	jc .ret
  3149 000012D3 3C0A                    	cmp al, 10
  3150 000012D5 720A                    	jb .ret_cmc
  3151 000012D7 2C07                    	sub al, 'A' - ('9' + 1)
  3152 000012D9 7207                    	jc .ret
  3153 000012DB 3C0A                    	cmp al, 10
  3154 000012DD 7203                    	jb .ret
  3155 000012DF 3C10                    	cmp al, 16
  3156                                  .ret_cmc:
  3157 000012E1 F5                      	cmc
  3158                                  .ret:
  3159 000012E2 C3                      	retn
  3160                                  
  3161                                  
  3162                                  capitalise:
  3163 000012E3 3C61                    	cmp al, 'a'
  3164 000012E5 7206                    	jb .gotcap
  3165 000012E7 3C7A                    	cmp al, 'z'
  3166 000012E9 7702                    	ja .gotcap
  3167 000012EB 3420                    	xor al, 'A' ^ 'a'
  3168                                  .gotcap:
  3169 000012ED C3                      	retn
  3170                                  
  3171                                  
  3172                                  	lframe
  3173                                  	lemit off
  3174                                  	lvar word, do
  3175                                  	lvar word, size
  3176                                  	lequ 10, buffersize
  3177                                  	lvar ?buffersize, buffer
  3178                                  	lenter
  3179                                  	lvar dword, namepointer
  3180                                  	lvar word, pass
  3181                                  	lvar dword, repeat
  3182                                  	lvar dword, number
  3183                                  
  3184                                  _wlcalc_do_seg: equ 0
  3185                                  _wlcalc_do_segrel: equ 1
  3186                                  _wlcalc_do_minussegrel: equ 2
  3187                                  _wlcalc_do_ext: equ 3
  3188                                  _wlcalc_do_minusext: equ 4
  3189                                  _wlcalc_do_extpara: equ 5
  3190                                  _wlcalc_do_minusextpara: equ 6
  3191                                  _wlcalc_do_opext: equ 7
  3192                                  _wlcalc_do_wrt: equ 8
  3193                                  _wlcalc_highest_seg_ext: equ 8
  3194                                  
  3195                                  		; INP:	dx:ax = read from file, zero-extended (if not a dword)
  3196                                  		;	bx:cx = dword [?number] = constant read from the label
  3197                                  		; OUT:	CY to signal "overflow" (will error out)
  3198                                  		;	NC to not signal "overflow",
  3199                                  		;	 dx:ax = output (will be truncated if not a dword)
  3200                                  		; CHG:	ax, bx, cx, dx
  3201                                  		; REM:	The ?number variable may be re-used for repetition.
  3202                                  _wlcalc_do_div:
  3203 000012EE 85DB                    	test bx, bx
  3204 000012F0 7510                    	jnz difficultdiv
  3205 000012F2 E30C                    	jcxz .error
  3206                                  
  3207 000012F4 93                      	xchg bx, ax		; bx = low word
  3208 000012F5 92                      	xchg ax, dx
  3209 000012F6 31D2                    	xor dx, dx		; dx:ax = high word
  3210 000012F8 F7F1                    	div cx
  3211 000012FA 93                      	xchg bx, ax		; bx = high word / divisor, ax = low word input
  3212 000012FB F7F1                    	div cx			; dx = remainder, ax = low word output
  3213 000012FD 89DA                    	mov dx, bx		; dx:ax = quotient
  3214                                  
  3215 000012FF A8                      	db __TEST_IMM8		; skip stc, NC
  3216                                  .error:
  3217 00001300 F9                      	stc
  3218 00001301 C3                      	retn
  3219                                  
  3220                                  difficultdiv:		; lDebug pick
  3221                                  .difficultdiv16:		; code adapted from Art of Assembly chapter 9
  3222                                  				; refer to http://www.plantation-productions.com/Webster/www.artofasm.com/DOS/ch09/CH09-4.html#HEADING4-99
  3223 00001302 55                      	push bp
  3224 00001303 56                      	push si
  3225 00001304 57                      	push di
  3226 00001305 89D5                    	mov bp, dx		; bp:ax = previous number
  3227 00001307 89CA                    	mov dx, cx		; bx:dx = divisor
  3228 00001309 31FF                    	xor di, di
  3229 0000130B 31F6                    	xor si, si		; clear variable si:di
  3230 0000130D 92                      	xchg ax, dx
  3231 0000130E 87EB                    	xchg bp, bx		; bx:dx = previous number, bp:ax = divisor
  3232 00001310 B92000                  	mov cx, 32
  3233                                  .bitloop:
  3234 00001313 D1E2                    	shl dx, 1
  3235 00001315 D1D3                    	rcl bx, 1
  3236 00001317 D1D7                    	rcl di, 1
  3237 00001319 D1D6                    	rcl si, 1		; si:di:bx:dx << 1
  3238 0000131B 39EE                    	cmp si, bp		; does the divisor fit into si:di here ?
  3239 0000131D 7502                    	jne @F
  3240 0000131F 39C7                    	cmp di, ax
  3241                                  @@:
  3242 00001321 7205                    	jb .trynext		; no -->
  3243                                  .goesinto:
  3244 00001323 29C7                    	sub di, ax
  3245 00001325 19EE                    	sbb si, bp		; subtract divisor
  3246 00001327 42                      	inc dx			; set a bit of the result (bit was zero before, never carries)
  3247                                  .trynext:
  3248 00001328 E2E9                    	loop .bitloop		; loop for 32 bits
  3249 0000132A 5F                      	pop di
  3250 0000132B 5E                      	pop si
  3251 0000132C 5D                      	pop bp			; bx:dx = quotient
  3252 0000132D 93                      	xchg ax, bx		; ax:dx = quotient
  3253 0000132E 92                      	xchg ax, dx		; dx:ax
  3254 0000132F F8                      	clc
  3255 00001330 C3                      	retn
  3256                                  
  3257                                  
  3258                                  _wlcalc_do_mul:
  3259 00001331 50                      	push ax
  3260 00001332 92                      	xchg ax, dx		; ax = high word in
  3261 00001333 F766E4                  	mul word [bp + ?number]	; dx:ax = high
  3262 00001336 91                      	xchg cx, ax		; cx = high
  3263 00001337 58                      	pop ax
  3264                                  %if 0
  3265                                  	test dx, dx		; > 32 bits ?
  3266                                  	stc			; CY
  3267                                  	jnz .ret		; yes -->
  3268                                  	mul word [bp + ?number]	; dx:ax = high
  3269                                  	add dx, bx		; CY if overflow
  3270                                  %endif
  3271                                  
  3272 00001338 89C3                    	mov bx, ax		; = low word
  3273 0000133A F766E4                  	mul word [bp + ?number]
  3274 0000133D 01D1                    	add cx, dx
  3275 0000133F 93                      	xchg ax, bx		; cx:bx = dword times low word, ax = low word
  3276 00001340 F766E6                  	mul word [bp + ?number + 2]
  3277 00001343 01C8                    	add ax, cx		; ax:bx = dword times dword
  3278 00001345 87DA                    	xchg bx, dx		; ax:dx
  3279 00001347 92                      	xchg dx, ax		; dx:ax
  3280 00001348 F8                      	clc
  3281                                  .ret:
  3282 00001349 C3                      	retn
  3283                                  
  3284                                  
  3285                                  _wlcalc_do_shr:
  3286 0000134A 85DB                    	test bx, bx
  3287 0000134C 753B                    	jnz _wlcalc_CY
  3288                                  @@:
  3289 0000134E D1EA                    	shr dx, 1
  3290 00001350 D1D8                    	rcr ax, 1
  3291 00001352 E2FA                    	loop @B
  3292 00001354 F8                      	clc
  3293 00001355 C3                      	retn
  3294                                  
  3295                                  
  3296                                  _wlcalc_do_shl:
  3297 00001356 85DB                    	test bx, bx
  3298 00001358 752F                    	jnz _wlcalc_CY
  3299                                  @@:
  3300 0000135A D1E0                    	shl ax, 1
  3301 0000135C D1D2                    	rcl dx, 1
  3302 0000135E E2FA                    	loop @B
  3303 00001360 F8                      	clc
  3304 00001361 C3                      	retn
  3305                                  
  3306                                  
  3307                                  _wlcalc_do_xor:
  3308 00001362 31C8                    	xor ax, cx
  3309 00001364 31DA                    	xor dx, bx
  3310 00001366 C3                      	retn
  3311                                  
  3312                                  _wlcalc_do_or:
  3313 00001367 09C8                    	or ax, cx
  3314 00001369 09DA                    	or dx, bx
  3315 0000136B C3                      	retn
  3316                                  
  3317                                  _wlcalc_do_and:
  3318 0000136C 21C8                    	and ax, cx
  3319 0000136E 21DA                    	and dx, bx
  3320 00001370 C3                      	retn
  3321                                  
  3322                                  _wlcalc_do_clr:
  3323 00001371 F7D1                    	not cx
  3324 00001373 F7D3                    	not bx
  3325 00001375 21C8                    	and ax, cx
  3326 00001377 21DA                    	and dx, bx
  3327 00001379 C3                      	retn
  3328                                  
  3329                                  
  3330                                  _wlcalc_do_add:
  3331 0000137A 01C8                    	add ax, cx
  3332 0000137C 11DA                    	adc dx, bx
  3333 0000137E F8                      	clc
  3334 0000137F C3                      	retn
  3335                                  
  3336                                  
  3337                                  _wlcalc_do_subr:
  3338 00001380 91                      	xchg ax, cx
  3339 00001381 87D3                    	xchg dx, bx
  3340                                  _wlcalc_do_sub:
  3341 00001383 29C8                    	sub ax, cx
  3342 00001385 19DA                    	sbb dx, bx
  3343 00001387 F8                      	clc
  3344 00001388 C3                      	retn
  3345                                  
  3346                                  _wlcalc_CY:
  3347 00001389 F9                      	stc
  3348 0000138A C3                      	retn
  3349                                  
  3350                                  _wlcalc_do_itoa:
  3351 0000138B 57                      	 push di
  3352 0000138C 56                      	 push si
  3353 0000138D 53                      	 push bx
  3354                                  	lframe 0, inner		; re-use existing stack frame
  3355                                  	lpar word, retn		; account for what's on the stack
  3356                                  	lpar word, di
  3357                                  	lpar word, si
  3358                                  	lpar word, bx
  3359                                  	lpar_return		; lleave will lea sp so it -> ?bx
  3360                                  	lenter
  3361                                  
  3362 0000138E 84FF                    	test bh, bh		; unknown flag set ?
  3363 00001390 7403E9C000              	jnz .error		; yes -->
  3364 00001395 B75F                    	mov bh, '_'		; (NASM style)
  3365 00001397 F6C30C                  	test bl, 1100b		; both bits clear ?
  3366 0000139A 7410                    	jz @F
  3367 0000139C B72E                    	mov bh, '.'		; (german)
  3368 0000139E F6C308                  	test bl, 1000b		; top bit clear ? (bottom bit must be set)
  3369 000013A1 7409                    	jz @F
  3370 000013A3 B72C                    	mov bh, ','		; (english)
  3371 000013A5 F6C304                  	test bl, 0100b		; bottom bit clear ? (top must be set)
  3372 000013A8 7402                    	jz @F
  3373 000013AA B727                    	mov bh, "'"		; both bits are set (C23 style)
  3374                                  @@:
  3375 000013AC D0EB                    	shr bl, 1
  3376 000013AE D0EB                    	shr bl, 1
  3377 000013B0 D0EB                    	shr bl, 1
  3378 000013B2 D0EB                    	shr bl, 1		; bl = high nybble
  3379 000013B4 53                      	 push bx
  3380                                  	lvar word, separator_high_and_width_low
  3381                                  	lequ ?separator_high_and_width_low, width
  3382                                  	lequ ?separator_high_and_width_low + 1, separator
  3383 000013B5 B3FF                    	mov bl, -1
  3384 000013B7 53                      	 push bx
  3385                                  	lvar word, counter
  3386                                  
  3387 000013B8 80F924                  	cmp cl, 36
  3388 000013BB 7603E99500              	ja .error
  3389 000013C0 80F902                  	cmp cl, 2
  3390 000013C3 7303E98D00              	jb .error
  3391 000013C8 80FD00                  	cmp ch, 0		; no buffer size ?
  3392 000013CB 740B                    	je @F			; yes -->
  3393 000013CD 80FD0A                  	cmp ch, ?buffersize	; in range ?
  3394 000013D0 7603E98000              	ja .error		; no -->
  3395 000013D5 886EFC                  	mov byte [bp + ?size], ch
  3396                                  				; change buffer size
  3397                                  @@:
  3398 000013D8 B500                    	mov ch, 0
  3399 000013DA F646DC02                	testopt [bp + ?bx], 2	; flag zero fill ?
  3400 000013DE B330                    	mov bl, '0'		; fill with zero digits text
  3401 000013E0 7502                    	jnz @F			; flag set, use zero fill -->
  3402 000013E2 B320                    	mov bl, 32		; fill with blanks
  3403                                  @@:
  3404 000013E4 51                      	 push cx
  3405 000013E5 8D76F2                  	lea si, [bp + ?buffer]	; ss:si -> buffer start
  3406 000013E8 89F7                    	mov di, si		; ss:di -> buffer
  3407 000013EA 8B4EFC                  	mov cx, word [bp + ?size]
  3408                                  @@:
  3409 000013ED 36881D                  	mov byte [ss:di], bl	; fill
  3410 000013F0 47                      	inc di
  3411 000013F1 E2FA                    	loop @B			; ss:di -> behind buffer
  3412 000013F3 59                      	 pop cx			; base
  3413                                  .loop:
  3414 000013F4 39F7                    	cmp di, si
  3415 000013F6 765D                    	jbe .error
  3416 000013F8 FE46D8                  	inc byte [bp + ?counter]; count up
  3417 000013FB 8B5EDA                  	mov bx, word [bp + ?separator_high_and_width_low]
  3418                                  				; bl = width (counter limit), bh = separator
  3419 000013FE 84DB                    	test bl, bl		; want separators ?
  3420 00001400 740D                    	je @F			; no -->
  3421 00001402 3A5ED8                  	cmp bl, byte [bp + ?counter]
  3422                                  				; need one before next digit ?
  3423 00001405 7708                    	ja @F			; no -->
  3424 00001407 C646D800                	mov byte [bp + ?counter], 0
  3425                                  				; reset counter
  3426 0000140B 4F                      	dec di
  3427 0000140C 36883D                  	mov byte [ss:di], bh	; store separator
  3428                                  @@:
  3429 0000140F 39F7                    	cmp di, si		; di <= start of buffer ?
  3430 00001411 7642                    	jbe .error		; yes, overflow -->
  3431 00001413 4F                      	dec di			; -> digit buffer
  3432 00001414 93                      	xchg bx, ax		; bx = low word
  3433 00001415 92                      	xchg ax, dx		; ax = high word
  3434 00001416 31D2                    	xor dx, dx		; dx:ax = high word
  3435 00001418 F7F1                    	div cx			; dx = remainder, ax = quotient word
  3436 0000141A 93                      	xchg bx, ax		; bx = quotient high word, ax = low word
  3437 0000141B F7F1                    	div cx			; dx = remainder, ax = quotient low word
  3438 0000141D 80C230                  	add dl, '0'		; dl = digit text if <= '9'
  3439 00001420 80FA39                  	cmp dl, '9'
  3440 00001423 7603                    	jbe @F
  3441 00001425 80C207                  	add dl, 'A' - ('9' + 1)	; dl = digit text >= 'A'
  3442                                  @@:
  3443 00001428 368815                  	mov byte [ss:di], dl
  3444 0000142B 89DA                    	mov dx, bx		; dx:ax = quotient
  3445 0000142D 09C3                    	or bx, ax		; quotient nonzero ?
  3446 0000142F 75C3                    	jnz .loop		; yes -->
  3447                                  
  3448 00001431 8B5EDC                  	mov bx, [bp + ?bx]
  3449 00001434 F6C301                  	test bl, 1		; flag padding after ?
  3450 00001437 7415                    	jz @F			; no -->
  3451 00001439 89F9                    	mov cx, di
  3452 0000143B 29F1                    	sub cx, si		; = length of padding
  3453 0000143D 740F                    	jz @F			; no padding, skip -->
  3454                                  .pushback:
  3455 0000143F 8B5EFC                  	mov bx, word [bp + ?size]	; base = buffer size
  3456 00001442 8A46F2                  	mov al, [bp + ?buffer]	; get first byte (padding)
  3457                                  .pushone:
  3458 00001445 368640FF                	xchg al, [ss:si + bx - 1]
  3459                                  				; xchg (initially the last byte, then decrement)
  3460 00001449 4B                      	dec bx			; decrement
  3461 0000144A 75F9                    	jnz .pushone
  3462 0000144C E2F1                    	loop .pushback
  3463                                  @@:
  3464 0000144E 8B56F4                  	mov dx, word [bp + ?buffer + 2]
  3465 00001451 8B46F2                  	mov ax, word [bp + ?buffer]
  3466                                  				; load buffer into registers for return
  3467 00001454 A8                      	db __TEST_IMM8		; skip stc, NC
  3468                                  .error:
  3469 00001455 F9                      	stc			; CY
  3470 00001456 8D66DC                  	lleave			; lea sp -> ?bx
  3471 00001459 5B                      	pop bx
  3472 0000145A 5E                      	pop si
  3473 0000145B 5F                      	pop di			; restore registers
  3474 0000145C C3                      	retn
  3475                                  
  3476                                  	lleave			; lemit off means this doesn't generate code
  3477                                  
  3478                                  
  3479                                  ;*****************************
  3480                                  ;* DUMP_OVL_FILE             *
  3481                                  ;*****************************
  3482                                  
  3483                                  ; copy temporary overlay file to end of EXE file
  3484                                  ; then close it and delete it
  3485                                  ; upon entry bx== overlay file handle
  3486                                  ; destroys ax,bx,cx,dx,si,di
  3487                                  
  3488                                  dump_ovl_file   PROC
  3489 0000145D 31C9                        xor cx,cx               ; move file pointer to start of file
  3490 0000145F 89CA                        mov dx,cx
  3491 00001461 B80242                      mov ax,4202h            ; move file pointer, offset from file end
  3492 00001464 CD21                        int 21h
  3493 00001466 E8(0000)                    call    restore_ems_map
  3494 00001469 7263                        jc  dof_ovl_err         ; error in seek
  3495                                  
  3496 0000146B 89D7                        mov di,dx               ; save overlay file size high word
  3497 0000146D 89C6                        mov si,ax               ; save overlay file size low word
  3498                                  
  3499 0000146F 803E[0000]00                cmp byte [is_no_ems],0         ; see if EMS used
  3500 00001474 7515                        jne dof_1               ; no
  3501                                  
  3502                                  ; EMS used, by definition it's okay to use physical page 0 for i/o buffer
  3503 00001476 31DB                        xor bx,bx
  3504 00001478 88D8                        mov al,bl
  3505 0000147A E8(0000)                    call    map_ems_page    ; map page 0
  3506                                  %if 0 ;COMMENT #
  3507                                      inc bx
  3508                                      mov al,bl
  3509                                      call    map_ems_page    ; map page 1
  3510                                      inc bx
  3511                                      mov al,bl
  3512                                      call    map_ems_page    ; map page 2
  3513                                      inc bx
  3514                                      mov al,bl
  3515                                      call    map_ems_page    ; map page 3
  3516                                      mov ax,0fff0h
  3517                                  END COMMENT #
  3518                                  %endif
  3519                                  
  3520 0000147D B80040                  	mov	ax,16384
  3521 00001480 A3[1C00]                    mov [temp_buffer_size],ax ; keep size of temporary buffer
  3522 00001483 A1[0000]                    mov ax,[ems_base]         ; use base of EMS memory as temporary base
  3523 00001486 A3[1E00]                    mov [temp_buffer_base],ax
  3524 00001489 EB31                        jmp SHORT dof_4a
  3525                                  
  3526                                  dof_1:
  3527 0000148B B448                        mov ah,48h              ; allocate memory
  3528 0000148D BBFFFF                      mov bx,0ffffh           ; force request to fail, function will return largest available block
  3529 00001490 CD21                        int 21h
  3530 00001492 83F808                      cmp ax,8                ; insufficient memory error is expected
  3531 00001495 7403                        je dof_2
  3532 00001497 E9(0000)                    jmp NEAR PTR dos_error  ; other errors are fatal
  3533                                  
  3534                                  dof_2:
  3535 0000149A 81FBFF0F                    cmp bx,0fffh            ; check if more than 0fffh free paragraphs (64K-16 bytes)
  3536 0000149E 7603                        jbe dof_3               ; no
  3537 000014A0 BBFF0F                      mov bx,0fffh            ; allocate only up to 64K-16 for temporary disk write
  3538                                  
  3539                                  dof_3:
  3540 000014A3 89D8                        mov ax,bx
  3541 000014A5 D1E0                        shl ax,1                ; convert paragraphs allocated to bytes, x2
  3542 000014A7 D1E0                        shl ax,1                ; x4
  3543 000014A9 D1E0                        shl ax,1                ; x8
  3544 000014AB D1E0                        shl ax,1                ; x16
  3545 000014AD A3[1C00]                    mov [temp_buffer_size],ax ; keep size of temporary buffer
  3546 000014B0 B448                        mov ah,48h              ; allocate memory
  3547 000014B2 CD21                        int 21h
  3548 000014B4 7303                        jnc dof_4               ; should be successful, since using <= previous max value
  3549 000014B6 E9(0000)                    jmp NEAR PTR dos_error  ; any error is fatal
  3550                                  
  3551                                  dof_4:
  3552 000014B9 A3[1E00]                    mov [temp_buffer_base],ax ; save address of temporary buffer
  3553                                  
  3554                                  dof_4a:
  3555 000014BC 8B1E[0000]                  mov bx,[ovl_handle]
  3556 000014C0 31C9                        xor cx,cx               ; move file pointer to start of file
  3557 000014C2 89CA                        mov dx,cx
  3558 000014C4 B80042                      mov ax,4200h            ; move file pointer, offset from file start
  3559 000014C7 CD21                        int 21h
  3560 000014C9 E8(0000)                    call    restore_ems_map
  3561 000014CC 7306                        jnc dof_5               ; no errors in seek
  3562                                  
  3563                                  dof_ovl_err:
  3564 000014CE BA[0000]                    mov dx,OFFSET ovl_filename wrt DGROUP
  3565 000014D1 E9(0000)                    jmp NEAR PTR dos_error  ; DOS file error
  3566                                  
  3567                                  dof_5:
  3568 000014D4 09FF                        or  di,di               ; see if byte count to write is 64K or more
  3569 000014D6 7506                        jne dof_6               ; yes, write a zero_block_size chunk
  3570 000014D8 3B36[1C00]                  cmp si,[temp_buffer_size] ; see if byte count is at least temp_buffer_size
  3571 000014DC 7265                        jb  dof_8               ; no, exit temp_buffer_size writing loop
  3572                                  
  3573                                  dof_6:
  3574 000014DE 8B0E[1C00]                  mov cx,[temp_buffer_size] ; number of bytes to read
  3575 000014E2 31D2                        xor dx,dx               ; zero offset into buffer
  3576 000014E4 8B1E[0000]                  mov bx,[ovl_handle]
  3577 000014E8 A1[1E00]                    mov ax,[temp_buffer_base]
  3578 000014EB 1E                          push    ds              ; save ds, critical register
  3579                                  
  3580 000014EC 3B06[0000]              	cmp	ax,[ems_base]			; see if reading to EMS
  3581 000014F0 8ED8                        mov ds,ax               ; ds -> segment to start write, DON'T MODIFY FLAGS
  3582 000014F2 7508                    	jne	dof_fileread1		; no
  3583 000014F4 E8(0000)                	call	read_to_ems		; call read to EMS code
  3584 000014F7 1F                          pop ds                  ; restore ds -> warplink data
  3585 000014F8 72D4                        jc  dof_ovl_err         ; error reading from file
  3586 000014FA EB11                    	jmp	SHORT dof_readdone1
  3587                                  
  3588                                  dof_fileread1:
  3589 000014FC B43F                        mov ah,3fh              ; read file
  3590 000014FE CD21                        int 21h
  3591 00001500 E8(0000)                    call    restore_ems_map
  3592 00001503 1F                          pop ds                  ; restore ds -> warplink data
  3593                                  to_dof_ovl_err_CY:
  3594 00001504 72C8                        jc  dof_ovl_err         ; error reading from file
  3595 00001506 39C8                    	cmp ax, cx
  3596 00001508 B8FEFF                  	mov ax, -2		; short read code
  3597 0000150B 75C1                    	jne dof_ovl_err
  3598                                  dof_readdone1:
  3599                                  
  3600                                  dof_6a:
  3601 0000150D 8B0E[1C00]                  mov cx,[temp_buffer_size] ; number of bytes to write
  3602 00001511 31D2                        xor dx,dx               ; zero offset into buffer
  3603 00001513 8B1E[1800]                  mov bx,[exe_handle]
  3604 00001517 A1[1E00]                    mov ax,[temp_buffer_base]
  3605 0000151A 1E                          push    ds              ; save ds, critical register
  3606 0000151B 8ED8                        mov ds,ax               ; ds -> segment to start write
  3607 0000151D B440                        mov ah,40h              ; write to file
  3608 0000151F CD21                        int 21h
  3609 00001521 E8(0000)                    call    restore_ems_map
  3610 00001524 1F                          pop ds                  ; restore ds -> WarpLink data
  3611 00001525 7306                        jnc dof_7               ; no errors
  3612                                  
  3613                                  dof_exe_err:
  3614 00001527 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
  3615 0000152A E9(0000)                    jmp NEAR PTR dos_error  ; error writing to file
  3616                                  
  3617                                  dof_7:
  3618 0000152D 39C8                        cmp ax, cx			; see if out of disk space
  3619 0000152F 7409                        je dof_7a              ; no
  3620                                  
  3621                                  ; out of disk space for executable file
  3622                                  dof_diskspace:
  3623 00001531 B83A00                      mov ax,DISK_FULL_ERR
  3624 00001534 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
  3625 00001537 E9(0000)                    jmp NEAR PTR link_error ; transfer to error handler
  3626                                  
  3627                                  dof_7a:
  3628 0000153A 2B36[1C00]                  sub si,[temp_buffer_size] ; back off number of bytes written from bytes to write
  3629 0000153E 83DF00                      sbb di,0                ; borrow to high word
  3630 00001541 EB91                        jmp SHORT dof_5         ; loop for next write
  3631                                  
  3632                                  ; transfer leftover bytes (file size modulo temp_buffer_size)
  3633                                  dof_8:
  3634 00001543 89F1                        mov cx,si               ; cx holds bytes to write
  3635 00001545 E34A                        jcxz    dof_release     ; no bytes to write
  3636 00001547 31D2                        xor dx,dx               ; zero offset into buffer
  3637 00001549 8B1E[0000]                  mov bx,[ovl_handle]
  3638 0000154D A1[1E00]                    mov ax,[temp_buffer_base]
  3639 00001550 1E                          push    ds              ; save ds, critical register
  3640                                  
  3641 00001551 3B06[0000]              	cmp	ax,[ems_base]			; see if reading to EMS
  3642 00001555 8ED8                        mov ds,ax               ; ds -> segment to start write, DON'T MODIFY FLAGS
  3643 00001557 7508                    	jne	dof_fileread2		; no
  3644 00001559 E8(0000)                	call	read_to_ems		; call read to EMS code
  3645 0000155C 1F                          pop ds                  ; restore ds -> warplink data
  3646 0000155D 72A5                        jc  to_dof_ovl_err_CY	; error reading from file
  3647 0000155F EB14                    	jmp	SHORT dof_readdone2
  3648                                  
  3649                                  dof_fileread2:
  3650 00001561 B43F                        mov ah,3fh              ; read file
  3651 00001563 CD21                        int 21h
  3652 00001565 E8(0000)                    call    restore_ems_map
  3653 00001568 1F                          pop ds                  ; restore ds -> warplink data
  3654 00001569 7299                        jc  to_dof_ovl_err_CY	; error reading from file
  3655 0000156B 39C8                    	cmp ax, cx
  3656 0000156D B8FEFF                  	mov ax, -2		; short read code
  3657 00001570 7403E959FF              	jne dof_ovl_err
  3658                                  dof_readdone2:
  3659                                  
  3660 00001575 89F1                        mov cx,si               ; cx holds bytes to write
  3661 00001577 31D2                        xor dx,dx               ; zero offset into buffer
  3662 00001579 8B1E[1800]                  mov bx,[exe_handle]
  3663 0000157D A1[1E00]                    mov ax,[temp_buffer_base]
  3664 00001580 1E                          push    ds              ; save ds, critical register
  3665 00001581 8ED8                        mov ds,ax               ; ds -> segment to start write
  3666 00001583 B440                        mov ah,40h              ; write to file
  3667 00001585 CD21                        int 21h
  3668 00001587 E8(0000)                    call    restore_ems_map
  3669 0000158A 1F                          pop ds                  ; restore ds -> warplink data
  3670 0000158B 729A                        jc  dof_exe_err         ; error writing to file
  3671                                  
  3672 0000158D 39C8                        cmp ax, cx			; see if out of disk space
  3673 0000158F 75A0                        jne  dof_diskspace        ; yes
  3674                                  
  3675                                  ; release temporary buffer back to dos
  3676                                  dof_release:
  3677 00001591 803E[0000]00                cmp byte [is_no_ems],0         ; see if EMS used for i/o buffer
  3678 00001596 740A                        je  dof_close           ; yes, no memory to release
  3679                                  
  3680 00001598 8E06[1E00]                  mov es,[temp_buffer_base]
  3681 0000159C B449                        mov ah,49h              ; release memory
  3682 0000159E CD21                        int 21h
  3683 000015A0 7285                        jc  dof_exe_err         ; error occurred in memory release
  3684                                  
  3685                                  ; close temporary file
  3686                                  dof_close:
  3687 000015A2 8B1E[0000]                  mov bx,[ovl_handle]       ; get overlay file handle
  3688 000015A6 B43E                        mov ah,3eh              ; close file
  3689 000015A8 CD21                        int 21h
  3690 000015AA E8(0000)                    call    restore_ems_map
  3691                                  
  3692                                  ; delete temporary overlay file
  3693 000015AD BA[0000]                    mov dx,OFFSET ovl_filename wrt DGROUP
  3694 000015B0 B441                        mov ah,41h              ; delete file
  3695 000015B2 CD21                        int 21h
  3696 000015B4 E8(0000)                    call    restore_ems_map
  3697 000015B7 C3                          ret
  3698                                  dump_ovl_file   ENDP
  3699                                  
  3700                                  ;*****************************
  3701                                  ;* WRITE_BYTES               *
  3702                                  ;*****************************
  3703                                  
  3704                                  ; write bytes to program's memory image
  3705                                  ; upon entry [es:si] -> buffer to write from, cx == number of bytes to write,
  3706                                  ; data_offset == offset from start of program
  3707                                  ; updates si
  3708                                  ; destroys ax,cx,di
  3709                                  
  3710                                  write_bytes PROC
  3711 000015B8 1E                          push    ds              ; save critical register
  3712 000015B9 55                          push    bp
  3713 000015BA 53                          push    bx
  3714 000015BB 52                          push    dx
  3715 000015BC A1[0000]                    mov ax,[buffer_base]
  3716 000015BF 8CC3                        mov bx,es
  3717 000015C1 39C3                        cmp bx,ax               ; see if write buffer is i/o buffer
  3718 000015C3 7405                        je  wb_is_io            ; yes
  3719 000015C5 B8FFFF                      mov ax,0ffffh           ; set to highest possible value so no overflow occurs
  3720 000015C8 EB03                        jmp SHORT wb_set_bp
  3721                                  
  3722                                  wb_is_io:
  3723 000015CA A1[0000]                    mov ax,[buffer_end]
  3724                                  
  3725                                  wb_set_bp:
  3726 000015CD 89C5                        mov bp,ax               ; check only for end of physical buffer overflow
  3727                                  
  3728 000015CF 803E[0000]00                cmp byte [is_clarion],0        ; see if clarion switch thrown
  3729 000015D4 740D                        je  wb_notcdata         ; no
  3730 000015D6 833E[0000]00                cmp word [ovl_data_id],0       ; see if clarion overlay data
  3731 000015DB 7406                        je  wb_notcdata         ; no
  3732 000015DD E8(0000)                    call    write_clar_data ; write to .OVL file
  3733 000015E0 E9AA00                      jmp NEAR PTR wb_ret     ; and return
  3734                                  
  3735                                  wb_notcdata:
  3736 000015E3 833E[0000]00                cmp word [ovl_code_id],0       ; see if write is to an overlay
  3737 000015E8 7406                        je  wb_1                ; no
  3738 000015EA E8(0000)                    call    ovl_file_write  ; write to .OVL file
  3739 000015ED E99D00                      jmp NEAR PTR wb_ret     ; and return
  3740                                  
  3741                                  wb_1:
  3742 000015F0 A1[0000]                    mov ax,WORD PTR [data_offset] ; get offset from program start in di:ax
  3743 000015F3 89C3                        mov bx,ax               ; bx holds low word data offset
  3744 000015F5 8B3E[0200]                  mov di,WORD PTR [data_offset+2]
  3745 000015F9 89FA                        mov dx,di               ; dx holds high word data offset
  3746 000015FB 01C8                        add ax,cx               ; add in number of bytes to write
  3747 000015FD 83D700                      adc di,0                ; carry to high word
  3748 00001600 83E801                      sub ax,1                ; adjust for number of bytes relative zero
  3749 00001603 83DF00                      sbb di,0                ; borrow to high word
  3750                                  
  3751 00001606 3B3E[0200]                  cmp di,WORD PTR [highest_exe_write+2] ; compare to highest previous address write high word
  3752 0000160A 7226                        jb  wb_2                ; lower than previous address write
  3753 0000160C 7706                        ja  wb_new_high         ; higher than previous
  3754 0000160E 3B06[0000]                  cmp ax,WORD PTR [highest_exe_write]   ; compare to highest previous address write low word
  3755 00001612 761E                        jbe wb_2                ;  lower than or equal to previous
  3756                                  
  3757                                  ; update highest address write to new value
  3758                                  wb_new_high:
  3759 00001614 A3[0000]                    mov WORD PTR [highest_exe_write],ax
  3760 00001617 893E[0200]                  mov WORD PTR [highest_exe_write+2],di
  3761                                  
  3762 0000161B 3B3E[0200]                  cmp di,WORD PTR [image_size+2]    ; check if attempt to write out of bounds
  3763 0000161F 7211                        jb  wb_2                ; no, in bounds
  3764 00001621 7706                        ja  wb_bounds           ; yes, out of bounds
  3765 00001623 3B06[0000]                  cmp ax,WORD PTR [image_size]      ; check low word, high words are equal
  3766 00001627 7209                        jb  wb_2                ; no, in bounds
  3767                                  
  3768                                  ; attempt to write out of bounds of program memory image
  3769                                  wb_bounds:
  3770 00001629 BA[0000]                    mov dx,OFFSET filename wrt DGROUP
  3771 0000162C B81D00                      mov ax,IMAGE_BOUNDS_ERR ; attempt to write data outside of program bounds
  3772 0000162F E9(0000)                    jmp NEAR PTR error_read_buff_pos    ; transfer control to error handler
  3773                                  
  3774                                  wb_2:
  3775 00001632 803E[0000]00                cmp byte [is_ondisk],0         ; check if memory image is on disk
  3776 00001637 7405                        je  wb_memory           ; no
  3777 00001639 E8(0000)                    call    temp_file_write ; write bytes to temporary file (memory pages)
  3778 0000163C EB4F                        jmp SHORT wb_ret        ; and return
  3779                                  
  3780                                  wb_memory:
  3781 0000163E 89DF                        mov di,bx               ; di has low word offset of data
  3782 00001640 83E70F                      and di,15               ; di has normalized offset
  3783 00001643 83E3F0                      and bx,0fff0h           ; clear out normalized offset bytes
  3784 00001646 89D0                        mov ax,dx               ; ax has high word of data bytes offset
  3785 00001648 93                          xchg    ax,bx           ; high word in bx, low word in ax (w/o normalized offset bytes)
  3786                                  
  3787                                  ; convert bx:ax byte count to segment value in ax
  3788 00001649 D1EB                        shr bx,1
  3789 0000164B D1D8                        rcr ax,1                ; /2
  3790 0000164D D1EB                        shr bx,1
  3791 0000164F D1D8                        rcr ax,1                ; /4
  3792 00001651 D1EB                        shr bx,1
  3793 00001653 D1D8                        rcr ax,1                ; /8
  3794 00001655 D1EB                        shr bx,1
  3795 00001657 D1D8                        rcr ax,1                ; /16
  3796                                  
  3797                                  ; ax:di == normalized segment:offset of data offset
  3798                                  
  3799 00001659 0306[0000]                  add ax,[image_mem_ptr]    ; add in segment of memory image
  3800 0000165D 8CC3                        mov bx,es
  3801 0000165F 8EDB                        mov ds,bx               ; ds -> source buffer segment
  3802 00001661 8EC0                        mov es,ax               ; es:di -> location in memory image to place data
  3803                                  
  3804 00001663 89F0                        mov ax,si               ; get offset of source
  3805 00001665 01C8                        add ax,cx               ; add in number of bytes to write
  3806 00001667 7204                        jc  wb_buff_wrap        ; overflow, buffer will wrap
  3807 00001669 39E8                        cmp ax,bp               ; see if past buffer end for total bytes written
  3808 0000166B 7616                        jbe wb_no_buff_wrap     ; no
  3809                                  
  3810                                  wb_buff_wrap:
  3811 0000166D 89CA                        mov dx,cx               ; save old byte count to write
  3812 0000166F 89E9                        mov cx,bp               ; get buffer end
  3813 00001671 29F1                        sub cx,si               ; compute bytes to buffer end
  3814 00001673 89C8                        mov ax,cx               ; save byte count written this pass
  3815 00001675 D1E9                        shr cx,1                ; convert byte count to write to words
  3816 00001677 F3A5                        rep movsw               ; move the string
  3817 00001679 D1D1                        rcl cx,1                ; pick up carry
  3818 0000167B F3A4                        rep movsb               ; transfer leftover byte, if any
  3819 0000167D 31F6                        xor si,si               ; wrap source offset to start of i/o buffer
  3820 0000167F 29C2                        sub dx,ax               ; update total count, subtracting off byte count written
  3821 00001681 89D1                        mov cx,dx               ; get new total in cx
  3822                                  
  3823                                  wb_no_buff_wrap:
  3824 00001683 D1E9                        shr cx,1                ; convert byte count to write to words
  3825 00001685 F3A5                        rep movsw               ; move the string
  3826 00001687 D1D1                        rcl cx,1                ; pick up carry
  3827 00001689 F3A4                        rep movsb               ; transfer leftover byte, if any
  3828                                  
  3829                                  wb_endloop:
  3830 0000168B 8EC3                        mov es,bx               ; restore es -> source buffer
  3831                                  
  3832                                  wb_ret:
  3833 0000168D 5A                          pop dx                  ; restore critical register
  3834 0000168E 5B                          pop bx
  3835 0000168F 5D                          pop bp
  3836 00001690 1F                          pop ds
  3837 00001691 C3                          ret
  3838                                  write_bytes ENDP
  3839                                  
  3840                                  ;*****************************
  3841                                  ;* UPDATE_GRP_OFF            *
  3842                                  ;*****************************
  3843                                  
  3844                                  ; make group offset the lowest address of the segments in the group
  3845                                  ; upon entry es -> segdef entry
  3846                                  ; destroys ax
  3847                                  
  3848                                  update_grp_off  PROC
  3849 00001692 1E                          push    ds              ; save critical register
  3850 00001693 26A11000                    mov ax,[es:16]          ; get pointer to group entry
  3851 00001697 8ED8                        mov ds,ax               ; ds -> group entry
  3852 00001699 26A10400                    mov ax,[es:4]           ; get segment offset high word
  3853 0000169D 3B060200                    cmp ax,[2]           ; compare to group offset high word
  3854 000016A1 771F                        ja  ugo_ret             ; segment offset higher than group offset
  3855 000016A3 720A                        jb  ugo_2               ; segment offset lower, update group offset
  3856 000016A5 26A10200                    mov ax,[es:2]           ; get segment offset low word
  3857 000016A9 3B060000                    cmp ax,[0]           ; compare to group offset low word
  3858 000016AD 7313                        jae ugo_ret             ; segment offset higher or equal to group offset
  3859                                  
  3860                                  ugo_2:
  3861 000016AF 26A10400                    mov ax,[es:4]           ; get high word
  3862 000016B3 A30200                      mov [2],ax           ; update group offset high word
  3863 000016B6 26A10200                    mov ax,[es:2]           ; get low word
  3864 000016BA A30000                      mov [0],ax           ; update group offset low word
  3865 000016BD 8CC0                        mov ax,es
  3866 000016BF A30800                      mov [8],ax           ; save segdef entry pointer of lowest segment
  3867                                  
  3868                                  ugo_ret:
  3869 000016C2 1F                          pop ds                  ; restore critical register
  3870 000016C3 C3                          ret
  3871                                  update_grp_off  ENDP
  3872                                  
  3873                                  ;*****************************
  3874                                  ;* GET_CLASS_TYPE            *
  3875                                  ;*****************************
  3876                                  
  3877                                  ; get type of segment class for DOSSEG segment ordering
  3878                                  ; type == 0 for segment class CODE
  3879                                  ;      == 1 for other segments outside of DGROUP
  3880                                  ;      == 2 for DGROUP segment class BEGDATA
  3881                                  ;      == 3 for DGROUP segment class not equal to BEGDATA, BSS, or STACK
  3882                                  ;      == 4 for DGROUP segment class BSS
  3883                                  ;      == 5 for DGROUP segment class STACK
  3884                                  ; classes are not case sensitive for type (but are for concatenation)
  3885                                  ; a suffix of the class name establishes type, e.g. BC_CODE is class CODE
  3886                                  ; upon entry ds:si -> class name, es -> warplink data,
  3887                                  ;  bx holds segment of segdef entry
  3888                                  ; returns class type in al
  3889                                  ; destroys ax,cx
  3890                                  
  3891                                  get_class_type  PROC
  3892 000016C4 06                          push    es              ; save critical register
  3893 000016C5 1E                          push    ds
  3894 000016C6 57                          push    di
  3895 000016C7 53                          push    bx
  3896                                  
  3897 000016C8 06                      	push	es
  3898 000016C9 1E                      	push	ds
  3899 000016CA 07                      	pop	es
  3900 000016CB 1F                      	pop	ds					; ds -> warplink data, es:si -> class name
  3901 000016CC 31C9                        xor cx,cx               ; cx will hold string char count
  3902 000016CE 89F3                        mov bx,si               ; bx -> class name
  3903                                  
  3904                                  gct_count_loop:
  3905 000016D0 26803F00                    cmp BYTE PTR [es:bx],0  ; see if at end of string
  3906 000016D4 7404                        je  gct_code_chk        ; yes
  3907 000016D6 41                          inc cx                  ; bump count of chars
  3908 000016D7 43                          inc bx                  ; bump char slot
  3909 000016D8 EBF6                        jmp SHORT gct_count_loop    ; loop to check next char
  3910                                  
  3911                                  gct_code_chk:
  3912 000016DA 83F904                      cmp cx,4                ; see if possible class CODE
  3913 000016DD 7216                        jb  gct_nodgroup_chk    ; no, name string too small
  3914 000016DF 89CF                        mov di,cx               ; di will offset into end of string
  3915 000016E1 83EF04                      sub di,4                ; bx+di -> last four chars of string
  3916 000016E4 89F3                        mov bx,si               ; bx -> class name
  3917 000016E6 01FB                        add bx,di               ; bx -> last four chars of string
  3918 000016E8 BF[0000]                    mov di,OFFSET codetext wrt DGROUP   ; di -> target string
  3919 000016EB E8B400                      call    caseless_strcmp ; see if strings match
  3920 000016EE 08C0                        or  al,al               ; check return value
  3921 000016F0 7503                        jne gct_nodgroup_chk    ; nonzero return value, string didn't match
  3922 000016F2 E9A800                      jmp NEAR PTR gct_ret    ; return al == 0 for class CODE
  3923                                  
  3924                                  ; see if segment is NOT in group DGROUP
  3925                                  gct_nodgroup_chk:
  3926 000016F5 8CC7                        mov di,es               ; save es -> class name string
  3927 000016F7 07                          pop es                  ; es -> segdef entry
  3928 000016F8 06                          push    es              ; restore value to stack
  3929 000016F9 26A11000                    mov ax,[es:16]          ; get group entry segment, if any
  3930 000016FD 09C0                        or  ax,ax               ; check if entry exists
  3931 000016FF 7505                        jne gct_2               ; yes
  3932                                  
  3933                                  ; no group exists for this segment, not in group DGROUP
  3934                                  gct_not_dgroup:
  3935 00001701 B001                        mov al,1                ; return al ==1 for segment not in DGROUP
  3936 00001703 E99700                      jmp NEAR PTR gct_ret
  3937                                  
  3938                                  gct_2:
  3939 00001706 8EC0                        mov es,ax               ; es -> group entry
  3940 00001708 268B1E0400                  mov bx,[es:4]           ; get group name offset in bx
  3941 0000170D 268E060600                  mov es,[es:6]           ; es:bx -> group name
  3942 00001712 83C308                      add bx,8                ; adjust past two doubleword pointers
  3943                                  
  3944                                  ; simple-minded check for group DGROUP, case sensitive
  3945 00001715 26803F44                    cmp BYTE PTR [es:bx],'D'    ; check first char
  3946 00001719 75E6                        jne gct_not_dgroup      ; doesn't match
  3947 0000171B 26807F0147                  cmp BYTE PTR [es:bx+1],'G'  ; check remaining chars
  3948 00001720 75DF                        jne gct_not_dgroup
  3949 00001722 26807F0252                  cmp BYTE PTR [es:bx+2],'R'
  3950 00001727 75D8                        jne gct_not_dgroup
  3951 00001729 26807F034F                  cmp BYTE PTR [es:bx+3],'O'
  3952 0000172E 75D1                        jne gct_not_dgroup
  3953 00001730 26807F0455                  cmp BYTE PTR [es:bx+4],'U'
  3954 00001735 75CA                        jne gct_not_dgroup
  3955 00001737 26807F0550                  cmp BYTE PTR [es:bx+5],'P'
  3956 0000173C 75C3                        jne gct_not_dgroup
  3957 0000173E 26807F0600                  cmp BYTE PTR [es:bx+6],0  
  3958 00001743 75BC                        jne gct_not_dgroup
  3959                                  
  3960                                  ; segment is a member of group DGROUP
  3961 00001745 8EC7                        mov es,di                   ; restore es -> class name
  3962                                  
  3963                                  ; see if segment is class BEGDATA
  3964                                  gct_begdata_chk:
  3965 00001747 83F907                      cmp cx,7                ; see if possible class BEGDATA
  3966 0000174A 7217                        jb  gct_bss_chk         ; no, name string too small
  3967 0000174C 89CF                        mov di,cx               ; di will offset into end of string
  3968 0000174E 83EF07                      sub di,7                ; bx+di -> last seven chars of string
  3969 00001751 89F3                        mov bx,si               ; bx -> class name
  3970 00001753 01FB                        add bx,di               ; bx -> last seven chars of string
  3971 00001755 BF[0600]                    mov di,OFFSET begdatatext wrt DGROUP    ; di -> target string
  3972 00001758 E84700                      call    caseless_strcmp ; see if strings match
  3973 0000175B 08C0                        or  al,al               ; check return value
  3974 0000175D 7504                        jne gct_bss_chk         ; nonzero return value, string didn't match
  3975 0000175F B002                        mov al,2                ; return al == 2 for class BEGDATA
  3976 00001761 EB3A                        jmp SHORT gct_ret
  3977                                  
  3978                                  ; see if segment is class BSS
  3979                                  gct_bss_chk:
  3980 00001763 83F903                      cmp cx,3                ; see if possible class BSS
  3981 00001766 7217                        jb  gct_stack_chk       ; no, name string too small
  3982 00001768 89CF                        mov di,cx               ; di will offset into end of string
  3983 0000176A 83EF03                      sub di,3                ; bx+di -> last three chars of string
  3984 0000176D 89F3                        mov bx,si               ; bx -> class name
  3985 0000176F 01FB                        add bx,di               ; bx -> last three chars of string
  3986 00001771 BF[0E00]                    mov di,OFFSET bsstext wrt DGROUP    ; di -> target string
  3987 00001774 E82B00                      call    caseless_strcmp ; see if strings match
  3988 00001777 08C0                        or  al,al               ; check return value
  3989 00001779 7504                        jne gct_stack_chk       ; nonzero return value, string didn't match
  3990 0000177B B004                        mov al,4                ; return al == 4 for class BSS
  3991 0000177D EB1E                        jmp SHORT gct_ret
  3992                                  
  3993                                  ; see if segment is class STACK
  3994                                  gct_stack_chk:
  3995 0000177F 83F905                      cmp cx,5                ; see if possible class STACK
  3996 00001782 7217                        jb  gct_other           ; no, name string too small
  3997 00001784 89CF                        mov di,cx               ; di will offset into end of string
  3998 00001786 83EF05                      sub di,5                ; bx+di -> last five chars of string
  3999 00001789 89F3                        mov bx,si               ; bx -> class name
  4000 0000178B 01FB                        add bx,di               ; bx -> last five chars of string
  4001 0000178D BF[1200]                    mov di,OFFSET stacktext wrt DGROUP  ; di -> target string
  4002 00001790 E80F00                      call    caseless_strcmp ; see if strings match
  4003 00001793 08C0                        or  al,al               ; check return value
  4004 00001795 7504                        jne gct_other           ; nonzero return value, string didn't match
  4005 00001797 B005                        mov al,5                ; return al == 5 for class STACK
  4006 00001799 EB02                        jmp SHORT gct_ret
  4007                                  
  4008                                  ; segment is in DGROUP but does NOT have class BEGDATA, BSS, or STACK
  4009                                  gct_other:
  4010 0000179B B003                        mov al,3                ; resturn al == 3 for non- BEGDATA, BSS, and STACK DGROUP segment
  4011                                  
  4012                                  gct_ret:
  4013 0000179D 5B                          pop bx                  ; restore critical register
  4014 0000179E 5F                          pop di
  4015 0000179F 1F                          pop ds
  4016 000017A0 07                          pop es
  4017 000017A1 C3                          ret
  4018                                  get_class_type  ENDP
  4019                                  
  4020                                  ;*****************************
  4021                                  ;* CASELESS_STRCMP           *
  4022                                  ;*****************************
  4023                                  
  4024                                  ; caseless string compare, upper and lowercase chars match 
  4025                                  ; checks string -> by es:bx against string -> by ds:di
  4026                                  ; returns al == 0 is match, al == 1 is no match
  4027                                  ; destroy ax,bx,di
  4028                                  
  4029                                  caseless_strcmp PROC
  4030                                  cs_comp_loop:
  4031 000017A2 268A07                      mov al,[es:bx]          ; get char
  4032 000017A5 08C0                        or  al,al               ; if zero then at end of strings
  4033 000017A7 7505                        jne cs_2                ; not done with string compare
  4034 000017A9 0A05                        or  al,[di]             ; merge in second string char, still zero (successful match) if both terminated
  4035 000017AB 7522                        jne cs_nomatch          ; not zero, flag unsuccessful match
  4036 000017AD C3                          ret
  4037                                  
  4038                                  cs_2:
  4039 000017AE 3C61                        cmp al,'a'              ; check lowercase lower bound
  4040 000017B0 7206                        jb  cs_3                ; no
  4041 000017B2 3C7A                        cmp al,'z'              ; check lowercase upper bound
  4042 000017B4 7702                        ja  cs_3                ; no
  4043 000017B6 2C20                        sub al,20h              ; convert to uppercase
  4044                                  
  4045                                  cs_3:
  4046 000017B8 8A25                        mov ah,[di]             ; get target string char
  4047 000017BA 80FC61                      cmp ah,'a'              ; check lowercase lower bound
  4048 000017BD 7208                        jb  cs_4                ; no
  4049 000017BF 80FC7A                      cmp ah,'z'              ; check lowercase upper bound
  4050 000017C2 7703                        ja  cs_4                ; no
  4051 000017C4 80EC20                      sub ah,20h              ; convert to uppercase
  4052                                  
  4053                                  cs_4:
  4054 000017C7 38E0                        cmp al,ah               ; see if chars match
  4055 000017C9 7504                        jne cs_nomatch          ; no
  4056 000017CB 43                          inc bx                  ; this char matches, try next char in string
  4057 000017CC 47                          inc di
  4058 000017CD EBD3                        jmp SHORT cs_comp_loop  ; loop till string complete
  4059                                  
  4060                                  cs_nomatch:
  4061 000017CF B001                        mov al,1                ; flag unsuccessful compare
  4062 000017D1 C3                          ret
  4063                                  caseless_strcmp ENDP
  4064                                  
  4065                                  		; INP:	cx = length
  4066                                  		;	es => buffer
  4067                                  		; CHG:	ax, cx
  4068                                  check_com_cut:
  4069 000017D2 57                      	push di
  4070 000017D3 31C0                    	xor ax, ax
  4071 000017D5 51                      	push cx
  4072 000017D6 31FF                    	xor di, di
  4073 000017D8 F3AE                    	repe scasb
  4074 000017DA 59                      	pop cx
  4075 000017DB 7413                    	je .nowarn
  4076 000017DD B090                    	mov al, 90h
  4077 000017DF 31FF                    	xor di, di
  4078 000017E1 F3AE                    	repe scasb
  4079 000017E3 740B                    	je .nowarn
  4080                                  
  4081 000017E5 52                      	push dx
  4082 000017E6 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
  4083 000017E9 B86B00                      mov ax,COM_PREFIX_UNKNOWN_WARN
  4084 000017EC E8(0000)                    call    link_warning
  4085 000017EF 5A                      	pop dx
  4086                                  .nowarn:
  4087 000017F0 5F                      	pop di
  4088 000017F1 C3                      	retn
  4089                                  
  4090                                  
  4091                                  END
