www.delorie.com/djgpp/v2faq/faq145.html | search |
| Previous | Next | Up | Top |
Q: I have some real-mode code that calls the segread
function. How can I make it work with DJGPP?
int86x
or intdosx
for a DOS or BIOS function supported by them, then just put the address of your buffer into the register which expects
the offset (regs.x.di
), forget about the segment, and call int86
or intdos
instead of int86x
and intdosx
. The DOS/BIOS functions
supported by int86
and intdos
are processed specially by the library, which will take care of the rest. Note that calling int86x
and intdosx
will
usually crash your program, since they expect that you pass them a real-mode segment:offset address to a buffer in conventional memory; this is done more easily with __dpmi_int
, see
below.
If you call __dpmi_int
, then you must put into that register pair an address of some buffer in conventional memory (in the first 1 MByte). If the size of that buffer doesn't
have to be larger than the size of transfer buffer used by DJGPP (at least 2KB, 16KB by default), then the easiest way is to use the transfer buffer. (Library functions don't assume the contents of
the transfer buffer to be preserved across function calls, so you can use it freely.) That buffer is used for all DOS/BIOS services supported by DJGPP, it resides in conventional memory, and is
allocated by the startup code. DJGPP makes the address and the size of the transfer buffer available for you in the _go32_info_block
external variable, which is documented the library
reference. Check the size of the buffer (usually, 16K bytes, but it can be made as small as 2KB), and if it suits you, use its linear address this way:
dpmi_regs.x.di = _go32_info_block.linear_address_of_transfer_buffer & 0x0f; dpmi_regs.x.es = _go32_info_block.linear_address_of_transfer_buffer >> 4;For your convenience, the header file go32.h defines a macro
__tb
which is an alias for _go32_info_block.linear_address_of_transfer_buffer.
Here's a simple example of calling a real-mode service. This function queries DOS about the country-specific information, by calling function 38h of the DOS Interrupt 21h, then returns the local
currency symbol as a C-style null-terminated string in malloc
ed storage. Note how the transfer buffer is used to retrieve the info: the address of the transfer buffer is passed to DOS,
so it stores the data there, and the function then retrieves part of that data using dosmemget
.
#include <sys/types.h> #include <sys/movedata.h> #include <dpmi.h> #include <go32.h> char * local_currency (void) { __dpmi_regs regs; regs.x.ax = 0x3800; /* AH = 38h, AL = 00h */ regs.x.ds = __tb >> 4; /* transfer buffer address in DS:DX */ regs.x.dx = __tb & 0x0f; __dpmi_int (0x21, ®s); /* call DOS */ if (regs.x.flags & 1) /* is carry flag set? */ /* The call failed; use the default symbol. */ return strdup ("$"); else { /* The call succeeded. The local currency symbol is stored as an ASCIIZ string at offset 2 in the transfer buffer. */ char *p = (char *)malloc (2); if (p != 0) dosmemget (__tb + 2, 2, p); return p; } }If the size of the transfer buffer isn't enough, you will have to allocate your own buffer in conventional memory with a call to the
__dpmi_allocate_dos_memory
library function. It
returns to you the segment of the allocated block (the offset is zero). If you only need a small number of such buffers which can be allocated once, then you don't have to worry about freeing them:
they will be freed by DOS when your program calls exit.
For bullet-proof code, you should test the size of the transfer buffer at runtime and act accordingly. This is because its size can be changed by the STUBEDIT program without your knowledge (however, it can never be less than 2KB, the size of the stub, because memory used by the stub is reused for the transfer buffer).
The function segread
used by some real-mode compilers does not exist in DJGPP. It is used in real-mode code to store the values of the CS, DS,
SS, and ES registers into a struct SREGS
variable, when some service that needs one of these registers is called from code written for small and tiny
memory models. DJGPP has the functions _my_cs
, _my_ds
, and _my_ss
for that purpose (ES and DS always hold the same selector in
code produced by GCC from a C or C++ source, so you don't need a fourth function). However, these will not be useful if the original real-mode code used the segment registers to invoke
DOS/BIOS services. For these cases, you will need to rewrite the code so that it copies the data to/from the transfer buffer and passes its address via __dpmi_int
, as described above.
webmaster donations bookstore | delorie software privacy |
Copyright ⌐ 1998 by Eli Zaretskii | Updated Sep 1998 |
You can help support this site by visiting the advertisers that sponsor it! (only once each, though)