     1                                  ;*********************************************************************
     2                                  ;*   MLPASS2E.ASM                                                    *
     3                                  ;*                                                                   *
     4                                  ;*   By:            Michael Devore                                   *
     5                                  ;*   Date:          04/03/92                                         *
     6                                  ;*   Model:         Small                                            *
     7                                  ;*   Version:       1.0                                              *
     8                                  ;*   Assembler:     MASM 5.0                                         *
     9                                  ;*   Environment:   MS-DOS 2.x+                                      *
    10                                  ;*                                                                   *
    11                                  ;*   linker pass 2 routines part E                                   *
    12                                  ;*                                                                   *
    13                                  ;*********************************************************************
    14                                  
    15                                  ;TITLE   MACHLINK mlpass2e
    16                                  ;PAGE    50,80
    17                                  
    18                                  ;.MODEL  SMALL
    19                                  
    20                                  ;*****************************
    21                                  ;* Include files             *
    22                                  ;*****************************
    23                                  
    24                                  [list -]
    29                                       
    30                                  ;*****************************
    31                                  ;* Public declarations       *
    32                                  ;*****************************
    33                                  
    34                                  ; procedures
    35                                  PUBLIC  proc2_modend
    36                                  
    37                                  ;*****************************
    38                                  ;* Data begins               *
    39                                  ;*****************************
    40                                  
    41                                  .DATA
    42                                  
    43                                  ;*****************************
    44                                  ;* External declarations     *
    45                                  ;*****************************
    46                                  
    47                                  ; variables
    48                                  EXTRN   frame_method:BYTE,target_method:BYTE
    49                                  EXTRN   frame_index:WORD,target_index:WORD
    50                                  EXTRN   is_resolved:BYTE
    51                                  EXTRN   fixup_pos:WORD,target_segment:WORD
    52                                  EXTRN   target_disp:DWORD,target_prog_off:DWORD
    53                                  
    54                                  %IFNDEF JUNIOR
    55                                  EXTRN   data_offset:DWORD
    56                                  %ENDIF
    57                                  
    58                                  ; initialized local variables
    59                                  
    60                                  EVEN                        ; maximize speed on 8086 and better
    61                                  
    62                                  ; byte values
    63                                  EVEN
    64 00000000 00                      is_entry_point  DB  0       ; nonzero if have an entry point from modend record
    65                                  
    66                                  .DATA?
    67                                  
    68                                  ; uninitialized local variables
    69                                  
    70                                  ;*****************************
    71                                  ;* Constant data             *
    72                                  ;*****************************
    73                                  
    74                                  .CONST
    75                                  
    76                                  EVEN
    77 00000000 24245F4D41494E5F45-     main_text   DB  '$$_MAIN_ENTRY',0
    77 00000009 4E54525900         
    78                                  
    79                                  ;*****************************
    80                                  ;* Code begins               *
    81                                  ;*****************************
    82                                  
    83                                  .CODE
    84                                  
    85                                  ;*****************************
    86                                  ;* External declarations     *
    87                                  ;*****************************
    88                                  
    89                                  ; procedures
    90                                  EXTRN   link_error:NEAR,dos_error:NEAR,load_file:NEAR
    91                                  EXTRN   check_index:NEAR,get_target_addr:NEAR,get_frame_addr:NEAR
    92                                  EXTRN   fixupp_offset_err:NEAR
    93                                  
    94                                  %IFNDEF JUNIOR
    95                                  EXTRN   get_symbol_offset:NEAR,write_bytes:NEAR
    96                                  %ENDIF
    97                                  
    98                                  ;*****************************
    99                                  ;* PROC2_MODEND              *
   100                                  ;*****************************
   101                                  
   102                                  ; pass 2 modend record processing
   103                                  ; upon entry cx=record length,bp=buffer_end,al=record type
   104                                  ; es:si -> first byte of record past record length
   105                                  ; destroys ax,bx,dx,di
   106                                  ; updates si
   107                                  
   108                                  proc2_modend    PROC
   109 00000000 268A04                      mov al,[es:si]          ; get module type byte
   110 00000003 46                          inc si
   111 00000004 49                          dec cx                  ; decrement record length to parse
   112 00000005 39EE                        cmp si,bp               ; check boundary conditions
   113 00000007 7203                        jb  pm_2                ; okay
   114 00000009 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   115                                  pm_2:
   116 0000000C 2440                        and al,40h              ; see if start bit set
   117 0000000E 7501                        jne pm_2a               ; yes, record contains entry point
   118 00000010 C3                          ret                     ; no, no start address/entry point
   119                                  
   120                                  pm_2a:
   121 00000011 803E[0000]00                cmp byte [is_entry_point],0    ; see if previous entry point (ignore this one)
   122 00000016 740A                        je  pm_1                ; no
   123                                  				; entry point already given
   124                                   extern filename
   125                                   extern link_warning
   126 00000018 BA[0000]                	mov dx, filename wrt DGROUP
   127 0000001B B86D00                  	mov ax, MULTIPLE_ENTRYPOINT_WARN
   128 0000001E E8(0000)                	call link_warning
   129 00000021 C3                      	retn
   130                                  
   131                                  pm_1:
   132 00000022 268A14                      mov dl,[es:si]          ; get end dat byte
   133 00000025 8936[0000]                  mov [fixup_pos],si        ; keep -> to byte in case of error
   134 00000029 46                          inc si
   135 0000002A 49                          dec cx                  ; decrement record length to parse
   136 0000002B 39EE                        cmp si,bp               ; check boundary conditions
   137 0000002D 7203                        jb  pm_3                ; okay
   138 0000002F E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   139                                  pm_3:
   140 00000032 F6C204                      test    dl,4            ; see if P bit is set
   141 00000035 7408                        je  pm_4                ; no
   142                                  
   143                                  ; bit 2 of end dat field, P bit in corresponding fix dat field cannot be set
   144 00000037 88D1                        mov cl,dl
   145 00000039 B81900                      mov ax,ENDDAT_VAL_ERR   ; bad end dat field value in MODEND record
   146 0000003C E9(0000)                    jmp NEAR PTR fixupp_offset_err  ; transfer control to error handler
   147                                  
   148                                  pm_4:
   149 0000003F 88D6                        mov dh,dl               ; dh holds end dat field value
   150 00000041 80E670                      and dh,70h              ; get frame field in dh
   151 00000044 D0EE                        shr dh,1
   152 00000046 D0EE                        shr dh,1
   153 00000048 D0EE                        shr dh,1
   154 0000004A D0EE                        shr dh,1                ; make frame value relative zero
   155                                  
   156 0000004C 88D0                        mov al,dl               ; get fix dat field
   157 0000004E A880                        test    al,80h          ; check if thread field for frame (fbit)
   158 00000050 7530                        jne pm_thrdframe        ; yes
   159                                  
   160                                  ; no thread field for frame
   161 00000052 80FE02                      cmp dh,2                ; see if index specified for this frame
   162 00000055 7725                        ja  pm_5                ; no
   163                                  
   164                                  ; index specified for this field
   165 00000057 30E4                        xor ah,ah               ; zap high byte
   166 00000059 268A04                      mov al,[es:si]          ; get frame datum first byte
   167 0000005C 46                          inc si
   168 0000005D 49                          dec cx                  ; decrement record length to parse
   169 0000005E 39EE                        cmp si,bp               ; check boundary conditions
   170 00000060 7203                        jb  pm_4a               ; okay
   171 00000062 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   172                                  pm_4a:
   173 00000065 3C80                        cmp al,80h              ; see if two byte field
   174 00000067 7210                        jb  pm_4b               ; no
   175 00000069 247F                        and al,7fh              ; strip high bit
   176 0000006B 88C4                        mov ah,al               ; move value to high byte
   177                                  
   178 0000006D 268A04                      mov al,[es:si]          ; get frame datum second byte
   179 00000070 46                          inc si
   180 00000071 49                          dec cx                  ; decrement record length to parse
   181 00000072 39EE                        cmp si,bp               ; check boundary conditions
   182 00000074 7203                        jb  pm_4b               ; okay
   183 00000076 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   184                                  
   185                                  pm_4b:
   186 00000079 A3[0000]                    mov [frame_index],ax      ; frame index, if any
   187                                  
   188                                  pm_5:
   189 0000007C 8836[0000]                  mov [frame_method],dh     ; frame method is the frame field
   190 00000080 EB2F                        jmp SHORT pm_6         ; bypass frame thread field code
   191                                  
   192                                  ; thread field for frame
   193                                  pm_thrdframe:
   194 00000082 D0E8                        shr al,1                ; make frame field value relative zero
   195 00000084 D0E8                        shr al,1
   196 00000086 D0E8                        shr al,1
   197 00000088 D0E8                        shr al,1
   198 0000008A 2407                        and al,7                ; mask off F bit
   199 0000008C 3C03                        cmp al,3                ; make sure frame thread field doesn't exceed 3
   200 0000008E 7608                        jbe pm_5a               ; okay
   201                                  
   202                                  ; frame thread field exceeds 3
   203 00000090 88C1                        mov cl,al
   204 00000092 B83700                      mov ax,ENDFRAME_THRD_ERR
   205 00000095 E9(0000)                    jmp NEAR PTR fixupp_offset_err  ; transfer control to error handler
   206                                  
   207                                  pm_5a:
   208 00000098 30E4                        xor ah,ah               ; zap high byte
   209 0000009A BB[0000]                    mov bx,OFFSET frame_thrd_meth wrt DGROUP    ; bx -> frame thread method array base
   210 0000009D 01C3                        add bx,ax               ; bx -> proper byte array element
   211 0000009F 8A1F                        mov bl,[bx]             ; get frame method
   212 000000A1 881E[0000]                  mov [frame_method],bl     ; save to memory variable
   213                                  
   214 000000A5 D1E0                        shl ax,1                ; convert to word offset
   215 000000A7 BB[0000]                    mov bx,OFFSET frame_thrd_index wrt DGROUP   ; bx -> frame thread index array base
   216 000000AA 01C3                        add bx,ax               ; bx -> proper word array element
   217 000000AC 8B07                        mov ax,[bx]             ; get frame index
   218 000000AE A3[0000]                    mov [frame_index],ax      ; save to memory variable
   219                                  
   220                                  pm_6:
   221 000000B1 88D0                        mov al,dl               ; get fix dat field
   222 000000B3 A808                        test    al,8            ; check if thread field for target (tbit)
   223 000000B5 752E                        jne pm_thrdtarg         ; yes
   224                                  
   225                                  ; no thread field for target
   226 000000B7 30E4                        xor ah,ah               ; zap high byte
   227 000000B9 268A04                      mov al,[es:si]          ; get target datum first byte
   228 000000BC 46                          inc si
   229 000000BD 49                          dec cx                  ; decrement record length to parse
   230 000000BE 39EE                        cmp si,bp               ; check boundary conditions
   231 000000C0 7203                        jb  pm_6a               ; okay
   232 000000C2 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   233                                  pm_6a:
   234 000000C5 3C80                        cmp al,80h              ; see if two byte field
   235 000000C7 7210                        jb  pm_6b               ; no
   236 000000C9 247F                        and al,7fh              ; strip high bit
   237 000000CB 88C4                        mov ah,al               ; move value to high byte
   238                                  
   239 000000CD 268A04                      mov al,[es:si]          ; get target datum second byte
   240 000000D0 46                          inc si
   241 000000D1 49                          dec cx                  ; decrement record length to parse
   242 000000D2 39EE                        cmp si,bp               ; check boundary conditions
   243 000000D4 7203                        jb  pm_6b               ; okay
   244 000000D6 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   245                                  
   246                                  pm_6b:
   247 000000D9 A3[0000]                    mov [target_index],ax     ; target index, if any
   248                                  
   249 000000DC 88D0                        mov al,dl               ; get fix dat field
   250 000000DE 2403                        and al,3                ; break out targt field
   251 000000E0 A2[0000]                    mov [target_method],al    ; target method is the targt field
   252                                  ;***    mov target_method,dh    ; target method is the frame field
   253                                  
   254 000000E3 EB1B                        jmp SHORT pm_7          ; bypass target thread field code
   255                                  
   256                                  ; thread field for target
   257                                  pm_thrdtarg:
   258 000000E5 2403                        and al,3                ; get targt field value in al
   259 000000E7 30E4                        xor ah,ah               ; zap high byte
   260 000000E9 BB[0000]                    mov bx,OFFSET target_thrd_meth wrt DGROUP   ; bx -> target thread method array base
   261 000000EC 01C3                        add bx,ax               ; bx -> proper byte array element
   262 000000EE 8A1F                        mov bl,[bx]             ; get target method
   263 000000F0 881E[0000]                  mov [target_method],bl    ; save to memory variable
   264                                  
   265 000000F4 D1E0                        shl ax,1                ; convert to word offset
   266 000000F6 BB[0000]                    mov bx,OFFSET target_thrd_index wrt DGROUP  ; bx -> target thread index array base
   267 000000F9 01C3                        add bx,ax               ; bx -> proper word array element
   268 000000FB 8B07                        mov ax,[bx]             ; get target index
   269 000000FD A3[0000]                    mov [target_index],ax     ; save to memory variable
   270                                  
   271                                  ; check index validity
   272                                  pm_7:
   273 00000100 803E[0000]03                cmp byte [frame_method],3      ; check if index specified for frame method
   274 00000105 730A                        jae pm_8                ; no
   275 00000107 A1[0000]                    mov ax,[frame_index]      ; get frame index for check_index routine
   276 0000010A 8A1E[0000]                  mov bl,[frame_method]
   277 0000010E E8(0000)                    call    check_index
   278                                  
   279                                  pm_8:
   280 00000111 A1[0000]                    mov ax,[target_index]     ; get target index for check_index
   281 00000114 8A1E[0000]                  mov bl,[target_method]
   282 00000118 E8(0000)                    call    check_index
   283                                  
   284                                  ; P bit always zero with MODEND entry point, so always target displacement
   285 0000011B 268A04                      mov al,[es:si]          ; get low byte of target displacement
   286 0000011E 46                          inc si
   287 0000011F 49                          dec cx                  ; decrement record length to parse
   288 00000120 39EE                        cmp si,bp               ; check boundary conditions
   289 00000122 7203                        jb  pm_8a               ; okay
   290 00000124 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   291                                  pm_8a:
   292 00000127 268A24                      mov ah,[es:si]          ; get high byte of target displacement
   293 0000012A 46                          inc si
   294 0000012B 49                          dec cx                  ; decrement record length to parse
   295 0000012C 39EE                        cmp si,bp               ; check boundary conditions
   296 0000012E 7203                        jb  pm_8b               ; okay
   297 00000130 E8(0000)                    call    load_file       ; load next portion of file into buffer, at end position
   298                                  pm_8b:
   299 00000133 A3[0000]                    mov WORD PTR [target_disp],ax ; save target displacement value
   300 00000136 99                          cwd
   301 00000137 8916[0200]                  mov WORD PTR [target_disp+2],dx   ; save sign extension of target displacement
   302                                  
   303                                  ; compute program offset of target address and its frame
   304 0000013B B001                        mov al,1
   305 0000013D A2[0000]                    mov [is_resolved],al      ; init is_resolved flag to assume fixup okay
   306 00000140 E8(0000)                    call    get_target_addr
   307                                  
   308 00000143 A0[0000]                    mov al,[frame_method]
   309 00000146 3C04                        cmp al,4                ; check if frame determined by location segment
   310 00000148 751C                        jne pm_11               ; no
   311 0000014A A1[0000]                    mov ax,WORD PTR [target_prog_off] ; get target's program offset in bx:ax
   312 0000014D 8B1E[0200]                  mov bx,WORD PTR [target_prog_off+2]   ; get high word
   313 00000151 D1EB                        shr bx,1
   314 00000153 D1D8                        rcr ax,1                ; /2
   315 00000155 D1EB                        shr bx,1
   316 00000157 D1D8                        rcr ax,1                ; /4
   317 00000159 D1EB                        shr bx,1
   318 0000015B D1D8                        rcr ax,1                ; /8
   319 0000015D D1EB                        shr bx,1
   320 0000015F D1D8                        rcr ax,1                ; /16, paragraph value (largest possible frame number)
   321 00000161 A3[0000]                    mov [entry_segval],ax
   322 00000164 EB16                        jmp SHORT pm_13         ; bypass other target segment computation code
   323                                  
   324                                  pm_11:
   325 00000166 3C05                        cmp al,5                ; check if frame determined by target's index
   326 00000168 7507                        jne pm_12               ; no
   327 0000016A B001                        mov al,1                ; flag to get_frame_addr procedure to use target data
   328 0000016C E8(0000)                    call    get_frame_addr
   329 0000016F EB05                        jmp SHORT pm_12a        ; bypass other target segment computation code
   330                                  
   331                                  ; frame determined by segment, group, or external index
   332                                  pm_12:
   333 00000171 30C0                        xor al,al               ; flag to get_frame_addr procedure to use frame data
   334 00000173 E8(0000)                    call    get_frame_addr
   335                                  
   336                                  pm_12a:
   337 00000176 A1[0000]                    mov ax,[target_segment]   ; get value place in target_segment by get_frame_addr procedure
   338 00000179 A3[0000]                    mov [entry_segval],ax     ; and place it in the programs' entry segment value memory variable
   339                                  
   340                                  pm_13:
   341 0000017C 803E[0000]00                cmp byte [is_resolved],0       ; check if reference to unresolved external
   342 00000181 7508                        jne pm_resolved         ; no, compute program's entry offset value
   343                                  
   344                                  ; reference to unresolved external
   345 00000183 C706[0000]0000              mov word [entry_segval],0      ; zero program's entry segment value
   346 00000189 EB27                        jmp SHORT pm_ret
   347                                  
   348                                  ; convert program's entry segment and offset value to segment:offset format
   349                                  pm_resolved:
   350 0000018B A1[0000]                    mov ax,[entry_segval]
   351 0000018E 31DB                        xor bx,bx               ; bx:ax will hold byte value of entry segment
   352 00000190 D1E0                        shl ax,1
   353 00000192 D1D3                        rcl bx,1                ; x2
   354 00000194 D1E0                        shl ax,1
   355 00000196 D1D3                        rcl bx,1                ; x4
   356 00000198 D1E0                        shl ax,1
   357 0000019A D1D3                        rcl bx,1                ; x8
   358 0000019C D1E0                        shl ax,1
   359 0000019E D1D3                        rcl bx,1                ; x16
   360 000001A0 8B3E[0000]                  mov di,WORD PTR [target_prog_off] ; get absolute offset low word
   361 000001A4 29C7                        sub di,ax
   362 000001A6 89D8                        mov ax,bx
   363 000001A8 8B1E[0000]                  mov bx,WORD PTR [target_prog_off] ; get absolute offset high word
   364 000001AC 29C3                        sub bx,ax               ; get entry offset in bx:di (bx should be zero)
   365 000001AE 893E[0000]                  mov [entry_offval],di     ; save program entry's offset to memory variable
   366                                  
   367                                  pm_ret:
   368 000001B2 803E[0000]00                cmp byte [is_comfile],0        ; check if COM file
   369 000001B7 7419                        je  pm_ret2             ; no
   370 000001B9 833E[0000]00                cmp word [entry_segval],0      ; see if begins at 0:100h
   371 000001BE 7409                        je  pm_14               ; okay so far
   372                                  
   373                                  ; bad entry point address for com file
   374                                  pm_com_entry:
   375 000001C0 BA[0000]                    mov dx,OFFSET exe_name wrt DGROUP
   376 000001C3 B83100                      mov ax,COM_ENTRY_ERR
   377 000001C6 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   378                                  
   379                                  pm_14:
   380 000001C9 A1[0000]                	mov ax, [comfile_cut_length]
   381 000001CC 3906[0000]                  cmp word [entry_offval], ax   ; check offset
   382 000001D0 75EE                        jne pm_com_entry        ; bad offset
   383                                  
   384                                  pm_ret2:
   385 000001D2 C606[0000]01                mov byte [is_entry_point],1    ; flag that entry point now exists
   386                                  
   387                                  ; if overlays, setup $$_main_entry variable
   388                                  %IFNDEF JUNIOR
   389 000001D7 833E[0000]00                cmp word [ovl_count],0         ; see if any overlays
   390 000001DC 7422                        je  pm_ret3             ; no
   391                                  
   392                                  ; write entry point offset word
   393 000001DE BF[0000]                    mov di,OFFSET main_text wrt DGROUP
   394 000001E1 E8(0000)                    call    get_symbol_offset
   395 000001E4 BE[0000]                    mov si,OFFSET entry_offval wrt DGROUP   ; es:si -> buffer
   396 000001E7 B90200                      mov cx,2                ; write one word
   397 000001EA E8(0000)                    call    write_bytes
   398                                  
   399                                  ; write entry point segment word
   400 000001ED 8306[0000]02                add WORD [data_offset],2  ; bump past offset value to segment value
   401 000001F2 8316[0200]00                adc WORD [data_offset+2],0    ; carry to high word
   402 000001F7 BE[0000]                    mov si,OFFSET entry_segval wrt DGROUP   ; es:si -> buffer
   403 000001FA B90200                      mov cx,2                ; write one word
   404 000001FD E8(0000)                    call    write_bytes
   405                                  %ENDIF
   406                                  
   407                                  pm_ret3:
   408 00000200 C3                          ret
   409                                  proc2_modend    ENDP
   410                                  
   411                                  END
