main 함수의 argv를 다른 함수에서 참조 하는 방법

alwaysN00b의 이미지

안녕하세요.

검색해도 잘 나오질 않는군요.

main(int argc, char *argv[])

라고 했을때

main 함수내 다른 함수에서 argv에 접근을 할려면 어떻게 해야하나요?
(다른 함수에 argv의 포인터를 넘겨주지 않구요)

어셈블러로 보면 알수 있을까 생각은 하는데 제가 어셈을 몰라 이렇게 질문 올림니다.
....
글 써놓고 보니 이해하시기 힘들것 같아..


main(int argc, char *argv[]){
   ....
   ....
   other_fun();
   ...
   ...
}

void other_fun(){
    char *abc[];
    //어떠한 작업으로 포인터를 알아낸다.
    printf("%s \n",abc[0]);
}

other_fun 에서 어떤 일을 해주면 main이 받은 argv 포인터를 알수 있을까요?

litdream의 이미지

우선 arg[] 만 알아선 안될것 같다는것부터 짚어야겠습니다.
int argc 가 없으면 boundary check 을 할수가 없죠?

삽질의 대마왕...

dangsan49의 이미지

설마 ...

char **g_argv;

main (int argc, char *argv[]) {
g_argv = argv;
...............
other_fun();
................
}

VENI, VIDI, VICI - Caesar, Gaius Julius -

pynoos의 이미지

답을 이미 찾으셨는지 모르겠지만...

http://bbs.kldp.org/viewtopic.php?p=103439#103439

위 글을 참고하시고 아래 코드를 이용하시면 될 것입니다.
Linux에서 테스트 하였습니다.

#include <stdio.h>

int main();

void stack_dump()
{
        void * first_variable;
        unsigned long * frame_ptr;
        char * argv_0 = 0;
        int stackcount = 0;

        frame_ptr = (unsigned long *) (&first_variable);
        frame_ptr++;

        /* *(frame_ptr + 0) : caller's frame pointer
         * *(frame_ptr + 1) : return address
         * *(frame_ptr + 2) : first argument
         * *(frame_ptr + 3) : second argument
         * *(frame_ptr + 4) : third argument
         * ...
         */
        for( stackcount = 0; ; stackcount++ )
        {
                unsigned long return_addr;
                return_addr = (unsigned long)*(frame_ptr+1);
                printf("%d: %p %p %p\n", stackcount, frame_ptr, *(frame_ptr+1), main);
                if( return_addr >= (unsigned long) & main &&
                    return_addr <= (unsigned long) & main + 100 )
                {
                        argv_0 = (char *)(*(frame_ptr+3));
                        break;
                }
                frame_ptr = (unsigned long *)(*frame_ptr);
        }
        if( argv_0 )
        {
                printf("DEEP_IN_FUNC: %s\n", argv_0 );
        }
        else
        {
                printf("OOPS..\n");
        }
}

void func3()
{
        stack_dump();
}

void func2()
{
        func3();
}

void func1()
{
        func2();
}

int main(int argc, char * argv[] )
{
        printf("MAIN: %s\n", argv[0] );
        func1();
        return 0;
}

참고로 argv_0 으로 한 것은 argv[1] 등을 구하려면, argv가 어떤 식으로 넘어가는지에 대한 이해가 있어야합니다.

argument는 줄줄이 이어서
"./a.out\0first argument\0second argument\0\0"

이런 문자열을 만들어 넘어갑니다. 따라서 두번째 인자argv[1] 을 구하려면 argv_0을 계속 찾아 가면서 \0을 만나도 계속 지나가면 argv[1] 값이 나옵니다. 그리고 맨 끝은 \0\0로 끝나지요... 고생하세요...

아, frame pointer에 대한 이해는 이렇습니다.
gcc가 -fno-omit-frame-pointer를 주지 않는한 다음과 같이 동작합니다.

1. 함수를 호출하기전에 스택에 가장 뒤의 인자부터 차례대로 쌓는다.
(쌓는다는 것은 stack pointer가 값이 줄어 들면서 큰 값에서 작은값이 된다는 말입니다.)
2. 돌아올 주소를 넣고 함수로 점프한다.
3. 함수에 들어오면 바로 이전 프레임 포인터를 저장한다.
4. 프레임 포인터를 현재의 스택포인터로 설정한다.

입니다.

프레임이란 함수가 사용하는 스택 구간을 말합니다.

3번직후 스택포인터는 이전 프레임 포인터를 저장한 번지를 가리키므로
위 함수중 frame_ptr = (unsigned long *)(*frame_ptr); 이 코드는 프레임포인터를 순회하여 주욱 올라가는 코드가 됩니다.

이 프레임 포인터는 사용될 때 -X 해서 사용하면 함수내의 자동변수를, +X 해서 사용하면 인자로 넘어온 값을 참조할 때 사용됩니다. 이 부분은 디스어셈블 코드등을 분석해보세요.

이렇게 해서 main 함수가 100바이트 정도의 함수라고 생각된다면 돌아갈 번지가 main으로부터 100바이트 이내에 있다고 생각하면 main함수를 호출할 때 들어 있는 스택을 알 수 있으므로... argv 를 알아 낼 수가 있습니다.

pynoos의 이미지

그런데 이거 아주 위험한 함수입니다. 사용상 책임을 저에게 묻지 마셔요.... :(

몇가지 가정이 계속 유효해야만 하거든요...

alwaysN00b의 이미지

pynoos 님!

정말 감사합니다. 시원한 답변이 되었습니다.

* *(frame_ptr + 2) : first argument 

main 함수가 쓰는 stackframe 인가 보군요.

그렇게 알고 만지작 거려봐야겠습니다.

argument는 줄줄이 이어서 
"./a.out\0first argument\0second argument\0\0" 

제가 알고 있어서 다행이네요.. 휴.. :D

언제나 시작

pynoos의 이미지

alwaysN00b wrote:

* *(frame_ptr + 2) : first argument 

main 함수가 쓰는 stackframe 인가 보군요.

그렇게 알고 만지작 거려봐야겠습니다.

아닌데요... 일반적으로 frame pointer를 안다면 저렇게 접근한다는 것이지요.
frame pointer를 4 byte씩 움직이게 되므로 실제는 + 8을하여 접근하는 것입니다.

alwaysN00b의 이미지

pynoos wrote:
alwaysN00b wrote:

* *(frame_ptr + 2) : first argument 

main 함수가 쓰는 stackframe 인가 보군요.

그렇게 알고 만지작 거려봐야겠습니다.

아닌데요... 일반적으로 frame pointer를 안다면 저렇게 접근한다는 것이지요.
frame pointer를 4 byte씩 움직이게 되므로 실제는 + 8을하여 접근하는 것입니다.

:oops: 답글중 stack_dump 함수를 보다 기뻐서 그만 바보같은 글을 써버렸네요.

좀더 공부해야 될것 같습니다. :)

언제나 시작

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.