In my embedded project I compile `amazon-freertos/lib/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c` in this way:
/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi-gcc \ -std=gnu11 \ -mcpu=cortex-m7 \ -mthumb \ -mapcs \ -mfloat-abi=hard \ -mfpu=fpv5-d16 \ -fno-common \ -fno-math-errno \ -fsingle-precision-constant \ -fno-trapping-math \ -fno-signaling-nans \ -fno-builtin \ -fstrict-aliasing \ -fstack-usage \ -Wstack-usage=300 \ -DCPU_MIMXRT1051DVL6B \ -D__FREERTOS__=1 \ -DFSL_RTOS_FREE_RTOS \ -DFSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE \ -D__MCUXPRESSO \ -D__USE_CMSIS \ -DARM_MATH_CM7 \ -D__NEWLIB__ \ -DDEBUG=0 \ -IDSP/source/ \ -Iamazon-freertos/lib/FreeRTOS-Plus-TCP/ \ -Iamazon-freertos/lib/FreeRTOS-Plus-TCP/portable/BufferManagement/ \ -Iamazon-freertos/lib/FreeRTOS-Plus-TCP/portable/NetworkInterface/imxrt105x/ \ -Iamazon-freertos/lib/FreeRTOS/ \ -Iamazon-freertos/lib/include/ \ -Iamazon-freertos/lib/FreeRTOS/portable/GCC/ARM_CM4F/ \ -Iamazon-freertos/lib/FreeRTOS/portable/MemMang/ \ -Og \ -g3 \ -Wall \ -ffunction-sections \ -fdata-sections \ -c \ -MMD \ -MP \ -Werror \ -D"ARCPRINTF( ... )=(void)0" \ --specs=nano.specs \ -Wa,-anhlmsd=build/DSP/amazon-freertos/lib/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.lst \ -o build/DSP/amazon-freertos/lib/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.o amazon-freertos/lib/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c
I have `ipconfigUSE_TCP` set to 1 in `amazon-freertos/lib/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfig.h``FreeRTOS_Sockets.c` declares `xBoundUDPSocketsList` and `xBoundTCPSocketsList`
/* The list that contains mappings between sockets and port numbers. Accesses to this list must be protected by critical sections of one kind or another. */ List_t xBoundUDPSocketsList; #if ipconfigUSE_TCP == 1 List_t xBoundTCPSocketsList; #endif /* ipconfigUSE_TCP == 1 */
Once I have my elf executable linked, run this command:
$ /opt/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi-nm -a -l -n -t x --print-size image/DSP.elf | grep -E '^[[:xdigit:]]{8} [[:xdigit:]]{8} B' | grep SocketsList 2001ac7c 00000014 B xBoundTCPSocketsList 2001ac90 00000014 B xBoundUDPSocketsList /home/max/Lavori/4202/src/repos/toremove/FW/amazon-freertos/lib/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c:162
Both symbols exist in the executable, but one (`xBoundTCPSocketsList`) does not seem to belong to any .c source.Both appear in the map file:
$ grep -n -A 1 -E 'xBoundTCPSocketsList|xBoundUDPSocketsList' image/DSP.map 61974: .bss.xBoundTCPSocketsList 61975- 0x000000002001ac7c 0x14 ./build/DSP/amazon-freertos/lib/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.o 61976: 0x000000002001ac7c xBoundTCPSocketsList 61977: .bss.xBoundUDPSocketsList 61978- 0x000000002001ac90 0x14 ./build/DSP/amazon-freertos/lib/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.o 61979: 0x000000002001ac90 xBoundUDPSocketsList
Even addr2line fails:
$ arm-none-eabi-addr2line -a -e image/DSP.elf 2001ac7c 2001ac90 0x2001ac7c ??:0 0x2001ac90 /home/max/Lavori/4202/src/repos/toremove/FW/amazon-freertos/lib/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c:162
even the `FreeRTOS_Sockets.lst` doesn't tell me anything more:
7337 .global xBoundTCPSocketsList 7338 .global xBoundUDPSocketsList 7339 .section .bss.xBoundTCPSocketsList,"aw",%nobits 7340 .align 2 7341 .set .LANCHOR2,. + 0 7344 xBoundTCPSocketsList: 7345 0000 00000000 .space 20 7345 00000000 7345 00000000 7345 00000000 7345 00000000 7346 .section .bss.xBoundUDPSocketsList,"aw",%nobits 7347 .align 2 7348 .set .LANCHOR1,. + 0 7351 xBoundUDPSocketsList: 7352 0000 00000000 .space 20 7352 00000000 7352 00000000 7352 00000000 7352 00000000
There are many other symbols present in the executable but which do not seem to be associated with any .c source file.Why this behavior? What changes between the two symbols `xBoundTCPSocketsList` and `xBoundUDPSocketsList`? Am I getting it wrong or omitting some debugging parameters when compiling? How do I get either nm or some other way to get the .c source where a symbol is declared?
best regards
Max
The variable xBoundTCPSocketsList is declared as extern in a header FreeRTOS_IP_Private.h. It is defined in the file FreeRTOS_Sockets.c which also happens to include FreeRTOS_IP_Private.h. As a result, the extern declaration and the definition of the variable are forced to appear, in that order, in the same file FreeRTOS_Sockets.c. This situation causes the dwarf debug information about the variable to be split into two entries. It is likely that the tools nm/objdump aren't able to cope with this split. I do not know if there's a switch that they take to force them to consider such splits.
But, I was able to workaround this situation by avoiding inserting the extern declaration for the variable in the FreeRTOS_Sockets.c file. Below are the steps:
/* FreeRTOS_IP_Private.h */ /* Replace the preprocessor directives surrounding * the extern declaration, as shown below */ /* Defined in FreeRTOS_Sockets.c */ #if ( ipconfigUSE_TCP == 1 ) && (!defined(FREERTOS_SOCKETS_C_FILE)) extern List_t xBoundTCPSocketsList; #endif
Edit: I think it is also possible to modify the step#1 to define-undefine the new macro, insideFreeRTOS_Sockets.c, just around the #include "FreeRTOS_IP_Private.h", instead of around the whole file.
Step#1 can then be alternatively written, in a more succint manner, as:
/* FreeRTOS_Sockets.c */ /* ... */ #define FREERTOS_SOCKETS_C_FILE #include "FreeRTOS_IP_Private.h" #undef FREERTOS_SOCKETS_C_FILE /* ... */
Edit2: Here is a bug in gcc, where an extern declaration and the corresponding definition, both seperate statements but still in the same file - a situation seen above, of an array resulted in gcc not placing the array bounds in the dwarf debug information, causing gdb to output incorrect size of the array.
a.surati said:It is defined in the file FreeRTOS_Sockets.c which also happens to include FreeRTOS_IP_Private.h.
That, surely, is a standard practice?
True. Extern-declaring a global inside a header, and then including that header (or pasting the extern-declaration) in the source files that need to refer to that global is a standard practice.
(1) The files, where the global isn't defined, have no other way to reference it.
(2) The file, where the global is defined, may or may not need the extern-declaration.
(2a) It may need the extern-decl, for e.g., if there's some code in the file, which needs to refer to the global, but which lies in the file before the position where the global is defined. By including the header, or by providing the same extern-declaration on the top, such a piece of code can refer to the global without having to move the definition of the global.
But, this situation (2a) causes gcc to split the the dwarf debug info about the variable into two entries, with one of them chained to the other through an DW_AT_specification attribute. The tools nm/objdump/addr2line seem to be troubled by such splitting/chaining. The gcc bug, mentioned in my first reply, proves that gcc/binutils are troubled by situation (2a) in more than one ways.
However, see here, where a dwarf engineer says, referring to his/her language expert:
"If this is for C/C++, for example, my shaky language lawyer suggests that it is not valid for both an external declaration and an allocating declaration to occur in the same unit, ...".
IIUC, it says that the extern-decl-statement and the corresponding definition-statement, if they are separate, may not appear together in the same compilation unit; IOW, it suggests that situation (2a) is 'forbidden'/'invalid'.
Edit: formatting the quote.
Edit2: CLang doesn't split the dwarf-debug-info entry in the situation (2a):
extern int xTCP; int xTCP=20; int main() { return xTCP; }
[user@mach bin]$ gcc -Og -gdwarf-2 -g3 a.c [user@mach bin]$ objdump --dwarf . . . <1><31>: Abbrev Number: 2 (DW_TAG_variable) <32> DW_AT_name : (indirect string, offset: 0x2629): xTCP <36> DW_AT_decl_file : 1 <37> DW_AT_decl_line : 1 <38> DW_AT_decl_column : 12 <39> DW_AT_type : <0x3f> <3d> DW_AT_external : 1 <3e> DW_AT_declaration : 1 . . . <1><46>: Abbrev Number: 4 (DW_TAG_variable) <47> DW_AT_specification: <0x31> <4b> DW_AT_decl_line : 2 <4c> DW_AT_decl_column : 5 <4d> DW_AT_location : 9 byte block: 3 28 40 0 0 0 0 0 0 (DW_OP_addr: 4028) . . . DW_MACRO_start_file - lineno: 0 filenum: 1 filename: a.c
[user@mach bin]$ ./clang -Og -gdwarf-2 -g3 a.c [user@mach bin]$ ./llvm-dwarfdump --debug-info --name=xTCP a.out: file format ELF64-x86-64 0x0000002e: DW_TAG_variable DW_AT_name ("xTCP") DW_AT_type (0x00000044 "int") DW_AT_external (0x01) DW_AT_decl_file ("/home/user/llvm/usr/bin/a.c") DW_AT_decl_line (2) DW_AT_location (DW_OP_addr 0x4028)
View all questions in GNU Toolchain forum