1

我在 Linux 环境中,我需要制作一个程序来检索放置在其可执行文件的某个部分中的一些数据。那么,如何从自身内部获取指向程序部分(按其名称)的指针?

我知道可以使用elf_getdata()将部分的索引作为参数传递给 get 和Elf_Datastruct ,并且该结构的字段之一是d_buf,它是指向实际数据的指针。但是,该elf_getdata()函数似乎将部分数据从文件复制到内存,这不是我想要的。我想要一个指向在加载时已加载到内存中的数据的指针。

所以,伙计们,有什么想法吗?

4

2 回答 2

5

实际上,使用libelfstruct Elf64_Shdr(对于 64 位系统)可以获得指向节的指针,因为该sh_addr字段确实指向将在运行时加载节的实际地址。因此,它可以用作指针。这样,甚至不需要使用该elf_getdata()函数来检索Elf_Data结构。

由于我想要做的是一个可以链接其他目标文件的库,因此我的代码可能具有打开可执行文件本身以利用某些libelf功能的功能,以便它可以从主文件部分读取数据,如如下:

// A global variable which stores the executable file name
extern const char *__progname;

void retrieve_data() {
  int fd;       // File descriptor for the executable ELF file
  char *section_name, path[384];
  size_t shstrndx;

  Elf *e;           // ELF struct
  Elf_Scn *scn;     // Section index struct
  Elf64_Shdr *shdr;     // Section struct

  // Create the full path of the executable
  getcwd(path, 255);
  strcat(path, "/");
  strncat(path, __progname, 127);

  if (elf_version(EV_CURRENT) == EV_NONE)
    errx(EXIT_FAILURE, "ELF library iinitialization failed: %s", elf_errmsg(-1));

  if ((fd = open(path, O_RDONLY, 0)) < 0)
    err(EXIT_FAILURE, "open \"%s\" failed", path);

  if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
    errx(EXIT_FAILURE, "elf_begin() failed: %s.", elf_errmsg(-1));

  // Retrieve the section index of the ELF section containing the string table of section names
  if (elf_getshdrstrndx(e, &shstrndx) != 0)
    errx(EXIT_FAILURE, "elf_getshdrstrndx() failed: %s.", elf_errmsg(-1));

  scn = NULL;

  // Loop over all sections in the ELF object
  while ((scn = elf_nextscn(e, scn)) != NULL) {
    // Given a Elf Scn pointer, retrieve the associated section header
    if ((shdr = elf64_getshdr(scn)) != shdr)
      errx(EXIT_FAILURE, "getshdr() failed: %s.", elf_errmsg(-1));

    // Retrieve the name of the section
    if ((section_name = elf_strptr(e, shstrndx, shdr->sh_name)) == NULL)
      errx(EXIT_FAILURE, "elf_strptr() failed: %s.", elf_errmsg(-1));

    // If the section is the one we want... (in my case, it is one of the main file sections)
    if (!strcmp(section_name, "Section name")) {
      // We can use the section adress as a pointer, since it corresponds to the actual
      // adress where the section is placed in the virtual memory
      struct data_t * section_data = (struct data_t *) shdr->sh_addr;

      // Do whatever we want

      // End the loop (if we only need this section)
      break;
    }
  }

  elf_end(e);
  close(fd);
}
于 2012-08-28T21:01:47.577 回答
3

ELF 标头不一定映射到内存中,因此依赖它可能有点冒险。这是一种不需要任何 API 的方法:

  1. 声明两个符号,表示相关部分的开始和结束。
  2. 用于__attribute__ ((section ("")))将它们放在具有已知名称的部分中
  3. 使用自定义链接器脚本,将您需要的部分放在两个变量的部分之间。

或者,您可以使用链接器生成的符号,就像_etext/_edata/_end 一样

于 2012-08-28T13:29:14.457 回答