Audio DSP 链接脚本文件解析
上篇文章(智能手表音乐播放功耗的优化)讲了怎么优化音乐场景下的功耗,其中第二点是优化memory的布局。那么在哪里优化memory的布局呢?就是在本文要讲的链接脚本(ld)文件里。作为audio DSP 软件工程师,ld文件要能看懂和会修改。作为程序来说,先编译后链接。编译得到目标文件,链接就是把这些目标文件合成一个输出文件。链接过程都由链接脚本控制,链接脚本主要用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分在程序地址空间内的布局。链接脚本有其语法,把语法搞懂了,就能看懂和会修改ld文件。本文就通过具体的例子来解析ld文件,使其通俗易懂。
链接脚本语法中有很多关键字,如OUTPUT等。本文要举的例子中都是一些基本的。如在工作中遇到没见过的,可以去网上搜,搞清楚意思,并能应用就可以了。我把例子按前后顺序分成了5张图,下面具体来看。
图1是ld文件的开头部分。
图 1
蓝框1处是关键字OUTPUT,格式为OUTPUT(filename),表示执行ld文件后的输出文件是什么。在CEVA DSP上,输出是elf文件。Elf文件是可执行链接文件,是执行链接的产物(编译后的产物是*.o),elf文件可以在CEVA的IDE集成开发环境上运行,但是不能在芯片上运行。要想在芯片上运行,需要将其转化为bin。至于怎么转,后面再讲。蓝框2处是关键字ENTRY,格式为ENTRY(symbol),是将symbol设为软件的入口地址,即程序执行的第一条指令。图1中symbol为__cxd_inttbl_start ,在代码中就相当于一个全局变量,表示软件从__cxd_inttbl_start开始运行。__cxd_inttbl_start在crt0.c文件里用到。Crt表示c runtime,0表示最开始。后面准备写一篇adsp boot的文章,到时再具体讲crt0.c。
图2是ld文件的第二部分。
图 2
蓝框3定义了各块Memory的起始地址和大小等各种变量,是给蓝框4中的关键字MEMORY用的。ADSP可用的memory包括内部的ITCM、DTCM以及外部的DDR、SRAM以及ROM等(ASIC设计时就可以让ADSP访问外部的DDR、SRAM、ROM)。例子中定义了DDR中可用的起始地址是0x29000000,可用大小是0x40000(这是与AP协商的结果)。也定义了ITCM/DTCM的起始地址均是0x0,大小都是128k。还定义了ROM的大小是128k,起始地址是0xc0860000,其中96k用来放code,32k用来放data。蓝框4中用关键字MEMORY描述了各块memory的起始地址和大小,其中用INTERNAL_CODE表示ITCM,INTERNAL_DATA表示DTCM。MEMORY的语法如下:
NAME表示memory名称,ORIGIN表示起始地址,LENGTH表示大小,ATTR表示属性(w表示可写,r表示可读, x表示可执行)。
图3/4/5就是各个section的具体内容。先从图3看起。
图 3
蓝框5是关键字SECTIONS,格式为SECTIONS { },大括号内是各个具体的section。蓝框6/7/8是三个section,均放在DDR(DDR_MEM)上。先看蓝框6。Section SLOW_I_RAM 从名字看出里面放的是指令(instruction, 即I),也就是code。关键字ALIGN表示字节对齐。从图中看出这一section开始处要4k(0x1000)对齐。要4k对齐的原因是这一section放的是code,为了加快访问速度,要设置cache属性为cacheable,cache要求4k对齐。. += __rom_check_shift中.是定位符,表示当前位置的地址。.开始表示section SLOW_I_RAM的起始地址,后来又自加了__rom_check_shift个字节。举个例子,假设section SLOW_I_RAM的起始地址是0x29000000,__rom_check_shift等于4。开始时.就表示地址0x29000000,加4后.就表示地址0x29000004。__rom_check_shift是用于做ROM的,做完ROM后这个值要变为0(关于怎么做ROM,可以见文章在audio DSP中如何做软件固化)。关键字PROVIDE用来定义一个符号,可以理解为定义了一个全局变量,这个全局变量可以在代码里用。关键字ABSOLUTE表示取绝对值。PROVIDE(__DDR_CODE_CACHED_START = ABSOLUTE(.))就表示定义个一个全局变量__DDR_CODE_CACHED_START,用它来指定要cached的code的起始地址,这个起始地址是用定位符获取的。*(IPC_SLOW_CODE)等表示这个section上放哪些具体的代码模块。放完code 段后又加了个PROVIDE(__DDR_CODE_CACHED_END = ABSOLUTE(.)),表示要cached的code的结束地址。这两个全局变量均用在配置memory的cache属性里,这一段放code,要配成cacheable。再来看蓝框7。从名字CONST_D_RAM看出是放常量的,属于data。为了加快访问速度,依旧要用配置成cacheable,所以用PROVIDE(__DDR_DATA_CACHED_START = ABSOLUTE(.))来指定要cache的起始地址,然后后面放数据段。最后看蓝框8,依旧是放data,不过是未初始化的,运行时不需要载入memory,所以用了关键字NOLOAD。关键字NOLOAD表示运行时不用载入memory。最后用PROVIDE(__DDR_DATA_CACHED_END = ABSOLUTE(.))来指定要cached的结束地址。蓝框7和蓝框8都是放data,只不过一个放的是常量等,一个放的是未初始化的。这两段都要配置成cacheable,所以cache的起始地址是蓝框7的开始处,结束地址是蓝框8的结束处。
再来看图4,它是关于ROM的。ROM是事先做好的,ld文件里有这两个section有两个目的。一是让它参与链接,得到ROM里函数和数据的地址,去与事先做好的比较,看是否改变。如果改变了,说明有问题,需要去解决,直到得到的地址与事先做好的完全一样。二是得到需要cache的起始和结束地址。ROM也算片外,为了加快速度,也需要用cache,包括code和data的。
图 4
图4展示了ROM里code(L2_I_ROM,蓝框9)和data(L2_D_ROM,蓝框10)段的内容。依旧要设置要cache的起始地址和结束地址。这里就不细讲了。
最后看图5,是关于ITCM和DTCM的。ITCM的放code,DTCM的分成两部分:常量和已初始化的以及bss上的。放bss上的包括未初始化的data以及各个任务用的栈等。这一部分不需要载入memory, 所以用了NOLOAD。
图 5
图3/4/5分别代表放在DDR/ROM/内部memory上。典型场景的code和data尽量放在内部memory上,非典型场景的code和data最好放在外部DDR上。
前文说了,链接的输出是elf文件,不能在芯片上运行。要想在芯片上运行,需要写个应用程序将其转化为bin,bin里包括运行时要load进memory的section。Ld文件里这么多section,哪些要放进bin里?就是上面那些section里没有用NOLOAD关键字的。ROM由于事先已经做好,两个section也不需要放进bin。总结就是DDR放code的section和放常量和已初始化数据的section以及ITCM上的section和DTCM上放常量和已初始化数据的section这4部分要放进bin里。boot时把DDR的section内容放到DDR上,把ITCM的内容拷进ITCM里,把DTCM的内容拷进DTCM里,系统就能正常运行了。
Audio DSP 链接脚本文件解析的更多相关文章
- makefile使用.lds链接脚本以及 $@ ,$^, $,< 解析
先来分析一个简单的.lds链接脚本 例1,假如现在有head.c init.c nand.c main.c这4个文件: 1.1 首先创建链接脚本nand.lds: SECTIONS { firtst ...
- makefile使用.lds链接脚本以及 $@ ,$^, $,< 解析【转】
转自:http://www.cnblogs.com/lifexy/p/7089873.html 先来分析一个简单的.lds链接脚本 例1,假如现在有head.c init.c nand.c main. ...
- JMeter——jmx脚本文件解析
<!--Jmeter版本信息--> <?xml version="1.0" encoding="UTF-8"?> <jmeterT ...
- 链接脚本(Linker Scripts)语法和规则解析(自官方手册)
为了便于与英文原文对照学习与理解(部分翻译可能不准确),本文中的每个子章节标题和引用使用的都是官方手册英文原称.命令及命令行选项统一使用斜体书写.高频小节会用蓝色字体标出. 3 Linker Scri ...
- [转]Linux下的lds链接脚本详解
转载自:http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml 一. 概论 每一个链接过程都由链接脚本(lin ...
- Linux下的lds链接脚本简介
转载:http://hubingforever.blog.163.com/blog/static/171040579201192472552886/ 一. 概论 每一个链接过程都由链接脚本(lin ...
- [转]Linux下的链接脚本基础
[转]http://linux.chinaunix.net/techdoc/beginner/2009/08/12/1129972.shtml 1. 前言 (1)每一个链接过程都由链接脚本(linke ...
- Linux下的lds链接脚本详解【转】
转自:http://www.cnblogs.com/li-hao/p/4107964.html 转载自:http://linux.chinaunix.net/techdoc/beginner/2009 ...
- Linux下的lds链接脚本详解
1. 概论2. 基本概念3. 脚本格式4. 简单例子5. 简单脚本命令6. 对符号的赋值7. SECTIONS命令8. MEMORY命令9. PHDRS命令10. VERSION命令11. 脚本内的表 ...
- Linux下的lds链接脚本基础
转载:http://soft.chinabyte.com/os/104/12255104.shtml 今天在看uboot引导Linux部分,发现要对链接脚本深入了解,才能知道各个目标文件的内存分布 ...
随机推荐
- JVM中线程的状态以及状态间的转换
线程在一定条件下,状态会发生变化.线程一共有以下几种状态: 新建状态(New):新创建了一个线程对象. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的 ...
- C# HOOK 键盘事件
C# HOOK 键盘事件 /* by: wgscd date:2023-8-15 desc: test hook in c# */ using System; using System.Collect ...
- 第一章 Java集合框架
----------------------------------------------------------------------------- Java集合框架(一)-ArrayList ...
- weixueyuan-Nginx Web服务4
https://www.weixueyuan.net/nginx/web/ Nginx静态资源服务器搭建 HTML 是一种标记语言,提供 HTML 文件读取是静态服务器最基本的功能,静态服务器的配置样 ...
- .NET 9 new features-C#13新的锁类型和语义
C# 13 中,引入了新的锁类型和语义,主要用于增强多线程编程中的同步机制. 传统上,C# 使用 lock 关键字与任意的 object 实例配合,实现线程间的互斥访问.然而,这种方式可能存在性能瓶颈 ...
- 一文搞懂 结构伪类 :nth-child && :nth-of-typ
结构伪类 从使用结构伪类的选择器开始 往上一层父辈开始筛选 从使用结构伪类的选择器开始 往上一层父辈开始筛选 从使用结构伪类的选择器开始 往上一层父辈开始筛选 不是从左往右选择 不是先父辈后筛选子类 ...
- react 爷爷组件件传递给孙子组件
爷爷组件 import React, { Component } from "react"; import "./App.css"; import TestHa ...
- 一键部署,玩转AI!天翼云Llama 3大模型学习机来了!
近日,Meta公司发布了其最新研发成果--开源大模型Llama 3,共包含Llama 3 8B和Llama 3 70B两种规格,参数量级分别为80亿与700亿,并表示这是目前同体量下性能最好的开源模型 ...
- 基于Linux系统的PXE搭建方法
本文分享自天翼云开发者社区<基于Linux系统的PXE搭建方法>,作者:t***n 一.底层环境准备 1.安装RedHat7.6系统 2.关闭防火墙和Selinux systemctl s ...
- 跟着蚂蚁走,它们知道路:用 ACO-ToT 增强 LLM 推理能力
跟着蚂蚁走,它们知道路:用 ACO-ToT 增强 LLM 推理能力 利用群体智能和思维树优化解锁高级 AI 推理能力 Salvatore Raieli 作者使用 AI 生成的图片 "我发现, ...