I am trying to write a program to JIT some code. The JITTed code needs to make calls back into the running application for run-time support and the run-time support symbols are not found when the function is materialized.
I tried to follow the Kaleidoscope tutorial. I need to call a function in the run-time from some IR generated code. For example, I want to call this function from some llvm IR.
extern "C" void* llvmNewVector() {
return new vector<int>();
}
According to the Kaleidoscope tutorial it should be declared extern "C" and in the run-time of the application. Within the LLVM IR I have created a function prototype and the IR is correctly generated (no errors after checking the function I am jitting).
It would seem to me that there would be something more to do to link this function to the jitted code, but the Kaleidoscope tutorial doesn't seem to do that.
My problem is that the jitted code fails to materialize because the external symbols are not resolved.
The following code prints "made it here" but gets no further.
cerr << "made it here." << endl;
auto Sym = ExitOnErr(TheJIT->lookup(name));
NativeCodePtr FP = (NativeCodePtr)Sym.getAddress();
assert(FP && "Failed to find function ");
cerr << "returning jitted function " << name << endl;
return FP;
I am sure I am doing something wrong or missing some step, but I have not been able to find it.
The output I get is:
made it here.
JIT session error: Symbols not found: { llvmNewVector }
Failed to materialize symbols: { my_test }
The code was compiled using LLVM-9 with the following flags:
clang++ -I. -g -I../include/ -std=c++11 -fexceptions -fvisibility=hidden -fno-rtti -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.cpp
For linking the following was used:
llvm-config --libs
I ran into this same issue and could solve it the following way:
The following lines of code in the tutorial, whose goal is to resolve symbols in the host process, does not seem to work.
ES.getMainJITDylib().setGenerator(
cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess(DL)));
So instead, I manually registered the symbols that I wanted linked like this:
SymbolMap M;
// Register every symbol that can be accessed from the JIT'ed code.
M[Mangle("llvmNewVector")] = JITEvaluatedSymbol(
pointerToJITTargetAddress(&llvmNewVector), JITSymbolFlags());
}
cantFail(ES.getMainJITDylib().define(absoluteSymbols(M)));
I added this code right after the two lines of code that I mentioned above, from the tutorial.
How about adding -Xlinker --export-dynamic option for clang?
I met the similar problem in the tutorial.
In my environment (Ubuntu 20.04), sin and cos can be resolved, but printd or putchard (the functions defined in the source code of Kaleidoscope processor) cannot.
After compilation, can you see the function name in the dynamic symbol table of the program?
objdump -T program | grep llvmNewVector
If there are no -T option in objdump (e.g., Mac), it might not be the case.
In my case, printd nor putchard do not appear in the dynamic symbol table (but appear in symbol table).
To add these function names into the dynamic symbol table, you need to pass -Xlinker --export-dynamic option for clang (actually, the option is passed to ld), for example (this is one for the tutorial),
clang++ -Xlinker --export-dynamic -g toy.cpp `llvm-config --ldflags --system-libs --libs all` -O3 -o toy
After compilation, the function names appear in dynamic symbol table, and the examples of the tutorial work well.
It depends on which llvm version you use. LLVM 10 has LLJIT class and it was working for me the following way
auto J = ExitOnErr(LLJITBuilder().create());
auto M = createDemoModule();
auto &dl = J->getDataLayout();
MangleAndInterner Mangle(J->getExecutionSession(), dl);
auto &jd = J->getMainJITDylib();
auto s = absoluteSymbols({{ Mangle("printd"), JITEvaluatedSymbol(pointerToJITTargetAddress(&printd), JITSymbolFlags::Exported)}});
jd.define(s);
the printd function was defined in the same file
extern "C" int32_t printd() {
std::cout << "calling " << __FUNCTION__ << "...\n";
return 11;
}
Related
I am trying to compile a program so that it starts on a different entry point. I am running WSL1 with Ubuntu 20.04.5, and GCC and G++ 9.4.0
I found that adding the flag -Wl,--entry=foo to the compiler will link foo() as the entry function. Testing, this has worked with gcc, but not with g++.
Using the example file src/main.c:
#include <stdlib.h>
#include <stdio.h>
int main()
{
printf("Entering %s:%s\n", __FILE__, __func__);
return 0;
}
int not_main()
{
printf("Entering %s:%s\n", __FILE__, __func__);
exit(0); // Necessary, otherwise it throws a segfault
}
When compiled with gcc -Wl,--entry=not_main -o entry.o src/main.c the output is what I want: Entering src/main.c:not_main.
However, when compiled with g++ -Wl,--entry=not_main -o entry.o src/main.c, the following warning appears: /usr/bin/ld: warning: cannot find entry symbol not_main; defaulting to 0000000000001080.
This defaults to the main() function, outputting Entering src/main.c:main. The function not_main() is not found by the linker, but it is present in the source code.
The documentation for g++ says:
g++ is a program that calls GCC and automatically specifies linking against the C++ library.
I don't see how g++ can differ from gcc, if internally one calls the other. I understand that it is not the compiler but the linker which changes the entry point, and that g++ (unlike gcc) is linking against the C++ library, but I fail to understand how that is problematic.
What am I missing?
Because of name mangling, the function is not not_main but _Z8not_mainv.
how g++ can differ from gcc,
What is the difference between g++ and gcc? why use g++ instead of gcc to compile *.cc files?
C++, unlike C, uses name mangling to distinguish different overloads of the same function name.
When compiled with gcc:
$ objdump -t entry.o | grep not_main
000000000000117c g F .text 0000000000000036 not_main
When compiled with g++:
$ objdump -t entry.o | grep not_main
0000000000000000 *UND* 0000000000000000 not_main
000000000000117c g F .text 0000000000000036 _Z8not_mainv
The *UND*efined reference to not_main was probably placed there by the linker since you requested this as the entry point. The actual not_main function has its name mangled to _Z8not_mainv.
To export not_main under its original name, use extern "C":
extern "C" int not_main()
{
printf("Entering %s:%s\n", __FILE__, __func__);
exit(0); // Necessary, otherwise it throws a segfault
}
I am building a large application using libkml. I am using the cmake port of libkml from here: https://github.com/rashadkm/libkml
I am getting a stranged undefined reference to symbol error even thought the symbol appears to be referenced and defined.
This is the make command:
/usr/bin/c++ -fPIC -Werror=return-type -Werror=return-type -Wall
-Werror=parentheses -Werror=uninitialized -Werror=missing-braces
-fPIC -O0 -Wall -fPIC -fvisibility=hidden -fno-strict-aliasing
-Wno-long-long -m64 -g -D_DEBUG --coverage -Wl,-Bsymbolic -Wl,--
no-undefined -shared -o GPS2KML.plb CMakeFiles/GPS2KML.dir
/gps.cpp.o CMakeFiles/GPS2KML.dir/kml.cpp.o CMakeFiles/GPS2KML.dir
/stdafx.cpp.o /trunk/src/filter/GPS2KML/external/libkml/lib/cmake
/libkml/../../libkmlconvenience.so.1.3.1 /trunk/src/filter/GPS2KML
/external/libkml/lib/cmake/libkml/../../libkmlengine.so.1.3.1
/trunk/src/filter/GPS2KML/external/libkml/lib/cmake/libkml/../..
/libkmldom.so.1.3.1 /trunk/src/filter/GPS2KML/external/libkml
/lib/cmake/libkml/../../libkmlbase.so.1.3.1 -lminizip -luriparser
-lexpat
The make output:
CMakeFiles/GPS2KML.dir/kml.cpp.o: In function `cKML::~cKML()':
/trunk/src/filter/GPS2KML/src/kml.cpp:55: undefined reference to `*kmldom::SerializePretty(boost::intrusive_ptr<kmldom::Element> const&)*'
collect2: error: ld returned 1 exit status
Now if i do this:
daniyal#daniyal-Inspiron-5521:/$ nm --demangle --extern-only --defined-only ../trunk/src/filter/GPS2KML/external/libkml/lib/libkmldom.so | grep SerializePretty
It clearly shows:
000000000013c9aa T kmldom::SerializePretty[abi:cxx11](boost::intrusive_ptr<kmldom::Element> const&)
Now I fail to understand what is the problem. I have check the existing questions on stackoverflow regarding this, I found four solutions in the existing questions:
In some cases the demangled symbol name did not match with the symbol that was causing error. This is clearly not my case.
Use -llibrary at the end of the command after putting the name of the .o file. So that when the linker encounters the library it has an undefined symbol present in that library. This is clearly not a solution for me as I have the libraries present at the end of the command.
In some cases the symbol is present in the shared library but does not have external linkage or is not defined. This can be confirmed by using nm with --extern-only and --defined-only. And hence this is also not a solution for me.
Edit:
Additional Info:
This is the cmake file I am using:
find_package(LibKML REQUIRED)
include_directories(${LIBKML_INCLUDE_DIRS})
add_filter(${PROJECT}
gps.h
gps.cpp
kml.h
kml.cpp
#can2gps.h
#can2gps.cpp
stdafx.h
stdafx.cpp )
target_link_libraries (${PROJECT} ${LIBKML_LIBRARIES})
add_filter roughly translates to this macro:
add_library(${NAME} MODULE ${ARGN} ${${NAME}_MOC} ${${NAME}_UI} ${${NAME}_QRC})
target_link_libraries(${NAME} ${BUILD_LIBS} ${QT_LIBRARIES} ${ADTF_OPENGL_LIBRARY} ${ADTF_ADDITIONAL_UTILS_LIBS})
set_target_properties(${NAME}
PROPERTIES
SUFFIX ".plb"
)
if(UNIX)
set_target_properties(${NAME}
PROPERTIES
PREFIX ""
)
It looks like you have an ABI mismatch issue. ABI is "Application Binary Interface", basically the specification for exactly how arguments make it onto the stack (or are put in registers) and various other things like that.
Try making sure your code is compiled with the -std=c++11 (or -std=gnu++11 if you use any GNU extensions) flag. It looks like that's how libkml was compiled. C++11 has a bunch of new features that require an ABI compatibility break with pre-C++11. C++14 and C++1z are less drastic changes, but they may also break ABI compatibility, I'm not sure. In this case though, the demangled symbol is clear, libkml wants at least C++11.
I'm trying to print a backtrace in code progrematically, compiling all my source with -g, as well as linking with it, and I also added fvisibility=internal.
but when I call the symbol list, all my code looks like:
module() [0x424b69]
why does the function name does not appear in the braces, what other possible flag should I add?
Thanks.
You should use
-rdynamic
Something like:
g++ -g -rdynamic main.cpp
From http://gcc.gnu.org/onlinedocs/gcc/Link-Options.html:
-rdynamic
Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only
used ones, to the dynamic symbol table. This option is needed for some
uses of dlopen or to allow obtaining backtraces from within a program.
I build a C++ project of mine using clang++, using the following command line command (split into lines):
clang++
-std=c++11
-W -Wall -Wextra -pedantic -Wno-newline-eof -Werror
-O4
-I<dirs>
-L<dirs>
-l<libs>
-framework <frameworks>
-D <defs>
-o <filename>
<files>
However, when I run strings <filename>, several class names show up, despite the -O4 in the command line. I've tried -Wl,-s which should tell llvm to strip all symbols, but that doesn't remove these.
The class names that show up seem to all have one thing in common: they have a vtable. One of these classes is :
class MyClass {
public:
virtual void myFunc() = 0;
};
It shows up as the symbol :
N9namespace7MyClassE
I don't like it that my namespace and class names show up in the final file. How do I strip these? My binary is a command line utility, so only the main function should be exported.
Even after supplying -fno-rtti (as suggested by #n.m.), some names still remain, such as :
__ZN15MyClassInstance6myFuncEv
(MyClassInstance being a subclass of the MyClass above)
Additionally, even the names of global variables are in the binary.
I solved this by supplying the clang argument -fno-rtti, which disables RTTI, a C++ feature I don't use anyway.
[edit]
It looks like -O4 does not imply strip, and the last few references to my class names can be removed by executing strip.
I am trying to compile a project that depends on the Xerces XML Parser. The project compiles for Windows without any difficulty, but I'm having some trouble compiling it with g++ in Cygwin.
In order to use Xerces, I am trying to compile my code against the static library libxerces-c.a. But when I do so, I get errors that look like this:
/tmp/cc2QGvMh.o:test.cpp:(.text+0x3a): undefined reference to `xercesc_2_8::DOMImplementationRegistry::getDOMImplementation(unsigned short const*)'
I've inspected the static library using ar, and confirmed that it contains the DOMImplementationRegistry.o file that defines the function that I am calling.
ar -t libxerces-c.a
...
DOMImplementationImpl.o
DOMImplementationRegistry.o
DOMLocatorImpl.o
...
I've also extracted the object files from the library, and used 'nm' to make sure that the function I am calling actually exists:
ar -x libxerces-c.a
nm --demangle DOMImplementationRegistry.o
...
00000080 T xercesc_2_8::getDOMImplSrcVectorMutex()
00000300 T xercesc_2_8::DOMImplementationRegistry::getDOMImplementation(unsigned short const*)
000002a0 T xercesc_2_8::DOMImplementationRegistry::addSource(xercesc_2_8::DOMImplementationSource*)
...
Since I can compile everything for Windows but not with g++, I thought that the error could be in the linker order (similar to the problem described in this question). However, even after changing the linker order, I am still getting the same compiler error. I have tried both
g++ -o test.exe test.cpp -Llib -lxerces-c
and
g++ -o test.exe test.cpp lib/libxerces-c.a
Any ideas?
Your project uses method from xercesc_2_6 namespace as pointed by compiler error message but your library offers xercesc_2_8 version. Problem is probably caused by mismatch between headers you use and library object file.
You didn't say the source of the archive. If it isn't compiled with cygwin, it could be a name mangling problem. Compiling the library from source might well fix this.
It could also be that the archive is built incorrectly so that it has internal resolution problems. Try giving the library name twice.
g++ -o test.exe test.cpp lib/libxerces-c.a lib/libxerces-c.a
If this works, the archive is broken and you should look for or build a new one.
Try the linker option --enable-stdcall-fixup (see 'man ld'). It will care for name mangling and calling conventions:
g++ -o test.exe test.o -Wl,--enable-stdcall-fixup -Llib -lxerces-c