MDK编译后变量地址分配讨论

2019-08-14 17:28发布

本帖最后由 shibusha 于 2017-7-7 12:12 编辑

注:本帖仅讨论MDK V4.72未开启代码优化的情况。

MDK编译完程序后,MAP文件中可以看到各函数和变量的相关地址。其中变量分为两个大部分Local Symbols,和Global Symbols。
Local Symbols主要是相关静态局部变量,Global Symbols主要是全局变量。
让我们看一下下面的例子:
[mw_shl_code=c,true]
struct test
{
        int ledd;
};
  
u32 gTest1 = 0;
u32 gTest2 = 0;
u8 gu8Test = 0;
u32 gTest3 = 0;

struct test testledd;

int main(void)
{
        static u32 staticu32Test = 0;
        static u8 staticTest = 0;

    SystemInit();                   //系统时钟等初始化
        
        while(1)
        {
                gTest1 = 1;
                gTest2 = 2;
                gTest3 = 3;
                testledd.ledd = 1;
                staticu32Test = 1;
                staticTest = 5;

        };
}[/mw_shl_code]


编译后地址如下,可以看到未开起编译优化的情况下,MDK会自动补全不足4字节的变量地址。
例如gu8Test长度是1字节,再分配下一个4字节变量时,MDK会跳过中间三个字节的地址。
    gTest1                                   0x20000018   Data           4  main.o(.data)
    gTest2                                   0x2000001c   Data           4  main.o(.data)
    gu8Test                                 0x20000020   Data           1  main.o(.data)
    gTest3                                   0x20000024   Data           4  main.o(.data)
    testledd                                  0x2000002d   Data           4  main.o(.data)


    staticu32Test                          0x20000028   Data           4  main.o(.data)
    staticTest                               0x2000002c   Data           1  main.o(.data)


细心的同学可能发现上面地址有两个问题,
1. 未开启优化的前提下,将两个静态局部变量的地址,放在了全局变量testledd前面,没有按照创建的顺序编译
2. testledd的地址是奇数,正常理解,M3中,此结构体地址默认分配应该是4字节的倍数(int型变量)。




此时我们将上述代码稍作修改,将四个全局变量改为如下
u32 gTest1 = 0;
u32 gTest2 = 0;
u8 gu8Test = 0;
u32 gTest3;
此时编译的地址为:
    gu8Test                                  0x20000020   Data           1  main.o(.data)
    gTest3                                   0x2000002c   Data           4  main.o(.data)
    testledd                                 0x20000030   Data           4  main.o(.data)
可以看到,未初始化gTest3的情况下,MDK的分配顺序如下:
1. 初始化的全局变量
2. 初始化的静态局部变量(为初始化也一致)
3. 未初始化的全局变量&结构体。
此时发现与第一种情况对比,gTest3的地址是4字节对齐的,而第一种情况下结构体testledd是没有4字节对齐的。

那么问题来了,MDK在分配普通变量的时候,跳过了不足4字节的变量来保证地址对齐,为何在编译更为复杂的结构体,反而选择了“节省内存”呢?
并且这种情况下使用指针访问testledd还容易出错.

再看一个情况:
u32 gTest1 = 0;
u32 gTest2 = 0;
u8 gu8Test = 0;
u32 gTest3 = 0;
u8 gTest4;

struct test testledd;

    gTest3                                   0x20000024   Data           4  main.o(.data)
    gTest4                                   0x2000002d   Data           1  main.o(.data)
    testledd                                 0x2000002e   Data           8  main.o(.data)

此时若初始化gTest4,结构体的地址又变回奇数。

以上是否可以理解为MDK编译后,在静态局部变量后的结构体,会被自动优化?

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。