Geekos-project1

文章详细介绍了如何解析ELF可执行文件,填充Exe_Format结构体,并通过Spawn_Init_Process、Start_Kernel_Thread等函数在GeekOS系统中创建内核线程和执行程序。关键步骤包括分析ELF文件头、程序头信息,以及修改elf.c和lprog.c文件以支持ELF格式的处理。
摘要由CSDN通过智能技术生成

       目的:熟悉ELF文件格式,了解GeekOS系统如何将ELF格式的可执行程序装入到内存,建立内核进程并运行的实现技术

       要求:修改/geekos/elf.c文件:在函数Parse_ELF_Executable( )中添加代码,分析ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值

一般执行操作:(若有权限限制问题,输出前带上sudo)

1、在~/project0/build下编写bochsrc配置文件

2、(可多一步骤,清除缓存,make clean)生成系统镜像文件,make depend

3、编译,make

4、运行镜像文件,bochs -f bochsrc(有的是直接可以bochs)

实现效果

原理探究

内核线程怎样建立起的?---~include\geekos\lprog.c

Spawn_Init_Process()->Staet_Kernel_Thread()->Spawner()->Read_Fully()->Parse_ELF_Excutable()->Spawn_Program()

Spawn_Init_Process函数:调用Staet_Kernel_Thread函数,而Staet_Kernel_Thread以Spawner函数作为进程体(主体)来建立核心级进程

Staet_Kernel_Thread函数:创建内核进程,使用Kernel_Thread结构体

Spawner函数:调用Read_Fully函数读ELF可执行文件,调用Spawn_Program函数执行ELF文件

        ——Spawn_Program函数:根据Exe_Format结构体中Exe_Segment结构体,计算内存大小以及空间,并复制到用户内存空间,再通过Trampoline函数执行用户进程---lprog.c文件

Exe_Format和Exe_Segment结构体

struct Exe_Format{
    struct Exe_Segment segmentList[EXE_MAX_SEGMENTS];
    int numSegments;    //定义了ELF文件中段的个数
    ulong_t entryAddr;  //代码入口地址 
}; 
struct Exe_Segment{
    ulong_t offsetInFile;   //段在可执行文件中的偏移值
    ulong_t lengthInFile;   //段在可执行文件中的长度 
    ulong_t startAddress;   //段在内存中的起始地址 
    ulong_t sizeInMemory;   //段在内存中的大小 
    int protFlags;          //保护标志
};

编写修改代码

1、修改/project1/src/geekos/elf.c,编写Parse_ELF_Executable函数

        ——参数:

                exeFileData  已转入内存的可执行文件所占用的空间起始地址

                exeFileLength    可执行文件的长度

                exeFormat    保存分析elf文件信息的结构体指针

        根据exeFileData  指向可得到ELF文件头,继而可得到程序多种信息

int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength,struct Exe_Format *exeFormat)
{
    //利用ELF头部结构体指向可执行文件头部,便于获取相关信息
    elfHeader *ehdr = (elfHeader*)exeFileData;
    //段的个数
    exeFormat->numSegments = ehdr->phnum;
    //代码入口地址
    exeFormat->entryAddr = ehdr->entry;
    //获取头部表在文件中的位置,便于读取信息
    programHeader *phdr = (programHeader*)(exeFileData + ehdr->phoff);
    //填充Exe_Segment
    unsigned int i;
    for(i = 0; i < exeFormat->numSegments; i++, phdr++)
    {
        struct Exe_Segment *segment = &exeFormat->segmentList[i];
        //获取该段在文件中的偏移量*
        segment->offsetInFile = phdr->offset;
        //获取该段的数据在文件中的长度
        segment->lengthInFile = phdr->fileSize;
        //获取该段在用户内存中的起始地址
        segment->startAddress = phdr->vaddr;
        //获取该段在内存中的大小
        segment->sizeInMemory = phdr->memSize;
        //获取该段的保护标志位
        segment->protFlags = phdr->flags;
    }
    return 0;
}

附加说明:

Start_Kernel_Thread函数的结构体:

struct Kernel_Thread* Start_Kernel_Thread(
    Thread_Start_Func startFunc,  //线程函数地址
    ulong_t arg, //线程函数参数
    int priority, //优先级
    bool detached  //线程属性,false为内核线程,true为用户线程
);

————~/src/geekos/elf.h

//ELF头部结构体——elfHeader 

typedef struct {
    unsigned  char    ident[16];
    unsigned  short    type;
    unsigned  short    machine;
    unsigned  int    version;
    unsigned  int    entry;        //代码入口地址
    unsigned  int    phoff;        //偏移地址
    unsigned  int    sphoff;
    unsigned  int    flags;
    unsigned  short    ehsize;
    unsigned  short    phentsize;
    unsigned  short    phnum;        //定义了ELF文件中段的个数
    unsigned  short    shentsize;
    unsigned  short    shnum;
    unsigned  short    shstrndx;
} elfHeader;

//ELF头部表结构体——programHeader  

typedef struct {
    unsigned  int   type;
    unsigned  int   offset;        //段在可执行文件中的偏移值
    unsigned  int   vaddr;        //段在内存中的起始地址
    unsigned  int   paddr;       
    unsigned  int   fileSize;        //段在可执行文件中的长度
    unsigned  int   memSize;        //段在内存中的大小

    unsigned  int   flags;               //保护标志
    unsigned  int   alignment;
} programHeader;

2、修改/project1/src/geekos/lprog.c

将virtSize局部变量修改为静态全局变量,即文件头部添加static unsigned long virtSize;
  修改Printrap_Handler函数
static void Printrap_Handler( struct Interrupt_State* state )
{
    char *msg;
    /* 此处修改以下内容以正确显示 a.c 中的局部变量 */
    if (state->eax <= virtSize)
        msg = (char *)virtSpace + state->eax;
    else
        msg = (char *)state->eax;
    print(msg);
    g_needReschedule = true;
    return;
}

3、修改~src/geekos/main.c中的Spawn_Init_Process函数,创建内核进程

Start_Kernel_Thread( Spawner, 0, PRIORITY_NORMAL, true );

 补充说明

————~\src\geekos\lprog文件中

图像界面输出的前两句为a.c变量的输出

后两句为spawner函数输出内容

其中spawner函数引用了a.exe,即可输出a.c的内容

spawner函数的顺利执行,则表示ELF在内核建立并完成运行!

参考文献

GeekOS课程设计-project1_geekos project1_本然233的博客-CSDN博客

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值