Why should I know this?

Runtime에 C/C++ 함수 크기 구하기 본문

Technic

Runtime에 C/C++ 함수 크기 구하기

die4taoam 2021. 6. 2. 00:40

C/C++ 에서 특수한 목적으로 함수의 크기를 구하려고 한다면 셋 중 하나의 결과가 나온다.

1. 컴파일 된 binary를 nm 등을 사용해 symbol 주소와 크기를 구한다.

이런 방식으로 함수의 크기를 사용하려면 컴파일 한 후 binary에 writing해주는 과정이 필요하다.

 

2. 선언된 함수 뒤에 크기 계산용 더미 함수를 추가하여 주소를 계산한다.

아래와 같은 방식이다.

static void fn_need_to_know_size()
{
    return 0;
}

static void fn_to_mark_end()
{
    return 0;
}

unsigned long size = (unsigned long)&fn_need_to_know_size - (unsigned long)&fn_to_mark_end;

하지만 이와 같은 방식은 컴파일 시에 다수 object들이 뒤섞이면 함수 순서를 보장해주지 않기 때문에 적용할 수 없는 방식이다.

 

3. 마지막으로 함수 안에 특정 키워드를 넣어 이를 찾는 방식.

이런 방식이다.

#include <stdio.h>
#include <assert.h>

#if defined(__aarch64__) || defined(__arm__)
#define MARK()  {\
    asm volatile("b 1f; .int 0xdeadbeaf;1:");\
}
#elif defined(__i386__) || defined(__amd64__)
#define MARK()  {\
    asm volatile("jmp 1f; .int 0xdeadbeaf;1:");\
}
#else
#error "not expected architecture"
#endif

void test_mark()
{
    MARK();
}

static unsigned long get_func_size(unsigned long faddr)
{
    unsigned long res = 0;
    unsigned char *fptr = (unsigned char *)faddr;
    for(int MAX_TRY = 100; MAX_TRY > 0; fptr++, MAX_TRY--) {
        if (*(unsigned int *)fptr == 0xdeadbeaf) {
            res = ((unsigned long)fptr) - faddr;
            break;
        }
    }

    return res;
}

int main() {
    unsigned long size = get_func_size((unsigned long)&test_mark);
	assert(size > 0);
    printf("%lx\n", size);
    return 0;
}

위의 코드는 사이즈를 구하고자 하는 함수의 최하단에 MARK() 를 추가해야 하는 번거로움이 있긴 하다. +@로 컴파일 할 때 유실될 수 있는 가능성도 없지 않나??? 는 생각이 들었는데, volatile 로 선언되었으므로 그런 일은 없을것이다.

 

정 걱정된다면 활용할 때는 예제처럼 assert로 확인하고,

빌드 후에 디스어셈블해서 정상적으로 컴파일 되었는지 확인해보면 되겟다!

 

Comments