首页 > 编程语言 >程序员的自我修养笔记——深入了解目标文件格式

程序员的自我修养笔记——深入了解目标文件格式

时间:2025-01-08 13:44:27浏览次数:1  
标签:文件 符号 ELF 目标 程序员 修养 文件格式 字符串 全局变量

  • 预处理、编译、汇编、链接
  • 预处理:展开宏定义、处理条件预编译指令、处理”#include“、删除注释、保留”#pragma“编译器指令
  • 编译:将预处理完的文件生成目标文件(.o或.obj文件),这个文件包含了编译阶段生成的汇编代码
  • 汇编:将生成的汇编文件转为机器指令、
  • 链接:多个目标文件和可能的库文件链接后得到可执行文件或者动态链接库文件。
  • 编译器将源代码转变成汇编代码的过程:

    • 词法分析:扫描器将源代码的字符序列分割成一系列记号。记号一般可以分为:关键字、标识符、字面量(数字、字符串等)、特殊符号(=、+等)
    • 语法分析:语法分析器对记号进行分析产生语法树(即表达式)
    • 语义分析:由语义分析器执行。在编译期间仅能分析静态语义,而动态语义需要在运行期才能确定。静态语义通常包括声明和类型的匹配、类型转换。
    • 中间语义生成:源代码级优先器将语法树转换成中间代码
    • 目标代码生成与优化:代码生成器将中间代码转换成目标机器代码,其过程与目标机器联系紧密。目标代码优化器将生成的目标代码进行优化

 

  • 静态链接:

处理各个模块之间相互引用的部分,使模块间能够正确的衔接。链接过程主要包括了地址和空间分配、符号决议、重定位。

    • 重定位:当编译器编译到一个本文件外的函数时,会先将该指令地址搁置,等到最后链接时由链接器对这些被搁置指令的地址进行修正,这个地址被修正的过程就叫做重定位,每个要被修正的地方则叫做重定位入口。
    • 地址和空间分配:在程序编译生成多个目标文件后,链接器需要为整个可执行程序确定一个合适的地址空间布局,并给各个目标文件中的代码段、数据段等分配相应的虚拟地址范围。
    • 符号决议:当不同的目标文件中存在对外部符号(如函数、全局变量等)的引用时,符号决议过程就是要确定这些符号的具体定义位置。比如,一个源文件中调用了另一个源文件中定义的函数,在编译为目标文件后,这个函数调用处就只是一个未确定的符号引用,符号决议阶段就要找到该函数实际定义所在的目标文件以及其在目标文件中的具体位置。
  • 可执行文件格式:

在LINUX下,可执行文件、动态链接库、静态链接库均按照ELF格式存储。

  • 目标文件:

源代码编译后但未进行链接的中间文件。其文件格式与可执行文件类似,仅有个别处结构不同。目标文件中除了编译后的机器指令代码、数据等内容还包括了链接时所需的一些信息比如符号表、调试信息、字符串等,这些信息内容以“节”或“段”的形式存储,机器指令被放在“代码段”中(“.code  或  .text”),而全局变量和局部静态变量则放在”数据段“中(" .data ")。

    • 举例说明:

       由上图可知:

      • 机器代码保存在 .text 段
      • 已经初始化的全局变量和局部变量保存在 .data 段
      • 未初始化的全局变量和局部变量保存在 .bss 段。
    • 指令和数据分开存放的好处:
      • 防止程序的指令被有意或无意地改写:当程序被装载后,数据和指令分别被映射到两个虚存区域。因为数据区域对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以这两个虚存区域的权限可以被分别设置成可读写和只读。
      • 提高缓存命中率
      • 内存共享方面:实现进程间程序共享、资源共享。
  • 目标文件结构分析:使用binutils的工具objdump来查看文件内部结构。

    • 打印目标文件基本信息:

       分析:由上述可知,除了基本的代码段、数据段和BSS段以外,还有只读数据段(.rodate)、注释信息段(.comment)、堆栈提示段(.note.GNU-stack)。

      • 列说明:
        • Size,指段的大小,通常以字节为单位。
        • VMA(Virtual Memory Address),指段在虚拟内存中的地址,是程序运行时该段所在的虚拟内存位置。
        • LMA(Load Memory Address),指段在加载到内存时的地址,大多数情况下LMA 与 VMA 是相同的,但在某些特殊情况下,如带有重定位功能的程序,它们可能会不同。LMA 主要关注的是节在物理内存或加载时的地址。
        • File off(File offset),指段在目标文件中的偏移量。
        • Align(Alignment),指段的对齐方式,通常以 2 的幂次方表示。
      • 属性说明:每个段的第二行说明了其属性,比如"CONTENTS"表示该段在文件中存在(指占有实际空间,所以BSS段无CONTENTS),"ALLOC"表示已分配内存,"LODA"表示可重定位,"READONLY"表示只读,"CODE"表示是代码段。
    • 代码段:

       分析:第一列内容为偏移量,中间四列为十六进制内容,最右边一列为.text段的ASCII码。(ASCII码中的”.“表示无法用ASCII码表示的)

    • ELF结构中常见其他段:

    • 自定义扩展段:GCC提供了一个扩展机制,使程序员可以指定变量所处的段以满足某些硬件的内存或I/O的地址布局从而实现某些特定功能。

       分析:在全局变量或函数之前加上”_attribute_((section("name")))“属性就可以把相应的变量或函数放到以”name“为段名的段中。关于自定义的段,其段名不能使用”.“作为前缀以免和系统段相混淆。

  • ELF文件重要结构:

      • ELF Header :位于 ELF 文件的开头,包含了关于 ELF 文件的基本信息,如文件类型(可执行文件、可重定位文件、共享库等)、目标机器架构(如 x86、ARM 等)、文件版本、入口点地址(对于可执行文件,指示程序开始执行的位置)、程序头表的偏移量和大小(如果存在)、节头表的偏移量和大小等。操作系统和相关工具通过读取 ELF 头来确定如何处理该文件。
        • ELF魔数:0x7F 0x45 0x4C 0x46  标识这是一个ELF格式的文件。
      • .text段:紧接在 ELF Header 之后,存放程序的可执行指令,通常被标记为只读。
      • .data段:一般在.text 段之后,包含已初始化的全局变量和静态变量,在程序加载到内存时会被一同加载到内存中,供程序在运行时使用。
      • .bss段:位于.data 段之后,存放未初始化的全局变量和静态变量。系统会在程序加载时为它们分配内存空间,并将其初始化为 0(对于数值类型)或空值(对于指针等类型)。
      • 其他节:可能包含各种其他类型的节,具体取决于程序的需求和编译器的设置,比如:.rodata (只读数据段,存放常量字符串等只读数据)、.debug (包含调试信息,如变量名、函数名、行号等,用于调试工具在调试程序时提供详细的信息)、 .comment (可能包含编译器版本、编译选项等注释信息)。
      • Section header table(节头表):在其他节之后,描述了 ELF 文件中各个节的信息,包括节的名称、类型、在文件中的偏移量、大小、虚拟内存地址、加载内存地址、对齐方式、标志等。链接器、加载器等工具通过节头表来定位和处理各个节。

        Section Header 的结构实际上是个以”Elf32_Shdr“结构体为元素的数组,数组元素的个数等于段的个数,每个”Elf32_Shdr“结构体都对应一个段,其结构体成员如下:

        •  关于段的属性取决于 sh_type(段的类型)和 sh_flags(段的标志位),如下图:

      • String Table(字符串表):
      • 与节头表等信息相关联,位置不固定。存储 ELF 文件中使用的各种字符串,如节名、符号名等。其他部分通过引用字符串表中的索引来使用这些字符串,节省空间并提高效率。
        • 字符串表在ELF文件中以段的形式保存,常见的有.strtab(字符串表)和 .shstrtab(段表字符串),它将字符串集中起来存放到一个表,用字符串在表中的偏移来引用字符串。
      • Sysbol Table(符号表):与字符串表等信息相关联,位置不固定。包含了程序中定义和引用的符号信息,如函数名、全局变量名、静态变量名等,以及它们的相关属性(如符号类型、绑定类型、可见性等)和在文件中的位置(如在哪个节中、偏移量等)。
        • 每个目标文件都会有一个符号表,每个符号都有符号值,也是它的地址。符号分类如下:
          • 全局符号:定义在本文件,可被其他目标文件引用。
          • 外部符号:在本文件中引用但不是定义在本文件中。
          • 段名:其值为该段的起始地址,有编译器产生。
          • 局部符号:只在单元内部可见。
          • 行号信息:指明目标文件指令与源代码中代码行的对应关系。
        • 符号表结构:符号表也是文件中的一个段,段名为 .symtab ,是一个 Elf32_Sym 结构的数组,这个数组的第一个元素为无效的”未定义“符号。其结构体成员如下:

          • 关于符号对应的值:在目标文件中,非 "COMMON 块" 类型的符号,其st_value 表示在段中的偏移;而 "COMMON块" 的则表示对齐属性。在可执行文件中,表示符号的虚拟地址。
          • 关于符号类型和绑定信息:低四位表示符号类型,高二十八位表示符号绑定信息。

          • 关于符号所在段:如果符号定义在本目标文件中,则表示在段表中的下标。否则如下表:

        • 特殊符号: 由链接器定义但程序员可以直接使用的符号。例如:

        • 强符号与弱符号:编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号。可以通过 ”_attribute_((weak))“ 来定义任何一个强符号为弱符号。强弱符号区分规则如下:

        • 强引用与弱引用:强引用要求符号必须是已定义的,否则会报错;而弱引用则是指,当符号未被定义时,链接器会默认其为0或是特殊值,并不进行报错。可使用 “_attribute_((weakref))” 来声明对一个外部函数的引用为弱引用。

 

标签:文件,符号,ELF,目标,程序员,修养,文件格式,字符串,全局变量
From: https://www.cnblogs.com/sejwy/p/18655923

相关文章

  • AI自动化编程:程序员的变革新篇还是失业序曲?
    在当今科技飞速发展的浪潮之下,AI自动化编程是否会将程序员推向失业的深渊,已然成为一个饱受争议却又与现实紧密交织的关键议题。接下来,不妨从多个维度深入探究这一错综复杂的问题。一、AI自动化编程的斐然优势AI编程工具宛如熠熠生辉的新星,其中GitHubCopilot、ChatGPT等......
  • AI编程工具使用-使用豆包大模型MarsCode AI编程插件结合IDEA辅助程序员编程使用实例
    1.MarsCode介绍 MarsCode是一个AI驱动的云端集成开发环境(IDE),支持作为VSCode和JetBrains等主流IDE的智能编程扩展使用。其主要功能包括代码补全、生成、优化、解释、注释生成、单元测试生成、错误修复等,并且支持云函数开发、API测试、存储和部署工具等‌。MarsCode支持多......
  • 2025年程序员转行方向推荐
    前言在人工智能(AI)迅速发展的背景下,传统编程领域的程序员改何去何从呢?2025年程序员可以转行去哪些地方呢?其实在现在AI时代对于传统的程序员来说是一个绝佳的实现职业转型、提升薪资待遇的机遇。那么对于考虑转行到大模型领域的程序员来说,有几个热门岗位是值得特别关注的。......
  • 程序员如何培养技术领导力?实现从码农向领导者的转型,解除35岁魔咒
    各位程序员!在代码世界埋头苦干时,是否憧憬过引领技术潮流、带团队冲锋?技术领导力并非天生,大多需要后天练就。从精通前沿技术到巧妙拆解难题,靠硬实力奠基;但学会倾听队友想法、精准分配任务、激励团队斗志,更是进阶“秘籍”。如何在攻坚项目里让大家拧成一股绳?怎样用技术视野规划......
  • 你还在死磕代码?醒醒吧!AI正在加速淘汰“旧式”程序员!
    最近技术圈最火的莫过于各种AI编程工具了,Devin、Cursor、Windsurf...看着它们“秀肌肉”,你是不是既感到未来已来,又隐隐有些焦虑?别慌,但也别掉以轻心。因为一个残酷的真相是:AI不会让所有程序员失业,但它一定会加速淘汰那些不懂AI、不会用AI的程序员。换句话说,未来不是“AIvs程序......
  • 你还在死磕代码?醒醒吧!AI正在加速淘汰“旧式”程序员!
    最近技术圈最火的莫过于各种AI编程工具了,Devin、Cursor、Windsurf...看着它们“秀肌肉”,你是不是既感到未来已来,又隐隐有些焦虑?别慌,但也别掉以轻心。因为一个残酷的真相是:AI不会让所有程序员失业,但它一定会加速淘汰那些不懂AI、不会用AI的程序员。换句话说,未来不是“AIvs程序......
  • 【中州养老】《重点!!》 项目学习心得图解day06(一)权限认证-项目集成SpringSecurity(黑m程
    Day06权限认证-项目集成SpringSecurity文章目录Day06权限认证-项目集成SpringSecurity一、登录功能实现二、LoginServiceImpl的login方法思路三、将用户数据存入线程中四、自定义授权管理器一、登录功能实现二、LoginServiceImpl的login方法思路功能描述用户......
  • 学习随记:word2vec的distance程序源码注释、输入输出文件格式说明
    word2vec中有5个程序,其中demo-word.sh中涉及两个:word2vec、distance。考虑到distance比较简单,所以我从这个入手,希望通过简单代码理解如何在一个高维数据空间计算距离(查找)。一维数据的查找,一般是通过二分法进行比较,找到完全相等的元素。完全相等本质是距离为0.推论,高维词向量......
  • 2025年程序员的副业机会:探索AI独立开发之路
    机会随着2025年的到来,我们迎来了一个前所未有的机遇——通过AI编程实现个人发展的飞跃。在硅谷著名投资人纳瓦尔的《纳瓦尔宝典》中,他强调了代码杠杆与媒体杠杆的重要性,指出这两者是普通人无需原始积累即可掌握的重要工具。如今,AI技术的普及让这一梦想触手可及,为追求时间自......
  • 程序员转型之路:探索代码外的精彩人生
    程序员职业生涯中,有许多机会从纯技术岗位转向其他领域,拓展职业发展边界。从技术管理、产品经理等传统方向,到跨界探索更广阔的领域,不同路径需要不同的技能与素质。本文将从以下三个方面探讨程序员的转型之路:可转型的领域或岗位,不同转型方向的核心技能与素质,以及如何充分利用......