Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!seismo!rochester!rutgers!lll-lcc!pyramid!decwrl!spar!hunt From: hunt@spar.SPAR.SLB.COM (Neil Hunt) Newsgroups: comp.lang.c Subject: Re: Accessing argc & argv from a function Message-ID: <229@spar.SPAR.SLB.COM> Date: Tue, 4-Aug-87 20:24:51 EDT Article-I.D.: spar.229 Posted: Tue Aug 4 20:24:51 1987 Date-Received: Fri, 7-Aug-87 04:18:52 EDT References: <420@sugar.UUCP> <39@flmis06.ATT.COM> <382@root44.co.uk> <5773@ut-ngp.UUCP> <289@wrs.UUCP> Reply-To: hunt@spar.UUCP (Neil Hunt) Organization: Schlumberger Palo Alto Research - CASLAB Lines: 115 In article <289@wrs.UUCP> dg@wrs.UUCP (David Goodenough) writes: >In article <5773@ut-ngp.UUCP> ayac071@ngp.UUCP (Bill Douglass) writes: >>In article <382@root44.co.uk> njh@root44.UUCP (Nigel Horne) writes: >>>In article <39@flmis06.ATT.COM> mikel@flmis06.ATT.COM (Mikel Manitius) writes: >>>> >>>>However I am still looking for a way to get at "argc" and "argv" from >>>>a function when I don't have access to "main". getenv() and putenv() >>>>gets it from somewhere... > >Technically getenv reference environ - a global variable which is a char ** >type of thing. However it just so happens that environ is also the third >argument to main(), *At the time main is called*. Remember that C is call by value... > which brings me to the following little program. >I wrote this over lunch the other day, and believe it or not it works. >I'm not suggesting that you all go and replace /bin/echo with this [among >other things I haven't implemented the -n switch :-) ], but it demonstrates >that what was requested is possible - if a little messy, and about as safe >as nitroglycerine. > There is just one flaw in this code, and that is that you are relying on environ == *after* main and various other functions have run. If it is not, then you when you find the correct stack frame for main, the test will fail, and you will continue to look for earlier and earlier stack frames, until a segmentation violation occurs. This assumption is violated under the following situations: 1 main changes envp. 2 main passes envp to another function as the third arg. 3 someone uses getenv or setenv to manipulate the environment which results in copying of the environment list as refered to by environ, without changing envp. The code I posted a couple of days ago, while not as nicely written using a struct frame to clean up the messiness, is slightly more reliable, as instead of checking to see if environ is the same as the third arg to main to determine whether it has found the main stack frame, it checks the return address against the address of main and the address of the following function, to see if a frame was called from main, and if so, goes one frame further. Of course, you do have to know what the name of the function following main is; this can be obtained using nm with options to print the symbol table in numerical order, if the source code is not available. Try this modification (which I haven't tested): >main() /* no args!! */ > { > int i; /* just used for address checking when we > * get to the bottom */ > getit(&i, 5); /* go do the work */ > } > >getit(ip, n) /* this recursively calls itself to put > * some fake crud on the stack */ >int *ip; > { > int ac; > char **av; > int i; > > if (n) > getit(ip, n - 1); /* not far enough down */ > else > { > findargs(&ac, &av, ip); /* at the bottom - get argc & argv */ > for (i = 1; i < ac; i++) > printf("%s%c", av[i], (i == ac - 1) ? '\n' : ' '); > /* and print args - just like echo!! */ > } > } > >struct frame /* stack frame structure for a 68K */ > { > struct frame *_dynamic; /* dynamic link to previous frame */ > char *_return; /* return address: I didn't know what type to > * make this, so I made it a char * */ > int _argc; /* argc when we get there */ > char **_argv; /* argv when we get there */ > char **_envp; /* envp when we get there */ > } *work; > >findargs(acp, avp, ip) /* this does the work - ip is not needed, > * it's just printed for verification */ >int *acp, *ip; >char ***avp; > { > int i; /* only one local variable, used to get a > * reference to the current stack frame */ > > work = (struct frame *) (&i + 1); > /* ugh! - point work at the current frame */ > while(! (work->_return >= (char *)main && /* check for return to main */ work->_return < (char *)getit)) work = work->_dynamic; /* advance one frame up the stack */ work = work->_dynamic; /* advance one final frame up the stack */ > * environment which we hope is main!! */ > *acp = work->_argc; /* get argc */ > *avp = work->_argv; /* and argv */ > > printf("%x %x\n", ip, work); > /* just to compare pointers - these two should > * be sizeof int apart */ > } Neil/.