Skip to content

Commit

Permalink
llext: add support for read-only data in DRAM
Browse files Browse the repository at this point in the history
With this data can be assigned to a separate read-only section, which
then will be kept in DRAM without copying it to SRAM on module
instantiation.

Signed-off-by: Guennadi Liakhovetski <[email protected]>
  • Loading branch information
lyakh committed Jan 9, 2025
1 parent 7d11802 commit 0f6caa5
Showing 1 changed file with 28 additions and 14 deletions.
42 changes: 28 additions & 14 deletions scripts/llext_link_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def main():
executable = []
writable = []
readonly = []
readonly_dram = []

text_found = False

Expand All @@ -101,10 +102,7 @@ def main():
if (s_flags & (SH_FLAGS.SHF_ALLOC | SH_FLAGS.SHF_EXECINSTR) ==
SH_FLAGS.SHF_ALLOC | SH_FLAGS.SHF_EXECINSTR and
s_type == 'SHT_PROGBITS'):
# An executable section, currently only a single .text is supported.
# In general additional executable sections are possible, e.g.
# .init. In the future support for arbitrary such sections can be
# added, similar to writable and read-only data below.
# An executable section.
if s_name == '.text':
text_found = True
text_addr = max_alignment(text_addr, 0x1000, s_alignment)
Expand All @@ -123,7 +121,10 @@ def main():

if s_type == 'SHT_PROGBITS' and s_flags & SH_FLAGS.SHF_ALLOC:
# .rodata or other read-only sections
readonly.append(section)
if s_name == '.coldrodata':
readonly_dram.append(section)
else:
readonly.append(section)

if not text_found:
raise RuntimeError('No .text section found in the object file')
Expand All @@ -136,24 +137,37 @@ def main():
# run at arbitrary memory locations. One of the use-cases is running
# parts of the module directly in DRAM - sacrificing performance but
# saving scarce SRAM. We achieve this by placing non-performance
# critical functions in a .cold ELF section. When compiling and linking
# such functions, an additional .cold.literal section is automatically
# created. Note, that for some reason the compiler also marks that
# section as executable.
# critical functions in a .cold ELF section, read-only data in a
# .coldrodata ELF section, etc. When compiling and linking such
# functions, an additional .cold.literal section is automatically
# created. Note, that for some reason the compiler also marks .cold as
# executable.
# This script links those sections at address 0. We could hard-code
# section names, but so far we choose to only link .text the "original"
# way and all other executable sections we link at 0.
exe_addr = 0
# way and all other executable sections we link at 0. For data sections
# we accept only the .coldrodata name for now.

dram_addr = 0

for section in executable:
s_alignment = section.header['sh_addralign']
s_name = section.name

exe_addr = align_up(exe_addr, s_alignment)
dram_addr = align_up(dram_addr, s_alignment)

command.append(f'-Wl,--section-start={s_name}=0x{dram_addr:x}')

dram_addr += section.header['sh_size']

for section in readonly_dram:
s_alignment = section.header['sh_addralign']
s_name = section.name

dram_addr = align_up(dram_addr, s_alignment)

command.append(f'-Wl,--section-start={s_name}=0x{exe_addr:x}')
command.append(f'-Wl,--section-start={s_name}=0x{dram_addr:x}')

exe_addr += section.header['sh_size']
dram_addr += section.header['sh_size']

start_addr = align_up(text_addr + text_size, 0x1000)

Expand Down

0 comments on commit 0f6caa5

Please sign in to comment.