| .. zephyr:code-sample:: llext-shell-loader |
| :name: Linkable loadable extensions shell module |
| :relevant-api: llext_apis |
| |
| Manage loadable extensions using shell commands. |
| |
| Overview |
| ******** |
| |
| This example provides shell access to the :ref:`llext` system and provides the |
| ability to manage loadable code extensions in the shell. |
| |
| Requirements |
| ************ |
| |
| A board with a supported LLEXT architecture and shell capable console. The |
| following example uses an ARMv7 CPU, but the same instructions can be adapted |
| to any LLEXT-supported target. |
| |
| Building |
| ******** |
| |
| The following command will build the main shell application: |
| |
| .. zephyr-app-commands:: |
| :zephyr-app: samples/subsys/llext/shell_loader |
| :board: robokit1 |
| :goals: build |
| :compact: |
| |
| .. note:: |
| |
| You may need to disable memory protection for the sample to work (e.g. |
| ``CONFIG_ARM_MPU=n``). See the full list of similar flags in |
| :zephyr_file:`tests/subsys/llext/no_mem_protection.conf`. |
| |
| This sample also includes the source for a very basic extension, |
| :zephyr_file:`samples/subsys/llext/shell_loader/hello_world.c`, which can be |
| used to test the LLEXT features. |
| |
| It can be compiled to :file:`build/hello_world.llext` using the Zephyr build |
| system like this: |
| |
| .. code-block:: console |
| |
| $ ninja -C build -vvv hello_world_ext |
| |
| On a host machine with the Zephyr SDK and the ``arm-zephyr-eabi`` toolchain in |
| ``PATH``, you can also obtain the same result directly with ``gcc``: |
| |
| .. code-block:: console |
| |
| $ arm-zephyr-eabi-gcc -mlong-calls -mthumb -c -o build/hello_world.llext samples/subsys/llext/shell/hello_world.c |
| |
| .. note:: |
| |
| LLEXT by default only imports symbols that have been explicitly exported by |
| the extension via the :c:macro:`EXPORT_SYMBOL` macro. Compiling with this |
| macro requires using the full Zephyr build system, or at least the |
| :ref:`LLEXT EDK <llext_build_edk>`. |
| |
| To avoid this complexity, this sample configures Zephyr to use all global |
| symbols defined in the extension ELF file via the Kconfig option |
| :kconfig:option:`CONFIG_LLEXT_IMPORT_ALL_GLOBALS`. This is not recommended |
| for large extensions as the memory usage increases significantly. |
| |
| The compiled extension can be inspected with the usual binutils utilities to |
| see symbols, sections, and relocations. Then, using additional tools, converted |
| to a hex string usable by the ``llext load_hex`` shell command: |
| |
| .. code-block:: console |
| |
| $ arm-zephyr-eabi-objdump -r -d -x build/hello_world.llext |
| |
| hello_world.elf: file format elf32-littlearm |
| hello_world.elf |
| architecture: armv4t, flags 0x00000011: |
| HAS_RELOC, HAS_SYMS |
| start address 0x00000000 |
| private flags = 0x5000000: [Version5 EABI] |
| |
| Sections: |
| Idx Name Size VMA LMA File off Algn |
| 0 .text 00000038 00000000 00000000 00000034 2**2 |
| CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE |
| 1 .data 00000000 00000000 00000000 0000006c 2**0 |
| CONTENTS, ALLOC, LOAD, DATA |
| 2 .bss 00000000 00000000 00000000 0000006c 2**0 |
| ALLOC |
| 3 .rodata 00000025 00000000 00000000 0000006c 2**2 |
| CONTENTS, ALLOC, LOAD, READONLY, DATA |
| 4 .comment 00000021 00000000 00000000 00000091 2**0 |
| CONTENTS, READONLY |
| 5 .ARM.attributes 0000002a 00000000 00000000 000000b2 2**0 |
| CONTENTS, READONLY |
| SYMBOL TABLE: |
| 00000000 l df *ABS* 00000000 hello_world.c |
| 00000000 l d .text 00000000 .text |
| 00000000 l d .data 00000000 .data |
| 00000000 l d .bss 00000000 .bss |
| 00000000 l d .rodata 00000000 .rodata |
| 00000000 l O .rodata 00000004 number |
| 00000000 l d .comment 00000000 .comment |
| 00000000 l d .ARM.attributes 00000000 .ARM.attributes |
| 00000000 g F .text 00000034 hello_world |
| 00000000 *UND* 00000000 printk |
| |
| |
| |
| Disassembly of section .text: |
| |
| 00000000 <hello_world>: |
| 0: b580 push {r7, lr} |
| 2: af00 add r7, sp, #0 |
| 4: 4b08 ldr r3, [pc, #32] ; (28 <hello_world+0x28>) |
| 6: 0018 movs r0, r3 |
| 8: 4b08 ldr r3, [pc, #32] ; (2c <hello_world+0x2c>) |
| a: f000 f813 bl 34 <hello_world+0x34> |
| e: 222a movs r2, #42 ; 0x2a |
| 10: 4b07 ldr r3, [pc, #28] ; (30 <hello_world+0x30>) |
| 12: 0011 movs r1, r2 |
| 14: 0018 movs r0, r3 |
| 16: 4b05 ldr r3, [pc, #20] ; (2c <hello_world+0x2c>) |
| 18: f000 f80c bl 34 <hello_world+0x34> |
| 1c: 46c0 nop ; (mov r8, r8) |
| 1e: 46bd mov sp, r7 |
| 20: bc80 pop {r7} |
| 22: bc01 pop {r0} |
| 24: 4700 bx r0 |
| 26: 46c0 nop ; (mov r8, r8) |
| 28: 00000004 .word 0x00000004 |
| 28: R_ARM_ABS32 .rodata |
| 2c: 00000000 .word 0x00000000 |
| 2c: R_ARM_ABS32 printk |
| 30: 00000014 .word 0x00000014 |
| 30: R_ARM_ABS32 .rodata |
| 34: 4718 bx r3 |
| 36: 46c0 nop ; (mov r8, r8) |
| |
| $ xxd -p build/hello_world.llext | tr -d '\n' |
| 7f454c4601010100000000000000000001002800010000000000000000000000680200000000000534000000000028000b000a0080b500af084b1800084b00f013f82a22074b11001800054b00f00cf8c046bd4680bc01bc0047c0460400000000000000140000001847c0462a00000068656c6c6f20776f726c640a0000000041206e756d62657220697320256c750a00004743433a20285a65706879722053444b20302e31362e31292031322e322e30004129000000616561626900011f000000053454000602080109011204140115011703180119011a011e06000000000000000000000000000000000100000000000000000000000400f1ff000000000000000000000000030001000000000000000000000000000300030000000000000000000000000003000400000000000000000000000000030005000f00000000000000000000000000050012000000000000000400000001000500190000000000000000000000000001000f0000002800000000000000000001001900000034000000000000000000010000000000000000000000000003000600000000000000000000000000030007001c000000010000003400000012000100280000000000000000000000100000000068656c6c6f5f776f726c642e63002464006e756d6265720024740068656c6c6f5f776f726c64007072696e746b000028000000020500002c000000020e00003000000002050000002e73796d746162002e737472746162002e7368737472746162002e72656c2e74657874002e64617461002e627373002e726f64617461002e636f6d6d656e74002e41524d2e6174747269627574657300000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f0000000100000006000000000000003400000038000000000000000000000004000000000000001b000000090000004000000000000000fc0100001800000008000000010000000400000008000000250000000100000003000000000000006c00000000000000000000000000000001000000000000002b0000000800000003000000000000006c0000000000000000000000000000000100000000000000300000000100000002000000000000006c00000025000000000000000000000004000000000000003800000001000000300000000000000091000000210000000000000000000000010000000100000041000000030000700000000000000000b20000002a0000000000000000000000010000000000000001000000020000000000000000000000dc000000f0000000090000000d000000040000001000000009000000030000000000000000000000cc0100002f0000000000000000000000010000000000000011000000030000000000000000000000140200005100000000000000000000000100000000000000 |
| |
| In this sample there are 3 absolute (``R_ARM_ABS32``) relocations, 2 of which |
| are meant to hold addresses into the ``.rodata`` sections where the strings are |
| located. A third is an address of where the ``printk`` function (symbol) can be |
| found. At load time LLEXT replaces the values in the ``.text`` section with |
| real memory addresses so that ``printk`` works as expected with the strings |
| included in the hello world sample. |
| |
| Running |
| ******* |
| |
| Once the board has booted, you will be presented with a shell prompt. |
| All the LLEXT system related commands are available as sub-commands of |
| ``llext``, and can be seen with ``llext help``: |
| |
| .. code-block:: console |
| |
| uart:~$ llext help |
| llext - Loadable extension commands |
| Subcommands: |
| list :List loaded extensions and their size in memory |
| load_hex :Load an elf file encoded in hex directly from the shell input. |
| Syntax: |
| <ext_name> <ext_hex_string> |
| unload :Unload an extension by name. Syntax: |
| <ext_name> |
| list_symbols :List extension symbols. Syntax: |
| <ext_name> |
| call_fn :Call extension function with prototype void fn(void). Syntax: |
| <ext_name> <function_name> |
| |
| The hex string generated above can be used to load the extension: |
| |
| .. code-block:: console |
| |
| uart:~$ llext load_hex hello_world 7f454c4601010100000000000000000001002800010000000000000000000000680200000000000534000000000028000b000a0080b500af084b1800084b00f013f82a22074b11001800054b00f00cf8c046bd4680bc01bc0047c0460400000000000000140000001847c0462a00000068656c6c6f20776f726c640a0000000041206e756d62657220697320256c750a00004743433a20285a65706879722053444b20302e31362e31292031322e322e30004129000000616561626900011f000000053454000602080109011204140115011703180119011a011e06000000000000000000000000000000000100000000000000000000000400f1ff000000000000000000000000030001000000000000000000000000000300030000000000000000000000000003000400000000000000000000000000030005000f00000000000000000000000000050012000000000000000400000001000500190000000000000000000000000001000f0000002800000000000000000001001900000034000000000000000000010000000000000000000000000003000600000000000000000000000000030007001c000000010000003400000012000100280000000000000000000000100000000068656c6c6f5f776f726c642e63002464006e756d6265720024740068656c6c6f5f776f726c64007072696e746b000028000000020500002c000000020e00003000000002050000002e73796d746162002e737472746162002e7368737472746162002e72656c2e74657874002e64617461002e627373002e726f64617461002e636f6d6d656e74002e41524d2e6174747269627574657300000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f0000000100000006000000000000003400000038000000000000000000000004000000000000001b000000090000004000000000000000fc0100001800000008000000010000000400000008000000250000000100000003000000000000006c00000000000000000000000000000001000000000000002b0000000800000003000000000000006c0000000000000000000000000000000100000000000000300000000100000002000000000000006c00000025000000000000000000000004000000000000003800000001000000300000000000000091000000210000000000000000000000010000000100000041000000030000700000000000000000b20000002a0000000000000000000000010000000000000001000000020000000000000000000000dc000000f0000000090000000d000000040000001000000009000000030000000000000000000000cc0100002f0000000000000000000000010000000000000011000000030000000000000000000000140200005100000000000000000000000100000000000000 |
| |
| This extension can then be seen in the list of loaded extensions (``list``), its symbols printed |
| (``list_symbols``), and the hello_world function which the extension exports can be called and |
| run (``call_fn``). |
| |
| .. code-block:: console |
| |
| uart:~$ llext call_fn hello_world hello_world |
| hello world |