__attribute( (section(x)) ) 在 GCC 和 ARMCC (Keil MDK) 中的使用

通过 __attribute( (section(x)) ) 来对函数进行快速测试

先从简单代码开始,以下代码通过宏 EXPORT 来帮助我们快速定义一个 myfun_t 变量, 所以在EXPORT(hello);就定义了一个 _hello 变量, 于是我们可以在 main 中进行访问

#include <stdio.h>

typedef struct
{
    void (*fun)(void);
    const char *desc;
} myfun_t;

#define EXPORT(x)               \
    static myfun_t _##x = {     \
        .fun = x                \
    }

void hello(void)
{
    printf("Hello\n");
}
EXPORT(hello);

int main(int argc, char const *argv[])
{
    _hello.fun();

    return 0;
}

__attribute 宏用来设置编译属性, __attribute( (section(x)) ) 可以指定编译器将变量存放到指定的内存区域, 之后我们就可以使用

extern type_t __start_<section_name>
extern type_t __stop_<section_name>

来进行访问, __start_<section_name> 代表段的起始, 是一个内置标签, 就像 int a = 12; 中的 a 一样, 它的数据类型取决于我们如何看待它, 和很多变量标签一样, 通过 & 可以访问变量所在的地址, 所以访问段的的起始地址为 &__start_mysection

#include <stdio.h>

#define MYSECTION __attribute((used, section("mysection")))

char mystr[] MYSECTION = "Good";
// int myvalue MYSECTION = 125;

int main(int argc, char const *argv[])
{
    extern char __start_mysection;
    printf("%s\n", &__start_mysection);
    
    // extern int __start_mysection;
    // printf("%d\n", myvalue);     // 125

    return 0;
}

测试代码

有了上面的基础, 就可以尝试写快速测试的代码了,一般来说我们希望快速测试一个函数, 编写完后在函数下面通过一个宏定义 TEST_FUNC_ADD 就可以将函数插入到测试代码的行列。

test.h

#pragma once

typedef struct
{
    void (*fun)(void);
    const char *name;
    const char *desc;
    char _tmp[8]; /* 32 位对齐 */
} test_command_t;

#define SECTION __attribute((used, section("myfun_section")))

#define EXPORT_TEST_COMMAND(f, n, d)       \
    static test_command_t _##f SECTION = { \
        .fun = f,                          \
        .name = n,                         \
        .desc = d,                         \
    }

#define TEST_FUNC_ADD(f, n, d, ...)           \
    static void _##f(void)                    \
    {                                         \
        int r = f(__VA_ARGS__);               \
        if (r == 0)                           \
            printf("Func %s TEST OK\n", n);   \
        else                                  \
            printf("%s TEST ERR %d\n", n, r); \
        return;                               \
    }                                         \
    EXPORT_TEST_COMMAND(_##f, n, d)

test.c

#include "test.h"
#include <stdio.h>
#include <string.h>

/* 获取函数列表所在的内存区间 */
extern test_command_t __start_myfun_section;
extern test_command_t __stop_myfun_section;
test_command_t *myfun_section_begin = &__start_myfun_section;
test_command_t *myfun_section_end = &__stop_myfun_section;

#define foreach_command(item) \
    for (test_command_t *item = myfun_section_begin; \
    item != myfun_section_end; item++)

void func1(void)
{
    printf("func1: hello\n");
}
EXPORT_TEST_COMMAND(func1, "print", "To print hello");

int func_test(int max)
{
    if (max < 10)
        return 0;

    return -1;
}
TEST_FUNC_ADD(func_test, "less", "Check less than 10", 8);

int main(int argc, char const *argv[])
{
    char command[256];

    while (1)
    {
        printf("\nsh# ");
        gets(command);

        if (strncmp(command, "help", 4) == 0)
        {
            foreach_command(entry)
            {
                printf("    %-15s\t -- %s\n", entry->name, entry->desc);
            }

            continue;
        }

        foreach_command(entry)
        {
            if (strcmp(entry->name, command) == 0)
            {
                entry->fun();
                break;
            }
        }
    }

    return 0;
}

然而上述功能只能对 GCC 平台有效, 如果是 ARMCC 或是其他平台, 因为编译器不同, 方法可能不一样, 为了跨平台, 就不得不添加平台检测的宏, 比如将下面的代码替换获取 myfun_section 所在的内存区间部分即可支持 ARMCC 平台。

#ifdef __ARMCC_VERSION  /* ARM C Compiler */
    extern test_command_t myfun_section$$Base;
    extern test_command_t myfun_section$$Limit;
    test_command_t *myfun_section_begin = &(myfun_section$$Base);
    test_command_t *myfun_section_end = &(myfun_section$$Limit);
#elif defined (__GNUC__)
    extern test_command_t __start_myfun_section;
    extern test_command_t __stop_myfun_section;
    test_command_t *myfun_section_begin = &__start_myfun_section;
    test_command_t *myfun_section_end = &__stop_myfun_section;
#else
    #error "The platform is not supported"
#endif

参考

<think>我们正在讨论ARMCC编译器GCC编译器的区别联系。首先,需要明确两者都是用于编译C/C++代码的工具,但由不同组织开发,且有不同的定位使用场景。###核心差异与联系分析####1.**开发背景与所属机构**-**ARMCC(ARMCompiler)**:由ARM公司开发维护,是ARM官方推荐的编译器套件,集成在KeilMDK、DS-5等IDE中。主要针对ARM架构芯片进行深度优化[^1]。-**GCC(GNUCompilerCollection)**:自由开源软件,由GNU项目维护,支持多种架构(包括ARM、x86等),广泛应用于Linux系统开发。####2.**优化能力与性能**-**ARMCC优势**:-对ARM指令集(如Thumb-2、Cortex-M/A系列)提供**更精细的优化**,尤其在代码大小性能上表现更优。-支持高级SIMD(NEON)指令自动矢量化[^1]。-**GCC优势**:-开源生态活跃,支持更多平台新兴特性(如RISC-V)。-通用性强,但在特定ARM芯片的优化可能落后于ARMCC。####3.**兼容性与标准支持**-**语言标准**:-GCC通常更快支持最新C++标准(如C++20)[^2]。-ARMCC更注重工业领域稳定性(如C99)。-**操作系统支持**:-GCC是Linux系统的默认编译器。-ARMCC主要用于嵌入式RTOS(如FreeRTOS、µC/OS)。####4.**存储分布与链接处理**-根据引用[2],两者在内存布局处理逻辑相似:-`Code`(代码段)、`RO_data`(只读数据)、`RW_data`(读写数据)、`ZI_data`(零初始化数据)的划分一致。-差异主要在于**链接脚本语法**(ARMCC使用scatterfile,GCC使用ldscript)。####5.**许可证与成本**-**ARMCC**:商业闭源软件,需购买授权(免费版有代码大小限制)。-**GCC**:完全免费(GPL许可证)。---###对比总结表|**维度**|**ARMCC**|**GCC**||------------------|-----------------------------------|-----------------------------||开发方|ARM公司|GNU项目||许可证|商业闭源|GPL开源||ARM架构优化|✅深度优化|⚠️通用优化||多平台支持|❌仅ARM|✅支持x86/RISC-V等||IDE集成|Keil/DS-5|Eclipse/VSCode插件等||最新C++标准支持|较慢(专注稳定性)|较快|---###典型场景选择建议-**选择ARMCC时**:-开发基于Cortex-M的实时嵌入式系统(要求代码尺寸最小化)。-需官方认证的编译器(如安全关键应用IEC61508)[^1]。-**选择GCC时**:-开发Linux驱动或应用(需与内核兼容)。-成本敏感型项目(无授权费用)或需多架构移植。---§§相关问题§§1.**ARMCCGCC在中断处理函数编写上有何差异?**(例如GCC要求`__attribute__((interrupt))`而ARMCC用`__irq`关键字[^2])2.**如何将ARMCC项目迁移到GCC?**(链接脚本/启动文件/编译器标志的转换要点)3.**GCC的ARM后端优化技术如何追赶ARMCC?**(分析ACLE扩展`-mcpu`参数的作用)</think> ### ARMCCGCC编译器的区别与联系 ARMCCGCC均为C/C++编译器,但存在显著差异。以下是核心对比: --- #### 1. **开发主体与性质** | 编译器 | 开发方 | 许可证 | 生态定位 | |--------|---------------|------------|----------------| | ARMCC | ARM公司 | 商业闭源 | 深度优化ARM架构 | | GCC | GNU开源社区 | GPL开源 | 跨平台通用编译器 | - **关键差异**:ARMCC是ARM官方商业产品,针对其芯片指令集(如Cortex-M/A)做了深度优化;GCC是开源生态的基础工具链,支持包括ARM在内的多种架构[^1]。 --- #### 2. **优化能力对比** - **ARMCC优势**: - **指令级优化**:针对Thumb-2指令集自动选择16位/32位混合编码,减少代码体积(最高压缩30%)[^1] - **SIMD加速**:内置NEON向量化编译器,自动将循环转换为SIMD指令 - **实时性优化**:对中断延迟使用有特殊优化(如`--min_rtt`选项) - **GCC优势**: - **通用性优化**:开源社区持续贡献优化(如Graphite循环优化、IPA过程间分析) - **插件扩展**:支持`-fplugin`添加自定义优化插件 - **新特性支持**:更快适配新语言标准(如C++20模块) --- #### 3. **内存布局差异(参考引用[2])** 两种编译器对存储分布的处理逻辑相似但实现不同: ```plaintext ┌─────────────┬──────────────┐ │ 内存区域 │ 对应段类型 │ ├─────────────┼──────────────┤ │ ROM占用 │ .text(Code) + │ │ │ .rodata │ ├─────────────┼──────────────┤ │ RAM初始化区 │ .data(RW_data)│ ├─────────────┼──────────────┤ │ RAM未初始化 │ .bss(ZI_data) │ └─────────────┴──────────────┘ ``` - **差异点**: - **启动文件**:ARMCC使用`startup_*.s`(含分散加载描述),GCC使用`crt0.o` - **只读数据位置**:ARMCC默认将常量放入`.constdata`段,GCC使用`.rodata` - **ZI段清零**:ARMCC通过`__main()`自动初始化ZI段,GCC需显式调用`_sbrk()`[^2] --- #### 4. **指令集支持** | 特性 | ARMCC | GCC | |--------------------|------------------------|-------------------------| | Thumb模式 | 默认启用(-thumb) | 需指定`-mthumb` | | 内联汇编语法 | ARM扩展语法 | AT&T/GAS标准语法 | | 中断处理 | `__irq`关键字 | `__attribute__((irq))` | --- #### 5. **典型应用场景** - **ARMCC适用**: - 对功耗代码大小敏感的嵌入式场景(如IoT设备) - 需ARM官方认证的安全关键系统(如ISO 26262) - **GCC适用**: - 开源项目(Linux内核、Zephyr RTOS) - 多架构交叉编译(如ARM+x86混合开发) --- ### 总结 ARMCCGCC本质是**商业闭源优化**与**开源通用性**的权衡: $$ \text{选择建议} = \begin{cases} \text{ARMCC} & \text{极致性能/尺寸优化} \\ \text{GCC} & \text{跨平台/开源协作需求} \end{cases} $$ ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值