Create the GlobalVariable which have extern in one header file - llvm

Good day. I am facing an 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 an initializer. So, I have the following:
GlobalVariable *gvar_data = new GlobalVariable(
M, blockItems->getType(), true, GlobalValue::CommonLinkage,
blockItems, "DATA_TABLE");
gvar_data->setAlignment(16);
gvar_data->setSection("data_section");
gvar_data->addAttribute(llvm::Attribute::OptimizeNone);
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:::::::::!

If you don't call setInitializer(), the GlobalVariable you make is extern. There is a function that'll supply an all-zeroes initializer for a type you supply, I don't remember its name off-hand, or you can make a suitable initializer yourself using classes such as ConstantStruct, ConstantInt and their siblings.

Related

Insert global variable declaration with a gcc plugin

I would like to know if it's possible to insert a global variable declaration with a gcc plugin. For example if I have the following code:
test.c:
int main(void) {
return 0;
}
and I want to transform it into:
int fake_var;
int main(void) {
return 0;
}
Is that possible?
If it's possible, in which pass and how can I do it?
I think you'll want to take a look at varpool_add_new_variable() in varpool.c. You should be able to pass a declaration built with type VAR_DECL to it. Similarly, take a look at add_new_static_var(), but I think the former is what you want, as it was added specifically to allow declaring globals in the middle/back end.
Using GCC -D option u can pass a value to a C program.
Eg:
int main()
{
printf("global decl %d\n", gvar);
}
gcc -Dgvar=10 gcc.c
This may give a closest behaviour you are looking for though this is not equivalent to a global variable declaration. This is a macro substitution at compile time.
below there is an example of create a global integer var:
//add_new_static_var, in cgraph.h
tree global_var = add_new_static_var(integer_type_node);
//if you want to name the var:
tree name = get_identifier("my_global_name");
DECL_NAME(global_var) = name;
/*AND if you have thought to use in another subsequent compilation, you
will need to give it an assembler name like this*/
change_decl_assembler_name(global_var, name);
Keep in mind that in another compilation that it's supposed you to link after with a previous compilation you will need to declare the global var too, but you will have to declare all var with DECL_EXTERNAL(global_var) = 1 in all compilation minus the original, and only in one compilation (i.e, the original: the compilation that hold the original var ) you must only to add the propertie TREE_PUBLIC(global_var) = 1
Ehm, no. Don't. Why would you want to? You can't use it.
The closest you can get is to define the variable in a new .c file and link it in separately, but it would still have to be declared (with extern) in test.c for test.c to use it.
you can create a file that contains the code you want to add to the top of the input file and use the -include yourfile option.
that advises the preprocessor to assume an #include "yourfile" at the top of the input file.
see this question:
Include header files using command line option?
But you have to separately build that c file since this file will be added to all compilation units.

How to declare a global integer instance in LLVM IR?

I was wondering if anyone knew how to declare a global integer instance in LLVM IR. So far, I've been doing the following:
// Create symbol to identify previous block. Added by Justin.
llvm::Type::TypeID stupidTypeID = llvm::Type::IntegerTyID;
llvm::Type* typePtr = llvm::Type::getPrimitiveType(_context, stupidTypeID);
llvm::GlobalVariable* prevBlockID = new llvm::GlobalVariable(typePtr,
false,
llvm::GlobalValue::LinkerPrivateLinkage,
NULL,
"PREV_BLOCK_ID");
When I try to run, I get the following error:
static llvm::PointerType* llvm::PointerType::get(llvm::Type*, unsigned int): Assertion `EltTy && "Can't get a pointer to <null> type!"' failed.
It's due to the wrong type. You can have a look at Type::getPrimitiveType implementation here. Simply put, that's NOT the API you are advised to use; for IntegerType, it returns nullptr. Also, in definition of TypeID in llvm/IR/Type.h, there comments that:
/// Note: If you add an element to this, you need to add an element to the
/// Type::getPrimitiveType function, or else things will break!
Basically you can generate the type by 2 approaches:
static get API for the specified type
In your case,
IntegerType *iTy = IntegerType::get(ctx, 32); // if it's 32bit INT
a helper class named TypeBuilder
It makes type generation more easily and universally. TypeBuilder is especially useful and intuitive when you need to define more complicated types, e.g, FunctionType, of course with the cost of compiling your source code slowly(should you care?).
IntegerType *intType = TypeBuilder<int, false>::get(ctx); // normal C int
IntegerType *intTy = TypeBuilder<types::i<32>, false>::get(ctx); // if it's 32bit INT
BTW, you can also try ELLCC online compiler to get the corresponding C++ code for generating LLVM IR of current c/c++ src, where you need to choose the target of Output Options as LLVM C++ API code. Alternatively you can try it yourself on your machine(Since internally the online compiler simply invokes llc):
llc input.ll -march=cpp -o -

Error when creating a global variable in llvm

I am trying to create a global variable in a function pass. The code is
gVar= new GlobalVariable(
/*Type=*/Int32Type,
/*isConstant=*/false,
/*Linkage=*/GlobalValue::CommonLinkage,
/*Initializer=*/0, // has initializer, specified below
/*Name=*/"gVar",
/*ThreadLocalMode*/GlobalVariable::InitialExecTLSModel);
However, I keep getting the following compiler error:
error: no matching function for call to ‘llvm::GlobalVariable::GlobalVariable(const llvm::Type*&, bool, llvm::GlobalValue::LinkageTypes, int, const char [4], llvm::GlobalVariable::ThreadLocalMode)’
Could you please tell me the right way to declare a global variable in llvm? Thank you very much!
In addition, I've referred to the header file:
http://llvm.org/docs/doxygen/html/GlobalVariable_8h_source.html
and this post
How can I declare a global variable in LLVM?
You need to pass a Module to the constructor. There are plenty of examples in the LLVM code base for creating global vars. For example, in examples/ExceptionDemo/ExceptionDemo.cpp:
new llvm::GlobalVariable(module,
stringConstant->getType(),
true,
llvm::GlobalValue::LinkerPrivateLinkage,
stringConstant,
"");
By the way - important note: you should not be creating new globals or doing anything else that modifies a module in a function pass. If you have to do that, you need a module pass.

Try to find global variables from compiled files. The program can't distinguish constants from global variables.

Good Day! I'm trying to find the decision for a long time.
My problem is:
For example I have 2 .cpp files, one of them containing
const std::string DICTIONARY_DEFAULT = "blah";
const std::string ADDTODICTIONARY_DEFAULT = "blah";
const std::string BUTTONS = "blah";
and the second one with
static int x1;
static int NewY1, NewY2, NewX1, NewX2;
Both fragments are in the global variables section. I need to print the global static variables (for example), but ignore constants. In nm output they're looking absolutely identical (b-type for every case, which means uninitialized local scope symbol). Is there any way to separate this cases automatically using only linux utilities (grep, regexps and so on are perfectly okay)?
MY TASK FOR BETTER UNDERSTANDING:
There is a program in C++, the main task is to find and to withdraw the list of global variables.
Input data looks like archives with lots of .cpp files. Every .cpp file is syntactically correct program in C++ (It Must successfully compiled using compilier GNU C++ and Microsoft Visual C++).
For every file from the archive I must output in separate string the name of the file and the list of global variables, like in the example:
Output Data :
000000.cpp ancestor ansv cost graph M N p qr query u
000001.cpp
000002.cpp
000003.cpp
000004.cpp
000005.cpp
000006.cpp
000007.cpp edge tree
finding global variables is a 'subject' of this clang tutorial -- in this tutorial author did it 'just for fun', but you may add some code to do exactly what you need... (btw, it is not so hard as one may guess :))
Short answer: There is actually no way to do it in every case
Long answer: Take a look at the SYMBOL TABLE using 'objdump -x file.o'. You can see that all global variables, both static and const, are allocated into a section called .bss. A section called .rodata also exists and it is, generally speaking, used to store const data. Unfortunately, in your case you are declaring two const std::string objects. Those objects are initialized by invoking their constructor before the 'main' function is run. Still, the initialization of their fields happens at run-time and so they are only 'logically' const, and not really const.
The compiler has no choice but to allocate them into the .bss section with all other globals.
If you add the following line
const int willBeInRoData = 42;
You will find that its symbol will be in the .rodata section and so it will be distinguishable from the other global integers.

Why can't I access my array subscript in global scope

If I have the following code in a function, I will not get an error and I can compile no problem, however, once I put it in global scope I will get an error for "cannot allocate an array of size zero", along with several other errors. Why does this happen and how can I get rid of the errors. I am aware of the risk of global variables, this is just a simple test case.
int* intest[2];
intest[0] = new int;
You are allowed declarations in global scope but not allowed to use the new operator or the assignment. Thus you need the declaration int *intest[2] in global scope (and all your code would see it) but C++ requires the new to be in the sequence of your main code. (probably in some sort of start up function for the app).
EDIT: as pointed out by #phresnel you can use the new operator in this scope but not the assignment (this is unusual but not illegal). However the following new operators used as initiation will work for you:
int *x[2]={new int,new int};
In general the use of such a global buffer is highly discouraged and is considered an anti-pattern - if you can avoid using it you probably should.
int* intest[2];
Is valid placing in the local scope however :
intest[0] = new int;
is not.
The difference is that the upper one is a initalisation statement (creating the variable) and the lower one is a executed code segment.
Code that should be "executed" cant be called in the global scope, for example you cant call a function in the global scope. When would that function be called?
I can create how many variables i want in the global scope but i cant run code from it except from constructors being called when initialisating the global variables.
If you want to execute code such as :
intest[0] = new int;
You would have to execute it trough main or another function, otherwise the program would not know when to execute it.
AFAIK, the global scope only allow u put define and declaration on it. Whereas intest[0] = new int; is a assignment that c/c++ compiler shall fail while compile.