C compiler / linker - How to hide internal symbols of a static library - c

MY GOAL IS: to compile a static library (normally .a extension) and have internal symbols hidden (function and variable names) when I open the library file with a text editor.
Currently I am on XC32 compiler of Microchip Technology, who makes the well known PIC microcontrollers.
Actually I can't share here my lib, but I have created a very simple one to make tests.
C source code is only:
int variable;
int sum (int a, int b)
{
return a+b;
}
and header is only:
int sum (int a, int b);
Created a library project on mplabX IDE and selected XC32 compiler. The project properties show these options:
I did changed these option:
xc32-as -> Have symbols in production build. uncheked
xc32-gcc -> Have symbols in production build. uncheked
xc32-ld -> Symbols & Macros -> Symbols. Selected option "strip all symbol info"
Then compiled. Library (.a extension) was generated. I opened it with text editor and the see theat the symbols are yet being shown:
For each of the compiler sections (xc32-as, xc32-gcc, xc32-ld etc), There is a field "Additional options".
I tried to input these options, but no one worked to hide the symbols:
-fvisibility=hidden on gcc and ld
-fvisibility=hidden on gcc and strip -r -S -x on ld
If I try strip -r -S -x on gcc I get:
pic32m-gcc.exe: error: strip: No such file or directory
pic32m-gcc.exe: error: missing argument to '-x'
Then I removed the addicional options for ld and gcc, placed "static" in front of the variable and function, and C source become:
static int variable;
static int sum (int a, int b)
{
return a+b;
}
Doing this (adding static in front of all), the symbols get correctly hidden. But on the other hand I am not able to use the lib attached to my app project, because when the compiler shows "undefined reference" to the functions of the lib. This is because: [From Wikipedia] In the C programming language, static is used with global variables and functions to set their scope to the containing file.
Then, how can I reach my goal in this case? (first phrase of the topic).
Regards.
EDIT:
This is being shown on the project properties on the IDE, I am compiling with it.
All the internal symbols are being shown near the bottom of the lib file where it shows the name of the c file, only in this place shows to c filename

Related

Where are avr-gcc libraries stored?

I'm trying to locate the .c files that are related to the #include header files in avr.
I want to have a look at some of the standard libraries that are defined in the avr-gcc library, particularly the PORT definitions contained in <avr/io.h>. I searched through the library in /usr/lib/avr/include/avr and found the header file, however what I am looking for is the .c file. Does this file exist? If so, where can I find it? If not, what is the header file referencing?
The compiler provided libraries are precompiled object code stored in static libraries. In gcc, libraries conventionally the extension .a (for "archive" for largely historic reasons), and the prefix "lib".
At build time, the linker will search the library archives to find the object-code modules necessary to resolve referenced to library symbols. It extracts the required modules and links them to the binary image being built.
In gcc a library libXXX.a is typically linked using the command line switch -lXXX - so the libXXX.a naming convention is important in that case. So for example the standard C library libc.a is looking linked by the switch -lc.
So to answer your question, there are normally no .c files for the compiler provided libraries provided with the toolchain. The library need not even have been written by in C.
That said, being open source, the source files (.c or otherwise) will be available from the repositories of the various libraries. For example, for the standard C library: https://www.nongnu.org/avr-libc/.
For other AVR architecture and I/O support libraries, you might inspect the associated header files or documentation. The header files will typically have a boiler-plate comment with a project URL for example.
PORTB and other special function registers are usually defined as macros in headers provided by avr-libc. Find your include/avr directory (the one that contains io.h). In that directory, there should be many other header files. As an example, iom328p.h contains the following line that defines PORTB on the ATmega328P:
#define PORTB _SFR_IO8(0x05)
If you are also looking for the libraries that are distributed as .a files, you should run avr-gcc -print-search-dirs.
There are several ways to find out where the system headers are located and which are included:
avr-gcc -v -mmcu=atmega8 foo.c ...
With option -v, GCC will print (amongst other stuff) whch include paths it is using. Check the output on a shell / console, where GCC will print the search paths:
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/avr/5.4.0/include
/usr/lib/gcc/avr/5.4.0/include-fixed
/usr/lib/gcc/avr/5.4.0/../../../avr/include
The last location is for AVR-LibC, which provides avr/io.h. Resolving the ..s, that path is just /usr/lib/avr/include. These paths depend on how avr-gcc was configured and installed, hence you have to run that command with your installation of avr-gcc.
avr-gcc -H -mmcu=atmega8 foo.c ...
Suppose the C-file foo.c reads:
#include <avr/io.h>
int main (void)
{
PORTD = 0;
}
for an easy example. With -H, GCC will print out which files it is actually including:
. /usr/lib/avr/include/avr/io.h
.. /usr/lib/avr/include/avr/sfr_defs.h
... /usr/lib/avr/include/inttypes.h
.... /usr/lib/gcc/avr/5.4.0/include/stdint.h
..... /usr/lib/avr/include/stdint.h
.. /usr/lib/avr/include/avr/iom8.h
.. /usr/lib/avr/include/avr/portpins.h
.. /usr/lib/avr/include/avr/common.h
.. /usr/lib/avr/include/avr/version.h
.. /usr/lib/avr/include/avr/fuse.h
.. /usr/lib/avr/include/avr/lock.h
avr-gcc -save-temps -g3 -mmcu=atmega8 foo.c ...
With DWARF-3 debugging info, the macro definitions will be recorded in the debug info and are visible in the pre-processed file (*.i for C code, *.ii for C++, *.s for pre-processed assembly). Hence, in foo.i we can find the definition of PORTD as
#define PORTD _SFR_IO8(0x12)
Starting from the line which contains that definition, scroll up until you find the annotation that tells in which file the macro definition happened. For example
# 45 "/usr/lib/avr/include/avr/iom8.h" 3
in the case of my toolchain installation. This means that the lines following that annotation follow line 45 of /usr/lib/avr/include/avr/iom8.h.
If you want to see the resolution of PORTD, scroll down to the end of foo.i which contains the pre-processed source:
# 3 "foo.c"
int main (void)
{
(*(volatile uint8_t *)((0x12) + 0x20)) = 0;
}
0x12 is the I/O address of PORTD, and 0x20 is the offset between I/O addresses and RAM addresses for ATmega8. This means the compiler may implement PORTD = 0 by means of out 0x12, __zero_reg__.
avr-gcc -print-file-name=libc.a -mmcu=...
Finally, this command will print the location (absolue path) of libraries like libc.a, libm.a, libgcc.a or lib<mcu>.a. The location of the library depends on how the compiler was configureed and installed, but also on command line options like -mmcu=.
avr-gcc -Wl,-Map,foo.map -mmcu=atmega8 foo.c -o foo.elf
This directs the linker to dump a "map" file foo.map where it reports which symbol will drag which module from which library. This is a text file that contains lines like:
LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr4/crtatmega8.o
...
LOAD /usr/lib/gcc/avr/5.4.0/avr4/libgcc.a
LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr4/libm.a
LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr4/libc.a
LOAD /usr/lib/gcc/avr/5.4.0/../../../avr/lib/avr4/libatmega8.a
libgcc.a is from the compiler's C runtime, and all the others are provided by AVR-LibC. Resolving the ..s, the AVR-LibC files for ATmega8 are located in /usr/lib/avr/lib/avr4/.

Compile and Link to .com file with Turbo C

I'm trying to compile and link a simple program to a DOS .com file using Turbo C compiler and linker. By that I try the simplest C-program I can think of.
void main()
{}
Are there command line arguments to link to com files in the Turbo C Linker?
The Error Message I get from the Linker is the following:
"Fatal: Cannot generate COM file: invalid entry point address"
I know that com files need entry point to be at 100h. Does Turbo C have an option to set this address?
It has been a long time since I have genuinely tried to use Turbo-C for this kind of thing. If you are compiling and linking on the command line separately with TCC.EXE and TLINK.EXE then this may work for you.
To compile and link to a COM file you can do this for each one of your C source files creating an OBJ file for each:
tcc -IF:\TURBOC3\INCLUDE -c -mt file1.c
tcc -IF:\TURBOC3\INCLUDE -c -mt file2.c
tcc -IF:\TURBOC3\INCLUDE -c -mt file3.c
tlink -t -LF:\TURBOC3\LIB c0t.obj file1.obj file2.obj file3.obj,myprog.com,myprog.map,cs.lib
Each C file is compiled individually using -mt (tiny memory model) to a corresponding OBJ file. The -I option specifies the path of the INCLUDE directory in your environment (change accordingly). The -c option tell TCC to compile to a OBJ file only.
When linking -t tells the linker to generate a COM program (and not an EXE), -LF:\TURBOC3\LIB is the path to the library directory in your environment (change accordingly). C0T.OBJ is the C runtime file for the tiny memory model. This includes the main entry point that you are missing. You then list all the other OBJ files separated by a space. After the first comma is the output file name. If using -t option name the program with a COM extension. After the second comma is the MAP file name (you can leave the file name blank if you don't want a MAP file). After the third comma is the list of libraries separated by spaces. With the tiny model you want to use the small model libraries. The C library for the small memory model is called CS.LIB .
As an example if we have a single source file called TEST.C that looks like:
#include<stdio.h>
int main()
{
printf("Hello, world!\n");
return 0;
}
If we want to compile and link this the commands would be:
tcc -IF:\TURBOC3\INCLUDE -c -mt test.c
tlink -t -LF:\TURBOC3\LIB c0t.obj test.obj,test.com,test.map,cs.lib
You will have to use the paths for your own environment. These commands should produce a program called TEST.COM. When run it should print:
Hello, world!
You can generate COM file while still using IDE to generate EXE. Following worked on TC 2.01. Change memory model to Tiny in the options, then compile the program and generate EXE file, then go to command prompt, and run EXE2BIN PROG.EXE PROG.COM. Replace PROG with your program name.
Your problem is about "entry point"
some compiler or linker can recognize void main() like entry point omiting a return value but no all of them.
You shoud use int main() entry point instead for better control of app and compiler can recognize main function as entry point
example:
int main() {
/* some compiler return 0 when you don't for main,
they can ask for return value */
}
from geekforgeeks:
A conforming implementation may provide more versions of main(), but they must all have return type int. The int returned by main() is a way for a program to return a value to “the system” that invokes it. On systems that doesn’t provide such a facility the return value is ignored, but that doesn’t make “void main()” legal C++ or legal C. Even if your compiler accepts “void main()” avoid it, or risk being considered ignorant by C and C++ programmers.
In C++, main() need not contain an explicit return statement. In that case, the value returned is 0, meaning successful execution.
source: https://www.geeksforgeeks.org/fine-write-void-main-cc/

Eclipse with MinGW does not link correctly

I use the Eclipse Luna IDE for C/C++ (CDT) and MinGW for programming C with Microsoft Windows 7.
I try to write a simple program which uses KissFFT
This is not directly a library, this are only some *.c and *.h-Files.
My example program is stored at E:\Programming\Programs\Simple_FFT\
That is my example program:
#include <stdio.h>
#include <stdlib.h>
#include <tools/kiss_fftr.h>
int nfft = 1024;
int inverse_fft = 0;
int main(void) {
kiss_fftr_cfg cfg = kiss_fftr_alloc(nfft, inverse_fft, NULL, NULL);
kiss_fft_scalar timedata[nfft]; //input
kiss_fft_cpx freqdata[nfft]; //output
while (1)
{
timedata[nfft] = 0;
kiss_fftr(cfg, timedata, freqdata);
free(cfg);
}
return 0;
}
As you can see I included kiss_fftr.h.
This file on the other hand is including kiss_fft.h.
In Eclipse, I went to Properties -> C/C++ General -> Paths and Symbols -> Includes -> GNU C -> and there i added the directorys E:\Programming\Libraries\kiss_fft130 and E:\Programming\Libraries\kiss_fft130\tools
Because this are the folders where the needed header files and c files are stored.
So everything fine, not?
But now the curious thing: I can't compile the program with Eclipse. I'm relatively new to programming but as far as I know, if I include a header file and the directory is included in Eclipse, the related *.c-file should be linked automatically.
Instead I get undefinded references:
src\Simple_FFT.o:Simple_FFT.c:(.text.startup+0x3b): undefined reference to `kiss_fftr_alloc'
src\Simple_FFT.o:Simple_FFT.c:(.text.startup+0x86): undefined reference to `kiss_fftr'
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: src\Simple_FFT.o: bad reloc address 0x20 in section `.eh_frame'
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: final link failed: Invalid operation
The problem is, that Eclipse is not linking the c-files of KissFFT to the included headers.
So I found two solutions to bypass this problem:
First: Compile the program manually:
gcc -o E:\Programming\Programs\Simple_FFT\Release\Simple_FFT -I"E:\Programming\Libraries\kiss_fft130" -I"E:\Programming\Libraries\kiss_fft130\tools" E:\Programming\Programs\Simple_FFT\src\Simple_FFT.c E:\Programming\Libraries\kiss_fft130\tools\kiss_fftr.c E:\Programming\Libraries\kiss_fft130\kiss_fft.c
As you can see, I included the *.c-Files "kiss_fftr and kiss_fft" manually and compilation is fine.
Second solution: In Eclipse, I went to Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -> MinGW C Linker -> Miscellaneous -> Other Objects -> and added E:\Programming\Libraries\kiss_fft130\kiss_fftr.c and E:\Programming\Libraries\kiss_fft130\kiss_fft.c.
Then the program is compiling fine, too.
Both is not my intention. Because I would have to manually link every *.c-file I use in my program. What is my failure in the properties of Eclipse, that it does not automatically link the correct files together?
Would be very happy to get an answer so I can start programming correctly :)
You need to add your C files folders to the Source Locations in the Project Properties->C/C++ General->Paths and Symbols. Or, if you have your kiss library compiled (.lib or .a) you should add it in the linker section Library Search path and Libraries

Why including an h file with external vars and funcs results in undefined references

What if I want these externals to be resolved in runtime with dlopen?
Im trying to understand why including an h file, with shared library external vars and funcs, to a C executable program results in undefined/unresolved. (when linking)
Why do I have to add "-lsomelib" flag to the gcc linkage if I only want these symbols to be resolved in runtime.
What does the link time linker need these deffinitions resolutions for. Why cant it wait for the resolution in runtime when using dlopen.
Can anyone help me understand this?
Here something that may help understanding:
there are 3 types of linking:
static linking (.a): the compiler includes the content of the library into your code at link time so that you can move the code to other computers with the same architecture and run it.
dynamic linking (.so): the compiler resolves the symbols at link time (during compilation); but the does not includes the code of the library in your executable. When the program is started, the library is loaded. And if the library is not found the program stop. You need the library on the computer that is running the program
dynamic loading: You are in charge of loading the library functions at runtime, using dlopen and etc. Specially used for plugins
see also: http://www.ibm.com/developerworks/library/l-dynamic-libraries/ and
Difference between shared objects (.so), static libraries (.a), and DLL's (.so)?
A header file (e.g. an *.h file referenced by some #include directive) is relevant to the C or C++ compiler. The linker does not know about source files (which are input to the compiler), but only about object files produced by the assembler (in executable and linkable format, i.e. ELF)
A library file (give by -lfoo) is relevant only at link time. The compiler does not know about libraries.
The dynamic linker needs to know which libraries should be linked. At runtime it does symbol resolution (against a fixed & known set of shared libraries). The dynamic linker won't try linking all the possible shared libraries present on your system (because it has too many shared objects, or because it may have several conflicting versions of a given library), it will link only a fixed set of libraries provided inside the executable. Use objdump(1) & readelf(1) & nm(1) to explore ELF object files and executables, and ldd(1) to understand shared libraries dependencies.
Notice that the g++ program is used both for compilation and for linking. (actually it is a driver program: it starts some cc1plus -the C++ compiler proper- to compile a C++ code to an assembly file, some as -the assembler- to assemble an assembly file into an object file, and some ld -the linker- to link object files and libraries).
Run g++ as g++ -v to understand what it is doing, i.e. what program[s] is it running.
If you don't link the required libraries, at link time, some references remain unresolved (because some object files contain an external reference and relocation).
(things are slightly more complex with link-time optimization, which we could ignore)
Read also Program Library HowTo, Levine's book linkers and loaders, and Drepper's paper: how to write shared libraries
If you use dynamic loading at runtime (by using dlopen(3) on some plugin), you need to know the type and signature of relevant functions (returned by dlsym(3)). A program loading plugins always have its specific plugin conventions. For examples look at the conventions used for geany plugins & GCC plugins (see also these slides about GCC plugins).
In practice, if you are developing your application accepting some plugins, you will define a set of names, their expected type, signature, and role. e.g.
typedef void plugin_start_function_t (const char*);
typedef int plugin_more_function_t (int, double);
then declare e.g. some variables (or fields in a data structure) to point to them with a naming convention
plugin_start_function_t* plustart; // app_plugin_start in plugins
#define NAME_plustart "app_plugin_start"
plugin_more_function_t* plumore; // app_plugin_more in plugins
#define NAME_plumore "app_plugin_more"
Then load the plugin and set these pointers, e.g.
void* plugdlh = dlopen(plugin_path, RTLD_NOW);
if (!plugdlh) {
fprintf(stderr, "failed to load %s: %s\n", plugin_path, dlerror());
exit(EXIT_FAILURE; }
then retrieve the symbols:
plustart = dlsym(plugdlh, NAME_plustart);
if (!plustart) {
fprintf(stderr, "failed to find %s in %s: %s\n",
NAME_plustart, plugin_path, dlerror();
exit(EXIT_FAILURE);
}
plumore = dlsym(plugdlh, NAME_plumore);
if (!plumore) {
fprintf(stderr, "failed to find %s in %s: %s\n",
NAME_plumore, plugin_path, dlerror();
exit(EXIT_FAILURE);
}
Then use appropriately the plustart and plumore function pointers.
In your plugin, you need to code
extern "C" void app_plugin_start(const char*);
extern "C" int app_plugin_more (int, double);
and give a definition to both of them. The plugin should be compiled as position independent code, e.g. with
g++ -Wall -fPIC -O -g pluginsrc1.c -o pluginsrc1.pic.o
g++ -Wall -fPIC -O -g pluginsrc2.c -o pluginsrc2.pic.o
and linked with
g++ -shared pluginsrc1.pic.o pluginsrc2.pic.o -o yourplugin.so
You may want to link extra shared libraries to your plugin.
You generally should link your main program (the one loading plugins) with the -rdynamic link flag (because you want some symbols of your main program to be visible to your plugins).
Read also the C++ dlopen mini howto

Undefined reference in C with gcrypt.h

I'm trying to use the library gcrypt.h but show this error:
undefined reference to `gcry_md_get_algo_dlen'
The code is:
int algo = GCRY_MD_SHA1;
unsigned int hash_len = gcry_md_get_algo_dlen(algo);
unsigned char hash[hash_len];
How can I fix it?
Make sure you have the most recent version of the library http://www.gnupg.org/download/#libgcrypt
If you have the right version make sure you added the library itself to your linker settings in Eclipse.
To do so:
Right-Click on your project -> Properties / C/C++Build / Settings / GCC C++ Linker / Libraries
There you add to libraries "gcrypt" ( you don't at the "lib" to it )
And also make sure that ( if the lib isnt under a system path ) you add the path where the library itself lies.
It looks like you are facing a Linking Error (Undefined reference to a function)
You have included the header "gcrypt.h" but the object file is not linked to your main file.
Library is NOT the same as the header (.h) file. C libraries are collections of compiled objects which are LINKED to your object code by the linker. Header files are lexically included by the preprocessor.
When you compile, you need to make sure that the libraries are where they're supposed to be AND the header files are where they're supposed to be. Either one can mess you up. Make sure that .o files are linked properly

Resources