5.16 加载内核映像文件(2)

首先是 编写 elf 头文件。

下载elf_foarmat.pdf

主要是elf 文件头, 这个主要用于找到 section的地址。

/**
 * ELF相关头文件及配置
 *
 * 作者:李述铜
 * 联系邮箱: 527676163@qq.com
 */
#ifndef OS_ELF_H
#define OS_ELF_H

#include "types.h"

// ELF相关数据类型
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef uint32_t Elf32_Sword;
typedef uint32_t Elf32_Word;

#pragma pack(1)

// ELF Header
#define EI_NIDENT       16
#define ELF_MAGIC       0x7F

typedef struct {
    char e_ident[EI_NIDENT];
    Elf32_Half e_type;
    Elf32_Half e_machine;
    Elf32_Word e_version;
    Elf32_Addr e_entry;
    Elf32_Off e_phoff;
    Elf32_Off e_shoff;
    Elf32_Word e_flags;
    Elf32_Half e_ehsize;
    Elf32_Half e_phentsize;
    Elf32_Half e_phnum;
    Elf32_Half e_shentsize;
    Elf32_Half e_shnum;
    Elf32_Half e_shstrndx;
}Elf32_Ehdr;

#define PT_LOAD         1

typedef struct {
    Elf32_Word p_type;
    Elf32_Off p_offset;
    Elf32_Addr p_vaddr;
    Elf32_Addr p_paddr;
    Elf32_Word p_filesz;
    Elf32_Word p_memsz;
    Elf32_Word p_flags;
    Elf32_Word p_align;
} Elf32_Phdr;

#pragma pack()

#endif //OS_ELF_H

然后是 load_32.c 中实现对elf 文件的解析。

// 这是读取 elf 文件的 代码段与数据段的函数
static uint32_t reload_elf_file (uint8_t * file_buffer) {
    // 读取的只是ELF文件,不像BIN那样可直接运行,需要从中加载出有效数据和代码
    // 简单判断是否是合法的ELF文件
    Elf32_Ehdr * elf_hdr = (Elf32_Ehdr *)file_buffer;
    if ((elf_hdr->e_ident[0] != ELF_MAGIC) || (elf_hdr->e_ident[1] != 'E')
        || (elf_hdr->e_ident[2] != 'L') || (elf_hdr->e_ident[3] != 'F')) {
        return 0;
    }

    // 然后从中加载程序头,将内容拷贝到相应的位置
	// e_phnum 代表着 program 表 的数量, 其实就一个。
	// 这里一个program 表头代表着 一个 Program 段
    for (int i = 0; i < elf_hdr->e_phnum; i++) {
		// 找到 program header 的地址。
		// e_phoof 代表着 program 段的偏移
        Elf32_Phdr * phdr = (Elf32_Phdr *)(file_buffer + elf_hdr->e_phoff) + i;
        if (phdr->p_type != PT_LOAD) {
            continue;
        }

		// 全部使用物理地址,此时分页机制还未打开
        uint8_t * src = file_buffer + phdr->p_offset;
        uint8_t * dest = (uint8_t *)phdr->p_paddr;
		//这里复制的其实 是 .text , .data .bss  段,都复制了,疑问这几个段在一个 program 段内。
        for (int j = 0; j < phdr->p_filesz; j++) {
            *dest++ = *src++;
        }

		// memsz和filesz不同时,后续要填0
		// 这是对 .bss 段的处理。
		// 按理说  p_memsz  要比 p_filesz 要大的,所以 将  p_memsz - phdr->p_filesz 大的地方写0 就可以了。
		dest= (uint8_t *)phdr->p_paddr + phdr->p_filesz;
		for (int j = 0; j < phdr->p_memsz - phdr->p_filesz; j++) {
			*dest++ = 0;
		}
    }

    return elf_hdr->e_entry;
}

然后需要注意 bss 段的拷贝。

在 program 表内有个 p_memsz 与 p_filesz

这两的差值 ,就是需要 填0 的 .bss 段。

程序的入口地址 在elf 的头里面。

	// 这里获得了 elf 的入口地址。
	uint32_t kernel_entry = reload_elf_file((uint8_t *)SYS_KERNEL_LOAD_ADDR);
	if (kernel_entry == 0) {
		die(-1);
	}

	((void (*)(boot_info_t *))kernel_entry)(&boot_info);

然后是 loader_32.c 中的死机函数。

static void die (int code) {
    for (;;) {
    }
}

然后去改调试文件的内容。改 launch.json, 这个地方不理解,可能跟 调试有关。

程序是可以走到最后的。

来看看 我的程序的反汇编。

感觉我的程序不对呀。但是确实能够走到最后。

先不管了。

相关推荐
hhhhhhh_hhhhhh_5 分钟前
ubuntu18.04连接不上网络问题
linux·运维·ubuntu
冷心笑看丽美人13 分钟前
探秘 DNS 服务器:揭开域名解析的神秘面纱
linux·运维·服务器·dns
军训猫猫头1 小时前
20.抽卡只有金,带保底(WPF) C#
ui·c#·wpf
冬天vs不冷1 小时前
Linux用户与权限管理详解
linux·运维·chrome
凯子坚持 c2 小时前
深入Linux权限体系:守护系统安全的第一道防线
linux·运维·系统安全
✿ ༺ ོIT技术༻2 小时前
C++11:新特性&右值引用&移动语义
linux·数据结构·c++
watermelonoops5 小时前
Deepin和Windows传文件(Xftp,WinSCP)
linux·ssh·deepin·winscp·xftp
疯狂飙车的蜗牛6 小时前
从零玩转CanMV-K230(4)-小核Linux驱动开发参考
linux·运维·驱动开发
远游客07138 小时前
centos stream 8下载安装遇到的坑
linux·服务器·centos
马甲是掉不了一点的<.<8 小时前
本地电脑使用命令行上传文件至远程服务器
linux·scp·cmd·远程文件上传