gcc generate wrong C symbol from C++ source file

Bug #1921483 reported by zhang wenjin
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain
New
Undecided
Unassigned

Bug Description

My test project has 3 files: main.cpp, test01.c, test02.cpp

test01.c ===>
    #include <stdint.h>

    const uint32_t testMaxDataLength = 16;
    const uint8_t testMaxData[16] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
    };

test02.cpp ==>
    #include <stdint.h>

    const uint32_t testCplusplusDatap[4] = {
      0x01234567, 0x89ABCDEF, 0xFFFF0000, 0x0000FFFF
    };

    #ifdef __cplusplus
    extern "C" {
    #endif

   const uint32_t testCDatap[2] = {
       0xFFFFFFFF, 0x00000000
   };

   #ifdef __cplusplus
   }
   #endif

main.cpp ===>
   #include <stdint.h>

   extern const uint32_t testCplusplusDatap[4];

   #ifdef __cplusplus
   extern "C" {
   #endif

   extern const uint32_t testMaxDataLength;
   extern const uint8_t testMaxData[16];
   extern const uint32_t testCDatap[2];

   #ifdef __cplusplus
   }
   #endif

   void main(void) {
        uint32_t total = 0;
        for (uint32_t i = 0; i < 4; i++) {
            total += testCplusplusDatap[i];
        }

        for (uint32_t i = 0; i < testMaxDataLength; i++) {
           total += testMaxData[i];
       }

       for (uint32_t i = 0; i < 2; i++) {
           total += testCDatap[i];
       }
   }

the gcc toolchain will report "undefined reference to `testCplusplusDatap' and `testCDatap'".
use arm-none-eabi-nm check test02.cpp.o, test01.c.o, main.cpp.o:
00000000 r _ZL10testCDatap
00000000 r _ZL18testCplusplusDatap
00000000 R testMaxData
00000000 R testMaxDataLength

         U testCDatap
         U testCplusplusDatap
         U testMaxData
         U testMaxDataLength

the _ZL10testCDatap is not C symbol. and main link require No C++ symbol testCplusplusDatap.

ARM-NONE-EABI-GCC version : arm-none-eabi-gcc (GNU Arm Embedded Toolchain 9-2020-q2-update) 9.3.1 20200408 (release)
compiler & Linker flags:
C++ & C common flags ==>
        "-mtune=cortex-m4",
        "-mcpu=cortex-m4",
        "-mapcs-frame",
        "-march=armv7e-m",
        "-mfloat-abi=hard",
        "-mfpu=fpv4-sp-d16",

        "-gdwarf-2",
        "-Wall",
        "-Wextra",
        "-Wno-missing-field-initializers",
        "-Wno-unused-parameter",
        "-Wno-sign-compare",
        "-Wno-comment",
        "-Wno-switch",

        "-fno-delete-null-pointer-checks",
        "-fno-strict-aliasing",
        "-ffunction-sections",
        "-fmessage-length=0",
        "-fdata-sections",
        "-fsigned-char",
        "-fno-builtin",
        "-ffast-math",
        "-mno-sched-prolog",
        "-mthumb",
        "-nostdlib",
        "-MMD",

C flags ===>
        "-std=gnu11",
        "-fno-hosted",
        "-Wno-old-style-declaration",
        "-fomit-frame-pointer",

C++ flags ==>
        "-std=gnu++0x",
        "-fno-exceptions",
        "-fpermissive",
        "-fno-rtti",

linker flags ==>
        "-mthumb",
        "-fmessage-length=0",
        "-ffunction-sections",
        "-fdata-sections",
        "-fsigned-char",
        "-Wall",
        "-Wextra",
        "-g3",
        "-Xlinker",
        "--gc-sections",
        "-Wl,--wrap=main",
        "--specs=nano.specs",
        "-mcpu=cortex-m4",
        "-march=armv7e-m",
        "-mfloat-abi=hard",
        "-mfpu=fpv4-sp-d16",

Tags: symbol
Revision history for this message
David Brown (davidbrown) wrote :

In C++, the default linkage for a "const" declaration is internal. This is different from non-const declarations, and different from C (or C++ with extern "C"), where the default linkage is external. So if you declare an object in a C++ file as "const uint32_t testCplusplusDatap[4] = {..." , then it it has internal linkage - the symbol is not exported from the current file.

There is nothing wrong with the names here, it is simply that the const symbol is left internal to the C++ file.

The quick solution is to add "extern" to the definition of the C++ const array.

The correct solution is to use headers, and be strict in making all your "extern" declarations in a header, while the C or C++ file #include's the matching header and has the definitions of the objects. Any objects that don't have a declaration in the header should be "static", if they are not C++ const objects. The use of the keyword "extern" within a C or C++ file, rather than a header, should therefore be a sign of questionable code structure.

(There are always exceptions to such rules - including quick tests.)

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.