What is difference between objcopy and dsymutil? - gcc

Are these two commands on linux:
objcopy --only-keep-debug foo foo.dbg
objcopy --add-gnu-debuglink=foo.dbg foo
equivalent to below on mac
dsymutil <binary> -o <binary>.dSYM
Equivalent in the sense that,
It creates a standalone debug info file.
It create a link between the executable and debug info file.
Then for stripping
is the commands on linux:
objcopy --strip-debug foo
OR
strip -g <binary>
equivalent to below on mac
strip -S <binary>

The --only-keep-debug part of the objcopy does functionally the same thing as dsymutil.
There isn't any tool to record the binary location in the dSYM. Rather the dSYM & the binary share a common UUID, and clients that want to find symbol files use the DebugSymbols framework, which uses various tricks (e.g. a Spotlight importer, search paths, a "dSYM finding external script", etc) to find the separate debug file. So there isn't a need for an equivalent to --add-gnu-debuglink.
The mac version of strip -S does strip debug information the same way that the binutils version does. The difference is that strip -S on OS X won't actually decrease the size of the binary much. On OS X, the debug information is always kept out of the executable - residing either in the .o files or in the dSYM. The executable only has a small "debug map" that tells lldb or dsymutil how to link the dwarf from the .o files. strip -S only has to remove the debug map.

Related

Does "-Wl,-soname" work on MinGW or is there an equivalent?

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 ??

Understanding the gcc abbreviations

I just took a look to the gcc-arm-none-eabi compiler binaries which are listed bellow but I really do not know all the used abbreviations. I would like to know which binary is the preprocessor, the linker, the compiler and so on ...
$ ls /opt/gcc-arm-none-eabi-5_4-2016q3/bin/
arm-none-eabi-addr2line
arm-none-eabi-ar
arm-none-eabi-as
arm-none-eabi-c++
arm-none-eabi-c++filt
arm-none-eabi-cpp
arm-none-eabi-elfedit
arm-none-eabi-g++
arm-none-eabi-gcc
arm-none-eabi-gcc-5.4.1
arm-none-eabi-gcc-ar
arm-none-eabi-gcc-nm
arm-none-eabi-gcc-ranlib
arm-none-eabi-gcov
arm-none-eabi-gcov-tool
arm-none-eabi-gdb
arm-none-eabi-gdb-py
arm-none-eabi-gprof
arm-none-eabi-ld
arm-none-eabi-ld.bfd
arm-none-eabi-nm
arm-none-eabi-objcopy
arm-none-eabi-objdump
arm-none-eabi-ranlib
arm-none-eabi-readelf
arm-none-eabi-size
arm-none-eabi-strings
arm-none-eabi-strip
I just can guess: gcc is the compiler? ld is the linker?
What is the exact purpose of all these binaries?
The leading 'arm-none-eabi' is the type of compiler. This is known as the tuple and is specified as a configure 'prefix'. Many of the binaries may be links or short wrapper scripts that call another binary (gcc). Also some of the names are just in case you have existing system binaries with the same name or multiple gcc installs.
You can find this information by running a man command on the program name. Briefly,
addr2line - convert an address (hex) to a code line number.
ar - a static library (or archive) tool.
as - an assembler
c++ - the C++ front-end
c++filt - convert a mangled name to function with prototypes.
cpp - the preprocessor only.
elfedit - elf header manipulation.
g++ - C++ with gnu extensions.
gcc - standard binary (given options can do the same as wrappers).
gcc-5.4.1 - full name for system with multiple GCC installs.
gcc-ar - rename in case of multiple 'ar'.
gcc-nm - rename in case of multiple 'nm'.
gcc-ranlib - rename in case of multiple 'ranlib'.
gcov - code coverage
gcov-tool - code coverage
gdb - the debugger
gdb-py - more minimal debugger
gprof - call graph/profiler.
ld - the linker (most likely gold).
ld.bfd - an older style linker with a few more features; MUCH slower for large C++ projects.
nm - display 'names' in a binary.
objcopy - manipulate a binary (sections).
objdump - information on a binary.
ranlib - generate a library index.
readelf - information on ELF binaries.
size - program section sizes
strings - dump all strings in a binary.
strip - remove debug information from a binary.
As a concept, the name 'gcc-ar' and 'ar' are physically the same thing. However, another 'ar' may exist in the path (a Solaris, or other Unix system) and the 'gcc-ar' name can be used to get the gcc specific 'ar'; all the 'gcc-XXX' things are for this use case.

GCC - generate absolute paths for #includes in debug symbols

OS is Windows, GCC is 4.7.2, GDB is 7.3.
I have a .c file in the C:/project/src/ folder with an include:
#include "../inc/header.h"
After the compilation I have a relative path in the debug symbols:
> objdump -WL obj.o | grep header.h
C:/project/src/../inc/header.h
...
Yet I want it to be C:/project/inc/header.h, because setting BPs in gdb fail for me if I use absolute paths when issuing the set breakpoint command.
This situation is artificial, but due to the environmental conditions the only solution to my issue will be either absolute paths generation in the debug symbols or teaching GDB to resolve relative paths.
Is there a switch for GCC to turn on the absolute path generation in the debug symbols?
The solution is in GDB, not GCC.
The easiest way is to add the directory containing the header to the search path:
(gdb) directory /path/to/include/
A more complicated one that you might need is pathname substitution rules:
(gdb) set substitute-path ../inc /path/to/inc

How to write Makefiles to get a relative path in debug symbols?

I have a structure of code like this:
project_dir/
source1.c
subdir/
source2.c
The Makefile calls subdir/Makefile, so that the file subdir/source2.c is compiled in this way:
gcc -g -someoptions source2.c
and symbols in GDB link to source2.c instead of subdir/source2.c (with the result that GDB can not find symbols in source files). How should I write a Makefile or what options to use in gcc to get symbols using the relative path to the project main directory (or eventually the absolute path)?
I can not use:
cd .. && gcc -g -someoptions ../subdir/source2.c
because I would have to change references to header files in all files in subdir.
Your question is platform-specific (e.g. on Linux GDB should just work(TM), so I assume you are not on Linux).
One option is to build like this:
gcc -g ${PWD}/source2.c -o ...
Another option is to use GDB dir command to add ${TOP}/project_dir/subdir to the list of directories that GDB will search for sources.

rpath=$ORIGIN not having desired effect?

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.

Resources