ld_script.cmake 11 KB

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