Skip to content

Commit

Permalink
libc: Don't use --whole-archive for libc common and picolibc hooks
Browse files Browse the repository at this point in the history
Removing these from the set of libraries linked with --whole-archive means
that functionality not explicitly referenced by the application won't be
included in the linker output.

This is done by splitting ZEPHYR_LIBS_PROPERTY into two lists,
ZEPHYR_LIBS_WHOLE and ZEPHYR_LIBS_PARTIAL. Linkers supporting this
operation can place only the ZEPHYR_LIBS_WHOLE list under the
--whole-archive mode while placing the ZEPHYR_LIBS_PARTIAL list under
--start-group with the kernel (ensuring that circular references will be
resolved).

So that any nested dependency libraries are also included in that group,
compute the transitive set of libraries and stick those into the explicit
link command.

To make sure any OS functions used by the toolchain are included,
LIBC_LINK_LIBRARIES is included in this set, which required handling that
value inside of the linker code instead of in the general code. A new
global variable, LIBC_LINK_LIBRARIES_SKIP, has been added that tells the
top level CMakeLists.txt to not call zephyr_link_libraries in this case.

Support for arcmwdt, ld, lld and xt-ld linkers is added; other linkers will
continue to use ZEPHYR_LIBS_PROPERTY unchanged.

Signed-off-by: Keith Packard <[email protected]>
  • Loading branch information
keith-packard committed Nov 19, 2023
1 parent dc4b9b4 commit 471daef
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 10 deletions.
18 changes: 16 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -590,8 +590,11 @@ endforeach()
set(ZEPHYR_CURRENT_MODULE_DIR)
set(ZEPHYR_CURRENT_CMAKE_DIR)

get_property(LIBC_LINK_LIBRARIES TARGET zephyr_interface PROPERTY LIBC_LINK_LIBRARIES)
zephyr_link_libraries(${LIBC_LINK_LIBRARIES})
# Check to see if the linker handles LIBC_LINK_LIBRARIES internally
if(NOT "${LIBC_LINK_LIBRARIES_SKIP}")
get_property(LIBC_LINK_LIBRARIES TARGET zephyr_interface PROPERTY LIBC_LINK_LIBRARIES)
zephyr_link_libraries(${LIBC_LINK_LIBRARIES})
endif()

set(syscall_list_h ${CMAKE_CURRENT_BINARY_DIR}/include/generated/syscall_list.h)
set(syscalls_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls.json)
Expand Down Expand Up @@ -860,6 +863,17 @@ foreach(zephyr_lib ${ZEPHYR_LIBS_PROPERTY})
continue()
endif()
endif()
# Create whole/partial lists which reflect the state of the PARTIAL
# property of the library. Depending on the linker, partial libs may
# be excluded from the --whole-archive set passed to the linker so
# that files not explicitly referenced will not be included in the
# output.
get_property(partial TARGET ${zephyr_lib} PROPERTY PARTIAL)
if("${partial}")
list(APPEND ZEPHYR_LIBS_PARTIAL ${zephyr_lib})
else()
list(APPEND ZEPHYR_LIBS_WHOLE ${zephyr_lib})
endif()

# TODO: Could this become an INTERFACE property of zephyr_interface?
add_dependencies(${zephyr_lib} zephyr_generated_headers)
Expand Down
8 changes: 7 additions & 1 deletion cmake/linker/arcmwdt/target.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,24 @@ function(toolchain_ld_link_elf)
${LINKERFLAGPREFIX}--entry=__start
${LINKERFLAGPREFIX}--Map=${TOOLCHAIN_LD_LINK_ELF_OUTPUT_MAP}
${LINKERFLAGPREFIX}--whole-archive
${ZEPHYR_LIBS_PROPERTY}
${ZEPHYR_LIBS_WHOLE}
${LINKERFLAGPREFIX}--no-whole-archive
${LINKERFLAGPREFIX},--start-group
kernel
${ZEPHYR_LIBS_PARTIAL}
$<TARGET_OBJECTS:${OFFSETS_LIB}>
${LIB_INCLUDE_DIR}
-L${PROJECT_BINARY_DIR}
${TOOLCHAIN_LIBS}
${LIBC_LINK_LIBRARIES}

${TOOLCHAIN_LD_LINK_ELF_DEPENDENCIES}
${LINKERFLAGPREFIX},--end-group
)
endfunction(toolchain_ld_link_elf)

set(LIBC_LINK_LIBRARIES_SKIP TRUE)

# linker options of temporary linkage for code generation
macro(toolchain_ld_baremetal)
zephyr_ld_options(
Expand Down
58 changes: 56 additions & 2 deletions cmake/linker/ld/target.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,34 @@ function(toolchain_ld_force_undefined_symbols)
endforeach()
endfunction()

function(toolchain_ld_all_targets output dir)
get_property(targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS)
get_property(subdirs DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)

foreach(subdir ${subdirs})
toolchain_ld_all_targets(subdir_targets ${subdir})
list(APPEND targets ${subdir_targets})
endforeach()

set(${output} ${targets} PARENT_SCOPE)
endfunction()

function(toolchain_ld_add_transitive targets output)
set(local_output ${${output}})
foreach(symbol ${ARGN})
list(FIND local_output "${symbol}" found_index)
if(${found_index} EQUAL -1)
list(APPEND local_output "${symbol}")
list(FIND ${targets} "${symbol}" target_index)
if(NOT ${target_index} EQUAL -1)
get_property(INTERFACE_LINK_LIBRARIES TARGET "${symbol}" PROPERTY INTERFACE_LINK_LIBRARIES)
toolchain_ld_add_transitive(targets local_output ${INTERFACE_LINK_LIBRARIES})
endif()
endif()
endforeach()
set(${output} ${local_output} PARENT_SCOPE)
endfunction()

# Link a target to given libraries with toolchain-specific argument order
#
# Usage:
Expand All @@ -124,28 +152,54 @@ function(toolchain_ld_link_elf)
set(use_linker "-fuse-ld=bfd")
endif()

get_property(LIBC_LINK_LIBRARIES TARGET zephyr_interface PROPERTY LIBC_LINK_LIBRARIES)

toolchain_ld_all_targets(LIBC_LINK_ALL_TARGETS ${CMAKE_CURRENT_LIST_DIR})

# Get the whole list of libraries to stick between --start-group and --end-group
toolchain_ld_add_transitive(LIBC_LINK_ALL_TARGETS LIBC_LINK_TRANSITIVE ${ZEPHYR_LIBS_WHOLE} ${ZEPHYR_LIBS_PARTIAL})

# Force the use of common malloc instead of libc malloc

if(CONFIG_COMMON_LIBC_MALLOC)
set(LIBC_LINK_MALLOC_MAP
${LINKERFLAGPREFIX},--defsym=malloc=z_malloc
${LINKERFLAGPREFIX},--defsym=realloc=z_realloc
${LINKERFLAGPREFIX},--defsym=calloc=z_calloc
)
else()
set(LIBC_LINK_MALLOC_MAP)
endif()

target_link_libraries(
${TOOLCHAIN_LD_LINK_ELF_TARGET_ELF}
${TOOLCHAIN_LD_LINK_ELF_LIBRARIES_PRE_SCRIPT}
${use_linker}
${TOPT}
${TOOLCHAIN_LD_LINK_ELF_LINKER_SCRIPT}
${TOOLCHAIN_LD_LINK_ELF_LIBRARIES_POST_SCRIPT}

${LINKERFLAGPREFIX},-Map=${TOOLCHAIN_LD_LINK_ELF_OUTPUT_MAP}
${LINKERFLAGPREFIX},--whole-archive
${ZEPHYR_LIBS_PROPERTY}
${ZEPHYR_LIBS_WHOLE}
${LINKERFLAGPREFIX},--no-whole-archive
${LIBC_LINK_MALLOC_MAP}
${LINKERFLAGPREFIX},--start-group
kernel
${ZEPHYR_LIBS_PARTIAL}
$<TARGET_OBJECTS:${OFFSETS_LIB}>
${LIB_INCLUDE_DIR}
-L${PROJECT_BINARY_DIR}
${TOOLCHAIN_LIBS}
${LIBC_LINK_LIBRARIES}
${LIBC_LINK_TRANSITIVE}

${TOOLCHAIN_LD_LINK_ELF_DEPENDENCIES}
${LINKERFLAGPREFIX},--end-group
)
endfunction(toolchain_ld_link_elf)

set(LIBC_LINK_LIBRARIES_SKIP TRUE)

# Load toolchain_ld-family macros
include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_base.cmake)
include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_baremetal.cmake)
Expand Down
7 changes: 6 additions & 1 deletion cmake/linker/lld/target.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,23 @@ function(toolchain_ld_link_elf)

${LINKERFLAGPREFIX},-Map=${TOOLCHAIN_LD_LINK_ELF_OUTPUT_MAP}
${LINKERFLAGPREFIX},--whole-archive
${ZEPHYR_LIBS_PROPERTY}
${ZEPHYR_LIBS_WHOLE}
${LINKERFLAGPREFIX},--no-whole-archive
${LINKERFLAGPREFIX},--start-group
kernel
${ZEPHYR_LIBS_PARTIAL}
$<TARGET_OBJECTS:${OFFSETS_LIB}>
${LIB_INCLUDE_DIR}
-L${PROJECT_BINARY_DIR}
${TOOLCHAIN_LIBS}
${LIBC_LINK_LIBRARIES}

${TOOLCHAIN_LD_LINK_ELF_DEPENDENCIES}
${LINKERFLAGPREFIX},--end-group
)
endfunction(toolchain_ld_link_elf)

set(LIBC_LINK_LIBRARIES_SKIP TRUE)

# Load toolchain_ld-family macros
include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_base.cmake)
Expand Down
8 changes: 7 additions & 1 deletion cmake/linker/xt-ld/target.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -126,18 +126,24 @@ function(toolchain_ld_link_elf)

${LINKERFLAGPREFIX},-Map=${TOOLCHAIN_LD_LINK_ELF_OUTPUT_MAP}
${LINKERFLAGPREFIX},--whole-archive
${ZEPHYR_LIBS_PROPERTY}
${ZEPHYR_LIBS_WHOLE}
${LINKERFLAGPREFIX},--no-whole-archive
${LINKERFLAGPREFIX},--start-group
kernel
${ZEPHYR_LIBS_PARTIAL}
$<TARGET_OBJECTS:${OFFSETS_LIB}>
${LIB_INCLUDE_DIR}
-L${PROJECT_BINARY_DIR}
${TOOLCHAIN_LIBS}
${LIBC_LINK_LIBRARIES}

${TOOLCHAIN_LD_LINK_ELF_DEPENDENCIES}
${LINKERFLAGPREFIX},--end-group
)
endfunction(toolchain_ld_link_elf)

set(LIBC_LINK_LIBRARIES_SKIP TRUE)

# xt-ld is Xtensa's own version of binutils' ld.
# So we can reuse most of the ld configurations.
include(${ZEPHYR_BASE}/cmake/linker/${LINKER}/target_base.cmake)
Expand Down
5 changes: 4 additions & 1 deletion cmake/modules/extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -578,8 +578,11 @@ endfunction()
# ALLOW_EMPTY <TRUE:FALSE>: Allow a Zephyr library to be empty.
# An empty Zephyr library will generate a CMake
# configure time warning unless `ALLOW_EMPTY` is TRUE.
# PARTIAL <TRUE:FALSE>: Specify the library outside of the whole-archive
# list so that only files used by the system will be
# linked.
function(zephyr_library_property)
set(single_args "ALLOW_EMPTY")
set(single_args "ALLOW_EMPTY" PARTIAL)
cmake_parse_arguments(LIB_PROP "" "${single_args}" "" ${ARGN})

if(LIB_PROP_UNPARSED_ARGUMENTS)
Expand Down
5 changes: 3 additions & 2 deletions lib/libc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ zephyr_syscall_header(
${ZEPHYR_BASE}/include/zephyr/sys/libc-hooks.h
)

# Placed first so that these functions override the C library
add_subdirectory(common)

add_subdirectory_ifdef(CONFIG_ARCMWDT_LIBC arcmwdt)
add_subdirectory_ifdef(CONFIG_ARMCLANG_STD_LIBC armstdc)
add_subdirectory_ifdef(CONFIG_MINIMAL_LIBC minimal)
add_subdirectory_ifdef(CONFIG_NEWLIB_LIBC newlib)
add_subdirectory_ifdef(CONFIG_PICOLIBC picolibc)

add_subdirectory(common)
1 change: 1 addition & 0 deletions lib/libc/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ zephyr_system_include_directories(include)

zephyr_library()
zephyr_library_property(ALLOW_EMPTY TRUE)
zephyr_library_property(PARTIAL TRUE)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ABORT source/stdlib/abort.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c)
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c)
Expand Down

0 comments on commit 471daef

Please sign in to comment.