2011-09-10 3 views
15

실행 파일의 텍스트 섹션의 시작과 끝 주소를 얻어야합니다. 그것을 어떻게 얻을 수 있습니까?실행 파일에서 텍스트 섹션의 시작과 끝 주소 얻기

_init 기호 또는 _start 기호에서 시작 주소를 얻을 수 있지만 종료 주소는 어떻게됩니까? .rodata 섹션을 시작하기 전에 text 섹션의 종료 주소가 마지막 주소로 간주됩니까?

또는 기본 ld 스크립트를 편집하고 텍스트 섹션의 시작과 끝을 나타내는 기호를 추가하고 컴파일 할 때 GCC로 전달해야합니까? 이 경우, 새 심볼을 어디에 넣어야합니까? init 및 fini 섹션을 고려해야합니까?

텍스트 섹션의 시작과 끝 주소를 얻는 좋은 방법은 무엇입니까?

+0

'readelf -h'를 사용하면 프로그램 헤더 파일의 오프셋이 제공되는 elf 헤더 정보를 볼 수 있습니다. –

+0

데이터 섹션과 동일 : http://stackoverflow.com/questions/1765969/unable-to-locate-definition-of-etext-edata-end –

답변

19

ELF 기반 플랫폼 용 GNU binutils 기본 링커 스크립트는 일반적으로 다양한 섹션의 시작과 끝을 찾는 데 사용할 수있는 상당히 다른 기호를 정의합니다.

텍스트 섹션의 끝은 보통 etext, _etext 또는 __etext의 세 가지 기호로 선택됩니다. 시작은 __executable_start입니다. 실행 파일 에 뭔가가 단순히 그들을를 참조하는 것이 아니라을 정의하는 경우 (즉, _etext 또는 __etext가 될 가능성이 있음을 의미합니다 특히. 이러한 기호는 보통이 무시됩니다 것을 의미 PROVIDE() 메커니즘을 사용하여 수출하고 있습니다 etext보다 안전 선택)

예 :.

$ cat etext.c 
#include <stdio.h> 

extern char __executable_start; 
extern char __etext; 

int main(void) 
{ 
    printf("0x%lx\n", (unsigned long)&__executable_start); 
    printf("0x%lx\n", (unsigned long)&__etext); 
    return 0; 
} 
$ gcc -Wall -o etext etext.c 
$ ./etext 
0x8048000 
0x80484a0 
$ 

나는 이러한 기호 중 하나가 표준으로 지정되어 있다고 생각하지 않기 때문에이 휴대용으로 간주되어서는 안된다 (아무 생각이 GNU 빈 여부 utils가 모두 ELF 기반 플랫폼을 제공하는지 또는 제공되는 심볼 세트가 다른 binutils 버전에서 변경되었는지 여부),이 정보가 필요한 작업을하고 있는지, b) 해킹을 고려하고 있는지, 링커 스크립트를 옵션으로 사용하면 이식성이 그리 중요하지 않습니다!

특정 플랫폼에서 특정 일을 만들 때 당신이 얻을 귀하의 정확한 설정을 확인하려면, 그것을 사용하도록 선택 링커 스크립트를 인쇄 할 수 ld (또는 gcc- -Wl,--verbose)에 --verbose 플래그를 제공 (다른 정말 여러 가지가 있습니다 기본 링커 스크립트는 링커 옵션과 작성중인 객체의 유형에 따라 다릅니다.

+0

그러면 더 나은 옵션이 될 것입니까? 링커 스크립트를 해킹하고 내 자신의 기호를 삽입 하시겠습니까? – phoxis

+1

아니요,이 기호가 플랫폼에서 작동하는 경우 해당 기호를 사용할 수도 있습니다. 위의 예제 코드는 적어도 Linux x86, Linux ppc 및 NetBSD x86에서 작동합니다. 작동하지 않는 다른 플랫폼이 있는지 여부는 알 수 없습니다. (해킹 된 링커 스크립트는 이식성이 떨어집니다. 해킹 된 Linux x86 링커 스크립트는 Linux ppc에서 거의 작동하지 않습니다.) –

2

.rodata은 항상 .text 다음에 오는 것이 보장되지 않습니다. 더 많은 정보를 얻으려면 objdump -h filereadelf --sections file을 사용할 수 있습니다. objdump를 사용하면 크기와 오프셋을 파일로 가져올 수 있습니다.

2

Linux의 경우 nm(1) 도구를 사용하여 오브젝트 파일이 제공하는 기호를 검사하십시오. 매튜 슬러티가 제시 한 두 가지 상징을 모두 배울 수있는이 상징 세트를 골라 낼 수 있습니다.

7

두 개 이상있을 수 있으므로 "the"텍스트 세그먼트에 대해 이야기하는 것은 잘못되었습니다 (라이브러리를 공유 할 때 일반적으로 보장되지만 단일 ELF 바이너리가 여러 개의 PT_LOAD 섹션을 가질 수도 있음). 어쨌든 같은 깃발).

다음 샘플 프로그램은 dl_iterate_phr에 의해 반환 된 모든 정보를 덤프합니다. PF_X 플래그와 함께 PT_LOAD 유형의 세그먼트에 관심이 있습니다 (-z execstack이 실제로 링커에 전달되면 PT_GNU_STACK에 플래그가 포함되므로 두 가지를 모두 확인해야 함).

#define _GNU_SOURCE 
#include <link.h> 
#include <stddef.h> 
#include <stdio.h> 
#include <stdlib.h> 

const char *type_str(ElfW(Word) type) 
{ 
    switch (type) 
    { 
    case PT_NULL: 
     return "PT_NULL"; // should not be seen at runtime, only in the file! 
    case PT_LOAD: 
     return "PT_LOAD"; 
    case PT_DYNAMIC: 
     return "PT_DYNAMIC"; 
    case PT_INTERP: 
     return "PT_INTERP"; 
    case PT_NOTE: 
     return "PT_NOTE"; 
    case PT_SHLIB: 
     return "PT_SHLIB"; 
    case PT_PHDR: 
     return "PT_PHDR"; 
    case PT_TLS: 
     return "PT_TLS"; 
    case PT_GNU_EH_FRAME: 
     return "PT_GNU_EH_FRAME"; 
    case PT_GNU_STACK: 
     return "PT_GNU_STACK"; 
    case PT_GNU_RELRO: 
     return "PT_GNU_RELRO"; 
    case PT_SUNWBSS: 
     return "PT_SUNWBSS"; 
    case PT_SUNWSTACK: 
     return "PT_SUNWSTACK"; 
    default: 
     if (PT_LOOS <= type && type <= PT_HIOS) 
     { 
      return "Unknown OS-specific"; 
     } 
     if (PT_LOPROC <= type && type <= PT_HIPROC) 
     { 
      return "Unknown processor-specific"; 
     } 
     return "Unknown"; 
    } 
} 

const char *flags_str(ElfW(Word) flags) 
{ 
    switch (flags & (PF_R | PF_W | PF_X)) 
    { 
    case 0 | 0 | 0: 
     return "none"; 
    case 0 | 0 | PF_X: 
     return "x"; 
    case 0 | PF_W | 0: 
     return "w"; 
    case 0 | PF_W | PF_X: 
     return "wx"; 
    case PF_R | 0 | 0: 
     return "r"; 
    case PF_R | 0 | PF_X: 
     return "rx"; 
    case PF_R | PF_W | 0: 
     return "rw"; 
    case PF_R | PF_W | PF_X: 
     return "rwx"; 
    } 
    __builtin_unreachable(); 
} 

static int callback(struct dl_phdr_info *info, size_t size, void *data) 
{ 
    int j; 
    (void)data; 

    printf("object \"%s\"\n", info->dlpi_name); 
    printf(" base address: %p\n", (void *)info->dlpi_addr); 
    if (size > offsetof(struct dl_phdr_info, dlpi_adds)) 
    { 
     printf(" adds: %lld\n", info->dlpi_adds); 
    } 
    if (size > offsetof(struct dl_phdr_info, dlpi_subs)) 
    { 
     printf(" subs: %lld\n", info->dlpi_subs); 
    } 
    if (size > offsetof(struct dl_phdr_info, dlpi_tls_modid)) 
    { 
     printf(" tls modid: %zu\n", info->dlpi_tls_modid); 
    } 
    if (size > offsetof(struct dl_phdr_info, dlpi_tls_data)) 
    { 
     printf(" tls data: %p\n", info->dlpi_tls_data); 
    } 
    printf(" segments: %d\n", info->dlpi_phnum); 

    for (j = 0; j < info->dlpi_phnum; j++) 
    { 
     const ElfW(Phdr) *hdr = &info->dlpi_phdr[j]; 
     printf(" segment %2d\n", j); 
     printf("  type: 0x%08X (%s)\n", hdr->p_type, type_str(hdr->p_type)); 
     printf("  file offset: 0x%08zX\n", hdr->p_offset); 
     printf("  virtual addr: %p\n", (void *)hdr->p_vaddr); 
     printf("  physical addr: %p\n", (void *)hdr->p_paddr); 
     printf("  file size: 0x%08zX\n", hdr->p_filesz); 
     printf("  memory size: 0x%08zX\n", hdr->p_memsz); 
     printf("  flags: 0x%08X (%s)\n", hdr->p_flags, flags_str(hdr->p_flags)); 
     printf("  align: %zd\n", hdr->p_align); 
     if (hdr->p_memsz) 
     { 
      printf("  derived address range: %p to %p\n", 
       (void *) (info->dlpi_addr + hdr->p_vaddr), 
       (void *) (info->dlpi_addr + hdr->p_vaddr + hdr->p_memsz)); 
     } 
    } 
    return 0; 
} 

int main(void) 
{ 
    dl_iterate_phdr(callback, NULL); 

    exit(EXIT_SUCCESS); 
} 
관련 문제