mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
fix(esp_system): enable linking with LLD on RISC-V targets
This commit is contained in:
@@ -35,10 +35,15 @@
|
||||
TEST_BUILD_OPTS_EXTRA: ""
|
||||
script:
|
||||
# CI specific options start from "--parallel-count xxx". could ignore when running locally
|
||||
#
|
||||
# In addition to the default sdkconfig.ci.* configs, build the
|
||||
# sdkconfig.ci_clang.* configs, which are meant only for the clang build
|
||||
# jobs (the generic build jobs would build them with the GCC toolchain).
|
||||
- run_cmd idf-build-apps build
|
||||
-p tools/test_apps/system/clang_build_test
|
||||
components/esp_security/test_apps/fault_assert_opt_check
|
||||
-t $IDF_TARGET
|
||||
--config-rules "sdkconfig.ci=default" "sdkconfig.ci.*=" "sdkconfig.ci_clang.*="
|
||||
--modified-components \"${MR_MODIFIED_COMPONENTS}\"
|
||||
--modified-files \"${MR_MODIFIED_FILES}\"
|
||||
$TEST_BUILD_OPTS_EXTRA
|
||||
|
||||
10
Kconfig
10
Kconfig
@@ -828,6 +828,16 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
result, consider enabling LTO selectively for specific components by
|
||||
adding the -flto=auto compile option to them.
|
||||
|
||||
config COMPILER_USE_LLD
|
||||
bool "Use LLD (ld.lld) as the linker"
|
||||
depends on IDF_TARGET_ARCH_RISCV
|
||||
default n
|
||||
help
|
||||
Link the application with the LLVM LLD linker instead of the GNU ld
|
||||
provided by the toolchain. The "ld.lld" binary must be available in
|
||||
PATH. Options not supported by LLD (e.g. --no-warn-rwx-segments)
|
||||
are omitted from the link automatically.
|
||||
|
||||
choice COMPILER_ORPHAN_SECTIONS
|
||||
prompt "Orphan sections handling"
|
||||
default COMPILER_ORPHAN_SECTIONS_ERROR
|
||||
|
||||
@@ -100,6 +100,8 @@ SECTIONS
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.*) .ctors))
|
||||
KEEP (*(SORT(.ctors.*)))
|
||||
KEEP (*(.ctors))
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*)))
|
||||
KEEP (*(.init_array))
|
||||
__init_array_end = ABSOLUTE(.);
|
||||
KEEP (*crtbegin.*(.dtors))
|
||||
KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors))
|
||||
@@ -153,6 +155,8 @@ SECTIONS
|
||||
*/
|
||||
/DISCARD/ : { *(.rela.*) }
|
||||
|
||||
#include "ld.elf.internal.sections"
|
||||
|
||||
/**
|
||||
* This section is not included in the binary image; it is only present in the ELF file.
|
||||
* It is used to keep certain symbols in the ELF file.
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
.note.GNU-stack 0 : { *(.note.GNU-stack) }
|
||||
|
||||
.riscv.attributes 0 : { *(.riscv.attributes) }
|
||||
#include "ld.elf.internal.sections"
|
||||
|
||||
/**
|
||||
* .xt.prop and .xt.lit sections will be used by the debugger and disassembler
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#endif // CONFIG_LIBC_NEWLIB
|
||||
|
||||
*(.fini)
|
||||
*(.fini_array)
|
||||
*(.fini_array.*)
|
||||
#if CONFIG_IDF_TARGET_ARCH_XTENSA
|
||||
*(.eh_frame_hdr)
|
||||
#endif // CONFIG_IDF_TARGET_ARCH_XTENSA
|
||||
|
||||
8
components/esp_system/ld/ld.elf.internal.sections
Normal file
8
components/esp_system/ld/ld.elf.internal.sections
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Linker-generated ELF sections. Must be explicitly placed in linker scripts
|
||||
* when using ld.lld with --orphan-handling=warn/error. GNU ld special-cases
|
||||
* these sections; ld.lld does not.
|
||||
*/
|
||||
.symtab 0 : { *(.symtab) }
|
||||
.strtab 0 : { *(.strtab) }
|
||||
.shstrtab 0 : { *(.shstrtab) }
|
||||
@@ -17,11 +17,16 @@
|
||||
#define ASTDBG_ISR _tee_ns_intr_handler
|
||||
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||
|
||||
.section .exception_vectors_table.text
|
||||
.section .exception_vectors_table.text, "ax"
|
||||
|
||||
/* Prevent the compiler from generating 2-byte instruction in the vector tables */
|
||||
.option push
|
||||
.option norvc
|
||||
/* The vector tables have a fixed layout, so keep linker relaxation from
|
||||
* touching them: with relaxation enabled the assembler emits the .balign
|
||||
* padding as R_RISCV_ALIGN-managed bytes, of which GNU ld may retain more
|
||||
* than the exact amount, changing the table size between builds. */
|
||||
.option norelax
|
||||
|
||||
/**
|
||||
* Non-hardware vectored interrupt entry. MTVEC CSR points here.
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
|
||||
.comment 0 : { *(.comment) }
|
||||
.note.GNU-stack 0: { *(.note.GNU-stack) }
|
||||
#include "ld.elf.internal.sections"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ARCH_RISCV
|
||||
.riscv.attributes 0: { *(.riscv.attributes) }
|
||||
@@ -70,5 +71,18 @@
|
||||
*/
|
||||
*(.rela.*)
|
||||
*(.got .got.plt) /* TODO: GCC-382 */
|
||||
|
||||
/**
|
||||
* GNU ld removes them via --gc-sections; LLD treats them as GC roots,
|
||||
* so they must be discarded explicitly to not trip --orphan-handling=error.
|
||||
*/
|
||||
*(.init)
|
||||
*(.init_array)
|
||||
*(.init_array.*)
|
||||
*(.fini)
|
||||
*(.fini_array)
|
||||
*(.fini_array.*)
|
||||
*(.eh_frame_hdr)
|
||||
*(.eh_frame)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,11 +18,13 @@ target_linker_script(${COMPONENT_LIB} INTERFACE "${heap_dir}/port/${target}/ld/$
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/ld")
|
||||
|
||||
idf_component_get_property(esp_system_dir esp_system COMPONENT_DIR)
|
||||
|
||||
# Preprocess esp_tee.ld.in linker script to include configuration, becomes esp_tee.ld
|
||||
add_custom_command(
|
||||
OUTPUT ${ld_output}
|
||||
COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o ${ld_output} -I ${config_dir}
|
||||
-I "${CMAKE_CURRENT_LIST_DIR}" ${ld_input}
|
||||
-I "${CMAKE_CURRENT_LIST_DIR}" -I "${esp_system_dir}/ld" ${ld_input}
|
||||
MAIN_DEPENDENCY ${ld_input}
|
||||
DEPENDS ${sdkconfig_header}
|
||||
COMMENT "Generating esp_tee.ld linker script..."
|
||||
|
||||
@@ -29,11 +29,16 @@
|
||||
.global _interrupt_handler
|
||||
.global _panic_handler
|
||||
|
||||
.section .exception_vectors_table.text
|
||||
.section .exception_vectors_table.text, "ax"
|
||||
|
||||
/* Prevent the compiler from generating 2-byte instruction in the vector tables */
|
||||
.option push
|
||||
.option norvc
|
||||
/* The vector tables have a fixed layout, so keep linker relaxation from
|
||||
* touching them: with relaxation enabled the assembler emits the .balign
|
||||
* padding as R_RISCV_ALIGN-managed bytes, of which GNU ld may retain more
|
||||
* than the exact amount, changing the table size between builds. */
|
||||
.option norelax
|
||||
|
||||
/**
|
||||
* Non-hardware vectored interrupt entry. MTVEC CSR points here.
|
||||
|
||||
@@ -1053,8 +1053,42 @@ macro(project project_name)
|
||||
target_link_options(${project_elf} PRIVATE "-Wl,--defsym=IDF_TARGET_${idf_target}=0")
|
||||
# Enable map file output
|
||||
target_link_options(${project_elf} PRIVATE "-Wl,--Map=${mapfile}")
|
||||
if(CONFIG_COMPILER_USE_LLD)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
# The last --ld-path on the link line takes precedence over the
|
||||
# one set in the toolchain file, selecting LLD for the link.
|
||||
# The bare name is looked up in PATH.
|
||||
target_link_options(${project_elf} PRIVATE "--ld-path=ld.lld")
|
||||
else()
|
||||
# GCC has no --ld-path; -fuse-ld=lld makes the driver search
|
||||
# its search paths and PATH for a binary named "ld.lld".
|
||||
target_link_options(${project_elf} PRIVATE "-fuse-ld=lld")
|
||||
endif()
|
||||
# Bare-metal images have no dynamic loader, so PT_GNU_RELRO is
|
||||
# meaningless. LLD enables relro by default and errors out when
|
||||
# relro sections (e.g. TLS .flash.tdata) are not contiguous in the
|
||||
# IDF linker scripts, so disable it.
|
||||
target_link_options(${project_elf} PRIVATE "-Wl,-z,norelro")
|
||||
# Some targets (e.g. esp32s3) use NOLOAD dummy sections that
|
||||
# deliberately overlap other sections' address ranges, because two
|
||||
# memory regions alias the same bus address space. GNU ld skips
|
||||
# NOBITS sections in its overlap check; LLD does not, so disable
|
||||
# the check there.
|
||||
target_link_options(${project_elf} PRIVATE "-Wl,--no-check-sections")
|
||||
set(linker_binary "ld.lld")
|
||||
else()
|
||||
set(linker_binary "${CMAKE_LINKER}")
|
||||
endif()
|
||||
# Report which linker the link will use, with its version banner
|
||||
execute_process(COMMAND ${linker_binary} "--version"
|
||||
OUTPUT_VARIABLE linker_version
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(REGEX REPLACE "\n.*" "" linker_version "${linker_version}")
|
||||
message(STATUS "Linker: ${linker_binary} (${linker_version})")
|
||||
unset(linker_version)
|
||||
# Check if linker supports --no-warn-rwx-segments
|
||||
execute_process(COMMAND ${CMAKE_LINKER} "--no-warn-rwx-segments" "--version"
|
||||
execute_process(COMMAND ${linker_binary} "--no-warn-rwx-segments" "--version"
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_QUIET
|
||||
ERROR_QUIET)
|
||||
@@ -1069,6 +1103,7 @@ macro(project project_name)
|
||||
# Throw error if orphan sections are found
|
||||
target_link_options(${project_elf} PRIVATE "-Wl,--orphan-handling=error")
|
||||
endif()
|
||||
unset(linker_binary)
|
||||
unset(idf_target)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -225,7 +225,10 @@ function(preprocess_linker_file cmake_target script_in output_var preserve_suffi
|
||||
if(script_parent_name STREQUAL idf_target)
|
||||
# Add "../.." directory to include path (e.g. for esp_system component)
|
||||
get_filename_component(dir_to_include "${script_parent_dir}" DIRECTORY)
|
||||
set(extra_cflags "-I\"${dir_to_include}\"")
|
||||
# Add esp_system/ld directory to include path for the shared linker
|
||||
# script fragments (e.g. ld.elf.internal.sections)
|
||||
idf_component_get_property(esp_system_dir esp_system COMPONENT_DIR)
|
||||
set(extra_cflags "-I\"${dir_to_include}\" -I\"${esp_system_dir}/ld\"")
|
||||
endif()
|
||||
|
||||
# Keep comments (-C): historical behavior for cmakev1 linker scripts. It was
|
||||
|
||||
@@ -512,8 +512,42 @@ function(__init_project_configuration)
|
||||
string(TOUPPER ${target_upper} target_upper)
|
||||
# Add this symbol as a hint for esp_idf_size to guess the target name
|
||||
list(APPEND link_options "-Wl,--defsym=IDF_TARGET_${target_upper}=0")
|
||||
if(CONFIG_COMPILER_USE_LLD)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
# The last --ld-path on the link line takes precedence over the
|
||||
# one set in the toolchain file, selecting LLD for the link.
|
||||
# The bare name is looked up in PATH.
|
||||
list(APPEND link_options "--ld-path=ld.lld")
|
||||
else()
|
||||
# GCC has no --ld-path; -fuse-ld=lld makes the driver search
|
||||
# its search paths and PATH for a binary named "ld.lld".
|
||||
list(APPEND link_options "-fuse-ld=lld")
|
||||
endif()
|
||||
# Bare-metal images have no dynamic loader, so PT_GNU_RELRO is
|
||||
# meaningless. LLD enables relro by default and errors out when
|
||||
# relro sections (e.g. TLS .flash.tdata) are not contiguous in the
|
||||
# IDF linker scripts, so disable it.
|
||||
list(APPEND link_options "-Wl,-z,norelro")
|
||||
# Some targets (e.g. esp32s3) use NOLOAD dummy sections that
|
||||
# deliberately overlap other sections' address ranges, because two
|
||||
# memory regions alias the same bus address space. GNU ld skips
|
||||
# NOBITS sections in its overlap check; LLD does not, so disable
|
||||
# the check there.
|
||||
list(APPEND link_options "-Wl,--no-check-sections")
|
||||
set(linker_binary "ld.lld")
|
||||
else()
|
||||
set(linker_binary "${CMAKE_LINKER}")
|
||||
endif()
|
||||
# Report which linker the link will use, with its version banner
|
||||
execute_process(COMMAND ${linker_binary} "-v"
|
||||
OUTPUT_VARIABLE linker_version
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(REGEX REPLACE "\n.*" "" linker_version "${linker_version}")
|
||||
message(STATUS "Linker: ${linker_binary} (${linker_version})")
|
||||
unset(linker_version)
|
||||
# Check if linker supports --no-warn-rwx-segments
|
||||
execute_process(COMMAND ${CMAKE_LINKER} "--no-warn-rwx-segments" "--version"
|
||||
execute_process(COMMAND ${linker_binary} "--no-warn-rwx-segments" "--version"
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_QUIET
|
||||
ERROR_QUIET)
|
||||
|
||||
@@ -1268,12 +1268,17 @@ function(__preprocess_linker_script script_in script_out flags component_include
|
||||
# ld.common file, so add the parent directory to the C preprocessor
|
||||
# search path. Works for that layout; a component with a different
|
||||
# layout, or one that must drop -C, should pass FLAGS instead.
|
||||
# esp_system/ld is added as well so that scripts of other components
|
||||
# can include the shared fragments living there (e.g.
|
||||
# ld.elf.internal.sections).
|
||||
set(base_flags "-C")
|
||||
get_filename_component(script_parent_dir "${script_in}" DIRECTORY)
|
||||
get_filename_component(script_parent_name "${script_parent_dir}" NAME)
|
||||
if(script_parent_name STREQUAL idf_target)
|
||||
get_filename_component(dir_to_include "${script_parent_dir}" DIRECTORY)
|
||||
string(APPEND base_flags " -I\"${dir_to_include}\"")
|
||||
idf_component_get_property(esp_system_dir esp_system COMPONENT_DIR)
|
||||
string(APPEND base_flags
|
||||
" -I\"${dir_to_include}\" -I\"${esp_system_dir}/ld\"")
|
||||
endif()
|
||||
else()
|
||||
# Explicit FLAGS replace the whole default set, including -C. config_dir
|
||||
|
||||
@@ -51,9 +51,9 @@ tools/test_apps/system/build_tests/trax_esp32s2:
|
||||
|
||||
tools/test_apps/system/clang_build_test:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32", "esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c5", "esp32c6", "esp32h2"]
|
||||
- if: IDF_TARGET in ["esp32", "esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c5", "esp32c6", "esp32h2", "esp32p4"]
|
||||
temporary: true
|
||||
reason: the other targets are not supported yet, esp32p4 # TODO: IDF-14355
|
||||
reason: the other targets are not supported yet
|
||||
|
||||
tools/test_apps/system/cxx_no_except:
|
||||
enable:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
This project is for testing if the application can be built with Clang toolchain.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Build test: link with LLD instead of GNU ld (esp32p4 only)
|
||||
CONFIG_IDF_TARGET="esp32p4"
|
||||
CONFIG_COMPILER_USE_LLD=y
|
||||
Reference in New Issue
Block a user