尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

学习记录与.rodata

学习记录与.rodata 目录前言.rodata 只读段Read‑Only Data与const修饰的变量为什么全局 const 变量不能指针强转修改.rodata 在 exe 磁盘文件 和 虚拟内存中的关系.rodata 到底属于哪一个大段容易混淆的案例为什么很多教材讲虚拟地址布局图不画.rodata全局初始化 const 与字符串常量rodata 细节rodata 属于.text 吗全局const int b什么时候在.rodata什么时候在.datarodata 还有什么东西放进去rodata 相关的易错综合辨析极易踩坑对比代码Linux 进程虚拟内存各段权限汇总运行时虚拟页区分磁盘 exe 文件 VS 运行时内存全部知识点总结前言虽然是我只是记录学习但是这个CSDN文章评分真是太怪了。上一篇没采用问答式写法掺了点自己看法结果评分还没有问答高。这篇就还是以问答式记录吧。.rodata 只读段Read‑Only Data前置回忆.text段存放程序机器指令.data存已经初始化的全局变量.bss存放未初始化全局变量。.rodata 是只读数据段属于可执行程序 exe 磁盘文件中的段程序加载时映射到进程虚拟地址空间。专门存放不会被修改的常量数据 **。**最典型例子字符串字面量。cchar *p hello world;hello world这个字符串常量编译的时候就被放进.rodata段。 它不在栈不在堆不在.data放在.rodata。⚠️关键这块内存硬件层面标记为只读CPU 不允许写操作。试图修改它程序直接崩溃段错误。检验问题3 题请你回答.rodata里面存放什么类型的数据char *phello;字符串hello存放在哪个段尝试修改p[0]x为什么程序会崩溃你回复这三道题答案有额外疑问也可以一起提出来。答完我继续下一小段讲解。1.不会被修改的常量数据2.rodata段3.因为p[0]属于可rodata段 只能读取✅全部答对。补充一点细节是操作系统页表把.rodata 对应的物理页设置成只读权限硬件 MMU 检测到写操作触发保护异常程序报段错误直接终止。与const修饰的变量并不是所有带const修饰的变量都会进入.rodata。 这是考研最高频的坑点。c// ①全局const变量 const int g_val 100; void test(void) { //②局部const变量 const int local_val 200; }全局的const int g_val 100;放在.rodata硬件只读绝对不能写。函数内部const int local_val 200;存放在栈上不是.rodataconst在这里仅仅只是 C 语言编译器的语法检查不是硬件内存保护。局部 const 变量只是编译器不让你直接修改。你用指针强转绕开编译器检查是可以改写栈上这份内存不会触发段错误崩溃。cconst int local_val 200; int *p (int *)local_val; *p 999; // 可以修改成功程序不会崩溃重点区分.rodata硬件层面只读写直接崩溃栈上局部 const仅编译器语法层面只读指针强转就能篡改检验 3 道题函数里面const int a 10;变量 a 存放在哪个位置全局const int b 20;变量 b 存放在哪个段为什么指针强转修改局部 const 不会段错误修改字符串字面量就会段错误请给出你的答案有疑问可以一并提出。1.栈上2.rodata段3.为什么全局变量不能通过指针去强改为什么全局 const 变量不能指针强转修改cconst int g_val 100; int* p (int *)g_val; *p 999;g_val在.rodata。 .rodata 虚拟页页表权限标记为禁止写。 哪怕你用指针强制转换只能骗过 C 编译器语法检查骗不过硬件 MMU。 CPU 执行写指令时MMU 查页表发现这一页没有写权限直接触发保护异常 → 段错误程序直接崩溃。强转 修改 C 语言的类型规则不能改变操作系统内存页的硬件读写权限。回到第 3 道考题完整参考答案字符串字面量存放在.rodata内存页硬件标记只读写操作触发硬件保护异常发生段错误 局部const变量在栈内存栈页本身拥有读写权限const仅仅是编译器语法限制。指针强转绕开编译检查后可以正常写栈内存硬件不会拦截不会崩溃。巩固 3 道检验题承接上面内容const关键字有哪两层保护分别是谁提供保护下面哪一段代码运行会发生段错误c//A void fun(){ const int x 10; int *q (int *)x; *q 100; } //B const int y 20; int *w (int *)y; *w 200;能不能说只要加了const修饰就一定放在.rodata为什么✅三道全部答对理解到位。 小结复盘局部const仅编译器语法保护内存在栈页可读写指针强转可篡改。全局const编译器 硬件双重保护存.rodata页表设置只读强转写直接段错误。.rodata 在 exe 磁盘文件 和 虚拟内存中的关系回忆之前学过.text、.dataexe 磁盘文件里保存完整真实数据程序启动操作系统把磁盘内容拷贝到虚拟内存对应段。.rodata 同样属于 exe 磁盘文件里面的段。编译链接完成之后字符串字面量、全局 const 常量就已经写进 exe 的.rodata段保存在硬盘。程序运行时操作系统把 exe 的.rodata映射到进程虚拟地址空间。⚠️注意这里是映射不是一定立刻把全部数据拷贝进物理内存。 遵循请求分页机制只有 CPU 第一次访问这条常量的时候才会发生缺页异常操作系统把磁盘上 rodata 内容加载进物理内存同时给这一页设置只读权限。对比.bss加深理解.rodataexe 磁盘文件存有真实数据。.bssexe 磁盘几乎不存数据仅仅记录需要多大空间运行时直接填 0。三道检验题.rodata段的数据磁盘 exe 文件中是否真实保存rodata 的数据是程序一运行就全部复制到物理内存吗和.bss 对比rodata 与 bss 在 exe 磁盘文件存储上的核心差别是什么写出你的答案有疑问可以一起问。1.是2.不是 需要第一次访问并分配物理页框3..bss只存数据多大不存具体数值而rodata存具体数值rodata到底属于哪一个大段✅三道回答全部正确。.rodata 到底属于哪一个大段在链接后的 exe 可执行文件目标文件视角.text、.rodata经常会被链接器合并到同一个代码段 (Code Segment)。代码段放机器指令 只读常量。 所以磁盘文件层面rodata 属于代码段 Code Segment 的一部分。在进程虚拟地址空间运行内存视角虚拟地址空间不再严格区分代码段内部子段。 只是两块虚拟内存页一部分页.text存放机器指令只读 可执行。另一部分页.rodata存放只读常量只读、不可执行。重要考研易错.text可读、可执行不能写.rodata只读不可执行二者权限不一样不能认为 rodata 就是 text。链接时磁盘文件可以合并运行时内存页权限可以分开。容易混淆的案例cchar str1[] hello; char *str2 hello;char str1[] hello;数组在栈上开辟内存。程序启动把 rodata 里的hello拷贝一份到栈数组。栈内存可读可写str1[0]A合法不会崩溃。char *str2 hello;指针变量str2本身在栈指针指向的字符串字面量hello存放在.rodata。str2[0]A写 rodata段错误崩溃。核心区分[]数组会发生拷贝*指针直接指向 rodata 原始常量。检验三道题磁盘 exe 文件中rodata 经常和哪个段合并为代码段运行时内存二者权限有什么区别char str[]test;字符串test原始常量放在哪里运行时 str 数组本体存放在哪里char* ptest;指针 p 本身存放在哪里test存放在哪里作答有疑问继续提。1.text text可读可执行rodata只能读和执行2.data 栈上3.栈上rodata为什么学习虚拟空间布局的时候没有提到rodata先订正第 1 题小错误.rodata只读不可执行不能执行.text可读、可执行、禁止写。 CPU 不会把 rodata 里面的数据当成指令跑。第 2 题订正原始常量test放在.rodata不是.data数组本体 str 在栈上 ✔。 第 3 题答案正确指针 p 本身在栈字符串字面量存.rodata✔。为什么很多教材讲虚拟地址布局图不画.rodata教材简化绘图经典虚拟内存布局图只画出五大块.text、.data、.bss、堆、栈。 很多书籍把.rodata 归到.text 代码段内部画图不单独画出。 磁盘目标文件链接器经常把.text与.rodata合并成代码段。 所以简图直接写代码段(.text)内部包含机器指令 只读常量图上就不单独标出 rodata。考研 408 特点408 大纲虚拟内存进程布局不会强制区分 text 与 rodata 但是 C 语言题目会考字符串常量存放在.rodata段错误根源属于 C 语言 操作系统交叉坑。真实 Linux 内存映射 运行程序cat /proc/[pid]/maps你能看到一块权限r-x.text读、执行一块权限r--.rodata仅读不能执行 真实运行环境二者是分开两块虚拟内存权限不一样。考试简图省略真实运行是两个不同内存区域。一句话总结画图省略 ≠ 内存不存在。简图把 rodata 藏进代码段实际运行独立权限不同。全局初始化 const 与字符串常量rodata 细节cconst int a 100; char* s abcd;二者都放在.rodata但是有一个细节 只有编译期就能确定的常量才会放进.rodata。如果是下面这种cint num 10; const int b num;b是全局 const但它的值要运行时才确定不能放到 rodata放到.data段。rodata 存放的是编译阶段就可以算出来的常量。运行时才得到的值就算 const 也进不去 rodata。三道检验题运行时环境.text与.rodata内存页权限分别是什么const int b num;num 是全局变量b 也是全局 constb 能否放入.rodata为什么为什么很多教科书进程虚拟内存布局图看不到.rodata请回答有疑问继续问。1.可读可写可执行2.不能 因为b需要执行后才能得到确定的值3.因为属于textrodata属于text吗还有全局变量const int b 为什么在radata为什么我记得在data里边存放呢先订正第 1 题.text可读、可执行、不可写 (r‑x).rodata只读、不可执行、不可写 (r‑‑)❌不是可读可写。写这两个段都会触发段错误。你的答案正确不能放入 rodata值运行时才确定。第 3 题半对磁盘 exe 文件链接阶段可以合并进 text代码段但运行时虚拟内存二者是分开的两块区域rodata 不属于 text。rodata 属于.text 吗✅磁盘 exe链接后链接器可以把.text.rodata合并为「代码段 Code Segment」只是文件层面的合并。✅程序运行、加载到虚拟内存之后二者完全分开不是同一个段.text权限r‑x放机器指令可以 CPU 执行。.rodata权限r‑‑放常量数据绝对不能执行。关键文件上可以合并内存运行时拆开权限不一样运行时 rodata 不属于.text。考试做题区分开。全局const int b什么时候在.rodata什么时候在.datac//情况A编译期常量编译就能算出数值 const int b 100;100编译期间就知道放在 .rodata硬件只读。c//情况B值运行时才可以算出 int num 20; const int b num;num是变量程序跑起来才知道 num 的值。编译器编译阶段拿不到 b 的数值。 此时 b 是全局 const存放在 .data 段.data段页面权限是可读可写。这里注意虽然加了 const只是 C 编译器语法不让直接修改。你指针强转写这个变量不会段错误可以改写成功因为所在页硬件允许写。总结表格表格定义存放段硬件页权限指针强转写的结果const int b100;.rodata只读 (r‑‑)段错误崩溃int num20; const int bnum;.data可读可写修改成功无崩溃你记忆的 “有的全局 const 在.data” 是正确的前提初始值不是编译期常量。 不是写了 const 就一定进 rodata硬性条件编译期就能确定最终数值。rodata 还有什么东西放进去除了字符串字面量、编译期全局 const。部分编译器下的浮点数常量编译期确定放进.rodata跳转表、常量数组const int arr[]{1,2,3}全局编译期确定存.rodata局部的const int arr[]{1,2,3}数组本体在栈运行时把常量拷贝到栈。cconst int arr[] {1,2,3}; //全局编译确定 → rodata void test(){ const int arr2[] {1,2,3}; //局部数组在栈上 }三道检验题运行状态下.text和.rodata的页权限分别是什么int x5; const int c x;全局 c 存放在哪个段指针强转修改会不会段错误为什么全局const int arr[]{1,3,5};存放在哪里局部const int arr2[]{1,3,5};数组本体存放在哪里作答有疑问继续抛出。1.可读可执行 不可读不可执行2.data 不会 因为data段可以修改3.rodata 栈上✅整体完成度很高订正第 1 题的小笔误.text可读、可执行、不可写r‑x.rodata只读、不可执行、不可写r‑‑rodata 是可读不是不可读。2、3 两题全部答对。 复盘第二题关键点虽然变量带const修饰但存放在.data内存页硬件拥有读写权限const仅编译器语法检查指针强转绕过后就可以改写不会触发段错误。rodata 相关的易错综合辨析把前面全部知识收拢做对比总结。记住一条铁律是否进入.rodata看两点①全局作用域②初始值编译期即可确定。两者缺一不可。局部const无论值是不是常量全部在栈永远不会进.rodata。cvoid test(){ const int a 100; //局部栈不是rodata }全局但是初值运行时才可以算出来进.data不进.rodata。cint m 10; const int b m; //全局但初值运行时确定 → .data全局 编译期常量 → 进入.rodata硬件只读。cconst int c 100; //全局编译就能确定100 → rodata字符串字面量abc无论写在函数内部还是全局位置字面量本体永远放在.rodata。cvoid test(){ char* p abc; // p在栈abc这个字符串本体rodata }极易踩坑对比代码cchar arr1[] hello; //数组栈上开辟空间拷贝rodata的helloarr1可修改 char* arr2 hello; //指针栈存指针直接指向rodata的hello写arr2段错误三道检验题局部const int x 500;x 能否存放到 rodata为什么全局const double pi 3.1415;pi 存放在哪个段指针强转修改会发生什么void fun(){ char* s linux; char buf[]linux; }说出linux字面量、s、buf 分别存储的位置。作答有疑问直接问。1.不能 因为在栈上2.rodata段 会报错3.“linux”在rodata s、buf在栈上请你列举出各个段的权限Linux 进程虚拟内存各段权限汇总运行时虚拟页表格段名存储内容页权限 (r‑w‑x)核心特点.text机器指令、程序代码r‑x可读、不可写、可执行唯一具备执行权限的段写入触发段错误.rodata字符串字面量、编译期常量全局constr‑‑可读、不可写、不可执行纯只读不能当作指令执行写直接段错误.data已初始化全局变量、static 局部变量有初值rw‑可读、可写、不可执行可以正常读写修改.bss未初始化全局变量、未初始化 static 变量rw‑可读、可写、不可执行程序启动由操作系统自动清零堆 (heap)malloc/realloc动态分配内存rw‑可读、可写、不可执行向上增长手动 free 释放栈 (stack)局部变量、栈帧、返回地址、函数参数rw‑可读、可写、不可执行向下生长函数调用自动开辟销毁权限符号说明 r read 读w write 写x execute 执行‑代表没有该权限三道检验题哪一个段具备执行权限.rodata能否执行代码向.bss写入数据会不会发生段错误理由.data、.bss、栈、堆权限全部一样吗写出你的答案有疑问随时提出。1.text2.不会 因为可写3.一样✅全部答对。 复盘重点整个进程虚拟地址空间只有.text拥有 x 执行权限rodata 只有读权限不能执行指令。.bss权限rw‑可读可写允许修改不会段错误只是程序刚启动时 OS 帮它全部置 0。.data/.bss/ 堆 / 栈 权限全部是rw‑权限完全一致只是存放的数据、生命周期、内存来源不一样。区分磁盘 exe 文件 VS 运行时内存表格段名磁盘 exe 文件是否保存真实数据加载到虚拟内存后.text保存机器指令映射请求分页加载权限r‑x.rodata保存常量真实数据映射请求分页加载权限r‑‑.data保存初始化变量真实值映射请求分页加载权限rw‑.bss不存实际数据只记录需要的空间大小运行时开辟空间操作系统清零权限rw‑堆exe 磁盘文件不存在堆进程运行之后 OS 新开辟malloc使用栈exe 磁盘文件不存在栈进程运行之后 OS 新开辟函数调用使用关键记忆堆、栈磁盘 exe 里面根本没有是程序跑起来操作系统才创建出来。三道检验题磁盘 exe 里面有没有栈和堆.bss在 exe 磁盘文件存储什么内容运行时操作系统做什么操作.rodata和.bss对比磁盘上最大区别是什么作答有不懂的地方直接提问。1.没有2.只记数据大小 开辟空间3. .bss只存数据大小 而.rodata存具体数全部知识点总结存放内容字符串字面量、编译期就能确定数值的全局 const 常量、全局 const 常量数组。磁盘 exe存在真实数据链接阶段可以和.text合并为代码段。运行内存二者分开。.textr‑x可读可执行不可写.rodatar‑‑只读不可写、不可执行const 两层保护局部const仅编译器语法检查变量在栈页权限rw‑指针强转可以篡改。全局编译期const编译器 硬件双重保护存.rodata写直接段错误。全局但运行时才能确定初值的const存入.data硬件允许写指针强转可以修改。char arr[]hellovschar*phellochar arr[]hello栈上开辟数组把.rodata 字符串拷贝过来可以修改。char* phellop 存栈直接指向.rodata 的字符串尝试写触发段错误。加载方式请求分页第一次访问发生缺页才把磁盘内容载入物理内存。和.bss区别.rodata磁盘保存真实常量.bss磁盘仅记录大小运行时清零。最终综合检验三道题全局const int a 10;与局部const int b 10;二者底层有什么本质区别存储位置、保护方式、指针强转后果const int num get();全局变量num 存放在哪个段指针强转修改会不会段错误为什么简述为什么.rodata不具备执行权限而.text要有执行权限作答全部做完.rodata知识点就彻底吃透。有任何疑问都可以问。1.a存在与rodata 由编译器和硬件保护 强转报错b在栈上受编译器保护可以通过指针强转2.data 不会 因为data允许修改3.第 1、2 题回答正确。第 3 题参考答案.text 存放机器指令CPU 需要把内存里面的二进制数据当作指令来译码执行所以必须赋予执行x权限。.rodata 只存放常量数据字符串、常量数值不是 CPU 指令这些内容只用来读取不需要被 CPU 执行。不给 rodata 执行权限是一种内存保护手段防止漏洞攻击者把恶意代码放在常量数据里哄骗 CPU 去执行提升程序安全性。一句话.text存指令需要跑.rodata存纯数据只供读不需要跑。
返回列表