深入理解程序的结构

news2024/11/14 18:10:11

文章目录

  • 前言
  • 一、程序的组成
  • 二、未初始化和初始化变量保存地址
  • 三、栈什么时候被创建
  • 四、内存映射段
  • 总结


前言

本篇文章我们来深入的理解一下理解程序的结构。

一、程序的组成

通常情况下,一个可执行程序由以下几个不同的段组成:

1.代码段 (Text Segment):
代码段通常被加载到只读内存区域中,并包含程序的指令和函数。在段加载完成后,代码段的内容不可更改。当程序开始执行时,指令将从代码段中加载并执行。

2.数据段 (Data Segment):
数据段通常存储了程序中的初始化数据,包括静态变量和可以修改的全局变量。数据段通常在可读写的内存区域中,并且在程序开始前就已经被初始化好了。

3.BSS段:
BSS 段通常存储了未初始化的全局变量和静态变量,它在执行前会被清零。这个段的名称来自Block Started by Symbol,这个名称来自汇编程序语言中的一种数据定义。

4..rodata 段
.rodata 段是可执行程序或共享库中的一个内存段(或区段),用于存储只读数据(read-only data)。rodata 是 “read-only data” 的缩写,表示该段中的数据是只读的,无法在运行时被修改。

.rodata 段主要包含以下类型的数据:

字符串常量:包括程序中使用的字符串文字,如错误消息、提示语等。这些字符串在程序运行期间不可修改。

全局常量:程序中定义的全局常量,如常量数组、常量结构体等。

格式化字符串:包括格式化输出函数(如printf)中使用的格式化字符串,这些字符串描述了输出的格式,因此必须保持不变。

5.堆 (Heap):
堆是程序在运行时动态分配内存的区域,由程序员手动管理和控制。堆在程序开始执行之前不存在,必须使用 malloc() 或者其他的内存分配函数来动态创建和释放。

65.栈 (Stack):
栈用于存储程序执行时的函数调用信息、局部变量和参数等信息。每当需要调用一个函数时,栈上就会生成一个新的栈帧,该函数所需要的信息都存储在这个栈帧中。当函数调用结束后,这个栈帧就会被弹出。

二、未初始化和初始化变量保存地址

在编译和链接的过程中,编译器和链接器对变量进行了不同的处理,导致未初始化变量和初始化变量在内存中保存的位置不同。

未初始化的全局变量或静态变量被存储在程序的 BSS 段(Block Started by Symbol)中。BSS 段在可执行文件中保留了足够的空间来容纳未初始化的静态变量。当程序加载到内存中时,操作系统会清零 BSS 段的内存区域,使得其中的变量都被自动初始化为零值(或 null 值)。因此,未初始化的全局变量和静态变量在内存中占据一片被清零的内存区域。

而初始化的全局变量或静态变量被存储在程序的 data 段中。data 段在可执行文件中保存了已经初始化的全局变量和静态变量的值。当程序加载到内存中时,操作系统会将 data 段中的数据复制到内存中相应的位置。因此,初始化的全局变量和静态变量在内存中占据的是已经被赋予初始值的内存区域。

需要注意的是,局部变量(即在函数内定义的变量)通常放在栈上,而不是 BSS 段或 data 段中。局部变量的生命周期与函数的执行周期相关,在每次函数调用时会被分配内存,并在函数返回时被释放。

这里来进行一个实验:

#include <stdio.h>

int g_val;

int g_data = 1;

int main(void)
{
    static int g_mainval = 1;
    static int g_value;

    int a;

    return 0;
}

在这里插入图片描述

三、栈什么时候被创建

栈是在程序执行期间动态创建和管理的,它用于存储局部变量、函数调用信息、函数参数等。栈是一种后进先出(LIFO)的数据结构,其中的数据以栈帧的形式存储。

栈的创建和销毁是由程序的执行流控制的。当程序执行到一个函数调用时,会在栈上创建一个新的栈帧,用于存储函数的局部变量、参数和返回地址等信息。这个过程称为函数调用的栈帧入栈。当函数执行完毕或遇到返回语句时,相应的栈帧会被销毁,从而释放栈上的内存空间,这个过程称为栈帧出栈。

在上面的程序中我们定义了局部变量a,但是使用nm命令后并没有查看到这个变量具体是存放在哪里的,因为局部变量都是存储在栈中的,而栈是在程序运行后才被创建的,所以没有执行这个程序我们是无法观察到这个变量具体存放在哪里的。

四、内存映射段

内存映射是指将文件或设备中的数据映射到进程的内存空间,使得进程可以像访问内存一样访问这些数据。内存映射段是指将不同的文件或设备映射到进程的不同内存区域的段(区段)。

在这里插入图片描述

使用内存映射的方式创建内存映射段包括以下步骤:

打开文件或选择设备:首先,需要打开要映射到内存的文件或选择要映射的设备。这可以通过文件系统中的文件路径或设备的标识符来完成。

调用内存映射函数:操作系统提供了特定的系统调用或库函数来进行内存映射。这些函数的名称和具体调用方法会根据操作系统的不同而有所差异。

指定映射参数:在调用内存映射函数时,需要指定映射的相关参数,例如要映射的文件描述符、映射的起始偏移量和长度、访问权限等。

分配内存:操作系统会为内存映射段分配一段连续的虚拟内存空间,这段内存空间在进程的地址空间中保留一块空闲区域。

关联文件或设备:操作系统会将打开的文件或设备的数据与分配的虚拟内存空间进行关联,使得进程可以通过访问内存来读写文件或设备的数据。

访问和操作数据:通过指针或偏移量等方式,进程可以直接在所分配的内存空间中读取和写入数据。对内存的操作会直接反映到关联的文件或设备中。

解除映射和释放资源:在不再需要内存映射段时,可以调用相应的解除映射函数来解除关联,并释放分配的内存资源。

内存映射具有以下几个重要的用途和优势,使得其在编程和操作系统中得到广泛应用:

简化文件和设备的访问:通过内存映射,可以将文件和设备中的数据映射到进程的内存空间,从而使得对文件和设备的访问变得更加简单、方便和高效。进程可以通过直接读取和写入内存的方式来访问数据,而不必进行繁琐的文件读写和设备访问操作。

提高性能:内存映射可以减少系统调用的次数,从而降低了IO操作的开销。相比于传统的文件读取和写入操作,内存映射可以大幅度提升数据访问的速度和效率,尤其是对于大型文件的操作。

共享和通信:多个进程可以同时映射同一个文件,实现数据的共享和通信。这种共享内存的方式能够提供高效的进程间通信机制,是一种常见的实现并发和分布式系统的方式。

简化数据结构和算法:内存映射可以使得进程将复杂的数据结构和算法映射到内存中,从而简化了程序的设计和实现。例如,使用内存映射可以将一整个文件直接映射到内存中,然后通过指针操作和数据访问来实现高效的文件处理和搜索操作。

无需读取整个文件:使用内存映射时,可以选择只映射文件中的部分数据,而不是将整个文件都映射到内存中。这种方式在处理大型文件时非常有用,可以避免一次性读取整个文件导致内存不足的问题。

总之,内存映射提供了一种便捷和高效的方式来访问文件和设备中的数据,简化了编程任务并提升了系统性能。它被广泛应用于许多领域,如文件系统、数据库、网络编程、并发编程等。

总结

本篇文章就讲解到这里,掌握这些知识有助于大家深入了解程序的结构。

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

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

相关文章

怎么针对微服务架构做单元测试?

Martin Fowler 是国际著名的软件专家&#xff0c;敏捷开发方法的创始人之一&#xff0c;现为 ThoughtWorks 公司的首席科学家。在面向对象分析设计、UML、模式、软件开发方法学、XP、重构等方面&#xff0c;都扮演着举足 什么是微服务&#xff1f; 微服务的由来 微服务的前身…

笑谈之传统行业的软件测试

最近进入一传统企业做O2O社区&#xff0c;在里面&#xff0c;项目管理一团混乱&#xff0c;上层对软件测试的理解更是匮乏。今天没有技术&#xff0c;仅是对这些现象的吐槽。当然我相信传统行业不都是这样&#xff0c;所以大家仅当笑谈。 产品经理写的需求文档永远是拿来作为做…

cas单点登录 前端步骤流程

CAS&#xff08;Central Authentication Service&#xff09;是一个开源的单点登录协议和实现&#xff0c;它提供了一种统一的方法来管理和验证用户身份&#xff0c;使用户只需通过一次登录即可访问多个应用程序。CAS 单点登录的工作原理是基于服务提供者 (Service Provider) 和…

MNIST机器学习入门

引入所需库 import osimport cv2 import matplotlib.pyplot as plt import numpy as np import pandas as pd import tensorflow as tf from PIL import ImageMNIST数据集 下载MNIST数据集 mnisttf.keras.datasets.mnist (x_train, y_train), (x_test, y_test) mnist.load_…

【干货】Android系统定制基础篇:第七部分-Android OTA升级(系统、应用)

OTA升级应用 项目地址&#xff1a;https://github.com/aystshen/Android-RomUpgrade. 这是一个负责 Android OTA 升级的后台应用&#xff0c;开机后自动运行后台 Service&#xff0c;支持系统升级和应用升级&#xff0c;支持本地升级&#xff08;tf卡、u盘&#xff09;和在线升…

数据库系统概述——第一章 绪论(知识点复习+练习题)

✨博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;离散数学考前复习&#xff08;知识点题&#xff09; &#x1f353;专栏&#xff1a;概率论期末速成&#xff08;一套卷&#xff09; &#x1f433;专栏&#xff1a;数字电路考前复习 &#x1f99a;专栏&#xff1a;数…

Qt 每月收支计算

Qt 每月收支计算&#xff0c;针对每月有支出&#xff08;房贷、车贷、花呗、借呗&#xff09;的情况&#xff0c;计算收支明细&#xff0c;直观看到未来的个人经济情况&#xff0c;培养良好的消费习惯&#xff0c;进行理性的财富支配&#xff0c;量入为出。 #include "mai…

云安全技术(三)之云计算相关的安全概念

云计算相关的安全概念 Security Concepts Relevant to Cloud Computing 1. 密码学和密钥管理 Cryptography and key management 1、加密技术: 有许多不同类型和等级的加密技术。在云环境中&#xff0c;云安全专家有责任评价应用程序的需求、所使用的技术、需要保护的数据类型&…

【UE 从零开始制作坦克】5-通过旋转摄像机控制炮塔旋转

效果 步骤 打开动画蓝图“ABP_West_Tank_M1A1Abrams” 我们在动画图表中可以发现控制坦克炮塔旋转和炮管旋转的变量分别是“TurretRotation”和“GunRotattion”&#xff0c;因此只需改变这两个旋转体的值即可控制炮塔和炮管的旋转。 切换到事件图表中&#xff0c;首先通过“T…

单向散列函数【密码学】(一)

目录 一、前言&#xff1a;密码学有什么用&#xff1f; 二、单向散列函数 1、单向函数 2、散列函数 3、单向散列函数 三、怎么解决完整性问题 四、如何设置合适的安全强度 一、前言&#xff1a;密码学有什么用&#xff1f; 二、单向散列函数 单向散列函数就是用来解决…

article-6-pss 并联六自由度机构轨迹规划

建模 ** [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-djltxj90-1687070335773)(data:image/svgxml;utf8, )] ** 程序如下&#xff1a; % clc % clear all % function []PSS1(XP,YP,ZP) tic %%%%%鍒濆浣嶇疆鐨勪綅濮?%%%%% % XP 0; %鍔ㄥ钩鍙…

存储笔记6 SAN

SAN&#xff08;Storage Area Networks&#xff09; SAN 优势 benefitsSAN 组件 componentsSAN连接选项 connective optionsFC协议 FC寻址 protocol addressing\FC拓扑 topologie SAN优缺点 光纤通道 fibre channel SAN组件 FC三种互联 FC端口类型 fabric 企业需要和科技…

RFID期末复习总结

一.概念部分 1.基础概念 射频识别无线电频率识别RFID 应答器&#xff1a;存放识别信息的电子数据载体 阅读器&#xff1a;将识别信息从应答器中读出&#xff08;还可以写入数据&#xff09; 应答器是统称&#xff0c;在各种专业场合有专业名字&#xff0c;比如射频卡&#…

pikachu靶场-PHP反序列化

在理解这个漏洞前,你需要先搞清楚php中serialize()&#xff0c;unserialize()这两个函数。 序列化serialize() 序列化说通俗点就是把一个对象变成可以传输的字符串,比如下面是一个对象: class S{public $test"pikachu";}$snew S(); //创建一个对象serialize($s); //…

FPGA时序约束--进阶篇(主时钟约束)

在FPGA设计中&#xff0c;时序约束的设置对于电路性能和可靠性都至关重要。在上一篇的文章中&#xff0c;已经详细介绍了FPGA时序约束的基础知识。 本文将重点讲解主时钟约束设置&#xff0c;给出详细的约束命令&#xff0c;并介绍了在Vivado中如何写入主时钟约束。 一、主时…

一文详解!接口测试(http与rpc)总结

目录 前言&#xff1a; 一、了解一下HTTP与RPC 二、HTTP接口测试 三、RPC接口测试 四、接口测试用例设计 五、测试思路总结 前言&#xff1a; 在接口测试方面&#xff0c;常见的接口类型有HTTP接口和RPC接口。这两者的测试方法略有不同&#xff0c;在测试前需要进行技术选…

[INFO] [copilotIgnore] inactive,github copilot没反应怎么解决

在使用github copilot的时候&#xff0c;插件不工作&#xff0c;后台出现了这种输出&#xff0c; 这种情况下就是它的激活出现了问题&#xff0c;如果账号的使用权没有问题的话&#xff0c;就将该插件disable之后再重新enable&#xff0c;重新观察输出&#xff0c;就会看到copi…

LAMP架构搭建实操

目录 一、LAMP架构概述 二、LAMP框架搭建 1.准备工作 2.部署apache 3.部署mysql 4.部署php 三、部署BBS论坛 一、LAMP架构概述 LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用…

win11系统提示msvcp140.dll丢失的三个解决方法,简单实用

Win11系统在运行photoshop或其他软件&#xff0c;游戏的时候&#xff0c;电脑提示“找不到msvcp140.dll”&#xff0c;“msvcp140.dll丢失”&#xff0c;“无法定位输入点msvcp140.dll”等问题&#xff0c;都是由于Windows11系统中的msvcp140.dll文件丢失或者损坏了。 问题场景…

数据结构 串

串 术语概念 在数据结构中&#xff0c;串&#xff08;String&#xff09;是由零个或多个字符组成的有限序列。它是一种常见的数据类型&#xff0c;常用于表示文本、字符串和符号序列等信息。串可以包含任意字符&#xff0c;包括字母、数字、符号以及空格等。 主串&#xff08…