hel*_*ore 26 c gcc arm gnu-arm
我有几个C源文件,它们都声明了个别名称相同的静态全局变量.我的理解是每个文件中的静态全局变量应该只在该文件中可见,并且不应该应用外部链接,但实际上我可以在调试时看到同名的变量共享相同的内存地址.
就像static关键字被忽略一样,全局变量被视为extern相反.为什么是这样?
foo.c的:
/* Private variables -----------------------------------*/
static myEnumType myVar = VALUE_A;
/* Exported functions ----------------------------------*/
void someFooFunc(void) {
myVar = VALUE_B;
}
Run Code Online (Sandbox Code Playgroud)
bar.c:
/* Private variables -----------------------------------*/
static myEnumType myVar = VALUE_A;
/* Exported functions ----------------------------------*/
void someBarFunc(void) {
myVar = VALUE_C;
}
Run Code Online (Sandbox Code Playgroud)
baz.c:
/* Private variables -----------------------------------*/
static myEnumType myVar = VALUE_A;
/* Exported functions ----------------------------------*/
void someBazFunc(void) {
myVar = VALUE_D;
}
Run Code Online (Sandbox Code Playgroud)
myVar = ...在每个函数内的行上设置断点.someFooFunc,someBarFunc并按someBazFunc顺序调用.someFooFunc myVar最初设置为VALUE_A,在踩到线路后设置为VALUE_B.someBarFunc myVar由于某种原因VALUE_B在步进之前初始设置为,而不是VALUE_A我所期望的,表明链接器可能已经基于具有相同名称的单独全局变量合并.someBazFunc当它被调用.&myVar每个断点处的值,则给出相同的地址.工具链:GNU ARM GCC(6.2 2016q4)
编译器选项:
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mlong-calls -O1 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-move-loop-invariants -Wall -Wextra -g3 -DDEBUG -DTRACE -DOS_USE_TRACE_ITM -DSTM32L476xx -I"../include" -I"../system/include" -I"../system/include/cmsis" -I"../system/include/stm32l4xx" -I"../system/include/cmsis/device" -I"../foo/inc" -std=gnu11 -MMD -MP -MF"foo/src/foo.d" -MT"foo/src/foo.o" -c -o "foo/src/foo.o" "../foo/src/foo.c"
Run Code Online (Sandbox Code Playgroud)
链接器选项:
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mlong-calls -O1 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-move-loop-invariants -Wall -Wextra -g3 -T mem.ld -T libs.ld -T sections.ld -nostartfiles -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"myProj.map" --specs=nano.specs -o ...
Run Code Online (Sandbox Code Playgroud)
ieh*_*ich 23
注意:我确实知道OP的目标平台是ARM,但是我仍然在发布x86方面的答案.原因是,我没有派上用场的ARM后端,而问题不仅限于特定的架构.
这是一个简单的试验台.请注意,我使用的int是自定义enumtypedef,因为它根本不重要.
foo.c的
static int myVar = 1;
int someFooFunc(void)
{
myVar += 2;
return myVar;
}
Run Code Online (Sandbox Code Playgroud)
bar.c
static int myVar = 1;
int someBarFunc(void)
{
myVar += 3;
return myVar;
}
Run Code Online (Sandbox Code Playgroud)
main.c中
#include <stdio.h>
int someFooFunc(void);
int someBarFunc(void);
int main(int argc, char* argv[])
{
printf("%d\n", someFooFunc());
printf("%d\n", someBarFunc());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用GCC 4.8.4在x86_64 Ubuntu 14.04上编译它:
$ g++ main.c foo.c bar.c
$ ./a.out
3
4
Run Code Online (Sandbox Code Playgroud)
有效地获得这样的结果意味着myVar变量在foo.c和bar.c不同.如果你看一下反汇编(by objdump -D ./a.out):
000000000040052d <_Z11someFooFuncv>:
40052d: 55 push %rbp
40052e: 48 89 e5 mov %rsp,%rbp
400531: 8b 05 09 0b 20 00 mov 0x200b09(%rip),%eax # 601040 <_ZL5myVar>
400537: 83 c0 02 add $0x2,%eax
40053a: 89 05 00 0b 20 00 mov %eax,0x200b00(%rip) # 601040 <_ZL5myVar>
400540: 8b 05 fa 0a 20 00 mov 0x200afa(%rip),%eax # 601040 <_ZL5myVar>
400546: 5d pop %rbp
400547: c3 retq
0000000000400548 <_Z11someBarFuncv>:
400548: 55 push %rbp
400549: 48 89 e5 mov %rsp,%rbp
40054c: 8b 05 f2 0a 20 00 mov 0x200af2(%rip),%eax # 601044 <_ZL5myVar>
400552: 83 c0 03 add $0x3,%eax
400555: 89 05 e9 0a 20 00 mov %eax,0x200ae9(%rip) # 601044 <_ZL5myVar>
40055b: 8b 05 e3 0a 20 00 mov 0x200ae3(%rip),%eax # 601044 <_ZL5myVar>
400561: 5d pop %rbp
400562: c3 retq
Run Code Online (Sandbox Code Playgroud)
您可以看到不同模块中静态变量的实际地址确实不同:0x601040for foo.c和0x601044for bar.c.但是,它们与单个符号相关联_ZL5myVar,这实际上搞砸了GDB逻辑.
您可以通过以下方式仔细检查objdump -t ./a.out:
0000000000601040 l O .data 0000000000000004 _ZL5myVar
0000000000601044 l O .data 0000000000000004 _ZL5myVar
Run Code Online (Sandbox Code Playgroud)
又一次,不同的地址,相同的符号.GDB如何解决这一冲突完全取决于实现.
我坚信这也是你的理由.但是,要确保双重,您可能需要在您的环境中尝试这些步骤.
| 归档时间: |
|
| 查看次数: |
1324 次 |
| 最近记录: |