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:
Objects are selected for inclusion in the application.
Objects are placed at memory addresses by the linker following placement rules.
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.
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 |
|---|---|
|
This roughly corresponds to |
|
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. |
|
This can be used in a hosted environment
when the application is loaded into a single
RAM memory.
It combines allocation of |
|
This type describes constants that are stored in read-only memory. |
|
Initialized data area. Only exists when building for hosted use. |
|
This type describes executable code. |
|
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.