당신은에 당신이 할 수 있어야 dlopen(3)
및 dlsym(3)
(리눅스 등)가있는 시스템에서 실행하는 경우 :
char thing_string[] = "thing_you_want_to_look_up";
void * handle = dlopen(NULL, RTLD_LAZY | RTLD_NOLOAD);
// you could do RTLD_NOW as well. shouldn't matter
if (!handle) {
fprintf(stderr, "Dynamic linking on main module : %s\n", dlerror());
exit(1);
}
void * addr = dlsym(handle, thing_string);
fprintf(stderr, "%s is at %p\n", thing_string, addr);
내가 다른 시스템이 작업을 수행하는 가장 좋은 방법을 모르는,이 아마 정적 변수 및 함수에는 작동하지 않습니다. C++ 심볼 이름은 그들과 함께 작업하는 데 관심이 있다면 엉망이됩니다.
공유 라이브러리에서이 기능을 확장하려면 /proc/self/maps
에서 현재로드 된 라이브러리의 이름을 가져온 다음 라이브러리 파일 이름을 dlopen
으로 전달하십시오. 그러나 라이브러리 이름이 변경되거나 삭제 된 경우 실패 할 수 있습니다.
다른 여러 가지 방법이 있습니다.
편집 이
/* name_addr.h */
struct name_addr {
const char * sym_name;
const void * sym_addr;
};
typedef struct name_addr name_addr_t;
void * sym_lookup(cost char * name);
extern const name_addr_t name_addr_table;
extern const unsigned name_addr_table_size;
/* name_addr_table.c */
#include "name_addr.h"
#define PREMEMBER(X) extern const void * X
#define REMEMBER(X) { .sym_name = #X , .sym_addr = (void *) X }
PREMEMBER(strcmp);
PREMEMBER(printf);
PREMEMBER(main);
PREMEMBER(memcmp);
PREMEMBER(bsearch);
PREMEMBER(sym_lookup);
/* ... */
const name_addr_t name_addr_table[] =
{
/* You could do a #include here that included the list, which would allow you
* to have an empty list by default without regenerating the entire file, as
* long as your compiler only warns about missing include targets.
*/
REMEMBER(strcmp),
REMEMBER(printf),
REMEMBER(main),
REMEMBER(memcmp),
REMEMBER(bsearch),
REMEMBER(sym_lookup);
/* ... */
};
const unsigned name_addr_table_size = sizeof(name_addr_table)/sizeof(name_addr_t);
/* name_addr_code.c */
#include "name_addr.h"
#include <string.h>
void * sym_lookup(cost char * name) {
unsigned to_go = name_addr_table_size;
const name_addr_t *na = name_addr_table;
while(to_to) {
if (!strcmp(name, na->sym_name)) {
return na->sym_addr;
}
na++;
to_do--;
}
/* set errno here if you are using errno */
return NULL; /* Or some other illegal value */
}
dlopen을를 사용하지 않고 당신은 링커가 주소에서 작성 처리됩니다 이런 식으로 할 경우 너 모든 후. ng가 배치되었습니다. 테이블에 나열한 모든 심볼에 헤더 파일을 포함 시키면 테이블 파일을 컴파일 할 때 경고 메시지가 나타나지 않지만 모든 파일을 extern void *
으로 설정하고 컴파일러에서 경고하도록하면 훨씬 쉽습니다. 그것들 모두 (이것은 가능할지라도 반드시 그런 것은 아니다).
기호를 반복해서 반복하지 않고 이진 검색을 사용할 수 있도록 기호를 정렬 할 수도 있습니다.
테이블에 sqrt
에 대한 항목이 있지만 전화를 걸지 않은 것처럼 프로그램에서 다른 방법으로 참조되지 않는 멤버가있는 경우 링커에서 다음을 원한다는 점에 유의해야합니다.)를 사용하여 해당 기능을 이미지에 연결하십시오. 이것은 그것을 폭파시킬 수 있습니다.
또한 전역 최적화 기능을 사용하는 경우이 테이블을 사용하면 컴파일러에서 나열된 모든 함수가이 목록의 포인터를 통해 액세스 될 수 있으며 모든 콜 포인트.
정적 함수를이 목록에 넣는 것은 쉽지 않습니다. 테이블을 동적으로 변경하고 각 모듈의 함수에서 런타임에 수행하거나 테이블이있는 객체 파일에 새 섹션을 생성하여이 작업을 수행 할 수 있습니다. gcc :
#define SECTION_REMEMBER(X) \
static const name_addr_t _name_addr##X = \
{.sym_name= #X , .sym_addr = (void *) X } \
__attribute__(section("sym_lookup_table"))
그리고 각 파일 끝에 기억하고 싶은 모든 기호가있는 .c 파일의 끝에이 목록을 추가하십시오. 이것은 링커가 링커가이 멤버들로 무엇을해야 하는지를 알 수 있도록하지만, 그 멤버가 상주하는 섹션의 시작과 끝을 보면서리스트를 반복 할 수있다. (정확히 어떻게 해야할지 모르겠다. 이 일은 끝날 수 있지만 너무 어렵지는 않습니다.) 하지만 이렇게하면 정렬 된 목록이 더 어려워집니다. 또한, 문자열 리터럴의 주소로 .sym_name
을 초기화하는 것이이 섹션에 문자열을 주입하는 결과를 가져 오지는 않을 것이라고 완전히 확신하지는 않지만, 그렇게 생각하지는 않습니다. 만약 그렇다면 이것은 일을 망칠 것입니다.
여전히 objdump를 사용하여 개체 파일 (아마도 elf)에 포함 된 기호 목록을 가져온 다음 관심있는 기호에 대해 필터링 한 다음 테이블 구성원이 나열한 테이블 파일을 다시 생성 할 수 있습니다.
당신이 말하는 플랫폼을 지정해야합니다. – nategoose