world leader in high performance signal processing
Trace: » port_linking

Porting VDSP Linker Steps to GNU ld

Linkers (linker -> ld)

The VDSP linker utility is invoked as linker while the GNU linker is invoked as ld.

Here is a comparison of the command line options:

VDSP GNU Description
@filename same Read additional options from file
-e GC Eliminate unused symbols
-ek <section> GC Filter section from symbol elimination
-entry <sym> --entry <sym> Set the entry point
-es <section> GC Eliminate unused symbols from specified section
-ev GC Verbosely eliminate unused symbols
-flags-meminit N/A Pass options to memory initializer utility
-flags-pp CPP Pass options to the preprocessor
-h same Display utility help
-i <path> CPP Add path to include search
-I <path> CPP Add path to include search
-ip N/A Fill in fragmented holes with free objects
-jcs21 (1) Convert out-of-range jumps to usable variant
-keep <sym> GC Keep unused symbol
-L <path> same Add path to library search
-M (2) Output dependency info for make
-Map <file> same Output map to file 1)
-MDmacro=def CPP Define a macro
-MM (2) Output dependency info for make and then do link
-MUDmacro CPP Undefine a macro
-meminit N/A Run the memory initializer utility
-nomemcheck N/A Turn off memory checking
-o <output> same Select output file
-od <dir> N/A Control output directory for LDF file
-pp CPP Stop after preprocessing
-proc <proc> (3) Select processor
-reserve-null N/A Reserve 4 bytes at address 0
-s same Strip all symbols
-S same Strip debug symbols
-save-temps (4) Save temporary files
-si-revision (3) Select processor silicon revision
-sp CPP Skip preprocessing
-T <ldf> same Select linker script
-t N/A Enable short file trace output
-tx -t Enable full path file trace output
-v --verbose Perform linking steps verbosely
-version --version Output version information
-warnonce --warn-once Warn only once per undefined symbol
-Wnumber N/A Control warnings
-Wwarn N/A Control warnings
-xref N/A Output an XML cross reference file
  1. The GNU toolchain does not currently support automatic selection of an appropriate jump/call instruction. There are plans to implement support for linker relaxation which would function the same as this flag, but automatically rather than having to code for it.
  2. The linker does not know anything about source files, so it knows nothing of dependencies. Use gcc's -M and related options to get automatic make dependency information.
  3. The linker does not care what processor it outputs for as the logic is all handled by gcc.
  4. The linker does not create any temporary files, thus there is no point in having a -save-temps option.

Linker Scripts (LDF -> LDS)

The main documentation for the GNU linker script format can be found here:
http://sourceware.org/binutils/docs/ld/Scripts.html

Operators

VDSP GNU Description
ABSOLUTE(exp) same Return absolute value of expression
ADDR(section) same Return start address of section
DEFINED(symbol) same Return 1 if symbol is defined
MEMORY_END(segment) N/A Return end address of segment (start + sizeof)
MEMORY_SIZEOF(segment) LENGTH(memory) Return size (in bytes) of segment
MEMORY_START(segment) ORIGIN(memory) Return start address of segment
SIZEOF(section) same Return size (in bytes) of segment
. same The location counter

Commands

VDSP GNU Description
ALIGN(num) same Align by number
ARCHITECTURE(proc) (4) Specify output processor
COMMON_MEMORY{} (1) Declare memory common for multicore systems
ELIMINATE() GC Eliminate unused symbols
ELIMINATE_SECTIONS() GC Eliminate unused symbols from specified section
ENTRY(symbol) same Set executable entry point
FILL(num) same Fill holes with number
FORCE_CONTIGUITY N/A Force contiguous output
INCLUDE(file) INCLUDE file Include the linker script file
INPUT_SECTION_ALIGN(num) ALIGN(num) Align input by num
INPUT_SECTIONS() (3) Map an input file to multiple outputs
KEEP() same Do not eliminate the unused symbols/sections
KEEP_SECTIONS(sections) GC Do not do elimination in the sections
LINK_AGAINST(file) N/A Use file to resolve symbols
MAP(file) N/A Output an XML map file
MEMORYP{} same Define memory regions for output
MPMEMORY{} (1) Declare core-specific memory for multicore systems
NOFORCE_CONTIGUITY N/A Do not warn about discontiguous memory output
OVERLAY_INPUT{} OVERLAY{} Create an overlay
PACKING() N/A Output memory in a different byte order
PLIT{} N/A Create a procedure linkage table for overlays
PROCESSOR{} CPP Run commands only for certain processors
RESERVE() (2) Reserve space for a symbol
RESERVE_EXPAND() (2) Reserve unused space for a symbol
RESOLVE(sym, addr) sym = addr Define a symbol and its address
SEARCH_DIR(paths) same Add paths to the input search list
SECTIONS{} same Define output sections
SHARED_MEMORY{} (1) Declare shared memory for multicore systems
  1. Multicore systems do not get any special handling. You have to declare the common regions yourself using MEMORY{} and then output objects to the appropriate places using SECTIONS{}.
  2. Special support is not provided for reserving space for symbols. These commands can be replaced with a series of simpler commands -- declare the alignment with ALIGN(), set the symbol with the location counter, then update the location counter.
  3. The GNU linker does not treat input sections specially. If you want to use the same input to multiple outputs, then specify the input by name multiple times. The wildcard globbing will not pick up things that have already been caught.
  4. The linker does not care what processor it outputs for as the logic is all handled by gcc.

MEMORY{}

http://sourceware.org/binutils/docs/ld/MEMORY.html

The VDSP linker uses the term segment when referring to the ranges defined by the MEMORY{} command. The GNU linker describes them as memory regions as it uses segment for something else (which is used infrequently).

A VDSP LDF file takes the form:

MEMORY
{
	segment_name: TYPE(...) START(...) LENGTH(...) END(...) WIDTH(...)
}

While the GNU LDS file takes the form:

MEMORY
{
	name (attr): ORIGIN = ..., LENGTH = ...
}
LDF LDS How to convert
TYPE() (attr) Use the R attribute for read-only section
START() ORIGIN = They're the same
LENGTH() LENGTH = They're the same
END() N/A Use LENGTH = instead
WIDTH() N/A The GNU linker does not care about address widths and the VDSP option makes no sense -- it can only ever be one value for Blackfin systems

SECTIONS{}

http://sourceware.org/binutils/docs/ld/SECTIONS.html

A VDSP LDF file takes the form:

SECTIONS
{
	section [type] [init] {
		section_commands
	} > memory
}

While the GNU LDS file takes the form:

SECTIONS
{
	section [addr] [type] : [AT(addr)] [ALIGN(num)] {
		section_commands
	} [>memory] [AT>memory] [=fill]
}

Commands

TBD

Overlays

TBD

http://sourceware.org/binutils/docs/ld/Overlay-Description.html

ALGORITHM ALL_FIT BEST_FIT FIRST_FIT NUMBER_OF_OVERLAYS OVERLAY_GROUP OVERLAY_ID OVERLAY_INPUT OVERLAY_OUTPUT

Elimination

The VDSP linker supports elimination on a per-symbol and per-section basis. The GNU toolchain also supports this same functionality in the end, but it takes a completely different tact.

When compiling C code, the compiler flags -ffunction-sections and -fdata-sections instruct GCC to place every function and variable in its own dedicated section. These typically take the form of .text.function and .data.variable where function and variable get replaced with the actual symbol name.

Then when linking, the --gc-sections flag instructs the linker to discard all sections that are not referenced. If you want to prevent specific symbols from being discarded in your linker script, you can use the KEEP() command.

Preprocessing

While VDSP supports preprocessing in the linker itself, the GNU toolchain does not. Instead, these steps are kept logically separate by design -- have one tool do one thing and one thing only, and have it do it well. As such, if you want to have a dynamic linker script (i.e. preprocess it), then you can first run it through the preprocessor before passing it to the linker. This is how many projects work such as Das U-Boot and the Linux kernel.

Typically you'll see rules like the following in the Makefile:

....
myscript.lds: myscript.lds.S
	$(CPP) $(CFLAGS) $(CPPFLAGS) $< > $@
....
myapp: myscript.lds
	$(LD) -Wl,-T,myscript.lds ....
....

This allows you to use all the normal CPP magic such as the -DDEFINE=value and -Ipath flags and the #if logic in the source itself. Since you have access to all the same defines as normal C code, you can do processor/silicon specific stuff by checking the normal ADSPBF### and related defines.

Misc

If the ported program is a library, you will need to link the library with your uClinux application. You may use Gnu Linker Scripts to direct the Gnu linker.

  • Define Sections in Linker scripts:

By default, the Linker uses Linker scripts defined in <bfin-uclinux-toolchain>/bfin-uclinux/lib/ldscripts/. when the ported library defines its sections, you may dump the scripts and define your section in the file:

For example, supposing the library defines “my_data_1” section and you want the linker copy this secions from all the source files to data section:

# Dump default linker script

./bfin-uclinux-ld --verbose > my_ld.x

# Modify my_ld.x, add in the .data{} definition:

SECTIONS
{
   ...
   .data
   {
     *(.data .data.* .gnu.linkonce.d.*)
     *(my_data_1) /* Add my data secton here */
   }
}
1) VDSP uses XML; GNU does not