近期,我们接到了多个客户的需求,希望将其基于 GCC 构建的 Infineon AURIX 平台项目迁移到 TASKING 工具集。虽然 GCC 作为开源工具具有免费使用的优势,但其在功能安全认证方面存在局限性,无法满足汽车电子等安全关键领域的要求。而 TASKING 工具集提供了完整的功能安全认证支持,符合 ISO 26262 等相关标准,因此成为了许多客户的首选。
为了帮助客户顺利完成这一迁移过程,我们整理了这份详细的迁移指南,涵盖了从源代码到链接器配置的各个方面。
其他的部分如果有需求,请联系我们:
support@softor.com.cn
tianpengbo@softor.com.cn
本迁移指南描述了将使用 GCC 构建的 AURIX/Tricore 软件项目移植到 TASKING 工具集的过程。它涵盖了对 C/C++ 源代码、汇编源代码、启动代码和链接器脚本文件的修改。
本指南的每个部分简要解释一个主题,可选地提供 TASKING 用户指南的参考,并以您应该采取的行动摘要结束。这些行动不一定需要按照列出的顺序执行。假设您熟悉 GCC 工具,但不熟悉 TASKING 工具。
TASKING 工具可以通过 Eclipse 集成开发环境 (IDE) 或命令行进行配置和执行。您可能已经有一个现有的 makefile 来构建项目,并且习惯于从命令行配置 GCC 工具,因此本指南通过命令行描述工具配置和执行。
您可以单独调用每个 TASKING 工具(编译器、汇编器和链接器),也可以通过控制程序调用。控制程序是一个统一的接口,它会根据输入文件的类型自动调用相应的工具,并传递适当的命令行选项。建议使用控制程序,除非对于较大的项目,建议直接调用链接器以获得更精细的控制。
将 GCC 项目迁移到 TASKING 工具集是一个系统性的过程,建议按照以下步骤进行:
符合 ISO-C (ISO/IEC 9899:1999) 的源代码可以无需修改地移植。代码的行为保持不变,因为所有数据和指针类型的大小和值范围是相等的。此外,除非更改默认设置,否则两个编译器都将字符视为有符号的。
检查 GCC 命令行设置是否使用无符号字符。如果设置了 GCC 选项 -funsigned-char 或 -fno-signed-char,则设置 TASKING 选项 --uchar。
实现定义的行为不会影响构建过程,但可能会影响可执行代码的行为。一旦您能够构建并执行您的软件,建议验证 GCC 和 TASKING 之间实现定义行为的差异是否会导致不必要的副作用。
行动摘要:
--signed-bitfields。命令行选项应与 GCC 项目兼容。显然,应正确指定包含路径和预处理器宏,并从项目中删除特定于 GCC 的文件。
运行 cctc -? 以获取可通过控制程序访问的所有编译器选项的列表。运行 cctc -? 以查看编译器支持的所有选项。使用选项 --help=o 查看扩展选项描述。
您可能已经使用 GCC 选项来指定应使用小寻址模式寻址的对象的最大大小。考虑从 GCC 项目复制这些设置,相关的 TASKING 选项是:--default-a0-size 和 --default-near-size。
行动摘要:
TASKING 工具集提供了一个选项来启用 GNU C 扩展以及 GNU C 扩展。有关更多信息,请参见 TASKING Tricore 用户指南第 2.2.2 节 GNU C 模式。
行动摘要:
--language=+gcc--gnu-version=<version>如果源代码专门针对 Infineon AURIX 设备并将使用 TASKING 工具构建,则建议更新源文件并使用 TASKING 语法来实现 AURIX 特定功能。
但是,如果您不想修改源文件,则可以使用预处理器对源代码进行必要的更改。使用 --include-file=<file> 命令行选项将包含文件插入到正在编译的源文件中,并将包含文件添加到 makefile 中的依赖项中。例如,GCC 风格的内在函数(见内在函数部分)可以使用预处理器指令 #define _enable() __enable() 轻松转换为 TASKING 语法。
行动摘要:
--include-file=<file>。GCC 中可用的每个内在函数也由 TASKING 提供。然而,GCC 只使用一个下划线,而 TASKING 使用两个下划线。要迁移您的内在函数调用,只需添加第二个下划线,例如 _enable() 变为 __enable()。
有一个例外,_rstv() 内在函数不是由 TASKING 提供的。创建以下内联函数来实现此内在函数:
inline void _rstv(void) { __asm("rstv"); }
未更新的内在函数将在构建期间显示为未解析的引用。
行动摘要:
_rstv() 的定义:inline void _rstv(void) { __asm("rstv"); }TASKING 支持 GCC __attribute__ 语法,但是并非支持 GCC 提供的所有属性。当出现不支持的属性时,TASKING 编译器会发出警告消息。
除以下 GCC 函数属性外,所有属性都受支持:constructor、deprecated、destructor、format_arg 和 no_instrument_function。
除以下 GCC 变量属性外,所有属性都受支持:fardate、mode、nocommon 和 vector_size。
除以下 GCC 类型属性外,所有属性都受支持:deprecated 和 transparent_union。
以下 TriCore 特定属性不受支持:asection、interrupt、interrupt_handler 和 long_call。但是,TASKING 使用不同的语法提供等效功能。
与 GCC 工具相反,TASKING 工具集是专门为在资源受限设备上执行的嵌入式软件开发而设计的。这导致了关于节命名、链接和定位以及中断函数支持的不同理念。更多细节可以在下面的部分中找到。
行动摘要:
默认情况下,TASKING 编译器为每个函数和变量创建一个命名节,通常不需要在源代码中明确指定节名称,这使得软件更易于阅读和维护。
GCC 提供 __attribute__((asection("<name>", "a=<align>", "f=<flags>"))) 语法来控制函数和变量的分配。参数 <name> 指定对象所在节的名称,<align> 指定节的对齐方式,<flags> 指定节是 ‘a’ 可分配的和 ‘x’ 可执行的。
如果需要在源代码中重命名节,则使用 TASKING 语法:
#pragma section type|all "<name>"
其中 type 可以是 code、data、bss 等,all 表示适用于所有类型的节,<name> 是您想要的节名称。
节对齐可以使用属性 __aligned(<value>) 指定。参数 <value> 以字节为单位指定对齐方式,并且必须是 2 的幂或 0。此外,TASKING 还提供了 _unaligned 和 _packed 类型修饰符来控制数据对齐:
_unaligned:表示该类型的数据不需要对齐_packed:表示该类型的数据将被紧密打包,不进行对齐GCC 还提供 pragma section 作为设置对象节的另一种方式。TASKING 也支持此 pragma。
然而,TASKING 提供了第三种更好的方法,使用内存限定符将变量放置在特定节中。使用这些限定符可以提高源代码的可读性和可维护性。TASKING 提供的内存限定符包括:
__near:将变量放置在近内存区域,使用更高效的寻址方式__far:将变量放置在远内存区域__cached:将变量放置在可缓存的内存区域__uncached:将变量放置在不可缓存的内存区域考虑使用这些 C 语言扩展来替代节属性。
行动摘要:
__attribute__((asection("<name>", "a=<align>", "f=<flags>"))) 替换为 #pragma section type|all "<name>" align(<value>)GCC 编译器要求您通过将函数指针传递给中断服务处理函数来为中断安装服务处理程序。
TASKING 提供了一种更简单的方法。有特定的关键字用于将函数转换为中断例程。例如,
void _interrupt(2) xrint(void) { dosomething(); }
将 xrint 转换为具有 ISR 优先级的中断例程。TASKING 还支持其他类型的中断函数:
_fast_interrupt:用于快速中断,具有更低的延迟_trap:用于陷阱处理函数您也可以直接在向量表中实现快速中断和其他高级功能。
行动摘要:
GCC 和 TASKING 编译器都支持函数内联。TASKING 提供了以下内联相关的选项:
--inline-level:控制内联的级别(0-3)--inline-depth:控制内联的深度--inline-size:控制内联函数的最大大小一旦构建了应用程序,您必须验证函数是否按照您的特定要求进行内联,并在需要时调整这些参数。
TASKING 使用相同的语法定义内联汇编。然而,底层汇编器并非 100% 兼容。如果在内联汇编语句中使用 GNU 特定的汇编语法,TASKING 汇编器会发出错误。
TASKING 提供了一组精心设计的内在函数,以支持无法用 ISO-C 语言结构映射的 TriCore 特定功能。这些内在函数包括:
__enable(), __disable(), __get_psw(), __set_psw() 等__mpy(), __mpyu(), __div() 等__btst(), __bset(), __bclr() 等__isync(), __dsync(), __halt() 等通常,您可以用一个或多个内在函数调用替换内联汇编代码,避免内联汇编的潜在陷阱。考虑这样做,否则请实现以下更改。
行动摘要:
__attribute__ ((section("..zdata"))) 替换为 __near。%A0 应替换为 %0。%A0、[%a]0 替换为 %0、[%a]。ld.d %e0 替换为 ld.d d0/d1,或使用 e 约束字符。在 TASKING 中,内联汇编的约束字符与 GCC 类似,但有一些差异,需要根据具体情况进行调整。subs %0,%0,%2 可以替换为 subs16 %0,%2。GCC 内置函数 __builtin_tricore_<name> 插入由内置名称指示的指令。
要迁移您的内置函数,您只需删除前缀 __builtin_tricore_ 并在函数名称前添加双下划线,例如 __builtin_tricore_nop() 变为 __nop()。
行动摘要:
__builtin_tricore_ 替换为 __(双下划线)。TASKING 使用 _circ 类型修饰符支持循环寻址,而 GCC 通过 circ_t 类型的实例以及初始化环形缓冲区和访问环形缓冲区的宏来支持循环寻址。在 TASKING 中,您可以这样定义和使用环形缓冲区:
// 定义一个大小为 16 的无符号整数环形缓冲区
unsigned int _circ(16) buffer;
// 访问环形缓冲区的元素
buffer[0] = 42; // 写入第一个元素
unsigned int value = buffer[5]; // 读取第六个元素
行动摘要:
建议用默认的 TASKING 启动代码替换项目的启动代码。TASKING 提供了以下启动代码选项:
TASKING 启动代码负责以下任务:
随后,您必须将对 GNU 启动代码所做的扩展迁移到 TASKING 启动代码中。
行动摘要:
以下 GNU 扩展不受支持,必须用 ISO-C 重写:
TASKING 工具集设计基于以下原则:编译器优化源代码,当您编写汇编代码时,您希望对生成的指令序列有精确的控制。因此,汇编器不优化代码,不像 GNU 汇编器那样将 32 位指令重写为 16 位等效指令,也不重新排序指令。
为您的特定项目设置适当的命令行选项。运行 astc -? 以获取所有汇编器选项的列表,使用 --help=o 查看扩展选项描述。
特殊字符 #(哈希)和 ;(分号)具有不同的语义。GCC 接受 ; 分隔语句,而 TASKING 需要
(换行)。GCC 使用 # 符号开始注释,而 TASKING 使用 ; 符号。
行动摘要:
GCC 使用 %(百分比)符号作为寄存器名称的前缀,而 TASKING 不使用前缀。
GCC 使用 psw应替换为mfcr d8, #psw`。
行动摘要:
GCC 使用点字符标记当前程序计数器 (PC)。请参见 3.2. 汇编器重要字符。
行动摘要:
行动摘要:
TASKING 提供了精心设计的表达式语法以及内置汇编函数,这些函数提供了 GCC 操作数前缀功能的超集。TASKING 的内置汇编函数包括:
@HI(<expr>):获取表达式的高 16 位@LO(<expr>):获取表达式的低 16 位@HO(<expr>):获取表达式的高 8 位@BYTE(<expr>):获取表达式的字节值将 GCC 特定的操作数前缀替换为具有等效语义的表达式。
行动摘要:
GCC 和 TASKING 都支持 ‘TriCore 架构手册’ 中描述的操作码(助记符)。无需转换。
使用 .SDECL "<name>", "<type>[, <attribute>]... [AT <address>] 指令添加节定义。
%0.0 应替换为 %LO,%0.1 应替换为 %HO
具有相同语法的 GCC 指令和 TASKING 指令在语义上是等效的。
某些 GCC 指令具有 TASKING 不支持的可选参数。如果使用此类参数,TASKING 汇编器会发出错误。您必须分析错误并采取适当的行动。例如,指令 .align <boundary>, <abs-expr>, <maximum> 的第二个和第三个参数在 GCC 中是可选的,而 TASKING 不支持。
某些 GCC 指令不受 TASKING 支持。如果使用此类指令,汇编器会发出错误。您必须分析错误并采取适当的行动。TASKING 可能提供具有相同语义的不同指令;或者该指令具有简单的功能,可以使用 TASKING 汇编语法轻松重写。一些示例:
简单替换:
.hword 替换为 .half.short 替换为 .half.rept 替换为 .dup.section 替换为 .sdecl 并添加 .section 指令。GCC 控制以 .(点)字符开始,而 TASKING 使用 $(美元)前缀。
.list 替换为 $LISTGCC .eject 指令在生成汇编时强制分页,使用 TASKING $PAGE 控制代替。
.eject 替换为 $PAGE使用 .ifgt <absolute expression> 的条件汇编不受支持,但可以使用 .if 指令并在表达式中包含大于比较来轻松实现。
行动摘要:
具有相同语法的 GCC TriCore 伪操作码指令和 TASKING 指令在语义上是等效的。
某些 GCC 伪操作码,如 .code16、.code32、.optim 和 .noopt 不受 TASKING 支持,因为 TASKING 的理念是编译器应该优化代码,如果您决定编写汇编,您希望对汇编输出有完美的控制。
行动摘要:
在概念层面,GCC 和 TASKING 链接器提供相同的功能。然而,这些工具没有共同的历史,用于控制链接和定位过程的脚本语言有很大不同。通常,人们只使用链接器功能的一小部分。本指南解释如何将常用的 Hightec 链接器功能转换为 TASKING 链接器语法。
对于较大的项目,您可能希望直接调用链接器而不是通过控制程序。但是,很难确定要设置哪些选项以及使用哪些库。您可以使用控制程序找到一组好的初始选项设置。
首先执行
cctc --cpu-list
以显示所有支持的处理器的列表,并选择项目中使用的 “cpu type”。
接下来执行
cctc main.c --dry-run --cpu=<type> --library-directory=<dir> --lsl-file=<file>
以查看如何调用链接器来创建可执行代码。
您应该将列出的链接器选项作为定义项目特定选项的起点。将为项目设置的编译器选项添加到上述命令中,因为这可能会影响链接器选项设置,例如使用哪些库。
运行 ltc -? 以获取所有链接器选项的列表。添加您认为有用的选项,但在第一实例中可能不需要其他选项。以下列表显示了最常用的 GCC 链接器命令行选项及其 TASKING 等效项(包括短格式和长格式)。请注意,GCC 链接器脚本也可以包含与 GCC 命令行选项具有相同功能的命令,这些命令必须转换为 TASKING 链接器命令行选项。
|
|
|
|---|---|
|
将归档文件 添加到要链接的文件列表中。 |
|
|
|
-D –define=CPU= -D –define=PROC__ 请注意,TASKING 核心名称与 GCC 核心名称不同。 |
|
|
仅搜索命令行上明确指定的库目录。 |
|
使用 作为链接器生成的目标文件的名称。 |
|
|
放松分支。本地分支的最大允许位移为 +/-16 MB。跳转到全局函数的 call、fcall、j 和 jl 指令可以由链接器放松,以达到 TriCore 整个 32 位地址空间内的任何有效代码地址。 |
|
|
|
执行任务级链接 |
|
|
|
|
详细信息 |
|
|
|
从文件读取命令行选项。 |
注意:某些选项是编译器选项,但在此列出是因为它们与链接器相关。
符号 __START 指定入口点,并在默认启动代码(文件 cstart.c)中定义。您可以使用命令行选项 --define=RESET=<address> 指定起始地址。实际上,您为与选择的 cpu-type 关联的链接器脚本文件中定义的预处理器符号 RESET 分配一个新值,当您指定选项 --cpu=<type> 时。
上下文保存区域、用户和系统堆栈、堆以及中断和陷阱表的大小和位置可以以类似的方式指定。以下是 TASKING 用户指南第 7.9.3 节中列出的常用预处理器宏:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
行动摘要:
-D --define=<macro>[=<def>] 更改默认设置,如起始地址、堆栈大小、堆大小、CSA 大小等。首先使用 TASKING 工具集中包含的默认链接器脚本文件构建项目。您的项目可能会链接和定位,没有任何问题。在下一步中,您的软件的内存布局将根据您的特定要求进行调整。
在概念层面,GCC 和 TASKING 工具对节使用类似的命名约定(.text、.data、.bss、.sdata、.zdata 等)。然而,请注意,TASKING 默认情况下为每个函数和变量创建单独的命名节。默认情况下,TASKING 编译器生成具有以下名称的节,其中节前缀通常等同于相应的 GCC 节名称:
section_type_prefix[.uncached][.core_association].module_name.symbol_name
当您使用节重命名 pragma 时,将应用以下命名约定:
section_type_prefix[.uncached][.core_association][.module_name][.symbol_name][.pragma_value]
TASKING 编译器生成的节名称包含以下部分:
section_type_prefix:节类型前缀,如 “text”、”data”、”bss” 等.uncached:可选,表示该节位于不可缓存的内存区域.core_association:可选,表示该节与特定核心关联.module_name:模块名称.symbol_name:符号名称.pragma_value:可选,节重命名 pragma 中指定的值一旦您想要描述应用程序的内存布局,您必须熟悉 TASKING 链接器脚本语言,简称 LSL。
建议快速浏览 TASKING 用户指南的第 7 章”使用链接器”和第 16 章”链接器脚本语言 (LSL)”,以了解链接器及其功能的概述。LSL 用于两个目的。首先,描述硬件架构,以告诉链接器指令中编码的地址如何映射到物理内存地址。其次,描述在内存中放置节的位置。当前只有后一部分是感兴趣的。
随工具集提供的标准 LSL 文件描述了 Infineon 发布的所有 AURIX(和前身)设备的硬件架构,包括可用内存。您不必修改这些 LSL 文件,也不必了解这些文件的详细信息。
由于您想要定义节布局,您应该阅读(而不是浏览)第 7 章的第 7.9.9 节和后续部分,还应查看第 18.8 节,其中列出了可能与您相关的 LSL 关键字的精确语法和语义。首先,另请参见下一节位置计数器。
本指南的其余部分包含示例,说明如何将常用的 GCC 链接器脚本语言构造转换为 TASKING 链接器脚本语言 (LSL)。
像大多数现代链接器一样,TASKING LSL 不支持”位置计数器”的概念。这是 GCC 和 TASKING 链接器设计背后不同理念的结果。TASKING 链接器是一个优化的多核链接器。链接器将自动将所有节拟合到内存中,并在非共享和共享内存中优化放置节。它不一定像 GCC 链接器那样从低地址到高地址顺序放置节。因此,为了在内存中创建特定的节布局,优化过程受到节布局描述的限制。
考虑以下 GCC 链接器脚本片段。来自 file1 的 .text 节位于输出节 output 的开头。后面跟着 1000 字节的间隙。然后是来自 file2 的 .text 节,后面也有 1000 字节的间隙,然后是来自 file3 的 .text 节。符号 = 0x12345678 指定在间隙中写入什么数据。
SECTIONS
{
output :
{
file1(.text)
. = . + 1000
file2(.text)
. = +1000
file3(.text)
. = 0x12345678
}
}
在 TASKING LSL 语法中,您使用关键字 reserved 创建间隙。在这个间隙中创建并定位一个命名节。您可以为每个单独的间隙指定填充模式。
section_layout :linear (direction = low_to_high)
{
group (ordered, contiguous)
{
select ".text*file1*";
reserved "reserved_text_1" (size = 1000, fill = 0x12345678);
select ".text*file2*";
reserved "reserved_text_2" (size = 1000, fill = 0x12345678);
select ".text*file3*";
}
}
GCC 命令 SECTIONS 用于描述输出文件的内存布局。TASKING 使用 section_layout 关键字用于此目的。
假设一个程序仅由代码、初始化数据和未初始化数据组成。这些将分别位于 .text、.data 和 .bss 节中。进一步假设这些是输入文件中出现的唯一节。对于此示例,代码应加载在地址 0x10000,数据应从地址 0x8000000 开始。这是一个 GCC 链接器脚本,它将这样做:
SECTIONS
{
. = 0x10000;
.text : { *(.text) }
. = 0x8000000;
.data : { *(.data) }
.bss : { *(.bss) }
}
相应的 TASKING LSL 语法如下。有关所用关键字的解释,请查阅 TASKING 用户指南。请注意,GCC GROUP 命令和 TASKING group 关键字提供完全不同的功能。
section_layout ::mpace (direction = low_to_high)
{
group (ordered, run_addr = 0x10000)
{
select "text*";
}
group (ordered, run_addr = 0x8000000)
{
select "data*";
select "bss*";
}
}
每个可加载或可分配的输出节都有两个地址。GNU 使用术语虚拟内存地址 (VMA),这是输出文件执行时节将具有的地址,以及加载内存地址 (LMA),这是节在闪存中加载/存储的地址。TASKING 对 LMA 的等效项是 load_addr。
通常,您不必描述系统中的内存,因为这是在随产品一起提供的 LSL 文件中完成的。通过命令行选项 --cpu=<type>,您已经选择了包含 AURIX 设备内存描述的适当 LSL 文件。大多数 AURIX 设备不支持外部内存,只有在特殊情况下,您可能需要指定外部内存的大小。
GCC 定义内存命令如下,
MEMORY
{
<name> [(<attr>)] : ORIGIN = <origin>, LENGTH = <len>
}
相应的 TASKING LSL 语法如下。有关所用关键字的解释,请查阅 TASKING 用户指南。
memory <mem name>
{
type = rom | ram | nvram | blockram;
mau = <size>;
size = <size>;
[priority = <number>;]
[exec_priority = <number>;]
[fill = <value>;]
[write_unit = <size>;]
map <map_name> (<map_description>);
}
map 关键字用于将内存附加到总线。请注意,没有 TASKING LSL 等效于 GCC 命令 REGION_ALIAS。不需要这样的关键字,因为内存映射到总线,总线随后映射到一个或多个、可能是异构的核心的一个或多个地址空间。因此,链接器可以推导出所有”region_aliases”。
以下是一个 GCC 示例,显示了符号赋值可能使用的三个不同位置。在此示例中,符号 floating_point 将被定义为零。符号 _etext 将被定义为最后一个 .text 输入节后的地址。符号 _bdata 将被定义为 .text 输出节后向上对齐到 4 字节边界的地址。
floating_point = 0
SECTIONS
{
.text : {
*(.text)
_etext = .;
_bdata = (. + 3) & ~ 3;
}
.data : { *(.data) }
}
此示例没有简单的 1 对 1 映射到 TASKING LSL。在 LSL 中,您可以创建预处理器符号,这些符号不会出现在输出文件中。LSL 不支持位置计数器,而是链接器创建符号,即所谓的链接器标签,标记节的开始和结束地址。请参见用户指南第 7.10 节链接器标签。这是相应的 TASKING LSL。
define preprocessor symbol = 10
section_layout ::mpace ()
{
"floating_point" = 0
group code { select "text"; }
group vars { select "data"; }
"_etext" = _lc_ge_code;
"_bdata" = (_lc_gb_vars + 3) & -3;
}
在某些情况下,希望链接器脚本仅在引用符号且未由链接中包含的任何对象定义时定义该符号。PROVIDE 关键字可用于定义符号,例如 etext,仅当它被引用但未定义时。语法是 PROVIDE (<symbol> = <expression>)。
以下是使用 PROVIDE 定义 etext 的 GCC 示例:
SECTIONS
{
.text : {
*(.text)
_etext = .;
PROVIDE (etext = .);
}
}
TASKING LSL 提供相同的功能,请参见第 16.8.4 节创建符号。这是相应的 TASKING LSL。
section_layout ::vtc:linear
{
group code { select .text*; }
"etext" := _lc_ge_code;
}
在程序启动时,节从其在闪存中的存储位置复制到 RAM 中的位置,未初始化的数据节用零填充。此程序初始化代码由链接器”创建”,覆盖所有节,包括用户指定名称的节。
如果您有自己的初始化代码,则使用命令行选项 --user-provided-initialization-code。
除了 TASKING 用户指南中提供的信息外,您还可以查阅应用笔记《TASKING TriCore 工具集的链接器脚本语言 (LSL) 技巧与窍门》,以了解更多关于 LSL 语言及其应用的信息。
__near、__far 等内存限定符代替节属性_interrupt 关键字简化中断处理Q: 迁移后代码大小增加了,如何优化?
A: 可以尝试以下方法:
--opt-level=3Q: 如何处理 TASKING 不支持的 GCC 扩展?
A: 对于不支持的扩展,需要:
Q: 迁移后中断处理不正常,怎么办?
A: 检查以下几点:
Q: 如何处理链接器脚本中的复杂内存布局?
A: 建议:
Q: 迁移后程序运行速度变慢,如何优化?
A: 可以考虑:
如果您有问题或改进本指南的建议,请随时联系 support@softor.com.cn ; tianpengbo@softor.com.cn
作者:tianpengbo / 田朋博。大家如果在项目中遇到相关技术问题,欢迎联系我交流。
support@softor.com.cn
tianpengbo@softor.com.cn
作者:tianpengbo / 田朋博。大家如果在项目中遇到相关技术问题,欢迎联系我交流。
support@softor.com.cn
tianpengbo@softor.com.cn