Create the GlobalVariable which have extern in one header file

Good day. I am facing issue with creating a GlobalVariable. I already have an extern for that global in a header file to use it in the following way

extern const void* DATA_TABLE[];

And with a LLVM PASS, I am trying to create this array with the same name and with initializer. So, I have following:

GlobalVariable *gvar_data = new GlobalVariable(
    M, blockItems->getType(), true, GlobalValue::CommonLinkage,
    blockItems, "DATA_TABLE");

I am not sure if I am using the correct Linkage or not.The pass has failed to complete it. Here is the runtime fault. Any guess what I am doing incorrect?

'common' global must have a zero initializer!
[10 x i8*]* @DATA_TABLE.1
LLVM ERROR: Broken module found, compilation aborted:::::::::!


As you've guessed, it's the linkage.

"common" is the name for the C situation where multiple source files
simply declare "int a;" with nothing else specified. The names get
merged, and the variable gets zero-initialized by default. A "real"
definition (like you're trying to provide) would take precedence over
this and specify the actual data.

You almost certainly want GlobalValue::ExternalLinkage for a
bog-standard global variable.



I have changed it to ExternalLinkage. Now, in LLVM IR, it looks like that:

@DATA_TABLE = external global [0 x i8*], section “data_section”, align 16 #0
@DATA_TABLE.1 = global [10 x i8*] [i8* inttoptr (i64 53415718 to i8*), i8* bitcast (void (%class.Hello*)* @_ZN5Hello5ptofnEv to i8*),…], section “data_section”, align 16 #0

In my uses:
%arrayidx = getelementptr inbounds [0 x i8*], [0 x i8*]* @DATA_TABLE, i64 0, i64 %3

Why it is creating another global variable instead of linking? Is that because of array size mismatch?

Here is my code:

GlobalVariable *old = M.getGlobalVariable("DATA_TABLE");

GlobalVariable *gNew = new GlobalVariable(
M, blockItems->getType(), false, GlobalValue::ExternalLinkage,
blockItems, "DATA_TABLE");


Why it is creating another global variable instead of linking?

You're explicitly calling "new" which creates a global variable. If
there's an existing global you want to reuse you should call
Module::getOrInsertGlobal instead. But...

Is that because of array size mismatch?

It's definitely not helping, and if you can't come up with a way to
get the type when creating the original variable you might have to
create two variables after all.

In that case you'd create your new variable with a known array length,
use ConstantExpr::getBitCast to cast it to [0 x i8*]* and then call
replaceAllUsesWith to make the existing code use your new variable
with initializer.