Linux 第十八章

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数C初学者入门训练题解CC的使用文章「初学」C++linux

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

程序地址空间

区间的地址分布

真正理解同一个地址进行读取不同内容

地址空间

虚拟地址和物理地址

虚拟地址:

物理地址:

struct mm_struct

页表


程序地址空间

区间的地址分布

[BCH@hcss-ecs-6176 10_21]$ cat test.c
#include<stdio.h>
#include<stdlib.h>
int un_gval;
int init_gval=100;
int main(int argc,char* argv[],char* env[])
{
        printf("code addr:%p\n",main);//代表代码区的地址
        const char *str="hello linux";
        printf("read only char addr:%p\n",str);//代表字符常量取得地址
        printf("init global value addr:%p\n",&init_gval);//代表初始化全局数据区
        printf("uninit global value addr:%p\n",&un_gval);//代表未初始化全局数据区
        char* heap1=(char*)malloc(100);
        printf("heap addr:%p\n",heap1);//代表堆区的地址
        printf("stack addr:%p\n",&str);//代表栈区的地址


        int i=0;
        for(;argv[i];i++)
        {
                printf("argv[%d]:%p\n",i,argv[i]);
        }


        for(i=0;env[i];i++)
        {
                printf("env[%d]:%p\n",i,env[i]);
        }
        return 0;
}

结果:
[BCH@hcss-ecs-6176 10_21]$ ./mytest
code addr:0x40057d
read only char addr:0x40077e
init global value addr:0x60103c
uninit global value addr:0x601044
heap addr:0x1c9d010
stack addr:0x7ffdc6730228
argv[0]:0x7ffdc67307fd
env[0]:0x7ffdc6730806
env[1]:0x7ffdc6730819
env[2]:0x7ffdc6730830
env[3]:0x7ffdc673083b
env[4]:0x7ffdc673084b
env[5]:0x7ffdc673085a
env[6]:0x7ffdc673087e
env[7]:0x7ffdc673088f
env[8]:0x7ffdc673089c
env[9]:0x7ffdc67308af
env[10]:0x7ffdc67308b8
env[11]:0x7ffdc6730e54
env[12]:0x7ffdc6730e82
env[13]:0x7ffdc6730e9b
env[14]:0x7ffdc6730ef5
env[15]:0x7ffdc6730f09
env[16]:0x7ffdc6730f1a
env[17]:0x7ffdc6730f31
env[18]:0x7ffdc6730f39
env[19]:0x7ffdc6730f48
env[20]:0x7ffdc6730f54
env[21]:0x7ffdc6730f88
env[22]:0x7ffdc6730fab
env[23]:0x7ffdc6730fca
env[24]:0x7ffdc6730fe4

真正理解同一个地址进行读取不同内容

[BCH@hcss-ecs-6176 10_21]$ cat test.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int g_val=100;
int main()
{
        pid_t id =fork();//创建子进程
        if(id==0)
        {
                //child
                int cnt=5;
                while(1)
                {
                        printf("pid:%d,ppid:%d,g_val:%d,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
                        sleep(1);
                        if(cnt==0)
                        {
                                g_val=200;
                                printf("child change g_val:100->200\n");
                        }
                        cnt--;
                }
        }
        else
        {
                //parent
                while(1)
                {
                        printf("pid:%d,ppid:%d,g_val:%d,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
                        sleep(1);
                }
        }
        return 0;
}




[BCH@hcss-ecs-6176 10_21]$ ./mytest
pid:29919,ppid:7584,g_val:100,&g_val:0x60105c
pid:29920,ppid:29919,g_val:100,&g_val:0x60105c
pid:29919,ppid:7584,g_val:100,&g_val:0x60105c
pid:29920,ppid:29919,g_val:100,&g_val:0x60105c
pid:29919,ppid:7584,g_val:100,&g_val:0x60105c
pid:29920,ppid:29919,g_val:100,&g_val:0x60105c
pid:29919,ppid:7584,g_val:100,&g_val:0x60105c
pid:29920,ppid:29919,g_val:100,&g_val:0x60105c
pid:29919,ppid:7584,g_val:100,&g_val:0x60105c
pid:29920,ppid:29919,g_val:100,&g_val:0x60105c
pid:29919,ppid:7584,g_val:100,&g_val:0x60105c
pid:29920,ppid:29919,g_val:100,&g_val:0x60105c
pid:29919,ppid:7584,g_val:100,&g_val:0x60105c
child change g_val:100->200
pid:29920,ppid:29919,g_val:200,&g_val:0x60105c//子进程的值是200,地址0x60105c
pid:29919,ppid:7584,g_val:100,&g_val:0x60105c//父进程的是100,地址0x60105c
pid:29920,ppid:29919,g_val:200,&g_val:0x60105c
pid:29919,ppid:7584,g_val:100,&g_val:0x60105c

得出的结论是:我们C/C++看到的地址,绝对不是物理地址!!!

我们平时用的地址都是虚拟地址/线性地址!!

地址空间

每一个进程运行之后,都会有一个进程地址空间存在!!

就可以解释fork之后形成了父进程和子进程

返回给父进程的id是子进程的pid,返回给子进程的是0

因为,父进程有自己的虚拟地址空间,给id在栈区开辟一个空间,然后通过页表实现虚拟地址映射物理地址,id的存储在内存中

子进程继承父进程,拷贝父进程的地址空间和页表,但是页表上虚拟地址映射物理地址不同,id在子进程虚拟地址和id在父进程虚拟地址是相同的,而映射的物理地址是不同的,所以内存中又会开辟空间去存储在子进程中的id

虚拟地址和物理地址

在 Linux 中,虚拟地址和物理地址是计算机系统中重要的概念,特别是在操作系统和硬件之间的交互中。

虚拟地址:

虚拟地址是由 CPU 生成的地址空间中的地址,它是进程所见到的地址。每个进程都有自己的虚拟地址空间,通常是连续的地址空间,从 0 开始。
虚拟地址提供了一种抽象机制,使得每个进程都认为它在独占系统资源,而不必担心与其他进程的冲突。
虚拟地址的转换是由硬件中的内存管理单元(MMU)来完成的。MMU 根据页面表(Page Table)将虚拟地址映射到物理地址。

物理地址:

物理地址是实际存在于计算机系统中的内存单元的地址,它是 RAM 中存储数据的位置。
物理地址是实际用于访问计算机系统中内存模块的地址。
虚拟地址通过地址映射机制转换为物理地址,然后在物理地址上进行访问和操作。
在 Linux 中,虚拟地址和物理地址的管理是由操作系统负责的。操作系统通过分页机制将进程的虚拟地址映射到物理地址,从而实现了内存管理和进程间的隔离。

struct mm_struct

虚拟地址空间也要被OS管理起来!!每一个进程都要有地址空间,系统中,一定要对地址空间做管理!!,地址空间最终一定是一个内核的数据结构对象!

在linux中,这个进程/虚拟地址空间的东西,叫做:struct mm_struct

Struct mm_struct
{
    Long code_start;
    Long code_end;
    Long data_start;
    Long data_end;
    Long heap_start;
    Long heap_end;
    Long stack_start;
    Long stack_end;
    …...
}

页表

总结:

1)每一个进程都是有页表的

2)如何理解切换:只要把上下文数据保存好,pcb、地址空间、页表就保存好了

3)让进程以统一的视角看待内存,所以一个进程,可以通过地址空间+页表可以将乱序的内存数据,变成有序,分门别类的规划好!无序变有序

4)页表还有访问权限字段这就是为什么常量字符串,不可被修改,就是由于对应的内存访问权限是只读的

5)存在虚拟地址空间,可以有效的进行进程内存的安全检查!

6)将进程管理和内存管理进行结耦,通过页表,让进程映射到不同的物理内存处,从而实现进程独立性

CPU中的CR3寄存器

存储当前进程的页目录表物理地址。当CPU从虚拟地址空间中访问内存时,会首先将虚拟地址通过分页机制翻译为物理地址,而这个翻译过程需要使用到页表。

  🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸 

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《嵌入式Linux基础教程(第2版)》PDF是一本深入浅出的嵌入式Linux学习指南,由谢希仁编著。本书主要介绍了嵌入式Linux的概念、架构、编程实践和应用开发等,适合初学者和有一定经验的开发者阅读。 本书分为六章,包括嵌入式系统与Linux系统、Linux的构建与移植、系统启动与运行、设备驱动程序编写、文件系统和网络应用开发等内容。其中,第一章主要讲解了嵌入式系统和Linux系统的概念,以及它们的优缺点。第二章则介绍了如何构建和移植Linux系统,包括构建Linux内核、交叉编译工具链的配置与使用、文件系统的制作和移植等。 第三章讲解了Linux系统启动的过程和原理,并介绍了以Bootloader、U-Boot为代表的启动程序的开发和应用。第四章是本书的重点内容之一,讲述了如何编写设备驱动程序,包括字符设备驱动程序和块设备驱动程序。第五章详细介绍了Linux的文件系统原理、文件系统的制作方法和移植方法,以及常见的文件系统的格式和应用。最后,第六章介绍了Linux下网络应用的编程开发,包括TCP/IP协议栈的实现、Socket编程、Web服务器开发等。 总的来说,《嵌入式Linux基础教程(第2版)》PDF是一本内容详实、实用性强的入门级嵌入式Linux教程。通过学习本书,读者可以了解嵌入式Linux的核心概念和实际应用,以及如何开发和部署嵌入式Linux系统。无论您是嵌入式工程师还是Linux爱好者,都可以从本书中获得丰富的知识和实践经验。 ### 回答2: 《嵌入式Linux基础教程》是一本经典的教材,是Linux嵌入式系统方面的必备读物。本书第2版更加全面深入地介绍了Linux嵌入式系统的基础知识和实践技巧。 该书从Linux基础入门开始讲起,逐步深入到嵌入式Linux系统的构建、移植和启动等方面,同时涵盖了Linux内核驱动、文件系统、网络等各个方面的知识。本书内容全面,讲解详细,对初学者来说非常友好。 另外,本书还涵盖了一些实用的案例,例如如何运用Linux构建一个完整的嵌入式系统,如何实现一个网络引导(Linux网络启动),对于想要在实践中学习的读者来说是极为有帮助的。 总的来说,《嵌入式Linux基础教程第2版》是一本非常优秀的入门教材,对于初学者学习嵌入式Linux系统非常有帮助,同时也为专业人士提供了深入研究的细节。强烈推荐给想要学习和使用嵌入式Linux系统的读者阅读并使用。 ### 回答3: 《嵌入式linux基础教程 第2版pdf》是一本涉及嵌入式系统和linux操作系统的教程书籍,适合初学者和开发者参考和学习。本书共分为12章,详细介绍了嵌入式系统的基础知识、linux操作系统的安装、配置、使用和应用开发等方面的内容。 在第一章中,本书从介绍嵌入式系统应用领域的基础知识开始,例如嵌入式系统的定义、分类、特点以及应用领域等。第二章涵盖了Linux操作系统的安装和配置,包括如何选择和下载适合嵌入式系统的Linux内核、使用交叉编译器进行交叉编译、安装组件等。 在第三章,本书介绍了Linux系统中的文件和目录结构,软件包管理等内容;第四章介绍了shell脚本编程和命令行工具使用;第五章介绍了嵌入式系统中的板级支持包和驱动程序的开发。此外,在第六章和第七章,本书讲述了Linux下的进程管理和内存管理。 在第八章和第九章,本书介绍了Linux下的socket编程和网络协议栈的原理及应用;第十章中,本书讲解了嵌入式系统中的文件系统和闪存存储器的使用和管理;第十一章介绍了Linux下的多线程编程和信号处理等内容。 在最后一章,本书将介绍基于嵌入式系统的应用的开发,例如芯片厂商提供的开发包和SDK,基于QT的图形用户界面开发等。 总的来说,这本书从基础概念到应用开发均有涵盖,有助于初学者了解嵌入式系统和Linux操作系统的基础知识,同时也是开发者进行嵌入式软件开发的好参考书。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值