Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 获取可执行文件中文本部分的开始和结束地址_C_Gcc_Ld - Fatal编程技术网

C 获取可执行文件中文本部分的开始和结束地址

C 获取可执行文件中文本部分的开始和结束地址,c,gcc,ld,C,Gcc,Ld,我需要获取可执行文件文本部分的开始和结束地址。我怎样才能得到它 我可以从\u init符号或\u start符号中获取起始地址,但是结束地址呢?我认为“文本>代码>节的结尾地址是在开始代码之前的最后一个地址吗? 或者我应该编辑默认的ld脚本并添加自己的符号来指示文本部分的开始和结束,并在编译时将其传递给GCC吗?在这种情况下,我应该把新的符号放在哪里,我应该考虑init和Fini部分吗?< /P> 获取文本部分的起始地址和结束地址的好方法是什么?.rodata不保证总是直接位于.text之后。您

我需要获取可执行文件文本部分的开始和结束地址。我怎样才能得到它

我可以从
\u init
符号或
\u start
符号中获取起始地址,但是结束地址呢?我认为“<代码>文本>代码>节的结尾地址是在开始代码之前的最后一个地址吗? 或者我应该编辑默认的ld脚本并添加自己的符号来指示文本部分的开始和结束,并在编译时将其传递给GCC吗?在这种情况下,我应该把新的符号放在哪里,我应该考虑init和Fini部分吗?< /P>
获取文本部分的起始地址和结束地址的好方法是什么?

.rodata
不保证总是直接位于
.text
之后。您可以使用
objdump-h文件
readelf--sections文件
获取更多信息。使用objdump,可以将大小和偏移量都输入到文件中。

基于ELF的平台的GNU binutils默认链接器脚本通常定义大量不同的符号,这些符号可用于查找各个部分的开始和结束

文本部分的结尾通常由三种不同符号的选择来引用:
etext
\u etext
\u etext
;该启动可作为
\u可执行文件\u启动
找到。(请注意,这些符号通常使用该机制导出,这意味着如果可执行文件中的其他内容定义了它们,而不仅仅是引用它们,它们将被覆盖。特别是,这意味着
\u etext
\u etext
可能比
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
$
$cat etext.c
#包括
外部字符可执行文件启动;
外部字符;
内部主(空)
{
printf(“0x%lx\n”,(无符号长)和\u可执行\u开始);
printf(“0x%lx\n”,(无符号长)和\uuuuetext);
返回0;
}
$gcc-Wall-o etext-etext.c
美元/文本
0x8048000
0x80484a0
$
我不相信这些符号中有任何一个是由任何标准指定的,因此这不应该被认为是可移植的(我不知道GNU binutils是否为所有基于ELF的平台提供了它们,或者提供的符号集是否在不同的binutils版本中发生了变化),虽然我猜如果a)你正在做一些需要这些信息的事情,b)你正在考虑黑客链接器脚本作为一个选项,那么可移植性就不太重要了


要查看在特定平台上构建特定内容时得到的确切符号集,请将
--verbose
标记指定给
ld
(或
-Wl,--verbose
指定给
gcc
)以打印它选择使用的链接器脚本(确实有几种不同的默认链接器脚本,它们根据链接器选项和正在构建的对象的类型而不同)。

Linux,考虑使用<代码> NM(1)。工具,用于检查对象文件提供的符号。您可以从这组符号中选择,从中可以了解Matthew Slattery在其答案中提供的两个符号。

提到“文本”段是不正确的,因为可能有多个(对于共享库的常见情况,这是可以保证的,但是一个ELF二进制文件仍然可以有多个具有相同标志的
PT_LOAD
部分)

下面的示例程序转储由
dl_iterate_phr
返回的所有信息。您对带有
PF_X
标志的
PT_LOAD
类型的任何段都感兴趣(请注意,
PT_GNU__STACK
如果将
-z execstack
传递给链接器,则
PT_GNU____堆栈
将包含该标志,因此您确实需要检查这两个标记)

定义GNU源
#包括
#包括
#包括
#包括
常量字符*类型(ElfW(Word)类型)
{
开关(类型)
{
案例PT_NULL:
return“PT_NULL”;//不应在运行时看到,只应在文件中看到!
案例PT_荷载:
返回“PT_负载”;
案例PT_动态:
返回“PT_动态”;
案例PT_INTERP:
返回“PT_INTERP”;
案例PT_注:
返回“PT_注释”;
案例PT_SHLIB:
返回“PT_SHLIB”;
病例PT_PHDR:
返回“PT_PHDR”;
案例PT_TLS:
返回“PT_TLS”;
案例PT_GNU_EH_框架:
返回“PT_GNU_EH_FRAME”;
案例PT_GNU_堆栈:
返回“PT_GNU_STACK”;
案例PT_GNU_RELRO:
返回“PT_GNU_RELRO”;
案例PT_SUNWBSS:
返回“PT_SUNWBSS”;
案例PT_SUNWSTACK:
返回“PT_SUNWSTACK”;
违约:
if(PT_LOOS dlpi_添加);
}
if(尺寸>偏移量(结构数据包phdr信息、数据包)
{
printf(“subs:%lld\n”,info->dlpi\u subs);
}
if(大小>偏移量(结构数据集phdr信息、数据集tls修改))
{
printf(“tls modid:%zu\n”,info->dlpi\u tls\u modid);
}
if(大小>偏移量(结构数据集phdr信息、数据集tls数据))
{
printf(“tls数据:%p\n”,信息->dlpi\U tls\U数据);
}
printf(“段:%d\n”,信息->dlpi\u phnum);
对于(j=0;jdlpi\u phnum;j++)
{
常量ElfW(Phdr)*hdr=&info->dlpi_Phdr[j];
printf(“段%2d\n”,j);
printf(“类型:0x%08X(%s)\n”,hdr->p_类型,type_str(hdr->p_类型));
printf(“文件偏移量:0x%08zX\n”,hdr->p_偏移量);
printf(“虚拟地址:%p\n”,(void*)hdr->p\u vaddr);
printf(“物理地址:%p\n”,(void*)hdr->p\u paddr);
printf(“文件大小:0x%08zX\n”,hdr->p_filesz);
printf(“内存大小:0x%08zX\n”,hdr->p_memsz);
printf(“标志:0x%08X(%s)\n”、hdr->p_标志、标志(hdr->p_标志));
printf(“对齐:%zd\n”,hdr->p\u对齐);
如果(hdr->p_memsz)
{
printf(“派生地址范围:%p到%p\n”,
(无效*)(信息->地址+hdr->地址),
(无效*)(信息->dlpi地址+hdr->p\U地址+
#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);
}