nm symbol output t vs T in a shared so library - gcc

I have added a new function (fuse_lowlevel_notify_inval_directory) in user space fuse library.
The compilation and creation of libfuse.so is finished without error.
But when my application tries to use this new function, the linker is throwing error: undefined reference to `fuse_lowlevel_notify_inval_directory'
collect2: ld returned 1 exit status
When I checked with nm
nm ../libfuse.so | grep inval
00000000000154ed T fuse_invalidate
**000000000001e142 t fuse_lowlevel_notify_inval_directory**
000000000001e26c T fuse_lowlevel_notify_inval_entry
000000000001e1cb T fuse_lowlevel_notify_inval_inode
T/t means the symbol is present in text section. if uppercase, the symbol is global (external). I suspect this is the issue. The new added function is showing lowercase t while other older functions are having upper case T. Any idea about what I might be doing wrong?

Any idea about what I might be doing wrong?
The t function is indeed local to the library. This could happen due to a number or reasons. The most likely ones are:
You declared the function static, or
You compiled the library with -fvisibility=hidden and did not have __attribute__((visibility("default"))) on the function, or
You linked this library with a linker version script (i.e. with --version-script=libfoo.version flag) that hides all functions, except those which are explicitly exported, and you didn't add your function to that list.
See this example of using --version-script to limit symbol visibility.

Related

Undefined reference when trying to link libxc to fortran [duplicate]

I am trying to build a Fortran program, but I get errors about an undefined reference or an unresolved external symbol. I've seen another question about these errors, but the answers there are mostly specific to C++.
What are common causes of these errors when writing in Fortran, and how do I fix/prevent them?
This is a canonical question for a whole class of errors when building Fortran programs. If you've been referred here or had your question closed as a duplicate of this one, you may need to read one or more of several answers. Start with this answer which acts as a table of contents for solutions provided.
A link-time error like these messages can be for many of the same reasons as for more general uses of the linker, rather than just having compiled a Fortran program. Some of these are covered in the linked question about C++ linking and in another answer here: failing to specify the library, or providing them in the wrong order.
However, there are common mistakes in writing a Fortran program that can lead to link errors.
Unsupported intrinsics
If a subroutine reference is intended to refer to an intrinsic subroutine then this can lead to a link-time error if that subroutine intrinsic isn't offered by the compiler: it is taken to be an external subroutine.
implicit none
call unsupported_intrinsic
end
With unsupported_intrinsic not provided by the compiler we may see a linking error message like
undefined reference to `unsupported_intrinsic_'
If we are using a non-standard, or not commonly implemented, intrinsic we can help our compiler report this in a couple of ways:
implicit none
intrinsic :: my_intrinsic
call my_intrinsic
end program
If my_intrinsic isn't a supported intrinsic, then the compiler will complain with a helpful message:
Error: ‘my_intrinsic’ declared INTRINSIC at (1) does not exist
We don't have this problem with intrinsic functions because we are using implicit none:
implicit none
print *, my_intrinsic()
end
Error: Function ‘my_intrinsic’ at (1) has no IMPLICIT type
With some compilers we can use the Fortran 2018 implicit statement to do the same for subroutines
implicit none (external)
call my_intrinsic
end
Error: Procedure ‘my_intrinsic’ called at (1) is not explicitly declared
Note that it may be necessary to specify a compiler option when compiling to request the compiler support non-standard intrinsics (such as gfortran's -fdec-math). Equally, if you are requesting conformance to a particular language revision but using an intrinsic introduced in a later revision it may be necessary to change the conformance request. For example, compiling
intrinsic move_alloc
end
with gfortran and -std=f95:
intrinsic move_alloc
1
Error: The intrinsic ‘move_alloc’ declared INTRINSIC at (1) is not available in the current standard settings but new in Fortran 2003. Use an appropriate ‘-std=*’ option or enable ‘-fall-intrinsics’ in order to use it.
External procedure instead of module procedure
Just as we can try to use a module procedure in a program, but forget to give the object defining it to the linker, we can accidentally tell the compiler to use an external procedure (with a different link symbol name) instead of the module procedure:
module mod
implicit none
contains
integer function sub()
sub = 1
end function
end module
use mod, only :
implicit none
integer :: sub
print *, sub()
end
Or we could forget to use the module at all. Equally, we often see this when mistakenly referring to external procedures instead of sibling module procedures.
Using implicit none (external) can help us when we forget to use a module but this won't capture the case here where we explicitly declare the function to be an external one. We have to be careful, but if we see a link error like
undefined reference to `sub_'
then we should think we've referred to an external procedure sub instead of a module procedure: there's the absence of any name mangling for "module namespaces". That's a strong hint where we should be looking.
Mis-specified binding label
If we are interoperating with C then we can specify the link names of symbols incorrectly quite easily. It's so easy when not using the standard interoperability facility that I won't bother pointing this out. If you see link errors relating to what should be C functions, check carefully.
If using the standard facility there are still ways to trip up. Case sensitivity is one way: link symbol names are case sensitive, but your Fortran compiler has to be told the case if it's not all lower:
interface
function F() bind(c)
use, intrinsic :: iso_c_binding, only : c_int
integer(c_int) :: f
end function f
end interface
print *, F()
end
tells the Fortran compiler to ask the linker about a symbol f, even though we've called it F here. If the symbol really is called F, we need to say that explicitly:
interface
function F() bind(c, name='F')
use, intrinsic :: iso_c_binding, only : c_int
integer(c_int) :: f
end function f
end interface
print *, F()
end
If you see link errors which differ by case, check your binding labels.
The same holds for data objects with binding labels, and also make sure that any data object with linkage association has matching name in any C definition and link object.
Equally, forgetting to specify C interoperability with bind(c) means the linker may look for a mangled name with a trailing underscore or two (depending on compiler and its options). If you're trying to link against a C function cfunc but the linker complains about cfunc_, check you've said bind(c).
Not providing a main program
A compiler will often assume, unless told otherwise, that it's compiling a main program in order to generate (with the linker) an executable. If we aren't compiling a main program that's not what we want. That is, if we're compiling a module or external subprogram, for later use:
module mod
implicit none
contains
integer function f()
f = 1
end function f
end module
subroutine s()
end subroutine s
we may get a message like
undefined reference to `main'
This means that we need to tell the compiler that we aren't providing a Fortran main program. This will often be with the -c flag, but there will be a different option if trying to build a library object. The compiler documentation will give the appropriate options in this case.
There are many possible ways you can see an error like this. You may see it when trying to build your program (link error) or when running it (load error). Unfortunately, there's rarely a simple way to see which cause of your error you have.
This answer provides a summary of and links to the other answers to help you navigate. You may need to read all answers to solve your problem.
The most common cause of getting a link error like this is that you haven't correctly specified external dependencies or do not put all parts of your code together correctly.
When trying to run your program you may have a missing or incompatible runtime library.
If building fails and you have specified external dependencies, you may have a programming error which means that the compiler is looking for the wrong thing.
Not linking the library (properly)
The most common reason for the undefined reference/unresolved external symbol error is the failure to link the library that provides the symbol (most often a function or subroutine).
For example, when a subroutine from the BLAS library, like DGEMM is used, the library that provides this subroutine must be used in the linking step.
In the most simple use cases, the linking is combined with compilation:
gfortran my_source.f90 -lblas
The -lblas tells the linker (here invoked by the compiler) to link the libblas library. It can be a dynamic library (.so, .dll) or a static library (.a, .lib).
In many cases, it will be necessary to provide the library object defining the subroutine after the object requesting it. So, the linking above may succeed where switching the command line options (gfortran -lblas my_source.f90) may fail.
Note that the name of the library can be different as there are multiple implementations of BLAS (MKL, OpenBLAS, GotoBLAS,...).
But it will always be shortened from lib... to l... as in liopenblas.so and -lopenblas.
If the library is in a location where the linker does not see it, you can use the -L flag to explicitly add the directory for the linker to consider, e.g.:
gfortran -L/usr/local/lib -lopenblas
You can also try to add the path into some environment variable the linker searches, such as LIBRARY_PATH, e.g.:
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/lib
When linking and compilation are separated, the library is linked in the linking step:
gfortran -c my_source.f90 -o my_source.o
gfortran my_source.o -lblas
Not providing the module object file when linking
We have a module in a separate file module.f90 and the main program program.f90.
If we do
gfortran -c module.f90
gfortran program.f90 -o program
we receive an undefined reference error for the procedures contained in the module.
If we want to keep separate compilation steps, we need to link the compiled module object file
gfortran -c module.f90
gfortran module.o program.f90 -o program
or, when separating the linking step completely
gfortran -c module.f90
gfortran -c program.f90
gfortran module.o program.o -o program
Problems with the compiler's own libraries
Most Fortran compilers need to link your code against their own libraries. This should happen automatically without you needing to intervene, but this can fail for a number of reasons.
If you are compiling with gfortran, this problem will manifest as undefined references to symbols in libgfortran, which are all named _gfortran_.... These error messages will look like
undefined reference to '_gfortran_...'
The solution to this problem depends on its cause:
The compiler library is not installed
The compiler library should have been installed automatically when you installed the compiler. If the compiler did not install correctly, this may not have happened.
This can be solved by correctly installing the library, by correctly installing the compiler. It may be worth uninstalling the incorrectly installed compiler to avoid conflicts.
N.B. proceed with caution when uninstalling a compiler: if you uninstall the system compiler it may uninstall other necessary programs, and may render other programs unusable.
The compiler cannot find the compiler library
If the compiler library is installed in a non-standard location, the compiler may be unable to find it. You can tell the compiler where the library is using LD_LIBRARY_PATH, e.g. as
export LD_LIBRARY_PATH="/path/to/library:$LD_LIBRARY_PATH"
If you can't find the compiler library yourself, you may need to install a new copy.
The compiler and the compiler library are incompatible
If you have multiple versions of the compiler installed, you probably also have multiple versions of the compiler library installed. These may not be compatible, and the compiler might find the wrong library version.
This can be solved by pointing the compiler to the correct library version, e.g. by using LD_LIBRARY_PATH as above.
The Fortran compiler is not used for linking
If you are linking invoking the linker directly, or indirectly through a C (or other) compiler, then you may need to tell this compiler/linker to include the Fortran compiler's runtime library. For example, if using GCC's C frontend:
gcc -o program fortran_object.o c_object.o -lgfortran

Calling Internal Functions in a Shared Library

I want to call an unexported function in glibc. Precisely, I want to call ptmalloc_init(). The problem is that the symbol is not exported. I have access to the glibc source code. Therefore, I added a function called ptmalloc_init_caller() in glibc source code and compiled the library. But again I can not see anything in the nm -D output and, as a consequence, can not call the added function from outside. Is there something special about building glibc that is omitted?
You need to make the ptmalloc_init function non-static and add it to malloc/Versions, e.g. under the GLIBC_PRIVATE section. Then it will be exported. Without the change to malloc/Versions, the function will not be mentioned in the generated version script (see libc.map in the build tree), and its symbol will have hidden visibility.

How can I keep a symbol during gcc strip?

Using arm-linux-gnueabi-gcc, I'm working with a shared object that has an undefined reference to "main". I'm using dlopen() to open this library. However, when my program is compiled with "-Wl,-s", the symbol main is removed, which causes dlopen() to fail with an undefined symbol "main".
In gcc, is there any way I can perform a strip, but keep the symbol main?
Edit: even better, can I put just the symbol "main" in the dynamic section (similar to -rdynamic)?
The shared object with an undefined reference to main appears to use the dynamic symbol table to search for the reference to "main". So, there are two options here:
Compile with "-Wl,-rdynamic". This will put all of the symbols into the dynamic symbol table. This works, but it results in a lot of extra symbols being put in there, too.
Compile with "-Wl,--dynamic-list=[path to my list file]". Then list "main" in the dynamic file to retain only main in the dynamic symbols table. This has the drawback that all dynamic references must now be managed, but for simple programs, this is adequate.
Example of (2):
Invocation:
arm-linux-gnueabi-gcc -fPIC mycode.c -Wl,-s,--dynamic-list=./dynamic_symbols.txt
dynamic_symbols.txt:
{ main; };

Undefined symbols: for -fvisibility=hidden

I am having a linker problem that I can't fix (using MacOS and xcode).
First off, when I compile with -fvisibility=hidden all is fine. If I omit that flag, I get
"XYZ::IPlugView::iid", referenced from:
__ZN9XYZ9IPlugView3iidE$non_lazy_ptr in pluginview.o
(maybe you meant: __ZN9XYZ9IPlugView3iidE$non_lazy_ptr)
I don't know if this is related, but before that are a couple warnings like
ld: warning: non-virtual thunk to XYZ...::release()has different visibility (hidden) in xyz/foo.o and (default) in xyz/bar.o
Any Ideas would be greatly appreciated....
Thanks!
The warnings might in fact be related. What these warnings are trying to tell you is that there is a symbol named XYZ...::release() and this symbol is defined twice, once in the file xyz/foo.o (probably compiled from xyz/foo.cc) and one in the file xyz/bar.o (probably compiled from xyz/bar.cc), however, the symbol is not twice defined with the same visibility, one symbol is default (visible outside the current binary/library you are compiling) and one is hidden (only visible within the current binary/library you are compiling). The same symbol cannot have two different visibilities, of course.
By using -fvisibility=hidden you tell the compiler: Whenever there is no code annotation that would otherwise define the visibility of a symbol, make this symbol hidden. This probably solves your problem as the duplicate symbols that used to be once hidden and once default are now twice hidden, because the definition that used to be default was probably implicitly made default and now its implicitly made hidden, which means the symbol is twice hidden and this resolves the conflict, since the two symbols are probably treated like a single one by the linker.
Within your source code, there are two ways to set the visibility of a symbol, either by attribute or by pragma. To make a symbol hidden, you can either append __attribute__ ((visibility ("hidden"))) in front of its definition or you can place a pragma #pragma GCC visibility push(visibility) somewhere in your source file, causing all symbol definitions below it to be set hidden until you either use the pragma #pragma GCC visibility pop to return to the previous visibility state (or back to the default one if there wasn't a previous one), use another pragma to change the visibility to something else or to the end of the file, whatever comes first.
I think in your case the symbol in question is once defined in foo.cc with an explicit visibility (which is hidden) and once in bar.cc with no explicit visibility, so it's either default or hidden, depending on your -fvisibility flag.

OSX 10.5 Leopard Symbol Mangling with $non_lazy_ptr

Why does Leopard mangle some symbols with $non_lazy_ptr? More importantly what is the best method to fix undefined symbol errors because a symbol has been mangled with $non_lazy_ptr?
From: Developer Connection - Indirect Addressing
Indirect addressing is the name of the code generation technique that allows symbols defined in one file to be referenced from another file, without requiring the referencing file to have explicit knowledge of the layout of the file that defines the symbol. Therefore, the defining file can be modified independently of the referencing file. Indirect addressing minimizes the number of locations that must be modified by the dynamic linker, which facilitates code sharing and improves performance.
When a file uses data that is defined in another file, it creates symbol references. A symbol reference identifies the file from which a symbol is imported and the referenced symbol. There are two types of symbol references: nonlazy and lazy.
Nonlazy symbol references are resolved (bound to their definitions) by the dynamic linker when a module is loaded.
A nonlazy symbol reference is essentially a symbol pointer—a pointer-sized piece of data. The compiler generates nonlazy symbol references for data symbols or function addresses.
Lazy symbol references are resolved by the dynamic linker the first time they are used (not at load time). Subsequent calls to the referenced symbol jump directly to the symbol’s definition.
Lazy symbol references are made up of a symbol pointer and a symbol stub, a small amount of code that directly dereferences and jumps through the symbol pointer. The compiler generates lazy symbol references when it encounters a call to a function defined in another file.
In human-speak: the compiler generates stubs with $non_lazy_ptr appended to them to speed up linking. You're probably seeing that function Foo referenced from _Foo$non_lazy_ptr is undefined, or something like that - these are not the same thing. Make sure that the symbol is actually declared and exported in the object files/libraries you're linking your app to. At least that was my problem, I also thought it's a weird linker thing until I found that my problem was elsewhere - there are several other possible causes found on Google.
ranlib -c libwhatever.a
is a solid fix for the issue. I had the same problem when building the PJSIP library for iOS. This library sort-of uses an autoconf based make system, but needs a little tweaking to various files to make everything alright for iOS. In the process of doing that I managed to remove the ranlib line in the rule for libraries and then started getting an error in the link of my project about _PJ_NO_MEMORY_EXCEPTION referenced from _PJ_NO_MEMORY_EXCEPTION$non_lazy_ptr being undefined.
Adding the ranlib line back to the library file solved it. Now my full entry for LIBS in rules.mak is
$(LIB): $(OBJDIRS) $(OBJS) $($(APP)_EXTRA_DEP)
if test ! -d $(LIBDIR); then $(subst ##,$(subst /,$(HOST_PSEP),$(LIBDIR)),$(HOST_MKDIR)); fi
$(LIBTOOL) -o $(LIB) $(OBJS)
$(RANLIB) -c $(LIB)
Hope this helps others as well trying to use general UNIX configured external libraries with iPhone or iOS.
If someone else stumbles the same problem I had:
Had a extern NSString* const someString; in the header file, but forgot to put it the implementation file. as NSString* const someString=#"someString";
This solved it.
ranlib -c on your library file fixes the problem

Resources