加载和执行ELF-64目标代码 - 不确定最后的步骤

时间:2011-11-30 22:59:01

标签: c loader elf

我正在编写一个小工具来试验ELF-64目标代码,该代码旨在解析和加载ELF-64目标代码,以便在父进程中执行。我相信我现在正走在正确的轨道上,但我需要为最后几步提供一些指示。

第1步:我解析目标文件并提取所有必要信息。我已使用readelf工具验证了这一点。

第2步:我使用SHF_ALLOC - 位设置和mmap内存遍历所有节标题。

第3步:这个看似简单无用的对象只包含一个main - 例程和一个return语句,据我所知,我不需要重新定位符号(我已经加倍了)用readelf检查。我已经使用TinyCC编译,以避免.eh_frame及其重定位条目被发出。

但是在这一点上我需要加载SHF_ALLOC - 位设置到内存中的部分,这是我怀疑我做错的地方。

offset = 0

foreach section in sections
    if section.flags & SHF_ALLOC
        memcpy(memory_address + offset, object_code + section.offset, section.size)
        offset += section_size

第4步:我不确定的最后一步。我需要调用已标记为可执行文件的已分配内存。

typedef int (main_t)(int argc, char* argv[]);

((main_t)object->address)(0, NULL);

我非常感谢对此的一些意见。我认为归结为缺乏理解.text - 究竟是什么 - 片段包含以及它们如何存储在内存中。

一些想法:

  • main位于0x0 - 段的偏移.text处吗?
  • 是否为
  • 分配了要按顺序对齐存储的段?

任何指向正确方向的东西都会有很大的帮助!谢谢!

PS。我打算很快学会重新定位符号。一步一步来。 : - )

2 个答案:

答案 0 :(得分:1)

您应该使用程序头,而不是节标题。节头用于链接器,程序头用于加载器。

分配的段旨在转到他们首选的VirtAddr,如果它们有一个(非预链接库可能有一个基本虚拟地址为0,这意味着加载器将为它们分配随机地址)。

ELF标题有一个入口点字段。这不是main,它通常是一些libc初始化代码......进行初始化...然后调用main。在将控制权传递给入口点之前,您应该设置符合ELF ABI的所有内容(将argcargvenvpauxv放在堆栈上,清除一些寄存器,我认为就是这样。)

答案 1 :(得分:0)

在一夜好眠之后,我设法把它拉了下来。

我首先使用生成的objdump反汇编目标文件:

/tmp/test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 81 ec 10 00 00 00    sub    $0x10,%rsp
   b:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
   f:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
  13:   b8 c8 00 00 00          mov    $0xc8,%eax
  18:   e9 00 00 00 00          jmpq   1d <main+0x1d>
  1d:   c9                      leaveq 
  1e:   c3                      retq 

此输出确保了main位于0x0的位置,这意味着如果我将.text - 段正确复制到mmap返回的地址的内存中,我应该可以用问题中找到的片段(我不确定)来调用它。它将使用调用线程的堆栈。

然后我将部分复制到内存时发现了一个小错误,section.offset文件开头的偏移量,我错误地认为这是从开头的偏移量节标题条目。

当我了解基础工作时,实验会更简单。 : - )