Skip to content

Commit 01d3316

Browse files
bjorniuppsalakartben
authored andcommitted
linker generator: Handle .last_section
Add cmake linker generator things for .last_section. Follow up to #88970. Fixes bug #89719, for gcc/ld & iar Signed-off-by: Björn Bergman <[email protected]>
1 parent f489670 commit 01d3316

File tree

4 files changed

+129
-124
lines changed

4 files changed

+129
-124
lines changed

cmake/linker/iar/config_file_script.cmake

Lines changed: 109 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,13 @@ function(process_region)
9797
EXPR "@ADDR(${symbol_start})@"
9898
)
9999
endif()
100+
# Treat BSS to be noinit
101+
if(type STREQUAL BSS)
102+
set_property(GLOBAL PROPERTY ${section}_NOINIT TRUE)
103+
endif()
104+
endforeach() # all sections
100105

101-
endforeach()
102-
106+
#Add houseeeping symbols for sektion start, end, size, load start.
103107
get_property(groups GLOBAL PROPERTY ${REGION_OBJECT}_GROUP_LIST_ORDERED)
104108
foreach(group ${groups})
105109
get_property(name GLOBAL PROPERTY ${group}_NAME)
@@ -146,6 +150,7 @@ function(process_region)
146150

147151
endforeach()
148152

153+
# create_symbol() for region-symbols that dont have an expression ?
149154
get_property(symbols GLOBAL PROPERTY ${REGION_OBJECT}_SYMBOLS)
150155
foreach(symbol ${symbols})
151156
get_property(name GLOBAL PROPERTY ${symbol}_NAME)
@@ -173,6 +178,7 @@ function(process_region)
173178
endif()
174179
endif()
175180

181+
#Short circuit our vma and lma to the parent's vma and lma
176182
if(${parent_type} STREQUAL GROUP)
177183
get_property(vma GLOBAL PROPERTY ${parent}_VMA)
178184
get_property(lma GLOBAL PROPERTY ${parent}_LMA)
@@ -244,7 +250,7 @@ function(system_to_string)
244250
set(${STRING_STRING} "${${STRING_STRING}}\n\n")
245251
set_property(GLOBAL PROPERTY ILINK_SYMBOL_ICF)
246252

247-
set(${STRING_STRING} "${${STRING_STRING}}\n")
253+
#Generate all regions
248254
foreach(region ${regions})
249255
get_property(empty GLOBAL PROPERTY ${region}_EMPTY)
250256
if(NOT empty)
@@ -254,8 +260,27 @@ function(system_to_string)
254260
set(ILINK_CURRENT_NAME)
255261
endif()
256262
endforeach()
257-
set(${STRING_STRING} "${${STRING_STRING}}\n")
263+
set(${STRING_STRING} "${${STRING_STRING}}\n/*SYSTEM_SECTIONS*/\n")
264+
265+
# Sections that sit directly under the system are fishy characters.
266+
# Currently there are two classes of them:
267+
# 1 - .rel.iplt & friends - these are not used by iar tools currently.
268+
# These do not have any parents, so get no placement. Ignore them for
269+
# now, since the get Error[Lc041]: "foo" defined but not referenced
270+
# 2 - TYPE LINKER_SCRIPT_FOOTER - these have vma and lma settings, and so
271+
# are easy to handle
272+
get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS)
273+
foreach(section ${sections})
274+
get_property(vma GLOBAL PROPERTY ${section}_VMA)
275+
get_property(lma GLOBAL PROPERTY ${section}_LMA)
276+
if(DEFINED lma OR DEFINED vma)
277+
to_string(OBJECT ${section} STRING ${STRING_STRING})
278+
place_in_region(STRING place OBJECT ${section})
279+
string(APPEND ${STRING_STRING} "${place}")
280+
endif()
281+
endforeach()
258282

283+
#Generate all image symbols we have collected
259284
get_property(symbols_icf GLOBAL PROPERTY ILINK_SYMBOL_ICF)
260285
foreach(image_symbol ${symbols_icf})
261286
set(${STRING_STRING} "${${STRING_STRING}}define image symbol ${image_symbol};\n")
@@ -281,6 +306,38 @@ function(system_to_string)
281306
set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE)
282307
endfunction()
283308

309+
#A helper to output "place in <Region>"
310+
function(place_in_region)
311+
cmake_parse_arguments(PLACE "" "OBJECT;STRING" "" ${ARGN})
312+
set(section ${PLACE_OBJECT})
313+
get_property(name GLOBAL PROPERTY ${section}_NAME)
314+
315+
get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN)
316+
317+
get_property(parent GLOBAL PROPERTY ${section}_PARENT)
318+
get_property(noinit GLOBAL PROPERTY ${section}_NOINIT)
319+
# This is only a trick to get the memories
320+
get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
321+
if(${parent_type} STREQUAL GROUP)
322+
get_property(vma GLOBAL PROPERTY ${parent}_VMA)
323+
get_property(lma GLOBAL PROPERTY ${parent}_LMA)
324+
endif()
325+
326+
if(DEFINED vma)
327+
set(ILINK_CURRENT_NAME ${vma})
328+
elseif(DEFINED lma)
329+
set(ILINK_CURRENT_NAME ${lma})
330+
else()
331+
# message(FATAL_ERROR "Need either vma or lma")
332+
endif()
333+
334+
set(result "\"${name}\": place in ${ILINK_CURRENT_NAME} { block ${name_clean} };\n")
335+
if(CONFIG_IAR_ZEPHYR_INIT AND DEFINED vma AND DEFINED lma AND (NOT ${noinit}) AND NOT ("${vma}" STREQUAL "${lma}") )
336+
string(APPEND result "\"${name}_init\": place in ${lma} { block ${name_clean}_init };\n")
337+
endif()
338+
set(${PLACE_STRING} "${result}" PARENT_SCOPE)
339+
endfunction()
340+
284341
function(group_to_string)
285342
cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN})
286343

@@ -302,55 +359,36 @@ function(group_to_string)
302359
set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place at address mem:${section_address} { block ${name_clean} };\n")
303360
endforeach()
304361

362+
#Generate sub-groups
305363
get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS)
306364
foreach(group ${groups})
307365
to_string(OBJECT ${group} STRING ${STRING_STRING})
308366
endforeach()
309367

368+
#Generate sections
310369
get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS)
311370
foreach(section ${sections})
312371
to_string(OBJECT ${section} STRING ${STRING_STRING})
313372

314-
get_property(name GLOBAL PROPERTY ${section}_NAME)
315-
316-
get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN)
317-
318-
get_property(parent GLOBAL PROPERTY ${section}_PARENT)
319-
get_property(noinit GLOBAL PROPERTY ${section}_NOINIT)
320-
# This is only a trick to get the memories
321-
get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
322-
if(${parent_type} STREQUAL GROUP)
323-
get_property(vma GLOBAL PROPERTY ${parent}_VMA)
324-
get_property(lma GLOBAL PROPERTY ${parent}_LMA)
325-
endif()
326-
327-
if(DEFINED vma)
328-
set(ILINK_CURRENT_NAME ${vma})
329-
elseif(DEFINED lma)
330-
set(ILINK_CURRENT_NAME ${lma})
331-
else()
332-
# message(FATAL_ERROR "Need either vma or lma")
333-
endif()
334-
335-
set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place in ${ILINK_CURRENT_NAME} { block ${name_clean} };\n")
336-
if(CONFIG_IAR_ZEPHYR_INIT AND DEFINED vma AND DEFINED lma AND NOT ${noinit})
337-
set(${STRING_STRING} "${${STRING_STRING}}\"${name}_init\": place in ${lma} { block ${name_clean}_init };\n")
338-
endif()
339-
373+
place_in_region(STRING place OBJECT ${section})
374+
string(APPEND ${STRING_STRING} "${place}")
340375
endforeach()
341376

342377
get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM)
343378
get_property(regions GLOBAL PROPERTY ${parent}_REGIONS)
344379
list(REMOVE_ITEM regions ${STRING_OBJECT})
345380

381+
#Go over REGIONS
346382
foreach(region ${regions})
347383
get_property(vma GLOBAL PROPERTY ${region}_NAME)
348384
get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED)
349385

386+
#Generate our fixed-sections that has vma in this region
350387
foreach(section ${sections})
351388
to_string(OBJECT ${section} STRING ${STRING_STRING})
352389
endforeach()
353390

391+
#generate our groups with vma in region
354392
get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS)
355393
foreach(group ${groups})
356394
to_string(OBJECT ${group} STRING ${STRING_STRING})
@@ -378,22 +416,6 @@ function(group_to_string)
378416
set_property(GLOBAL PROPERTY ILINK_CURRENT_SECTIONS)
379417
endif()
380418
endif()
381-
382-
if(${name_clean} STREQUAL last_ram_section)
383-
get_property(group_name_lma GLOBAL PROPERTY ILINK_ROM_REGION_NAME)
384-
set(${STRING_STRING} "${${STRING_STRING}}\n")
385-
if(${CONFIG_LINKER_LAST_SECTION_ID})
386-
set(${STRING_STRING} "${${STRING_STRING}}define section last_section_id { udata32 ${CONFIG_LINKER_LAST_SECTION_ID_PATTERN}; };\n")
387-
set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { section last_section_id };\n")
388-
else()
389-
set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { };\n")
390-
endif()
391-
# Not really the right place, we want the last used flash bytes not end of the world!
392-
# set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place at end of ${group_name_lma} { block last_section };\n")
393-
set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place in ${group_name_lma} { block last_section };\n")
394-
set(${STRING_STRING} "${${STRING_STRING}}keep { block last_section };\n")
395-
endif()
396-
397419
endforeach()
398420
endforeach()
399421

@@ -677,11 +699,6 @@ function(section_to_string)
677699
set(block_attr)
678700
set(block_attr_str)
679701

680-
if(empty)
681-
set(TEMP "${TEMP}\n {")
682-
set(empty FALSE)
683-
endif()
684-
685702
list(GET input -1 last_input)
686703

687704
set(TEMP "${TEMP} {")
@@ -697,21 +714,6 @@ function(section_to_string)
697714

698715
set(section_type "")
699716

700-
# build for ram, no section_type
701-
# if("${lma}" STREQUAL "${vma}")
702-
# # if("${vma}" STREQUAL "")
703-
# set(section_type "")
704-
# # else()
705-
# # set(section_type " readwrite")
706-
# # endif()
707-
# elseif(NOT "${vma}" STREQUAL "")
708-
# set(section_type " readwrite")
709-
# elseif(NOT "${lma}" STREQUAL "")
710-
# set(section_type " readonly")
711-
# else()
712-
# message(FATAL_ERROR "How to handle this? lma=${lma} vma=${vma}")
713-
# endif()
714-
715717
set(TEMP "${TEMP}${section_type} ${part}section ${setting}")
716718
set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${setting}")
717719
set(section_type "")
@@ -777,66 +779,51 @@ function(section_to_string)
777779

778780
set(TEMP "${TEMP}\n};")
779781

780-
get_property(type GLOBAL PROPERTY ${parent}_OBJ_TYPE)
781-
if(${type} STREQUAL REGION)
782-
get_property(name GLOBAL PROPERTY ${parent}_NAME)
783-
get_property(address GLOBAL PROPERTY ${parent}_ADDRESS)
784-
get_property(size GLOBAL PROPERTY ${parent}_SIZE)
785-
786-
endif()
787-
788782
get_property(current_sections GLOBAL PROPERTY ILINK_CURRENT_SECTIONS)
789-
790-
if(DEFINED group_parent_vma AND DEFINED group_parent_lma)
791-
if(${noinit})
792-
list(JOIN current_sections ", " SELECTORS)
793-
set(TEMP "${TEMP}\ndo not initialize {\n${SELECTORS}\n};")
794-
else()
795-
796-
if(DEFINED current_sections)
797-
if(CONFIG_IAR_DATA_INIT)
798-
set(TEMP "${TEMP}\ninitialize by copy\n")
799-
set(TEMP "${TEMP}{\n")
800-
foreach(section ${current_sections})
801-
set(TEMP "${TEMP} ${section},\n")
802-
endforeach()
803-
set(TEMP "${TEMP}};")
804-
805-
set(TEMP "${TEMP}\n\"${name}_init\": place in ${group_parent_lma} {\n")
806-
foreach(section ${current_sections})
807-
set(TEMP "${TEMP} ${section}_init,\n")
808-
endforeach()
809-
set(TEMP "${TEMP}};")
810-
elseif(CONFIG_IAR_ZEPHYR_INIT)
811-
# Generate the _init block and the initialize manually statement.
812-
# Note that we need to have the X_init block defined even if we have
813-
# no sections, since there will come a "place in XXX" statement later.
814-
815-
# "${TEMP}" is there too keep the ';' else it will be a list
816-
string(REGEX REPLACE "(block[ \t\r\n]+)([^ \t\r\n]+)" "\\1\\2_init" INIT_TEMP "${TEMP}")
817-
string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)([^ \t\r\n,]+)" "\\1\\2\\3\\4_init" INIT_TEMP "${INIT_TEMP}")
818-
string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)" "ro\\2\\3" INIT_TEMP "${INIT_TEMP}")
819-
string(REGEX REPLACE "alphabetical order, " "" INIT_TEMP "${INIT_TEMP}")
820-
string(REGEX REPLACE "{ readwrite }" "{ }" INIT_TEMP "${INIT_TEMP}")
821-
822-
# If any content is marked as keep, is has to be applied to the init block
823-
# too, esp. for blocks that are not referenced (e.g. empty blocks wiht min_size)
824-
if(to_be_kept)
825-
list(APPEND to_be_kept "block ${name_clean}_init")
826-
endif()
827-
set(TEMP "${TEMP}\n${INIT_TEMP}\n")
828-
set(TEMP "${TEMP}\ninitialize manually with copy friendly\n")
829-
set(TEMP "${TEMP}{\n")
830-
foreach(section ${current_sections})
831-
set(TEMP "${TEMP} ${section},\n")
832-
endforeach()
833-
set(TEMP "${TEMP}};")
834-
set(current_sections)
783+
if(${noinit})
784+
list(JOIN current_sections ", " SELECTORS)
785+
set(TEMP "${TEMP}\ndo not initialize {\n${SELECTORS}\n};")
786+
elseif(DEFINED group_parent_vma AND DEFINED group_parent_lma)
787+
if(DEFINED current_sections)
788+
if(CONFIG_IAR_DATA_INIT)
789+
set(TEMP "${TEMP}\ninitialize by copy\n")
790+
set(TEMP "${TEMP}{\n")
791+
foreach(section ${current_sections})
792+
set(TEMP "${TEMP} ${section},\n")
793+
endforeach()
794+
set(TEMP "${TEMP}};")
795+
796+
set(TEMP "${TEMP}\n\"${name}_init\": place in ${group_parent_lma} {\n")
797+
foreach(section ${current_sections})
798+
set(TEMP "${TEMP} ${section}_init,\n")
799+
endforeach()
800+
set(TEMP "${TEMP}};")
801+
elseif(CONFIG_IAR_ZEPHYR_INIT)
802+
# Generate the _init block and the initialize manually statement.
803+
# Note that we need to have the X_init block defined even if we have
804+
# no sections, since there will come a "place in XXX" statement later.
805+
806+
# "${TEMP}" is there too keep the ';' else it will be a list
807+
string(REGEX REPLACE "(block[ \t\r\n]+)([^ \t\r\n]+)" "\\1\\2_init" INIT_TEMP "${TEMP}")
808+
string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)([^ \t\r\n,]+)" "\\1\\2\\3\\4_init" INIT_TEMP "${INIT_TEMP}")
809+
string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)" "ro\\2\\3" INIT_TEMP "${INIT_TEMP}")
810+
string(REGEX REPLACE "alphabetical order, " "" INIT_TEMP "${INIT_TEMP}")
811+
string(REGEX REPLACE "{ readwrite }" "{ }" INIT_TEMP "${INIT_TEMP}")
812+
813+
# If any content is marked as keep, is has to be applied to the init block
814+
# too, esp. for blocks that are not referenced (e.g. empty blocks wiht min_size)
815+
if(to_be_kept)
816+
list(APPEND to_be_kept "block ${name_clean}_init")
835817
endif()
818+
set(TEMP "${TEMP}\n${INIT_TEMP}\n")
819+
set(TEMP "${TEMP}\ninitialize manually with copy friendly\n")
820+
set(TEMP "${TEMP}{\n")
821+
foreach(section ${current_sections})
822+
set(TEMP "${TEMP} ${section},\n")
823+
endforeach()
824+
set(TEMP "${TEMP}};")
836825
endif()
837-
838826
set(current_sections)
839-
840827
endif()
841828
endif()
842829

cmake/linker/linker_script_common.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ function(create_section)
221221
else()
222222
set(parent ${SECTION_SYSTEM})
223223
endif()
224+
if(SECTION_TYPE STREQUAL "LINKER_SCRIPT_FOOTER")
225+
set(SECTION_VMA) # pretend that we have no VMA, so the section ends up in
226+
# the general heap of sections directly below the system
227+
set(parent ${SECTION_SYSTEM})
228+
endif()
224229

225230
set_property(GLOBAL PROPERTY SECTION_${SECTION_NAME}_PARENT ${parent})
226231
add_section(OBJECT ${parent} SECTION ${SECTION_NAME} ADDRESS ${SECTION_ADDRESS} VMA ${SECTION_VMA})

cmake/linker_script/arm/linker.cmake

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ if(CONFIG_USERSPACE)
155155
zephyr_linker_symbol(SYMBOL "_app_smem_rom_start" EXPR "@__app_smem_group_load_start@")
156156

157157

158-
zephyr_linker_section(NAME .bss VMA RAM LMA FLASH TYPE BSS)
158+
zephyr_linker_section(NAME .bss GROUP RAM_REGION TYPE BSS)
159159
zephyr_linker_section_configure(SECTION .bss INPUT COMMON)
160160
zephyr_linker_section_configure(SECTION .bss INPUT ".kernel_bss.*")
161161

@@ -175,7 +175,7 @@ include(${COMMON_ZEPHYR_LINKER_DIR}/common-ram.cmake)
175175
include(${COMMON_ZEPHYR_LINKER_DIR}/kobject-data.cmake)
176176

177177
if(NOT CONFIG_USERSPACE)
178-
zephyr_linker_section(NAME .bss VMA RAM LMA FLASH TYPE BSS)
178+
zephyr_linker_section(NAME .bss GROUP RAM_REGION TYPE BSS)
179179
zephyr_linker_section_configure(SECTION .bss INPUT COMMON)
180180
zephyr_linker_section_configure(SECTION .bss INPUT ".kernel_bss.*")
181181
# As memory is cleared in words only, it is simpler to ensure the BSS
@@ -256,3 +256,12 @@ dt_comp_path(paths COMPATIBLE "zephyr,memory-region")
256256
foreach(path IN LISTS paths)
257257
zephyr_linker_dts_section(PATH ${path})
258258
endforeach()
259+
260+
261+
# .last_section must be last in romable region
262+
# .last_section contains a fixed word to ensure location counter and actual
263+
# rom region data usage match when CONFIG_LINKER_LAST_SECTION_ID=y.
264+
zephyr_linker_section(NAME .last_section VMA FLASH LMA FLASH
265+
NOINPUT TYPE LINKER_SCRIPT_FOOTER)
266+
# KEEP can not be passed to zephyr_linker_section, so:
267+
zephyr_linker_section_configure(SECTION .last_section INPUT ".last_section" KEEP)

cmake/modules/extensions.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5167,6 +5167,10 @@ endfunction()
51675167
# the given passes. Empty list means no passes.
51685168
# PASS NOT [<p1>] [<p2>...] makes the section present in
51695169
# all but the given passes. Empty list means all passes.
5170+
# TYPE <type> : Tag section for special treatment.
5171+
# NOLOAD, BSS - Ensure that the section is NOLOAD
5172+
# LINKER_SCRIPT_FOOTER - One single section to be
5173+
# generated last
51705174
# Note: VMA and LMA are mutual exclusive with GROUP
51715175
#
51725176
function(zephyr_linker_section)

0 commit comments

Comments
 (0)