计算机组成原理 | 深入理解ELF格式和静态链接

news2024/11/19 9:26:37

深入解析C语言代码到机器码的过程

第二阶段
Loader
Cache
CPU
第一阶段
Compile
Assemble
Link
Load
读取指令和数据
CPU
内存
装载器
链接
汇编
编译
C代码
可执行文件
图:从C代码到机器码执行过程

从大的方面来说,可以划分为两个阶段:

  1. 第一个阶段:由编译(Compile)、汇编(Assemble)以及链接(Link)三个阶段组成,生成了一个可执行文件(Executable Program)。
  2. 第二个阶段:通过装载器(Loader)把可执行文件装载(Load)到内存中,然后CPU 从内存中读取指令和数据,来开始真正执行程序。

第一个阶段:编译、汇编和链接

  1. 编译(Compile):在这个阶段,使用C语言编译器(如GCC)将C源代码文件(.c文件)编译成汇编代码文件(.s文件)。编译器会对C代码进行词法分析、语法分析和语义分析,然后生成中间代码表示程序的逻辑结构。
  2. 汇编(Assemble):在这个阶段,使用汇编器(如GNU汇编器)将汇编代码文件(.s文件)转换为机器码指令文件(.o文件)。汇编器会将汇编代码中的每条指令翻译为对应的机器码指令。
  3. 链接(Link):在这个阶段,使用链接器(如GNU链接器)将多个机器码指令文件(.o文件)以及所需的库文件链接在一起,生成最终的可执行文件(Executable Program)。链接器会解析函数和全局变量的引用,并将它们的定义与相应的引用进行关联,创建可执行文件。

第二个阶段:装载和执行

  1. 装载(Load):在这个阶段,操作系统的装载器(Loader)负责将可执行文件加载到内存中的适当位置。装载器会分配内存空间,将可执行文件的指令、数据和其他资源复制到相应的内存地址。
  2. 执行:一旦可执行文件被成功加载到内存中,CPU从内存中读取指令和数据,并按照指令的顺序开始执行程序。CPU会根据指令进行算术运算、逻辑判断、内存访问等操作,最终实现程序的功能。

深入理解ELF格式:在Linux系统中的重要作用

什么是ELF?

  • ELF(Executable and Linkable Format,可执行与可链接格式)

  • 在Linux系统中,使用ELF来存储和组织数据

ELF的文件结构

ELF主要文件结构:

  1. .text Section:代码段或者指令段(Code Section),用来保存程序的代码和指令;
  2. .data Section:数据段(Data Section),用来保存程序里面设置好的初始化数据信息;
  3. .rel.text Secion,:重定位表(Relocation Table)。重定位表里,保留的是当前的文件里面,哪些跳转地址其实是我们不知道的。
  4. .symtab Section:符号表(Symbol Table)。符号表保留了我们所说的当前文件里面定义的函数名称和对应地址的地址簿。

img

图:ELF文件关键结构

ELF格式在编译过程中的关键作用

  1. 编译阶段(Compile):编译器生成的目标文件通常使用ELF格式来存储编译后的代码和数据。
  2. 汇编阶段(Assemble):ELF格式在这个阶段中用于存储汇编后的机器指令和数据。
  3. 链接阶段(Link):链接阶段是ELF格式的主要应用领域。在链接阶段,链接器读取多个目标文件和库文件,根据符号引用关系进行符号解析和重定位,最终生成可执行文件。ELF格式提供了段表、符号表和重定位表等结构来描述文件的各个部分和符号之间的关系,使得链接器能够准确地处理符号引用和重定位操作。
  4. 装载阶段(Load):ELF格式在这个阶段中帮助操作系统(Operation System)理解可执行文件的布局和重定位需求。

ELF运行示例

C代码

以下两个文件 add_lib.clink_example.c 协同工作,实现了一个加法功能。

// add_lib.c
int add(int a, int b)
{
    return a+b;
}
// link_example.c

#include <stdio.h>
int main()
{
    int a = 10;
    int b = 5;
    int c = add(a, b);
    printf("c = %d\n", c);
}

汇编

以下是 add_lib.clink_example.c生成的目标文件(Object File):add_lib.olink_example .o

使用gcc编译:

$ gcc -g -c add_lib.c link_example.c
$ objdump -d -M intel -S add_lib.o
$ objdump -d -M intel -S link_example.o

通过编译后我们得到的汇编代码:

# add_lib函数的汇编代码

add_lib.o:     file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <add>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   89 7d fc                mov    DWORD PTR [rbp-0x4],edi
   7:   89 75 f8                mov    DWORD PTR [rbp-0x8],esi
   a:   8b 55 fc                mov    edx,DWORD PTR [rbp-0x4]
   d:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]
  10:   01 d0                   add    eax,edx
  12:   5d                      pop    rbp
  13:   c3                      ret    
# link_example函数的汇编代码

link_example.o:     file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   48 83 ec 10             sub    rsp,0x10
   8:   c7 45 fc 0a 00 00 00    mov    DWORD PTR [rbp-0x4],0xa
   f:   c7 45 f8 05 00 00 00    mov    DWORD PTR [rbp-0x8],0x5
  16:   8b 55 f8                mov    edx,DWORD PTR [rbp-0x8]
  19:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
  1c:   89 d6                   mov    esi,edx
  1e:   89 c7                   mov    edi,eax
  20:   b8 00 00 00 00          mov    eax,0x0
  25:   e8 00 00 00 00          call   2a <main+0x2a>
  2a:   89 45 f4                mov    DWORD PTR [rbp-0xc],eax
  2d:   8b 45 f4                mov    eax,DWORD PTR [rbp-0xc]
  30:   89 c6                   mov    esi,eax
  32:   48 8d 3d 00 00 00 00    lea    rdi,[rip+0x0]        # 39 <main+0x39>
  39:   b8 00 00 00 00          mov    eax,0x0
  3e:   e8 00 00 00 00          call   43 <main+0x43>
  43:   b8 00 00 00 00          mov    eax,0x0
  48:   c9                      leave  
  49:   c3                      ret    

链接

gcc -c add_lib.s
gcc -c link_example.s

可执行代码

gcc -o executable add_lib.o link_example.o
$ ./executable
c = 15 # 运行结果为15
  • 注意:main 函数里调用 add 的跳转地址,不再是下一条指令的地址了,而是 add 函数的入口地址了

link_example:     file format elf64-x86-64
Disassembly of section .init:
...
Disassembly of section .plt:
...
Disassembly of section .plt.got:
...
Disassembly of section .text:
...

 6b0:   55                      push   rbp
 6b1:   48 89 e5                mov    rbp,rsp
 6b4:   89 7d fc                mov    DWORD PTR [rbp-0x4],edi
 6b7:   89 75 f8                mov    DWORD PTR [rbp-0x8],esi
 6ba:   8b 55 fc                mov    edx,DWORD PTR [rbp-0x4]
 6bd:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]
 6c0:   01 d0                   add    eax,edx
 6c2:   5d                      pop    rbp
 6c3:   c3                      ret    
00000000000006c4 <main>:
 6c4:   55                      push   rbp
 6c5:   48 89 e5                mov    rbp,rsp
 6c8:   48 83 ec 10             sub    rsp,0x10
 6cc:   c7 45 fc 0a 00 00 00    mov    DWORD PTR [rbp-0x4],0xa
 6d3:   c7 45 f8 05 00 00 00    mov    DWORD PTR [rbp-0x8],0x5
 6da:   8b 55 f8                mov    edx,DWORD PTR [rbp-0x8]
 6dd:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
 6e0:   89 d6                   mov    esi,edx
 6e2:   89 c7                   mov    edi,eax
 6e4:   b8 00 00 00 00          mov    eax,0x0
 6e9:   e8 c2 ff ff ff          call   6b0 <add>  # 直接在main函数中调用add函数的入口地址
 6ee:   89 45 f4                mov    DWORD PTR [rbp-0xc],eax
 6f1:   8b 45 f4                mov    eax,DWORD PTR [rbp-0xc]
 6f4:   89 c6                   mov    esi,eax
 6f6:   48 8d 3d 97 00 00 00    lea    rdi,[rip+0x97]        
 6fd:   b8 00 00 00 00          mov    eax,0x0
 702:   e8 59 fe ff ff          call   560 <printf@plt>
 707:   b8 00 00 00 00          mov    eax,0x0
 70c:   c9                      leave  
 70d:   c3                      ret    
 70e:   66 90                   xchg   ax,ax
...
Disassembly of section .fini:
...

链接器会扫描所有输入的目标文件,然后把所有符号表里的信息收集起来,构成一个全局的符号表。然后再根据重定位表,把所有不确定要跳转地址的代码,根据符号表里面存储的地址,进行一次修正。最后,把所有的目标文件的对应段进行一次合并,变成了最终的可执行代码。

img

图:可执行文件生成过程示意图

Windows OS:PE

  • Windows 的可执行文件格式是一种叫作 PE(Portable Executable Format)。
  • Linux 下的装载器只能解析 ELF 格式而不能解析 PE 格式。

如何在Window系统和Linux系统下进行格式兼容?

  • Linux 下著名的开源项目 Wine,支持兼容 PE 格式的装载器,使得我们能直接在 Linux 下运行 Windows 程序
  • Windows 里面也提供了 WSL,也就是 Windows Subsystem for Linux,可以解析和加载 ELF 格式的文件
  • 虽然存在各种工具可以实现可执行文件格式兼容,但是程序还依赖各种操作系统本身提供的动态链接库,系统调用等,仍然需要针对特定平台进行适配和测试。换句话说,格式兼容只是第一步。

参考文献

  • 徐文浩. ELF和静态链接:为什么程序无法同时在Linux和Windows下运行?极客时间. 2019

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/641401.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

whatsapp如何开发国外客户

WhatsApp可以说是目前2023年最火的社交营销方式之一&#xff0c;目前全球活跃人数大概在10亿&#xff0c;每日发送消息超过650亿条&#xff0c;语音和通话的时长超过20亿分钟&#xff0c;全球三分之一的人在用WhatsApp的&#xff0c;所有做外贸&#xff0c;WhatsApp是必不可少的…

ESXi 7.0 U3m Fujitsu (富士通) 定制版 OEM Custom Installer CD

VMware ESXi 7.0 Update 3m - 领先的裸机 Hypervisor (All OEM Customized Installer CDs) ESXi 7.0 U3m Standard (标准版) ESXi 7.0 U3m Dell (戴尔) 定制版 OEM Custom Installer CD ESXi 7.0 U3m HPE (慧与) 定制版 OEM Custom Installer CD ESXi 7.0 U3m Lenovo (联想) 定…

AIGC + RTE,一个实时互动的应用实践

一夜之间&#xff0c;区块链、元宇宙、Web3、VR等风口似乎都消散了&#xff0c;似乎只有 AI 才是C位。声网 RTC 云市场各类插件 AIGC&#xff0c;会迸发出什么样的火花呢&#xff1f; 最近&#xff0c;声网内部组织了一次黑客松&#xff0c;经过激烈的角逐&#xff0c;我们团…

【华为OD机试真题2023B卷 JAVAJS】完全二叉树非叶子部分后序遍历

华为OD2023(B卷)机试题库全覆盖,刷题指南点这里 完全二叉树非叶子部分后序遍历 知识点数组树递归 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 给定一个以顺序储存结构存储整数值的完全二叉树序列(最多1000个整数),请找出此完全二叉树的所有非叶子节点部分,…

成功邀请媒体采访的关键步骤,媒介易助你成为媒体热门

在企业品牌推广和宣传中&#xff0c;与媒体建立合作关系&#xff0c;并邀请媒体进行采访是非常重要的环节。通过媒体的报道和宣传&#xff0c;企业可以扩大品牌的曝光度&#xff0c;提升品牌形象和知名度。然而&#xff0c;成功的媒体邀约并非易事&#xff0c;需要一定的策略和…

启动QT Linux应用程序后黑屏闪烁?

启动QT Linux应用程序后黑屏闪烁&#xff1f; 提问 问 4 年&#xff0c; 3 个月 前 修改于 3 个月前 点击833次 1 我将嵌入式Linux&#xff08;imx6q&#xff09;与eglfs一起使用。 帧缓冲在启动Qt应用程序时正在绘制黑屏。 简单的应用程序是黑色的1秒下。重度施用4~5秒。 这仅…

如何关闭A770显卡的灯效

A770的灯效看起来是不错&#xff0c;但对于我这样的实用主义者来说&#xff0c;他没啥用。所以想着怎么样能把他给关了。 查了一下&#xff0c;intel光放给出的办法如下&#xff1a; 如何使用英特尔 RGB 控制器配置英特尔 Arc™ A770 显卡有限版卡上 LED 的外观和行为。 英特…

java读取文件内容

直接上代码&#xff0c;两个类&#xff1a;一个工具类&#xff0c;一个测试类 工具类代码&#xff1a; package org.example.study.util;import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils;import java.io.*; import java.nio.charset.Charset…

FMC子卡设计资料原理图:FMC210-1路1Gsps AD、1路2.5Gsps DA的FMC子卡

FMC210-1路1Gsps AD、1路2.5Gsps DA的FMC子卡 一、板卡概述 FMC-1AD2DA是我司自主研发的一款1路1G AD采集、1路2.5G DA回放的FMC子卡。板卡采用标准FMC子卡架构&#xff0c;可方便的与其他FMC板卡实现高速互联&#xff0c;可广泛用于高频模拟信号采集、雷达系统测试等场…

【ChatGPT-工具篇 2】采用预置命令进行Prompt的输入

采用预置命令向ChatGPT输入命令 案例如下&#xff1a; {"ai_tutor":{"Author":"Andy.L","name":"JavaTutor","version":"1.0","features":{"personalization":{"depth"…

最值得推荐收藏的10个PPT文件误删恢复软件

PowerPoint 是一种非常流行的软件应用程序&#xff0c;专业人士和学生广泛使用它来制作演示文稿。它是 Microsoft Office 套件的一部分&#xff0c;Microsoft Office 套件是一组在世界各地的办公室、家庭和学校中使用的生产力工具。PowerPoint 演示文稿可以包含图像、视频、图表…

【计组理论期末考试模拟题】21级计科专业计算机组成原理

【计组理论期末考试模拟题】21级计科专业计算机组成原理 一、选择题二、多选题三、填空题四、程序填空题五、编程题 一、选择题 2-1 在定点二进制运算器中&#xff0c;减法运算一般通过&#xff08;&#xff09;来实现。 A.原码运算的二进制减法器 B.补码运算的二进制加法器 C…

2023 可信数据库发展大会:近百位行业大咖将出席演讲

当前&#xff0c;全球数字经济加速发展&#xff0c;以信息技术和数据作为关键要素的数字经济成为全球新一轮科技革命和产业变革的重要引擎&#xff0c;作为数字经济的数据底座和基础软件的重要一员&#xff0c;数据库产业正经历前所未有之大变局。伴随政策规划有力指导、技术不…

短视频账号矩阵系统---技术架构文档分析

文章目录 前言一、目录及主要文件说明二、图文以及源代码示例 1.开发图录详情2.前端功能以及图文分析 三、开发目录及文件说明总结 前言 短视频账号矩阵系统源码开发&#xff0c;短视频账号矩阵系统架构包括两大核心模块&#xff1a;账号管理和内容管理。账号管理模块包括账号…

项目管理专业人员能力评价(CSPM)含金量高吗?都考什么?

2021年10月&#xff0c;中共中央、国务院发布的《国家标准化发展纲要》明确提出构建多层次从业人员培养培训体系&#xff0c;开展专业人才培养培训和国家质量基础设施综合教育。建立健全人才的职业能力评价和激励机制。由中国标准化协会&#xff08;CAS&#xff09;组织开展的项…

ESXi 7.0 U3m Dell (戴尔) 定制版 OEM Custom Installer CD

VMware ESXi 7.0 Update 3m - 领先的裸机 Hypervisor (All OEM Customized Installer CDs) ESXi 7.0 U3m Standard (标准版) ESXi 7.0 U3m Dell (戴尔) 定制版 OEM Custom Installer CD ESXi 7.0 U3m HPE (慧与) 定制版 OEM Custom Installer CD ESXi 7.0 U3m Lenovo (联想) 定…

佩戴舒适的蓝牙耳机推荐哪款?几款好用舒适度不错的蓝牙耳机推荐

​一款佩戴舒适的蓝牙耳机可以戴很长时间&#xff0c;听着音乐多满足&#xff01;但还有很多小伙伴不知道蓝牙耳机如何选购的&#xff0c;下面我来推荐几款佩戴舒适且音质表现好的蓝牙耳机给到大家&#xff0c;来看看有哪些吧。 一、南卡OE蓝牙耳机 推荐指数&#xff1a;五颗…

vue3-实战-08-管理后台-SPU模块开发

目录 1-列表页面开发 1.1-列表页面需求原型分析 1.2-接口封装和数据类型定义 1.3-组件获取数据 1.4-页面组件动态渲染数据 2-添加修改SPU 2.1-原型需求分析 2.2-接口封装和数据类型定义 2.3-请求服务器获取数据 2.4-收集表单数据提交数据 3-添加SKU 3.1-原型及需求…

C语言交换两个变量的值,不能使用第三个变量。

今天学习了一个新的方法&#xff0c;感觉有必要记录一下&#xff0c;免得自己忘记。 问题是&#xff1a;交换两个变量的值。不能使用第三个变量。 我们正常的做法是&#xff1a;比如有变量a2&#xff0c;变量b3&#xff0c;我们创建变量c&#xff0c;把a的值放到c里面&#x…

ESXi 7.0 U3m NEC (日电) 定制版 OEM Custom Installer CD

VMware ESXi 7.0 Update 3m - 领先的裸机 Hypervisor (All OEM Customized Installer CDs) ESXi 7.0 U3m Standard (标准版) ESXi 7.0 U3m Dell (戴尔) 定制版 OEM Custom Installer CD ESXi 7.0 U3m HPE (慧与) 定制版 OEM Custom Installer CD ESXi 7.0 U3m Lenovo (联想) 定…