操作ELF文件的方法

8.2.2  操作ELF格式文件的方法

综合以上的描述,总结执行ELF格式文件的方法,步骤如下:

(1)从文件起始位置读取一个struct elf32_ehdr结构体,验证文件的正确性以及文件与操作系统是否匹配。

(2)找到该结构体中e_entry成员,从系统中获得这个值所指向的内存地址。

(3)读出struct elf32_ehdr结构体中的e_phoff、e_phextsize以及e_phnum三个成员。根据这三个值,利用struct elf32_phdr结构体遍历文件中每一个Program头。

(4)在遍历的过程中,检查struct elf32_phdr结构体中的p_type成员,如果为1,则调用存储设备的相关函数,将文件内偏移为p_offset、大小为p_filesz的一段数据从存储器中读取到p_vaddr所指向的内存位置。

(5)调用执行函数,使程序从e_entry内存处开始执行。

这样,一个ELF格式文件的执行过程就可以顺利完成了,将上述步骤用程序来实现,如下:

代码8-6

  1. void plat_boot(void){
  2. int i;
  3. for(i=0;init[i];i++){
  4. init[i]();
  5. }
  6. init_sys_mmu();
  7. start_mmu();
  8. //  timer_init();
  9. init_page_map();
  10. kmalloc_init();
  11. ramdisk_driver_init();
  12. romfs_init();
  13. struct inode *node;
  14. struct elf32_phdr *phdr;
  15. struct elf32_ehdr *ehdr;
  16. int phnum,pos,dpos;
  17. char *buf;
  18. if((buf=kmalloc(1024))==(void *)0){
  19. printk("get free pages error\n");
  20. goto HALT;
  21. }
  22. if((node=fs_type[ROMFS]->namei(fs_type[ROMFS],"main"\
  23. ))==(void *)0){
  24. printk("inode read eror\n");
  25. goto HALT;
  26. }
  27. if(fs_type[ROMFS]->device->dout(fs_type[ROMFS]->device,buf,\
  28. fs_type[ROMFS]->get_daddr(node),node->dsize)){
  29. printk("dout error\n");
  30. goto HALT;
  31. }
  32. ehdr=(struct elf32_ehdr *)buf;
  33. phdr=(struct elf32_phdr *)((char *)buf+ehdr->e_phoff);
  34. for(i=0;i<ehdr->e_phnum;i++){
  35. if(CHECK_PT_TYPE_LOAD(phdr)){
  36. if(fs_type[ROMFS]->device->dout (fs_type[ROMFS]->device,\
  37. (char *)phdr->p_vaddr,\
  38. fs_type[ROMFS]->get_daddr(node)+\
  39. phdr->p_offset,phdr->p_filesz)<0){
  40. printk("dout error\n");
  41. goto HALT;
  42. }
  43. }
  44. phdr++;
  45. }
  46. exec(ehdr->e_entry);
  47. HALT:
  48. while(1);
  49. }

在代码8-6中,程序首先通过romfs文件系统的namei函数读取RAM盘上的main文件,得到代表该文件的inode结构体。不同于代码8-3中的"main.bin"文件,这里的main文件是直接由编译器编译生成的ELF格式文件。于是,我们可以依据执行ELF程序的一般步骤对它进行处理。

首先要做的就是通过存储设备的dout函数从文件系统中读出main文件的内容,并保存到buf中。为了保证程序简单直观,这里我们没有验证缓冲区的大小是否足够装下ELF和Program头信息,程序仅仅通过kmalloc函数申请了一个1K大小的内存来存储文件开头的部分。这样做,运行本书的例子至少是没有问题的。

接下来,我们需要找到描述ELF头信息的结构体struct elf32_ehdr 的位置,并通过读取它的e_phoff成员找到第一个struct elf32_phdr结构体。这两个结构体的地址,分别被保存在变量ehdr和phdr中。

然后,程序从phdr变量开始,通过循环读取每一个Program头信息,依次判断struct elf32_phdr结构体的p_type成员是否为1。如果该成员为1,则表示此Program头所描述的正是代码段或数据段。此时需要再次调用dout函数,将用户应用程序的代码或数据从存储设备中复制到内存里。这两个信息分别记录在了struct elf32_phdr结构体的p_offset和p_vaddr结构体的成员中。

当所有的代码和数据最终都被加载到内存的正确位置后,就可以调用exec来运行用户应用程序了。用户程序的入口地址可从struct elf32_ehdr的e_entry成员中得到。

有了这样的方法,操作系统在运行用户程序时,便不再需要了解用户程序的细节。而仅需从应用程序中读出与程序运行有关的信息,根据这些信息的提示准备好程序运行的环境。这样,理论上就实现了运行任意二进制应用程序的可能。

然而从另一个角度来看,这种运行应用程序的方法还存在一个致命的缺陷,那就是我们无法保证用户应用程序的运行地址恰好是有效的。

这需要分两种情况去分析。第一种情况是,用户应用程序的运行地址已经超出了物理内存的范围,例如,一个ELF格式的用户应用程序需要运行在内存为0x40000000的地址中,但我们的虚拟系统,不计算RAM盘所占用的内存空间,一共只有8M的可用内存,0x40000000这个地址远远超过了硬件原有内存的范围。第二种情况是,用户应用程序的运行地址虽然落在了物理内存的范围内,但这个地址却恰好被别的应用程序提前占用了。无论哪一种情况发生,都会使我们的操作系统将一个原本可以正常运行的用户应用程序拒之门外。

想要解决这个问题,可以通过虚拟内存映射将原本无效的内存地址映射到有效的空间中。于是,我们只需要将应用程序的代码和数据保存到任意一个没有被使用的有效内存中,然后修改页表,将这个内存地址映射到用户应用程序规定的地址。由此,读者也可以深入地体会一下虚拟地址映射对于一个功能强大的操作系统来说是多么的重要。

当然,想要实现这样的功能,我们的操作系统代码需要进行很大的调整,这其中至少包含内存管理部分和MMU部分两个子结构。为了不占用过多的篇幅,这段代码我们就不去具体实现了。读者如果感兴趣的话,可以尝试自行实现。

下面我们来实践一下这段代码。

操作ELF文件的方法

时间: 2024-09-29 09:18:58

操作ELF文件的方法的相关文章

C# 操作txt文件的方法大全

c# 操作txt文件 # 操作txt文件 c#创建文本 private const string FILE_NAME = "ErroLog.txt"; public static void WriteFile(string str) ...{ StreamWriter sr; if (File.Exists(FILE_NAME)) //如果文件存在,则创建File.AppendText对象 ...{ sr = File.AppendText(FILE_NAME); } else //如

利用XmlDocument操作XML文件

利用XmlDocument可以方便的操作XML文件. 1.操作XML文件基本方法 (1)添加对System.Xml的引用,并使用using语句添加引用: (2)假设要读取的XML文件如下: <?xml version="1.0" encoding="utf-8"?> <Students> <Student> <Name>张靓靓</Name> <Age>20</Age> <Hob

C#项目中操作Excel文件——使用NPOI库

转载自:http://blog.csdn.net/dcrmg/article/details/52356236# 感谢-牧野- 实际C#项目中经常会涉及到需要对本地Excel文件进行操作,特别是一些包含数据记录.分析.汇总功能模块的项目.常用的操作Excel文件的方法主要有三个: 1. OleDb: 这种方式是把整个Excel文件当做一个数据源来进行数据的读取操作. 优点:实现方式简单,读取速度快: 缺点:读取Excel数据的过程不太灵活,对内存的占用比较高,当数据量变的很大时,容易由于内存空间

将插座变量(IBOutlet)关联到*.xib文件中对象 + 将对*.xib对象的操作关联到动作方法(IBAction)

将插座变量(IBOutlet)关联到*.xib文件中对象 以BNRDetailViewController.m和BNRDetailViewController.xib为例(<iOS编程>第10章例子) 1.打开BNRDetailViewController.xib,添加一个UITextField对象: 2.在辅助编辑器中打开BNRDetailViewController.m,方法是:按住Option键并点击项目导航面板中的BNRDetailViewController.m: 3.按住Contr

c#操作XML文件的通用方法

c#操作XML文件的通用方法 本文导读:我们在编写C#程序时,经常会通过C#访问XML文件,实现对XML文档的读写操作.下面为大家列出了通用的调用方法,大家可以将这些方法放在共用类里,其它的程序共享调用就可以了. 下面通过一个类将我们平时用c#操作XML文件的通用方法详细的介绍一下,关于asp.net C#操作xml文档实现代码,大家可以参考参考. c# 代码 1 sing System; 2 using System.Data; 3 using System.Configuration; 4

Excel-VBA操作文件四大方法之一

在我们日常使用Excel的时候,不仅会用到当前Excel文件的数据,还经常需要访问其他的数据文件.这些数据文件可能是Excel文件.文本文件或数据库文件等.经常有朋友会问如何在vba代码里操作这些数据文件?本文就系统地介绍一下在Excel中应用VBA操作数据文件的方法. 本文主要介绍四种常用的方法:1.利用Excel对象来处理文件:2.利用VBA文件处理语句来处理文件:3.利用FileSystemObject对象来处理文件:4.利用API函数来处理文件. 当然对于数据库文件,还可以利用ADO+S

ELF文件的加载过程(load_elf_binary函数详解)--Linux进程的管理与调度(十三)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-04 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的描述 加载和动态链接 从编译/链接和运行的角度看,应用程序和库程序的连接有两种方式. 一种是固定的.静态的连接,就是把需要用到的库函数的目标代码(二进制)代码从程序库中抽取出来,链接进应用软件的目标映像中: 另一种是动态链接,是指库函数的代码并不进入应用软件的目标映像,应用软件在编译/链接阶段并

JAVA使用和操作properties文件

java中的properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是"键=值"的格式,在properties文件中,可以用"#"来作注释,properties文件在Java编程中用到的地方很多,操作很方便.Properties 类存在于包 Java.util 中,该类继承自 Hashtable. 1. getProperty ( String  key) ,   用指定的键在此属性列表中搜索

java使用POI操作excel文件,实现批量导出,和导入

一.POI的定义 JAVA中操作Excel的有两种比较主流的工具包: JXL 和 POI .jxl 只能操作Excel 95, 97, 2000也即以.xls为后缀的excel.而poi可以操作Excel 95及以后的版本,即可操作后缀为 .xls 和 .xlsx两种格式的excel. POI全称 Poor Obfuscation Implementation,直译为"可怜的模糊实现",利用POI接口可以通过JAVA操作Microsoft office 套件工具的读写功能.官网:htt