可执行文件以及其加载过程

2024-05-29 06:04

本文主要是介绍可执行文件以及其加载过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在计算机系统中,可执行文件是指包含机器代码的文件,计算机可以直接执行这些代码以运行特定的任务或程序。不同的操作系统对可执行文件有不同的定义和处理方式。本文将探讨常见操作系统中的可执行文件格式及其加载过程,特别是以ELF(Executable and Linkable Format)文件格式为例,深入了解其动态库加载过程。同时,我们还将介绍静态链接和动态链接的区别。

可执行文件简介

可执行文件是程序经过编译和链接后生成的文件,其中包含了机器指令、数据和必要的元信息,使得操作系统能够加载并执行该程序。不同操作系统使用不同的可执行文件格式:

  • Windows:使用PE(Portable Executable)格式,文件扩展名通常为.exe.dll
  • macOS:使用Mach-O(Mach Object)格式,文件扩展名通常为.app.dylib
  • Linux:使用ELF(Executable and Linkable Format)格式,文件扩展名通常为没有特定的要求,但共享库使用.so

ELF 文件格式

ELF文件格式是用于Linux和其他Unix-like操作系统的标准文件格式,适用于可执行文件、目标文件和共享库。ELF文件由多个部分组成,每个部分包含不同类型的数据,主要结构包括:

  1. ELF Header(ELF头)

    • 包含了文件类型、架构、入口点等基本信息。
    • 关键字段包括e_ident、e_type、e_machine、e_entry等。
  2. Program Header Table(程序头表)

    • 描述了文件中各个程序段的位置和属性。
    • 关键字段包括p_type、p_offset、p_vaddr、p_filesz等。
  3. Section Header Table(节头表)

    • 描述了文件中各个节的位置和属性。
    • 关键字段包括sh_name、sh_type、sh_flags、sh_addr等。
  4. Sections(节)

    • 各种类型的数据段,如代码段(.text)、数据段(.data)、只读数据段(.rodata)、未初始化数据段(.bss)。

ABI(Application Binary Interface)

ABI是定义应用程序在特定操作系统和硬件架构上运行的二进制接口的约定。它包括数据类型大小和对齐、函数调用约定、系统调用接口、二进制文件格式等。不同的操作系统和架构有各自的ABI规范,确保应用程序的二进制兼容性。

  • Windows ABI

    • 使用PE文件格式。
    • 定义了多种调用约定,如stdcall、cdecl、fastcall。
    • 使用WinAPI作为主要的系统调用接口。
    • 常用C标准库实现包括MSVCRT。
  • macOS ABI

    • 使用Mach-O文件格式。
    • 使用System V AMD64 ABI调用约定。
    • 使用POSIX标准系统调用接口,扩展了一些特有的系统调用。
    • 使用libSystem作为C标准库实现。

ELF 文件格式在 ABI 中的作用

ELF文件格式是ABI的重要组成部分,规定了二进制文件的结构,确保操作系统能够正确加载和执行应用程序。具体而言:

  • 标准文件格式:定义了可执行文件、目标文件和共享库的标准文件格式,确保二进制兼容性。
  • 程序头表和节头表:定义了二进制文件中各个段和节的布局。
  • 符号表和重定位信息:提供了符号解析和重定位的必要信息。
  • 动态链接:支持动态链接,通过动态库实现代码共享和内存节省。
  • 系统调用和C库接口:通过ELF文件描述库文件的结构,确保应用程序与操作系统接口一致。

静态链接与动态链接

在编译和链接过程中,静态链接和动态链接是两种不同的方法,用于将程序代码和库代码组合在一起。

静态链接
  • 定义:在编译时将所有使用到的库函数代码复制到最终的可执行文件中。
  • 优点
    • 运行时不需要外部库,所有代码都在一个可执行文件中。
    • 可以避免由于库版本变化导致的兼容性问题。
  • 缺点
    • 可执行文件体积较大,因为包含了所有依赖的库代码。
    • 无法在运行时更新或替换库,更新程序需要重新编译整个可执行文件。
动态链接
  • 定义:在运行时将库代码加载到内存中,并与可执行文件链接。
  • 优点
    • 可执行文件体积较小,因为库代码不包含在可执行文件中。
    • 可以在运行时更新或替换库,更新程序只需要替换库文件而不需要重新编译整个可执行文件。
    • 多个程序可以共享同一个库的实例,节省内存。
  • 缺点
    • 运行时依赖于外部库文件,缺少库文件或库版本不兼容可能导致程序无法运行。
    • 动态链接和符号解析会增加一些运行时开销。

ELF 动态库加载过程

在Linux系统中,加载共享库(.so文件)的过程涉及多个步骤,包括解析、映射、符号解析和重定位。以下是详细的加载过程:

  1. 启动程序

    • 操作系统首先加载可执行文件到内存中,读取其ELF头部信息,找到动态段(.dynamic)。
  2. 加载器(Loader)

    • 加载器读取程序头表,找到动态段信息,指示需要加载哪些共享库。
  3. 查找共享库

    • 加载器根据动态段信息查找共享库,路径包括DT_RUNPATH、LD_LIBRARY_PATH和系统默认路径。
  4. 映射共享库

    • 使用mmap将共享库的各个段映射到进程的虚拟地址空间。
  5. 解析符号

    • 加载器解析共享库中的符号,确保所有符号都能在内存中找到。
  6. 重定位(Relocation)

    • 处理重定位条目,调整代码和数据指针,使其指向正确的内存地址。
  7. 调用初始化函数

    • 调用共享库的初始化函数,完成库的初始化。

动态链接器(Dynamic Linker)

动态链接器(如ld.sold-linux.so)是负责加载和链接共享库的程序。在程序启动时,操作系统会先加载动态链接器,然后由动态链接器负责加载所有需要的共享库并进行符号解析和重定位。

示例:动态库加载过程

假设有一个可执行文件app依赖于共享库libfoo.solibbar.so,加载过程如下:

  1. 启动app

    • 操作系统加载app的ELF文件,读取其程序头表,找到动态段。
    • 动态段指示需要加载libfoo.solibbar.so
  2. 查找libfoo.solibbar.so

    • 加载器按顺序查找LD_LIBRARY_PATHDT_RUNPATH和系统默认路径,找到共享库文件。
  3. 映射共享库

    • 使用mmap将共享库的各个段映射到进程的虚拟地址空间。
  4. 解析符号

    • 动态链接器解析共享库中的符号,确保所有符号都能在内存中找到。
  5. 重定位

    • 处理重定位条目,更新内存中的地址使其指向正确的目标。
  6. 调用初始化函数

    • 调用共享库的初始化函数,完成库的初始化。

总结

可执行文件是操作系统运行程序的核心文件类型,不同操作系统有不同的可执行文件格式和加载方式。ELF文件格式是Linux和其他Unix-like操作系统的标准文件格式,通过详细的结构和动态链接支持,实现了程序的高效加载和运行。静态链接和动态链接是两种不同的链接方法,各有优缺点。了解这些技术和过程,对于系统编程和跨平台开发至关重要。

这篇关于可执行文件以及其加载过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1012848

相关文章

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

Solr 使用Facet分组过程中与分词的矛盾解决办法

对于一般查询而言  ,  分词和存储都是必要的  .  比如  CPU  类型  ”Intel  酷睿  2  双核  P7570”,  拆分成  ”Intel”,”  酷睿  ”,”P7570”  这样一些关键字并分别索引  ,  可能提供更好的搜索体验  .  但是如果将  CPU  作为 Facet  字段  ,  最好不进行分词  .  这样就造成了矛盾  ,  解决方法

Python:豆瓣电影商业数据分析-爬取全数据【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】

**爬取豆瓣电影信息,分析近年电影行业的发展情况** 本文是完整的数据分析展现,代码有完整版,包含豆瓣电影爬取的具体方式【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】   最近MBA在学习《商业数据分析》,大实训作业给了数据要进行数据分析,所以先拿豆瓣电影练练手,网络上爬取豆瓣电影TOP250较多,但对于豆瓣电影全数据的爬取教程很少,所以我自己做一版。 目

ORACLE语法-包(package)、存储过程(procedure)、游标(cursor)以及java对Result结果集的处理

陈科肇 示例: 包规范 CREATE OR REPLACE PACKAGE PACK_WMS_YX IS-- Author : CKZ-- Created : 2015/8/28 9:52:29-- Purpose : 同步数据-- Public type declarations,游标 退休订单TYPE retCursor IS REF CURSOR;-- RETURN vi_co_co

OpenStack创建虚拟机过程

OpenStack创建虚拟机过程 一、在分析OpenStack创建虚拟机的过程之前,先来梳理一下需要用用到哪些组件。 二、每一步都需要去keystone去进行验证,下图有详细的流程。 登录界面或命令行通过RESTful API向keystone获取认证信息。keystone通过用户请求认证信息,并生成auth-token返回给对应的认证请求。界面或命令行通过RESTful API

使用WebP解决网站加载速度问题,这些细节你需要了解

说到网页的图片格式,大家最常想到的可能是JPEG、PNG,毕竟这些老牌格式陪伴我们这么多年。然而,近几年,有一个格式悄悄崭露头角,那就是WebP。很多人可能听说过,但到底它好在哪?你的网站或者项目是不是也应该用WebP呢?别着急,今天咱们就来好好聊聊WebP这个图片格式的前世今生,以及它值不值得你花时间去用。 为什么会有WebP? 你有没有遇到过这样的情况?网页加载特别慢,尤其是那

Maven生命周期:深入理解构建过程

目录 1. Maven生命周期简介 2. 默认生命周期的阶段 3. 清理生命周期 4. 站点生命周期 5. Maven生命周期的灵活性 6. 结论         在Java开发中,Maven是一个不可或缺的工具,它通过自动化项目的构建、依赖管理和文档生成等任务,极大地提高了开发效率。Maven的核心之一是其构建生命周期,它定义了项目构建过程中的一系列阶段。在这篇文章中,我们将深