【程序员的自我修养02】初识ELF文件格式

绪论

        大家好,欢迎来到【程序员的自我修养】专栏。正如其专栏名,本专栏主要分享学习《程序员的自我修养——链接、装载与库》的知识点以及结合自己的工作经验以及思考。编译原理相关知识本身就比较有难度,我会尽自己最大的努力,争取深入浅出。若你希望与一群志同道合的朋友一起学习,也希望加入到我们的学习群中。文末有加入方式。

简介

        我们知道linux 可执行文件是ELF格式(Executable Linkable Format)。但实际上,不仅是可执行文件可重定位文件(.o目标文件和静态库)、共享目标文件(动态库)、核心转储文件(core文件)都是以ELF格式存储的。因此深入了解ELF文件就显示的十分重要。

注:静态库的实质就是多个.o文件的集合

查看文件类型

我们可以通过file命令查看文件的类型。如下:

//a.c
#include<stdio.h>
int a()
{
    printf("i'm a\n");
}
//main.c
extern int a();
int main()
{
    a();
    return 0;
}

疑问:为什么可执行程序main显示的是共享目标文件shared object?这说明了什么?

答:那是因为gcc默认开启了--enable-default-pie参数,其目的是让程序能装载在随机的地址,从而减少攻击者借用系统中的可执行代码实施攻击。类似缓冲区溢出之类的攻击将无法实现。可以在链接选项中增加-no-pie禁用该默认选项。

ELF文件应该包含哪些内容

        问题:静态全局变量和静态局部变量存储在哪里?全局变量和局部变量存储在哪里?初始化和未初始化的全局变量又分别存储在哪里?

我相信这些应该是大家面试过程中经常遇到的问题。让我们再重温一下。如下:

        由上可知,初始化的静态变量和全局变量保存在.data段;未初始化的静态变量和全局变量保存在.bss段;局部变量和代码语句保存在.text段

        总体而言,上面的源代码编译之后会分成两个部分:程序代码程序数据。其中.data和.bss都属于程序数据。不知大家是否有这样的疑问:我们写代码时,并不会区分代码和数据,都是交叉编写的。为什么ELF文件要将它们区分开来,分段存储呢

其实分段主要有三个好处,这也值得我们学习。

  • 防止程序的指令被有意或无意的改写。因为程序装载之后,我们可以将代码段和数据段映射到不同的虚拟区域A,B。由于数据的是可读可写的,那么我们可以将虚拟区域B设置为可读写权限;而代码段对于进程而言是只读的,所以虚拟区域A设置为只读权限。
  • 提高CPU的缓存命中率。现在的CPU一般会有数据缓存和指令缓存,再结合局部性原理。分段就能极大提高缓存命中率。
  • 共享内存。这个也是主要的原因,我们知道动态库被多个程序依赖时,内存中只需要有一份代码段的副本即可。若进行分段,这样对于操作系统操作起来就什么简单。若代码段和数据段交叉混合,那么管理起来就非常困难。

        难道我们的ELF文件的内容布局正如上图吗?答案肯定不是。这仅仅是其中的一部分。下一节,我们开始深入了解ELF的文件格式。

        本章节的示例代码如下:

//example.c
int global_init_var = 84;
int global_unint_var;
extern int printf(char* argv,...);
void func1(int i)
{
        printf("%d\n",i);
}
int main()
{
        static int static_var = 85;
        static int static_var2;

        int a = 1;
        int b;
        func1(static_var + static_var2 + a +b);
        return 0;
}

ELF 文件头信息

        我们不妨从”头“开始了解ELF文件信息。我们可以通过readelf -h example.o命令查看文件头,如下:

yihua@ubuntu:~/test/example$ readelf -h example.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          1104 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         13
  Section header string table index: 12

一般情况下,我们比较关注以下信息:

  • Magic:其中第五个字节标识文件类型:0x01表示32位,0x02表示64位,因为我的虚拟机自带GCC编译链是64位的,所以是0x02。第六个字节是字节序,表示该ELF文件是大端或小端,0x00无效、0x01小端格式、0x02大端格式。

注:ELF文件的大小端并不是由编译平台决定的,而是由编译和链接决定的。它与目标执行平台大小端无关,它的作用是告诉目标执行平台,本文件的代码段,数据段的存储方式,用于解析。

  • Machine: 表示文件的CPU平台属性,由上可知,X86-64。
  • Entry point address:入口地址,规定该ELF程序的入口虚拟地址,即:操作系统在加载完该程序后从这个地址开始执行进程的指令。可重定位文件一般没有入口地址,可执行文件有。如下:

由图可知:example可执行文件的入口地址在文件的偏移0x540地址。我们再通过反汇编查看这个地址是。

yihua@ubuntu:~/test/example$ objdump -d example

example:     file format elf64-x86-64


Disassembly of section .init:

00000000000004f0 <_init>:
 4f0:   48 83 ec 08             sub    $0x8,%rsp
 4f4:   48 8b 05 ed 0a 20 00    mov    0x200aed(%rip),%rax        # 200fe8 <__gmon_start__>
 4fb:   48 85 c0                test   %rax,%rax
 4fe:   74 02                   je     502 <_init+0x12>
 500:   ff d0                   callq  *%rax
 502:   48 83 c4 08             add    $0x8,%rsp
 506:   c3                      retq

Disassembly of section .plt:

0000000000000510 <.plt>:
 510:   ff 35 aa 0a 20 00       pushq  0x200aaa(%rip)        # 200fc0 <_GLOBAL_OFFSET_TABLE_+0x8>
 516:   ff 25 ac 0a 20 00       jmpq   *0x200aac(%rip)        # 200fc8 <_GLOBAL_OFFSET_TABLE_+0x10>
 51c:   0f 1f 40 00             nopl   0x0(%rax)

0000000000000520 <printf@plt>:
 520:   ff 25 aa 0a 20 00       jmpq   *0x200aaa(%rip)        # 200fd0 <printf@GLIBC_2.2.5>
 526:   68 00 00 00 00          pushq  $0x0
 52b:   e9 e0 ff ff ff          jmpq   510 <.plt>

Disassembly of section .plt.got:

0000000000000530 <__cxa_finalize@plt>:
 530:   ff 25 c2 0a 20 00       jmpq   *0x200ac2(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
 536:   66 90                   xchg   %ax,%ax

Disassembly of section .text:

0000000000000540 <_start>:
 540:   31 ed                   xor    %ebp,%ebp
 542:   49 89 d1                mov    %rdx,%r9
 545:   5e                      pop    %rsi
 546:   48 89 e2                mov    %rsp,%rdx
 549:   48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
 54d:   50                      push   %rax
 54e:   54                      push   %rsp
 54f:   4c 8d 05 ca 01 00 00    lea    0x1ca(%rip),%r8        # 720 <__libc_csu_fini>
 556:   48 8d 0d 53 01 00 00    lea    0x153(%rip),%rcx        # 6b0 <__libc_csu_init>
 55d:   48 8d 3d 0a 01 00 00    lea    0x10a(%rip),%rdi        # 66e <main>
 564:   ff 15 76 0a 20 00       callq  *0x200a76(%rip)        # 200fe0 <__libc_start_main@GLIBC_2.2.5>
 56a:   f4                      hlt
 56b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

000000000000064a <func1>:
 64a:   55                      push   %rbp
 64b:   48 89 e5                mov    %rsp,%rbp
 64e:   48 83 ec 10             sub    $0x10,%rsp
 652:   89 7d fc                mov    %edi,-0x4(%rbp)
 655:   8b 45 fc                mov    -0x4(%rbp),%eax
 658:   89 c6                   mov    %eax,%esi
 65a:   48 8d 3d d3 00 00 00    lea    0xd3(%rip),%rdi        # 734 <_IO_stdin_used+0x4>
 661:   b8 00 00 00 00          mov    $0x0,%eax
 666:   e8 b5 fe ff ff          callq  520 <printf@plt>
 66b:   90                      nop
 66c:   c9                      leaveq
 66d:   c3                      retq

000000000000066e <main>:
 66e:   55                      push   %rbp
 66f:   48 89 e5                mov    %rsp,%rbp
 672:   48 83 ec 10             sub    $0x10,%rsp
 676:   c7 45 f8 01 00 00 00    movl   $0x1,-0x8(%rbp)
 67d:   8b 15 91 09 20 00       mov    0x200991(%rip),%edx        # 201014 <static_var.1801>
 683:   8b 05 93 09 20 00       mov    0x200993(%rip),%eax        # 20101c <static_var2.1802>
 689:   01 c2                   add    %eax,%edx
 68b:   8b 45 f8                mov    -0x8(%rbp),%eax
 68e:   01 c2                   add    %eax,%edx
 690:   8b 45 fc                mov    -0x4(%rbp),%eax
 693:   01 d0                   add    %edx,%eax
 695:   89 c7                   mov    %eax,%edi
 697:   e8 ae ff ff ff          callq  64a <func1>
 69c:   b8 00 00 00 00          mov    $0x0,%eax
 6a1:   c9                      leaveq
 6a2:   c3                      retq
 6a3:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 6aa:   00 00 00
 6ad:   0f 1f 00                nopl   (%rax)

可知:程序的入口是__start函数,在正式进入我们main函数前,其实已经执行了多个函数处理

  • Start of section headers 、Size of section headers、Number of section headers:这三个参数,表示段表的内容。Start of section headers表示段表,在本文件中的偏移地址。Size of section headers表示每个段的大小。Number of section headers表示段的数量

到此,我们已经进一步了解ELF文件的格式了,大致如下:

总结

        本章介绍了linux平台下可重定位文件,动态库文件,可执行文件的存储格式都是ELF类型。之后我们尝试探究ELF文件中应该有哪些内容,通过自己的猜测应该具备.text、.data、.bss段。

        再通过readelf -h命令,又了解到ELF文件中还有file Header section table。下一章,我们再通过了解段表,更进一步了解ELF文件的内容布局。还请关注不迷路哦~~~

        有任何相关问题欢迎留言讨论,我会尽快回复。

        若您正遇到相关问题,苦于没有一群志同道合的朋友交流,探讨。也欢迎加入我们的讨论组群。可通过私聊,我拉您入群。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

卷积的理解,卷积与通道的关系

神经网络中的卷积操作卷积在图像领域的功能单通道卷积多通道卷积&#xff08;1个卷积核&#xff09;多通道卷积&#xff08;多个卷积核&#xff09;总结扩展 图像处理中的卷积核恒等&#xff08;Identity&#xff09;边缘检测&#xff08;Edge detection&#xff09;锐化&#…

SAP ABAP ALV Tree 的使用

在 SAP 业务系统中&#xff0c;大量地使用到了ALV Tree 对象&#xff0c;该对象在表格基础上对同类数据 进行归类&#xff0c;并对各分类能进行数据汇总&#xff0c;如图8-10 所示。 以航班表&#xff08;SPFLI&#xff09;为例&#xff1a; &#xff08;1&#xff09;按国家…

主流数据库类型总结

前言&#xff1a;随着互联网的高速发展&#xff0c;为了满足不同的应用场景&#xff0c;数据库的种类越来越多容易混淆&#xff0c;所以有必要在此总结一下。数据库根据数据结构可分为关系型数据库和非关系型数据库。非关系型数据库中根据应用场景又可分为键值&#xff08;Key-…

深度学习之十二(图像翻译AI算法--UNIT(Unified Neural Translation))

概念 UNIT(Unified Neural Translation)是一种用于图像翻译的 AI 模型。它是一种基于生成对抗网络(GAN)的框架,用于将图像从一个域转换到另一个域。在图像翻译中,这意味着将一个风格或内容的图像转换为另一个风格或内容的图像,而不改变图像的内容或语义。 UNIT 的核心…

微服务--06--Sentinel 限流、熔断

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.微服务保护雪崩问题服务保护方案1.1.请求限流1.2.线程隔离1.3.服务熔断 2.Sentinel2.1.介绍和安装官方网站&#xff1a;[https://sentinelguard.io/zh-cn/](https…

Windows安装EMQX(搭建MQTT服务)

1、EMQX介绍 EMQ X是云原生分布式物联网接入平台。 EMQ X (Erlang/Enterprise/Elastic MQTT Broker) 是基于 Erlang/OTP 平台开发的开源物联网 MQTT 消息服务器。 Erlang/OTP是出色的软实时 (Soft-Realtime)、低延时 (Low-Latency)、分布式 (Distributed)的语言平台。 MQTT 是…

自学MySql(一)

1.安装下载 下载网址 2、将mysql的bin目录添加到环境变量&#xff08;可选&#xff09; 3、使用一下命令测试

最新消息:滴滴 P0 事故原因,原因出来了

最新消息滴滴P0故障原因&#xff0c;是由于k8s集群升级导致的&#xff0c;后面又进行版本回退&#xff0c;由于现在大型互联网公司基本都是基于K8s进行部署的&#xff0c;如果K8s集群一出问题&#xff0c;上面运行的业务Pod和运维系统全部都得宕机&#xff0c;导致没法回滚。 …

深入理解网络阻塞 I/O:BIO

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

源码安装mysql

使用源码安装mysql&#xff0c;这里选择的版本是mysql5.7.35 ,系统是Centos7.6 官网下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 下载源码压缩包 [rootlocalhost ~]# cd /opt[rootlocalhost opt]# wget https://downloads.mysql.com/archives/get/…

一觉醒来!Keras 3.0史诗级更新,大一统深度学习三大后端框架【Tensorflow/PyTorch/Jax】

不知道大家入门上手机器学习项目是首先入坑的哪个深度学习框架&#xff0c;对于我来说&#xff0c;最先看到的听到的就是Tensorflow了&#xff0c;但是实际上手做项目开发的时候却发现了一个很重要的问题&#xff0c;不容易上手&#xff0c;基于原生的tf框架来直接开发模总是有…

ssh-keygen(centos)

A—免密登陆—>B (1)A 机器&#xff0c;通过命令”ssh-keygen -t rsa“, 生成id_rsa,id_rsa.pub authorized_keys:存放远程免密登录的公钥,主要通过这个文件记录多台机器的公钥 id_rsa : 生成的私钥文件 id_rsa.pub &#xff1a; 生成的公钥文件 know_hosts : 已知的主机公钥…

javaagent字节码增强浅尝

概述 javaagent 技术广泛应用于对代码的增强&#xff0c;比如统计方法执行时间、GC 信息打印、分布式链路跟踪等&#xff1b;实现方式包括 javassist 和 bytebuddy&#xff0c;bytebuddy 是对 javassist 的改进&#xff1b;类似于 spring 中的 AOP&#xff1b; Instrumentati…

SpringBoot application.yml配置文件写法

1&#xff0c;基本介绍 &#xff08;1&#xff09;YAML 是 JSON 的超集&#xff0c;简洁而强大&#xff0c;是一种专门用来书写配置文件的语言&#xff0c;可以替代 application.properties。 &#xff08;2&#xff09;在创建一个 SpringBoot 项目时&#xff0c;引入的 spri…

231129 刷题日报

本周值班第3天&#xff0c;今天终于收到二面电话&#xff0c;一度以为挂了。。加油卷&#xff01; 今天尊重下艾宾浩斯遗忘曲线&#xff0c;重复下前几天看的01背包&#xff0c;子集背包&#xff0c;完全背包。 416. 分割等和子集 518. 零钱兑换 II 38min做了一道新题&#…

OSI七层参考模型及其协议和各层设备

OSI网络模型是开放系统互联&#xff08;Open Systems Interconnection&#xff09;参考模型&#xff0c;它是由国际标准化组织&#xff08;ISO&#xff09;制定的。这个模型将网络系统划分为七个层次&#xff0c;OSI网络模型的七层是&#xff1a;物理层、数据链路层、网络层、传…

【网络奇遇之旅】:那年我与计算机网络的初相遇

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; 计算机网络 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 一. 前言二. 计算机网络的定义三. 计算机网络的功能3.1 资源共享3.2 通信功能3.3 其他功能 四. 计算机网络…

MyBatis教程之简介(一)

1、MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff0c; iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到Github。 iBatis一词来源于“inter…

android framework分屏“官方”黑屏bug问题发现,你会分析吗?-千里马实战作业挑战

背景 hi&#xff0c;粉丝朋友们&#xff1a; 大家都知道马哥课程以实战为特色&#xff0c;这里的实战就是最贴近公司里面开发的实战项目。这些实战主要来自哪呢&#xff1f; 1、以前在公司的工作积累&#xff0c;自己在公司做过什么&#xff0c;这部分比较好毕竟都是搞过的 2…

常见的类 nn.Conv2d,nn.BatchNorm2D,nn.AdaptiveAvgPool2d

nn.Conv2d理论部分代码部分PaddlePaddle 版torch 版分析 nn.BatchNorm2D理论部分代码部分PaddlePaddle 版Torch 版分析PaddlePaddle 版Torch 版 nn.AdaptiveAvgPool2d理论部分代码部分PaddlePaddle 版分析Torch 版 可以到适配的飞桨公开项目更好的理解&#xff1a;练习 PyTorch…