Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!seismo!rutgers!labrea!decwrl!spar!hunt From: hunt@spar.SPAR.SLB.COM (Neil Hunt) Newsgroups: comp.lang.c Subject: Re: Accessing argc & argv from a functi Message-ID: <154@spar.SPAR.SLB.COM> Date: Thu, 30-Jul-87 18:57:26 EDT Article-I.D.: spar.154 Posted: Thu Jul 30 18:57:26 1987 Date-Received: Sat, 1-Aug-87 11:28:04 EDT References: <420@sugar.UUCP> <39@flmis06.ATT.COM> <1130@nu3b2.UUCP> Organization: Schlumberger Palo Alto Research - CASLAB Lines: 235 Summary: Accessing stack allows other function parameters to be obtained. Reply_To: hunt@spar.UUCP (Neil Hunt) In article <1130@nu3b2.UUCP> rwhite@nu3b2.UUCP (Robert C. White Jr.) 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... > >If you have access to the runtime stuff, you can kludge the runtime to put >the argv and argc in some global variable you can find. > >nomatter how you slice it the pointer to argv will HAVE to be passed >somewhare. > Depends how portable you have to be ! ************************************************************ ********************** WARNING ************************* ************************************************************ * * * The following comments and program examples could be * * hazardous to your health and sanity. * * * * Please fasten your seatbelts and disable lint. * * * ************************************************************ If you know something about the compiler and machine, you can access the run time stack and access arguments of previous functions as you will ! For example, I am using a SUN, with the SUN C compiler. I know that the stack is organised as follows: ----------------------- Stack frame for func1 paramN-1 .. param1 param0 return_address frame_pointer <-+ local_var0 | local_var1 | ... | local_varN-1 | -----------------+----- Stack frame for func2 called from func1 paramN-1 | .. | param1 | param0 | return_address | frame_pointer *--+ /* points to previous frame pointer. */ local_var_0 local_var_1 ... local_var_N-1 ----------------------- etc. Now from a function called from main, take the address of the first parameter (param0 in func2), subtract 2 * sizeof(pointer) = 8 bytes from this address, and you have a current frame pointer. Indirect the frame pointer, and you have the frame pointer of the function which called you, in this case, main. Knowing that the parameters are passed at addresses 2,3,.. above the frame pointer, you can now obtain the parameters to the previous function. The following program demonstrates: ------------------------------------------------------------------------- main(argc, argv, envp) int argc; char **argv; char **envp; { /* * Print the args values for reference. */ printf("%x %x %x\n", argc, argv, envp); /* * Call a function. */ test(0); } test(arg) int arg; { char *frame_pointer; char *prev_frame_pointer; int argc; char **argv; char **envp; /* * Obtain a frame pointer, * indirect to previous frame (called from main) * Obtain main's parameters from mains frame pointer. */ frame_pointer = ((char *)&arg) - 8; prev_frame_pointer = *((char **)frame_pointer); argc = (*(int *)(prev_frame_pointer+8)); argv = (*(char ***)(prev_frame_pointer+12)); envp = (*(char ***)(prev_frame_pointer+16)); /* * Print main's args for reference. */ printf("%x %x %x\n", argc, argv, envp); } ------------------------------------------------------------------------- % test 1 efffba0 efffba8 1 efffba0 efffba8 % test this is a test with real args 8 efffb64 efffb88 8 efffb64 efffb88 How about that !! If your function which needs to access the args to main is buried deeper than one call, you will have to indirect frame_pointer more times. If you do not know how many times, you can find out by looking at the return addresses to see which frame belongs to a function which will return to an address within the range of _main and the next function. The example below demonstrates: ------------------------------------------------------------------------- main(argc, argv, envp) int argc; char **argv; char **envp; { /* * Print args for reference. */ printf("%x %x %x\n", argc, argv, envp); test(); } test() { /* * Print range of return addresses to main. */ printf(" Address %x <= main < %x\n", main, test); /* * Call deeper on the stack. * Can place arbitrary recursion here ! */ test_deeper(0); } test_deeper(arg) int arg; { char *frame_pointer; char *prev_frame_pointer; char *return_address; int argc; char **argv; char **envp; /* * Get the current frame pointer. */ frame_pointer = ((char *)&arg) - 8; for( ; ; ) { /* * Check return address of this frame, * see if it is within range of main, */ return_address = *((char **)(frame_pointer + 4)); printf(" Return address = %x\n", return_address); if(return_address < (char *)main) exit(-1); if(return_address < (char *)test) break; /* * Go up another frame in the call stack. */ frame_pointer = *((char **)frame_pointer); printf(" Going back up one more level at %x\n", frame_pointer); } /* * Obtain main's frame pointer and args. */ prev_frame_pointer = *((char **)frame_pointer); argc = (*(int *)(prev_frame_pointer+8)); argv = (*(char ***)(prev_frame_pointer+12)); envp = (*(char ***)(prev_frame_pointer+16)); printf("%x %x %x\n", argc, argv, envp); } ------------------------------------------------------------------------- % test 1 efffba0 efffba8 Address 20a0 <= main < 20d4 Return address = 2104 Going back up one more level at efffb80 Return address = 20d0 1 efffba0 efffba8 % test this is another test 5 efffb7c efffb94 Address 20a0 <= main < 20d4 Return address = 2104 Going back up one more level at efffb5c Return address = 20d0 5 efffb7c efffb94 One final thing to note: if the original main function changes the values of argc, argv or envp (as in argv++ for example) then you will get the changed value of those variables, just as if you were still in the main program. Don't you love what you can do in C ? Neil/. PS: % lint test.c test.c(51): warning: questionable conversion of function pointer test.c(53): warning: questionable conversion of function pointer printf returns value which is always ignored Wow ! I expected at least a core dump from lint.