C++ can't access global variable declared in Assembly

93 Views Asked by At

System: Centos

I have a C++ file, a assembly file and a GYP file:

C++ file: src/node_main.cc

#include <iostream>
using namespace std;
extern "C" {
extern char __attribute__((weak)) global_variable;
}  // extern "C"


int main()
{

    printf("global_variable:%p", reinterpret_cast<uintptr_t>(&global_variable));
    return 0;
}

Assembly file: src/global_variable.S

.global global_variable

global_variable:

GYP file: node.gyp

{
    'targets': [
        {
            'target_name': 'global_variable',
            'type': 'none',
            'conditions': [
                [ 'OS in "linux freebsd solaris"', {
                  'type': 'static_library',
                  'sources': [
                    'src/global_variable.S'
                  ]
                }],
            ]
        },
        {
            'target_name': 'myexperiment',
            'type': 'executable',
            'sources': [
                'src/node_main.cc'
            ],
            'dependencies': [ 'global_variable' ],
            'conditions': [
                [ 'OS in "linux freebsd"', {
                  'dependencies': [ 'global_variable' ],
                #   'ldflags+': [
                #     '<(PRODUCT_DIR)/obj.target/global_variable/src/global_variable.o'
                #   ]
                }]
            ]
        }
    ]
}

My build command:

python3 main.py
make

My question: When I comment out the "ldflags+", I can't access "global_variable":

./out/Default/myexperiment

Execute "myexperiment" will print "global_variable:(nil)".

When I use the "ldflags", I can access "global_variable", it will print "global_variable:0x4006e6".

I used "make -n" command and tried to see what happened to g++, using "ldflags+":

g++ -o out/Default/myexperiment out/Default/obj.target/global_variable/src/global_variable.o  -Wl,--start-group out/Default/obj.target/myexperiment/src/node_main.o out/Default/obj.target/libglobal_variable.a  -Wl,--end-group

not using "ldflags+":

g++ -o out/Default/myexperiment   -Wl,--start-group out/Default/obj.target/myexperiment/src/node_main.o out/Default/obj.target/libglobal_variable.a  -Wl,--end-group

It seems the only difference is: "global_variable.o".

If "global_variable.o" is added, the global variable can be accessed, otherwise the global variable is nil, despite "libglobal_variable.a" is added to both.

Thoroughly confused.

1

There are 1 best solutions below

0
jasonjifly On

Today I tried a lot of experiments, it took me two days to figure it out.

Finally I found the key: __attribute__((weak))

When using weak with static library, the linker will not try to find a definition from static library, so the definition will be discarded.

When linking with object file, the linker will unconditionally link it to the output file.

So it's unrelated to Assembler and GYP. It's because I didn't fully understand how .a file work with linker.

This answer helps me a lot: https://stackoverflow.com/questions/51656838/attribute-weak-and-static-libraries#:~:text=The%20weak%20attribute%20causes%20the,targets%2C%20and%20also%20for%20a.

Thank everyone!