Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Call Absolute in QBasic 1.1 <-> writing assembly

Status
Not open for further replies.
Dec 31, 2006
13
US
Hello all,

Some time ago I tried to make sense of the "call absolute" statement in QBasic 1.1 , and was amazed that I could not find anything worthy on the 'net.

What I tried to do was to find, for every argument used in the "call absolute" statement, in Assembly, what type it was (int, long, string, array(s), user defined, etc.), where it was stored, and what it's size was.

I was amazed,to say the least, to discover that it seemed not to be possible. For starters, I could not even determine if the, on stack stored, double-byte data should be interpreted as an constant, or a variable-pointer :-( :-(

Therefore I'm asking if anybody can shed some light on this matter ...
 
@agual
You're right. I've downloaded "winer.zip" and the last chapter talked about some assembler.

Alas, it talks about Assembler in QB, and my problem is not with creating an Assembly-program, nor with QB. My problem is with retrieving argument-related data in *QBasic 1.1*.

I.e. when I do a call absolute (&h1234, "BitFiddler",varptr(MyProg%(0))), how/where can I find/retieve, in the assembly-program "MyProg", the value 1234 (hex) and the string "bitFiddler" ?
 
I'm not an expert about assembly but maybe it could be a way to achieve your task.

You could reserve memory space at the beginning of Myprog% to pass values from Qb to Asm(and Asm to Qb).

I.e.
REM ### START ###
DIM Myprog%(34)

DEF SEG = VARSEG(Myprog%(0))
FOR i% = 0 TO 63
READ d%
POKE VARPTR(Myprog%(0)) + i%, d%
NEXT i%
DEF SEG

MouseInit

END

DATA 00,00,00,00,00,00,&HB8,00,00
DATA &HCD,&H33,&H3D,&HFF,&HFF,&H75,&H0D,&H0E,&H07
DATA &HBA,&H24,&H00,&HB9,&HFF,&HFF,&HB8,&H0C,&H00
DATA &HCD,&H33,&HCB,&HB8,00,00
DATA &HCD,&H33,&HCB,&H2E,&H89,&H0E,00,00
DATA &H2E,&H89,&H16,02,00,&H2E,&H89,&H1E,04,00
DATA &HCB,&HB8,01,00,&HCD,&H33
DATA &HCB,&HB8,02,00,&HCD,&H33,&HCB

SUB MouseInit
DEF SEG = VARSEG(a%(0))
CALL ABSOLUTE(VARPTR(Myprog%(0)) + 6)
DEF SEG
END SUB
REM ### END ###

So you can retrive data in Qb ->
DEF SEG = VARSEG(Myprog%(0))
DataToRetrive% = VARPTR(Myprog%(1...6)) ' 6 bytes
DEF SEG

And retriving data in Asm ->
MOV AX, [0000] or
MOV AX, [0100]
or something like that..

Hope it will help!
 
@Oak
Yes, this (and other) methods can be used moderatily well, and I have used them in the past.

But I would like to be able to use QBasic's own mechanism to retrieve the contents of the user-supplied arguments ...

So, although I can let QBasic communicate with some Assembly-code, I regard all of the used methods as work-arounds (and am not really thrilled about their work/check -ability), and would like to know if somebody here knows the straight way to it :)
 
The preferred method for calling assembler functions from QB is to make a separate assembler module, assemble it to its own OBJ file using an assembler like MASM or TASM, then link the OBJ file into the project. You can then use a [tt]DECLARE[/tt] statement to specify parameters, calling convention and import name. For instance:
[tt]

----8<--- testasm.asm ---8<----
.model medium
.386
.code

public assembler_function

assembler_function proc near
push bp
mov bp, sp
mov ax, ss:[ignore][bp + 6][/ignore] ; pull an INTEGER from the stack
pop bp ; leave the value in AX for the FUNCTION return value
retf ; QB will clean up the stack because the calling
assembler_function endp ; convention is CDECL

end
----8<--- test.bas ---8<----
DECLARE FUNCTION asmTest% CDECL ALIAS &quot;assembler_function&quot; (BYVAL intArgument%)

PRINT asmTest(5) ' should output 5
----8<--- build procedure & test run ---8<----
[ignore][c:\qb71\test][/ignore]tasm testasm.asm[ignore]
Turbo Assembler Version 4.1 Copyright (c) 1988, 1993 Borland International

Assembling file: testasm.asm
Error messages: None
Warning messages: None
Passes: 1
Remaining memory: 412k


[c:\qb71\test][/ignore]bc /g2/ot test.bas,test.obj,nul.lst[ignore]
Microsoft (R) BASIC Compiler Version 7.10
Copyright (C) Microsoft Corporation 1982-1990. All rights reserved.

44228 Bytes Available
43923 Bytes Free

0 Warning Error(s)
0 Severe Error(s)

[c:\qb71\test][/ignore]link test.obj+testasm.obj,test.exe,nul.map,..\bcl71enr.lib;[ignore]

Microsoft (R) Segmented-Executable Linker Version 5.10
Copyright (C) Microsoft Corp 1984-1990. All rights reserved.


[c:\qb71\test][/ignore]test.exe[ignore]
5

[/ignore][ignore][c:\qb71\test][/ignore]

As you can see, building the binary is a bit more involved than regular, but the approach is far more powerful & flexible (and safe). It is also more maintainable, especially if you are working on large projects (though of course if you're working on large projects, you should move up to a modern language like C#).

As for the string format -- I believe QB passes a pointer to the string's descriptor, which contains the length of the string followed by the actual string data. I haven't investigated this and I haven't spent much time playing with QB strings in assembler routines. I certainly have no clue how to create a new QB string, though I would feel fairly confident overwriting the already-allocated block of memory owned by a string with a new string. The first step in figuring out how the string works, though, is to start following pointers in a debugger :) Good luck.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top