Path: utzoo!utgpu!watserv1!watmath!att!att!pacbell.com!ucsd!usc!elroy.jpl.nasa.gov!jarthur!dfoster From: dfoster@jarthur.Claremont.EDU (Derek R. Foster) Newsgroups: comp.os.msdos.programmer Subject: Re: Porting UNIX apps. to MS-DOS Message-ID: <9478@jarthur.Claremont.EDU> Date: 1 Nov 90 06:03:45 GMT References: <1990Oct26.223541.26634@NCoast.ORG> <9449@jarthur.Claremont.EDU> <1990Oct31.190520.11526@Octopus.COM> Organization: Harvey Mudd College, Claremont, CA 91711 Lines: 101 In article <1990Oct31.190520.11526@Octopus.COM> stever@octopus.UUCP (Steve Resnick ) writes: >In article <9449@jarthur.Claremont.EDU> dfoster@jarthur.Claremont.EDU (Derek R. Foster) writes: > >[Stuff deleted] >> >>Although this is generally true in "nice" programs, there may be a somewhat >>kludgy workaround for this. DISCLAIMER: I haven't tried the following >>suggestion. This is all theory on my part, and I would be interested in >>hearing comments on it. Also the code I present is sketchy at best, and >>is probably outright wrong in some respects. Don't expect it to work; >>just use it as a model. >> >>Anyway, you might try changing the stack segment pointer to point into >>a new segment of your own when the old one gets filled. For instance, >>if you can identify a particular part of the program which will be >>called only when the stack is almost filled, you might try something >>like ... >> >>void huge char ABuffer[(some fancy calculation probably involving _stklen >> to preserve the ability to detect stack overflow) + 16 (the 16 is to >> ensure that I can always get a buffer of at least the size I want >> which starts on an even paragraph boundary)]; >> >Warning Will Robinson! :) There is nothing to prevent you from changing the >stack on a '86 processor, but you *cannot* access more than 64K. Even >though TC supports huge pointers and deals with the additional segment >arithmetic, the processor doesn't. Eg, PUSH/POP instructions will fail >on a segment wraparound. Although this is technically true, the way you have phrased it is somewhat misleading. The limit is 64k PER STACK SEGMENT. The technique I am using first fills up the "default" stack segment, <= 64k, then switches to a new one when that one is full, also <= 64k, for a resultant "effective" stack size of >64k. So even though the stack pointer (which, as another poster pointed out, I forgot to mention in my sample code) can never be farther away from _SS than 64k, we could build an indefinitely long "linked list" of stacks, just as long as we remember to switch from one to the other when we are in danger of over/underflowing the one we are in. We should never have to deal with PUSHes and POPs over a segment boundary during this process, since if the stack pointer gets close to one, we're supposed to switch to a new stack. > >If you do change the stack segment and pointer to a new address you cannot >do any stack checking since the stack segement is different than the one >defined by the C runtime startup routines. > Not necessarily... I think it is _highly_ likely that _stklen measures the height of the stack relative to the stack segment register, and not to some absolute position in memory. (After all, what would be the point of using the segment value of a quantity if it's never supposed to change, and you always have a (normally constant) register pointing at it?) As such, if each "link" in the "linked list" is of a size to accomodate _stklen, then if we overflow the current stack segment by exceeding _stklen, a "stack overflow" message is printed, but if we instead switch to a new stack and reset the stack pointer, we can keep adding to the new stack until we are again in danger of exceeding _stklen relative to the _new_ stack segment. Thus the stack checking routines perform their intended purpose, sort of, namely detecting a program trying to write stack data outside of any stack segment. >> oldSS = _SS; > > You *MUST* disable interrupts during this operation. If an interrupt > occures during the stack segment transition, you will not return > from the interrupt correctly and crash the machine. True. Definitely disable interrupts. Oh, incidentally, another bug in my example code: don't store the old _SS in an automatic (local) variable. Since this variable actually resides on the first stack, once you change it, you have no way to access the old value. Use a static variable instead. In fact, remember that changing _SS and/or _SP will make a function "forget" ALL its local variables' values until the old values of _SS and _SP are restored. Perhaps a better way to do my second example would be to have a function which has no other purpose than to swap the stacks, call other functions, then swap the stacks back. The calling routine would then decide whether to call the other functions directly, or to make a call through the swapping function. (The decision being made by determining how much stack space is left in the current segment.) This way you wouldn't have to worry about losing the values of various local variables over the course of a stack swap. Also, for the same reason, don't even THINK of trying this technique in a memory model with near pointers. You won't be able to refer to local variables of previously-called functions by address if you do, since they may be in a different segment... Bad Things would happen. >steve.resnick@f105.n143.z1.FIDONET.ORG - or - apple!camphq!105!steve.resnick >Flames, grammar errors, spelling errrors >/dev/nul >The Asylum OS/2 BBS - (408)263-8017 IFNA 1:143/105.0 I hope this clarifies things a little. Thanks for the input. Derek Riippa Foster