1

私は Linux 環境を使用しており、実行可能ファイルのセクションの 1 つに配置されたデータを取得するプログラムを作成する必要があります。では、プログラムのセクションへのポインターを (その名前で) それ自体から取得するにはどうすればよいでしょうか?

elf_getdata()セクションのインデックスを引数として get およびElf_Datastructに渡すことができることを知っています。この構造体のフィールドの 1 つはd_buf、実際のデータへのポインタです。ただし、elf_getdata()関数はファイルからメモリにセクション データのコピーを作成するようですが、それは私が望むものではありません。ロード時にメモリにロードされたデータへのポインタが必要です。

それで、皆さん、何か考えはありますか?

4

2 に答える 2

5

実際には、 をlibelf使用すると、Elf64_Shdr構造体 (64 ビット システムの場合) を使用してセクションへのポインターを取得できます。これは、sh_addrフィールド do が実行時にセクションがロードされる実際のアドレスを指しているためです。したがって、ポインターとして使用できます。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ヘッダーは必ずしもメモリにマップされるとは限らないため、ELFヘッダーに依存するのは少し危険です。APIを必要としない方法は次のとおりです。

  1. 問題のセクションの開始と終了を示す2つの記号を宣言します。
  2. __attribute__ ((section ("")))既知の名前のセクションに配置するために使用します
  3. 2つの変数のセクションの間に必要なセクションを配置するカスタムリンカースクリプトを使用します。

または、 _etext / _edata / _endの場合と同じように、リンカーで生成されたシンボルを使用できます。

于 2012-08-28T13:29:14.457 に答える