23. Linker

The linker combines object files from the C compiler and assembler into an executable. Object files can also originate from libraries, such as the provided C runtime library.

Cross compilers need information about the target system, and these systems can differ significantly. A host linker, in contrast, is already tailored for its system.

23.1. Running the linker

Like other tools, the linker is command-line based and can also be used from an IDE. The IDE runs the linker via its command-line interface.

Basic invocation

The linker is invoked in the following way:

$ ln68k [options] [object-files] [library-files] rules-file

A rules file is required to describe the target. This .scm file contains information about the target system’s memory and section placement rules.

Command-line options and input files can appear in any order.

Command-line options are optional arguments that tune linker behavior. They always start with a dash. Two variants exist: single-letter options (e.g., -l for a list file) begin with a single dash, while long descriptive options start with two dashes.

Some options require an argument, which appears after the option. It can be separated by a space or an equal (=) sign. For single-argument options, the argument may appear without a separator:

$ ln68k --debug file.o clib-68000-lc-sd.a placement.scm -o rocket.elf

In this example debugging information is retained in the output executable which is also named rocket.elf.

To display the version of the linker, use --version:

$ ln68k --version
Calypsi linker for Motorola 68000 version 5.16

23.2. Linking process

The goal of the linker is to combine object files produced by the compiler and the assembler. Object files have the file extensions .o. From now on we will refer to object files as “objects” as that is how they are seen by the linker once have been read from the file system.

The linker selects and combines objects in several stages:

  1. Objects are selected for inclusion in the application.

  2. Objects are placed at memory addresses by the linker following placement rules.

  3. After placement the final address of each object is known. Using this knowledge the linker resolves relocations. This fixes all address references in the application.

  4. The final program is emitted as an executable file.

23.3. Simplified placement rules

Understanding the linker process can be daunting due to its flexibility and numerous operations. Fortunately, it can often be used without in-depth knowledge, as it automatically derives placement rules from internal tool knowledge.

The linker cannot know available memory ranges or their types. This section describes placement in a simplified way; for more details, refer to Memory.

Note

On the Amiga you do not need to provide any linker placement rules as these are automatically generated internally.

Minimal rules

A minimal (or simplified) linker rules file primarily specifies memory locations:

(define memories
  '((memory flash (address (#x100000 . #x1fffff))
            (type ROM))
    (memory dataRAM (address (#x200000 . #x20ffff))
            (type RAM))
    (memory Vector (address (#x0000 . #x03ff))
            (section (reset #x0000)))
    ))

Each memory has a name, address range, and type.

The available types are shown in the following table.

Memory type

Description

RAM

This roughly corresponds to bss, and also includes the data area in an embedded system.

ROM

This is a combination of executable code, read-only variables, and everything else that should go into read-only memory, e.g. switch tables, string literals and constants.

ANY

This can be used in a hosted environment when the application is loaded into a single RAM memory. It combines allocation of RAM and ROM sections in the same memory range.

rodata

This type describes constants that are stored in read-only memory.

data

Initialized data area. Only exists when building for hosted use.

text

This type describes executable code.

bss

This is the data area for an embedded system or bare metal system. In a hosted system this holds the zero initialized data.

An error message will be given if the linker fails to automatically bind sections to memory, indicating the the sections which are causing problems. In such case you can bind those sections to a memory using a section rule. See Section placement.

In some cases you may have areas that need specific placement. This may be due to API jump tables or entry points. In such case you can explicitly place such sections using a section rule with an explicit address.

Note

If you have a special memory, such as a video memory that requires special access methods and cannot handle normal code or data, you may want to prevent the linker from doing automatic section binding there. This can be done by not specifying any type for it. In such case only sections with explicit binding will be placed in that memory.

23.4. ROM based systems

A ROM based system is typically an embedded or bare-metal system that runs without an operating system, taking control at power-on. The Calypsi linker assumes a ROM based system unless configured otherwise.

On a ROM based system, the application provides the reset vector. The C runtime configures itself by initializing static variables, setting up the stack, the heap (if used), and the C runtime itself. The I/O system is also initialized, but requires you to provide stubs for low-level stream-style I/O operations; see Stubs interface for more information.

If the hardware for your application has specific initialization needs, these must be provided by the application.

Initializing variables are done by clearing memory and filling in non-zero initializers using information stored in the ROM. The linker will split the initialized variables into two parts: the value part is stored in ROM and is copied to RAM during initialization before main() is called.

23.5. Host based systems

The alternative to a ROM based system is a hosted system that uses an operating system to load the application. Such operating systems vary from simple kernels to more elaborate systems.

Support for some hosted systems is provided, but given the vast number of alternatives, you may need to provide your own support.

The --target and --hosted command-line options configure the linker for hosted builds. Selecting a suitable application output file format is also part of this process.

When building for a hosted system, variables are initialized by loading their values in place. This avoids the duplication found in ROM based systems where initializers are stored in ROM and copied to RAM. The downside is that initialization occurs only once, during loading. If the application restarts, variables are not reinitialized. Linker options can override this behavior for detailed control, if needed.

See Target specifics for details about target specific support for supported hosts.

Simple hosted placement

The combination of an often simple executable file format and an application being loaded into RAM with both code and data gives certain problems. An application consists of both “bits” areas (code, tables and constant data) and “nobits” which is typically zero initialized data areas. In addition there are “data” areas where initializers are loaded in place, so they are a form of “bits” memory as well. Due to limitations in executable file formats, it is desirable to group “bits” and “nobits” separated, as the latter is often not represented in the executable file.

This can be solved by using a combined memory of type “any”. The linker creates placement groups in that memory for different areas, one for each memory type. Placement is tailored for the executable file format.

Specific address placement

Using placement groups clashes with restricting a section to a specific address or limited memory area. If bits sections are placed first, then nobits sections, and there are also sections with address restrictions in the same memory, conflicts can arise.

To avoid conflicts, the linker forbids section rules with arbitrary restrictions when placement groups are used. However, some specific placement may be desirable, such as stub code placed first in memory. Such fixed address placement is allowed, but it must be specified in the memory that contains the placement groups.

23.6. Objects

This section looks at the objects being linked, how they are selected and how to control it.

C startup

In a C program the main() function starts the application. Before main() is called, code initializes the C runtime. This prebuilt system startup can be customized in rare cases; see C startup for details.

Although the C startup is a small module, it is intricate. Knowledge of how Calypsi handles its C runtime is necessary to modify it.

In general the C startup handles hardware initialization, stack setup, heap initialization and configuring the I/O system. It may also do things related to the exit() handling.

The startup code is written so that subsystems which are not used by the application are omitted. This selection process is a combination of the C startup, the linker and the C library.

Libraries

Multiple object files can be combined into a library file with a .a extension. This extension stands for archive, the common name for link libraries on UNIX.

The standard C library is provided as a library file.

Note

There are several variants of such library files provided to handle different compiler settings. You will normally not need to specify it as the linker in almost every situation is able to pick a suitable library automatically based on the provided object files.

Selected objects

Objects are selected from object files specified on the linker command line. All mentioned object files are included in the linker process.

Libraries also contribute objects as needed. The linker includes only objects from a library that are actually used by the application, which helps reduce the application size.

Object selection process

The linker selects object based on a tree shake algorithm. This is a worklist algorithm that starts with a root object. The root object references one or more external symbols. These symbols are placed in the work list. The linker will then process the first symbol in the work list and try to fulfill it using the available objects. Doing so may produce further external symbol which are placed in the work list unless they have already been processed.

This process continues until the work list is empty. If there are unresolved symbols they will be emitted as undefined symbol error messages.

When all symbols have been processed, the linker knows which objects are needed for the application.

The root

The actual root is a symbol named __program_root_section which identifies the section that must be included first. For a ROM based bare metal system, this is typically the section that holds the reset vector. For an operating system based system startup, it may be some stub or simply the section that contans the first executable code.

Note

If you study the system startup code you will find the __program_start symbol which can be seen as a close relative to the __program_root_section symbol. The purpose of the __program_start symbol is to tell the debugger about the first executable instruction of the application. It has no special meaning to the linker.

Placement

The actual placement of objects is described in Section placement.

Relocations

Consider a function in your application. This is described by a symbol with the same name as the function. In order to make a function call, the compiler needs to emit an instruction to transfer control to the function. How can the compiler know the address of the function when it does not know where the function is located? The answer is that it emits a relocation, which instructs the linker to adjust the application code when the final address is known.

Somewhat simplified, the relocation describes a location inside the object code that has to be altered. The called function is mentioned by its symbol. With this relocation information, the linker can figure out the location in the application to alter, and what to put there, to allow the actual call to be correctly made.

Relocating the program can be done by the linker once all objects have been given their final locations in the memory space of the application.

Note

In some supported operating systems relocations are only done partially by the linker and a further relocation is done when the operating system loads the application to memory.

23.7. Memory

When describing the target system, the linker uses memories. A memory is a named entity specifying a continuous range of storage locations. Memory descriptions have the following attributes:

name

The memory name identifies a particular memory area.

address range

The start and end addresses (inclusive) specify the memory’s address range.

section

Names of sections to bind to the current memory.

placement group

A memory can only hold sections of one type; mixing code with zero- initialized data within a single memory is disallowed. In some output formats, it may be desirable to place different types of areas immediately adjacent within a single memory range. Placement groups function as sub-memories within a parent memory, each capable of holding sections of a distinct type. For example, one placement group can hold code sections, another data sections, and a third BSS sections. The parent memory defines the overall range, and placement groups allocate memory within this range flexibly, allowing one group to begin immediately after the previous one concludes.

type

Specifies which section types can be placed in this memory. See Minimal rules for more information.

qualifier

Defines the address spaces that can be placed in this memory.

fill word

Value used to fill unused locations in the memory, defaults to zero.

23.8. Linker rules file

The rules file (extension .scm) describes the available memory areas and defines rules for section placement. Sections can be explicitly bound to memory areas, or implicitly placed by omitting a binding rule. Implicit placement requires specifying a type for the memory; see Minimal rules.

You can often use a simplified rules file as described in Simplified placement rules. This section details linker rules. These rules can be elaborate and often unnecessary. You can intermix simplified and detailed rules to gain control without over-complicating the file. This approach helps you balance memory and placement requirements.

A full rules file can look as follows:

(define memories
  '((memory flash (address (#x100000 . #x1fffff))
            (section (nearcode (#x100000 . #x10a000))
                     code inear ifar cfar switch data_init_table))
    (memory NearRAM (address (#x200000 . #x20ffff))
            (section znear near))
    (memory RAM (address (#x210000 . #x23ffff))
            (section sstack stack zfar far heap))
    (memory Vector (address (#x0000 . #x03ff))
            (section (reset #x0000)))
    (block stack (size #x1000))
    (block sstack (size #x200))
    (block heap (size #x4000))
    (base-address _NearBaseAddress NearRAM #x8000)
    ))

The use of spacing for indentation here is unimportant to the linker tool, it is used it to make the file easier to read.

Section placement

Sections are bound to a specific memory by being mentioned after the section keyword. Placement of a section may be further restricted as described below.

Free placement

The code and switch sections appear alone (no surrounding parentheses). Sections with these names can be placed anywhere in the memory they belong to.

Restricted placement

The nearcode section appears with a specified range (#x100000 . #x10a000). If the range is larger than the size of the section, the section is place somewhere inside the allowed range.

Fixed placement

The reset section is placed at the fixed address 0x00000000 by having only a given address, not a range.

Block rule

Most sections are created by the compiler or the assembler and passed to the linker in the object file. It is also possible to create a section to represent a memory block in the linker rules file. Such blocks are used for the stack and the heap.

A block rule is defined among the memory rules. It has a name which is its section name and a size:

(define memories
  '((memory flash (address (#x8000 . #xffff))
    ...
    (block stack  (size #x800))
    (block heap   (size #x800))

You can omit mentioning blocks as the linker will attempt to create them automatically if left out. They are typically used for dynamic memory areas, such as heap and stack. There are some of these built in and the desired size can be specified on the command line. There is also a default size that the linker will fall back if it is not specified.

Stack size

The stack keeps track of the dynamic execution state, which includes how to return from function calls and local variables that are not held in registers. It also provides temporary storage during execution. The size needed depends on the application and the stack size can be defined in the linker rules files using a block rule:

(define memories
  '((memory RAM (address (#x210000 . #x23ffff))
            (section stack sstack zfar far heap))
    (block stack (size #x1000))
    (block sstack (size #x200))
   ))

Here the user stack size is set to 1000 hexadecimal (4096 bytes decimal) and is bound to the memory area named RAM.

The supervisor stack sstack is also needed on the 68000 and is here given the size 200 hexadecimal (512 bytes decimal) and is also bound to a memory area named RAM.

Note

You can override a stack size defined in the linker rules file using the --stack-size command-line option. This is often the preferred method.

Heap size

The heap is the area from which memory is obtained when using library functions such as malloc(). You only need to define a heap if your application actually uses functions such as malloc() or calloc(). It is perfectly fine for an application to run without a heap, and it may in some cases be desirable to do so.

If you decide to use a heap in your application you need to define its size in the linker rules file using a block rule:

(define memories
  '((memory RAM (address (#x210000 . #x23ffff))
            (section stack sstack zfar far heap))
    (block stack (size #x1000))          ; user stack
    (block sstack (size #x200))          ; supervisor stack
    (block heap (size #x4000))           ; heap
   ))

Here the heap size is set to 2000 hexadecimal (8192 bytes decimal) and is bound to a memory area named RAM. The text following a semicolon is a comment.

Note

You can override or define the heap size in the linker rules file using the --heap-size command-line option. This is often the preferred method.

Base address

A base address is a memory region permanently pointed to by a 68000 CPU register. Using base addressing for object access is typically more efficient due to optimized addressing modes on the 68000.

Defined in the linker rules file via a base-address rule, it works by associating a special symbol with the actual memory area it covers.

The 68000 defines one base addresses that describes a Near address area which allows for somewhat shorter instructions compared to full 32 bit addressing.

The A4 address register is reserved to point to this area. As the 68000 has eight address registers and one is also the stack pointer, it leaves six address registers for general purpose use which is still quite generous.

The Near address area pointed to be the A4 register is a single 64K bytes large memory area. This area is used in the Small data model for static and global data objects. In addition to this, you also have the stack and heap which are not allocated from this memory range.

The base address is defined in the linker rules file in the following way:

(define memories
  '(...
    (memory NearRAM (address (#x200000 . #x20ffff))
            (section znear))
    ...
    (base-address _NearBaseAddress NearRAM    #x8000)
    ))

The _NearBaseAddress symbol is tied to the NearRAM memory using an offset of 8000 hexadecimal, meaning the base address is in the middle of the memory range. This is because the offset from the A4 base register is a signed 16 bit offset. Here it is given the address 208000 hexadecimal.

In both cases the C startup module takes care of setting up the A4 CPU register before the main() function is called.

Placement groups

ELF output format limitations prevent mixing section types within a single memory. However, placement groups allow flexible organization.

When an application changes, varying section sizes within a memory range can be cumbersome, requiring frequent adjustments to memory ranges. Placement groups resolve this by dynamically allocating within the overall parent memory address range.

A placement group acts as a sub-memory within a parent, each holding sections of a single type. Multiple placement groups of different types can exist within one parent memory. Sections are filled one at a time. Once a group is placed, the linker continues allocation from the next free address, maximizing memory utilization without manual range specification for each group.

You can define placement groups in the following way:

(define memories
  '(...
     (memory near-bank (address (#x10000 . #x1ffff))
             (placement-group near-bits (section near cnear))
             (placement-group near-nobits (section znear)))

In this example the near-bank memory contains two placement groups near-bits and near-nobits. The near-bits placement group contains two sections near and cnear. The near-nobits placement group has a single section znear which is a zero initialized BSS section.

Note

The use of near and cnear makes sense when compiling for a hosted environment where a writable near section and a read-only cnear section can be placed next to each other as both are loaded into system RAM memory. On a ROM based embedded system they would go into separate memories.

Note

The names near-bits and near-nobits have no special meaning to the linker.

23.9. Scatter

In some situations you have a memory bound to a given address range at runtime, but that is stored at a different address in the application image.

Examples of this are an overlay system, a banking system, or a ROM that is located at some address, but parts of it is copied to RAM at a different location.

The linker implements this using scatter-to which is a property that can be given to a memory:

(memory bankSlotRAM
        (address (#xa000 . #xbfff))
        (scatter-to RAM-banks)
        :generate-instances
        (section bankedcode))

In this case the bankSlotRAM memory has an address range A000-BFFF. Sections of type bankedcode are bound to it.

Using the scatter-to property, the entire memory is converted to a new section named RAM-banks. This section can be placed in another memory:

(memory bankedRAM (address (#x2000 . #x1fffff))
        (section RAM-banks))

The optional :generate-instances is useful when implementing an overlay system. It indicates that once the bankSlotRAM memory is full, a new empty instance can be generated to accommodate further bankedcode sections. Thus, memory is created on the fly and each instance is scattered to the bankedRAM memory.

If :generate-instances is not specified then only one instance of the memory is allowed.

Note

Relocations in the memory are done towards the runtime address, which is bankSlotRAM in the example above. This is the address area where the memory is intended to appear at runtime.

23.10. Linker list files

A list file can be generated from the linker using the --list-file (or -l) command-line option.

The list file is a valuable tool if you want to see how much memory your application actually needs. It can also answer questions about what objects are included from libraries, why they are included and where they are placed.

This is especially useful if want to understand how your application uses memory and can give insights to have it may be tuned.

As an example, consider the following example program:

#include <calypsi/stubs.h>

__task int main () {
  return 0;
}

This is intended to be a minimal program, but with debug support to allow the debugger to catch the call to exit().

If built and linked with the standard library and you specify the command-line options "-l --cross-reference --rtattr exit=simplified" you will get a list file which contains something like:

####################
#                  #
# Memories summary #
#                  #
####################

Name               Range             Size     Used     Checksum  Largest unallocated
------------------------------------------------------------------------------------
Vector             00000000-000003ff 00000400   0.8%   none      000003f8
flash              00100000-001fffff 00100000   0.0%   none      000fffb2
NearRAM            00200000-0020ffff 00010000  12.5%   none      0000e000
  > NearRAM-NoBits 00200000-00201fff 00002000 100.0%   none      0000e000


####################
#                  #
# Sections summary #
#                  #
####################

Name   Range              Size     Memory         Fragments
-----------------------------------------------------------
reset  00000000-00000007  00000008 Vector         1
code   00100000-0010004d  0000004e flash          7
sstack 00200000-00200fff  00001000 NearRAM-NoBits 1
stack  00201000-00201fff  00001000 NearRAM-NoBits 1


###################
#                 #
# Placement rules #
#                 #
###################

Name             Address range     Key
----------------------------------------------------------------------
NearRAM          00200000-0020ffff DATA
  NearRAM-NoBits 00200000-0020ffff BSS
    > stack
    > sstack
Vector           00000000-000003ff
  > (reset 00000000)
flash            00100000-001fffff TEXT and RODATA
  > code

Name   Size     Align
----------------------
stack  00001000 2
sstack 00001000 2

Name             Memory  Offset
----------------------------------
_NearBaseAddress NearRAM 00008000

################
#              #
# Object files #
#              #
################

Unit Filename          Archive
-----------------------------------------
  0  main.o            -
          >  code 00000004
  2  cstartup.o        clib-68000-lc-sd.a
          # picked based on cstartup=normal (built-in default)
          >  code  0000002e
          >  reset 00000008
  5  simplified_exit.o clib-68000-lc-sd.a
          # picked based on exit=simplified (specified on the command line)
          >  code 00000008
  7  debug_exit.o      clib-68000-lc-sd.a
          # picked based on stubs=semi_hosted (due to configured to use semi-hosting)
          >  code 00000012
  8  debug_break.o     clib-68000-lc-sd.a
          # picked based on stubs=semi_hosted (due to configured to use semi-hosting)
          >  code 00000002

###################
#                 #
# Cross reference #
#                 #
###################

Section 'sstack'  placed at address 00200000-00200fff of size 00001000
(linker generated)

Section 'stack'  placed at address 00201000-00201fff of size 00001000
(linker generated)

__program_root_section in section 'reset'
 placed at address 00000000-00000007 of size 00000008
(cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 8)
    Defines:
        __program_root_section = 00000000
    References:
        .sectionEnd(sstack)
        __program_start in (cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 2)

__program_start in section 'code'
 placed at address 00100000-0010001b of size 0000001c
(cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 2)
    Defines:
        __program_start = 00100000
    References:
        _NearBaseAddress
        .sectionEnd(stack)
        __low_level_init in (cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 7)
    Referenced from:
        __program_root_section (cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 8)

Section 'code'  placed at address 0010001c-00100029 of size 0000000e
(cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 6)
    References:
        exit in (simplified_exit.o (from clib-68000-lc-sd.a) unit 5 section index 2)
        main in (main.o unit 0 section index 2)

_Stub_exit in section 'code'
 placed at address 0010002a-0010003b of size 00000012
(debug_exit.o (from clib-68000-lc-sd.a) unit 7 section index 2)
    Defines:
        _Stub_exit = 0010002a
    References:
        _DebugBreak in (debug_break.o (from clib-68000-lc-sd.a) unit 8 section index 2)
    Referenced from:
        exit (simplified_exit.o (from clib-68000-lc-sd.a) unit 5 section index 2)

exit in section 'code'  placed at address 0010003c-00100043 of size 00000008
(simplified_exit.o (from clib-68000-lc-sd.a) unit 5 section index 2)
    Defines:
        exit = 0010003c
    References:
        _Stub_exit in (debug_exit.o (from clib-68000-lc-sd.a) unit 7 section index 2)
    Referenced from:
        (cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 6)

__low_level_init in section 'code'
 placed at address 00100044-00100047 of size 00000004
(cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 7)
    Defines:
        __low_level_init = 00100044
    Referenced from:
        __program_start (cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 2)

main in section 'code'  placed at address 00100048-0010004b of size 00000004
(main.o unit 0 section index 2)
    Defines:
        main = 00100048
    Referenced from:
        (cstartup.o (from clib-68000-lc-sd.a) unit 2 section index 6)

_DebugBreak in section 'code'
 placed at address 0010004c-0010004d of size 00000002
(debug_break.o (from clib-68000-lc-sd.a) unit 8 section index 2)
    Defines:
        _DebugBreak = 0010004c
    Referenced from:
        _Stub_exit (debug_exit.o (from clib-68000-lc-sd.a) unit 7 section index 2)

##########################
#                        #
# Memory sizes (decimal) #
#                        #
##########################

Executable       (Text):   86 bytes
Non-initialized        : 8192 bytes

The linker list file displays how section fragments are distributed across memories and the total allocated memory size.

The Memories summary area summarizes the application’s memories, including the size, usage, largest unallocated block, and an optional checksum of each memory.

The Sections summary area summarizes section placement and fragment counts.

The Object files area lists object files, their originating libraries (if any), and their section and overall size contributions.

The Cross reference area provides detailed information for each code segment, including its entry point, name, address range, size, defined symbols, referenced symbols, and referencing code segments. This offers full bi-directional reference information for all application code segments.

Finally, the Memory sizes area summarizes the total memory used. Note that memory amounts are given in decimal here; elsewhere in the list file hexadecimal numbers are used.

23.11. Output formats

Additional executable output format can be selected with the --output-format command-line option.

Note

The linker will always produce an ELF output which is the format used by the db68k debugger.

ELF/DWARF

This is the base output format of the executable file. It contains an ELF program image of the executable application. If you specify --debug all DWARF debugging information sections found in the object files are passed on to the final executable image. The output file has file extension .elf.

Intel hex

The Intel hex file format contains the output binary as ASCII text. Output files have the .hex extension.

Motorola S-record

This is the Motorola S-record, sometimes called SREC. The output binary is expressed in ASCII text form. The output file has file extension .srec.

The S-record format has variants: S19, S28, and S37, corresponding to 16, 24, and 32-bit addresses. Using these formats forces the linker to output in a specific address size. The output file extension used corresponds to the format variant choosen, .s19, .s28 or .s37.

Raw

The raw format represents program memory as a raw binary image file. Output files use the .raw file extension.

Note

In the default setting only one memory area can be emitted in Raw format. Multiple areas can be emitted by specifying the --raw-multiple-memories command-line option, this also has the effect of changing the name of the output file(s). When this option is active the output file names are based on the name of the memory areas in the .scm file.

23.12. More on linker rules

The linker rules file is a Scheme programming language source file, hence the .scm extension.

You do not need to be familiar with Scheme to specify linker rules, simply follow the examples to set things up.

The examples present a Scheme “program” with a single memories variable bound to a data structure. The linker reads the file with a Scheme interpreter, then examines the memories variable’s contents. This has two implications: a) the file’s syntax is Scheme-dictated, based on s-expressions; and b) more elaborate programs using Scheme macros are possible. generate the memory rules.

23.13. Command line options

This section details ln68k command-line options.

Options overview

If the linker is run without command-line arguments, it will indicate that object files are required:

$ ln68k
the linker requires some object files to work with (use --help for help)
Terminating due to errors

A more detailed help message can be requested with the --help option:

$ ln68k --help
Calypsi linker for Motorola 68000 version 5.16

Usage: ln68k [--version] [-o|--output-file OUTPUT-FILE] [-g|--debug]
             [--semi-hosted] [--no-data-init-table-section]
             [--override IDENTIFIER] ([--cross-reference] |
             [--no-cross-reference]) [--rtattr NAME=VALUE] [--verbose] [-l]
             [--list-file LIST-FILE] [--memories-expression EXPRESSION]
             [--program-root SYMBOL] [--root-symbol SYMBOL]
             [--program-start SYMBOL] [--copy-initialize SECTION]
             [--no-copy-initialize SECTION] [--no-automatic-placement-rules]
             [--raw-multiple-memories] [--no-merge-raw-memories]
             [--force-output] [--no-auto-libraries] [--cstartup VALUE]
             [--no-tree-shaking] [--output-format FORMAT] [--sstack-size SIZE]
             [--stack-size SIZE] [--heap-size SIZE] ([--hosted] | [--rom-code])
             [--core CORE] [--target TARGET] [--hunk-max-size SIZE] [FILE...]
  use 'ln68k --help' for detailed help

Available options:
  --version                Display version number
  -o,--output-file OUTPUT-FILE
                           Name of output file
  -g,--debug               Produce debugging information
  --semi-hosted            Enable debug stubs for semi-hosting
  --no-data-init-table-section
                           Do not generate any data_init_table section (mainly
                           useful for assembly projects)
  --override IDENTIFIER    Override symbol in archive library (treat it as weak)
  --cross-reference        Include cross reference and map information in the
                           list file (this is the default)
  --no-cross-reference     Do not include cross reference and map information in
                           the list file
  --rtattr NAME=VALUE      Specify runtime attribute to select specific
                           alternative from library (e.g. printf=float,
                           scanf=nofloat)
  --verbose                Generate more detailed output
  -l                       Generate a list file, defaults to 'ln68k.lst'
  --list-file LIST-FILE    Generate list file, using given name
  --memories-expression EXPRESSION
                           Expression that extracts the list of memory
                           descriptions from the .scm file, defaults to
                           'memories'
  --program-root SYMBOL    Program root point, defaults to
                           '__program_root_section'
  --root-symbol SYMBOL     Add a root symbol
  --program-start SYMBOL   Program start symbol, defaults to '__program_start'
  --copy-initialize SECTION
                           Override default and initialize this section by
                           copying
  --no-copy-initialize SECTION
                           Override default and do not initialize this section
                           by copying
  --no-automatic-placement-rules
                           Do not add rules to a .scm linker rules file
  --raw-multiple-memories  Allow multiple memories for raw style output format
  --no-merge-raw-memories  Never attempt to merge raw memories
  --force-output           Ignore (some) errors and attempt to generate output
  --no-auto-libraries      Do not automatically add runtime libraries
  --cstartup VALUE         Define the C startup to be used, synonym to '--rtattr
                           cstartup=VALUE'
  --no-tree-shaking        Do not perform tree shaking and keep unused section
                           fragment in output
  --output-format FORMAT   Format, one of 'intel-hex', 'S-record', 'S19', 'S28',
                           'S37', 'raw', 'hunk', 'tos' or 'pgz' (in addition to
                           the ELF/DWARF output)
  --sstack-size SIZE       Supervisor stack size override (overrides size
                           defined in the .scm file)
  --stack-size SIZE        Stack size override (overrides size defined in the
                           .scm file)
  --heap-size SIZE         Heap size override (size normally defined in the .scm
                           file)
  --hosted                 Initialize data sections in place by loading
                           executable (hosted enviroment)
  --rom-code               Run from ROM/Flash, initialize data sections by
                           copying from ROM
  --core CORE              Core, one of '68000', '68010', '68020', '68030',
                           '68040', '68060' or '68080' (defaults to '68000')
  --target TARGET          Target system, one of 'Amiga', 'A2560U', 'A2560K' or
                           'TOS' (defaults to embedded/ROM use, if omitted)
  --hunk-max-size SIZE     Largest Hunk size allowed, defaults to 256K (or
                           largest single object in the application)
  -h,--help                Show this help text

Options in detail

--output-file, -o

Use this option to specify the name of the output executable file. If not given, the output file is aout with a file extension based on the format of the file, e.g. aout.elf or aout.hex.

--debug

Merge DWARF symbolic debugging information from the object file and output that in ELF executable file.

-g

Synonym for --debug.

--semi-hosted

Enable debug stubs for semi-hosting support. The program is linked with stubs for semi-hosting in the debugger. This allows the debugger to support standard I/O on behalf of the target and various other low level operations, such as capture exit() and implement assert().

--no-data-init-table-section

Do not create any data initialization sections. This is mainly intended for assembly projects, but it can also be used for C if you do not want any initialization of static data objects to be done.

--override

Treat specified symbol as weak when taken from a library. This can be used if you want to replace a specific routine in a library with your own variant.

--cross-reference

Also include cross reference information in the list file. This is enabled by default.

--no-cross-reference

Do not include cross reference information in the list file.

--rtattr NAME=VALUE

Used to control selection of a specific variant of a module that exists in multiple weak versions. A typical situation is to select a custom C startup module or other variant of exit().

It can also be used to override the automatic selection of printf() and scanf() formatter capability.

--cstartup=VALUE

Select a specific custom C startup module to be used. This is a slightly easier way than using the --rtattr option.

--verbose

Ask the linker to be more talkative. Mainly useful in cases where you run into errors. This option will generate a lot more information about the situation.

-l

Generate a list file. The name used is the name of the input file (ignoring any directory path) with a .lst file extension. See also --list-file.

--list-file

Generate a list file. The name of the list file is given as argument to this option. See also -l to generate a list file based on the source filename.

--memories-expression

This is the expression used to extract the memory description after reading a .scm rules file. This is set to memories by default and that should suffice in almost every situation.

--program-root

This is the root of the application and everything referenced from this section, directly or indirectly is part of the application.

If you are building a normal C project you should not change this.

--root-symbol

Add a root symbol that is regarded as something to always include in the build. This can be used to override a specific symbol, or if you have a root inside a library as they are otherwise ignored.

--program-start

This symbol defines the first actual executable instruction in the program. This is used as the entry point which is defined in some output formats.

If you are building a normal C project you should not change this.

--output-format

With this option you specify an additional file format for the produced executable application. An ELF executable is always produced.

--raw-multiple-memories

This option enables output to multiple files in the Raw file format. By default only one area is allowed and an error will result if the application uses more than one program area. Specifying this option will also result in different output filenames that are based on the memory areas in the .scm file.

--no-merge-raw-memories

This option controls whether adjacent memories are merged in the RAW output format.

--heap-size

The heap size can be defined in the linker control file (.scm). This option makes it possible to override the heap size and is useful if you use a common linker control file and want to avoid modifying the .scm file.

Note

The heap is completely removed if you set the size to 0. If the application tries to use the heap in that situation, the linker will complain that the heap section is undefined.

--sstack-size

The supervisor stack size is normally defined in the linker control file (.scm). This option makes it possible to override the supervisor stack size and is useful if you use a common linker control file and want to avoid modifying the file.

--stack-size

The stack size can be defined in the linker control file (.scm). This option makes it possible to override the stack size and is useful if you use a common linker control file and want to avoid modifying the file.

--hosted

Specifies a hosted environment. Data object initialization by copying from ROM is omitted; instead, the application is loaded into memory, and initialized data objects receive values during the load action.

--rom-code

This is the opposite of --hosted. Data objects gets initialized by copying from ROM. This is the default and allows the application to be written to ROM or flash and started by turning the device on.

--copy-initialize

This option takes a data section name as argument. You can use this option to override the default of whether the section is initializated by copying or by loading.

This option can be used together with the --hosted option to make an exception for a given data section and have that initialized by copying. It can be used when the load mechanism is unable to load directly into a memory area. You can specify this option multiple times.

--no-copy-initialize

This option takes a data section name as argument. It is used to override the default of whether the section is initializated by copying or by loading. This option mostly exists for symmetry reasons. You can specify this option multiple times.

--core

Specifies the core used, currently 68000, 68010, 68020, 68030, 68040, 68060 and 68080 are supported. This is provided mainly for completeness and symmetry with the other tools. It has no practical meaning to the linker at the moment.

--target

Specifies a certain target system. Using this option may affect the setting of --hosted versus --rom-code and is preferred if the target system used is supported by this option.

--no-automatic-placement-rules

Do not attempt to add any rules, like section placments or missing blocks to a linker rules file. This is useful if you want to state everything explicitly, as it will result in errors if the linker rules (.scm) file is incomplete. In most cases you want to allow the linker to complete a partial linker rules file and this option should not be specified in such case.

--force-output

Ignore certain errors and allow output to be generated anyway. This is mainly intended for getting a list file to help understanding the cause of errors for troubleshooting.

--no-auto-libraries

The linker will attempt to pick a suitable C library based on the input. This command-line option disables this mechanism. If given you will need to specify the C library explicitly on the command line.