OCaml dynamic linking and -nodynlink compilation flag - ocaml

According to the OCaml User's Manual chapter on ocamlopt:
-nodynlink Allow the compiler to use some optimizations that are valid only for code that is never dynlinked.
...
-shared [...] Under some systems (currently, only Linux AMD 64), all the OCaml code linked in a plugin must have been compiled without the -nodynlink flag. [...]
To me, this implies that:
The restriction "do not use the -nodynlink compilation flag" only applies to the plugin.
Non-plugin parts (the application being extended) may be compiled using -nodynlink.
So my actual question is two-fold:
Is my above interpretation correct?
When I violated above restrictions on purpose, the compiler/loader/etc did not give me a warning message. What kind of errors / bad behavior would I have to expect as a result of my wrongdoing?
Thank you in advance!

The first point is correct. However many modern operating systems use PIE executables by default, which is incompatible with the -nodynlink option.
Concerning your second point, specifying the -shared in second position will erase the -nodynlink flag, which may explain why you did not get any error. Otherwise, for non-empty plugins, the linker should generate a relocation error. Typically trying to compile
let printer () = Format.printf "I am a plugin#."
let () = Lib.register := printer :: !Lib.register
with
# ocamlopt -shared -nodynlink plugin.ml -o plugin.cmxs
gives me
/usr/bin/ld: plugin.o: warning: relocation against `camlPlugin__Pfield_51' in >read-only section `.text'
/usr/bin/ld: plugin.o: relocation R_X86_64_PC32 against symbol >`camlPlugin__const_block_11' can not be used when making a shared object; >recompile with -fPIC
/usr/bin/ld: final link failed: bad value

Related

g++ failing to link statically when compiling to binary format: "skipping incompatible libm.a when searching for -lm"

While attempting to write a kernel in C++, I've run into a peculiar issue.
When prompting g++ to compile even a very basic C++ file statically and to binary, it simply keeps skipping over the static math library (libm.a), ultimately failing to compile.
Attempting to compile a simple C++ file:
test.cpp
int main() {
return 0;
}
using this g++ command:
g++ -static test.cpp -Wl,--oformat=binary
I receive the following error output:
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/libm.a when searching for -lm
/usr/bin/ld: skipping incompatible /lib/x86_64-linux-gnu/libm.a when searching for -lm
/usr/bin/ld: skipping incompatible /usr/lib/x86_64-linux-gnu/libm.a when searching for -lm
/usr/bin/ld: skipping incompatible /lib/x86_64-linux-gnu/libm.a when searching for -lm
/usr/bin/ld: skipping incompatible /usr/lib/x86_64-linux-gnu/libm.a when searching for -lm
/usr/bin/ld: cannot find -lm: No such file or directory
I am running Linux Mint Cinnamon V. 21 (Vanessa) on a VirtualBox VM.
In my attempt to narrow down the issue, I have also attempted to exclude the -static flag:
g++ test.cpp -Wl,--oformat=binary
Which results in a different error entirely:
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/11/libstdc++.so: error adding symbols: file in wrong format
collect2: error: ld returned 1 exit status
After thorough research, I was made aware that this could be caused by an incompatibility between 32-bit libraries and 64-bit files. Everything is supposed to be in 64 bit.
I did attempt to determine bitness of libm.a using file.
When using the file command on /usr/lib/x86_64-linux-gnu/libm.a, I receive the following output:
libm.a: ASCII text
indicating neither bitness. This led me to conclude that perhaps the library is damaged and needs updating. After running sudo apt-get install libc6-dev, the issue persists, however.
I'm not sure what to do at this point.
Update:
I've opened libm.a in a text editor and the entire contents of the file are:
/* GNU ld script
*/
OUTPUT_FORMAT(elf64-x86-64)
GROUP ( /usr/lib/x86_64-linux-gnu/libm-2.35.a /usr/lib/x86_64-linux-gnu/libmvec.a )
Update 2: apparently this is a linker script. Both referenced files libm-2.35.a and libmvec.a are present in my directory and are, according to objdump, 64-bit-versions.
Based on the compiler's error output, it seems that in my case, for whatever reason, g++ (or more specifically, ld) fails to use this linker script. What could possibly cause this?
I have come to the conclusion that it is not normally possible to statically link C++ code involving object oriented features into a fully functional binary file, as libm.a can apparently be linked to ELF only.
besides: even the static version of glibc, which is also required, references other dynamic libraries, making it useless for kernel code.
there might be some sort of workaround, but it seems that g++ does not support this functionality by default.

Why do I need -fPIC for compiling with --unresolved-symbols=ignore-in-object-files?

I have the following 2 files:
main.cpp:
#include <iostream>
int f();
int main(){
std::cout<<f();
}
functions.cpp:
int f(){
return 42;
}
I compile functions.cpp into libfunctions.so using this command:
g++ -fPIC -shared functions.cpp -o libfunctions.so
I compile main.cpp into a.out using this command:
g++ main.cpp -Wl,--unresolved-symbols=ignore-in-object-files
When I run a.out using this command:
LD_PRELOAD=./libfunctions.so ./a.out
I get a segmentation fault.
But if I compile main.cpp into a.out using this command:
g++ -fPIC main.cpp -Wl,--unresolved-symbols=ignore-in-object-files
Then it works.
I understand why shared libraries have to be compiled with -fPIC, since one cannot know the address at which where they will be loaded at load time. However I do not understand why main.cpp must also be compiled as PIC. I thought that since the load address for a.out is known at link time, then surely there is no need to compile with -fPIC.
What am I missing?
I assume you are using the GNU toolchain. binutils ld sometimes produces corrupt binaries for invalid input, unfortunately, rather than failing with an error message.
In your case, I get:
./a.out: error while loading shared libraries: unexpected PLT reloc type 0x00
This error message is correct:
Relocation section '.rela.plt' at offset 0x628 contains 4 entries:
Offset Info Type Sym. Value Sym. Name + Addend
…
000000000000 000000000000 R_X86_64_NONE 0
R_X86_64_NONE has the value zero, and it is sometimes used by ld instead of a real relocation if an error is encountered.
Whether this is an ld bug, is debatable. ld produced the binary you asked for, ignoring the error. It did produce an invalid relocation. When compiling with -fno-plt, I get no relocation at all, but the program still crashes because the resolved symbol appears to have offset 0 relative to the executable or text section.
I suspect that with -fPIC, it happens to work for you because ld produces a dynamic relocation for the unknown symbol. (I cannot get binutils 2.30 to produce this relocation, though.)
In general, it is impossible to generate a correct dynamic relocation to an undefined symbol. Without the definition, on many architectures, it is impossible to tell whether the target is a function or object. Undefined references to objects need accurate size information if copy relocations are used. Both function and object references need a symbol definition to obtain the correct symbol version (if any). There are many reasons why underlinking is extremely problematic.
It may be worth reporting this as a binutils linker bug, but I assume it will be treated as very low priority.

How do I tell GCC not to link with the runtime library and the standard library?

I passed the following commandline arguments to GCC:
gcc -e _main -nostdlib -nodefaultlibs -fno-exceptions -nostartfiles -fno-rtti -g C:\ntdll.cpp
It gave me the following error:
/ cygdrive / c / Users / ---- / AppData / Local / Temp / ccDrwTbB.o: In function `main':
C : \users\nabeel\desktop / ntdll.cpp:5 : undefined reference to `__main'
C : \users\nabeel\desktop / ntdll.cpp:5 : (.text + 0x9) : relocation truncated to fit : R_X86_64_PC32 against undefined symbol `__main'
collect2 : error : ld returned 1 exit status
Any idea why this may be happening?
//ntdll.cpp:
int main()
{
}
GCC version 4.9.3 on Windows (Cygwin)
Why do you use -nostartfiles option? With that option, you need to define your own __start entry which prepares the environment and calls the main function.
Remove the option -nostartfiles and try again.
See https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
As I understand, you need to tell gcc not to link with runtime library -nostdlib and standard library -nodefaultlibs
One of the standard libraries bypassed by -nostdlib and -nodefaultlibs is libgcc.a, a library of internal subroutines that GCC uses to overcome shortcomings of particular machines, or special needs for some languages. (See Interfacing to GCC Output, for more discussion of libgcc.a.) In most cases, you need libgcc.a even when you want to avoid other standard libraries. In other words, when you specify -nostdlib or -nodefaultlibs you should usually specify -lgcc as well. This ensures that you have no unresolved references to internal GCC library subroutines. (For example, __main, used to ensure C++ constructors will be called; see collect2.)

undefined reference error in using dlopen in c++

I am trying to cross-compile apache-qpid for an arm system from a debian.
There is undefined reference to __dlopen error, but it seems that it is related to the previous warning:
using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking ...
Here is the detail:
[ 86%] Linking CXX shared library libqpidcommon.so
CMakeFiles/qpidcommon.dir/qpid/sys/posix/Shlib.cpp.o: In function
`qpid::sys::Shlib::load(char const*)':
/home/mert/qpid-cpp-0.34/src/qpid/sys/posix/Shlib.cpp:32: warning: Using
'dlopen' in statically linked applications requires at runtime the shared
libraries from the glibc version used for linking
/home/mert/IDE/cVEND/00.00.14/bin/../arm-feig-linux-
gnueabi/sysroot/usr/lib/libdl.a(dlopen.o): In function `dlopen':
dlopen.c:(.text+0xc): undefined reference to `__dlopen'
I do not know what is happening exactly and how to solve it.
Here there is a similiar thing, I tried to add -static -ldl -lc C_FLAGS but made no difference.
Any help appreciated.
EDIT :
EDIT :
I am not sure exactly what is solved the problem, but I think that -ldl was looking exactly for libdl.so, but in arm directory, it was libdl-2.19.so, thus, probably it was then looking for and finding in another directory. I have linked libdl.so to libdl-2.19.so and now it is compiling.
The linker needs the options, not the compiler. See LDFLAGS.
https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
Extra flags to give to compilers when they are supposed to invoke the
linker, ‘ld’, such as -L. Libraries (-lfoo) should be added to the
LDLIBS variable instead.
If this error occurs during the make step try doing
make LIBS=-ldl
And make sure the library path is present in LDFLAGS
export LDFLAGS=-L<path/to/ldl>

Compiling program using gfortran and the HDF-EOS2 library

I have the problem of linking the HDF-EOS library to a Fortran90 program. I have compiled the library from source to a directory specified in $prefix. My simple compile command is:
gfortran -I$prefix/include -L$prefix/lib -Wl,-rpath -Wl,$prefix/lib -lhdfeos -lGctp -lmfhdf -ldf -lz -lsz -ljpeg tst.f90
When compiling, I get the following error:
undefined reference to `gdopen_'
In the program, which I am not supposed to change, the HDF-EOS library is used via the external keyword, e.g.
integer(kind=4), external :: gdopen
In the library, nm $prefix/lib/libhdfeos.a | grep gdopen gives me:
00000000000120c0 T gdopen
When compiling with -fno-underscoring, I get just a different error:
gfortran -fno-underscoring -I$prefix/include -L$prefix/lib -Wl,-rpath -Wl,$prefix/lib -lhdfeos -lGctp -lmfhdf -ldf -lz -lsz -ljpeg tst.f90
the error is then:
undefined reference to `gdopen'
Also, gfortran finds the libraries, otherwise it would complain. Is the error related to the underscore? What else can I try? I work on Fedora and gfortran version 4.7.2.
Yes, very likely to be caused by the underscore.
Try compiling with -fno-underscoring (https://gcc.gnu.org/onlinedocs/gfortran/Code-Gen-Options.html), but fixing it by a proper bind(C) interface would be better.
This tutorial (Did you read it before going here? Very easy to find even for a complete novice in the library, like me.) also states you should use -fno-underscoring.
Continue by implementing the rest what the tutorial recommends, including compiling with FC=$(HDF4_DIR)/bin/h4fc.