字节对齐与绝对定位

字节对齐:

//KEIL编译器
__align(num) 这个用于修改最高级别对象的字节边界

eg: __align(64) u8 mem1base[MEM1_MAX_SIZE];

//IAR GCC 编译器
#pragma pack(num) 指定下面变量按num字节对齐 作用域为下面所有变量,如果要恢复需要使用#pragma pack()
#pragma pack() 能够取消自定义的对齐方式,恢复默认对齐
//eg push pop声明作用域

#pragma pack(push)
#pragma pack(4)

struct。。。//需要字节对齐的变量或结构体

#pragma pack(pop)

#pragma pack(4)
u8 mem1base[MEM1_MAX_SIZE];             //内部SRAM内存池
u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000))); 
#pragma pack()	
#pragma pack(push)
#pragma pack(32)
//#pragma location=0x20230000
u8 mem1base[MEM1_MAX_SIZE] ;									//内部SRAM内存池
#pragma location=0x80800000
u8 mem2base[MEM2_MAX_SIZE] ;//__attribute__((at(0x80800000)));    //外部SDRAM内存池,前面8M给LTDC用了(1280*800*2)
#pragma pack(pop)	

MDK与IAR的绝对定位

1.直接通过链接文件地址,需要定义section段和修改链接文件//如rt1052工程

#if defined(__CC_ARM) || defined(__GNUC__)  //GCC 与 MDK
    __attribute__((section(".boot_hdr.conf")))
#elif defined(__ICCARM__)                   //IAR
#pragma location=".boot_hdr.conf"
#endif

2.通过关键字定义
IAR编译器:#pragma location= //@应该也可以

#pragma pack(push)
#pragma pack(32)
//#pragma location=0x20230000
u8 mem1base[MEM1_MAX_SIZE] ;									//内部SRAM内存池
#pragma location=0x80800000
u8 mem2base[MEM2_MAX_SIZE] ;//__attribute__((at(0x80800000)));    //外部SDRAM内存池,前面8M给LTDC用了(1280*800*2)
#pragma pack(pop)	

MDK编译器:attribute((at(0X20000000)))

__align(64) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X20000000)));	//原子 malloc函数	

总结示例如下

#if defined ( __CC_ARM   )      // MDK
const uint8_t Test_flash[] __attribute__((at(0x08030000))) = "Test Flash";
const uint32_t Test_Addr __attribute__((at(0x08030010))) = 0x12345678;
#elif defined ( __ICCARM__ )    // IAR
const uint8_t Test_flash[] @ 0x08030000 = "Test Flash";
const uint32_t Test_Addr @ 0x08030010 = 0x12345678;
#else
const uint8_t Test_flash[] = "Test Flash";
const uint32_t Test_Addr = 0x12345678;
#endif

MDK常量定位到rom会有以下为题:
我用的STM32F107VC,有256K的flash,而现在的测试程序10K左右。
IAR会很干脆的将我要定位的数据放到指定的位置,中间空白的地方保持0xFF;
而MDK则不干脆,在0x08030000附近,还有程序的其它const数据放进去了。
这还不是最重要的,最重要的是主程序和0x08030000之间的数据都清成ix00了。
这会导致两个问题,第一个问题是:我编译完毕后看到的信息,flash是很大很大的(本质是包括了那些0x00);
第二个问题是,我下载程序需要的时间长很多。

查看文章 STM32 keil mdk启动代码发分析_转2010年01月29日 星期五 13:50 ;// Stack Configuration ;// Stack Size (in Bytes) ;// Stack_Size EQU 0x00000200 ;//定义堆栈大小 AREA STACK, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段 按8字节对齐 ;AREA 伪指令用于定义一个代码段或数据段 NOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0 Stack_Mem SPACE Stack_Size ;//保留Stack_Size大小的堆栈空间 分 配连续 Stack_Size 字节的存储单元并初始化为 0 __initial_sp ;//标号,代表堆栈顶部地址,后面有用 ;// Heap Configuration ;// Heap Size (in Bytes) ;// Heap_Size EQU 0x00000020 ;//定义堆空间大小 AREA HEAP, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段,8字节对齐 __heap_base Heap_Mem SPACE Heap_Size ;//保留Heap_Size的堆空间 __heap_limit ;//标号,代表堆末尾地址,后面有用 PRESERVE8 ;//指示编译器8字节对齐 THUMB ;//指示编译器为THUMB指令 ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY ;//定义只读数据段,其实放在CODE区,位于0地址 EXTERN NMIException EXTERN HardFaultException EXTERN MemManageException EXTERN BusFaultException EXTERN UsageFaultException EXTERN SVCHandler EXTERN DebugMonitor EXTERN PendSVC EXTERN SysTickHandler ;//声明这些符号在外部定义,同C ;//在××it.c中实现这些函数 ,中断就能自动调用了 EXPORT __Vectors EXPORT __initial_sp ;EXPORT:在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用;I
在C语言中,结构体的字节对齐是为了优化内存访问速度和对齐要求而进行的一种对齐方式。结构体的字节对齐确保结构体中的成员按照一定的规则进行排列,以便于处理器高效地访问内存。 结构体的字节对齐规则通常由编译器根据特定的对齐选项和目标平台的要求来确定。在C语言中,可以使用`#pragma pack`指令或者编译器提供的特定选项来控制结构体的字节对齐方式。 默认情况下,大多数编译器会按照特定的对齐规则进行字节对齐。这些规则通常是根据基本数据类型的大小来确定的。例如,常见的对齐规则是按照4字节对齐(即结构体成员的偏移量必须是4的倍数)或者8字节对齐。 以下是一个示例,展示了如何使用`#pragma pack`指令来设置结构体的字节对齐方式: ```c #pragma pack(push, 1) // 以1字节对齐 struct MyStruct { char c; int i; double d; }; #pragma pack(pop) // 恢复默认的对齐方式 int main() { printf("sizeof(MyStruct) = %zu\n", sizeof(struct MyStruct)); return 0; } ``` 在上面的示例中,`#pragma pack(push, 1)`指令将当前的对齐方式推入一个栈中,并将对齐方式设置为1字节对齐。然后定义了一个包含不同类型成员的结构体。最后,使用`#pragma pack(pop)`指令将对齐方式恢复为默认值。 请注意,修改结构体的字节对齐方式可能会导致内存浪费或者访问错误,因此在修改字节对齐方式时要特别小心。建议仅在必要时进行修改,并确保了解目标平台的字节对齐要求。 希望这能回答你的问题!如果还有疑问,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值