[comp.os.msdos.programmer] Int 10H Function 13H - How Do I access BP from C ?

d87-vik@dront.nada.kth.se (Ville K{rkk{inen) (10/20/90)

Organization: Royal Institute of Technology, Stockholm, Sweden

I'm trying to access the Int 10 Function 13 ( Write string in teletype mode )
from Microsoft C 5.10. Everything has worked out fine so far, but today I found
out that the calling convention requires the offset of the string to be stored
in the BP register ! (BasePointer actually).

Now I wonder, is there a way to set the BP from C, or do I have to write a
.asm-hack that first saves the BP before the actual call, and then restores
it.(Which if I'm not wrong requires an update to MSC 6.0)

Any comments appreciated !

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
----- We are confronted with vaste quantities of plastic people. F Zappa ------
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Ville.

trier@klah.INS.CWRU.Edu (Stephen C. Trier) (10/20/90)

In article <1990Oct19.202013.28397@nada.kth.se> d87-vik@dront.nada.kth.se (Ville K{rkk{inen) writes:
>Now I wonder, is there a way to set the BP from C, or do I have to write a
>.asm-hack that first saves the BP before the actual call, and then restores
>it.(Which if I'm not wrong requires an update to MSC 6.0)

Use the functions int86 or int86x.  With these, you load your registers
into a structure, then pass the registers to the function.  The function
takes care of the rest.  All registers can be set this way.

A C compiler that can't link to assembly is pretty poor.  MS-C can certainly
do it from version 4.0 on; I imagine it's been supported since version 1.0.

-- 
Stephen Trier                              Case Western Reserve University
Work: trier@cwlim.ins.cwru.edu             Information Network Services
Home: sct@seldon.clv.oh.us
       "If we can't fix it, it ain't broke." - Ernie Ellenberger

d87-vik@dront.nada.kth.se (Ville K{rkk{inen) (10/22/90)

Forgive me for not mentioning that I am aware of the existance of functions
intdos,int86 and int86x. In fact I am using all of these, each when appropiate.

So I just like to add this to my original posting  before I drown in answers 
like "RTFM- use int86x.....!!!". The problem is *NOT* as easy as might be
seen in a quick first glance. I have had no problems whatsoever using other
functions that requires a pointer to some data to be stored as a segment and 
and an offset in that segment. 

My problem is that Int10h - Func13h requires the offset of my data to be stored
in BP,that is, the BasePointer. Note this,BP is a pointer, not a register
defined in the REGS union. Some of my answers has been quite helpful though,
I have been told of the existance of a "regpacks" struct defined somewhere
in TC (I'm stuck to MS-C 5.1), where the BP was accessible in "r_bp".
So my problem is not a  "what to do" one, but a "how to do".

Any hints to where I can find a similar structure defined in MS-C appreciated.

So please have patience with me and give it a little thought.

Ville.

gday@digigw.digital.co.jp (Gordon Day) (10/23/90)

In article <1990Oct21.204236.22011@nada.kth.se>, d87-vik@dront.nada.kth.se (Ville K{rkk{inen) writes:
> 
> My problem is that Int10h-Func13h requires the offset of my data to be stored
> in BP,that is, the BasePointer. Note this,BP is a pointer, not a register
> defined in the REGS union. 

Unfortunately, you can't do this from Microsoft C (at least, not without some
inline assembler).  The value of a specific register cannot be read or changed
from C on the PC which is why the interrupt-type functions provided by the MSC
libraries are implemented in assembly.  The reason is that the definition 
of the language doesn't support the idea of "named" registers, that is, a 
mapping of a special variable name directly to a physical machine register.  
There is nothing stopping a compiler implementor from doing this (e.g. the 
VAX based BSD4.3 C compiler), but no compilers (to my knowledge) on the PC do,
as it is both easier and much less of a bad hack to provide an assembly 
based library routine to do it.  

So, you'll have to grit your teeth and write a new "int86x()" that takes a 
REGS-type struct that includes a value to/from the BP register.  It's not a
terribly difficult thing to do, just remember not trash your stack frame.

> So please have patience with me and give it a little thought.

Consider it done.


Gordon W. Day

nbladt@aut.UUCP (Norbert Bladt) (10/24/90)

trier@klah.INS.CWRU.Edu (Stephen C. Trier) writes:

>In article <1990Oct19.202013.28397@nada.kth.se> d87-vik@dront.nada.kth.se (Ville K{rkk{inen) writes:
>>Now I wonder, is there a way to set the BP from C, or do I have to write a
[story about setting BP deleted]

>>it.(Which if I'm not wrong requires an update to MSC 6.0)
Right w.r.t. the update !

>Use the functions int86 or int86x.  With these, you load your registers
Right !

[more text how to use int86 deleted].

>A C compiler that can't link to assembly is pretty poor.  MS-C can certainly
>do it from version 4.0 on; I imagine it's been supported since version 1.0.
You missed the point !
Inline assembly indeed requries MS-C 6.0 (and MASM or TASM I would guess).
I once saw a program named MASM.EXE which just called TASM with some additional
parameters, so you really don't need MASM.

But, try it with the int86 or int86x, first.

Norbert Bladt.
-- 
Please use this path as return address. DON'T USE THE RETURN PATH IN THE HEADER
Norbert Bladt, Ascom Autelca AG, Worbstr. 201, CH-3073 Guemligen, Switzerland
Phone: +41 31 52 92 14
EMail: ..!uunet!mcsun!chx400!hslrswi!bladt

fmgst@unix.cis.pitt.edu (Filip Gieszczykiewicz) (10/24/90)

.>A C compiler that can't link to assembly is pretty poor.  MS-C can certainly
.>do it from version 4.0 on; I imagine it's been supported since version 1.0.
.You missed the point !
.Inline assembly indeed requries MS-C 6.0 (and MASM or TASM I would guess).
.I once saw a program named MASM.EXE which just called TASM with some additional
.parameters, so you really don't need MASM.

	You can also use A86 assembler on Simtel. It has a .com file
	that you rename to MASM.COM and it executes like the real
	thing. I also think that it provides a more compact result and
	is _almost_ Masm comaptible.
.
.But, try it with the int86 or int86x, first.

	Weeeellll... First, it's slow. Second, you can't do anything
	other than they supply. For example, the guy is trying to
	use registers that are not passed by the INT86 routines
	(or so I understood) and it's foolish to rewrite them ;-)
.
.Norbert Bladt.

	Take care.
-- 
_______________________________________________________________________________
"The Force will be with you, always." It _is_ with me and has been for 10 years
Filip Gieszczykiewicz  "... a Jedi does it with a mind trick... " ;-)
FMGST@PITTVMS  or  fmgst@unix.cis.pitt.edu "My ideas. ALL MINE!!"

shurr@cbnews.att.com (Larry A. Shurr) (10/25/90)

In article <685@digigw.digital.co.jp>, gday@digigw.digital.co.jp (Gordon Day) writes:
} In article <1990Oct21.204236.22011@nada.kth.se>, d87-vik@dront.nada.kth.se (Ville K{rkk{inen) writes:
} } [Wishes to access BP from C source level in MSoft C.]

} Unfortunately, you can't do this from Microsoft C (at least, not without some
} inline assembler).

} The reason is that the definition 
} of the language doesn't support the idea of "named" registers, that is, a 
} mapping of a special variable name directly to a physical machine register.  
} There is nothing stopping a compiler implementor from doing this (e.g. the 
} VAX based BSD4.3 C compiler), but no compilers (to my knowledge) on the PC do,

You may be interested to know that Turbo C does provide this facility.  Thus,
one can write:

	_AX = 1;

and the AX register gets the value 1.  You must, however, keep your brain 
engaged when using this facility, I once coded the following:

	_AX = foo;
	_BX = this + that;

Afterwords, both AX and BX contained the value of the expression "this + that."
Imagine that!  The compiler used the AX register to calculate the value of
the expression, clobbering what I had put in there beforehand... just like you
would expect.

regards, Larry
-- 
Larry A. Shurr (cbnmva!las@att.ATT.COM or att!cbnmva!las)
The end of the world has been delayed due to a shortage of trumpet players.
(The above reflects my opinions, not those of AGS or AT&T, but you knew that.)

Ralf.Brown@B.GP.CS.CMU.EDU (10/27/90)

In article <685@digigw.digital.co.jp>, gday@digigw.digital.co.jp (Gordon Day) wrote:
}inline assembler).  The value of a specific register cannot be read or changed
}from C on the PC which is why the interrupt-type functions provided by the MSC
}libraries are implemented in assembly.  The reason is that the definition 
}of the language doesn't support the idea of "named" registers, that is, a 
}mapping of a special variable name directly to a physical machine register.  
}There is nothing stopping a compiler implementor from doing this (e.g. the 
}VAX based BSD4.3 C compiler), but no compilers (to my knowledge) on the PC do,

Don't tell Turbo C, which has let you directly manipulate the CPU registers
since v1.00.  I regularly write code like

	_AX = 0x2B00 ;
	_CX = 0x4445 ;
	_DX = 0x5351 ;
	geninterrupt(0x21) ;
	if (_AL != 0xFF)
	   DESQview_version = _BX ;
	else
	   DESQview_version = 0 ;

though it takes some care when putting things other than numeric literals
into a register (since many complex assignments clobber other registers).
TC will let you mess with BP, DS, SS, and SP, but one does so at one's own
peril, since those registers are vital to the continued running of the
compiled C code.
--
UUCP: {ucbvax,harvard}!cs.cmu.edu!ralf -=- 412-268-3053 (school) -=- FAX: ask
ARPA: ralf@cs.cmu.edu  BIT: ralf%cs.cmu.edu@CMUCCVMA  FIDO: 1:129/3.1
Disclaimer?    |   I was gratified to be able to answer promptly, and I did.
What's that?   |   I said I didn't know.  --Mark Twain

shack@cs.arizona.edu (David Shackelford) (10/30/90)

In article <685@digigw.digital.co.jp> gday@digigw.digital.co.jp (Gordon Day) writes:
>In article <1990Oct21.204236.22011@nada.kth.se>, d87-vik@dront.nada.kth.se (Ville K{rkk{inen) writes:
>> 
>> My problem is that Int10h-Func13h requires the offset of my data to be stored
>> in BP,that is, the BasePointer. Note this,BP is a pointer, not a register
>> defined in the REGS union. 
> [stuff on MSC & VAX deleted], but no compilers (to my knowledge) on the PC do,
>
>Gordon W. Day

TurboC has aliases to the actual registers defined, and you can directly write
to the hardware with a couple of restrictions.  You cannot change the segment
registers, SP, or BP.  Unfortunately, this means that the original poster
would not be able to use this anyway.

I don't understand why the int86?() functions don't work, as the regs structure
does contain a BP field, which is properly modified and sent to the BIOS func.
(At least it is in TURBOC, can't say for other compilers).  I use this all of
the time in my mouse handler functions.

Perhaps a code example from the non-working program might help to find a fix.

Dave    | shack@cs.arizona.edu

lsalomo@hubcap.clemson.edu (lsalomo) (10/30/90)

From article <488@caslon.cs.arizona.edu>, by shack@cs.arizona.edu (David Shackelford):
> TurboC has aliases to the actual registers defined, and you can directly write
> to the hardware with a couple of restrictions.  You cannot change the segment
> registers, SP, or BP.  Unfortunately, this means that the original poster
> would not be able to use this anyway.

Yes, you can change any of the registers, provided you disable interrupts
before the modification, and enable them afterwards.  I wrote a multi-tasking
OS kernal whose dispatcher did this very thing...

Cheers,
Q - the "Q"uestor for knowledge (, a degree, etc.)

lsalomo@hubcap.clemson.edu
ibmman@prism.clemson.edu
ibmman@clemson.clemson.edu
=============================================================================
"Gee Wally, I think there's something wrong with the Beaver."
=============================================================================

hughes@locusts.Berkeley.EDU (Eric Hughes) (11/21/90)

In article <1990Oct21.204236.22011@nada.kth.se>
d87-vik@dront.nada.kth.se (Ville K{rkk{inen) writes:
>My problem is that Int10h - Func13h requires the offset of my data to
>be stored in BP,that is, the BasePointer. Note this,BP is a pointer,
>not a register defined in the REGS union.

BP is the base pointer from which all auto variables are referenced
and which saves the value of SP.  If you change the value of BP, you
must change it back again before the C function returns.  The only
code which changes BP in compiled code (for MS C 5.1, the compiler in
question) are the function prolog and epilog, which set up the stack
frame.

Really, the easiest way to get at the BIOS service you want is to wrap
it in some assembly language which uses the C calling convention.  See
the mixed model programming guide on how to do this.

Now you *can*, through some total deviousness, get a copy of the
string you want to print in the location pointed by BP and safely
return from that function, but once you've done that, you need to
invoke the interrupt without changing stack frames.  I don't know of a
way to trick MS C 5.1 into generating an int 10h instruction without
using self-modifying code.  (Take a pointer to a function which
contains a dummy instruction, calculate an offset based on an assembly
code listing, make sure you write into the code segment somehow, and
poke in the instruction by hand.)  The upshot of this is that assembly
is pretty much required.

Eric Hughes
hughes@ocf.berkeley.edu

dgil@pa.reuter.COM (Dave Gillett) (11/30/90)

In <HUGHES.90Nov20114508@locusts.Berkeley.EDU> hughes@locusts.Berkeley.EDU (Eric Hughes) writes:

>In article <1990Oct21.204236.22011@nada.kth.se>
>d87-vik@dront.nada.kth.se (Ville K{rkk{inen) writes:
>>My problem is that Int10h - Func13h requires the offset of my data to
>>be stored in BP,that is, the BasePointer. Note this,BP is a pointer,
>>not a register defined in the REGS union.

>BP is the base pointer from which all auto variables are referenced
>and which saves the value of SP.


     Function 13H actually has three problems:
          (a) It expects a pointer in ES:BP.
               BP is normally an offset into the Stack segment (SS:BP).  So
               I expect that the function has internal overhead associated
               with making a usable address out of the supplied paramenters.

          (b) BP is unusable from high-level languages.
               As Eric has explained, BP is used to implement stack frames
               as part of the calling sequence generated by almost all
               MS-DOS compilers.  So you effectively have to resort to
               assembly language (Turbo C's inline 'asm' keyword can help,
               but what if you're using some other compiler?) to use this
               function.

          (c) Many machine BIOSes don't have it.
               Maybe you don't consider this a problem, but *I* generally
               write stuff that should work on any PC.

     Now, since it is possible to write a routine which has all of the visible
effects of function 13H, with none of these drawbacks and negligible
performance difference, with only a trivial amount of effort, I would say
that the correct answer to Ville is "Don't even try to use that function!"
                                               Dave

Note:  We don't get comp.os.msdos.* here, for some mysterious reason.