linux中ELF加载过程分析

2025秋招LLM大模型多模态面试题(八)- langchain完整面试题 1. **什么是 LangChain** 2. **LangChain 包含哪些核心模块** - 模型输入/输出(Model I/O) - 组件管理 - 数据处理 - 链式组合 - 记忆与上下文管理 - 外部集成 3. **一些核心概念** 4. **什么是 LangChain Agent?** 5. **什么是 LangChain model?** 6. **LangChain 包含哪些特点?** 7. **LangChain 如何使用?** - LangChai 阅读详情

 

sys_execve
   | - do_execve
|
| - search_binary_handler          
           |- linux_binfmt= elf_format
       |- elf_format-> load_elf_binary
| - elf_entry = load_elf_interp()
          |-   
| if  (BAD_ADDR(elf_entry))
                |     force_sig(SIGSEGV, current);
|      retval =-EINVAL;
 
  
binfmt_elf.c: line 1024
              elf_entry = loc->elf_ex.e_entry;
              if (BAD_ADDR(elf_entry)) {
                     force_sig(SIGSEGV, current);
                     retval = -EINVAL;
                     goto out_free_dentry;
              }
 
ELF可行档的载入:
 
内核中实际执行 execv() 或 execve() 系统调用的程序是 do_execve() ,这个函数先打开目标映像文件,并从目标文件的头部 ( 从第一个字节开始 ) 读入若干 (128) 字节,然后调用另一个函数 search_binary_handler() ,在那里面让各种可执行程序的处理程序前来认领和处理。内核所支持的每种可执行程序都有个 struct linux_binfmt 数据结构,通过向内核登记挂入一个队列。而 search_binary_handler() ,则扫描这个队列,让各个数据结构所提供的处理程序、即各种映像格式、逐一前来认领。如果某个格式的处理程序发现特征相符而,便执行该格式映像的装入和启动。
我们从 ELF 格式映像的 linux_binfmt 数据结构开始:
CODE:
#define load_elf_binary load_elf32_binary

static struct linux_binfmt elf_format = {
.module = THIS_MODULE,
.load_binary = load_elf_binary,
.load_shlib = load_elf_library,
.core_dump = elf_core_dump,
.min_coredump = ELF_EXEC_PAGESIZE
};
 
ELF 格式的二进制映像的认领、装入和启动是由 load_elf_binary() 完成的。而 “ 共享库 ” 、即动态连接库映像的装入则由 load_elf_library() 完成。实际上共享库的映像也是二进制的,但是一般说 “ 二进制 ” 映像是指带有 main() 函数的、可以独立运行并构成一个进程主体的可执行程序的二进制映像。
 
CODE:
[sys_execve() > do_execve() > search_binary_handler() > load_elf_binary()]

整个 ELF 映像就是由文件头、区段头表、程序头表、一定数量的区段、以及一定数量的部构成
而 ELF 映像的装入 / 启动过程,则就是在各种头部信息的指引下将某些部或区段装入一个进程的用户空间,并为其运行做好准备 ( 例如装入所需的共享库 ) ,最后 ( 在目标进程首次受调度运行时 ) 让 CPU 进入其程序入口的过程。
 
接着是对 elf_bss 、 elf_brk 、 start_code 、 end_code 等等变量的初始化。这些变量分别纪录着当前 ( 到此刻为止 ) 目标映像的 bss 段、代码段、数据段、以及动态分配 “ 堆 ” 在用户空间的位置。除 start_code 的初始值为 0xffffffff 外,其余均为 0 。随着映像内容的装入,这些变量也会逐步得到调整,读者不妨自己留意这些变量在整个过程中的变化。
读入了程序头表,并对 start_code 等变量进行初始化以后,下面的第一步就是在程序头表中寻找 “ 解释器 ” 部、并加以处理的过程。
 
ELF 格式的二进制映像在装入和启动的过程中需要得到一个工具软件的协助,其主要的目的在于为目标映像建立起跟共享库的动态连接。这个工具称为 “ 解释器 ” 。一个 ELF 映像在装入时需要用什么解释器是在编译 / 连接是就决定好了的,这信息就保存在映像的 “ 解释器 ” 部中。 “ 解释器 ” 部的类型为 PT_INTERP ,找到后就根据其位置 p_offset 和大小 p_filesz 把整个 “ 解释器 ” 部读入缓冲区。整个 “ 解释器 ” 部实际上只是一个字符串,即解释器的文件名,例如 “/lib/ld-linux.so.2” 。有了解释器的文件名以后,就通过 open_exec() 打开这个文件,再通过 kernel_read() 读入其开头 128 个字节,这就是映像的头部。早期的解释器映像是 a.out 格式的,现在已经都是 ELF 格式的了, /lib/ld-linux.so.2 就是个 ELF 映像。
 
 
程序段的载入:
还是从目标映像的程序头表中搜索,这一次是寻找类型为 PT_LOAD 的部 (Segment) 。在二进制映像中,只有类型为 PT_LOAD 的部才是需要装入的。
找到一个 PT_LOAD 片以后,先要确定其装入地址。正如代码前面的注释所述,这里先假定装入地址是固定的,然后再根据映像是否允许浮动而作出调整。具体片头数据结构中的 p_vaddr 提供了映像在连接时确定的装入地址 vaddr 。如果映像的类型为 ET_EXEC , ( 或者 load_addr_set 已经被设置成 1 ,见下 ) 那么装入地址就是固定的。而若类型为 ET_DYN 、即共享库,那么即使装入地址固定也要加上一个偏移量,代码中给出了计算方法,其中 ELF_ET_DYN_BASE 对于 x86 定义为 (TASK_SIZE / 3 * 2) ,所以这是 2GB 边界,而 ELF_PAGESTART 表示按页面边界对齐。
确定了装入地址以后,就通过 elf_map() 、实际上是 elf32_map() 、建立用户空间虚存区间与目标映像文件中某个连续区间之间的映射。这个函数基本上就是 do_mmap() ,其返回值就是实际映射的 ( 起始 ) 地址。对于类型为 ET_EXEC 的可执行程序映像而言,代码中的 load_bias 是 0 ,所以装入的起点就是映像自己提供的地址 vaddr 。另一方面,对于 ET_EXEC ,由于参数中的 elf_flags 中的 MAP_FIXED 标志位为 1 ,所以给定的映射地址是刚性的而不容许变通,如果与已经映射的区间有冲突就以失败告终。不过,目标映像的映射是从一片空白开始的,所以实际上不可能失败。顺便提一下,现在又多了一种 ELF 格式的目标映像,称为 FDPIC ,其装入地址就是可浮动的。
即使总的装入地址是浮动的,一旦装入了第一个 Segment 以后,下一个 Segment 的装入地址就应该是固定的了,所以这里一方面把 load_addr_set 设置成 1 ,
 
 
 
[sys_execve() > do_execve() > search_binary_handler() > load_elf_binary()]

if (elf_interpreter) {
if (interpreter_type == INTERPRETER_AOUT)
elf_entry = load_aout_interp(&loc->interp_ex, interpreter);
else
elf_entry = load_elf_interp(&loc->interp_elf_ex, interpreter, &interp_load_addr);
. . . . . .
reloc_func_desc = interp_load_addr;

allow_write_access(interpreter);
fput(interpreter);
kfree(elf_interpreter);
} else {
elf_entry = loc->elf_ex.e_entry;
}

这段程序的逻辑很简单:如果需要装入解释器,并且解释器的映像是 ELF 格式的,就通过 load_elf_interp() 装入其映像,并把将来进入用户空间时的入口地址设置成 load_elf_interp() 的返回值,那显然是解释器的程序入口。 而若不装入解释器,那么这个地址就是目标映像本身的程序入口。
显然,关键的操作是由 load_elf_interp() 完成的,所以我们追下去看 load_elf_interp() 的代码。
 
do_brk() 从用户空间分配一段空间。这段代码总体上与前面映射目标映像的那一段相似。注意解释器映像的类型一般都是 ET_DYN ,所以 load_addr 可能不等于 0 。
 
 
进程可使用 exec 系统调用执行新的命令。 exec 系统调用将一次性释放全部虚拟内存空间,之后生成新的空间并将新的命令影射入内。

   
do_execve (文件路径,参数。环境)
       
打开文件( open_namei 函数)
       
计算 exec 后的 UID/GID ,读入文件头( prepare_binprm 函数)
       
读入命令名,环境变量,起动参数( copy_strings 函数)
       
呼叫各种不同二进制文件的操作函数( search_binary_handler 函数)

    ELF
格式的话,经由 search_binary_handler 函数呼叫 load_elf_binary 函数。如果是动态联结,同时影射动态联结器( ld*.so )

    load_elf_binary(linux_binprm* bprm,pt_regs* regs)
       
分析 ELF 文件头
       
读入程序的头部分( kernel_read 函数)
        if
(存在解释器头部) {
               
读入解释器名( ld*.so ) (kernel_read 函数 )  | ( zalem note :可用
               
打开解释器文件( open_exec 函数)                 | objdump -s -j .interp xxx
            
读入解释器文件的头部( kernel_read 函数)    | 命令查看,
       
)                                                           |linux 下是 /lib/ld-linux.so.x )
       
释放空间,清楚信号,关闭指定了 close-on-exec 标识的文件( flush_old_exec 函数)
       
生成堆栈空间,塞入环境变量 / 参数部分( setup_arg_pages 函数)
        for
(可引导的所有的程序头) {
               
将文件影射入内存空间( elf_map,do_mmap 函数)
        }
        if
(为动态联结) {
               
影射动态联结器( load_elf_interp 函数)
        }
       
释放文件( sys_close 函数)
       
确定执行中的 UID , GID ( compute_creds 函数)
       
生成 bss 领域( set_brk 函数)
        bss
领域清零( padzero 函数)
       
设定从 exec 返回时的 IP , SP ( start_thread 函数)(动态联结时的 IP 指向解释器的入口)
【kafka】控制台默认不能发送大数据 4096 4095 4129 1.概述 因为某些原因,需要做一个测试,然后我想往topic中,发送一条消息,然后再消费它。但是消息有点大,一条消息是36K. 消费者 [root@1 kafka]# bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic xxx.devicealarm | grep 网络攻击 生产者,生产者发送了一个消息消息是一个json,json中有这个数据特征 网络攻击 [root@1 kafka]# bin/kafka-console-p 阅读详情

相关推荐

CISSP背书三次失败后的终极解决方案

本文分享了作者CISSP认证三次线上背书审核失败的经历与终极解决方案。针对(ISC)²官方审核的严格性,文章详细剖析了使用公积金证明、工作证明盖章签字等常见材料的误区,并最终提出了通过构建“官方邮件往来”证据链的核心策略,以动态、可验证的方式成功通过审核,为后来者提供了详实的避坑指南和实操清单。

weixin_29219539的博客 153

ELF文件加载与动态链接(一)

关于ELF文件的详细介绍,推荐阅读:ELF文件格式分析 —— 滕启明。ELF文件由ELF头部、程序头部表、节区头部表以及节区4部分组成。 通过objdump工具和readelf工具,可以观察ELF文件详细信息。 ELF文件加载过程分析 从编译、链接和运行的角度,应用程序和库程序的链接有两种方式。一种是静态链接,库程序的二进制代码链接进应用程序的映像中;一种是动态链接,库函数的...

weixin_30239339的博客 419

一张图看懂中国民航适航审定体系:从适航司到审定中心,到底谁管谁?

本文深入解析中国民航适航审定体系,从立法层到执行层的完整链条,揭示适航管理的金字塔结构和核心流程。涵盖适航司、审定中心等关键机构职能,以及型号审定、生产许可审定等全生命周期管理,展现中国适航体系的特色实践与创新探索。

weixin_30896511的博客 476

ELF在Linux下的加载过程

主要函数调用: sys_execve    | - do_execve | | - search_binary_handler                    |- linux_binfmt= elf_format        |- elf_format-> load_elf_binary | - elf_entry = load_elf_interp()

joker0910的专栏 7849

ByteTrack参数调优全攻略:从原理到实战(含YOLOv8示例)

本文深入解析了ByteTrack多目标跟踪算法的核心原理与参数调优策略。通过拆解其独特的两阶段关联机制,并结合YOLOv8检测器,提供了针对不同应用场景(如拥挤行人、高速车辆)的精细化参数调整指南与实战示例,旨在帮助开发者解决ID切换、目标丢失等工程落地难题,提升跟踪系统的鲁棒性与实用性。

cheese的博客 322

史上最全的Logisim运算器实验教程(基于华中科技大学计算机组成原理实验)

本博客是实现了Logisim的运算器设计,有具体的运算器设计的思路和运算器设计的电路,适合一步一步的按照思路做。

qq_62325622的博客 4万+

Linux加载启动可执行程序的过程(一)内核空间加载ELF的过程

linux内核启动时将ELF格式注册到内核可支持的文件格式链表中,也就是通过register_binfmt 函数将定义的elf_format结构体添加到链表中。该结构体如下: 当我们执行一个可执行程序的时候, 内核会list_for_each_entry遍历所有注册的linux_binfmt对象, 对其调用load_binrary方法来尝试加载, 直到加载成功为止。上面代码可以看倒,E...

lionzl的专栏 1442

171、运动控制中的标定:摩擦力与死区补偿标定

摘要(149字) 运动控制系统中的摩擦力与死区补偿是提升精度的关键。摩擦力分为静摩擦、库仑摩擦和粘滞摩擦,其中Stribeck效应是低速抖动的主因;死区则表现为控制信号的无效区间。有效标定方法包括恒速测试(摩擦力)和斜坡响应法(死区)。补偿策略需采用分段前馈和动态调整,避免过度补偿导致振荡。实践中要注意机械状态检查、补偿量限幅,并定期重新标定。硬件升级配合算法补偿才能实现最优控制,标定工作应优先于PID参数调整。

m0_50546716的博客 229

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

日期 内核版本 架构 作者 GitHub 优快云 2016-06-04 Linux-4.6 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的描述 加载和动态链接从编译/链接和运行的角度看,应用程序和库程序的连接有两种方式。 一种是固定的、静态的连接,就是把需要用到的库函数的目标代码(二进制)代

OSKernelLAB(gatieme) 3万+

【系统架构设计师】论文模板样例:论软件系统架构风格

本人于年月参与项目,该系统为*,在该项目组中我担任系统架构师岗位,主要负责系统整体架构设计。本文以该车联网项目为例,主要讨论了软件架构风格在该项目中的具体应用。底层架构风格我们采用了虚拟机风格中的解释器,因该公交共有几十种不同的数据协议,使用解释器风格可以满足整车数据协议兼容性需求;中间层关于应用层的数据流转采用了独立构件风格中的隐式调用,以减低系统间耦合度、简化软件架构,提高可修改性方面的架构属性;应用系统层采用了B/S的架构风格,统一解决公交行业性难题“实施推广难、维护难”问题。

数据知道的博客 9927

pip install mysql出现error: subprocess - exited-with-error的解决方案

本文主要介绍了pip install mysql出现error: subprocess - exited-with-error的解决方案,希望能对使用mysql的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 5万+

linux内存布局和地址空间布局随机化(ASLR)下的可分配地址空间

https://zsummer.github.io/2019/11/04/2019-11-04-aslr/ 地址空间布局随机化(ASLR) 《mmap的随机化》 《Meltdown(熔断漏洞)- Reading Kernel Memory from User Space/KASLR | 原文+中文翻译》 导语 64位下的linux地址空间虽然看起来虽然庞大2^64 但是实际上进行内核与用户空间的划分后, 包括ASLR以及PIE等机制的启用, 实际留给mmap和brk的可分配区域远远小于这个值, 大

RToax 3073

压缩包密码破解工具ZIP Cracker2.0.1.2 正式版

一款多功能文件密码破解工具,支持ZIP、RAR、Office等主流加密格式,提供CPU/GPU双模式破解。该软件采用黑客风格界面,具备环境自检修复功能,支持实时监控硬件使用率。内置hashcat等专业破解工具,通过拖拽文件即可快速破解,GPU模式速度可达CPU的10-100倍。最新版本优化了中文路径支持,并提升了启动速度。

bfq05234214的博客 482

Linux elf文件的加载过程分析

前言 在linux shell命令行启动一个程序时,实际上新启动的进程是作为shell进程的子进程存在的。shell进程会先fork出一个子进程,此时子进程是父进程的一个拷贝,所以其代码段和数据段都来自于父进程,但是子进程是要执行新的程序的,所以会调用execv函数,载入新的程序,此过程中,子进程的代码段,数据段等都会替换成新的进程的。 本文主要是对elf文件的加载过程做一个简要的分析。 lin...

liuhangtiant的博客 2053

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

linux 解析elf文件格式,Linux elf文件的加载过程分析-Go语言中文社区

前言在linux shell命令行启动一个程序时,实际上新启动的进程是作为shell进程的子进程存在的。shell进程会先fork出一个子进程,此时子进程是父进程的一个拷贝,所以其代码段和数据段都来自于父进程,但是子进程是要执行新的程序的,所以会调用execv函数,载入新的程序,此过程中,子进程的代码段,数据段等都会替换成新的进程的。本文主要是对elf文件的加载过程做一个简要的分析。linux只支...

weixin_31574891的博客 526

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

linux中ELF加载过程分析 - 博青港湾-技术空间 - 优快云Blog

导读: sys_execve   | - do_execve|| - search_binary_handler                     |- linux_binfmt= elf_format       |- elf_format-> load_elf_binary| - elf_entry = load_elf_interp()          |- 

xu的blog 2835

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

ELF文件的加载和动态链接过程

近段时间在研究Erlang核心特性的实现,也许过段时间会有个系列的总结,期待... 今天看到有人写一个深入Hello World的文章,想起来读研的时候做的一个关于程序加载和链接的课程设计,也是以Hello World为例说明的,随发出来共享。文后有下载链接。 ====================================================== 本文...

一墨的博客 1357

Linux下ELF文件格式

(in English for practice^_^)In this article,I will talk about the ELF files for Linux,and their diffs as to comprehend the linking process in a diff view angle.There are many articles talking about tha

feilengcui008的专栏 928
上一篇: RISC/DSP融合可满足VoIP产品的功耗、成本和性能目标
下一篇: 软交换与NGN
suacker
博客等级 码龄24年 46粉丝 19原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值