在 x86 32位系统下,进程的虚拟地址空间为 232 (4G)大小,其中在windows系统下4G地址空间中0x00000000-0x7FFFFFFF 是用户地址空间,0x80000000-0xFFFFFFFF 是内核空间。在Linux系统下,0xC00000000-0XFFFFFFFF为系统空间,为所有的系统进程所共享,0X00000000-0XBFFFFFFF为用户空间。本文主要研究在Linux系统下的虚拟地址空间。

我们所写的程序都在磁盘上存放,而在运行时向内存中加载的只有指令和数据。而这些指令和数据都不可能直接加载到真实的内存中,而是加载到虚拟地址空间中。每个进制都有自己的虚拟地址空间,并且结构相同都被划分出若干段。其中,用户空间是每个进程私有的,而内核空间是所有进程共享的。

Linux用户进程分段存储内容

Section 属性 存储内容
局部变量、const局部常量、函数参数、返回地址等
动态分配的内存
BSS段 可读;可写 未初始化/初始化为0的静态变量/全局变量
数据段 可读;可写 初始化为~0的静态变量/全局变量
代码段 只读;可执行 可执行代码、常量(字符串常量;const全局常量;enum常量;#define常量等)

下面通过一段代码来初步了解虚拟地址空间。

#include <iostream>

int gdata1 = 10;	// 已初始化的全局变量
int gdata2 = 0; // 初始化为0的全局变量
int gdata3; // 未初始化的全局变量
static int gdata4 = 11; // 静态、已初始化的变量
static int gdata5 = 0; // 静态、初始化为0的变量
static int gdata6; // 静态、未初始化的变量
int main()
{
int a = 12; // 已初始化的局部变量
int b = 0; // 初始化为0的局部变量
int c; // 未初始化的局部变量
static int e = 13; // 局部、静态、已初始化
static int f = 0; // 局部、静态、初始化为0
static int g; // 局部、静态、未初始化
return 0;
}

在上述代码中:

gdata1——gdata6 为全局变量,最终是以数据的形式被加载到内存中,并添加到符号表中。其中:

  • 未初始化或初始化未0的全局变量存放于 .bss 段
  • 已初始化的全局变量存放于 .data 段

    在main 函数内部

    a,b,c 三个局部变量最终以指令的形式被加载到内存中,不会添加到符号表中。如:mov dword ptr[a], 0ch 指令 ,存放于 .text段,而在该指令运行时会在栈上开辟出一块空间用于存放a的值,因此我们也说局部变量在栈上开辟空间。

    e,f,g 静态的局部变量存放于数据段,在程序运行至该行代码时进行初始化。因此,e存放 .data 段,f,g存放于 .bss 段。
查看文件段表

在Linux系统下可执行文件为ELF格式,可以通过readlef -S a.outobjdump -h a.out 查看我们之前写的程序的ELF文件的段表

$ objdump -h a.out

a.out:     file format elf64-x86-64

Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001c 0000000000400238 0000000000400238 00000238 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.ABI-tag 00000020 0000000000400254 0000000000400254 00000254 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024 0000000000400274 0000000000400274 00000274 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .gnu.hash 00000024 0000000000400298 0000000000400298 00000298 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .dynsym 00000090 00000000004002c0 00000000004002c0 000002c0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynstr 00000090 0000000000400350 0000000000400350 00000350 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .gnu.version 0000000c 00000000004003e0 00000000004003e0 000003e0 2**1
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version_r 00000040 00000000004003f0 00000000004003f0 000003f0 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .rela.dyn 00000018 0000000000400430 0000000000400430 00000430 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.plt 00000078 0000000000400448 0000000000400448 00000448 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .init 0000001a 00000000004004c0 00000000004004c0 000004c0 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
11 .plt 00000060 00000000004004e0 00000000004004e0 000004e0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .text 000001d2 0000000000400540 0000000000400540 00000540 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .fini 00000009 0000000000400714 0000000000400714 00000714 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .rodata 00000010 0000000000400720 0000000000400720 00000720 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
15 .eh_frame_hdr 00000044 0000000000400730 0000000000400730 00000730 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
16 .eh_frame 00000134 0000000000400778 0000000000400778 00000778 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
17 .init_array 00000010 0000000000600df8 0000000000600df8 00000df8 2**3
CONTENTS, ALLOC, LOAD, DATA
18 .fini_array 00000008 0000000000600e08 0000000000600e08 00000e08 2**3
CONTENTS, ALLOC, LOAD, DATA
19 .jcr 00000008 0000000000600e10 0000000000600e10 00000e10 2**3
CONTENTS, ALLOC, LOAD, DATA
20 .dynamic 000001e0 0000000000600e18 0000000000600e18 00000e18 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .got 00000008 0000000000600ff8 0000000000600ff8 00000ff8 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .got.plt 00000040 0000000000601000 0000000000601000 00001000 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .data 00000010 0000000000601040 0000000000601040 00001040 2**2
CONTENTS, ALLOC, LOAD, DATA
24 .bss 00000020 0000000000601050 0000000000601050 00001050 2**2
ALLOC
25 .comment 0000002d 0000000000000000 0000000000000000 00001050 2**0
CONTENTS, READONLY

表中的每一列分别对应 section的大小、虚拟地址(Virtual Memory Address)、装载地址(Load Memory Address),文件偏移。

查看符号表

通过readelf -s a.outobjdump -t a.out查看该应用程序ELF文件的符号表

a.out:     file format elf64-x86-64

SYMBOL TABLE:
0000000000400238 l d .interp 0000000000000000 .interp
0000000000400254 l d .note.ABI-tag 0000000000000000 .note.ABI-tag
0000000000400274 l d .note.gnu.build-id 0000000000000000 .note.gnu.build-id
0000000000400298 l d .gnu.hash 0000000000000000 .gnu.hash
00000000004002c0 l d .dynsym 0000000000000000 .dynsym
0000000000400350 l d .dynstr 0000000000000000 .dynstr
00000000004003e0 l d .gnu.version 0000000000000000 .gnu.version
00000000004003f0 l d .gnu.version_r 0000000000000000 .gnu.version_r
0000000000400430 l d .rela.dyn 0000000000000000 .rela.dyn
0000000000400448 l d .rela.plt 0000000000000000 .rela.plt
00000000004004c0 l d .init 0000000000000000 .init
00000000004004e0 l d .plt 0000000000000000 .plt
0000000000400540 l d .text 0000000000000000 .text
0000000000400714 l d .fini 0000000000000000 .fini
0000000000400720 l d .rodata 0000000000000000 .rodata
0000000000400730 l d .eh_frame_hdr 0000000000000000 .eh_frame_hdr
0000000000400778 l d .eh_frame 0000000000000000 .eh_frame
0000000000600df8 l d .init_array 0000000000000000 .init_array
0000000000600e08 l d .fini_array 0000000000000000 .fini_array
0000000000600e10 l d .jcr 0000000000000000 .jcr
0000000000600e18 l d .dynamic 0000000000000000 .dynamic
0000000000600ff8 l d .got 0000000000000000 .got
0000000000601000 l d .got.plt 0000000000000000 .got.plt
0000000000601040 l d .data 0000000000000000 .data
0000000000601050 l d .bss 0000000000000000 .bss
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
0000000000600e10 l O .jcr 0000000000000000 __JCR_LIST__
0000000000400570 l F .text 0000000000000000 deregister_tm_clones
00000000004005a0 l F .text 0000000000000000 register_tm_clones
00000000004005e0 l F .text 0000000000000000 __do_global_dtors_aux
0000000000601050 l O .bss 0000000000000001 completed.6355
0000000000600e08 l O .fini_array 0000000000000000 __do_global_dtors_aux_fini_array_entry
0000000000400600 l F .text 0000000000000000 frame_dummy
0000000000600df8 l O .init_array 0000000000000000 __frame_dummy_init_array_entry
0000000000000000 l df *ABS* 0000000000000000 a.cpp
000000000060105c l O .bss 0000000000000001 _ZStL8__ioinit
0000000000601048 l O .data 0000000000000004 _ZL6gdata4
0000000000601060 l O .bss 0000000000000004 _ZL6gdata5
0000000000601064 l O .bss 0000000000000004 _ZL6gdata6
0000000000400641 l F .text 000000000000003d _Z41__static_initialization_and_destruction_0ii
000000000040067e l F .text 0000000000000015 _GLOBAL__sub_I_gdata1
0000000000601068 l O .bss 0000000000000004 _ZZ4mainE1g
000000000060106c l O .bss 0000000000000004 _ZZ4mainE1f
000000000060104c l O .data 0000000000000004 _ZZ4mainE1e
0000000000000000 l df *ABS* 0000000000000000 crtstuff.c
00000000004008a8 l O .eh_frame 0000000000000000 __FRAME_END__
0000000000600e10 l O .jcr 0000000000000000 __JCR_END__
0000000000000000 l df *ABS* 0000000000000000
0000000000400730 l .eh_frame_hdr 0000000000000000 __GNU_EH_FRAME_HDR
0000000000601000 l O .got.plt 0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000600e08 l .init_array 0000000000000000 __init_array_end
0000000000600df8 l .init_array 0000000000000000 __init_array_start
0000000000600e18 l O .dynamic 0000000000000000 _DYNAMIC
0000000000601040 w .data 0000000000000000 data_start
0000000000400710 g F .text 0000000000000002 __libc_csu_fini
0000000000400540 g F .text 0000000000000000 _start
0000000000000000 w *UND* 0000000000000000 __gmon_start__
0000000000601054 g O .bss 0000000000000004 gdata2
0000000000400714 g F .fini 0000000000000000 _fini
0000000000000000 F *UND* 0000000000000000 _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
0000000000000000 F *UND* 0000000000000000 __libc_start_main@@GLIBC_2.2.5
0000000000000000 F *UND* 0000000000000000 __cxa_atexit@@GLIBC_2.2.5
0000000000400530 F *UND* 0000000000000000 _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
0000000000400720 g O .rodata 0000000000000004 _IO_stdin_used
0000000000601040 g .data 0000000000000000 __data_start
0000000000601044 g O .data 0000000000000004 gdata1
0000000000601050 g O .data 0000000000000000 .hidden __TMC_END__
0000000000400728 g O .rodata 0000000000000000 .hidden __dso_handle
00000000004006a0 g F .text 0000000000000065 __libc_csu_init
0000000000601050 g .bss 0000000000000000 __bss_start
0000000000601070 g .bss 0000000000000000 _end
0000000000601050 g .data 0000000000000000 _edata
0000000000601058 g O .bss 0000000000000004 gdata3
000000000040062d g F .text 0000000000000014 main
00000000004004c0 g F .init 0000000000000000 _init

其中,我们可以看到gdata1-6 以及 e,f,g所属的分段,

0000000000601044 g     O .data  0000000000000004              gdata1
0000000000601054 g O .bss 0000000000000004 gdata2
0000000000601058 g O .bss 0000000000000004 gdata3 0000000000601048 l O .data 0000000000000004 _ZL6gdata4
0000000000601060 l O .bss 0000000000000004 _ZL6gdata5
0000000000601064 l O .bss 0000000000000004 _ZL6gdata6 0000000000601068 l O .bss 0000000000000004 _ZZ4mainE1g
000000000060106c l O .bss 0000000000000004 _ZZ4mainE1f
000000000060104c l O .data 0000000000000004 _ZZ4mainE1e

我们所写的程序,不管时C语言或是C++语言最终编译器都会先转化为汇编指令,而后再转化成机器指令存储在磁盘上。在我们运行程序时,把程序的指令和数据加载到虚拟内存空间中,然后根据内存中分段的偏移映射到物理内存上执行。

C++ | 虚拟地址空间的更多相关文章

  1. linux进程虚拟地址空间

    转载源 在多任务操作系统中,每个进程都运行在属于自己的内存沙盘中.这个沙盘就是虚拟地址空间(Virtual Address Space),在32位模式下它是一个4GB的内存地址块.在Linux系统中, ...

  2. [memory]虚拟地址空间分布

    一.开篇 踏入嵌入式软件行业也接近2年了,从研一开学起懵懵懂懂的開始学习C语言.因为本科时对这方面了解的少之又少,所以学起来比較困难.可是有一群无私奉献的小伙伴,慢慢的,慢慢的,慢慢的,一仅仅脚踏进了 ...

  3. Linux进程虚拟地址空间管理2

    2017-04-12 前篇文章对Linux进程地址空间的布局以及各个部分的功能做了简要介绍,本文主要对各个部分的具体使用做下简要分析,主要涉及三个方面:1.MMAP文件的映射过程 2.用户 内存的动态 ...

  4. LInux进程虚拟地址空间的管理

    2017-04-07 脱离物理内存的管理,今天咱们来聊聊进程虚拟内存的管理.因为进程直接分配和使用的都是虚拟内存,而物理内存则是有系统“按需”分配给进程,在进程看来,只知道虚拟内存的存在! 前言: 关 ...

  5. [windows官网]虚拟地址空间

    虚拟地址空间 https://docs.microsoft.com/zh-cn/windows-hardware/drivers/gettingstarted/virtual-address-spac ...

  6. 转:如何在32位程序中突破地址空间4G的限制

    //如何在32位程序中突破地址空间4G的限制 //首先要获得内存中锁定页的权限 #define _WIN32_WINNT 0x0501 //xp系统 #include <windows.h> ...

  7. 《Linux内核设计与实现》读书笔记(十五)- 进程地址空间(kernel 2.6.32.60)

    进程地址空间也就是每个进程所使用的内存,内核对进程地址空间的管理,也就是对用户态程序的内存管理. 主要内容: 地址空间(mm_struct) 虚拟内存区域(VMA) 地址空间和页表 1. 地址空间(m ...

  8. linux地址空间划分

    LDD讲的很明白了: Linux 是一个虚拟内存系统, 意味着用户程序见到的地址不直接对应于硬件使用的物理地址. 虚拟内存引入了一个间接层, 它允许了许多好事情. 有了虚拟内存, 系统重运行的程序可以 ...

  9. 内核源码分析之进程地址空间(基于3.16-rc4)

    所谓进程的地址空间,指的就是进程的虚拟地址空间.当创建一个进程时,内核会为该进程分配一个线性的地址空间(虚拟地址空间),有了虚拟地址空间后,内核就可以通过页表将进程的物理地址地址空间映射到其虚拟地址空 ...

随机推荐

  1. SqlServer 局域网内不能连接对方数据库?

    一直都是连接的远程测试服务器的数据库,今天想把自己的数据库开放出来让公司同事连接,竟然连接失败!转了很大一个圈终于搞定了. 接下来就把这次心历路程发出来,希望能帮助到有需要的博友. PS: 我和同事的 ...

  2. 迷你avalonjs框架

    valon2是一款基于虚拟DOM与属性劫持的 迷你. 易用. 高性能 的 前端MVVM框架, 拥有超优秀的兼容性, 支持移动开发, 后端渲染, WEB Component式组件开发, 无需编译, 开箱 ...

  3. 在linux上oracle服务启动停止详细

    转至:https://www.cnblogs.com/baihuitestsoftware/articles/6365431.html 在CentOS 6.3下安装完Oracle 10g R2,重开机 ...

  4. Lua中如何实现类似gdb的断点调试—06断点行号检查与自动修正

    前面两篇我们对性能做了一个优化,接下来继续来丰富调试器的特性. 我们前面提到过,函数内并不是所有行都是有效行,空行和注释行就不是有效行.我们之前在添加断点的时候,并没有对行号进行检查,任何行号都能成功 ...

  5. SQL从零到迅速精通【数据库应用】

    数据库理论的研究主要集中于关系规范化理论和关系数据理论等.数据库技术与计算机技术的结合使得数据库中新的技术层出不穷.最初的数据库系统主要应用于银行管理.飞机订票等事务处理环境.后来渐渐应用于工程设计与 ...

  6. 神奇的 CSS,让文字智能适配背景颜色

    最近几天,有好几个同学都问了同样一个问题. 页面上有一段文本,能否实现这段文本在不同背景色下展示不同的颜色?也就是俗称的智能变色.像是下面这样: 文本在黑色底色上表现为白色,在白色底色上表现为黑色.看 ...

  7. 翻译 | Kubernetes 将改变数据库的管理方式

    作者:Álvaro Hernández 当技术决策人考虑在 Kubernetes 上部署数据库时,面临的第一个问题就是:"Kubernetes 有应对有状态服务的能力吗?"多年来的 ...

  8. Windows下载安装RabbitMQ教程-------报错卸载重新安装 (要卸载干净 -看下文)

    Could not update enabled plugins file at c:\Users\忙聸鹿忙聳掳忙聰戮\AppData\Roaming\RabbitMQ\enabled_plugins ...

  9. Java基础——自动装箱与拆箱

    装箱:把基本数据类型转换为对应的包装类类型 //装箱Integer i=Integer.ValuesOf(100);//自动装箱integer i1=100;//能够直接赋值成功的称为自动装箱,也调用 ...

  10. 更新或添加properties文件(保留存在的properties文件的原有格式)

    转载: https://www.cnblogs.com/wangzhisdu/p/7815549.html import java.io.BufferedWriter; import java.io. ...