我有一个ARM项目,我想保留某些未使用的变量和它们的数据,直到它们被使用。
我看到过防止gcc删除一个未使用变量:__attribute__((used))
对我来说不适用于全局变量(文档中暗示它只适用于函数)(arm-none-eabi gcc 7),但通过__attribute__((section(".data")))
将符号放在不同的节中确实有效。这可能是因为链接器的只有在通过-fdata-sections
给它们自己的节时才能剥离符号。我不喜欢它,但它有效。
所以,我尝试了这个方法,但是变量没有被保留-我想这是因为在那个项目中的某个东西在链接时启用了-Wl,--gc-sections
。这里是一个最小的例子,展示了我所尝试做的事情(基本上主文件只引用了头文件,在头文件中,要“保留”的变量被声明为extern -除此之外,主程序没有使用这些变量;然后在单独的.c文件中定义这些相同的变量):test.c
#include <stdio.h>
#include "test_opt.h"
const char greeting[] = "Hello World - am used";
int main(void) {
printf("%s!\n", greeting);
return 0;
}
test_opt.h
#include <stdint.h>
extern const char mystring[];
struct MyStruct {
uint16_t param_one;
uint8_t param_two;
unsigned char param_three[32];
};
typedef struct MyStruct MyStruct_t;
extern const MyStruct_t mystruct;
mystruct.c
#include "test_opt.h"
const char __attribute__((section(".MYSTRING"))) mystring[] = "Me, mystring, I am not being used";
const MyStruct_t __attribute__((section(".MYSTRUCT"))) mystruct = {
.param_one = 65535,
.param_two = 42,
.param_three = "myStructer here",
};
使用常规MINGW 64 gcc进行测试
让我们首先尝试不使用-Wl,--gc-sections
:
$ gcc -Wall -g mystruct.c test_opt.c -o test_opt.exe
$ strings ./test_opt.exe | grep -i 'mystring\|mystruct'
Me, mystring, I am not being used
*myStructer here
mystring
MyStruct
MyStruct_t
mystruct
mystruct.c
mystruct.c
mystruct.c
mystruct.c
mystring
mystruct
.MYSTRING
.MYSTRUCT
.MYSTRING
.MYSTRUCT
显然,变量和内容在此处可见。
现在,让我们尝试-Wl,--gc-sections
:
$ gcc -Wall -g -Wl,--gc-sections mystruct.c test_opt.c -o test_opt.exe
$ strings ./test_opt.exe | grep -i 'mystring\|mystruct'
mystring
MyStruct
MyStruct_t
mystruct
mystruct.c
mystruct.c
mystruct.c
mystruct.c
mystring
mystruct
显然,这里我们仍然有一些符号调试信息留下-但没有部分,也没有数据被报告。
使用ARM gcc进行测试
让我们使用ARM gcc重新进行相同的实验-首先不使用-Wl,--gc-sections
:
$ arm-none-eabi-gcc -Wall -g test_opt.c mystruct.c -o test_opt.elf -lc -lnosys
$ arm-none-eabi-strings ./test_opt.elf | grep -i 'mystring\|mystruct'
Me, mystring, I am not being used
*myStructer here
mystruct.c
MyStruct_t
MyStruct
mystruct
mystruct.c
mystring
mystruct.c
mystring
mystruct
.MYSTRING
.MYSTRUCT
与之前相同,变量、内容和节名称均可见。
现在,让我们尝试使用-Wl,--gc-sections
:
$ arm-none-eabi-gcc -Wall -g -Wl,--gc-sections test_opt.c mystruct.c -o test_opt.elf -lc -lnosys
$ arm-none-eabi-strings ./test_opt.elf | grep -i 'mystring\|mystruct'
请注意,与上一种情况不同,此处既没有留下任何数据内容,* 也没有 * 任何调试信息/符号名称!
所以,我的问题是:假设-Wl,--gc-sections
在项目中被启用,并且我不想删除它(因为我喜欢它的其他功能),我是否可以在代码中为一些特殊的变量指定“保留这些变量,即使它们未被使用/未被引用”,以这样一种方式,即使-Wl,--gc-sections
被启用,它们也被保留?
请注意,将keep
添加到属性,例如:
const char __attribute__((keep,section(".MYSTRING"))) mystring[] = "Me, mystring, I am not being used";
...使用(或不使用)-Wl,--gc-sections
进行编译时,通常会产生编译器警告:
mystruct.c:3:1: warning: 'keep' attribute directive ignored [-Wattributes]
3 | const char __attribute__((keep,section(".MYSTRING"))) mystring[] = "Me, mystring, I am not being used";
| ^~~~~
......我猜是因为如果我没有看错箭头,变量已经声明为const
(或者因为已经假定某个部分是“保留”的)?所以属性keep
肯定不是这里的答案......
2条答案
按热度按时间new9mtju1#
要通知链接器需要保留某些变量,应使用
-Wl,--undefined=XXX
选项:请注意,
__attribute__((used))
是一个仅用于编译器的标志,用于禁止-Wunused-variable
警告。6rqinv9w2#
OK -我发现了一些东西;不理想,但至少它只是一个“语法黑客”,我不必想出愚蠢的东西来处理结构体,只是为了让它们出现在可执行文件中(通常甚至我在这种情况下想出的代码,得到优化了
:)
)。我第一次尝试了
(void) varname;
hack用于How can I suppress "unused parameter" warnings in C?-我把它留在下面只是为了表明它不工作。最后奏效的是:基本上,只需在
main()
所在的位置创建一个static const void*
,并将指向该结构体的指针分配给它(编辑:*中的!);我猜由于“static const”的原因,编译器不会删除变量及其部分,即使使用-Wl,--gc-sections
也是如此。因此test_opt.c
现在变为:......我们可以测试:
请注意,在上面的示例中,只有
mystruct
最终被保留-mystring
仍然被优化掉了。EDIT:请注意,如果你试图作弊并将任务移到main之外:
......编译器就会看穿你的诡计,并向你致意:
......而你的情况也没有好转。