;       SCCSID = @(#)thunk.asm  6.2 92/02/24
;SCCSID = @(#)thunk.asm 6.2 92/02/24
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************
        page    ,132
        TITLE   Thunk - load-on reference
;******************************************************************************
;*******   C H A N G E       H I S T O R Y   **********************************
;******************************************************************************
;     = 04/03/89 TPL, Sizzle work, PTR B701685
;@T5  = 05/10/89 TPL, PTR B701685 fix
;D549 = 11/03/89 WKB,CJJ DCR 549 changes
;@T52 = 01/15/90 TPL, DCR 704 work
;@T85 = 02/23/92 TPL, Reduce usage of DosLoadModule, B733000
;MDLL = 01/10/94 BJN, Page Tune segments for Merged DLL.

.xlist
        include basemaca.inc            ;;;;;; 2.0 unique (dosmac replacement)
        include mi.inc                  ;;;;;; 2.0 unique (dossymc replacement)
        include struc.inc
        include viocdata.inc
        include viomac.inc
        include vioequ.inc                                              ;@T52
.list

.386p                                                                   ;D549

EXTRN   DOSLOADMODULE:FAR
EXTRN   DOSGETPROCADDR:FAR
EXTRN   suicide:NEAR

common segment byte public 'far_data'   USE16                      ;D549;@T52
common  ends

CTEXT_TUNE4  segment byte public 'code'      USE16                      ;MDLL;D549;@T52
        assume  cs:CTEXT_TUNE4, ds:nothing, es:nothing, ss:nothing      ;MDLL


;***    Thunker - handle load-on-reference calls
;
;       Dynlink modules, despite being segmentd, etc, are not very granular.
;       In particular, at load time all linkes between modules are snapped
;       resulting in a fair amount of overhead in terms of LDT initialization,
;       loading PRELOAD segments and allocating instance data segments.
;       This occurs whether or not a particular reference is ever used.
;
;       We cannot change the loader to perform the linkage at reference time
;       since there are nor error paths from things like MOV DS,REF, we are
;       forced to implement a thunk mechanism whereby the first reference
;       to a routine loads the relevant module.
;
;       Thunker is the main driver for this.  It is passed the address
;       of a thunk.  Thunker will the load the indicated module and
;       retrieve the indicated entry point.  Once this occurs
;       successfully, Thunker will then fix the thunk so that subsequent
;       references to the thunk will simply return.
;
;       ENTRY   (AX) =  offset in DS of thunk
;       EXIT    (AX) =  error code or 0.  If successful, AX contains
;                       0 and the thunk is set up to call the relevant
;                       routine.  If failure, AX contains error code
;                       and the thunk is left alone.  It is assumed
;                       that immediately following the call to Thunker,
;                       a call to the function occurs.  By default, the
;                       routine is a simple far return which appears
;                       that the error in AX gets returned.

Procedure   Thunker,near
;LocalVar   hMod,WORD                                                   ;@T85
LocalVar    pfn,DWORD                                                   ;@T5
        EnterProc
        push    bx
        push    si                                                      ;@T85

        mov     bx,ax                   ; BX = offset to pfnCall within DS @T85
        mov     si,[bx].hModule         ; SI = offset to module handle  ;@T85
        mov     si,word ptr [si]        ; SI = module handle            ;@T85
        sub     ax,ax                   ; clear RC                      ;@T85
        .if     <zero si>               ; Module Handle exists?         ;@T85
            push    ax                  ; sel of error buffer           ;@T85
            push    ax                  ; off of error buffer           ;@T85
            push    ax                  ; length of error buffer        ;@T85
            push    common              ; sel of mod name
            push    [bx].szModOff       ; off of mod name
            push    ds                  ; sel of returned handle        ;@T85
;@T85       lea     ax,hMod
            push    [bx].hModule        ; off of returned handle        ;@T85

            call    DOSLOADMODULE       ; load the module
            .if     <zero ax>           ; successful?                   ;@T85
                mov     si,[bx].hModule ; setup offset to module handle ;@T85
                mov     si,word ptr [si]; SI = module handle            ;@T85
            .endif                      ;                               ;@T85
        .endif                          ;                               ;@T85
        .if     <zero ax>               ; did we load sucessfully?
            push    si                  ; module handle for entry retrieval @T85
            push    ax                  ;
            push    [bx].hOrdinal       ; use ordinal number
            push    ss                  ; selector of returned address  ;@T5
            lea     ax,pfn              ;                               ;@T5
            push    ax                  ; offset of returned address    ;@T5

            call    DOSGETPROCADDR      ; find entry point
            .if     <zero ax>           ; did we find entry?
                mov     ax,pfn.Segmt    ; (ax) = selector of function   ;@T5
                mov     [bx].pfnCall.Segmt,ax                           ;@T5
                mov     ax,pfn.Offst    ; (ax) = offset of function     ;@T5
                mov     [bx].pfnCall.Offst,ax                           ;@T5
                mov     [bx].pfnTnk,offset ThunkerNearRet ; patch out thunk
                sub     ax,ax           ; clear return code
            .endif
        .endif
        pop     si                      ;                               ;@T85
        pop     bx
        LeaveProc
        .if     <nonzero ax>            ; resource error encountered?
            call    suicide             ; terminate process
        .endif                          ;
ThunkerNearRet:
        ret
EndProc Thunker

Procedure   ThunkerFarRet,far                                           ;@T5
        ret                                                             ;@T5
EndProc     ThunkerFarRet                                               ;@T5

CTEXT_TUNE4    ends                                                     ;MDLL

end
