When I compile with -fsanitize=address, GCC/Clang implicitly make use of an ASAN dynamic library which provides runtime support for ASAN. If your built library is dynamically loaded by another application, it is necessary to set LD_PRELOAD to include this dynamic library, so that it gets run at application start up time.
It is often not obvious which copy of libasan.so GCC/Clang expects to use, because there may be multiple copies of ASAN on your system (if you have multiple compilers installed.) Is there a reliable way to determine the location of the shared library you need to load?
You can use -print-file-name flag:
GCC_ASAN_PRELOAD=$(gcc -print-file-name=libasan.so)
CLANG_ASAN_PRELOAD=$(clang -print-file-name=libclang_rt.asan-x86_64.so)
You could also extract libasan path from the library itself via ldd:
$ echo 'void foo() {}' | gcc -x c -fPIC -shared -fsanitize=address -
$ ldd a.out | grep libasan.so | awk '{print $3}'
/usr/lib/x86_64-linux-gnu/libasan.so.4
Related
I'm experimenting a bit with building DLLs on windows using MINGW.
A very good summary (in my opinion) can be found at:
https://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/
There is even a basic project which can be used for the purpose of this discussion:
https://github.com/TransmissionZero/MinGW-DLL-Example/releases/tag/rel%2Fv1.1
Note there is a cosmetic mistake in this project which will make it fail out of the box: the Makefile does not create an "obj" directory - Either adjust the Makefile or create it manually.
So here is the real question.
How to change the Windows DLL name so it differs from the actual DLL file name ??
Essentially I'm trying to achieve on Windows, the effect which is very well described here on Linux:
https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html
Initially I tried changing "InternalName" and ""OriginalFilename" in the resource file used to create the DLL but that does not work.
In a second step, I tried adding "-Wl,-soname,SoName.dll" on the command that performs the final link, to change the Windows DLL name.
However, that does not seem to have the expected effect (I'm using MingW 7.3.0, x86_64-posix-seh-rev0).
Two things makes me say that:
1/ The test executable still works (I would expect it to fail, because it tries to locate SoName.dll but can't find it).
2/ "pexports.exe AddLib.dll" produces the output below, where the library name hasn't changed:
LIBRARY "AddLib.dll"
EXPORTS
Add
bar DATA
foo DATA
Am I doing anything wrong ? Are my expectations wrong perhaps ?
Thanks for your help !
David
First of all, I would like to say it's important to use either a .def file for specifying the exported symbols or use __declspec(dllexport) / __declspec(dllimport), but never mix these two methods. There is also another method using the -Wl,--export-all-symbols linker flag, but I think that's ugly and should only be used when quick and dirty is what you want.
It is possible to tell MinGW to use a DLL filename that does not match the library name. In the link step use -o to specify the DLL and use -Wl,--out-implib, to specify the library file.
Let me illustrate by showing how to build chebyshev as a both static and shared library. Its sources consist of only only 2 files: chebyshev.h and chebyshev.c.
Compile
gcc -c -o chebyshev.o chebyshev.c -I. -O3
Create static library
ar cr libchebyshev.a chebyshev.o
Create a .def file (as it wasn't supplied and __declspec(dllexport) / __declspec(dllimport) wasn't used either). Note that this file doesn't contain a line with LIBRARY allowing the linker to specify the DLL filename later.
There are several ways to do this if the .def file wasn't supplied by the project:
3.1. Get the symbols from the .h file(s). This may be hard as sometimes you need to distinguish for example between type definitions (like typedef, enum, struct) and actual functions and variables that need to be exported;
echo "EXPORTS" > chebyshev.def
sed -n -e "s/^.* \**\(chebyshev_.*\) *(.*$/\1/p" chebyshev.h >> chebyshev.def
3.2. Use nm to list symbols in the library file and filter out the type of symbols you need.
echo "EXPORTS" > chebyshev.def
nm -f posix --defined-only -p libchebyshev.a | sed -n -e "s/^_*\([^ ]*\) T .*$/\1/p" >> chebyshev.def
Link the static library into the shared library.
gcc -shared -s -mwindows -def chebyshev.def -o chebyshev-0.dll -Wl,--out-implib,libchebyshev.dll.a libchebyshev.a
If you have a project that uses __declspec(dllexport) / __declspec(dllimport) things are a lot easier. And you can even have the link step generate a .def file using the -Wl,--output-def, linker flag like this:
gcc -shared -s -mwindows -o myproject.dll -Wl,--out-implib,myproject.dll.a -Wl,--output-def,myproject.def myproject.o
This answer is based on my experiences with C. For C++ you really should use __declspec(dllexport) / __declspec(dllimport).
I believe I have found one mechanism to achieve on Windows, the effect described for Linux in https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html
This involves dll_tool
In the example Makefile there was originally this line:
gcc -o AddLib.dll obj/add.o obj/resource.o -shared -s -Wl,--subsystem,windows,--out-implib,libaddlib.a
I simply replaced it with the 2 lines below instead:
dlltool -e obj/exports.o --dllname soname.dll -l libAddLib.a obj/resource.o obj/add.o
gcc -o AddLib.dll obj/resource.o obj/add.o obj/exports.o -shared -s -Wl,--subsystem,windows
Really, the key seems to be the creation with dlltool of an exports file in conjunction with dllname. This exports file is linked with the object files that make up the body of the DLL and it handles the interface between the DLL and the outside world. Note that dlltool also creates the "import library" at the same time
Now I get the expected effect, and I can see that the "Internal DLL name" (not sure what the correct terminology is) has changed:
First evidence:
>> dlltool.exe -I libAddLib.a
soname.dll
Second evidence:
>> pexports.exe AddLib.dll
LIBRARY "soname.dll"
EXPORTS
Add
bar DATA
foo DATA
Third evidence:
>> AddTest.exe
Error: the code execution cannot proceed because soname.dll was not found.
Although the desired effect is achieved, this still seems to be some sort of workaround. My understanding (but I could well be wrong) is that the gcc option "-Wl,-soname" should achieve exactly the same thing. At least it does on Linux, but is this broken on Windows perhaps ??
I build my own static library with gcc and ar like this.
g++ \
... list of library sources ... \
... a lot of -L -l -I -D options etc... \
-c \
&& ar crf ./lib/libpackager.a *.o
Then I use this library in my app. Currently I built it like this.
g++ \
myApp.cpp \
... same -L -l -I options as in library ... \
-L. -lpackager \
-o myApp
It works, but I am little odd for me that I need to duplicate all -l and -L during building the app. Is it possible include all this library dependencies inside the library. My goal to build app like this.
g++ myApp.cpp -L. -lpackager -o myApp
Transferring comments into an answer.
Specifying the -l and -L operations when compiling to object files is irrelevant. Some versions of GCC warn about arguments that won't be used because they are link-time arguments, and linking won't be used when you include the -c flag.
The ar command doesn't know what to do with the C compiler's -l and -L arguments (it might have its own uses for the flags; one version of ar accepts but ignores -l).
So, you have to specify the dependencies when you link with the static library. That is the way life has been since the early 70s — that aspect hasn't changed yet.
Shared libraries can be built with the dependency information, but not static libraries.
As I understand it, I need to build a shared library and link it in a static way, right?
No. You either need to build and link a shared library as a shared library, or you need to accept that using a static library means you will need to specify other libraries on the command line when you use this library. There are systems to help manage such information; pkg-config is one such. AFAIK, you cannot link a shared library in a 'static way'.
In my project I have makefiles which build Solaris kernel modules, and they use gcc to compile files but use ld to link all .o files together into a kernel module. I am trying to include some coverage options like gcov (-fprofile-arcs) or tcov (-xprofile=tcov) in my build, hence I want to replace ld with gcc during linking also.
But as soon as I use replace gcc with ld, the builds start failing with lot of "undefined symbol" errors, even if I use some compile flags and get rid of these errors, the kernel module will not load into my Solaris kernel at all.
For example:
$ /usr/ccs/bin/ld -r -dy -Nstrmod/rpcmod -Nfs/nfs \
-Nmisc/rpcsec -Nmisc/klmmod -Nfs/zfs \
-o debug64/nfssrv \
debug64/nfs_server.o debug64/nfs_srv.o debug64/nfs3_srv.o \
debug64/nfs_acl_srv.o debug64/nfs_auth.o obj64/nfs41_srv.o \
obj64/ctl_ds_srv.o obj64/dserv_server.o
ld works fine but with gcc I get following errors:
/opt/gcc-4.4.4/bin/gcc -m64 -z muldefs \
-Lmod/rpcmod -Lfs/nfs -Lmisc/rpcsec \
-Lmisc/klmmod -Lfs/zfs \
-o obj64/nfssrv \
obj64/nfs_server.o obj64/nfs_srv.o obj64/nfs3_srv.o
obj64/nfs_acl_srv.o obj64/nfs_auth.o obj64/nfs41_srv.o
obj64/ctl_ds_srv.o obj64/dserv_server.o
Undefined first referenced
symbol in file
hz obj64/nfs_server.o
p0 obj64/nfs_server.o
nfs_range_set obj64/nfs41_srv.o
getf obj64/nfs_server.o
log2 obj64/nfs4_state.o
main /usr/lib/amd64/crt1.o
stoi obj64/ctl_ds_srv.o
dmu_object_alloc obj64/dserv_server.o
nvpair_name obj64/nfs4_srv.o
__dtrace_probe_nfss41__i__destroy_encap_session obj64/nfs41_srv.o
__dtrace_probe_nfssrv__i__dscp_freeing_device_entries obj64/ctl_ds_srv.o
mod_install obj64/nfs_server.o
xdr_faststatfs obj64/nfs_server.o
xdr_WRITE3res obj64/nfs_server.o
svc_pool_control obj64/nfs_server.o
Warning the option -L allows to specify a path where to search for libraries, to specify a library you want to link with you (also) have to use the option -l
So a priori you have to add the options -lrpcmod -lnfs -lrpcsec -lklmmod -lzfs
More details in GCC Linking Options
By default, the GNU linker called through the gcc compiler driver will try to create a standard executable. Consequently, if you don't tell it otherwise, ld will use its default linker script, the C startup code and it will look for a main() routine and everything else that makes a valid executable.
I'm not too familiar with Solaris, but would bet this will not be suitable to build kernel modules. I would expect kernel modules will at least require some options like -ffreestanding, -nostdlibs and most likely a non-default linker script that's probably very different from the default one used for applications.
Even if you manage to link your kernel modules this way, I seriously doubt you will be finished. The gcov instrumentation routines most likely do not expect to live within a kernel driver but expect a proper C execution environment (e.g. it will at least expect to fopen() a file to fwrite() its findings). A kernel driver, however, does not have this comfort. You'll probably find yourself confronted with the problem to get the gcov data somehow out of your kernel modules.
Not saying this is not doable, but it certainly will be a lot of work.
I would like to create a symbol definition table to be used in a separate application during linking. ARM's armlink linker has the following flag but I'm using arm-eabi:
--symdefs=filename
The GNU objcopy utility has an option --extract-symbol that may do what you want. It generates an object file with only symbol data - no actual code or data.
It is specifically intended to generate a .sym file for use in the VxWorks RTOS which has a command shell and dynamic linker/loader that uses this information. It is also used by the VxWorks host shell and source-level debugger.
The binutils nm utility on the other hand generates output very similar to armlink's --symdefs which you might easily post-process into exactly the form you need.
-Wl,-Map -Wl,mapfile -Wl,--cref
added to the final gcc (link) command line should do the trick.
This the correct answer from arm gnu launchpad:
Do you intend to load the symdef file with the GNU toolchain or with armcc one? If the former I think using nm on the object file and then linking with -R <filename> would work. So you would do arm-none-eabi-nm -D ./prog > ./prog.defsym after linking prog and then arm-none-eabi-gcc -Wl,-R,./prog.defsym when you want to use this.
I've got a binary "CeeloPartyServer" that needs to find libFoundation.so at runtime, on a FreeBSD machine. They're both in the same directory. I compile (on another platform, using a cross compiler) CeeloPartyServer using linker flag -rpath=$ORIGIN.
> readelf -d CeeloPartyServer |grep -i rpath
0x0000000f (RPATH) Library rpath: [$ORIGIN]
> ls
CeeloPartyServer Contents Foundation.framework libFoundation.so
> ./CeeloPartyServer
/libexec/ld-elf.so.1: Shared object "libFoundation.so" not found, required by "CeeloPartyServer"
Why isn't it finding the library when I try to run it?
My exact linker line is: -lm -lmysql -rpath=$ORIGIN.
I am pretty sure I don't have to escape $ or anything like that since my readelf analysis does in fact show that library rpath is set to $ORIGIN. What am I missing?
I'm assuming you are using gcc and binutils.
If you do
readelf -d CeeloPartyServer | grep ORIGIN
You should get back the RPATH line you found above, but you should also see some entries about flags. The following is from a library that I built.
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../lib]
0x000000000000001e (FLAGS) ORIGIN
0x000000006ffffffb (FLAGS_1) Flags: ORIGIN
If you aren't seeing some sort of FLAGS entries, you probably haven't told the linker to mark the object as requiring origin processing. With binutils ld, you do this by passing the -z origin flag.
I'm guessing you are using gcc to drive the link though, so in that case you will need to pass flag through the compiler by adding -Wl,-z,origin to your gcc link line.
Depending on how many layers this flag passes through before the linker sees it, you may need to use $$ORIGIN or even \$$ORIGIN. You will know that you have it right when readelf shows an RPATH header that looks like $ORIGIN/../lib or similar. The extra $ and the backslash are just to prevent the $ from being processed by other tools in the chain.
\$\ORIGIN if you are using chrpath and \$\$ORIGIN if you are providing directly in LDFLAGS
using ldd CeeloPartyServer to check the dependency .so is starting with ./ or not. (e.g. libFoundation.so and ./libFoundation.so)
For common situation it should be libFoundation.so and without the prefix ./
if ./ prefix is necessary for some uncommon case, make sure the CWD is the same folder with libFoundation.so, and the $ORIGIN would be invalid.
=======
For example:
g++ --shared -Wl,--rpath="\$ORIGIN" ./libFoundation.so -o lib2.so
would got a library lib2.so with ./libFoundation.so
g++ --shared -Wl,--rpath="\$ORIGIN" libFoundation.so -o lib2.so
would got libFoundation.so instead.