21.从0学ARM-为什么使用结构体效率会高?一文给你讲透

发布者:开元轩最新更新时间:2021-08-04 来源: eefocus关键字:ARM  结构体  效率 手机看文章 扫描二维码
随时随地手机看文章

作为过来人,我发现很多程序猿新手,在编写代码的时候,特别喜欢定义很多独立的全局变量,而不是把这些变量封装到一个结构体中,主要原因是图方便,但是要知道,这其实是一个不好的习惯,而且会降低整体代码的性能。


另一方面,最近有幸与大神【公众号:裸机思维】的傻孩子交流的时候,他聊到:“其实Cortex在架构层面就是更偏好面向对象的(哪怕你只是使用了结构体),其表现形式就是:Cortex所有的寻址模式都是间接寻址——换句话说一定依赖一个寄存器作为基地址。


举例来说,同样是访问外设寄存器,过去在8位和16位机时代,人们喜欢给每一个寄存器都单独绑定地址——当作全局变量来访问,而现在Cortex在架构上更鼓励底层驱动以寄存器页(也就是结构体)为单位来定义寄存器,这也就是说,同一个外设的寄存器是借助拥有同一个基地址的结构体来访问的。”


以Cortex A9架构为前提,下面一口君详细给你解释为什么使用结构体效率会更高一些。


一、全局变量反汇编

1. 源文件

gcd.s


.text.global _start

_start:

ldr sp,=0x70000000         /*get stack top pointer*/

b main


main.c


/*

 * main.c

 *

 *  Created on: 2020-12-12

 *      Author: pengdan

 */int xx=0;int yy=0;int zz=0;int main(void){

xx=0x11;

yy=0x22;

zz=0x33;while(1);return 0;}


map.lds


OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{. = 0x40008000;. = ALIGN(4);.text      :{

gcd.o(.text)*(.text)}. = ALIGN(4);.rodata : 

{ *(.rodata) }. = ALIGN(4);.data : 

{ *(.data) }. = ALIGN(4);.bss : { *(.bss) }}


Makefile


TARGET=gcd

TARGETC=main

all:

arm-none-linux-gnueabi-gcc -O1 -g -c -o $(TARGETC).o  $(TARGETC).c

arm-none-linux-gnueabi-gcc -O1 -g -c -o $(TARGET).o $(TARGET).s

arm-none-linux-gnueabi-gcc -O1 -g -S -o $(TARGETC).s  $(TARGETC).c

arm-none-linux-gnueabi-ld $(TARGETC).o $(TARGET).o -Tmap.lds  -o  $(TARGET).elf 

arm-none-linux-gnueabi-objcopy -O binary -S $(TARGET).elf $(TARGET).bin

arm-none-linux-gnueabi-objdump -D $(TARGET).elf > $(TARGET).dis


clean:

rm -rf *.o *.elf *.dis *.bin


【交叉编译工具,自行搜索安装】


2. 反汇编结果:

全局变量汇编指令
由上图可知,每存储1个int型全局变量需要8个字节,

literal pool (文字池)占用4个字节

literal pool的本质就是ARM汇编语言代码节中的一块用来存放常量数据而非可执行代码的内存块。

使用literal pool (文字池)的原因


当想要在一条指令中使用一个 4字节长度的常量数据(这个数据可以是内存地址,也可以是数字常量)的时候,由于ARM指令集是定长的(ARM指令4字节或Thumb指令2字节),所以就无法把这个4字节的常量数据编码在一条编译后的指令中。此时,ARM编译器(编译C源程序)/汇编器(编译汇编程序) 就会在代码节中分配一块内存,并把这个4字节的数据常量保存于此,之后,再使用一条指令把这个4 字节的数字常量加载到寄存器中参与运算。


在C源代码中,文字池的分配是由编译器在编译时自行安排的,在进行汇编程序设计时,开发者可以自己进行文字池的分配,如果开发者没有进行文字池的安排,那么汇编器就会代劳。


bss段占用4个字节

每访问1次全局变量,总共需要3条指令,访问3次全局变量用了12条指令。
访问全局变量xx

14. 通过当前pc值40008018偏移32个字节,找到xx变量的链接地址40008038,然后取出其内容40008044存放在r3中,该值就是xx在bss段的地址15. 通过将立即数0x11即#17赋值给r216. 将r2的内让那个写入到r3对应的指向的内存,即xx标号对应的内存中


二、结构体反汇编

1. 修改main.c如下:

 /*

  2  * main.c                                                           

  3  *

  4  *  Created on: 2020-12-12

  5  *      Author: 一口Linux

  6  */

  7 struct

  8 {

  9     int xx;

 10     int yy;

 11     int zz;

 12 }peng;

 13 int main(void)

 14 {

 15     peng.xx=0x11;

 16     peng.yy=0x22;

 17     peng.zz=0x33;

 18 

 19     while(1);

 20     return 0;

 21 }


2. 反汇编代码如下:

结构体变量的反汇编

由上图可知:


结构体变量peng位于bss段,地址是4000802c

访问结构体成员也需要利用pc找到结构体变量peng对应的文字池中地址40008028,然后间接找到结构体变量peng地址4000802c

与定义成3个全局变量相比,优点:


结构体的所有成员在literal pool 中共用同一个地址;而每一个全局变量在literal pool 中都有一个地址,节省了8个字节。

访问结构体其他成员的时候,不需要再次装载基地址,只需要2条指令即可实现赋值;访问3个成员,总共需要7条指令,节省了5条指令

彩!


所以对于需要大量访问结构体成员的功能函数,所有访问结构体成员的操作只需要加载一次基地址即可。


使用结构体就可以大大的节省指令周期,而节省指令周期对于提高cpu的运行效率自然不言而喻。


所以,重要问题说3遍


尽量使用结构体

尽量使用结构体

尽量使用结构体


三、继续优化

那么指令还能不能更少一点呢?

答案是可以的,

修改Makefile如下:


TARGET=gcd                                                                                

TARGETC=main

all: arm-none-linux-gnueabi-gcc -Os   -lto -g -c -o $(TARGETC).o  $(TARGETC).c

     arm-none-linux-gnueabi-gcc -Os  -lto -g -c -o $(TARGET).o $(TARGET).s

     arm-none-linux-gnueabi-gcc -Os  -lto -g -S -o $(TARGETC).s  $(TARGETC).c

     arm-none-linux-gnueabi-ld   $(TARGETC).o    $(TARGET).o -Tmap.lds  -o  $(TARGET).elf

     arm-none-linux-gnueabi-objcopy -O binary -S $(TARGET).elf $(TARGET).bin

     arm-none-linux-gnueabi-objdump -D $(TARGET).elf > $(TARGET).dis

clean: rm -rf *.o *.elf *.dis *.bin


仍然用第二章的main.c文件


执行结果

可以看到代码已经被优化到5条。


14. 把peng的地址40008024装载到r3中15. r0写入立即数0x1116. r1写入立即数0x2217. r0写入立即数0x3318. 通过stm指令将r0、r1、r2的值顺


关键字:ARM  结构体  效率 引用地址:21.从0学ARM-为什么使用结构体效率会高?一文给你讲透

上一篇:9. 从0学ARM Cortex-A9 LED汇编、C语言驱动编写
下一篇:7. 从0学ARM-GNU伪指令、代码编译,lds使用

推荐阅读最新更新时间:2024-10-31 10:54

爱特梅尔推出业界首款支持千兆字节以上的ARM7 闪存微控制器
通用内存接口 (UMI) 配有错误纠正代码控制器, 能够防止NAND 闪存丢失数位 爱特梅尔公司 (Atmel Corporation) 现已为基于ARM7 的USB微控制器 SAM7 系列增添三款新产品。全新的 SAM7SE 微控制器 (MCU) 备有32、256和512Kbyte 的闪存容量选择,是业界唯一配有外部总线接口 (external bus interface, EBI) 的ARM7 MCU,能够直接访问大容量的外部 NAND 闪存、SDRAM、CompactFlash、SRAM以及 ROM存储器。由于 SAM7SE MCU 能够快速而有效地存取千兆字节以上的数据,因此是流动门诊医疗记录等数据记录应用的理想之选。
[新品]
ARM Linux (S3C6410架构/2.6.35内核)的内存映射(五)
ARM Linux的访问权限控制 ARM1176JZF-S处理器为访问权限控制定义了两个层次:第一层是 域 (Domain)的访问类型,第二层是页或者段的 读写权限 (Access Permission)。具体来说,过程是这样的: 1. 在ARM处理器中,MMU将整个存储空间分成最多16个域,记作D0~D15,每个域对应一定的存储区域,该区域具有相同的访问控制属性。每个域的访问权限分别由CP15的C3寄存器中的两位来设定,c3寄存器的大小为32bits,刚好可以设置16个域的访问权限。 Bits 31, 30 29, 28 27, 26 25, 24 23, 22 21, 20 19,
[单片机]
Arm老乡UltraSoC获融资,携RISC-V等架构的分析技术来华
  与 ARM 一样发源于英国剑桥,这家做SoC嵌入式分析的IP公司尽管只有二十几人,但刚刚获得了600万美元的风投。不久前,该公司信心满满地来中国,参加了中国系列活动,例如在一年一度的ICCAD(中国集成电路设计业年会)2017上露面。下面就随嵌入式小编一起来了解一下相关内容吧。   这家公司就是 UltraSoC ,首席执行官Rupert Baines先生在ICCAD期间向电子产品世界记者介绍了RISC-V及该公司的产品。    RISC-V是CPU界的Linux    UltraSoC 的一大亮点是支持RISC-V,也是RISC-V联盟的活跃成员。据悉,现在RISC-V发展很快,已有一些客户用RISC-V做服务器、分布
[嵌入式]
提高电源转换效率的交错式PFC控制技术及应用
多年以来,多种创新型功率因数校正(PFC)技术不断问世。采用升压拓扑结构的有源功率因数校正就是首批创新技术中的一种。由于不再需要大体积的无源PFC解决方案,所以有源功率因数校正技术提高了功率密度。另一个创新技术为转移模式PFC,该技术消除了PFC预调节器的升压二极管中的反向恢复电流,不但降低了转换器的开关损耗,而且还提高了系统效率。用来增加功率密度并提高系统效率的PFC下一个创新技术为交错式PFC预调节器。 电源设计工程师设计交错式PFC转换器已有数年,但因缺少合适的控制器,所以对电源控制的设计必须非常谨慎。为使交错式PFC设计变得更轻松,德州仪器(TI)开发出两款交错式PFC控制器:一款为针对平均电流模式预调节器的控制器
[电源管理]
提高电源转换<font color='red'>效率</font>的交错式PFC控制技术及应用
ePropelled推出新的EV推进系统 可将电源效率提高15%
ePropelled是一家提供领先电力推进系统的技术公司。据外媒报道,该公司推出了具有突破性意义的 电动汽车 推进系统。新系统可将电源效率(power efficiency)至少提高15%,帮助制造商减少电池组的尺寸和成本,从而促进电动汽车的推广和应用。 (图片来源:ePropelled) ePropelled的动态扭矩切换系统(Dynamic Torque Switching™,eDTS)由三个主要部件组成,包括eDTS电动机(即无刷永磁同步电机)、电力电子驱动器(包括高压逆变器和根据车辆需求自动选择最有效操作模式的控制系统),以及电子开关矩阵,可将电动机的很多绕组连接到驱动器相位。 该eDTS系统使用由创新软件控
[汽车电子]
ePropelled推出新的EV推进系统 可将电源<font color='red'>效率</font>提高15%
未来十年还是arm的天下吗
在2000年,我(本文作者)去一家嵌入式Linux公司Lineo工作,尽管我的台式机(还记得吗?)运行的是x86,但Lineo出售的所有产品都涉及MIPS,基于RISC的芯片(如英特尔的i960和...ARM)。几十年来,尽管ARM在移动设备和其他地方仍然具有高度相关性,但在某系额领域,x86似乎不可逾越,这使我们对ARM的未来有了一些怀疑。 但是最近,x86看起来脆弱了许多。 苹果公司可能会尽其最大努力,以使其新的基于ARM的M1处理器变得越来越强,但很少有人会拥有基于ARM的Mac。相比之下,几乎每个人都将使用基于ARM的移动设备或与由运行在AWS或Microsoft Azure(已宣布)或Google Clou
[嵌入式]
未来十年还是<font color='red'>arm</font>的天下吗
大功率效率的功率放大器
为响应服务供应商拓展高性能无线宽带覆盖范围的需求,ANADIGICS, Inc.近日针对WiMAX用户端设备(CPE)和小型蜂窝基站解决方案推出了新型功率放大器(PA)。ANADIGICS的AWB7221是现有针对WiMAX用户端设备最具功率效率的功率放大器,同时也是支持3G和4G网络的Femtocells最具成本效率的选择。   AWB7221的高线性发射功率给用户端设备带来了强大的上行链路,支持宽广、高数据速率的网络覆盖。该器件具有优秀的功率效率,可降低用户端设备或 Femtocell的整体功率消耗,从而降低系统冷却要求和设计成本。AWB7221功率放大器提升了北美、日本和韩国等全球主要WiMAX市场的网络品质,同时还支持
[网络通信]
Part3_lesson1---ARM汇编编程概述
bootloader以及内核需要使用汇编语言,特别是在初始化的时候!以及在效率要求很高的地方会使用。 汇编程序框架: 其入口在_start处,这个入口需要用一个关键字为.global来声明它是一个全局的标号,那么在外部文件才能够引用到它。 .section表示这是一个段,.text表示这是一个代码段。 简化之后的框架 要调试某个文件是把格式为elf的文件烧写到内存里面去调试。 要下载某个文件是要把格式为二进制的文件烧写到nandflash里面去运行。 start.S文件 makefile文件的编写: all:start.o   arm-linux-ld -Ttext 0x50000000 -o start.elf
[单片机]
Part3_lesson1---<font color='red'>ARM</font>汇编编程概述
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved