|
| 1 | +# ToDo: |
| 2 | +# - Ensure LMA / VMA sections are correctly grouped similar to scatter file creation. |
| 3 | +cmake_minimum_required(VERSION 3.18) |
| 4 | + |
| 5 | +set(SORT_TYPE_NAME SORT_BY_NAME) |
| 6 | + |
| 7 | +function(system_to_string) |
| 8 | + cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) |
| 9 | + |
| 10 | + get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) |
| 11 | + get_property(regions GLOBAL PROPERTY ${STRING_OBJECT}_REGIONS) |
| 12 | + get_property(format GLOBAL PROPERTY ${STRING_OBJECT}_FORMAT) |
| 13 | + get_property(entry GLOBAL PROPERTY ${STRING_OBJECT}_ENTRY) |
| 14 | + get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS) |
| 15 | + |
| 16 | + set(${STRING_STRING} "OUTPUT_FORMAT(\"${format}\")\n\n") |
| 17 | + |
| 18 | + set(${STRING_STRING} "${${STRING_STRING}}MEMORY\n{\n") |
| 19 | + foreach(region ${regions}) |
| 20 | + get_property(name GLOBAL PROPERTY ${region}_NAME) |
| 21 | + get_property(address GLOBAL PROPERTY ${region}_ADDRESS) |
| 22 | + get_property(flags GLOBAL PROPERTY ${region}_FLAGS) |
| 23 | + get_property(size GLOBAL PROPERTY ${region}_SIZE) |
| 24 | + |
| 25 | + if(DEFINED flags) |
| 26 | + set(flags "(${flags})") |
| 27 | + endif() |
| 28 | + |
| 29 | + if(DEFINED address) |
| 30 | + set(start ": ORIGIN = (${address})") |
| 31 | + endif() |
| 32 | + |
| 33 | + if(DEFINED size) |
| 34 | + set(size ", LENGTH = (${size})") |
| 35 | + endif() |
| 36 | + set(memory_region " ${name} ${flags} ${start}${size}") |
| 37 | + |
| 38 | + set(${STRING_STRING} "${${STRING_STRING}}${memory_region}\n") |
| 39 | + endforeach() |
| 40 | + |
| 41 | + set(${STRING_STRING} "${${STRING_STRING}}}\n\n") |
| 42 | + |
| 43 | + set(${STRING_STRING} "${${STRING_STRING}}ENTRY(\"${entry}\")\n\n") |
| 44 | + |
| 45 | + set(${STRING_STRING} "${${STRING_STRING}}SECTIONS\n{") |
| 46 | + foreach(region ${regions}) |
| 47 | + to_string(OBJECT ${region} STRING ${STRING_STRING}) |
| 48 | + endforeach() |
| 49 | + |
| 50 | + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED) |
| 51 | + foreach(section ${sections}) |
| 52 | + to_string(OBJECT ${section} STRING ${STRING_STRING}) |
| 53 | + endforeach() |
| 54 | + |
| 55 | + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS) |
| 56 | + foreach(section ${sections}) |
| 57 | + to_string(OBJECT ${section} STRING ${STRING_STRING}) |
| 58 | + endforeach() |
| 59 | + |
| 60 | + foreach(symbol ${symbols}) |
| 61 | + to_string(OBJECT ${symbol} STRING ${STRING_STRING}) |
| 62 | + endforeach() |
| 63 | + |
| 64 | + set(${STRING_STRING} "${${STRING_STRING}}\n}\n" PARENT_SCOPE) |
| 65 | +endfunction() |
| 66 | + |
| 67 | +function(symbol_to_string) |
| 68 | + cmake_parse_arguments(STRING "" "SYMBOL;STRING" "" ${ARGN}) |
| 69 | + |
| 70 | + get_property(name GLOBAL PROPERTY ${STRING_SYMBOL}_NAME) |
| 71 | + get_property(expr GLOBAL PROPERTY ${STRING_SYMBOL}_EXPR) |
| 72 | + get_property(size GLOBAL PROPERTY ${STRING_SYMBOL}_SIZE) |
| 73 | + get_property(symbol GLOBAL PROPERTY ${STRING_SYMBOL}_SYMBOL) |
| 74 | + get_property(subalign GLOBAL PROPERTY ${STRING_SYMBOL}_SUBALIGN) |
| 75 | + |
| 76 | + string(REPLACE "\\" "" expr "${expr}") |
| 77 | + string(REGEX MATCHALL "%([^%]*)%" match_res ${expr}) |
| 78 | + |
| 79 | + foreach(match ${match_res}) |
| 80 | + string(REPLACE "%" "" match ${match}) |
| 81 | + string(REPLACE "%${match}%" "${match}" expr ${expr}) |
| 82 | + endforeach() |
| 83 | + |
| 84 | + set(${STRING_STRING} "${${STRING_STRING}}\n${symbol} = ${expr};\n" PARENT_SCOPE) |
| 85 | +endfunction() |
| 86 | + |
| 87 | +function(group_to_string) |
| 88 | + cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) |
| 89 | + |
| 90 | + get_property(type GLOBAL PROPERTY ${STRING_OBJECT}_OBJ_TYPE) |
| 91 | + if(${type} STREQUAL REGION) |
| 92 | + get_property(empty GLOBAL PROPERTY ${STRING_OBJECT}_EMPTY) |
| 93 | + if(empty) |
| 94 | + return() |
| 95 | + endif() |
| 96 | + |
| 97 | + get_property(address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS) |
| 98 | + set(${STRING_STRING} "${${STRING_STRING}}\n . = ${address};\n\n") |
| 99 | + else() |
| 100 | + get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) |
| 101 | + string(TOLOWER ${name} name) |
| 102 | + set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_start = .;\n") |
| 103 | + |
| 104 | + get_objects(LIST sections OBJECT ${STRING_OBJECT} TYPE SECTION) |
| 105 | + list(GET sections 0 section) |
| 106 | + get_property(first_section_name GLOBAL PROPERTY ${section}_NAME) |
| 107 | + |
| 108 | + set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_size = __${name}_end - __${name}_start;\n") |
| 109 | + set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_load_start = LOADADDR(${first_section_name});\n") |
| 110 | + endif() |
| 111 | + |
| 112 | + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED) |
| 113 | + foreach(section ${sections}) |
| 114 | + to_string(OBJECT ${section} STRING ${STRING_STRING}) |
| 115 | + endforeach() |
| 116 | + |
| 117 | + get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS) |
| 118 | + foreach(group ${groups}) |
| 119 | + to_string(OBJECT ${group} STRING ${STRING_STRING}) |
| 120 | + endforeach() |
| 121 | + |
| 122 | + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS) |
| 123 | + foreach(section ${sections}) |
| 124 | + to_string(OBJECT ${section} STRING ${STRING_STRING}) |
| 125 | + endforeach() |
| 126 | + |
| 127 | + get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM) |
| 128 | + get_property(regions GLOBAL PROPERTY ${parent}_REGIONS) |
| 129 | + list(REMOVE_ITEM regions ${STRING_OBJECT}) |
| 130 | + foreach(region ${regions}) |
| 131 | + if(${type} STREQUAL REGION) |
| 132 | + get_property(address GLOBAL PROPERTY ${region}_ADDRESS) |
| 133 | + set(${STRING_STRING} "${${STRING_STRING}}\n . = ${address};\n\n") |
| 134 | + endif() |
| 135 | + |
| 136 | + get_property(vma GLOBAL PROPERTY ${region}_NAME) |
| 137 | + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED) |
| 138 | + foreach(section ${sections}) |
| 139 | + to_string(OBJECT ${section} STRING ${STRING_STRING}) |
| 140 | + endforeach() |
| 141 | + |
| 142 | + get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS) |
| 143 | + foreach(group ${groups}) |
| 144 | + to_string(OBJECT ${group} STRING ${STRING_STRING}) |
| 145 | + endforeach() |
| 146 | + |
| 147 | + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS) |
| 148 | + foreach(section ${sections}) |
| 149 | + to_string(OBJECT ${section} STRING ${STRING_STRING}) |
| 150 | + endforeach() |
| 151 | + endforeach() |
| 152 | + |
| 153 | + if(NOT ${type} STREQUAL REGION) |
| 154 | + set(${STRING_STRING} "${${STRING_STRING}}\n __${name}_end = .;\n") |
| 155 | + endif() |
| 156 | + |
| 157 | + get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS) |
| 158 | + foreach(symbol ${symbols}) |
| 159 | + to_string(OBJECT ${symbol} STRING ${STRING_STRING}) |
| 160 | + endforeach() |
| 161 | + |
| 162 | + set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) |
| 163 | +endfunction() |
| 164 | + |
| 165 | +function(section_to_string) |
| 166 | + cmake_parse_arguments(STRING "" "SECTION;STRING" "" ${ARGN}) |
| 167 | + |
| 168 | + get_property(name GLOBAL PROPERTY ${STRING_SECTION}_NAME) |
| 169 | + get_property(name_clean GLOBAL PROPERTY ${STRING_SECTION}_NAME_CLEAN) |
| 170 | + get_property(address GLOBAL PROPERTY ${STRING_SECTION}_ADDRESS) |
| 171 | + get_property(type GLOBAL PROPERTY ${STRING_SECTION}_TYPE) |
| 172 | + get_property(align_in GLOBAL PROPERTY ${STRING_SECTION}_ALIGN_WITH_INPUT) |
| 173 | + get_property(align GLOBAL PROPERTY ${STRING_SECTION}_ALIGN) |
| 174 | + get_property(subalign GLOBAL PROPERTY ${STRING_SECTION}_SUBALIGN) |
| 175 | + get_property(vma GLOBAL PROPERTY ${STRING_SECTION}_VMA) |
| 176 | + get_property(lma GLOBAL PROPERTY ${STRING_SECTION}_LMA) |
| 177 | + get_property(noinput GLOBAL PROPERTY ${STRING_SECTION}_NOINPUT) |
| 178 | + get_property(noinit GLOBAL PROPERTY ${STRING_SECTION}_NOINIT) |
| 179 | + get_property(nosymbols GLOBAL PROPERTY ${STRING_SECTION}_NOSYMBOLS) |
| 180 | + get_property(parent GLOBAL PROPERTY ${STRING_SECTION}_PARENT) |
| 181 | + |
| 182 | + string(REGEX REPLACE "^[\.]" "" name_clean "${name}") |
| 183 | + string(REPLACE "." "_" name_clean "${name_clean}") |
| 184 | + |
| 185 | + set(SECTION_TYPE_NOLOAD NOLOAD) |
| 186 | + set(SECTION_TYPE_BSS NOLOAD) |
| 187 | + if(DEFINED type) |
| 188 | + set(type " (${SECTION_TYPE_${type}})") |
| 189 | + endif() |
| 190 | + |
| 191 | + set(TEMP "${TEMP} :") |
| 192 | + set(secalign "") |
| 193 | + |
| 194 | + if(align_in) |
| 195 | + set(secalign " ALIGN_WITH_INPUT") |
| 196 | + endif() |
| 197 | + |
| 198 | + if(DEFINED align) |
| 199 | + set(secalign "${secalign} ALIGN(${align})") |
| 200 | + endif() |
| 201 | + |
| 202 | + if(DEFINED subalign) |
| 203 | + set(secalign "${secalign} SUBALIGN(${subalign})") |
| 204 | + endif() |
| 205 | + |
| 206 | + set(TEMP "${name} ${address}${type} :${secalign}\n{") |
| 207 | + if(NOT nosymbols) |
| 208 | + set(TEMP "${TEMP}\n __${name_clean}_start = .;") |
| 209 | + endif() |
| 210 | + |
| 211 | + if(NOT noinput) |
| 212 | + set(TEMP "${TEMP}\n *(${name})") |
| 213 | + set(TEMP "${TEMP}\n *(\"${name}.*\")") |
| 214 | + endif() |
| 215 | + |
| 216 | + get_property(indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES) |
| 217 | + foreach(idx ${indicies}) |
| 218 | + get_property(align GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ALIGN) |
| 219 | + get_property(any GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ANY) |
| 220 | + get_property(first GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FIRST) |
| 221 | + get_property(keep GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP) |
| 222 | + get_property(sort GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SORT) |
| 223 | + get_property(flags GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FLAGS) |
| 224 | + get_property(input GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT) |
| 225 | + get_property(symbols GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SYMBOLS) |
| 226 | + get_property(offset GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_OFFSET) |
| 227 | + |
| 228 | + if(DEFINED SETTINGS_ALIGN) |
| 229 | + set(TEMP "${TEMP}\n . = ALIGN(${align});") |
| 230 | + endif() |
| 231 | + |
| 232 | + if(DEFINED symbols) |
| 233 | + list(LENGTH symbols symbols_count) |
| 234 | + if(${symbols_count} GREATER 0) |
| 235 | + list(GET symbols 0 symbol_start) |
| 236 | + endif() |
| 237 | + if(${symbols_count} GREATER 1) |
| 238 | + list(GET symbols 1 symbol_end) |
| 239 | + endif() |
| 240 | + endif() |
| 241 | + |
| 242 | + if(DEFINED symbol_start) |
| 243 | + set(TEMP "${TEMP}\n ${symbol_start} = .;") |
| 244 | + endif() |
| 245 | + |
| 246 | + foreach(setting ${input}) |
| 247 | + if(DEFINED offset AND NOT ("${offset}" STREQUAL "${current_offset}")) |
| 248 | + set(TEMP "${TEMP}\n . = ${offset};") |
| 249 | + set(current_offset ${offset}) |
| 250 | + endif() |
| 251 | + |
| 252 | + if(keep AND sort) |
| 253 | + set(TEMP "${TEMP}\n KEEP(*(${SORT_TYPE_${sort}}(${setting})));") |
| 254 | + elseif(SETTINGS_SORT) |
| 255 | + message(WARNING "Not tested") |
| 256 | + set(TEMP "${TEMP}\n *(${SORT_TYPE_${sort}}(${setting}));") |
| 257 | + elseif(keep) |
| 258 | + set(TEMP "${TEMP}\n KEEP(*(${setting}));") |
| 259 | + else() |
| 260 | + set(TEMP "${TEMP}\n *(${setting})") |
| 261 | + endif() |
| 262 | + endforeach() |
| 263 | + |
| 264 | + if(DEFINED symbol_end) |
| 265 | + set(TEMP "${TEMP}\n ${symbol_end} = .;") |
| 266 | + endif() |
| 267 | + |
| 268 | + set(symbol_start) |
| 269 | + set(symbol_end) |
| 270 | + endforeach() |
| 271 | + |
| 272 | + if(NOT nosymbols) |
| 273 | + set(TEMP "${TEMP}\n __${name_clean}_end = .;") |
| 274 | + endif() |
| 275 | + |
| 276 | + set(TEMP "${TEMP}\n}") |
| 277 | + |
| 278 | + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) |
| 279 | + if(${parent_type} STREQUAL GROUP) |
| 280 | + get_property(vma GLOBAL PROPERTY ${parent}_VMA) |
| 281 | + get_property(lma GLOBAL PROPERTY ${parent}_LMA) |
| 282 | + endif() |
| 283 | + |
| 284 | + if(DEFINED vma) |
| 285 | + set(TEMP "${TEMP} > ${vma}") |
| 286 | + endif() |
| 287 | + |
| 288 | + if(DEFINED vma AND DEFINED lma) |
| 289 | + set(TEMP "${TEMP} AT") |
| 290 | + endif() |
| 291 | + |
| 292 | + if(DEFINED lma) |
| 293 | + set(TEMP "${TEMP} > ${lma}") |
| 294 | + endif() |
| 295 | + |
| 296 | + if(NOT nosymbols) |
| 297 | + set(TEMP "${TEMP}\n__${name_clean}_size = __${name_clean}_end - __${name_clean}_start;") |
| 298 | + set(TEMP "${TEMP}\n__${name_clean}_load_start = LOADADDR(${name});") |
| 299 | + endif() |
| 300 | + |
| 301 | + set(${STRING_STRING} "${${STRING_STRING}}\n${TEMP}\n" PARENT_SCOPE) |
| 302 | +endfunction() |
| 303 | + |
| 304 | +# /DISCARD/ is an ld specific section, so let's append it here before processing. |
| 305 | +list(APPEND SECTIONS "{NAME\;/DISCARD/\;NOINPUT\;TRUE\;NOSYMBOLS\;TRUE}") |
| 306 | + |
| 307 | +function(process_region) |
| 308 | + cmake_parse_arguments(REGION "" "OBJECT" "" ${ARGN}) |
| 309 | + |
| 310 | + process_region_common(${ARGN}) |
| 311 | + |
| 312 | + set(groups) |
| 313 | + get_objects(LIST groups OBJECT ${REGION_OBJECT} TYPE GROUP) |
| 314 | + foreach(group ${groups}) |
| 315 | + get_property(parent GLOBAL PROPERTY ${group}_PARENT) |
| 316 | + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) |
| 317 | + |
| 318 | + if(${parent_type} STREQUAL GROUP) |
| 319 | + get_property(vma GLOBAL PROPERTY ${parent}_VMA) |
| 320 | + get_property(lma GLOBAL PROPERTY ${parent}_LMA) |
| 321 | + |
| 322 | + set_property(GLOBAL PROPERTY ${group}_VMA ${vma}) |
| 323 | + set_property(GLOBAL PROPERTY ${group}_LMA ${lma}) |
| 324 | + endif() |
| 325 | + endforeach() |
| 326 | +endfunction() |
| 327 | + |
| 328 | +include(${CMAKE_CURRENT_LIST_DIR}/../linker_script_common.cmake) |
0 commit comments