Path: csiph.com!usenet.pasdenom.info!aioe.org!.POSTED!not-for-mail From: "Rod Pemberton" Newsgroups: comp.os.msdos.programmer Subject: Re: XMS transfer troubles with Turbo C Date: Sun, 27 Jul 2014 12:32:41 -0400 Organization: Aioe.org NNTP Server Lines: 109 Message-ID: References: <53d13fd3$0$2229$426a74cc@news.free.fr> <53d3bc6c$0$2043$426a74cc@news.free.fr> <53d4b104$0$2197$426a34cc@news.free.fr> NNTP-Posting-Host: CNsg4fVcCsvs3UaOgZtQCw.user.speranza.aioe.org Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit X-Complaints-To: abuse@aioe.org User-Agent: Opera Mail/12.16 (Linux) X-Notice: Filtered by postfilter v. 0.8.2 Xref: csiph.com comp.os.msdos.programmer:1464 On Sun, 27 Jul 2014 03:57:57 -0400, Mateusz Viste wrote: > On 07/26/2014 07:21 PM, Rod Pemberton wrote: >>> Specifically, what's the "cs:" for? XMSDriver is a DWORD that contains >>> the address of an external function. >> >> CS is a code segment override. It tells the processor to use the code >> segment register for the segment > > That's what I was thinking - but since XMSDriver is a "far" pointer > (32bit long), isn't it supposed to already contain the right segment > address in it's upper 16 bits? > x86 has multiple forms of the call instruction. One will pick up the segment and offset from memory. They other will just use the offset. Usually, you just need a "far" keyword to the form which uses both. So, instead of setting up the CS as I suggested, you probably just need a far keyword. >> I suspect that you don't want CS here. CS is the CS of your code, >> not the CS of the XMSDriver. > > In fact, this CS thing isn't from me (obviously, since I don't > understand what it's supposed to do). It's code I read in the XMS > library by Michael Graff. In almost every function, he calls the XMS > driver routine using this: > > call [dword _XMSDriver] > I would think he'd need a "far" keyword here. Otherwise, the assembler is like to use the offset only form. E.g., somesuch: call far [dword _XMSDriver] call [far dword _XMSDriver] > And how the above works is pretty clear to me. But then, specifically > for the xms "move" action (ie. the routine where one needs to play with > SI and DS), he does it differently: > > push ds ; save Turbo's data segment > mov ah,XMoveEMB ; function code > lds si,[MoveRec] ; Point ds:si to MoveRec > call [dword cs:_XMSDriver] ; call the XMS driver > mov al,bl ; transfer XMS error code to al > pop ds ; restore Turbo's data segment > > And that's the "cs:" call I was wondering about... This implies that _XMSDriver routine is within his code segment. That's unlikely, unless _XMSDriver routine is a routine of his and not the actual call to the XMS driver. That might be why he doesn't need a "far" keyword above too. >> Assuming you've saved the segment and offset from Int 2fh, AH=4310h >> like in the XMS 3.0 specification, you'd do something like: >> >> mov es, [XMSDriver+2] ; saved segment >> call [dword es:XMSDriver] >> >> You can push and pop es, if needed. > > Thanks for the suggestion - I will try it, even though I don't > understand why such "code segment override" would be needed in the first > place, since my XMSDriver pointer should already have the right segment > set... It's the difference between a "near" and "far" call in x86. x86 supports a call to just an offset. In that case, the CS segment is used as the segment for the address. x86 also supports a far call. This loads both the segment and offset. Your address will need to match whatever form you're using for assembly or C. The C compiler may use a different format of it's own too. E.g., for 16-bit RM C, typically, the MK_FP() macro or function is used to construct an address, whereas in 32-bit PM C code, the compiler will usually just use the offset since offsets are larger, 32-bits. This means you can assign addresses directly to a pointer in 32-bit code. Sometimes you have to add an offset to adjust where the pointer points. Othertimes, you don't. This is C compiler specific stuff. > Fun fact: if I call printf() just before calling my XMS stuff, > everything magically works. Always. That's usually an indication of a memory leak or out-of-bounds reference of some sort. printf() routines allocate memory. When they do, your code works. > I discovered this yesterday, when trying to trace the SEG:OFFSET address > I use to call XMSdriver when it makes my computer freeze, and just > adding a single a printf() before the XMS call made everything work... > My two thoughts so far are that either printf() plays with CS in a way > that pleases the XMSDriver (sounds like an unlikely coincidence), or > printf() introduces a very slight delay that is long enough so a > hypothetical (and unknown to me) IRQ executes during printf(), instead > of executing during my XMS routine where I change DS and SI registers. It could be something other than a memory leak. I'm not familiar with Turbo C. But, that's been the case with DJGPP (GCC for DOS). I read your other messages, but have nothing to add. Rod Pemberton