weiqi7777

静态程序编译链接与装载(四)ELF程序如何执行

0
阅读(1733)

ELF有执行视图,那么ELF是怎么执行的起来的呢?

这里,分为2个进行说明:

一、CPU在EDA上,仿真执行ELF

在验证环境中,会有一块memory,专门用来放置CPU要执行的指令,以及访问的数据。而verilog提供了$memreadh系统函数,可以将hex文件,直接载入到memory中。

因此只要将ELF文件,转化成hex文件即可。

比如对于如下的链接脚本:

3个代码段,起始地址从0x5000_0000开始,2个数据段,从0x8000_0000开始。

最终转换出来的hex文件如图下所示:

因为VMA和LMA一样,所以hex文件中的地址,也就是VMA。

对于如下的链接脚本,使用AT,修改了加载地址,也就是LMA。

此时转换得到hex文件如下图所示:

二、对于操作系统

对于操作系统而言,如何执行ELF程序。

demo代码如下图所示:

gcc –static a.c -o out.elf 进行编译, 得到out.elf

readelf –a out.elf,查看elf信息

有42个段,但是对于执行,我们关心的执行视图,也就是segment。如下图所示。

elf有2个segment, section中属于 可读可执行的section,合并成 1个segment

section中属于 可读可写的section,合并成1个segment

将可执行程序, out.elf 通过后台,执行2次, 查看程序运行的memory映射关系

可以看出,segment1和segment2的va地址,两个程序的地址映射都是一样的。但是看不到PA地址。

那么操作系统有时如何执行ELF程序的呢?

  • 读取ELF程序前128字节。判断是ELF,调用ELF解析程序进行下一步
  • 调用fork,创建进程,并且创建页表,此时还没有将elf程序,装载到内存
  • 将执行入口,设置为elf的entry point address
  • 返回到用户态,从入口地址开始执行
  • 产生mmu abort,切换到内核态,内核分配memory物理空间,建立页表映射,并将elf中数据,搬移到memory物理空间中去
  • 返回到用户态,继续执行

三、自定义加载地址

可以在链接脚本中,使用AT关键字,自定义加载地址。

例如如下代码,3个代码段,2个数据段。

链接脚本如下:

makefile如下:

查看elf的section信息,有8个段。

有2个segment。VMA和LMA一致。

将链接脚本,修改如下,使用AT,为section,指定LMA。

重新,编译,查看ELF的segment,变成3个segment

  • segment0:LMA是0x1000,boot section的集合
  • segment1:LMA是0x2000,text1和text2 section的集合
  • segment2:LMA是0x5000,data和data1 section的集合