ELF加载过程代码注解

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    国内:https://weharmony.gitee.io
    国外:https://weharmony.github.io
上级 29bc8c40
......@@ -1351,7 +1351,7 @@ LITE_OS_SEC_TEXT UINT32 OsExecRecycleAndInit(LosProcessCB *processCB, const CHAR
alloc_std_fd(OsCurrProcessGet()->files->fdt);
#endif
OsSwtmrRecycle(processCB->processID);//定时器回收
OsSwtmrRecycle(processCB->processID);//回收定时器
processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID;
#ifdef LOSCFG_SECURITY_VID
......@@ -1363,7 +1363,7 @@ LITE_OS_SEC_TEXT UINT32 OsExecRecycleAndInit(LosProcessCB *processCB, const CHAR
#endif
processCB->processStatus &= ~OS_PROCESS_FLAG_EXIT; //去掉进程退出标签
processCB->processStatus |= OS_PROCESS_FLAG_ALREADY_EXEC;//加上进程运行 elf标签
processCB->processStatus |= OS_PROCESS_FLAG_ALREADY_EXEC;//加上进程运行elf标签
return LOS_OK;
}
......
......@@ -1562,8 +1562,8 @@ LITE_OS_SEC_TEXT VOID OsTaskExitGroup(UINT32 status)
//任务退群并销毁,进入任务的回收链表之后再进入空闲链表,等着再次被分配使用.
LITE_OS_SEC_TEXT VOID OsExecDestroyTaskGroup(VOID)
{
OsTaskExitGroup(OS_PRO_EXIT_OK);//进程
OsTaskCBRecyleToFree();
OsTaskExitGroup(OS_PRO_EXIT_OK);//任务退出
OsTaskCBRecyleToFree();//回收任务资源
}
//暂停当前进程的所有任务
LITE_OS_SEC_TEXT VOID OsProcessSuspendAllTask(VOID)
......
......@@ -69,7 +69,7 @@ extern "C" {
// |---------------------------|映射区结束位置 USER_MAP_BASE + USER_MAP_SIZE
// | 虚拟地址-物理地址映射区 |
// | |
// |---------------------------|映射区开始位置 USER_MAP_BASE
// |---------------------------|映射区开始位置 USER_MAP_BASE = (USER_ASPACE_TOP_MAX >> 1)
// | |
// | |
// | /\ |
......@@ -99,7 +99,7 @@ extern "C" {
#define USER_ASPACE_TOP_MAX ((vaddr_t)(USER_ASPACE_BASE + USER_ASPACE_SIZE))//用户空间顶部位置
#define USER_HEAP_BASE ((vaddr_t)(USER_ASPACE_TOP_MAX >> 2)) //堆的开始地址
#define USER_MAP_BASE ((vaddr_t)(USER_ASPACE_TOP_MAX >> 1)) //用户映射区
#define USER_MAP_BASE ((vaddr_t)(USER_ASPACE_TOP_MAX >> 1)) //用户映射区开始地址
#define USER_MAP_SIZE ((vaddr_t)(USER_ASPACE_SIZE >> 3)) //用户空间映射大小 = 1/8 用户空间
#ifndef PAGE_SIZE
......
......@@ -180,7 +180,7 @@ typedef struct VmSpace {
#define VM_MAP_REGION_FLAG_FIXED (1<<17)
#define VM_MAP_REGION_FLAG_FIXED_NOREPLACE (1<<18)
#define VM_MAP_REGION_FLAG_INVALID (1<<19) /* indicates that flags are not specified */
//从外部权限标签转化为线性区权限标签
STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned long flags)
{
UINT32 regionFlags = 0;
......
......@@ -95,28 +95,43 @@ STATUS_T OsNamedMmapingPermCheck(struct file *filep, unsigned long flags, unsign
return LOS_OK;
}
//匿名映射
STATUS_T OsAnonMMap(LosVmMapRegion *region)
{
LOS_SetRegionTypeAnon(region);
return LOS_OK;
}
/**************************************************
系统调用|申请虚拟内存
mmap基础概念:
一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系.
实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,
即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,
从而可以实现不同进程间的文件共享。
https://www.cnblogs.com/huxiao-tee/p/4660352.html
http://abcdxyzk.github.io/blog/2015/09/11/kernel-mm-mmap/
参数 描述
addr 用来请求使用某个特定的虚拟内存地址。如果取NULL,结果地址就将自动分配(这是推荐的做法),
否则会降低程序的可移植性,因为不同系统的可用地址范围不一样。
length 内存段的大小。
addr 指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。
length 代表将文件中多大的部分映射到内存。
prot 用于设置内存段的访问权限,有如下权限:
PROT_READ:允许读该内存段。
PROT_WRITE:允许写该内存段。
PROT_EXEC:允许执行该内存段。
PROT_NONE:不能访问。
PROT_EXEC 映射区域可被执行
PROT_READ 映射区域可被读取
PROT_WRITE 映射区域可被写入
PROT_NONE 映射区域不能存取
flags 控制程序对内存段的改变所造成的影响,有如下属性:
MAP_PRIVATE:内存段私有,对它的修改值仅对本进程有效。
MAP_SHARED:把对该内存段的修改保存到磁盘文件中。
fd 打开的文件描述符。
offset 以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射。
MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
MAP_SHARED 对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。
fd: 要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。
有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,然后对该文件进行映射,可以同样达到匿名内存映射的效果。
offset 文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是PAGE_SIZE的整数倍。
成功返回:虚拟内存地址,这地址是页对齐。
失败返回:(void *)-1。
**************************************************/
......
......@@ -36,25 +36,38 @@
#define AUX_VECTOR_SIZE_BASE 20
#define AUX_VECTOR_SIZE ((AUX_VECTOR_SIZE_ARCH + AUX_VECTOR_SIZE_BASE + 1) << 1)
/* AUX VECTOR */
#define AUX_NULL 0
#define AUX_IGNORE 1
#define AUX_EXECFD 2
#define AUX_PHDR 3
#define AUX_PHENT 4
#define AUX_PHNUM 5
#define AUX_PAGESZ 6
#define AUX_BASE 7
#define AUX_FLAGS 8
#define AUX_ENTRY 9
#define AUX_NOTELF 10
#define AUX_UID 11
#define AUX_EUID 12
#define AUX_GID 13
#define AUX_EGID 14
/*
http://articles.manugarg.com/aboutelfauxiliaryvectors.html
ELF辅助向量是一种将某些内核级别信息传输到用户进程的机制。此类信息的一个示例是指向内存中系统调用
入口点的指针(AT_SYSINFO)。该信息本质上是动态的,只有在内核完成加载后才知道。
信息由二进制加载程序传递给用户进程,二进制加载程序是内核子系统本身的一部分。内置内核或内核模块。
二进制加载程序将二进制文件(程序)转换为系统上的进程。通常,每种二进制格式都有一个不同的加载器;
值得庆幸的是,二进制格式并不多-大多数基于linux的系统现在都使用ELF二进制文件。
ELF二进制加载器在以下文件 /usr/src/linux/fs/binfmt_elf.c中定义。
ELF加载器解析ELF文件,在内存中映射各个程序段,设置入口点并初始化进程堆栈。
它将ELF辅助向量与其他信息(如argc,argv,envp)一起放在进程堆栈中。初始化后,进程的堆栈如下所示:
*/
/* AUX VECTOR *//* Legal values for a_type (entry type). */
#define AUX_NULL 0 /* End of vector */
#define AUX_IGNORE 1 /* Entry should be ignored */
#define AUX_EXECFD 2 /* File descriptor of program */
#define AUX_PHDR 3 /* Program headers for program */
#define AUX_PHENT 4 /* Size of program header entry */
#define AUX_PHNUM 5 /* Number of program headers */
#define AUX_PAGESZ 6 /* System page size */
#define AUX_BASE 7 /* Base address of interpreter */
#define AUX_FLAGS 8 /* Flags */
#define AUX_ENTRY 9 /* Entry point of program */
#define AUX_NOTELF 10 /* Program is not ELF */
#define AUX_UID 11 /* Real uid */
#define AUX_EUID 12 /* Effective uid */
#define AUX_GID 13 /* Real gid */
#define AUX_EGID 14 /* Effective gid */
#define AUX_PLATFORM 15
#define AUX_HWCAP 16
#define AUX_CLKTCK 17
#define AUX_CLKTCK 17 /* Frequency of times() */
#define AUX_SECURE 23
#define AUX_BASE_PLATFORM 24
#define AUX_RANDOM 25
......
......@@ -193,9 +193,9 @@ typedef struct {
#define LD_PT_LOAD 1 //此类型表明本程序头指向一个可装载的段.段的内容会被从文件中拷贝到内存中.如前所述,段在文件中的大小是p_filesz,在内存中的大小是p_memsz.如果p_memsz大于p_filesz,在内存中多出的存储空间应填0补充,也就是说,段在内存中可以比在文件中占用空间更大;而相反,p_filesz永远不应该比p_memsz大,因为这样的话,内存中就将无法完整地映射段的内容.在程序头表中,所有PT_LOAD类型的程序头按照p_vaddr的值做升序排列.
#define LD_PT_DYNAMIC 2 //描述了动态加载段
#define LD_PT_INTERP 3 //本段指向了一个以"null"结尾的字符串,这个字符串是一个ELF解析器的路径.这种段类型只对可执行程序有意义,当它出现在共享目标文件中时,是一个无意义的多余项.在一个ELF文件中它最多只能出现一次,而且必须出现在其它可装载段的表项之前
#define LD_PT_NOTE 4
#define LD_PT_SHLIB 5
#define LD_PT_PHDR 6 //描述了program header table自身的信息
#define LD_PT_NOTE 4 //本段指向了一个以"null"结尾的字符串,这个字符串包含一些附加的信息
#define LD_PT_SHLIB 5 //该段类型是保留的,而且未定义语法.UNIX System V系统上的应用程序不会包含这种表项.
#define LD_PT_PHDR 6 //此类型的程序头如果存在的话,它表明的是其自身所在的程序头表在文件或内存中的位置和大小.这样的段在文件中可以不存在,只有当所在程序头表所覆盖的段只是整个程序的一部分时,才会出现一次这种表项,而且这种表项一定出现在其它可装载段的表项之前.
#define LD_PT_GNU_STACK 0x6474e551
/* e_version and EI_VERSION */
......
......@@ -54,12 +54,12 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define INTERP_FULL_PATH "/lib/libc.so"
#define INVALID_FD (-1)
#define STRINGS_COUNT_MAX 256
#define ELF_PHDR_NUM_MAX 128
#define FILE_LENGTH_MAX 0x1000000
#define MEM_SIZE_MAX 0x1000000
#define INTERP_FULL_PATH "/lib/libc.so" //解析器路径
#define INVALID_FD (-1)//无效文件描述符,用于初始值.
#define STRINGS_COUNT_MAX 256 //argv[], envp[]最大数量
#define ELF_PHDR_NUM_MAX 128 //ELF最大段数量
#define FILE_LENGTH_MAX 0x1000000 //段占用的文件大小 最大1M
#define MEM_SIZE_MAX 0x1000000 //运行时占用进程空间内存大小最大1M
#ifndef FILE_PATH_MAX
#define FILE_PATH_MAX PATH_MAX
......@@ -68,22 +68,22 @@ extern "C" {
#define FILE_PATH_MIN 2
#endif
#define USER_STACK_SIZE 0x100000
#define USER_PARAM_BYTE_MAX 0x1000
#define USER_STACK_TOP_MAX USER_ASPACE_TOP_MAX
#define USER_STACK_SIZE 0x100000 //用户空间栈大小 1M
#define USER_PARAM_BYTE_MAX 0x1000 //4K
#define USER_STACK_TOP_MAX USER_ASPACE_TOP_MAX //用户空间栈顶位置
#define EXEC_MMAP_BASE 0x02000000
#define EXEC_MMAP_BASE 0x02000000 //可执行文件分配基地址
#ifdef LOSCFG_ASLR
#define RANDOM_MASK ((((USER_ASPACE_TOP_MAX + GB - 1) & (-GB)) >> 3) - 1)
#endif
#define STACK_ALIGN_SIZE 0x10
#define STACK_ALIGN_SIZE 0x10 //栈对齐
/* The permissions on sections in the program header. */
#define PF_R 0x4
#define PF_W 0x2
#define PF_X 0x1
/* The permissions on sections in the program header. */ //对段的操作权限
#define PF_R 0x4 //只读
#define PF_W 0x2 //只写
#define PF_X 0x1 //可执行
//ELF信息结构体,
typedef struct {
LD_ELF_EHDR elfEhdr; //ELF头信息
......@@ -93,24 +93,24 @@ typedef struct {
} ELFInfo;
//ELF加载信息
typedef struct {
ELFInfo execInfo;//可执行文件信息
ELFInfo interpInfo;
ELFInfo execInfo; //可执行文件信息
ELFInfo interpInfo;//解析器文件信息 lib/libc.so
const CHAR *fileName;//文件名称
CHAR *execName;//程序名称
INT32 argc; //参数个数
INT32 envc; //环境变量个数
CHAR *const *argv; //参数数组
CHAR *const *envp; //环境变量数组
UINTPTR stackTop;//栈
UINTPTR stackTop;//栈底位置,递减满栈下,stackTop是高地址位
UINTPTR stackTopMax;//栈最大上限
UINTPTR stackBase;//栈
UINTPTR stackParamBase;
UINT32 stackSize;
INT32 stackProt;
UINTPTR stackBase;//栈顶位置
UINTPTR stackParamBase;//栈参数空间,放置启动ELF时的外部参数,大小为 USER_PARAM_BYTE_MAX 4K
UINT32 stackSize;//栈大小
INT32 stackProt;//LD_PT_GNU_STACK栈的权限 ,例如(RW)
UINTPTR loadAddr; //加载地址
UINTPTR elfEntry; //入口地址
UINTPTR topOfMem;
UINTPTR oldFiles;
UINTPTR elfEntry; //装载点地址 即: _start 函数地址
UINTPTR topOfMem; //虚拟空间顶部位置,loadInfo->topOfMem = loadInfo->stackTopMax - sizeof(UINTPTR);
UINTPTR oldFiles; //旧空间的文件映像
LosVmSpace *newSpace;//新虚拟空间
LosVmSpace *oldSpace;//旧虚拟空间
#ifdef LOSCFG_ASLR
......
......@@ -155,14 +155,14 @@ INT32 LOS_DoExecveFile(const CHAR *fileName, CHAR * const *argv, CHAR * const *e
if (ret != LOS_OK) {
return ret;
}
//对当前进程旧虚拟空间和文件进行回收
ret = OsExecRecycleAndInit(OsCurrProcessGet(), loadInfo.fileName, loadInfo.oldSpace, loadInfo.oldFiles);
if (ret != LOS_OK) {
(VOID)LOS_VmSpaceFree(loadInfo.oldSpace);//释放虚拟空间
goto OUT;
}
ret = OsExecve(&loadInfo);//运行已加载ELF内容
ret = OsExecve(&loadInfo);//运行ELF内容
if (ret != LOS_OK) {
goto OUT;
}
......
......@@ -37,7 +37,7 @@
#include "fs_file.h"
//鸿蒙与Linux标准库的差异 https://gitee.com/openharmony/docs/blob/master/kernel/%E4%B8%8ELinux%E6%A0%87%E5%87%86%E5%BA%93%E7%9A%84%E5%B7%AE%E5%BC%82.md
//鸿蒙与Linux标准库的差异 https://weharmony.gitee.io/zh-cn/device-dev/kernel/%E4%B8%8ELinux%E6%A0%87%E5%87%86%E5%BA%93%E7%9A%84%E5%B7%AE%E5%BC%82/
/**************************************************
系统调用|申请虚拟内存(分配线性地址区间)
参数 描述
......
git add -A
git commit -m 'ELF动态加载代码注解
git commit -m 'ELF加载过程代码注解
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
国内:https://weharmony.gitee.io
国外:https://weharmony.github.io
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册