当前位置: 首页 > article >正文

深入RISC-V链接脚本:从.lds文件看C程序的内存‘出生’与‘搬家’全过程

深入RISC-V链接脚本从.lds文件看C程序的内存‘出生’与‘搬家’全过程在嵌入式开发的世界里一个C程序从源代码到最终在硬件上运行经历了编译、链接和加载三个关键阶段。这个过程就像一个人的生命历程编译是出生链接是成长而加载运行则是独立生活。本文将带你深入RISC-V架构下的链接脚本(.lds文件)世界通过一个生动形象的比喻揭示C程序如何在内存中完成它的出生与搬家全过程。1. 程序的生命周期从源代码到运行当我们编写一个简单的C程序比如一个包含初始化变量、未初始化变量、函数和main()的代码它要经历几个关键阶段才能最终在RISC-V MCU上运行// 示例程序simple.c int initialized_var 42; // 已初始化全局变量 char uninitialized_array[64]; // 未初始化全局数组 void func() { static int local_static 0; // 局部静态变量 local_static; } int main() { func(); return 0; }这个简单的程序在变成可执行文件的过程中经历了以下转变编译阶段编译器将.c文件转换为.o目标文件此时代码(text)被编译为机器指令已初始化数据(data)被分配初始值未初始化数据(bss)仅保留大小信息符号表记录各个变量和函数的地址信息链接阶段链接器将多个.o文件和库合并根据链接脚本的指示确定各段(text/data/bss等)在内存中的最终位置解析和重定位所有符号引用生成完整的可执行文件(通常是ELF格式)加载运行阶段程序被加载到内存并执行代码段(text)被加载到Flash或RAM数据段(data)从Flash复制到RAMBSS段被清零栈和堆空间被初始化2. 链接脚本程序内存布局的建筑师链接脚本(.lds文件)是这个过程中的核心规划文件它决定了程序各个部分在内存中的布局。我们可以将其比作一个城市的规划师负责安排住宅区(代码)、商业区(数据)、公共设施(栈/堆)等在城市(内存)中的位置。2.1 基本结构解析一个典型的RISC-V链接脚本包含以下几个关键部分/* 内存区域定义 */ MEMORY { FLASH (rx) : ORIGIN 0x00000000, LENGTH 64K RAM (xrw) : ORIGIN 0x20000000, LENGTH 20K } /* 入口点 */ ENTRY(_start) /* 段布局 */ SECTIONS { .text : { *(.text*) } FLASH .data : { *(.data*) } RAM ATFLASH .bss : { *(.bss*) } RAM .stack : { ... } RAM }关键概念对比表概念类比说明MEMORY城市用地规划定义可用的内存区域及其属性SECTIONS功能区划分安排各个段在内存中的位置VMA工作地点程序运行时使用的地址LMA居住地点数据实际存储的地址定位符(.)城市规划指针当前的内存位置可向前移动2.2 内存区域(MEMORY)定义MEMORY命令定义了系统的内存地图就像城市规划中划分住宅区、商业区一样MEMORY { FLASH (rx) : ORIGIN 0x00000000, LENGTH 64K /* 只读可执行 */ RAM (xrw) : ORIGIN 0x20000000, LENGTH 20K /* 可读写可执行 */ }属性标志说明r- 只读w- 可写x- 可执行a- 可分配l- 已初始化3. 关键段的重定位数据段的搬家过程在嵌入式系统中RAM通常比Flash快但容量小且断电后数据会丢失。因此我们需要精心安排数据在存储(Flash)和运行(RAM)时的不同位置。3.1 LMA与VMA数据的住所与工作场所LMA(Load Memory Address)数据在Flash中的存储地址VMA(Virtual Memory Address)数据在RAM中的运行地址链接脚本中通过REGION ATLMA_REGION语法指定.data : { _data_vma .; /* VMA起始地址 */ *(.data*) _edata .; /* VMA结束地址 */ } RAM ATFLASH /* VMA在RAMLMA在FLASH */ _data_lma LOADADDR(.data); /* 获取LMA起始地址 */3.2 启动时的数据搬运系统启动时需要将.data段从Flash(LMA)复制到RAM(VMA)。这个过程通常在启动文件中用汇编实现/* 数据段搬运代码 */ la a0, _data_lma /* 源地址(Flash)加载到a0 */ la a1, _data_vma /* 目标地址(RAM)加载到a1 */ la a2, _edata /* 结束地址加载到a2 */ 1: lw t0, (a0) /* 从Flash加载一个字 */ sw t0, (a1) /* 存储到RAM */ addi a0, a0, 4 /* 源地址4 */ addi a1, a1, 4 /* 目标地址4 */ bltu a1, a2, 1b /* 循环直到搬运完成 */数据搬运过程示意图Flash (LMA) → RAM (VMA) ------------ ------------ | 初始值42 | → | 运行时值42 | | 初始值0 | → | 运行时值0 | | ... | → | ... | ------------ ------------4. 特殊段的处理BSS与栈/堆4.1 BSS段未初始化数据的清零BSS段包含未初始化的全局和静态变量链接时只需知道大小运行时需要清零.bss : { _sbss .; /* BSS起始地址 */ *(.bss*) *(COMMON*) _ebss .; /* BSS结束地址 */ } RAM启动代码中的清零操作/* BSS段清零 */ la a0, _sbss /* 起始地址 */ la a1, _ebss /* 结束地址 */ 1: sw zero, (a0) /* 存储0 */ addi a0, a0, 4 /* 地址4 */ bltu a0, a1, 1b /* 循环直到结束 */4.2 栈与堆的动态内存管理栈和堆是程序运行时动态使用的内存区域它们的布局通常在链接脚本中定义/* 堆定义 */ _end .; /* 堆起始地址(紧接BSS) */ _heap_end ORIGIN(RAM) LENGTH(RAM) - __stack_size; /* 堆结束地址 */ /* 栈定义 */ .stack : { _stack_start .; . __stack_size; _stack_end .; } RAM内存布局示例------------------- 0x20000000 | 已初始化数据(data) | ------------------- | 未初始化数据(bss) | ------------------- | 堆空间(heap) | | ... | ------------------- | 栈空间(stack) | ← 栈指针(sp) ------------------- 0x200050005. 高级技巧与实战建议5.1 全局指针优化RISC-V的gp(全局指针)寄存器可以优化全局变量访问。链接脚本中定义.data : { /* ... */ . ALIGN(8); PROVIDE( __global_pointer$ . 0x800 ); /* gp指向中间位置 */ /* ... */ } RAM ATFLASH启动代码中初始化gp.option push .option norelax la gp, __global_pointer$ /* 加载gp寄存器 */ .option pop5.2 链接脚本调试技巧生成内存映射文件riscv-none-embed-ld -T script.ld -Mapoutput.map ...关键符号检查riscv-none-embed-nm -n output.elf段大小分析riscv-none-embed-size -A output.elf5.3 常见问题解决方案问题1数据未正确搬运导致变量值异常排查检查链接脚本中_data_lma和_data_vma定义确认启动代码中的搬运逻辑正确使用调试器查看内存内容问题2栈溢出导致程序崩溃解决增大链接脚本中的__stack_size添加栈使用量检查.stack : { ASSERT((. (ORIGIN(RAM) LENGTH(RAM))), Error: Stack overflow); /* ... */ }问题3全局变量访问效率低优化合理设置__global_pointer$将频繁访问的变量放入.sdata段使用-mcmodelmedany编译选项

相关文章:

深入RISC-V链接脚本:从.lds文件看C程序的内存‘出生’与‘搬家’全过程

深入RISC-V链接脚本:从.lds文件看C程序的内存‘出生’与‘搬家’全过程 在嵌入式开发的世界里,一个C程序从源代码到最终在硬件上运行,经历了编译、链接和加载三个关键阶段。这个过程就像一个人的生命历程:编译是"出生"&…...

qmc-decoder:专业QMC音频文件解密转换工具

qmc-decoder:专业QMC音频文件解密转换工具 【免费下载链接】qmc-decoder Fastest & best convert qmc 2 mp3 | flac tools 项目地址: https://gitcode.com/gh_mirrors/qm/qmc-decoder qmc-decoder是一款高效、专业的QMC音频文件解密转换工具,…...

MLIR编译器技术:分层IR设计与AI加速实践

1. MLIR与编译器技术概述 编译器技术作为计算机科学的基础设施,长期以来扮演着将高级语言转换为机器码的关键角色。传统编译器如GCC、LLVM采用固定层次的中间表示(IR),这在通用计算时代表现良好。但随着AI和高性能计算领域对异构硬…...

Diablo Edit2:终极暗黑破坏神2存档编辑器完全指南

Diablo Edit2:终极暗黑破坏神2存档编辑器完全指南 【免费下载链接】diablo_edit Diablo II Character editor. 项目地址: https://gitcode.com/gh_mirrors/di/diablo_edit 你是否厌倦了在暗黑破坏神2中反复刷装备的枯燥过程?是否因为技能点分配失…...

ComfyUI-Manager插件不显示问题终极指南:从原理到实战的完整解决方案

ComfyUI-Manager插件不显示问题终极指南:从原理到实战的完整解决方案 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable…...

Beyond Compare 5 开源密钥生成器:逆向工程与授权机制的深度解析

Beyond Compare 5 开源密钥生成器:逆向工程与授权机制的深度解析 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 在软件安全与逆向工程领域,授权验证机制始终是开发者与安…...

【实战避坑】从清华源手动下载到权限修复:一站式解决d2l安装疑难杂症

1. 为什么你的d2l安装总是失败?从下载到权限的全流程避坑指南 每次看到"动手学深度学习"课程里那些酷炫的案例,你是不是也迫不及待想动手试试?但现实往往很骨感——光是安装d2l这个入门包就能卡住80%的新手。我见过太多人在第一步就…...

别再硬算幂函数了!FPGA图像处理中,用查找表(LUT)实现伽马校正的完整流程与资源优化

别再硬算幂函数了!FPGA图像处理中,用查找表(LUT)实现伽马校正的完整流程与资源优化 在实时图像处理系统中,伽马校正(Gamma Correction)是一个无法绕开的关键环节。无论是医疗影像的增强显示&…...

抖音无水印视频下载神器:3分钟快速上手,轻松保存高清无水印视频

抖音无水印视频下载神器:3分钟快速上手,轻松保存高清无水印视频 【免费下载链接】douyin_downloader 抖音短视频无水印下载 win编译版本下载:https://www.lanzous.com/i9za5od 项目地址: https://gitcode.com/gh_mirrors/dou/douyin_downlo…...

这3个降AI提示词千万别用!让你的知网AI率反涨10个点过不了AIGC检测

这3个降AI提示词千万别用!让你的知网AI率反涨10个点过不了AIGC检测 室友的真实事故——降 AI 提示词用错知网 AI 率反涨 3 月 19 号晚上室友哭着发消息:「我上网搜了一个降 AI 万能提示词改完段落送知网测——AI 率从 67% 涨到 77% 了!这怎…...

深入解析Spring Boot启动流程:从SpringApplication.run()到应用就绪

1. 项目概述:为什么我们需要深入理解SpringApplication.run()如果你是一个Java开发者,尤其是使用Spring Boot框架的,那么SpringApplication.run(YourApplication.class, args)这行代码对你来说一定不陌生。它几乎是每个Spring Boot应用的启动…...

本事同根生,相煎何太急

简 介: 【轮腿组比赛难度调整建议】针对智能车竞赛轮腿穿越组室外赛道的视觉识别难题,参赛选手提出以下建议:1.科目三元素应避开塑胶跑道线干扰区域;2.当前轮腿组任务量(机械、控制、导航、视觉等)已远超往…...

HART协议实战:从帧结构解析到MCU数据处理的完整代码指南

1. HART协议基础与帧结构解析 第一次接触HART协议时,我被它独特的"模拟信号数字信号"叠加方式惊艳到了。想象一下,在工业现场常见的4-20mA模拟信号线上,还能叠加数字通信信号,就像在一条老式电话线上同时传输语音和宽带…...

教育大模型EduChat:从部署到应用的全链路实践指南

1. 项目概述:当教育遇上大语言模型 作为一名长期关注教育技术与人工智能交叉领域的研究者和实践者,我见证过太多“AI教育”的概念从喧嚣到沉寂。直到最近几年,以ChatGPT为代表的大语言模型(LLM)横空出世,才…...

MoviePilot连接TMDB异常的终极诊断指南:5步快速排查与完整解决方案

MoviePilot连接TMDB异常的终极诊断指南:5步快速排查与完整解决方案 【免费下载链接】MoviePilot NAS媒体库自动化管理工具 项目地址: https://gitcode.com/gh_mirrors/mo/MoviePilot MoviePilot作为NAS媒体库自动化管理工具,其核心功能依赖TheMov…...

在VSCode+GCC+STM32环境中实现非阻塞式串口调试:中断驱动的printf重定向实践

1. 为什么需要非阻塞式串口调试 在嵌入式开发中,串口调试就像是我们和硬件对话的"嘴巴"和"耳朵"。想象一下,当你和朋友聊天时,如果每次说话都要等对方完全听完才能做其他事情,那该有多难受?传统的…...

别再写for循环了!用Java8的groupingBy分组统计,5分钟搞定报表数据聚合

告别繁琐循环:Java8 groupingBy让数据聚合优雅如诗 当我们需要从数据库查询结果中生成各类业务报表时,那些重复的for循环是否已经让你感到厌倦?比如按地区统计销售额、按部门计算平均年龄,传统做法往往需要编写大量样板代码。而Ja…...

BurpSuite实战:从代理配置到漏洞扫描的完整工作流解析

1. BurpSuite入门:代理配置与证书安装 第一次打开BurpSuite时,那个黑底红字的启动界面总让我想起黑客电影里的场景。不过别被吓到,这其实是个非常友好的Web安全测试工具。我刚开始用的时候,最头疼的就是代理配置问题。这里分享下…...

EVPN实战解析:分布式网关部署与关键配置精要

1. 为什么需要EVPN分布式网关? 在多租户数据中心网络环境中,虚拟机迁移和三层互通是刚需。传统集中式网关就像只有一个出入口的大型停车场,所有车辆必须绕道中央区域才能到达目的地,而分布式网关则相当于在每个楼层都设置了出入口…...

为什么你需要Scroll Reverser?macOS滚动方向独立控制的终极解决方案

为什么你需要Scroll Reverser?macOS滚动方向独立控制的终极解决方案 【免费下载链接】Scroll-Reverser Per-device scrolling prefs on macOS. 项目地址: https://gitcode.com/gh_mirrors/sc/Scroll-Reverser 在macOS上使用触控板和鼠标时,你是否…...

macOS微信防撤回终极指南:3分钟轻松安装WeChatIntercept插件

macOS微信防撤回终极指南:3分钟轻松安装WeChatIntercept插件 【免费下载链接】WeChatIntercept 微信防撤回插件,一键安装,仅MAC可用,支持v3.7.0微信 项目地址: https://gitcode.com/gh_mirrors/we/WeChatIntercept 还在为微…...

Wwise与Godot音频集成:专业游戏音频中间件在开源引擎中的实现

1. 项目概述:连接两大巨头的桥梁如果你是一位游戏音频设计师,或者是一位对游戏音频实现有追求的开发者,那么“Wwise”和“Godot”这两个名字对你来说一定不陌生。Wwise是业界顶级的交互式音频中间件,以其强大的音频逻辑编排、动态…...

Python应用性能监控实战:New Relic探针架构与部署指南

1. 项目概述:一个现代应用性能管理的Python探针如果你正在用Python开发Web应用、微服务或者任何需要对外提供服务的后端系统,那么“性能”和“可观测性”这两个词一定不会陌生。当线上服务突然变慢、错误率飙升,或者用户反馈某个接口卡顿时&a…...

终结摄像头依赖:深度拆解 RuView,用商品化 Wi-Fi 信号构建私密、实时的边缘空间智能

发布日期: 2026-02-15 标签: #无线感知 #WiFi感知 #边缘AI #CSI #生命体征监测 #空间智能 一、 引言 在智能家居、智慧医疗和工业安防的落地过程中,传统的“摄像头方案”始终面临着两大难以调和的工程痛点:隐私泄露的法律风险以…...

aitextgen与GPT-2-simple对比:为什么aitextgen是更好的选择

aitextgen与GPT-2-simple对比:为什么aitextgen是更好的选择 【免费下载链接】aitextgen A robust Python tool for text-based AI training and generation using GPT-2. 项目地址: https://gitcode.com/gh_mirrors/ai/aitextgen aitextgen是一个强大的Pytho…...

别再手动画甘特图了!用VS Code插件MarkWhen,写几行文本就能生成炫酷时间轴

用MarkWhen在VS Code中打造极简时间轴:告别繁琐拖拽,拥抱文本化项目管理 在数字时代,时间管理和项目规划已经成为每个高效能人士的必修课。无论是开发者跟踪项目里程碑,学生规划学习路径,还是个人记录生活轨迹&#xf…...

跟着 MDN 学 HTML day_55:HTML 音频与视频嵌入实战指南

在现代网页设计中,多媒体内容已经成为提升用户体验的核心元素。无论是背景音乐、播客节目,还是产品演示视频,都离不开 HTML 中的音频和视频嵌入技术。HTML5 为我们提供了原生的 audio 和 video 元素,使得在网页中嵌入媒体内容变得…...

Microsoft Defender for Cloud AI工作负载安全:防范越狱攻击的终极方案

Microsoft Defender for Cloud AI工作负载安全:防范越狱攻击的终极方案 【免费下载链接】Microsoft-Defender-for-Cloud Welcome to the Microsoft Defender for Cloud community repository 项目地址: https://gitcode.com/gh_mirrors/mi/Microsoft-Defender-for…...

【紧急更新】Perplexity v3.2.1已悄然移除默认引用锚点!立即启用这4种透明度兜底机制保学术安全

更多请点击: https://intelliparadigm.com 第一章:Perplexity引用透明度优化的紧急背景与影响评估 在大型语言模型推理链(Chain-of-Thought)与多跳检索增强生成(RAG)系统中,Perplexity 作为核心…...

别再复制官网代码了!Vue + Ant Design 图标与分隔符的本地化实战(附避坑指南)

Vue Ant Design 图标与分隔符的本地化实战指南 在Vue项目中使用Ant Design Vue组件库时,很多开发者习惯直接从官网复制示例代码。然而,这种"拿来主义"常常导致项目运行时出现图标不显示、样式依赖CDN资源等问题。本文将带你从零开始&#xff…...