rename a symbol using a linker script - linker

Is it possible to use a linker script or mapfile to rename a symbol?
I'm trying to adapt some code written in a mix of C++ and Fortran so that it will work with more than one Fortran compiler - on Linux. It is currently written for the Solaris Studio compiler with the option for case-sensitivity enabled. I'd like to handle variations in Fortran symbol name mangling automatically (such as from the Makefile).
It does appear to be possible to create aliases so, a linker script containing:
C_Function_ = c_function;
will sort-of work. Unfortunately, adding the -T option to reference this script causes some other change in behaviour and I get errors due to libdl.so.2/librt.so.1 not being found. Is there some sort of default linker script that I need to include or something? I've tried with both bfd and gold linkers on Linux.

You cannot really rename symbols, but you can define aliases to existing symbols like
PROVIDE(c_function = C_function_);
...
in a linker script.
If you pass this linker script with the -T option to ld, it will replace the original (default) linker script. If you rather want to have the linker script extend the default, pass it without the -T option (just like you would with an additional object file).
This way, everything should work as expected.

Related

Removing symbols from `.a`s

I'm compiling a C++ static library using g++ via Cmake. I want to remove symbols relating to the internal implementation so they don't show up in nm. (See here and here for the same with shared libraries.)
This answer tells you how to do it on iOS, and I'm trying to understand what happens under the hood so I can replicate on Linux. They invoke ld with:
-r/--relocatable to Generate relocatable output---i.e., generate an output file that can in turn serve as input to ld.
-x/--discard-all: Delete all local symbols.
AFAICS the -r glues all the modules into one module, and then the -x removes symbols only used inside that module. Is that right?
It's not clear how the linker 'knows' which symbols will be exported externally? Does it rely on __attribute__((visibility("hidden/default"))) as in the .so case?
Edit: clearly I'm confused... I thought cmake invoked ld to link the .os into .a. Googled + clarified above.
Question still stands: how do I modify the build process to exclude most symbols?

cannot find symbol "Embeddedrcall_Init"

I am trying to create a dll file using swig for an embeddedR C Program in windows environment. I am using the below commands:
C:\swigwin-3.0.12\Examples\r\Z>swig -c++ -tcl embeddedRCall.i
C:\swigwin-3.0.12\Examples\r\Z>gcc -c embeddedRCall.c -I/swigwin-3.0.12/Examples/r/Z
C:\swigwin-3.0.12\Examples\r\Z>gcc -c embeddedRCall_wrap.c -I/Tcl/include/tcl8.6 -I/swigwin-3.0.12/Examples/r/Z
C:\swigwin-3.0.12\Examples\r\Z>gcc -shared embeddedRCall.o embeddedRCall_wrap.o -o embeddedRCall.dll -L/Tcl/lib -L/R/R-3.3.2/bin/i386 -lR -lRblas -lRiconv -lRlapack -ltcl86
% load embeddedRCall
cannot find symbol "Embeddedrcall_Init"
I was able to load other example.dll files with tclsh
However I was unable to figure out the reason-- I am already using tcl 32 bit
My module file name is and module name is embeddedRcall
Am I missing something???
I am relatively new to TCL can someone please help me.
You should have an exported (extern "C") function symbol in your library called something like Embeddedrcall_Init; it is the entry point that lets Tcl install the library into a specific interpreter instance. (It has to be found explicitly because it takes an argument.) By default, the name of the function is found by munging the name of the library (strip version number, case convert, append _Init) but the determination of the name can be overridden by the optional second argument to load.
To be more exact, if the entry is actually called EmbeddedRCall_Init, you would have to load it with:
load embeddedRCall EmbeddedRCall
# The _Init suffix is fixed when loading into a standard interp
Note the case difference! (Also, we recommend using fully qualified path names to loaded libraries, as it avoids some complexities in the dlopen() system.)

GCC - Adding Libraries

I want to use functions in the header files gmp.h and mpfr.h, which are in the file /opt/local/include.
But when I run gcc with -v, all of the search paths are something like /Application/Xcode.app/Contents/etc.
I have tried adding LD_LIBRARY_PATH="/opt/local/include" to .bash_profile but it doesn't work. The compiler either tells me that 'gmp.h' file not found, or Undefined symbols for architecture x86_64.
What should I do?
Converting comments into an answer.
You need to add -I/opt/local/include to compile commands (to specify where the headers are) and -L/opt/local/lib and -lgmp and -lmpfr (possibly in the reverse order — MPFR before GMP) to link commands.
That works! Would you mind explaining a little bit the logic behind this? For example if I had another header file header.h I need, how should I include it?
You include it with #include "header.h". You compile the code with -I/directory/containing/header to find the header. You specify where the library (libheader.a or libheader.dylib, since you seem to be on macOS) is too, with -L/directory/containing/lib and -lheader — or whatever is appropriate.
The -I tells the preprocessor to look in the named directory for header files, so it looks for /directory/containing/header/header.h, for example.
The -L tells the linker where to find libraries (so it looks for /directory/containing/lib/libheader.dylib etc).
The -lheader tells the linker to look for libheader.a or libheader.dylib (or local equivalents) for the libraries.
Except for the use of .dylib vs .so vs .dll vs … (and .a vs .lib vs …), the same principles apply to other systems too.
This is probably a duplicate.

Make or Shell Variables In Linker Script

Is it possible for a linker script to access makefile/shell variables and make a decision based on the said variable?
For example, suppose I want to change the start of the RAM area below without using a different linker script, would it be possible to use a make variable to do this?
MEMORY
{
ifeq ($(SOME_VAR),0)
RAM (wx) : ORIGIN = 0x100000, LENGTH = 128K
else
RAM (wx) : ORIGIN = 0x200000, LENGTH = 128K
endif
}
ld does not import any variables from the environment, so it cannot use them directly. The best way to do this is to create your own linker script with the environment variables you want to export, and have the original linker script include it as so:
makefile:
foo:
echo SOMEVAR=$(SOMEVAR) > environment_linker_script
ld ...
enviroment_linker_script:
SOMEVAR=xxx
master_linker_script:
include environment_linker_script
ifeq ($(SOME_VAR),0) ...
I doubt it although it would depend on the linker you're using. It might be possible for the linker to read some exported variables from make but as I said all this would be dependent on specific linker functionality. Another idea could be as long as the linker file isn't going to be too complicated one option would be to actually generate it using your makefile. There are many examples you could google for about having makefiles generate header files, you could follow the same path for generating a linker file.
If the solution of deciding within the makefile which one of several linker scripts is not sufficient, then generating the script within make might be a viable option.
This solution relies on GNU make's verbatim variables, which get exported to environment variables and are referenced with $$.
I am using this for defining a path variable to be used to include a linker script in another linker script like so:
define LDSCRIPT_DEF
/* Include the original libopencm3 linker script */
INCLUDE $(OPENCM3_DIR)/lib/stm32/f4/stm32f405x6.ld
/* Do custom stuff */
endef
export LDSCRIPT_DEF
$(LDSCRIPT):
#echo "$$LDSCRIPT_DEF" > $(LDSCRIPT)
Explanation: this is a part of the makefile and only works if the makefiles use $(LDSCRIPT) as a prerequisite in all relevant rules.

Porting NewLib for my OS: some questions

I am trying to port NewLib for my OS (I am following this tutorial: http://wiki.osdev.org/Porting_Newlib), and I have some questions.
Once LibGloss is done and compiled, when exactly will I have to use the libnosys.a that have been created? Is it when I will compile my main.c?
mipsel-uknown-elf-gcc main.c -Llibnosys.a`
My crt0.c is done. And I have to "link it as the first object". How can I do that? Is it something like this?
mipsel-uknown-elf-ld crt0.o main.o
Thanks for your answers!
Linking as the first object might work just fine like you are displaying, but the docs does mention using a linker script and adding crt0.o as STARTUP() -- I'm not too familiar with linker scripts, but you can find the default linker script and possibly create it/adjust it:
Syntax of linking script: http://wiki.osdev.org/Linker_Scripts
http://sourceware.org/binutils/docs-2.19/ld/Scripts.html#Scripts
The linker always uses a linker script. If you do not supply one yourself, the linker
will use a default script that is compiled into the linker executable. You can use the
`--verbose' command line option to display the default linker script. Certain command
line options, such as `-r' or `-N', will affect the default linker script.
The same can probably be done with other system libraries that always have to be part of the linking.
It's fine to add all on the command line, but a bit tedious in the end.
Are you getting any errors or wrong results since you are asking or what?

Resources