Make or Shell Variables In Linker Script - linker

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.

Related

Can I save a C static library anywhere I want?

I have created a library in C and want to link it when compiled. Do I have to save in a certain folder in my computer's file system or can I create my own file structure within my application to save it?
Update: My error turned out to be not properly including a header file. My files and linker were fine but it was simple syntax error.
You can save it wherever you want. Just make sure that the compiler knows the location. In the case of gcc for example, you can use:
gcc -L path/to/libdir -l:mylib.a ...
(assuming mylib.a is in path/to/libdir)
Or even:
gcc path/to/libdir/mylib.a ...

Create new segment in linker script while keeping default ones

I have created some special sections in a linked file and I want them to be in separated segments to have different page permissions.
In linker script, PHDRS command can specify segments in linked file. However, as the document says, PHDRS will create no default-defined segments other than specified in the command. And I found no PHDRS command in ld --verbose output.
Is there any way to keep the default ones? Or what is the default specifications of segments so I can write them in my own linker script?
Came across this when looking for similar answers. It's late, but someone else might come across it. To get the currently used linker script you can use gcc -Wl,--verbose ... or ld --verbose ... when linking, which will dump the script (and a bunch of other stuff) to stdout. As far as I'm aware, there is no way to keep the default program headers and just append an entry to them without writing a custom script to parse the output of the above. If you want to add a section on the other hand, apparently there's a trick with objcopy --add-section that allows you to add a section to an existing elf file.

rename a symbol using a linker script

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.

Makefile: Select to compile against dynamic or static library programatically

I develop a software that needs to be compiled against libraries coming for an external supplier. In some cases the libraries are available as shared libraries (libexample1.so) or as static libraries (libexample1.a).
I want my makefiles to be able to detect that situation. My idea is to check for the static library file, and if it does not exist redefine some compile flags.
My code now is this:
$(PROGRAM1):$(PROGRAM1_OBJS)
ifneq ("$(wildcard $(STATIC_LIB_PATH)","")
#echo "Compiling against static library"
else
#echo "Compiling against dynamic library"
STATIC_LIB_PATH = ""# SETTING IT TO EMPTY
LDFLAGS += -lexample1
endif
(compilation instructions)
This is not working for me as it is trying to execute the STATIC_LIB_PATH... Any suggestions on how to approach this situation? Is this the best approach or are there better ways to do it?
If you want to set make variables, you must do so outside of a recipe. Inside of a recipe, it will be interpreted as a command to execute.
In your case, you can move the assignment before any rule
ifeq ("$(wildcard $(STATIC_LIB_PATH)","")
STATIC_LIB_PATH = # SETTING IT TO EMPTY
LDFLAGS += -lexample1
endif
# ...
$(PROGRAM1):$(PROGRAM1_OBJS)
(compilation instructions)
Usually, you don't need to check for static vs dynamic libraries. The compiler and linker already select the proper library. So, you only need to specify
LDFLAGS += -lexample1
and the linker picks the dynamic version if available, and the static one if there's only a static library.

How to force use of static library over shared?

In my SConscript I have the following line:
Program("xtest", Split("main.cpp"), LIBS="mylib fltk Xft Xinerama Xext X11 m")
How do I get scons to use mylib.a instead of mylib.so, while linking dynamically with the other libraries?
EDIT: Looking to use as few platform specific hacks as possible.
Passing the full filepath wrapped in a File node will force static linking. For example:
lib = File('/usr/lib/libfoo.a')
Program('bar', 'main.c', LIBS = [lib])
Will produce the following linker command line
g++ -o bar main.o /usr/lib/libfoo.a
Notice how the "-l" flag is not passed to the linker for this LIBS entry. This effectively forces static linking. The alternative is to modify LINKFLAGS to get what you want with the caveat that you are bypassing the library dependency scanner -- the status of the library will not be checked for rebuilds.
To make this platform independent you append the env['SHLIBSUFFIX'] onto the library you want to use. env['SHLIBSUFFIX'] gives you this environments suffix for shared libraries.
You also have the ['SHLIBPREFIX'], ['LIBPREFIX'], ['LIBSUFFIX'] and ['PROGSUFFIX'], all useful for situations like this.
Edit:
I obviously haven't made myself understood, so I will clarify.
The return value of these lookups are strings to the pre/suffixes that platform uses. In that way you can refer to the file you need on each platform. Note that you cannot use it as a pure string, it has to be embedded as a file node as BennyG suggests. Working with nodes are anyway the best solution as file nodes are much more versatile than a string.
Hope this helps.

Resources