Linux(链接器的意义)

news2025/6/18 2:01:06

文章目录

  • 前言
  • 一、链接器概念介绍
  • 二、目标文件
  • 三、main函数是第一个被执行的函数吗?
  • 四、链接脚本的意义和作用
  • 总结


前言

本篇文章我们来讲解链接器的意义。

一、链接器概念介绍

链接器(Linker)是计算机编译器系统中的一个重要组成部分,它用于将编译后生成的目标模块(Object Module)链接在一起,生成可执行文件或动态链接库(Dynamic Linking Library)。

链接器的主要任务是将符号(Symbol)引用解析到符号定义上,将多个目标模块合并为一个可执行文件或动态链接库,生成符号表(Symbol Table),并对程序代码做最后的检查和优化。

在编译过程中,C、C++等程序源代码先经过编译器的处理,生成目标代码文件,然后由链接器将多个目标代码合并成单个可执行文件或动态链接库,以便于程序执行和使用。

二、目标文件

首先我们先编写两个文件一个是main.c一个是func.c。

main.c:

extern void func(void);

int g_a = 0;

int main(void)
{
    func();

    return 0;
}

func.c:

#include <stdio.h>


void func(void)
{
    printf("Hello World\n");
}


将这两个文件编译成目标文件.o

使用nm命令查看两个目标文件的信息:
在这里插入图片描述
在这里插入图片描述

通过nm命令我们可以发现这两个目标文件里面的各个段都是没有具体地址的。但是我们可以查看到具体的段大小。

目录文件需要注意的地方:
1.各个段没有具体的起始地址,只有段大小信息。
2.各个标识符没有实际地址,只有段中的相对地址。
3.段和标识符的实际地址需要链接器具体确定。

链接器的几个主要作用:

符号解析:将目标文件中的符号引用和定义进行匹配,并生成符号表信息,方便程序执行时进行符号地址绑定。

文件合并:将多个目标文件合并为单个可执行文件或动态链接库。

地址空间分配:将符号或变量分配到内存中的具体地址。

重定位:合并多个目标模块时,需要对地址进行重定位,以便在程序的正确地址空间中运行。

跳转补丁:对目标代码进行修补,以确保跳转地址的正确性和有效性。

使用链接器将他们链接起来:
在这里插入图片描述
链接完成后我们就可以查看到具体的段地址等信息了。

三、main函数是第一个被执行的函数吗?

在我们编写代码的时候第一个执行的函数就是main函数,那么很多人就可能会认为第一个执行的程序就是main函数,其实这是不正确的。下面我就来证明一下main函数不是第一个被执行的程序。

首先使用objdump -d 命令来生成一个汇编文件:
在这里插入图片描述
使用cat 命令来查看这个文件:

在_start这里我们可以查看到main函数:
这里也可以看到_start函数的地址:0000000000000530
在这里插入图片描述
使用objdump - h命令显示文件的段表,包括段的名称、大小、虚拟地址、文件偏移等信息。
这里可以看到text段和_start的段地址是一样的。所以我们可以证明执行代码的时候首先执行的是_start函数,而不是main函数。
在这里插入图片描述

我们查看_start里面的信息就可以知道程序开始时到底做了什么操作:
在这里插入图片描述
在这里插入图片描述

四、链接脚本的意义和作用

链接脚本(Linker Script)是用于指导链接器如何将目标文件链接生成最终的可执行文件或者动态链接库的脚本。链接脚本描述了代码的内存分配、数据的布局、初始化、以及其他一些链接时需要的信息。

链接脚本通常使用一种简单的编程语言,例如 GNU Linker 的链接脚本是使用类似 C 的语言写成的脚本。通常它包含了以下信息:

地址空间布局:链接脚本可以指定代码段、数据段、BSS段等在内存中的位置和大小,并决定它们的起始地址和结束地址。

符号表:链接脚本可以定义符号表,这些符号可以是全局变量、函数、常量等,它们将在链接过程中被绑定。

初始化和清除:链接器会按照链接脚本指定的顺序对段进行初始化,清除,或者进行其他的一些工作。

程序入口:链接脚本中可以指定程序入口,例如 main() 函数所在的地址。

链接脚本的主要作用是描述生成可执行文件或者动态链接库所需的各种相关信息,同时还可以完成其他一些链接时的必要处理,并附加一些必要的元数据,例如程序入口点和动态链接库函数符号等。通过使用链接脚本,程序员可以更加精细地控制生成的可执行文件或者动态链接库的各种属性,同时也可以有效地解决某些链接时需要的问题。

下面我们来编写一个链接脚本:

ENTRY(main)     /* 设置程序入口为 main 函数 */
SECTIONS {
    . = 0x08000000;  /* 指定起始地址 */

    /* 定义代码段,包含 .text 和 .rodata 段 */
    .text   ALIGN(4) :
    {
        *(.text)        /* 提取目标文件中的所有代码段 */
        *(.rodata)      /* 提取目标文件中的只读数据段 */
    } >FLASH

    /* 定义数据段,包含 .data 和 .bss 段 */
    .data   ALIGN(4) :
    {
        *(.data)        /* 提取目标文件中的所有数据段 */
    } >SRAM

    /* 定义bss段 */
    .bss (NOLOAD) :
    {
        _sbss = .;      /* 设置 bss 段的起始地址 */
        *(.bss)         /* 提取目标文件中的 bss 数据段 */
        *(COMMON)       /* 提取目标文件中的 common 数据段 */
        _ebss = .;      /* 设置 bss 段的结束地址 */
    } >SRAM

    /* 设置栈和堆 */
    _stack_end = ORIGIN(SRAM) + LENGTH(SRAM);  /* 设置栈的结束地址 */
    _heap_start = _stack_end;      /* 设置堆的起始地址 */
    _heap_end = ORIGIN(SRAM) + LENGTH(SRAM);    /* 设置堆的结束地址 */
}

此链接脚本是用于将代码段和只读数据段从FLASH存储器分配到0x08000000和数据段和BSS段从SRAM存储器分配到0x20000000。它还定义了堆和栈的位置,以及一些变量。

该脚本首先定义程序入口为 main 函数,然后使用 SECTIONS 区块来定义不同段的位置和大小。代码段和只读数据段使用 ALIGN 对齐到4字节,并通过 >FLASH 分配到 FLASH 存储器中。数据段使用 ALIGN 对齐到4字节,并通过 >SRAM 分配到 SRAM 存储器中。BSS段没有实际数据,仅分配段空间,通过 NOLOAD 让链接器不会从可执行文件中复制数据到RAM中从而节省存储空间,使用 _sbss 和 _ebss 定义BSS段起始和结束地址。最后,通过自定义变量来设置栈和堆的位置。

总结

本篇文章就讲解到这里了,希望大家好好掌握这些知识点。

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

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

相关文章

MongoDB安装、设置密码、操作命令、配置文件说明、备份与还原

目录 一、mongodb概述 二、mongodb安装部署 三、mongodb设置密码 四、MongoDB操作命令与说明 五、配置文件说明 六、备份与还原 一、mongodb概述 MongoDB是一个非关系型数据库管理系统&#xff0c;它使用文档模型存储数据。MongoDB中的文档类似于JSON对象&#xff0c;可以…

总结899

目标规划&#xff1a; 月目标&#xff1a;6月&#xff08;线性代数强化9讲&#xff0c;背诵15篇短文&#xff0c;考研核心词过三遍&#xff09; 周目标&#xff1a;线性代数强化3讲&#xff0c;英语背3篇文章并回诵&#xff0c;检测 今日已做&#xff1a; 1.读了两篇文章&a…

Spring:InvalidDefinitionException: Direct self-reference leading to cycle

一、现象 一个列表接口报错&#xff0c;没有返回信息&#xff0c;异常堆栈如下&#xff1a; 11:52:05.096 [http-nio-8180-exec-36] ERROR c.u.s.f.w.e.GlobalExceptionHandler - [handleRuntimeException,65] - 请求地址XXXXX,发生未知异常. org.springframework.http.conve…

(el-Tree)操作:Element-plus 中Tree 树形控件的样式等的使用

Ⅰ、Element-plus 提供的Tree树形控件组件与想要目标情况的对比&#xff1a; 1、Element-plus 提供Tree组件情况&#xff1a; 其一、Element-ui 自提供的Table代码情况为(示例的代码)&#xff1a; // Element-plus 自提供的代码&#xff1a; // 此时是使用了 ts 语言环境&…

06-揭开神秘面纱:Golang method的魅力解析

&#x1f4c3;个人主页&#xff1a;个人主页 &#x1f525;系列专栏&#xff1a;Golang基础 &#x1f4ac;Go&#xff08;又称Golang&#xff09;是由Google开发的开源编程语言。它结合了静态类型的安全性和动态语言的灵活性&#xff0c;拥有高效的并发编程能力和简洁的语法。G…

宝鸡陇县中学弱电系统集成设计方案_kaic

摘 要 随着世界各国教育信息化的推进&#xff0c;我国在教育信息基础设施和资源上也在逐步加快步伐。校园信息化平台的建设关系到校园网站的技术实现、广播系统、视频监控系统的建设&#xff0c;能够使知识获取更便捷、校园文化生活更丰富、校园管理更精准。利用信息交互的特性…

chatgpt赋能python:Python如何排列输出列表的数

Python如何排列输出列表的数 Python是一门广泛应用于数据分析、科学计算等领域的编程语言&#xff0c;其简洁易学、强大的编程特性使得其成为很多领域中的首选语言。在Python中&#xff0c;列表是一种非常常见的数据结构&#xff0c;其可以存储大量相关数据&#xff0c;并且通…

【八大排序(五)】快排进阶篇-挖坑法+前后指针法

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:八大排序专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习排序知识   &#x1f51d;&#x1f51d; 快排进阶篇 1. 前情回顾2. 思路回顾3. 单…

chatgpt赋能python:Python排列组合:让编程更简单

Python排列组合&#xff1a;让编程更简单 Python是一种现代化的编程语言&#xff0c;同时也是一种强大的工具。在Python中&#xff0c;排列组合是极其重要的一种操作。在本篇文章中&#xff0c;我们将介绍Python中的排列组合&#xff0c;并探讨如何利用Python编程语言进行排列…

十.多线程

1、进程与线程 &#xff08;1&#xff09;操作系统与进程 1.程序&#xff1a;代码。 2.进程&#xff1a;程序的动态执行过程。 &#xff08;2&#xff09;进程与线程 线程&#xff1a;线程&#xff1a;是比进程更小的执行单位&#xff0c;一个进程在其执行过程中&#xff0…

chatgpt赋能python:Python中如何找到编程中的错误

Python中如何找到编程中的错误 Python是一种旨在提高开发者生产力的高级编程语言。由于其简洁性和可读性&#xff0c;它越来越成为开发者们的首选语言。然而&#xff0c;就像其他编程语言一样&#xff0c;Python编程中难免会有错误。本文将介绍一些有用的技巧和工具&#xff0…

STM32速成笔记—概述

文章目录 前言一、专栏简介二、前期准备三、编程规范以及程序架构简介1. 编程规范2. 程序架构 四、STM32F103ZET6简介 前言 本人技术菜鸟一枚&#xff0c;2022年大学毕业&#xff0c;大学加入老师实验室&#xff0c;参加过一些嵌入式相关的比赛&#xff0c;获得过2020年TI杯大学…

【利用AI让知识体系化】简要了解网络七层协议

文章目录 一、前言引言目的和意义 二、网络七层协议简介OSI参考模型七层协议分层结构和各层协议简介 三、物理层 - Layer 1物理层概述物理层的作用物理层标准和协议 四、数据链路层 - Layer 2数据链路层概述常见的协议 五、网络层 - Layer 3网络层概述网络层的作用IP地址的作用…

Nuxt.js:用 Vue.js 打造服务端渲染应用程序

文章目录 I. 简介Nuxt.js是什么Nuxt.js的历史和发展Nuxt.js的特点和优势1. 服务端渲染2. 自动生成路由3. 静态文件服务4. 异步数据加载5. 基于Webpack的构建系统6. 支持模块化的Vue组件7. 可定制的ESLint与StyleLint8. 支持PWA等高级功能 II. Nuxt.js基础Nuxt.js的安装和配置Nu…

ACL2023 | WebCPM:清华发布中文LFQA 数据集,探索搜索引擎和PLM大模型结合新范式

一、概述 title&#xff1a;WEBCPM: Interactive Web Search for Chinese Long-form Question Answering 论文地址&#xff1a;https://arxiv.org/abs/2305.06849 代码&#xff1a;https://github.com/thunlp/WebCPM 1.1 Motivation 开发一个类似于WebGPT一样的中文版本的…

如何保证数据库分布式事务的强一致性

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 针对分布式数据库&#xff0c;如何保证分布式事务的强一致性&#xff0c;是分布式数据库的关键。分布式事务的强一致性方案这里介绍两种&#xff0c;一种是GTM(global transaction manager),另一种是基于XA协议的两阶…

12道前端知识题目深入浅出下JavaScript

文章目录 1. 原型和原型链2. 作用域和闭包3. 高阶函数和函数式编程4. 异步编程和Promise、async/await5. 正则表达式6. 对象属性描述符和代理7. ES6新特性如模板字符串、解构赋值、箭头函数、let/const等8. 设计模式和架构模式设计模式架构模式 9. 性能优化技巧和调试技巧1. 性…

chatgpt赋能python:Python如何持续保存CSV文件

Python如何持续保存CSV文件 如果你需要不断更新数据并将其保存到CSV文件中&#xff0c;Python语言可以轻松完成这个任务。本文将介绍如何使用Python在代码执行的同时&#xff0c;将数据不断写入CSV文件中&#xff0c;实现持续保存的功能。 CSV文件是什么&#xff1f; CSV代表…

chatgpt赋能python:抓包是什么?

抓包是什么&#xff1f; 当我们在浏览器中访问一个网站时&#xff0c;我们的电脑会向网络服务器发送请求并接收响应。这个过程中&#xff0c;有一些工具可以让我们查看和分析这些请求和响应&#xff0c;其中最常用的就是“抓包”。 抓包就是指截获网络通信过程中的数据包并分…

chatgpt赋能python:Python怎么指定循环次数?

Python怎么指定循环次数&#xff1f; Python是一种广泛应用于编程领域的高级编程语言&#xff0c;它具有简单易学、代码可读性强、语言编写规范等诸多优点。其中&#xff0c;循环是Python语法中的重要一环&#xff0c;而如何指定循环次数则是其中一个重要的问题。 什么是循环…