Run-Time Fixup Facts; Pointer to STRINGASSIGN Hangs If No /O (68186)
The information in this article applies to:
- Microsoft Basic Professional Development System (PDS) for MS-DOS and MS OS/2 7.1
- Microsoft Basic Professional Development System (PDS) for MS-DOS and MS OS/2 7.0
This article was previously published under Q68186 SUMMARY
The C and assembly languages support "pointers to functions" (or
"function pointers" for short). However, function pointers to routines
that are in the Basic run-time module (such as STRINGLENGTH,
STRINGADDRESS, and STRINGASSIGN) do not work unless you compile with
BC /O. Function pointers to routines in the Basic run-time don't work
properly without /O because the "back patcher" used in Basic's
run-time system can't back patch indirect far calls.
(Function pointers to routines in the Basic run-time module do work
with Basic's /O because /O uses no back-patched fixups.)
Your assembler or C program can only make direct calls (by name) to
run-time module routines, such as STRINGLENGTH, STRINGADDRESS, and
STRINGASSIGN, when you compile the invoking Basic program without /O.
This limitation is by design.
MORE INFORMATION
Note that the STRINGLENGTH, STRINGADDRESS, STRINGASSIGN, and
STRINGRELEASE routines allow you to use Basic PDS's far
variable-length strings in mixed-language (C, assembler, and Pascal)
programming. For more information, see pages 368-375 of the "Microsoft
Basic 7.0: Language Reference" (for 7.00 and 7.10).
How "Back Patching" Operates in Basic's Run-Time Module
If you compile without the BC /O option, you cannot use a function
pointer to a Basic run-time routine, such as STRINGLENGTH,
STRINGADDRESS, or STRINGASSIGN, because of the back-patched fixups
used by the run-time module.
Under MS-DOS, Basic run-time modules are analogous to (but not exactly
the same as) an OS/2 or Windows DLL (dynamically linked library).
Under OS/2, a Basic run-time module really is a DLL. Below is a quick
description of how Basic's run-time module system works under MS-DOS:
- At LINK time, a small Basic .LIB file satisfies (provides "fixups"
for) all of the calls for run-time support. For example, you might
link to BRT71ENR.LIB (for 7.10) or BRT70ENR.LIB (for 7.00).
- During run time, a call to STRINGADDRESS jumps to the fixup
location determined at LINK time. At this fixup location is
information that describes the offset in the run-time module
(BRT7nxxx.EXE) where this call should really jump. (This
information is available only at run time, and not at LINK time.)
- Now that the call to STRINGADDRESS really knows where to jump, the
call is physically "back patched" with the correct far address for
the actual call to STRINGADDRESS. (This is called a back-patched
fixup.)
- The first call to STRINGADDRESS can now execute the correct routine
located in the BRT7nxxx.EXE run-time module.
- Now that the first STRINGADDRESS call has been "back patched," all
subsequent calls to STRINGADDRESS will jump straight to the
STRINGADDRESS routine in BRT7nxxx.EXE (the Basic run-time module),
instead of sidetracking through the small fixup routine provided in
BRT7nxxx.LIB.
The problem with attempting to use a function pointer to the
STRINGADDRESS routine when not compiled with /O is that the run-time
back patcher doesn't know how to back patch indirect far calls. The
indirect far call uses 4 bytes of stack space, whereas the back-patch
pointer expects to use 5 bytes of stack space, so the back patch is
off by 1 byte on indirect far calls, which causes the hanging problem.
Correct back patching can only be done for direct calls to
STRINGADDRESS and STRINGLENGTH.
When compiled with /O, Basic directly calls support routines instead
of back patching the calls. This explains why the code example below
works with BC /O, but fails when compiled without BC /O.
The following three methods work around this design limitation:
- Compile all programs with /O.
-or-
- Change the function pointer calls (calls to stradr and strlen in
the assembler example below) to direct calls to STRINGADDRESS and
STRINGLENGTH.
-or-
- Write two assembly PROCedures, with names such as stradr and
strlen. The PROC called stradr would directly call STRINGADDRESS.
The PROC strlen would directly call STRINGLENGTH.
Code Example
The Basic routine below works correctly when compiled with BC /O, but
when compiled without /O, the Basic routine hangs when calling the
assembly routine (at run time).
TEST.BAS
' Basic code to call the assembly procedure below.
DECLARE SUB TestText (a$, length%, SegAddress&)
DIM length%, SegAddress&
a$ = "blah"
PRINT "A$'s segmented address is: ", HEX$(SSEGADD(a$))
PRINT "Calling the assembly routine."
CALL TestText(a$, length%, SegAddress&)
PRINT length%
PRINT "A$'s segmented address is: ", HEX$(SegAddress&)
' This should be the same as the value printed above.
PRINT "Back from the assembly call."
END
TESTTEXT.ASM
extrn STRINGADDRESS:FAR
extrn STRINGLENGTH:FAR
.MODEL MEDIUM, Basic
.DATA
stradr dd STRINGADDRESS ; Attempt to make a pointer to
; StringAddress
strlen dd STRINGLENGTH ; A pointer to STRINGLENGTH
.CODE
; Pointer to a$'s adescriptor is at [BP + 10]
; Pointer to length% is at [BP + 8]
; Pointer to SegAddress is at [BP + 6]
PUBLIC TestText
TestText PROC
push bp
mov bp,sp
mov ax, [BP+10] ; Address of A$'s descriptor off the stack
push ax ; Pass it to STRINGLENGTH.
; call STRINGLENGTH ; This direct call always works.
call DWORD PTR strlen ; This fails without /O.
mov BX,[BP+8] ; BX Now points to length%
mov [BX],AX ; Put the value return by STRINGLENGTH in
; length%
mov ax, [BP + 10] ; Get the address of the descriptor.
push ax ; Pass it to StringAddress.
; call STRINGADDRESS ; ** This direct call always works.
call DWORD PTR stradr ; ** This fails without /O.
mov bx,[BP+6] ; Get the address of SegAddress&
mov [bx],ax ; The segment was stored in ax,
mov [bx+2],dx ; the offset was stored in dx.
pop bp ; Restore the BP register's value.
ret 2
TestText ENDP
END
REFERENCES
A fixup record (or "fixup" for short) is composed of binding and
relocation information (for the linker) put into the object code
(.OBJ) by the compiler. For background information about object code
format and fixup records, see pages 650-651 and 682-693 in the "MS-DOS
Encyclopedia" published by Microsoft Press (1988).
Modification Type: | Major | Last Reviewed: | 10/20/2003 |
---|
Keywords: | KB68186 |
---|
|