c语言小知识点 7 __attribute #pragma pack (n)使用及(scatter file)分散加载文件 .sct

知识点15

使用伪指令#pragma pack (n) C编译器将按照n个字节对齐。

使用伪指令#pragma pack (),取消自定义字节对齐方式

另外,还有如下的一种方式:

 __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结 构中有成员的长度大于n,则按照最大成员的长度来对齐。

__attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数 进行对齐

具体用法详见pdf文档

 

知识点16:

scatter file)分散加载文件 .sct

首先介绍几个概念:

1.ARM映像文件

ARM映像文件是一个层次性结构的文件,其中包含了域(region)、输出段(output section)和输入段(input section)。各部分关系如下:

一个映像文件由一个或多个域组成

每个域包含一个或多个输出段

每个输出段包含一个或多个输入段

各输入段包含了目标文件中的代码和数据

输入段中包含了4类内容:代码、已经初始化的数据、未经初始化的存储区域、内容初始化成0的存储区域。每个输入段有相应的属性,可以为只读的(RO)、可读写的(RW)以及初始化成0的(ZI)。ARM连接器根据各输入段的属性将这些输入段分组,再组成不同的输出段以及域。

一个输出段中包含了一系列的具有相同的RORWZI属性的输入段。输出段的属性与其中包含的输入段的属性相同。在一个输出段内部,各输入段是按照一定的规则排序的,这个后面再补充。

一个域中包含了1~3个输出段,其中各输出段的属性各不相同。各输出段的排列顺序是由其属性决定的。其中,RO属性的输出段排在最前面,其次是RW属性的输出段,最后是ZI属性的输出段。一个域通常映射到一个物理存储器上,如ROMRAM等。

2.ARM映像文件各组成部分的地址映射

分散加载机制允许为链接器指定映像的存储器映射信息,可实现对映像组件分组和布局的全面控制。分散加载通常仅用于具有复杂存储器映射的映像(尽管也可用于简单映像),也就是适合加载和执行时内存映射中的多个区是分散的情况。

要构建映像的存储器映射,链接器必须有:描述节如何分组成区的分组信息、描述映像区在存储器映射中的放置地址的放置信息。

分散加载区域分两类:

加载区:该映像文件开始运行前存放的区域,即当系统启动或加载时应用程序存放的区域。

执行区:映像文件运行时的区域,即系统启动后,应用程序进行执行和数据访问的存储器区域,系统在实时运行时可以有一个或多个执行块。

3.分散加载文件(即scatter file,后缀为.scf

分散加载文件是一个文本文件,通过编写一个分散加载文件来指定ARM连接器在生成映像文件时如何分配RO,RW,ZI等数据的存放地址。如果不用SCATTER文件指定,那么ARM连接器会按照默认的方式来生成映像文件,一般情况下我们是不需要使用分散加载文件的。

但在某些场合,我们希望把某些数据放在指定的地址处,那么这时候SCATTER文件就发挥了非常大的作用。而且SCATTER文件用起来非常简单好用。

举个例子:比如像LPC2378芯片具有多个不连续的SRAM,通用的RAM32KB,可是32KB不够用,我想把某个.C中的RW数据放在USBSRAM中,那么就可以通过SCATTER文件来完成这个功能。

分散加载文件的语法:

load_region_name  start_address | "+"offset  [attributes] [max_size]

{

    execution_region_name  start_address | "+"offset  [attributes][max_size]

    {

        module_select_pattern  ["("

                                    ("+" input_section_attr | input_section_pattern)

                                    ([","] "+" input_section_attr | "," input_section_pattern)) *

                               ")"]

    }

}

load_region         加载区,用来保存永久性数据(程序和只读变量)的区域;

execution_region    执行区,程序执行时,从加载区域将数据复制到相应执行区后才能被正确执行;

load_region_name    加载区域名,用于“Linker”区别不同的加载区域,最多31个字符;

start_address       起始地址,指示区域的首地址;

+offset             前一个加载区域尾地址+offset 做为当前的起始地址,且“offset”应为“0”或“4”的倍数;

attributes          区域属性,可设置如下属性:

                           PI       与地址无关方式存放;
                           RELOC    重新部署,保留定位信息,以便重新定位该段到新的执行区;
                           OVERLAY  覆盖,允许多个可执行区域在同一个地址,ADS不支持;
                           ABSOLUTE 绝对地址(默认);

max_size                该区域的大小; 

execution_region_name:执行区域名;

start_address       该执行区的首地址,必须字对齐;

+offset             同上;

attributes          同上;

                           PI          与地址无关,该区域的代码可任意移动后执行;
                           OVERLAY     覆盖;
                           ABSOLUTE    绝对地址(默认);
                           FIXED       固定地址;
                           UNINIT      不用初始化该区域的ZI段;

module_select_pattern: 目标文件滤波器,支持通配符“*”和“?”;

                        *.o匹配所有目标,* (或“.ANY”)匹配所有目标文件和库。

input_section_attr    每个input_section_attr必须跟随在“+”后;且大小写不敏感;

                        RO-CODE CODE
                        RO-DATA CONST
                        ROTEXT, selects both RO-CODE and RO-DATA
                        RW-DATA
                        RW-CODE
                        RW DATA, selects both RW-CODE and RW-DATA
                        ZI BSS
                        ENTRY, that is a section containing an ENTRY point.
                        FIRST,用于指定存放在一个执行区域的第一个或最后一个区域;
                        LAST,同上;

input_section_pattern: 段名; 

汇编中指定段:
     AREA    vectors, CODE, READONLY
C中指定段:
#pragma arm section [sort_type[[=]"name"]] [,sort_type="name"]*
sort_type:      coderwdatarodatazidata
                如果“sort_type”指定了但没有指定“name”,那么之前的修改的段名将被恢复成默认值。
#pragma arm section     // 恢复所有段名为默认设置。
应用:
    #pragma arm section rwdata = "SRAM",zidata = "SRAM"
        static OS_STK  SecondTaskStk[256];              // rwdata”“zidata”将定位在“sram”段中。
    #pragma arm section                                 // 恢复默认设置

 

样例:

 简单存储器映射实例

LOAD_ROM 0x0000 0x8000       //Name of load region, Start address for load region, Maximum size of load region

{

    EXEC_ROM 0x0000 0x8000   //Name of first exec region, Start address for exec region, Maximum size of this region

    {

        *(+RO)               //Place all code and RO data into this exec region

    }

    RAM 0x10000 0x60000      //Start of second exec region

    {

        *(+RW, +ZI)          //Place all RW and ZI data into this exec region

    }

}

复杂存储器映射实例:

LOAD_ROM_1 0x0000                //Start address for first load region

{

    EXEC_ROM_1 0x0000            //Start address for first exec region

    {

        program1.o (+RO)         //Place all code and RO data from program1.o into this exec region

    }

    DRAM 0x18000 0x8000          //Start address for this exec region  Maximum size of this exec region

    {

        program1.o (+RW, +ZI)    //Place all RW and ZI data from program1.o into this exec region

    }

}

 

LOAD_ROM_2 0x4000                //Start address for second load region

{

    EXEC_ROM_2 0x4000

    {

        program2.o (+RO)         //Place all code and RO data from program2.o into this exec region

    }

    SRAM 0x8000 0x8000

    {

        program2.o (+RW, +ZI)    //Place all RW and ZI data from program2.o into this exec region

    }

}

具体格式描述请参考资料: 分散加载描述文件

 一个具体的例子:

; *************************************************************

; *   Scatter-Loading Description File generated by uVision   *

; *************************************************************

 

LR_IROM1 0x00000000 0x00080000  {       ; 第一个加载域,名字是LR_IROM1,起始地址0x00000000 大小是0x00080000

    ER_IROM1 0x00000000 0x00080000  {   ; 第一个运行时域,名字是ER_IROM1 起始地址0x00000000 大小事0x00080000

        *.o (RESET, +First)             ; IAP第一阶段在FLASH中运行

        *(InRoot$$Sections)             ; All library sections that must be in a root region

        .ANY (+RO)                      ; .ANY*功能相似,用.ANY可以把已经被指定的具有RW,ZI属性的数据排除

    }

    RW_IRAM1 0x10000000 0x00010000  {   ; RW data

        .ANY(+RW +ZI)

    }

    RW_SDRAM1 0xA0000000 0x00800000  {  ; RW data

        STARTUP_LPC177X_8X.o (HEAP)     ;HEAP用来定位堆栈的底

        *.LIB(+RW +ZI)

    }

}

 

### 回答1: __attribute__是C语言中的一个特殊关键字,用于指定变量、函数、类型等的特殊属性。它可以用于优化代码、控制内存对齐、指定函数调用约定等方面。常见的__attribute__属性包括:aligned、packed、noreturn、deprecated等。使用__attribute__可以提高代码的可读性、可维护性和可移植性。 ### 回答2: C语言中的__attribute__是一种非常有用的特殊组合,它提供了许多编译器相关的功能,例如:控制数据的对齐方式,指定函数的参数和返回值,显式地将变量放入指定的内存区域等等。 __attribute__的使用方式非常简单,只需要在需要使用的变量、函数、类型或其他实体的定义前添加__attribute__并指定要使用的属性即可。例如,在声明变量的时候使用__attribute__((align(16)))就可以将该变量的字节对齐方式设置为16个字节。 除此之外,__attribute__还提供了许多其他有用的选项。例如,可以使用__attribute__((noinline))防止编译器将函数内联以优化代码,或者使用__attribute__((warn_unused_result))强制函数返回值被检查。 值得注意的是,__attribute__是一种非标准化的C语言扩展,因此在使用时需要谨慎。不同的编译器厂商可能会实现不同的__attribute__属性,而且一些老旧的编译器可能完全不支持这种特性。因此,为了确保代码的可移植性,最好只在确信目标平台支持__attribute__的情况下才使用它。 总而言之,__attribute__是一个非常强大和有用的特性,它可以帮助开发人员优化代码,提高性能,并提供许多有用的编译时功能。如果正确使用,__attribute__可以极大地简化一些编程任务,并帮助开发人员创建更好的代码。 ### 回答3: C语言中的__attribute__是一个GCC扩展,可以用于给变量、函数、结构体等添加属性,以达到一些特定的目的。__attribute__主要包括以下几种属性: 1. __attribute__((packed)):将变量或结构体成员的对齐方式设置为紧凑型(即不留空隙),以节省空间。 2. __attribute__((aligned(n))):将变量或结构体成员的对齐方式设置为n字节对齐,通常用于优化访问速度。 3. __attribute__((noreturn)):标记一个函数不返回值,可以用于避免编译器产生不必要的警告。 4. __attribute__((section("section_name"))):将函数或变量放置在指定名称的代码节或数据节中,这对于实现动态链接库、操作系统内核等有重要作用。 5. __attribute__((unused)):标记一个变量或函数未使用,可以避免编译器产生警告。 6. __attribute__((weak)):将函数或变量设置为弱定义符号。如果在程序中存在多个符号名称相同但定义内容不同的情况,链接器会选择其中具有强符号定义的符号,若都为弱符号定义,则会选择其中一个。 除此以外,__attribute__还有许多其它用法,不同的GNU扩展编译器也会提供一些特有的__attribute__用于辅助编写高效的代码。 需要注意的是,__attribute__是GCC的扩展特性,在C语言标准中并未定义,因此在使用时需要考虑兼容性问题。在使用时应该根据不同的编译器和平台,选择合适的__attribute__以避免产生错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值