I've got a question over on the Nasm forum that I can't figure out the answer to.

"Normally", we'd be writing an asm routine and calling it from QB. This guy is trying to write an asm "main" and call a function (B$PESD) from the Quick Basic Library (BCOM45.LIB) to print a message (don't ask "why"... that way lies madness).

He's got working code using the "simplified" Masm directives - ".model medium, basic", but can't get it to work (no output at all, apparently) with Nasm, or with Masm's "classic" directives.

Any Masm gurus know what ".model medium, basic" does? Particularly the "basic" modifier? I think I can beat Nasm into submission if I know what we're supposed to be doing...

TIA for any help or advice.

Best,
Frank



Posted on 2009-10-26 11:00:08 by fbkotler
I found this that seems to illustrate some of the differences.
Posted on 2009-10-26 11:22:59 by SpooK
Probably BASIC runtime is not properly initialized when he tries to call that function.

Is he trying to statically link against BCOM45.LIB? Brave effort, perhaps he should compile and link several simple BASIC programs and examine generated .Obj/.Exe files for clues.

Entry point appears to be in CRT0 module, namely __astart. It calls _main in RTINIT, which uses BC_SAB segment as a placeholder for some initialization structure (it does far jmp via some pointer at offset 0 in this segment +30h).

What's so valuable in this (supposedly output) function?

BASIC in the .MODEL directive sets default calling/naming conventions for PROC/PROTO and external/public symbols. They're identical for Pascal/FORTRAN/BASIC, symbols all-caps, parameters pushed left-to-right, callee stack cleanup. Does anybody read manuals nowadays?

UPDATE: It's BC_SA segment that really contains far pointer to module descriptor (sandwiched between BC_SAB and BC_SAE). Module descriptor contains notorious "bm<MODNAME>" signature and is 0x30 bytes in length. Immediately after it module startup code begins. With some patience willing developer can coax BASIC runtime to think that his .Obj is legal BASIC module.
Posted on 2009-10-26 14:07:34 by baldr
Thanks for the link, SpooK - I've passed it along.

Baldr's suggestion the some "initialization" may be required makes perfect sense to me, but doesn't explain why "avcaballero" (the guy on the Nasm forum) Masm example works, and his Nasm example doesn't. Here's (part of) what he's posted:

Working Masm code:

0001 BA9A22        MOV    DX,229A
0004 8EDA          MOV    DS,DX
0006 8CD3          MOV    BX,SS
0008 2BDA          SUB    BX,DX
000A D1E3          SHL    BX,1
000C D1E3          SHL    BX,1
000E D1E3          SHL    BX,1
0010 D1E3          SHL    BX,1
0012 FA            CLI
0013 8ED2          MOV    SS,DX
0015 03E3          ADD    SP,BX
0017 FB            STI
0018 B81A00        MOV    AX,001A
001B 50            PUSH  AX
001C 9ACA1DFB1F    CALL  1FFB:1DCA
0021 B44C          MOV    AH,4C
0023 CD21          INT    21

Not working Nasm code:

0000 B83522        MOV    AX,2235
0003 8ED0          MOV    SS,AX
0005 BC0001        MOV    SP,0100
0008 B83322        MOV    AX,2233
000B 8ED8          MOV    DS,AX
000D B81200        MOV    AX,0012
0010 50            PUSH  AX
0011 9AC41DF91F    CALL  1FF9:1DC4
0016 B44C          MOV    AH,4C
0018 CD21          INT    21

I've just learned from baldr's reply to dre (in "physical address") that the stack manipulation is generated by the ".STARTUP" macro. Outside of the difference in the way the stack is set up (why??? in either case? DOS sets up the stack for us!), it looks about the same to me. He's tried (or promised to try) duplicating the stack manipulation exactly the way Masm does it. No joy yet...

Apologies for the awkwardness of doing this "second hand". We're probably doing something simple wrong. Perhaps he'll be along to discuss it for himself...

Skywalker just mentioned moving a post to "heap" because it was 16-bit code. Should I have done that?

Thanks for the help so far!

Best,
Frank

Posted on 2009-10-26 17:35:53 by fbkotler

Skywalker just mentioned moving a post to "heap" because it was 16-bit code. Should I have done that?


MAIN is pretty much for everything ASM, The Heap is pretty much for everything non-ASM.
Posted on 2009-10-26 19:48:25 by SpooK
Many moons ago 16bit code used to get sent to the heap. Why never really made sense to me...
Posted on 2009-10-26 20:08:30 by JimmyClif

Many moons ago 16bit code used to get sent to the heap. Why never really made sense to me...


I'm guessing it was back when this place was solely concentrating on Win32ASM and/or MASM32 :lol:
Posted on 2009-10-26 20:10:55 by SpooK
Well, it was his post... :)

16-bit code - especially calling QB from asm - isn't a real "high interest" area these days. Thought you might be reserving "main" for 32-bit code...

Best,
Frank

Posted on 2009-10-26 20:11:59 by fbkotler
I don't code DOS, haven't in years, and I can't honestly say I've ever had any interest in PB. But just out of curiosity, has he tried something like:

	BITS 16
EXTERN B$PESD

;:::::<< DYNAMIC STRING MACRO >>:::::;
%macro DSTR 2
%push _DSTR_
%%lbl: DB %2
%{1}: DW ($-%%lbl), %%lbl
%pop
%endm

SEGMENT DATA ALIGN=16
DSTR g_Desc, "Hola, Quick Basic!"

SEGMENT BSS STACK
RESB 256

SEGMENT CODE FAR
..start:
;:::::<< UPDATE DATA SEGMENT >>:::::;
MOV DX, DATA
MOV DS, DX

;:::::<< SETUP STACK SEGMENT >>:::::;
MOV BX, SS
SUB BX, DX
SHL BX, 4
CLI
MOV SS, DX
ADD SP, BX
STI

;:::::<< CALL B$PESD >>:::::;
MOV AX, g_Desc
PUSH AX
CALL B$PESD

;:::::<< EXIT TO DOS >>:::::;
MOV AH, 4Ch
INT 21H


Ignore the macro, I just added that while doing a little testing to try and accomplish a similar disassembly to the MASM version. If that works, it might have something to do with something I read once before about PB internal procedures using some kind of internal interrupt trapping system for allowing procedures to communicate without dealing with various relocations. This might be why the IF is set before the call.

I am glad you brought this here however, I'm kinda liking the dynamic string layout and it seems much more useful than ASCIIZ. I might start using it internally in some of my stuff.  :thumbsup:
Posted on 2009-10-26 21:36:15 by Synfire
Well, the original code he posted did something like:

mov ax, pila
mov ss, ax
mov sp, initiopila

There's an example in the Nasm manual that shows this - pointless, AFAIK. Dos sets ss:sp, this just reloads the same values, in my experience. He doesn't cli/sti around it. The CPU is supposed to disable interrupts for one instruction after a move to ss, but some buggy CPUs failed to do this, so it was considered "good form" to cli/sti around it. I don't think we're likely to run into any of the offending CPUs these days, but I suppose it's still "good form". Are you saying that this might be key to calling Qbasic? Worth a try...

I don't understand the point of the stack manipulation that Masm apparently emits from the ".STARTUP" macro/directive. We make ss=ds and adjust sp so it points to the same place as the original ss:sp... I suppose it allows us to reference the data segment with bp... maybe QB counts on that??? I'll pass the idea along...

Nice macro. I'll pass that along, too. If I may ask, what's the purpose of the "%push"/"%pop" of the context stack? My (limited) understanding was that the context stack was useful mostly in multiple macros that had to interact with each other - like IF/ELSE/ENDIF, or so.

Are you running Linux? Are you familiar with sys_writev (and sys_readv)? A similar macro might be useful for making "vectors" to use with sys_writev... Just a thought..

Thanks for looking at this!

Best,
Frank

Posted on 2009-10-27 00:23:01 by fbkotler
Thank you for your interest!...

16 bit coding generates controversia as I can see... Well, someone could say that asm programming too... :)

What I am doing is documenting asm coding for myself. Now I am writing mixing asm and hll. Writing an message in asm calling "printf" in c is probably more common, but i thought why not in Turbo Pascal too? and quick basic?. Well, I could do it in Quick Basic with masm simplified code, but I couldn't in turbo pascal :(.

I think 16 bit programming is the first place to learn programming. At least asm programming. Only 16 bit programming?. No, of course.

I will probe something more as soon as I can.

Attachments:
Posted on 2009-10-27 05:47:47 by avcaballero
Ooops! can't paste images, I submit a file!
Attachments:
Posted on 2009-10-27 07:01:56 by avcaballero
QuickBASIC RTL expects specific variation of medium model, SS equals DS (i.e. they're grouped together). I added group DGROUP Datos Pila and replaced them in seg. reg. initialization with DGROUP. It works.
Posted on 2009-10-27 10:27:36 by baldr
Yuhuuuu!. It's like to see born a baby... Thank you!

Posted on 2009-10-27 10:57:51 by avcaballero

Nice macro. I'll pass that along, too. If I may ask, what's the purpose of the "%push"/"%pop" of the context stack? My (limited) understanding was that the context stack was useful mostly in multiple macros that had to interact with each other - like IF/ELSE/ENDIF, or so.


During the development of NASMX I found that local labels '%%lbl' in this instance, don't expand well and sometimes conflict when you don't setup a context for the macro. By adding a context you effectively put the local value into it's own space to avoid any possible, future or past, naming conflicts. So personally I always setup macros with:

%macro NAME 0
%push _NAME_
; code here
%pop
%endm


Unless I explicitly need the context stack to span multiple macros in which case I move the %pop into the other macro. This mirrors the include layout of:

%ifndef _NAME_
%define _NAME_

%endif


Almost exactly and I've grown fond of both. :)


Are you running Linux? Are you familiar with sys_writev (and sys_readv)? A similar macro might be useful for making "vectors" to use with sys_writev... Just a thought..


Yea, I'm running Linux. That's why I made that macro when I saw what he was doing. Almost all syscall interrupts deal with flat strings and a size attribute. I basically had the same idea as you, I'm working on adding a dstring.h for use in my personal system.h file. They will take up a little more space in the executable (or memory) but execution times should drop being as there won't be a need for routines like strlen, and since branches tend to work faster backwards it'll increase the speed of procedures like strcmp.
Posted on 2009-10-27 23:08:44 by Synfire