Retro video games delivered to your door every month!
Click above to get retro games delivered to your door ever month!
X-Hacker.org- Peter Norton Programmer's Guide - Norton Guide http://www.X-Hacker.org [<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]

  Turbo Pascal version 4.0 uses a large memory model, with multiple
  executable code segments and multiple data segments. However, Turbo Pascal
  compiles all the executable code in the body of a program into a single
  segment, so assembly-language subroutines that you declare within the main
  body of a program should use a near call-return sequence. In contrast,
  Turbo Pascal uses separate segments for subroutines declared in the
  INTERFACE section of a Turbo Pascal UNIT. (A UNIT in Turbo Pascal is a
  collection of predefined subroutines and data items.) Such subroutines
  must be accessed through a far call-return sequence; data is accessed
  using far addresses. When you write an assembly-language subroutine for
  Turbo Pascal, be sure you use the right call-return sequence.

  The following example is a Turbo Pascal variation of our absolute-value
  function. Because it is designed to be called from the main body of a
  Pascal program, it uses a near call-return sequence.

  CODE            SEGMENT byte public
                  ASSUME  cs:CODE

                  PUBLIC  AbsFunc
  AbsFunc         PROC    near            ; call with near CALL

                  push    bp
                  mov     bp,sp

                  mov     ax,[bp+4]       ; AX = value of parameter
                  cwd
                  xor     ax,dx
                  sub     ax,dx           ; AX contains the result

                  pop     bp
                  ret     2               ; near return

  AbsFunc         ENDP

  CODE            ENDS

  If you assemble this subroutine into the object file ABSFUNC.OBJ, you can
  link it into a Turbo Pascal program by using the $L compiler directive and
  declaring AbsFunc() as an EXTERNAL function:

  {$L absfunc}        { object filename }
  FUNCTION AbsFunc(x: INTEGER): INTEGER; EXTERNAL;

  Turbo Pascal uses a large memory model, so data pointers are always passed
  to subroutines as 32-bit addresses. You can see this by writing the same
  subroutine as a PROCEDURE instead of a FUNCTION and declaring x as an
  integer variable. The VAR keyword in the parameter list instructs the
  Turbo Pascal compiler to pass the parameter by reference, that is, to pass
  the parameter's address instead of its value:

  {$L absproc}            { object filename }
  PROCEDURE AbsProc (VAR x:INTEGER); EXTERNAL;

  The subroutine differs from the previous one in that it must obtain the
  32-bit address of x from the stack in order to obtain the actual value of
  x:

  CODE            SEGMENT byte public
                  ASSUME  cs:CODE

                  PUBLIC  AbsProc
  AbsProc         PROC    near            ; call with near CALL

                  push    bp
                  mov     bp,sp

                  les     bx,[bp+4]       ; ES:BX = segmented addr of x
                  mov     ax,es:[bx]      ; AX = value of x
                  cwd
                  xor     ax,dx
                  sub     ax,dx

                  mov     es:[bx],ax      ; leave result in x

                  pop     bp
                  ret     4               ; near return

  AbsProc         ENDP

  CODE            ENDS

  This subroutine resembles LargeAbs(), our large-model example for
  Microsoft C. The important difference is that Turbo Pascal's
  subroutine-calling convention requires a near subroutine call because the
  subroutine was declared in the body of a Pascal program. Had we declared
  AbsProc() in the INTERFACE portion of a UNIT, the subroutine would have
  used a far call-return sequence.

Online resources provided by: http://www.X-Hacker.org --- NG 2 HTML conversion by Dave Pearson