[<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]
        How FORCE Passes Parameters
        --------------------------------------------------------------------
              Before I answer the questions coming up, I think we should
        have a quick discussion on how FORCE passes parameters.  Understand-
        ing of this is crucial to mixing ASM and FORCE effectively, so here
        we go:

              FORCE passes parameters in two different ways:  by reference
        and by value.  When you pass by reference, FORCE passes the address
        of the parameter rather than pushing the entire parameter on to the
        stack, as is done when you pass by value.  That is, when you pass
        by value, you pass a copy of the original, and when you pass by
        reference, you pass a pointer to the original.

              FORCE decides on how to pass parameters by looking at the
        function prototypes, and checking to see whether the "PARAMETERS"
        part of the function prototype has the modifiers VALUE or CONST.
        Make sense?  Clear as mud, right?  Here's code to say what I mean:

        FUNCTION INT hash PROTOTYPE
           PARAMETERS VALUE INT      && will pass the actual integer, say 5

        FUNCTION INT hash2 PROTOTYPE
           PARAMETERS INT      && will pass the full address, say 023A:0004


        How to pass parameters from FORCE functions to ASM functions
        --------------------------------------------------------------------
        Q:              What is involved in writing ASM routines for FORCE?

        A:              Writing ASM routines for FORCE is fairly straightforward, if you
        know assembly language.  I'm afraid a quick ASM tutor is beyond the
        scope of this FAQ list, so if you don't know ASM, go learn it, and
        then come back (see you in a bit).  And, if you haven't read the
        above section on "How FORCE Passes Parameters," do so now.

        When writing ASM routines for FORCE, follow two rules of thumb:
                1) All calls and pointers are far.
                2) You must save DS, SI, ES, and DI for each routine.

        What that translates to is that when you declare your "procs," you
        can't   declare them as NEAR (unless they are not called by FORCE),
        and when you reference pointers from the stack, you must grab not
        only the offset, but also the segment.  Using the simplified segment
        directive ".model large" can save you some work for the former, but
        you have to do the latter by hand.  Here's a quick little code segment
        to say what I mean (and you seasoned ASM programmers, please refrain
        from laughing at my code for a few minutes; ASM isn't my primary
        language):

        The force prototype looks like this:

        FUNCTION INT hash PROTOTYPE
                PARAMETERS char, value int

        and the assembly would begin like this:

        _hash           proc    far     ; not near!
                                push    bp              ; set up our stack ref
                                mov     bp,sp
                                push    ds              ; save the segment registers    
                                push    si

                                mov     ax,word ptr ss:[ bp+8 ] ; grab the string's segment
                                mov     ds,ax
                                mov     ax,word ptr ss:[ bp+6 ] ; grab the string's offset
                                mov     si,ax
                                mov     dx,word ptr ss:[ bp+10] ; grab the hashvalue
                ...     etc     ...
                                pop     si              ; restore the segment registers 
                                pop     ds              ; (we didn't use es or di)
                                pop     bp
                                ret
        _hash   endp

                Short and sweet as it is, that little code segment shows 
        both of the two "rules of thumb" I stated above, 1) that procedures
        must be FAR, and 2) you must preserve the values of the DS:SI and
        ES:DI segment:offset registers.

                Recall from the section "How FORCE Passes Parameters" that
        FORCE will pass the address of any parameter unless that parameter
        is modified with the CONST of VALUE modifiers.

                Therefore, when you write your assembler routines, be sure that
        their corresponding FORCE prototypes are correct, or you'll destroy
        your stack.  For example, if the prototype for the function hash()
        above looked like this:

        FUNCTION INT hash PROTOTYPE
                PARAMETERS VALUE char, VALUE int

        FORCE would load the entire 255 (or whatever) characters of the
        string on to the stack and then call your hash() function.  If you
        were expecting the address instead, you'd end up referencing a
        string god-knows-where in memory, probably at 'lm':'Ho' or some-
        thing like that.

                If you stick with the two rules of thumb stated above, you'll
        be okay.  For anything more complicated than that, leave me a
        message on the board and I'll take care of you there.   
        
        


See Also: General Compatibility
This page created by ng2html v1.05, the Norton guide to HTML conversion utility. Written by Dave Pearson