Skip to content
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b8f699f
Separate linker scripts out into include files
will-v-pi Dec 1, 2025
6dc06e6
Add customisable heap location, with pico_set_linker_script_var function
will-v-pi Dec 1, 2025
727cabd
Add kitchen sink test of custom linker scripts
will-v-pi Dec 1, 2025
3a83dc7
Separate out rp2_common and platform-specific linker script sections
will-v-pi Dec 2, 2025
4b1a3ec
More de-duplication
will-v-pi Dec 2, 2025
ae97a22
Make overriding ram locations simpler
will-v-pi Dec 2, 2025
3811e67
Make it possible to reference default locations in pico_set_linker_sc…
will-v-pi Dec 4, 2025
a20f86a
Add pico_add_linker_script_override_path to make overriding individua…
will-v-pi Feb 11, 2026
6bd9e5b
Add simple overlay demo
will-v-pi Feb 26, 2026
2bf8555
Add scripts to bazel build
will-v-pi Feb 27, 2026
fe2d56b
Move linker scripts out of crt0
will-v-pi Mar 6, 2026
1bd7089
Make rp2350 text sections the default
will-v-pi Mar 6, 2026
72adb67
Rename scripts include directories to standard_scripts and platform_s…
will-v-pi Mar 6, 2026
e47fe09
Move and add example to Bazel docs for changing linker scripts
will-v-pi Mar 6, 2026
9c0ed0c
Add cc_library load to new bazel files
will-v-pi Mar 6, 2026
e44bdea
Add excludes.ld files for default memmap
will-v-pi Mar 16, 2026
dc3a2e8
Put mem functions in SRAM
will-v-pi Mar 16, 2026
8b9d9ec
Rename standard_scripts and platform_scripts to script_include
will-v-pi Mar 19, 2026
91c3a9a
Move pico_platform_link stuff into pico_plaftorm
will-v-pi Mar 19, 2026
614f7f0
Remove rigidity from linker include paths
will-v-pi Mar 19, 2026
da23cf4
Rename all linker scripts intended to be included to .incl
will-v-pi Mar 19, 2026
780c05e
Separate into section_... files which do only contain one section, an…
will-v-pi Mar 19, 2026
2e7ca67
Add section_extra files to make adding extra sections simpler
will-v-pi Mar 19, 2026
4180427
Fix comments, and add some more extra files
will-v-pi Mar 19, 2026
c122bf7
Add generated override files - currently unused, but can be overridde…
will-v-pi Mar 19, 2026
ea8320b
pico_add_linker_script_override_path can now be called after target_l…
will-v-pi Mar 19, 2026
ad35ad8
Add extra post_platform_end sections
will-v-pi Mar 19, 2026
8e3aca5
review fixups
will-v-pi Mar 19, 2026
e9e9a09
Fix bazel PICO_DEFAULT_LINKER_SCRIPT comment
will-v-pi Mar 20, 2026
519544e
Add PICO_DEFAULT_BINARY_TYPE to Bazel
will-v-pi Mar 20, 2026
3f0615d
Fix PICO_DEFAULT_BINARY_TYPE descriptions
will-v-pi Mar 20, 2026
a26a42b
Add azel pico_set_binary_type transition, to allow setting binary typ…
will-v-pi Mar 25, 2026
df68b1e
Refactor bazel functionality following review
will-v-pi Mar 25, 2026
41fd36e
Add kitchen_sink_ram_section and kitchen_sink_simple_overlay tests to…
will-v-pi Mar 25, 2026
ea9b114
Some tidyups
will-v-pi Mar 25, 2026
c483e66
Update bazel/util/transition.bzl
will-v-pi Mar 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions bazel/config/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,22 @@ string_flag(
build_setting_default = "Debug",
)

# PICO_BAZEL_CONFIG: PICO_DEFAULT_LINKER_SCRIPT, [Bazel only] The library that provides a linker script to link into all binaries, default=//src/rp2_common/pico_crt0:default_linker_script, group=pico_standard_link
# PICO_BAZEL_CONFIG: PICO_DEFAULT_BINARY_TYPE, The default binary type to use, type=string, default=default, group=build
string_flag(
name = "PICO_DEFAULT_BINARY_TYPE",
build_setting_default = "default",
values = [
"default",
"no_flash",
"copy_to_ram",
"blocked_ram",
],
)

# PICO_BAZEL_CONFIG: PICO_DEFAULT_LINKER_SCRIPT, [Bazel only] The library that provides a linker script to link into all binaries, default=//src/rp2_common/pico_standard_link:default_linker_script, group=pico_standard_link
label_flag(
name = "PICO_DEFAULT_LINKER_SCRIPT",
build_setting_default = "//src/rp2_common/pico_crt0:default_linker_script",
build_setting_default = "//src/rp2_common/pico_standard_link:default_linker_script",
)

# PICO_BAZEL_CONFIG: PICO_NO_TARGET_NAME, Don't define PICO_TARGET_NAME, type=bool, default=0, group=build
Expand Down
15 changes: 15 additions & 0 deletions bazel/constraint/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,18 @@ config_setting(
name = "pico_compilation_no_fastbuild_args_set",
flag_values = {"//bazel/config:PICO_COMPILATION_NO_FASTBUILD_ARGS": "True"},
)

config_setting(
name = "pico_binary_type_no_flash",
flag_values = {"//bazel/config:PICO_DEFAULT_BINARY_TYPE": "no_flash"},
)

config_setting(
name = "pico_binary_type_copy_to_ram",
flag_values = {"//bazel/config:PICO_DEFAULT_BINARY_TYPE": "copy_to_ram"},
)

config_setting(
name = "pico_binary_type_blocked_ram",
flag_values = {"//bazel/config:PICO_DEFAULT_BINARY_TYPE": "blocked_ram"},
)
49 changes: 49 additions & 0 deletions bazel/util/pico_linker_scripts.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "use_cpp_toolchain")

def _include_linker_script_dir_impl(ctx):
link_include_dir = str(ctx.label.package)
depset_direct = ["-L" + str(link_include_dir)]
if len(ctx.files.use_scripts):
for script in ctx.files.use_scripts:
depset_direct.append("-T" + str(script.path))

linking_inputs = cc_common.create_linker_input(
owner = ctx.label,
user_link_flags = depset(
direct = depset_direct,
),
)
return [
CcInfo(linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = [linking_inputs]))),
]

include_linker_script_dir = rule(
implementation = _include_linker_script_dir_impl,
attrs = {
"use_scripts": attr.label_list(allow_files = [".ld"]),
},
toolchains = use_cpp_toolchain(),
fragments = ["cpp"],
)

def _use_linker_script_file_impl(ctx):
link_file = ctx.file.script.path

linking_inputs = cc_common.create_linker_input(
owner = ctx.label,
user_link_flags = depset(
direct = ["-T" + str(link_file)],
),
)
return [
CcInfo(linking_context = cc_common.create_linking_context(linker_inputs = depset(direct = [linking_inputs]))),
]

use_linker_script_file = rule(
implementation = _use_linker_script_file_impl,
attrs = {
"script": attr.label(mandatory = True, allow_single_file = [".ld"]),
},
toolchains = use_cpp_toolchain(),
fragments = ["cpp"],
)
5 changes: 5 additions & 0 deletions src/common/pico_base_headers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ cc_library(
"//bazel/constraint:rp2040": ["PICO_RP2040=1"],
"//bazel/constraint:rp2350": ["PICO_RP2350=1"],
"//conditions:default": [],
}) + select({
"//bazel/constraint:pico_binary_type_no_flash": ["PICO_NO_FLASH=1"],
"//bazel/constraint:pico_binary_type_copy_to_ram": ["PICO_COPY_TO_RAM=1"],
"//bazel/constraint:pico_binary_type_blocked_ram": ["PICO_USE_BLOCKED_RAM=1"],
"//conditions:default": [],
}),
)

Expand Down
97 changes: 97 additions & 0 deletions src/rp2040/pico_platform/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,100 @@ cc_library(
"//src/rp2_common/pico_standard_link",
],
)

load("//bazel/util:pico_linker_scripts.bzl", "use_linker_script_file")

exports_files(
[
"memmap_blocked_ram.ld",
"memmap_copy_to_ram.ld",
"memmap_default.ld",
"memmap_no_flash.ld",
],
)

use_linker_script_file(
name = "memmap_default_args",
script = "memmap_default.ld",
)

use_linker_script_file(
name = "memmap_blocked_ram_args",
script = "memmap_blocked_ram.ld",
)

use_linker_script_file(
name = "memmap_copy_to_ram_args",
script = "memmap_copy_to_ram.ld",
)

use_linker_script_file(
name = "memmap_no_flash_args",
script = "memmap_no_flash.ld",
)

cc_library(
name = "default_linker_script",
target_compatible_with = ["//bazel/constraint:rp2040"],
visibility = [
"//src/rp2_common/pico_standard_link:__pkg__",
],
deps = [
"//src/rp2_common/pico_crt0:no_warn_rwx_flag",
"//src/rp2040/pico_platform/script_include:rp2040_linker_scripts",
"//src/rp2_common/pico_standard_link/script_include:rp2_linker_scripts",
"//src/rp2_common/pico_standard_link:default_flash_region",
"memmap_default.ld",
"memmap_default_args",
],
)

# PICO_BUILD_DEFINE: PICO_USE_BLOCKED_RAM, whether this is a 'blocked_ram' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link
cc_library(
name = "blocked_ram_linker_script",
target_compatible_with = ["//bazel/constraint:rp2040"],
visibility = [
"//src/rp2_common/pico_standard_link:__pkg__",
],
deps = [
"//src/rp2_common/pico_crt0:no_warn_rwx_flag",
"//src/rp2040/pico_platform/script_include:rp2040_linker_scripts",
"//src/rp2_common/pico_standard_link/script_include:rp2_linker_scripts",
"//src/rp2_common/pico_standard_link:default_flash_region",
"memmap_blocked_ram.ld",
"memmap_blocked_ram_args",
],
)

# PICO_BUILD_DEFINE: PICO_COPY_TO_RAM, whether this is a 'copy_to_ram' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link
cc_library(
name = "copy_to_ram_linker_script",
target_compatible_with = ["//bazel/constraint:rp2040"],
visibility = [
"//src/rp2_common/pico_standard_link:__pkg__",
],
deps = [
"//src/rp2_common/pico_crt0:no_warn_rwx_flag",
"//src/rp2040/pico_platform/script_include:rp2040_linker_scripts",
"//src/rp2_common/pico_standard_link/script_include:rp2_linker_scripts",
"//src/rp2_common/pico_standard_link:default_flash_region",
"memmap_copy_to_ram.ld",
"memmap_copy_to_ram_args",
],
)

# PICO_BUILD_DEFINE: PICO_NO_FLASH, whether this is a 'no_flash' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link
cc_library(
name = "no_flash_linker_script",
target_compatible_with = ["//bazel/constraint:rp2040"],
visibility = [
"//src/rp2_common/pico_standard_link:__pkg__",
],
deps = [
"//src/rp2_common/pico_crt0:no_warn_rwx_flag",
"//src/rp2040/pico_platform/script_include:rp2040_linker_scripts",
"//src/rp2_common/pico_standard_link/script_include:rp2_linker_scripts",
"memmap_no_flash.ld",
"memmap_no_flash_args",
],
)
15 changes: 15 additions & 0 deletions src/rp2040/pico_platform/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ if (NOT TARGET pico_platform)
pico_platform_panic
pico_platform_sections
)

pico_register_common_scope_var(PICO_LINKER_SCRIPT_PATH)
if (NOT PICO_LINKER_SCRIPT_PATH)
set(PICO_LINKER_SCRIPT_PATH ${CMAKE_CURRENT_LIST_DIR})
endif()

pico_register_common_scope_var(PICO_LINKER_DEFAULT_LOCATIONS_PATH)
if (NOT PICO_LINKER_DEFAULT_LOCATIONS_PATH)
set(PICO_LINKER_DEFAULT_LOCATIONS_PATH ${CMAKE_CURRENT_LIST_DIR}/script_include/default_locations.ld)
endif()

pico_register_common_scope_var(PICO_LINKER_SCRIPT_INCLUDE_DIRS)
list(APPEND PICO_LINKER_SCRIPT_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}/script_include)

pico_promote_common_scope_vars()
endif()

function(pico_add_platform_library TARGET)
Expand Down
4 changes: 4 additions & 0 deletions src/rp2040/pico_platform/memmap_blocked_ram.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* Use blocked ram */
RAM_ORIGIN = 0x21000000;

INCLUDE "memmap_default.incl"
1 change: 1 addition & 0 deletions src/rp2040/pico_platform/memmap_copy_to_ram.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
INCLUDE "memmap_copy_to_ram.incl"
1 change: 1 addition & 0 deletions src/rp2040/pico_platform/memmap_default.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
INCLUDE "memmap_default.incl"
1 change: 1 addition & 0 deletions src/rp2040/pico_platform/memmap_no_flash.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
INCLUDE "memmap_no_flash.incl"
29 changes: 29 additions & 0 deletions src/rp2040/pico_platform/script_include/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")

package(default_visibility = ["//visibility:public"])

load("//bazel/util:pico_linker_scripts.bzl", "include_linker_script_dir")

filegroup(
name = "rp2040_linker_script_incls",
srcs = glob([
"*.incl",
]),
)

include_linker_script_dir(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd pitch an interface like this:

linker_script(
    name = "default_locations",
    library_paths = ["."],
    additional_linker_inputs = glob(["*.incl"]),
    srcs = [
        "default_locations.ld",
    ],
)

If that's too much of a pain to implement, feel free to punt and leave me an action item to clean it up.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all your comments - I've changed it to this interface:

linker_scripts(
    name = "rp2040_linker_script_includes",
    link_scripts = ["default_locations.ld"],
    include_scripts = glob(["*.incl"]),
)

I think this makes it clearer - the link_scripts are .ld files explicitly linked with -T, whereas include_scripts are .incl files which have their package directory included with -L and are added as additional inputs

I couldn't see how to implement library_paths = ["."], so instead opted for getting the paths from the .label.package of the include_scripts, which I think is good solution

name = "rp2040_linker_script_args",
use_scripts = ["default_locations.ld"],
)

cc_library(
name = "rp2040_linker_scripts",
target_compatible_with = ["//bazel/constraint:rp2040"],
deps = [
"default_locations.ld",
"rp2040_linker_script_args",
],
additional_linker_inputs = [
"rp2040_linker_script_incls",
],
)
8 changes: 8 additions & 0 deletions src/rp2040/pico_platform/script_include/default_locations.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
RAM_ORIGIN_DEFAULT = 0x20000000;
RAM_LENGTH_DEFAULT = 256k;
SCRATCH_X_ORIGIN_DEFAULT = 0x20040000;
SCRATCH_X_LENGTH_DEFAULT = 4k;
SCRATCH_Y_ORIGIN_DEFAULT = 0x20041000;
SCRATCH_Y_LENGTH_DEFAULT = 4k;
XIP_RAM_ORIGIN_DEFAULT = 0x15000000;
XIP_RAM_LENGTH_DEFAULT = 16k;
16 changes: 16 additions & 0 deletions src/rp2040/pico_platform/script_include/section_boot2.incl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
SECTIONS
{
/* Second stage bootloader is prepended to the image. It must be 256 bytes big
and checksummed. It is usually built by the boot_stage2 target
in the Raspberry Pi Pico SDK
*/

.boot2 : {
__boot2_start__ = .;
KEEP (*(.boot2))
__boot2_end__ = .;
} > TEXT_STORE

ASSERT(__boot2_end__ - __boot2_start__ == 256,
"ERROR: Pico second stage bootloader must be exactly 256 bytes in size for RP2040")
}
47 changes: 47 additions & 0 deletions src/rp2040/pico_platform/script_include/section_no_flash_text.incl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* Defines the following symbols for use by code:
__logical_binary_start
__binary_info_header_end
__embedded_block_end
__reset_start, __reset_end
*/

SECTIONS
{
/* Note in NO_FLASH builds the entry point for both the bootrom, and debugger
entry (ELF entry point), are *first* in the image, and the vector table
follows immediately afterward. This is because the bootrom enters RAM
binaries directly at their lowest address (preferring main RAM over XIP
cache-as-SRAM if both are used).
*/

.text : {
__logical_binary_start = .;
__reset_start = .;
KEEP (*(.reset))
__reset_end = .;
KEEP (*(.binary_info_header))
__binary_info_header_end = .;
KEEP (*(.embedded_block))
__embedded_block_end = .;
. = ALIGN(256);
KEEP (*(.vectors))
*(.text*)
. = ALIGN(4);
*(.init)
*(.fini)
/* Pull all c'tors into .text */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* Followed by destructors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)

*(.eh_frame*)
} > RAM
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SECTIONS
{
ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* This swaps section_boot2 and section_default_text, because RP2040 binaries must begin with boot2 */

INCLUDE "section_flash_begin.incl"
INCLUDE "section_boot2.incl"
INCLUDE "section_copy_to_ram_flashtext.incl"
INCLUDE "section_copy_to_ram_rodata.incl"
INCLUDE "sections_arm_ex.incl"
INCLUDE "section_binary_info.incl"
INCLUDE "section_ram_vector_table.incl"
INCLUDE "section_uninitialized_data.incl"
INCLUDE "section_copy_to_ram_text.incl"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* This swaps section_boot2 and section_default_text, because RP2040 binaries must begin with boot2 */

INCLUDE "section_flash_begin.incl"
INCLUDE "section_boot2.incl"
INCLUDE "section_default_text.incl"
INCLUDE "section_default_rodata.incl"
INCLUDE "sections_arm_ex.incl"
INCLUDE "section_binary_info.incl"
Loading
Loading