Hello world from the tests is no longer what it once was, a simple hello_world function that prints. The sample was here to let people explore and learn about how LLEXT and ELFs work. Moving the sample extension code to the shell loader sample disconnects the two and lets the sample remain simpler. We use the new CONFIG_LLEXT_IMPORT_ALL_GLOBALS to show how to build an extension with and without the Zephyr build system. Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
187 lines
11 KiB
ReStructuredText
187 lines
11 KiB
ReStructuredText
.. 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
|