使用C语言清除BSS段,我们肯定要获取BSS段的起始地址和结束地址,那么,C语言要怎么实现使用lds文件中的变量abc?
答:需要以下两步,这两步是重点。
- 在函数中声明该变量为extern类型(类型不重要,因为我们主要是取值,具体原因后面会说);
- 使用时,要取址,比如, int *p = &abc;//p的值即为lds中abc的值。
比如下图中,使用extern声明代码段的起始地址和bss段的起始地址,然后取值用指针进行复制操作,这样lds中的变量也可以像C语言中的普通变量一样操作。(实际上,它们和C语言中的变量不同。)
在C语言中需要声明,那么在汇编指令中,为什么可以直接使用?(如下图,为重定位和清除bss段的汇编代码)
下面开始解答:
在C函数中,如果我们声明如下变量。这样,该变量为全局变量:
int g_i; //程序中必然有四字节空间来保存这个变量
但是,如果我们在lds链接文件中声明了a1,a2,a3…an个变量,那么,.bin文件中是不会保存这些变量的,这是为啥?
答:这是因为C程序中不保存lds文件中的变量(因为一般用不到),而且真正要用到的时候,我们也并不是没办法。
我们编译程序时,有一个symbol table符号表,万一要用这些变量,可以通过这个符号表在链接的时候使用。
以上面为例,除了g_i,我们再声明两个变量:
int g_i, g_j, g_k;
那么在链接的时候,会有一个符号表如下:
画质不好,但是还是能看懂的。这里每个圈表示一个变量,一个变量由名字和地址构成。显然,C语言中的变量,名字即为变量名,地址即为变量的地址。但是,我们前面说过,.bin文件中不会保存lds文件中的变量,所以lds文件中的变量,地址填的是值,名字则还是变量名。 所以,我们在copy2sdram函数中才要使用取址符号来修饰这个lds变量,因为它的地址才是它的值。
另外,我们要明白。
- 这个符号表只存在于链接时,作用是辅助链接,不存在与.bin文件中。
- lds文件中,无论变量还是常量,里面的值都来自于链接脚本,在链接时由编译器决定。
在使用上,他们和C语言中的普通变量是不同的:
- 对于g_i,它是一个C语言变量,使用&g_i就可以得到它的地址Addr;
- 对于lds中的a1,他们没有地址,因为.bin文件里面不会保存它们,C语言中使用它们时,使用&a1取它们的值。
综上所述,使用ld中的变量,就是借助symbol table保存lds的变量,使用时加上&得到它们的值。