熟悉又陌生的arm 编译器详解(armcc/armclang)

点击蓝字

ec349d60f578fbd90cb3c5a846903cf2.png

关注我们

因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享

来源于网络,侵删

arm编译器学习

首先来了解一下编译器,其通常分为三个部分:前端+优化器+后端。

  • 前端:词法、语法和语义分析,将源代码转化为抽象语法树,生成中间代码

  • 优化器:对得到的中间代码进行优化,使得代码更加高效,

  • 后端:将优化的代码转化为针对各自平台的机器代码。

再通俗地说编译器的工作就是:源代码->预处理->编译->目标代码->链接->可执行程序。

c5aa95cad4aecb3f0934875d4ec0da92.png

再来简单看看一些编译器的历史,GCC、LLVM以及Clang等,以及文章介绍的armcc 以及armclang。

  1. GCC (GNU Compiler Collection)是GNU开发的编译器,许可证为GPL的自由软件;

  2. GCC 原来只能处理C,现在可以处理C++、Pascal、Object-C、Java等。

  3. 苹果公司之前一直使用GCC作为编译器,但是GCC对Objective-C支持一直不怎么好,好多新特性没有增加,所以苹果公司开始寻求编译器的替代品。

  4. 这个时候LLVM就出现了,是Chris Lattner在硕士和博士时提出和形成的编译器,不过其是采用GCC的前端进行语义分析,然后LLVM做优化和生成目标代码,可以叫做LLVM-GCC。

  5. 后来苹果公司直接计划绕开GCC,于是招募了Chris Lattner 博士开发编译器,Clang就这样诞生了,其基于LLVM开发的C/C++/Obj-C编译器,实际上其是一个编译器前端,来取代GCC或者超越GCC

  6. armcc 是arm 公司开发的一款编译器,集成在KEIL以及ARM DS IDE里面,于5.06版本后停滞(AC5),不继续维护,其前端基于 Edison Design Group 。

  7. armclang 集成于armcc,基于新的架构 clang 和LLVM,作为arm 的第六代编译器,AC6,成为今后主推的编译器。

armcc 编译器

arm 公司 开发的一款编译器,在2005年收购 KEIL 公司后,这块编译器就集成在KEIL IDE里面,以及自家开发的ARM DS5,编译器以及IDE相关的文档可以去ARM 公司的官网下载。

下载的文档主要分几个部分:armcc 编译器、armasm 汇编器、armlink 链接器、armar 打包以及fromelf bin文件。

1、armcc

armcc 编译器 主要是编译.c/.cpp源文件文件,生成目标文件,通过各种编译选项 command-line来支持各种特性。接着来罗列几个常见的编译选项。

一般的arm cc的编译器的编译器的语法如下:

armcc [options] [source] 
举例如下:
armcc -I ../common/ -I ../driver  -g --apcs=interwork --cpu=Cortex-R5 -c ../common/led.c -o ../out/led.o
123
  • -c/-C/-o/-D-c 代表 只是编译,不进入链接步骤, -C 保留预处理的输出,然后-E 可以指定预处理输出到某个指定文件。

armcc -c -C -E  -I ../common/ -I ../driver -g --apcs=interwork --cpu=Cortex-R5 ../common/led.c -o ../out/led.i
这样之后,可以看到预处理的结果,比如宏替换后的结果,方便分析问题。
12

-o 指定输出的文件名称

9d963ebab679d90cf5f535cbeb956fe1.png

-D 定义宏名称,例如:-DLOG -DUART=1 -U 移除已经定义的宏名称

#define LOG
#define UART 1在编译器命令行指定上面的宏,相当于在程序里面定义上述代码的定义
1234
  • -I:指定include的目录 ,如果路径没指定,编译阶段就会报错,找不到相关的文件,相比大家都见过这个错误吧!

    01f0dfb842cf997178d188d86a3ea857.png
  • –c99 --c90 指的的是C语言的语法版本,

    c442f16cb7d5e6aa376a8ff0e45f26b1.png
  • –cpu=name 比如 --cpu=Cortex-R5

    84b2627e7a8e0be83c2364fa05a3a1ce.pnga72c7ffcb16d10b66582428e739bea66.png
  • -M/–md 这两个是用来为每个源文件产生编译依赖,–md 生成.d文件,表示这个目标文件所依赖的头文件。这个在增量编译非常有用,再找到依赖关系后,更新依赖,则可以只编译修改的文件以及依赖的文件。

    26c8b68aeecc6dfb1469943eed95a5e1.png
armcc  -c -M  -I ..\SYSTEM\sys  -I ...  sys.c --no_depend_single_line --md  
1

d9c27506c4dca937f4d99152f0e1bd66.png

在这里插入图片描述
  • –diag_error/–diag_suppress/–diag_warning 对编译的警告以及错误进行处理,比如屏蔽某个编译警告/错误

--diag_error=warning                      将err的编译消息视为warning,
--diag_suppress=3017,1256,1148            将编译消息 编码为 3017,1256,1148的诊断消息屏蔽
--diag_warning=1234,5678                  屏蔽编码为 1234,5678的warning的诊断消息      
--diag_warning=error                      将warning视为error
1234
94e16890a95a17ed731c2f987245bb3e.png

例如下面的20、223 这种编码序号。

c4bd936ec68b39abcd391320ada9adaa.png

在这里插入图片描述
  • –feedback=filename 编译反馈,主要是用来去除没有用到的代码 (数据以及code),需要与链接的选项一起使用,通常需要编译两次

--feedback=unused_section.txt   编译器阶段把没用到的代码和code单独放在一个section,方便链接阶段去除,链接阶段,生成不用的section区
--feedback=image_none           忽略链接阶段的链接脚本,忽略代码布局,则不会生成axf文件
--remove                        去除不用的section
--keep memory_alyout.o\(rw\)    可以设置memory_out.o中的rw段不删除                         
通过feedback,空间从950k -> 800k (双core的bin 所需空间)
12345
  • –inline/–forceinline

    前者会对函数是否内敛进行考虑,后者强制将所有函数进行内敛,要对单个函数进行内敛,可以考虑对函数进行修饰,__forceinline。

    • 需要注意的是,并不是所有的函数都可以内联,比如递归函数

89048223b9a46ed6930c80beb6c10361.png

  • –littleend/–bigend 数据大小端设置,

    c14adc4b6e183797eeea159213a14e6a.png
  • -O0/O1/O2/O3/Otime/Ospace 编译优化选项

-O0最小优化关闭大多数优化。启用调试时,此选项提供最佳调试视图,因为生成代码的结构直接对应于源代码。所有干扰调试视图的优化都被禁用。

  • 可以在任何可到达的点设置断点,包括死代码(程序执行不到的地方 或者没有受调用的地方)。

  • 变量的值在其范围内的任何地方都可用,但它所在的位置除外未初始化。

  • Backtrace 提供了读取源代码时预期的函数调用栈关系。

  • 虽然 -O0 生成的调试视图与源代码最接近,但用户可能更喜欢 -O1 生成的调试视图,因为这提高了代码的质量在不改变基本结构的情况下。

  • 死代码包括对程序结果没有影响的可达代码,例如对从未使用过的局部变量的赋值。无法访问的代码是专门的代码无法通过任何控制流路径访问,例如紧跟在返回之后的代码 陈述。

-O1受限优化。编译器只执行可以描述为调试信息的优化。删除未使用的内联函数未使用的静态函数关掉严重降低调试视图的优化。如果与 –debug 一起使用,此选项会给出总体上令人满意的调试视图且具有良好的代码密度。调试视图与 –O0 的区别在于:

  • 不能在死代码上设置断点

  • 变量的值在初始化后可能在其范围内不可用。例如,如果他们分配的位置已被重复使用。

  • 没有影响的函数可能会被乱序调用,或者如果结果是不需要的。

  • Backtrace 可能不准确,因为在栈的方面处理有变化,存在调用优化。

  • 优化级别 –O1 在源代码和对象之间产生良好的对应关系代码,特别是当源代码不包含死代码时。

  • 生成的代码可以是明显小于 –O0 处的代码,这可以简化目标代码的分析

-O2高度优化。如果与 --debug 一起使用,调试视图可能不太令人满意,因为目标代码到源代码的映射并不总是清晰的。编译器可能会执行调试信息无法描述的优化。这是默认的优化级别。调试视图与 –O1 的区别在于:

  • 源代码到目标代码的映射可能是多对一的,因为可能多个源代码位置映射到目标文件的一个点,更激进的指令优化。

  • 允许指令调度跨越序列点。这可能导致变量在特定点的报告值与期望的值不匹配

  • 编译器自动内联函数

-O3最大优化。启用调试后,此选项通常会提供较差的调试视图。ARM 建议在较低的优化级别进行调试。如果同时使用 -O3 和 -Otime,编译器会执行更积极的额外优化,例如:

  • 高级标量优化,包括循环展开。这可以给显着以较小的代码大小成本获得性能优势,但存在构建时间较长的风险。

  • 更积极的内联和自动内联。

  • 这些优化有效地重写了输入源代码,导致目标代码与源代码的最低对应和最差的调试视图。--loop_optimization_level=option ,控制在 –O3 –Otime 执行的循环优化效果。循环优化的数量越高,源代码和目标代码之间的对应关系就越差。

  • 使用 --vectorize 选项还降低了源代码和目标代码之间的对应关系。有关在源代码上执行的高级转换的更多信息,请访问–O3 –Otime 使用 --remarks 命令行选项。

  • 因为优化会影响目标代码到源代码的映射,所以使用 -Ospace 和 -Otime 选择优化级别通常会影响调试视图

  • 如果需要简单的调试视图,选项 -O0 是最好的选择。选择 -O0 通常会将 ELF 映像的大小增加 7% 到 15%。要减小调试表的大小,请使用–remove_unneeded_entities 选项

  • –split_sections为每个源文件的函数创建一个section,方便在链接的时候去掉.o文件 中的不用的函数。–attribute((section(…))) 可以修饰data 和 function,将其放到指定的section,而不是放到默认的section

  • –thumb将该.c文件编译成 thumb指令,

#pragma  arm         编译成arm指令
#pragma  thumb       编译成thumb指令
#pragam  push        保存#pragma 状态
#pragma  pop         弹出状态 与上面的可以一起使用
#pragma  pack(n)   设置 n字节对齐,对于结构体来说。
12345
  • –use_frame_pointer这个设置栈顶指针,每次进入函数后,会首先将栈顶压入栈,之后再做其他的寄存器压栈,这样的好处是backtrace的调用关系很容易找出来。详见ARM开发中几个常见的寄存器详解

  • -apcs=interwork 支持内部thumb与arm 指令相互切换,比如BLX,这个支持thumb指令的地方用处较多,

2、armasm

  • 嵌入式汇编

    • 函数形参列表可以使用变量,但是函数体必须要用寄存器,函数体都是汇编语言实现

    • 需要汇编语言处理返回指令

__asm return-type function-name(parameter-list)
{
// ARM/Thumb assembly code
instruction{;comment is optional}
...
instruction
}/*示例1*/
__asm int f(int i)
{ADD r0, r0, #1 
}/*示例2*/
#include <stdio.h>
__asm void my_strcpy(const char *src, char *dst)
{
loopLDRB r2, [r0], #1STRB r2, [r1], #1CMP r2, #0BNE loopBX lr
}
int main(void)
{const char *a = "Hello world!";char b[20];my_strcpy (a, b);printf("Original string: '%s'\n", a);printf("Copied string: '%s'\n", b);return 0;
}
  • 内联汇编

    • 同一行如果有多行指令,必须要有封号(;)

    • 如果一个指令超出一行,需要增加反斜杠(\)

    • 在多行格式中,允许在内联汇编语言块中的任何位置使用C和C++注释。但是注释不能嵌入到多条指令的行中。

    • 在汇编语言中,逗号(,)用作分隔符,所以C表达式的逗号运算符必须用括号括起来来和它们进行区分

    • 标签必须后跟冒号,:,如C和C++标签

    • asm语句必须位于C++函数内部。asm语句可以在任何需要C++语句的地方使用

    • 内联程序集代码中的寄存器名被视为C或C++变量。它们不一定与同名的物理寄存器有关。如果寄存器未声明为C或C++变量,编译器将生成警告

    • 不得在内联程序集代码中保存和还原寄存器,编译器会执行此操作。此外,内联汇编程序不提供对物理寄存器的直接访问。然而,可以通过变量间接访问寄存器

    • pc/lr/sp:__current_pc,__current_sp, and __return_address 来read

    • 内联汇编中不要修改处理器模式或者协处理器的状态

int f(int x)
{__asm{STMFD sp!, {r0} // save r0 - illegal: read before writeADD r0, x, 1EOR x, r0, xLDMFD sp!, {r0} // restore r0 - not needed.}return x;
}
The function must be written as:
int f(int x)
{int r0;__asm{ADD r0, x, 1EOR x, r0, x}return x;
}int foo(int x, int y)
{
__asm
{SUBS x,x,yBEQ end
}
return 1;
end:return 0;
}
如果你年满18周岁以上,又觉得学【C语言】太难?想尝试其他编程语言,那么我推荐你学Python,现有价值499元Python零基础课程限时免费领取,限10个名额!
▲扫描二维码-免费领取

戳“阅读原文”我们一起进步

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图文详解STM32单片机远程升级

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删1、需要两份程序BootLoader和App程序&#xff0c;两份程序均可以通过jlink下载&#xff0c;只需要将下载地址修改一下即可&#xff1a;2、在Boot…

建立索引lucene_用Lucene建立搜索索引

建立索引lucene本文是我们名为“ Apache Lucene基础知识 ”的学院课程的一部分。 在本课程中&#xff0c;您将了解Lucene。 您将了解为什么这样的库很重要&#xff0c;然后了解Lucene中搜索的工作方式。 此外&#xff0c;您将学习如何将Lucene Search集成到您自己的应用程序中…

spring javafx_Oracle Spring Clean JavaFX应该吗?

spring javafx我们确实在Codename One上依赖JavaFX&#xff0c;我们的模拟器需要它。 我们的桌面版本使用它&#xff0c;而我们的设计器工具基于Swing。 我们希望它成功&#xff0c;这对我们的业务至关重要&#xff01; 即使您是Java EE开发人员并且不关心桌面编程&#xff0c;…

哪些著名软件是用C、C++编写的?

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删经常跟大家谈论C/C是多么的厉害&#xff0c;但总是耳听为虚&#xff0c;还需眼见为实&#xff0c;那如何做到眼见为实呢&#xff1f;当然还是要从…

java ee 下版本_将旧版本从Java EE 5减少到7

java ee 下版本Java EE 5于2005年首次引入&#xff0c;而Java EE 7于2013年问世。这两个版本之间存在7年的差距&#xff0c;从技术角度来说&#xff0c;这就像一个世纪。 许多组织仍然对使用Java EE 5感到困惑&#xff0c;并且有很多正当的理由选择不升级。 不过&#xff0c;如…

哪款 Linux 才是更好的 CentOS 替代品?

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删AlmaLinux 是基于 RHEL 的企业级 Linux 发行版。以下是选择 AlmaLinux 作为 CentOS 替代方案的一些原因。CentOS 将于 2024 年 6 月到期。截至 2…

绩效从C到S,分享渣渣程序员逆袭秘诀!

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删绩效面谈结束&#xff0c;从会议室出来&#xff0c;有一种不真实的感觉——这个季度我竟然拿了S&#xff1f;&#xff01;要知道&#xff0c;上个…

海贼王为什么画风突变_什么是突变测试?

海贼王为什么画风突变最近&#xff0c;我再三提到突变测试一词。 因为可以说这种方法能够以超出代码覆盖范围的方式检测测试安全网的空白&#xff0c;所以我花了一些时间来追赶这个话题并尝试一下。 这篇文章总结了我的发现&#xff0c;作为对该主题的快速介绍。 什么是变异测…

C语言 #define 与 typedef 的区别与用法

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删在C语言编程中&#xff0c;typedef 和 #define是最常用语句&#xff0c;可能很多工作过几年的工程师都没有去深究过它们的一些用法和区别。typed…

硬核!400 行代码实现一个虚拟机

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删我们都知道理工科类的大学专业&#xff0c;一般都会在大一选择教授 C 语言作为编程入门语言&#xff0c;我最初接触编程也是入的 C 语言的坑。课…

Spring集成基础知识

本文是我们名为“ EAI的Spring集成 ”的学院课程的一部分。 在本课程中&#xff0c;向您介绍了企业应用程序集成模式以及Spring Integration如何解决它们。 接下来&#xff0c;您将深入研究Spring Integration的基础知识&#xff0c;例如通道&#xff0c;转换器和适配器。 在这…

C++最佳实践 | 工具

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删前言C最佳实践: 支持Fork的编码标准文档本文档旨在收集对C最佳实践所进行的协作性讨论&#xff0c;是《Effective C》(Meyers) 和《C Coding Sta…

C语言函数返回 1 和返回 0 哪个好?

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删基本上&#xff0c;没有人会将大段的C语言代码全部塞入 main() 函数。更好的做法是按照复用率高、耦合性低的原则&#xff0c;尽可能的将代码拆分…

抽象工厂和工厂方法示例_抽象工厂设计模式示例

抽象工厂和工厂方法示例本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查…

史上最污技术解读,我竟然秒懂了

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删假设你是个妹子&#xff0c;你有一位男朋友&#xff0c;于此同时你和另外一位男生暧昧不清&#xff0c;比朋友好&#xff0c;又不是恋人。你随时…

tdd java_Java TDD简介–第1部分

tdd java欢迎来到测试驱动开发 &#xff08;TDD&#xff09;系列的介绍。 我们将在TDD上下文中讨论Java和JUnit &#xff0c;但这只是工具。 本文的主要目的是使您全面了解TDD&#xff0c;而无论使用哪种编程语言和测试框架。 如果您在项目中不使用TDD&#xff0c;那么您要么是…

C++最佳实践 | 代码风格

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删C最佳实践:1. 工具2. 代码风格&#xff08;本文&#xff09;3. 安全性4. 可维护性5. 可移植性及多线程6. 性能7. 正确性和脚本代码风格代码风格最…

okhttp 连接池_okhttp 源码分析

https://square.github.io/okhttp/​square.github.iosquare/okhttp​github.com0 概述okhttp是一个现代的网络请求框架Http/2 支持 所有访问同一个主机的Request都共用一个socketconnection pool 连接池 减少请求延迟GZIP 压缩数据&#xff0c;减少传输所用的带宽Response Cac…

程序员日均写7行代码被开除,公司:正常员工每天200行

点击蓝字关注我们因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络&#xff0c;侵删根据前不久CSDN发布的《2021-2022中国开发者调查报告》显示&#xff0c;大部分程序员平均每天会写200行左右的代码。那么代码的数量能衡量一个程…

抽象工厂和工厂方法示例_工厂方法设计模式示例

抽象工厂和工厂方法示例本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查…