内核如何获得在Linux下运行的可执行二进制文件?

内核如何获得在Linux下运行的可执行二进制文件?

这似乎是一个简单的问题,但任何人都可以帮我深挖? 如何将文件加载到内存以及如何开始执行代码?

任何人都可以帮助我,并一步一步告诉发生了什么?

Linux 4.0上exec系统调用的最佳时刻

  • fs/exec.cSYSCALL_DEFINE3(execve定义系统调用

    简单地转发到do_execve

  • do_execve

    转发到do_execveat_common

  • do_execveat_common

    要查找下一个主要函数,请跟踪返回值retval最后修改的时间。

    开始构build一个struct linux_binprm *bprm来描述程序,并将其传递给exec_binprm来执行。

  • exec_binprm

    再次,按照返回值来查找下一个主要调用。

  • search_binary_handler

    • 处理程序由可执行文件的第一个魔术字节决定。

      两个最常见的处理程序是用于解释文件( #! magic)和ELF( \x7fELF magic)的处理程序,但还有其他内置的内核,例如a.out 。 用户也可以通过/ proc / sys / fs / binfmt_misc注册自己的

      ELF处理程序在fs/binfmt_elf.c定义。

    • formats列表包含所有的处理程序。

      每个处理程序文件包含如下所示

       static int __init init_elf_binfmt(void) { register_binfmt(&elf_format); return 0; } 

      elf_format是在该文件中定义的struct linux_binfmt

      __init是神奇的,并将这些代码放入一个魔术部分,当内核启动时会被调用: __init在Linux内核代码中的含义是什么?

      链接器级别的dependency injection!

    • 还有一个recursion计数器,以防解释器无限地执行。

      尝试这个:

       echo '#!/tmp/a' > /tmp/a chmod +x /tmp/a /tmp/a 
    • 我们再次遵循返回值来看看接下来会发生什么,并且看到它来自:

       retval = fmt->load_binary(bprm); 

      其中load_binary是为结构上的每个处理程序定义的:C风格的多态。

  • fs/binfmt_elf.c:load_binary

    是否实际工作:

    • 根据规格parsingELF文件
    • 根据parsing的ELF(内存到一个struct linux_binprm ,注册到一个struct pt_regs )设置进程的初始程序状态。
    • 调用start_thread ,这是真正开始计划的地方

待办事项:进一步继续进行来源分析。 我期望接下来会发生什么:

  • 内核分析ELF的/lib64/ld-linux-x86-64.so.2头以finddynamic加载器(通常设置为/lib64/ld-linux-x86-64.so.2 )。
  • 内核将dynamic加载器和要执行的ELF映射到内存
  • 启动dynamic加载程序,在内存中带一个指向ELF的指针。
  • 现在在userland,加载器以某种方式parsing精灵标题,并且对它们进行dlopen
  • dlopen使用可configuration的searchpath来查找这些库( ldd和friends),将它们映射到内存中,并以某种方式通知ELF在哪里find其丢失的符号
  • 加载器调用ELF的_start

来自linux内核的两个系统调用是相关的。 fork系统调用(或者vfork或者clone )被用来创build一个新的进程,类似于调用的进程(除了init之外,每个Linux用户登陆进程都由fork或者朋友创build)。 execve系统调用用一个新的进程地址空间replace进程地址空间(主要是通过ELF可执行文件和匿名段的mmap-段的sorting,然后初始化寄存器,包括堆栈指针)。 x86-64 ABI补充和Linux组件如何提供细节。

dynamic链接发生在execve之后,涉及/lib/x86_64-linux-gnu/ld-2.13.so文件,ELF被视为“解释器”。

阅读已经引用的ELF文档后,您应该只是读取实际执行的内核代码 。

如果您在理解代码时遇到困难,请构build一个UML Linux ,然后您可以在debugging器中遍历该代码。

您可以从理解可执行文件格式(如ELF)开始。 http://en.wikipedia.org/wiki/Executable_and_Linkable_Format

ELF文件包含几个标题部分,描述应该如何将部分二进制文件加载到内存中。

然后,我build议读一下加载二进制文件和处理dynamic链接的linux部分, ld-linux 。 这也是对ld-linux的一个很好的描述: http : //www.cs.virginia.edu/~dww4s/articles/ld_linux.html