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:

$ ln65816 [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:

$ ln65816 --debug file.o clib-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:

$ ln65816 --version
Calypsi linker for 65816 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.

Minimal rules

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

(define memories
  '((memory flash (address (#x8000 . #xffff)) (type ROM))
    (memory RAM   (address (#x0100 . #x7fff)) (type RAM))
    ))

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 (#x8000 . #xffff))
            (section code switch idata izpage
                     cdata data_init_table (reset #xfffc)))
    (memory directPage
            (address (#x0 . #xff))
            (section registers zzpage zpage))
    (memory RAM (address (#x0100 . #x7fff))
            (section stack heap data zdata))
    (block stack  (size #x800))               ; machine stack size
    (block heap   (size #x800))               ; heap size
    ))

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 stack section appears with a specified range ((#x100 . #x1ff)). 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 0xfffc 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 LoRAM (address (#x4000 . #xefff))
            (section stack data zdata))
    (block stack (size #x1000))
   ))

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

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 LoRAM (address (#x4000 . #xefff))
            (section stack heap data zdata))
    (block stack (size #x1000))
    (block heap  (size #x2000))
   ))

Here the heap size is set to 2000 hexadecimal (8192 bytes decimal) and is bound to a memory area named LoRAM.

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 65816 CPU register. Using base addressing for object access is typically more efficient due to optimized addressing modes on the 65816.

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 65816 defines two base addresses, one for the tiny area which corresponds to the direct page and one for the bank register which describes a single 64K bank.

They are defined in the linker rules file in the following way:

(define memories
  '(...
    (memory NearRAM (address (#x20000 . #x2ffff))
            (section znear))
    (memory DirectPage (address (#xf000 . #xf0ff))
            (section (registers ztiny)))
    ...
    (base-address _DirectPageStart DirectPage 0)
    (base-address _NearBaseAddress NearRAM    0)
    ))

The _DirectPageStart symbol is tied to the DirectPage memory using an offset of zero (meaning start of the memory area). here it is given the address value 00f000.

The _NearBaseAddress symbol is tied to the NearRAM memory using an offset of zero (meaning start of the memory area). Here it is given the address 20000 hexadecimal, which is bank 2.

In both cases the C startup module takes care of setting up the corresponding CPU registers 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
----------------------------------------------------------------------------
LoRAM-tiny       004000-0040ff 000100    7.8%  none      0000ec
LoRAM            004100-00efff 00af00    9.1%  none      009f00
  > LoRAM-nobits 004100-0050ff 001000  100.0%  none      009f00
LoCode           00f000-00ffe3 000fe4    0.9%  none      000fdc
  > LoCode-code  00f000-00f023 000024  100.0%  none      000fdc
LoCode-vector    00ffe4-00ffff 00001c    7.1%  none      000ffc
flash            010000-01ffff 010000    0.0%  none      00ffe5
NearRAM          020000-02ffff 010000    0.0%  none      010000
CompactCode      040000-04ffff 010000    0.0%  none      010000


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

Name      Range          Size    Memory        Fragments
--------------------------------------------------------
registers 004000-004013  000014  LoRAM-tiny    1
stack     004100-0050ff  001000  LoRAM-nobits  1
code      00f000-00f023  000024  LoCode-code   2
reset     00fffc-00fffd  000002  LoCode-vector 1
farcode   010000-01001a  00001b  flash         5


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

Name             Address range  Key
----------------------------------------------------------------------
CompactCode      040000-04ffff
  > compactcode
LoCode-vector    00ffe4-00ffff  Plain
  > (reset 00fffc)
LoCode           00f000-00ffe3  Plain
  LoCode-cbits   00f000-00ffe3  Plain and RODATA
  LoCode-code    00f000-00ffe3  PlainFunction and TEXT
    > code
LoRAM            004100-00efff  Plain
  LoRAM-nobits   004100-00efff  Plain and BSS
    > stack
  LoRAM-bits     004100-00efff  Plain and DATA
LoRAM-tiny       004000-0040ff  Tiny and BSS
  > registers
NearRAM          020000-02ffff  DATA
  NearRAM-NoBits 020000-02ffff  BSS
flash            010000-01ffff  TEXT and RODATA
  > farcode

Name  Size   Align
-------------------
stack 001000 no

Name             Memory     Offset
-----------------------------------
_DirectPageStart LoRAM-tiny 000000

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

Unit Filename          Archive
-----------------------------------
  0  main.o            -
          >  farcode 000004
  2  cstartup.o        clib-lc-sd.a
          # picked based on cstartup=normal (built-in default)
          >  code    000024
          >  farcode 000001
          >  reset   000002
  4  simplified_exit.o clib-lc-sd.a
          # picked based on exit=simplified (specified on the command line)
          >  farcode 000005
  6  debug_exit.o      clib-lc-sd.a
          # picked based on stubs=semi_hosted (due to configured to use semi-hosting)
          >  farcode 000010
  7  debug_break.o     clib-lc-sd.a
          # picked based on stubs=semi_hosted (due to configured to use semi-hosting)
          >  farcode 000001
  8  pseudoRegisters.o clib-lc-sd.a
          >  registers 000014

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

__program_start in section 'code'
 placed at address 00f000-00f018 of size 000019
(cstartup.o (from clib-lc-sd.a) unit 2 section index 2)
    Defines:
        __program_start = 00f000
    References:
        _DirectPageStart
        .sectionEnd(stack)
        _Vfp in (pseudoRegisters.o (from clib-lc-sd.a) unit 8 section index 2)
        __low_level_init in (cstartup.o (from clib-lc-sd.a) unit 2 section index 8)
    Referenced from:
        __program_root_section (cstartup.o (from clib-lc-sd.a) unit 2 section index 7)

Section 'code'  placed at address 00f019-00f023 of size 00000b
(cstartup.o (from clib-lc-sd.a) unit 2 section index 6)
    References:
        exit in (simplified_exit.o (from clib-lc-sd.a) unit 4 section index 2)
        main in (main.o unit 0 section index 2)

__program_root_section in section 'reset'
 placed at address 00fffc-00fffd of size 000002
(cstartup.o (from clib-lc-sd.a) unit 2 section index 7)
    Defines:
        __program_root_section = 00fffc
    References:
        __program_start in (cstartup.o (from clib-lc-sd.a) unit 2 section index 2)

Section 'stack'  placed at address 004100-0050ff of size 001000
(linker generated)

_Dp in section 'registers'  placed at address 004000-004013 of size 000014
(pseudoRegisters.o (from clib-lc-sd.a) unit 8 section index 2)
    Defines:
        _Vfp = 004010
        _Dp = 004000
    Referenced from:
        __program_start (cstartup.o (from clib-lc-sd.a) unit 2 section index 2)
        _Stub_exit (debug_exit.o (from clib-lc-sd.a) unit 6 section index 2)

_Stub_exit in section 'farcode'  placed at address 010000-01000f of size 000010
(debug_exit.o (from clib-lc-sd.a) unit 6 section index 2)
    Defines:
        _Stub_exit = 010000
    References:
        _DebugBreak in (debug_break.o (from clib-lc-sd.a) unit 7 section index 2)
        _Dp in (pseudoRegisters.o (from clib-lc-sd.a) unit 8 section index 2)
    Referenced from:
        exit (simplified_exit.o (from clib-lc-sd.a) unit 4 section index 2)

exit in section 'farcode'  placed at address 010010-010014 of size 000005
(simplified_exit.o (from clib-lc-sd.a) unit 4 section index 2)
    Defines:
        exit = 010010
    References:
        _Stub_exit in (debug_exit.o (from clib-lc-sd.a) unit 6 section index 2)
    Referenced from:
        (cstartup.o (from clib-lc-sd.a) unit 2 section index 6)

main in section 'farcode'  placed at address 010015-010018 of size 000004
(main.o unit 0 section index 2)
    Defines:
        main = 010015
    Referenced from:
        (cstartup.o (from clib-lc-sd.a) unit 2 section index 6)

_DebugBreak in section 'farcode'
 placed at address 010019-010019 of size 000001
(debug_break.o (from clib-lc-sd.a) unit 7 section index 2)
    Defines:
        _DebugBreak = 010019
    Referenced from:
        _Stub_exit (debug_exit.o (from clib-lc-sd.a) unit 6 section index 2)

__low_level_init in section 'farcode'
 placed at address 01001a-01001a of size 000001
(cstartup.o (from clib-lc-sd.a) unit 2 section index 8)
    Defines:
        __low_level_init = 01001a
    Referenced from:
        __program_start (cstartup.o (from clib-lc-sd.a) unit 2 section index 2)

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

Executable       (Text):   65 bytes
Non-initialized        : 4116 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 db65816 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 ln65816 command-line options.

Options overview

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

$ ln65816
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:

$ ln65816 --help
Calypsi linker for 65816 version 5.16

Usage: ln65816 [--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] [--stack-size SIZE]
               [--heap-size SIZE] ([--hosted] | [--rom-code])
               [--initialize-large-data] [--core CORE] [--target TARGET]
               [FILE...]
  use 'ln65816 --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 'ln65816.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', 'pgz' or 'prg' (in addition to the
                           ELF/DWARF output)
  --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
  --initialize-large-data  Enable initialization of data areas that can span
                           over 64K boundaries
  --core CORE              Core, one of '65816' (defaults to '65816')
  --target TARGET          Target system, one of 'C256', 'F256' or 'SNES'
                           (defaults to embedded/ROM use, if omitted)
  -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

The linker will attempt to merge memories when emitting in the Commodore PRG format for memories in the first bank (address 0x0000-0xffff). This is to generate as few memories as possible due to limitations in the PRG format. You can avoid this automatic merging by specifying the --no-merge-raw-memories command-line option. This option also 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.

--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. 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.

--initialize-large-data

Data initialization is limited to Far objects which means that they cannot be allocated across 64K address banks. If you have custom data objects, e.g. graphics data with such needs, you can use this option.

When enabled two things happens. The data initializer table the is generated by the linker will use 32-bit size instead of 16-bit. The runtime attribute initialize is given the value "large" (rather than "normal" which is default). The result is that the linker will use a different data initialization module that can handle the larger initialization.