'libdenpli.so : undefined reference to symbol 'Tcl_InitStubs' - gcc

I am getting 'libdenpli.so : undefined reference to symbol 'Tcl_InitStubs' while creating executable.
When I check with nm, I am getting this output:
nm libdenpli.so | grep Tcl_InitStubs
U denaliTcl_InitStubs
I looked at other machine with different platform where it worked fine. And I seen the output with t:
nm libdenpli.so | grep Tcl_InitStubs
<address> t denaliTcl_InitStubs
What is the difference?

As you can see in nm's manpage:
"t" The symbol is in the text (code) section.
"U" The symbol is undefined.
In other words, your libdenpli.so uses the symbol, but does not define it -- you need to link to the library that defines that symbol as well.
Since the other system's library seems to define it, maybe there are differences on how the libraries are supposed to be linked with, due to version, platform, build options, etc. Try to take a look at the documentation of the library to see how you are supposed to link to it.

Related

Getting "cannot find symbol .... while executing load ..." error when trying to run Hello World as a C extension (dll) example

I have used the C code from the following verbatim: https://wiki.tcl-lang.org/page/Hello+World+as+a+C+extension
/*
* hello.c -- A minimal Tcl C extension.
*/
#include <tcl.h>
static int
Hello_Cmd(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
Tcl_SetObjResult(interp, Tcl_NewStringObj("Hello, World!", -1));
return TCL_OK;
}
/*
* Hello_Init -- Called when Tcl loads your extension.
*/
int DLLEXPORT
Hello_Init(Tcl_Interp *interp)
{
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
/* changed this to check for an error - GPS */
if (Tcl_PkgProvide(interp, "Hello", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "hello", Hello_Cmd, NULL, NULL);
return TCL_OK;
}
My command for compiling is nearly verbatim except for the last character, indicating Tcl version 8.6 rather than 8.4, and it compiles without error:
gcc -shared -o hello.dll -DUSE_TCL_STUBS -I$TCLINC -L$TCLLIB -ltclstub86
Then I created the following Tcl program:
load hello.dll Hello
puts "got here"
But when running it with tclsh get the following error:
cannot find symbol "Hello_Init"
while executing
"load ./hello.dll Hello"
(file "hello.tcl" line 1)
So I am essentially following a couple of suggestions from Donal Fellows answer here: cannot find symbol "Embeddedrcall_Init" The OP there however commented that, like me, the suggestion(s) hadn't resolved their issue. One thing that I didn't try from that answer was "You should have an exported (extern "C") function symbol in your library" -- could that be the difference maker? Shouldn't it have been in the example all along then?
At the suggestion of somebody on comp.lang.tcl I found "DLL Export Viewer" but when I run it against the DLL it reports 0 functions found :( What am I doing wrong?
Could it be an issue with MinGW/gcc on Windows, and I need to bite the bullet and do this with Visual Studio? That's overkill I'd like to avoid if possible.
The core of the problem is that your function Hello_Init is not ending up in the global symbol table exported by the resulting DLL. (Some linkers would put such things in as _Hello_Init instead of Hello_Init; Tcl adapts to them transparently.) The symbol must be there for Tcl's load command to work: without it, there's simply no consistent way to tell your extension code what the Tcl_Interp context handle is (which allows it to make commands, variables, etc.)
(If you'd been working with C++, one of the possible problem is a missing extern "C" whose actual meaning is to turn off name mangling. That's probably not the problem here.)
Since you are on Windows — going by the symbols in your DLL, such as EnterCriticalSection and GetLastError — the problem is probably linked to exactly how you are linking. I'm guessing that Tcl is defining your function to have __declspec(dllexport) (assuming you've not defined STATIC_BUILD, which absolutely should not be used when building a DLL) and yet that's not getting respected. Assuming you're using a modern-enough version of GCC… which you probably are.
I'm also going through the process of how to build tcl extensions in C and had exactly the same problem when working though this same example using tcl 8.6.
i.e. I was compiling using MinGW GCC (64-bit), and used the following:
gcc -shared -o hello.dll -DUSE_TCL_STUBS "-IC:\\ActiveTcl\\include" "-LC:\\ActiveTcl\\lib" -ltclstub86
And like the OP I got no compile error, but when loading the dll at a tclsh prompt tcl complained :
'cannot find symbol "Hello_Init"'
I can't say that I understand, but I was able to find a solution that works thanks to some trial and error, and some information on the tcl wiki here
https://wiki.tcl-lang.org/page/Building+Tcl+DLL%27s+for+Windows
In my case I had to adjust the compiler statement to the following
gcc -shared -o hello.dll hello.c "-IC:\\ActiveTcl\\include" "-LC:\\ActiveTcl\\bin" -ltcl86t
Obviously those file paths are specific to my system, but basically
I had to add an explicit reference to the .c file
I had to include the tcl86t dll library from the tcl bin directory
I had to remove the -DUSE_TCL_STUBS flag ( meaning that the references -LC:\\ActiveTcl\\lib and -ltclstub86 could also be removed)
(attempting to use the -DUSE_TCL_STUBS flag caused the compiler to complain with C:\ActiveTcl\lib/tclstub86.lib: error adding symbols: File format not recognized )
This successfully compiled a dll that I could load, and then call the hello function to print my 'Hello World' message.
Something else I stumbled over, and which wasn't immediately obvious:
reading https://www.tcl.tk/man/tcl8.6/TclCmd/load.htm, tcl epxects to find an 'init' function based on a certain naming convention.
if the C extension does not define a package name then the name of that init function will be derived from the dll filename.
This caused a few problems for me (when compiling via Eclipse IDE), as the dll name was being automatically determined from the eclipse projet name.
For example, if I recompile the same example, but call the .dll something else, eg.
gcc -shared -o helloWorldExenstion.dll hello.c "-IC:\\ActiveTcl\\include" "-LC:\\ActiveTcl\\bin" -ltcl86t
Then at tclsh prompt:
% load helloWorldExtension
cannot find symbol "Helloworldextension_Init"

Override GCC linker symbols in c code using weak declaration

I am building an elf target. I have a linker script where I input some of the symbol locations like(these symbols are defined in a different locations like ROM whose address is provided below),
A = 0x12345678;
B = 0x1234567c;
D = 0x1234568c;
In the C code I can use these variables A and B without declaring them which is expected.
I want to know if I can override the symbol D i.e., My current executable can have its own declaration of D. In that case the linker should ignore D. Is there a way to declare the symbols in linker script as 'weak'? so that the linker can use 'input symbols' only if it is not declared in any of the linked objects.
Use PROVIDE directive
PROVIDE(D = 0x1234568c);
From ld documentation
In some cases, it is desirable for a linker script to define a symbol only if it is referenced and is not defined by any object included in the link.
…
If, on the other hand, the program defines … the linker will silently use the definition in the program.

GHCi linking with cross-calling dynlibs fails on OSX

Setting
Compiler: GHC 7.10.3
I must use two dynamic libraries (libpetsc and libslepc), one of which uses functions from the other. When linking my application, I encounter the following error, which mentions one such symbol (KSPConvergedReasons). NB. my own code does not use this symbol.
user specified .o/.so/.DLL could not be loaded
(dlopen($SLEPC_DIR/arch-darwin-c-debug/lib/libslepc.dylib, 5): Symbol
not found: _KSPConvergedReasons
Referenced from: $SLEPC_DIR/arch-darwin-c-debug/lib/libslepc.dylib
Expected in: flat namespace
in $SLEPC_DIR/arch-darwin-c-debug/lib/libslepc.dylib)
Surely enough, nm -u shows _KSPConvergedReasons as an undefined
symbol (see below).
I don't understand the reason of this behaviour since I first compile
with all the relevant PETSc and SLEPc headers and link against both
.dylibs.
NB:
The symbol in question (KSPConvergedReasons) does exist in the callee library (libpetsc):
$ nm ${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc.3.7.2.dylib | grep KSPConv
000000000110a652 T _KSPConvergedDefault
0000000001109703 T _KSPConvergedDefaultCreate
000000000110b934 T _KSPConvergedDefaultDestroy
0000000001109a96 T _KSPConvergedDefaultSetUIRNorm
000000000110a074 T _KSPConvergedDefaultSetUMIRNorm
000000000106533d T _KSPConvergedLSQR
0000000001743280 D _KSPConvergedReasons
...
Build + link sequence
Build the C code generated from my own library, which in turn uses headers from the two aforementioned libs:
gcc -c -g -w ${SRCDIR}/Internal/InlineC.c -o ${LIBDIR}/InlineC_c.o -I${PETSC_DIR_ARCH}/include -I${PETSC_DIR}/include -I${SLEPC_DIR_ARCH}/include -I${SLEPC_DIR}/include
Link :
stack exec ghci ${SRCDIR}/Spec.hs ${SRCDIR}/Internal/InlineC.hs ${LIBDIR}/InlineC_c.o -- -isrc/ -L${PETSC_DIR_ARCH}/lib -L${SLEPC_DIR_ARCH}/lib -lpetsc -lmpich -lslepc
Question
Why is this happening and how can I fix this?
Thank you in advance for any pointers,
Marco
Undefined symbols in calling dynlib :
$ nm -u libslepc.3.7.1.dylib | grep KSP
_KSPAppendOptionsPrefix
_KSPConvergedReasons
...

The -l option in GCC

I have just begun reading the book Advanced Programming in Unix Environment and try to compile the first example code, just the same as in this question.
Although the problem for the compilation is solved using the command,
gcc -o myls myls.c -I SCADDRESS/include/ -L SCADDRESS/lib/ -lapue
I looked it up in the GCC manual, but what does the GCC option -lxxx mean? Where xxx stands for the base name of a header file (in this case, it's apue.h). According to the manual, xxx should be some library files, either end with .so for shared object files, or with .a for static libraries.
This is documented in §2.13 "Options for Linking" in the GCC manual:
-llibrary
Search the library named library when linking.
It makes a difference where in the command you write this option; the
linker searches processes libraries and object files in the order they
are specified. Thus, `foo.o -lz bar.o' searches library `z'
after file `foo.o' but before `bar.o'. If `bar.o' refers
to functions in `z', those functions may not be loaded.
The linker searches a standard list of directories for the library,
which is actually a file named `liblibrary.a'. The linker then uses this file as if it had been specified precisely by name.
The directories searched include several standard system directories
plus any that you specify with `-L'.
Normally the files found this way are library files--archive files
whose members are object files. The linker handles an archive file by
scanning through it for members which define symbols that have so far
been referenced but not defined. But if the file that is found is an
ordinary object file, it is linked in the usual fashion. The only
difference between using an `-l' option and specifying a file name is that `-l' surrounds library with `lib' and `.a'
and searches several directories.
The -l option tells GCC to link in the specified library. In this case, the library is apue, and that it happens to line up with the name of a header file is just how the apue coders designed their project.
In reality, the -l option has nothing to do with header files. Like cas says in the comments, read the man page; it'll give you much more information.

Loading LKM get undefined symbol error

when i try to load my Linux kernel module i get an error about an undefined symbol (obviously i get a warning during make). In particular i need to use the macro pgd_offset_k in my module (defined in asm/pgtable.h). This is expanded in pgd_offset(&init_mm, (address)). The undefined symbol is init_mm. I have also verified its presence in /proc/kallsyms:
$ cat /proc/kallsyms |grep -w init_mm
c07d49a0 D init_mm
Any ideas?
init_mm is not exported past 2.6.29, on the basis that no out-of-tree code should be using it. Can you not do without pgd_offset_k?

Resources