网站平台项目交接需要什么,杭州市工程建设招标网,最佳的搜索引擎,交互设计和ui设计的区别点击蓝字关注我们因公众号更改推送规则#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络#xff0c;侵删arm编译器学习首先来了解一下编译器#xff0c;其通常分为三个部分#xff1a;前端优化器后端。前端#xff1a;词法、语法和语义分析#x…点击蓝字关注我们因公众号更改推送规则请点“在看”并加“星标”第一时间获取精彩技术分享来源于网络侵删arm编译器学习首先来了解一下编译器其通常分为三个部分前端优化器后端。前端词法、语法和语义分析将源代码转化为抽象语法树生成中间代码优化器对得到的中间代码进行优化使得代码更加高效后端将优化的代码转化为针对各自平台的机器代码。再通俗地说编译器的工作就是源代码-预处理-编译-目标代码-链接-可执行程序。再来简单看看一些编译器的历史GCC、LLVM以及Clang等以及文章介绍的armcc 以及armclang。GCC GNU Compiler Collection是GNU开发的编译器许可证为GPL的自由软件GCC 原来只能处理C现在可以处理C、Pascal、Object-C、Java等。苹果公司之前一直使用GCC作为编译器但是GCC对Objective-C支持一直不怎么好好多新特性没有增加所以苹果公司开始寻求编译器的替代品。这个时候LLVM就出现了是Chris Lattner在硕士和博士时提出和形成的编译器不过其是采用GCC的前端进行语义分析然后LLVM做优化和生成目标代码可以叫做LLVM-GCC。后来苹果公司直接计划绕开GCC于是招募了Chris Lattner 博士开发编译器Clang就这样诞生了其基于LLVM开发的C/C/Obj-C编译器实际上其是一个编译器前端来取代GCC或者超越GCCarmcc 是arm 公司开发的一款编译器集成在KEIL以及ARM DS IDE里面于5.06版本后停滞AC5不继续维护其前端基于 Edison Design Group 。armclang 集成于armcc基于新的架构 clang 和LLVM作为arm 的第六代编译器AC6成为今后主推的编译器。armcc 编译器arm 公司 开发的一款编译器在2005年收购 KEIL 公司后这块编译器就集成在KEIL IDE里面以及自家开发的ARM DS5编译器以及IDE相关的文档可以去ARM 公司的官网下载。下载的文档主要分几个部分armcc 编译器、armasm 汇编器、armlink 链接器、armar 打包以及fromelf bin文件。1、armccarmcc 编译器 主要是编译.c/.cpp源文件文件生成目标文件通过各种编译选项 command-line来支持各种特性。接着来罗列几个常见的编译选项。一般的arm cc的编译器的编译器的语法如下armcc [options] [source]
举例如下
armcc -I ../common/ -I ../driver -g --apcsinterwork --cpuCortex-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 --apcsinterwork --cpuCortex-R5 ../common/led.c -o ../out/led.i
这样之后可以看到预处理的结果比如宏替换后的结果方便分析问题。
12-o 指定输出的文件名称-D 定义宏名称例如-DLOG -DUART1 -U 移除已经定义的宏名称#define LOG
#define UART 1在编译器命令行指定上面的宏相当于在程序里面定义上述代码的定义
1234-I指定include的目录 如果路径没指定编译阶段就会报错找不到相关的文件相比大家都见过这个错误吧–c99 --c90 指的的是C语言的语法版本–cpuname 比如 --cpuCortex-R5-M/–md 这两个是用来为每个源文件产生编译依赖–md 生成.d文件表示这个目标文件所依赖的头文件。这个在增量编译非常有用再找到依赖关系后更新依赖则可以只编译修改的文件以及依赖的文件。armcc -c -M -I ..\SYSTEM\sys -I ... sys.c --no_depend_single_line --md
1在这里插入图片描述–diag_error/–diag_suppress/–diag_warning 对编译的警告以及错误进行处理比如屏蔽某个编译警告/错误--diag_errorwarning 将err的编译消息视为warning,
--diag_suppress3017,1256,1148 将编译消息 编码为 3017,1256,1148的诊断消息屏蔽
--diag_warning1234,5678 屏蔽编码为 1234,5678的warning的诊断消息
--diag_warningerror 将warning视为error
1234例如下面的20、223 这种编码序号。在这里插入图片描述–feedbackfilename 编译反馈主要是用来去除没有用到的代码 数据以及code需要与链接的选项一起使用通常需要编译两次。--feedbackunused_section.txt 编译器阶段把没用到的代码和code单独放在一个section方便链接阶段去除链接阶段生成不用的section区
--feedbackimage_none 忽略链接阶段的链接脚本忽略代码布局则不会生成axf文件
--remove 去除不用的section
--keep memory_alyout.o\(rw\) 可以设置memory_out.o中的rw段不删除
通过feedback空间从950k - 800k (双core的bin 所需空间)
12345–inline/–forceinline前者会对函数是否内敛进行考虑后者强制将所有函数进行内敛要对单个函数进行内敛可以考虑对函数进行修饰__forceinline。需要注意的是并不是所有的函数都可以内联比如递归函数。–littleend/–bigend 数据大小端设置-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_leveloption 控制在 –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 packn 设置 n字节对齐对于结构体来说。
12345–use_frame_pointer这个设置栈顶指针每次进入函数后会首先将栈顶压入栈之后再做其他的寄存器压栈这样的好处是backtrace的调用关系很容易找出来。详见ARM开发中几个常见的寄存器详解-apcsinterwork 支持内部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个名额▲扫描二维码-免费领取戳“阅读原文”我们一起进步